mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-02 06:41:51 +00:00
imported AGI engine
svn-id: r22588
This commit is contained in:
parent
3a025038da
commit
107073537e
5
AUTHORS
5
AUTHORS
@ -24,6 +24,10 @@ ScummVM Team
|
||||
Gregory Montoir
|
||||
Eugene Sandulenko
|
||||
|
||||
AGI:
|
||||
Pawel Kolodziejski
|
||||
Eugene Sandulenko
|
||||
|
||||
BASS:
|
||||
Robert Goeffringmann
|
||||
Oliver Kiehl
|
||||
@ -193,6 +197,7 @@ Special thanks to
|
||||
Jezar - For his freeverb filter implementation
|
||||
Jim Leiterman - Various info on his FM-TOWNS/Marty SCUMM ports
|
||||
lloyd - For deep tech details about C64 Zak & MM
|
||||
Sarien Team - Original AGI engine code
|
||||
Jimmi Thogersen - For ScummRev, and much obscure code/documentation
|
||||
Tristan - For additional work on the original MT-32 emulator
|
||||
|
||||
|
@ -368,6 +368,9 @@ void PluginManager::loadPlugins() {
|
||||
#ifndef DISABLE_CINE
|
||||
LINK_PLUGIN(CINE)
|
||||
#endif
|
||||
#ifndef DISABLE_CINE
|
||||
LINK_PLUGIN(AGI)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
338
dists/msvc8/agi.vcproj
Normal file
338
dists/msvc8/agi.vcproj
Normal file
@ -0,0 +1,338 @@
|
||||
<?xml version="1.0" encoding="windows-1250"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="agi"
|
||||
ProjectGUID="{F5F57066-CDF4-4F80-B9E7-7F4D21850D6E}"
|
||||
RootNamespace="agi"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="agi_Debug"
|
||||
IntermediateDirectory="agi_Debug"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../..;../../engines"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
|
||||
MinimalRebuild="true"
|
||||
ExceptionHandling="1"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
BufferSecurityCheck="true"
|
||||
EnableFunctionLevelLinking="true"
|
||||
ForceConformanceInForLoopScope="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="false"
|
||||
SuppressStartupBanner="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/agi.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="agi_Release"
|
||||
IntermediateDirectory="agi_Release"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
|
||||
Optimization="3"
|
||||
InlineFunctionExpansion="2"
|
||||
OmitFramePointers="true"
|
||||
AdditionalIncludeDirectories="../../;../../common"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
|
||||
StringPooling="true"
|
||||
ExceptionHandling="1"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="false"
|
||||
EnableFunctionLevelLinking="false"
|
||||
ForceConformanceInForLoopScope="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="true"
|
||||
DebugInformationFormat="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/agi.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\agi.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\agi.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\agi_v2.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\agi_v3.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\checks.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\console.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\console.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\cycle.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\font.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\global.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\graphics.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\graphics.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\id.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\inv.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\keyboard.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\keyboard.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\list.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\logic.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\logic.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\lzw.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\lzw.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\menu.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\menu.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\motion.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\objects.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\op_cmd.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\op_dbg.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\op_test.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\opcodes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\patches.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\picture.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\picture.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\savegame.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\savegame.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\sound.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\sound.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\sprite.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\sprite.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\text.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\text.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\view.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\view.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\agi\words.cpp"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -4,6 +4,7 @@
|
||||
Version="8,00"
|
||||
Name="gob"
|
||||
ProjectGUID="{976D947A-A45F-4437-991E-412F695C64C7}"
|
||||
RootNamespace="gob"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
@ -246,6 +247,14 @@
|
||||
RelativePath="..\..\engines\gob\goblin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\gob\goblin_v1.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\gob\goblin_v2.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\gob\init.cpp"
|
||||
>
|
||||
@ -286,6 +295,14 @@
|
||||
RelativePath="..\..\engines\gob\map.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\gob\map_v1.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\gob\map_v2.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\gob\mult.cpp"
|
||||
>
|
||||
|
@ -4,6 +4,7 @@
|
||||
Version="8,00"
|
||||
Name="kyra"
|
||||
ProjectGUID="{9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}"
|
||||
RootNamespace="kyra"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
@ -190,6 +191,10 @@
|
||||
RelativePath="..\..\engines\kyra\kyra.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\kyra\kyra3.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\kyra\plugin.cpp"
|
||||
>
|
||||
@ -254,6 +259,10 @@
|
||||
RelativePath="..\..\engines\kyra\sound_adlib.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\kyra\sound_digital.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\kyra\sprites.cpp"
|
||||
>
|
||||
@ -278,6 +287,14 @@
|
||||
RelativePath="..\..\engines\kyra\timer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\kyra\vqa.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\kyra\vqa.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\engines\kyra\wsamovie.cpp"
|
||||
>
|
||||
|
@ -1,15 +1,16 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual C++ Express 2005
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scummvm", "scummvm.vcproj", "{8434CB15-D08F-427D-9E6D-581AE5B28440}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{6CC3E421-779D-4E80-8100-520886A0F9FF} = {6CC3E421-779D-4E80-8100-520886A0F9FF}
|
||||
{1CA4AC50-5426-433A-8B5E-FFE39568098E} = {1CA4AC50-5426-433A-8B5E-FFE39568098E}
|
||||
{F5F57066-CDF4-4F80-B9E7-7F4D21850D6E} = {F5F57066-CDF4-4F80-B9E7-7F4D21850D6E}
|
||||
{676DB4C5-9A3E-4EE1-8483-EBB79DC0700E} = {676DB4C5-9A3E-4EE1-8483-EBB79DC0700E}
|
||||
{9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC} = {9D9A98A0-F88F-4CA2-B8FF-462470EBE3EC}
|
||||
{976D947A-A45F-4437-991E-412F695C64C7} = {976D947A-A45F-4437-991E-412F695C64C7}
|
||||
{E0EC9C72-A33E-49DA-B1DC-BB44B9799BFA} = {E0EC9C72-A33E-49DA-B1DC-BB44B9799BFA}
|
||||
{6A55AF61-7CA1-49E0-9385-59C1FE9D4DB7} = {6A55AF61-7CA1-49E0-9385-59C1FE9D4DB7}
|
||||
{B5527758-2F51-4CCD-AAE1-B0E28654BD6A} = {B5527758-2F51-4CCD-AAE1-B0E28654BD6A}
|
||||
{1CA4AC50-5426-433A-8B5E-FFE39568098E} = {1CA4AC50-5426-433A-8B5E-FFE39568098E}
|
||||
{B6AFD548-63D2-40CD-A652-E87095AFCBAF} = {B6AFD548-63D2-40CD-A652-E87095AFCBAF}
|
||||
{C8AAE83E-198B-4ECA-A877-166827953979} = {C8AAE83E-198B-4ECA-A877-166827953979}
|
||||
{1A1CA028-61B5-4A6C-A918-F5D8721AB1AC} = {1A1CA028-61B5-4A6C-A918-F5D8721AB1AC}
|
||||
@ -37,6 +38,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lure", "lure.vcproj", "{1A1
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cine", "cine.vcproj", "{1CA4AC50-5426-433A-8B5E-FFE39568098E}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "agi", "agi.vcproj", "{F5F57066-CDF4-4F80-B9E7-7F4D21850D6E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
@ -91,6 +94,10 @@ Global
|
||||
{1CA4AC50-5426-433A-8B5E-FFE39568098E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{1CA4AC50-5426-433A-8B5E-FFE39568098E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{1CA4AC50-5426-433A-8B5E-FFE39568098E}.Release|Win32.Build.0 = Release|Win32
|
||||
{F5F57066-CDF4-4F80-B9E7-7F4D21850D6E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F5F57066-CDF4-4F80-B9E7-7F4D21850D6E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F5F57066-CDF4-4F80-B9E7-7F4D21850D6E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F5F57066-CDF4-4F80-B9E7-7F4D21850D6E}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -4,6 +4,7 @@
|
||||
Version="8,00"
|
||||
Name="scummvm"
|
||||
ProjectGUID="{8434CB15-D08F-427D-9E6D-581AE5B28440}"
|
||||
RootNamespace="scummvm"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
@ -67,7 +68,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib sdl.lib zdll.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib sword1_debug/sword1.lib sword2_debug/sword2.lib lure_debug/lure.lib cine_debug/cine.lib kyra_debug/kyra.lib gob_debug/gob.lib queen_debug/queen.lib saga_debug/saga.lib scumm_debug/scumm.lib simon_debug/simon.lib sky_debug/sky.lib"
|
||||
AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib sword1_debug/sword1.lib sword2_debug/sword2.lib lure_debug/lure.lib cine_debug/cine.lib kyra_debug/kyra.lib gob_debug/gob.lib queen_debug/queen.lib saga_debug/saga.lib agi_debug/agi.lib scumm_debug/scumm.lib simon_debug/simon.lib sky_debug/sky.lib"
|
||||
OutputFile="$(OutDir)/scummvm.exe"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcmt.lib"
|
||||
@ -155,7 +156,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib sdl.lib zdll.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib saga_release/saga.lib sword1_release/sword1.lib sword2_release/sword2.lib lure_release/lure.lib cine_release/cine.lib kyra_release/kyra.lib gob_release/gob.lib queen_release/queen.lib scumm_release/scumm.lib simon_release/simon.lib sky_release/sky.lib"
|
||||
AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib saga_release/saga.lib agi_release/agi.lib sword1_release/sword1.lib sword2_release/sword2.lib lure_release/lure.lib cine_release/cine.lib kyra_release/kyra.lib gob_release/gob.lib queen_release/queen.lib scumm_release/scumm.lib simon_release/simon.lib sky_release/sky.lib"
|
||||
OutputFile="$(OutDir)/scummvm.exe"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="true"
|
||||
@ -997,6 +998,14 @@
|
||||
RelativePath="..\..\graphics\imageman.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\graphics\paletteman.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\graphics\paletteman.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\graphics\primitives.cpp"
|
||||
>
|
||||
|
@ -34,6 +34,13 @@
|
||||
Eugene Sandulenko & \textit{}\\
|
||||
\end{tabular}
|
||||
\end{list}
|
||||
\item \textbf{ AGI}
|
||||
\begin{list}{}{\setlength{\leftmargin}{0.2cm}}
|
||||
\item \begin{tabular}[h]{p{0.3\linewidth}p{0.6\linewidth}}
|
||||
Pawe{\l} Ko{\l}odziejski & \textit{}\\
|
||||
Eugene Sandulenko & \textit{}\\
|
||||
\end{tabular}
|
||||
\end{list}
|
||||
\item \textbf{ BASS}
|
||||
\begin{list}{}{\setlength{\leftmargin}{0.2cm}}
|
||||
\item \begin{tabular}[h]{p{0.3\linewidth}p{0.6\linewidth}}
|
||||
@ -293,6 +300,7 @@ And to all the contributors, users, and beta testers we've missed. Thanks!
|
||||
Jezar & \textit{For his freeverb filter implementation}\\
|
||||
Jim Leiterman & \textit{Various info on his FM-TOWNS/Marty SCUMM ports}\\
|
||||
lloyd & \textit{For deep tech details about C64 Zak \& MM}\\
|
||||
Sarien Team & \textit{Original AGI engine code}\\
|
||||
Jimmi Th{\o}gersen & \textit{For ScummRev, and much obscure code/documentation}\\
|
||||
Tristan & \textit{For additional work on the original MT-32 emulator}\\
|
||||
\end{tabular}
|
||||
|
627
engines/agi/agi.cpp
Normal file
627
engines/agi/agi.cpp
Normal file
@ -0,0 +1,627 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
#include "common/file.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/config-manager.h"
|
||||
|
||||
#include "base/plugins.h"
|
||||
|
||||
#include "backends/fs/fs.h"
|
||||
|
||||
#include "sound/mididrv.h"
|
||||
#include "sound/mixer.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/text.h"
|
||||
#include "agi/graphics.h"
|
||||
#include "agi/sprite.h"
|
||||
#include "agi/opcodes.h"
|
||||
#include "agi/keyboard.h"
|
||||
#include "agi/menu.h"
|
||||
#include "agi/savegame.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
void gfx_set_palette();
|
||||
|
||||
extern int optind;
|
||||
|
||||
struct agi_options opt;
|
||||
struct game_id_list game_info;
|
||||
struct agi_game game;
|
||||
|
||||
static struct agi_loader *loader; /* loader */
|
||||
|
||||
extern struct agi_loader agi_v2;
|
||||
extern struct agi_loader agi_v3;
|
||||
|
||||
static volatile uint32 tick_timer = 0;
|
||||
|
||||
#define TICK_SECONDS 20
|
||||
|
||||
static int key_control = 0;
|
||||
static int key_alt = 0;
|
||||
|
||||
#define KEY_QUEUE_SIZE 16
|
||||
|
||||
static int key_queue[KEY_QUEUE_SIZE];
|
||||
static int key_queue_start = 0;
|
||||
static int key_queue_end = 0;
|
||||
|
||||
#define key_enqueue(k) do { key_queue[key_queue_end++] = (k); \
|
||||
key_queue_end %= KEY_QUEUE_SIZE; } while (0)
|
||||
#define key_dequeue(k) do { (k) = key_queue[key_queue_start++]; \
|
||||
key_queue_start %= KEY_QUEUE_SIZE; } while (0)
|
||||
|
||||
static void process_events() {
|
||||
OSystem::Event event;
|
||||
int key = 0;
|
||||
|
||||
while (g_system->pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case OSystem::EVENT_QUIT:
|
||||
deinit_video();
|
||||
deinit_machine();
|
||||
g_system->quit();
|
||||
break;
|
||||
case OSystem::EVENT_LBUTTONDOWN:
|
||||
key = BUTTON_LEFT;
|
||||
mouse.button = 1;
|
||||
key_enqueue(key);
|
||||
mouse.x = event.mouse.x;
|
||||
mouse.y = event.mouse.y;
|
||||
break;
|
||||
case OSystem::EVENT_RBUTTONDOWN:
|
||||
key = BUTTON_RIGHT;
|
||||
mouse.button = 2;
|
||||
key_enqueue(key);
|
||||
mouse.x = event.mouse.x;
|
||||
mouse.y = event.mouse.y;
|
||||
break;
|
||||
case OSystem::EVENT_MOUSEMOVE:
|
||||
mouse.x = event.mouse.x;
|
||||
mouse.y = event.mouse.y;
|
||||
break;
|
||||
case OSystem::EVENT_LBUTTONUP:
|
||||
case OSystem::EVENT_RBUTTONUP:
|
||||
mouse.button = 0;
|
||||
break;
|
||||
case OSystem::EVENT_KEYDOWN:
|
||||
if (event.kbd.flags == OSystem::KBD_CTRL) {
|
||||
key_control |= 1;
|
||||
key = 0;
|
||||
break;
|
||||
} else if (event.kbd.flags == OSystem::KBD_ALT) {
|
||||
key_alt |= 1;
|
||||
key = 0;
|
||||
break;
|
||||
} else if (event.kbd.flags == OSystem::KBD_SHIFT) {
|
||||
key = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (key = event.kbd.keycode) {
|
||||
case 256 + 20: // left arrow
|
||||
key = KEY_LEFT;
|
||||
break;
|
||||
case 256 + 19: // right arrow
|
||||
key = KEY_RIGHT;
|
||||
break;
|
||||
case 256 + 17: // up arrow
|
||||
key = KEY_UP;
|
||||
break;
|
||||
case 256 + 18: // down arrow
|
||||
key = KEY_DOWN;
|
||||
break;
|
||||
case 256 + 24: // page up
|
||||
key = KEY_UP_RIGHT;
|
||||
break;
|
||||
case 256 + 25: // page down
|
||||
key = KEY_DOWN_RIGHT;
|
||||
break;
|
||||
case 256 + 22: // home
|
||||
key = KEY_UP_LEFT;
|
||||
break;
|
||||
case 256 + 23: // end
|
||||
key = KEY_DOWN_LEFT;
|
||||
break;
|
||||
case '+':
|
||||
key = '+';
|
||||
break;
|
||||
case '-':
|
||||
key = '-';
|
||||
break;
|
||||
case 9:
|
||||
key = 0x0009;
|
||||
break;
|
||||
case 282:
|
||||
key = 0x3b00;
|
||||
break;
|
||||
case 283:
|
||||
key = 0x3c00;
|
||||
break;
|
||||
case 284:
|
||||
key = 0x3d00;
|
||||
break;
|
||||
case 285:
|
||||
key = 0x3e00;
|
||||
break;
|
||||
case 286:
|
||||
key = 0x3f00;
|
||||
break;
|
||||
case 287:
|
||||
key = 0x4000;
|
||||
break;
|
||||
case 288:
|
||||
key = 0x4100;
|
||||
break;
|
||||
case 289:
|
||||
key = 0x4200;
|
||||
break;
|
||||
case 290:
|
||||
key = 0x4300;
|
||||
break;
|
||||
case 291:
|
||||
key = 0x4400;
|
||||
break;
|
||||
case 292:
|
||||
key = KEY_STATUSLN;
|
||||
break;
|
||||
case 293:
|
||||
key = KEY_PRIORITY;
|
||||
break;
|
||||
case 27:
|
||||
key = 0x1b;
|
||||
break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
key = KEY_ENTER;
|
||||
break;
|
||||
default:
|
||||
if (!isalpha(key))
|
||||
break;
|
||||
if (key_control)
|
||||
key = (key & ~0x20) - 0x40;
|
||||
else if (key_alt)
|
||||
key = scancode_table[(key & ~0x20) - 0x41] << 8;
|
||||
break;
|
||||
}
|
||||
if (key)
|
||||
key_enqueue(key);
|
||||
break;
|
||||
case OSystem::EVENT_KEYUP:
|
||||
if (event.kbd.flags == OSystem::KBD_CTRL) {
|
||||
key_control &= ~1;
|
||||
key = 0;
|
||||
break;
|
||||
} else if (event.kbd.flags == OSystem::KBD_ALT) {
|
||||
key_alt &= ~1;
|
||||
key = 0;
|
||||
break;
|
||||
} else if (event.kbd.flags == OSystem::KBD_SHIFT) {
|
||||
key = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int agi_is_keypress_low() {
|
||||
process_events();
|
||||
return key_queue_start != key_queue_end;
|
||||
}
|
||||
|
||||
void agi_timer_low() {
|
||||
static uint32 m = 0;
|
||||
uint32 dm;
|
||||
|
||||
if (tick_timer < m)
|
||||
m = 0;
|
||||
|
||||
while ((dm = tick_timer - m) < 5) {
|
||||
process_events();
|
||||
g_system->delayMillis(10);
|
||||
g_system->updateScreen();
|
||||
}
|
||||
m = tick_timer;
|
||||
}
|
||||
|
||||
int agi_get_keypress_low() {
|
||||
int k;
|
||||
|
||||
while (key_queue_start == key_queue_end) /* block */
|
||||
agi_timer_low();
|
||||
key_dequeue(k);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
static uint32 agi_timer_function_low(uint32 i) {
|
||||
tick_timer++;
|
||||
return i;
|
||||
}
|
||||
|
||||
static void init_pri_table() {
|
||||
int i, p, y = 0;
|
||||
|
||||
for (p = 1; p < 15; p++) {
|
||||
for (i = 0; i < 12; i++) {
|
||||
game.pri_table[y++] = p < 4 ? 4 : p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int agi_init() {
|
||||
int ec, i;
|
||||
|
||||
debug(2, "initializing");
|
||||
debug(2, "game.ver = 0x%x", game.ver);
|
||||
|
||||
/* reset all flags to false and all variables to 0 */
|
||||
for (i = 0; i < MAX_FLAGS; i++)
|
||||
game.flags[i] = 0;
|
||||
for (i = 0; i < MAX_VARS; i++)
|
||||
game.vars[i] = 0;
|
||||
|
||||
/* clear all resources and events */
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
memset(&game.views[i], 0, sizeof(struct agi_view));
|
||||
memset(&game.pictures[i], 0, sizeof(struct agi_picture));
|
||||
memset(&game.logics[i], 0, sizeof(struct agi_logic));
|
||||
memset(&game.sounds[i], 0, sizeof(struct agi_sound));
|
||||
}
|
||||
|
||||
/* clear view table */
|
||||
for (i = 0; i < MAX_VIEWTABLE; i++)
|
||||
memset(&game.view_table[i], 0, sizeof(struct vt_entry));
|
||||
|
||||
init_words();
|
||||
|
||||
menu_init();
|
||||
init_pri_table();
|
||||
|
||||
/* clear string buffer */
|
||||
for (i = 0; i < MAX_STRINGS; i++)
|
||||
game.strings[i][0] = 0;
|
||||
|
||||
/* setup emulation */
|
||||
|
||||
switch (loader->int_version >> 12) {
|
||||
case 2:
|
||||
report("Emulating Sierra AGI v%x.%03x\n",
|
||||
(int)(loader->int_version >> 12) & 0xF,
|
||||
(int)(loader->int_version) & 0xFFF);
|
||||
break;
|
||||
case 3:
|
||||
report("Emulating Sierra AGI v%x.002.%03x\n",
|
||||
(int)(loader->int_version >> 12) & 0xF,
|
||||
(int)(loader->int_version) & 0xFFF);
|
||||
break;
|
||||
}
|
||||
|
||||
game.game_flags |= opt.amiga ? ID_AMIGA : 0;
|
||||
game.game_flags |= opt.agds ? ID_AGDS : 0;
|
||||
|
||||
if (game.game_flags & ID_AMIGA)
|
||||
report("Amiga padded game detected.\n");
|
||||
|
||||
if (game.game_flags & ID_AGDS)
|
||||
report("AGDS mode enabled.\n");
|
||||
|
||||
ec = loader->init(); /* load vol files, etc */
|
||||
|
||||
if (ec == err_OK)
|
||||
ec = loader->load_objects(OBJECTS);
|
||||
|
||||
/* note: demogs has no words.tok */
|
||||
if (ec == err_OK)
|
||||
ec = loader->load_words(WORDS);
|
||||
|
||||
/* FIXME: load IIgs instruments and samples */
|
||||
/* load_instruments("kq.sys16"); */
|
||||
|
||||
/* Load logic 0 into memory */
|
||||
if (ec == err_OK)
|
||||
ec = loader->load_resource(rLOGIC, 0);
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
void agi_unload_resources() {
|
||||
int i;
|
||||
|
||||
/* Make sure logic 0 is always loaded */
|
||||
for (i = 1; i < MAX_DIRS; i++) {
|
||||
loader->unload_resource(rLOGIC, i);
|
||||
}
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
loader->unload_resource(rVIEW, i);
|
||||
loader->unload_resource(rPICTURE, i);
|
||||
loader->unload_resource(rSOUND, i);
|
||||
}
|
||||
}
|
||||
|
||||
int agi_deinit() {
|
||||
int ec;
|
||||
|
||||
clean_input(); /* remove all words from memory */
|
||||
agi_unload_resources(); /* unload resources in memory */
|
||||
loader->unload_resource(rLOGIC, 0);
|
||||
ec = loader->deinit();
|
||||
unload_objects();
|
||||
unload_words();
|
||||
|
||||
clear_image_stack();
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
int agi_detect_game() {
|
||||
int ec = err_OK;
|
||||
|
||||
loader = &agi_v2;
|
||||
ec = loader->detect_game();
|
||||
|
||||
if (ec != err_OK) {
|
||||
loader = &agi_v3;
|
||||
ec = loader->detect_game();
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
int agi_version() {
|
||||
return loader->version;
|
||||
}
|
||||
|
||||
int agi_get_release() {
|
||||
return loader->int_version;
|
||||
}
|
||||
|
||||
void agi_set_release(int n) {
|
||||
loader->int_version = n;
|
||||
}
|
||||
|
||||
int agi_load_resource(int r, int n) {
|
||||
int i;
|
||||
|
||||
i = loader->load_resource(r, n);
|
||||
#ifdef PATCH_LOGIC
|
||||
if (r == rLOGIC)
|
||||
patch_logic(n);
|
||||
#endif
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int agi_unload_resource(int r, int n) {
|
||||
return loader->unload_resource(r, n);
|
||||
}
|
||||
|
||||
const char *_savePath;
|
||||
extern AGIMusic *g_agi_music;
|
||||
|
||||
struct GameSettings {
|
||||
const char *gameid;
|
||||
const char *description;
|
||||
byte id;
|
||||
uint32 features;
|
||||
const char *detectname;
|
||||
};
|
||||
|
||||
static const GameSettings agi_settings[] = {
|
||||
{"agi", "AGI game", GID_AGI, MDT_ADLIB, "VIEWDIR"},
|
||||
{NULL, NULL, 0, 0, NULL}
|
||||
};
|
||||
|
||||
Common::RandomSource * rnd;
|
||||
|
||||
AgiEngine::AgiEngine(OSystem * syst) : Engine(syst) {
|
||||
|
||||
// Setup mixer
|
||||
if (!_mixer->isReady()) {
|
||||
warning("Sound initialization failed.");
|
||||
}
|
||||
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
|
||||
|
||||
_savePath = _saveFileMan->getSavePath();
|
||||
|
||||
const GameSettings *g;
|
||||
|
||||
const char *gameid = ConfMan.get("gameid").c_str();
|
||||
for (g = agi_settings; g->gameid; ++g)
|
||||
if (!scumm_stricmp(g->gameid, gameid))
|
||||
_gameId = g->id;
|
||||
|
||||
rnd = new Common::RandomSource();
|
||||
|
||||
game.clock_enabled = false;
|
||||
game.state = STATE_INIT;
|
||||
}
|
||||
|
||||
void AgiEngine::initialize() {
|
||||
memset(&opt, 0, sizeof(struct agi_options));
|
||||
opt.gamerun = GAMERUN_RUNGAME;
|
||||
#ifdef USE_HIRES
|
||||
opt.hires = true;
|
||||
#endif
|
||||
opt.soundemu = SOUND_EMU_NONE;
|
||||
|
||||
init_machine();
|
||||
|
||||
game.color_fg = 15;
|
||||
game.color_bg = 0;
|
||||
|
||||
*game.name = 0;
|
||||
|
||||
game.sbuf = (uint8 *) calloc(_WIDTH, _HEIGHT);
|
||||
#ifdef USE_HIRES
|
||||
game.hires = (uint8 *) calloc(_WIDTH * 2, _HEIGHT);
|
||||
#endif
|
||||
|
||||
init_sprites();
|
||||
init_video();
|
||||
|
||||
tick_timer = 0;
|
||||
Common::g_timer->installTimerProc((Common::Timer::TimerProc) agi_timer_function_low, 10 * 1000, NULL);
|
||||
|
||||
console_init();
|
||||
|
||||
game.ver = -1; /* Don't display the conf file warning */
|
||||
|
||||
debugC(2, kDebugLevelMain, "Detect game");
|
||||
if (agi_detect_game() == err_OK) {
|
||||
game.state = STATE_LOADED;
|
||||
debugC(2, kDebugLevelMain, "game loaded");
|
||||
} else {
|
||||
report("Could not open AGI game");
|
||||
}
|
||||
|
||||
debugC(2, kDebugLevelMain, "Init sound");
|
||||
init_sound();
|
||||
g_agi_music = new AGIMusic(_mixer);
|
||||
}
|
||||
|
||||
AgiEngine::~AgiEngine() {
|
||||
agi_deinit();
|
||||
delete g_agi_music;
|
||||
deinit_sound();
|
||||
deinit_video();
|
||||
deinit_sprites();
|
||||
#ifdef USE_HIRES
|
||||
free(game.hires);
|
||||
#endif
|
||||
free(game.sbuf);
|
||||
deinit_machine();
|
||||
delete rnd;
|
||||
}
|
||||
|
||||
void AgiEngine::errorString(const char *buf1, char *buf2) {
|
||||
strcpy(buf2, buf1);
|
||||
}
|
||||
|
||||
int AgiEngine::init() {
|
||||
// Initialize backend
|
||||
_system->beginGFXTransaction();
|
||||
initCommonGFX(false);
|
||||
_system->initSize(320, 200);
|
||||
_system->endGFXTransaction();
|
||||
|
||||
Common::addSpecialDebugLevel(kDebugLevelMain, "Main", "Generic debug level");
|
||||
Common::addSpecialDebugLevel(kDebugLevelResources, "Resources", "Resources debugging");
|
||||
Common::addSpecialDebugLevel(kDebugLevelSprites, "Sprites", "Sprites debugging");
|
||||
Common::addSpecialDebugLevel(kDebugLevelInventory, "Inventory", "Inventory debugging");
|
||||
Common::addSpecialDebugLevel(kDebugLevelInput, "Input", "Input events debugging");
|
||||
Common::addSpecialDebugLevel(kDebugLevelMenu, "Menu", "Menu debugging");
|
||||
Common::addSpecialDebugLevel(kDebugLevelScripts, "Scrpits", "Scripts debugging");
|
||||
Common::addSpecialDebugLevel(kDebugLevelSound, "Sound", "Sound debugging");
|
||||
Common::addSpecialDebugLevel(kDebugLevelText, "Text", "Text output debugging");
|
||||
|
||||
initialize();
|
||||
|
||||
gfx_set_palette();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AgiEngine::go() {
|
||||
_system->showMouse(true);
|
||||
|
||||
report(" \nAGI engine " VERSION " is ready.\n");
|
||||
if (game.state < STATE_LOADED) {
|
||||
console_prompt();
|
||||
do {
|
||||
main_cycle();
|
||||
} while (game.state < STATE_RUNNING);
|
||||
if (game.ver < 0)
|
||||
game.ver = 0; /* Enable conf file warning */
|
||||
}
|
||||
|
||||
run_game();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
GameList Engine_AGI_gameIDList() {
|
||||
GameList games;
|
||||
const Agi::GameSettings *g = Agi::agi_settings;
|
||||
|
||||
while (g->gameid) {
|
||||
games.push_back(*g);
|
||||
g++;
|
||||
}
|
||||
|
||||
return games;
|
||||
}
|
||||
|
||||
GameDescriptor Engine_AGI_findGameID(const char *gameid) {
|
||||
const Agi::GameSettings *g = Agi::agi_settings;
|
||||
while (g->gameid) {
|
||||
if (0 == scumm_stricmp(gameid, g->gameid))
|
||||
break;
|
||||
g++;
|
||||
}
|
||||
return *g;
|
||||
}
|
||||
|
||||
DetectedGameList Engine_AGI_detectGames(const FSList &fslist) {
|
||||
DetectedGameList detectedGames;
|
||||
const Agi::GameSettings * g;
|
||||
|
||||
for (g = Agi::agi_settings; g->gameid; ++g) {
|
||||
// Iterate over all files in the given directory
|
||||
for (FSList::const_iterator file = fslist.begin();
|
||||
file != fslist.end(); ++file) {
|
||||
const char *gameName = file->displayName().c_str();
|
||||
|
||||
if (0 == scumm_stricmp(g->detectname, gameName)) {
|
||||
// Match found, add to list of candidates, then abort inner loop.
|
||||
detectedGames.push_back(*g);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return detectedGames;
|
||||
}
|
||||
|
||||
PluginError Engine_AGI_create(OSystem *syst, Engine **engine) {
|
||||
assert(engine);
|
||||
*engine = new Agi::AgiEngine(syst);
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN(AGI, "AGI Engine");
|
545
engines/agi/agi.h
Normal file
545
engines/agi/agi.h
Normal file
@ -0,0 +1,545 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_H
|
||||
#define __AGI_H
|
||||
|
||||
#include "common/stdafx.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/util.h"
|
||||
#include "common/file.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "base/engine.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
typedef signed int Err;
|
||||
|
||||
/*
|
||||
* Version and other definitions
|
||||
*/
|
||||
#define INLINE __inline
|
||||
#define VERSION __DATE__ " " __TIME__
|
||||
|
||||
/* Default features -- can be overriden in portdefs.h */
|
||||
#define USE_CONSOLE
|
||||
#define USE_PCM_SOUND
|
||||
#define USE_IIGS_SOUND
|
||||
#define USE_HIRES
|
||||
#define USE_MOUSE
|
||||
#define AGDS_SUPPORT
|
||||
|
||||
#define TITLE "AGI engine"
|
||||
|
||||
#define DIR_ "dir"
|
||||
#define LOGDIR "logdir"
|
||||
#define PICDIR "picdir"
|
||||
#define VIEWDIR "viewdir"
|
||||
#define SNDDIR "snddir"
|
||||
#define OBJECTS "object"
|
||||
#define WORDS "words.tok"
|
||||
|
||||
#define MAX_DIRS 256
|
||||
#define MAX_VARS 256
|
||||
#define MAX_FLAGS (256 >> 3)
|
||||
#define MAX_VIEWTABLE 255 /* KQ3 uses o255! */
|
||||
#define MAX_WORDS 20
|
||||
#define MAX_STRINGS 24 /* MAX_STRINGS + 1 used for get.num */
|
||||
#define MAX_STRINGLEN 40
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 260
|
||||
#endif
|
||||
|
||||
#define _EMPTY 0xfffff
|
||||
#define EGO_OWNED 0xff
|
||||
|
||||
#define CRYPT_KEY_SIERRA "Avis Durgan"
|
||||
#define CRYPT_KEY_AGDS "Alex Simkin"
|
||||
|
||||
#ifndef INLINE
|
||||
#define INLINE
|
||||
#endif
|
||||
|
||||
#ifndef USE_PCM_SOUND
|
||||
#undef USE_IIGS_SOUND
|
||||
#endif
|
||||
|
||||
#define MSG_BOX_COLOUR 0x0f /* White */
|
||||
#define MSG_BOX_TEXT 0x00 /* Black */
|
||||
#define MSG_BOX_LINE 0x04 /* Red */
|
||||
#define STATUS_FG 0x00 /* Black */
|
||||
#define STATUS_BG 0x0f /* White */
|
||||
#define PATCH_LOGIC /* disable copy protection on some games */
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
/* AGI resources */
|
||||
#include "agi/console.h"
|
||||
#include "agi/view.h"
|
||||
#include "agi/picture.h"
|
||||
#include "agi/logic.h"
|
||||
#include "agi/sound.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
int getflag(int);
|
||||
void setflag(int, int);
|
||||
void flipflag(int);
|
||||
int getvar(int);
|
||||
void setvar(int, int);
|
||||
void decrypt(uint8 * mem, int len);
|
||||
void release_sprites(void);
|
||||
int main_cycle(void);
|
||||
int view_pictures(void);
|
||||
int parse_cli(int, char **);
|
||||
int run_game(void);
|
||||
int init_machine(void);
|
||||
int deinit_machine(void);
|
||||
int get_direction(int x, int y, int x0, int y0, int s);
|
||||
void inventory(void);
|
||||
void list_games(void);
|
||||
uint32 match_crc(uint32, char *, int);
|
||||
int v2id_game(void);
|
||||
int v3id_game(void);
|
||||
int v4id_game(uint32 ver);
|
||||
void update_timer(void);
|
||||
int get_app_dir(char *app_dir, unsigned int size);
|
||||
|
||||
enum {
|
||||
NO_GAMEDIR = 0,
|
||||
GAMEDIR
|
||||
};
|
||||
|
||||
enum AGIErrors {
|
||||
err_OK = 0,
|
||||
err_DoNothing,
|
||||
err_BadCLISwitch,
|
||||
err_InvalidAGIFile,
|
||||
err_BadFileOpen,
|
||||
err_NotEnoughMemory,
|
||||
err_BadResource,
|
||||
err_UnknownAGIVersion,
|
||||
err_RestartGame,
|
||||
err_NoLoopsInView,
|
||||
err_ViewDataError,
|
||||
err_NoGameList,
|
||||
|
||||
err_Unk = 127
|
||||
};
|
||||
|
||||
enum kDebugLevels {
|
||||
kDebugLevelMain = 1 << 0,
|
||||
kDebugLevelResources = 1 << 1,
|
||||
kDebugLevelSprites = 1 << 2,
|
||||
kDebugLevelInventory = 1 << 3,
|
||||
kDebugLevelInput = 1 << 4,
|
||||
kDebugLevelMenu = 1 << 5,
|
||||
kDebugLevelScripts = 1 << 6,
|
||||
kDebugLevelSound = 1 << 7,
|
||||
kDebugLevelText = 1 << 8
|
||||
};
|
||||
|
||||
/**
|
||||
* AGI resources.
|
||||
*/
|
||||
enum {
|
||||
rLOGIC = 1,
|
||||
rSOUND,
|
||||
rVIEW,
|
||||
rPICTURE
|
||||
};
|
||||
|
||||
enum {
|
||||
RES_LOADED = 1,
|
||||
RES_COMPRESSED = 0x40
|
||||
};
|
||||
|
||||
enum {
|
||||
lCOMMAND_MODE = 1,
|
||||
lTEST_MODE
|
||||
};
|
||||
|
||||
struct game_id_list {
|
||||
struct game_id_list *next;
|
||||
uint32 version;
|
||||
uint32 crc;
|
||||
char *gName;
|
||||
char *switches;
|
||||
};
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
struct mouse {
|
||||
int button;
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Command-line options.
|
||||
*/
|
||||
struct agi_options {
|
||||
#define GAMERUN_RUNGAME 0
|
||||
#define GAMERUN_PICVIEW 1
|
||||
#define GAMERUN_WORDS 2
|
||||
#define GAMERUN_OBJECTS 3
|
||||
#define GAMERUN_GAMES 4
|
||||
#define GAMERUN_CRC 5
|
||||
int gamerun; /**< game run mode*/
|
||||
int emuversion; /**< AGI version to emulate */
|
||||
int agds; /**< enable AGDS mode */
|
||||
int amiga; /**< enable Amiga mode */
|
||||
int fullscreen; /**< use full screen mode if available */
|
||||
int nosound; /**< disable sound */
|
||||
int egapal; /**< use PC EGA palette */
|
||||
int cgaemu; /**< use PC CGA emulation */
|
||||
#ifdef USE_HIRES
|
||||
int hires; /**< use hi-res pictures */
|
||||
#endif
|
||||
int soundemu; /**< sound emulation mode */
|
||||
#ifdef USE_MOUSE
|
||||
int agimouse; /**< AGI Mouse 1.0 emulation */
|
||||
#endif
|
||||
};
|
||||
|
||||
extern struct agi_options opt;
|
||||
extern uint8 *exec_name;
|
||||
|
||||
extern volatile uint32 clock_ticks;
|
||||
extern volatile uint32 clock_count;
|
||||
extern volatile uint32 msg_box_secs2;
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
extern struct agi_debug debug_;
|
||||
#endif
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
extern struct mouse mouse;
|
||||
#endif
|
||||
|
||||
int console_keyhandler(int);
|
||||
int console_init(void);
|
||||
void console_cycle(void);
|
||||
void console_lock(void);
|
||||
void console_prompt(void);
|
||||
#define report printf
|
||||
|
||||
enum GameId {
|
||||
GID_AGI = 1
|
||||
};
|
||||
|
||||
extern Common::RandomSource * rnd;
|
||||
extern const char *_savePath;
|
||||
|
||||
class AgiEngine:public::Engine {
|
||||
int _gameId;
|
||||
|
||||
void errorString(const char *buf_input, char *buf_output);
|
||||
|
||||
protected:
|
||||
int init();
|
||||
int go();
|
||||
void shutdown();
|
||||
void initialize();
|
||||
|
||||
|
||||
public:
|
||||
AgiEngine(OSystem * syst);
|
||||
virtual ~ AgiEngine();
|
||||
int getGameId() {
|
||||
return _gameId;
|
||||
}};
|
||||
|
||||
#define WIN_TO_PIC_X(x) ((x) / 2)
|
||||
#define WIN_TO_PIC_Y(y) ((y) < 8 ? 999 : (y) >= (8 + _HEIGHT) ? 999 : (y) - 8)
|
||||
|
||||
/**
|
||||
* AGI variables.
|
||||
*/
|
||||
enum {
|
||||
V_cur_room = 0, /* 0 */
|
||||
V_prev_room,
|
||||
V_border_touch_ego,
|
||||
V_score,
|
||||
V_border_code,
|
||||
V_border_touch_obj, /* 5 */
|
||||
V_ego_dir,
|
||||
V_max_score,
|
||||
V_free_pages,
|
||||
V_word_not_found,
|
||||
V_time_delay, /* 10 */
|
||||
V_seconds,
|
||||
V_minutes,
|
||||
V_hours,
|
||||
V_days,
|
||||
V_joystick_sensitivity, /* 15 */
|
||||
V_ego_view_resource,
|
||||
V_agi_err_code,
|
||||
V_agi_err_code_info,
|
||||
V_key,
|
||||
V_computer, /* 20 */
|
||||
V_window_reset,
|
||||
V_soundgen,
|
||||
V_volume,
|
||||
V_max_input_chars,
|
||||
V_sel_item, /* 25 */
|
||||
V_monitor
|
||||
};
|
||||
|
||||
/**
|
||||
* AGI flags
|
||||
*/
|
||||
enum {
|
||||
F_ego_water = 0, /* 0 */
|
||||
F_ego_invisible,
|
||||
F_entered_cli,
|
||||
F_ego_touched_p2,
|
||||
F_said_accepted_input,
|
||||
F_new_room_exec, /* 5 */
|
||||
F_restart_game,
|
||||
F_script_blocked,
|
||||
F_joy_sensitivity,
|
||||
F_sound_on,
|
||||
F_debugger_on, /* 10 */
|
||||
F_logic_zero_firsttime,
|
||||
F_restore_just_ran,
|
||||
F_status_selects_items,
|
||||
F_menus_work,
|
||||
F_output_mode, /* 15 */
|
||||
F_auto_restart
|
||||
};
|
||||
|
||||
struct agi_event {
|
||||
uint16 data;
|
||||
uint8 occured;
|
||||
};
|
||||
|
||||
struct agi_object {
|
||||
int location;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct agi_word {
|
||||
int id;
|
||||
char *word;
|
||||
};
|
||||
|
||||
struct agi_dir {
|
||||
uint8 volume;
|
||||
uint32 offset;
|
||||
uint32 len;
|
||||
uint32 clen;
|
||||
uint8 flags;
|
||||
/* 0 = not in mem, can be freed
|
||||
* 1 = in mem, can be released
|
||||
* 2 = not in mem, cant be released
|
||||
* 3 = in mem, cant be released
|
||||
* 0x40 = was compressed
|
||||
*/
|
||||
};
|
||||
|
||||
struct agi_block {
|
||||
int active;
|
||||
int x1, y1;
|
||||
int x2, y2;
|
||||
uint8 *buffer; /* used for window background */
|
||||
};
|
||||
|
||||
#define EGO_VIEW_TABLE 0
|
||||
#define HORIZON 36
|
||||
#define _WIDTH 160
|
||||
#define _HEIGHT 168
|
||||
|
||||
/**
|
||||
* AGI game structure.
|
||||
* This structure contains all global data of an AGI game executed
|
||||
* by the interpreter.
|
||||
*/
|
||||
struct agi_game {
|
||||
#define STATE_INIT 0x00
|
||||
#define STATE_LOADED 0x01
|
||||
#define STATE_RUNNING 0x02
|
||||
int state; /**< state of the interpreter */
|
||||
|
||||
char name[8]; /**< lead in id (e.g. `GR' for goldrush) */
|
||||
char id[8]; /**< game id */
|
||||
uint32 crc; /**< game CRC */
|
||||
|
||||
/* game flags and variables */
|
||||
uint8 flags[MAX_FLAGS];
|
||||
/**< 256 1-bit flags */
|
||||
uint8 vars[MAX_VARS];
|
||||
/**< 256 variables */
|
||||
|
||||
/* internal variables */
|
||||
int horizon; /**< horizon y coordinate */
|
||||
int line_status; /**< line number to put status on */
|
||||
int line_user_input;
|
||||
/**< line to put user input on */
|
||||
int line_min_print;
|
||||
/**< num lines to print on */
|
||||
int cursor_pos; /**< column where the input cursor is */
|
||||
uint8 input_buffer[40];
|
||||
/**< buffer for user input */
|
||||
uint8 echo_buffer[40];
|
||||
/**< buffer for echo.line */
|
||||
int keypress;
|
||||
#define INPUT_NORMAL 0x01
|
||||
#define INPUT_GETSTRING 0x02
|
||||
#define INPUT_MENU 0x03
|
||||
#define INPUT_NONE 0x04
|
||||
int input_mode; /**< keyboard input mode */
|
||||
int input_enabled;
|
||||
/**< keyboard input enabled */
|
||||
int lognum; /**< current logic number */
|
||||
|
||||
/* internal flags */
|
||||
int player_control;
|
||||
/**< player is in control */
|
||||
int quit_prog_now;
|
||||
/**< quit now */
|
||||
int status_line; /**< status line on/off */
|
||||
int clock_enabled;
|
||||
/**< clock is on/off */
|
||||
int exit_all_logics;
|
||||
/**< break cycle after new.room */
|
||||
int picture_shown;
|
||||
/**< show.pic has been issued */
|
||||
int has_prompt; /**< input prompt has been printed */
|
||||
#define ID_AGDS 0x00000001
|
||||
#define ID_AMIGA 0x00000002
|
||||
int game_flags; /**< agi options flags */
|
||||
|
||||
uint8 pri_table[_HEIGHT];
|
||||
/**< priority table */
|
||||
|
||||
/* windows */
|
||||
uint32 msg_box_ticks;
|
||||
/**< timed message box tick counter */
|
||||
struct agi_block block;
|
||||
struct agi_block window;
|
||||
int has_window;
|
||||
|
||||
/* graphics & text */
|
||||
int gfx_mode;
|
||||
char cursor_char;
|
||||
unsigned int color_fg;
|
||||
unsigned int color_bg;
|
||||
uint8 *sbuf; /**< 160x168 AGI screen buffer */
|
||||
#ifdef USE_HIRES
|
||||
uint8 *hires; /**< 320x168 hi-res buffer */
|
||||
#endif
|
||||
|
||||
/* player command line */
|
||||
struct agi_word ego_words[MAX_WORDS];
|
||||
int num_ego_words;
|
||||
|
||||
unsigned int num_objects;
|
||||
|
||||
struct agi_event ev_keyp[MAX_DIRS];
|
||||
/**< keyboard keypress events */
|
||||
char strings[MAX_STRINGS + 1][MAX_STRINGLEN];
|
||||
/**< strings */
|
||||
|
||||
/* directory entries for resources */
|
||||
struct agi_dir dir_logic[MAX_DIRS];
|
||||
struct agi_dir dir_pic[MAX_DIRS];
|
||||
struct agi_dir dir_view[MAX_DIRS];
|
||||
struct agi_dir dir_sound[MAX_DIRS];
|
||||
|
||||
/* resources */
|
||||
struct agi_picture pictures[MAX_DIRS];
|
||||
/**< AGI picture resources */
|
||||
struct agi_logic logics[MAX_DIRS];
|
||||
/**< AGI logic resources */
|
||||
struct agi_view views[MAX_DIRS]; /**< AGI view resources */
|
||||
struct agi_sound sounds[MAX_DIRS];
|
||||
/**< AGI sound resources */
|
||||
|
||||
/* view table */
|
||||
struct vt_entry view_table[MAX_VIEWTABLE];
|
||||
|
||||
int32 ver; /**< detected game version */
|
||||
|
||||
int simple_save; /**< select simple savegames */
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
struct agi_loader {
|
||||
int version;
|
||||
int int_version;
|
||||
int (*init) (void);
|
||||
int (*deinit) (void);
|
||||
int (*detect_game) ();
|
||||
int (*load_resource) (int, int);
|
||||
int (*unload_resource) (int, int);
|
||||
int (*load_objects) (char *);
|
||||
int (*load_words) (char *);
|
||||
};
|
||||
|
||||
extern struct agi_game game;
|
||||
|
||||
int agi_init(void);
|
||||
int agi_deinit(void);
|
||||
int agi_version(void);
|
||||
int agi_get_release(void);
|
||||
void agi_set_release(int);
|
||||
int agi_detect_game();
|
||||
int agi_load_resource(int, int);
|
||||
int agi_unload_resource(int, int);
|
||||
void agi_unload_resources(void);
|
||||
|
||||
/* words */
|
||||
int show_words(void);
|
||||
int load_words(char *);
|
||||
void unload_words(void);
|
||||
int find_word(char *word, int *flen);
|
||||
void dictionary_words(char *);
|
||||
|
||||
/* objects */
|
||||
int show_objects(void);
|
||||
int load_objects(char *fname);
|
||||
int alloc_objects(int);
|
||||
void unload_objects(void);
|
||||
char *object_name(unsigned int);
|
||||
int object_get_location(unsigned int);
|
||||
void object_set_location(unsigned int, int);
|
||||
|
||||
void new_input_mode(int);
|
||||
void old_input_mode(void);
|
||||
|
||||
int run_logic(int);
|
||||
|
||||
void agi_timer_low();
|
||||
int agi_get_keypress_low();
|
||||
int agi_is_keypress_low();
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif /* __AGI_H */
|
309
engines/agi/agi_v2.cpp
Normal file
309
engines/agi/agi_v2.cpp
Normal file
@ -0,0 +1,309 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
#include "common/file.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
static int agi_v2_init(void);
|
||||
static int agi_v2_deinit(void);
|
||||
static int agi_v2_detect_game();
|
||||
static int agi_v2_load_resource(int, int);
|
||||
static int agi_v2_unload_resource(int, int);
|
||||
static int agi_v2_load_objects(char *);
|
||||
static int agi_v2_load_words(char *);
|
||||
|
||||
struct agi_loader agi_v2 = {
|
||||
2,
|
||||
0,
|
||||
agi_v2_init,
|
||||
agi_v2_deinit,
|
||||
agi_v2_detect_game,
|
||||
agi_v2_load_resource,
|
||||
agi_v2_unload_resource,
|
||||
agi_v2_load_objects,
|
||||
agi_v2_load_words
|
||||
};
|
||||
|
||||
static int agi_v2_detect_game() {
|
||||
if (!Common::File::exists(LOGDIR) ||
|
||||
!Common::File::exists(PICDIR) ||
|
||||
!Common::File::exists(SNDDIR) ||
|
||||
!Common::File::exists(VIEWDIR))
|
||||
return err_InvalidAGIFile;
|
||||
|
||||
agi_v2.int_version = 0x2917; /* setup for 2.917 */
|
||||
return v2id_game();
|
||||
}
|
||||
|
||||
static int agi_v2_load_dir(struct agi_dir *agid, char *fname) {
|
||||
Common::File fp;
|
||||
uint8 *mem;
|
||||
uint32 flen;
|
||||
unsigned int i;
|
||||
char *path;
|
||||
|
||||
path = fname;
|
||||
report("Loading directory: %s\n", path);
|
||||
|
||||
if ((!fp.open(path))) {
|
||||
return err_BadFileOpen;
|
||||
}
|
||||
|
||||
fp.seek(0, SEEK_END);
|
||||
flen = fp.pos();
|
||||
fp.seek(0, SEEK_SET);
|
||||
|
||||
if ((mem = (uint8 *) malloc(flen + 32)) == NULL) {
|
||||
fp.close();
|
||||
return err_NotEnoughMemory;
|
||||
}
|
||||
|
||||
fp.read(mem, flen);
|
||||
|
||||
/* set all directory resources to gone */
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
agid[i].volume = 0xff;
|
||||
agid[i].offset = _EMPTY;
|
||||
}
|
||||
|
||||
/* build directory entries */
|
||||
for (i = 0; i < flen; i += 3) {
|
||||
agid[i / 3].volume = *(mem + i) >> 4;
|
||||
agid[i / 3].offset = READ_BE_UINT24(mem + i) & (uint32) _EMPTY;
|
||||
debugC(3, kDebugLevelResources, "%d: volume %d, offset 0x%05x", i / 3, agid[i / 3].volume, agid[i / 3].offset);
|
||||
}
|
||||
|
||||
free(mem);
|
||||
fp.close();
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
static int agi_v2_init() {
|
||||
int ec = err_OK;
|
||||
|
||||
/* load directory files */
|
||||
ec = agi_v2_load_dir(game.dir_logic, LOGDIR);
|
||||
if (ec == err_OK)
|
||||
ec = agi_v2_load_dir(game.dir_pic, PICDIR);
|
||||
if (ec == err_OK)
|
||||
ec = agi_v2_load_dir(game.dir_view, VIEWDIR);
|
||||
if (ec == err_OK)
|
||||
ec = agi_v2_load_dir(game.dir_sound, SNDDIR);
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
static int agi_v2_deinit() {
|
||||
int ec = err_OK;
|
||||
|
||||
#if 0
|
||||
/* unload words */
|
||||
agi_v2_unload_words();
|
||||
|
||||
/* unload objects */
|
||||
agi_v2_unload_objects();
|
||||
#endif
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
static int agi_v2_unload_resource(int t, int n) {
|
||||
debugC(3, kDebugLevelResources, "unload resource");
|
||||
|
||||
switch (t) {
|
||||
case rLOGIC:
|
||||
unload_logic(n);
|
||||
break;
|
||||
case rPICTURE:
|
||||
unload_picture(n);
|
||||
break;
|
||||
case rVIEW:
|
||||
unload_view(n);
|
||||
break;
|
||||
case rSOUND:
|
||||
unload_sound(n);
|
||||
break;
|
||||
}
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does noting but load a raw resource into memory,
|
||||
* if further decoding is required, it must be done by another
|
||||
* routine. NULL is returned if unsucsessfull.
|
||||
*/
|
||||
static uint8 *agi_v2_load_vol_res(struct agi_dir *agid) {
|
||||
uint8 *data = NULL;
|
||||
char x[MAX_PATH], *path;
|
||||
Common::File fp;
|
||||
unsigned int sig;
|
||||
|
||||
sprintf(x, "vol.%i", agid->volume);
|
||||
path = x;
|
||||
debugC(3, kDebugLevelResources, "Vol res: path = %s", path);
|
||||
|
||||
if (agid->offset != _EMPTY && fp.open(path)) {
|
||||
debugC(3, kDebugLevelResources, "loading resource at offset %d", agid->offset);
|
||||
fp.seek(agid->offset, SEEK_SET);
|
||||
fp.read(&x, 5);
|
||||
if ((sig = READ_BE_UINT16((uint8 *) x)) == 0x1234) {
|
||||
agid->len = READ_LE_UINT16((uint8 *) x + 3);
|
||||
data = (uint8 *) calloc(1, agid->len + 32);
|
||||
if (data != NULL) {
|
||||
fp.read(data, agid->len);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
/* FIXME: call some panic handler instead of
|
||||
* deiniting directly
|
||||
*/
|
||||
deinit_video_mode();
|
||||
#endif
|
||||
report("Error: bad signature %04x\n", sig);
|
||||
// fprintf (stderr, "ACK! BAD RESOURCE!!!\n");
|
||||
return 0;
|
||||
}
|
||||
fp.close();
|
||||
} else {
|
||||
/* we have a bad volume resource */
|
||||
/* set that resource to NA */
|
||||
agid->offset = _EMPTY;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads a resource into memory, a raw resource is loaded in
|
||||
* with above routine, then further decoded here.
|
||||
*/
|
||||
int agi_v2_load_resource(int t, int n) {
|
||||
int ec = err_OK;
|
||||
uint8 *data = NULL;
|
||||
|
||||
debugC(3, kDebugLevelResources, "(t = %d, n = %d)", t, n);
|
||||
if (n > MAX_DIRS)
|
||||
return err_BadResource;
|
||||
|
||||
switch (t) {
|
||||
case rLOGIC:
|
||||
if (~game.dir_logic[n].flags & RES_LOADED) {
|
||||
debugC(3, kDebugLevelResources, "loading logic resource %d", n);
|
||||
agi_v2.unload_resource(rLOGIC, n);
|
||||
|
||||
/* load raw resource into data */
|
||||
data = agi_v2_load_vol_res(&game.dir_logic[n]);
|
||||
|
||||
game.logics[n].data = data;
|
||||
ec = data ? decode_logic(n) : err_BadResource;
|
||||
|
||||
game.logics[n].sIP = 2;
|
||||
}
|
||||
|
||||
/* if logic was cached, we get here */
|
||||
/* reset code pointers incase it was cached */
|
||||
|
||||
game.logics[n].cIP = game.logics[n].sIP;
|
||||
break;
|
||||
case rPICTURE:
|
||||
/* if picture is currently NOT loaded *OR* cacheing is off,
|
||||
* unload the resource (caching == off) and reload it
|
||||
*/
|
||||
|
||||
debugC(3, kDebugLevelResources, "loading picture resource %d", n);
|
||||
if (game.dir_pic[n].flags & RES_LOADED)
|
||||
break;
|
||||
|
||||
/* if loaded but not cached, unload it */
|
||||
/* if cached but not loaded, etc */
|
||||
agi_v2.unload_resource(rPICTURE, n);
|
||||
data = agi_v2_load_vol_res(&game.dir_pic[n]);
|
||||
|
||||
if (data != NULL) {
|
||||
game.pictures[n].rdata = data;
|
||||
game.dir_pic[n].flags |= RES_LOADED;
|
||||
} else {
|
||||
ec = err_BadResource;
|
||||
}
|
||||
break;
|
||||
case rSOUND:
|
||||
debugC(3, kDebugLevelResources, "loading sound resource %d", n);
|
||||
if (game.dir_sound[n].flags & RES_LOADED)
|
||||
break;
|
||||
|
||||
data = agi_v2_load_vol_res(&game.dir_sound[n]);
|
||||
|
||||
if (data != NULL) {
|
||||
game.sounds[n].rdata = data;
|
||||
game.dir_sound[n].flags |= RES_LOADED;
|
||||
decode_sound(n);
|
||||
} else {
|
||||
ec = err_BadResource;
|
||||
}
|
||||
break;
|
||||
case rVIEW:
|
||||
/* Load a VIEW resource into memory...
|
||||
* Since VIEWS alter the view table ALL the time
|
||||
* can we cache the view? or must we reload it all
|
||||
* the time?
|
||||
*/
|
||||
if (game.dir_view[n].flags & RES_LOADED)
|
||||
break;
|
||||
|
||||
debugC(3, kDebugLevelResources, "loading view resource %d", n);
|
||||
agi_v2.unload_resource(rVIEW, n);
|
||||
data = agi_v2_load_vol_res(&game.dir_view[n]);
|
||||
if (data) {
|
||||
game.views[n].rdata = data;
|
||||
game.dir_view[n].flags |= RES_LOADED;
|
||||
ec = decode_view(n);
|
||||
} else {
|
||||
ec = err_BadResource;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ec = err_BadResource;
|
||||
break;
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
static int agi_v2_load_objects(char *fname) {
|
||||
return load_objects(fname);
|
||||
}
|
||||
|
||||
static int agi_v2_load_words(char *fname) {
|
||||
return load_words(fname);
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
389
engines/agi/agi_v3.cpp
Normal file
389
engines/agi/agi_v3.cpp
Normal file
@ -0,0 +1,389 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/lzw.h"
|
||||
|
||||
#include "backends/fs/fs.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
static int agi_v3_init(void);
|
||||
static int agi_v3_deinit(void);
|
||||
static int agi_v3_detect_game();
|
||||
static int agi_v3_load_resource(int, int);
|
||||
static int agi_v3_unload_resource(int, int);
|
||||
static int agi_v3_load_objects(char *);
|
||||
static int agi_v3_load_words(char *);
|
||||
|
||||
struct agi_loader agi_v3 = {
|
||||
3,
|
||||
0,
|
||||
agi_v3_init,
|
||||
agi_v3_deinit,
|
||||
agi_v3_detect_game,
|
||||
agi_v3_load_resource,
|
||||
agi_v3_unload_resource,
|
||||
agi_v3_load_objects,
|
||||
agi_v3_load_words
|
||||
};
|
||||
|
||||
int agi_v3_detect_game() {
|
||||
int ec = err_Unk;
|
||||
bool found = false;
|
||||
|
||||
FSList fslist;
|
||||
FilesystemNode dir(ConfMan.get("path"));
|
||||
|
||||
if (!dir.listDir(fslist, FilesystemNode::kListFilesOnly)) {
|
||||
warning("AgiEngine: invalid game path '%s'",
|
||||
dir.path().c_str());
|
||||
return err_InvalidAGIFile;
|
||||
}
|
||||
|
||||
for (FSList::const_iterator file = fslist.begin();
|
||||
file != fslist.end() && !found; ++file) {
|
||||
Common::String f = file->displayName();
|
||||
f.toLowercase();
|
||||
|
||||
if (f.hasSuffix("vol.0")) {
|
||||
strncpy(game.name, f.c_str(), f.size() > 5 ? f.size() - 5 : f.size());
|
||||
debugC(3, kDebugLevelMain, "game.name = %s", game.name);
|
||||
agi_v3.int_version = 0x3149; // setup for 3.002.149
|
||||
ec = v3id_game();
|
||||
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
debugC(3, kDebugLevelMain, "not found");
|
||||
ec = err_InvalidAGIFile;
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
static int agi_v3_load_dir(struct agi_dir *agid, Common::File *fp,
|
||||
uint32 offs, uint32 len) {
|
||||
int ec = err_OK;
|
||||
uint8 *mem;
|
||||
unsigned int i;
|
||||
|
||||
fp->seek(offs, SEEK_SET);
|
||||
if ((mem = (uint8 *) malloc(len + 32)) != NULL) {
|
||||
fp->read(mem, len);
|
||||
|
||||
/* set all directory resources to gone */
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
agid[i].volume = 0xff;
|
||||
agid[i].offset = _EMPTY;
|
||||
}
|
||||
|
||||
/* build directory entries */
|
||||
for (i = 0; i < len; i += 3) {
|
||||
agid[i / 3].volume = *(mem + i) >> 4;
|
||||
agid[i / 3].offset = READ_BE_UINT24(mem + i) & (uint32) _EMPTY;
|
||||
}
|
||||
|
||||
free(mem);
|
||||
} else {
|
||||
ec = err_NotEnoughMemory;
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
struct agi3vol {
|
||||
uint32 sddr;
|
||||
uint32 len;
|
||||
};
|
||||
|
||||
int agi_v3_init(void) {
|
||||
int ec = err_OK;
|
||||
struct agi3vol agi_vol3[4];
|
||||
int i;
|
||||
uint16 xd[4];
|
||||
Common::File fp;
|
||||
Common::String path;
|
||||
|
||||
path = Common::String(game.name) + DIR_;
|
||||
|
||||
if (!fp.open(path)) {
|
||||
printf("Failed to open \"%s\"\n", path.c_str());
|
||||
return err_BadFileOpen;
|
||||
}
|
||||
/* build offset table for v3 directory format */
|
||||
fp.read(&xd, 8);
|
||||
fp.seek(0, SEEK_END);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
agi_vol3[i].sddr = READ_LE_UINT16((uint8 *) & xd[i]);
|
||||
|
||||
agi_vol3[0].len = agi_vol3[1].sddr - agi_vol3[0].sddr;
|
||||
agi_vol3[1].len = agi_vol3[2].sddr - agi_vol3[1].sddr;
|
||||
agi_vol3[2].len = agi_vol3[3].sddr - agi_vol3[2].sddr;
|
||||
agi_vol3[3].len = fp.pos() - agi_vol3[3].sddr;
|
||||
|
||||
if (agi_vol3[3].len > 256 * 3)
|
||||
agi_vol3[3].len = 256 * 3;
|
||||
|
||||
fp.seek(0, SEEK_SET);
|
||||
|
||||
/* read in directory files */
|
||||
ec = agi_v3_load_dir(game.dir_logic, &fp, agi_vol3[0].sddr,
|
||||
agi_vol3[0].len);
|
||||
|
||||
if (ec == err_OK) {
|
||||
ec = agi_v3_load_dir(game.dir_pic, &fp, agi_vol3[1].sddr, agi_vol3[1].len);
|
||||
}
|
||||
|
||||
if (ec == err_OK) {
|
||||
ec = agi_v3_load_dir(game.dir_view, &fp, agi_vol3[2].sddr, agi_vol3[2].len);
|
||||
}
|
||||
|
||||
if (ec == err_OK) {
|
||||
ec = agi_v3_load_dir(game.dir_sound, &fp, agi_vol3[3].sddr, agi_vol3[3].len);
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
int agi_v3_deinit() {
|
||||
int ec = err_OK;
|
||||
|
||||
#if 0
|
||||
/* unload words */
|
||||
agi_v3_unload_words();
|
||||
|
||||
/* unload objects */
|
||||
agi_v3_unload_objects();
|
||||
#endif
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
int agi_v3_unload_resource(int t, int n) {
|
||||
switch (t) {
|
||||
case rLOGIC:
|
||||
unload_logic(n);
|
||||
break;
|
||||
case rPICTURE:
|
||||
unload_picture(n);
|
||||
break;
|
||||
case rVIEW:
|
||||
unload_view(n);
|
||||
break;
|
||||
case rSOUND:
|
||||
unload_sound(n);
|
||||
break;
|
||||
}
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does noting but load a raw resource into memory.
|
||||
* If further decoding is required, it must be done by another
|
||||
* routine.
|
||||
*
|
||||
* NULL is returned if unsucsessful.
|
||||
*/
|
||||
uint8 *agi_v3_load_vol_res(struct agi_dir *agid) {
|
||||
char x[MAX_PATH];
|
||||
uint8 *data = NULL, *comp_buffer;
|
||||
Common::File fp;
|
||||
Common::String path;
|
||||
|
||||
debugC(3, kDebugLevelResources, "(%p)", agid);
|
||||
sprintf(x, "vol.%i", agid->volume);
|
||||
path = Common::String(game.name) + x;
|
||||
|
||||
if (agid->offset != _EMPTY && fp.open(path)) {
|
||||
fp.seek(agid->offset, SEEK_SET);
|
||||
fp.read(&x, 7);
|
||||
|
||||
if (READ_BE_UINT16((uint8 *) x) != 0x1234) {
|
||||
#if 0
|
||||
/* FIXME */
|
||||
deinit_video_mode();
|
||||
#endif
|
||||
debugC(3, kDebugLevelResources, "path = %s", path.c_str());
|
||||
debugC(3, kDebugLevelResources, "offset = %d", agid->offset);
|
||||
debugC(3, kDebugLevelResources, "x = %x %x", x[0], x[1]);
|
||||
error("ACK! BAD RESOURCE");
|
||||
|
||||
g_system->quit();
|
||||
}
|
||||
|
||||
agid->len = READ_LE_UINT16((uint8 *) x + 3); /* uncompressed size */
|
||||
agid->clen = READ_LE_UINT16((uint8 *) x + 5); /* compressed len */
|
||||
|
||||
comp_buffer = (uint8 *)calloc(1, agid->clen + 32);
|
||||
fp.read(comp_buffer, agid->clen);
|
||||
|
||||
if (x[2] & 0x80 || agid->len == agid->clen) {
|
||||
/* do not decompress */
|
||||
data = comp_buffer;
|
||||
|
||||
#if 0
|
||||
/* CM: added to avoid problems in
|
||||
* convert_v2_v3_pic() when clen > len
|
||||
* e.g. Sierra demo 4, first picture
|
||||
* (Tue Mar 16 13:13:43 EST 1999)
|
||||
*/
|
||||
agid->len = agid->clen;
|
||||
|
||||
/* Now removed to fix Gold Rush! in demo4 */
|
||||
#endif
|
||||
} else {
|
||||
/* it is compressed */
|
||||
data = (uint8 *)calloc(1, agid->len + 32);
|
||||
LZW_expand(comp_buffer, data, agid->len);
|
||||
free(comp_buffer);
|
||||
agid->flags |= RES_COMPRESSED;
|
||||
}
|
||||
|
||||
fp.close();
|
||||
} else {
|
||||
/* we have a bad volume resource */
|
||||
/* set that resource to NA */
|
||||
agid->offset = _EMPTY;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads a resource into memory, a raw resource is loaded in
|
||||
* with above routine, then further decoded here.
|
||||
*/
|
||||
int agi_v3_load_resource(int t, int n) {
|
||||
int ec = err_OK;
|
||||
uint8 *data = NULL;
|
||||
|
||||
if (n > MAX_DIRS)
|
||||
return err_BadResource;
|
||||
|
||||
switch (t) {
|
||||
case rLOGIC:
|
||||
/* load resource into memory, decrypt messages at the end
|
||||
* and build the message list (if logic is in memory)
|
||||
*/
|
||||
if (~game.dir_logic[n].flags & RES_LOADED) {
|
||||
/* if logic is already in memory, unload it */
|
||||
agi_v3.unload_resource(rLOGIC, n);
|
||||
|
||||
/* load raw resource into data */
|
||||
data = agi_v3_load_vol_res(&game.dir_logic[n]);
|
||||
game.logics[n].data = data;
|
||||
|
||||
/* uncompressed logic files need to be decrypted */
|
||||
if (data != NULL) {
|
||||
/* resloaded flag gets set by decode logic */
|
||||
/* needed to build string table */
|
||||
ec = decode_logic(n);
|
||||
game.logics[n].sIP = 2;
|
||||
} else {
|
||||
ec = err_BadResource;
|
||||
}
|
||||
|
||||
/*logics[n].sIP=2; *//* saved IP = 2 */
|
||||
/*logics[n].cIP=2; *//* current IP = 2 */
|
||||
|
||||
game.logics[n].cIP = game.logics[n].sIP;
|
||||
}
|
||||
|
||||
/* if logic was cached, we get here */
|
||||
/* reset code pointers incase it was cached */
|
||||
|
||||
game.logics[n].cIP = game.logics[n].sIP;
|
||||
break;
|
||||
case rPICTURE:
|
||||
/* if picture is currently NOT loaded *OR* cacheing is off,
|
||||
* unload the resource (caching==off) and reload it
|
||||
*/
|
||||
if (~game.dir_pic[n].flags & RES_LOADED) {
|
||||
agi_v3.unload_resource(rPICTURE, n);
|
||||
data = agi_v3_load_vol_res(&game.dir_pic[n]);
|
||||
if (data != NULL) {
|
||||
data = convert_v3_pic(data, game.dir_pic[n].len);
|
||||
game.pictures[n].rdata = data;
|
||||
game.dir_pic[n].flags |= RES_LOADED;
|
||||
} else {
|
||||
ec = err_BadResource;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case rSOUND:
|
||||
if (game.dir_sound[n].flags & RES_LOADED)
|
||||
break;
|
||||
|
||||
if ((data = agi_v3_load_vol_res(&game.dir_sound[n])) != NULL) {
|
||||
game.sounds[n].rdata = data;
|
||||
game.dir_sound[n].flags |= RES_LOADED;
|
||||
decode_sound(n);
|
||||
} else {
|
||||
ec = err_BadResource;
|
||||
}
|
||||
break;
|
||||
case rVIEW:
|
||||
/* Load a VIEW resource into memory...
|
||||
* Since VIEWS alter the view table ALL the time can we
|
||||
* cache the view? or must we reload it all the time?
|
||||
*/
|
||||
/* load a raw view from a VOL file into data */
|
||||
if (game.dir_view[n].flags & RES_LOADED)
|
||||
break;
|
||||
|
||||
agi_v3.unload_resource(rVIEW, n);
|
||||
if ((data = agi_v3_load_vol_res(&game.dir_view[n])) != NULL) {
|
||||
game.views[n].rdata = data;
|
||||
game.dir_view[n].flags |= RES_LOADED;
|
||||
ec = decode_view(n);
|
||||
} else {
|
||||
ec = err_BadResource;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ec = err_BadResource;
|
||||
break;
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
static int agi_v3_load_objects(char *fname) {
|
||||
return load_objects(fname);
|
||||
}
|
||||
|
||||
static int agi_v3_load_words(char *fname) {
|
||||
return load_words(fname);
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
320
engines/agi/checks.cpp
Normal file
320
engines/agi/checks.cpp
Normal file
@ -0,0 +1,320 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
static int check_position(struct vt_entry *v) {
|
||||
debugC(4, kDebugLevelSprites, "check position @ %d, %d", v->x_pos, v->y_pos);
|
||||
|
||||
if (v->x_pos < 0 ||
|
||||
v->x_pos + v->x_size > _WIDTH ||
|
||||
v->y_pos - v->y_size + 1 < 0 ||
|
||||
v->y_pos >= _HEIGHT ||
|
||||
((~v->flags & IGNORE_HORIZON) && v->y_pos <= game.horizon)) {
|
||||
debugC(4, kDebugLevelSprites, "check position failed: x=%d, y=%d, h=%d, w=%d",
|
||||
v->x_pos, v->y_pos, v->x_size, v->y_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MH1 needs this, but it breaks LSL1 */
|
||||
if (agi_get_release() >= 0x3000) {
|
||||
if (v->y_pos < v->y_size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there's another object on the way
|
||||
*/
|
||||
static int check_collision(struct vt_entry *v) {
|
||||
struct vt_entry *u;
|
||||
|
||||
if (v->flags & IGNORE_OBJECTS)
|
||||
return 0;
|
||||
|
||||
for (u = game.view_table; u < &game.view_table[MAX_VIEWTABLE]; u++) {
|
||||
if ((u->flags & (ANIMATED | DRAWN)) != (ANIMATED | DRAWN))
|
||||
continue;
|
||||
|
||||
if (u->flags & IGNORE_OBJECTS)
|
||||
continue;
|
||||
|
||||
/* Same object, check next */
|
||||
if (v->entry == u->entry)
|
||||
continue;
|
||||
|
||||
/* No horizontal overlap, check next */
|
||||
if (v->x_pos + v->x_size < u->x_pos ||
|
||||
v->x_pos > u->x_pos + u->x_size)
|
||||
continue;
|
||||
|
||||
/* Same y, return error! */
|
||||
if (v->y_pos == u->y_pos)
|
||||
goto return_1;
|
||||
|
||||
/* Crossed the baseline, return error! */
|
||||
if ((v->y_pos > u->y_pos && v->y_pos2 < u->y_pos2) ||
|
||||
(v->y_pos < u->y_pos && v->y_pos2 > u->y_pos2)) {
|
||||
goto return_1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return_1:
|
||||
debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", v->entry);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_priority(struct vt_entry *v) {
|
||||
int i, trigger, water, pass, pri;
|
||||
uint8 *p0;
|
||||
|
||||
if (~v->flags & FIXED_PRIORITY) {
|
||||
/* Priority bands */
|
||||
v->priority = game.pri_table[v->y_pos];
|
||||
}
|
||||
|
||||
trigger = 0;
|
||||
water = 0;
|
||||
pass = 1;
|
||||
|
||||
if (v->priority == 0x0f)
|
||||
goto _check_ego;
|
||||
|
||||
water = 1;
|
||||
|
||||
p0 = &game.sbuf[v->x_pos + v->y_pos * _WIDTH];
|
||||
|
||||
for (i = 0; i < v->x_size; i++, p0++) {
|
||||
pri = *p0 >> 4;
|
||||
|
||||
if (pri == 0) { /* unconditional black. no go at all! */
|
||||
pass = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pri == 3) /* water surface */
|
||||
continue;
|
||||
|
||||
water = 0;
|
||||
|
||||
if (pri == 1) { /* conditional blue */
|
||||
if (v->flags & IGNORE_BLOCKS)
|
||||
continue;
|
||||
|
||||
debugC(4, kDebugLevelSprites, "Blocks observed!");
|
||||
pass = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pri == 2) { /* trigger */
|
||||
debugC(4, kDebugLevelSprites, "stepped on trigger");
|
||||
#ifdef USE_CONSOLE
|
||||
if (!debug_.ignoretriggers)
|
||||
#endif
|
||||
trigger = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (pass) {
|
||||
if (!water && v->flags & ON_WATER)
|
||||
pass = 0;
|
||||
if (water && v->flags & ON_LAND)
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
_check_ego:
|
||||
if (v->entry == 0) {
|
||||
setflag(F_ego_touched_p2, trigger ? true : false);
|
||||
setflag(F_ego_water, water ? true : false);
|
||||
}
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Update position of objects
|
||||
* This function updates the position of all animated, updating view
|
||||
* table entries according to its motion type, step size, etc. The
|
||||
* new position must be valid according to the sprite positioning
|
||||
* rules, otherwise the previous position will be kept.
|
||||
*/
|
||||
void update_position() {
|
||||
struct vt_entry *v;
|
||||
int x, y, old_x, old_y, border;
|
||||
|
||||
game.vars[V_border_code] = 0;
|
||||
game.vars[V_border_touch_ego] = 0;
|
||||
game.vars[V_border_touch_obj] = 0;
|
||||
|
||||
for (v = game.view_table; v < &game.view_table[MAX_VIEWTABLE]; v++) {
|
||||
if ((v->flags & (ANIMATED | UPDATE | DRAWN)) != (ANIMATED | UPDATE | DRAWN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (v->step_time_count != 0) {
|
||||
if (--v->step_time_count != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
v->step_time_count = v->step_time;
|
||||
|
||||
x = old_x = v->x_pos;
|
||||
y = old_y = v->y_pos;
|
||||
|
||||
/* If object has moved, update its position */
|
||||
if (~v->flags & UPDATE_POS) {
|
||||
int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
|
||||
int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
|
||||
x += v->step_size * dx[v->direction];
|
||||
y += v->step_size * dy[v->direction];
|
||||
}
|
||||
|
||||
/* Now check if it touched the borders */
|
||||
border = 0;
|
||||
|
||||
/* Check left/right borders */
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
border = 4;
|
||||
} else if (x <= 0 && agi_get_release() == 0x3086) { /* KQ4 */
|
||||
x = 0; /* See bug #590462 */
|
||||
border = 4;
|
||||
} else if (v->entry == 0 && x == 0 && v->flags & ADJ_EGO_XY) {
|
||||
/* Extra test to walk west clicking the mouse */
|
||||
x = 0;
|
||||
border = 4;
|
||||
} else if (x + v->x_size > _WIDTH) {
|
||||
x = _WIDTH - v->x_size;
|
||||
border = 2;
|
||||
}
|
||||
|
||||
/* Check top/bottom borders. */
|
||||
if (y - v->y_size + 1 < 0) {
|
||||
y = v->y_size - 1;
|
||||
border = 1;
|
||||
} else if (y > _HEIGHT - 1) {
|
||||
y = _HEIGHT - 1;
|
||||
border = 3;
|
||||
} else if ((~v->flags & IGNORE_HORIZON) && y <= game.horizon) {
|
||||
debugC(4, kDebugLevelSprites, "y = %d, horizon = %d", y, game.horizon);
|
||||
y = game.horizon + 1;
|
||||
border = 1;
|
||||
}
|
||||
|
||||
/* Test new position. rollback if test fails */
|
||||
v->x_pos = x;
|
||||
v->y_pos = y;
|
||||
if (check_collision(v) || !check_priority(v)) {
|
||||
v->x_pos = old_x;
|
||||
v->y_pos = old_y;
|
||||
border = 0;
|
||||
fix_position(v->entry);
|
||||
}
|
||||
|
||||
if (border != 0) {
|
||||
if (v == game.view_table) {
|
||||
game.vars[V_border_touch_ego] = border;
|
||||
} else {
|
||||
game.vars[V_border_code] = v->entry;
|
||||
game.vars[V_border_touch_obj] = border;
|
||||
}
|
||||
if (v->motion == MOTION_MOVE_OBJ) {
|
||||
in_destination(v);
|
||||
}
|
||||
}
|
||||
|
||||
v->flags &= ~UPDATE_POS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust position of a sprite
|
||||
* This function adjusts the position of a sprite moving it until
|
||||
* certain criteria is matched. According to priority and control line
|
||||
* data, a sprite may not always appear at the location we specified.
|
||||
* This behaviour is also known as the "Budin-Sonneveld effect".
|
||||
*
|
||||
* @param n view table entry number
|
||||
*/
|
||||
void fix_position(int n) {
|
||||
struct vt_entry *v = &game.view_table[n];
|
||||
int count, dir, size;
|
||||
|
||||
debugC(4, kDebugLevelSprites, "adjusting view table entry #%d (%d,%d)", n, v->x_pos, v->y_pos);
|
||||
|
||||
/* test horizon */
|
||||
if ((~v->flags & IGNORE_HORIZON) && v->y_pos <= game.horizon)
|
||||
v->y_pos = game.horizon + 1;
|
||||
|
||||
dir = 0;
|
||||
count = size = 1;
|
||||
|
||||
while (!check_position(v) || check_collision(v) || !check_priority(v)) {
|
||||
switch (dir) {
|
||||
case 0: /* west */
|
||||
v->x_pos--;
|
||||
if (--count)
|
||||
continue;
|
||||
dir = 1;
|
||||
break;
|
||||
case 1: /* south */
|
||||
v->y_pos++;
|
||||
if (--count)
|
||||
continue;
|
||||
dir = 2;
|
||||
size++;
|
||||
break;
|
||||
case 2: /* east */
|
||||
v->x_pos++;
|
||||
if (--count)
|
||||
continue;
|
||||
dir = 3;
|
||||
break;
|
||||
case 3: /* north */
|
||||
v->y_pos--;
|
||||
if (--count)
|
||||
continue;
|
||||
dir = 0;
|
||||
size++;
|
||||
break;
|
||||
}
|
||||
|
||||
count = size;
|
||||
}
|
||||
|
||||
debugC(4, kDebugLevelSprites, "view table entry #%d position adjusted to (%d,%d)", n, v->x_pos, v->y_pos);
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
873
engines/agi/console.cpp
Normal file
873
engines/agi/console.cpp
Normal file
@ -0,0 +1,873 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2002 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/graphics.h"
|
||||
#include "agi/sprite.h"
|
||||
#include "agi/text.h"
|
||||
#include "agi/keyboard.h"
|
||||
#include "agi/opcodes.h"
|
||||
#include "agi/console.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
|
||||
/*
|
||||
* The main interpreter engine has not been designed to have a console, and a few
|
||||
* kludges were needed to make the console work. First of all, the main
|
||||
* interpreter loop works at cycle level, not instruction level. To keep
|
||||
* the illusion that the console is threaded, a console updating function
|
||||
* is called from loops inside instructions such as get.string().
|
||||
*/
|
||||
|
||||
#define CONSOLE_LINES_ONSCREEN 20
|
||||
#define CONSOLE_PROMPT "$"
|
||||
#define CONSOLE_CURSOR_HOLLOW 1
|
||||
#define CONSOLE_CURSOR_SOLID 2
|
||||
#define CONSOLE_CURSOR_EMPTY 3
|
||||
#define CONSOLE_COLOR 14
|
||||
#define CONSOLE_SCROLLUP_KEY KEY_PGUP
|
||||
#define CONSOLE_SCROLLDN_KEY KEY_PGDN
|
||||
#define CONSOLE_START_KEY KEY_HOME
|
||||
#define CONSOLE_END_KEY KEY_END
|
||||
#define CONSOLE_INPUT_SIZE 39
|
||||
|
||||
struct console_command {
|
||||
char cmd[8];
|
||||
char dsc[40];
|
||||
void (*handler) (void);
|
||||
};
|
||||
|
||||
struct agi_console console;
|
||||
struct agi_debug debug_;
|
||||
|
||||
/* This used to be a linked list, but we reduce total memory footprint
|
||||
* by implementing it as a statically allocated array.
|
||||
*/
|
||||
#define MAX_CCMD 16
|
||||
static struct console_command ccmd_list[MAX_CCMD];
|
||||
static int num_ccmd = 0;
|
||||
|
||||
static uint8 has_console = 0;
|
||||
static uint8 console_input = 0;
|
||||
|
||||
static char *_p0, *_p1, *_p2, *_p3, *_p4, *_p5; /* FIXME: array */
|
||||
static char _p[80];
|
||||
static int _pn;
|
||||
|
||||
/*
|
||||
* Console line management
|
||||
*/
|
||||
|
||||
static int first_line = 0;
|
||||
|
||||
static void add_console_line(char *s) {
|
||||
int last_line;
|
||||
|
||||
last_line = (CONSOLE_LINES_BUFFER - 1 + first_line) % CONSOLE_LINES_BUFFER;
|
||||
|
||||
strncpy(console.line[last_line], s, CONSOLE_LINE_SIZE);
|
||||
first_line %= CONSOLE_LINES_BUFFER;
|
||||
}
|
||||
|
||||
static char *get_console_line(int n) {
|
||||
return console.line[(n + first_line) % CONSOLE_LINES_BUFFER];
|
||||
}
|
||||
|
||||
static char *get_last_console_line() {
|
||||
int last_line = (CONSOLE_LINES_BUFFER - 1 + first_line) % CONSOLE_LINES_BUFFER;
|
||||
|
||||
return console.line[last_line];
|
||||
}
|
||||
|
||||
/*
|
||||
* Console command parsing
|
||||
* 'o' commands added by Shaun Jackman <sjackman@shaw.ca>, 11 Apr 2002
|
||||
*/
|
||||
|
||||
static int console_parse(char *b) {
|
||||
struct console_command *d;
|
||||
int i;
|
||||
|
||||
for (; *b && *b == ' '; b++) {
|
||||
} /* eat spaces */
|
||||
for (; *b && b[strlen(b) - 1] == ' '; b[strlen(b) - 1] = 0) {
|
||||
}
|
||||
if (!*b)
|
||||
return 0;
|
||||
|
||||
/* get or set flag/var/obj values */
|
||||
if ((b[0] == 'f' || b[0] == 'v' || b[0] == 'o') && isdigit(b[1])) {
|
||||
char *e;
|
||||
int f = (int)strtoul(&b[1], &e, 10);
|
||||
if (*e == 0) {
|
||||
if (f >= 0 && f <= 255) {
|
||||
switch (b[0]) {
|
||||
case 'f':
|
||||
report(getflag(f) ? "true\n" : "false\n");
|
||||
break;
|
||||
case 'v':
|
||||
report("%3d\n", getvar(f));
|
||||
break;
|
||||
case 'o':
|
||||
report("%3d]%-24s(%3d)\n", f, object_name(f), object_get_location(f));
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
} else if (*e == '=') {
|
||||
int n = (int)strtoul(e + 1, NULL, 0);
|
||||
switch (b[0]) {
|
||||
case 'f':
|
||||
setflag(f, !!n);
|
||||
break;
|
||||
case 'v':
|
||||
setvar(f, n);
|
||||
break;
|
||||
case 'o':
|
||||
object_set_location(f, n);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* tokenize the input line */
|
||||
if (strchr(b, ' '))
|
||||
strcpy(_p, strchr(b, ' ') + 1);
|
||||
_p0 = strtok(b, " ");
|
||||
_p1 = strtok(NULL, " ");
|
||||
_p2 = strtok(NULL, " ");
|
||||
_p3 = strtok(NULL, " ");
|
||||
_p4 = strtok(NULL, " ");
|
||||
_p5 = strtok(NULL, " ");
|
||||
|
||||
/* set number of parameters. ugh, must rewrite this later */
|
||||
_pn = 5;
|
||||
if (!_p5)
|
||||
_pn = 4;
|
||||
if (!_p4)
|
||||
_pn = 3;
|
||||
if (!_p3)
|
||||
_pn = 2;
|
||||
if (!_p2)
|
||||
_pn = 1;
|
||||
if (!_p1)
|
||||
_pn = 0;
|
||||
|
||||
debugC(5, kDebugLevelMain, "number of parameters: %d", _pn);
|
||||
|
||||
for (i = 0; i < num_ccmd; i++) {
|
||||
d = &ccmd_list[i];
|
||||
if (!strcmp(_p0, d->cmd) && d->handler) {
|
||||
d->handler();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; logic_names_cmd[i].name; i++) {
|
||||
if (!strcmp(_p0, logic_names_cmd[i].name)) {
|
||||
uint8 p[16];
|
||||
if (_pn != logic_names_cmd[i].num_args) {
|
||||
report("AGI command wants %d arguments\n", logic_names_cmd[i].num_args);
|
||||
return 0;
|
||||
}
|
||||
p[0] = _p1 ? (char)strtoul(_p1, NULL, 0) : 0;
|
||||
p[1] = _p2 ? (char)strtoul(_p2, NULL, 0) : 0;
|
||||
p[2] = _p3 ? (char)strtoul(_p3, NULL, 0) : 0;
|
||||
p[3] = _p4 ? (char)strtoul(_p4, NULL, 0) : 0;
|
||||
p[4] = _p5 ? (char)strtoul(_p5, NULL, 0) : 0;
|
||||
|
||||
debugC(5, kDebugLevelMain, "ccmd: %s %d %d %d", logic_names_cmd[i].name, p[0], p[1], p[2]);
|
||||
|
||||
execute_agi_command(i, p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Console commands
|
||||
*/
|
||||
|
||||
static void ccmd_help() {
|
||||
int i;
|
||||
|
||||
if (!_p1) {
|
||||
report("Command Description\n");
|
||||
report("------- --------------------------------\n");
|
||||
for (i = 0; i < num_ccmd; i++)
|
||||
report("%-8s%s\n", ccmd_list[i].cmd, ccmd_list[i].dsc);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_ccmd; i++) {
|
||||
if (!strcmp(ccmd_list[i].cmd, _p1) && ccmd_list[i].handler) {
|
||||
report("%s\n", ccmd_list[i].dsc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
report("Unknown command or no help available\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_ver() {
|
||||
report(VERSION "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_crc() {
|
||||
char name[80];
|
||||
report("0x%05x\n", game.crc);
|
||||
if (match_crc(game.crc, name, 80))
|
||||
report("%s\n", name);
|
||||
else
|
||||
report("Unknown game\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_quit() {
|
||||
deinit_video();
|
||||
/* deinit_machine (); */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void ccmd_exec() {
|
||||
if (game.state < STATE_LOADED) {
|
||||
report("No game loaded.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (game.state >= STATE_RUNNING) {
|
||||
report("Game already running.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
report("Executing AGI game.\n");
|
||||
game.state = STATE_RUNNING;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_HIRES
|
||||
|
||||
static void ccmd_hires() {
|
||||
if (_pn != 1 || (strcmp(_p1, "on") && strcmp(_p1, "off"))) {
|
||||
report("Usage: hires on|off\n");
|
||||
return;
|
||||
}
|
||||
|
||||
opt.hires = !strcmp(_p1, "on");
|
||||
erase_both();
|
||||
show_pic();
|
||||
blit_both();
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void ccmd_agiver() {
|
||||
int ver, maj, min;
|
||||
|
||||
ver = agi_get_release();
|
||||
maj = (ver >> 12) & 0xf;
|
||||
min = ver & 0xfff;
|
||||
|
||||
report(maj <= 2 ? "%x.%03x\n" : "%x.002.%03x\n", maj, min);
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_flags() {
|
||||
int i, j;
|
||||
|
||||
report(" ");
|
||||
for (j = 0; j < 10; j++)
|
||||
report("%d ", j);
|
||||
report("\n");
|
||||
|
||||
for (i = 0; i < 255;) {
|
||||
report("%3d ", i);
|
||||
for (j = 0; j < 10; j++, i++) {
|
||||
report("%c ", getflag(i) ? 'T' : 'F');
|
||||
}
|
||||
report("\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_vars() {
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 255;) {
|
||||
for (j = 0; j < 5; j++, i++) {
|
||||
report("%03d:%3d ", i, getvar(i));
|
||||
}
|
||||
report("\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
static void ccmd_say() {
|
||||
setflag(F_entered_cli, true);
|
||||
dictionary_words(_p);
|
||||
}
|
||||
|
||||
static void ccmd_inv() {
|
||||
unsigned int i, j;
|
||||
|
||||
for (j = i = 0; i < game.num_objects; i++) {
|
||||
if (object_get_location(i) == EGO_OWNED) {
|
||||
report("%3d]%-16.16s", i, object_name(i));
|
||||
if (j % 2)
|
||||
report("\n");
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if (j == 0) {
|
||||
report("none\n");
|
||||
return;
|
||||
}
|
||||
if (j % 2)
|
||||
report("\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void ccmd_objs() {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < game.num_objects; i++) {
|
||||
report("%3d]%-24s(%3d)\n", i, object_name(i), object_get_location(i));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_opcode() {
|
||||
if (_pn != 1 || (strcmp(_p1, "on") && strcmp(_p1, "off"))) {
|
||||
report("Usage: opcode on|off\n");
|
||||
return;
|
||||
}
|
||||
|
||||
debug_.opcodes = !strcmp(_p1, "on");
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_logic0() {
|
||||
if (_pn != 1 || (strcmp(_p1, "on") && strcmp(_p1, "off"))) {
|
||||
report("Usage: logic0 on|off\n");
|
||||
return;
|
||||
}
|
||||
|
||||
debug_.logic0 = !strcmp(_p1, "on");
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_trigger() {
|
||||
if (_pn != 1 || (strcmp(_p1, "on") && strcmp(_p1, "off"))) {
|
||||
report("Usage: trigger on|off\n");
|
||||
return;
|
||||
}
|
||||
|
||||
debug_.ignoretriggers = strcmp(_p1, "on");
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_step() {
|
||||
debug_.enabled = 1;
|
||||
|
||||
if (_pn == 0) {
|
||||
debug_.steps = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
debug_.steps = strtoul(_p1, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_debug() {
|
||||
debug_.enabled = 1;
|
||||
debug_.steps = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static void ccmd_cont() {
|
||||
debug_.enabled = 0;
|
||||
debug_.steps = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register console commands
|
||||
*/
|
||||
static void console_cmd(char *cmd, char *dsc, void (*handler) (void)) {
|
||||
assert(num_ccmd < MAX_CCMD);
|
||||
|
||||
strcpy(ccmd_list[num_ccmd].cmd, cmd);
|
||||
strcpy(ccmd_list[num_ccmd].dsc, dsc);
|
||||
ccmd_list[num_ccmd].handler = handler;
|
||||
|
||||
num_ccmd++;
|
||||
}
|
||||
|
||||
/* Console reporting */
|
||||
|
||||
/* A slightly modified strtok() for report() */
|
||||
static char *get_token(char *s, char d) {
|
||||
static char *x;
|
||||
char *n, *m;
|
||||
|
||||
if (s)
|
||||
x = s;
|
||||
|
||||
m = x;
|
||||
n = strchr(x, d);
|
||||
|
||||
if (n) {
|
||||
*n = 0;
|
||||
x = n + 1;
|
||||
} else {
|
||||
x = strchr(x, 0);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
static void build_console_lines(int n) {
|
||||
int j, y1;
|
||||
char *line;
|
||||
|
||||
clear_console_screen(GFX_HEIGHT - n * 10);
|
||||
|
||||
for (j = CONSOLE_LINES_ONSCREEN - n; j < CONSOLE_LINES_ONSCREEN; j++) {
|
||||
line = get_console_line(console.first_line + j);
|
||||
print_text_console(line, 0, j, strlen(line) + 1, CONSOLE_COLOR, 0);
|
||||
}
|
||||
|
||||
y1 = console.y - n * 10;
|
||||
if (y1 < 0)
|
||||
y1 = 0;
|
||||
|
||||
/* CM:
|
||||
* This will cause blinking when using menus+console, but this
|
||||
* function is called by report() which can be called from any
|
||||
* point with or without sprites placed. If we protect the
|
||||
* flush_block() call with redraw/release sprites cloning will
|
||||
* happen when activating the console. This could be fixed by
|
||||
* keeping a control flag in redraw/release to not do the
|
||||
* actions twice, but I don't want to do that -- not yet.
|
||||
*/
|
||||
flush_block(0, y1, GFX_WIDTH - 1, console.y);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
int console_init() {
|
||||
console_cmd("agiver", "Show emulated Sierra AGI version", ccmd_agiver);
|
||||
console_cmd("cont", "Resume interpreter execution", ccmd_cont);
|
||||
console_cmd("debug", "Stop interpreter execution", ccmd_debug);
|
||||
console_cmd("crc", "Show AGI game CRC", ccmd_crc);
|
||||
#if 0
|
||||
console_cmd("exec", "Execute loaded AGI game", ccmd_exec);
|
||||
#endif
|
||||
console_cmd("flags", "Dump all AGI flags", ccmd_flags);
|
||||
console_cmd("help", "List available commands", ccmd_help);
|
||||
#ifdef USE_HIRES
|
||||
console_cmd("hires", "Turn hi-res mode on/off", ccmd_hires);
|
||||
#endif
|
||||
console_cmd("logic0", "Turn logic 0 debugging on/off", ccmd_logic0);
|
||||
console_cmd("objs", "List all objects and locations", ccmd_objs);
|
||||
console_cmd("opcode", "Turn opcodes on/off in debug", ccmd_opcode);
|
||||
console_cmd("quit", "Quit the interpreter", ccmd_quit);
|
||||
#if 0
|
||||
console_cmd("inv", "List current inventory", ccmd_inv);
|
||||
console_cmd("say", "Pass argument to the AGI parser", ccmd_say);
|
||||
#endif
|
||||
console_cmd("step", "Execute the next AGI instruction", ccmd_step);
|
||||
console_cmd("trigger", "Turn trigger lines on/off", ccmd_trigger);
|
||||
console_cmd("vars", "Dump all AGI variables", ccmd_vars);
|
||||
console_cmd("ver", "Show interpreter version", ccmd_ver);
|
||||
|
||||
console.active = 1;
|
||||
console.input_active = 1;
|
||||
console.index = 0;
|
||||
console.max_y = 150;
|
||||
console.y = console.max_y;
|
||||
console.first_line = CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN;
|
||||
|
||||
debug_.enabled = 0;
|
||||
debug_.opcodes = 0;
|
||||
debug_.logic0 = 1;
|
||||
debug_.priority = 0;
|
||||
|
||||
has_console = 1;
|
||||
clear_screen(0);
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
static void build_console_layer() {
|
||||
build_console_lines(console.max_y / 10);
|
||||
}
|
||||
|
||||
void report(char *message, ...) {
|
||||
char x[512], y[512], z[64], *msg, *n;
|
||||
va_list args;
|
||||
int i, s, len;
|
||||
|
||||
if (!has_console)
|
||||
return;
|
||||
|
||||
va_start(args, message);
|
||||
#ifdef HAVE_VSNPRINTF
|
||||
vsnprintf(y, 510, (char *)message, args);
|
||||
#else
|
||||
vsprintf(y, (char *)message, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
|
||||
if (console_input) {
|
||||
strcpy(z, get_last_console_line());
|
||||
strcpy(x, ">");
|
||||
} else {
|
||||
strcpy(x, get_last_console_line());
|
||||
}
|
||||
|
||||
strcat(x, y);
|
||||
|
||||
len = 40;
|
||||
msg = n = word_wrap_string(x, &len);
|
||||
|
||||
for (s = 1; *n; n++)
|
||||
if (*n == '\n')
|
||||
s++;
|
||||
|
||||
add_console_line(get_token(msg, '\n'));
|
||||
for (i = 1; i < s; i++) {
|
||||
first_line++;
|
||||
n = get_token(NULL, '\n');
|
||||
add_console_line(n);
|
||||
}
|
||||
|
||||
console.first_line = CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN;
|
||||
|
||||
if (console_input) {
|
||||
add_console_line(z);
|
||||
}
|
||||
|
||||
/* Build layer */
|
||||
if (console.y) {
|
||||
if (s > 1)
|
||||
build_console_layer();
|
||||
else
|
||||
build_console_lines(1);
|
||||
}
|
||||
|
||||
free(msg);
|
||||
|
||||
do_update();
|
||||
}
|
||||
|
||||
void console_cycle() {
|
||||
static int old_y = 0;
|
||||
static int blink = 0;
|
||||
static char cursor[] = " ";
|
||||
|
||||
/* If no game has been loaded, keep the console visible! */
|
||||
if (game.state < STATE_RUNNING) {
|
||||
console.active = 1;
|
||||
console.count = 10;
|
||||
}
|
||||
|
||||
/* Initial console auto-hide timer */
|
||||
if (console.count > 0)
|
||||
console.count--;
|
||||
if (console.count == 0) {
|
||||
console.active = 0;
|
||||
console.count = -1;
|
||||
}
|
||||
|
||||
if (console.active) {
|
||||
if (console.y < console.max_y)
|
||||
console.y += 15;
|
||||
else
|
||||
console.y = console.max_y;
|
||||
} else {
|
||||
console.count = -1;
|
||||
|
||||
if (console.y > 0)
|
||||
console.y -= 15;
|
||||
else
|
||||
console.y = 0;
|
||||
}
|
||||
|
||||
/* console shading animation */
|
||||
if (old_y != console.y) {
|
||||
int y = console.y;
|
||||
if (old_y > console.y) {
|
||||
/* going up */
|
||||
y = old_y;
|
||||
}
|
||||
flush_block(0, 0, GFX_WIDTH - 1, y);
|
||||
old_y = console.y;
|
||||
}
|
||||
|
||||
blink++;
|
||||
blink %= 16;
|
||||
if (console.input_active) {
|
||||
*cursor = blink < 8 ?
|
||||
CONSOLE_CURSOR_SOLID : CONSOLE_CURSOR_EMPTY;
|
||||
} else {
|
||||
*cursor = CONSOLE_CURSOR_HOLLOW;
|
||||
}
|
||||
if (console.y > 0
|
||||
&& console.first_line ==
|
||||
CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN) {
|
||||
int16 y1 = console.y - 10, y2 = console.y - 1;
|
||||
if (y1 < 0)
|
||||
y1 = 0;
|
||||
if (y2 < 0)
|
||||
y2 = 0;
|
||||
print_text_console(cursor, (1 + console.index), 19, 2, CONSOLE_COLOR, 0);
|
||||
flush_block((1 + console.index) * 8, y1, (1 + console.index) * 8 + 7, y2 - 1);
|
||||
}
|
||||
|
||||
do_update();
|
||||
}
|
||||
|
||||
/* Return true if key was handled */
|
||||
int console_keyhandler(int k) {
|
||||
static char buffer[CONSOLE_INPUT_SIZE];
|
||||
int16 y1, y2;
|
||||
char m[2];
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
/* Right button switches console on/off */
|
||||
if (!opt.agimouse) /* AGI Mouse uses right button */
|
||||
if (k == BUTTON_RIGHT)
|
||||
k = CONSOLE_ACTIVATE_KEY;
|
||||
#endif
|
||||
|
||||
if (!console.active) {
|
||||
if (k == CONSOLE_ACTIVATE_KEY) {
|
||||
console.active = 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!console.input_active) {
|
||||
if (k == CONSOLE_SWITCH_KEY) {
|
||||
console.input_active = 1;
|
||||
return true;
|
||||
}
|
||||
if (k == CONSOLE_ACTIVATE_KEY) {
|
||||
console.active = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
y1 = console.y - 10;
|
||||
y2 = console.y - 1;
|
||||
|
||||
if (y1 < 0)
|
||||
y1 = 0;
|
||||
if (y2 < 0)
|
||||
y2 = 0;
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
/* Ignore left button in console */
|
||||
if (k == BUTTON_LEFT)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
/* this code breaks scrolling up, maybe it shoud only be executed
|
||||
* in the default case?
|
||||
*/
|
||||
if (k) {
|
||||
/* make sure it's not enter or a scroll key */
|
||||
if ((k != KEY_ENTER) && (k != CONSOLE_SCROLLUP_KEY) && (k != CONSOLE_SCROLLDN_KEY)
|
||||
&& (k != CONSOLE_START_KEY)) {
|
||||
/* on any other input reset the console to the bottom */
|
||||
if (console.first_line != CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN) {
|
||||
console.first_line = CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN;
|
||||
build_console_layer();
|
||||
}
|
||||
console.count = -1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (k) {
|
||||
case KEY_ENTER:
|
||||
console_lock();
|
||||
console.index = 0;
|
||||
report("\n");
|
||||
|
||||
if (console_parse(buffer) != 0)
|
||||
report("What? Where?\n");
|
||||
|
||||
buffer[0] = 0;
|
||||
console_prompt();
|
||||
break;
|
||||
case KEY_BACKSPACE:{
|
||||
char *x;
|
||||
if (!console.index)
|
||||
break;
|
||||
x = get_last_console_line();
|
||||
x[console.index] = 0;
|
||||
*m = CONSOLE_CURSOR_EMPTY;
|
||||
print_text_console(m, (console.index + 1), 19, 2, CONSOLE_COLOR, 0);
|
||||
flush_block((console.index + 1) * CHAR_COLS, y1, (console.index + 1 + 1) * CHAR_COLS - 1, y2);
|
||||
console.index--;
|
||||
buffer[console.index] = 0;
|
||||
}
|
||||
break;
|
||||
case CONSOLE_ACTIVATE_KEY:
|
||||
console.active = !console.active;
|
||||
if (console.active)
|
||||
build_console_layer();
|
||||
break;
|
||||
case CONSOLE_SWITCH_KEY:
|
||||
console.count = -1;
|
||||
if (console.y)
|
||||
console.input_active = !console.input_active;
|
||||
break;
|
||||
case CONSOLE_SCROLLUP_KEY:
|
||||
console.count = -1;
|
||||
if (!console.y)
|
||||
break;
|
||||
if (console.first_line > (CONSOLE_LINES_ONSCREEN / 2))
|
||||
console.first_line -= CONSOLE_LINES_ONSCREEN / 2;
|
||||
else
|
||||
console.first_line = 0;
|
||||
build_console_layer();
|
||||
break;
|
||||
case CONSOLE_SCROLLDN_KEY:
|
||||
console.count = -1;
|
||||
if (!console.y)
|
||||
break;
|
||||
if (console.first_line < (CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN - CONSOLE_LINES_ONSCREEN / 2))
|
||||
console.first_line += CONSOLE_LINES_ONSCREEN / 2;
|
||||
else
|
||||
console.first_line = CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN;
|
||||
build_console_layer();
|
||||
break;
|
||||
case CONSOLE_START_KEY:
|
||||
console.count = -1;
|
||||
if (console.y)
|
||||
console.first_line = 0;
|
||||
break;
|
||||
case CONSOLE_END_KEY:
|
||||
console.count = -1;
|
||||
if (console.y)
|
||||
console.first_line = CONSOLE_LINES_BUFFER - CONSOLE_LINES_ONSCREEN;
|
||||
break;
|
||||
default:
|
||||
if (k >= 0x20 && k <= 0x7f && (console.index < CONSOLE_INPUT_SIZE - 2)) {
|
||||
char l[42];
|
||||
buffer[console.index] = k;
|
||||
*m = k;
|
||||
m[1] = 0;
|
||||
console.index++;
|
||||
|
||||
sprintf(l, "%s%c", get_last_console_line(), k);
|
||||
strncpy(get_last_console_line(), l, CONSOLE_LINE_SIZE);
|
||||
|
||||
buffer[console.index] = 0;
|
||||
print_text_console(m, console.index, 19, 2, CONSOLE_COLOR, 0);
|
||||
flush_block(console.index * 8, y1, console.index * 8 + 7, y2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
do_update();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void console_prompt() {
|
||||
report(CONSOLE_PROMPT);
|
||||
console_input = 1;
|
||||
}
|
||||
|
||||
void console_lock() {
|
||||
console_input = 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void *debug;
|
||||
|
||||
void report(char *message, ...) {
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
int console_init() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Date: Sun, 14 Oct 2001 23:02:02 -0700
|
||||
* From: Vasyl Tsvirkunov <vasyl@pacbell.net>
|
||||
*
|
||||
* This one was rather harmless and affected only builds without console.
|
||||
* In SQ1&2 (and likely some others) name entry screen did not update
|
||||
* properly. The bug caused by implicit assumption in cycle.c that
|
||||
* console_cycle() updates the screen. Well, it does, if console is enabled.
|
||||
* The fix is simple. In the second version of console_cycle() in console.c
|
||||
* (the "dummy" one) add call to do_update(). The thing raises some
|
||||
* questions about overall architecture of main cycle, but otherwise the fix
|
||||
* works just fine.
|
||||
*/
|
||||
void console_cycle() {
|
||||
do_update();
|
||||
}
|
||||
|
||||
void console_lock() {
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
void console_prompt() {
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
int console_keyhandler(int i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* USE_CONSOLE */
|
||||
|
||||
} // End of namespace Agi
|
71
engines/agi/console.h
Normal file
71
engines/agi/console.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_CONSOLE_H
|
||||
#define __AGI_CONSOLE_H
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
|
||||
#define CONSOLE_LINES_BUFFER 80
|
||||
#define CONSOLE_LINE_SIZE (GFX_WIDTH / 8)
|
||||
#define CONSOLE_ACTIVATE_KEY '`'
|
||||
#define CONSOLE_SWITCH_KEY '~'
|
||||
|
||||
struct agi_console {
|
||||
int active;
|
||||
int input_active;
|
||||
int index;
|
||||
int y;
|
||||
int max_y;
|
||||
int first_line;
|
||||
int count;
|
||||
char *line[CONSOLE_LINES_BUFFER];
|
||||
};
|
||||
|
||||
struct agi_debug {
|
||||
int enabled;
|
||||
int opcodes;
|
||||
int logic0;
|
||||
int steps;
|
||||
int priority;
|
||||
int statusline;
|
||||
int ignoretriggers;
|
||||
};
|
||||
|
||||
extern struct agi_console console;
|
||||
|
||||
#endif /* USE_CONSOLE */
|
||||
|
||||
int console_keyhandler(int);
|
||||
int console_init(void);
|
||||
void console_cycle(void);
|
||||
void console_lock(void);
|
||||
void console_prompt(void);
|
||||
void report(char *, ...);
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif /* __AGI_CONSOLE_H */
|
423
engines/agi/cycle.cpp
Normal file
423
engines/agi/cycle.cpp
Normal file
@ -0,0 +1,423 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/text.h"
|
||||
#include "agi/sprite.h"
|
||||
#include "agi/graphics.h"
|
||||
#include "agi/keyboard.h"
|
||||
#include "agi/menu.h"
|
||||
#include "agi/savegame.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#define TICK_SECONDS 20
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
struct mouse mouse;
|
||||
#endif
|
||||
|
||||
volatile uint32 clock_ticks;
|
||||
volatile uint32 clock_count;
|
||||
|
||||
/**
|
||||
* Set up new room.
|
||||
* This function is called when ego enters a new room.
|
||||
* @param n room number
|
||||
*/
|
||||
void new_room(int n) {
|
||||
struct vt_entry *v;
|
||||
int i;
|
||||
|
||||
debugC(4, kDebugLevelMain, "*** room %d ***", n);
|
||||
stop_sound();
|
||||
|
||||
i = 0;
|
||||
for (v = game.view_table; v < &game.view_table[MAX_VIEWTABLE]; v++) {
|
||||
v->entry = i++;
|
||||
v->flags &= ~(ANIMATED | DRAWN);
|
||||
v->flags |= UPDATE;
|
||||
v->step_time = 1;
|
||||
v->step_time_count = 1;
|
||||
v->cycle_time = 1;
|
||||
v->cycle_time_count = 1;
|
||||
v->step_size = 1;
|
||||
}
|
||||
agi_unload_resources();
|
||||
|
||||
game.player_control = true;
|
||||
game.block.active = false;
|
||||
game.horizon = 36;
|
||||
game.vars[V_prev_room] = game.vars[V_cur_room];
|
||||
game.vars[V_cur_room] = n;
|
||||
game.vars[V_border_touch_obj] = 0;
|
||||
game.vars[V_border_code] = 0;
|
||||
game.vars[V_ego_view_resource] = game.view_table[0].current_view;
|
||||
|
||||
agi_load_resource(rLOGIC, n);
|
||||
|
||||
/* Reposition ego in the new room */
|
||||
switch (game.vars[V_border_touch_ego]) {
|
||||
case 1:
|
||||
game.view_table[0].y_pos = _HEIGHT - 1;
|
||||
break;
|
||||
case 2:
|
||||
game.view_table[0].x_pos = 0;
|
||||
break;
|
||||
case 3:
|
||||
game.view_table[0].y_pos = HORIZON + 1;
|
||||
break;
|
||||
case 4:
|
||||
game.view_table[0].x_pos = _WIDTH - game.view_table[0].x_size;
|
||||
break;
|
||||
}
|
||||
|
||||
game.vars[V_border_touch_ego] = 0;
|
||||
setflag(F_new_room_exec, true);
|
||||
|
||||
game.exit_all_logics = true;
|
||||
|
||||
write_status();
|
||||
write_prompt();
|
||||
}
|
||||
|
||||
static void reset_controllers() {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
game.ev_keyp[i].occured = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void interpret_cycle() {
|
||||
int old_sound, old_score;
|
||||
|
||||
if (game.player_control)
|
||||
game.vars[V_ego_dir] = game.view_table[0].direction;
|
||||
else
|
||||
game.view_table[0].direction = game.vars[V_ego_dir];
|
||||
|
||||
check_all_motions();
|
||||
|
||||
old_score = game.vars[V_score];
|
||||
old_sound = getflag(F_sound_on);
|
||||
|
||||
game.exit_all_logics = false;
|
||||
while (run_logic(0) == 0 && !game.quit_prog_now) {
|
||||
game.vars[V_word_not_found] = 0;
|
||||
game.vars[V_border_touch_obj] = 0;
|
||||
game.vars[V_border_code] = 0;
|
||||
old_score = game.vars[V_score];
|
||||
setflag(F_entered_cli, false);
|
||||
game.exit_all_logics = false;
|
||||
reset_controllers();
|
||||
}
|
||||
reset_controllers();
|
||||
|
||||
game.view_table[0].direction = game.vars[V_ego_dir];
|
||||
|
||||
if (game.vars[V_score] != old_score || getflag(F_sound_on) != old_sound)
|
||||
write_status();
|
||||
|
||||
game.vars[V_border_touch_obj] = 0;
|
||||
game.vars[V_border_code] = 0;
|
||||
setflag(F_new_room_exec, false);
|
||||
setflag(F_restart_game, false);
|
||||
setflag(F_restore_just_ran, false);
|
||||
|
||||
if (game.gfx_mode) {
|
||||
update_viewtable();
|
||||
do_update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update AGI interpreter timer.
|
||||
*/
|
||||
void update_timer() {
|
||||
clock_count++;
|
||||
if (clock_count <= TICK_SECONDS)
|
||||
return;
|
||||
|
||||
clock_count -= TICK_SECONDS;
|
||||
|
||||
if (!game.clock_enabled)
|
||||
return;
|
||||
|
||||
setvar(V_seconds, getvar(V_seconds) + 1);
|
||||
if (getvar(V_seconds) < 60)
|
||||
return;
|
||||
|
||||
setvar(V_seconds, 0);
|
||||
setvar(V_minutes, getvar(V_minutes) + 1);
|
||||
if (getvar(V_minutes) < 60)
|
||||
return;
|
||||
|
||||
setvar(V_minutes, 0);
|
||||
setvar(V_hours, getvar(V_hours) + 1);
|
||||
if (getvar(V_hours) < 24)
|
||||
return;
|
||||
|
||||
setvar(V_hours, 0);
|
||||
setvar(V_days, getvar(V_days) + 1);
|
||||
}
|
||||
|
||||
static int old_mode = -1;
|
||||
|
||||
void new_input_mode(int i) {
|
||||
old_mode = game.input_mode;
|
||||
game.input_mode = i;
|
||||
}
|
||||
|
||||
void old_input_mode() {
|
||||
game.input_mode = old_mode;
|
||||
}
|
||||
|
||||
/* If main_cycle returns false, don't process more events! */
|
||||
int main_cycle() {
|
||||
unsigned int key, kascii;
|
||||
struct vt_entry *v = &game.view_table[0];
|
||||
|
||||
poll_timer(); /* msdos driver -> does nothing */
|
||||
update_timer();
|
||||
|
||||
if (game.ver == 0) {
|
||||
message_box("Warning: game CRC not listed, assuming AGI version 2.917.");
|
||||
game.ver = -1;
|
||||
}
|
||||
|
||||
key = do_poll_keyboard();
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
/* In AGI Mouse emulation mode we must update the mouse-related
|
||||
* vars in every interpreter cycle.
|
||||
*/
|
||||
if (opt.agimouse) {
|
||||
game.vars[28] = mouse.x / 2;
|
||||
game.vars[29] = mouse.y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
if (key == KEY_PRIORITY) {
|
||||
erase_both();
|
||||
debug_.priority = !debug_.priority;
|
||||
show_pic();
|
||||
blit_both();
|
||||
commit_both();
|
||||
key = 0;
|
||||
}
|
||||
|
||||
if (key == KEY_STATUSLN) {
|
||||
debug_.statusline = !debug_.statusline;
|
||||
write_status();
|
||||
key = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Click-to-walk mouse interface */
|
||||
if (game.player_control && v->flags & ADJ_EGO_XY) {
|
||||
v->direction = get_direction(v->x_pos, v->y_pos, v->parm1, v->parm2, v->step_size);
|
||||
|
||||
if (v->direction == 0)
|
||||
in_destination(v);
|
||||
}
|
||||
|
||||
kascii = KEY_ASCII(key);
|
||||
|
||||
if (!console_keyhandler(key)) {
|
||||
if (kascii)
|
||||
setvar(V_key, kascii);
|
||||
process_key:
|
||||
switch (game.input_mode) {
|
||||
case INPUT_NORMAL:
|
||||
if (!handle_controller(key)) {
|
||||
if (key == 0 || !game.input_enabled)
|
||||
break;
|
||||
handle_keys(key);
|
||||
|
||||
/* if ESC pressed, activate menu before
|
||||
* accept.input from the interpreter cycle
|
||||
* sets the input mode to normal again
|
||||
* (closes: #540856)
|
||||
*/
|
||||
if (key == KEY_ESCAPE) {
|
||||
key = 0;
|
||||
goto process_key;
|
||||
}
|
||||
|
||||
/* commented out to close bug #438872
|
||||
* if (key) game.keypress = key;
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case INPUT_GETSTRING:
|
||||
handle_controller(key);
|
||||
handle_getstring(key);
|
||||
setvar(V_key, 0); /* clear ENTER key */
|
||||
break;
|
||||
case INPUT_MENU:
|
||||
menu_keyhandler(key);
|
||||
console_cycle();
|
||||
return false;
|
||||
case INPUT_NONE:
|
||||
handle_controller(key);
|
||||
if (key)
|
||||
game.keypress = key;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (game.input_mode == INPUT_MENU) {
|
||||
console_cycle();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
console_cycle();
|
||||
|
||||
if (game.msg_box_ticks > 0)
|
||||
game.msg_box_ticks--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int play_game() {
|
||||
int ec = err_OK;
|
||||
|
||||
debugC(2, kDebugLevelMain, "initializing...");
|
||||
debugC(2, kDebugLevelMain, "game.ver = 0x%x", game.ver);
|
||||
|
||||
stop_sound();
|
||||
clear_screen(0);
|
||||
|
||||
game.horizon = HORIZON;
|
||||
game.player_control = false;
|
||||
|
||||
setflag(F_logic_zero_firsttime, true); /* not in 2.917 */
|
||||
setflag(F_new_room_exec, true); /* needed for MUMG and SQ2! */
|
||||
setflag(F_sound_on, true); /* enable sound */
|
||||
setvar(V_time_delay, 2); /* "normal" speed */
|
||||
|
||||
game.gfx_mode = true;
|
||||
game.quit_prog_now = false;
|
||||
game.clock_enabled = true;
|
||||
game.line_user_input = 22;
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
if (opt.agimouse)
|
||||
report("Using AGI Mouse 1.0 protocol\n");
|
||||
#endif
|
||||
|
||||
report("Running AGI script.\n");
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
console.count = 5;
|
||||
console_prompt();
|
||||
#endif
|
||||
|
||||
setflag(F_entered_cli, false);
|
||||
setflag(F_said_accepted_input, false);
|
||||
game.vars[V_word_not_found] = 0;
|
||||
game.vars[V_key] = 0;
|
||||
|
||||
debugC(2, kDebugLevelMain, "Entering main loop");
|
||||
do {
|
||||
|
||||
if (!main_cycle())
|
||||
continue;
|
||||
|
||||
if (getvar(V_time_delay) == 0 ||
|
||||
(1 + clock_count) % getvar(V_time_delay) == 0) {
|
||||
if (!game.has_prompt && game.input_mode == INPUT_NORMAL) {
|
||||
write_prompt();
|
||||
game.has_prompt = 1;
|
||||
} else
|
||||
if (game.has_prompt && game.input_mode == INPUT_NONE) {
|
||||
write_prompt();
|
||||
game.has_prompt = 0;
|
||||
}
|
||||
|
||||
interpret_cycle();
|
||||
|
||||
setflag(F_entered_cli, false);
|
||||
setflag(F_said_accepted_input, false);
|
||||
game.vars[V_word_not_found] = 0;
|
||||
game.vars[V_key] = 0;
|
||||
}
|
||||
|
||||
if (game.quit_prog_now == 0xff)
|
||||
ec = err_RestartGame;
|
||||
|
||||
} while (game.quit_prog_now == 0);
|
||||
|
||||
stop_sound();
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
int run_game() {
|
||||
int i, ec = err_OK;
|
||||
|
||||
#ifdef USE_HIRES
|
||||
if (opt.cgaemu)
|
||||
opt.hires = 0;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < MAX_DIRS; i++)
|
||||
memset(&game.ev_keyp[i], 0, sizeof(struct agi_event));
|
||||
|
||||
/* Execute the game */
|
||||
do {
|
||||
debugC(2, kDebugLevelMain, "game loop");
|
||||
debugC(2, kDebugLevelMain, "game.ver = 0x%x", game.ver);
|
||||
|
||||
if (agi_init() != err_OK)
|
||||
break;
|
||||
if (ec == err_RestartGame)
|
||||
setflag(F_restart_game, true);
|
||||
|
||||
setvar(V_computer, 0); /* IBM PC (4 = Atari ST) */
|
||||
setvar(V_soundgen, 1); /* IBM PC SOUND */
|
||||
setvar(V_monitor, 0x3); /* EGA monitor */
|
||||
setvar(V_max_input_chars, 38);
|
||||
game.input_mode = INPUT_NONE;
|
||||
game.input_enabled = 0;
|
||||
game.has_prompt = 0;
|
||||
|
||||
game.state = STATE_RUNNING;
|
||||
ec = play_game();
|
||||
game.state = STATE_LOADED;
|
||||
agi_deinit();
|
||||
} while (ec == err_RestartGame);
|
||||
|
||||
menu_deinit();
|
||||
|
||||
release_image_stack();
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
295
engines/agi/font.cpp
Normal file
295
engines/agi/font.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
/* 8x8 font patterns */
|
||||
uint8 cur_font[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, /* cursor hollow */
|
||||
0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, /* cursor solid */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cursor empty */
|
||||
0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
|
||||
0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00,
|
||||
0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00,
|
||||
0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
|
||||
0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* \n */
|
||||
0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
|
||||
0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
|
||||
0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00,
|
||||
0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C,
|
||||
0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00,
|
||||
0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
|
||||
0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
|
||||
0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
|
||||
0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00,
|
||||
0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
|
||||
0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
|
||||
0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E,
|
||||
0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00,
|
||||
0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00,
|
||||
0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
|
||||
0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
|
||||
0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00,
|
||||
0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00,
|
||||
0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00,
|
||||
0x6C, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
|
||||
0x10, 0x7C, 0xD0, 0x7C, 0x16, 0xFC, 0x10, 0x00,
|
||||
0x00, 0x66, 0xAC, 0xD8, 0x36, 0x6A, 0xCC, 0x00,
|
||||
0x38, 0x4C, 0x38, 0x78, 0xCE, 0xCC, 0x7A, 0x00,
|
||||
0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
|
||||
0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
|
||||
0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
|
||||
0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
|
||||
0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
|
||||
0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00,
|
||||
0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xE6, 0x7C, 0x00,
|
||||
0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x00,
|
||||
0x7C, 0xC6, 0x06, 0x1C, 0x70, 0xC6, 0xFE, 0x00,
|
||||
0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00,
|
||||
0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
|
||||
0xFE, 0xC0, 0xFC, 0x06, 0x06, 0xC6, 0x7C, 0x00,
|
||||
0x7C, 0xC6, 0xC0, 0xFC, 0xC6, 0xC6, 0x7C, 0x00,
|
||||
0xFE, 0xC6, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
|
||||
0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0x00,
|
||||
0x7C, 0xC6, 0xC6, 0x7E, 0x06, 0xC6, 0x7C, 0x00,
|
||||
0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
|
||||
0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
|
||||
0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00,
|
||||
0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00,
|
||||
0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
|
||||
0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
|
||||
0x7C, 0x82, 0x9E, 0xA6, 0x9E, 0x80, 0x7C, 0x00,
|
||||
0x7C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00,
|
||||
0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
|
||||
0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00,
|
||||
0xFC, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00,
|
||||
0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
|
||||
0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
|
||||
0x7C, 0xC6, 0xC6, 0xC0, 0xCE, 0xC6, 0x7E, 0x00,
|
||||
0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00,
|
||||
0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
|
||||
0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
|
||||
0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
|
||||
0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
|
||||
0x82, 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
|
||||
0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
|
||||
0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
|
||||
0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
|
||||
0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x06,
|
||||
0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xE6, 0x00,
|
||||
0x7C, 0xC6, 0xC0, 0x7C, 0x06, 0xC6, 0x7C, 0x00,
|
||||
0x7E, 0x5A, 0x5A, 0x18, 0x18, 0x18, 0x3C, 0x00,
|
||||
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
|
||||
0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00,
|
||||
0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x82, 0x00,
|
||||
0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00,
|
||||
0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00,
|
||||
0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
|
||||
0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
|
||||
0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
|
||||
0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
|
||||
0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
|
||||
0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00,
|
||||
0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00,
|
||||
0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00,
|
||||
0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x78,
|
||||
0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
|
||||
0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
|
||||
0x00, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0x78,
|
||||
0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
|
||||
0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
|
||||
0x00, 0x00, 0xCC, 0xFE, 0xD6, 0xD6, 0xD6, 0x00,
|
||||
0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
|
||||
0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
|
||||
0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
|
||||
0x00, 0x00, 0xDE, 0x76, 0x60, 0x60, 0xF0, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC0, 0x7C, 0x06, 0x7C, 0x00,
|
||||
0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00,
|
||||
0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
|
||||
0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00,
|
||||
0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00,
|
||||
0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
|
||||
0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
|
||||
0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
|
||||
0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00,
|
||||
0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
|
||||
0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00,
|
||||
0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/*0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00, */
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*replacement 0x7F */
|
||||
|
||||
#ifdef AGDS_SUPPORT
|
||||
0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
|
||||
0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
|
||||
0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
|
||||
0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
|
||||
0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
|
||||
0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
|
||||
0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
|
||||
0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
|
||||
0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
|
||||
0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
|
||||
0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
|
||||
0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
|
||||
0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
|
||||
0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
|
||||
0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
|
||||
0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
|
||||
0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
|
||||
0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
|
||||
0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
|
||||
0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
|
||||
0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
|
||||
0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
|
||||
0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
|
||||
0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
|
||||
0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
|
||||
0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
|
||||
0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
|
||||
0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
|
||||
0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
|
||||
0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
|
||||
0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
|
||||
0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
|
||||
0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
|
||||
0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
|
||||
0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
|
||||
0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
|
||||
0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
|
||||
0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
|
||||
0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
|
||||
0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
|
||||
0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
|
||||
0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
|
||||
0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
|
||||
0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
|
||||
0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
|
||||
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
|
||||
0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
|
||||
0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
|
||||
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
||||
0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
|
||||
0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
|
||||
0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
|
||||
0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
|
||||
0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
|
||||
0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
|
||||
0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
|
||||
0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
|
||||
0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
|
||||
0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
|
||||
0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
|
||||
0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
|
||||
0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
|
||||
0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
|
||||
0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
|
||||
0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
|
||||
0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
|
||||
0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
|
||||
0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
|
||||
0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
|
||||
0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
|
||||
0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
|
||||
0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
|
||||
0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
|
||||
0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
|
||||
0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
|
||||
0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
|
||||
0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
|
||||
0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
|
||||
0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
|
||||
0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
|
||||
0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
|
||||
#endif /* AGDS_SUPPORT */
|
||||
};
|
||||
|
||||
} // End of namespace Agi
|
73
engines/agi/global.cpp
Normal file
73
engines/agi/global.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
int getflag(int n) {
|
||||
uint8 *set = (uint8 *) & game.flags;
|
||||
|
||||
set += n >> 3;
|
||||
return (*set & (1 << (n & 0x07))) != 0;
|
||||
}
|
||||
|
||||
void setflag(int n, int v) {
|
||||
uint8 *set = (uint8 *) & game.flags;
|
||||
|
||||
set += n >> 3;
|
||||
if (v)
|
||||
*set |= 1 << (n & 0x07); /* set bit */
|
||||
else
|
||||
*set &= ~(1 << (n & 0x07)); /* clear bit */
|
||||
}
|
||||
|
||||
void flipflag(int n) {
|
||||
uint8 *set = (uint8 *) & game.flags;
|
||||
|
||||
set += n >> 3;
|
||||
*set ^= 1 << (n & 0x07); /* flip bit */
|
||||
}
|
||||
|
||||
void setvar(int var, int val) {
|
||||
game.vars[var] = val;
|
||||
}
|
||||
|
||||
int getvar(int var) {
|
||||
return game.vars[var];
|
||||
}
|
||||
|
||||
void decrypt(uint8 *mem, int len) {
|
||||
uint8 *key;
|
||||
int i;
|
||||
|
||||
key = opt.agds ? (uint8 *)CRYPT_KEY_AGDS : (uint8 *)CRYPT_KEY_SIERRA;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
*(mem + i) ^= *(key + (i % 11));
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
742
engines/agi/graphics.cpp
Normal file
742
engines/agi/graphics.cpp
Normal file
@ -0,0 +1,742 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/graphics.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#define DEV_X0(x) ((x) << 1)
|
||||
#define DEV_X1(x) (((x) << 1) + 1)
|
||||
#define DEV_Y(x) (x)
|
||||
|
||||
#ifndef MAX_INT
|
||||
# define MAX_INT (int)((unsigned)~0 >> 1)
|
||||
#endif
|
||||
|
||||
static uint8 *agi_screen;
|
||||
#ifdef USE_CONSOLE
|
||||
static uint8 *console_screen;
|
||||
#endif
|
||||
|
||||
static unsigned char *screen;
|
||||
|
||||
extern uint8 cur_font[];
|
||||
|
||||
/**
|
||||
* 16 color RGB palette (plus 16 transparent colors).
|
||||
* This array contains the 6-bit RGB values of the EGA palette exported
|
||||
* to the console drivers.
|
||||
*/
|
||||
uint8 ega_palette[16 * 3] = {
|
||||
0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x2a,
|
||||
0x00, 0x2a, 0x00,
|
||||
0x00, 0x2a, 0x2a,
|
||||
0x2a, 0x00, 0x00,
|
||||
0x2a, 0x00, 0x2a,
|
||||
0x2a, 0x15, 0x00,
|
||||
0x2a, 0x2a, 0x2a,
|
||||
0x15, 0x15, 0x15,
|
||||
0x15, 0x15, 0x3f,
|
||||
0x15, 0x3f, 0x15,
|
||||
0x15, 0x3f, 0x3f,
|
||||
0x3f, 0x15, 0x15,
|
||||
0x3f, 0x15, 0x3f,
|
||||
0x3f, 0x3f, 0x15,
|
||||
0x3f, 0x3f, 0x3f
|
||||
};
|
||||
|
||||
/**
|
||||
* 16 color amiga-ish palette.
|
||||
*/
|
||||
uint8 new_palette[16 * 3] = {
|
||||
0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3f,
|
||||
0x00, 0x2A, 0x00,
|
||||
0x00, 0x2A, 0x2A,
|
||||
0x33, 0x00, 0x00,
|
||||
0x2f, 0x1c, 0x37,
|
||||
0x23, 0x14, 0x00,
|
||||
0x2f, 0x2f, 0x2f,
|
||||
0x15, 0x15, 0x15,
|
||||
0x00, 0x2f, 0x3f,
|
||||
0x00, 0x33, 0x15,
|
||||
0x15, 0x3F, 0x3F,
|
||||
0x3f, 0x27, 0x23,
|
||||
0x3f, 0x15, 0x3f,
|
||||
0x3b, 0x3b, 0x00,
|
||||
0x3F, 0x3F, 0x3F
|
||||
};
|
||||
|
||||
uint8 palette[32 * 3];
|
||||
|
||||
static uint16 cga_map[16] = {
|
||||
0x0000, /* 0 - black */
|
||||
0x0d00, /* 1 - blue */
|
||||
0x0b00, /* 2 - green */
|
||||
0x0f00, /* 3 - cyan */
|
||||
0x000b, /* 4 - red */
|
||||
0x0b0d, /* 5 - magenta */
|
||||
0x000d, /* 6 - brown */
|
||||
0x0b0b, /* 7 - gray */
|
||||
0x0d0d, /* 8 - dark gray */
|
||||
0x0b0f, /* 9 - light blue */
|
||||
0x0b0d, /* 10 - light green */
|
||||
0x0f0d, /* 11 - light cyan */
|
||||
0x0f0d, /* 12 - light red */
|
||||
0x0f00, /* 13 - light magenta */
|
||||
0x0f0b, /* 14 - yellow */
|
||||
0x0f0f /* 15 - white */
|
||||
};
|
||||
|
||||
struct update_block {
|
||||
int x1, y1;
|
||||
int x2, y2;
|
||||
};
|
||||
|
||||
static struct update_block update = {
|
||||
MAX_INT, MAX_INT, 0, 0
|
||||
};
|
||||
|
||||
struct gfx_driver *gfx; /* graphics driver */
|
||||
|
||||
/*
|
||||
* Layer 4: 640x480? ================== User display
|
||||
* ^
|
||||
* | do_update(), put_block()
|
||||
* |
|
||||
* Layer 3: 640x480? ================== Framebuffer
|
||||
* ^
|
||||
* | flush_block(), put_pixels()
|
||||
* |
|
||||
* Layer 2: 320x200 ================== AGI engine screen (console), put_pixel()
|
||||
* |
|
||||
* Layer 1: 160x168 ================== AGI screen
|
||||
*/
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
|
||||
/**
|
||||
* Draws a row of pixels in the output device framebuffer.
|
||||
* This function adds the console layer using transparent colors if
|
||||
* appropriate.
|
||||
*/
|
||||
static void put_pixels(const int x, const int y, const int w, uint8 *p) {
|
||||
int i;
|
||||
uint8 _b[GFX_WIDTH] = { 0 };
|
||||
uint8 *b, *c = NULL;
|
||||
|
||||
if (console.y <= y) {
|
||||
gfx_putpixels(x, y, w, p);
|
||||
return;
|
||||
}
|
||||
|
||||
b = &_b[0];
|
||||
c = &console_screen[x + (y + GFX_HEIGHT - 1 - console.y) * GFX_WIDTH];
|
||||
|
||||
for (i = 0; i < w; i++, c++, p++) {
|
||||
*b++ = *c ? *c : *p + 16;
|
||||
}
|
||||
|
||||
gfx_putpixels(x, y, w, _b);
|
||||
}
|
||||
|
||||
static void init_console() {
|
||||
int i;
|
||||
|
||||
/* Console */
|
||||
console.line[0] = (char *)calloc(CONSOLE_LINES_BUFFER, CONSOLE_LINE_SIZE + 1);
|
||||
for (i = 1; i < CONSOLE_LINES_BUFFER; i++)
|
||||
console.line[i] = console.line[i - 1] + CONSOLE_LINE_SIZE + 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void put_pixels(const int x, const int y, const int w, uint8 *p) {
|
||||
gfx->put_pixels(x, y, w, p);
|
||||
}
|
||||
|
||||
static void init_console()
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* USE_CONSOLE */
|
||||
|
||||
#define SHAKE_MAG 3
|
||||
static uint8 *shake_h, *shake_v;
|
||||
|
||||
void shake_start() {
|
||||
int i;
|
||||
|
||||
if ((shake_h = (uint8 *)malloc(GFX_WIDTH * SHAKE_MAG)) == NULL)
|
||||
return;
|
||||
|
||||
if ((shake_v = (uint8 *)malloc(SHAKE_MAG * (GFX_HEIGHT - SHAKE_MAG))) == NULL) {
|
||||
free(shake_h);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < GFX_HEIGHT - SHAKE_MAG; i++) {
|
||||
memcpy(shake_v + i * SHAKE_MAG, agi_screen + i * GFX_WIDTH, SHAKE_MAG);
|
||||
}
|
||||
|
||||
for (i = 0; i < SHAKE_MAG; i++) {
|
||||
memcpy(shake_h + i * GFX_WIDTH, agi_screen + i * GFX_WIDTH, GFX_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
void shake_screen(int n) {
|
||||
int i;
|
||||
|
||||
if (n == 0) {
|
||||
for (i = 0; i < (GFX_HEIGHT - SHAKE_MAG); i++) {
|
||||
memmove(&agi_screen[GFX_WIDTH * i],
|
||||
&agi_screen[GFX_WIDTH * (i + SHAKE_MAG) + SHAKE_MAG],
|
||||
GFX_WIDTH - SHAKE_MAG);
|
||||
}
|
||||
} else {
|
||||
for (i = GFX_HEIGHT - SHAKE_MAG - 1; i >= 0; i--) {
|
||||
memmove(&agi_screen[GFX_WIDTH * (i + SHAKE_MAG) + SHAKE_MAG],
|
||||
&agi_screen[GFX_WIDTH * i], GFX_WIDTH - SHAKE_MAG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void shake_end() {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GFX_HEIGHT - SHAKE_MAG; i++) {
|
||||
memcpy(agi_screen + i * GFX_WIDTH, shake_v + i * SHAKE_MAG, SHAKE_MAG);
|
||||
}
|
||||
|
||||
for (i = 0; i < SHAKE_MAG; i++) {
|
||||
memcpy(agi_screen + i * GFX_WIDTH, shake_h + i * GFX_WIDTH, GFX_WIDTH);
|
||||
}
|
||||
|
||||
flush_block(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
|
||||
|
||||
free(shake_v);
|
||||
free(shake_h);
|
||||
}
|
||||
|
||||
void put_text_character(int l, int x, int y, unsigned int c, int fg, int bg) {
|
||||
int x1, y1, xx, yy, cc;
|
||||
uint8 *p;
|
||||
|
||||
p = cur_font + ((unsigned int)c * CHAR_LINES);
|
||||
for (y1 = 0; y1 < CHAR_LINES; y1++) {
|
||||
for (x1 = 0; x1 < CHAR_COLS; x1++) {
|
||||
xx = x + x1;
|
||||
yy = y + y1;
|
||||
cc = (*p & (1 << (7 - x1))) ? fg : bg;
|
||||
#ifdef USE_CONSOLE
|
||||
if (l) {
|
||||
console_screen[xx + yy * GFX_WIDTH] = cc;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
agi_screen[xx + yy * GFX_WIDTH] = cc;
|
||||
}
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
/* FIXME: we don't want this when we're writing on the
|
||||
* console!
|
||||
*/
|
||||
flush_block(x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1);
|
||||
}
|
||||
|
||||
void draw_rectangle(int x1, int y1, int x2, int y2, int c) {
|
||||
int y, w, h;
|
||||
uint8 *p0;
|
||||
|
||||
if (x1 >= GFX_WIDTH)
|
||||
x1 = GFX_WIDTH - 1;
|
||||
if (y1 >= GFX_HEIGHT)
|
||||
y1 = GFX_HEIGHT - 1;
|
||||
if (x2 >= GFX_WIDTH)
|
||||
x2 = GFX_WIDTH - 1;
|
||||
if (y2 >= GFX_HEIGHT)
|
||||
y2 = GFX_HEIGHT - 1;
|
||||
|
||||
w = x2 - x1 + 1;
|
||||
h = y2 - y1 + 1;
|
||||
p0 = &agi_screen[x1 + y1 * GFX_WIDTH];
|
||||
for (y = 0; y < h; y++) {
|
||||
memset(p0, c, w);
|
||||
p0 += GFX_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_frame(int x1, int y1, int x2, int y2, int c1, int c2) {
|
||||
int y, w;
|
||||
uint8 *p0;
|
||||
|
||||
/* top line */
|
||||
w = x2 - x1 + 1;
|
||||
p0 = &agi_screen[x1 + y1 * GFX_WIDTH];
|
||||
memset(p0, c1, w);
|
||||
|
||||
/* bottom line */
|
||||
p0 = &agi_screen[x1 + y2 * GFX_WIDTH];
|
||||
memset(p0, c2, w);
|
||||
|
||||
/* side lines */
|
||||
for (y = y1; y <= y2; y++) {
|
||||
agi_screen[x1 + y * GFX_WIDTH] = c1;
|
||||
agi_screen[x2 + y * GFX_WIDTH] = c2;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_box(int x1, int y1, int x2, int y2, int colour1, int colour2, int m) {
|
||||
x1 += m;
|
||||
y1 += m;
|
||||
x2 -= m;
|
||||
y2 -= m;
|
||||
|
||||
draw_rectangle(x1, y1, x2, y2, colour1);
|
||||
draw_frame(x1 + 2, y1 + 2, x2 - 2, y2 - 2, colour2, colour2);
|
||||
flush_block(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
void print_character(int x, int y, char c, int fg, int bg) {
|
||||
x *= CHAR_COLS;
|
||||
y *= CHAR_LINES;
|
||||
|
||||
put_text_character(0, x, y, c, fg, bg);
|
||||
// redundant! already inside put_text_character!
|
||||
// flush_block (x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw button
|
||||
* @param x x coordinate of the button
|
||||
* @param y y coordinate of the button
|
||||
* @param a set if the button has focus
|
||||
* @param p set if the button is pressed
|
||||
*/
|
||||
void draw_button(int x, int y, char *s, int a, int p) {
|
||||
int len = strlen(s);
|
||||
int x1, y1, x2, y2;
|
||||
|
||||
x1 = x - 3;
|
||||
y1 = y - 3;
|
||||
x2 = x + CHAR_COLS * len + 2;
|
||||
y2 = y + CHAR_LINES + 2;
|
||||
|
||||
while (*s) {
|
||||
put_text_character(0, x + (!!p), y + (!!p), *s++,
|
||||
a ? 15 : 0, a ? 0 : 15);
|
||||
x += CHAR_COLS;
|
||||
}
|
||||
|
||||
x1 -= 2;
|
||||
y1 -= 2;
|
||||
x2 += 2;
|
||||
y2 += 2;
|
||||
|
||||
flush_block(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
int test_button(int x, int y, char *s) {
|
||||
int len = strlen(s);
|
||||
int x1, y1, x2, y2;
|
||||
|
||||
x1 = x - 3;
|
||||
y1 = y - 3;
|
||||
x2 = x + CHAR_COLS * len + 2;
|
||||
y2 = y + CHAR_LINES + 2;
|
||||
|
||||
if ((int)mouse.x >= x1 && (int)mouse.y >= y1
|
||||
&& (int)mouse.x <= x2 && (int)mouse.y <= y2)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void put_block(int x1, int y1, int x2, int y2) {
|
||||
gfx_putblock(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
void put_screen() {
|
||||
put_block(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
|
||||
}
|
||||
|
||||
void poll_timer() {
|
||||
agi_timer_low();
|
||||
}
|
||||
|
||||
int get_key() {
|
||||
return agi_get_keypress_low();
|
||||
}
|
||||
|
||||
int keypress() {
|
||||
return agi_is_keypress_low();
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize the color palette
|
||||
* This function initializes the color palette using the specified 16-color
|
||||
* RGB palette and creates 16 extra palette entries with translucent colors
|
||||
* for the interpreter console.
|
||||
* @param p A pointer to the 16-color RGB palette.
|
||||
*/
|
||||
void init_palette(uint8 *p) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 48; i++) {
|
||||
palette[i] = p[i];
|
||||
palette[i + 48] = (p[i] + 0x30) >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_set_palette() {
|
||||
int i;
|
||||
byte pal[32 * 4];
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
pal[i * 4 + 0] = palette[i * 3 + 0] << 2;
|
||||
pal[i * 4 + 1] = palette[i * 3 + 1] << 2;
|
||||
pal[i * 4 + 2] = palette[i * 3 + 2] << 2;
|
||||
pal[i * 4 + 3] = 0;
|
||||
}
|
||||
g_system->setPalette(pal, 0, 32);
|
||||
}
|
||||
|
||||
void gfx_putpixels(int x, int y, int w, uint8 *p) {
|
||||
uint8 *p0 = screen + x + y * 320;
|
||||
memcpy(p0, p, w);
|
||||
}
|
||||
|
||||
/* put a block onto the screen */
|
||||
void gfx_putblock(int x1, int y1, int x2, int y2) {
|
||||
if (x1 >= GFX_WIDTH)
|
||||
x1 = GFX_WIDTH - 1;
|
||||
if (y1 >= GFX_HEIGHT)
|
||||
y1 = GFX_HEIGHT - 1;
|
||||
if (x2 >= GFX_WIDTH)
|
||||
x2 = GFX_WIDTH - 1;
|
||||
if (y2 >= GFX_HEIGHT)
|
||||
y2 = GFX_HEIGHT - 1;
|
||||
|
||||
// force full update until fix wrong partial updates
|
||||
g_system->copyRectToScreen(screen, 320, 0, 0, 320, 200);
|
||||
//g_system->copyRectToScreen(screen, 320, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
|
||||
//g_system->updateScreen();
|
||||
}
|
||||
|
||||
static const byte mouseCursorArrow[] = {
|
||||
0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00,
|
||||
0x78, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00,
|
||||
0x7F, 0x80, 0x7C, 0x00, 0x6C, 0x00, 0x46, 0x00,
|
||||
0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0xC0, 0x00, 0xE0, 0x00, 0xF0, 0x00, 0xF8, 0x00,
|
||||
0xFC, 0x00, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x80,
|
||||
0xFF, 0xC0, 0xFF, 0xC0, 0xFE, 0x00, 0xFF, 0x00,
|
||||
0xCF, 0x00, 0x07, 0x80, 0x07, 0x80, 0x03, 0x80
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize graphics device.
|
||||
*
|
||||
* @see deinit_video()
|
||||
*/
|
||||
int init_video() {
|
||||
if (opt.egapal)
|
||||
init_palette(ega_palette);
|
||||
else
|
||||
init_palette(new_palette);
|
||||
|
||||
init_console();
|
||||
|
||||
if ((agi_screen = (uint8 *)calloc(GFX_WIDTH, GFX_HEIGHT)) == NULL)
|
||||
return err_NotEnoughMemory;
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
if ((console_screen = (uint8 *)calloc(GFX_WIDTH, GFX_HEIGHT)) == NULL) {
|
||||
free(agi_screen);
|
||||
return err_NotEnoughMemory;
|
||||
}
|
||||
#endif
|
||||
|
||||
gfx_set_palette();
|
||||
|
||||
byte mouseCursor[16 * 16];
|
||||
const byte *src = mouseCursorArrow;
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
int offs = i * 8;
|
||||
for (byte mask = 0x80; mask != 0; mask >>= 1) {
|
||||
if (src[0] & mask) {
|
||||
mouseCursor[offs] = 2;
|
||||
} else if (src[32] & mask) {
|
||||
mouseCursor[offs] = 0;
|
||||
} else {
|
||||
mouseCursor[offs] = 0xFF;
|
||||
}
|
||||
++offs;
|
||||
}
|
||||
++src;
|
||||
}
|
||||
g_system->setMouseCursor(mouseCursor, 16, 16, 1, 1);
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize graphics device.
|
||||
*
|
||||
* @see init_video()
|
||||
*/
|
||||
int deinit_video() {
|
||||
free(agi_screen);
|
||||
#ifdef USE_CONSOLE
|
||||
free(console_screen);
|
||||
#endif
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
int init_machine() {
|
||||
screen = (unsigned char *)malloc(320 * 200);
|
||||
clock_count = 0;
|
||||
clock_ticks = 0;
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
int deinit_machine() {
|
||||
free(screen);
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write pixels on the output device.
|
||||
* This function writes a row of pixels on the output device. Only the
|
||||
* lower 4 bits of each pixel in the row will be used, making this
|
||||
* function suitable for use with rows from the AGI screen.
|
||||
* @param x x coordinate of the row start (AGI coord.)
|
||||
* @param y y coordinate of the row start (AGI coord.)
|
||||
* @param n number of pixels in the row
|
||||
* @param p pointer to the row start in the AGI screen
|
||||
*/
|
||||
void put_pixels_a(int x, int y, int n, uint8 *p) {
|
||||
if (opt.cgaemu) {
|
||||
for (x *= 2; n--; p++, x += 2) {
|
||||
register uint16 q = (cga_map[(*p & 0xf0) >> 4] << 4) | cga_map[*p & 0x0f];
|
||||
#ifdef USE_CONSOLE
|
||||
if (debug_.priority)
|
||||
q >>= 4;
|
||||
#endif
|
||||
*(uint16 *)&agi_screen[x + y * GFX_WIDTH] = q & 0x0f0f;
|
||||
}
|
||||
} else {
|
||||
for (x *= 2; n--; p++, x += 2) {
|
||||
register uint16 q = ((uint16) * p << 8) | *p;
|
||||
#ifdef USE_CONSOLE
|
||||
if (debug_.priority)
|
||||
q >>= 4;
|
||||
#endif
|
||||
*(uint16 *)&agi_screen[x + y * GFX_WIDTH] = q & 0x0f0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_HIRES
|
||||
|
||||
void put_pixels_hires(int x, int y, int n, uint8 *p) {
|
||||
//y += CHAR_LINES;
|
||||
for (; n--; p++, x++) {
|
||||
uint8 q = *p;
|
||||
#ifdef USE_CONSOLE
|
||||
if (debug_.priority)
|
||||
q >>= 4;
|
||||
#endif
|
||||
agi_screen[x + y * GFX_WIDTH] = q & 0x0f;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Schedule blocks for blitting on the output device.
|
||||
* This function gets the coordinates of a block in the AGI screen and
|
||||
* schedule it to be updated in the output device.
|
||||
* @param x1 x coordinate of the upper left corner of the block (AGI coord.)
|
||||
* @param y1 y coordinate of the upper left corner of the block (AGI coord.)
|
||||
* @param x2 x coordinate of the lower right corner of the block (AGI coord.)
|
||||
* @param y2 y coordinate of the lower right corner of the block (AGI coord.)
|
||||
*
|
||||
* @see do_update()
|
||||
*/
|
||||
void schedule_update(int x1, int y1, int x2, int y2) {
|
||||
if (x1 < update.x1)
|
||||
update.x1 = x1;
|
||||
if (y1 < update.y1)
|
||||
update.y1 = y1;
|
||||
if (x2 > update.x2)
|
||||
update.x2 = x2;
|
||||
if (y2 > update.y2)
|
||||
update.y2 = y2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update scheduled blocks on the output device.
|
||||
* This function exposes the blocks scheduled for updating to the output
|
||||
* device. Blocks can be scheduled at any point of the AGI cycle.
|
||||
*
|
||||
* @see schedule_update()
|
||||
*/
|
||||
void do_update() {
|
||||
if (update.x1 <= update.x2 && update.y1 <= update.y2) {
|
||||
gfx_putblock(update.x1, update.y1, update.x2, update.y2);
|
||||
}
|
||||
|
||||
/* reset update block variables */
|
||||
update.x1 = MAX_INT;
|
||||
update.y1 = MAX_INT;
|
||||
update.x2 = 0;
|
||||
update.y2 = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a block of the framebuffer with contents of the AGI engine screen.
|
||||
* This function updates a block in the output device with the contents of
|
||||
* the AGI engine screen, handling console transparency.
|
||||
* @param x1 x coordinate of the upper left corner of the block
|
||||
* @param y1 y coordinate of the upper left corner of the block
|
||||
* @param x2 x coordinate of the lower right corner of the block
|
||||
* @param y2 y coordinate of the lower right corner of the block
|
||||
*
|
||||
* @see flush_block_a()
|
||||
*/
|
||||
void flush_block(int x1, int y1, int x2, int y2) {
|
||||
int y, w;
|
||||
uint8 *p0;
|
||||
|
||||
schedule_update(x1, y1, x2, y2);
|
||||
|
||||
p0 = &agi_screen[x1 + y1 * GFX_WIDTH];
|
||||
w = x2 - x1 + 1;
|
||||
|
||||
for (y = y1; y <= y2; y++) {
|
||||
put_pixels(x1, y, w, p0);
|
||||
p0 += GFX_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a block of the framebuffer receiving AGI picture coordinates.
|
||||
* @param x1 x AGI picture coordinate of the upper left corner of the block
|
||||
* @param y1 y AGI picture coordinate of the upper left corner of the block
|
||||
* @param x2 x AGI picture coordinate of the lower right corner of the block
|
||||
* @param y2 y AGI picture coordinate of the lower right corner of the block
|
||||
*
|
||||
* @see flush_block()
|
||||
*/
|
||||
void flush_block_a(int x1, int y1, int x2, int y2) {
|
||||
//y1 += 8;
|
||||
//y2 += 8;
|
||||
flush_block(DEV_X0(x1), DEV_Y(y1), DEV_X1(x2), DEV_Y(y2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the framebuffer with contents of the AGI engine screen (console-aware).
|
||||
* This function updates the output device with the contents of the AGI
|
||||
* screen, handling console transparency.
|
||||
*/
|
||||
void flush_screen() {
|
||||
flush_block(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the output device screen (console-aware).
|
||||
* This function clears the output device screen and updates the
|
||||
* output device. Contents of the AGI screen are left untouched. This
|
||||
* function can be used to simulate a switch to a text mode screen in
|
||||
* a graphic-only device.
|
||||
* @param c color to clear the screen
|
||||
*/
|
||||
void clear_screen(int c) {
|
||||
memset(agi_screen, c, GFX_WIDTH * GFX_HEIGHT);
|
||||
flush_screen();
|
||||
}
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
/**
|
||||
* Clear the console screen.
|
||||
* This function clears the top n lines of the console screen.
|
||||
* @param n number of lines to clear (in pixels)
|
||||
*/
|
||||
void clear_console_screen(int n) {
|
||||
memset(console_screen + n * GFX_WIDTH, 0, (GFX_HEIGHT - n) * GFX_WIDTH);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Save a block of the AGI engine screen
|
||||
*/
|
||||
void save_block(int x1, int y1, int x2, int y2, uint8 *b) {
|
||||
uint8 *p0;
|
||||
int w, h;
|
||||
|
||||
p0 = &agi_screen[x1 + GFX_WIDTH * y1];
|
||||
w = x2 - x1 + 1;
|
||||
h = y2 - y1 + 1;
|
||||
while (h--) {
|
||||
memcpy(b, p0, w);
|
||||
b += w;
|
||||
p0 += GFX_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore a block of the AGI engine screen
|
||||
*/
|
||||
void restore_block(int x1, int y1, int x2, int y2, uint8 *b) {
|
||||
uint8 *p0;
|
||||
int w, h;
|
||||
|
||||
p0 = &agi_screen[x1 + GFX_WIDTH * y1];
|
||||
w = x2 - x1 + 1;
|
||||
h = y2 - y1 + 1;
|
||||
while (h--) {
|
||||
memcpy(p0, b, w);
|
||||
b += w;
|
||||
p0 += GFX_WIDTH;
|
||||
}
|
||||
flush_block(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
86
engines/agi/graphics.h
Normal file
86
engines/agi/graphics.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_GRAPHICS_H
|
||||
#define __AGI_GRAPHICS_H
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#define GFX_WIDTH 320
|
||||
#define GFX_HEIGHT 200
|
||||
#define CHAR_COLS 8
|
||||
#define CHAR_LINES 8
|
||||
|
||||
extern uint8 palette[];
|
||||
|
||||
/* Transparent layer */
|
||||
extern uint8 layer1_data[];
|
||||
extern uint8 layer2_data[];
|
||||
|
||||
void gfx_putpixels(int x, int y, int w, uint8 * p);
|
||||
void gfx_putblock(int x1, int y1, int x2, int y2);
|
||||
|
||||
void put_text_character(int, int, int, unsigned int, int, int);
|
||||
void shake_screen(int);
|
||||
void shake_start(void);
|
||||
void shake_end(void);
|
||||
void save_screen(void);
|
||||
void restore_screen(void);
|
||||
|
||||
int init_video(void);
|
||||
int deinit_video(void);
|
||||
void schedule_update(int, int, int, int);
|
||||
void do_update(void);
|
||||
void put_screen(void);
|
||||
void flush_block(int, int, int, int);
|
||||
void flush_block_a(int, int, int, int);
|
||||
void put_pixels_a(int, int, int, uint8 *);
|
||||
void flush_screen(void);
|
||||
void clear_screen(int);
|
||||
void clear_console_screen(int);
|
||||
void draw_box(int, int, int, int, int, int, int);
|
||||
void draw_button(int, int, char *, int, int);
|
||||
int test_button(int, int, char *);
|
||||
void draw_rectangle(int, int, int, int, int);
|
||||
void save_block(int, int, int, int, uint8 *);
|
||||
void restore_block(int, int, int, int, uint8 *);
|
||||
void init_palette(uint8 *);
|
||||
|
||||
void put_pixel(int, int, int);
|
||||
|
||||
#ifdef USE_HIRES
|
||||
void put_pixels_hires(int x, int y, int n, uint8 * p);
|
||||
#endif
|
||||
int keypress(void);
|
||||
int get_key(void);
|
||||
void print_character(int, int, char, int, int);
|
||||
void poll_timer(void);
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif /* __AGI_GRAPHICS_H */
|
475
engines/agi/id.cpp
Normal file
475
engines/agi/id.cpp
Normal file
@ -0,0 +1,475 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/opcodes.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
/*
|
||||
* Determine what AGI v2 system to emulate, these are the major version
|
||||
* to emulate, thus 2.915 comes under 2.917, 2.4xxx is 2.440, etc.
|
||||
*
|
||||
* 0x2089
|
||||
* 0x2272
|
||||
* 0x2440
|
||||
* 0x2917
|
||||
* 0x2936
|
||||
*/
|
||||
|
||||
const char *ids_database = "\
|
||||
# CRC Int Ver [options] Game name # Comment \n\
|
||||
\n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
# PC-DOS versions \n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
\n\
|
||||
0x484AA 0x2440 AGI Demo 1 (PC) 05/87 [AGI 2.425] # A.K.A. Demo 5 \n\
|
||||
0x8CC43 0x2917 AGI Demo 2 (PC 5.25) 11/87 [v1] [AGI 2.915] # Demo 1 \n\
|
||||
0x8856C 0x2917 AGI Demo 2 (PC 3.5) 11/87 [AGI 2.915] \n\
|
||||
0x843AC 0x2917 AGI Demo 2 (PC 5.25) 01/88 [v2] [AGI 2.917] # Demo 3 \n\
|
||||
0x89592 0x3149 AGI Demo 3 (PC) 09/88 [AGI 3.002.102] # Demo 4 \n\
|
||||
0x24A18 0x2440 Black Cauldron (PC) 2.00 6/14/87 [AGI 2.439] \n\
|
||||
0x22B50 0x3149 Black Cauldron (PC 5.25) 2.10 11/10/88 [AGI 3.002.098] \n\
|
||||
0x23E0E 0x3149 Black Cauldron (PC 3.5) 2.10 11/10/88 [AGI 3.002.098] \n\
|
||||
0xB5A25 0x3149 Gold Rush! (PC 5.25) 2.01 12/22/88 [AGI 3.002.149] \n\
|
||||
0xB1C9E 0x3149 Gold Rush! (PC 3.5) 2.01 12/22/88 [AGI 3.002.149] \n\
|
||||
0x49EDA 0x2917 King's Quest 1 (PC 5.25/3.5) 2.0F [AGI 2.917] # also 2.425 \n\
|
||||
0x633CB 0x2440 King's Quest 2 (PC 5.25/3.5) 2.1 [AGI 2.411] \n\
|
||||
0x63338 0x2917 King's Quest 2 (PC 5.25/3.5) 2.2 [AGI 2.426] # also 2.917 \n\
|
||||
0x88673 0x2272 King's Quest 3 (PC) 1.01 11/08/86 [AGI 2.272] \n\
|
||||
0x840D3 0x2440 King's Quest 3 (PC 5.25) 2.00 5/25/87 [AGI 2.435] \n\
|
||||
0x83191 0x2440 King's Quest 3 (PC 3.5) 2.00 5/25/87 [AGI 2.435] \n\
|
||||
0x83695 0x2936 King's Quest 3 (PC 3.5) 2.14 3/15/88 [AGI 2.936] \n\
|
||||
0x8410B 0x2936 King's Quest 3 (PC 5.25) 2.14 3/15/88 [AGI 2.936] \n\
|
||||
0xB124B 0x3086 King's Quest 4 (PC 3.5) 2.0 7/27/88 [AGI 3.002.086] \n\
|
||||
0xB291F 0x3086 King's Quest 4 (PC 3.5) 2.2 9/27/88 [AGI 3.002.086] \n\
|
||||
0xB3722 0x3086 King's Quest 4 (PC 5.25) 2.3 9/27/88 [AGI 3.002.086] \n\
|
||||
0x9CB15 0x3149 King's Quest 4 demo (PC) [AGI 3.002.102] \n\
|
||||
0x6F5E1 0x2440 Leisure Suit Larry 1 (PC 5.25/3.5) 1.00 6/1/87 [AGI 2.440] \n\
|
||||
0x4C16D 0x3149 Manhunter NY (PC 5.25) 1.22 8/31/88 [AGI 3.002.107] # also 3.003.102 \n\
|
||||
0x49687 0x3149 Manhunter NY (PC 3.5) 1.22 8/31/88 [AGI 3.002.102] \n\
|
||||
0x53971 0x3149 Manhunter SF (PC 3.5) 3.02 7/26/89 [AGI 3.002.149] \n\
|
||||
0x584F9 0x3149 Manhunter SF (PC 5.25) 3.03 8/17/89 [AGI 3.002.149] \n\
|
||||
0x5D77C 0x2917 Mixed-Up Mother Goose (PC) [AGI 2.915] \n\
|
||||
0x5D7C6 0x2917 Mixed Up Mother Goose (PC) [AGI 2.915] (Broken) \n\
|
||||
0x7F18B 0x2917 Police Quest 1 (PC) 2.0A 10/23/87 [AGI 2.903/2.911] \n\
|
||||
0x7EF35 0x2917 Police Quest 1 (PC) 2.0E 11/17/87 [AGI 2.915] \n\
|
||||
0x7EF06 0x2917 Police Quest 1 (PC 5.25/ST) 2.0G 12/03/87 [AGI 2.917] \n\
|
||||
0x7E0BC 0x2917 Police Quest 1 (PC 3.5) 2.0G 12/03/87 [AGI 2.917] \n\
|
||||
0x67FCC 0x2089 Space Quest 1 (PC) 1.0 [AGI 2.089] \n\
|
||||
0x68036 0x2089 Space Quest 1 (PC) 1.0X [AGI 2.089] \n\
|
||||
0x67F6E 0x2272 Space Quest 1 (PC) 1.1A [AGI 2.272] \n\
|
||||
0x68244 0x2440 Space Quest 1 (PC 5.25/3.5) 2.2 [AGI 2.426/2.917] \n\
|
||||
0x8DB32 0x2917 Space Quest 2 (PC 5.25) 2.0A [AGI 2.912] \n\
|
||||
0x8D825 0x2917 Space Quest 2 (PC 3.5) 2.0A [AGI 2.912] \n\
|
||||
0x8DA3E 0x2917 Space Quest 2 (PC 5.25/ST) 2.0C/A [AGI 2.915] \n\
|
||||
0x8E6A7 0x2917 Space Quest 2 (PC 3.5) 2.0C/B [AGI 2.917] \n\
|
||||
0x8E29B 0x2936 Space Quest 2 (PC 3.5) 2.0F [AGI 2.936] \n\
|
||||
0x8DF84 0x2936 Space Quest 2 (PC 5.25) 2.0D [AGI 2.936] \n\
|
||||
0x8DE46 0x2936 Space Quest 2 (PC 3.5) 2.0D [AGI 2.936] \n\
|
||||
0x8E310 0x2936 Space Quest 2 (PC 5.25) 2.0F [AGI 2.936] \n\
|
||||
0x31677 0x2272 Xmas Card 1986 (PC) [AGI 2.272] \n\
|
||||
\n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
# Apple //gs versions \n\
|
||||
# all guessed interpreter versions \n\
|
||||
# \n\
|
||||
# Notes: \n\
|
||||
# - (CE) in Apple IIgs versions stands for Carlos Escobar --PDD \n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
\n\
|
||||
0x93260 0x2917 AGI Demo 2 (IIgs) 1.0C (Censored) \n\
|
||||
0x285FB 0x3149 Black Cauldron (Apple IIgs) 1.0O 2/24/89 (CE) # 2.24.89 (CE) \n\
|
||||
0xB6F67 0x3149 Gold Rush! (Apple IIgs) 1.0M 2/28/89 (CE) aka 2.01 12/22/88 \n\
|
||||
0x4A9E8 0x2272 King's Quest 1 (IIgs) 1.0S-88223 \n\
|
||||
0x79D1B 0x2917 King's Quest 2 (IIgs) 2.0A 6/16/88 (CE) \n\
|
||||
0x85CD4 0x2917 King's Quest 3 (IIgs) 2.0A 8/28/88 (CE) \n\
|
||||
0xAF778 0x3086 King's Quest 4 (IIgs) 1.0K 11/22/88 (CE) \n\
|
||||
0x6E41E 0x2440 Leisure Suit Larry 1 (IIgs) 1.0E \n\
|
||||
0x4C705 0x3149 Manhunter NY (IIgs) 2.0E 10/05/88 (CE) \n\
|
||||
0x5F4E8 0x2917 Mixed Up Mother Goose (IIgs) \n\
|
||||
0x7DB3F 0x2917 Police Quest 1 (IIgs) 2.0A-88318 \n\
|
||||
0x7DBE5 0x2917 Police Quest 1 (IIgs) 2.0B-88421 \n\
|
||||
0x69EC0 0x2917 Space Quest 1 (IIgs) 2.2 \n\
|
||||
0x8E983 0x2936 Space Quest 2 (IIgs) 2.0A 7/25/88 (CE) \n\
|
||||
\n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
# Macintosh versions \n\
|
||||
# all guessed interpreter versions \n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
\n\
|
||||
0x4C02C 0x2440 King's Quest 1 (Mac) 2.0C \n\
|
||||
0x6382E 0x2440 King's Quest 2 (Mac) 2.0R \n\
|
||||
0x8410B 0x2440 King's Quest 3 (Mac) 2.14 3/15/88 \n\
|
||||
0x78202 0x2440 Leisure Suit Larry 1 (Mac) 1.05 6/26/87 \n\
|
||||
0x7EF06 0x2440 Police Quest 1 (Mac) 2.0G 12/3/87 \n\
|
||||
0x6A277 0x2440 Space Quest 1 (Mac) 1.5D \n\
|
||||
0x8DF84 0x2936 Space Quest 2 (Mac) 2.0D \n\
|
||||
\n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
# Atari ST versions \n\
|
||||
# all guessed interpreter versions \n\
|
||||
# \n\
|
||||
# Notes: \n\
|
||||
# - Chris Iden wrote the Atari ST port of AGI --PDD \n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
\n\
|
||||
0x1A7AF 0x2272 Donald Duck's Playground (ST) 1.0A 8/8/86 \n\
|
||||
0x4A079 0x2272 King's Quest 1 (ST) 1.0V \n\
|
||||
0x882B7 0x2272 King's Quest 3 (ST) 1.02 11/18/86 \n\
|
||||
0xB68AB 0x3149 Gold Rush! (ST) 1.01 1/13/89 aka 2.01 12/22/88 \n\
|
||||
0x6F7E1 0x2440 Leisure Suit Larry 1 (ST) 1.04 6/18/87 \n\
|
||||
0x4CE19 0x3149 Manhunter NY (ST) 1.03 10/20/88 \n\
|
||||
0x5360B 0x3149 Manhunter SF (ST) 1.0 7/29/89 \n\
|
||||
0x69597 0x2440 Space Quest 1 (ST) 1.1A \n\
|
||||
\n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
# Amiga versions \n\
|
||||
# Use option -A- to enable padding \n\
|
||||
# \n\
|
||||
# Notes: \n\
|
||||
# - Amiga KQ3 (2.333) seems to need interpreter version 3.002.086 \n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
\n\
|
||||
0x25640 0x2440 [A] Black Cauldron (Amiga) 2.00 6/14/87 # guessed int \n\
|
||||
0x1AFBA 0x2272 [A] Donald Duck's Playground (Amiga) 1.0C # guessed int \n\
|
||||
0xB3E1A 0x3149 [A] Gold Rush! (Amiga) 1.01 1/13/89 aka 2.05 3/9/89 # 2.316 \n\
|
||||
0x49C6B 0x2440 [A] King's Quest 1 (Amiga) 1.0U # 2.082 \n\
|
||||
0x5D395 0x2440 [A] King's Quest 2 (Amiga) 2.0J # guessed int \n\
|
||||
0x5BCE6 0x2440 [A] King's Quest 2 (Amiga) 2.0J (Broken) \n\
|
||||
0x5F4B9 0x2440 [A] King's Quest 2 (Amiga) 2.0J (Broken) # 2.176 \n\
|
||||
0x888C1 0x2440 [A] King's Quest 3 (Amiga) 1.01 11/8/86 \n\
|
||||
0x84793 0x3086 [A] King's Quest 3 (Amiga) 2.15 11/15/89 # 2.333 \n\
|
||||
0x6FDDB 0x2440 [A] Leisure Suit Larry 1 (Amiga) 1.05 6/26/87 # x.yyy \n\
|
||||
0x4BA94 0x3149 [A] Manhunter NY (Amiga) 1.06 3/18/89 # x.yyy \n\
|
||||
0x53D51 0x3086 [A] Manhunter SF (Amiga) 3.06 8/17/89 # 2.333 \n\
|
||||
0x5CFB1 0x3086 [A] Mixed-Up Mother Goose (Amiga) 1.1 # guessed int \n\
|
||||
0x7F752 0x3149 [A] Police Quest 1 (Amiga) 2.0B 2/22/89 # 2.310 \n\
|
||||
0x696DD 0x2440 [A] Space Quest 1 (Amiga) 1.2 # 2.082 \n\
|
||||
0x8FEA6 0x2936 [A] Space Quest 2 (Amiga) 2.0F # 2.202 \n\
|
||||
\n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
# CoCo versions \n\
|
||||
# what version of DOS AGI does CoCo 2.023 correspond with? \n\
|
||||
# guessing 2.272 because the PC version 1.0 is 2.272; doesn't fit date though \n\
|
||||
# \n\
|
||||
# Notes: \n\
|
||||
# - Chris Iden wrote the CoCo port of AGI --PDD \n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
\n\
|
||||
0x7CBE8 0x2272 King's Quest 3 (CoCo3) 1.0C 6/27/88 # 2.023 \n\
|
||||
0x70D35 0x2440 Leisure Suit Larry 1 (CoCo3) \n\
|
||||
\n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
# AGDS games \n\
|
||||
# Use option -a- for AGDS games \n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
\n\
|
||||
0x5501A 0x2440 [a] Groza # AGDS sample game \n\
|
||||
\n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
# Fan-made AGI games \n\
|
||||
#---------------------------------------------------------------------------- \n\
|
||||
\n\
|
||||
0x3F2F7 0x2917 [m] AGI Mouse 0.7 Demo \n\
|
||||
0x3F744 0x2917 [m] AGI Mouse 1.0 Demo # 2.917 6/24/00 \n\
|
||||
0x3F74F 0x2917 [m] AGI Mouse 1.1 Demo # 2.917 1/01/01 \n\
|
||||
0x17599 0x2917 [m] Sliding Tile Game v1.00 # 2.917 6/02/01 \n\
|
||||
0x785c4 0x2936 [m] Jolimie v0.6 # 2.936 2000 \n\
|
||||
#Jolimie uses AGIPal only and not AGIMouse; no way to separate these currently \n\
|
||||
0x40D80 0x2440 AGI Trek # 2.440 9/21/98 \n\
|
||||
0x64CB7 0x2440 Space Trek 1.0 # 2.440 12/13/98 \n\
|
||||
0x6596A 0x2917 Space Trek (remake) # 2.917 6/09/99 \n\
|
||||
0x96909 0x2917 Operation: RECON teaser 1.1 # \n\
|
||||
0x185A6 0x2917 AGI Piano v1.0 # ? 1998 \n\
|
||||
0x91ACF 0x2917 Dave's Quest .07 # ? \n\
|
||||
0x620F6 0x2917 Time Quest demo D0.2 # ? 1998 \n\
|
||||
0x7466F 0x2917 Tex McPhilip I # ? 2000 \n\
|
||||
0x9E400 0x2917 Tex McPhilip II # ? 2000 \n\
|
||||
0xAB9A8 0x2917 Justin Quest 1.0 # 2.917 \n\
|
||||
0x7D473 0x2917 The Ruby Cast demo 0.2 # 2.917 1998 \n\
|
||||
0xB4D7A 0x2917 Residence 44 Quest 1.0a # 2.917 1999 \n\
|
||||
0x5D077 0x2917 Escape Quest demo # ? 1998 \n\
|
||||
0x5A434 0x2917 Acidopolis (1.0) demo # ? \n\
|
||||
0x45CDF 0x2917 Go West, Young Hippie demo # 2.917 \n\
|
||||
0x4C9DC 0x2917 Speeder Bike Challenge v1.0 # ? \n\
|
||||
0x112BF9 0x2917 Space Quest 0: Replicated 1.04 # 6/27/2003 \n\
|
||||
0x6E70F 0x2917 Space Quest: The Lost Chapter v10.0 \n\
|
||||
0x5859E 0x2917 Phantasmagoria \n\
|
||||
0x7B5DF 0x2917 Dashiki demo \n\
|
||||
0x9405B 0x2917 Dashiki 256-color demo (Unsupported) \n\
|
||||
0x6ADCD 0x2917 Jen's Quest 0.1 demo \n\
|
||||
0x4EE64 0x2917 Monkey Man \n\
|
||||
";
|
||||
|
||||
int setup_v2_game(int ver, uint32 crc);
|
||||
int setup_v3_game(int ver, uint32 crc);
|
||||
int v4id_game(uint32 crc);
|
||||
|
||||
uint32 match_crc(uint32 crc, char *name, int len) {
|
||||
char *c, *t, buf[256];
|
||||
uint32 id, ver;
|
||||
|
||||
Common::MemoryReadStream f((const byte *)ids_database, strlen(ids_database));
|
||||
|
||||
while (!f.eos()) {
|
||||
f.readLine(buf, 256);
|
||||
c = strchr(buf, '#');
|
||||
if (c)
|
||||
*c = 0;
|
||||
|
||||
/* Remove spaces at end of line */
|
||||
if (strlen(buf)) {
|
||||
for (c = buf + strlen(buf) - 1;
|
||||
*c == ' ' || *c == '\t'; *c-- = 0) {
|
||||
}
|
||||
}
|
||||
|
||||
t = strtok(buf, " \t\r\n");
|
||||
if (t == NULL)
|
||||
continue;
|
||||
id = strtoul(t, NULL, 0);
|
||||
|
||||
t = strtok(NULL, " \t\r\n");
|
||||
if (t == NULL)
|
||||
continue;
|
||||
ver = strtoul(t, NULL, 0);
|
||||
|
||||
t = strtok(NULL, "\n\r");
|
||||
for (; *t == ' ' || *t == '\t'; t++);
|
||||
|
||||
if (id == crc) {
|
||||
/* Now we must check options enclosed in brackets
|
||||
* like [A] for Amiga
|
||||
*/
|
||||
|
||||
if (*t == '[') {
|
||||
while (*t != ']') {
|
||||
switch (*t++) {
|
||||
case 'A':
|
||||
opt.amiga = true;
|
||||
break;
|
||||
case 'a':
|
||||
opt.agds = true;
|
||||
break;
|
||||
#ifdef USE_MOUSE
|
||||
case 'm':
|
||||
opt.agimouse = true;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
t++;
|
||||
|
||||
for (; (*t == ' ' || *t == '\t') && *t; t++) {
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(name, t, len);
|
||||
return ver;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32 match_version(uint32 crc) {
|
||||
int ver;
|
||||
char name[80];
|
||||
|
||||
if ((ver = match_crc(crc, name, 80)) > 0)
|
||||
report("AGI game detected: %s\n\n", name);
|
||||
|
||||
return ver;
|
||||
}
|
||||
|
||||
int v2id_game() {
|
||||
int y, ver;
|
||||
uint32 len, c, crc;
|
||||
uint8 *buff;
|
||||
Common::File fp;
|
||||
char *fn[] = { "viewdir", "logdir", "picdir", "snddir", "words.tok", "object", "" };
|
||||
|
||||
buff = (uint8 *)malloc(8192);
|
||||
|
||||
for (crc = y = 0; fn[y][0]; y++) {
|
||||
char *path = fn[y];
|
||||
if (fp.open(path)) {
|
||||
for (len = 1; len > 0;) {
|
||||
memset(buff, 0, 8192);
|
||||
len = fp.read(buff, 8000);
|
||||
for (c = 0; c < len; c++)
|
||||
crc += *(buff + c);
|
||||
}
|
||||
fp.close();
|
||||
}
|
||||
}
|
||||
free(buff);
|
||||
|
||||
report("Computed CRC: 0x%05x\n", crc);
|
||||
ver = match_version(crc);
|
||||
game.crc = crc;
|
||||
game.ver = ver;
|
||||
debugC(2, kDebugLevelMain, "game.ver = 0x%x", game.ver);
|
||||
agi_set_release(ver);
|
||||
return setup_v2_game(ver, crc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently, there is no known difference between v3.002.098 -> v3.002.149
|
||||
* So version emulated;
|
||||
*
|
||||
* 0x0086,
|
||||
* 0x0149
|
||||
*/
|
||||
|
||||
int v3id_game() {
|
||||
int ec = err_OK, y, ver;
|
||||
uint32 len, c, crc;
|
||||
uint8 *buff;
|
||||
Common::File fp;
|
||||
char *fn[] = { "words.tok", "object", "" };
|
||||
Common::String path;
|
||||
|
||||
buff = (uint8 *)malloc(8192);
|
||||
|
||||
for (crc = 0, y = 0; fn[y][0] != 0x0; y++) {
|
||||
path = fn[y];
|
||||
if (fp.open(path)) {
|
||||
len = 1;
|
||||
while (len > 0) {
|
||||
memset(buff, 0, 8192);
|
||||
len = fp.read(buff, 8000);
|
||||
for (c = 0; c < len; c++)
|
||||
crc += *(buff + c);
|
||||
}
|
||||
fp.close();
|
||||
}
|
||||
}
|
||||
|
||||
/* now do the directory file */
|
||||
|
||||
path = Common::String(game.name) + DIR_;
|
||||
|
||||
if (fp.open(path)) {
|
||||
for (len = 1; len > 0;) {
|
||||
memset(buff, 0, 8192);
|
||||
len = fp.read(buff, 8000);
|
||||
for (c = 0; c < len; c++)
|
||||
crc += *(buff + c);
|
||||
}
|
||||
fp.close();
|
||||
}
|
||||
|
||||
free(buff);
|
||||
|
||||
report("Computed CRC: 0x%05x\n", crc);
|
||||
ver = match_version(crc);
|
||||
game.crc = crc;
|
||||
game.ver = ver;
|
||||
agi_set_release(ver);
|
||||
|
||||
ec = setup_v3_game(ver, crc);
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int setup_v2_game(int ver, uint32 crc) {
|
||||
int ec = err_OK;
|
||||
|
||||
if (ver == 0) {
|
||||
report("Unknown v2 Sierra game: %08x\n\n", crc);
|
||||
agi_set_release(0x2917);
|
||||
}
|
||||
|
||||
/* setup the differences in the opcodes and other bits in the
|
||||
* AGI v2 specs
|
||||
*/
|
||||
if (opt.emuversion)
|
||||
agi_set_release(opt.emuversion);
|
||||
|
||||
if (opt.agds)
|
||||
agi_set_release(0x2440); /* ALL AGDS games built for 2.440 */
|
||||
|
||||
switch (agi_get_release()) {
|
||||
case 0x2089:
|
||||
logic_names_cmd[0x86].num_args = 0; /* quit: 0 args */
|
||||
logic_names_cmd[0x97].num_args = 3; /* print.at: 3 args */
|
||||
logic_names_cmd[0x98].num_args = 3; /* print.at.v: 3 args */
|
||||
break;
|
||||
case 0x2272:
|
||||
/* KQ3 0x88673 (2.272) requires print.at with 4 arguments */
|
||||
break;
|
||||
case 0x2440:
|
||||
break;
|
||||
case 0x2917:
|
||||
break;
|
||||
case 0x2936:
|
||||
break;
|
||||
default:
|
||||
report("** Cannot setup for unknown version\n");
|
||||
ec = err_UnknownAGIVersion;
|
||||
break;
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int setup_v3_game(int ver, uint32 crc) {
|
||||
int ec = err_OK;
|
||||
|
||||
if (ver == 0) {
|
||||
report("Unknown v3 Sierra game: %08x\n\n", crc);
|
||||
agi_set_release(ver = 0x3149);
|
||||
}
|
||||
|
||||
if (opt.emuversion)
|
||||
agi_set_release(ver = opt.emuversion);
|
||||
|
||||
switch (ver) {
|
||||
case 0x3086:
|
||||
logic_names_cmd[0xad].num_args = 1; /* 173 : 1 args */
|
||||
break;
|
||||
case 0x3149:
|
||||
logic_names_cmd[0xad].num_args = 0; /* 173 : 0 args */
|
||||
break;
|
||||
default:
|
||||
report("Error: cannot setup for unknown version\n");
|
||||
ec = err_UnknownAGIVersion;
|
||||
break;
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
212
engines/agi/inv.cpp
Normal file
212
engines/agi/inv.cpp
Normal file
@ -0,0 +1,212 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/sprite.h"
|
||||
#include "agi/graphics.h"
|
||||
#include "agi/keyboard.h"
|
||||
#include "agi/text.h"
|
||||
#include "agi/keyboard.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
/*
|
||||
* Messages and coordinates
|
||||
*/
|
||||
|
||||
#define NOTHING_X 16
|
||||
#define NOTHING_Y 3
|
||||
#define NOTHING_MSG "nothing"
|
||||
|
||||
#define ANY_KEY_X 4
|
||||
#define ANY_KEY_Y 24
|
||||
#define ANY_KEY_MSG "Press a key to return to the game"
|
||||
|
||||
#define YOUHAVE_X 11
|
||||
#define YOUHAVE_Y 0
|
||||
#define YOUHAVE_MSG "You are carrying:"
|
||||
|
||||
#define SELECT_X 2
|
||||
#define SELECT_Y 24
|
||||
#define SELECT_MSG "Press ENTER to select, ESC to cancel"
|
||||
|
||||
static uint8 *intobj = NULL;
|
||||
|
||||
static void print_item(int n, int fg, int bg)
|
||||
{
|
||||
print_text(object_name(intobj[n]), 0, n % 2 ? 39 - strlen(object_name(intobj[n])) : 1,
|
||||
(n / 2) + 2, 40, fg, bg);
|
||||
}
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
static int find_item() {
|
||||
int r, c;
|
||||
|
||||
r = mouse.y / CHAR_LINES;
|
||||
c = mouse.x / CHAR_COLS;
|
||||
|
||||
debugC(6, kDebugLevelInventory, "r = %d, c = %d", r, c);
|
||||
|
||||
if (r < 2)
|
||||
return -1;
|
||||
|
||||
return (r - 2) * 2 + (c > 20);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int show_items() {
|
||||
unsigned int x, i;
|
||||
|
||||
for (x = i = 0; x < game.num_objects; x++) {
|
||||
if (object_get_location(x) == EGO_OWNED) {
|
||||
/* add object to our list! */
|
||||
intobj[i] = x;
|
||||
print_item(i, STATUS_FG, STATUS_BG);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
print_text(NOTHING_MSG, 0, NOTHING_X, NOTHING_Y, 40, STATUS_FG, STATUS_BG);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void select_items(int n) {
|
||||
int fsel = 0;
|
||||
|
||||
while (42) {
|
||||
if (n > 0)
|
||||
print_item(fsel, STATUS_BG, STATUS_FG);
|
||||
|
||||
switch (wait_any_key()) {
|
||||
case KEY_ENTER:
|
||||
setvar(V_sel_item, intobj[fsel]);
|
||||
goto exit_select;
|
||||
case KEY_ESCAPE:
|
||||
setvar(V_sel_item, 0xff);
|
||||
goto exit_select;
|
||||
case KEY_UP:
|
||||
if (fsel >= 2)
|
||||
fsel -= 2;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if (fsel + 2 < n)
|
||||
fsel += 2;
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
if (fsel % 2 == 1)
|
||||
fsel--;
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
if (fsel % 2 == 0 && fsel + 1 < n)
|
||||
fsel++;
|
||||
break;
|
||||
#ifdef USE_MOUSE
|
||||
case BUTTON_LEFT:{
|
||||
int i = find_item();
|
||||
if (i >= 0 && i < n) {
|
||||
setvar(V_sel_item, intobj[fsel = i]);
|
||||
debugC(6, kDebugLevelInventory, "item found: %d", fsel);
|
||||
show_items();
|
||||
print_item(fsel, STATUS_BG, STATUS_FG);
|
||||
do_update();
|
||||
goto exit_select;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
show_items();
|
||||
do_update();
|
||||
}
|
||||
|
||||
exit_select:
|
||||
debugC(6, kDebugLevelInventory, "selected: %d", fsel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Display inventory items.
|
||||
*/
|
||||
void inventory() {
|
||||
int old_fg, old_bg;
|
||||
int n;
|
||||
|
||||
/* screen is white with black text */
|
||||
old_fg = game.color_fg;
|
||||
old_bg = game.color_bg;
|
||||
game.color_fg = 0;
|
||||
game.color_bg = 15;
|
||||
clear_screen(game.color_bg);
|
||||
|
||||
print_text(YOUHAVE_MSG, 0, YOUHAVE_X, YOUHAVE_Y, 40, STATUS_FG, STATUS_BG);
|
||||
|
||||
/* FIXME: doesn't check if objects overflow off screen... */
|
||||
|
||||
intobj = (uint8 *) malloc(4 + game.num_objects);
|
||||
memset(intobj, 0, (4 + game.num_objects));
|
||||
|
||||
n = show_items();
|
||||
|
||||
if (getflag(F_status_selects_items)) {
|
||||
print_text(SELECT_MSG, 0, SELECT_X, SELECT_Y, 40, STATUS_FG, STATUS_BG);
|
||||
} else {
|
||||
print_text(ANY_KEY_MSG, 0, ANY_KEY_X, ANY_KEY_Y, 40, STATUS_FG, STATUS_BG);
|
||||
}
|
||||
|
||||
flush_screen();
|
||||
|
||||
/* If flag 13 is set, we want to highlight & select an item.
|
||||
* opon selection, put objnum in var 25. Then on esc put in
|
||||
* var 25 = 0xff.
|
||||
*/
|
||||
|
||||
if (getflag(F_status_selects_items))
|
||||
select_items(n);
|
||||
|
||||
free(intobj);
|
||||
|
||||
if (!getflag(F_status_selects_items))
|
||||
wait_any_key();
|
||||
|
||||
clear_screen(0);
|
||||
write_status();
|
||||
show_pic();
|
||||
game.color_fg = old_fg;
|
||||
game.color_bg = old_bg;
|
||||
game.has_prompt = 0;
|
||||
flush_lines(game.line_user_input, 24);
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
388
engines/agi/keyboard.cpp
Normal file
388
engines/agi/keyboard.cpp
Normal file
@ -0,0 +1,388 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/graphics.h"
|
||||
#include "agi/keyboard.h"
|
||||
#include "agi/menu.h"
|
||||
#include "agi/text.h" /* remove later */
|
||||
|
||||
namespace Agi {
|
||||
|
||||
char last_sentence[40];
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
extern struct agi_console console;
|
||||
#endif
|
||||
|
||||
/* FIXME */
|
||||
extern int open_dialogue;
|
||||
|
||||
struct string_data {
|
||||
int x;
|
||||
int y;
|
||||
int len;
|
||||
int str;
|
||||
};
|
||||
|
||||
struct string_data stringdata;
|
||||
|
||||
/*
|
||||
* IBM-PC keyboard scancodes
|
||||
*/
|
||||
uint8 scancode_table[26] = {
|
||||
30, /* A */
|
||||
48, /* B */
|
||||
46, /* C */
|
||||
32, /* D */
|
||||
18, /* E */
|
||||
33, /* F */
|
||||
34, /* G */
|
||||
35, /* H */
|
||||
23, /* I */
|
||||
36, /* J */
|
||||
37, /* K */
|
||||
38, /* L */
|
||||
50, /* M */
|
||||
49, /* N */
|
||||
24, /* O */
|
||||
25, /* P */
|
||||
16, /* Q */
|
||||
19, /* R */
|
||||
31, /* S */
|
||||
20, /* T */
|
||||
22, /* U */
|
||||
47, /* V */
|
||||
17, /* W */
|
||||
45, /* X */
|
||||
21, /* Y */
|
||||
44 /* Z */
|
||||
};
|
||||
|
||||
void init_words() {
|
||||
game.num_ego_words = 0;
|
||||
}
|
||||
|
||||
void clean_input() {
|
||||
while (game.num_ego_words)
|
||||
free(game.ego_words[--game.num_ego_words].word);
|
||||
}
|
||||
|
||||
void get_string(int x, int y, int len, int str) {
|
||||
new_input_mode(INPUT_GETSTRING);
|
||||
stringdata.x = x;
|
||||
stringdata.y = y;
|
||||
stringdata.len = len;
|
||||
stringdata.str = str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw key grabber.
|
||||
* poll_keyboard() is the raw key grabber (above the gfx driver, that is).
|
||||
* It handles console keys and insulates AGI from the console. In the main
|
||||
* loop, handle_keys() handles keyboard input and ego movement.
|
||||
*/
|
||||
int do_poll_keyboard() {
|
||||
int key = 0;
|
||||
|
||||
/* If a key is ready, rip it */
|
||||
if (keypress()) {
|
||||
key = get_key();
|
||||
debugC(3, kDebugLevelInput, "key %02x pressed", key);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
int handle_controller(int key) {
|
||||
struct vt_entry *v = &game.view_table[0];
|
||||
int i;
|
||||
|
||||
/* The Black Cauldron needs KEY_ESCAPE to use menus */
|
||||
if (key == 0 /*|| key == KEY_ESCAPE */ )
|
||||
return false;
|
||||
|
||||
debugC(3, kDebugLevelInput, "key = %04x", key);
|
||||
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
if (game.ev_keyp[i].data == key) {
|
||||
debugC(3, kDebugLevelInput, "event %d: key press", i);
|
||||
game.ev_keyp[i].occured = true;
|
||||
report("event AC:%i occured\n", i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
if (key == BUTTON_LEFT) {
|
||||
if (getflag(F_menus_work) && mouse.y <= CHAR_LINES) {
|
||||
new_input_mode(INPUT_MENU);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (game.player_control) {
|
||||
int d = 0;
|
||||
|
||||
if (!KEY_ASCII(key)) {
|
||||
switch (key) {
|
||||
case KEY_UP:
|
||||
d = 1;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
d = 5;
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
d = 7;
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
d = 3;
|
||||
break;
|
||||
case KEY_UP_RIGHT:
|
||||
d = 2;
|
||||
break;
|
||||
case KEY_DOWN_RIGHT:
|
||||
d = 4;
|
||||
break;
|
||||
case KEY_UP_LEFT:
|
||||
d = 8;
|
||||
break;
|
||||
case KEY_DOWN_LEFT:
|
||||
d = 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef USE_MOUSE
|
||||
if (!opt.agimouse) {
|
||||
/* Handle mouse button events */
|
||||
if (key == BUTTON_LEFT) {
|
||||
v->flags |= ADJ_EGO_XY;
|
||||
v->parm1 = WIN_TO_PIC_X(mouse.x);
|
||||
v->parm2 = WIN_TO_PIC_Y(mouse.y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
v->flags &= ~ADJ_EGO_XY;
|
||||
|
||||
if (d || key == KEY_STATIONARY) {
|
||||
v->direction = v->direction == d ? 0 : d;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void handle_getstring(int key) {
|
||||
static int pos = 0; /* Cursor position */
|
||||
static char buf[40];
|
||||
|
||||
if (KEY_ASCII(key) == 0)
|
||||
return;
|
||||
|
||||
debugC(3, kDebugLevelInput, "handling key: %02x", key);
|
||||
|
||||
switch (key) {
|
||||
case KEY_ENTER:
|
||||
debugC(3, kDebugLevelInput, "KEY_ENTER");
|
||||
game.has_prompt = 0;
|
||||
buf[pos] = 0;
|
||||
strcpy(game.strings[stringdata.str], buf);
|
||||
debugC(3, kDebugLevelInput, "buffer=[%s]", buf);
|
||||
buf[pos = 0] = 0;
|
||||
new_input_mode(INPUT_NORMAL);
|
||||
print_character(stringdata.x + strlen(game.strings[stringdata.str]) + 1,
|
||||
stringdata.y, ' ', game.color_fg, game.color_bg);
|
||||
return;
|
||||
case KEY_ESCAPE:
|
||||
debugC(3, kDebugLevelInput, "KEY_ESCAPE");
|
||||
game.has_prompt = 0;
|
||||
buf[pos = 0] = 0;
|
||||
strcpy(game.strings[stringdata.str], buf);
|
||||
new_input_mode(INPUT_NORMAL);
|
||||
/* new_input_mode (INPUT_MENU); */
|
||||
break;
|
||||
case KEY_BACKSPACE: /*0x08: */
|
||||
if (!pos)
|
||||
break;
|
||||
|
||||
print_character(stringdata.x + (pos + 1), stringdata.y,
|
||||
' ', game.color_fg, game.color_bg);
|
||||
|
||||
pos--;
|
||||
buf[pos] = 0;
|
||||
break;
|
||||
default:
|
||||
if (key < 0x20 || key > 0x7f)
|
||||
break;
|
||||
|
||||
if (pos >= stringdata.len)
|
||||
break;
|
||||
|
||||
buf[pos++] = key;
|
||||
buf[pos] = 0;
|
||||
|
||||
/* Echo */
|
||||
print_character(stringdata.x + pos, stringdata.y, buf[pos - 1],
|
||||
game.color_fg, game.color_bg);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* print cursor */
|
||||
print_character(stringdata.x + pos + 1, stringdata.y,
|
||||
(char)game.cursor_char, game.color_fg, game.color_bg);
|
||||
}
|
||||
|
||||
void handle_keys(int key) {
|
||||
uint8 *p = NULL;
|
||||
int c = 0;
|
||||
static uint8 formated_entry[256];
|
||||
int l = game.line_user_input;
|
||||
int fg = game.color_fg, bg = game.color_bg;
|
||||
|
||||
setvar(V_word_not_found, 0);
|
||||
|
||||
debugC(3, kDebugLevelInput, "handling key: %02x", key);
|
||||
|
||||
switch (key) {
|
||||
case KEY_ENTER:
|
||||
debugC(3, kDebugLevelInput, "KEY_ENTER");
|
||||
game.keypress = 0;
|
||||
|
||||
/* Remove all leading spaces */
|
||||
for (p = game.input_buffer; *p && *p == 0x20; p++);
|
||||
|
||||
/* Copy to internal buffer */
|
||||
for (; *p; p++) {
|
||||
/* Squash spaces */
|
||||
if (*p == 0x20 && *(p + 1) == 0x20) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
formated_entry[c++] = tolower(*p);
|
||||
}
|
||||
formated_entry[c++] = 0;
|
||||
|
||||
/* Handle string only if it's not empty */
|
||||
if (formated_entry[0]) {
|
||||
strcpy((char *)game.echo_buffer, (const char *)game.input_buffer);
|
||||
strcpy(last_sentence, (const char *)formated_entry);
|
||||
dictionary_words(last_sentence);
|
||||
}
|
||||
|
||||
/* Clear to start a new line */
|
||||
game.has_prompt = 0;
|
||||
game.input_buffer[game.cursor_pos = 0] = 0;
|
||||
debugC(3, kDebugLevelInput, "clear lines");
|
||||
clear_lines(l, l + 1, bg);
|
||||
flush_lines(l, l + 1);
|
||||
|
||||
break;
|
||||
case KEY_ESCAPE:
|
||||
debugC(3, kDebugLevelInput, "KEY_ESCAPE");
|
||||
new_input_mode(INPUT_MENU);
|
||||
break;
|
||||
case KEY_BACKSPACE:
|
||||
/* Ignore backspace at start of line */
|
||||
if (game.cursor_pos == 0)
|
||||
break;
|
||||
|
||||
/* erase cursor */
|
||||
print_character(game.cursor_pos + 1, l, ' ', fg, bg);
|
||||
game.input_buffer[--game.cursor_pos] = 0;
|
||||
/* Print cursor */
|
||||
print_character(game.cursor_pos + 1, l, game.cursor_char, fg, bg);
|
||||
break;
|
||||
default:
|
||||
/* Ignore invalid keystrokes */
|
||||
if (key < 0x20 || key > 0x7f)
|
||||
break;
|
||||
|
||||
/* Maximum input size reached */
|
||||
if (game.cursor_pos >= getvar(V_max_input_chars))
|
||||
break;
|
||||
|
||||
game.input_buffer[game.cursor_pos++] = key;
|
||||
game.input_buffer[game.cursor_pos] = 0;
|
||||
|
||||
/* echo */
|
||||
print_character(game.cursor_pos, l, game.input_buffer[game.cursor_pos - 1], fg, bg);
|
||||
|
||||
/* Print cursor */
|
||||
print_character(game.cursor_pos + 1, l, game.cursor_char, fg, bg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int wait_key() {
|
||||
int key;
|
||||
|
||||
/* clear key queue */
|
||||
while (keypress()) {
|
||||
get_key();
|
||||
}
|
||||
|
||||
debugC(3, kDebugLevelInput, "waiting...");
|
||||
while (42) {
|
||||
poll_timer(); /* msdos driver -> does nothing */
|
||||
key = do_poll_keyboard();
|
||||
if (!console_keyhandler(key)) {
|
||||
if (key == KEY_ENTER || key == KEY_ESCAPE
|
||||
#ifdef USE_MOUSE
|
||||
|| key == BUTTON_LEFT
|
||||
#endif
|
||||
)
|
||||
break;
|
||||
}
|
||||
console_cycle();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
int wait_any_key() {
|
||||
int key;
|
||||
|
||||
/* clear key queue */
|
||||
while (keypress()) {
|
||||
get_key();
|
||||
}
|
||||
|
||||
debugC(3, kDebugLevelInput, "waiting...");
|
||||
while (42) {
|
||||
poll_timer(); /* msdos driver -> does nothing */
|
||||
key = do_poll_keyboard();
|
||||
if (!console_keyhandler(key) && key)
|
||||
break;
|
||||
console_cycle();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
94
engines/agi/keyboard.h
Normal file
94
engines/agi/keyboard.h
Normal file
@ -0,0 +1,94 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_KEYBOARD_H
|
||||
#define __AGI_KEYBOARD_H
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
/* QNX4 has a KEY_DOWN defined which we don't need to care about */
|
||||
#undef KEY_DOWN
|
||||
|
||||
/* Allegro defines these */
|
||||
#undef KEY_BACKSPACE
|
||||
#undef KEY_ENTER
|
||||
#undef KEY_LEFT
|
||||
#undef KEY_RIGHT
|
||||
#undef KEY_UP
|
||||
#undef KEY_PGUP
|
||||
#undef KEY_PGDN
|
||||
#undef KEY_HOME
|
||||
#undef KEY_END
|
||||
|
||||
#define KEY_BACKSPACE 0x08
|
||||
#define KEY_ESCAPE 0x1B
|
||||
#define KEY_ENTER 0x0D
|
||||
#define KEY_UP 0x4800
|
||||
#define KEY_DOWN 0x5000
|
||||
#define KEY_LEFT 0x4B00
|
||||
#define KEY_STATIONARY 0x4C00
|
||||
#define KEY_RIGHT 0x4D00
|
||||
|
||||
#define KEY_DOWN_LEFT 0x4F00
|
||||
#define KEY_DOWN_RIGHT 0x5100
|
||||
#define KEY_UP_LEFT 0x4700
|
||||
#define KEY_UP_RIGHT 0x4900
|
||||
|
||||
#define KEY_STATUSLN 0xd900 /* F11 */
|
||||
#define KEY_PRIORITY 0xda00 /* F12 */
|
||||
|
||||
#define KEY_PGUP 0x4900 /* Page Up (fixed by Ziv Barber) */
|
||||
#define KEY_PGDN 0x5100 /* Page Down */
|
||||
#define KEY_HOME 0x4700 /* Home */
|
||||
#define KEY_END 0x4f00 /* End * */
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
#define BUTTON_LEFT 0xF101 /* Left mouse button */
|
||||
#define BUTTON_RIGHT 0xF202 /* Right mouse button */
|
||||
#endif
|
||||
|
||||
#define KEY_SCAN(k) (k >> 8)
|
||||
#define KEY_ASCII(k) (k & 0xff)
|
||||
|
||||
extern uint8 scancode_table[];
|
||||
|
||||
void init_words(void);
|
||||
void clean_input(void);
|
||||
int do_poll_keyboard(void);
|
||||
void clean_keyboard(void);
|
||||
void handle_keys(int);
|
||||
void handle_getstring(int);
|
||||
int handle_controller(int);
|
||||
void get_string(int, int, int, int);
|
||||
uint16 agi_get_keypress(void);
|
||||
int wait_key(void);
|
||||
int wait_any_key(void);
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif /* __AGI_KEYBOARD_H */
|
140
engines/agi/list.h
Normal file
140
engines/agi/list.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* List management macros from the Linux kernel
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_LIST_H
|
||||
#define _LINUX_LIST_H
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
/**
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static INLINE void __list_add(struct list_head *tnew, struct list_head *prev, struct list_head *next) {
|
||||
next->prev = tnew;
|
||||
tnew->next = next;
|
||||
tnew->prev = prev;
|
||||
prev->next = tnew;
|
||||
}
|
||||
|
||||
/**
|
||||
* add a new entry
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*
|
||||
* @param new new entry to be added
|
||||
* @param head list head to add it after
|
||||
*/
|
||||
static INLINE void list_add(struct list_head *tnew, struct list_head *head) {
|
||||
__list_add(tnew, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* add a new entry
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*/
|
||||
static INLINE void list_add_tail(struct list_head *tnew, struct list_head *head) {
|
||||
__list_add(tnew, head->prev, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a list entry (makes prev/next entries point to each other)
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static INLINE void __list_del(struct list_head *prev, struct list_head *next) {
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes entry from list.
|
||||
* @param entry the element to delete from the list.
|
||||
*/
|
||||
static INLINE void list_del(struct list_head *entry) {
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* tests whether a list is empty
|
||||
* @param head the list to test.
|
||||
*/
|
||||
static INLINE int list_empty(struct list_head *head) {
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* join two lists
|
||||
* @param list the new list to add.
|
||||
* @param head the place to add it in the first list.
|
||||
*/
|
||||
static INLINE void list_splice(struct list_head *list, struct list_head *head) {
|
||||
struct list_head *first = list->next;
|
||||
|
||||
if (first != list) {
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the struct for this entry
|
||||
* @param ptr the &struct list_head pointer.
|
||||
* @param type the type of the struct this is embedded in.
|
||||
* @param member the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* iterate over a list
|
||||
* @param pos the &struct list_head to use as a loop counter.
|
||||
* @param head the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head, next) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif
|
116
engines/agi/logic.cpp
Normal file
116
engines/agi/logic.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
/**
|
||||
* Decode logic resource
|
||||
* This function decodes messages from the specified raw logic resource
|
||||
* into a message list.
|
||||
* @param n The number of the logic resource to decode.
|
||||
*/
|
||||
int decode_logic(int n) {
|
||||
int ec = err_OK;
|
||||
int mstart, mend, mc;
|
||||
uint8 *m0;
|
||||
|
||||
/* decrypt messages at end of logic + build message list */
|
||||
|
||||
/* report ("decoding logic #%d\n", n); */
|
||||
m0 = game.logics[n].data;
|
||||
|
||||
mstart = READ_LE_UINT16(m0) + 2;
|
||||
mc = *(m0 + mstart);
|
||||
mend = READ_LE_UINT16(m0 + mstart + 1);
|
||||
m0 += mstart + 3; /* cover header info */
|
||||
mstart = mc << 1;
|
||||
|
||||
/* if the logic was not compressed, decrypt the text messages
|
||||
* only if there are more than 0 messages
|
||||
*/
|
||||
if ((~game.dir_logic[n].flags & RES_COMPRESSED) && mc > 0)
|
||||
decrypt(m0 + mstart, mend - mstart); /* decrypt messages */
|
||||
|
||||
/* build message list */
|
||||
m0 = game.logics[n].data;
|
||||
mstart = READ_LE_UINT16(m0) + 2; /* +2 covers pointer */
|
||||
game.logics[n].num_texts = *(m0 + mstart);
|
||||
|
||||
/* resetp logic pointers */
|
||||
game.logics[n].sIP = 2;
|
||||
game.logics[n].cIP = 2;
|
||||
game.logics[n].size = READ_LE_UINT16(m0) + 2; /* logic end pointer */
|
||||
|
||||
/* allocate list of pointers to point into our data */
|
||||
|
||||
game.logics[n].texts = (char **)calloc(1 + game.logics[n].num_texts, sizeof(char *));
|
||||
|
||||
/* cover header info */
|
||||
m0 += mstart + 3;
|
||||
|
||||
if (game.logics[n].texts != NULL) {
|
||||
/* move list of strings into list to make real pointers */
|
||||
for (mc = 0; mc < game.logics[n].num_texts; mc++) {
|
||||
mend = READ_LE_UINT16(m0 + mc * 2);
|
||||
game.logics[n].texts[mc] = mend ? (char *)m0 + mend - 2 : (char *)"";
|
||||
}
|
||||
/* set loaded flag now its all completly loaded */
|
||||
game.dir_logic[n].flags |= RES_LOADED;
|
||||
} else {
|
||||
/* unload data
|
||||
* blah DF YA WANKER!!@!@# frag. i'm so dumb. not every logic
|
||||
* has text
|
||||
*/
|
||||
free(game.logics[n].data);
|
||||
ec = err_NotEnoughMemory;
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unload logic resource
|
||||
* This function unloads the specified logic resource, freeing any
|
||||
* memory chunks allocated for this resource.
|
||||
* @param n The number of the logic resource to unload
|
||||
*/
|
||||
void unload_logic(int n) {
|
||||
if (game.dir_logic[n].flags & RES_LOADED) {
|
||||
free(game.logics[n].data);
|
||||
if (game.logics[n].num_texts)
|
||||
free(game.logics[n].texts);
|
||||
game.logics[n].num_texts = 0;
|
||||
game.dir_logic[n].flags &= ~RES_LOADED;
|
||||
}
|
||||
|
||||
/* if cached, we end up here */
|
||||
game.logics[n].sIP = 2;
|
||||
game.logics[n].cIP = 2;
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
49
engines/agi/logic.h
Normal file
49
engines/agi/logic.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_LOGIC_H
|
||||
#define __AGI_LOGIC_H
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
/**
|
||||
* AGI logic resource structure.
|
||||
*/
|
||||
struct agi_logic {
|
||||
uint8 *data; /**< raw resource data */
|
||||
int size; /**< size of data */
|
||||
int sIP; /**< saved IP */
|
||||
int cIP; /**< current IP */
|
||||
int num_texts; /**< number of messages */
|
||||
char **texts; /**< message list */
|
||||
};
|
||||
|
||||
int decode_logic(int);
|
||||
void unload_logic(int);
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif /* __AGI_LOGIC_H */
|
191
engines/agi/lzw.cpp
Normal file
191
engines/agi/lzw.cpp
Normal file
@ -0,0 +1,191 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
** decomp.c
|
||||
**
|
||||
** Routines that deal with AGI version 3 specific features.
|
||||
** The original LZW code is from DJJ, October 1989, p.86.
|
||||
** It has been modified to handle AGI compression.
|
||||
**
|
||||
** (c) 1997 Lance Ewing
|
||||
***************************************************************************/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/lzw.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#define MAXBITS 12
|
||||
#define TABLE_SIZE 18041 /* strange number */
|
||||
#define START_BITS 9
|
||||
|
||||
static int32 BITS, MAX_VALUE, MAX_CODE;
|
||||
static uint32 *prefix_code;
|
||||
static uint8 *append_character;
|
||||
static uint8 *decode_stack;
|
||||
static int32 input_bit_count = 0; /* Number of bits in input bit buffer */
|
||||
static uint32 input_bit_buffer = 0L;
|
||||
|
||||
static void initLZW() {
|
||||
decode_stack = (uint8 *)calloc(1, 8192);
|
||||
prefix_code = (uint32 *)malloc(TABLE_SIZE * sizeof(uint32));
|
||||
append_character = (uint8 *)malloc(TABLE_SIZE * sizeof(uint8));
|
||||
input_bit_count = 0; /* Number of bits in input bit buffer */
|
||||
input_bit_buffer = 0L;
|
||||
}
|
||||
|
||||
static void closeLZW() {
|
||||
free(decode_stack);
|
||||
free(prefix_code);
|
||||
free(append_character);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** setBITS
|
||||
**
|
||||
** Purpose: To adjust the number of bits used to store codes to the value
|
||||
** passed in.
|
||||
***************************************************************************/
|
||||
int setBITS(int32 value) {
|
||||
if (value == MAXBITS)
|
||||
return true;
|
||||
|
||||
BITS = value;
|
||||
MAX_VALUE = (1 << BITS) - 1;
|
||||
MAX_CODE = MAX_VALUE - 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** decode_string
|
||||
**
|
||||
** Purpose: To return the string that the code taken from the input buffer
|
||||
** represents. The string is returned as a stack, i.e. the characters are
|
||||
** in reverse order.
|
||||
***************************************************************************/
|
||||
static uint8 *decode_string(uint8 *buffer, uint32 code) {
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; code > 255;) {
|
||||
*buffer++ = append_character[code];
|
||||
code = prefix_code[code];
|
||||
if (i++ >= 4000) {
|
||||
fprintf(stderr, "lzw: error in code expansion.\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
*buffer = code;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** input_code
|
||||
**
|
||||
** Purpose: To return the next code from the input buffer.
|
||||
***************************************************************************/
|
||||
static uint32 input_code(uint8 **input) {
|
||||
uint32 r;
|
||||
|
||||
while (input_bit_count <= 24) {
|
||||
input_bit_buffer |= (uint32) * (*input)++ << input_bit_count;
|
||||
input_bit_count += 8;
|
||||
}
|
||||
r = (input_bit_buffer & 0x7FFF) % (1 << BITS);
|
||||
input_bit_buffer >>= BITS;
|
||||
input_bit_count -= BITS;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** expand
|
||||
**
|
||||
** Purpose: To uncompress the data contained in the input buffer and store
|
||||
** the result in the output buffer. The fileLength parameter says how
|
||||
** many bytes to uncompress. The compression itself is a form of LZW that
|
||||
** adjusts the number of bits that it represents its codes in as it fills
|
||||
** up the available codes. Two codes have special meaning:
|
||||
**
|
||||
** code 256 = start over
|
||||
** code 257 = end of data
|
||||
***************************************************************************/
|
||||
void LZW_expand(uint8 *in, uint8 *out, int32 len) {
|
||||
int32 c, lzwnext, lzwnew, lzwold;
|
||||
uint8 *s, *end;
|
||||
|
||||
initLZW();
|
||||
|
||||
setBITS(START_BITS); /* Starts at 9-bits */
|
||||
lzwnext = 257; /* Next available code to define */
|
||||
|
||||
end = (unsigned char *)((long)out + (long)len);
|
||||
|
||||
lzwold = input_code(&in); /* Read in the first code */
|
||||
c = lzwold;
|
||||
lzwnew = input_code(&in);
|
||||
|
||||
while ((out < end) && (lzwnew != 0x101)) {
|
||||
if (lzwnew == 0x100) {
|
||||
/* Code to "start over" */
|
||||
lzwnext = 258;
|
||||
setBITS(START_BITS);
|
||||
lzwold = input_code(&in);
|
||||
c = lzwold;
|
||||
*out++ = (char)c;
|
||||
lzwnew = input_code(&in);
|
||||
} else {
|
||||
if (lzwnew >= lzwnext) {
|
||||
/* Handles special LZW scenario */
|
||||
*decode_stack = c;
|
||||
s = decode_string(decode_stack + 1, lzwold);
|
||||
} else
|
||||
s = decode_string(decode_stack, lzwnew);
|
||||
|
||||
/* Reverse order of decoded string and
|
||||
* store in out buffer
|
||||
*/
|
||||
c = *s;
|
||||
while (s >= decode_stack)
|
||||
*out++ = *s--;
|
||||
|
||||
if (lzwnext > MAX_CODE)
|
||||
setBITS(BITS + 1);
|
||||
|
||||
prefix_code[lzwnext] = lzwold;
|
||||
append_character[lzwnext] = c;
|
||||
lzwnext++;
|
||||
lzwold = lzwnew;
|
||||
|
||||
lzwnew = input_code(&in);
|
||||
}
|
||||
}
|
||||
closeLZW();
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
33
engines/agi/lzw.h
Normal file
33
engines/agi/lzw.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_LZW_H
|
||||
#define __AGI_LZW_H
|
||||
|
||||
namespace Agi {
|
||||
|
||||
void LZW_expand(uint8 *, uint8 *, int32);
|
||||
|
||||
} // End of namespace Agi
|
||||
#endif
|
503
engines/agi/menu.cpp
Normal file
503
engines/agi/menu.cpp
Normal file
@ -0,0 +1,503 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2002 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/sprite.h"
|
||||
#include "agi/graphics.h"
|
||||
#include "agi/keyboard.h"
|
||||
#include "agi/menu.h"
|
||||
#include "agi/text.h"
|
||||
#include "agi/list.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
struct agi_menu {
|
||||
struct list_head list; /**< list head for menubar list */
|
||||
struct list_head down; /**< list head for menu options */
|
||||
int index; /**< number of menu in menubar */
|
||||
int width; /**< width of menu in characters */
|
||||
int height; /**< height of menu in characters */
|
||||
int col; /**< column of menubar entry */
|
||||
int wincol; /**< column of menu window */
|
||||
char *text; /**< menu name */
|
||||
};
|
||||
|
||||
struct agi_menu_option {
|
||||
struct list_head list; /**< list head for menu options */
|
||||
int enabled; /**< option is enabled or disabled */
|
||||
int event; /**< menu event */
|
||||
int index; /**< number of option in this menu */
|
||||
char *text; /**< text of menu option */
|
||||
};
|
||||
|
||||
static LIST_HEAD(menubar);
|
||||
|
||||
static int h_cur_menu;
|
||||
static int v_cur_menu;
|
||||
|
||||
static struct agi_menu *get_menu(int i) {
|
||||
struct list_head *h;
|
||||
struct agi_menu *m;
|
||||
|
||||
list_for_each(h, &menubar, next) {
|
||||
m = list_entry(h, struct agi_menu, list);
|
||||
if (m->index == i)
|
||||
return m;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct agi_menu_option *get_menu_option(int i, int j) {
|
||||
struct list_head *h;
|
||||
struct agi_menu *m;
|
||||
struct agi_menu_option *d;
|
||||
|
||||
m = get_menu(i);
|
||||
|
||||
list_for_each(h, &m->down, next) {
|
||||
d = list_entry(h, struct agi_menu_option, list);
|
||||
if (d->index == j)
|
||||
return d;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void draw_menu_bar() {
|
||||
struct list_head *h;
|
||||
struct agi_menu *m;
|
||||
|
||||
clear_lines(0, 0, MENU_BG);
|
||||
flush_lines(0, 0);
|
||||
|
||||
list_for_each(h, &menubar, next) {
|
||||
m = list_entry(h, struct agi_menu, list);
|
||||
print_text(m->text, 0, m->col, 0, 40, MENU_FG, MENU_BG);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void draw_menu_hilite(int cur_menu) {
|
||||
struct agi_menu *m;
|
||||
|
||||
m = get_menu(cur_menu);
|
||||
debugC(6, kDebugLevelMenu, "[%s]", m->text);
|
||||
print_text(m->text, 0, m->col, 0, 40, MENU_BG, MENU_FG);
|
||||
flush_lines(0, 0);
|
||||
}
|
||||
|
||||
/* draw box and pulldowns. */
|
||||
static void draw_menu_option(int h_menu) {
|
||||
struct list_head *h;
|
||||
struct agi_menu *m = NULL;
|
||||
struct agi_menu_option *d = NULL;
|
||||
|
||||
/* find which vertical menu it is */
|
||||
m = get_menu(h_menu);
|
||||
|
||||
draw_box(m->wincol * CHAR_COLS, 1 * CHAR_LINES, (m->wincol + m->width + 2) * CHAR_COLS,
|
||||
(1 + m->height + 2) * CHAR_LINES, MENU_BG, MENU_LINE, 0);
|
||||
|
||||
list_for_each(h, &m->down, next) {
|
||||
d = list_entry(h, struct agi_menu_option, list);
|
||||
print_text(d->text, 0, m->wincol + 1, d->index + 2, m->width + 2,
|
||||
d->enabled ? MENU_FG : MENU_DISABLED, MENU_BG);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_menu_option_hilite(int h_menu, int v_menu) {
|
||||
struct agi_menu *m;
|
||||
struct agi_menu_option *d;
|
||||
|
||||
m = get_menu(h_menu);
|
||||
d = get_menu_option(h_menu, v_menu);
|
||||
|
||||
print_text(d->text, 0, m->wincol + 1, v_menu + 2, m->width + 2,
|
||||
MENU_BG, d->enabled ? MENU_FG : MENU_DISABLED);
|
||||
}
|
||||
|
||||
static void new_menu_selected(int i) {
|
||||
show_pic();
|
||||
draw_menu_bar();
|
||||
draw_menu_hilite(i);
|
||||
draw_menu_option(i);
|
||||
}
|
||||
|
||||
#ifdef USE_MOUSE
|
||||
static int mouse_over_text(unsigned int line, unsigned int col, char *s) {
|
||||
if (mouse.x < col * CHAR_COLS)
|
||||
return false;
|
||||
|
||||
if (mouse.x > (col + strlen(s)) * CHAR_COLS)
|
||||
return false;
|
||||
|
||||
if (mouse.y < line * CHAR_LINES)
|
||||
return false;
|
||||
|
||||
if (mouse.y >= (line + 1) * CHAR_LINES)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int h_index;
|
||||
static int v_index;
|
||||
static int h_col;
|
||||
static int h_max_menu;
|
||||
static int v_max_menu[10];
|
||||
|
||||
#if 0
|
||||
static void add_about_option() {
|
||||
struct agi_menu *m;
|
||||
struct agi_menu_option *d;
|
||||
char text[] = "About AGI engine";
|
||||
|
||||
d = malloc(sizeof(struct agi_menu_option));
|
||||
d->text = strdup(text);
|
||||
d->enabled = true;
|
||||
d->event = 255;
|
||||
d->index = (v_max_menu[0] += 1);
|
||||
|
||||
m = list_entry(menubar.next, struct agi_menu, list);
|
||||
list_add_tail(&d->list, &m->down);
|
||||
m->height++;
|
||||
if (m->width < strlen(text))
|
||||
m->width = strlen(text);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
void menu_init() {
|
||||
h_index = 0;
|
||||
h_col = 1;
|
||||
h_cur_menu = 0;
|
||||
v_cur_menu = 0;
|
||||
}
|
||||
|
||||
void menu_deinit() {
|
||||
struct list_head *h, *h2, *v, *v2;
|
||||
struct agi_menu *m = NULL;
|
||||
struct agi_menu_option *d = NULL;
|
||||
|
||||
for (h = (&menubar)->prev; h != (&menubar); h = h2) {
|
||||
m = list_entry(h, struct agi_menu, list);
|
||||
h2 = h->prev;
|
||||
debugC(3, kDebugLevelMenu, "deiniting hmenu %s", m->text);
|
||||
for (v = (&m->down)->prev; v != (&m->down); v = v2) {
|
||||
d = list_entry(v, struct agi_menu_option, list);
|
||||
v2 = v->prev;
|
||||
debugC(3, kDebugLevelMenu, " deiniting vmenu %s", d->text);
|
||||
list_del(v);
|
||||
free(d->text);
|
||||
free(d);
|
||||
}
|
||||
list_del(h);
|
||||
free(m->text);
|
||||
free(m);
|
||||
}
|
||||
}
|
||||
|
||||
void menu_add(char *s) {
|
||||
struct agi_menu *m;
|
||||
|
||||
m = (agi_menu *) malloc(sizeof(struct agi_menu));
|
||||
m->text = strdup(s);
|
||||
while (m->text[strlen(m->text) - 1] == ' ')
|
||||
m->text[strlen(m->text) - 1] = 0;
|
||||
m->down.next = &m->down;
|
||||
m->down.prev = &m->down;
|
||||
m->width = 0;
|
||||
m->height = 0;
|
||||
m->index = h_index++;
|
||||
m->col = h_col;
|
||||
m->wincol = h_col - 1;
|
||||
v_index = 0;
|
||||
v_max_menu[m->index] = 0;
|
||||
h_col += strlen(m->text) + 1;
|
||||
h_max_menu = m->index;
|
||||
|
||||
debugC(3, kDebugLevelMenu, "add menu: '%s' %02x", s, m->text[strlen(m->text)]);
|
||||
list_add_tail(&m->list, &menubar);
|
||||
}
|
||||
|
||||
void menu_add_item(char *s, int code) {
|
||||
struct agi_menu *m;
|
||||
struct agi_menu_option *d;
|
||||
int l;
|
||||
|
||||
d = (agi_menu_option *) malloc(sizeof(struct agi_menu_option));
|
||||
d->text = strdup(s);
|
||||
d->enabled = true;
|
||||
d->event = code;
|
||||
d->index = v_index++;
|
||||
|
||||
m = list_entry(menubar.prev, struct agi_menu, list);
|
||||
m->height++;
|
||||
|
||||
v_max_menu[m->index] = d->index;
|
||||
|
||||
l = strlen(d->text);
|
||||
if (l > 40)
|
||||
l = 38;
|
||||
if (m->wincol + l > 38)
|
||||
m->wincol = 38 - l;
|
||||
if (l > m->width)
|
||||
m->width = l;
|
||||
|
||||
debugC(3, kDebugLevelMenu, "Adding menu item: %s (size = %d)", s, m->height);
|
||||
list_add_tail(&d->list, &m->down);
|
||||
}
|
||||
|
||||
void menu_submit() {
|
||||
struct list_head *h, *h2;
|
||||
struct agi_menu *m = NULL;
|
||||
|
||||
debugC(3, kDebugLevelMenu, "Submitting menu");
|
||||
|
||||
/* add_about_option (); */
|
||||
|
||||
/* If a menu has no options, delete it */
|
||||
for (h = (&menubar)->prev; h != (&menubar); h = h2) {
|
||||
m = list_entry(h, struct agi_menu, list);
|
||||
h2 = h->prev;
|
||||
if ((&m->down)->prev == (&m->down)) {
|
||||
list_del(h);
|
||||
free(m->text);
|
||||
free(m);
|
||||
h_max_menu--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int menu_keyhandler(int key) {
|
||||
static int clock_val;
|
||||
static int menu_active = false;
|
||||
struct agi_menu_option *d;
|
||||
struct list_head *h;
|
||||
struct agi_menu *m;
|
||||
static int button_used = 0;
|
||||
|
||||
if (!getflag(F_menus_work))
|
||||
return false;
|
||||
|
||||
if (!menu_active) {
|
||||
clock_val = game.clock_enabled;
|
||||
game.clock_enabled = false;
|
||||
draw_menu_bar();
|
||||
}
|
||||
#ifdef USE_MOUSE
|
||||
/*
|
||||
* Mouse handling
|
||||
*/
|
||||
if (mouse.button) {
|
||||
int hmenu, vmenu;
|
||||
|
||||
button_used = 1; /* Button has been used at least once */
|
||||
if (mouse.y <= CHAR_LINES) {
|
||||
/* on the menubar */
|
||||
hmenu = 0;
|
||||
|
||||
list_for_each(h, &menubar, next) {
|
||||
m = list_entry(h, struct agi_menu, list);
|
||||
if (mouse_over_text(0, m->col, m->text)) {
|
||||
break;
|
||||
} else {
|
||||
hmenu++;
|
||||
}
|
||||
}
|
||||
|
||||
if (hmenu <= h_max_menu) {
|
||||
if (h_cur_menu != hmenu) {
|
||||
v_cur_menu = -1;
|
||||
new_menu_selected(hmenu);
|
||||
}
|
||||
h_cur_menu = hmenu;
|
||||
}
|
||||
} else {
|
||||
/* not in menubar */
|
||||
struct agi_menu_option *do1;
|
||||
|
||||
vmenu = 0;
|
||||
|
||||
m = get_menu(h_cur_menu);
|
||||
list_for_each(h, &m->down, next) {
|
||||
do1 = list_entry(h, struct agi_menu_option, list);
|
||||
if (mouse_over_text(2 + do1->index, m->wincol + 1, do1->text)) {
|
||||
break;
|
||||
} else {
|
||||
vmenu++;
|
||||
}
|
||||
}
|
||||
|
||||
if (vmenu <= v_max_menu[h_cur_menu]) {
|
||||
if (v_cur_menu != vmenu) {
|
||||
draw_menu_option(h_cur_menu);
|
||||
draw_menu_option_hilite(h_cur_menu, vmenu);
|
||||
}
|
||||
v_cur_menu = vmenu;
|
||||
}
|
||||
}
|
||||
} else if (button_used) {
|
||||
/* Button released */
|
||||
button_used = 0;
|
||||
|
||||
debugC(6, kDebugLevelMenu | kDebugLevelInput, "button released!");
|
||||
|
||||
if (v_cur_menu < 0)
|
||||
v_cur_menu = 0;
|
||||
|
||||
draw_menu_option_hilite(h_cur_menu, v_cur_menu);
|
||||
|
||||
if (mouse.y <= CHAR_LINES) {
|
||||
/* on the menubar */
|
||||
} else {
|
||||
/* see which option we selected */
|
||||
m = get_menu(h_cur_menu);
|
||||
list_for_each(h, &m->down, next) {
|
||||
d = list_entry(h, struct agi_menu_option, list);
|
||||
if (mouse_over_text(2 + d->index,
|
||||
m->wincol + 1, d->text)) {
|
||||
/* activate that option */
|
||||
if (d->enabled) {
|
||||
debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
|
||||
game.ev_keyp[d->event].occured = true;
|
||||
game.ev_keyp[d->event].data = d->event;
|
||||
goto exit_menu;
|
||||
}
|
||||
}
|
||||
}
|
||||
goto exit_menu;
|
||||
}
|
||||
}
|
||||
#endif /* USE_MOUSE */
|
||||
|
||||
if (!menu_active) {
|
||||
if (h_cur_menu >= 0) {
|
||||
draw_menu_hilite(h_cur_menu);
|
||||
draw_menu_option(h_cur_menu);
|
||||
if (!button_used && v_cur_menu >= 0)
|
||||
draw_menu_option_hilite(h_cur_menu, v_cur_menu);
|
||||
}
|
||||
menu_active = true;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case KEY_ESCAPE:
|
||||
debugC(6, kDebugLevelMenu | kDebugLevelInput, "KEY_ESCAPE");
|
||||
goto exit_menu;
|
||||
case KEY_ENTER:
|
||||
debugC(6, kDebugLevelMenu | kDebugLevelInput, "KEY_ENTER");
|
||||
d = get_menu_option(h_cur_menu, v_cur_menu);
|
||||
if (d->enabled) {
|
||||
debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
|
||||
game.ev_keyp[d->event].occured = true;
|
||||
goto exit_menu;
|
||||
}
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
case KEY_UP:
|
||||
v_cur_menu += key == KEY_DOWN ? 1 : -1;
|
||||
|
||||
if (v_cur_menu < 0)
|
||||
v_cur_menu = 0;
|
||||
if (v_cur_menu > v_max_menu[h_cur_menu])
|
||||
v_cur_menu = v_max_menu[h_cur_menu];
|
||||
|
||||
draw_menu_option(h_cur_menu);
|
||||
draw_menu_option_hilite(h_cur_menu, v_cur_menu);
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case KEY_LEFT:
|
||||
h_cur_menu += key == KEY_RIGHT ? 1 : -1;
|
||||
|
||||
if (h_cur_menu < 0)
|
||||
h_cur_menu = h_max_menu;
|
||||
if (h_cur_menu > h_max_menu)
|
||||
h_cur_menu = 0;
|
||||
|
||||
v_cur_menu = 0;
|
||||
new_menu_selected(h_cur_menu);
|
||||
draw_menu_option_hilite(h_cur_menu, v_cur_menu);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
exit_menu:
|
||||
button_used = 0;
|
||||
show_pic();
|
||||
write_status();
|
||||
|
||||
setvar(V_key, 0);
|
||||
game.keypress = 0;
|
||||
game.clock_enabled = clock_val;
|
||||
old_input_mode();
|
||||
debugC(3, kDebugLevelMenu, "exit_menu: input mode reset to %d", game.input_mode);
|
||||
menu_active = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void menu_set_item(int event, int state) {
|
||||
struct list_head *h, *v;
|
||||
struct agi_menu *m = NULL;
|
||||
struct agi_menu_option *d = NULL;
|
||||
|
||||
/* scan all menus for event number # */
|
||||
|
||||
debugC(6, kDebugLevelMenu, "event = %d, state = %d", event, state);
|
||||
list_for_each(h, &menubar, next) {
|
||||
m = list_entry(h, struct agi_menu, list);
|
||||
list_for_each(v, &m->down, next) {
|
||||
d = list_entry(v, struct agi_menu_option, list);
|
||||
if (d->event == event) {
|
||||
d->enabled = state;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void menu_enable_all() {
|
||||
struct list_head *h, *v;
|
||||
struct agi_menu *m = NULL;
|
||||
struct agi_menu_option *d = NULL;
|
||||
|
||||
list_for_each(h, &menubar, next) {
|
||||
m = list_entry(h, struct agi_menu, list);
|
||||
list_for_each(v, &m->down, next) {
|
||||
d = list_entry(v, struct agi_menu_option, list);
|
||||
d->enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
46
engines/agi/menu.h
Normal file
46
engines/agi/menu.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_MENU_H
|
||||
#define __AGI_MENU_H
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#define MENU_BG 0x0f /* White */
|
||||
#define MENU_DISABLED 0x07 /* Grey */
|
||||
|
||||
#define MENU_FG 0x00 /* Black */
|
||||
#define MENU_LINE 0x00 /* Black */
|
||||
|
||||
void menu_init(void);
|
||||
void menu_deinit(void);
|
||||
void menu_add(char *);
|
||||
void menu_add_item(char *, int);
|
||||
void menu_submit(void);
|
||||
void menu_set_item(int, int);
|
||||
int menu_keyhandler(int);
|
||||
void menu_enable_all(void);
|
||||
|
||||
} // End of namespace Agi
|
||||
#endif
|
42
engines/agi/module.mk
Normal file
42
engines/agi/module.mk
Normal file
@ -0,0 +1,42 @@
|
||||
MODULE := engines/agi
|
||||
|
||||
MODULE_OBJS = \
|
||||
agi.o \
|
||||
agi_v2.o \
|
||||
agi_v3.o \
|
||||
checks.o \
|
||||
console.o \
|
||||
cycle.o \
|
||||
font.o \
|
||||
global.o \
|
||||
graphics.o \
|
||||
id.o \
|
||||
inv.o \
|
||||
keyboard.o \
|
||||
logic.o \
|
||||
lzw.o \
|
||||
menu.o \
|
||||
motion.o \
|
||||
objects.o \
|
||||
op_cmd.o \
|
||||
op_dbg.o \
|
||||
op_test.o \
|
||||
patches.o \
|
||||
picture.o \
|
||||
savegame.o \
|
||||
sound.o \
|
||||
sprite.o \
|
||||
text.o \
|
||||
view.o \
|
||||
words.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
engines/agi
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifdef BUILD_PLUGINS
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/common.rules
|
232
engines/agi/motion.cpp
Normal file
232
engines/agi/motion.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
static int check_step(int delta, int step) {
|
||||
return (-step >= delta) ? 0 : (step <= delta) ? 2 : 1;
|
||||
}
|
||||
|
||||
static int check_block(int x, int y) {
|
||||
if (x <= game.block.x1 || x >= game.block.x2)
|
||||
return false;
|
||||
|
||||
if (y <= game.block.y1 || y >= game.block.y2)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void changepos(struct vt_entry *v) {
|
||||
int b, x, y;
|
||||
int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
|
||||
int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
|
||||
|
||||
x = v->x_pos;
|
||||
y = v->y_pos;
|
||||
b = check_block(x, y);
|
||||
|
||||
x += v->step_size * dx[v->direction];
|
||||
y += v->step_size * dy[v->direction];
|
||||
|
||||
if (check_block(x, y) == b) {
|
||||
v->flags &= ~MOTION;
|
||||
} else {
|
||||
v->flags |= MOTION;
|
||||
v->direction = 0;
|
||||
if /*_is_ego_view*/ (v)
|
||||
game.vars[V_ego_dir] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void motion_wander(struct vt_entry *v) {
|
||||
if (v->parm1--) {
|
||||
if (~v->flags & DIDNT_MOVE)
|
||||
return;
|
||||
}
|
||||
|
||||
v->direction = rnd->getRandomNumber(8);
|
||||
|
||||
if /*_is_ego_view */ (v) {
|
||||
game.vars[V_ego_dir] = v->direction;
|
||||
while (v->parm1 < 6) {
|
||||
v->parm1 = rnd->getRandomNumber(50); /* huh? */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void motion_followego(struct vt_entry *v) {
|
||||
int ego_x, ego_y;
|
||||
int obj_x, obj_y;
|
||||
int dir;
|
||||
|
||||
ego_x = game.view_table[0].x_pos + game.view_table[0].x_size / 2;
|
||||
ego_y = game.view_table[0].y_pos;
|
||||
|
||||
obj_x = v->x_pos + v->x_size / 2;
|
||||
obj_y = v->y_pos;
|
||||
|
||||
/* Get direction to reach ego */
|
||||
dir = get_direction(obj_x, obj_y, ego_x, ego_y, v->parm1);
|
||||
|
||||
/* Already at ego coordinates */
|
||||
if (dir == 0) {
|
||||
v->direction = 0;
|
||||
v->motion = MOTION_NORMAL;
|
||||
setflag(v->parm2, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (v->parm3 == 0xff) {
|
||||
v->parm3 = 0;
|
||||
} else if (v->flags & DIDNT_MOVE) {
|
||||
int d;
|
||||
|
||||
while ((v->direction = rnd->getRandomNumber(8)) == 0) {
|
||||
}
|
||||
|
||||
d = (abs(ego_y - obj_y) + abs(ego_x - obj_x)) / 2;
|
||||
|
||||
if (d < v->step_size) {
|
||||
v->parm3 = v->step_size;
|
||||
return;
|
||||
}
|
||||
|
||||
while ((v->parm3 = rnd->getRandomNumber(d)) < v->step_size) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (v->parm3 != 0) {
|
||||
int k;
|
||||
|
||||
/* DF: this is ugly and I dont know why this works, but
|
||||
* other line does not! (watcom complained about lvalue)
|
||||
*
|
||||
* if (((int8)v->parm3 -= v->step_size) < 0)
|
||||
* v->parm3 = 0;
|
||||
*/
|
||||
k = v->parm3;
|
||||
k -= v->step_size;
|
||||
v->parm3 = k;
|
||||
|
||||
if ((int8) v->parm3 < 0)
|
||||
v->parm3 = 0;
|
||||
} else {
|
||||
v->direction = dir;
|
||||
}
|
||||
}
|
||||
|
||||
static void motion_moveobj(struct vt_entry *v) {
|
||||
v->direction = get_direction(v->x_pos, v->y_pos, v->parm1, v->parm2, v->step_size);
|
||||
|
||||
/* Update V6 if ego */
|
||||
if (v == game.view_table)
|
||||
game.vars[V_ego_dir] = v->direction;
|
||||
|
||||
if (v->direction == 0)
|
||||
in_destination(v);
|
||||
}
|
||||
|
||||
static void check_motion(struct vt_entry *v) {
|
||||
switch (v->motion) {
|
||||
case MOTION_WANDER:
|
||||
motion_wander(v);
|
||||
break;
|
||||
case MOTION_FOLLOW_EGO:
|
||||
motion_followego(v);
|
||||
break;
|
||||
case MOTION_MOVE_OBJ:
|
||||
motion_moveobj(v);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((game.block.active && (~v->flags & IGNORE_BLOCKS)) && v->direction)
|
||||
changepos(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void check_all_motions() {
|
||||
struct vt_entry *v;
|
||||
|
||||
for (v = game.view_table; v < &game.view_table[MAX_VIEWTABLE]; v++) {
|
||||
if ((v->flags & (ANIMATED | UPDATE | DRAWN)) == (ANIMATED | UPDATE | DRAWN)
|
||||
&& v->step_time_count == 1) {
|
||||
check_motion(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given entry is at destination point.
|
||||
* This function is used to updated the flags of an object with move.obj
|
||||
* type motion that * has reached its final destination coordinates.
|
||||
* @param v Pointer to view table entry
|
||||
*/
|
||||
void in_destination(struct vt_entry *v) {
|
||||
if (v->motion == MOTION_MOVE_OBJ) {
|
||||
v->step_size = v->parm3;
|
||||
setflag(v->parm4, true);
|
||||
}
|
||||
v->motion = MOTION_NORMAL;
|
||||
if (v == game.view_table)
|
||||
game.player_control = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for static function motion_moveobj().
|
||||
* This function is used by cmd_move_object() in the first motion cycle
|
||||
* after setting the motion mode to MOTION_MOVE_OBJ.
|
||||
* @param v Pointer to view table entry
|
||||
*/
|
||||
void move_obj(struct vt_entry *v) {
|
||||
motion_moveobj(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get direction from motion coordinates
|
||||
* This function gets the motion direction from the current and previous
|
||||
* object coordinates and the step size.
|
||||
* @param x0 Original x coordinate of the object
|
||||
* @param y0 Original y coordinate of the object
|
||||
* @param x x coordinate of the object
|
||||
* @param y y coordinate of the object
|
||||
* @param s step size
|
||||
*/
|
||||
int get_direction(int x0, int y0, int x, int y, int s) {
|
||||
int dir_table[9] = { 8, 1, 2, 7, 0, 3, 6, 5, 4 };
|
||||
return dir_table[check_step(x - x0, s) + 3 * check_step(y - y0, s)];
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
167
engines/agi/objects.cpp
Normal file
167
engines/agi/objects.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
extern int decode_objects(uint8 *mem, uint32 flen);
|
||||
|
||||
static struct agi_object *objects; /* objects in the game */
|
||||
|
||||
int alloc_objects(int n) {
|
||||
if ((objects = (agi_object *) calloc(n, sizeof(struct agi_object))) == NULL)
|
||||
return err_NotEnoughMemory;
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
int decode_objects(uint8 *mem, uint32 flen) {
|
||||
unsigned int i, so, padsize;
|
||||
|
||||
padsize = game.game_flags & ID_AMIGA ? 4 : 3;
|
||||
|
||||
game.num_objects = 0;
|
||||
objects = NULL;
|
||||
|
||||
/* check if first pointer exceeds file size
|
||||
* if so, its encrypted, else it is not
|
||||
*/
|
||||
|
||||
if (READ_LE_UINT16(mem) > flen) {
|
||||
report("Decrypting objects... ");
|
||||
decrypt(mem, flen);
|
||||
report("done.\n");
|
||||
}
|
||||
|
||||
/* alloc memory for object list
|
||||
* byte 3 = number of animated objects. this is ignored.. ??
|
||||
*/
|
||||
if (READ_LE_UINT16(mem) / padsize >= 256) {
|
||||
#ifdef AGDS_SUPPORT
|
||||
/* die with no error! AGDS game needs not to die to work!! :( */
|
||||
return err_OK;
|
||||
#else
|
||||
/* no AGDS support, die with error */
|
||||
return err_BadResource;
|
||||
#endif
|
||||
}
|
||||
|
||||
game.num_objects = READ_LE_UINT16(mem) / padsize;
|
||||
debugC(5, kDebugLevelResources, "num_objects = %d (padsize = %d)", game.num_objects, padsize);
|
||||
|
||||
if (alloc_objects(game.num_objects) != err_OK)
|
||||
return err_NotEnoughMemory;
|
||||
|
||||
/* build the object list */
|
||||
for (i = 0, so = padsize; i < game.num_objects; i++, so += padsize) {
|
||||
int offset;
|
||||
|
||||
(objects + i)->location = *(mem + so + 2);
|
||||
offset = READ_LE_UINT16(mem + so) + padsize;
|
||||
|
||||
if ((uint) offset < flen) {
|
||||
(objects + i)->name = (char *)strdup((const char *)mem + offset);
|
||||
} else {
|
||||
printf("ERROR: object %i name beyond object filesize! "
|
||||
"(%04x > %04x)\n", i, offset, flen);
|
||||
(objects + i)->name = strdup("");
|
||||
}
|
||||
}
|
||||
report("Reading objects: %d objects read.\n", game.num_objects);
|
||||
|
||||
return err_OK;
|
||||
|
||||
}
|
||||
|
||||
int load_objects(char *fname) {
|
||||
Common::File fp;
|
||||
uint32 flen;
|
||||
uint8 *mem;
|
||||
char *path;
|
||||
|
||||
objects = NULL;
|
||||
game.num_objects = 0;
|
||||
|
||||
debugC(5, kDebugLevelResources, "(fname = %s)", fname);
|
||||
path = fname;
|
||||
report("Loading objects: %s\n", path);
|
||||
|
||||
if (!fp.open(path))
|
||||
return err_BadFileOpen;
|
||||
|
||||
fp.seek(0, SEEK_END);
|
||||
flen = fp.pos();
|
||||
fp.seek(0, SEEK_SET);
|
||||
|
||||
if ((mem = (uint8 *) calloc(1, flen + 32)) == NULL) {
|
||||
fp.close();
|
||||
return err_NotEnoughMemory;
|
||||
}
|
||||
|
||||
fp.read(mem, flen);
|
||||
fp.close();
|
||||
|
||||
decode_objects(mem, flen);
|
||||
free(mem);
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
void unload_objects() {
|
||||
unsigned int i;
|
||||
|
||||
if (objects != NULL) {
|
||||
for (i = 0; i < game.num_objects; i++)
|
||||
free(objects[i].name);
|
||||
free(objects);
|
||||
}
|
||||
}
|
||||
|
||||
void object_set_location(unsigned int n, int i) {
|
||||
if (n >= game.num_objects) {
|
||||
report("Error: Can't access object %d.\n", n);
|
||||
return;
|
||||
}
|
||||
objects[n].location = i;
|
||||
}
|
||||
|
||||
int object_get_location(unsigned int n) {
|
||||
if (n >= game.num_objects) {
|
||||
report("Error: Can't access object %d.\n", n);
|
||||
return 0;
|
||||
}
|
||||
return objects[n].location;
|
||||
}
|
||||
|
||||
char *object_name(unsigned int n) {
|
||||
if (n >= game.num_objects) {
|
||||
report("Error: Can't access object %d.\n", n);
|
||||
return "";
|
||||
}
|
||||
return objects[n].name;
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
1513
engines/agi/op_cmd.cpp
Normal file
1513
engines/agi/op_cmd.cpp
Normal file
File diff suppressed because it is too large
Load Diff
353
engines/agi/op_dbg.cpp
Normal file
353
engines/agi/op_dbg.cpp
Normal file
@ -0,0 +1,353 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/opcodes.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#define ip (game.logics[lognum].cIP)
|
||||
#define code (game.logics[lognum].data)
|
||||
|
||||
#ifdef _L
|
||||
#undef _L
|
||||
#endif
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
#define _L(a,b,c) { a, b, c }
|
||||
#else
|
||||
#define _L(a,b,c) { b, c }
|
||||
#endif
|
||||
|
||||
struct agi_logicnames logic_names_test[] = {
|
||||
_L("", 0, 0x00),
|
||||
_L("equaln", 2, 0x80),
|
||||
_L("equalv", 2, 0xC0),
|
||||
_L("lessn", 2, 0x80),
|
||||
_L("lessv", 2, 0xC0),
|
||||
_L("greatern", 2, 0x80),
|
||||
_L("greaterv", 2, 0xC0),
|
||||
_L("isset", 1, 0x00),
|
||||
_L("issetv", 1, 0x80),
|
||||
_L("has", 1, 0x00),
|
||||
_L("obj.in.room", 2, 0x40),
|
||||
_L("posn", 5, 0x00),
|
||||
_L("controller", 1, 0x00),
|
||||
_L("have.key", 0, 0x00),
|
||||
|
||||
/* Not 0 args. Has variable number. */
|
||||
_L("said", 0, 0x00),
|
||||
|
||||
_L("compare.strings", 2, 0x00),
|
||||
_L("obj.in.box", 5, 0x00),
|
||||
_L("center.posn", 5, 0x00),
|
||||
_L("right.posn", 5, 0x00)
|
||||
};
|
||||
|
||||
struct agi_logicnames logic_names_if[] = {
|
||||
_L("OR", 0, 0x00),
|
||||
_L("NOT", 0, 0x00),
|
||||
_L("ELSE", 0, 0x00),
|
||||
_L("IF", 0, 0x00)
|
||||
};
|
||||
|
||||
struct agi_logicnames logic_names_cmd[] = {
|
||||
_L("return", 0, 0x00), /* 00 */
|
||||
_L("increment", 1, 0x80), /* 01 */
|
||||
_L("decrement", 1, 0x80), /* 02 */
|
||||
_L("assignn", 2, 0x80), /* 03 */
|
||||
_L("assignv", 2, 0xC0), /* 04 */
|
||||
_L("addn", 2, 0x80), /* 05 */
|
||||
_L("addv", 2, 0xC0), /* 06 */
|
||||
_L("subn", 2, 0x80), /* 07 */
|
||||
_L("subv", 2, 0xC0), /* 08 */
|
||||
_L("lindirectv", 2, 0xC0), /* 09 */
|
||||
_L("rindirect", 2, 0xC0), /* 0A */
|
||||
_L("lindirectn", 2, 0x80), /* 0B */
|
||||
_L("set", 1, 0x00), /* 0C */
|
||||
_L("reset", 1, 0x00), /* 0D */
|
||||
_L("toggle", 1, 0x00), /* 0E */
|
||||
_L("set.v", 1, 0x80), /* 0F */
|
||||
_L("reset.v", 1, 0x80), /* 10 */
|
||||
_L("toggle.v", 1, 0x80), /* 11 */
|
||||
_L("new.room", 1, 0x00), /* 12 */
|
||||
_L("new.room.v", 1, 0x80), /* 13 */
|
||||
_L("load.logics", 1, 0x00), /* 14 */
|
||||
_L("load.logics.v", 1, 0x80), /* 15 */
|
||||
_L("call", 1, 0x00), /* 16 */
|
||||
_L("call.v", 1, 0x80), /* 17 */
|
||||
_L("load.pic", 1, 0x80), /* 18 */
|
||||
_L("draw.pic", 1, 0x80), /* 19 */
|
||||
_L("show.pic", 0, 0x00), /* 1A */
|
||||
_L("discard.pic", 1, 0x80), /* 1B */
|
||||
_L("overlay.pic", 1, 0x80), /* 1C */
|
||||
_L("show.pri.screen", 0, 0x00), /* 1D */
|
||||
_L("load.view", 1, 0x00), /* 1E */
|
||||
_L("load.view.v", 1, 0x80), /* 1F */
|
||||
_L("discard.view", 1, 0x00), /* 20 */
|
||||
_L("animate.obj", 1, 0x00), /* 21 */
|
||||
_L("unanimate.all", 0, 0x00), /* 22 */
|
||||
_L("draw", 1, 0x00), /* 23 */
|
||||
_L("erase", 1, 0x00), /* 24 */
|
||||
_L("position", 3, 0x00), /* 25 */
|
||||
_L("position.v", 3, 0x60), /* 26 */
|
||||
_L("get.posn", 3, 0x60), /* 27 */
|
||||
_L("reposition", 3, 0x60), /* 28 */
|
||||
_L("set.view", 2, 0x00), /* 29 */
|
||||
_L("set.view.v", 2, 0x40), /* 2A */
|
||||
_L("set.loop", 2, 0x00), /* 2B */
|
||||
_L("set.loop.v", 2, 0x40), /* 2C */
|
||||
_L("fix.loop", 1, 0x00), /* 2D */
|
||||
_L("release.loop", 1, 0x00), /* 2E */
|
||||
_L("set.cel", 2, 0x00), /* 2F */
|
||||
_L("set.cel.v", 2, 0x40), /* 30 */
|
||||
_L("last.cel", 2, 0x40), /* 31 */
|
||||
_L("current.cel", 2, 0x40), /* 32 */
|
||||
_L("current.loop", 2, 0x40), /* 33 */
|
||||
_L("current.view", 2, 0x40), /* 34 */
|
||||
_L("number.of.loops", 2, 0x40), /* 35 */
|
||||
_L("set.priority", 2, 0x00), /* 36 */
|
||||
_L("set.priority.v", 2, 0x40), /* 37 */
|
||||
_L("release.priority", 1, 0x00), /* 38 */
|
||||
_L("get.priority", 2, 0x40), /* 39 */
|
||||
_L("stop.update", 1, 0x00), /* 3A */
|
||||
_L("start.update", 1, 0x00), /* 3B */
|
||||
_L("force.update", 1, 0x00), /* 3C */
|
||||
_L("ignore.horizon", 1, 0x00), /* 3D */
|
||||
_L("observe.horizon", 1, 0x00), /* 3E */
|
||||
_L("set.horizon", 1, 0x00), /* 3F */
|
||||
_L("object.on.water", 1, 0x00), /* 40 */
|
||||
_L("object.on.land", 1, 0x00), /* 41 */
|
||||
_L("object.on.anything", 1, 0x00), /* 42 */
|
||||
_L("ignore.objs", 1, 0x00), /* 43 */
|
||||
_L("observe.objs", 1, 0x00), /* 44 */
|
||||
_L("distance", 3, 0x20), /* 45 */
|
||||
_L("stop.cycling", 1, 0x00), /* 46 */
|
||||
_L("start.cycling", 1, 0x00), /* 47 */
|
||||
_L("normal.cycle", 1, 0x00), /* 48 */
|
||||
_L("end.of.loop", 2, 0x00), /* 49 */
|
||||
_L("reverse.cycle", 1, 0x00), /* 4A */
|
||||
_L("reverse.loop", 2, 0x00), /* 4B */
|
||||
_L("cycle.time", 2, 0x40), /* 4C */
|
||||
_L("stop.motion", 1, 0x00), /* 4D */
|
||||
_L("start.motion", 1, 0x00), /* 4E */
|
||||
_L("step.size", 2, 0x40), /* 4F */
|
||||
_L("step.time", 2, 0x40), /* 50 */
|
||||
_L("move.obj", 5, 0x00), /* 51 */
|
||||
_L("move.obj.v", 5, 0x70), /* 52 */
|
||||
_L("follow.ego", 3, 0x00), /* 53 */
|
||||
_L("wander", 1, 0x00), /* 54 */
|
||||
_L("normal.motion", 1, 0x00), /* 55 */
|
||||
_L("set.dir", 2, 0x40), /* 56 */
|
||||
_L("get.dir", 2, 0x40), /* 57 */
|
||||
_L("ignore.blocks", 1, 0x00), /* 58 */
|
||||
_L("observe.blocks", 1, 0x00), /* 59 */
|
||||
_L("block", 4, 0x00), /* 5A */
|
||||
_L("unblock", 0, 0x00), /* 5B */
|
||||
_L("get", 1, 0x00), /* 5C */
|
||||
_L("get.v", 1, 0x80), /* 5D */
|
||||
_L("drop", 1, 0x00), /* 5E */
|
||||
_L("put", 2, 0x00), /* 5F */
|
||||
_L("put.v", 2, 0x40), /* 60 */
|
||||
_L("get.room.v", 2, 0xC0), /* 61 */
|
||||
_L("load.sound", 1, 0x00), /* 62 */
|
||||
_L("sound", 2, 0x00), /* 63 */
|
||||
_L("stop.sound", 0, 0x00), /* 64 */
|
||||
_L("print", 1, 0x00), /* 65 */
|
||||
_L("print.v", 1, 0x80), /* 66 */
|
||||
_L("display", 3, 0x00), /* 67 */
|
||||
_L("display.v", 3, 0xE0), /* 68 */
|
||||
_L("clear.lines", 3, 0x00), /* 69 */
|
||||
_L("text.screen", 0, 0x00), /* 6A */
|
||||
_L("graphics", 0, 0x00), /* 6B */
|
||||
_L("set.cursor.char", 1, 0x00), /* 6C */
|
||||
_L("set.text.attribute", 2, 0x00), /* 6D */
|
||||
_L("shake.screen", 1, 0x00), /* 6E */
|
||||
_L("configure.screen", 3, 0x00), /* 6F */
|
||||
_L("status.line.on", 0, 0x00), /* 70 */
|
||||
_L("status.line.off", 0, 0x00), /* 71 */
|
||||
_L("set.string", 2, 0x00), /* 72 */
|
||||
_L("get.string", 5, 0x00), /* 73 */
|
||||
_L("word.to.string", 2, 0x00), /* 74 */
|
||||
_L("parse", 1, 0x00), /* 75 */
|
||||
_L("get.num", 2, 0x40), /* 76 */
|
||||
_L("prevent.input", 0, 0x00), /* 77 */
|
||||
_L("accept.input", 0, 0x00), /* 78 */
|
||||
_L("set.key", 3, 0x00), /* 79 */
|
||||
_L("add.to.pic", 7, 0x00), /* 7A */
|
||||
_L("add.to.pic.v", 7, 0xFE), /* 7B */
|
||||
_L("status", 0, 0x00), /* 7C */
|
||||
_L("save.game", 0, 0x00), /* 7D */
|
||||
_L("restore.game", 0, 0x00), /* 7E */
|
||||
_L("init.disk", 0, 0x00), /* 7F */
|
||||
_L("restart.game", 0, 0x00), /* 80 */
|
||||
_L("show.obj", 1, 0x00), /* 81 */
|
||||
_L("random", 3, 0x20), /* 82 */
|
||||
_L("program.control", 0, 0x00), /* 83 */
|
||||
_L("player.control", 0, 0x00), /* 84 */
|
||||
_L("obj.status.v", 1, 0x80), /* 85 */
|
||||
/* 0 args for AGI version 2.089 */
|
||||
_L("quit", 1, 0x00), /* 86 */
|
||||
|
||||
_L("show.mem", 0, 0x00), /* 87 */
|
||||
_L("pause", 0, 0x00), /* 88 */
|
||||
_L("echo.line", 0, 0x00), /* 89 */
|
||||
_L("cancel.line", 0, 0x00), /* 8A */
|
||||
_L("init.joy", 0, 0x00), /* 8B */
|
||||
_L("toggle.monitor", 0, 0x00), /* 8C */
|
||||
_L("version", 0, 0x00), /* 8D */
|
||||
_L("script.size", 1, 0x00), /* 8E */
|
||||
_L("set.game.id", 1, 0x00), /* 8F */
|
||||
_L("log", 1, 0x00), /* 90 */
|
||||
_L("set.scan.start", 0, 0x00), /* 91 */
|
||||
_L("reset.scan.start", 0, 0x00), /* 92 */
|
||||
_L("reposition.to", 3, 0x00), /* 93 */
|
||||
_L("reposition.to.v", 3, 0x60), /* 94 */
|
||||
_L("trace.on", 0, 0x00), /* 95 */
|
||||
_L("trace.info", 3, 0x00), /* 96 */
|
||||
|
||||
/* 3 args for AGI versions before 2.440 */
|
||||
_L("print.at", 4, 0x00), /* 97 */
|
||||
_L("print.at.v", 4, 0x80), /* 98 */
|
||||
|
||||
_L("discard.view.v", 1, 0x80), /* 99 */
|
||||
_L("clear.text.rect", 5, 0x00), /* 9A */
|
||||
_L("set.upper.left", 2, 0x00), /* 9B */
|
||||
_L("set.menu", 1, 0x00), /* 9C */
|
||||
_L("set.menu.item", 2, 0x00), /* 9D */
|
||||
_L("submit.menu", 0, 0x00), /* 9E */
|
||||
_L("enable.item", 1, 0x00), /* 9F */
|
||||
_L("disable.item", 1, 0x00), /* A0 */
|
||||
_L("menu.input", 0, 0x00), /* A1 */
|
||||
_L("show.obj.v", 1, 0x01), /* A2 */
|
||||
_L("open.dialogue", 0, 0x00), /* A3 */
|
||||
_L("close.dialogue", 0, 0x00), /* A4 */
|
||||
_L("mul.n", 2, 0x80), /* A5 */
|
||||
_L("mul.v", 2, 0xC0), /* A6 */
|
||||
_L("div.n", 2, 0x80), /* A7 */
|
||||
_L("div.v", 2, 0xC0), /* A8 */
|
||||
_L("close.window", 0, 0x00), /* A9 */
|
||||
|
||||
_L("set.simple", 1, 0x00), /* AA */
|
||||
_L("push.script", 0, 0x00), /* AB */
|
||||
_L("pop.script", 0, 0x00), /* AC */
|
||||
_L("hold.key", 0, 0x00), /* AD */
|
||||
_L("set.pri.base", 1, 0x00), /* AE */
|
||||
_L("discard.sound", 1, 0x00), /* AF */
|
||||
|
||||
/* 1 arg for AGI version 3.002.086 */
|
||||
_L("hide.mouse", 0, 0x00), /* B0 */
|
||||
|
||||
_L("allow.menu", 1, 0x00), /* B1 */
|
||||
_L("show.mouse", 0, 0x00), /* B2 */
|
||||
_L("fence.mouse", 4, 0x00), /* B3 */
|
||||
_L("mouse.posn", 2, 0x00), /* B4 */
|
||||
_L("release.key", 0, 0x00), /* B5 */
|
||||
_L("adj.ego.move.to.xy", 0, 0x00), /* B6 */
|
||||
_L(NULL, 0, 0x00)
|
||||
};
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
|
||||
void debug_console(int lognum, int mode, char *str) {
|
||||
struct agi_logicnames *x;
|
||||
uint8 a, c, z;
|
||||
|
||||
if (str) {
|
||||
report(" %s\n", str);
|
||||
return;
|
||||
}
|
||||
|
||||
report("%03d:%04x ", lognum, ip);
|
||||
|
||||
switch (*(code + ip)) {
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
x = logic_names_if;
|
||||
|
||||
if (debug_.opcodes) {
|
||||
report("%02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
|
||||
" ",
|
||||
(uint8) * (code + (0 + ip)) & 0xFF,
|
||||
(uint8) * (code + (1 + ip)) & 0xFF,
|
||||
(uint8) * (code + (2 + ip)) & 0xFF,
|
||||
(uint8) * (code + (3 + ip)) & 0xFF,
|
||||
(uint8) * (code + (4 + ip)) & 0xFF,
|
||||
(uint8) * (code + (5 + ip)) & 0xFF,
|
||||
(uint8) * (code + (6 + ip)) & 0xFF,
|
||||
(uint8) * (code + (7 + ip)) & 0xFF,
|
||||
(uint8) * (code + (8 + ip)) & 0xFF);
|
||||
}
|
||||
report("%s ", (x + *(code + ip) - 0xFC)->name);
|
||||
break;
|
||||
default:
|
||||
x = mode == lCOMMAND_MODE ? logic_names_cmd : logic_names_test;
|
||||
a = (unsigned char)(x + *(code + ip))->num_args;
|
||||
c = (unsigned char)(x + *(code + ip))->arg_mask;
|
||||
|
||||
if (debug_.opcodes) {
|
||||
report("%02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
|
||||
" ",
|
||||
(uint8) * (code + (0 + ip)) & 0xFF,
|
||||
(uint8) * (code + (1 + ip)) & 0xFF,
|
||||
(uint8) * (code + (2 + ip)) & 0xFF,
|
||||
(uint8) * (code + (3 + ip)) & 0xFF,
|
||||
(uint8) * (code + (4 + ip)) & 0xFF,
|
||||
(uint8) * (code + (5 + ip)) & 0xFF,
|
||||
(uint8) * (code + (6 + ip)) & 0xFF,
|
||||
(uint8) * (code + (7 + ip)) & 0xFF,
|
||||
(uint8) * (code + (8 + ip)) & 0xFF);
|
||||
}
|
||||
report("%s ", (x + *(code + ip))->name);
|
||||
|
||||
for (z = 1; a > 0;) {
|
||||
if (~c & 0x80) {
|
||||
report("%d", *(code + (ip + z)));
|
||||
} else {
|
||||
report("v%d[%d]", *(code + (ip + z)), getvar(*(code + (ip + z))));
|
||||
}
|
||||
c <<= 1;
|
||||
z++;
|
||||
if (--a > 0)
|
||||
report(",");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
report("\n");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void debug_console(int lognum, int mode, char *str) {
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
#endif /* USE_CONSOLE */
|
||||
|
||||
} // End of namespace Agi
|
419
engines/agi/op_test.cpp
Normal file
419
engines/agi/op_test.cpp
Normal file
@ -0,0 +1,419 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/keyboard.h"
|
||||
#include "agi/opcodes.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
static uint8 test_obj_right(uint8, uint8, uint8, uint8, uint8);
|
||||
static uint8 test_obj_centre(uint8, uint8, uint8, uint8, uint8);
|
||||
static uint8 test_obj_in_box(uint8, uint8, uint8, uint8, uint8);
|
||||
static uint8 test_posn(uint8, uint8, uint8, uint8, uint8);
|
||||
static uint8 test_said(uint8, uint8 *);
|
||||
static uint8 test_controller(uint8);
|
||||
static uint8 test_keypressed(void);
|
||||
static uint8 test_compare_strings(uint8, uint8);
|
||||
|
||||
#define ip (game.logics[lognum].cIP)
|
||||
#define code (game.logics[lognum].data)
|
||||
|
||||
#define test_equal(v1,v2) (getvar(v1) == (v2))
|
||||
#define test_less(v1,v2) (getvar(v1) < (v2))
|
||||
#define test_greater(v1,v2) (getvar(v1) > (v2))
|
||||
#define test_isset(flag) (getflag (flag))
|
||||
#define test_has(obj) (object_get_location (obj) == EGO_OWNED)
|
||||
#define test_obj_in_room(obj,v) (object_get_location (obj) == getvar (v))
|
||||
|
||||
extern int timer_hack; /* For the timer loop in MH1 logic 153 */
|
||||
|
||||
static uint8 test_compare_strings(uint8 s1, uint8 s2) {
|
||||
char ms1[MAX_STRINGLEN];
|
||||
char ms2[MAX_STRINGLEN];
|
||||
int j, k, l;
|
||||
|
||||
strcpy(ms1, game.strings[s1]);
|
||||
strcpy(ms2, game.strings[s2]);
|
||||
|
||||
l = strlen(ms1);
|
||||
for (k = 0, j = 0; k < l; k++) {
|
||||
switch (ms1[k]) {
|
||||
case 0x20:
|
||||
case 0x09:
|
||||
case '-':
|
||||
case '.':
|
||||
case ',':
|
||||
case ':':
|
||||
case ';':
|
||||
case '!':
|
||||
case '\'':
|
||||
break;
|
||||
|
||||
default:
|
||||
ms1[j++] = toupper(ms1[k]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ms1[j] = 0x0;
|
||||
|
||||
l = strlen(ms2);
|
||||
for (k = 0, j = 0; k < l; k++) {
|
||||
switch (ms2[k]) {
|
||||
case 0x20:
|
||||
case 0x09:
|
||||
case '-':
|
||||
case '.':
|
||||
case ',':
|
||||
case ':':
|
||||
case ';':
|
||||
case '!':
|
||||
case '\'':
|
||||
break;
|
||||
|
||||
default:
|
||||
ms2[j++] = toupper(ms2[k]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ms2[j] = 0x0;
|
||||
|
||||
return !strcmp(ms1, ms2);
|
||||
}
|
||||
|
||||
static uint8 test_keypressed() {
|
||||
int x = game.keypress;
|
||||
|
||||
game.keypress = 0;
|
||||
if (!x) {
|
||||
int mode = game.input_mode;
|
||||
game.input_mode = INPUT_NONE;
|
||||
main_cycle();
|
||||
game.input_mode = mode;
|
||||
}
|
||||
|
||||
if (x)
|
||||
debugC(5, kDebugLevelScripts | kDebugLevelInput, "keypress = %02x", x);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static uint8 test_controller(uint8 cont) {
|
||||
return game.ev_keyp[cont].occured;
|
||||
}
|
||||
|
||||
static uint8 test_posn(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) {
|
||||
struct vt_entry *v = &game.view_table[n];
|
||||
uint8 r;
|
||||
|
||||
r = v->x_pos >= x1 && v->y_pos >= y1 && v->x_pos <= x2 && v->y_pos <= y2;
|
||||
|
||||
debugC(7, kDebugLevelScripts, "(%d,%d) in (%d,%d,%d,%d): %s", v->x_pos, v->y_pos, x1, y1, x2, y2, r ? "true" : "false");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static uint8 test_obj_in_box(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) {
|
||||
struct vt_entry *v = &game.view_table[n];
|
||||
|
||||
return v->x_pos >= x1 &&
|
||||
v->y_pos >= y1 && v->x_pos + v->x_size - 1 <= x2 && v->y_pos <= y2;
|
||||
}
|
||||
|
||||
/* if n is in centre of box */
|
||||
static uint8 test_obj_centre(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) {
|
||||
struct vt_entry *v = &game.view_table[n];
|
||||
|
||||
return v->x_pos + v->x_size / 2 >= x1 &&
|
||||
v->x_pos + v->x_size / 2 <= x2 && v->y_pos >= y1 && v->y_pos <= y2;
|
||||
}
|
||||
|
||||
/* if nect N is in right corner */
|
||||
static uint8 test_obj_right(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) {
|
||||
struct vt_entry *v = &game.view_table[n];
|
||||
|
||||
return v->x_pos + v->x_size - 1 >= x1 &&
|
||||
v->x_pos + v->x_size - 1 <= x2 && v->y_pos >= y1 && v->y_pos <= y2;
|
||||
}
|
||||
|
||||
/* When player has entered something, it is parsed elsewhere */
|
||||
static uint8 test_said(uint8 nwords, uint8 *cc) {
|
||||
int c, n = game.num_ego_words;
|
||||
int z = 0;
|
||||
|
||||
if (getflag(F_said_accepted_input) || !getflag(F_entered_cli))
|
||||
return false;
|
||||
|
||||
/* FR:
|
||||
* I think the reason for the code below is to add some speed....
|
||||
*
|
||||
* if (nwords != num_ego_words)
|
||||
* return false;
|
||||
*
|
||||
* In the disco scene in Larry 1 when you type "examine blonde",
|
||||
* inside the logic is expected ( said("examine", "blonde", "rol") )
|
||||
* where word("rol") = 9999
|
||||
*
|
||||
* According to the interpreter code 9999 means that whatever the
|
||||
* user typed should be correct, but it looks like code 9999 means that
|
||||
* if the string is empty at this point, the entry is also correct...
|
||||
*
|
||||
* With the removal of this code, the behaviour of the scene was
|
||||
* corrected
|
||||
*/
|
||||
|
||||
for (c = 0; nwords && n; c++, nwords--, n--) {
|
||||
z = READ_LE_UINT16(cc);
|
||||
cc += 2;
|
||||
|
||||
switch (z) {
|
||||
case 9999: /* rest of line (empty string counts to...) */
|
||||
nwords = 1;
|
||||
break;
|
||||
case 1: /* any word */
|
||||
break;
|
||||
default:
|
||||
if (game.ego_words[c].id != z)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The entry string should be entirely parsed, or last word = 9999 */
|
||||
if (n && z != 9999)
|
||||
return false;
|
||||
|
||||
/* The interpreter string shouldn't be entirely parsed, but next
|
||||
* word must be 9999.
|
||||
*/
|
||||
if (nwords != 0 && READ_LE_UINT16(cc) != 9999)
|
||||
return false;
|
||||
|
||||
setflag(F_said_accepted_input, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int test_if_code(int lognum) {
|
||||
int ec = true;
|
||||
int retval = true;
|
||||
uint8 op = 0;
|
||||
uint8 not_test = false;
|
||||
uint8 or_test = false;
|
||||
uint16 last_ip = ip;
|
||||
uint8 p[16] = { 0 };
|
||||
|
||||
while (retval && !game.quit_prog_now) {
|
||||
#ifdef USE_CONSOLE
|
||||
if (debug_.enabled && (debug_.logic0 || lognum))
|
||||
debug_console(lognum, lTEST_MODE, NULL);
|
||||
#endif
|
||||
|
||||
last_ip = ip;
|
||||
op = *(code + ip++);
|
||||
memmove(p, (code + ip), 16);
|
||||
|
||||
switch (op) {
|
||||
case 0xFF: /* END IF, TEST true */
|
||||
goto end_test;
|
||||
case 0xFD:
|
||||
not_test = !not_test;
|
||||
continue;
|
||||
case 0xFC: /* OR */
|
||||
/* if or_test is ON and we hit 0xFC, end of OR, then
|
||||
* or is STILL false so break.
|
||||
*/
|
||||
if (or_test) {
|
||||
ec = false;
|
||||
retval = false;
|
||||
goto end_test;
|
||||
}
|
||||
|
||||
or_test = true;
|
||||
continue;
|
||||
|
||||
case 0x00:
|
||||
/* return true? */
|
||||
goto end_test;
|
||||
case 0x01:
|
||||
ec = test_equal(p[0], p[1]);
|
||||
if (p[0] == 11)
|
||||
timer_hack++;
|
||||
break;
|
||||
case 0x02:
|
||||
ec = test_equal(p[0], getvar(p[1]));
|
||||
if (p[0] == 11 || p[1] == 11)
|
||||
timer_hack++;
|
||||
break;
|
||||
case 0x03:
|
||||
ec = test_less(p[0], p[1]);
|
||||
if (p[0] == 11)
|
||||
timer_hack++;
|
||||
break;
|
||||
case 0x04:
|
||||
ec = test_less(p[0], getvar(p[1]));
|
||||
if (p[0] == 11 || p[1] == 11)
|
||||
timer_hack++;
|
||||
break;
|
||||
case 0x05:
|
||||
ec = test_greater(p[0], p[1]);
|
||||
if (p[0] == 11)
|
||||
timer_hack++;
|
||||
break;
|
||||
case 0x06:
|
||||
ec = test_greater(p[0], getvar(p[1]));
|
||||
if (p[0] == 11 || p[1] == 11)
|
||||
timer_hack++;
|
||||
break;
|
||||
case 0x07:
|
||||
ec = test_isset(p[0]);
|
||||
break;
|
||||
case 0x08:
|
||||
ec = test_isset(getvar(p[0]));
|
||||
break;
|
||||
case 0x09:
|
||||
ec = test_has(p[0]);
|
||||
break;
|
||||
case 0x0A:
|
||||
ec = test_obj_in_room(p[0], p[1]);
|
||||
break;
|
||||
case 0x0B:
|
||||
ec = test_posn(p[0], p[1], p[2], p[3], p[4]);
|
||||
break;
|
||||
case 0x0C:
|
||||
ec = test_controller(p[0]);
|
||||
break;
|
||||
case 0x0D:
|
||||
ec = test_keypressed();
|
||||
break;
|
||||
case 0x0E:
|
||||
ec = test_said(p[0], (uint8 *) code + (ip + 1));
|
||||
ip = last_ip;
|
||||
ip++; /* skip opcode */
|
||||
ip += p[0] * 2; /* skip num_words * 2 */
|
||||
ip++; /* skip num_words opcode */
|
||||
break;
|
||||
case 0x0F:
|
||||
debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", game.strings[p[0]], game.strings[p[1]]);
|
||||
ec = test_compare_strings(p[0], p[1]);
|
||||
break;
|
||||
case 0x10:
|
||||
ec = test_obj_in_box(p[0], p[1], p[2], p[3], p[4]);
|
||||
break;
|
||||
case 0x11:
|
||||
ec = test_obj_centre(p[0], p[1], p[2], p[3], p[4]);
|
||||
break;
|
||||
case 0x12:
|
||||
ec = test_obj_right(p[0], p[1], p[2], p[3], p[4]);
|
||||
break;
|
||||
default:
|
||||
ec = false;
|
||||
goto end_test;
|
||||
}
|
||||
|
||||
if (op <= 0x12)
|
||||
ip += logic_names_test[op].num_args;
|
||||
|
||||
/* exchange ec value */
|
||||
if (not_test)
|
||||
ec = !ec;
|
||||
|
||||
/* not is only enabled for 1 test command */
|
||||
not_test = false;
|
||||
|
||||
if (or_test && ec) {
|
||||
/* a true inside an OR statement passes
|
||||
* ENTIRE statement scan for end of OR
|
||||
*/
|
||||
|
||||
/* CM: test for opcode < 0xfc changed from 'op' to
|
||||
* '*(code+ip)', to avoid problem with the 0xfd (NOT)
|
||||
* opcode byte. Changed a bad ip += ... ip++ construct.
|
||||
* This should fix the crash with Larry's logic.0 code:
|
||||
*
|
||||
* if ((isset(4) ||
|
||||
* !isset(2) ||
|
||||
* v30 == 2 ||
|
||||
* v30 == 1)) {
|
||||
* goto Label1;
|
||||
* }
|
||||
*
|
||||
* The bytecode is:
|
||||
* ff fc 07 04 fd 07 02 01 1e 02 01 1e 01 fc ff
|
||||
*/
|
||||
|
||||
/* find end of OR */
|
||||
while (*(code + ip) != 0xFC) {
|
||||
if (*(code + ip) == 0x0E) { /* said */
|
||||
ip++;
|
||||
/* cover count + ^words */
|
||||
ip += 1 + ((*(code + ip)) * 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*(code + ip) < 0xFC)
|
||||
ip += logic_names_test[*(code + ip)].num_args;
|
||||
ip++;
|
||||
}
|
||||
ip++;
|
||||
|
||||
or_test = false;
|
||||
retval = true;
|
||||
} else {
|
||||
retval = or_test ? retval || ec : retval && ec;
|
||||
}
|
||||
}
|
||||
end_test:
|
||||
|
||||
/* if false, scan for end of IP? */
|
||||
if (retval)
|
||||
ip += 2;
|
||||
else {
|
||||
ip = last_ip;
|
||||
while (*(code + ip) != 0xff) {
|
||||
if (*(code + ip) == 0x0e) {
|
||||
ip++;
|
||||
ip += (*(code + ip)) * 2 + 1;
|
||||
} else if (*(code + ip) < 0xfc) {
|
||||
ip += logic_names_test[*(code + ip)].num_args;
|
||||
ip++;
|
||||
} else {
|
||||
ip++;
|
||||
}
|
||||
}
|
||||
ip++; /* skip over 0xFF */
|
||||
ip += READ_LE_UINT16(code + ip) + 2;
|
||||
}
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
if (debug_.enabled && (debug_.logic0 || lognum))
|
||||
debug_console(lognum, 0xFF, retval ? (char *)"=true" : (char *)"=false");
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
55
engines/agi/opcodes.h
Normal file
55
engines/agi/opcodes.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_OPCODES_H
|
||||
#define __AGI_OPCODES_H
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
struct agi_logicnames {
|
||||
#ifdef USE_CONSOLE /* ifndef NO_DEBUG */
|
||||
char *name;
|
||||
#endif
|
||||
uint16 num_args;
|
||||
uint16 arg_mask;
|
||||
};
|
||||
|
||||
extern struct agi_logicnames logic_names_test[];
|
||||
extern struct agi_logicnames logic_names_cmd[];
|
||||
extern struct agi_logicnames logic_names_if[];
|
||||
|
||||
void debug_console(int, int, char *);
|
||||
int test_if_code(int);
|
||||
void new_room(int);
|
||||
void execute_agi_command(uint8, uint8 *);
|
||||
|
||||
#ifdef PATCH_LOGIC
|
||||
void patch_logic(int);
|
||||
#endif
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif /* __AGI_OPCODES_H */
|
144
engines/agi/patches.cpp
Normal file
144
engines/agi/patches.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/opcodes.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#ifdef PATCH_LOGIC
|
||||
|
||||
#define ip (game.logics[n].cIP)
|
||||
#define code (game.logics[n].data)
|
||||
#define size (game.logics[n].size)
|
||||
|
||||
/*
|
||||
* Patches
|
||||
*/
|
||||
|
||||
static uint8 kq4data_find[] = {
|
||||
0x0C, 0x04, 0xFF, 0x07, 0x05, 0xFF, 0x15, 0x00,
|
||||
0x03, 0x0A, 0x00, 0x77, 0x83, 0x71, 0x0D, 0x97,
|
||||
0x03, 0x98, 0xCE, 0x18, 0x98, 0x19, 0x98, 0x1B,
|
||||
0x98, 0x0C, 0x5A, 0x1A, 0x00
|
||||
};
|
||||
|
||||
static uint8 kq4data_fix[] = {
|
||||
/* v19 = 0
|
||||
* new.room(96)
|
||||
* return
|
||||
*/
|
||||
0x03, 0x13, 0x0, 0x12, 0x60, 0x00
|
||||
};
|
||||
|
||||
static uint8 grdata_find[] = {
|
||||
0x0C, 0x04, 0xFF, 0x07, 0x05, 0xFF, 0x16, 0x00,
|
||||
0x0C, 0x96, 0x03, 0x0A, 0x00, 0x77, 0x83, 0x71,
|
||||
0x0D, 0xD9, 0x03, 0xDC, 0xBF, 0x18, 0xDC, 0x19,
|
||||
0xDC, 0x1B, 0xDC, 0x0C, 0x95, 0x1A
|
||||
};
|
||||
|
||||
static uint8 grdata_fix[] = {
|
||||
/* reset(227)
|
||||
* v19 = 0
|
||||
* v246 = 1
|
||||
* set(15)
|
||||
* new.room(73)
|
||||
*/
|
||||
0x0D, 0xE3, 0x03, 0x13, 0x00, 0x03, 0xF6, 0x01,
|
||||
0x0C, 0x0F, 0x12, 0x49
|
||||
};
|
||||
|
||||
#if 0
|
||||
static uint8 lsl1data_find[] = {
|
||||
0xFF, 0xFD, 0x07, 0x1E, 0xFC, 0x07, 0x6D, 0x01,
|
||||
0x5F, 0x03, 0xFC, 0xFF, 0x12, 0x00, 0x0C, 0x6D,
|
||||
0x78, 0x8A, 0x77, 0x69, 0x16, 0x18, 0x00, 0x0D,
|
||||
0x30, 0x0D, 0x55, 0x78, 0x65, 0x0A
|
||||
};
|
||||
|
||||
static uint8 lsl1data_fix[] = {
|
||||
/* set(109)
|
||||
* reset(48)
|
||||
* reset(85)
|
||||
* accept.input()
|
||||
* new.room(11)
|
||||
*/
|
||||
0x0C, 0x6D, 0x0D, 0x30, 0x0D, 0x55, 0x78, 0x12,
|
||||
0x0B
|
||||
};
|
||||
#endif
|
||||
|
||||
static uint8 mh1data_find[] = {
|
||||
0xFF, 0x07, 0x05, 0xFF, 0xE6, 0x00,
|
||||
0x03, 0x0A, 0x02, 0x77, 0x83, 0x71,
|
||||
0x6F, 0x01, 0x17, 0x00, 0x03, 0x00,
|
||||
0x9F, 0x03, 0x37, 0x00, 0x03, 0x32,
|
||||
0x03, 0x03, 0x3B, 0x00, 0x6C, 0x03
|
||||
};
|
||||
|
||||
static uint8 mh1data_fix[] = {
|
||||
0x0C, 0x05, 0x16, 0x5A, 0x12, 0x99
|
||||
};
|
||||
|
||||
void patch_logic(int n) {
|
||||
switch (n) {
|
||||
#if 0
|
||||
/* ALT-X in the questions takes care of that */
|
||||
case 6:
|
||||
/* lsl1 bypass questions */
|
||||
if (!strcmp(game.id, "LLLLL")) {
|
||||
if (!memcmp(lsl1data_find, (code + ip), 30))
|
||||
memmove((code + ip), lsl1data_fix, 9);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 125:
|
||||
/* gold rush code break */
|
||||
if (!strcmp(game.id, "GR")) {
|
||||
if (!memcmp(grdata_find, (code + ip), 30))
|
||||
memmove((code + ip), grdata_fix, 12);
|
||||
}
|
||||
break;
|
||||
case 140:
|
||||
/* kings quest 4 code break */
|
||||
if (!strcmp(game.id, "KQ4")) {
|
||||
if (memcmp(kq4data_find, (code + ip), 29) == 0)
|
||||
memmove((code + ip), kq4data_fix, 6);
|
||||
}
|
||||
break;
|
||||
case 159:
|
||||
/* manhunter 1 amiga */
|
||||
if (ip + 30 < size && !memcmp(mh1data_find, (code + ip), 30)) {
|
||||
memmove((code + ip), mh1data_fix, 6);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // End of namespace Agi
|
1034
engines/agi/picture.cpp
Normal file
1034
engines/agi/picture.cpp
Normal file
File diff suppressed because it is too large
Load Diff
47
engines/agi/picture.h
Normal file
47
engines/agi/picture.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_PICTURE_H
|
||||
#define __AGI_PICTURE_H
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
/**
|
||||
* AGI picture resource.
|
||||
*/
|
||||
struct agi_picture {
|
||||
uint32 flen; /**< size of raw data */
|
||||
uint8 *rdata; /**< raw vector image data */
|
||||
};
|
||||
|
||||
int decode_picture(int, int);
|
||||
int unload_picture(int);
|
||||
void show_pic(void);
|
||||
uint8 *convert_v3_pic(uint8 *data, uint32 len);
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif /* __AGI_PICTURE_H */
|
790
engines/agi/savegame.cpp
Normal file
790
engines/agi/savegame.cpp
Normal file
@ -0,0 +1,790 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Savegame support by Vasyl Tsvirkunov <vasyl@pacbell.net>
|
||||
* Multi-slots by Claudio Matsuoka <claudio@helllabs.org>
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/graphics.h"
|
||||
#include "agi/sprite.h"
|
||||
#include "agi/text.h"
|
||||
#include "agi/savegame.h"
|
||||
#include "agi/keyboard.h"
|
||||
#include "agi/menu.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#if defined(WIN32)
|
||||
#define MKDIR(a,b) mkdir(a)
|
||||
#else
|
||||
#define MKDIR(a,b) mkdir(a,b)
|
||||
#endif
|
||||
|
||||
/* Image stack support */
|
||||
struct image_stack_element {
|
||||
uint8 type;
|
||||
uint8 pad;
|
||||
int16 parm1;
|
||||
int16 parm2;
|
||||
int16 parm3;
|
||||
int16 parm4;
|
||||
int16 parm5;
|
||||
int16 parm6;
|
||||
int16 parm7;
|
||||
};
|
||||
|
||||
#define INITIAL_IMAGE_STACK_SIZE 32
|
||||
static int stack_size = 0;
|
||||
static struct image_stack_element *image_stack = NULL;
|
||||
static int image_stack_pointer = 0;
|
||||
|
||||
void clear_image_stack(void) {
|
||||
image_stack_pointer = 0;
|
||||
}
|
||||
|
||||
void release_image_stack(void) {
|
||||
if (image_stack)
|
||||
free(image_stack);
|
||||
image_stack = NULL;
|
||||
stack_size = image_stack_pointer = 0;
|
||||
}
|
||||
|
||||
void record_image_stack_call(uint8 type, int16 p1, int16 p2, int16 p3,
|
||||
int16 p4, int16 p5, int16 p6, int16 p7) {
|
||||
struct image_stack_element *pnew;
|
||||
|
||||
if (image_stack_pointer == stack_size) {
|
||||
if (stack_size == 0) { /* first call */
|
||||
image_stack = (struct image_stack_element *)
|
||||
malloc(INITIAL_IMAGE_STACK_SIZE * sizeof(struct image_stack_element));
|
||||
stack_size = INITIAL_IMAGE_STACK_SIZE;
|
||||
} else { /* has to grow */
|
||||
struct image_stack_element *new_stack;
|
||||
new_stack = (struct image_stack_element *)
|
||||
malloc(2 * stack_size * sizeof(struct image_stack_element));
|
||||
memcpy(new_stack, image_stack, stack_size * sizeof(struct image_stack_element));
|
||||
free(image_stack);
|
||||
image_stack = new_stack;
|
||||
stack_size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
pnew = &image_stack[image_stack_pointer];
|
||||
image_stack_pointer++;
|
||||
|
||||
pnew->type = type;
|
||||
pnew->parm1 = p1;
|
||||
pnew->parm2 = p2;
|
||||
pnew->parm3 = p3;
|
||||
pnew->parm4 = p4;
|
||||
pnew->parm5 = p5;
|
||||
pnew->parm6 = p6;
|
||||
pnew->parm7 = p7;
|
||||
}
|
||||
|
||||
void replay_image_stack_call(uint8 type, int16 p1, int16 p2, int16 p3,
|
||||
int16 p4, int16 p5, int16 p6, int16 p7) {
|
||||
switch (type) {
|
||||
case ADD_PIC:
|
||||
debugC(8, kDebugLevelMain, "--- decoding picture %d ---", p1);
|
||||
agi_load_resource(rPICTURE, p1);
|
||||
decode_picture(p1, p2);
|
||||
break;
|
||||
case ADD_VIEW:
|
||||
agi_load_resource(rVIEW, p1);
|
||||
add_to_pic(p1, p2, p3, p4, p5, p6, p7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
static char *strSig = "AGI:";
|
||||
|
||||
static void write_uint8(Common::File *f, int8 val) {
|
||||
f->write(&val, 1);
|
||||
}
|
||||
|
||||
static void write_sint16(Common::File *f, int16 val) {
|
||||
static uint8 buf[2];
|
||||
buf[0] = (uint8) ((val >> 8) & 255);
|
||||
buf[1] = (uint8) (val & 255);
|
||||
f->write(buf, 2);
|
||||
}
|
||||
|
||||
static void write_uint16(Common::File *f, uint16 val) {
|
||||
static uint8 buf[2];
|
||||
buf[0] = (uint8) ((val >> 8) & 255);
|
||||
buf[1] = (uint8) (val & 255);
|
||||
f->write(buf, 2);
|
||||
}
|
||||
|
||||
static uint8 read_uint8(Common::File *f) {
|
||||
static uint8 buf[1];
|
||||
f->read(buf, 1);
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
static uint16 read_uint16(Common::File *f) {
|
||||
static uint8 buf[2];
|
||||
f->read(buf, 2);
|
||||
return (buf[0] << 8) | buf[1];
|
||||
}
|
||||
|
||||
static int16 read_sint16(Common::File *f) {
|
||||
static uint8 buf[2];
|
||||
f->read(buf, 2);
|
||||
return (int16) ((buf[0] << 8) | buf[1]);
|
||||
}
|
||||
|
||||
static void write_string(Common::File *f, char *s) {
|
||||
write_sint16(f, (int16) strlen(s));
|
||||
f->write(s, strlen(s));
|
||||
}
|
||||
|
||||
static void read_string(Common::File *f, char *s) {
|
||||
int16 size = read_sint16(f);
|
||||
f->read(s, size);
|
||||
s[size] = (char)0;
|
||||
}
|
||||
|
||||
static void write_bytes(Common::File *f, char *s, int16 size) {
|
||||
f->write(s, size);
|
||||
}
|
||||
|
||||
static void read_bytes(Common::File *f, char *s, int16 size) {
|
||||
f->read(s, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Version 0: view table has 64 entries
|
||||
* Version 1: view table has 256 entries (needed in KQ3)
|
||||
*/
|
||||
#define SAVEGAME_VERSION 1
|
||||
|
||||
int save_game(char *s, char *d) {
|
||||
int16 i;
|
||||
struct image_stack_element *ptr = image_stack;
|
||||
Common::File f;
|
||||
|
||||
f.open(s, Common::File::kFileWriteMode);
|
||||
|
||||
if (!f.isOpen())
|
||||
return err_BadFileOpen;
|
||||
|
||||
write_bytes(&f, strSig, 8);
|
||||
write_string(&f, d);
|
||||
|
||||
write_uint8(&f, (uint8) SAVEGAME_VERSION);
|
||||
write_uint8(&f, (uint8) game.state);
|
||||
/* game.name */
|
||||
write_string(&f, game.id);
|
||||
/* game.crc */
|
||||
|
||||
for (i = 0; i < MAX_FLAGS; i++)
|
||||
write_uint8(&f, game.flags[i]);
|
||||
for (i = 0; i < MAX_VARS; i++)
|
||||
write_uint8(&f, game.vars[i]);
|
||||
|
||||
write_sint16(&f, (int8) game.horizon);
|
||||
write_sint16(&f, (int16) game.line_status);
|
||||
write_sint16(&f, (int16) game.line_user_input);
|
||||
write_sint16(&f, (int16) game.line_min_print);
|
||||
/* game.cursor_pos */
|
||||
/* game.input_buffer */
|
||||
/* game.echo_buffer */
|
||||
/* game.keypress */
|
||||
write_sint16(&f, (int16) game.input_mode);
|
||||
write_sint16(&f, (int16) game.lognum);
|
||||
|
||||
write_sint16(&f, (int16) game.player_control);
|
||||
write_sint16(&f, (int16) game.quit_prog_now);
|
||||
write_sint16(&f, (int16) game.status_line);
|
||||
write_sint16(&f, (int16) game.clock_enabled);
|
||||
write_sint16(&f, (int16) game.exit_all_logics);
|
||||
write_sint16(&f, (int16) game.picture_shown);
|
||||
write_sint16(&f, (int16) game.has_prompt);
|
||||
write_sint16(&f, (int16) game.game_flags);
|
||||
|
||||
/* Reversed to keep compatibility with old savegames */
|
||||
write_sint16(&f, (int16)!game.input_enabled);
|
||||
|
||||
for (i = 0; i < _HEIGHT; i++)
|
||||
write_uint8(&f, game.pri_table[i]);
|
||||
|
||||
/* game.msg_box_ticks */
|
||||
/* game.block */
|
||||
/* game.window */
|
||||
/* game.has_window */
|
||||
|
||||
write_sint16(&f, (int16)game.gfx_mode);
|
||||
write_uint8(&f, game.cursor_char);
|
||||
write_sint16(&f, (int16)game.color_fg);
|
||||
write_sint16(&f, (int16)game.color_bg);
|
||||
|
||||
/* game.hires (#ifdef USE_HIRES) */
|
||||
/* game.sbuf */
|
||||
/* game.ego_words */
|
||||
/* game.num_ego_words */
|
||||
|
||||
write_sint16(&f, (int16)game.num_objects);
|
||||
for (i = 0; i < (int16)game.num_objects; i++)
|
||||
write_sint16(&f, (int16)object_get_location(i));
|
||||
|
||||
/* game.ev_keyp */
|
||||
for (i = 0; i < MAX_STRINGS; i++)
|
||||
write_string(&f, game.strings[i]);
|
||||
|
||||
/* record info about loaded resources */
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
write_uint8(&f, game.dir_logic[i].flags);
|
||||
write_sint16(&f, (int16)game.logics[i].sIP);
|
||||
write_sint16(&f, (int16)game.logics[i].cIP);
|
||||
}
|
||||
for (i = 0; i < MAX_DIRS; i++)
|
||||
write_uint8(&f, game.dir_pic[i].flags);
|
||||
for (i = 0; i < MAX_DIRS; i++)
|
||||
write_uint8(&f, game.dir_view[i].flags);
|
||||
for (i = 0; i < MAX_DIRS; i++)
|
||||
write_uint8(&f, game.dir_sound[i].flags);
|
||||
|
||||
/* game.pictures */
|
||||
/* game.logics */
|
||||
/* game.views */
|
||||
/* game.sounds */
|
||||
|
||||
for (i = 0; i < MAX_VIEWTABLE; i++) {
|
||||
struct vt_entry *v = &game.view_table[i];
|
||||
|
||||
write_uint8(&f, v->step_time);
|
||||
write_uint8(&f, v->step_time_count);
|
||||
write_uint8(&f, v->entry);
|
||||
write_sint16(&f, v->x_pos);
|
||||
write_sint16(&f, v->y_pos);
|
||||
write_uint8(&f, v->current_view);
|
||||
|
||||
/* v->view_data */
|
||||
|
||||
write_uint8(&f, v->current_loop);
|
||||
write_uint8(&f, v->num_loops);
|
||||
|
||||
/* v->loop_data */
|
||||
|
||||
write_uint8(&f, v->current_cel);
|
||||
write_uint8(&f, v->num_cels);
|
||||
|
||||
/* v->cel_data */
|
||||
/* v->cel_data_2 */
|
||||
|
||||
write_sint16(&f, v->x_pos2);
|
||||
write_sint16(&f, v->y_pos2);
|
||||
|
||||
/* v->s */
|
||||
|
||||
write_sint16(&f, v->x_size);
|
||||
write_sint16(&f, v->y_size);
|
||||
write_uint8(&f, v->step_size);
|
||||
write_uint8(&f, v->cycle_time);
|
||||
write_uint8(&f, v->cycle_time_count);
|
||||
write_uint8(&f, v->direction);
|
||||
|
||||
write_uint8(&f, v->motion);
|
||||
write_uint8(&f, v->cycle);
|
||||
write_uint8(&f, v->priority);
|
||||
|
||||
write_uint16(&f, v->flags);
|
||||
|
||||
write_uint8(&f, v->parm1);
|
||||
write_uint8(&f, v->parm2);
|
||||
write_uint8(&f, v->parm3);
|
||||
write_uint8(&f, v->parm4);
|
||||
}
|
||||
|
||||
/* Save image stack */
|
||||
|
||||
for (i = 0; i < image_stack_pointer; i++) {
|
||||
ptr = &image_stack[i];
|
||||
write_uint8(&f, ptr->type);
|
||||
write_sint16(&f, ptr->parm1);
|
||||
write_sint16(&f, ptr->parm2);
|
||||
write_sint16(&f, ptr->parm3);
|
||||
write_sint16(&f, ptr->parm4);
|
||||
write_sint16(&f, ptr->parm5);
|
||||
write_sint16(&f, ptr->parm6);
|
||||
write_sint16(&f, ptr->parm7);
|
||||
}
|
||||
write_uint8(&f, 0);
|
||||
|
||||
f.close();
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
int load_game(char *s) {
|
||||
int i, ver, vt_entries = MAX_VIEWTABLE;
|
||||
uint8 t;
|
||||
int16 parm[7];
|
||||
char sig[8];
|
||||
char id[8];
|
||||
char description[256];
|
||||
Common::File f;
|
||||
|
||||
f.open(s);
|
||||
|
||||
if (!f.isOpen())
|
||||
return err_BadFileOpen;
|
||||
|
||||
read_bytes(&f, sig, 8);
|
||||
if (strncmp(sig, strSig, 8)) {
|
||||
f.close();
|
||||
return err_BadFileOpen;
|
||||
}
|
||||
|
||||
read_string(&f, description);
|
||||
|
||||
ver = read_uint8(&f);
|
||||
if (ver == 0)
|
||||
vt_entries = 64;
|
||||
game.state = read_uint8(&f);
|
||||
/* game.name - not saved */
|
||||
read_string(&f, id);
|
||||
if (strcmp(id, game.id)) {
|
||||
f.close();
|
||||
return err_BadFileOpen;
|
||||
}
|
||||
/* game.crc - not saved */
|
||||
|
||||
for (i = 0; i < MAX_FLAGS; i++)
|
||||
game.flags[i] = read_uint8(&f);
|
||||
for (i = 0; i < MAX_VARS; i++)
|
||||
game.vars[i] = read_uint8(&f);
|
||||
|
||||
game.horizon = read_sint16(&f);
|
||||
game.line_status = read_sint16(&f);
|
||||
game.line_user_input = read_sint16(&f);
|
||||
game.line_min_print = read_sint16(&f);
|
||||
|
||||
/* These are never saved */
|
||||
game.cursor_pos = 0;
|
||||
game.input_buffer[0] = 0;
|
||||
game.echo_buffer[0] = 0;
|
||||
game.keypress = 0;
|
||||
|
||||
game.input_mode = read_sint16(&f);
|
||||
game.lognum = read_sint16(&f);
|
||||
|
||||
game.player_control = read_sint16(&f);
|
||||
game.quit_prog_now = read_sint16(&f);
|
||||
game.status_line = read_sint16(&f);
|
||||
game.clock_enabled = read_sint16(&f);
|
||||
game.exit_all_logics = read_sint16(&f);
|
||||
game.picture_shown = read_sint16(&f);
|
||||
game.has_prompt = read_sint16(&f);
|
||||
game.game_flags = read_sint16(&f);
|
||||
game.input_enabled = !read_sint16(&f);
|
||||
|
||||
for (i = 0; i < _HEIGHT; i++)
|
||||
game.pri_table[i] = read_uint8(&f);
|
||||
|
||||
if (game.has_window)
|
||||
close_window();
|
||||
game.msg_box_ticks = 0;
|
||||
game.block.active = false;
|
||||
/* game.window - fixed by close_window() */
|
||||
/* game.has_window - fixed by close_window() */
|
||||
|
||||
game.gfx_mode = read_sint16(&f);
|
||||
game.cursor_char = read_uint8(&f);
|
||||
game.color_fg = read_sint16(&f);
|
||||
game.color_bg = read_sint16(&f);
|
||||
|
||||
/* game.hires (#ifdef USE_HIRES) - rebuilt from image stack */
|
||||
/* game.sbuf - rebuilt from image stack */
|
||||
|
||||
/* game.ego_words - fixed by clean_input */
|
||||
/* game.num_ego_words - fixed by clean_input */
|
||||
|
||||
game.num_objects = read_sint16(&f);
|
||||
for (i = 0; i < (int16) game.num_objects; i++)
|
||||
object_set_location(i, read_sint16(&f));
|
||||
|
||||
/* Those are not serialized */
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
game.ev_keyp[i].occured = false;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_STRINGS; i++)
|
||||
read_string(&f, game.strings[i]);
|
||||
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
if (read_uint8(&f) & RES_LOADED)
|
||||
agi_load_resource(rLOGIC, i);
|
||||
else
|
||||
agi_unload_resource(rLOGIC, i);
|
||||
game.logics[i].sIP = read_sint16(&f);
|
||||
game.logics[i].cIP = read_sint16(&f);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
if (read_uint8(&f) & RES_LOADED)
|
||||
agi_load_resource(rPICTURE, i);
|
||||
else
|
||||
agi_unload_resource(rPICTURE, i);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
if (read_uint8(&f) & RES_LOADED)
|
||||
agi_load_resource(rVIEW, i);
|
||||
else
|
||||
agi_unload_resource(rVIEW, i);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_DIRS; i++) {
|
||||
if (read_uint8(&f) & RES_LOADED)
|
||||
agi_load_resource(rSOUND, i);
|
||||
else
|
||||
agi_unload_resource(rSOUND, i);
|
||||
}
|
||||
|
||||
/* game.pictures - loaded above */
|
||||
/* game.logics - loaded above */
|
||||
/* game.views - loaded above */
|
||||
/* game.sounds - loaded above */
|
||||
|
||||
for (i = 0; i < vt_entries; i++) {
|
||||
struct vt_entry *v = &game.view_table[i];
|
||||
|
||||
v->step_time = read_uint8(&f);
|
||||
v->step_time_count = read_uint8(&f);
|
||||
v->entry = read_uint8(&f);
|
||||
v->x_pos = read_sint16(&f);
|
||||
v->y_pos = read_sint16(&f);
|
||||
v->current_view = read_uint8(&f);
|
||||
|
||||
/* v->view_data - fixed below */
|
||||
|
||||
v->current_loop = read_uint8(&f);
|
||||
v->num_loops = read_uint8(&f);
|
||||
|
||||
/* v->loop_data - fixed below */
|
||||
|
||||
v->current_cel = read_uint8(&f);
|
||||
v->num_cels = read_uint8(&f);
|
||||
|
||||
/* v->cel_data - fixed below */
|
||||
/* v->cel_data_2 - fixed below */
|
||||
|
||||
v->x_pos2 = read_sint16(&f);
|
||||
v->y_pos2 = read_sint16(&f);
|
||||
|
||||
/* v->s - fixed below */
|
||||
|
||||
v->x_size = read_sint16(&f);
|
||||
v->y_size = read_sint16(&f);
|
||||
v->step_size = read_uint8(&f);
|
||||
v->cycle_time = read_uint8(&f);
|
||||
v->cycle_time_count = read_uint8(&f);
|
||||
v->direction = read_uint8(&f);
|
||||
|
||||
v->motion = read_uint8(&f);
|
||||
v->cycle = read_uint8(&f);
|
||||
v->priority = read_uint8(&f);
|
||||
|
||||
v->flags = read_uint16(&f);
|
||||
|
||||
v->parm1 = read_uint8(&f);
|
||||
v->parm2 = read_uint8(&f);
|
||||
v->parm3 = read_uint8(&f);
|
||||
v->parm4 = read_uint8(&f);
|
||||
}
|
||||
for (i = vt_entries; i < MAX_VIEWTABLE; i++) {
|
||||
memset(&game.view_table[i], 0, sizeof(struct vt_entry));
|
||||
}
|
||||
|
||||
/* Fix some pointers in viewtable */
|
||||
|
||||
for (i = 0; i < MAX_VIEWTABLE; i++) {
|
||||
struct vt_entry *v = &game.view_table[i];
|
||||
|
||||
if (game.dir_view[v->current_view].offset == _EMPTY)
|
||||
continue;
|
||||
|
||||
if (!(game.dir_view[v->current_view].flags & RES_LOADED))
|
||||
agi_load_resource(rVIEW, v->current_view);
|
||||
|
||||
set_view(v, v->current_view); /* Fix v->view_data */
|
||||
set_loop(v, v->current_loop); /* Fix v->loop_data */
|
||||
set_cel(v, v->current_cel); /* Fix v->cel_data */
|
||||
v->cel_data_2 = v->cel_data;
|
||||
v->s = NULL; /* not sure if it is used... */
|
||||
}
|
||||
|
||||
erase_both();
|
||||
|
||||
/* Clear input line */
|
||||
clear_screen(0);
|
||||
write_status();
|
||||
|
||||
/* Recreate background from saved image stack */
|
||||
clear_image_stack();
|
||||
while ((t = read_uint8(&f)) != 0) {
|
||||
for (i = 0; i < 7; i++)
|
||||
parm[i] = read_sint16(&f);
|
||||
replay_image_stack_call(t, parm[0], parm[1], parm[2],
|
||||
parm[3], parm[4], parm[5], parm[6]);
|
||||
}
|
||||
|
||||
f.close();
|
||||
|
||||
setflag(F_restore_just_ran, true);
|
||||
|
||||
game.has_prompt = 0; /* force input line repaint if necessary */
|
||||
clean_input();
|
||||
|
||||
erase_both();
|
||||
blit_both();
|
||||
commit_both();
|
||||
show_pic();
|
||||
do_update();
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
#define NUM_SLOTS 12
|
||||
|
||||
static int select_slot() {
|
||||
int i, key, active = 0;
|
||||
int rc = -1;
|
||||
int hm = 2, vm = 3; /* box margins */
|
||||
char desc[NUM_SLOTS][40];
|
||||
|
||||
for (i = 0; i < NUM_SLOTS; i++) {
|
||||
char name[MAX_PATH];
|
||||
Common::File f;
|
||||
char sig[8];
|
||||
sprintf(name, "%s/%05X_%s_%02d.sav", _savePath, game.crc, game.id, i);
|
||||
f.open(name);
|
||||
if (!f.isOpen()) {
|
||||
strcpy(desc[i], " (empty slot)");
|
||||
} else {
|
||||
read_bytes(&f, sig, 8);
|
||||
if (strncmp(sig, strSig, 8)) {
|
||||
strcpy(desc[i], "(corrupt file)");
|
||||
} else {
|
||||
read_string(&f, desc[i]);
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
|
||||
while (42) {
|
||||
char dstr[64];
|
||||
for (i = 0; i < NUM_SLOTS; i++) {
|
||||
sprintf(dstr, "[%-32.32s]", desc[i]);
|
||||
print_text(dstr, 0, hm + 1, vm + 4 + i,
|
||||
(40 - 2 * hm) - 1, i == active ? MSG_BOX_COLOUR : MSG_BOX_TEXT,
|
||||
i == active ? MSG_BOX_TEXT : MSG_BOX_COLOUR);
|
||||
|
||||
}
|
||||
|
||||
poll_timer(); /* msdos driver -> does nothing */
|
||||
key = do_poll_keyboard();
|
||||
if (!console_keyhandler(key)) {
|
||||
switch (key) {
|
||||
case KEY_ENTER:
|
||||
rc = active;
|
||||
strncpy(game.strings[MAX_STRINGS], desc[i], MAX_STRINGLEN);
|
||||
goto press;
|
||||
case KEY_ESCAPE:
|
||||
rc = -1;
|
||||
goto getout;
|
||||
#ifdef USE_MOUSE
|
||||
case BUTTON_LEFT:
|
||||
break;
|
||||
#endif
|
||||
case KEY_DOWN:
|
||||
active++;
|
||||
active %= NUM_SLOTS;
|
||||
break;
|
||||
case KEY_UP:
|
||||
active--;
|
||||
if (active < 0)
|
||||
active = NUM_SLOTS - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
console_cycle();
|
||||
}
|
||||
|
||||
press:
|
||||
debugC(8, kDebugLevelMain | kDebugLevelInput, "Button pressed: %d", rc);
|
||||
|
||||
getout:
|
||||
close_window();
|
||||
return rc;
|
||||
}
|
||||
|
||||
int savegame_simple() {
|
||||
char path[MAX_PATH];
|
||||
|
||||
sprintf(path, "%s/%05X_%s_%02d.sav", _savePath, game.crc, game.id, 0);
|
||||
save_game(path, "Default savegame");
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
int savegame_dialog() {
|
||||
char path[MAX_PATH];
|
||||
char *desc;
|
||||
char *buttons[] = { "Do as I say!", "I regret", NULL };
|
||||
char dstr[200];
|
||||
int rc, slot = 0;
|
||||
int hm, vm, hp, vp; /* box margins */
|
||||
int w;
|
||||
|
||||
hm = 2;
|
||||
vm = 3;
|
||||
hp = hm * CHAR_COLS;
|
||||
vp = vm * CHAR_LINES;
|
||||
w = (40 - 2 * hm) - 1;
|
||||
|
||||
sprintf(path, "%s/%05X_%s_%02d.sav", _savePath, game.crc, game.id, slot);
|
||||
|
||||
draw_window(hp, vp, GFX_WIDTH - hp, GFX_HEIGHT - vp);
|
||||
print_text("Select a slot in which you wish to save the game:",
|
||||
0, hm + 1, vm + 1, w, MSG_BOX_TEXT, MSG_BOX_COLOUR);
|
||||
print_text("Press ENTER to select, ESC cancels",
|
||||
0, hm + 1, vm + 17, w, MSG_BOX_TEXT, MSG_BOX_COLOUR);
|
||||
|
||||
slot = select_slot();
|
||||
if (slot < 0) /* ESC pressed */
|
||||
return err_OK;
|
||||
|
||||
/* Get savegame description */
|
||||
draw_window(hp, vp + 5 * CHAR_LINES, GFX_WIDTH - hp,
|
||||
GFX_HEIGHT - vp - 9 * CHAR_LINES);
|
||||
print_text("Enter a description for this game:",
|
||||
0, hm + 1, vm + 6, w, MSG_BOX_TEXT, MSG_BOX_COLOUR);
|
||||
draw_rectangle(3 * CHAR_COLS, 11 * CHAR_LINES - 1,
|
||||
37 * CHAR_COLS, 12 * CHAR_LINES, MSG_BOX_TEXT);
|
||||
flush_block(3 * CHAR_COLS, 11 * CHAR_LINES - 1,
|
||||
37 * CHAR_COLS, 12 * CHAR_LINES);
|
||||
|
||||
get_string(2, 11, 33, MAX_STRINGS);
|
||||
print_character(3, 11, game.cursor_char, MSG_BOX_COLOUR, MSG_BOX_TEXT);
|
||||
do {
|
||||
main_cycle();
|
||||
} while (game.input_mode == INPUT_GETSTRING);
|
||||
close_window();
|
||||
|
||||
desc = game.strings[MAX_STRINGS];
|
||||
sprintf(dstr, "Are you sure you want to save the game "
|
||||
"described as:\n\n%s\n\nin slot %d?\n\n\n", desc, slot);
|
||||
|
||||
rc = selection_box(dstr, buttons);
|
||||
|
||||
if (rc != 0) {
|
||||
message_box("Game NOT saved.");
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
sprintf(path, "%s/%05X_%s_%02d.sav", _savePath, game.crc, game.id, slot);
|
||||
debugC(8, kDebugLevelMain | kDebugLevelResources, "file is [%s]", path);
|
||||
|
||||
save_game(path, desc);
|
||||
|
||||
message_box("Game saved.");
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
int loadgame_simple() {
|
||||
char path[MAX_PATH];
|
||||
int rc = 0;
|
||||
|
||||
sprintf(path, "%s/%05X_%s_%02d.sav", _savePath, game.crc, game.id, 0);
|
||||
|
||||
erase_both();
|
||||
stop_sound();
|
||||
close_window();
|
||||
|
||||
if ((rc = load_game(path)) == err_OK) {
|
||||
message_box("Game restored.");
|
||||
game.exit_all_logics = 1;
|
||||
menu_enable_all();
|
||||
} else {
|
||||
message_box("Error restoring game.");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int loadgame_dialog() {
|
||||
char path[MAX_PATH];
|
||||
int rc, slot = 0;
|
||||
int hm, vm, hp, vp; /* box margins */
|
||||
int w;
|
||||
|
||||
hm = 2;
|
||||
vm = 3;
|
||||
hp = hm * CHAR_COLS;
|
||||
vp = vm * CHAR_LINES;
|
||||
w = (40 - 2 * hm) - 1;
|
||||
|
||||
sprintf(path, "%s/%05X_%s_%02d.sav", _savePath, game.crc, game.id, slot);
|
||||
|
||||
erase_both();
|
||||
stop_sound();
|
||||
|
||||
draw_window(hp, vp, GFX_WIDTH - hp, GFX_HEIGHT - vp);
|
||||
print_text("Select a game which you wish to\nrestore:",
|
||||
0, hm + 1, vm + 1, w, MSG_BOX_TEXT, MSG_BOX_COLOUR);
|
||||
print_text("Press ENTER to select, ESC cancels",
|
||||
0, hm + 1, vm + 17, w, MSG_BOX_TEXT, MSG_BOX_COLOUR);
|
||||
|
||||
slot = select_slot();
|
||||
|
||||
if (slot < 0) {
|
||||
message_box("Game NOT restored.");
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
sprintf(path, "%s/%05X_%s_%02d.sav", _savePath, game.crc, game.id, slot);
|
||||
|
||||
if ((rc = load_game(path)) == err_OK) {
|
||||
message_box("Game restored.");
|
||||
game.exit_all_logics = 1;
|
||||
menu_enable_all();
|
||||
} else {
|
||||
message_box("Error restoring game.");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
50
engines/agi/savegame.h
Normal file
50
engines/agi/savegame.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_SAVEGAME_H
|
||||
#define __AGI_SAVEGAME_H
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
int savegame_dialog(void);
|
||||
int loadgame_dialog(void);
|
||||
int savegame_simple(void);
|
||||
int loadgame_simple(void);
|
||||
|
||||
/* Image stack support */
|
||||
#define ADD_PIC 1
|
||||
#define ADD_VIEW 2
|
||||
|
||||
void clear_image_stack(void);
|
||||
void record_image_stack_call(uint8 type, int16 p1, int16 p2, int16 p3,
|
||||
int16 p4, int16 p5, int16 p6, int16 p7);
|
||||
void replay_image_stack_call(uint8 type, int16 p1, int16 p2, int16 p3,
|
||||
int16 p4, int16 p5, int16 p6, int16 p7);
|
||||
void release_image_stack(void);
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif
|
772
engines/agi/sound.cpp
Normal file
772
engines/agi/sound.cpp
Normal file
@ -0,0 +1,772 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/stdafx.h"
|
||||
|
||||
#include "sound/mixer.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#define USE_INTERPOLATION
|
||||
#define USE_CHORUS
|
||||
|
||||
/* TODO: add support for variable sampling rate in the output device
|
||||
*/
|
||||
|
||||
#ifdef USE_IIGS_SOUND
|
||||
|
||||
/**
|
||||
* AGI engine sound envelope structure.
|
||||
*/
|
||||
struct sound_envelope {
|
||||
uint8 bp;
|
||||
uint8 inc_hi;
|
||||
uint8 inc_lo;
|
||||
};
|
||||
|
||||
struct sound_wavelist {
|
||||
uint8 top;
|
||||
uint8 addr;
|
||||
uint8 size;
|
||||
uint8 mode;
|
||||
uint8 rel_hi;
|
||||
uint8 rel_lo;
|
||||
};
|
||||
|
||||
struct sound_instrument {
|
||||
struct sound_envelope env[8];
|
||||
uint8 relseg;
|
||||
uint8 priority;
|
||||
uint8 bendrange;
|
||||
uint8 vibdepth;
|
||||
uint8 vibspeed;
|
||||
uint8 spare;
|
||||
uint8 wac;
|
||||
uint8 wbc;
|
||||
struct sound_wavelist wal[8];
|
||||
struct sound_wavelist wbl[8];
|
||||
};
|
||||
|
||||
struct sound_iigs_sample {
|
||||
uint8 type_lo;
|
||||
uint8 type_hi;
|
||||
uint8 srate_lo;
|
||||
uint8 srate_hi;
|
||||
uint16 unknown[2];
|
||||
uint8 size_lo;
|
||||
uint8 size_hi;
|
||||
uint16 unknown2[13];
|
||||
};
|
||||
|
||||
#if 0
|
||||
static struct sound_instrument *instruments;
|
||||
static int num_instruments;
|
||||
static uint8 *wave;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static int playing;
|
||||
static struct channel_info chn[NUM_CHANNELS];
|
||||
static int endflag = -1;
|
||||
static int playing_sound = -1;
|
||||
static uint8 *song;
|
||||
static uint8 env;
|
||||
|
||||
struct sound_driver *snd;
|
||||
|
||||
extern struct sound_driver sound_dummy;
|
||||
|
||||
static void stop_note(int i);
|
||||
static void play_note(int i, int freq, int vol);
|
||||
|
||||
#ifdef USE_PCM_SOUND
|
||||
|
||||
int16 *snd_buffer;
|
||||
static int16 *waveform;
|
||||
|
||||
static int16 waveform_ramp[WAVEFORM_SIZE] = {
|
||||
0, 8, 16, 24, 32, 40, 48, 56,
|
||||
64, 72, 80, 88, 96, 104, 112, 120,
|
||||
128, 136, 144, 152, 160, 168, 176, 184,
|
||||
192, 200, 208, 216, 224, 232, 240, 255,
|
||||
0, -248, -240, -232, -224, -216, -208, -200,
|
||||
-192, -184, -176, -168, -160, -152, -144, -136,
|
||||
-128, -120, -112, -104, -96, -88, -80, -72,
|
||||
-64, -56, -48, -40, -32, -24, -16, -8 /* Ramp up */
|
||||
};
|
||||
|
||||
static int16 waveform_square[WAVEFORM_SIZE] = {
|
||||
255, 230, 220, 220, 220, 220, 220, 220,
|
||||
220, 220, 220, 220, 220, 220, 220, 220,
|
||||
220, 220, 220, 220, 220, 220, 220, 220,
|
||||
220, 220, 220, 220, 220, 220, 220, 110,
|
||||
-255, -230, -220, -220, -220, -220, -220, -220,
|
||||
-220, -220, -220, -220, -220, -220, -220, -220,
|
||||
-220, -220, -220, -220, -220, -220, -220, -220,
|
||||
-220, -220, -220, -110, 0, 0, 0, 0 /* Square */
|
||||
};
|
||||
|
||||
static int16 waveform_mac[WAVEFORM_SIZE] = {
|
||||
45, 110, 135, 161, 167, 173, 175, 176,
|
||||
156, 137, 123, 110, 91, 72, 35, -2,
|
||||
-60, -118, -142, -165, -170, -176, -177, -179,
|
||||
-177, -176, -164, -152, -117, -82, -17, 47,
|
||||
92, 137, 151, 166, 170, 173, 171, 169,
|
||||
151, 133, 116, 100, 72, 43, -7, -57,
|
||||
-99, -141, -156, -170, -174, -177, -178, -179,
|
||||
-175, -172, -165, -159, -137, -114, -67, -19
|
||||
};
|
||||
|
||||
#endif /* USE_PCM_SOUND */
|
||||
|
||||
#ifdef USE_IIGS_SOUND
|
||||
|
||||
static uint16 period[] = {
|
||||
1024, 1085, 1149, 1218, 1290, 1367,
|
||||
1448, 1534, 1625, 1722, 1825, 1933
|
||||
};
|
||||
|
||||
static struct agi_note play_sample[] = {
|
||||
{0xff, 0x7f, 0x18, 0x00, 0x7f},
|
||||
{0xff, 0xff, 0x00, 0x00, 0x00},
|
||||
{0xff, 0xff, 0x00, 0x00, 0x00},
|
||||
{0xff, 0xff, 0x00, 0x00, 0x00}
|
||||
};
|
||||
|
||||
static int note_to_period(int note) {
|
||||
return 10 * (period[note % 12] >> (note / 12 - 3));
|
||||
}
|
||||
|
||||
#endif /* USE_IIGS_SOUND */
|
||||
|
||||
void unload_sound(int resnum) {
|
||||
if (game.dir_sound[resnum].flags & RES_LOADED) {
|
||||
if (game.sounds[resnum].flags & SOUND_PLAYING)
|
||||
/* FIXME: Stop playing */
|
||||
;
|
||||
|
||||
/* Release RAW data for sound */
|
||||
free(game.sounds[resnum].rdata);
|
||||
game.sounds[resnum].rdata = NULL;
|
||||
game.dir_sound[resnum].flags &= ~RES_LOADED;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_sound(int resnum) {
|
||||
#ifdef USE_IIGS_SOUND
|
||||
int type, size;
|
||||
int16 *buf;
|
||||
uint8 *src;
|
||||
struct sound_iigs_sample *smp;
|
||||
|
||||
debugC(3, kDebugLevelSound, "(%d)", resnum);
|
||||
type = READ_LE_UINT16(game.sounds[resnum].rdata);
|
||||
|
||||
if (type == AGI_SOUND_SAMPLE) {
|
||||
/* Convert sample data to 16 bit signed format
|
||||
*/
|
||||
smp = (struct sound_iigs_sample *)game.sounds[resnum].rdata;
|
||||
size = ((int)smp->size_hi << 8) + smp->size_lo;
|
||||
src = (uint8 *) game.sounds[resnum].rdata;
|
||||
buf = (int16 *) calloc(1, 54 + (size << 1) + 100); /* FIXME */
|
||||
memcpy(buf, src, 54);
|
||||
for (; size--; buf[size + 54] = ((int16) src[size + 54] - 0x80) << 4); /* FIXME */
|
||||
game.sounds[resnum].rdata = (uint8 *) buf;
|
||||
free(src);
|
||||
}
|
||||
#endif /* USE_IIGS_SOUND */
|
||||
}
|
||||
|
||||
void start_sound(int resnum, int flag) {
|
||||
int i, type;
|
||||
#ifdef USE_IIGS_SOUND
|
||||
struct sound_iigs_sample *smp;
|
||||
#endif
|
||||
|
||||
if (game.sounds[resnum].flags & SOUND_PLAYING)
|
||||
return;
|
||||
|
||||
stop_sound();
|
||||
|
||||
if (game.sounds[resnum].rdata == NULL)
|
||||
return;
|
||||
|
||||
type = READ_LE_UINT16(game.sounds[resnum].rdata);
|
||||
|
||||
if (type != AGI_SOUND_SAMPLE && type != AGI_SOUND_MIDI && type != AGI_SOUND_4CHN)
|
||||
return;
|
||||
|
||||
game.sounds[resnum].flags |= SOUND_PLAYING;
|
||||
game.sounds[resnum].type = type;
|
||||
playing_sound = resnum;
|
||||
song = (uint8 *) game.sounds[resnum].rdata;
|
||||
|
||||
switch (type) {
|
||||
#ifdef USE_IIGS_SOUND
|
||||
case AGI_SOUND_SAMPLE:
|
||||
debugC(3, kDebugLevelSound, "IIGS sample");
|
||||
smp = (struct sound_iigs_sample *)game.sounds[resnum].rdata;
|
||||
for (i = 0; i < NUM_CHANNELS; i++) {
|
||||
chn[i].type = type;
|
||||
chn[i].flags = 0;
|
||||
chn[i].ins = (int16 *) & game.sounds[resnum].rdata[54];
|
||||
chn[i].size = ((int)smp->size_hi << 8) + smp->size_lo;
|
||||
chn[i].ptr = &play_sample[i];
|
||||
chn[i].timer = 0;
|
||||
chn[i].vol = 0;
|
||||
chn[i].end = 0;
|
||||
}
|
||||
break;
|
||||
case AGI_SOUND_MIDI:
|
||||
debugC(3, kDebugLevelSound, "IIGS MIDI sequence");
|
||||
|
||||
for (i = 0; i < NUM_CHANNELS; i++) {
|
||||
chn[i].type = type;
|
||||
chn[i].flags = AGI_SOUND_LOOP | AGI_SOUND_ENVELOPE;
|
||||
chn[i].ins = waveform;
|
||||
chn[i].size = WAVEFORM_SIZE;
|
||||
chn[i].vol = 0;
|
||||
chn[i].end = 0;
|
||||
}
|
||||
|
||||
chn[0].timer = *(song + 2);
|
||||
chn[0].ptr = (struct agi_note *)(song + 3);
|
||||
break;
|
||||
#endif
|
||||
case AGI_SOUND_4CHN:
|
||||
/* Initialize channel info */
|
||||
for (i = 0; i < NUM_CHANNELS; i++) {
|
||||
chn[i].type = type;
|
||||
chn[i].flags = AGI_SOUND_LOOP;
|
||||
if (env) {
|
||||
chn[i].flags |= AGI_SOUND_ENVELOPE;
|
||||
chn[i].adsr = AGI_SOUND_ENV_ATTACK;
|
||||
}
|
||||
#ifdef USE_PCM_SOUND
|
||||
chn[i].ins = waveform;
|
||||
chn[i].size = WAVEFORM_SIZE;
|
||||
#endif
|
||||
chn[i].ptr = (struct agi_note *)(song + (song[i << 1] | (song[(i << 1) + 1] << 8)));
|
||||
chn[i].timer = 0;
|
||||
chn[i].vol = 0;
|
||||
chn[i].end = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef USE_PCM_SOUND
|
||||
memset(snd_buffer, 0, BUFFER_SIZE << 1);
|
||||
#endif
|
||||
endflag = flag;
|
||||
|
||||
/* Nat Budin reports that the flag should be reset when sound starts
|
||||
*/
|
||||
setflag(endflag, false);
|
||||
|
||||
/* FIXME: should wait for sound time instead of setting the flag
|
||||
* immediately
|
||||
*/
|
||||
if (opt.nosound) {
|
||||
setflag(endflag, true);
|
||||
stop_sound();
|
||||
}
|
||||
}
|
||||
|
||||
void stop_sound() {
|
||||
int i;
|
||||
|
||||
endflag = -1;
|
||||
for (i = 0; i < NUM_CHANNELS; i++)
|
||||
stop_note(i);
|
||||
|
||||
if (playing_sound != -1) {
|
||||
game.sounds[playing_sound].flags &= ~SOUND_PLAYING;
|
||||
playing_sound = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int16 *buffer;
|
||||
|
||||
int init_sound() {
|
||||
int r = -1;
|
||||
|
||||
#ifdef USE_PCM_SOUND
|
||||
buffer = snd_buffer = (int16 *) calloc(2, BUFFER_SIZE);
|
||||
#endif
|
||||
|
||||
env = false;
|
||||
|
||||
#ifdef USE_PCM_SOUND
|
||||
switch (opt.soundemu) {
|
||||
case SOUND_EMU_NONE:
|
||||
waveform = waveform_ramp;
|
||||
env = true;
|
||||
break;
|
||||
case SOUND_EMU_AMIGA:
|
||||
case SOUND_EMU_PC:
|
||||
waveform = waveform_square;
|
||||
break;
|
||||
case SOUND_EMU_MAC:
|
||||
waveform = waveform_mac;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
report("Initializing sound:\n");
|
||||
|
||||
report("sound: envelopes ");
|
||||
if (env) {
|
||||
report("enabled (decay=%d, sustain=%d)\n", ENV_DECAY, ENV_SUSTAIN);
|
||||
} else {
|
||||
report("disabled\n");
|
||||
}
|
||||
|
||||
#ifdef USE_IIGS_SOUND
|
||||
/*load_instruments ("demo.sys"); */
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void deinit_sound(void) {
|
||||
debugC(3, kDebugLevelSound, "()");
|
||||
if (snd)
|
||||
snd->deinit();
|
||||
#ifdef USE_PCM_SOUND
|
||||
free(snd_buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void stop_note(int i) {
|
||||
chn[i].adsr = AGI_SOUND_ENV_RELEASE;
|
||||
|
||||
#ifdef USE_CHORUS
|
||||
/* Stop chorus ;) */
|
||||
if (chn[i].type == AGI_SOUND_4CHN &&
|
||||
opt.soundemu == SOUND_EMU_NONE && i < 3) {
|
||||
stop_note(i + 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __TURBOC__
|
||||
if (i == 0)
|
||||
nosound();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void play_note(int i, int freq, int vol) {
|
||||
if (!getflag(F_sound_on))
|
||||
vol = 0;
|
||||
else if (vol && opt.soundemu == SOUND_EMU_PC)
|
||||
vol = 160;
|
||||
|
||||
#ifdef USE_PCM_SOUND
|
||||
chn[i].phase = 0;
|
||||
#endif
|
||||
|
||||
chn[i].freq = freq;
|
||||
chn[i].vol = vol;
|
||||
chn[i].env = 0x10000;
|
||||
chn[i].adsr = AGI_SOUND_ENV_ATTACK;
|
||||
|
||||
#ifdef USE_CHORUS
|
||||
/* Add chorus ;) */
|
||||
if (chn[i].type == AGI_SOUND_4CHN &&
|
||||
opt.soundemu == SOUND_EMU_NONE && i < 3) {
|
||||
int newfreq = freq * 1007 / 1000;
|
||||
if (freq == newfreq)
|
||||
newfreq++;
|
||||
play_note(i + 4, newfreq, vol * 2 / 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __TURBOC__
|
||||
if (i == 0)
|
||||
sound(freq);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_IIGS_SOUND
|
||||
|
||||
void play_midi_sound() {
|
||||
uint8 *p;
|
||||
uint8 parm1, parm2;
|
||||
static uint8 cmd, ch;
|
||||
|
||||
playing = 1;
|
||||
|
||||
if (chn[0].timer > 0) {
|
||||
chn[0].timer -= 2;
|
||||
return;
|
||||
}
|
||||
|
||||
p = (uint8 *) chn[0].ptr;
|
||||
|
||||
if (*p & 0x80) {
|
||||
cmd = *p++;
|
||||
ch = cmd & 0x0f;
|
||||
cmd >>= 4;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case 0x08:
|
||||
parm1 = *p++;
|
||||
parm2 = *p++;
|
||||
if (ch < NUM_CHANNELS)
|
||||
stop_note(ch);
|
||||
break;
|
||||
case 0x09:
|
||||
parm1 = *p++;
|
||||
parm2 = *p++;
|
||||
if (ch < NUM_CHANNELS)
|
||||
play_note(ch, note_to_period(parm1), 127);
|
||||
break;
|
||||
case 0x0b:
|
||||
parm1 = *p++;
|
||||
parm2 = *p++;
|
||||
debugC(3, kDebugLevelSound, "controller %02x, ch %02x, val %02x", parm1, ch, parm2);
|
||||
break;
|
||||
case 0x0c:
|
||||
parm1 = *p++;
|
||||
#if 0
|
||||
if (ch < NUM_CHANNELS) {
|
||||
chn[ch].ins = (uint16 *) & wave[waveaddr[parm1]];
|
||||
chn[ch].size = wavesize[parm1];
|
||||
}
|
||||
debugC(3, kDebugLevelSound, "set patch %02x (%d,%d), ch %02x",
|
||||
parm1, waveaddr[parm1], wavesize[parm1], ch);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
chn[0].timer = *p++;
|
||||
chn[0].ptr = (struct agi_note *)p;
|
||||
|
||||
if (*p >= 0xfc) {
|
||||
debugC(3, kDebugLevelSound, "end of sequence");
|
||||
playing = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void play_sample_sound() {
|
||||
play_note(0, 11025 * 10, 200);
|
||||
playing = 1;
|
||||
}
|
||||
|
||||
#endif /* USE_IIGS_SOUND */
|
||||
|
||||
void play_agi_sound() {
|
||||
int i, freq;
|
||||
|
||||
for (playing = i = 0; i < (opt.soundemu == SOUND_EMU_PC ? 1 : 4); i++) {
|
||||
playing |= !chn[i].end;
|
||||
|
||||
if (chn[i].end)
|
||||
continue;
|
||||
|
||||
if ((--chn[i].timer) <= 0) {
|
||||
stop_note(i);
|
||||
freq = ((chn[i].ptr->frq_0 & 0x3f) << 4) | (int)(chn[i].ptr->frq_1 & 0x0f);
|
||||
|
||||
if (freq) {
|
||||
uint8 v = chn[i].ptr->vol & 0x0f;
|
||||
play_note(i, freq * 10, v == 0xf ? 0 : 0xff - (v << 1));
|
||||
}
|
||||
|
||||
chn[i].timer = ((int)chn[i].ptr->dur_hi << 8) | chn[i].ptr->dur_lo;
|
||||
|
||||
if (chn[i].timer == 0xffff) {
|
||||
chn[i].end = 1;
|
||||
chn[i].vol = 0;
|
||||
chn[i].env = 0;
|
||||
#ifdef USE_CHORUS
|
||||
/* chorus */
|
||||
if (chn[i].type == AGI_SOUND_4CHN && opt.soundemu == SOUND_EMU_NONE && i < 3) {
|
||||
chn[i + 4].vol = 0;
|
||||
chn[i + 4].env = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
chn[i].ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void play_sound() {
|
||||
int i;
|
||||
|
||||
if (endflag == -1)
|
||||
return;
|
||||
|
||||
#ifdef USE_IIGS_SOUND
|
||||
if (chn[0].type == AGI_SOUND_MIDI) {
|
||||
/* play_midi_sound (); */
|
||||
playing = 0;
|
||||
} else if (chn[0].type == AGI_SOUND_SAMPLE) {
|
||||
play_sample_sound();
|
||||
} else
|
||||
#endif
|
||||
play_agi_sound();
|
||||
|
||||
if (!playing) {
|
||||
for (i = 0; i < NUM_CHANNELS; chn[i++].vol = 0);
|
||||
|
||||
if (endflag != -1)
|
||||
setflag(endflag, true);
|
||||
|
||||
if (playing_sound != -1)
|
||||
game.sounds[playing_sound].flags &= ~SOUND_PLAYING;
|
||||
playing_sound = -1;
|
||||
endflag = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_PCM_SOUND
|
||||
|
||||
uint32 mix_sound(void) {
|
||||
register int i, p;
|
||||
int16 *src;
|
||||
int c, b, m;
|
||||
|
||||
memset(snd_buffer, 0, BUFFER_SIZE << 1);
|
||||
|
||||
for (c = 0; c < NUM_CHANNELS; c++) {
|
||||
if (!chn[c].vol)
|
||||
continue;
|
||||
|
||||
m = chn[c].flags & AGI_SOUND_ENVELOPE ?
|
||||
chn[c].vol * chn[c].env >> 16 : chn[c].vol;
|
||||
|
||||
if (chn[c].type != AGI_SOUND_4CHN || c != 3) {
|
||||
src = chn[c].ins;
|
||||
|
||||
p = chn[c].phase;
|
||||
for (i = 0; i < BUFFER_SIZE; i++) {
|
||||
b = src[p >> 8];
|
||||
#ifdef USE_INTERPOLATION
|
||||
b += ((src[((p >> 8) + 1) % chn[c].size] - src[p >> 8]) * (p & 0xff)) >> 8;
|
||||
#endif
|
||||
snd_buffer[i] += (b * m) >> 4;
|
||||
|
||||
p += (uint32) 118600 *4 / chn[c].freq;
|
||||
|
||||
/* FIXME */
|
||||
if (chn[c].flags & AGI_SOUND_LOOP) {
|
||||
p %= chn[c].size << 8;
|
||||
} else {
|
||||
if (p >= chn[c].size << 8) {
|
||||
p = chn[c].vol = 0;
|
||||
chn[c].end = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
chn[c].phase = p;
|
||||
} else {
|
||||
/* Add white noise */
|
||||
for (i = 0; i < BUFFER_SIZE; i++) {
|
||||
b = rnd->getRandomNumber(255) - 128;
|
||||
snd_buffer[i] += (b * m) >> 4;
|
||||
}
|
||||
}
|
||||
|
||||
switch (chn[c].adsr) {
|
||||
case AGI_SOUND_ENV_ATTACK:
|
||||
/* not implemented */
|
||||
chn[c].adsr = AGI_SOUND_ENV_DECAY;
|
||||
break;
|
||||
case AGI_SOUND_ENV_DECAY:
|
||||
if (chn[c].env > chn[c].vol * ENV_SUSTAIN + ENV_DECAY) {
|
||||
chn[c].env -= ENV_DECAY;
|
||||
} else {
|
||||
chn[c].env = chn[c].vol * ENV_SUSTAIN;
|
||||
chn[c].adsr = AGI_SOUND_ENV_SUSTAIN;
|
||||
}
|
||||
break;
|
||||
case AGI_SOUND_ENV_SUSTAIN:
|
||||
break;
|
||||
case AGI_SOUND_ENV_RELEASE:
|
||||
if (chn[c].env >= ENV_RELEASE) {
|
||||
chn[c].env -= ENV_RELEASE;
|
||||
} else {
|
||||
chn[c].env = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BUFFER_SIZE;
|
||||
}
|
||||
|
||||
#ifdef USE_IIGS_SOUND
|
||||
|
||||
#if 0
|
||||
int load_instruments(char *fname) {
|
||||
Common::File fp;
|
||||
int i, j, k;
|
||||
struct sound_instrument ai;
|
||||
int num_wav;
|
||||
char *path;
|
||||
|
||||
path = "sierrast";
|
||||
|
||||
if (!fp.open(path))
|
||||
return err_BadFileOpen;
|
||||
report("Loading samples: %s\n", path);
|
||||
|
||||
if ((wave = malloc(0x10000 * 2)) == NULL)
|
||||
return err_NotEnoughMemory;
|
||||
|
||||
fp.read(wave, 0x10000);
|
||||
fp.close();
|
||||
for (i = 0x10000; i--;) {
|
||||
((int16 *) wave)[i] = 2 * ((int16) wave[i] - 128);
|
||||
}
|
||||
|
||||
fp = fopen("bla", "w");
|
||||
fwrite(wave, 2, 0x10000, fp);
|
||||
fclose(fp);
|
||||
|
||||
report("Loading instruments: %s\n", path);
|
||||
|
||||
if ((fp = fopen(path, "rb")) == NULL)
|
||||
return err_BadFileOpen;
|
||||
|
||||
fseek(fp, 0x8469, SEEK_SET);
|
||||
|
||||
for (num_wav = j = 0; j < 40; j++) {
|
||||
fread(&ai, 1, 32, fp);
|
||||
|
||||
if (ai.env[0].bp > 0x7f)
|
||||
break;
|
||||
|
||||
#if 0
|
||||
printf("Instrument %d loaded ----------------\n", j);
|
||||
printf("Envelope:\n");
|
||||
for (i = 0; i < 8; i++)
|
||||
printf("[seg %d]: BP %02x Inc %04x\n", i, ai.env[i].bp,
|
||||
((int)ai.env[i].inc_hi << 8) | ai.env[i].inc_lo);
|
||||
printf("rel seg: %d, pri inc: %d, bend range: %d, vib dep: %d, "
|
||||
"vib spd: %d\n", ai.relseg, ai.priority,
|
||||
ai.bendrange, ai.vibdepth, ai.vibspeed);
|
||||
printf("A wave count: %d, B wave count: %d\n", ai.wac, ai.wbc);
|
||||
#endif
|
||||
|
||||
for (k = 0; k < ai.wac; k++, num_wav++) {
|
||||
fread(&ai.wal[k], 1, 6, fp);
|
||||
#if 0
|
||||
printf("[A %d of %d] top: %02x, wave address: %02x, "
|
||||
"size: %02x, mode: %02x, relPitch: %04x\n", k + 1,
|
||||
ai.wac, ai.wal[k].top, ai.wal[k].addr, ai.wal[k].size,
|
||||
ai.wal[k].mode, ((int)ai.wal[k].rel_hi << 8) | ai.wal[k].rel_lo);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (k = 0; k < ai.wbc; k++, num_wav++) {
|
||||
fread(&ai.wbl[k], 1, 6, fp);
|
||||
#if 0
|
||||
printf("[B %d of %d] top: %02x, wave address: %02x, "
|
||||
"size: %02x, mode: %02x, relPitch: %04x\n", k + 1, ai.wbc,
|
||||
ai.wbl[k].top, ai.wbl[k].addr, ai.wbl[k].size,
|
||||
ai.wbl[k].mode, ((int)ai.wbl[k].rel_hi << 8) | ai.wbl[k].rel_lo);
|
||||
#endif
|
||||
}
|
||||
waveaddr[j] = 256 * ai.wal[0].addr;
|
||||
wavesize[j] = 256 * (1 << ((ai.wal[0].size) & 0x07));
|
||||
#if 1
|
||||
printf("%d addr = %d\n", j, waveaddr[j]);
|
||||
printf(" size = %d\n", wavesize[j]);
|
||||
#endif
|
||||
}
|
||||
|
||||
num_instruments = j;
|
||||
printf("%d Ensoniq 5503 instruments loaded. (%d waveforms)\n", num_instruments, num_wav);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
void unload_instruments() {
|
||||
free(instruments);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USE_IIGS_SOUND */
|
||||
|
||||
static void fill_audio(void *udata, int16 * stream, uint len) {
|
||||
int16 *origData = stream;
|
||||
len <<= 2;
|
||||
uint origLen = len;
|
||||
|
||||
uint32 p = 0;
|
||||
static uint32 n = 0, s = 0;
|
||||
|
||||
debugC(5, kDebugLevelSound, "(%p, %p, %d)", udata, stream, len);
|
||||
memcpy(stream, (uint8 *) buffer + s, p = n);
|
||||
for (n = 0, len -= p; n < len; p += n, len -= n) {
|
||||
play_sound();
|
||||
n = mix_sound() << 1;
|
||||
if (len < n) {
|
||||
memcpy((uint8 *) stream + p, buffer, len);
|
||||
s = len;
|
||||
n -= s;
|
||||
return;
|
||||
} else {
|
||||
memcpy((uint8 *) stream + p, buffer, n);
|
||||
}
|
||||
}
|
||||
play_sound();
|
||||
n = mix_sound() << 1;
|
||||
memcpy((uint8 *) stream + p, buffer, s = len);
|
||||
n -= s;
|
||||
}
|
||||
|
||||
AGIMusic::AGIMusic(Audio::Mixer *pMixer) {
|
||||
_mixer = pMixer;
|
||||
_sampleRate = pMixer->getOutputRate();
|
||||
_mixer->setupPremix(this);
|
||||
}
|
||||
|
||||
void AGIMusic::premixerCall(int16 *data, uint len) {
|
||||
Agi::fill_audio(NULL, data, len);
|
||||
}
|
||||
|
||||
void AGIMusic::setVolume(uint8 volume) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
AGIMusic::~AGIMusic(void) {
|
||||
_mixer->setupPremix(NULL);
|
||||
}
|
||||
|
||||
AGIMusic *g_agi_music;
|
||||
|
||||
#endif /* USE_PCM_SOUND */
|
||||
|
||||
} // End of namespace Agi
|
167
engines/agi/sound.h
Normal file
167
engines/agi/sound.h
Normal file
@ -0,0 +1,167 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_SOUND_H
|
||||
#define __AGI_SOUND_H
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
#define BUFFER_SIZE 410
|
||||
|
||||
#define SOUND_EMU_NONE 0
|
||||
#define SOUND_EMU_PC 1
|
||||
#define SOUND_EMU_TANDY 2
|
||||
#define SOUND_EMU_MAC 3
|
||||
#define SOUND_EMU_AMIGA 4
|
||||
|
||||
#define SOUND_PLAYING 0x01
|
||||
#define WAVEFORM_SIZE 64
|
||||
#define ENV_ATTACK 10000 /**< envelope attack rate */
|
||||
#define ENV_DECAY 1000 /**< envelope decay rate */
|
||||
#define ENV_SUSTAIN 100 /**< envelope sustain level */
|
||||
#define ENV_RELEASE 7500 /**< envelope release rate */
|
||||
#define NUM_CHANNELS 7 /**< number of sound channels */
|
||||
|
||||
/**
|
||||
* AGI engine sound driver structure.
|
||||
*/
|
||||
struct sound_driver {
|
||||
char *description;
|
||||
int (*init) (int16 * buffer);
|
||||
void (*deinit) (void);
|
||||
};
|
||||
|
||||
/**
|
||||
* AGI sound resource structure.
|
||||
*/
|
||||
struct agi_sound {
|
||||
uint32 flen; /**< size of raw data */
|
||||
uint8 *rdata; /**< raw sound data */
|
||||
uint8 flags; /**< sound flags */
|
||||
uint16 type; /**< sound resource type */
|
||||
};
|
||||
|
||||
/**
|
||||
* AGI sound note structure.
|
||||
*/
|
||||
struct agi_note {
|
||||
uint8 dur_lo; /**< LSB of note duration */
|
||||
uint8 dur_hi; /**< MSB of note duration */
|
||||
uint8 frq_0; /**< LSB of note frequency */
|
||||
uint8 frq_1; /**< MSB of note frequency */
|
||||
uint8 vol; /**< note volume */
|
||||
};
|
||||
|
||||
/**
|
||||
* AGI engine sound channel structure.
|
||||
*/
|
||||
struct channel_info {
|
||||
#define AGI_SOUND_SAMPLE 0x0001
|
||||
#define AGI_SOUND_MIDI 0x0002
|
||||
#define AGI_SOUND_4CHN 0x0008
|
||||
uint32 type;
|
||||
struct agi_note *ptr;
|
||||
#ifdef USE_PCM_SOUND
|
||||
int16 *ins;
|
||||
int32 size;
|
||||
uint32 phase;
|
||||
#endif
|
||||
#define AGI_SOUND_LOOP 0x0001
|
||||
#define AGI_SOUND_ENVELOPE 0x0002
|
||||
uint32 flags;
|
||||
#define AGI_SOUND_ENV_ATTACK 3
|
||||
#define AGI_SOUND_ENV_DECAY 2
|
||||
#define AGI_SOUND_ENV_SUSTAIN 1
|
||||
#define AGI_SOUND_ENV_RELEASE 0
|
||||
uint32 adsr;
|
||||
int32 timer;
|
||||
uint32 end;
|
||||
uint32 freq;
|
||||
uint32 vol;
|
||||
uint32 env;
|
||||
};
|
||||
|
||||
void decode_sound(int);
|
||||
void unload_sound(int);
|
||||
void play_sound(void);
|
||||
int init_sound(void);
|
||||
void deinit_sound(void);
|
||||
void start_sound(int, int);
|
||||
void stop_sound(void);
|
||||
uint32 mix_sound(void);
|
||||
void __init_sound(void);
|
||||
int load_instruments(char *fname);
|
||||
|
||||
extern struct sound_driver *snd;
|
||||
|
||||
#endif /* __AGI_SOUND_H */
|
||||
|
||||
#ifdef USE_PCM_SOUND
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#include "sound/audiostream.h"
|
||||
|
||||
namespace Audio {
|
||||
class Mixer;
|
||||
} // End of namespace Audio
|
||||
|
||||
namespace Agi {
|
||||
|
||||
class AGIMusic : public Audio::AudioStream {
|
||||
public:
|
||||
AGIMusic(Audio::Mixer * pMixer);
|
||||
~AGIMusic(void);
|
||||
virtual void setVolume(uint8 volume);
|
||||
|
||||
// AudioStream API
|
||||
int readBuffer(int16 * buffer, const int numSamples) {
|
||||
premixerCall(buffer, numSamples / 2);
|
||||
return numSamples;
|
||||
}
|
||||
|
||||
bool isStereo() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool endOfData() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
int getRate() const {
|
||||
return _sampleRate;
|
||||
}
|
||||
|
||||
private:
|
||||
Audio::Mixer * _mixer;
|
||||
uint32 _sampleRate;
|
||||
|
||||
void premixerCall(int16 * buf, uint len);
|
||||
};
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif
|
868
engines/agi/sprite.cpp
Normal file
868
engines/agi/sprite.cpp
Normal file
@ -0,0 +1,868 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/list.h"
|
||||
#include "agi/sprite.h"
|
||||
#include "agi/graphics.h"
|
||||
#include "agi/text.h"
|
||||
#include "agi/savegame.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
/**
|
||||
* Sprite structure.
|
||||
* This structure holds information on visible and priority data of
|
||||
* a rectangular area of the AGI screen. Sprites are chained in two
|
||||
* circular lists, one for updating and other for non-updating sprites.
|
||||
*/
|
||||
struct sprite {
|
||||
struct list_head list;
|
||||
struct vt_entry *v; /**< pointer to view table entry */
|
||||
int16 x_pos; /**< x coordinate of the sprite */
|
||||
int16 y_pos; /**< y coordinate of the sprite */
|
||||
int16 x_size; /**< width of the sprite */
|
||||
int16 y_size; /**< height of the sprite */
|
||||
uint8 *buffer; /**< buffer to store background data */
|
||||
#ifdef USE_HIRES
|
||||
uint8 *hires; /**< buffer for hi-res background */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Sprite pool replaces dynamic allocation
|
||||
*/
|
||||
#undef ALLOC_DEBUG
|
||||
|
||||
#ifdef USE_HIRES
|
||||
#define POOL_SIZE 68000 /* Gold Rush mine room needs > 50000 */
|
||||
/* Speeder bike challenge needs > 67000 */
|
||||
#else
|
||||
#define POOL_SIZE 25000
|
||||
#endif
|
||||
static uint8 *sprite_pool;
|
||||
static uint8 *pool_top;
|
||||
|
||||
static void *pool_alloc(int size) {
|
||||
uint8 *x;
|
||||
|
||||
/* Adjust size to 32-bit boundary to prevent data misalignment
|
||||
* errors.
|
||||
*/
|
||||
size = (size + 3) & ~3;
|
||||
|
||||
x = pool_top;
|
||||
pool_top += size;
|
||||
|
||||
if (pool_top >= (uint8 *)sprite_pool + POOL_SIZE) {
|
||||
debugC(1, kDebugLevelMain | kDebugLevelResources, "not enough memory");
|
||||
pool_top = x;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static void pool_release(void *s) {
|
||||
pool_top = (uint8 *)s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Blitter functions
|
||||
*/
|
||||
|
||||
/* Blit one pixel considering the priorities */
|
||||
|
||||
static void blit_pixel(uint8 *p, uint8 *end, uint8 col, int spr, int width, int *hidden) {
|
||||
int epr = 0, pr = 0; /* effective and real priorities */
|
||||
|
||||
/* CM: priority 15 overrides control lines and is ignored when
|
||||
* tracking effective priority. This tweak is needed to fix
|
||||
* bug #451768, and should not affect Sierra games because
|
||||
* sprites shouldn't have priority 15 (like the AGI Mouse
|
||||
* demo "mouse pointer")
|
||||
*
|
||||
* Update: this solution breaks other games, and can't be used.
|
||||
*/
|
||||
|
||||
if (p >= end)
|
||||
return;
|
||||
|
||||
/* Check if we're on a control line */
|
||||
if ((pr = *p & 0xf0) < 0x30) {
|
||||
uint8 *p1;
|
||||
/* Yes, get effective priority going down */
|
||||
for (p1 = p; p1 < end && (epr = *p1 & 0xf0) < 0x30;
|
||||
p1 += width);
|
||||
if (p1 >= end)
|
||||
epr = 0x40;
|
||||
} else {
|
||||
epr = pr;
|
||||
}
|
||||
|
||||
if (spr >= epr) {
|
||||
/* Keep control line information visible, but put our
|
||||
* priority over water (0x30) surface
|
||||
*/
|
||||
*p = (pr < 0x30 ? pr : spr) | col;
|
||||
*hidden = false;
|
||||
|
||||
/* Except if our priority is 15, which should never happen
|
||||
* (fixes bug #451768)
|
||||
*
|
||||
* Update: breaks other games, can't be used
|
||||
*
|
||||
* if (spr == 0xf0)
|
||||
* *p = spr | col;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_HIRES
|
||||
|
||||
#define X_FACT 2 /* Horizontal hires factor */
|
||||
|
||||
static int blit_hires_cel(int x, int y, int spr, struct view_cel *c) {
|
||||
uint8 *q = NULL;
|
||||
uint8 *h0, *h, *end;
|
||||
int i, j, t, m, col;
|
||||
int hidden = true;
|
||||
|
||||
q = c->data;
|
||||
t = c->transparency;
|
||||
m = c->mirror;
|
||||
spr <<= 4;
|
||||
h0 = &game.hires[(x + y * _WIDTH + m * (c->width - 1)) * X_FACT];
|
||||
|
||||
end = game.hires + _WIDTH * X_FACT * _HEIGHT;
|
||||
|
||||
for (i = 0; i < c->height; i++) {
|
||||
h = h0;
|
||||
while (*q) {
|
||||
col = (*q & 0xf0) >> 4;
|
||||
for (j = *q & 0x0f; j; j--, h += X_FACT * (1 - 2 * m)) {
|
||||
if (col != t) {
|
||||
blit_pixel(h, end, col, spr, _WIDTH * X_FACT, &hidden);
|
||||
blit_pixel(h + 1, end, col, spr, _WIDTH * X_FACT, &hidden);
|
||||
}
|
||||
}
|
||||
q++;
|
||||
}
|
||||
h0 += _WIDTH * X_FACT;
|
||||
q++;
|
||||
}
|
||||
return hidden;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int blit_cel(int x, int y, int spr, struct view_cel *c) {
|
||||
uint8 *p0, *p, *q = NULL, *end;
|
||||
int i, j, t, m, col;
|
||||
int hidden = true;
|
||||
|
||||
/* Fixes bug #477841 (crash in PQ1 map C4 when y == -2) */
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (y >= _HEIGHT)
|
||||
y = _HEIGHT - 1;
|
||||
if (x >= _WIDTH)
|
||||
x = _WIDTH - 1;
|
||||
|
||||
#ifdef USE_HIRES
|
||||
if (opt.hires)
|
||||
blit_hires_cel(x, y, spr, c);
|
||||
#endif
|
||||
|
||||
q = c->data;
|
||||
t = c->transparency;
|
||||
m = c->mirror;
|
||||
spr <<= 4;
|
||||
p0 = &game.sbuf[x + y * _WIDTH + m * (c->width - 1)];
|
||||
|
||||
end = game.sbuf + _WIDTH * _HEIGHT;
|
||||
|
||||
for (i = 0; i < c->height; i++) {
|
||||
p = p0;
|
||||
while (*q) {
|
||||
col = (*q & 0xf0) >> 4;
|
||||
for (j = *q & 0x0f; j; j--, p += 1 - 2 * m) {
|
||||
if (col != t) {
|
||||
blit_pixel(p, end, col, spr, _WIDTH, &hidden);
|
||||
}
|
||||
}
|
||||
q++;
|
||||
}
|
||||
p0 += _WIDTH;
|
||||
q++;
|
||||
}
|
||||
|
||||
return hidden;
|
||||
}
|
||||
|
||||
static void objs_savearea(struct sprite *s) {
|
||||
int y;
|
||||
int16 x_pos = s->x_pos, y_pos = s->y_pos;
|
||||
int16 x_size = s->x_size, y_size = s->y_size;
|
||||
uint8 *p0, *q;
|
||||
#ifdef USE_HIRES
|
||||
uint8 *h0, *k;
|
||||
#endif
|
||||
|
||||
if (x_pos + x_size > _WIDTH)
|
||||
x_size = _WIDTH - x_pos;
|
||||
|
||||
if (x_pos < 0) {
|
||||
x_size += x_pos;
|
||||
x_pos = 0;
|
||||
}
|
||||
|
||||
if (y_pos + y_size > _HEIGHT)
|
||||
y_size = _HEIGHT - y_pos;
|
||||
|
||||
if (y_pos < 0) {
|
||||
y_size += y_pos;
|
||||
y_pos = 0;
|
||||
}
|
||||
|
||||
if (x_size <= 0 || y_size <= 0)
|
||||
return;
|
||||
|
||||
p0 = &game.sbuf[x_pos + y_pos * _WIDTH];
|
||||
q = s->buffer;
|
||||
#ifdef USE_HIRES
|
||||
h0 = &game.hires[(x_pos + y_pos * _WIDTH) * 2];
|
||||
k = s->hires;
|
||||
#endif
|
||||
for (y = 0; y < y_size; y++) {
|
||||
memcpy(q, p0, x_size);
|
||||
q += x_size;
|
||||
p0 += _WIDTH;
|
||||
#ifdef USE_HIRES
|
||||
memcpy(k, h0, x_size * 2);
|
||||
k += x_size * 2;
|
||||
h0 += _WIDTH * 2;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void objs_restorearea(struct sprite *s) {
|
||||
int y, offset;
|
||||
int16 x_pos = s->x_pos, y_pos = s->y_pos;
|
||||
int16 x_size = s->x_size, y_size = s->y_size;
|
||||
uint8 *p0, *q;
|
||||
#ifdef USE_HIRES
|
||||
uint8 *h0, *k;
|
||||
#endif
|
||||
|
||||
if (x_pos + x_size > _WIDTH)
|
||||
x_size = _WIDTH - x_pos;
|
||||
|
||||
if (x_pos < 0) {
|
||||
x_size += x_pos;
|
||||
x_pos = 0;
|
||||
}
|
||||
|
||||
if (y_pos + y_size > _HEIGHT)
|
||||
y_size = _HEIGHT - y_pos;
|
||||
|
||||
if (y_pos < 0) {
|
||||
y_size += y_pos;
|
||||
y_pos = 0;
|
||||
}
|
||||
|
||||
if (x_size <= 0 || y_size <= 0)
|
||||
return;
|
||||
|
||||
p0 = &game.sbuf[x_pos + y_pos * _WIDTH];
|
||||
q = s->buffer;
|
||||
#ifdef USE_HIRES
|
||||
h0 = &game.hires[(x_pos + y_pos * _WIDTH) * 2];
|
||||
k = s->hires;
|
||||
#endif
|
||||
offset = game.line_min_print * CHAR_LINES;
|
||||
for (y = 0; y < y_size; y++) {
|
||||
memcpy(p0, q, x_size);
|
||||
put_pixels_a(x_pos, y_pos + y + offset, x_size, p0);
|
||||
q += x_size;
|
||||
p0 += _WIDTH;
|
||||
#ifdef USE_HIRES
|
||||
memcpy(h0, k, x_size * 2);
|
||||
if (opt.hires) {
|
||||
put_pixels_hires(x_pos * 2, y_pos + y + offset, x_size * 2, h0);
|
||||
}
|
||||
k += x_size * 2;
|
||||
h0 += _WIDTH * 2;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sprite management functions
|
||||
*/
|
||||
|
||||
static LIST_HEAD(spr_upd_head);
|
||||
static LIST_HEAD(spr_nonupd_head);
|
||||
|
||||
/**
|
||||
* Condition to determine whether a sprite will be in the 'updating' list.
|
||||
*/
|
||||
static int test_updating(struct vt_entry *v) {
|
||||
/* Sanity check (see bug #779302) */
|
||||
if (~game.dir_view[v->current_view].flags & RES_LOADED)
|
||||
return 0;
|
||||
|
||||
return (v->flags & (ANIMATED | UPDATE | DRAWN)) == (ANIMATED | UPDATE | DRAWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition to determine whether a sprite will be in the 'non-updating' list.
|
||||
*/
|
||||
static int test_not_updating(struct vt_entry *v) {
|
||||
/* Sanity check (see bug #779302) */
|
||||
if (~game.dir_view[v->current_view].flags & RES_LOADED)
|
||||
return 0;
|
||||
|
||||
return (v->flags & (ANIMATED | UPDATE | DRAWN)) == (ANIMATED | DRAWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert sprite priority to y value.
|
||||
*/
|
||||
static INLINE int prio_to_y(int p) {
|
||||
int i;
|
||||
|
||||
if (p == 0)
|
||||
return -1;
|
||||
|
||||
for (i = 167; i >= 0; i--) {
|
||||
if (game.pri_table[i] < p)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1; /* (p - 5) * 12 + 48; */
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and initialize a new sprite structure.
|
||||
*/
|
||||
static struct sprite *new_sprite(struct vt_entry *v) {
|
||||
struct sprite *s;
|
||||
|
||||
s = (struct sprite *)pool_alloc(sizeof(struct sprite));
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
s->v = v; /* link sprite to associated view table entry */
|
||||
s->x_pos = v->x_pos;
|
||||
s->y_pos = v->y_pos - v->y_size + 1;
|
||||
s->x_size = v->x_size;
|
||||
s->y_size = v->y_size;
|
||||
s->buffer = (uint8 *) pool_alloc(s->x_size * s->y_size);
|
||||
#ifdef USE_HIRES
|
||||
s->hires = (uint8 *) pool_alloc(s->x_size * s->y_size * 2);
|
||||
#endif
|
||||
v->s = s; /* link view table entry to this sprite */
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert sprite in the specified sprite list.
|
||||
*/
|
||||
static void spr_addlist(struct list_head *head, struct vt_entry *v) {
|
||||
struct sprite *s;
|
||||
|
||||
s = new_sprite(v);
|
||||
list_add_tail(&s->list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort sprites from lower y values to build a sprite list.
|
||||
*/
|
||||
static struct list_head *build_list(struct list_head *head,
|
||||
int (*test) (struct vt_entry *)) {
|
||||
int i, j, k;
|
||||
struct vt_entry *v;
|
||||
struct vt_entry *entry[0x100];
|
||||
int y_val[0x100];
|
||||
int min_y = 0xff, min_index = 0;
|
||||
|
||||
/* fill the arrays with all sprites that satisfy the 'test'
|
||||
* condition and their y values
|
||||
*/
|
||||
i = 0;
|
||||
for (v = game.view_table; v < &game.view_table[MAX_VIEWTABLE]; v++) {
|
||||
if (test(v)) {
|
||||
entry[i] = v;
|
||||
y_val[i] = v->flags & FIXED_PRIORITY ? prio_to_y(v->priority) : v->y_pos;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* now look for the smallest y value in the array and put that
|
||||
* sprite in the list
|
||||
*/
|
||||
for (j = 0; j < i; j++) {
|
||||
min_y = 0xff;
|
||||
for (k = 0; k < i; k++) {
|
||||
if (y_val[k] < min_y) {
|
||||
min_index = k;
|
||||
min_y = y_val[k];
|
||||
}
|
||||
}
|
||||
|
||||
y_val[min_index] = 0xff;
|
||||
spr_addlist(head, entry[min_index]);
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build list of updating sprites.
|
||||
*/
|
||||
static struct list_head *build_upd_blitlist() {
|
||||
return build_list(&spr_upd_head, test_updating);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build list of non-updating sprites.
|
||||
*/
|
||||
static struct list_head *build_nonupd_blitlist() {
|
||||
return build_list(&spr_nonupd_head, test_not_updating);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the given sprite list.
|
||||
*/
|
||||
static void free_list(struct list_head *head) {
|
||||
struct list_head *h;
|
||||
struct sprite *s;
|
||||
|
||||
list_for_each(h, head, prev) {
|
||||
s = list_entry(h, struct sprite, list);
|
||||
list_del(h);
|
||||
#ifdef USE_HIRES
|
||||
pool_release(s->hires);
|
||||
#endif
|
||||
pool_release(s->buffer);
|
||||
pool_release(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy sprites from the pic buffer to the screen buffer, and check if
|
||||
* sprites of the given list have moved.
|
||||
*/
|
||||
static void commit_sprites(struct list_head *head) {
|
||||
struct list_head *h;
|
||||
|
||||
list_for_each(h, head, next) {
|
||||
struct sprite *s = list_entry(h, struct sprite, list);
|
||||
int x1, y1, x2, y2, w, h;
|
||||
|
||||
w = (s->v->cel_data->width > s->v->cel_data_2->width) ?
|
||||
s->v->cel_data->width : s->v->cel_data_2->width;
|
||||
|
||||
h = (s->v->cel_data->height >
|
||||
s->v->cel_data_2->height) ? s->v->cel_data->
|
||||
height : s->v->cel_data_2->height;
|
||||
|
||||
s->v->cel_data_2 = s->v->cel_data;
|
||||
|
||||
if (s->v->x_pos < s->v->x_pos2) {
|
||||
x1 = s->v->x_pos;
|
||||
x2 = s->v->x_pos2 + w - 1;
|
||||
} else {
|
||||
x1 = s->v->x_pos2;
|
||||
x2 = s->v->x_pos + w - 1;
|
||||
}
|
||||
|
||||
if (s->v->y_pos < s->v->y_pos2) {
|
||||
y1 = s->v->y_pos - h + 1;
|
||||
y2 = s->v->y_pos2;
|
||||
} else {
|
||||
y1 = s->v->y_pos2 - h + 1;
|
||||
y2 = s->v->y_pos;
|
||||
}
|
||||
|
||||
commit_block(x1, y1, x2, y2);
|
||||
|
||||
if (s->v->step_time_count != s->v->step_time)
|
||||
continue;
|
||||
|
||||
if (s->v->x_pos == s->v->x_pos2 && s->v->y_pos == s->v->y_pos2) {
|
||||
s->v->flags |= DIDNT_MOVE;
|
||||
continue;
|
||||
}
|
||||
|
||||
s->v->x_pos2 = s->v->x_pos;
|
||||
s->v->y_pos2 = s->v->y_pos;
|
||||
s->v->flags &= ~DIDNT_MOVE;
|
||||
}
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
if (debug_.statusline)
|
||||
write_status();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase all sprites in the given list.
|
||||
*/
|
||||
static void erase_sprites(struct list_head *head) {
|
||||
struct list_head *h;
|
||||
|
||||
list_for_each(h, head, prev) {
|
||||
struct sprite *s = list_entry(h, struct sprite, list);
|
||||
objs_restorearea(s);
|
||||
}
|
||||
|
||||
free_list(head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blit all sprites in the given list.
|
||||
*/
|
||||
static void blit_sprites(struct list_head *head) {
|
||||
struct list_head *h = NULL;
|
||||
int hidden;
|
||||
|
||||
list_for_each(h, head, next) {
|
||||
struct sprite *s = list_entry(h, struct sprite, list);
|
||||
objs_savearea(s);
|
||||
debugC(8, kDebugLevelSprites, "s->v->entry = %d (prio %d)", s->v->entry, s->v->priority);
|
||||
hidden = blit_cel(s->x_pos, s->y_pos, s->v->priority, s->v->cel_data);
|
||||
if (s->v->entry == 0) { /* if ego, update f1 */
|
||||
setflag(F_ego_invisible, hidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
void commit_upd_sprites() {
|
||||
commit_sprites(&spr_upd_head);
|
||||
}
|
||||
|
||||
void commit_nonupd_sprites() {
|
||||
commit_sprites(&spr_nonupd_head);
|
||||
}
|
||||
|
||||
/* check moves in both lists */
|
||||
void commit_both() {
|
||||
commit_upd_sprites();
|
||||
commit_nonupd_sprites();
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase updating sprites.
|
||||
* This function follows the list of all updating sprites and restores
|
||||
* the visible and priority data of their background buffers back to
|
||||
* the AGI screen.
|
||||
*
|
||||
* @see erase_nonupd_sprites()
|
||||
* @see erase_both()
|
||||
*/
|
||||
void erase_upd_sprites() {
|
||||
erase_sprites(&spr_upd_head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase non-updating sprites.
|
||||
* This function follows the list of all non-updating sprites and restores
|
||||
* the visible and priority data of their background buffers back to
|
||||
* the AGI screen.
|
||||
*
|
||||
* @see erase_upd_sprites()
|
||||
* @see erase_both()
|
||||
*/
|
||||
void erase_nonupd_sprites() {
|
||||
erase_sprites(&spr_nonupd_head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase all sprites.
|
||||
* This function follows the lists of all updating and non-updating
|
||||
* sprites and restores the visible and priority data of their background
|
||||
* buffers back to the AGI screen.
|
||||
*
|
||||
* @see erase_upd_sprites()
|
||||
* @see erase_nonupd_sprites()
|
||||
*/
|
||||
void erase_both() {
|
||||
erase_upd_sprites();
|
||||
erase_nonupd_sprites();
|
||||
}
|
||||
|
||||
/**
|
||||
* Blit updating sprites.
|
||||
* This function follows the list of all updating sprites and blits
|
||||
* them on the AGI screen.
|
||||
*
|
||||
* @see blit_nonupd_sprites()
|
||||
* @see blit_both()
|
||||
*/
|
||||
void blit_upd_sprites() {
|
||||
debugC(7, kDebugLevelSprites, "blit updating");
|
||||
blit_sprites(build_upd_blitlist());
|
||||
}
|
||||
|
||||
/**
|
||||
* Blit non-updating sprites.
|
||||
* This function follows the list of all non-updating sprites and blits
|
||||
* them on the AGI screen.
|
||||
*
|
||||
* @see blit_upd_sprites()
|
||||
* @see blit_both()
|
||||
*/
|
||||
void blit_nonupd_sprites() {
|
||||
debugC(7, kDebugLevelSprites, "blit non-updating");
|
||||
blit_sprites(build_nonupd_blitlist());
|
||||
}
|
||||
|
||||
/**
|
||||
* Blit all sprites.
|
||||
* This function follows the lists of all updating and non-updating
|
||||
* sprites and blits them on the AGI screen.
|
||||
*
|
||||
* @see blit_upd_sprites()
|
||||
* @see blit_nonupd_sprites()
|
||||
*/
|
||||
void blit_both() {
|
||||
blit_nonupd_sprites();
|
||||
blit_upd_sprites();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add view to picture.
|
||||
* This function is used to implement the add.to.pic AGI command. It
|
||||
* copies the specified cel from a view resource on the current picture.
|
||||
* This cel is not a sprite, it can't be moved or removed.
|
||||
* @param view number of view resource
|
||||
* @param loop number of loop in the specified view resource
|
||||
* @param cel number of cel in the specified loop
|
||||
* @param x x coordinate to place the view
|
||||
* @param y y coordinate to place the view
|
||||
* @param pri priority to use
|
||||
* @param mar if < 4, create a margin around the the base of the cel
|
||||
*/
|
||||
void add_to_pic(int view, int loop, int cel, int x, int y, int pri, int mar) {
|
||||
struct view_cel *c = NULL;
|
||||
int x1, y1, x2, y2, y3;
|
||||
uint8 *p1, *p2;
|
||||
|
||||
debugC(3, kDebugLevelSprites, "v=%d, l=%d, c=%d, x=%d, y=%d, p=%d, m=%d", view, loop, cel, x, y, pri, mar);
|
||||
|
||||
record_image_stack_call(ADD_VIEW, view, loop, cel, x, y, pri, mar);
|
||||
|
||||
/*
|
||||
* Was hardcoded to 8, changed to pri_table[y] to fix Gold
|
||||
* Rush (see bug #587558)
|
||||
*/
|
||||
if (pri == 0)
|
||||
pri = game.pri_table[y];
|
||||
|
||||
c = &game.views[view].loop[loop].cel[cel];
|
||||
|
||||
x1 = x;
|
||||
y1 = y - c->height + 1;
|
||||
x2 = x + c->width - 1;
|
||||
y2 = y;
|
||||
|
||||
if (x1 < 0) {
|
||||
x2 -= x1;
|
||||
x1 = 0;
|
||||
}
|
||||
if (y1 < 0) {
|
||||
y2 -= y1;
|
||||
y1 = 0;
|
||||
}
|
||||
if (x2 >= _WIDTH)
|
||||
x2 = _WIDTH - 1;
|
||||
if (y2 >= _HEIGHT)
|
||||
y2 = _HEIGHT - 1;
|
||||
|
||||
erase_both();
|
||||
|
||||
debugC(4, kDebugLevelSprites, "blit_cel (%d, %d, %d, c)", x, y, pri);
|
||||
blit_cel(x1, y1, pri, c);
|
||||
|
||||
/* If margin is 0, 1, 2, or 3, the base of the cel is
|
||||
* surrounded with a rectangle of the corresponding priority.
|
||||
* If margin >= 4, this extra margin is not shown.
|
||||
*/
|
||||
if (mar < 4) {
|
||||
/* add rectangle around object, don't clobber control
|
||||
* info in priority data. The box extends to the end of
|
||||
* its priority band!
|
||||
*
|
||||
* SQ1 needs +1 (see bug #810331)
|
||||
*/
|
||||
y3 = (y2 / 12) * 12 + 1;
|
||||
|
||||
p1 = &game.sbuf[x1 + y3 * _WIDTH];
|
||||
p2 = &game.sbuf[x2 + y3 * _WIDTH];
|
||||
|
||||
for (y = y3; y <= y2; y++) {
|
||||
if ((*p1 >> 4) >= 4)
|
||||
*p1 = (mar << 4) | (*p1 & 0x0f);
|
||||
if ((*p2 >> 4) >= 4)
|
||||
*p2 = (mar << 4) | (*p2 & 0x0f);
|
||||
p1 += _WIDTH;
|
||||
p2 += _WIDTH;
|
||||
}
|
||||
|
||||
debugC(4, kDebugLevelSprites, "pri box: %d %d %d %d (%d)", x1, y3, x2, y2, mar);
|
||||
p1 = &game.sbuf[x1 + y3 * _WIDTH];
|
||||
p2 = &game.sbuf[x1 + y2 * _WIDTH];
|
||||
for (x = x1; x <= x2; x++) {
|
||||
if ((*p1 >> 4) >= 4)
|
||||
*p1 = (mar << 4) | (*p1 & 0x0f);
|
||||
if ((*p2 >> 4) >= 4)
|
||||
*p2 = (mar << 4) | (*p2 & 0x0f);
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
}
|
||||
|
||||
blit_both();
|
||||
|
||||
debugC(4, kDebugLevelSprites, "commit_block (%d, %d, %d, %d)", x1, y1, x2, y2);
|
||||
commit_block(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show object and description
|
||||
* This function shows an object from the player's inventory, displaying
|
||||
* a message box with the object description.
|
||||
* @param n Number of the object to show
|
||||
*/
|
||||
void show_obj(int n) {
|
||||
struct view_cel *c;
|
||||
struct sprite s;
|
||||
int x1, y1, x2, y2;
|
||||
|
||||
agi_load_resource(rVIEW, n);
|
||||
if (!(c = &game.views[n].loop[0].cel[0]))
|
||||
return;
|
||||
|
||||
x1 = (_WIDTH - c->width) / 2;
|
||||
y1 = 112;
|
||||
x2 = x1 + c->width - 1;
|
||||
y2 = y1 + c->height - 1;
|
||||
|
||||
s.x_pos = x1;
|
||||
s.y_pos = y1;
|
||||
s.x_size = c->width;
|
||||
s.y_size = c->height;
|
||||
s.buffer = (uint8 *)malloc(s.x_size * s.y_size);
|
||||
#ifdef USE_HIRES
|
||||
s.hires = (uint8 *)malloc(s.x_size * s.y_size * 2);
|
||||
#endif
|
||||
|
||||
objs_savearea(&s);
|
||||
blit_cel(x1, y1, s.x_size, c);
|
||||
commit_block(x1, y1, x2, y2);
|
||||
message_box(game.views[n].descr);
|
||||
objs_restorearea(&s);
|
||||
commit_block(x1, y1, x2, y2);
|
||||
|
||||
free(s.buffer);
|
||||
|
||||
/* Added to fix a memory leak --Vasyl */
|
||||
#ifdef USE_HIRES
|
||||
free(s.hires);
|
||||
#endif
|
||||
}
|
||||
|
||||
void commit_block(int x1, int y1, int x2, int y2) {
|
||||
int i, w, offset;
|
||||
uint8 *q;
|
||||
#ifdef USE_HIRES
|
||||
uint8 *h;
|
||||
#endif
|
||||
|
||||
if (!game.picture_shown)
|
||||
return;
|
||||
|
||||
/* Clipping */
|
||||
if (x1 < 0)
|
||||
x1 = 0;
|
||||
if (x2 < 0)
|
||||
x2 = 0;
|
||||
if (y1 < 0)
|
||||
y1 = 0;
|
||||
if (y2 < 0)
|
||||
y2 = 0;
|
||||
if (x1 >= _WIDTH)
|
||||
x1 = _WIDTH - 1;
|
||||
if (x2 >= _WIDTH)
|
||||
x2 = _WIDTH - 1;
|
||||
if (y1 >= _HEIGHT)
|
||||
y1 = _HEIGHT - 1;
|
||||
if (y2 >= _HEIGHT)
|
||||
y2 = _HEIGHT - 1;
|
||||
|
||||
debugC(7, kDebugLevelSprites, "%d, %d, %d, %d", x1, y1, x2, y2);
|
||||
|
||||
w = x2 - x1 + 1;
|
||||
q = &game.sbuf[x1 + _WIDTH * y1];
|
||||
#ifdef USE_HIRES
|
||||
h = &game.hires[(x1 + _WIDTH * y1) * 2];
|
||||
#endif
|
||||
offset = game.line_min_print * CHAR_LINES;
|
||||
for (i = y1; i <= y2; i++) {
|
||||
put_pixels_a(x1, i + offset, w, q);
|
||||
q += _WIDTH;
|
||||
#ifdef USE_HIRES
|
||||
if (opt.hires) {
|
||||
put_pixels_hires(x1 * 2, i + offset, w * 2, h);
|
||||
}
|
||||
h += _WIDTH * 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
flush_block_a(x1, y1 + offset, x2, y2 + offset);
|
||||
}
|
||||
|
||||
int init_sprites() {
|
||||
if ((sprite_pool = (uint8 *)malloc(POOL_SIZE)) == NULL)
|
||||
return err_NotEnoughMemory;
|
||||
|
||||
pool_top = sprite_pool;
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
void deinit_sprites() {
|
||||
free(sprite_pool);
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
47
engines/agi/sprite.h
Normal file
47
engines/agi/sprite.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_SPRITE_H
|
||||
#define __AGI_SPRITE_H
|
||||
|
||||
namespace Agi {
|
||||
|
||||
int init_sprites(void);
|
||||
void deinit_sprites(void);
|
||||
void erase_upd_sprites(void);
|
||||
void erase_nonupd_sprites(void);
|
||||
void erase_both(void);
|
||||
void blit_upd_sprites(void);
|
||||
void blit_nonupd_sprites(void);
|
||||
void blit_both(void);
|
||||
void commit_upd_sprites(void);
|
||||
void commit_nonupd_sprites(void);
|
||||
void commit_both(void);
|
||||
void add_to_pic(int, int, int, int, int, int, int);
|
||||
void show_obj(int);
|
||||
void commit_block(int, int, int, int);
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif /* __AGI_SPRITE_H */
|
677
engines/agi/text.cpp
Normal file
677
engines/agi/text.cpp
Normal file
@ -0,0 +1,677 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/sprite.h" /* for commit_both() */
|
||||
#include "agi/graphics.h"
|
||||
#include "agi/keyboard.h"
|
||||
#include "agi/text.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
static void print_text2(int l, char *msg, int foff, int xoff, int yoff,
|
||||
int len, int fg, int bg) {
|
||||
int x1, y1;
|
||||
int maxx, minx, ofoff;
|
||||
int update;
|
||||
/* Note: Must be unsigned to use AGDS cyrillic characters! */
|
||||
unsigned char *m;
|
||||
|
||||
/* kludge! */
|
||||
update = 1;
|
||||
if (l == 2) {
|
||||
update = l = 0;
|
||||
}
|
||||
|
||||
/* FR: strings with len == 1 were not printed
|
||||
*/
|
||||
if (len == 1) {
|
||||
put_text_character(l, xoff + foff, yoff, *msg, fg, bg);
|
||||
maxx = 1;
|
||||
minx = 0;
|
||||
ofoff = foff;
|
||||
y1 = 0; /* Check this */
|
||||
} else {
|
||||
maxx = 0;
|
||||
minx = GFX_WIDTH;
|
||||
ofoff = foff;
|
||||
|
||||
for (m = (unsigned char *)msg, x1 = y1 = 0; *m; m++) {
|
||||
|
||||
if (*m >= 0x20 || *m == 1 || *m == 2 || *m == 3) {
|
||||
/* FIXME */
|
||||
int ypos;
|
||||
|
||||
ypos = (y1 * CHAR_LINES) + yoff;
|
||||
|
||||
if ((x1 != (len - 1) || x1 == 39) && (ypos <= (GFX_HEIGHT - CHAR_LINES))) {
|
||||
int xpos;
|
||||
|
||||
xpos = (x1 * CHAR_COLS) + xoff + foff;
|
||||
|
||||
if (xpos >= GFX_WIDTH)
|
||||
continue;
|
||||
|
||||
put_text_character(l, xpos, ypos, *m, fg, bg);
|
||||
|
||||
if (x1 > maxx)
|
||||
maxx = x1;
|
||||
if (x1 < minx)
|
||||
minx = x1;
|
||||
}
|
||||
|
||||
x1++;
|
||||
/* DF: changed the len-1 to len... */
|
||||
if (x1 == len && m[1] != '\n')
|
||||
y1++, x1 = foff = 0;
|
||||
} else {
|
||||
y1++;
|
||||
x1 = foff = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (l)
|
||||
return;
|
||||
|
||||
if (maxx < minx)
|
||||
return;
|
||||
|
||||
maxx *= CHAR_COLS;
|
||||
minx *= CHAR_COLS;
|
||||
|
||||
if (update) {
|
||||
schedule_update(foff + xoff + minx, yoff, ofoff + xoff + maxx + CHAR_COLS - 1,
|
||||
yoff + y1 * CHAR_LINES + CHAR_LINES + 1);
|
||||
/* Making synchronous text updates reduces CPU load
|
||||
* when updating status line and input area
|
||||
*/
|
||||
do_update();
|
||||
}
|
||||
}
|
||||
|
||||
/* len is in characters, not pixels!!
|
||||
*/
|
||||
static void blit_textbox(char *p, int y, int x, int len) {
|
||||
/* if x | y = -1, then centre the box */
|
||||
int xoff, yoff, lin, h, w;
|
||||
char *msg, *m;
|
||||
|
||||
debugC(3, kDebugLevelText, "x=%d, y=%d, len=%d", x, y, len);
|
||||
if (game.window.active)
|
||||
close_window();
|
||||
|
||||
if (x == 0 && y == 0 && len == 0)
|
||||
x = y = -1;
|
||||
|
||||
if (len <= 0 || len >= 40)
|
||||
len = 32;
|
||||
|
||||
xoff = x * CHAR_COLS;
|
||||
yoff = y * CHAR_LINES;
|
||||
len--;
|
||||
|
||||
m = msg = word_wrap_string(agi_sprintf(p), &len);
|
||||
|
||||
for (lin = 1; *m; m++) {
|
||||
/* Test \r for MacOS 8 */
|
||||
if (*m == '\n' || *m == '\r')
|
||||
lin++;
|
||||
}
|
||||
|
||||
if (lin * CHAR_LINES > GFX_HEIGHT)
|
||||
lin = (GFX_HEIGHT / CHAR_LINES);
|
||||
|
||||
w = (len + 2) * CHAR_COLS;
|
||||
h = (lin + 2) * CHAR_LINES;
|
||||
|
||||
if (xoff < 0)
|
||||
xoff = (GFX_WIDTH - w - CHAR_COLS) / 2;
|
||||
else
|
||||
xoff -= CHAR_COLS;
|
||||
|
||||
if (yoff < 0)
|
||||
yoff = (GFX_HEIGHT - 3 * CHAR_LINES - h) / 2;
|
||||
|
||||
draw_window(xoff, yoff, xoff + w - 1, yoff + h - 1);
|
||||
|
||||
print_text2(2, msg, 0, CHAR_COLS + xoff, CHAR_LINES + yoff,
|
||||
len + 1, MSG_BOX_TEXT, MSG_BOX_COLOUR);
|
||||
|
||||
free(msg);
|
||||
|
||||
do_update();
|
||||
}
|
||||
|
||||
static void erase_textbox() {
|
||||
if (!game.window.active) {
|
||||
debugC(3, kDebugLevelText, "no window active");
|
||||
return;
|
||||
}
|
||||
|
||||
debugC(4, kDebugLevelText, "x1=%d, y1=%d, x2=%d, y2=%d", game.window.x1,
|
||||
game.window.y1, game.window.x2, game.window.y2);
|
||||
|
||||
restore_block(game.window.x1, game.window.y1,
|
||||
game.window.x2, game.window.y2, game.window.buffer);
|
||||
|
||||
free(game.window.buffer);
|
||||
game.window.active = false;
|
||||
|
||||
do_update();
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Print text in the AGI engine screen.
|
||||
*/
|
||||
void print_text(char *msg, int f, int x, int y, int len, int fg, int bg) {
|
||||
f *= CHAR_COLS;
|
||||
x *= CHAR_COLS;
|
||||
y *= CHAR_LINES;
|
||||
|
||||
debugC(4, kDebugLevelText, "%s, %d, %d, %d, %d, %d, %d", msg, f, x, y, len, fg, bg);
|
||||
print_text2(0, agi_sprintf(msg), f, x, y, len, fg, bg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print text in the AGI engine console.
|
||||
*/
|
||||
void print_text_console(char *msg, int x, int y, int len, int fg, int bg) {
|
||||
x *= CHAR_COLS;
|
||||
y *= 10;
|
||||
|
||||
print_text2(1, msg, 0, x, y, len, fg, bg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap text line to the specified width.
|
||||
* @param str String to wrap.
|
||||
* @param len Length of line.
|
||||
*/
|
||||
char *word_wrap_string(char *str, int *len) {
|
||||
/* If the message has a long word (longer than 31 character) then
|
||||
* loop in line 239 (for (; *v != ' '; v--, c--);) can wrap
|
||||
* around 0 and write large number in c. This causes returned
|
||||
* length to be negative (!) and eventually crashes in calling
|
||||
* code. The fix is simple -- remove unsigned in maxc, c, l
|
||||
* declaration. --Vasyl
|
||||
*/
|
||||
char *msg, *v, *e;
|
||||
int maxc, c, l = *len;
|
||||
|
||||
v = msg = strdup(str);
|
||||
e = msg + strlen(msg);
|
||||
maxc = 0;
|
||||
|
||||
while (42) {
|
||||
debugC(3, kDebugLevelText, "[%s], %d", msg, maxc);
|
||||
if (strchr(v, ' ') == NULL && (int)strlen(v) > l) {
|
||||
debugC(1, kDebugLevelText | kDebugLevelMain, "Word too long in message");
|
||||
l = strlen(v);
|
||||
}
|
||||
/* Must include \r for MacOS 8 */
|
||||
while ((c = strcspn(v, "\n\r")) <= l) {
|
||||
debugC(3, kDebugLevelText, "c = %d, maxc = %d", c, maxc);
|
||||
if (c > maxc)
|
||||
maxc = c;
|
||||
if ((v += c + 1) >= e)
|
||||
goto end;
|
||||
}
|
||||
c = l;
|
||||
if ((v += l) >= e)
|
||||
break;
|
||||
|
||||
/* The same line that caused that bug I mentioned
|
||||
* should also do another check:
|
||||
* for (; *v != ' ' && *v != '\n'; v--, c--);
|
||||
* While this does not matter in most cases, in the case of
|
||||
* long words it caused extra \n inserted in the line
|
||||
* preceding long word. This one is definitely non-critical;
|
||||
* one might argue that the function is not supposed to deal
|
||||
* with long words. BTW, that condition at the beginning of
|
||||
* the while loop that checks word length does not make much
|
||||
* sense -- it verifies the length of the first word but for
|
||||
* the rest it does something odd. Overall, even with these
|
||||
* changes the function is still not completely robust.
|
||||
* --Vasyl
|
||||
*/
|
||||
if (*v != ' ')
|
||||
for (; *v != ' ' && *v != '\n' && *v != '\r';
|
||||
v--, c--);
|
||||
if (c > maxc)
|
||||
maxc = c;
|
||||
*v++ = '\n';
|
||||
}
|
||||
end:
|
||||
*len = maxc;
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove existing window, if any.
|
||||
*/
|
||||
void close_window() {
|
||||
debugC(4, kDebugLevelText, "close window");
|
||||
erase_both();
|
||||
erase_textbox(); /* remove window, if any */
|
||||
blit_both();
|
||||
commit_both(); /* redraw sprites */
|
||||
game.has_window = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a message box.
|
||||
* This function displays the specified message in a text box
|
||||
* centered in the screen and waits until a key is pressed.
|
||||
* @param p The text to be displayed
|
||||
*/
|
||||
int message_box(char *s) {
|
||||
int k;
|
||||
|
||||
erase_both();
|
||||
blit_textbox(s, -1, -1, -1);
|
||||
blit_both();
|
||||
k = wait_key();
|
||||
debugC(4, kDebugLevelText, "wait_key returned %02x", k);
|
||||
close_window();
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a message box with buttons.
|
||||
* This function displays the specified message in a text box
|
||||
* centered in the screen and waits until a button is pressed.
|
||||
* @param p The text to be displayed
|
||||
* @param b NULL-terminated list of button labels
|
||||
*/
|
||||
int selection_box(char *m, char **b) {
|
||||
int x, y, i, s;
|
||||
int key, active = 0;
|
||||
int rc = -1;
|
||||
int bx[5], by[5];
|
||||
|
||||
erase_both();
|
||||
blit_textbox(m, -1, -1, -1);
|
||||
|
||||
x = game.window.x1 + 5 * CHAR_COLS / 2;
|
||||
y = game.window.y2 - 5 * CHAR_LINES / 2;
|
||||
s = game.window.x2 - game.window.x1 + 1 - 5 * CHAR_COLS;
|
||||
debugC(3, kDebugLevelText, "s = %d", s);
|
||||
|
||||
/* Automatically position buttons */
|
||||
for (i = 0; b[i]; i++) {
|
||||
s -= CHAR_COLS * strlen(b[i]);
|
||||
}
|
||||
|
||||
if (i > 1) {
|
||||
debugC(3, kDebugLevelText, "s / %d = %d", i - 1, s / (i - 1));
|
||||
s /= (i - 1);
|
||||
} else {
|
||||
x += s / 2;
|
||||
}
|
||||
|
||||
for (i = 0; b[i]; i++) {
|
||||
bx[i] = x;
|
||||
by[i] = y;
|
||||
x += CHAR_COLS * strlen(b[i]) + s;
|
||||
}
|
||||
|
||||
blit_both();
|
||||
|
||||
/* clear key queue */
|
||||
while (keypress()) {
|
||||
get_key();
|
||||
}
|
||||
|
||||
debugC(4, kDebugLevelText, "waiting...");
|
||||
while (42) {
|
||||
for (i = 0; b[i]; i++)
|
||||
draw_button(bx[i], by[i], b[i], i == active, 0);
|
||||
|
||||
poll_timer(); /* msdos driver -> does nothing */
|
||||
key = do_poll_keyboard();
|
||||
if (!console_keyhandler(key)) {
|
||||
switch (key) {
|
||||
case KEY_ENTER:
|
||||
rc = active;
|
||||
goto press;
|
||||
case KEY_ESCAPE:
|
||||
rc = -1;
|
||||
goto getout;
|
||||
#ifdef USE_MOUSE
|
||||
case BUTTON_LEFT:
|
||||
for (i = 0; b[i]; i++) {
|
||||
if (test_button(bx[i], by[i], b[i])) {
|
||||
rc = active = i;
|
||||
goto press;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 0x09: /* Tab */
|
||||
debugC(3, kDebugLevelText, "Focus change");
|
||||
active++;
|
||||
active %= i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
console_cycle();
|
||||
}
|
||||
|
||||
press:
|
||||
debugC(4, kDebugLevelText, "Button pressed: %d", rc);
|
||||
|
||||
getout:
|
||||
close_window();
|
||||
debugC(2, kDebugLevelText, "Result = %d", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int print(char *p, int lin, int col, int len) {
|
||||
if (p == NULL)
|
||||
return 0;
|
||||
|
||||
debugC(4, kDebugLevelText, "lin = %d, col = %d, len = %d", lin, col, len);
|
||||
|
||||
if (col == 0 && lin == 0 && len == 0)
|
||||
lin = col = -1;
|
||||
|
||||
if (len == 0)
|
||||
len = 30;
|
||||
|
||||
blit_textbox(p, lin, col, len);
|
||||
|
||||
if (getflag(F_output_mode)) {
|
||||
/* non-blocking window */
|
||||
setflag(F_output_mode, false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* blocking */
|
||||
|
||||
if (game.vars[V_window_reset] == 0) {
|
||||
int k;
|
||||
setvar(V_key, 0);
|
||||
k = wait_key();
|
||||
close_window();
|
||||
return k;
|
||||
}
|
||||
|
||||
/* timed window */
|
||||
|
||||
debugC(3, kDebugLevelText, "f15==0, v21==%d => timed", getvar(21));
|
||||
game.msg_box_ticks = getvar(V_window_reset) * 10;
|
||||
setvar(V_key, 0);
|
||||
|
||||
do {
|
||||
main_cycle();
|
||||
if (game.keypress == KEY_ENTER) {
|
||||
debugC(4, kDebugLevelText, "KEY_ENTER");
|
||||
setvar(V_window_reset, 0);
|
||||
game.keypress = 0;
|
||||
break;
|
||||
}
|
||||
} while (game.msg_box_ticks > 0);
|
||||
|
||||
setvar(V_window_reset, 0);
|
||||
|
||||
close_window();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void print_status(char *message, ...) {
|
||||
char x[42];
|
||||
va_list args;
|
||||
|
||||
va_start(args, message);
|
||||
|
||||
#ifdef HAVE_VSNPRINTF
|
||||
vsnprintf(x, 41, message, args);
|
||||
#else
|
||||
vsprintf(x, message, args);
|
||||
#endif
|
||||
|
||||
va_end(args);
|
||||
|
||||
debugC(4, kDebugLevelText, "fg=%d, bg=%d", STATUS_FG, STATUS_BG);
|
||||
print_text(x, 0, 0, game.line_status, 40, STATUS_FG, STATUS_BG);
|
||||
}
|
||||
|
||||
static char *safe_strcat(char *s, const char *t) {
|
||||
if (t != NULL)
|
||||
strcat(s, t);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats AGI string.
|
||||
* This function turns a AGI string into a real string expanding values
|
||||
* according to the AGI format specifiers.
|
||||
* @param s string containing the format specifier
|
||||
* @param n logic number
|
||||
*/
|
||||
#define MAX_LEN 768
|
||||
char *agi_sprintf(char *s) {
|
||||
static char y[MAX_LEN];
|
||||
char x[MAX_LEN];
|
||||
char z[16], *p;
|
||||
|
||||
debugC(3, kDebugLevelText, "logic %d, '%s'", game.lognum, s);
|
||||
p = x;
|
||||
|
||||
for (*p = 0; *s;) {
|
||||
switch (*s) {
|
||||
case '\\':
|
||||
s++;
|
||||
goto literal;
|
||||
case '%':
|
||||
s++;
|
||||
switch (*s++) {
|
||||
int i;
|
||||
case 'v':
|
||||
i = strtoul(s, NULL, 10);
|
||||
while (*s >= '0' && *s <= '9')
|
||||
s++;
|
||||
sprintf(z, "%015i", getvar(i));
|
||||
|
||||
i = 99;
|
||||
if (*s == '|') {
|
||||
s++;
|
||||
i = strtoul(s, NULL, 10);
|
||||
while (*s >= '0' && *s <= '9')
|
||||
s++;
|
||||
}
|
||||
|
||||
if (i == 99) {
|
||||
/* remove all leading 0 */
|
||||
/* don't remove the 3rd zero if 000 */
|
||||
for (i = 0;
|
||||
z[i] == '0' && i < 14; i++);
|
||||
} else {
|
||||
i = 15 - i;
|
||||
}
|
||||
safe_strcat(p, z + i);
|
||||
break;
|
||||
case '0':
|
||||
i = strtoul(s, NULL, 10) - 1;
|
||||
safe_strcat(p, object_name(i));
|
||||
break;
|
||||
case 'g':
|
||||
i = strtoul(s, NULL, 10) - 1;
|
||||
safe_strcat(p, game.logics[0].texts[i]);
|
||||
break;
|
||||
case 'w':
|
||||
i = strtoul(s, NULL, 10) - 1;
|
||||
safe_strcat(p, game.ego_words[i].word);
|
||||
break;
|
||||
case 's':
|
||||
i = strtoul(s, NULL, 10);
|
||||
safe_strcat(p, game.strings[i]);
|
||||
break;
|
||||
case 'm':
|
||||
i = strtoul(s, NULL, 10) - 1;
|
||||
if (game.logics[game.lognum].num_texts > i)
|
||||
safe_strcat(p, agi_sprintf(game. logics[game.lognum].texts[i]));
|
||||
break;
|
||||
}
|
||||
|
||||
while (*s >= '0' && *s <= '9')
|
||||
s++;
|
||||
while (*p)
|
||||
p++;
|
||||
break;
|
||||
|
||||
default:
|
||||
literal:
|
||||
assert(p < x + MAX_LEN);
|
||||
*p++ = *s++;
|
||||
*p = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(y, x);
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the status line.
|
||||
*/
|
||||
void write_status() {
|
||||
char x[64];
|
||||
|
||||
#ifdef USE_CONSOLE
|
||||
if (debug_.statusline) {
|
||||
#ifdef USE_MOUSE
|
||||
print_status("%3d(%03d) %3d,%3d(%3d,%3d) ",
|
||||
getvar(0), getvar(1), game.view_table[0].x_pos,
|
||||
game.view_table[0].y_pos, WIN_TO_PIC_X(mouse.x),
|
||||
WIN_TO_PIC_Y(mouse.y));
|
||||
#else
|
||||
print_status("%3d(%03d) %3d,%3d ",
|
||||
getvar(0), getvar(1), game.view_table[0].x_pos,
|
||||
game.view_table[0].y_pos);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif /* USE_CONSOLE */
|
||||
|
||||
if (!game.status_line) {
|
||||
int l = game.line_status;
|
||||
clear_lines(l, l, 0);
|
||||
flush_lines(l, l);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(x, " Score:%i of %-3i", game.vars[V_score], game.vars[V_max_score]);
|
||||
print_status("%-17s Sound:%s ", x, getflag(F_sound_on) ? "on " : "off");
|
||||
}
|
||||
|
||||
/**
|
||||
* Print user input prompt.
|
||||
*/
|
||||
void write_prompt() {
|
||||
int l, fg, bg, pos;
|
||||
|
||||
if (!game.input_enabled || game.input_mode != INPUT_NORMAL)
|
||||
return;
|
||||
|
||||
l = game.line_user_input;
|
||||
fg = game.color_fg;
|
||||
bg = game.color_bg;
|
||||
pos = game.cursor_pos;
|
||||
|
||||
debugC(4, kDebugLevelText, "erase line %d", l);
|
||||
clear_lines(l, l, game.color_bg);
|
||||
|
||||
debugC(4, kDebugLevelText, "prompt = '%s'", agi_sprintf(game.strings[0]));
|
||||
print_text(game.strings[0], 0, 0, l, 1, fg, bg);
|
||||
print_text((char *)game.input_buffer, 0, 1, l, pos + 1, fg, bg);
|
||||
print_character(pos + 1, l, game.cursor_char, fg, bg);
|
||||
|
||||
flush_lines(l, l);
|
||||
do_update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear text lines in the screen.
|
||||
* @param l1 start line
|
||||
* @param l2 end line
|
||||
* @param c color
|
||||
*/
|
||||
void clear_lines(int l1, int l2, int c) {
|
||||
/* do we need to adjust for +8 on topline?
|
||||
* inc for endline so it matches the correct num
|
||||
* ie, from 22 to 24 is 3 lines, not 2 lines.
|
||||
*/
|
||||
|
||||
l1 *= CHAR_LINES;
|
||||
l2 *= CHAR_LINES;
|
||||
l2 += CHAR_LINES - 1;
|
||||
|
||||
draw_rectangle(0, l1, GFX_WIDTH - 1, l2, c);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void flush_lines(int l1, int l2) {
|
||||
l1 *= CHAR_LINES;
|
||||
l2 *= CHAR_LINES;
|
||||
l2 += CHAR_LINES - 1;
|
||||
|
||||
flush_block(0, l1, GFX_WIDTH - 1, l2);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void draw_window(int x1, int y1, int x2, int y2) {
|
||||
game.window.active = true;
|
||||
game.window.x1 = x1;
|
||||
game.window.y1 = y1;
|
||||
game.window.x2 = x2;
|
||||
game.window.y2 = y2;
|
||||
game.window.buffer = (uint8 *) malloc((x2 - x1 + 1) * (y2 - y1 + 1));
|
||||
|
||||
debugC(4, kDebugLevelText, "x1=%d, y1=%d, x2=%d, y2=%d", x1, y1, x2, y2);
|
||||
save_block(x1, y1, x2, y2, game.window.buffer);
|
||||
draw_box(x1, y1, x2, y2, MSG_BOX_COLOUR, MSG_BOX_LINE, 2);
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
48
engines/agi/text.h
Normal file
48
engines/agi/text.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_TEXT_H
|
||||
#define __AGI_TEXT_H
|
||||
|
||||
#include "agi/agi.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
int message_box(char *);
|
||||
int selection_box(char *, char **);
|
||||
void close_window(void);
|
||||
void draw_window(int, int, int, int);
|
||||
void print_text(char *, int, int, int, int, int, int);
|
||||
void print_text_console(char *, int, int, int, int, int);
|
||||
int print(char *, int, int, int);
|
||||
char *word_wrap_string(char *, int *);
|
||||
char *agi_sprintf(char *);
|
||||
void write_status(void);
|
||||
void write_prompt(void);
|
||||
void clear_lines(int, int, int);
|
||||
void flush_lines(int, int);
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif /* __AGI_TEXT_H */
|
396
engines/agi/view.cpp
Normal file
396
engines/agi/view.cpp
Normal file
@ -0,0 +1,396 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2003 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/sprite.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
static void _set_cel(struct vt_entry *v, int n) {
|
||||
struct view_loop *current_vl;
|
||||
struct view_cel *current_vc;
|
||||
|
||||
v->current_cel = n;
|
||||
|
||||
current_vl = &game.views[v->current_view].loop[v->current_loop];
|
||||
|
||||
/* Added by Amit Vainsencher <amitv@subdimension.com> to prevent
|
||||
* crash in KQ1 -- not in the Sierra interpreter
|
||||
*/
|
||||
if (current_vl->num_cels == 0)
|
||||
return;
|
||||
|
||||
if (!(v->flags & UPDATE)
|
||||
&& (agi_get_release() >= 0x3000))
|
||||
return;
|
||||
|
||||
current_vc = ¤t_vl->cel[n];
|
||||
v->cel_data = current_vc;
|
||||
v->x_size = current_vc->width;
|
||||
v->y_size = current_vc->height;
|
||||
}
|
||||
|
||||
static void _set_loop(struct vt_entry *v, int n) {
|
||||
struct view_loop *current_vl;
|
||||
debugC(7, kDebugLevelResources, "vt entry #%d, loop = %d", v->entry, n);
|
||||
|
||||
/* Added to avoid crash when leaving the arcade machine in MH1
|
||||
* -- not in AGI 2.917
|
||||
*/
|
||||
if (n >= v->num_loops)
|
||||
n = 0;
|
||||
|
||||
v->current_loop = n;
|
||||
current_vl = &game.views[v->current_view].loop[v->current_loop];
|
||||
|
||||
v->num_cels = current_vl->num_cels;
|
||||
if (v->current_cel >= v->num_cels)
|
||||
v->current_cel = 0;
|
||||
|
||||
if (!(v->flags & UPDATE) && (agi_get_release() >= 0x3000))
|
||||
return;
|
||||
|
||||
v->loop_data = &game.views[v->current_view].loop[n];
|
||||
}
|
||||
|
||||
static void update_view(struct vt_entry *v) {
|
||||
int cel, last_cel;
|
||||
|
||||
if (v->flags & DONTUPDATE) {
|
||||
v->flags &= ~DONTUPDATE;
|
||||
return;
|
||||
}
|
||||
|
||||
cel = v->current_cel;
|
||||
last_cel = v->num_cels - 1;
|
||||
|
||||
switch (v->cycle) {
|
||||
case CYCLE_NORMAL:
|
||||
if (++cel > last_cel)
|
||||
cel = 0;
|
||||
break;
|
||||
case CYCLE_END_OF_LOOP:
|
||||
if (cel < last_cel) {
|
||||
debugC(5, kDebugLevelResources, "cel %d (last = %d)", cel + 1, last_cel);
|
||||
if (++cel != last_cel)
|
||||
break;
|
||||
}
|
||||
setflag(v->parm1, true);
|
||||
v->flags &= ~CYCLING;
|
||||
v->direction = 0;
|
||||
v->cycle = CYCLE_NORMAL;
|
||||
break;
|
||||
case CYCLE_REV_LOOP:
|
||||
if (cel) {
|
||||
if (--cel)
|
||||
break;
|
||||
}
|
||||
setflag(v->parm1, true);
|
||||
v->flags &= ~CYCLING;
|
||||
v->direction = 0;
|
||||
v->cycle = CYCLE_NORMAL;
|
||||
break;
|
||||
case CYCLE_REVERSE:
|
||||
if (cel == 0) {
|
||||
cel = last_cel;
|
||||
} else {
|
||||
cel--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
set_cel(v, cel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decode an AGI view resource.
|
||||
* This function decodes the raw data of the specified AGI view resource
|
||||
* and fills the corresponding views array element.
|
||||
* @param n number of view resource to decode
|
||||
*/
|
||||
int decode_view(int n) {
|
||||
int loop, cel;
|
||||
uint8 *v, *lptr;
|
||||
uint16 lofs, cofs;
|
||||
struct view_loop *vl;
|
||||
struct view_cel *vc;
|
||||
|
||||
debugC(5, kDebugLevelResources, "decode_view(%d)", n);
|
||||
v = game.views[n].rdata;
|
||||
|
||||
assert(v != NULL);
|
||||
|
||||
game.views[n].descr = READ_LE_UINT16(v + 3) ? (char *)(v + READ_LE_UINT16(v + 3)) : (char *)(v + 3);
|
||||
|
||||
/* if no loops exist, return! */
|
||||
if ((game.views[n].num_loops = *(v + 2)) == 0)
|
||||
return err_NoLoopsInView;
|
||||
|
||||
/* allocate memory for all views */
|
||||
game.views[n].loop = (view_loop *)
|
||||
calloc(game.views[n].num_loops, sizeof(struct view_loop));
|
||||
|
||||
if (game.views[n].loop == NULL)
|
||||
return err_NotEnoughMemory;
|
||||
|
||||
/* decode all of the loops in this view */
|
||||
lptr = v + 5; /* first loop address */
|
||||
|
||||
for (loop = 0; loop < game.views[n].num_loops; loop++, lptr += 2) {
|
||||
lofs = READ_LE_UINT16(lptr); /* loop header offset */
|
||||
vl = &game.views[n].loop[loop]; /* the loop struct */
|
||||
|
||||
vl->num_cels = *(v + lofs);
|
||||
debugC(6, kDebugLevelResources, "view %d, num_cels = %d", n, vl->num_cels);
|
||||
vl->cel = (view_cel *) calloc(vl->num_cels, sizeof(struct view_cel));
|
||||
if (vl->cel == NULL) {
|
||||
free(game.views[n].loop);
|
||||
game.views[n].num_loops = 0;
|
||||
return err_NotEnoughMemory;
|
||||
}
|
||||
|
||||
/* decode the cells */
|
||||
for (cel = 0; cel < vl->num_cels; cel++) {
|
||||
cofs = lofs + READ_LE_UINT16(v + lofs + 1 + (cel * 2));
|
||||
vc = &vl->cel[cel];
|
||||
|
||||
vc->width = *(v + cofs);
|
||||
vc->height = *(v + cofs + 1);
|
||||
vc->transparency = *(v + cofs + 2) & 0xf;
|
||||
vc->mirror_loop = (*(v + cofs + 2) >> 4) & 0x7;
|
||||
vc->mirror = (*(v + cofs + 2) >> 7) & 0x1;
|
||||
|
||||
/* skip over width/height/trans|mirror data */
|
||||
cofs += 3;
|
||||
|
||||
vc->data = v + cofs;
|
||||
/* If mirror_loop is pointing to the current loop,
|
||||
* then this is the original.
|
||||
*/
|
||||
if (vc->mirror_loop == loop)
|
||||
vc->mirror = 0;
|
||||
} /* cel */
|
||||
} /* loop */
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unloads all data in a view resource
|
||||
* @param n number of view resource
|
||||
*/
|
||||
void unload_view(int n) {
|
||||
int x;
|
||||
|
||||
debugC(5, kDebugLevelResources, "discard view %d", n);
|
||||
if (~game.dir_view[n].flags & RES_LOADED)
|
||||
return;
|
||||
|
||||
/* Rebuild sprite list, see bug #779302 */
|
||||
erase_both();
|
||||
blit_both();
|
||||
commit_both();
|
||||
|
||||
/* free all the loops */
|
||||
for (x = 0; x < game.views[n].num_loops; x++)
|
||||
free(game.views[n].loop[x].cel);
|
||||
|
||||
free(game.views[n].loop);
|
||||
free(game.views[n].rdata);
|
||||
|
||||
game.dir_view[n].flags &= ~RES_LOADED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a view table entry to use the specified cel of the current loop.
|
||||
* @param v pointer to view table entry
|
||||
* @param n number of cel
|
||||
*/
|
||||
void set_cel(struct vt_entry *v, int n) {
|
||||
assert(v->view_data != NULL);
|
||||
assert(v->num_cels >= n);
|
||||
|
||||
_set_cel(v, n);
|
||||
|
||||
/* If position isn't appropriate, update it accordingly */
|
||||
if (v->x_pos + v->x_size > _WIDTH) {
|
||||
v->flags |= UPDATE_POS;
|
||||
v->x_pos = _WIDTH - v->x_size;
|
||||
}
|
||||
if (v->y_pos - v->y_size + 1 < 0) {
|
||||
v->flags |= UPDATE_POS;
|
||||
v->y_pos = v->y_size - 1;
|
||||
}
|
||||
if (v->y_pos <= game.horizon && (~v->flags & IGNORE_HORIZON)) {
|
||||
v->flags |= UPDATE_POS;
|
||||
v->y_pos = game.horizon + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a view table entry to use the specified loop of the current view.
|
||||
* @param v pointer to view table entry
|
||||
* @param n number of loop
|
||||
*/
|
||||
void set_loop(struct vt_entry *v, int n) {
|
||||
assert(v->view_data != NULL);
|
||||
assert(v->num_loops >= n);
|
||||
_set_loop(v, n);
|
||||
set_cel(v, v->current_cel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a view table entry to use the specified view resource.
|
||||
* @param v pointer to view table entry
|
||||
* @param n number of AGI view resource
|
||||
*/
|
||||
void set_view(struct vt_entry *v, int n) {
|
||||
v->view_data = &game.views[n];
|
||||
v->current_view = n;
|
||||
v->num_loops = v->view_data->num_loops;
|
||||
set_loop(v, v->current_loop >= v->num_loops ? 0 : v->current_loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the view table entry as updating.
|
||||
* @param v pointer to view table entry
|
||||
*/
|
||||
void start_update(struct vt_entry *v) {
|
||||
if (~v->flags & UPDATE) {
|
||||
erase_both();
|
||||
v->flags |= UPDATE;
|
||||
blit_both();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the view table entry as non-updating.
|
||||
* @param v pointer to view table entry
|
||||
*/
|
||||
void stop_update(struct vt_entry *v) {
|
||||
if (v->flags & UPDATE) {
|
||||
erase_both();
|
||||
v->flags &= ~UPDATE;
|
||||
blit_both();
|
||||
}
|
||||
}
|
||||
|
||||
/* loops to use according to direction and number of loops in
|
||||
* the view resource
|
||||
*/
|
||||
static int loop_table_2[] = {
|
||||
0x04, 0x04, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x01
|
||||
};
|
||||
|
||||
static int loop_table_4[] = {
|
||||
0x04, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x01
|
||||
};
|
||||
|
||||
/**
|
||||
* Update view table entries.
|
||||
* This function is called at the end of each interpreter cycle
|
||||
* to update the view table entries and blit the sprites.
|
||||
*/
|
||||
void update_viewtable() {
|
||||
struct vt_entry *v;
|
||||
int i, loop;
|
||||
|
||||
i = 0;
|
||||
for (v = game.view_table; v < &game.view_table[MAX_VIEWTABLE]; v++) {
|
||||
if ((v->flags & (ANIMATED | UPDATE | DRAWN)) != (ANIMATED | UPDATE | DRAWN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
loop = 4;
|
||||
if (~v->flags & FIX_LOOP) {
|
||||
switch (v->num_loops) {
|
||||
case 2:
|
||||
case 3:
|
||||
loop = loop_table_2[v->direction];
|
||||
break;
|
||||
case 4:
|
||||
loop = loop_table_4[v->direction];
|
||||
break;
|
||||
default:
|
||||
/* for KQ4 */
|
||||
if (agi_get_release() == 0x3086)
|
||||
loop = loop_table_4[v->direction];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* AGI 2.272 (ddp, xmas) doesn't test step_time_count! */
|
||||
if (loop != 4 && loop != v->current_loop) {
|
||||
if (agi_get_release() <= 0x2272 ||
|
||||
v->step_time_count == 1) {
|
||||
set_loop(v, loop);
|
||||
}
|
||||
}
|
||||
|
||||
if (~v->flags & CYCLING)
|
||||
continue;
|
||||
|
||||
if (v->cycle_time_count == 0)
|
||||
continue;
|
||||
|
||||
if (--v->cycle_time_count == 0) {
|
||||
update_view(v);
|
||||
v->cycle_time_count = v->cycle_time;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
#ifdef USE_CONSOLE
|
||||
/* To correctly update sprites when we use the console
|
||||
* we must work with all sprites.
|
||||
*/
|
||||
if (console.y > 0) {
|
||||
erase_both();
|
||||
update_position();
|
||||
blit_both();
|
||||
commit_both();
|
||||
} else
|
||||
#endif
|
||||
/* If we're not using the console, updating only
|
||||
* the active sprites lets us save some CPU cycles.
|
||||
* This is how the original Sierra AGI works.
|
||||
*/
|
||||
{
|
||||
erase_upd_sprites();
|
||||
update_position();
|
||||
blit_upd_sprites();
|
||||
commit_upd_sprites();
|
||||
}
|
||||
|
||||
game.view_table[0].flags &= ~(ON_WATER | ON_LAND);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
142
engines/agi/view.h
Normal file
142
engines/agi/view.h
Normal file
@ -0,0 +1,142 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2001 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AGI_VIEW_H
|
||||
#define __AGI_VIEW_H
|
||||
|
||||
namespace Agi {
|
||||
|
||||
struct view_cel {
|
||||
uint8 height;
|
||||
uint8 width;
|
||||
uint8 transparency;
|
||||
uint8 mirror_loop;
|
||||
uint8 mirror;
|
||||
uint8 *data;
|
||||
};
|
||||
|
||||
struct view_loop {
|
||||
int num_cels;
|
||||
struct view_cel *cel;
|
||||
};
|
||||
|
||||
/**
|
||||
* AGI view resource structure.
|
||||
*/
|
||||
struct agi_view {
|
||||
int num_loops;
|
||||
struct view_loop *loop;
|
||||
char *descr;
|
||||
uint8 *rdata;
|
||||
};
|
||||
|
||||
/**
|
||||
* AGI view table entry
|
||||
*/
|
||||
struct vt_entry {
|
||||
uint8 step_time;
|
||||
uint8 step_time_count;
|
||||
uint8 entry;
|
||||
int16 x_pos;
|
||||
int16 y_pos;
|
||||
uint8 current_view;
|
||||
struct agi_view *view_data;
|
||||
uint8 current_loop;
|
||||
uint8 num_loops;
|
||||
struct view_loop *loop_data;
|
||||
uint8 current_cel;
|
||||
uint8 num_cels;
|
||||
struct view_cel *cel_data;
|
||||
struct view_cel *cel_data_2;
|
||||
int16 x_pos2;
|
||||
int16 y_pos2;
|
||||
void *s;
|
||||
int16 x_size;
|
||||
int16 y_size;
|
||||
uint8 step_size;
|
||||
uint8 cycle_time;
|
||||
uint8 cycle_time_count;
|
||||
uint8 direction;
|
||||
|
||||
#define MOTION_NORMAL 0
|
||||
#define MOTION_WANDER 1
|
||||
#define MOTION_FOLLOW_EGO 2
|
||||
#define MOTION_MOVE_OBJ 3
|
||||
uint8 motion;
|
||||
|
||||
#define CYCLE_NORMAL 0
|
||||
#define CYCLE_END_OF_LOOP 1
|
||||
#define CYCLE_REV_LOOP 2
|
||||
#define CYCLE_REVERSE 3
|
||||
uint8 cycle;
|
||||
|
||||
uint8 priority;
|
||||
|
||||
#define DRAWN 0x0001
|
||||
#define IGNORE_BLOCKS 0x0002
|
||||
#define FIXED_PRIORITY 0x0004
|
||||
#define IGNORE_HORIZON 0x0008
|
||||
#define UPDATE 0x0010
|
||||
#define CYCLING 0x0020
|
||||
#define ANIMATED 0x0040
|
||||
#define MOTION 0x0080
|
||||
#define ON_WATER 0x0100
|
||||
#define IGNORE_OBJECTS 0x0200
|
||||
#define UPDATE_POS 0x0400
|
||||
#define ON_LAND 0x0800
|
||||
#define DONTUPDATE 0x1000
|
||||
#define FIX_LOOP 0x2000
|
||||
#define DIDNT_MOVE 0x4000
|
||||
#define ADJ_EGO_XY 0x8000
|
||||
uint16 flags;
|
||||
|
||||
uint8 parm1;
|
||||
uint8 parm2;
|
||||
uint8 parm3;
|
||||
uint8 parm4;
|
||||
}; /* struct vt_entry */
|
||||
|
||||
/* Motion */
|
||||
void check_all_motions(void);
|
||||
void move_obj(struct vt_entry *);
|
||||
void in_destination(struct vt_entry *);
|
||||
void fix_position(int);
|
||||
void update_position(void);
|
||||
|
||||
/* View table management */
|
||||
void set_cel(struct vt_entry *, int);
|
||||
void set_loop(struct vt_entry *, int);
|
||||
void set_view(struct vt_entry *, int);
|
||||
void start_update(struct vt_entry *);
|
||||
void stop_update(struct vt_entry *);
|
||||
void update_viewtable(void);
|
||||
|
||||
void unload_view(int);
|
||||
int decode_view(int);
|
||||
void add_to_pic(int, int, int, int, int, int, int);
|
||||
void draw_obj(int);
|
||||
|
||||
} // End of namespace Agi
|
||||
|
||||
#endif /* __AGI_VIEW_H */
|
213
engines/agi/words.cpp
Normal file
213
engines/agi/words.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2006 The ScummVM project
|
||||
*
|
||||
* Copyright (C) 1999-2002 Sarien Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* New find_word algorithm by Thomas Akesson <tapilot@home.se>
|
||||
*/
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/keyboard.h" /* for clean_input() */
|
||||
|
||||
namespace Agi {
|
||||
|
||||
static uint8 *words; /* words in the game */
|
||||
static uint32 words_flen; /* length of word memory */
|
||||
|
||||
/*
|
||||
* Local implementation to avoid problems with strndup() used by
|
||||
* gcc 3.2 Cygwin (see #635984)
|
||||
*/
|
||||
static char *my_strndup(char *src, int n) {
|
||||
char *tmp = strncpy((char *)malloc(n + 1), src, n);
|
||||
tmp[n] = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int load_words(char *fname) {
|
||||
Common::File fp;
|
||||
uint32 flen;
|
||||
uint8 *mem = NULL;
|
||||
char *path = NULL;
|
||||
|
||||
words = NULL;
|
||||
|
||||
path = fname;
|
||||
|
||||
if (!fp.open(path)) {
|
||||
report("Warning: can't open %s\n", path);
|
||||
return err_OK /*err_BadFileOpen */ ;
|
||||
}
|
||||
report("Loading dictionary: %s\n", path);
|
||||
|
||||
fp.seek(0, SEEK_END);
|
||||
flen = fp.pos();
|
||||
words_flen = flen;
|
||||
fp.seek(0, SEEK_SET);
|
||||
|
||||
if ((mem = (uint8 *)calloc(1, flen + 32)) == NULL) {
|
||||
fp.close();
|
||||
return err_NotEnoughMemory;
|
||||
}
|
||||
|
||||
fp.read(mem, flen);
|
||||
fp.close();
|
||||
|
||||
words = mem;
|
||||
|
||||
return err_OK;
|
||||
}
|
||||
|
||||
void unload_words() {
|
||||
if (words != NULL) {
|
||||
free(words);
|
||||
words = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a word in the dictionary
|
||||
* Uses an algorithm hopefully like the one Sierra used. Returns the ID
|
||||
* of the word and the length in flen. Returns -1 if not found.
|
||||
*
|
||||
* Thomas Åkesson, November 2001
|
||||
*/
|
||||
int find_word(char *word, int *flen) {
|
||||
int mchr = 0; /* matched chars */
|
||||
int len, fchr, id = -1;
|
||||
uint8 *p = words;
|
||||
uint8 *q = words + words_flen;
|
||||
*flen = 0;
|
||||
|
||||
debugC(2, kDebugLevelScripts, "find_word(%s)", word);
|
||||
if (word[0] >= 'a' && word[0] <= 'z')
|
||||
fchr = word[0] - 'a';
|
||||
else
|
||||
return -1;
|
||||
|
||||
len = strlen(word);
|
||||
|
||||
/* Get the offset to the first word beginning with the
|
||||
* right character
|
||||
*/
|
||||
p += READ_BE_UINT16(p + 2 * fchr);
|
||||
|
||||
while (p[0] >= mchr) {
|
||||
if (p[0] == mchr) {
|
||||
p++;
|
||||
/* Loop through all matching characters */
|
||||
while ((p[0] ^ word[mchr]) == 0x7F && mchr < len) {
|
||||
mchr++;
|
||||
p++;
|
||||
}
|
||||
/* Check if this is the last character of the word
|
||||
* and if it matches
|
||||
*/
|
||||
if ((p[0] ^ word[mchr]) == 0xFF && mchr < len) {
|
||||
mchr++;
|
||||
if (word[mchr] == 0 || word[mchr] == 0x20) {
|
||||
id = READ_BE_UINT16(p + 1);
|
||||
*flen = mchr;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p >= q)
|
||||
return -1;
|
||||
|
||||
/* Step to the next word */
|
||||
while (p[0] < 0x80)
|
||||
p++;
|
||||
p += 3;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void dictionary_words(char *msg) {
|
||||
char *p = NULL;
|
||||
char *q = NULL;
|
||||
int wid, wlen;
|
||||
|
||||
debugC(2, kDebugLevelScripts, "msg = \"%s\"", msg);
|
||||
|
||||
clean_input();
|
||||
|
||||
for (p = msg; p && *p && getvar(V_word_not_found) == 0;) {
|
||||
if (*p == 0x20)
|
||||
p++;
|
||||
|
||||
if (*p == 0)
|
||||
break;
|
||||
|
||||
wid = find_word(p, &wlen);
|
||||
debugC(2, kDebugLevelScripts, "find_word(p) == %d", wid);
|
||||
|
||||
switch (wid) {
|
||||
case -1:
|
||||
debugC(2, kDebugLevelScripts, "unknown word");
|
||||
game.ego_words[game.num_ego_words].word = strdup(p);
|
||||
q = game.ego_words[game.num_ego_words].word;
|
||||
game.ego_words[game.num_ego_words].id = 19999;
|
||||
setvar(V_word_not_found, 1 + game.num_ego_words);
|
||||
game.num_ego_words++;
|
||||
p += strlen(p);
|
||||
break;
|
||||
case 0:
|
||||
/* ignore this word */
|
||||
debugC(2, kDebugLevelScripts, "ignore word");
|
||||
p += wlen;
|
||||
q = NULL;
|
||||
break;
|
||||
default:
|
||||
/* an OK word */
|
||||
debugC(3, kDebugLevelScripts, "ok word (%d)", wid);
|
||||
game.ego_words[game.num_ego_words].id = wid;
|
||||
game.ego_words[game.num_ego_words].word = my_strndup(p, wlen);
|
||||
game.num_ego_words++;
|
||||
p += wlen;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p != NULL && *p) {
|
||||
debugC(2, kDebugLevelScripts, "p = %s", p);
|
||||
*p = 0;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (q != NULL) {
|
||||
for (; (*q != 0 && *q != 0x20); q++);
|
||||
if (*q) {
|
||||
*q = 0;
|
||||
q++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debugC(4, kDebugLevelScripts, "num_ego_words = %d", game.num_ego_words);
|
||||
if (game.num_ego_words > 0) {
|
||||
setflag(F_entered_cli, true);
|
||||
setflag(F_said_accepted_input, false);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
@ -25,6 +25,10 @@ static const char *credits[] = {
|
||||
"\\C\\c0""Gregory Montoir",
|
||||
"\\C\\c0""Eugene Sandulenko",
|
||||
"\\C\\c0""",
|
||||
"\\C\\c1""AGI",
|
||||
"\\C\\c0""Pawel Kolodziejski",
|
||||
"\\C\\c0""Eugene Sandulenko",
|
||||
"\\C\\c0""",
|
||||
"\\C\\c1""BASS",
|
||||
"\\C\\c0""Robert Goeffringmann",
|
||||
"\\C\\c0""Oliver Kiehl",
|
||||
@ -235,6 +239,8 @@ static const char *credits[] = {
|
||||
"\\C\\c2""Various info on his FM-TOWNS/Marty SCUMM ports",
|
||||
"\\C\\c0""lloyd",
|
||||
"\\C\\c2""For deep tech details about C64 Zak & MM",
|
||||
"\\C\\c0""Sarien Team",
|
||||
"\\C\\c2""Original AGI engine code",
|
||||
"\\C\\c0""Jimmi Thogersen",
|
||||
"\\C\\c2""For ScummRev, and much obscure code/documentation",
|
||||
"\\C\\c0""Tristan",
|
||||
|
@ -459,6 +459,11 @@ begin_credits("Credits");
|
||||
add_person("Eugene Sandulenko", "sev", "");
|
||||
end_section();
|
||||
|
||||
begin_section("AGI");
|
||||
add_person("Paweł Kołodziejski", "aquadran", "");
|
||||
add_person("Eugene Sandulenko", "sev", "");
|
||||
end_section();
|
||||
|
||||
begin_section("BASS"); # Beneath a Steel Sky
|
||||
add_person("Robert Göffringmann", "lavosspawn", "");
|
||||
add_person("Oliver Kiehl", "olki", "");
|
||||
@ -669,6 +674,7 @@ begin_credits("Credits");
|
||||
add_person("", "Jezar", "For his freeverb filter implementation");
|
||||
add_person("Jim Leiterman", "", "Various info on his FM-TOWNS/Marty SCUMM ports");
|
||||
add_person("", "lloyd", "For deep tech details about C64 Zak & MM");
|
||||
add_person("Sarien Team", "", "Original AGI engine code");
|
||||
add_person("Jimmi Thøgersen", "", "For ScummRev, and much obscure code/documentation");
|
||||
add_person("", "Tristan", "For additional work on the original MT-32 emulator");
|
||||
end_persons();
|
||||
|
Loading…
x
Reference in New Issue
Block a user