commit 42ce77ce05c1fd8fa000160ef2776faac9eb1156 Author: aperturesecurity Date: Sun Sep 30 16:17:16 2018 +0300 Rebirth and Nuke diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..e96b083e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,358 @@ +# ELF object file. +*.o + +# PE shared library and associated files. +*.lib +*.exp +*.dll + +# PE executable. +*.exe + +# GCC dependency file. +*.d + +# Resource file. +*.res + +# Created by https://www.gitignore.io/api/visualstudio + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +WinDebug/ +WinRel/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +*.pubxml.user + +# End of https://www.gitignore.io/api/visualstudio diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..aa961c0f0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,34 @@ +language: cpp + +os: + - linux + - osx + +notifications: + email: + on_failure: change # default: always + +addons: + # Packages for Linux + apt: + packages: + - mingw-w64 + +env: + - MAKE_BUILD=make + - MAKE_BUILD=debug + +before_install: + # Packages for OSX + - if [ $TRAVIS_OS_NAME = osx ]; then brew install mingw-w64; fi + +before_script: + - touch storm.dll + - touch diabloui.dll + +script: + - if [ $MAKE_BUILD = make ]; then make; fi + - if [ $MAKE_BUILD = debug ]; then make debug; fi + +after_script: + - make clean diff --git a/3rdParty/PKWare/explode.cpp b/3rdParty/PKWare/explode.cpp new file mode 100644 index 000000000..8d69af309 --- /dev/null +++ b/3rdParty/PKWare/explode.cpp @@ -0,0 +1,522 @@ +/*****************************************************************************/ +/* explode.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Implode function of PKWARE Data Compression library */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */ +/* 08.04.03 1.01 Lad Renamed to explode.cpp to be compatible with pkware */ +/* 02.05.03 1.01 Lad Stress test done */ +/* 22.04.10 1.01 Lad Documented */ +/*****************************************************************************/ + +#include +#include + +#include "pkware.h" + +#define PKDCL_OK 0 +#define PKDCL_STREAM_END 1 // All data from the input stream is read +#define PKDCL_NEED_DICT 2 // Need more data (dictionary) +#define PKDCL_CONTINUE 10 // Internal flag, not returned to user +#define PKDCL_GET_INPUT 11 // Internal flag, not returned to user + +static char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n" + "Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n" + "Patent No. 5,051,745\r\n" + "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n" + "Version 1.11\r\n"; + +//----------------------------------------------------------------------------- +// Tables + +static unsigned char DistBits[] = +{ + 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +static unsigned char DistCode[] = +{ + 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A, + 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C, + 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, + 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00 +}; + +static unsigned char ExLenBits[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 +}; + +static unsigned short LenBase[] = +{ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106 +}; + +static unsigned char LenBits[] = +{ + 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07 +}; + +static unsigned char LenCode[] = +{ + 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00 +}; + +static unsigned char ChBitsAsc[] = +{ + 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08, + 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B, + 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06, + 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08, + 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05, + 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, + 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D +}; + +static unsigned short ChCodeAsc[] = +{ + 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0, + 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0, + 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360, + 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60, + 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8, + 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098, + 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C, + 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710, + 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8, + 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E, + 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8, + 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088, + 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A, + 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D, + 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078, + 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0, + 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040, + 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380, + 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180, + 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280, + 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080, + 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300, + 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0, + 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320, + 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220, + 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0, + 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0, + 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340, + 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900, + 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600, + 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200, + 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000 +}; + +//----------------------------------------------------------------------------- +// Local functions + +static void GenDecodeTabs( + unsigned char * positions, // [out] Table of positions + unsigned char * start_indexes, // [in] Table of start indexes + unsigned char * length_bits, // [in] Table of lengths. Each length is stored as number of bits + size_t elements) // [in] Number of elements in start_indexes and length_bits +{ + unsigned int index; + unsigned int length; + size_t i; + + for(i = 0; i < elements; i++) + { + length = 1 << length_bits[i]; // Get the length in bytes + + for(index = start_indexes[i]; index < 0x100; index += length) + { + positions[index] = (unsigned char)i; + } + } +} + +static void GenAscTabs(TDcmpStruct * pWork) +{ + unsigned short * pChCodeAsc = &ChCodeAsc[0xFF]; + unsigned int acc, add; + unsigned short count; + + for(count = 0x00FF; pChCodeAsc >= ChCodeAsc; pChCodeAsc--, count--) + { + unsigned char * pChBitsAsc = pWork->ChBitsAsc + count; + unsigned char bits_asc = *pChBitsAsc; + + if(bits_asc <= 8) + { + add = (1 << bits_asc); + acc = *pChCodeAsc; + + do + { + pWork->offs2C34[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x100); + } + else if((acc = (*pChCodeAsc & 0xFF)) != 0) + { + pWork->offs2C34[acc] = 0xFF; + + if(*pChCodeAsc & 0x3F) + { + bits_asc -= 4; + *pChBitsAsc = bits_asc; + + add = (1 << bits_asc); + acc = *pChCodeAsc >> 4; + do + { + pWork->offs2D34[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x100); + } + else + { + bits_asc -= 6; + *pChBitsAsc = bits_asc; + + add = (1 << bits_asc); + acc = *pChCodeAsc >> 6; + do + { + pWork->offs2E34[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x80); + } + } + else + { + bits_asc -= 8; + *pChBitsAsc = bits_asc; + + add = (1 << bits_asc); + acc = *pChCodeAsc >> 8; + do + { + pWork->offs2EB4[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x100); + } + } +} + +//----------------------------------------------------------------------------- +// Removes given number of bits in the bit buffer. New bits are reloaded from +// the input buffer, if needed. +// Returns: PKDCL_OK: Operation was successful +// PKDCL_STREAM_END: There are no more bits in the input buffer + +static int WasteBits(TDcmpStruct * pWork, unsigned int nBits) +{ + // If number of bits required is less than number of (bits in the buffer) ? + if(nBits <= pWork->extra_bits) + { + pWork->extra_bits -= nBits; + pWork->bit_buff >>= nBits; + return PKDCL_OK; + } + + // Load input buffer if necessary + pWork->bit_buff >>= pWork->extra_bits; + if(pWork->in_pos == pWork->in_bytes) + { + pWork->in_pos = sizeof(pWork->in_buff); + if((pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param)) == 0) + return PKDCL_STREAM_END; + pWork->in_pos = 0; + } + + // Update bit buffer + pWork->bit_buff |= (pWork->in_buff[pWork->in_pos++] << 8); + pWork->bit_buff >>= (nBits - pWork->extra_bits); + pWork->extra_bits = (pWork->extra_bits - nBits) + 8; + return PKDCL_OK; +} + +//----------------------------------------------------------------------------- +// Decodes next literal from the input (compressed) data. +// Returns : 0x000: One byte 0x00 +// 0x001: One byte 0x01 +// ... +// 0x0FF: One byte 0xFF +// 0x100: Repetition, length of 0x02 bytes +// 0x101: Repetition, length of 0x03 bytes +// ... +// 0x304: Repetition, length of 0x206 bytes +// 0x305: End of stream +// 0x306: Error + +static unsigned int DecodeLit(TDcmpStruct * pWork) +{ + unsigned int extra_length_bits; // Number of bits of extra literal length + unsigned int length_code; // Length code + unsigned int value; + + // Test the current bit in byte buffer. If is not set, simply return the next 8 bits. + if(pWork->bit_buff & 1) + { + // Remove one bit from the input data + if(WasteBits(pWork, 1)) + return 0x306; + + // The next 8 bits hold the index to the length code table + length_code = pWork->LengthCodes[pWork->bit_buff & 0xFF]; + + // Remove the apropriate number of bits + if(WasteBits(pWork, pWork->LenBits[length_code])) + return 0x306; + + // Are there some extra bits for the obtained length code ? + if((extra_length_bits = pWork->ExLenBits[length_code]) != 0) + { + unsigned int extra_length = pWork->bit_buff & ((1 << extra_length_bits) - 1); + + if(WasteBits(pWork, extra_length_bits)) + { + if((length_code + extra_length) != 0x10E) + return 0x306; + } + length_code = pWork->LenBase[length_code] + extra_length; + } + + // In order to distinguish uncompressed byte from repetition length, + // we have to add 0x100 to the length. + return length_code + 0x100; + } + + // Remove one bit from the input data + if(WasteBits(pWork, 1)) + return 0x306; + + // If the binary compression type, read 8 bits and return them as one byte. + if(pWork->ctype == CMP_BINARY) + { + unsigned int uncompressed_byte = pWork->bit_buff & 0xFF; + + if(WasteBits(pWork, 8)) + return 0x306; + return uncompressed_byte; + } + + // When ASCII compression ... + if(pWork->bit_buff & 0xFF) + { + value = pWork->offs2C34[pWork->bit_buff & 0xFF]; + + if(value == 0xFF) + { + if(pWork->bit_buff & 0x3F) + { + if(WasteBits(pWork, 4)) + return 0x306; + + value = pWork->offs2D34[pWork->bit_buff & 0xFF]; + } + else + { + if(WasteBits(pWork, 6)) + return 0x306; + + value = pWork->offs2E34[pWork->bit_buff & 0x7F]; + } + } + } + else + { + if(WasteBits(pWork, 8)) + return 0x306; + + value = pWork->offs2EB4[pWork->bit_buff & 0xFF]; + } + + return WasteBits(pWork, pWork->ChBitsAsc[value]) ? 0x306 : value; +} + +//----------------------------------------------------------------------------- +// Decodes the distance of the repetition, backwards relative to the +// current output buffer position + +static unsigned int DecodeDist(TDcmpStruct * pWork, unsigned int rep_length) +{ + unsigned int dist_pos_code; // Distance position code + unsigned int dist_pos_bits; // Number of bits of distance position + unsigned int distance; // Distance position + + // Next 2-8 bits in the input buffer is the distance position code + dist_pos_code = pWork->DistPosCodes[pWork->bit_buff & 0xFF]; + dist_pos_bits = pWork->DistBits[dist_pos_code]; + if(WasteBits(pWork, dist_pos_bits)) + return 0; + + if(rep_length == 2) + { + // If the repetition is only 2 bytes length, + // then take 2 bits from the stream in order to get the distance + distance = (dist_pos_code << 2) | (pWork->bit_buff & 0x03); + if(WasteBits(pWork, 2)) + return 0; + } + else + { + // If the repetition is more than 2 bytes length, + // then take "dsize_bits" bits in order to get the distance + distance = (dist_pos_code << pWork->dsize_bits) | (pWork->bit_buff & pWork->dsize_mask); + if(WasteBits(pWork, pWork->dsize_bits)) + return 0; + } + return distance + 1; +} + +static unsigned int Expand(TDcmpStruct * pWork) +{ + unsigned int next_literal; // Literal decoded from the compressed data + unsigned int result; // Value to be returned + unsigned int copyBytes; // Number of bytes to copy to the output buffer + + pWork->outputPos = 0x1000; // Initialize output buffer position + + // Decode the next literal from the input data. + // The returned literal can either be an uncompressed byte (next_literal < 0x100) + // or an encoded length of the repeating byte sequence that + // is to be copied to the current buffer position + while((result = next_literal = DecodeLit(pWork)) < 0x305) + { + // If the literal is greater than 0x100, it holds length + // of repeating byte sequence + // literal of 0x100 means repeating sequence of 0x2 bytes + // literal of 0x101 means repeating sequence of 0x3 bytes + // ... + // literal of 0x305 means repeating sequence of 0x207 bytes + if(next_literal >= 0x100) + { + unsigned char * source; + unsigned char * target; + unsigned int rep_length; // Length of the repetition, in bytes + unsigned int minus_dist; // Backward distance to the repetition, relative to the current buffer position + + // Get the length of the repeating sequence. + // Note that the repeating block may overlap the current output position, + // for example if there was a sequence of equal bytes + rep_length = next_literal - 0xFE; + + // Get backward distance to the repetition + if((minus_dist = DecodeDist(pWork, rep_length)) == 0) + { + result = 0x306; + break; + } + + // Target and source pointer + target = &pWork->out_buff[pWork->outputPos]; + source = target - minus_dist; + + // Update buffer output position + pWork->outputPos += rep_length; + + // Copy the repeating sequence + while(rep_length-- > 0) + *target++ = *source++; + } + else + { + pWork->out_buff[pWork->outputPos++] = (unsigned char)next_literal; + } + + // Flush the output buffer, if number of extracted bytes has reached the end + if(pWork->outputPos >= 0x2000) + { + // Copy decompressed data into user buffer + copyBytes = 0x1000; + pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param); + + // Now copy the decompressed data to the first half of the buffer. + // This is needed because the decompression might reuse them as repetitions. + // Note that if the output buffer overflowed previously, the extra decompressed bytes + // are stored in "out_buff_overflow", and they will now be + // within decompressed part of the output buffer. + memmove(pWork->out_buff, &pWork->out_buff[0x1000], pWork->outputPos - 0x1000); + pWork->outputPos -= 0x1000; + } + } + + // Flush any remaining decompressed bytes + copyBytes = pWork->outputPos - 0x1000; + pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param); + return result; +} + + +//----------------------------------------------------------------------------- +// Main exploding function. + +unsigned int explode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param) +{ + TDcmpStruct * pWork = (TDcmpStruct *)work_buf; + + // Initialize work struct and load compressed data + // Note: The caller must zero the "work_buff" before passing it to explode + pWork->read_buf = read_buf; + pWork->write_buf = write_buf; + pWork->param = param; + pWork->in_pos = sizeof(pWork->in_buff); + pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param); + if(pWork->in_bytes <= 4) + return CMP_BAD_DATA; + + pWork->ctype = pWork->in_buff[0]; // Get the compression type (CMP_BINARY or CMP_ASCII) + pWork->dsize_bits = pWork->in_buff[1]; // Get the dictionary size + pWork->bit_buff = pWork->in_buff[2]; // Initialize 16-bit bit buffer + pWork->extra_bits = 0; // Extra (over 8) bits + pWork->in_pos = 3; // Position in input buffer + + // Test for the valid dictionary size + if(4 > pWork->dsize_bits || pWork->dsize_bits > 6) + return CMP_INVALID_DICTSIZE; + + pWork->dsize_mask = 0xFFFF >> (0x10 - pWork->dsize_bits); // Shifted by 'sar' instruction + + if(pWork->ctype != CMP_BINARY) + { + if(pWork->ctype != CMP_ASCII) + return CMP_INVALID_MODE; + + memcpy(pWork->ChBitsAsc, ChBitsAsc, sizeof(pWork->ChBitsAsc)); + GenAscTabs(pWork); + } + + memcpy(pWork->LenBits, LenBits, sizeof(pWork->LenBits)); + GenDecodeTabs(pWork->LengthCodes, LenCode, pWork->LenBits, sizeof(pWork->LenBits)); + memcpy(pWork->ExLenBits, ExLenBits, sizeof(pWork->ExLenBits)); + memcpy(pWork->LenBase, LenBase, sizeof(pWork->LenBase)); + memcpy(pWork->DistBits, DistBits, sizeof(pWork->DistBits)); + GenDecodeTabs(pWork->DistPosCodes, DistCode, pWork->DistBits, sizeof(pWork->DistBits)); + if(Expand(pWork) != 0x306) + return CMP_NO_ERROR; + + return CMP_ABORT; +} diff --git a/3rdParty/PKWare/implode.cpp b/3rdParty/PKWare/implode.cpp new file mode 100644 index 000000000..68eb66466 --- /dev/null +++ b/3rdParty/PKWare/implode.cpp @@ -0,0 +1,775 @@ +/*****************************************************************************/ +/* implode.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Implode function of PKWARE Data Compression library */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 11.04.03 1.00 Lad First version of implode.cpp */ +/* 02.05.03 1.00 Lad Stress test done */ +/* 22.04.10 1.01 Lad Documented */ +/*****************************************************************************/ + +#include +#include + +#include "pkware.h" + +#if ((1200 < _MSC_VER) && (_MSC_VER < 1400)) +#pragma optimize("", off) +#endif + +//----------------------------------------------------------------------------- +// Defines + +#define MAX_REP_LENGTH 0x204 // The longest allowed repetition + +static char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n" + "Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n" + "Patent No. 5,051,745\r\n" + "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n" + "Version 1.11\r\n"; + +//----------------------------------------------------------------------------- +// Tables + +static unsigned char DistBits[] = +{ + 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +static unsigned char DistCode[] = +{ + 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A, + 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C, + 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, + 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00 +}; + +static unsigned char ExLenBits[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 +}; + +static unsigned char LenBits[] = +{ + 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07 +}; + +static unsigned char LenCode[] = +{ + 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00 +}; + +static unsigned char ChBitsAsc[] = +{ + 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08, + 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B, + 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06, + 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08, + 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05, + 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, + 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D +}; + +static unsigned short ChCodeAsc[] = +{ + 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0, + 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0, + 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360, + 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60, + 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8, + 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098, + 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C, + 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710, + 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8, + 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E, + 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8, + 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088, + 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A, + 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D, + 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078, + 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0, + 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040, + 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380, + 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180, + 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280, + 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080, + 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300, + 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0, + 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320, + 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220, + 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0, + 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0, + 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340, + 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900, + 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600, + 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200, + 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000 +}; + +//----------------------------------------------------------------------------- +// Macros + +// Macro for calculating hash of the current byte pair. +// Note that most exact byte pair hash would be buffer[0] + buffer[1] << 0x08, +// but even this way gives nice indication of equal byte pairs, with significantly +// smaller size of the array that holds numbers of those hashes +#define BYTE_PAIR_HASH(buffer) ((buffer[0] * 4) + (buffer[1] * 5)) + +//----------------------------------------------------------------------------- +// Local functions + +// Builds the "hash_to_index" table and "pair_hash_offsets" table. +// Every element of "hash_to_index" will contain lowest index to the +// "pair_hash_offsets" table, effectively giving offset of the first +// occurence of the given PAIR_HASH in the input data. +static void SortBuffer(TCmpStruct * pWork, unsigned char * buffer_begin, unsigned char * buffer_end) +{ + unsigned short * phash_to_index; + unsigned char * buffer_ptr; + unsigned short total_sum = 0; + unsigned long byte_pair_hash; // Hash value of the byte pair + unsigned short byte_pair_offs; // Offset of the byte pair, relative to "work_buff" + + // Zero the entire "phash_to_index" table + memset(pWork->phash_to_index, 0, sizeof(pWork->phash_to_index)); + + // Step 1: Count amount of each PAIR_HASH in the input buffer + // The table will look like this: + // offs 0x000: Number of occurences of PAIR_HASH 0 + // offs 0x001: Number of occurences of PAIR_HASH 1 + // ... + // offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 (the highest hash value) + for(buffer_ptr = buffer_begin; buffer_ptr < buffer_end; buffer_ptr++) + pWork->phash_to_index[BYTE_PAIR_HASH(buffer_ptr)]++; + + // Step 2: Convert the table to the array of PAIR_HASH amounts. + // Each element contains count of PAIR_HASHes that is less or equal + // to element index + // The table will look like this: + // offs 0x000: Number of occurences of PAIR_HASH 0 or lower + // offs 0x001: Number of occurences of PAIR_HASH 1 or lower + // ... + // offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 or lower + for(phash_to_index = pWork->phash_to_index; phash_to_index < &pWork->phash_to_index_end; phash_to_index++) + { + total_sum = total_sum + phash_to_index[0]; + phash_to_index[0] = total_sum; + } + + // Step 3: Convert the table to the array of indexes. + // Now, each element contains index to the first occurence of given PAIR_HASH + for(buffer_end--; buffer_end >= buffer_begin; buffer_end--) + { + byte_pair_hash = BYTE_PAIR_HASH(buffer_end); + byte_pair_offs = (unsigned short)(buffer_end - pWork->work_buff); + + pWork->phash_to_index[byte_pair_hash]--; + pWork->phash_offs[pWork->phash_to_index[byte_pair_hash]] = byte_pair_offs; + } +} + +static void FlushBuf(TCmpStruct * pWork) +{ + unsigned char save_ch1; + unsigned char save_ch2; + unsigned int size = 0x800; + + pWork->write_buf(pWork->out_buff, &size, pWork->param); + + save_ch1 = pWork->out_buff[0x800]; + save_ch2 = pWork->out_buff[pWork->out_bytes]; + pWork->out_bytes -= 0x800; + + memset(pWork->out_buff, 0, sizeof(pWork->out_buff)); + + if(pWork->out_bytes != 0) + pWork->out_buff[0] = save_ch1; + if(pWork->out_bits != 0) + pWork->out_buff[pWork->out_bytes] = save_ch2; +} + +static void OutputBits(TCmpStruct * pWork, unsigned int nbits, unsigned long bit_buff) +{ + unsigned int out_bits; + + // If more than 8 bits to output, do recursion + if(nbits > 8) + { + OutputBits(pWork, 8, bit_buff); + bit_buff >>= 8; + nbits -= 8; + } + + // Add bits to the last out byte in out_buff; + out_bits = pWork->out_bits; + pWork->out_buff[pWork->out_bytes] |= (unsigned char)(bit_buff << out_bits); + pWork->out_bits += nbits; + + // If 8 or more bits, increment number of bytes + if(pWork->out_bits > 8) + { + pWork->out_bytes++; + bit_buff >>= (8 - out_bits); + + pWork->out_buff[pWork->out_bytes] = (unsigned char)bit_buff; + pWork->out_bits &= 7; + } + else + { + pWork->out_bits &= 7; + if(pWork->out_bits == 0) + pWork->out_bytes++; + } + + // If there is enough compressed bytes, flush them + if(pWork->out_bytes >= 0x800) + FlushBuf(pWork); +} + +// This function searches for a repetition +// (a previous occurence of the current byte sequence) +// Returns length of the repetition, and stores the backward distance +// to pWork structure. +static unsigned int FindRep(TCmpStruct * pWork, unsigned char * input_data) +{ + unsigned short * phash_to_index; // Pointer into pWork->phash_to_index table + unsigned short * phash_offs; // Pointer to the table containing offsets of each PAIR_HASH + unsigned char * repetition_limit; // An eventual repetition must be at position below this pointer + unsigned char * prev_repetition; // Pointer to the previous occurence of the current PAIR_HASH + unsigned char * prev_rep_end; // End of the previous repetition + unsigned char * input_data_ptr; + unsigned short phash_offs_index; // Index to the table with PAIR_HASH positions + unsigned short min_phash_offs; // The lowest allowed hash offset + unsigned short offs_in_rep; // Offset within found repetition + unsigned int equal_byte_count; // Number of bytes that are equal to the previous occurence + unsigned int rep_length = 1; // Length of the found repetition + unsigned int rep_length2; // Secondary repetition + unsigned char pre_last_byte; // Last but one byte from a repetion + unsigned short di_val; + + // Calculate the previous position of the PAIR_HASH + phash_to_index = pWork->phash_to_index + BYTE_PAIR_HASH(input_data); + min_phash_offs = (unsigned short)((input_data - pWork->work_buff) - pWork->dsize_bytes + 1); + phash_offs_index = phash_to_index[0]; + + // If the PAIR_HASH offset is below the limit, find a next one + phash_offs = pWork->phash_offs + phash_offs_index; + if(*phash_offs < min_phash_offs) + { + while(*phash_offs < min_phash_offs) + { + phash_offs_index++; + phash_offs++; + } + *phash_to_index = phash_offs_index; + } + + // Get the first location of the PAIR_HASH, + // and thus the first eventual location of byte repetition + phash_offs = pWork->phash_offs + phash_offs_index; + prev_repetition = pWork->work_buff + phash_offs[0]; + repetition_limit = input_data - 1; + + // If the current PAIR_HASH was not encountered before, + // we haven't found a repetition. + if(prev_repetition >= repetition_limit) + return 0; + + // We have found a match of a PAIR_HASH. Now we have to make sure + // that it is also a byte match, because PAIR_HASH is not unique. + // We compare the bytes and count the length of the repetition + input_data_ptr = input_data; + for(;;) + { + // If the first byte of the repetition and the so-far-last byte + // of the repetition are equal, we will compare the blocks. + if(*input_data_ptr == *prev_repetition && input_data_ptr[rep_length-1] == prev_repetition[rep_length-1]) + { + // Skip the current byte + prev_repetition++; + input_data_ptr++; + equal_byte_count = 2; + + // Now count how many more bytes are equal + while(equal_byte_count < MAX_REP_LENGTH) + { + prev_repetition++; + input_data_ptr++; + + // Are the bytes different ? + if(*prev_repetition != *input_data_ptr) + break; + + equal_byte_count++; + } + + // If we found a repetition of at least the same length, take it. + // If there are multiple repetitions in the input buffer, this will + // make sure that we find the most recent one, which in turn allows + // us to store backward length in less amount of bits + input_data_ptr = input_data; + if(equal_byte_count >= rep_length) + { + // Calculate the backward distance of the repetition. + // Note that the distance is stored as decremented by 1 + pWork->distance = (unsigned int)(input_data - prev_repetition + equal_byte_count - 1); + + // Repetitions longer than 10 bytes will be stored in more bits, + // so they need a bit different handling + if((rep_length = equal_byte_count) > 10) + break; + } + } + + // Move forward in the table of PAIR_HASH repetitions. + // There might be a more recent occurence of the same repetition. + phash_offs_index++; + phash_offs++; + prev_repetition = pWork->work_buff + phash_offs[0]; + + // If the next repetition is beyond the minimum allowed repetition, we are done. + if(prev_repetition >= repetition_limit) + { + // A repetition must have at least 2 bytes, otherwise it's not worth it + return (rep_length >= 2) ? rep_length : 0; + } + } + + // If the repetition has max length of 0x204 bytes, we can't go any fuhrter + if(equal_byte_count == MAX_REP_LENGTH) + { + pWork->distance--; + return equal_byte_count; + } + + // Check for possibility of a repetition that occurs at more recent position + phash_offs = pWork->phash_offs + phash_offs_index; + if(pWork->work_buff + phash_offs[1] >= repetition_limit) + return rep_length; + + // + // The following part checks if there isn't a longer repetition at + // a latter offset, that would lead to better compression. + // + // Example of data that can trigger this optimization: + // + // "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEQQQQQQQQQQQQ" + // "XYZ" + // "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ"; + // + // Description of data in this buffer + // [0x00] Single byte "E" + // [0x01] Single byte "E" + // [0x02] Repeat 0x1E bytes from [0x00] + // [0x20] Single byte "X" + // [0x21] Single byte "Y" + // [0x22] Single byte "Z" + // [0x23] 17 possible previous repetitions of length at least 0x10 bytes: + // - Repetition of 0x10 bytes from [0x00] "EEEEEEEEEEEEEEEE" + // - Repetition of 0x10 bytes from [0x01] "EEEEEEEEEEEEEEEE" + // - Repetition of 0x10 bytes from [0x02] "EEEEEEEEEEEEEEEE" + // ... + // - Repetition of 0x10 bytes from [0x0F] "EEEEEEEEEEEEEEEE" + // - Repetition of 0x1C bytes from [0x10] "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ" + // The last repetition is the best one. + // + + pWork->offs09BC[0] = 0xFFFF; + pWork->offs09BC[1] = 0x0000; + di_val = 0; + + // Note: I failed to figure out what does the table "offs09BC" mean. + // If anyone has an idea, let me know to zezula_at_volny_dot_cz + for(offs_in_rep = 1; offs_in_rep < rep_length; ) + { + if(input_data[offs_in_rep] != input_data[di_val]) + { + di_val = pWork->offs09BC[di_val]; + if(di_val != 0xFFFF) + continue; + } + pWork->offs09BC[++offs_in_rep] = ++di_val; + } + + // + // Now go through all the repetitions from the first found one + // to the current input data, and check if any of them migh be + // a start of a greater sequence match. + // + + prev_repetition = pWork->work_buff + phash_offs[0]; + prev_rep_end = prev_repetition + rep_length; + rep_length2 = rep_length; + + for(;;) + { + rep_length2 = pWork->offs09BC[rep_length2]; + if(rep_length2 == 0xFFFF) + rep_length2 = 0; + + // Get the pointer to the previous repetition + phash_offs = pWork->phash_offs + phash_offs_index; + + // Skip those repetitions that don't reach the end + // of the first found repetition + do + { + phash_offs++; + phash_offs_index++; + prev_repetition = pWork->work_buff + *phash_offs; + if(prev_repetition >= repetition_limit) + return rep_length; + } + while(prev_repetition + rep_length2 < prev_rep_end); + + // Verify if the last but one byte from the repetition matches + // the last but one byte from the input data. + // If not, find a next repetition + pre_last_byte = input_data[rep_length - 2]; + if(pre_last_byte == prev_repetition[rep_length - 2]) + { + // If the new repetition reaches beyond the end + // of previously found repetition, reset the repetition length to zero. + if(prev_repetition + rep_length2 != prev_rep_end) + { + prev_rep_end = prev_repetition; + rep_length2 = 0; + } + } + else + { + phash_offs = pWork->phash_offs + phash_offs_index; + do + { + phash_offs++; + phash_offs_index++; + prev_repetition = pWork->work_buff + *phash_offs; + if(prev_repetition >= repetition_limit) + return rep_length; + } + while(prev_repetition[rep_length - 2] != pre_last_byte || prev_repetition[0] != input_data[0]); + + // Reset the length of the repetition to 2 bytes only + prev_rep_end = prev_repetition + 2; + rep_length2 = 2; + } + + // Find out how many more characters are equal to the first repetition. + while(*prev_rep_end == input_data[rep_length2]) + { + if(++rep_length2 >= 0x204) + break; + prev_rep_end++; + } + + // Is the newly found repetion at least as long as the previous one ? + if(rep_length2 >= rep_length) + { + // Calculate the distance of the new repetition + pWork->distance = (unsigned int)(input_data - prev_repetition - 1); + if((rep_length = rep_length2) == 0x204) + return rep_length; + + // Update the additional elements in the "offs09BC" table + // to reflect new rep length + while(offs_in_rep < rep_length2) + { + if(input_data[offs_in_rep] != input_data[di_val]) + { + di_val = pWork->offs09BC[di_val]; + if(di_val != 0xFFFF) + continue; + } + pWork->offs09BC[++offs_in_rep] = ++di_val; + } + } + } +} + +static void WriteCmpData(TCmpStruct * pWork) +{ + unsigned char * input_data_end; // Pointer to the end of the input data + unsigned char * input_data = pWork->work_buff + pWork->dsize_bytes + 0x204; + unsigned int input_data_ended = 0; // If 1, then all data from the input stream have been already loaded + unsigned int save_rep_length; // Saved length of current repetition + unsigned int save_distance = 0; // Saved distance of current repetition + unsigned int rep_length; // Length of the found repetition + unsigned int phase = 0; // + + // Store the compression type and dictionary size + pWork->out_buff[0] = (char)pWork->ctype; + pWork->out_buff[1] = (char)pWork->dsize_bits; + pWork->out_bytes = 2; + + // Reset output buffer to zero + memset(&pWork->out_buff[2], 0, sizeof(pWork->out_buff) - 2); + pWork->out_bits = 0; + + while(input_data_ended == 0) + { + unsigned int bytes_to_load = 0x1000; + int total_loaded = 0; + int bytes_loaded; + + // Load the bytes from the input stream, up to 0x1000 bytes + while(bytes_to_load != 0) + { + bytes_loaded = pWork->read_buf((char *)pWork->work_buff + pWork->dsize_bytes + 0x204 + total_loaded, + &bytes_to_load, + pWork->param); + if(bytes_loaded == 0) + { + if(total_loaded == 0 && phase == 0) + goto __Exit; + input_data_ended = 1; + break; + } + else + { + bytes_to_load -= bytes_loaded; + total_loaded += bytes_loaded; + } + } + + input_data_end = pWork->work_buff + pWork->dsize_bytes + total_loaded; + if(input_data_ended) + input_data_end += 0x204; + + // + // Warning: The end of the buffer passed to "SortBuffer" is actually 2 bytes beyond + // valid data. It is questionable if this is actually a bug or not, + // but it might cause the compressed data output to be dependent on random bytes + // that are in the buffer. + // To prevent that, the calling application must always zero the compression + // buffer before passing it to "implode" + // + + // Search the PAIR_HASHes of the loaded blocks. Also, include + // previously compressed data, if any. + switch(phase) + { + case 0: + SortBuffer(pWork, input_data, input_data_end + 1); + phase++; + if(pWork->dsize_bytes != 0x1000) + phase++; + break; + + case 1: + SortBuffer(pWork, input_data - pWork->dsize_bytes + 0x204, input_data_end + 1); + phase++; + break; + + default: + SortBuffer(pWork, input_data - pWork->dsize_bytes, input_data_end + 1); + break; + } + + // Perform the compression of the current block + while(input_data < input_data_end) + { + // Find if the current byte sequence wasn't there before. + rep_length = FindRep(pWork, input_data); + while(rep_length != 0) + { + // If we found repetition of 2 bytes, that is 0x100 or fuhrter back, + // don't bother. Storing the distance of 0x100 bytes would actually + // take more space than storing the 2 bytes as-is. + if(rep_length == 2 && pWork->distance >= 0x100) + break; + + // When we are at the end of the input data, we cannot allow + // the repetition to go past the end of the input data. + if(input_data_ended && input_data + rep_length > input_data_end) + { + // Shorten the repetition length so that it only covers valid data + rep_length = (unsigned long)(input_data_end - input_data); + if(rep_length < 2) + break; + + // If we got repetition of 2 bytes, that is 0x100 or more backward, don't bother + if(rep_length == 2 && pWork->distance >= 0x100) + break; + goto __FlushRepetition; + } + + if(rep_length >= 8 || input_data + 1 >= input_data_end) + goto __FlushRepetition; + + // Try to find better repetition 1 byte later. + // Example: "ARROCKFORT" "AROCKFORT" + // When "input_data" points to the second string, FindRep + // returns the occurence of "AR". But there is longer repetition "ROCKFORT", + // beginning 1 byte after. + save_rep_length = rep_length; + save_distance = pWork->distance; + rep_length = FindRep(pWork, input_data + 1); + + // Only use the new repetition if it's length is greater than the previous one + if(rep_length > save_rep_length) + { + // If the new repetition if only 1 byte better + // and the previous distance is less than 0x80 bytes, use the previous repetition + if(rep_length > save_rep_length + 1 || save_distance > 0x80) + { + // Flush one byte, so that input_data will point to the secondary repetition + OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]); + input_data++; + continue; + } + } + + // Revert to the previous repetition + rep_length = save_rep_length; + pWork->distance = save_distance; + + __FlushRepetition: + + OutputBits(pWork, pWork->nChBits[rep_length + 0xFE], pWork->nChCodes[rep_length + 0xFE]); + if(rep_length == 2) + { + OutputBits(pWork, pWork->dist_bits[pWork->distance >> 2], + pWork->dist_codes[pWork->distance >> 2]); + OutputBits(pWork, 2, pWork->distance & 3); + } + else + { + OutputBits(pWork, pWork->dist_bits[pWork->distance >> pWork->dsize_bits], + pWork->dist_codes[pWork->distance >> pWork->dsize_bits]); + OutputBits(pWork, pWork->dsize_bits, pWork->dsize_mask & pWork->distance); + } + + // Move the begin of the input data by the length of the repetition + input_data += rep_length; + goto _00402252; + } + + // If there was no previous repetition for the current position in the input data, + // just output the 9-bit literal for the one character + OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]); + input_data++; +_00402252:; + } + + if(input_data_ended == 0) + { + input_data -= 0x1000; + memmove(pWork->work_buff, pWork->work_buff + 0x1000, pWork->dsize_bytes + 0x204); + } + } + +__Exit: + + // Write the termination literal + OutputBits(pWork, pWork->nChBits[0x305], pWork->nChCodes[0x305]); + if(pWork->out_bits != 0) + pWork->out_bytes++; + pWork->write_buf(pWork->out_buff, &pWork->out_bytes, pWork->param); + return; +} + +//----------------------------------------------------------------------------- +// Main imploding function + +unsigned int PKEXPORT implode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param, + unsigned int *type, + unsigned int *dsize) +{ + TCmpStruct * pWork = (TCmpStruct *)work_buf; + unsigned int nChCode; + unsigned int nCount; + unsigned int i; + int nCount2; + + // Fill the work buffer information + // Note: The caller must zero the "work_buff" before passing it to implode + pWork->read_buf = read_buf; + pWork->write_buf = write_buf; + pWork->dsize_bytes = *dsize; + pWork->ctype = *type; + pWork->param = param; + pWork->dsize_bits = 4; + pWork->dsize_mask = 0x0F; + + // Test dictionary size + switch(*dsize) + { + case CMP_IMPLODE_DICT_SIZE3: // 0x1000 bytes + pWork->dsize_bits++; + pWork->dsize_mask |= 0x20; + // No break here !!! + + case CMP_IMPLODE_DICT_SIZE2: // 0x800 bytes + pWork->dsize_bits++; + pWork->dsize_mask |= 0x10; + // No break here !!! + + case CMP_IMPLODE_DICT_SIZE1: // 0x400 + break; + + default: + return CMP_INVALID_DICTSIZE; + } + + // Test the compression type + switch(*type) + { + case CMP_BINARY: // We will compress data with binary compression type + for(nChCode = 0, nCount = 0; nCount < 0x100; nCount++) + { + pWork->nChBits[nCount] = 9; + pWork->nChCodes[nCount] = (unsigned short)nChCode; + nChCode = (nChCode & 0x0000FFFF) + 2; + } + break; + + + case CMP_ASCII: // We will compress data with ASCII compression type + for(nCount = 0; nCount < 0x100; nCount++) + { + pWork->nChBits[nCount] = (unsigned char )(ChBitsAsc[nCount] + 1); + pWork->nChCodes[nCount] = (unsigned short)(ChCodeAsc[nCount] * 2); + } + break; + + default: + return CMP_INVALID_MODE; + } + + for(i = 0; i < 0x10; i++) + { + if(1 << ExLenBits[i]) + { + for(nCount2 = 0; nCount2 < (1 << ExLenBits[i]); nCount2++) + { + pWork->nChBits[nCount] = (unsigned char)(ExLenBits[i] + LenBits[i] + 1); + pWork->nChCodes[nCount] = (unsigned short)((nCount2 << (LenBits[i] + 1)) | ((LenCode[i] & 0xFFFF00FF) * 2) | 1); + nCount++; + } + } + } + + // Copy the distance codes and distance bits and perform the compression + memcpy(&pWork->dist_codes, DistCode, sizeof(DistCode)); + memcpy(&pWork->dist_bits, DistBits, sizeof(DistBits)); + WriteCmpData(pWork); + return CMP_NO_ERROR; +} diff --git a/3rdParty/PKWare/pkware.h b/3rdParty/PKWare/pkware.h new file mode 100644 index 000000000..6218044ba --- /dev/null +++ b/3rdParty/PKWare/pkware.h @@ -0,0 +1,142 @@ +/*****************************************************************************/ +/* pkware.h Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Header file for PKWARE Data Compression Library */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 31.03.03 1.00 Lad The first version of pkware.h */ +/*****************************************************************************/ + +#ifndef __PKWARE_H__ +#define __PKWARE_H__ + +//----------------------------------------------------------------------------- +// Defines + +#define CMP_BINARY 0 // Binary compression +#define CMP_ASCII 1 // Ascii compression + +#define CMP_NO_ERROR 0 +#define CMP_INVALID_DICTSIZE 1 +#define CMP_INVALID_MODE 2 +#define CMP_BAD_DATA 3 +#define CMP_ABORT 4 + +#define CMP_IMPLODE_DICT_SIZE1 1024 // Dictionary size of 1024 +#define CMP_IMPLODE_DICT_SIZE2 2048 // Dictionary size of 2048 +#define CMP_IMPLODE_DICT_SIZE3 4096 // Dictionary size of 4096 + +//----------------------------------------------------------------------------- +// Define calling convention + +#ifndef PKEXPORT +#ifdef WIN32 +#define PKEXPORT __cdecl // Use for normal __cdecl calling +#else +#define PKEXPORT +#endif +#endif + +//----------------------------------------------------------------------------- +// Internal structures + +// Compression structure +typedef struct +{ + unsigned int distance; // 0000: Backward distance of the currently found repetition, decreased by 1 + unsigned int out_bytes; // 0004: # bytes available in out_buff + unsigned int out_bits; // 0008: # of bits available in the last out byte + unsigned int dsize_bits; // 000C: Number of bits needed for dictionary size. 4 = 0x400, 5 = 0x800, 6 = 0x1000 + unsigned int dsize_mask; // 0010: Bit mask for dictionary. 0x0F = 0x400, 0x1F = 0x800, 0x3F = 0x1000 + unsigned int ctype; // 0014: Compression type (CMP_ASCII or CMP_BINARY) + unsigned int dsize_bytes; // 0018: Dictionary size in bytes + unsigned char dist_bits[0x40]; // 001C: Distance bits + unsigned char dist_codes[0x40]; // 005C: Distance codes + unsigned char nChBits[0x306]; // 009C: Table of literal bit lengths to be put to the output stream + unsigned short nChCodes[0x306]; // 03A2: Table of literal codes to be put to the output stream + unsigned short offs09AE; // 09AE: + + void * param; // 09B0: User parameter + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // 9B4 + void (*write_buf)(char *buf, unsigned int *size, void *param); // 9B8 + + unsigned short offs09BC[0x204]; // 09BC: + unsigned long offs0DC4; // 0DC4: + unsigned short phash_to_index[0x900]; // 0DC8: Array of indexes (one for each PAIR_HASH) to the "pair_hash_offsets" table + unsigned short phash_to_index_end; // 1FC8: End marker for "phash_to_index" table + char out_buff[0x802]; // 1FCA: Compressed data + unsigned char work_buff[0x2204]; // 27CC: Work buffer + // + DICT_OFFSET => Dictionary + // + UNCMP_OFFSET => Uncompressed data + unsigned short phash_offs[0x2204]; // 49D0: Table of offsets for each PAIR_HASH +} TCmpStruct; + +#define CMP_BUFFER_SIZE sizeof(TCmpStruct) // Size of compression structure. + // Defined as 36312 in pkware header file + + +// Decompression structure +typedef struct +{ + unsigned long offs0000; // 0000 + unsigned long ctype; // 0004: Compression type (CMP_BINARY or CMP_ASCII) + unsigned long outputPos; // 0008: Position in output buffer + unsigned long dsize_bits; // 000C: Dict size (4, 5, 6 for 0x400, 0x800, 0x1000) + unsigned long dsize_mask; // 0010: Dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000) + unsigned long bit_buff; // 0014: 16-bit buffer for processing input data + unsigned long extra_bits; // 0018: Number of extra (above 8) bits in bit buffer + unsigned int in_pos; // 001C: Position in in_buff + unsigned long in_bytes; // 0020: Number of bytes in input buffer + void * param; // 0024: Custom parameter + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // Pointer to function that reads data from the input stream + void (*write_buf)(char *buf, unsigned int *size, void *param);// Pointer to function that writes data to the output stream + + unsigned char out_buff[0x2204]; // 0030: Output circle buffer. + // 0x0000 - 0x0FFF: Previous uncompressed data, kept for repetitions + // 0x1000 - 0x1FFF: Currently decompressed data + // 0x2000 - 0x2203: Reserve space for the longest possible repetition + unsigned char in_buff[0x800]; // 2234: Buffer for data to be decompressed + unsigned char DistPosCodes[0x100]; // 2A34: Table of distance position codes + unsigned char LengthCodes[0x100]; // 2B34: Table of length codes + unsigned char offs2C34[0x100]; // 2C34: Buffer for + unsigned char offs2D34[0x100]; // 2D34: Buffer for + unsigned char offs2E34[0x80]; // 2EB4: Buffer for + unsigned char offs2EB4[0x100]; // 2EB4: Buffer for + unsigned char ChBitsAsc[0x100]; // 2FB4: Buffer for + unsigned char DistBits[0x40]; // 30B4: Numbers of bytes to skip copied block length + unsigned char LenBits[0x10]; // 30F4: Numbers of bits for skip copied block length + unsigned char ExLenBits[0x10]; // 3104: Number of valid bits for copied block + unsigned short LenBase[0x10]; // 3114: Buffer for +} TDcmpStruct; + +#define EXP_BUFFER_SIZE sizeof(TDcmpStruct) // Size of decompression structure + // Defined as 12596 in pkware headers + +//----------------------------------------------------------------------------- +// Public functions + +#ifdef __cplusplus + extern "C" { +#endif + +unsigned int PKEXPORT implode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param, + unsigned int *type, + unsigned int *dsize); + + +unsigned int PKEXPORT explode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param); + +#ifdef __cplusplus + } // End of 'extern "C"' declaration +#endif + +#endif // __PKWARE_H__ diff --git a/3rdParty/Storm/Source/Storm.dsp b/3rdParty/Storm/Source/Storm.dsp new file mode 100644 index 000000000..1e7bb6d83 --- /dev/null +++ b/3rdParty/Storm/Source/Storm.dsp @@ -0,0 +1,93 @@ +# Microsoft Developer Studio Project File - Name="Storm" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=Storm - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Storm.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Storm.mak" CFG="Storm - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Storm - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Storm - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Storm - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /def:"storm.def" + +!ELSEIF "$(CFG)" == "Storm - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /O1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:"storm.def" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Storm - Win32 Release" +# Name "Storm - Win32 Debug" +# Begin Source File + +SOURCE=.\storm.cpp +# End Source File +# End Target +# End Project diff --git a/3rdParty/Storm/Source/Storm.vcxproj b/3rdParty/Storm/Source/Storm.vcxproj new file mode 100644 index 000000000..51be2f53c --- /dev/null +++ b/3rdParty/Storm/Source/Storm.vcxproj @@ -0,0 +1,146 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + {B28F69CE-15A1-424D-BBB5-2727258D675B} + + + + DynamicLibrary + v141 + false + + + DynamicLibrary + v141 + false + + + + + + + + + + + + + + + .\WinRel\ + .\WinRel\ + false + + + .\WinDebug\ + .\WinDebug\ + true + + + + MultiThreaded + Default + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\WinRel\ + .\WinRel\Storm.pch + .\WinRel\ + .\WinRel\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\WinRel\Storm.tlb + true + NUL + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\WinRel\Storm.bsc + + + true + true + Windows + storm.def + .\WinRel\Storm.dll + .\WinRel\Storm.lib + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreadedDebug + Default + Disabled + true + Level3 + true + EditAndContinue + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\WinDebug\ + .\WinDebug\Storm.pch + .\WinDebug\ + .\WinDebug\ + + + true + _DEBUG;%(PreprocessorDefinitions) + .\WinDebug\Storm.tlb + true + NUL + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\WinDebug\Storm.bsc + + + true + true + true + Windows + storm.def + .\WinDebug\Storm.dll + .\WinDebug\Storm.lib + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/3rdParty/Storm/Source/storm.cpp b/3rdParty/Storm/Source/storm.cpp new file mode 100644 index 000000000..2802af22a --- /dev/null +++ b/3rdParty/Storm/Source/storm.cpp @@ -0,0 +1,238 @@ +#include "storm.h" + +#define rBool { return TRUE; } +#define rPVoid { return NULL; } +#define rVoid { return; } +#define rInt { return 0; } + +BOOL STORMAPI SNetCreateGame(const char *pszGameName, const char *pszGamePassword, const char *pszGameStatString, DWORD dwGameType, char *GameTemplateData, int GameTemplateSize, int playerCount, char *creatorName, char *a11, int *playerID) rBool; +BOOL STORMAPI SNetDestroy() rBool; +BOOL STORMAPI SNetEnumProviders(int (STORMAPI *callback)(DWORD, DWORD, DWORD, DWORD), int mincaps) rBool; + +BOOL STORMAPI SNetEnumGames(int (STORMAPI *callback)(DWORD, DWORD, DWORD), int *hintnextcall) rBool; +BOOL STORMAPI SNetDropPlayer(int playerid, DWORD flags) rBool; +BOOL STORMAPI SNetGetGameInfo(int type, void *dst, size_t length, size_t *byteswritten) rBool; + +BOOL STORMAPI SNetGetNumPlayers(int *firstplayerid, int *lastplayerid, int *activeplayers) rBool; + +BOOL STORMAPI SNetGetPlayerCaps(char playerid, PCAPS playerCaps) rBool; +BOOL STORMAPI SNetGetPlayerName(int playerid, char *buffer, size_t buffersize) rBool; +//BOOL STORMAPI SNetGetProviderCaps(PCAPS providerCaps) rBool; +BOOL STORMAPI SNetGetTurnsInTransit(int *turns) rBool; +BOOL STORMAPI SNetInitializeDevice(int a1, int a2, int a3, int a4, int *a5) rBool; +//BOOL STORMAPI SNetInitializeProvider(DWORD providerName, client_info *gameClientInfo, user_info *userData, battle_info *bnCallbacks, module_info *moduleData) rBool; +BOOL STORMAPI SNetJoinGame(int id, char *gameName, char *gamePassword, char *playerName, char *userStats, int *playerid) rBool; +BOOL STORMAPI SNetLeaveGame(int type) rBool; +BOOL STORMAPI SNetPerformUpgrade(DWORD *upgradestatus) rBool; +BOOL STORMAPI SNetReceiveMessage(int *senderplayerid, char **data, int *databytes) rBool; +BOOL STORMAPI SNetReceiveTurns(int a1, int arraysize, char **arraydata, unsigned int *arraydatabytes, DWORD *arrayplayerstatus) rBool; +//HANDLE STORMAPI SNetRegisterEventHandler(int type, void (STORMAPI *sEvent)(PS_EVT)) rPVoid; + +int STORMAPI SNetSelectGame(int a1, int a2, int a3, int a4, int a5, int *playerid) rInt; + +BOOL STORMAPI SNetSendMessage(int playerID, void *data, size_t databytes) rBool; +BOOL STORMAPI SNetSendTurn(char *data, size_t databytes) rBool; + +BOOL STORMAPI SNetSetGameMode(DWORD modeFlags, bool makePublic) rBool; + +BOOL STORMAPI SNetEnumGamesEx(int a1, int a2, int (__fastcall *callback)(DWORD, DWORD, DWORD), int *hintnextcall) rBool; +BOOL STORMAPI SNetSendServerChatCommand(const char *command) rBool; + +BOOL STORMAPI SNetDisconnectAll(DWORD flags) rBool; +BOOL STORMAPI SNetCreateLadderGame(const char *pszGameName, const char *pszGamePassword, const char *pszGameStatString, DWORD dwGameType, DWORD dwGameLadderType, DWORD dwGameModeFlags, char *GameTemplateData, int GameTemplateSize, int playerCount, char *creatorName, char *a11, int *playerID) rBool; +BOOL STORMAPI SNetReportGameResult(unsigned a1, int size, int *results, const char* headerInfo, const char* detailInfo) rBool; + +int STORMAPI SNetSendLeagueCommand(char *cmd, char *callback) rInt; +int STORMAPI SNetSendReplayPath(int a1, int a2, char *replayPath) rInt; +int STORMAPI SNetGetLeagueName(int leagueID) rInt; +BOOL STORMAPI SNetGetPlayerNames(char **names) rBool; +int STORMAPI SNetLeagueLogout(char *bnetName) rInt; +int STORMAPI SNetGetLeaguePlayerName(char *curPlayerLeageName, size_t nameSize) rInt; + +HGDIOBJ STORMAPI SDlgDefDialogProc(HWND hDlg, signed int DlgType, HDC textLabel, HWND hWnd) rPVoid; + +HANDLE STORMAPI SDlgDialogBoxIndirectParam(HMODULE hModule, LPCSTR lpName, HWND hWndParent, LPVOID lpParam, LPARAM lParam) rPVoid; + +BOOL STORMAPI SDlgEndDialog(HWND hDlg, HANDLE nResult) rBool; + +BOOL STORMAPI SDlgSetControlBitmaps(HWND parentwindow, int *id, int a3, char *buffer2, char *buffer, int flags, int mask) rBool; + +BOOL STORMAPI SDlgBltToWindowE(HWND hWnd, HRGN a2, char *a3, int a4, void *buffer, RECT *rct, SIZE *size, int a8, int a9, DWORD rop) rBool; +BOOL STORMAPI SDlgSetBitmapE(HWND hWnd, int a2, char *src, int mask1, int flags, int a6, int a7, int width, int a9, int mask2) rBool; + +int STORMAPI Ordinal224(int a1) rInt; + +BOOL STORMAPI SFileCloseArchive(HANDLE hArchive) rBool; +BOOL STORMAPI SFileCloseFile(HANDLE hFile) rBool; + +BOOL STORMAPI SFileDdaBeginEx(HANDLE directsound, DWORD flags, DWORD mask, unsigned __int32 lDistanceToMove, signed __int32 volume, signed int a6, int a7) rBool; +BOOL STORMAPI SFileDdaDestroy() rBool; +BOOL STORMAPI SFileDdaEnd(HANDLE directsound) rBool; +BOOL STORMAPI SFileDdaGetPos(HANDLE directsound, int a2, int a3) rBool; + +BOOL STORMAPI SFileDdaInitialize(HANDLE directsound) rBool; +BOOL STORMAPI SFileDdaSetVolume(HANDLE directsound, signed int bigvolume, signed int volume) rBool; +BOOL STORMAPI SFileDestroy() rBool; + +BOOL STORMAPI SFileGetFileArchive(HANDLE hFile, HANDLE archive) rBool; +LONG STORMAPI SFileGetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) rInt; +BOOL STORMAPI SFileOpenArchive(const char *szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE *phMpq) rBool; +BOOL STORMAPI SFileOpenFile(const char *filename, HANDLE *phFile) rBool; +BOOL STORMAPI SFileOpenFileEx(HANDLE hMpq, const char *szFileName, DWORD dwSearchScope, HANDLE *phFile) rBool; +BOOL STORMAPI SFileReadFile(HANDLE hFile, void *buffer, DWORD nNumberOfBytesToRead, DWORD *read, LONG lpDistanceToMoveHigh) rBool; + +void STORMAPI SFileSetLocale(LCID lcLocale) rVoid; + +BOOL STORMAPI SFileSetIoErrorMode(int mode, BOOL (STORMAPI *callback)(char*,int,int) ) rBool; +BOOL STORMAPI SFileGetArchiveName(HANDLE hArchive, char *name, int length) rBool; +BOOL STORMAPI SFileGetFileName(HANDLE hFile, char *buffer, int length) rBool; + +BOOL STORMAPI SFileLoadFile(char *filename, void *buffer, int buffersize, int a4, int a5) rBool; +BOOL STORMAPI SFileUnloadFile(HANDLE hFile) rBool; +BOOL STORMAPI SFileLoadFileEx(void *hArchive, char *filename, int a3, int a4, int a5, DWORD searchScope, struct _OVERLAPPED *lpOverlapped) rBool; + +BOOL STORMAPI SBltROP3(void *lpDstBuffer, void *lpSrcBuffer, int width, int height, int a5, int a6, int a7, DWORD rop) rBool; +BOOL STORMAPI SBltROP3Clipped(void *lpDstBuffer, RECT *lpDstRect, POINT *lpDstPt, int a4, void *lpSrcBuffer, RECT *lpSrcRect, POINT *lpSrcPt, int a8, int a9, DWORD rop) rBool; + +BOOL STORMAPI SBmpDecodeImage(DWORD dwImgType, void *pSrcBuffer, DWORD dwSrcBuffersize, PALETTEENTRY *pPalette, void *pDstBuffer, DWORD dwDstBuffersize, DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwBpp) rBool; + +BOOL STORMAPI SBmpLoadImage(const char *pszFileName, PALETTEENTRY *pPalette, void *pBuffer, DWORD dwBuffersize, DWORD *pdwWidth, DWORD *dwHeight, DWORD *pdwBpp) rBool; + +BOOL STORMAPI SBmpSaveImage(const char*, PALETTEENTRY*, void*, DWORD, DWORD, DWORD) rBool; +HANDLE STORMAPI SBmpAllocLoadImage(const char *fileName, PALETTEENTRY *palette, void **buffer, int *width, int *height, int unused6, int unused7, void *(STORMAPI *allocFunction)(DWORD)) rPVoid; + +BOOL STORMAPI SCodeCompile(char *directives1, char *directives2, char *loopstring, unsigned int maxiterations, unsigned int flags, HANDLE handle) rBool; +BOOL STORMAPI SCodeDelete(HANDLE handle) rBool; + +int STORMAPI SCodeExecute(HANDLE handle, int a2) rInt; + +BOOL STORMAPI SDrawAutoInitialize(HINSTANCE hInst, LPCSTR lpClassName, LPCSTR lpWindowName, WNDPROC pfnWndProc, int nMode, int nWidth, int nHeight, int nBits) rBool; +BOOL STORMAPI SDrawCaptureScreen(const char *source) rBool; + +HWND STORMAPI SDrawGetFrameWindow(HWND *sdraw_framewindow) rPVoid; +BOOL STORMAPI SDrawGetObjects(LPDIRECTDRAW *ddInterface, LPDIRECTDRAWSURFACE *primarySurface, LPDIRECTDRAWSURFACE *surface2, LPDIRECTDRAWSURFACE *surface3, LPDIRECTDRAWSURFACE *backSurface, LPDIRECTDRAWPALETTE *ddPalette, HPALETTE *hPalette) rBool; +BOOL STORMAPI SDrawGetScreenSize(DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwBpp) rBool; + +BOOL STORMAPI SDrawLockSurface(int surfacenumber, RECT *lpDestRect, void **lplpSurface, int *lpPitch, int arg_unused) rBool; +BOOL STORMAPI SDrawManualInitialize(HWND hWnd, LPDIRECTDRAW ddInterface, LPDIRECTDRAWSURFACE primarySurface, LPDIRECTDRAWSURFACE surface2, LPDIRECTDRAWSURFACE surface3, LPDIRECTDRAWSURFACE backSurface, LPDIRECTDRAWPALETTE ddPalette, HPALETTE hPalette) rBool; + +BOOL STORMAPI SDrawPostClose() rBool; +//BOOL STORMAPI SDrawRealizePalette() rBool; + +BOOL STORMAPI SDrawUnlockSurface(int surfacenumber, void *lpSurface, int a3, RECT *lpRect) rBool; +BOOL STORMAPI SDrawUpdatePalette(unsigned int firstentry, unsigned int numentries, PALETTEENTRY *pPalEntries, int a4) rBool; + +BOOL STORMAPI SEvtDispatch(DWORD dwMessageID, DWORD dwFlags, int type, PS_EVT pEvent) rBool; + +BOOL STORMAPI SGdiDeleteObject(HANDLE handle) rBool; + +BOOL STORMAPI SGdiExtTextOut(int a1, int a2, int a3, int a4, unsigned int a8, signed int a6, signed int a7, const char *string, unsigned int arg20) rBool; +BOOL STORMAPI SGdiImportFont(HGDIOBJ handle, int windowsfont) rBool; + +BOOL STORMAPI SGdiSelectObject(int handle) rBool; +BOOL STORMAPI SGdiSetPitch(int pitch) rBool; + +BOOL STORMAPI Ordinal393(char *string, int, int) rBool; + +void* STORMAPI SMemAlloc(size_t amount, char *logfilename, int logline, char defaultValue) rPVoid; + +BOOL STORMAPI SMemFree(void *location, char *logfilename, int logline, char defaultValue) rBool; + +void* STORMAPI SMemReAlloc(void *location, size_t amount, char *logfilename, int logline, char defaultValue) rPVoid; + +BOOL STORMAPI SRegLoadData(const char *keyname, const char *valuename, int size, LPBYTE lpData, BYTE flags, LPDWORD lpcbData) rBool; +BOOL STORMAPI SRegLoadString(const char *keyname, const char *valuename, BYTE flags, char *buffer, size_t buffersize) rBool; +BOOL STORMAPI SRegLoadValue(const char *keyname, const char *valuename, BYTE flags, int *value) rBool; +BOOL STORMAPI SRegSaveData(const char *keyname, const char *valuename, int size, BYTE *lpData, DWORD cbData) rBool; +BOOL STORMAPI SRegSaveString(const char *keyname, const char *valuename, BYTE flags, char *string) rBool; +BOOL STORMAPI SRegSaveValue(const char *keyname, const char *valuename, BYTE flags, DWORD result) rBool; + +BOOL STORMAPI SRegDeleteValue(const char *keyname, const char *valuename, BYTE flags) rBool; + +BOOL STORMAPI STransBlt(void *lpSurface, int x, int y, int width, HANDLE hTrans) rBool; +BOOL STORMAPI STransBltUsingMask(void *lpSurface, void *lpSource, int pitch, int width, HANDLE hTrans) rBool; + +BOOL STORMAPI STransDelete(HANDLE hTrans) rBool; + +BOOL STORMAPI STransDuplicate(HANDLE hTransSource, HANDLE hTransDest) rBool; +BOOL STORMAPI STransIntersectDirtyArray(HANDLE hTrans, char * dirtyarraymask, unsigned flags, HANDLE * phTransResult) rBool; +BOOL STORMAPI STransInvertMask(HANDLE hTrans, HANDLE * phTransResult) rBool; + +BOOL STORMAPI STransSetDirtyArrayInfo(int width, int height, int depth, int bits) rBool; + +BOOL STORMAPI STransPointInMask(HANDLE hTrans, int x, int y) rBool; +BOOL STORMAPI STransCombineMasks(HANDLE hTransA, HANDLE hTransB, int left, int top, int flags, HANDLE * phTransResult) rBool; + +BOOL STORMAPI STransCreateE(void *pBuffer, int width, int height, int bpp, int a5, int bufferSize, HANDLE *phTransOut) rBool; + +BOOL STORMAPI SVidDestroy() rBool; +BOOL STORMAPI SVidGetSize(HANDLE video, int width, int height, int zero) rBool; +BOOL STORMAPI SVidInitialize(HANDLE video) rBool; +BOOL STORMAPI SVidPlayBegin(char *filename, int arg4, int a3, int a4, int a5, int a6, HANDLE* video) rBool; + +BOOL STORMAPI SVidPlayContinueSingle(HANDLE video, int a2, int a3) rBool; +BOOL STORMAPI SVidPlayEnd(HANDLE video) rBool; + +BOOL STORMAPI SErrDisplayError(DWORD dwErrMsg, const char *logfilename, int logline, const char *message, BOOL allowOption, int exitCode) rBool; +BOOL STORMAPI SErrGetErrorStr(DWORD dwErrCode, char *buffer, size_t bufferchars) rBool; +DWORD STORMAPI SErrGetLastError() rInt; + +void STORMAPI SErrSetLastError(DWORD dwErrCode) rVoid; + +void STORMAPI SErrSuppressErrors(BOOL suppressErrors) rVoid; + +void STORMAPI SMemCopy(void *dest, const void *source, size_t size) rVoid; +void STORMAPI SMemFill(void *location, size_t length, char fillWith) rVoid; + +void STORMAPI SMemZero(void *location, DWORD length) rVoid; +int STORMAPI SMemCmp(void *location1, void *location2, DWORD size) rInt; + +int STORMAPI SStrCopy(char *dest, const char *src, int max_length) rInt; +DWORD STORMAPI SStrHash(const char *string, DWORD flags, DWORD Seed) rInt; +int STORMAPI SStrNCat(char *dest, const char *src, DWORD max_length) rInt; + +int STORMAPI SStrLen(const char* string) rInt; + +int STORMAPI SStrCmp(const char *string1, const char *string2, size_t size) rInt; +int STORMAPI SStrCmpI(const char *string1, const char *string2, size_t size) rInt; +char* STORMAPI SStrUpper(char* string) rPVoid; + +void STORMAPI SRgn523(HANDLE hRgn, RECT *pRect, int a3, int a4) rVoid; +void STORMAPI SRgnCreateRegion(HANDLE *hRgn, int a2) rVoid; +void STORMAPI SRgnDeleteRegion(HANDLE hRgn) rVoid; + +void STORMAPI SRgn529i(int handle, int a2, int a3) rVoid; + +BOOL SErrDisplayErrorFmt(DWORD dwErrMsg, const char *logfilename, int logline, BOOL allowOption, int exitCode, const char *format, ...) rBool; + +void STORMAPI SErrCatchUnhandledExceptions() rVoid; + +char* STORMAPI SStrChr(const char *string, char c) rPVoid; +char* STORMAPI SStrChrR(const char *string, char c) rPVoid; + +size_t SStrVPrintf(char *dest, size_t size, const char *format, ...) rInt; + +int STORMAPI SBigDel(void *buffer) rInt; + +int STORMAPI SBigFromBinary(void *buffer, const void *str, size_t size) rInt; + +int STORMAPI SBigNew(void **buffer) rInt; + +int STORMAPI SBigPowMod(void *buffer1, void *buffer2, int a3, int a4) rInt; + +int STORMAPI SBigToBinaryBuffer(void *buffer, int length, int a3, int a4) rInt; +// + +void __stdcall SDrawMessageBox(char *,char *,int) rVoid; +void __cdecl SDrawDestroy(void) rVoid; +bool __cdecl StormDestroy(void) rBool; +bool __stdcall SFileSetBasePath(char *) rBool; +void __cdecl SDrawRealizePalette(void) rVoid; +bool __cdecl SVidPlayContinue(void) rBool; +bool __stdcall SNetGetOwnerTurnsWaiting(int *) rBool; +void * __stdcall SNetUnregisterEventHandler(int,void (__stdcall*)(struct _SNETEVENT *)) rPVoid; +void * __stdcall SNetRegisterEventHandler(int,void (__stdcall*)(struct _SNETEVENT *)) rPVoid; +bool __stdcall SNetSetBasePlayer(int) rBool; +int __stdcall SNetInitializeProvider(unsigned long,struct _SNETPROGRAMDATA *,struct _SNETPLAYERDATA *,struct _SNETUIDATA *,struct _SNETVERSIONDATA *) rInt; +int __stdcall SNetGetProviderCaps(struct _SNETCAPS *) rInt; +int __stdcall SFileSetFilePointer(HANDLE,int,HANDLE,int) rInt; diff --git a/3rdParty/Storm/Source/storm.def b/3rdParty/Storm/Source/storm.def new file mode 100644 index 000000000..fde2f7b9a --- /dev/null +++ b/3rdParty/Storm/Source/storm.def @@ -0,0 +1,441 @@ +LIBRARY "Storm" + +EXPORTS + SNetCreateGame @101 NONAME + SNetDestroy @102 NONAME + SNetEnumProviders @103 NONAME + ;SNetEnumDevices @104 NONAME + SNetEnumGames @105 NONAME + SNetDropPlayer @106 NONAME + SNetGetGameInfo @107 NONAME + ;SNetGetNetworkLatency @108 NONAME + SNetGetNumPlayers @109 NONAME + SNetGetOwnerTurnsWaiting @110 NONAME + ;SNetGetPerformanceData @111 NONAME + SNetGetPlayerCaps @112 NONAME + SNetGetPlayerName @113 NONAME + SNetGetProviderCaps @114 NONAME + SNetGetTurnsInTransit @115 NONAME + SNetInitializeDevice @116 NONAME + SNetInitializeProvider @117 NONAME + SNetJoinGame @118 NONAME + SNetLeaveGame @119 NONAME + SNetPerformUpgrade @120 NONAME + SNetReceiveMessage @121 NONAME + SNetReceiveTurns @122 NONAME + SNetRegisterEventHandler @123 NONAME + ;SNetResetLatencyMeasurements @124 NONAME + SNetSelectGame @125 NONAME + ;SNetSelectProvider @126 NONAME + SNetSendMessage @127 NONAME + SNetSendTurn @128 NONAME + SNetSetBasePlayer @129 NONAME + SNetSetGameMode @130 NONAME + SNetUnregisterEventHandler @131 NONAME + + SNetEnumGamesEx @133 NONAME + SNetSendServerChatCommand @134 NONAME + ;SNetSendDatagram @135 NONAME + ;SNetReceiveDatagram @136 NONAME + SNetDisconnectAll @137 NONAME + SNetCreateLadderGame @138 NONAME + SNetReportGameResult @139 NONAME + ;SNetCheckDataFile @140 NONAME + SNetSendLeagueCommand @141 NONAME + SNetSendReplayPath @142 NONAME + SNetGetLeagueName @143 NONAME + SNetGetPlayerNames @144 NONAME + SNetLeagueLogout @145 NONAME + SNetGetLeaguePlayerName @146 NONAME + + ;Ordinal150 @150 NONAME + ;Ordinal151 @151 NONAME + + ;SDlgBeginPaint @201 NONAME + ;SDlgBltToWindowI @202 NONAME + ;SDlgCheckTimers @203 NONAME + ;SDlgCreateDialogIndirectParam @204 NONAME + ;SDlgCreateDialogParam @205 NONAME + SDlgDefDialogProc @206 NONAME + + SDlgDialogBoxIndirectParam @208 NONAME + ;SDlgDialogBoxParam @209 NONAME + ;SDlgDrawBitmap @210 NONAME + SDlgEndDialog @211 NONAME + ;SDlgEndPaint @212 NONAME + ;SDlgKillTimer @213 NONAME + ;SDlgSetBaseFont @214 NONAME + ;SDlgSetBitmapI @215 NONAME + SDlgSetControlBitmaps @216 NONAME + ;SDlgSetCursor @217 NONAME + ;SDlgSetSystemCursor @218 NONAME + ;SDlgSetTimer @219 NONAME + ;SDlgUpdateCursor @220 NONAME + SDlgBltToWindowE @221 NONAME + SDlgSetBitmapE @222 NONAME + ;SDlgSetLocale @223 NONAME + Ordinal224 @224 NONAME + + ;SFileAuthenticateArchive @251 NONAME + SFileCloseArchive @252 NONAME + SFileCloseFile @253 NONAME + ;SFileDdaBegin @254 NONAME + SFileDdaBeginEx @255 NONAME + SFileDdaDestroy @256 NONAME + SFileDdaEnd @257 NONAME + SFileDdaGetPos @258 NONAME + ;SFileDdaGetVolume @259 NONAME + SFileDdaInitialize @260 NONAME + SFileDdaSetVolume @261 NONAME + SFileDestroy @262 NONAME + ;SFileEnableDirectAccess @263 NONAME + SFileGetFileArchive @264 NONAME + SFileGetFileSize @265 NONAME + SFileOpenArchive @266 NONAME + SFileOpenFile @267 NONAME + SFileOpenFileEx @268 NONAME + SFileReadFile @269 NONAME + SFileSetBasePath @270 NONAME + SFileSetFilePointer @271 NONAME + SFileSetLocale @272 NONAME + ;SFileGetBasePath @273 NONAME + SFileSetIoErrorMode @274 NONAME + SFileGetArchiveName @275 NONAME + SFileGetFileName @276 NONAME + ;SFileGetArchiveInfo @277 NONAME + ;SFileSetPlatform @278 NONAME + SFileLoadFile @279 NONAME + SFileUnloadFile @280 NONAME + SFileLoadFileEx @281 NONAME + ;SFilePrioritizeRequest @282 NONAME + ;SFileCancelRequest @283 NONAME + ;SFileSetAsyncBudget @284 NONAME + ;SFileSetDataChunkSize @285 NONAME + ;SFileEnableSeekOptimization @286 NONAME + ;SFileReadFileEx @287 NONAME + ;SFileFileExists @288 NONAME + ;SFileFileExistsEx @289 NONAME + ;SFileReadFileEx2 @290 NONAME + ;SFileReadFile2 @291 NONAME + ;SFileLoadFile2 @292 NONAME + ;SFileOpenFileAsArchive @293 NONAME + ;SFileGetLocale @294 NONAME + ;SFileRegisterLoadNotifyProc @295 NONAME + ;SFileGetFileCompressedSize @296 NONAME + ;Ordinal297 @297 NONAME + ;Ordinal298 @298 NONAME + ;SFileAuthenticateArchiveEx @299 NONAME + ;SFileOpenPathAsArchive @300 NONAME + StormDestroy @301 NONAME + ;StormGetInstance @302 NONAME + ;StormGetOption @303 NONAME + ;StormSetOption @304 NONAME + + ;SBltGetSCode @312 NONAME + SBltROP3 @313 NONAME + SBltROP3Clipped @314 NONAME + ;SBltROP3Tiled @315 NONAME + + SBmpDecodeImage @321 NONAME + + SBmpLoadImage @323 NONAME + SBmpSaveImage @324 NONAME + SBmpAllocLoadImage @325 NONAME + ;SBmpSaveImageEx @326 NONAME + + SCodeCompile @331 NONAME + SCodeDelete @332 NONAME + + SCodeExecute @334 NONAME + ;SCodeGetPseudocode @335 NONAME + + SDrawAutoInitialize @341 NONAME + SDrawCaptureScreen @342 NONAME + ;SDrawClearSurface @343 NONAME + SDrawDestroy @344 NONAME + ;SDrawFlipPage @345 NONAME + SDrawGetFrameWindow @346 NONAME + SDrawGetObjects @347 NONAME + SDrawGetScreenSize @348 NONAME + ;SDrawGetServiceLevel @349 NONAME + SDrawLockSurface @350 NONAME + SDrawManualInitialize @351 NONAME + SDrawMessageBox @352 NONAME + SDrawPostClose @353 NONAME + SDrawRealizePalette @354 NONAME + ;SDrawSelectGdiSurface @355 NONAME + SDrawUnlockSurface @356 NONAME + SDrawUpdatePalette @357 NONAME + ;SDrawUpdateScreen @358 NONAME + ;SDrawWaitForVerticalBlank @359 NONAME + + SEvtDispatch @372 NONAME + ;SEvtRegisterHandler @373 NONAME + ;SEvtUnregisterHandler @374 NONAME + ;SEvtUnregisterType @375 NONAME + ;SEvtPopState @376 NONAME + ;SEvtPushState @377 NONAME + ;SEvtBreakHandlerChain @378 NONAME + + ;SGdiBitBlt @381 NONAME + ;SGdiCreateFont @382 NONAME + SGdiDeleteObject @383 NONAME + ;SGdiDestroy @384 NONAME + SGdiExtTextOut @385 NONAME + SGdiImportFont @386 NONAME + ;SGdiLoadFont @387 NONAME + ;SGdiRectangle @388 NONAME + SGdiSelectObject @389 NONAME + SGdiSetPitch @390 NONAME + ;SGdiTextOut @391 NONAME + ;SGdi392 @392 NONAME + Ordinal393 @393 NONAME + + ;SMem399 @399 NONAME + + SMemAlloc @401 NONAME + ;SMemDestroy @402 NONAME + SMemFree @403 NONAME + ;SMemGetSize @404 NONAME + SMemReAlloc @405 NONAME + ;Storm406 @406 NONAME + + ;SMsgDispatchMessage @412 NONAME + ;SMsgDoMessageLoop @413 NONAME + ;SMsgRegisterCommand @414 NONAME + ;SMsgRegisterKeyDown @415 NONAME + ;SMsgRegisterKeyUp @416 NONAME + ;SMsgRegisterMessage @417 NONAME + ;SMsgPopRegisterState @418 NONAME + ;SMsgPushRegisterState @419 NONAME + ;SMsg420 @420 NONAME + SRegLoadData @421 NONAME + SRegLoadString @422 NONAME + SRegLoadValue @423 NONAME + SRegSaveData @424 NONAME + SRegSaveString @425 NONAME + SRegSaveValue @426 NONAME + ;SRegGetBaseKey @427 NONAME + SRegDeleteValue @428 NONAME + ;SReg429 @429 NONAME + ;SReg430 @430 NONAME + STransBlt @431 NONAME + STransBltUsingMask @432 NONAME + ;STransCreateI @433 NONAME + STransDelete @434 NONAME + + STransDuplicate @436 NONAME + STransIntersectDirtyArray @437 NONAME + STransInvertMask @438 NONAME + ;STransLoadI @439 NONAME + STransSetDirtyArrayInfo @440 NONAME + ;STransUpdateDirtyArray @441 NONAME + STransPointInMask @442 NONAME + STransCombineMasks @443 NONAME + ;STransCreateI @444 NONAME + STransCreateE @445 NONAME + ;STrans446 @446 NONAME + ;STransLoadE @447 NONAME + + SVidDestroy @451 NONAME + SVidGetSize @452 NONAME + SVidInitialize @453 NONAME + SVidPlayBegin @454 NONAME + ;SVidPlayBeginFromMemory @455 NONAME + SVidPlayContinue @456 NONAME + SVidPlayContinueSingle @457 NONAME + SVidPlayEnd @458 NONAME + ;SVidSetVolume @459 NONAME + ;Storm460 @460 NONAME + SErrDisplayError @461 NONAME + SErrGetErrorStr @462 NONAME + SErrGetLastError @463 NONAME + ;SErrRegisterMessageSource @464 NONAME + SErrSetLastError @465 NONAME + ;SErrReportNamedResourceLeak @466 NONAME + ;SErrReportResourceLeak @467 NONAME + SErrSuppressErrors @468 NONAME + ;SErrRegisterHandler @469 NONAME + ;SErrUnregisterHandler @470 NONAME + ;Storm471 @471 NONAME + ;SCmdGetBool @472 NONAME + ;SCmdGetNum @473 NONAME + ;SCmdGetString @474 NONAME + ;SCmdProcess @475 NONAME + ;SCmdRegisterArgList @476 NONAME + ;SCmdRegisterArgument @477 NONAME + ;SCmdStringExists @478 NONAME + ;SCmdProcessCommandLine @479 NONAME + ;Ordinal480 @480 NONAME + ;SMemFindNextBlock @481 NONAME + ;SMemFindNextHeap @482 NONAME + ;SMemGetHeapByCaller @483 NONAME + ;SMemGetHeapByPtr @484 NONAME + ;SMemHeapAlloc @485 NONAME + ;SMemHeapCreate @486 NONAME + ;SMemHeapDestroy @487 NONAME + ;SMemHeapFree @488 NONAME + ;SMemHeapRealloc @489 NONAME + ;SMemHeapSize @490 NONAME + SMemCopy @491 NONAME + SMemFill @492 NONAME + ;SMemMove @493 NONAME + SMemZero @494 NONAME + SMemCmp @495 NONAME + ;SMem496 @496 NONAME + ;SMemDumpState @497 NONAME + ;Ordinal498 @498 NONAME + + SStrCopy @501 NONAME + SStrHash @502 NONAME + SStrNCat @503 NONAME + ;SStrTokenize @504 NONAME + ;SStrPack @505 NONAME + SStrLen @506 NONAME + ;SStrDup @507 NONAME + SStrCmp @508 NONAME + SStrCmpI @509 NONAME + SStrUpper @510 NONAME + ;SMsgBreakHandlerChain @511 NONAME + ;SMsgUnregisterCommand @512 NONAME + ;SMsgUnregisterKeyDown @513 NONAME + ;SMsgUnregisterKeyUp @514 NONAME + ;SMsgUnregisterMessage @515 NONAME + ;SMsgGetDispatcher @516 NONAME + ;SMsgSetDefaultWindow @517 NONAME + ;SMsgGetDefaultWindow @518 NONAME + ;SMsg519 @519 NONAME + + ;SRgn521 @521 NONAME + + SRgn523 @523 NONAME + SRgnCreateRegion @524 NONAME + SRgnDeleteRegion @525 NONAME + + ;SRgn527 @527 NONAME + ;SRgn528i @528 NONAME + SRgn529i @529 NONAME + ;SRgn530i @530 NONAME + ;SRgn531i @531 NONAME + ;SRgn532i @532 NONAME + ;SRgn533i @533 NONAME + ;SRgn534 @534 NONAME + ;SRgn535f @535 NONAME + ;SRgn536f @536 NONAME + ;SRgn537f @537 NONAME + ;SRgn538f @538 NONAME + ;SRgn539f @539 NONAME + ;SRgn540f @540 NONAME + ;SLogClose @541 NONAME + ;SLogCreate @542 NONAME + ;SLog543 @543 NONAME + ;SLogDump @544 NONAME + ;SLogFlush @545 NONAME + ;SLogFlushAll @546 NONAME + ;SLogPend @547 NONAME + ;SLogWrite @548 NONAME + ;SLog549 @549 NONAME + ;SLogCriticalLog @550 NONAME + ;SCompCompress @551 NONAME + ;SCompDecompress @552 NONAME + ;SLogVWrite @553 NONAME + ;Ordinal554 @554 NONAME + ;Ordinal555 @555 NONAME + ;Ordinal556 @556 NONAME + ;Ordinal557 @557 NONAME + ;Ordinal558 @558 NONAME + ;Ordinal559 @559 NONAME + ;Ordinal560 @560 NONAME + ;SErrCheckDebugSymbolLibrary @561 NONAME + SErrDisplayErrorFmt @562 NONAME + ;SErrIsDisplayingError @563 NONAME + ;SErrPrepareAppFatal @564 NONAME + ;SErrSetLogTitleString @565 NONAME + ;SErrDisplayAppFatal @566 NONAME + SErrCatchUnhandledExceptions @567 NONAME + ;Storm568 @568 NONAME + ;SStrChr @569 NONAME + ;SStrChrR @570 NONAME + SStrChr @571 NONAME + SStrChrR @572 NONAME + ;SStrToDouble @573 NONAME + ;SStrToFloat @574 NONAME + ;SStrToInt @575 NONAME + ;SStrToUnsigned @576 NONAME + ;SStrToInt64 @577 NONAME + SStrVPrintf @578 NONAME + ;SStrLower @579 NONAME + ;SStrHash64 @580 NONAME + ;SStrPrintf @581 NONAME + ;SDrawSetClientRect @582 NONAME + ;SDrawGetClientRect @583 NONAME + ;SStrStrI @584 NONAME + ;SStrStrI @585 NONAME + ;SStrStr @586 NONAME + ;SStrStr @587 NONAME + ;SNet588 @588 NONAME + + ;SBigAdd @601 NONAME + ;SBigAnd @602 NONAME + ;SBigCompare @603 NONAME + ;SBigCopy @604 NONAME + ;SBigDec @605 NONAME + SBigDel @606 NONAME + ;SBigDiv @607 NONAME + ;SBigFindPrime @608 NONAME + SBigFromBinary @609 NONAME + ;SBigFromStr @610 NONAME + ;SBigFromStream @611 NONAME + ;SBigFromUnsigned @612 NONAME + ;SBigGcd @613 NONAME + ;SBigInc @614 NONAME + ;SBigInvMod @615 NONAME + ;SBigIsEven @616 NONAME + ;SBigIsOdd @617 NONAME + ;SBigIsOne @618 NONAME + ;SBigIsPrime @619 NONAME + ;SBigIsZero @620 NONAME + ;SBigMod @621 NONAME + ;SBigMul @622 NONAME + ;SBigMulMod @623 NONAME + SBigNew @624 NONAME + ;SBigNot @625 NONAME + ;SBigOr @626 NONAME + ;SBigPow @627 NONAME + SBigPowMod @628 NONAME + ;SBigRand @629 NONAME + ;SBigSet2Exp @630 NONAME + ;SBigSetOne @631 NONAME + ;SBigSetZero @632 NONAME + ;SBigShl @633 NONAME + ;SBigShr @634 NONAME + ;SBigSquare @635 NONAME + ;SBigSub @636 NONAME + ;SBigToBinaryArray @637 NONAME + SBigToBinaryBuffer @638 NONAME + ;SBigToBinaryPtr @639 NONAME + ;SBigToStrArray @640 NONAME + ;SBigToStrBuffer @641 NONAME + ;SBigToStrPtr @642 NONAME + ;SBigToStreamArray @643 NONAME + ;SBigToStreamBuffer @644 NONAME + ;SBigToStreamPtr @645 NONAME + ;SBigToUnsigned @646 NONAME + ;SBigXor @647 NONAME + + ;SUniConvertUTF16to8Len @901 NONAME + ;SUniConvertUTF16to8 @902 NONAME + ;SUniConvertUTF8to16Len @903 NONAME + ;SUniConvertUTF8to16 @904 NONAME + ;SUniS905 @905 NONAME + ;SUniS906 @906 NONAME + ;SUniFindAfterUTF8Chr @907 NONAME + ;SUniFindUTF8ChrStart @908 NONAME + ;SUniConvertUTF16To909 @909 NONAME + ;SUniConvertUTF16To910 @910 NONAME + ;SUniConvertUTF16To911 @911 NONAME + ;SUniConvert912 @912 NONAME + ;SUniConvert913 @913 NONAME + ;SUniConvert914 @914 NONAME + ;SUniConvertUTF8ToWin @915 NONAME +; END diff --git a/3rdParty/Storm/Source/storm.h b/3rdParty/Storm/Source/storm.h new file mode 100644 index 000000000..9f0e3da6b --- /dev/null +++ b/3rdParty/Storm/Source/storm.h @@ -0,0 +1,1311 @@ +#pragma once + +#ifndef __BLIZZARD_STORM_HEADER +#define __BLIZZARD_STORM_HEADER + +#ifndef MINIWIN +#include +#include +#include +#include +#else +#include "miniwin.h" +#endif + +// Note to self: Linker error => forgot a return value in cpp + +// Storm API definition +#ifndef STORMAPI +#define STORMAPI __stdcall +#endif + +#ifndef __STORM_SMAX +#define __STORM_SMAX(x,y) (x < y ? y : x) +#endif + +#ifndef __STORM_SSIZEMAX +#define __STORM_SSIZEMAX(x,y) (__STORM_SMAX(sizeof(x),sizeof(y))) +#endif + +#ifndef __STORM_SMIN +#define __STORM_SMIN(x,y) (x < y ? x : y) +#endif + +#ifndef __STORM_SSIZEMIN +#define __STORM_SSIZEMIN(x,y) (__STORM_SMIN(sizeof(x),sizeof(y))) +#endif + +typedef struct _WRECT +{ + WORD left; + WORD top; + WORD right; + WORD bottom; +} WRECT, *PWRECT; + +typedef struct _WPOINT +{ + WORD x; + WORD y; +} WPOINT, *PWPOINT; + +typedef struct _WSIZE +{ + WORD cx; + WORD cy; +} WSIZE, *PWSIZE; + + + +// Game states +#define GAMESTATE_PRIVATE 0x01 +#define GAMESTATE_FULL 0x02 +#define GAMESTATE_ACTIVE 0x04 +#define GAMESTATE_STARTED 0x08 +#define GAMESTATE_REPLAY 0x80 + +#ifdef __GNUC__ +extern "C" { +#endif + +BOOL STORMAPI SNetCreateGame(const char *pszGameName, const char *pszGamePassword, const char *pszGameStatString, DWORD dwGameType, char *GameTemplateData, int GameTemplateSize, int playerCount, char *creatorName, char *a11, int *playerID); +BOOL STORMAPI SNetDestroy(); +BOOL STORMAPI SNetEnumProviders(int (STORMAPI *callback)(DWORD, DWORD, DWORD, DWORD), int mincaps); + +BOOL STORMAPI SNetEnumGames(int (STORMAPI *callback)(DWORD, DWORD, DWORD), int *hintnextcall); + +/* SNetDropPlayer @ 106 + * + * Drops a player from the current game. + * + * playerid: The player ID for the player to be dropped. + * flags: + * + * Returns TRUE if the function was called successfully and FALSE otherwise. + */ +BOOL +STORMAPI +SNetDropPlayer( + int playerid, + DWORD flags); + +/* SNetGetGameInfo @ 107 + * + * Retrieves specific game information from Storm, such as name, password, + * stats, mode, game template, and players. + * + * type: The type of data to retrieve. See GAMEINFO_ flags. + * dst: The destination buffer for the data. + * length: The maximum size of the destination buffer. + * byteswritten: The number of bytes written to the destination buffer. + * + * Returns TRUE if the function was called successfully and FALSE otherwise. + */ +BOOL +STORMAPI +SNetGetGameInfo( + int type, + void *dst, + size_t length, + size_t *byteswritten = NULL); + + +#define SNGetGameInfo(typ,dst) SNetGetGameInfo(typ, &dst, sizeof(dst)) + + + +// Game info fields +#define GAMEINFO_NAME 1 +#define GAMEINFO_PASSWORD 2 +#define GAMEINFO_STATS 3 +#define GAMEINFO_MODEFLAG 4 +#define GAMEINFO_GAMETEMPLATE 5 +#define GAMEINFO_PLAYERS 6 + + +BOOL STORMAPI SNetGetNumPlayers(int *firstplayerid, int *lastplayerid, int *activeplayers); + + +typedef struct _CAPS +{ + DWORD dwSize; // Size of this structure // sizeof(CAPS) + DWORD dwUnk_0x04; // Some flags? + DWORD maxmessagesize; // Size of the packet buffer, must be beteen 128 and 512 + DWORD dwUnk_0x0C; // Unknown + DWORD dwDisplayedPlayerCount; // Displayed player count in the mode selection list + DWORD dwUnk_0x14; // some kind of timeout or timer related + DWORD dwPlayerLatency; // ... latency? + DWORD dwPlayerCount; // the number of players that can participate, must be between 1 and 20 + DWORD dwCallDelay; // the number of calls before data is sent over the network // between 2 and 8; single player is set to 1 +} CAPS, *PCAPS; + + +BOOL STORMAPI SNetGetPlayerCaps(char playerid, PCAPS playerCaps); + +/* SNetGetPlayerName @ 113 + * + * Retrieves the name of a player given their player ID. + * + * playerid: The player's ID. + * buffer: The buffer that will receive the name. + * buffersize: The maximum size of buffer. + * + * Returns TRUE if the function was called successfully and FALSE otherwise. + */ +BOOL +STORMAPI +SNetGetPlayerName( + int playerid, + char *buffer, + size_t buffersize); + +/* SNetGetProviderCaps @ 114 + * + * Retrieves network provider capacity information. + * + * providerCaps: A pointer to a CAPS structure that will receive the information. + * + * Returns TRUE if the function was called successfully and FALSE otherwise. + */ +//BOOL +//STORMAPI +//SNetGetProviderCaps( +// PCAPS providerCaps); + +/* SNetGetTurnsInTransit @ 115 + * + * Retrieves the number of turns (buffers) that have been queued + * before sending them over the network. + * + * turns: A pointer to an integer that will receive the value. + * + * Returns TRUE if the function was called successfully and FALSE otherwise. + */ +BOOL +STORMAPI +SNetGetTurnsInTransit( + int *turns); + + +BOOL STORMAPI SNetInitializeDevice(int a1, int a2, int a3, int a4, int *a5); + +// Network provider structures +typedef struct _client_info +{ + DWORD dwSize; // 60 + char *pszName; + char *pszVersion; + DWORD dwProduct; + DWORD dwVerbyte; + DWORD dwUnk5; + DWORD dwMaxPlayers; + DWORD dwUnk7; + DWORD dwUnk8; + DWORD dwUnk9; + DWORD dwUnk10; // 0xFF + char *pszCdKey; + char *pszCdOwner; + DWORD dwIsShareware; + DWORD dwLangId; +} client_info; + +typedef struct _user_info +{ + DWORD dwSize; // 16 + char *pszPlayerName; + char *pszUnknown; + DWORD dwUnknown; +} user_info; + +typedef struct _battle_info +{ + DWORD dwSize; // 92 + DWORD dwUnkType; + HWND hFrameWnd; + void *pfnBattleGetResource; + void *pfnBattleGetErrorString; + void *pfnBattleMakeCreateGameDialog; + void *pfnBattleUpdateIcons; + DWORD dwUnk_07; + void *pfnBattleErrorDialog; + void *pfnBattlePlaySound; + DWORD dwUnk_10; + void *pfnBattleGetCursorLink; + DWORD dwUnk_12; + void *pfnUnk_13; + DWORD dwUnk_14; + void *pfnBattleMakeProfileDialog; + char *pszProfileStrings; + void *pfnBattleDrawProfileInfo; + void *pfnUnk_18; + DWORD dwUnk_19; + void *pfnUnk_20; + void *pfnUnk_21; + void *pfnBattleSetLeagueName; +} battle_info; + +typedef struct _module_info +{ + DWORD dwSize; // 20 + char *pszVersionString; + char *pszModuleName; + char *pszMainArchive; + char *pszPatchArchive; +} module_info; + +typedef struct _game +{ + DWORD dwIndex; + DWORD dwGameState; + DWORD dwUnk_08; + SOCKADDR saHost; + DWORD dwUnk_1C; + DWORD dwTimer; + DWORD dwUnk_24; + char szGameName[128]; + char szGameStatString[128]; + _game *pNext; + void *pExtra; + DWORD dwExtraBytes; + DWORD dwProduct; + DWORD dwVersion; +} game; + +typedef struct _storm_head +{ + WORD wChecksum; + WORD wLength; + WORD wSent; + WORD wReceived; + BYTE bCommandClass; + BYTE bCommandType; + BYTE bPlayerId; + BYTE bFlags; +} storm_head; + + +// Traffic flags +#define STRAFFIC_NORMAL 0 +#define STRAFFIC_VERIFY 1 +#define STRAFFIC_RESEND 2 +#define STRAFFIC_REPLY 4 + + +/* SNetInitializeProvider @ 117 + * + * Initializes a provider by storing the provider callbacks, and calling + * spiInitialize() using the parameters passed to this function. + * Note: The use of the parameters is determined by the network + * module. + * + * providerName: The provider's identifier. Example: 'TENB' (BNET). + * gameClientInfo: A pointer to a clientInfo structure containing + * information about the game client. + * userData: A pointer to a userInfo structure containing information + * about the player. + * bnCallbacks: A pointer to a battleInfo structure containing callbacks + * and other information that is specific to Battle.net. + * moduleData: A pointer to a moduleInfo structure containing the + * executable information and paths to MPQ archives. + * + * Returns TRUE if the function was called successfully and FALSE otherwise. + */ +//BOOL +//STORMAPI +//SNetInitializeProvider( +// DWORD providerName, +// client_info *gameClientInfo, +// user_info *userData, +// battle_info *bnCallbacks, +// module_info *moduleData); + + +BOOL STORMAPI SNetJoinGame(int id, char *gameName, char *gamePassword, char *playerName, char *userStats, int *playerid); + +/* SNetLeaveGame @ 119 + * + * Notifies Storm that the player has left the game. Storm will + * notify all connected peers through the network provider. + * + * type: The leave type. It doesn't appear to be important, no documentation available. + * + * Returns TRUE if the function was called successfully and FALSE otherwise. + */ +BOOL +STORMAPI +SNetLeaveGame( + int type); + +BOOL STORMAPI SNetPerformUpgrade(DWORD *upgradestatus); +BOOL STORMAPI SNetReceiveMessage(int *senderplayerid, char **data, int *databytes); +BOOL STORMAPI SNetReceiveTurns(int a1, int arraysize, char **arraydata, unsigned int *arraydatabytes, DWORD *arrayplayerstatus); + +// Values for arrayplayerstatus +#define SNET_PS_OK 0 +#define SNET_PS_WAITING 2 +#define SNET_PS_NOTRESPONDING 3 +#define SNET_PS_UNKNOWN default + + +// Event structure +typedef struct _s_evt +{ + DWORD dwFlags; + int dwPlayerId; + void *pData; + DWORD dwSize; +} S_EVT, *PS_EVT; + + +// @TODO: "type" is unknown. +//HANDLE STORMAPI SNetRegisterEventHandler(int type, void (STORMAPI *sEvent)(PS_EVT)); + +int STORMAPI SNetSelectGame(int a1, int a2, int a3, int a4, int a5, int *playerid); + +/* SNetSendMessage @ 127 + * + * Sends a message to a player given their player ID. Network message + * is sent using class 01 and is retrieved by the other client using + * SNetReceiveMessage(). + * + * playerID: The player index of the player to receive the data. + * Conversely, this field can be one of the following constants: + * SNPLAYER_ALL | Sends the message to all players, including oneself. + * SNPLAYER_OTHERS | Sends the message to all players, except for oneself. + * data: A pointer to the data. + * databytes: The amount of bytes that the data pointer contains. + * + * Returns TRUE if the function was called successfully and FALSE otherwise. + */ +BOOL +STORMAPI +SNetSendMessage( + int playerID, + void *data, + size_t databytes); + + +// Macro values to target specific players +#define SNPLAYER_ALL -1 +#define SNPLAYER_OTHERS -2 + + +/* SNetSendTurn @ 128 + * + * Sends a turn (data packet) to all players in the game. Network data + * is sent using class 02 and is retrieved by the other client using + * SNetReceiveTurns(). + * + * data: A pointer to the data. + * databytes: The amount of bytes that the data pointer contains. + * + * Returns TRUE if the function was called successfully and FALSE otherwise. + */ +BOOL +STORMAPI +SNetSendTurn( + char *data, + size_t databytes); + +/* SNetSetGameMode @ 130 + * + * Set's the game's mode flags, notifying the network + * provider that the state of the game has changed. + * For example: notifies Battle.net when the game is + * full. + * + * You should first call SNetGetGameInfo to retrieve + * the existing mode flags. + * + * modeFlags: The new flags for the game mode. + * GAMESTATE_PRIVATE | The game is passworded. + * GAMESTATE_FULL | The game is full. + * GAMESTATE_ACTIVE | The game is available. + * GAMESTATE_STARTED | The game is in progress. + * GAMESTATE_REPLAY | The game is a replay. + * makePublic: Used to make the game a public game, removing the GAMESTATE_PRIVATE flag. + * + * Returns TRUE if the function was called successfully and FALSE otherwise. + */ +BOOL +STORMAPI +SNetSetGameMode( + DWORD modeFlags, + bool makePublic = false); + +#define SNMakeGamePublic() SNetSetGameMode( (DWORD mode, SNetGetGameInfo(GAMEINFO_MODEFLAGS, &mode, 4), mode), true) + +BOOL STORMAPI SNetEnumGamesEx(int a1, int a2, int (__fastcall *callback)(DWORD, DWORD, DWORD), int *hintnextcall); +BOOL STORMAPI SNetSendServerChatCommand(const char *command); + +BOOL STORMAPI SNetDisconnectAll(DWORD flags); +BOOL STORMAPI SNetCreateLadderGame(const char *pszGameName, const char *pszGamePassword, const char *pszGameStatString, DWORD dwGameType, DWORD dwGameLadderType, DWORD dwGameModeFlags, char *GameTemplateData, int GameTemplateSize, int playerCount, char *creatorName, char *a11, int *playerID); + +#define SNET_GAME_RESULT_WIN 1 +#define SNET_GAME_RESULT_LOSS 2 +#define SNET_GAME_RESULT_DRAW 3 +#define SNET_GAME_RESULT_DISCONNECT 4 + +BOOL STORMAPI SNetReportGameResult(unsigned a1, int size, int *results, const char* headerInfo, const char* detailInfo); + +int STORMAPI SNetSendLeagueCommand(char *cmd, char *callback); +int STORMAPI SNetSendReplayPath(int a1, int a2, char *replayPath); +int STORMAPI SNetGetLeagueName(int leagueID); +BOOL STORMAPI SNetGetPlayerNames(char **names); +int STORMAPI SNetLeagueLogout(char *bnetName); +int STORMAPI SNetGetLeaguePlayerName(char *curPlayerLeageName, size_t nameSize); + +HGDIOBJ STORMAPI SDlgDefDialogProc(HWND hDlg, signed int DlgType, HDC textLabel, HWND hWnd); + +HANDLE STORMAPI SDlgDialogBoxIndirectParam(HMODULE hModule, LPCSTR lpName, HWND hWndParent, LPVOID lpParam, LPARAM lParam); + +BOOL STORMAPI SDlgEndDialog(HWND hDlg, HANDLE nResult); + +BOOL STORMAPI SDlgSetControlBitmaps(HWND parentwindow, int *id, int a3, char *buffer2, char *buffer, int flags, int mask); + +/* +// lpCursorName can only be IDC_ARROW +BOOL STORMAPI SDlgSetSystemCursor(void *lpSrcBuffer, void *p_a2, LPSIZE lpSize, LPCSTR lpCursorName); +*/ + +BOOL STORMAPI SDlgBltToWindowE(HWND hWnd, HRGN a2, char *a3, int a4, void *buffer, RECT *rct, SIZE *size, int a8, int a9, DWORD rop); +BOOL STORMAPI SDlgSetBitmapE(HWND hWnd, int a2, char *src, int mask1, int flags, int a6, int a7, int width, int a9, int mask2); + +int STORMAPI Ordinal224(int a1); + +BOOL STORMAPI SFileCloseArchive(HANDLE hArchive); +BOOL STORMAPI SFileCloseFile(HANDLE hFile); + +BOOL STORMAPI SFileDdaBeginEx(HANDLE directsound, DWORD flags, DWORD mask, unsigned __int32 lDistanceToMove, signed __int32 volume, signed int a6, int a7); +BOOL STORMAPI SFileDdaDestroy(); +BOOL STORMAPI SFileDdaEnd(HANDLE directsound); +BOOL STORMAPI SFileDdaGetPos(HANDLE directsound, int a2, int a3); + +BOOL STORMAPI SFileDdaInitialize(HANDLE directsound); +BOOL STORMAPI SFileDdaSetVolume(HANDLE directsound, signed int bigvolume, signed int volume); +BOOL STORMAPI SFileDestroy(); + +BOOL STORMAPI SFileGetFileArchive(HANDLE hFile, HANDLE archive); +LONG STORMAPI SFileGetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh); +BOOL STORMAPI SFileOpenArchive(const char *szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE *phMpq); + +// values for dwFlags +enum MPQFlags +{ + MPQ_NO_LISTFILE = 0x0010, + MPQ_NO_ATTRIBUTES = 0x0020, + MPQ_FORCE_V1 = 0x0040, + MPQ_CHECK_SECTOR_CRC = 0x0080 +}; + + +BOOL STORMAPI SFileOpenFile(const char *filename, HANDLE *phFile); +BOOL STORMAPI SFileOpenFileEx(HANDLE hMpq, const char *szFileName, DWORD dwSearchScope, HANDLE *phFile); + +// values for dwSearchScope +enum SFileFlags +{ + SFILE_FROM_MPQ = 0x00000000, + SFILE_FROM_ABSOLUTE = 0x00000001, + SFILE_FROM_RELATIVE = 0x00000002, + SFILE_FROM_DISK = 0x00000004 +}; + +BOOL STORMAPI SFileReadFile(HANDLE hFile, void *buffer, DWORD nNumberOfBytesToRead, DWORD *read, LONG lpDistanceToMoveHigh); + +void STORMAPI SFileSetLocale(LCID lcLocale); + +// mode: 0 - Silent (callback is NULL) +// 1 - Application Defined +// 2 - Handled by storm (callback is NULL) +// BOOL STORMAPI callback(const char *pszFilename, DWORD dwErrCode, DWORD dwErrCount) +BOOL STORMAPI SFileSetIoErrorMode(DWORD mode, BOOL (STORMAPI *callback)(const char*,DWORD,DWORD) ); + +BOOL STORMAPI SFileGetArchiveName(HANDLE hArchive, char *name, int length); +BOOL STORMAPI SFileGetFileName(HANDLE hFile, char *buffer, int length); + +BOOL STORMAPI SFileLoadFile(char *filename, void *buffer, int buffersize, int a4, int a5); +BOOL STORMAPI SFileUnloadFile(HANDLE hFile); +BOOL STORMAPI SFileLoadFileEx(void *hArchive, char *filename, int a3, int a4, int a5, DWORD searchScope, struct _OVERLAPPED *lpOverlapped); + +// Options are DWORD except for #6 +// 1: [TRUE|FALSE] - If true, reports resource leaks (SErrReportResourceLeak/SErrReportNamedResourceLeak) to the attached debugger instead of a message box. +// 2: This option is unused. +// 3: [TRUE|FALSE] - If true, reports general memory leaks to the attached debugger instead of a message box. +// 4: This option is unused. +// 5: [TRUE|FALSE] - If true, reports log messages and log dumps to the attached debugger. +// 6: { DWORD blocks_allocated; DWORD blocks_freed; } Used to determine the amount of memory/heap blocks that have been allocated and freed by storm. +// Can also be used for custom allocations outside of storm. +// +//BOOL STORMAPI StormGetOption(int type, void *pValue, size_t *pSize); +//BOOL STORMAPI StormSetOption(int type, void *pValue, size_t size); + +BOOL STORMAPI SBltROP3(void *lpDstBuffer, void *lpSrcBuffer, int srcDrawWidth, int srcDrawHeight, int dstWidth, int srcWidth, int a7, DWORD rop); +BOOL STORMAPI SBltROP3Clipped(void *lpDstBuffer, RECT *lpDstRect, POINT *lpDstPt, int a4, void *lpSrcBuffer, RECT *lpSrcRect, POINT *lpSrcPt, int a8, int a9, DWORD rop); + +#define SBMP_DEFAULT 0 +#define SBMP_BMP 1 +#define SBMP_PCX 2 +#define SBMP_TGA 3 + + +/* SBmpDecodeImage @ 321 + * + * Decodes an image that has already been loaded into a buffer. + * + * dwImgType: Optional, the image type. See SBMP_ macros. + * pSrcBuffer: A pointer to the source buffer. + * dwSrcBuffersize: The size of the data in the source buffer. + * pPalette: An optional buffer that receives the image palette. + * pDstBuffer: A buffer that receives the image data. + * dwDstBuffersize: The size of the specified image buffer. If the size of the + * destination buffer is 0, then the destination buffer is not used. + * pdwWidth: An optional variable that receives the image width. + * pdwHeight: An optional variable that receives the image height. + * pdwBpp: An optional variable that receives the image bits per pixel. + * + * Returns TRUE if the image was supported and decoded correctly, FALSE otherwise. + */ +BOOL +STORMAPI +SBmpDecodeImage( + DWORD dwImgType, + void *pSrcBuffer, + DWORD dwSrcBuffersize, + PALETTEENTRY *pPalette = NULL, + void *pDstBuffer = NULL, + DWORD dwDstBuffersize = 0, + DWORD *pdwWidth = NULL, + DWORD *pdwHeight = NULL, + DWORD *pdwBpp = NULL); + + +/* SBmpLoadImage @ 323 + * + * Load an image from an available archive into a buffer. + * + * pszFileName: The name of the graphic in an active archive. + * pPalette: An optional buffer that receives the image palette. + * pBuffer: A buffer that receives the image data. + * dwBuffersize: The size of the specified image buffer. + * pdwWidth: An optional variable that receives the image width. + * pdwHeight: An optional variable that receives the image height. + * pdwBpp: An optional variable that receives the image bits per pixel. + * + * Returns TRUE if the image was supported and loaded correctly, FALSE otherwise. + */ +BOOL +STORMAPI +SBmpLoadImage( + const char *pszFileName, + PALETTEENTRY *pPalette = NULL, + void *pBuffer = NULL, + DWORD dwBuffersize = 0, + DWORD *pdwWidth = NULL, + DWORD *pdwHeight = NULL, + DWORD *pdwBpp = NULL); + +/* SBmpSaveImage @ 324 + * + * Save an image from a buffer to a file. The image format is determined + * from the filename and is either .gif, .pcx, .tga, or .bmp being the default. + * + * pszFileName: The name of the file to create. + * pPalette: A pointer to a palette array containing 256 entries. + * pBuffer: A buffer containing the image data. + * pdwWidth: The width of the image. + * pdwHeight: The height of the image. + * pdwBpp: The bits per pixel. + * + * Returns TRUE if the image was saved correctly, FALSE otherwise. + */ +BOOL +STORMAPI +SBmpSaveImage( + const char *pszFileName, + PALETTEENTRY *pPalette, + void *pBuffer, + DWORD dwWidth, + DWORD dwHeight, + DWORD dwBpp = 8); + + +HANDLE STORMAPI SBmpAllocLoadImage(const char *fileName, PALETTEENTRY *palette, void **buffer, int *width, int *height, int unused6, int unused7, void *(STORMAPI *allocFunction)(DWORD)); + +BOOL STORMAPI SCodeCompile(char *directives1, char *directives2, char *loopstring, unsigned int maxiterations, unsigned int flags, HANDLE handle); +BOOL STORMAPI SCodeDelete(HANDLE handle); + +int STORMAPI SCodeExecute(HANDLE handle, int a2); + +BOOL STORMAPI SDrawAutoInitialize(HINSTANCE hInst, LPCSTR lpClassName, LPCSTR lpWindowName, WNDPROC pfnWndProc, int nMode, int nWidth, int nHeight, int nBits); + + +/* SDrawCaptureScreen @ 342 + * + * Saves a screenshot from the primary surface being handled by Storm. + * + * pszOutput: The name of the output file. The save format is automatically set by the extension. + * The extensions supported are .gif, .pcx, .tga, and .bmp. It will write a bitmap by default. + * + * Returns TRUE if successful and FALSE otherwise. + */ +BOOL +STORMAPI +SDrawCaptureScreen( + const char *pszOutput); + + +/* SDrawGetFrameWindow @ 346 + * + * Retrieves the window handle that was specified in + * SDrawManualInitialize or created in SDrawAutoInitialize. + * + * sdraw_framewindow: Optional variable that receives the returned handle. + * + * Returns the handle of the window. + */ +HWND +STORMAPI +SDrawGetFrameWindow( + HWND *sdraw_framewindow = NULL); + + +/* SDrawGetObjects @ 347 + * + * Retrieves the object information that was initialized using + * SDrawManualInitialize or SDrawAutoInitialize. + * + * ddInterface: The DirectDraw interface. + * primarySurface: The primary DirectDraw surface. + * surface2: A second unknown surface. + * surface3: A third unknown surface. + * backSurface: The back DirectDraw surface. + * ddPalette: The DirectDraw palette. + * hPalette: The palette handle. + * + * Returns FALSE if the direct draw interface has not been initialized. + */ +BOOL +STORMAPI +SDrawGetObjects( + LPDIRECTDRAW *ddInterface = NULL, + LPDIRECTDRAWSURFACE *primarySurface = NULL, + LPDIRECTDRAWSURFACE *surface2 = NULL, + LPDIRECTDRAWSURFACE *surface3 = NULL, + LPDIRECTDRAWSURFACE *backSurface = NULL, + LPDIRECTDRAWPALETTE *ddPalette = NULL, + HPALETTE *hPalette = NULL); + + +/* SDrawGetScreenSize @ 348 + * + * Obtains information for the current screen resolution. + * + * pdwWidth: Optional variable that receives the screen width. + * pdwHeight: Optional variable that receives the screen height. + * pdwBpp: Optional variable that receives the bits per pixel. + * + * Returns FALSE if no variables were specified. + */ +BOOL +STORMAPI +SDrawGetScreenSize( + DWORD *pdwWidth, + DWORD *pdwHeight, + DWORD *pdwBpp); + + +// undefined +BOOL STORMAPI SDrawLockSurface(int surfacenumber, RECT *lpDestRect, void **lplpSurface, int *lpPitch, int arg_unused); + + +/* SDrawManualInitialize @ 351 + * + * Sets the DirectDraw variables to be referenced in Storm. + * + * hWnd: The handle of the DirectDraw window. + * ddInterface: The DirectDraw interface. + * primarySurface: The first and primary surface. + * surface2: A second surface. Behaviour not completely known. + * surface3: A third surface. Behaviour not completely known. + * backSurface: The fourth and final surface. The back surface. + * ddPalette: The DirectDraw palette if the application requires it. + * hPalette: The palette handle that belongs to the window. + * If this is NULL and ddPalette is specified, then it + * will be created automatically. A palette can be created + * using the CreatePalette WinAPI function. + * + * Returns FALSE if no variables were specified. + */ +BOOL +STORMAPI +SDrawManualInitialize( + HWND hWnd = NULL, + LPDIRECTDRAW ddInterface = NULL, + LPDIRECTDRAWSURFACE primarySurface = NULL, + LPDIRECTDRAWSURFACE surface2 = NULL, + LPDIRECTDRAWSURFACE surface3 = NULL, + LPDIRECTDRAWSURFACE backSurface = NULL, + LPDIRECTDRAWPALETTE ddPalette = NULL, + HPALETTE hPalette = NULL); + + +/* SDrawPostClose @ 353 + * + * Posts a WM_QUIT message to the active drawing window specified + * in SDrawManualInitialize or created in SDrawAutoInitialize. + * + * Returns TRUE if successful and FALSE otherwise. + */ +BOOL +STORMAPI +SDrawPostClose(); + + +// undefined +//BOOL STORMAPI SDrawRealizePalette(); + +BOOL STORMAPI SDrawUnlockSurface(int surfacenumber, void *lpSurface, int a3, RECT *lpRect); +BOOL STORMAPI SDrawUpdatePalette(unsigned int firstentry, unsigned int numentries, PALETTEENTRY *pPalEntries, int a4); + +BOOL STORMAPI SEvtDispatch(DWORD dwMessageID, DWORD dwFlags, int type, PS_EVT pEvent); + +BOOL STORMAPI SGdiDeleteObject(HANDLE handle); + +BOOL STORMAPI SGdiExtTextOut(int a1, int a2, int a3, int a4, unsigned int a8, signed int a6, signed int a7, const char *pszString, unsigned int arg20); +BOOL STORMAPI SGdiImportFont(HGDIOBJ handle, int windowsfont); + +BOOL STORMAPI SGdiSelectObject(int handle); +BOOL STORMAPI SGdiSetPitch(int pitch); + +BOOL STORMAPI Ordinal393(char *pszString, int, int); + + +/* SMemAlloc @ 401 + * + * Allocates a block of memory. This block is different + * from the standard malloc by including a header containing + * information about the block. + * + * amount: The amount of memory to allocate, in bytes. + * logfilename: The name of the file or object that this call belongs to. + * logline: The line in the file or one of the SLOG_ macros. + * defaultValue: The default value of a byte in the allocated memory. + * + * Returns a pointer to the allocated memory. This pointer does NOT include + * the additional storm header. + */ +void* +STORMAPI +SMemAlloc( + size_t amount, + char *logfilename, + int logline, + char defaultValue = 0); + +#define SMAlloc(amount) SMemAlloc((amount), __FILE__, __LINE__) + + +/* SMemFree @ 403 + * + * Frees a block of memory that was created using SMemAlloc, + * includes the log file and line for debugging purposes. + * + * location: The memory location to be freed. + * logfilename: The name of the file or object that this call belongs to. + * logline: The line in the file or one of the SLOG_ macros. + * defaultValue: + * + * Returns TRUE if the call was successful and FALSE otherwise. + */ +BOOL +STORMAPI +SMemFree( + void *location, + char *logfilename, + int logline, + char defaultValue = 0); + +#define SMFree(loc) SMemFree((loc), __FILE__, __LINE__) + + +/* SMemReAlloc @ 405 + * + * Reallocates a block of memory that was created using SMemAlloc, + * includes the log file and line for debugging purposes. + * + * location: The memory location to be re-allocated. If this parameter + * is NULL, then SMemAlloc is called with the remaining parameters. + * amount: The amount of memory to re-allocate. + * logfilename: The name of the file or object that this call belongs to. + * logline: The line in the file or one of the SLOG_ macros. + * defaultValue: + * + * Returns a pointer to the re-allocated memory. This pointer does NOT include + * the additional storm header. + */ +void* +STORMAPI +SMemReAlloc( + void *location, + size_t amount, + char *logfilename, + int logline, + char defaultValue = 0); + +#define SMReAlloc(loc,s) SMemReAlloc((loc),(s), __FILE__, __LINE__) + +// Can be provided instead of logline/__LINE__ parameter to indicate different errors. +#define SLOG_EXPRESSION 0 +#define SLOG_FUNCTION -1 +#define SLOG_OBJECT -2 +#define SLOG_HANDLE -3 +#define SLOG_FILE -4 +#define SLOG_EXCEPTION -5 + + +BOOL STORMAPI SRegLoadData(const char *keyname, const char *valuename, int size, LPBYTE lpData, BYTE flags, LPDWORD lpcbData); +BOOL STORMAPI SRegLoadString(const char *keyname, const char *valuename, BYTE flags, char *buffer, size_t buffersize); +BOOL STORMAPI SRegLoadValue(const char *keyname, const char *valuename, BYTE flags, int *value); +BOOL STORMAPI SRegSaveData(const char *keyname, const char *valuename, int size, BYTE *lpData, DWORD cbData); +BOOL STORMAPI SRegSaveString(const char *keyname, const char *valuename, BYTE flags, char *string); +BOOL STORMAPI SRegSaveValue(const char *keyname, const char *valuename, BYTE flags, DWORD result); + +BOOL STORMAPI SRegDeleteValue(const char *keyname, const char *valuename, BYTE flags); + +// Flags for SReg functions + +// Default behaviour checks both HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER +// relative to the "Software\\Blizzard Entertainment\\" key in both hives. +#define SREG_NONE 0x00000000 +#define SREG_EXCLUDE_LOCAL_MACHINE 0x00000001 // excludes checking the HKEY_LOCAL_MACHINE hive +#define SREG_BATTLE_NET 0x00000002 // sets the relative key to "Software\\Battle.net\\" instead +#define SREG_EXCLUDE_CURRENT_USER 0x00000004 // excludes checking the HKEY_CURRENT_USER hive +#define SREG_ABSOLUTE 0x00000010 // specifies that the key is not a relative key + +BOOL STORMAPI STransBlt(void *lpSurface, int x, int y, int width, HANDLE hTrans); +BOOL STORMAPI STransBltUsingMask(void *lpDest, void *lpSource, int pitch, int width, HANDLE hTrans); + +BOOL STORMAPI STransDelete(HANDLE hTrans); + +BOOL STORMAPI STransDuplicate(HANDLE hTransSource, HANDLE hTransDest); +BOOL STORMAPI STransIntersectDirtyArray(HANDLE hTrans, char * dirtyarraymask, unsigned flags, HANDLE * phTransResult); +BOOL STORMAPI STransInvertMask(HANDLE hTrans, HANDLE * phTransResult); + +BOOL STORMAPI STransSetDirtyArrayInfo(int width, int height, int depth, int bits); + +BOOL STORMAPI STransPointInMask(HANDLE hTrans, int x, int y); // Name is a pure guess +BOOL STORMAPI STransCombineMasks(HANDLE hTransA, HANDLE hTransB, int left, int top, int flags, HANDLE * phTransResult); + +BOOL STORMAPI STransCreateE(void *pBuffer, int width, int height, int bpp, int a5, int bufferSize, HANDLE *phTransOut); + +BOOL STORMAPI SVidDestroy(); +BOOL STORMAPI SVidGetSize(HANDLE video, int width, int height, int zero); +BOOL STORMAPI SVidInitialize(HANDLE video); +BOOL STORMAPI SVidPlayBegin(char *filename, int arg4, int a3, int a4, int a5, int a6, HANDLE* video); + +BOOL STORMAPI SVidPlayContinueSingle(HANDLE video, int a2, int a3); +BOOL STORMAPI SVidPlayEnd(HANDLE video); + +/* SErrDisplayError @ 461 + * + * Displays a formatted error message. The message is detailed and flexible for many applications. + * The message will be different if there is a debugger attached. Will typically terminate the application + * unless the option to continue is given. + * + * dwErrMessage: The error code. See SErrGetLastError and GetLastError. + * logfilename: The name of the file or object that this call belongs to. + * logline: The line in the file or one of the SLOG_ macros. + * message: A message or expression with additional information. + * allowOption: If TRUE, allows the user the option to continue execution, otherwise the program will terminate. + * exitCode: The exit code used for program termination. + * + * Returns TRUE if the user chose to continue execution, FALSE otherwise. + */ +BOOL +STORMAPI +SErrDisplayError( + DWORD dwErrMsg, + const char *logfilename, + int logline, + const char *message = NULL, + BOOL allowOption = FALSE, + int exitCode = 1); + +#define SAssert(x) { if ( !(x) ) SErrDisplayError(STORM_ERROR_ASSERTION, __FILE__, __LINE__, #x) } + +#define SEDisplayError(err) SErrDisplayError(e, __FILE__, __LINE__) + +/* SErrGetErrorStr @ 462 + * + * Retrieves a string that describes the specified error code for + * the system, Storm, DirectDraw, or DirectSound. + * + * dwErrCode: The error code to look up. + * buffer: The destination buffer to receive the string. + * bufferchars: The size of the destination buffer. + * + * Returns TRUE if the call was successful and FALSE otherwise. + */ +BOOL +STORMAPI +SErrGetErrorStr( + DWORD dwErrCode, + char *buffer, + size_t bufferchars); + +#define SEGetErrorStr(e,b) SErrGetErrorStr(e,b,sizeof(b)) + + +/* SErrGetLastError @ 463 + * + * Retrieves the last error that was specifically + * set for the Storm library. + * + * Returns the last error set within the Storm library. + */ +DWORD +STORMAPI +SErrGetLastError(); + + +// Registers a module as a message source for SErrGetErrorStr, always returns TRUE +// groupID is a group in a MessageTable entry for example in STORM_ERROR_BAD_ARGUMENT 0x85100065, 0x510 is the group. +// BOOL STORMAPI SErrRegisterMessageSource(WORD groupID, HMODULE hSourceModule, int a3) + + +/* SErrSetLastError @ 465 + * + * Sets the last error for the Storm library and the Kernel32 library. + * + * dwErrCode: The error code that will be set. + */ +void +STORMAPI +SErrSetLastError( + DWORD dwErrCode = NO_ERROR); + +// +// void STORMAPI SErrReportNamedResourceLeak(const char *pszMsg, const char *pszSubMsg = nullptr) +// void STORMAPI SErrReportResourceLeak(const char *pszMsg) + +void STORMAPI SErrSuppressErrors(BOOL suppressErrors); + +// Values for dwErrCode +#define STORM_ERROR_ASSERTION 0x85100000 +#define STORM_ERROR_BAD_ARGUMENT 0x85100065 +#define STORM_ERROR_GAME_ALREADY_STARTED 0x85100066 +#define STORM_ERROR_GAME_FULL 0x85100067 +#define STORM_ERROR_GAME_NOT_FOUND 0x85100068 +#define STORM_ERROR_GAME_TERMINATED 0x85100069 +#define STORM_ERROR_INVALID_PLAYER 0x8510006a +#define STORM_ERROR_NO_MESSAGES_WAITING 0x8510006b +#define STORM_ERROR_NOT_ARCHIVE 0x8510006c +#define STORM_ERROR_NOT_ENOUGH_ARGUMENTS 0x8510006d +#define STORM_ERROR_NOT_IMPLEMENTED 0x8510006e +#define STORM_ERROR_NOT_IN_ARCHIVE 0x8510006f +#define STORM_ERROR_NOT_IN_GAME 0x85100070 +#define STORM_ERROR_NOT_INITIALIZED 0x85100071 +#define STORM_ERROR_NOT_PLAYING 0x85100072 +#define STORM_ERROR_NOT_REGISTERED 0x85100073 +#define STORM_ERROR_REQUIRES_CODEC1 0x85100074 +#define STORM_ERROR_REQUIRES_CODEC2 0x85100075 +#define STORM_ERROR_REQUIRES_CODEC3 0x85100076 +#define STORM_ERROR_REQUIRES_UPGRADE 0x85100077 +#define STORM_ERROR_STILL_ACTIVE 0x85100078 +#define STORM_ERROR_VERSION_MISMATCH 0x85100079 +#define STORM_ERROR_MEM_NOT_ALLOCATED 0x8510007a +#define STORM_ERROR_MEM_CORRUPTED 0x8510007b +#define STORM_ERROR_MEM_INVALID 0x8510007c +#define STORM_ERROR_MEM_MANAGER_NOT_INITIALIZED 0x8510007d +#define STORM_ERROR_MEM_NOT_FREED 0x8510007e +#define STORM_ERROR_RESOURCES_NOT_RELEASED 0x8510007f +#define STORM_ERROR_OUT_OF_BOUNDS 0x85100080 +#define STORM_ERROR_NULL_POINTER 0x85100081 +#define STORM_ERROR_CDKEY_MISMATCH 0x85100082 +#define STORM_ERROR_FILE_CORRUPTED 0x85100083 +#define STORM_ERROR_FATAL 0x85100084 +#define STORM_ERROR_GAMETYPE_UNAVAILABLE 0x85100085 + + +/* SMemCopy @ 491 + * + * Copies a block of memory from source to destination. + * This function immediately calls memcpy. See online documentation + * of memcpy for more details. + * + * dest: The destination buffer. + * source: The source buffer. + * size: The number of bytes to copy. + */ +void +STORMAPI +SMemCopy( + void *dest, + const void *source, + size_t size); + +#define SMCopy(d,s) ( SMemCopy(d, s, __STORM_SSIZEMIN(s,d)) ) + +/* SMemFill @ 492 + * + * Fills a block of memory with the specified character. + * This function immediately calls memset. See online documentation + * of memset for more details. + * + * dest: The destination buffer. + * source: The size of the destination buffer. + * size: The format to use. + */ +void +STORMAPI +SMemFill( + void *location, + size_t length, + char fillWith = 0); + +#define SMFill(l,f) (SMemFill(l, sizeof(l), f)) + +/* SMemZero @ 494 + * + * Fills a block of memory with the integer 0x00 (Zero). + * + * location: The location to write at. + * length: The amount of bytes to write. + */ +void +STORMAPI +SMemZero( + void *location, + size_t length); + +#define SMZero(l) (SMemZero(l, sizeof(l))) + + +int STORMAPI SMemCmp(void *location1, void *location2, DWORD size); + +#define SMCmp(l,x) ( SMemCmp(l, x, __STORM_SSIZEMIN(x,l)) ) + +/* SStrCopy @ 501 + * + * Copies a string from src to dest (including NULL terminator) + * until the max_length is reached. + * + * dest: The destination array. + * src: The source array. + * max_length: The maximum length of dest. + * + * Returns the number of characters copied. + */ +int +STORMAPI +SStrCopy( + char *dest, + const char *src, + int max_length = 0x7FFFFFFF); + +#define SSCopy(d,s) (SStrCopy(d, s, sizeof(d))) + +#define STORM_HASH_ABSOLUTE 1 + +/* SStrHash @ 502 + * + * Creates a simple hash for the string. This function + * should NOT be used for sensitive information. + * + * string: The input string. + * flags: If STORM_HASH_ABSOLUTE is set then this + function uses the absolute string, otherwise + it will convert backslashes to forward + slashes and some other processing. + * seed: The hash seed. If this value is 0 then the + * default value 0x7FED7FED will be used. + * + * Returns the 32-bit hash of the string. + */ +DWORD +STORMAPI +SStrHash( + const char *string, + DWORD flags = 0, + DWORD Seed = 0); + +int STORMAPI SStrNCat(char *dest, const char *src, DWORD max_length); + +/* SStrLen @ 506 + * + * Retrieves the length of a string. + * + * string: The input string of which to obtain a + * length for. + * + * Returns the length of the string. + */ +int +STORMAPI +SStrLen( + const char *string); + +/* SStrCmp @ 508 + * + * Compares two strings case sensitive. + * + * string1: The first string. + * string2: The second string. + * size: The maximum amount of characters to compare. + * + * Returns 0 if strings are equal. See strcmp documentation for more details. + */ +int +STORMAPI +SStrCmp( + const char *string1, + const char *string2, + size_t size); + +#define SSCmp(s,x) ( SStrCmp(s,x,__STORM_SSIZEMIN(s,x)) ) + +/* SStrCmpI @ 509 + * + * Compares two strings case insensitive. + * + * string1: The first string. + * string2: The second string. + * size: The maximum amount of characters to compare. + * + * Returns 0 if strings are equal. See strcmpi documentation for more details. + */ +int +STORMAPI +SStrCmpI( + const char *string1, + const char *string2, + size_t size); + +#define SSCmpI(s,x) ( SStrCmpI(s,x,__STORM_SSIZEMIN(s,x)) ) + +/* SStrUpper @ 510 + * + * Converts all lower-case alpha characters of a string to upper-case. + * + * string: The string to convert. + * + * Returns the same pointer given in the input. + */ +char* +STORMAPI +SStrUpper( + char* string); + +void STORMAPI SRgn523(HANDLE hRgn, RECT *pRect, int a3, int a4); +void STORMAPI SRgnCreateRegion(HANDLE *hRgn, int a2); +void STORMAPI SRgnDeleteRegion(HANDLE hRgn); + +void STORMAPI SRgn529i(int handle, int a2, int a3); + + +/* SErrDisplayErrorFmt @ 562 + * + * Displays a formatted error message. The message is detailed and flexible for many applications. + * The message will be different if there is a debugger attached. Will typically terminate the application + * unless the option to continue is given. + * + * dwErrMessage: The error code. See SErrGetLastError and GetLastError. + * logfilename: The name of the file or object that this call belongs to. + * logline: The line in the file or one of the SLOG_ macros. + * allowOption: If TRUE, allows the user the option to continue execution, otherwise the program will terminate. + * exitCode: The exit code used for program termination. + * format: Additional message formatting. See printf. + * + * Returns TRUE if the user chose to continue execution, FALSE otherwise. + */ +BOOL +SErrDisplayErrorFmt( + DWORD dwErrMsg, + const char *logfilename, + int logline, + BOOL allowOption, + int exitCode, + const char *format, + ...); + +//#define SEDisplayErrorFmt(err,...) SErrDisplayErrorFmt(err, __FILE__, __LINE__, FALSE, 1, __VA_ARGS__) + +/* SErrCatchUnhandledExceptions @ 567 + * + * Registers a top-level exception filter managed entirely by Storm. + * The registered filter will display formatted exception information by calling SErrDisplayError. + */ +void +STORMAPI +SErrCatchUnhandledExceptions(); + + +/* SStrChr @ 571 + * + * Searches a string for the given character. See + * strchr documentation for more details. + * + * string: The string to search. + * c: The character to search for. + * + * Returns a pointer to the first occurance of the character. + */ +char* +STORMAPI +SStrChr( + const char *string, + char c); + + +char *STORMAPI SStrChrR(const char *string, char c); + + +/* SStrVPrintf @ 578 + * + * Prints a formatted string to a destination buffer. + * This function calls vsnprintf with some extra error handling. + * See online documentation of vsnprintf for more details. + * + * dest: The destination buffer. + * size: The size of the destination buffer. + * format: The format to use. + * + * Returns the number of characters written. + */ +size_t +SStrVPrintf( + char *dest, + size_t size, + const char *format, ...); + + +int STORMAPI SBigDel(void *buffer); + +int STORMAPI SBigFromBinary(void *buffer, const void *str, size_t size); + +int STORMAPI SBigNew(void **buffer); + +int STORMAPI SBigPowMod(void *buffer1, void *buffer2, int a3, int a4); + +int STORMAPI SBigToBinaryBuffer(void *buffer, int length, int a3, int a4); + +void __stdcall SDrawMessageBox(char *,char *,int); +void __cdecl SDrawDestroy(void); +bool __cdecl StormDestroy(void); +bool __stdcall SFileSetBasePath(char *); +void __cdecl SDrawRealizePalette(void); +bool __cdecl SVidPlayContinue(void); +bool __stdcall SNetGetOwnerTurnsWaiting(int *); +void * __stdcall SNetUnregisterEventHandler(int,void (__stdcall*)(struct _SNETEVENT *)); +void * __stdcall SNetRegisterEventHandler(int,void (__stdcall*)(struct _SNETEVENT *)); +bool __stdcall SNetSetBasePlayer(int); +int __stdcall SNetInitializeProvider(unsigned long,struct _SNETPROGRAMDATA *,struct _SNETPLAYERDATA *,struct _SNETUIDATA *,struct _SNETVERSIONDATA *); +int __stdcall SNetGetProviderCaps(struct _SNETCAPS *); +int __stdcall SFileSetFilePointer(HANDLE,int,HANDLE,int); + +#ifdef __GNUC__ +} +#endif + +#endif diff --git a/3rdParty/Storm/Source/storm_gcc.def b/3rdParty/Storm/Source/storm_gcc.def new file mode 100644 index 000000000..d6b10a925 --- /dev/null +++ b/3rdParty/Storm/Source/storm_gcc.def @@ -0,0 +1,495 @@ +LIBRARY "Storm" + +EXPORTS + SNetCreateGame @101 NONAME + SNetCreateGame@40 @101 NONAME + SNetDestroy @102 NONAME + SNetDestroy@0 @102 NONAME + SNetEnumProviders @103 NONAME + ;SNetEnumDevices @104 NONAME + SNetEnumGames @105 NONAME + SNetDropPlayer @106 NONAME + SNetDropPlayer@8 @106 NONAME + SNetGetGameInfo @107 NONAME + SNetGetGameInfo@16 @107 NONAME + ;SNetGetNetworkLatency @108 NONAME + SNetGetNumPlayers @109 NONAME + SNetGetOwnerTurnsWaiting @110 NONAME + SNetGetOwnerTurnsWaiting@4 @110 NONAME + ;SNetGetPerformanceData @111 NONAME + SNetGetPlayerCaps @112 NONAME + SNetGetPlayerName @113 NONAME + SNetGetProviderCaps @114 NONAME + SNetGetProviderCaps@4 @114 NONAME + SNetGetTurnsInTransit @115 NONAME + SNetGetTurnsInTransit@4 @115 NONAME + SNetInitializeDevice @116 NONAME + SNetInitializeProvider @117 NONAME + SNetInitializeProvider@20 @117 NONAME + SNetJoinGame @118 NONAME + SNetLeaveGame @119 NONAME + SNetLeaveGame@4 @119 NONAME + SNetPerformUpgrade @120 NONAME + SNetPerformUpgrade@4 @120 NONAME + SNetReceiveMessage @121 NONAME + SNetReceiveMessage@12 @121 NONAME + SNetReceiveTurns @122 NONAME + SNetReceiveTurns@20 @122 NONAME + SNetRegisterEventHandler @123 NONAME + SNetRegisterEventHandler@8 @123 NONAME + ;SNetResetLatencyMeasurements @124 NONAME + SNetSelectGame @125 NONAME + ;SNetSelectProvider @126 NONAME + SNetSendMessage @127 NONAME + SNetSendMessage@12 @127 NONAME + SNetSendTurn @128 NONAME + SNetSendTurn@8 @128 NONAME + SNetSetBasePlayer @129 NONAME + SNetSetBasePlayer@4 @129 NONAME + SNetSetGameMode @130 NONAME + SNetUnregisterEventHandler @131 NONAME + SNetUnregisterEventHandler@8 @131 NONAME + + SNetEnumGamesEx @133 NONAME + SNetSendServerChatCommand @134 NONAME + SNetSendServerChatCommand@4 @134 NONAME + ;SNetSendDatagram @135 NONAME + ;SNetReceiveDatagram @136 NONAME + SNetDisconnectAll @137 NONAME + SNetCreateLadderGame @138 NONAME + SNetReportGameResult @139 NONAME + ;SNetCheckDataFile @140 NONAME + SNetSendLeagueCommand @141 NONAME + SNetSendReplayPath @142 NONAME + SNetGetLeagueName @143 NONAME + SNetGetPlayerNames @144 NONAME + SNetLeagueLogout @145 NONAME + SNetGetLeaguePlayerName @146 NONAME + + ;Ordinal150 @150 NONAME + ;Ordinal151 @151 NONAME + + ;SDlgBeginPaint @201 NONAME + ;SDlgBltToWindowI @202 NONAME + ;SDlgCheckTimers @203 NONAME + ;SDlgCreateDialogIndirectParam @204 NONAME + ;SDlgCreateDialogParam @205 NONAME + SDlgDefDialogProc @206 NONAME + + SDlgDialogBoxIndirectParam @208 NONAME + ;SDlgDialogBoxParam @209 NONAME + ;SDlgDrawBitmap @210 NONAME + SDlgEndDialog @211 NONAME + ;SDlgEndPaint @212 NONAME + ;SDlgKillTimer @213 NONAME + ;SDlgSetBaseFont @214 NONAME + ;SDlgSetBitmapI @215 NONAME + SDlgSetControlBitmaps @216 NONAME + ;SDlgSetCursor @217 NONAME + ;SDlgSetSystemCursor @218 NONAME + ;SDlgSetTimer @219 NONAME + ;SDlgUpdateCursor @220 NONAME + SDlgBltToWindowE @221 NONAME + SDlgSetBitmapE @222 NONAME + ;SDlgSetLocale @223 NONAME + Ordinal224 @224 NONAME + + ;SFileAuthenticateArchive @251 NONAME + SFileCloseArchive @252 NONAME + SFileCloseArchive@4 @252 NONAME + SFileCloseFile @253 NONAME + SFileCloseFile@4 @253 NONAME + ;SFileDdaBegin @254 NONAME + SFileDdaBeginEx @255 NONAME + SFileDdaBeginEx@28 @255 NONAME + SFileDdaDestroy @256 NONAME + SFileDdaDestroy@0 @256 NONAME + SFileDdaEnd @257 NONAME + SFileDdaEnd@4 @257 NONAME + SFileDdaGetPos @258 NONAME + SFileDdaGetPos@12 @258 NONAME + ;SFileDdaGetVolume @259 NONAME + SFileDdaInitialize @260 NONAME + SFileDdaInitialize@4 @260 NONAME + SFileDdaSetVolume @261 NONAME + SFileDdaSetVolume@12 @261 NONAME + SFileDestroy @262 NONAME + ;SFileEnableDirectAccess @263 NONAME + SFileGetFileArchive @264 NONAME + SFileGetFileArchive@8 @264 NONAME + SFileGetFileSize @265 NONAME + SFileGetFileSize@8 @265 NONAME + SFileOpenArchive @266 NONAME + SFileOpenArchive@16 @266 NONAME + SFileOpenFile @267 NONAME + SFileOpenFile@8 @267 NONAME + SFileOpenFileEx @268 NONAME + SFileOpenFileEx@16 @268 NONAME + SFileReadFile @269 NONAME + SFileReadFile@20 @269 NONAME + SFileSetBasePath @270 NONAME + SFileSetBasePath@4 @270 NONAME + SFileSetFilePointer @271 NONAME + SFileSetFilePointer@16 @271 NONAME + SFileSetLocale @272 NONAME + ;SFileGetBasePath @273 NONAME + SFileSetIoErrorMode @274 NONAME + SFileGetArchiveName @275 NONAME + SFileGetFileName @276 NONAME + ;SFileGetArchiveInfo @277 NONAME + ;SFileSetPlatform @278 NONAME + SFileLoadFile @279 NONAME + SFileUnloadFile @280 NONAME + SFileLoadFileEx @281 NONAME + ;SFilePrioritizeRequest @282 NONAME + ;SFileCancelRequest @283 NONAME + ;SFileSetAsyncBudget @284 NONAME + ;SFileSetDataChunkSize @285 NONAME + ;SFileEnableSeekOptimization @286 NONAME + ;SFileReadFileEx @287 NONAME + ;SFileFileExists @288 NONAME + ;SFileFileExistsEx @289 NONAME + ;SFileReadFileEx2 @290 NONAME + ;SFileReadFile2 @291 NONAME + ;SFileLoadFile2 @292 NONAME + ;SFileOpenFileAsArchive @293 NONAME + ;SFileGetLocale @294 NONAME + ;SFileRegisterLoadNotifyProc @295 NONAME + ;SFileGetFileCompressedSize @296 NONAME + ;Ordinal297 @297 NONAME + ;Ordinal298 @298 NONAME + ;SFileAuthenticateArchiveEx @299 NONAME + ;SFileOpenPathAsArchive @300 NONAME + StormDestroy @301 NONAME + ;StormGetInstance @302 NONAME + ;StormGetOption @303 NONAME + ;StormSetOption @304 NONAME + + ;SBltGetSCode @312 NONAME + SBltROP3 @313 NONAME + SBltROP3Clipped @314 NONAME + ;SBltROP3Tiled @315 NONAME + + SBmpDecodeImage @321 NONAME + + SBmpLoadImage @323 NONAME + SBmpSaveImage @324 NONAME + SBmpAllocLoadImage @325 NONAME + ;SBmpSaveImageEx @326 NONAME + + SCodeCompile @331 NONAME + SCodeDelete @332 NONAME + + SCodeExecute @334 NONAME + ;SCodeGetPseudocode @335 NONAME + + SDrawAutoInitialize @341 NONAME + SDrawCaptureScreen @342 NONAME + ;SDrawClearSurface @343 NONAME + SDrawDestroy @344 NONAME + ;SDrawFlipPage @345 NONAME + SDrawGetFrameWindow @346 NONAME + SDrawGetFrameWindow@4 @346 NONAME + SDrawGetObjects @347 NONAME + SDrawGetScreenSize @348 NONAME + ;SDrawGetServiceLevel @349 NONAME + SDrawLockSurface @350 NONAME + SDrawManualInitialize @351 NONAME + SDrawManualInitialize@32 @351 NONAME + SDrawMessageBox @352 NONAME + SDrawMessageBox@12 @352 NONAME + SDrawPostClose @353 NONAME + SDrawRealizePalette @354 NONAME + ;SDrawSelectGdiSurface @355 NONAME + SDrawUnlockSurface @356 NONAME + SDrawUpdatePalette @357 NONAME + SDrawUpdatePalette@16 @357 NONAME + ;SDrawUpdateScreen @358 NONAME + ;SDrawWaitForVerticalBlank @359 NONAME + + SEvtDispatch @372 NONAME + ;SEvtRegisterHandler @373 NONAME + ;SEvtUnregisterHandler @374 NONAME + ;SEvtUnregisterType @375 NONAME + ;SEvtPopState @376 NONAME + ;SEvtPushState @377 NONAME + ;SEvtBreakHandlerChain @378 NONAME + + ;SGdiBitBlt @381 NONAME + ;SGdiCreateFont @382 NONAME + SGdiDeleteObject @383 NONAME + ;SGdiDestroy @384 NONAME + SGdiExtTextOut @385 NONAME + SGdiImportFont @386 NONAME + ;SGdiLoadFont @387 NONAME + ;SGdiRectangle @388 NONAME + SGdiSelectObject @389 NONAME + SGdiSetPitch @390 NONAME + ;SGdiTextOut @391 NONAME + ;SGdi392 @392 NONAME + Ordinal393 @393 NONAME + + ;SMem399 @399 NONAME + + SMemAlloc @401 NONAME + SMemAlloc@16 @401 NONAME + ;SMemDestroy @402 NONAME + SMemFree @403 NONAME + SMemFree@16 @403 NONAME + ;SMemGetSize @404 NONAME + SMemReAlloc @405 NONAME + ;Storm406 @406 NONAME + + ;SMsgDispatchMessage @412 NONAME + ;SMsgDoMessageLoop @413 NONAME + ;SMsgRegisterCommand @414 NONAME + ;SMsgRegisterKeyDown @415 NONAME + ;SMsgRegisterKeyUp @416 NONAME + ;SMsgRegisterMessage @417 NONAME + ;SMsgPopRegisterState @418 NONAME + ;SMsgPushRegisterState @419 NONAME + ;SMsg420 @420 NONAME + SRegLoadData @421 NONAME + SRegLoadData@24 @421 NONAME + SRegLoadString @422 NONAME + SRegLoadString@20 @422 NONAME + SRegLoadValue @423 NONAME + SRegLoadValue@16 @423 NONAME + SRegSaveData @424 NONAME + SRegSaveData@20 @424 NONAME + SRegSaveString @425 NONAME + SRegSaveString@16 @425 NONAME + SRegSaveValue @426 NONAME + SRegSaveValue@16 @426 NONAME + ;SRegGetBaseKey @427 NONAME + SRegDeleteValue @428 NONAME + ;SReg429 @429 NONAME + ;SReg430 @430 NONAME + STransBlt @431 NONAME + STransBltUsingMask @432 NONAME + ;STransCreateI @433 NONAME + STransDelete @434 NONAME + + STransDuplicate @436 NONAME + STransIntersectDirtyArray @437 NONAME + STransInvertMask @438 NONAME + ;STransLoadI @439 NONAME + STransSetDirtyArrayInfo @440 NONAME + ;STransUpdateDirtyArray @441 NONAME + STransPointInMask @442 NONAME + STransCombineMasks @443 NONAME + ;STransCreateI @444 NONAME + STransCreateE @445 NONAME + ;STrans446 @446 NONAME + ;STransLoadE @447 NONAME + + SVidDestroy @451 NONAME + SVidDestroy@0 @451 NONAME + SVidGetSize @452 NONAME + SVidInitialize @453 NONAME + SVidInitialize@4 @453 NONAME + SVidPlayBegin @454 NONAME + SVidPlayBegin@28 @454 NONAME + ;SVidPlayBeginFromMemory @455 NONAME + SVidPlayContinue @456 NONAME + SVidPlayContinueSingle @457 NONAME + SVidPlayEnd @458 NONAME + SVidPlayEnd@4 @458 NONAME + ;SVidSetVolume @459 NONAME + ;Storm460 @460 NONAME + SErrDisplayError @461 NONAME + SErrGetErrorStr @462 NONAME + SErrGetErrorStr@12 @462 NONAME + SErrGetLastError @463 NONAME + SErrGetLastError@0 @463 NONAME + ;SErrRegisterMessageSource @464 NONAME + SErrSetLastError @465 NONAME + SErrSetLastError@4 @465 NONAME + ;SErrReportNamedResourceLeak @466 NONAME + ;SErrReportResourceLeak @467 NONAME + SErrSuppressErrors @468 NONAME + ;SErrRegisterHandler @469 NONAME + ;SErrUnregisterHandler @470 NONAME + ;Storm471 @471 NONAME + ;SCmdGetBool @472 NONAME + ;SCmdGetNum @473 NONAME + ;SCmdGetString @474 NONAME + ;SCmdProcess @475 NONAME + ;SCmdRegisterArgList @476 NONAME + ;SCmdRegisterArgument @477 NONAME + ;SCmdStringExists @478 NONAME + ;SCmdProcessCommandLine @479 NONAME + ;Ordinal480 @480 NONAME + ;SMemFindNextBlock @481 NONAME + ;SMemFindNextHeap @482 NONAME + ;SMemGetHeapByCaller @483 NONAME + ;SMemGetHeapByPtr @484 NONAME + ;SMemHeapAlloc @485 NONAME + ;SMemHeapCreate @486 NONAME + ;SMemHeapDestroy @487 NONAME + ;SMemHeapFree @488 NONAME + ;SMemHeapRealloc @489 NONAME + ;SMemHeapSize @490 NONAME + SMemCopy @491 NONAME + SMemFill @492 NONAME + ;SMemMove @493 NONAME + SMemZero @494 NONAME + SMemCmp @495 NONAME + ;SMem496 @496 NONAME + ;SMemDumpState @497 NONAME + ;Ordinal498 @498 NONAME + + SStrCopy @501 NONAME + SStrCopy@12 @501 NONAME + SStrHash @502 NONAME + SStrNCat @503 NONAME + ;SStrTokenize @504 NONAME + ;SStrPack @505 NONAME + SStrLen @506 NONAME + ;SStrDup @507 NONAME + SStrCmp @508 NONAME + SStrCmpI @509 NONAME + SStrUpper @510 NONAME + ;SMsgBreakHandlerChain @511 NONAME + ;SMsgUnregisterCommand @512 NONAME + ;SMsgUnregisterKeyDown @513 NONAME + ;SMsgUnregisterKeyUp @514 NONAME + ;SMsgUnregisterMessage @515 NONAME + ;SMsgGetDispatcher @516 NONAME + ;SMsgSetDefaultWindow @517 NONAME + ;SMsgGetDefaultWindow @518 NONAME + ;SMsg519 @519 NONAME + + ;SRgn521 @521 NONAME + + SRgn523 @523 NONAME + SRgnCreateRegion @524 NONAME + SRgnDeleteRegion @525 NONAME + + ;SRgn527 @527 NONAME + ;SRgn528i @528 NONAME + SRgn529i @529 NONAME + ;SRgn530i @530 NONAME + ;SRgn531i @531 NONAME + ;SRgn532i @532 NONAME + ;SRgn533i @533 NONAME + ;SRgn534 @534 NONAME + ;SRgn535f @535 NONAME + ;SRgn536f @536 NONAME + ;SRgn537f @537 NONAME + ;SRgn538f @538 NONAME + ;SRgn539f @539 NONAME + ;SRgn540f @540 NONAME + ;SLogClose @541 NONAME + ;SLogCreate @542 NONAME + ;SLog543 @543 NONAME + ;SLogDump @544 NONAME + ;SLogFlush @545 NONAME + ;SLogFlushAll @546 NONAME + ;SLogPend @547 NONAME + ;SLogWrite @548 NONAME + ;SLog549 @549 NONAME + ;SLogCriticalLog @550 NONAME + ;SCompCompress @551 NONAME + ;SCompDecompress @552 NONAME + ;SLogVWrite @553 NONAME + ;Ordinal554 @554 NONAME + ;Ordinal555 @555 NONAME + ;Ordinal556 @556 NONAME + ;Ordinal557 @557 NONAME + ;Ordinal558 @558 NONAME + ;Ordinal559 @559 NONAME + ;Ordinal560 @560 NONAME + ;SErrCheckDebugSymbolLibrary @561 NONAME + SErrDisplayErrorFmt @562 NONAME + ;SErrIsDisplayingError @563 NONAME + ;SErrPrepareAppFatal @564 NONAME + ;SErrSetLogTitleString @565 NONAME + ;SErrDisplayAppFatal @566 NONAME + SErrCatchUnhandledExceptions @567 NONAME + ;Storm568 @568 NONAME + ;SStrChr @569 NONAME + ;SStrChrR @570 NONAME + SStrChr @571 NONAME + SStrChrR @572 NONAME + ;SStrToDouble @573 NONAME + ;SStrToFloat @574 NONAME + ;SStrToInt @575 NONAME + ;SStrToUnsigned @576 NONAME + ;SStrToInt64 @577 NONAME + SStrVPrintf @578 NONAME + ;SStrLower @579 NONAME + ;SStrHash64 @580 NONAME + ;SStrPrintf @581 NONAME + ;SDrawSetClientRect @582 NONAME + ;SDrawGetClientRect @583 NONAME + ;SStrStrI @584 NONAME + ;SStrStrI @585 NONAME + ;SStrStr @586 NONAME + ;SStrStr @587 NONAME + ;SNet588 @588 NONAME + + ;SBigAdd @601 NONAME + ;SBigAnd @602 NONAME + ;SBigCompare @603 NONAME + ;SBigCopy @604 NONAME + ;SBigDec @605 NONAME + SBigDel @606 NONAME + ;SBigDiv @607 NONAME + ;SBigFindPrime @608 NONAME + SBigFromBinary @609 NONAME + ;SBigFromStr @610 NONAME + ;SBigFromStream @611 NONAME + ;SBigFromUnsigned @612 NONAME + ;SBigGcd @613 NONAME + ;SBigInc @614 NONAME + ;SBigInvMod @615 NONAME + ;SBigIsEven @616 NONAME + ;SBigIsOdd @617 NONAME + ;SBigIsOne @618 NONAME + ;SBigIsPrime @619 NONAME + ;SBigIsZero @620 NONAME + ;SBigMod @621 NONAME + ;SBigMul @622 NONAME + ;SBigMulMod @623 NONAME + SBigNew @624 NONAME + ;SBigNot @625 NONAME + ;SBigOr @626 NONAME + ;SBigPow @627 NONAME + SBigPowMod @628 NONAME + ;SBigRand @629 NONAME + ;SBigSet2Exp @630 NONAME + ;SBigSetOne @631 NONAME + ;SBigSetZero @632 NONAME + ;SBigShl @633 NONAME + ;SBigShr @634 NONAME + ;SBigSquare @635 NONAME + ;SBigSub @636 NONAME + ;SBigToBinaryArray @637 NONAME + SBigToBinaryBuffer @638 NONAME + ;SBigToBinaryPtr @639 NONAME + ;SBigToStrArray @640 NONAME + ;SBigToStrBuffer @641 NONAME + ;SBigToStrPtr @642 NONAME + ;SBigToStreamArray @643 NONAME + ;SBigToStreamBuffer @644 NONAME + ;SBigToStreamPtr @645 NONAME + ;SBigToUnsigned @646 NONAME + ;SBigXor @647 NONAME + + ;SUniConvertUTF16to8Len @901 NONAME + ;SUniConvertUTF16to8 @902 NONAME + ;SUniConvertUTF8to16Len @903 NONAME + ;SUniConvertUTF8to16 @904 NONAME + ;SUniS905 @905 NONAME + ;SUniS906 @906 NONAME + ;SUniFindAfterUTF8Chr @907 NONAME + ;SUniFindUTF8ChrStart @908 NONAME + ;SUniConvertUTF16To909 @909 NONAME + ;SUniConvertUTF16To910 @910 NONAME + ;SUniConvertUTF16To911 @911 NONAME + ;SUniConvert912 @912 NONAME + ;SUniConvert913 @913 NONAME + ;SUniConvert914 @914 NONAME + ;SUniConvertUTF8ToWin @915 NONAME +; END diff --git a/3rdParty/StormLib/LICENSE b/3rdParty/StormLib/LICENSE new file mode 100644 index 000000000..2cb432d4e --- /dev/null +++ b/3rdParty/StormLib/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 1999-2013 Ladislav Zezula + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/3rdParty/StormLib/src/FileStream.cpp b/3rdParty/StormLib/src/FileStream.cpp new file mode 100644 index 000000000..a65ea339f --- /dev/null +++ b/3rdParty/StormLib/src/FileStream.cpp @@ -0,0 +1,2830 @@ +/*****************************************************************************/ +/* FileStream.cpp Copyright (c) Ladislav Zezula 2010 */ +/*---------------------------------------------------------------------------*/ +/* File stream support for StormLib */ +/* */ +/* Windows support: Written by Ladislav Zezula */ +/* Mac support: Written by Sam Wilkins */ +/* Linux support: Written by Sam Wilkins and Ivan Komissarov */ +/* Big-endian: Written & debugged by Sam Wilkins */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 11.06.10 1.00 Lad Derived from StormPortMac.cpp and StormPortLinux.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" +#include "FileStream.h" + +#ifdef _MSC_VER +#pragma comment(lib, "wininet.lib") // Internet functions for HTTP stream +#pragma warning(disable: 4800) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) +#endif + +//----------------------------------------------------------------------------- +// Local defines + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE ((HANDLE)-1) +#endif + +//----------------------------------------------------------------------------- +// Local functions - platform-specific functions + +#ifdef FULL +#ifndef PLATFORM_WINDOWS +static DWORD nLastError = ERROR_SUCCESS; + +DWORD GetLastError() +{ + return nLastError; +} + +void SetLastError(DWORD nError) +{ + nLastError = nError; +} +#endif +#endif + +static DWORD StringToInt(const char * szString) +{ + DWORD dwValue = 0; + + while('0' <= szString[0] && szString[0] <= '9') + { + dwValue = (dwValue * 10) + (szString[0] - '9'); + szString++; + } + + return dwValue; +} + +//----------------------------------------------------------------------------- +// Dummy init function + +static void BaseNone_Init(TFileStream *) +{ + // Nothing here +} + +//----------------------------------------------------------------------------- +// Local functions - base file support + +static bool BaseFile_Create(TFileStream * pStream) +{ +#ifdef PLATFORM_WINDOWS + { + DWORD dwWriteShare = (pStream->dwFlags & STREAM_FLAG_WRITE_SHARE) ? FILE_SHARE_WRITE : 0; + + pStream->Base.File.hFile = CreateFile(pStream->szFileName, + GENERIC_READ | GENERIC_WRITE, + dwWriteShare | FILE_SHARE_READ, + NULL, + CREATE_ALWAYS, + 0, + NULL); + if(pStream->Base.File.hFile == INVALID_HANDLE_VALUE) + return false; + } +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + { + intptr_t handle; + + handle = open(pStream->szFileName, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if(handle == -1) + { + nLastError = errno; + return false; + } + + pStream->Base.File.hFile = (HANDLE)handle; + } +#endif + + // Reset the file size and position + pStream->Base.File.FileSize = 0; + pStream->Base.File.FilePos = 0; + return true; +} + +static bool BaseFile_Open(TFileStream * pStream, const TCHAR * szFileName, DWORD dwStreamFlags) +{ +#ifdef PLATFORM_WINDOWS + { + ULARGE_INTEGER FileSize; + DWORD dwWriteAccess = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? 0 : FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES; + DWORD dwWriteShare = (dwStreamFlags & STREAM_FLAG_WRITE_SHARE) ? FILE_SHARE_WRITE : 0; + + // Open the file + pStream->Base.File.hFile = CreateFile(szFileName, + FILE_READ_DATA | FILE_READ_ATTRIBUTES | dwWriteAccess, + FILE_SHARE_READ | dwWriteShare, + NULL, + OPEN_EXISTING, + 0, + NULL); + if(pStream->Base.File.hFile == INVALID_HANDLE_VALUE) + return false; + + // Query the file size + FileSize.LowPart = GetFileSize(pStream->Base.File.hFile, &FileSize.HighPart); + pStream->Base.File.FileSize = FileSize.QuadPart; + + // Query last write time + GetFileTime(pStream->Base.File.hFile, NULL, NULL, (LPFILETIME)&pStream->Base.File.FileTime); + } +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + { + struct stat64 fileinfo; + int oflag = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? O_RDONLY : O_RDWR; + intptr_t handle; + + // Open the file + handle = open(szFileName, oflag | O_LARGEFILE); + if(handle == -1) + { + nLastError = errno; + return false; + } + + // Get the file size + if(fstat64(handle, &fileinfo) == -1) + { + nLastError = errno; + close(handle); + return false; + } + + // time_t is number of seconds since 1.1.1970, UTC. + // 1 second = 10000000 (decimal) in FILETIME + // Set the start to 1.1.1970 00:00:00 + pStream->Base.File.FileTime = 0x019DB1DED53E8000ULL + (10000000 * fileinfo.st_mtime); + pStream->Base.File.FileSize = (ULONGLONG)fileinfo.st_size; + pStream->Base.File.hFile = (HANDLE)handle; + } +#endif + + // Reset the file position + pStream->Base.File.FilePos = 0; + return true; +} + +static bool BaseFile_Read( + TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position + void * pvBuffer, // Pointer to data to be read + DWORD dwBytesToRead) // Number of bytes to read from the file +{ + ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.File.FilePos; + DWORD dwBytesRead = 0; // Must be set by platform-specific code + +#ifdef PLATFORM_WINDOWS + { + // Note: StormLib no longer supports Windows 9x. + // Thus, we can use the OVERLAPPED structure to specify + // file offset to read from file. This allows us to skip + // one system call to SetFilePointer + + // Update the byte offset + pStream->Base.File.FilePos = ByteOffset; + + // Read the data + if(dwBytesToRead != 0) + { + OVERLAPPED Overlapped; + + Overlapped.OffsetHigh = (DWORD)(ByteOffset >> 32); + Overlapped.Offset = (DWORD)ByteOffset; + Overlapped.hEvent = NULL; + if(!ReadFile(pStream->Base.File.hFile, pvBuffer, dwBytesToRead, &dwBytesRead, &Overlapped)) + return false; + } + } +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + { + ssize_t bytes_read; + + // If the byte offset is different from the current file position, + // we have to update the file position xxx + if(ByteOffset != pStream->Base.File.FilePos) + { + lseek64((intptr_t)pStream->Base.File.hFile, (off64_t)(ByteOffset), SEEK_SET); + pStream->Base.File.FilePos = ByteOffset; + } + + // Perform the read operation + if(dwBytesToRead != 0) + { + bytes_read = read((intptr_t)pStream->Base.File.hFile, pvBuffer, (size_t)dwBytesToRead); + if(bytes_read == -1) + { + nLastError = errno; + return false; + } + + dwBytesRead = (DWORD)(size_t)bytes_read; + } + } +#endif + + // Increment the current file position by number of bytes read + // If the number of bytes read doesn't match to required amount, return false + pStream->Base.File.FilePos = ByteOffset + dwBytesRead; + if(dwBytesRead != dwBytesToRead) + SetLastError(ERROR_HANDLE_EOF); + return (dwBytesRead == dwBytesToRead); +} + +/** + * \a pStream Pointer to an open stream + * \a pByteOffset Pointer to file byte offset. If NULL, writes to current position + * \a pvBuffer Pointer to data to be written + * \a dwBytesToWrite Number of bytes to write to the file + */ + +static bool BaseFile_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite) +{ + ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.File.FilePos; + DWORD dwBytesWritten = 0; // Must be set by platform-specific code + +#ifdef PLATFORM_WINDOWS + { + // Note: StormLib no longer supports Windows 9x. + // Thus, we can use the OVERLAPPED structure to specify + // file offset to read from file. This allows us to skip + // one system call to SetFilePointer + + // Update the byte offset + pStream->Base.File.FilePos = ByteOffset; + + // Read the data + if(dwBytesToWrite != 0) + { + OVERLAPPED Overlapped; + + Overlapped.OffsetHigh = (DWORD)(ByteOffset >> 32); + Overlapped.Offset = (DWORD)ByteOffset; + Overlapped.hEvent = NULL; + if(!WriteFile(pStream->Base.File.hFile, pvBuffer, dwBytesToWrite, &dwBytesWritten, &Overlapped)) + return false; + } + } +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + { + ssize_t bytes_written; + + // If the byte offset is different from the current file position, + // we have to update the file position + if(ByteOffset != pStream->Base.File.FilePos) + { + lseek64((intptr_t)pStream->Base.File.hFile, (off64_t)(ByteOffset), SEEK_SET); + pStream->Base.File.FilePos = ByteOffset; + } + + // Perform the read operation + bytes_written = write((intptr_t)pStream->Base.File.hFile, pvBuffer, (size_t)dwBytesToWrite); + if(bytes_written == -1) + { + nLastError = errno; + return false; + } + + dwBytesWritten = (DWORD)(size_t)bytes_written; + } +#endif + + // Increment the current file position by number of bytes read + pStream->Base.File.FilePos = ByteOffset + dwBytesWritten; + + // Also modify the file size, if needed + if(pStream->Base.File.FilePos > pStream->Base.File.FileSize) + pStream->Base.File.FileSize = pStream->Base.File.FilePos; + + if(dwBytesWritten != dwBytesToWrite) + SetLastError(ERROR_DISK_FULL); + return (dwBytesWritten == dwBytesToWrite); +} + +/** + * \a pStream Pointer to an open stream + * \a NewFileSize New size of the file + */ +static bool BaseFile_Resize(TFileStream * pStream, ULONGLONG NewFileSize) +{ +#ifdef PLATFORM_WINDOWS + { + LONG FileSizeHi = (LONG)(NewFileSize >> 32); + LONG FileSizeLo; + DWORD dwNewPos; + bool bResult; + + // Set the position at the new file size + dwNewPos = SetFilePointer(pStream->Base.File.hFile, (LONG)NewFileSize, &FileSizeHi, FILE_BEGIN); + if(dwNewPos == INVALID_SET_FILE_POINTER && GetLastError() != ERROR_SUCCESS) + return false; + + // Set the current file pointer as the end of the file + bResult = (bool)SetEndOfFile(pStream->Base.File.hFile); + if(bResult) + pStream->Base.File.FileSize = NewFileSize; + + // Restore the file position + FileSizeHi = (LONG)(pStream->Base.File.FilePos >> 32); + FileSizeLo = (LONG)(pStream->Base.File.FilePos); + SetFilePointer(pStream->Base.File.hFile, FileSizeLo, &FileSizeHi, FILE_BEGIN); + return bResult; + } +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + { + if(ftruncate64((intptr_t)pStream->Base.File.hFile, (off64_t)NewFileSize) == -1) + { + nLastError = errno; + return false; + } + + pStream->Base.File.FileSize = NewFileSize; + return true; + } +#endif +} + +// Gives the current file size +static bool BaseFile_GetSize(TFileStream * pStream, ULONGLONG * pFileSize) +{ + // Note: Used by all thre base providers. + // Requires the TBaseData union to have the same layout for all three base providers + *pFileSize = pStream->Base.File.FileSize; + return true; +} + +// Gives the current file position +static bool BaseFile_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset) +{ + // Note: Used by all thre base providers. + // Requires the TBaseData union to have the same layout for all three base providers + *pByteOffset = pStream->Base.File.FilePos; + return true; +} + +// Renames the file pointed by pStream so that it contains data from pNewStream +static bool BaseFile_Replace(TFileStream * pStream, TFileStream * pNewStream) +{ +#ifdef PLATFORM_WINDOWS + // Delete the original stream file. Don't check the result value, + // because if the file doesn't exist, it would fail + DeleteFile(pStream->szFileName); + + // Rename the new file to the old stream's file + return (bool)MoveFile(pNewStream->szFileName, pStream->szFileName); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + // "rename" on Linux also works if the target file exists + if(rename(pNewStream->szFileName, pStream->szFileName) == -1) + { + nLastError = errno; + return false; + } + + return true; +#endif +} + +static void BaseFile_Close(TFileStream * pStream) +{ + if(pStream->Base.File.hFile != INVALID_HANDLE_VALUE) + { +#ifdef PLATFORM_WINDOWS + CloseHandle(pStream->Base.File.hFile); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + close((intptr_t)pStream->Base.File.hFile); +#endif + } + + // Also invalidate the handle + pStream->Base.File.hFile = INVALID_HANDLE_VALUE; +} + +// Initializes base functions for the disk file +static void BaseFile_Init(TFileStream * pStream) +{ + pStream->BaseCreate = BaseFile_Create; + pStream->BaseOpen = BaseFile_Open; + pStream->BaseRead = BaseFile_Read; + pStream->BaseWrite = BaseFile_Write; + pStream->BaseResize = BaseFile_Resize; + pStream->BaseGetSize = BaseFile_GetSize; + pStream->BaseGetPos = BaseFile_GetPos; + pStream->BaseClose = BaseFile_Close; +} + +//----------------------------------------------------------------------------- +// Local functions - base memory-mapped file support + +static bool BaseMap_Open(TFileStream * pStream, const TCHAR * szFileName, DWORD dwStreamFlags) +{ +#ifdef PLATFORM_WINDOWS + + ULARGE_INTEGER FileSize; + HANDLE hFile; + HANDLE hMap; + bool bResult = false; + + // Keep compiler happy + dwStreamFlags = dwStreamFlags; + + // Open the file for read access + hFile = CreateFile(szFileName, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + // Retrieve file size. Don't allow mapping file of a zero size. + FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart); + if(FileSize.QuadPart != 0) + { + // Now create mapping object + hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if(hMap != NULL) + { + // Map the entire view into memory + // Note that this operation will fail if the file can't fit + // into usermode address space + pStream->Base.Map.pbFile = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); + if(pStream->Base.Map.pbFile != NULL) + { + // Retrieve file time + GetFileTime(hFile, NULL, NULL, (LPFILETIME)&pStream->Base.Map.FileTime); + + // Retrieve file size and position + pStream->Base.Map.FileSize = FileSize.QuadPart; + pStream->Base.Map.FilePos = 0; + bResult = true; + } + + // Close the map handle + CloseHandle(hMap); + } + } + + // Close the file handle + CloseHandle(hFile); + } + + // If the file is not there and is not available for random access, + // report error + if(bResult == false) + return false; +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + struct stat64 fileinfo; + intptr_t handle; + bool bResult = false; + + // Open the file + handle = open(szFileName, O_RDONLY); + if(handle != -1) + { + // Get the file size + if(fstat64(handle, &fileinfo) != -1) + { + pStream->Base.Map.pbFile = (LPBYTE)mmap(NULL, (size_t)fileinfo.st_size, PROT_READ, MAP_PRIVATE, handle, 0); + if(pStream->Base.Map.pbFile != NULL) + { + // time_t is number of seconds since 1.1.1970, UTC. + // 1 second = 10000000 (decimal) in FILETIME + // Set the start to 1.1.1970 00:00:00 + pStream->Base.Map.FileTime = 0x019DB1DED53E8000ULL + (10000000 * fileinfo.st_mtime); + pStream->Base.Map.FileSize = (ULONGLONG)fileinfo.st_size; + pStream->Base.Map.FilePos = 0; + bResult = true; + } + } + close(handle); + } + + // Did the mapping fail? + if(bResult == false) + { + nLastError = errno; + return false; + } +#endif + + return true; +} + +static bool BaseMap_Read( + TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position + void * pvBuffer, // Pointer to data to be read + DWORD dwBytesToRead) // Number of bytes to read from the file +{ + ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.Map.FilePos; + + // Do we have to read anything at all? + if(dwBytesToRead != 0) + { + // Don't allow reading past file size + if((ByteOffset + dwBytesToRead) > pStream->Base.Map.FileSize) + return false; + + // Copy the required data + memcpy(pvBuffer, pStream->Base.Map.pbFile + (size_t)ByteOffset, dwBytesToRead); + } + + // Move the current file position + pStream->Base.Map.FilePos += dwBytesToRead; + return true; +} + +static void BaseMap_Close(TFileStream * pStream) +{ +#ifdef PLATFORM_WINDOWS + if(pStream->Base.Map.pbFile != NULL) + UnmapViewOfFile(pStream->Base.Map.pbFile); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + if(pStream->Base.Map.pbFile != NULL) + munmap(pStream->Base.Map.pbFile, (size_t )pStream->Base.Map.FileSize); +#endif + + pStream->Base.Map.pbFile = NULL; +} + +// Initializes base functions for the mapped file +static void BaseMap_Init(TFileStream * pStream) +{ + // Supply the file stream functions + pStream->BaseOpen = BaseMap_Open; + pStream->BaseRead = BaseMap_Read; + pStream->BaseGetSize = BaseFile_GetSize; // Reuse BaseFile function + pStream->BaseGetPos = BaseFile_GetPos; // Reuse BaseFile function + pStream->BaseClose = BaseMap_Close; + + // Mapped files are read-only + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; +} + +//----------------------------------------------------------------------------- +// Local functions - base HTTP file support + +static const TCHAR * BaseHttp_ExtractServerName(const TCHAR * szFileName, TCHAR * szServerName) +{ + // Check for HTTP + if(!_tcsnicmp(szFileName, _T("http://"), 7)) + szFileName += 7; + + // Cut off the server name + if(szServerName != NULL) + { + while(szFileName[0] != 0 && szFileName[0] != _T('/')) + *szServerName++ = *szFileName++; + *szServerName = 0; + } + else + { + while(szFileName[0] != 0 && szFileName[0] != _T('/')) + szFileName++; + } + + // Return the remainder + return szFileName; +} + +static bool BaseHttp_Open(TFileStream * pStream, const TCHAR * szFileName, DWORD dwStreamFlags) +{ +#ifdef PLATFORM_WINDOWS + + HINTERNET hRequest; + DWORD dwTemp = 0; + + // Keep compiler happy + dwStreamFlags = dwStreamFlags; + + // Don't connect to the internet + if(!InternetGetConnectedState(&dwTemp, 0)) + return false; + + // Initiate the connection to the internet + pStream->Base.Http.hInternet = InternetOpen(_T("StormLib HTTP MPQ reader"), + INTERNET_OPEN_TYPE_PRECONFIG, + NULL, + NULL, + 0); + if(pStream->Base.Http.hInternet != NULL) + { + TCHAR szServerName[MAX_PATH]; + DWORD dwFlags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_UI | INTERNET_FLAG_NO_CACHE_WRITE; + + // Initiate connection with the server + szFileName = BaseHttp_ExtractServerName(szFileName, szServerName); + pStream->Base.Http.hConnect = InternetConnect(pStream->Base.Http.hInternet, + szServerName, + INTERNET_DEFAULT_HTTP_PORT, + NULL, + NULL, + INTERNET_SERVICE_HTTP, + dwFlags, + 0); + if(pStream->Base.Http.hConnect != NULL) + { + // Open HTTP request to the file + hRequest = HttpOpenRequest(pStream->Base.Http.hConnect, _T("GET"), szFileName, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0); + if(hRequest != NULL) + { + if(HttpSendRequest(hRequest, NULL, 0, NULL, 0)) + { + ULONGLONG FileTime = 0; + DWORD dwFileSize = 0; + DWORD dwDataSize; + DWORD dwIndex = 0; + + // Check if the MPQ has Last Modified field + dwDataSize = sizeof(ULONGLONG); + if(HttpQueryInfo(hRequest, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME, &FileTime, &dwDataSize, &dwIndex)) + pStream->Base.Http.FileTime = FileTime; + + // Verify if the server supports random access + dwDataSize = sizeof(DWORD); + if(HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwFileSize, &dwDataSize, &dwIndex)) + { + if(dwFileSize != 0) + { + InternetCloseHandle(hRequest); + pStream->Base.Http.FileSize = dwFileSize; + pStream->Base.Http.FilePos = 0; + return true; + } + } + } + + // Close the request + InternetCloseHandle(hRequest); + } + + // Close the connection handle + InternetCloseHandle(pStream->Base.Http.hConnect); + pStream->Base.Http.hConnect = NULL; + } + + // Close the internet handle + InternetCloseHandle(pStream->Base.Http.hInternet); + pStream->Base.Http.hInternet = NULL; + } + + // If the file is not there or is not available for random access, report error + pStream->BaseClose(pStream); + return false; + +#else + + // Not supported + SetLastError(ERROR_NOT_SUPPORTED); + pStream = pStream; + return false; + +#endif +} + +static bool BaseHttp_Read( + TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position + void * pvBuffer, // Pointer to data to be read + DWORD dwBytesToRead) // Number of bytes to read from the file +{ +#ifdef PLATFORM_WINDOWS + ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.Http.FilePos; + DWORD dwTotalBytesRead = 0; + + // Do we have to read anything at all? + if(dwBytesToRead != 0) + { + HINTERNET hRequest; + LPCTSTR szFileName; + LPBYTE pbBuffer = (LPBYTE)pvBuffer; + TCHAR szRangeRequest[0x80]; + DWORD dwStartOffset = (DWORD)ByteOffset; + DWORD dwEndOffset = dwStartOffset + dwBytesToRead; + + // Open HTTP request to the file + szFileName = BaseHttp_ExtractServerName(pStream->szFileName, NULL); + hRequest = HttpOpenRequest(pStream->Base.Http.hConnect, _T("GET"), szFileName, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0); + if(hRequest != NULL) + { + // Add range request to the HTTP headers + // http://www.clevercomponents.com/articles/article015/resuming.asp + _stprintf(szRangeRequest, _T("Range: bytes=%u-%u"), (unsigned int)dwStartOffset, (unsigned int)dwEndOffset); + HttpAddRequestHeaders(hRequest, szRangeRequest, 0xFFFFFFFF, HTTP_ADDREQ_FLAG_ADD_IF_NEW); + + // Send the request to the server + if(HttpSendRequest(hRequest, NULL, 0, NULL, 0)) + { + while(dwTotalBytesRead < dwBytesToRead) + { + DWORD dwBlockBytesToRead = dwBytesToRead - dwTotalBytesRead; + DWORD dwBlockBytesRead = 0; + + // Read the block from the file + if(dwBlockBytesToRead > 0x200) + dwBlockBytesToRead = 0x200; + InternetReadFile(hRequest, pbBuffer, dwBlockBytesToRead, &dwBlockBytesRead); + + // Check for end + if(dwBlockBytesRead == 0) + break; + + // Move buffers + dwTotalBytesRead += dwBlockBytesRead; + pbBuffer += dwBlockBytesRead; + } + } + InternetCloseHandle(hRequest); + } + } + + // Increment the current file position by number of bytes read + pStream->Base.Http.FilePos = ByteOffset + dwTotalBytesRead; + + // If the number of bytes read doesn't match the required amount, return false + if(dwTotalBytesRead != dwBytesToRead) + SetLastError(ERROR_HANDLE_EOF); + return (dwTotalBytesRead == dwBytesToRead); + +#else + + // Not supported + pStream = pStream; + pByteOffset = pByteOffset; + pvBuffer = pvBuffer; + dwBytesToRead = dwBytesToRead; + SetLastError(ERROR_NOT_SUPPORTED); + return false; + +#endif +} + +static void BaseHttp_Close(TFileStream * pStream) +{ +#ifdef PLATFORM_WINDOWS + if(pStream->Base.Http.hConnect != NULL) + InternetCloseHandle(pStream->Base.Http.hConnect); + pStream->Base.Http.hConnect = NULL; + + if(pStream->Base.Http.hInternet != NULL) + InternetCloseHandle(pStream->Base.Http.hInternet); + pStream->Base.Http.hInternet = NULL; +#else + pStream = pStream; +#endif +} + +// Initializes base functions for the mapped file +static void BaseHttp_Init(TFileStream * pStream) +{ + // Supply the stream functions + pStream->BaseOpen = BaseHttp_Open; + pStream->BaseRead = BaseHttp_Read; + pStream->BaseGetSize = BaseFile_GetSize; // Reuse BaseFile function + pStream->BaseGetPos = BaseFile_GetPos; // Reuse BaseFile function + pStream->BaseClose = BaseHttp_Close; + + // HTTP files are read-only + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; +} + +//----------------------------------------------------------------------------- +// Local functions - base block-based support + +// Generic function that loads blocks from the file +// The function groups the block with the same availability, +// so the called BlockRead can finish the request in a single system call +static bool BlockStream_Read( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position + void * pvBuffer, // Pointer to data to be read + DWORD dwBytesToRead) // Number of bytes to read from the file +{ + ULONGLONG BlockOffset0; + ULONGLONG BlockOffset; + ULONGLONG ByteOffset; + ULONGLONG EndOffset; + LPBYTE TransferBuffer; + LPBYTE BlockBuffer; + DWORD BlockBufferOffset; // Offset of the desired data in the block buffer + DWORD BytesNeeded; // Number of bytes that really need to be read + DWORD BlockSize = pStream->BlockSize; + DWORD BlockCount; + bool bPrevBlockAvailable; + bool bCallbackCalled = false; + bool bBlockAvailable; + bool bResult = true; + + // The base block read function must be present + assert(pStream->BlockRead != NULL); + + // NOP reading of zero bytes + if(dwBytesToRead == 0) + return true; + + // Get the current position in the stream + ByteOffset = (pByteOffset != NULL) ? pByteOffset[0] : pStream->StreamPos; + EndOffset = ByteOffset + dwBytesToRead; + if(EndOffset > pStream->StreamSize) + { + SetLastError(ERROR_HANDLE_EOF); + return false; + } + + // Calculate the block parameters + BlockOffset0 = BlockOffset = ByteOffset & ~((ULONGLONG)BlockSize - 1); + BlockCount = (DWORD)(((EndOffset - BlockOffset) + (BlockSize - 1)) / BlockSize); + BytesNeeded = (DWORD)(EndOffset - BlockOffset); + + // Remember where we have our data + assert((BlockSize & (BlockSize - 1)) == 0); + BlockBufferOffset = (DWORD)(ByteOffset & (BlockSize - 1)); + + // Allocate buffer for reading blocks + TransferBuffer = BlockBuffer = STORM_ALLOC(BYTE, (BlockCount * BlockSize)); + if(TransferBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return false; + } + + // If all blocks are available, just read all blocks at once + if(pStream->IsComplete == 0) + { + // Now parse the blocks and send the block read request + // to all blocks with the same availability + assert(pStream->BlockCheck != NULL); + bPrevBlockAvailable = pStream->BlockCheck(pStream, BlockOffset); + + // Loop as long as we have something to read + while(BlockOffset < EndOffset) + { + // Determine availability of the next block + bBlockAvailable = pStream->BlockCheck(pStream, BlockOffset); + + // If the availability has changed, read all blocks up to this one + if(bBlockAvailable != bPrevBlockAvailable) + { + // Call the file stream callback, if the block is not available + if(pStream->pMaster && pStream->pfnCallback && bPrevBlockAvailable == false) + { + pStream->pfnCallback(pStream->UserData, BlockOffset0, (DWORD)(BlockOffset - BlockOffset0)); + bCallbackCalled = true; + } + + // Load the continuous blocks with the same availability + assert(BlockOffset > BlockOffset0); + bResult = pStream->BlockRead(pStream, BlockOffset0, BlockOffset, BlockBuffer, BytesNeeded, bPrevBlockAvailable); + if(!bResult) + break; + + // Move the block offset + BlockBuffer += (DWORD)(BlockOffset - BlockOffset0); + BytesNeeded -= (DWORD)(BlockOffset - BlockOffset0); + bPrevBlockAvailable = bBlockAvailable; + BlockOffset0 = BlockOffset; + } + + // Move to the block offset in the stream + BlockOffset += BlockSize; + } + + // If there is a block(s) remaining to be read, do it + if(BlockOffset > BlockOffset0) + { + // Call the file stream callback, if the block is not available + if(pStream->pMaster && pStream->pfnCallback && bPrevBlockAvailable == false) + { + pStream->pfnCallback(pStream->UserData, BlockOffset0, (DWORD)(BlockOffset - BlockOffset0)); + bCallbackCalled = true; + } + + // Read the complete blocks from the file + if(BlockOffset > pStream->StreamSize) + BlockOffset = pStream->StreamSize; + bResult = pStream->BlockRead(pStream, BlockOffset0, BlockOffset, BlockBuffer, BytesNeeded, bPrevBlockAvailable); + } + } + else + { + // Read the complete blocks from the file + if(EndOffset > pStream->StreamSize) + EndOffset = pStream->StreamSize; + bResult = pStream->BlockRead(pStream, BlockOffset, EndOffset, BlockBuffer, BytesNeeded, true); + } + + // Now copy the data to the user buffer + if(bResult) + { + memcpy(pvBuffer, TransferBuffer + BlockBufferOffset, dwBytesToRead); + pStream->StreamPos = ByteOffset + dwBytesToRead; + } + else + { + // If the block read failed, set the last error + SetLastError(ERROR_FILE_INCOMPLETE); + } + + // Call the callback to indicate we are done + if(bCallbackCalled) + pStream->pfnCallback(pStream->UserData, 0, 0); + + // Free the block buffer and return + STORM_FREE(TransferBuffer); + return bResult; +} + +static bool BlockStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize) +{ + *pFileSize = pStream->StreamSize; + return true; +} + +static bool BlockStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset) +{ + *pByteOffset = pStream->StreamPos; + return true; +} + +static void BlockStream_Close(TBlockStream * pStream) +{ + // Free the data map, if any + if(pStream->FileBitmap != NULL) + STORM_FREE(pStream->FileBitmap); + pStream->FileBitmap = NULL; + + // Call the base class for closing the stream + pStream->BaseClose(pStream); +} + +//----------------------------------------------------------------------------- +// File stream allocation function + +static STREAM_INIT StreamBaseInit[4] = +{ + BaseFile_Init, + BaseMap_Init, + BaseHttp_Init, + BaseNone_Init +}; + +// This function allocates an empty structure for the file stream +// The stream structure is created as flat block, variable length +// The file name is placed after the end of the stream structure data +static TFileStream * AllocateFileStream( + const TCHAR * szFileName, + size_t StreamSize, + DWORD dwStreamFlags) +{ + TFileStream * pMaster = NULL; + TFileStream * pStream; + const TCHAR * szNextFile = szFileName; + size_t FileNameSize; + + // Sanity check + assert(StreamSize != 0); + + // The caller can specify chain of files in the following form: + // C:\archive.MPQ*http://www.server.com/MPQs/archive-server.MPQ + // In that case, we use the part after "*" as master file name + while(szNextFile[0] != 0 && szNextFile[0] != _T('*')) + szNextFile++; + FileNameSize = (size_t)((szNextFile - szFileName) * sizeof(TCHAR)); + + // If we have a next file, we need to open it as master stream + // Note that we don't care if the master stream exists or not, + // If it doesn't, later attempts to read missing file block will fail + if(szNextFile[0] == _T('*')) + { + // Don't allow another master file in the string + if(_tcschr(szNextFile + 1, _T('*')) != NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + // Open the master file + pMaster = FileStream_OpenFile(szNextFile + 1, STREAM_FLAG_READ_ONLY); + } + + // Allocate the stream structure for the given stream type + pStream = (TFileStream *)STORM_ALLOC(BYTE, StreamSize + FileNameSize + sizeof(TCHAR)); + if(pStream != NULL) + { + // Zero the entire structure + memset(pStream, 0, StreamSize); + pStream->pMaster = pMaster; + pStream->dwFlags = dwStreamFlags; + + // Initialize the file name + pStream->szFileName = (TCHAR *)((BYTE *)pStream + StreamSize); + memcpy(pStream->szFileName, szFileName, FileNameSize); + pStream->szFileName[FileNameSize / sizeof(TCHAR)] = 0; + + // Initialize the stream functions + StreamBaseInit[dwStreamFlags & 0x03](pStream); + } + + return pStream; +} + +//----------------------------------------------------------------------------- +// Local functions - flat stream support + +static DWORD FlatStream_CheckFile(TBlockStream * pStream) +{ + LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap; + DWORD WholeByteCount = (pStream->BlockCount / 8); + DWORD ExtraBitsCount = (pStream->BlockCount & 7); + BYTE ExpectedValue; + + // Verify the whole bytes - their value must be 0xFF + for(DWORD i = 0; i < WholeByteCount; i++) + { + if(FileBitmap[i] != 0xFF) + return 0; + } + + // If there are extra bits, calculate the mask + if(ExtraBitsCount != 0) + { + ExpectedValue = (BYTE)((1 << ExtraBitsCount) - 1); + if(FileBitmap[WholeByteCount] != ExpectedValue) + return 0; + } + + // Yes, the file is complete + return 1; +} + +static bool FlatStream_LoadBitmap(TBlockStream * pStream) +{ + FILE_BITMAP_FOOTER Footer; + ULONGLONG ByteOffset; + LPBYTE FileBitmap; + DWORD BlockCount; + DWORD BitmapSize; + + // Do not load the bitmap if we should not have to + if(!(pStream->dwFlags & STREAM_FLAG_USE_BITMAP)) + return false; + + // Only if the size is greater than size of bitmap footer + if(pStream->Base.File.FileSize > sizeof(FILE_BITMAP_FOOTER)) + { + // Load the bitmap footer + ByteOffset = pStream->Base.File.FileSize - sizeof(FILE_BITMAP_FOOTER); + if(pStream->BaseRead(pStream, &ByteOffset, &Footer, sizeof(FILE_BITMAP_FOOTER))) + { + // Make sure that the array is properly BSWAP-ed + BSWAP_ARRAY32_UNSIGNED((LPDWORD)(&Footer), sizeof(FILE_BITMAP_FOOTER)); + + // Verify if there is actually a footer + if(Footer.Signature == ID_FILE_BITMAP_FOOTER && Footer.Version == 0x03) + { + // Get the offset of the bitmap, number of blocks and size of the bitmap + ByteOffset = MAKE_OFFSET64(Footer.MapOffsetHi, Footer.MapOffsetLo); + BlockCount = (DWORD)(((ByteOffset - 1) / Footer.BlockSize) + 1); + BitmapSize = ((BlockCount + 7) / 8); + + // Check if the sizes match + if(ByteOffset + BitmapSize + sizeof(FILE_BITMAP_FOOTER) == pStream->Base.File.FileSize) + { + // Allocate space for the bitmap + FileBitmap = STORM_ALLOC(BYTE, BitmapSize); + if(FileBitmap != NULL) + { + // Load the bitmap bits + if(!pStream->BaseRead(pStream, &ByteOffset, FileBitmap, BitmapSize)) + { + STORM_FREE(FileBitmap); + return false; + } + + // Update the stream size + pStream->BuildNumber = Footer.BuildNumber; + pStream->StreamSize = ByteOffset; + + // Fill the bitmap information + pStream->FileBitmap = FileBitmap; + pStream->BitmapSize = BitmapSize; + pStream->BlockSize = Footer.BlockSize; + pStream->BlockCount = BlockCount; + pStream->IsComplete = FlatStream_CheckFile(pStream); + return true; + } + } + } + } + } + + return false; +} + +static void FlatStream_UpdateBitmap( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG StartOffset, + ULONGLONG EndOffset) +{ + LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap; + DWORD BlockIndex; + DWORD BlockSize = pStream->BlockSize; + DWORD ByteIndex; + BYTE BitMask; + + // Sanity checks + assert((StartOffset & (BlockSize - 1)) == 0); + assert(FileBitmap != NULL); + + // Calculate the index of the block + BlockIndex = (DWORD)(StartOffset / BlockSize); + ByteIndex = (BlockIndex / 0x08); + BitMask = (BYTE)(1 << (BlockIndex & 0x07)); + + // Set all bits for the specified range + while(StartOffset < EndOffset) + { + // Set the bit + FileBitmap[ByteIndex] |= BitMask; + + // Move all + StartOffset += BlockSize; + ByteIndex += (BitMask >> 0x07); + BitMask = (BitMask >> 0x07) | (BitMask << 0x01); + } + + // Increment the bitmap update count + pStream->IsModified = 1; +} + +static bool FlatStream_BlockCheck( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG BlockOffset) +{ + LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap; + DWORD BlockIndex; + BYTE BitMask; + + // Sanity checks + assert((BlockOffset & (pStream->BlockSize - 1)) == 0); + assert(FileBitmap != NULL); + + // Calculate the index of the block + BlockIndex = (DWORD)(BlockOffset / pStream->BlockSize); + BitMask = (BYTE)(1 << (BlockIndex & 0x07)); + + // Check if the bit is present + return (FileBitmap[BlockIndex / 0x08] & BitMask) ? true : false; +} + +static bool FlatStream_BlockRead( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG StartOffset, + ULONGLONG EndOffset, + LPBYTE BlockBuffer, + DWORD BytesNeeded, + bool bAvailable) +{ + DWORD BytesToRead = (DWORD)(EndOffset - StartOffset); + + // The starting offset must be aligned to size of the block + assert(pStream->FileBitmap != NULL); + assert((StartOffset & (pStream->BlockSize - 1)) == 0); + assert(StartOffset < EndOffset); + + // If the blocks are not available, we need to load them from the master + // and then save to the mirror + if(bAvailable == false) + { + // If we have no master, we cannot satisfy read request + if(pStream->pMaster == NULL) + return false; + + // Load the blocks from the master stream + // Note that we always have to read complete blocks + // so they get properly stored to the mirror stream + if(!FileStream_Read(pStream->pMaster, &StartOffset, BlockBuffer, BytesToRead)) + return false; + + // Store the loaded blocks to the mirror file. + // Note that this operation is not required to succeed + if(pStream->BaseWrite(pStream, &StartOffset, BlockBuffer, BytesToRead)) + FlatStream_UpdateBitmap(pStream, StartOffset, EndOffset); + + return true; + } + else + { + if(BytesToRead > BytesNeeded) + BytesToRead = BytesNeeded; + return pStream->BaseRead(pStream, &StartOffset, BlockBuffer, BytesToRead); + } +} + +static void FlatStream_Close(TBlockStream * pStream) +{ + FILE_BITMAP_FOOTER Footer; + + if(pStream->FileBitmap && pStream->IsModified) + { + // Write the file bitmap + pStream->BaseWrite(pStream, &pStream->StreamSize, pStream->FileBitmap, pStream->BitmapSize); + + // Prepare and write the file footer + Footer.Signature = ID_FILE_BITMAP_FOOTER; + Footer.Version = 3; + Footer.BuildNumber = pStream->BuildNumber; + Footer.MapOffsetLo = (DWORD)(pStream->StreamSize & 0xFFFFFFFF); + Footer.MapOffsetHi = (DWORD)(pStream->StreamSize >> 0x20); + Footer.BlockSize = pStream->BlockSize; + BSWAP_ARRAY32_UNSIGNED(&Footer, sizeof(FILE_BITMAP_FOOTER)); + pStream->BaseWrite(pStream, NULL, &Footer, sizeof(FILE_BITMAP_FOOTER)); + } + + // Close the base class + BlockStream_Close(pStream); +} + +static bool FlatStream_CreateMirror(TBlockStream * pStream) +{ + ULONGLONG MasterSize = 0; + ULONGLONG MirrorSize = 0; + LPBYTE FileBitmap = NULL; + DWORD dwBitmapSize; + DWORD dwBlockCount; + bool bNeedCreateMirrorStream = true; + bool bNeedResizeMirrorStream = true; + + // Do we have master function and base creation function? + if(pStream->pMaster == NULL || pStream->BaseCreate == NULL) + return false; + + // Retrieve the master file size, block count and bitmap size + FileStream_GetSize(pStream->pMaster, &MasterSize); + dwBlockCount = (DWORD)((MasterSize + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE); + dwBitmapSize = (DWORD)((dwBlockCount + 7) / 8); + + // Setup stream size and position + pStream->BuildNumber = DEFAULT_BUILD_NUMBER; // BUGBUG: Really??? + pStream->StreamSize = MasterSize; + pStream->StreamPos = 0; + + // Open the base stream for write access + if(pStream->BaseOpen(pStream, pStream->szFileName, 0)) + { + // If the file open succeeded, check if the file size matches required size + pStream->BaseGetSize(pStream, &MirrorSize); + if(MirrorSize == MasterSize + dwBitmapSize + sizeof(FILE_BITMAP_FOOTER)) + { + // Attempt to load an existing file bitmap + if(FlatStream_LoadBitmap(pStream)) + return true; + + // We need to create new file bitmap + bNeedResizeMirrorStream = false; + } + + // We need to create mirror stream + bNeedCreateMirrorStream = false; + } + + // Create a new stream, if needed + if(bNeedCreateMirrorStream) + { + if(!pStream->BaseCreate(pStream)) + return false; + } + + // If we need to, then resize the mirror stream + if(bNeedResizeMirrorStream) + { + if(!pStream->BaseResize(pStream, MasterSize + dwBitmapSize + sizeof(FILE_BITMAP_FOOTER))) + return false; + } + + // Allocate the bitmap array + FileBitmap = STORM_ALLOC(BYTE, dwBitmapSize); + if(FileBitmap == NULL) + return false; + + // Initialize the bitmap + memset(FileBitmap, 0, dwBitmapSize); + pStream->FileBitmap = FileBitmap; + pStream->BitmapSize = dwBitmapSize; + pStream->BlockSize = DEFAULT_BLOCK_SIZE; + pStream->BlockCount = dwBlockCount; + pStream->IsComplete = 0; + pStream->IsModified = 1; + + // Note: Don't write the stream bitmap right away. + // Doing so would cause sparse file resize on NTFS, + // which would take long time on larger files. + return true; +} + +static TFileStream * FlatStream_Open(const TCHAR * szFileName, DWORD dwStreamFlags) +{ + TBlockStream * pStream; + ULONGLONG ByteOffset = 0; + + // Create new empty stream + pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags); + if(pStream == NULL) + return NULL; + + // Do we have a master stream? + if(pStream->pMaster != NULL) + { + if(!FlatStream_CreateMirror(pStream)) + { + FileStream_Close(pStream); + SetLastError(ERROR_FILE_NOT_FOUND); + return NULL; + } + } + else + { + // Attempt to open the base stream + if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags)) + { + FileStream_Close(pStream); + return NULL; + } + + // Load the bitmap, if required to + if(dwStreamFlags & STREAM_FLAG_USE_BITMAP) + FlatStream_LoadBitmap(pStream); + } + + // If we have a stream bitmap, set the reading functions + // which check presence of each file block + if(pStream->FileBitmap != NULL) + { + // Set the stream position to zero. Stream size is already set + assert(pStream->StreamSize != 0); + pStream->StreamPos = 0; + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; + + // Supply the stream functions + pStream->StreamRead = (STREAM_READ)BlockStream_Read; + pStream->StreamGetSize = BlockStream_GetSize; + pStream->StreamGetPos = BlockStream_GetPos; + pStream->StreamClose = (STREAM_CLOSE)FlatStream_Close; + + // Supply the block functions + pStream->BlockCheck = (BLOCK_CHECK)FlatStream_BlockCheck; + pStream->BlockRead = (BLOCK_READ)FlatStream_BlockRead; + } + else + { + // Reset the base position to zero + pStream->BaseRead(pStream, &ByteOffset, NULL, 0); + + // Setup stream size and position + pStream->StreamSize = pStream->Base.File.FileSize; + pStream->StreamPos = 0; + + // Set the base functions + pStream->StreamRead = pStream->BaseRead; + pStream->StreamWrite = pStream->BaseWrite; + pStream->StreamResize = pStream->BaseResize; + pStream->StreamGetSize = pStream->BaseGetSize; + pStream->StreamGetPos = pStream->BaseGetPos; + pStream->StreamClose = pStream->BaseClose; + } + + return pStream; +} + +//----------------------------------------------------------------------------- +// Local functions - partial stream support + +static bool IsPartHeader(PPART_FILE_HEADER pPartHdr) +{ + // Version number must be 2 + if(pPartHdr->PartialVersion == 2) + { + // GameBuildNumber must be an ASCII number + if(isdigit(pPartHdr->GameBuildNumber[0]) && isdigit(pPartHdr->GameBuildNumber[1]) && isdigit(pPartHdr->GameBuildNumber[2])) + { + // Block size must be power of 2 + if((pPartHdr->BlockSize & (pPartHdr->BlockSize - 1)) == 0) + return true; + } + } + + return false; +} + +static DWORD PartStream_CheckFile(TBlockStream * pStream) +{ + PPART_FILE_MAP_ENTRY FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap; + DWORD dwBlockCount; + + // Get the number of blocks + dwBlockCount = (DWORD)((pStream->StreamSize + pStream->BlockSize - 1) / pStream->BlockSize); + + // Check all blocks + for(DWORD i = 0; i < dwBlockCount; i++, FileBitmap++) + { + // Few sanity checks + assert(FileBitmap->LargeValueHi == 0); + assert(FileBitmap->LargeValueLo == 0); + assert(FileBitmap->Flags == 0 || FileBitmap->Flags == 3); + + // Check if this block is present + if(FileBitmap->Flags != 3) + return 0; + } + + // Yes, the file is complete + return 1; +} + +static bool PartStream_LoadBitmap(TBlockStream * pStream) +{ + PPART_FILE_MAP_ENTRY FileBitmap; + PART_FILE_HEADER PartHdr; + ULONGLONG ByteOffset = 0; + ULONGLONG StreamSize = 0; + DWORD BlockCount; + DWORD BitmapSize; + + // Only if the size is greater than size of the bitmap header + if(pStream->Base.File.FileSize > sizeof(PART_FILE_HEADER)) + { + // Attempt to read PART file header + if(pStream->BaseRead(pStream, &ByteOffset, &PartHdr, sizeof(PART_FILE_HEADER))) + { + // We need to swap PART file header on big-endian platforms + BSWAP_ARRAY32_UNSIGNED(&PartHdr, sizeof(PART_FILE_HEADER)); + + // Verify the PART file header + if(IsPartHeader(&PartHdr)) + { + // Get the number of blocks and size of one block + StreamSize = MAKE_OFFSET64(PartHdr.FileSizeHi, PartHdr.FileSizeLo); + ByteOffset = sizeof(PART_FILE_HEADER); + BlockCount = (DWORD)((StreamSize + PartHdr.BlockSize - 1) / PartHdr.BlockSize); + BitmapSize = BlockCount * sizeof(PART_FILE_MAP_ENTRY); + + // Check if sizes match + if((ByteOffset + BitmapSize) < pStream->Base.File.FileSize) + { + // Allocate space for the array of PART_FILE_MAP_ENTRY + FileBitmap = STORM_ALLOC(PART_FILE_MAP_ENTRY, BlockCount); + if(FileBitmap != NULL) + { + // Load the block map + if(!pStream->BaseRead(pStream, &ByteOffset, FileBitmap, BitmapSize)) + { + STORM_FREE(FileBitmap); + return false; + } + + // Make sure that the byte order is correct + BSWAP_ARRAY32_UNSIGNED(FileBitmap, BitmapSize); + + // Update the stream size + pStream->BuildNumber = StringToInt(PartHdr.GameBuildNumber); + pStream->StreamSize = StreamSize; + + // Fill the bitmap information + pStream->FileBitmap = FileBitmap; + pStream->BitmapSize = BitmapSize; + pStream->BlockSize = PartHdr.BlockSize; + pStream->BlockCount = BlockCount; + pStream->IsComplete = PartStream_CheckFile(pStream); + return true; + } + } + } + } + } + + return false; +} + +static void PartStream_UpdateBitmap( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG StartOffset, + ULONGLONG EndOffset, + ULONGLONG RealOffset) +{ + PPART_FILE_MAP_ENTRY FileBitmap; + DWORD BlockSize = pStream->BlockSize; + + // Sanity checks + assert((StartOffset & (BlockSize - 1)) == 0); + assert(pStream->FileBitmap != NULL); + + // Calculate the first entry in the block map + FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + (StartOffset / BlockSize); + + // Set all bits for the specified range + while(StartOffset < EndOffset) + { + // Set the bit + FileBitmap->BlockOffsHi = (DWORD)(RealOffset >> 0x20); + FileBitmap->BlockOffsLo = (DWORD)(RealOffset & 0xFFFFFFFF); + FileBitmap->Flags = 3; + + // Move all + StartOffset += BlockSize; + RealOffset += BlockSize; + FileBitmap++; + } + + // Increment the bitmap update count + pStream->IsModified = 1; +} + +static bool PartStream_BlockCheck( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG BlockOffset) +{ + PPART_FILE_MAP_ENTRY FileBitmap; + + // Sanity checks + assert((BlockOffset & (pStream->BlockSize - 1)) == 0); + assert(pStream->FileBitmap != NULL); + + // Calculate the block map entry + FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + (BlockOffset / pStream->BlockSize); + + // Check if the flags are present + return (FileBitmap->Flags & 0x03) ? true : false; +} + +static bool PartStream_BlockRead( + TBlockStream * pStream, + ULONGLONG StartOffset, + ULONGLONG EndOffset, + LPBYTE BlockBuffer, + DWORD BytesNeeded, + bool bAvailable) +{ + PPART_FILE_MAP_ENTRY FileBitmap; + ULONGLONG ByteOffset; + DWORD BytesToRead; + DWORD BlockIndex = (DWORD)(StartOffset / pStream->BlockSize); + + // The starting offset must be aligned to size of the block + assert(pStream->FileBitmap != NULL); + assert((StartOffset & (pStream->BlockSize - 1)) == 0); + assert(StartOffset < EndOffset); + + // If the blocks are not available, we need to load them from the master + // and then save to the mirror + if(bAvailable == false) + { + // If we have no master, we cannot satisfy read request + if(pStream->pMaster == NULL) + return false; + + // Load the blocks from the master stream + // Note that we always have to read complete blocks + // so they get properly stored to the mirror stream + BytesToRead = (DWORD)(EndOffset - StartOffset); + if(!FileStream_Read(pStream->pMaster, &StartOffset, BlockBuffer, BytesToRead)) + return false; + + // The loaded blocks are going to be stored to the end of the file + // Note that this operation is not required to succeed + if(pStream->BaseGetSize(pStream, &ByteOffset)) + { + // Store the loaded blocks to the mirror file. + if(pStream->BaseWrite(pStream, &ByteOffset, BlockBuffer, BytesToRead)) + { + PartStream_UpdateBitmap(pStream, StartOffset, EndOffset, ByteOffset); + } + } + } + else + { + // Get the file map entry + FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + BlockIndex; + + // Read all blocks + while(StartOffset < EndOffset) + { + // Get the number of bytes to be read + BytesToRead = (DWORD)(EndOffset - StartOffset); + if(BytesToRead > pStream->BlockSize) + BytesToRead = pStream->BlockSize; + if(BytesToRead > BytesNeeded) + BytesToRead = BytesNeeded; + + // Read the block + ByteOffset = MAKE_OFFSET64(FileBitmap->BlockOffsHi, FileBitmap->BlockOffsLo); + if(!pStream->BaseRead(pStream, &ByteOffset, BlockBuffer, BytesToRead)) + return false; + + // Move the pointers + StartOffset += pStream->BlockSize; + BlockBuffer += pStream->BlockSize; + BytesNeeded -= pStream->BlockSize; + FileBitmap++; + } + } + + return true; +} + +static void PartStream_Close(TBlockStream * pStream) +{ + PART_FILE_HEADER PartHeader; + ULONGLONG ByteOffset = 0; + + if(pStream->FileBitmap && pStream->IsModified) + { + // Prepare the part file header + memset(&PartHeader, 0, sizeof(PART_FILE_HEADER)); + PartHeader.PartialVersion = 2; + PartHeader.FileSizeHi = (DWORD)(pStream->StreamSize >> 0x20); + PartHeader.FileSizeLo = (DWORD)(pStream->StreamSize & 0xFFFFFFFF); + PartHeader.BlockSize = pStream->BlockSize; + + // Make sure that the header is properly BSWAPed + BSWAP_ARRAY32_UNSIGNED(&PartHeader, sizeof(PART_FILE_HEADER)); + sprintf(PartHeader.GameBuildNumber, "%u", (unsigned int)pStream->BuildNumber); + + // Write the part header + pStream->BaseWrite(pStream, &ByteOffset, &PartHeader, sizeof(PART_FILE_HEADER)); + + // Write the block bitmap + BSWAP_ARRAY32_UNSIGNED(pStream->FileBitmap, pStream->BitmapSize); + pStream->BaseWrite(pStream, NULL, pStream->FileBitmap, pStream->BitmapSize); + } + + // Close the base class + BlockStream_Close(pStream); +} + +static bool PartStream_CreateMirror(TBlockStream * pStream) +{ + ULONGLONG RemainingSize; + ULONGLONG MasterSize = 0; + ULONGLONG MirrorSize = 0; + LPBYTE FileBitmap = NULL; + DWORD dwBitmapSize; + DWORD dwBlockCount; + bool bNeedCreateMirrorStream = true; + bool bNeedResizeMirrorStream = true; + + // Do we have master function and base creation function? + if(pStream->pMaster == NULL || pStream->BaseCreate == NULL) + return false; + + // Retrieve the master file size, block count and bitmap size + FileStream_GetSize(pStream->pMaster, &MasterSize); + dwBlockCount = (DWORD)((MasterSize + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE); + dwBitmapSize = (DWORD)(dwBlockCount * sizeof(PART_FILE_MAP_ENTRY)); + + // Setup stream size and position + pStream->BuildNumber = DEFAULT_BUILD_NUMBER; // BUGBUG: Really??? + pStream->StreamSize = MasterSize; + pStream->StreamPos = 0; + + // Open the base stream for write access + if(pStream->BaseOpen(pStream, pStream->szFileName, 0)) + { + // If the file open succeeded, check if the file size matches required size + pStream->BaseGetSize(pStream, &MirrorSize); + if(MirrorSize >= sizeof(PART_FILE_HEADER) + dwBitmapSize) + { + // Check if the remaining size is aligned to block + RemainingSize = MirrorSize - sizeof(PART_FILE_HEADER) - dwBitmapSize; + if((RemainingSize & (DEFAULT_BLOCK_SIZE - 1)) == 0 || RemainingSize == MasterSize) + { + // Attempt to load an existing file bitmap + if(PartStream_LoadBitmap(pStream)) + return true; + } + } + + // We need to create mirror stream + bNeedCreateMirrorStream = false; + } + + // Create a new stream, if needed + if(bNeedCreateMirrorStream) + { + if(!pStream->BaseCreate(pStream)) + return false; + } + + // If we need to, then resize the mirror stream + if(bNeedResizeMirrorStream) + { + if(!pStream->BaseResize(pStream, sizeof(PART_FILE_HEADER) + dwBitmapSize)) + return false; + } + + // Allocate the bitmap array + FileBitmap = STORM_ALLOC(BYTE, dwBitmapSize); + if(FileBitmap == NULL) + return false; + + // Initialize the bitmap + memset(FileBitmap, 0, dwBitmapSize); + pStream->FileBitmap = FileBitmap; + pStream->BitmapSize = dwBitmapSize; + pStream->BlockSize = DEFAULT_BLOCK_SIZE; + pStream->BlockCount = dwBlockCount; + pStream->IsComplete = 0; + pStream->IsModified = 1; + + // Note: Don't write the stream bitmap right away. + // Doing so would cause sparse file resize on NTFS, + // which would take long time on larger files. + return true; +} + + +static TFileStream * PartStream_Open(const TCHAR * szFileName, DWORD dwStreamFlags) +{ + TBlockStream * pStream; + + // Create new empty stream + pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags); + if(pStream == NULL) + return NULL; + + // Do we have a master stream? + if(pStream->pMaster != NULL) + { + if(!PartStream_CreateMirror(pStream)) + { + FileStream_Close(pStream); + SetLastError(ERROR_FILE_NOT_FOUND); + return NULL; + } + } + else + { + // Attempt to open the base stream + if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags)) + { + FileStream_Close(pStream); + return NULL; + } + + // Load the part stream block map + if(!PartStream_LoadBitmap(pStream)) + { + FileStream_Close(pStream); + SetLastError(ERROR_BAD_FORMAT); + return NULL; + } + } + + // Set the stream position to zero. Stream size is already set + assert(pStream->StreamSize != 0); + pStream->StreamPos = 0; + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; + + // Set new function pointers + pStream->StreamRead = (STREAM_READ)BlockStream_Read; + pStream->StreamGetPos = BlockStream_GetPos; + pStream->StreamGetSize = BlockStream_GetSize; + pStream->StreamClose = (STREAM_CLOSE)PartStream_Close; + + // Supply the block functions + pStream->BlockCheck = (BLOCK_CHECK)PartStream_BlockCheck; + pStream->BlockRead = (BLOCK_READ)PartStream_BlockRead; + return pStream; +} + +//----------------------------------------------------------------------------- +// Local functions - MPQE stream support + +static const char * szKeyTemplate = "expand 32-byte k000000000000000000000000000000000000000000000000"; + +static const char * AuthCodeArray[] = +{ + // Starcraft II (Heart of the Swarm) + // Authentication code URL: http://dist.blizzard.com/mediakey/hots-authenticationcode-bgdl.txt + // -0C- -1C--08- -18--04- -14--00- -10- + "S48B6CDTN5XEQAKQDJNDLJBJ73FDFM3U", // SC2 Heart of the Swarm-all : "expand 32-byte kQAKQ0000FM3UN5XE000073FD6CDT0000LJBJS48B0000DJND" + + // Diablo III: Agent.exe (1.0.0.954) + // Address of decryption routine: 00502b00 + // Pointer to decryptor object: ECX + // Pointer to key: ECX+0x5C + // Authentication code URL: http://dist.blizzard.com/mediakey/d3-authenticationcode-enGB.txt + // -0C- -1C--08- -18--04- -14--00- -10- + "UCMXF6EJY352EFH4XFRXCFH2XC9MQRZK", // Diablo III Installer (deDE): "expand 32-byte kEFH40000QRZKY3520000XC9MF6EJ0000CFH2UCMX0000XFRX" + "MMKVHY48RP7WXP4GHYBQ7SL9J9UNPHBP", // Diablo III Installer (enGB): "expand 32-byte kXP4G0000PHBPRP7W0000J9UNHY4800007SL9MMKV0000HYBQ" + "8MXLWHQ7VGGLTZ9MQZQSFDCLJYET3CPP", // Diablo III Installer (enSG): "expand 32-byte kTZ9M00003CPPVGGL0000JYETWHQ70000FDCL8MXL0000QZQS" + "EJ2R5TM6XFE2GUNG5QDGHKQ9UAKPWZSZ", // Diablo III Installer (enUS): "expand 32-byte kGUNG0000WZSZXFE20000UAKP5TM60000HKQ9EJ2R00005QDG" + "PBGFBE42Z6LNK65UGJQ3WZVMCLP4HQQT", // Diablo III Installer (esES): "expand 32-byte kK65U0000HQQTZ6LN0000CLP4BE420000WZVMPBGF0000GJQ3" + "X7SEJJS9TSGCW5P28EBSC47AJPEY8VU2", // Diablo III Installer (esMX): "expand 32-byte kW5P200008VU2TSGC0000JPEYJJS90000C47AX7SE00008EBS" + "5KVBQA8VYE6XRY3DLGC5ZDE4XS4P7YA2", // Diablo III Installer (frFR): "expand 32-byte kRY3D00007YA2YE6X0000XS4PQA8V0000ZDE45KVB0000LGC5" + "478JD2K56EVNVVY4XX8TDWYT5B8KB254", // Diablo III Installer (itIT): "expand 32-byte kVVY40000B2546EVN00005B8KD2K50000DWYT478J0000XX8T" + "8TS4VNFQRZTN6YWHE9CHVDH9NVWD474A", // Diablo III Installer (koKR): "expand 32-byte k6YWH0000474ARZTN0000NVWDVNFQ0000VDH98TS40000E9CH" + "LJ52Z32DF4LZ4ZJJXVKK3AZQA6GABLJB", // Diablo III Installer (plPL): "expand 32-byte k4ZJJ0000BLJBF4LZ0000A6GAZ32D00003AZQLJ520000XVKK" + "K6BDHY2ECUE2545YKNLBJPVYWHE7XYAG", // Diablo III Installer (ptBR): "expand 32-byte k545Y0000XYAGCUE20000WHE7HY2E0000JPVYK6BD0000KNLB" + "NDVW8GWLAYCRPGRNY8RT7ZZUQU63VLPR", // Diablo III Installer (ruRU): "expand 32-byte kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "6VWCQTN8V3ZZMRUCZXV8A8CGUX2TAA8H", // Diablo III Installer (zhTW): "expand 32-byte kMRUC0000AA8HV3ZZ0000UX2TQTN80000A8CG6VWC0000ZXV8" +// "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // Diablo III Installer (zhCN): "expand 32-byte kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + + // Starcraft II (Wings of Liberty): Installer.exe (4.1.1.4219) + // Address of decryption routine: 0053A3D0 + // Pointer to decryptor object: ECX + // Pointer to key: ECX+0x5C + // Authentication code URL: http://dist.blizzard.com/mediakey/sc2-authenticationcode-enUS.txt + // -0C- -1C--08- -18--04- -14--00- -10- + "Y45MD3CAK4KXSSXHYD9VY64Z8EKJ4XFX", // SC2 Wings of Liberty (deDE): "expand 32-byte kSSXH00004XFXK4KX00008EKJD3CA0000Y64ZY45M0000YD9V" + "G8MN8UDG6NA2ANGY6A3DNY82HRGF29ZH", // SC2 Wings of Liberty (enGB): "expand 32-byte kANGY000029ZH6NA20000HRGF8UDG0000NY82G8MN00006A3D" + "W9RRHLB2FDU9WW5B3ECEBLRSFWZSF7HW", // SC2 Wings of Liberty (enSG): "expand 32-byte kWW5B0000F7HWFDU90000FWZSHLB20000BLRSW9RR00003ECE" + "3DH5RE5NVM5GTFD85LXGWT6FK859ETR5", // SC2 Wings of Liberty (enUS): "expand 32-byte kTFD80000ETR5VM5G0000K859RE5N0000WT6F3DH500005LXG" + "8WLKUAXE94PFQU4Y249PAZ24N4R4XKTQ", // SC2 Wings of Liberty (esES): "expand 32-byte kQU4Y0000XKTQ94PF0000N4R4UAXE0000AZ248WLK0000249P" + "A34DXX3VHGGXSQBRFE5UFFDXMF9G4G54", // SC2 Wings of Liberty (esMX): "expand 32-byte kSQBR00004G54HGGX0000MF9GXX3V0000FFDXA34D0000FE5U" + "ZG7J9K938HJEFWPQUA768MA2PFER6EAJ", // SC2 Wings of Liberty (frFR): "expand 32-byte kFWPQ00006EAJ8HJE0000PFER9K9300008MA2ZG7J0000UA76" + "NE7CUNNNTVAPXV7E3G2BSVBWGVMW8BL2", // SC2 Wings of Liberty (itIT): "expand 32-byte kXV7E00008BL2TVAP0000GVMWUNNN0000SVBWNE7C00003G2B" + "3V9E2FTMBM9QQWK7U6MAMWAZWQDB838F", // SC2 Wings of Liberty (koKR): "expand 32-byte kQWK70000838FBM9Q0000WQDB2FTM0000MWAZ3V9E0000U6MA" + "2NSFB8MELULJ83U6YHA3UP6K4MQD48L6", // SC2 Wings of Liberty (plPL): "expand 32-byte k83U6000048L6LULJ00004MQDB8ME0000UP6K2NSF0000YHA3" + "QA2TZ9EWZ4CUU8BMB5WXCTY65F9CSW4E", // SC2 Wings of Liberty (ptBR): "expand 32-byte kU8BM0000SW4EZ4CU00005F9CZ9EW0000CTY6QA2T0000B5WX" + "VHB378W64BAT9SH7D68VV9NLQDK9YEGT", // SC2 Wings of Liberty (ruRU): "expand 32-byte k9SH70000YEGT4BAT0000QDK978W60000V9NLVHB30000D68V" + "U3NFQJV4M6GC7KBN9XQJ3BRDN3PLD9NE", // SC2 Wings of Liberty (zhTW): "expand 32-byte k7KBN0000D9NEM6GC0000N3PLQJV400003BRDU3NF00009XQJ" + + NULL +}; + +static DWORD Rol32(DWORD dwValue, DWORD dwRolCount) +{ + DWORD dwShiftRight = 32 - dwRolCount; + + return (dwValue << dwRolCount) | (dwValue >> dwShiftRight); +} + +static void CreateKeyFromAuthCode( + LPBYTE pbKeyBuffer, + const char * szAuthCode) +{ + LPDWORD KeyPosition = (LPDWORD)(pbKeyBuffer + 0x10); + LPDWORD AuthCode32 = (LPDWORD)szAuthCode; + + memcpy(pbKeyBuffer, szKeyTemplate, MPQE_CHUNK_SIZE); + KeyPosition[0x00] = AuthCode32[0x03]; + KeyPosition[0x02] = AuthCode32[0x07]; + KeyPosition[0x03] = AuthCode32[0x02]; + KeyPosition[0x05] = AuthCode32[0x06]; + KeyPosition[0x06] = AuthCode32[0x01]; + KeyPosition[0x08] = AuthCode32[0x05]; + KeyPosition[0x09] = AuthCode32[0x00]; + KeyPosition[0x0B] = AuthCode32[0x04]; + BSWAP_ARRAY32_UNSIGNED(pbKeyBuffer, MPQE_CHUNK_SIZE); +} + +static void DecryptFileChunk( + DWORD * MpqData, + LPBYTE pbKey, + ULONGLONG ByteOffset, + DWORD dwLength) +{ + ULONGLONG ChunkOffset; + DWORD KeyShuffled[0x10]; + DWORD KeyMirror[0x10]; + DWORD RoundCount = 0x14; + + // Prepare the key + ChunkOffset = ByteOffset / MPQE_CHUNK_SIZE; + memcpy(KeyMirror, pbKey, MPQE_CHUNK_SIZE); + BSWAP_ARRAY32_UNSIGNED(KeyMirror, MPQE_CHUNK_SIZE); + KeyMirror[0x05] = (DWORD)(ChunkOffset >> 32); + KeyMirror[0x08] = (DWORD)(ChunkOffset); + + while(dwLength >= MPQE_CHUNK_SIZE) + { + // Shuffle the key - part 1 + KeyShuffled[0x0E] = KeyMirror[0x00]; + KeyShuffled[0x0C] = KeyMirror[0x01]; + KeyShuffled[0x05] = KeyMirror[0x02]; + KeyShuffled[0x0F] = KeyMirror[0x03]; + KeyShuffled[0x0A] = KeyMirror[0x04]; + KeyShuffled[0x07] = KeyMirror[0x05]; + KeyShuffled[0x0B] = KeyMirror[0x06]; + KeyShuffled[0x09] = KeyMirror[0x07]; + KeyShuffled[0x03] = KeyMirror[0x08]; + KeyShuffled[0x06] = KeyMirror[0x09]; + KeyShuffled[0x08] = KeyMirror[0x0A]; + KeyShuffled[0x0D] = KeyMirror[0x0B]; + KeyShuffled[0x02] = KeyMirror[0x0C]; + KeyShuffled[0x04] = KeyMirror[0x0D]; + KeyShuffled[0x01] = KeyMirror[0x0E]; + KeyShuffled[0x00] = KeyMirror[0x0F]; + + // Shuffle the key - part 2 + for(DWORD i = 0; i < RoundCount; i += 2) + { + KeyShuffled[0x0A] = KeyShuffled[0x0A] ^ Rol32((KeyShuffled[0x0E] + KeyShuffled[0x02]), 0x07); + KeyShuffled[0x03] = KeyShuffled[0x03] ^ Rol32((KeyShuffled[0x0A] + KeyShuffled[0x0E]), 0x09); + KeyShuffled[0x02] = KeyShuffled[0x02] ^ Rol32((KeyShuffled[0x03] + KeyShuffled[0x0A]), 0x0D); + KeyShuffled[0x0E] = KeyShuffled[0x0E] ^ Rol32((KeyShuffled[0x02] + KeyShuffled[0x03]), 0x12); + + KeyShuffled[0x07] = KeyShuffled[0x07] ^ Rol32((KeyShuffled[0x0C] + KeyShuffled[0x04]), 0x07); + KeyShuffled[0x06] = KeyShuffled[0x06] ^ Rol32((KeyShuffled[0x07] + KeyShuffled[0x0C]), 0x09); + KeyShuffled[0x04] = KeyShuffled[0x04] ^ Rol32((KeyShuffled[0x06] + KeyShuffled[0x07]), 0x0D); + KeyShuffled[0x0C] = KeyShuffled[0x0C] ^ Rol32((KeyShuffled[0x04] + KeyShuffled[0x06]), 0x12); + + KeyShuffled[0x0B] = KeyShuffled[0x0B] ^ Rol32((KeyShuffled[0x05] + KeyShuffled[0x01]), 0x07); + KeyShuffled[0x08] = KeyShuffled[0x08] ^ Rol32((KeyShuffled[0x0B] + KeyShuffled[0x05]), 0x09); + KeyShuffled[0x01] = KeyShuffled[0x01] ^ Rol32((KeyShuffled[0x08] + KeyShuffled[0x0B]), 0x0D); + KeyShuffled[0x05] = KeyShuffled[0x05] ^ Rol32((KeyShuffled[0x01] + KeyShuffled[0x08]), 0x12); + + KeyShuffled[0x09] = KeyShuffled[0x09] ^ Rol32((KeyShuffled[0x0F] + KeyShuffled[0x00]), 0x07); + KeyShuffled[0x0D] = KeyShuffled[0x0D] ^ Rol32((KeyShuffled[0x09] + KeyShuffled[0x0F]), 0x09); + KeyShuffled[0x00] = KeyShuffled[0x00] ^ Rol32((KeyShuffled[0x0D] + KeyShuffled[0x09]), 0x0D); + KeyShuffled[0x0F] = KeyShuffled[0x0F] ^ Rol32((KeyShuffled[0x00] + KeyShuffled[0x0D]), 0x12); + + KeyShuffled[0x04] = KeyShuffled[0x04] ^ Rol32((KeyShuffled[0x0E] + KeyShuffled[0x09]), 0x07); + KeyShuffled[0x08] = KeyShuffled[0x08] ^ Rol32((KeyShuffled[0x04] + KeyShuffled[0x0E]), 0x09); + KeyShuffled[0x09] = KeyShuffled[0x09] ^ Rol32((KeyShuffled[0x08] + KeyShuffled[0x04]), 0x0D); + KeyShuffled[0x0E] = KeyShuffled[0x0E] ^ Rol32((KeyShuffled[0x09] + KeyShuffled[0x08]), 0x12); + + KeyShuffled[0x01] = KeyShuffled[0x01] ^ Rol32((KeyShuffled[0x0C] + KeyShuffled[0x0A]), 0x07); + KeyShuffled[0x0D] = KeyShuffled[0x0D] ^ Rol32((KeyShuffled[0x01] + KeyShuffled[0x0C]), 0x09); + KeyShuffled[0x0A] = KeyShuffled[0x0A] ^ Rol32((KeyShuffled[0x0D] + KeyShuffled[0x01]), 0x0D); + KeyShuffled[0x0C] = KeyShuffled[0x0C] ^ Rol32((KeyShuffled[0x0A] + KeyShuffled[0x0D]), 0x12); + + KeyShuffled[0x00] = KeyShuffled[0x00] ^ Rol32((KeyShuffled[0x05] + KeyShuffled[0x07]), 0x07); + KeyShuffled[0x03] = KeyShuffled[0x03] ^ Rol32((KeyShuffled[0x00] + KeyShuffled[0x05]), 0x09); + KeyShuffled[0x07] = KeyShuffled[0x07] ^ Rol32((KeyShuffled[0x03] + KeyShuffled[0x00]), 0x0D); + KeyShuffled[0x05] = KeyShuffled[0x05] ^ Rol32((KeyShuffled[0x07] + KeyShuffled[0x03]), 0x12); + + KeyShuffled[0x02] = KeyShuffled[0x02] ^ Rol32((KeyShuffled[0x0F] + KeyShuffled[0x0B]), 0x07); + KeyShuffled[0x06] = KeyShuffled[0x06] ^ Rol32((KeyShuffled[0x02] + KeyShuffled[0x0F]), 0x09); + KeyShuffled[0x0B] = KeyShuffled[0x0B] ^ Rol32((KeyShuffled[0x06] + KeyShuffled[0x02]), 0x0D); + KeyShuffled[0x0F] = KeyShuffled[0x0F] ^ Rol32((KeyShuffled[0x0B] + KeyShuffled[0x06]), 0x12); + } + + // Decrypt one data chunk + BSWAP_ARRAY32_UNSIGNED(MpqData, MPQE_CHUNK_SIZE); + MpqData[0x00] = MpqData[0x00] ^ (KeyShuffled[0x0E] + KeyMirror[0x00]); + MpqData[0x01] = MpqData[0x01] ^ (KeyShuffled[0x04] + KeyMirror[0x0D]); + MpqData[0x02] = MpqData[0x02] ^ (KeyShuffled[0x08] + KeyMirror[0x0A]); + MpqData[0x03] = MpqData[0x03] ^ (KeyShuffled[0x09] + KeyMirror[0x07]); + MpqData[0x04] = MpqData[0x04] ^ (KeyShuffled[0x0A] + KeyMirror[0x04]); + MpqData[0x05] = MpqData[0x05] ^ (KeyShuffled[0x0C] + KeyMirror[0x01]); + MpqData[0x06] = MpqData[0x06] ^ (KeyShuffled[0x01] + KeyMirror[0x0E]); + MpqData[0x07] = MpqData[0x07] ^ (KeyShuffled[0x0D] + KeyMirror[0x0B]); + MpqData[0x08] = MpqData[0x08] ^ (KeyShuffled[0x03] + KeyMirror[0x08]); + MpqData[0x09] = MpqData[0x09] ^ (KeyShuffled[0x07] + KeyMirror[0x05]); + MpqData[0x0A] = MpqData[0x0A] ^ (KeyShuffled[0x05] + KeyMirror[0x02]); + MpqData[0x0B] = MpqData[0x0B] ^ (KeyShuffled[0x00] + KeyMirror[0x0F]); + MpqData[0x0C] = MpqData[0x0C] ^ (KeyShuffled[0x02] + KeyMirror[0x0C]); + MpqData[0x0D] = MpqData[0x0D] ^ (KeyShuffled[0x06] + KeyMirror[0x09]); + MpqData[0x0E] = MpqData[0x0E] ^ (KeyShuffled[0x0B] + KeyMirror[0x06]); + MpqData[0x0F] = MpqData[0x0F] ^ (KeyShuffled[0x0F] + KeyMirror[0x03]); + BSWAP_ARRAY32_UNSIGNED(MpqData, MPQE_CHUNK_SIZE); + + // Update byte offset in the key + KeyMirror[0x08]++; + if(KeyMirror[0x08] == 0) + KeyMirror[0x05]++; + + // Move pointers and decrease number of bytes to decrypt + MpqData += (MPQE_CHUNK_SIZE / sizeof(DWORD)); + dwLength -= MPQE_CHUNK_SIZE; + } +} + +static bool MpqeStream_DetectFileKey(TEncryptedStream * pStream) +{ + ULONGLONG ByteOffset = 0; + BYTE EncryptedHeader[MPQE_CHUNK_SIZE]; + BYTE FileHeader[MPQE_CHUNK_SIZE]; + + // Read the first file chunk + if(pStream->BaseRead(pStream, &ByteOffset, EncryptedHeader, sizeof(EncryptedHeader))) + { + // We just try all known keys one by one + for(int i = 0; AuthCodeArray[i] != NULL; i++) + { + // Prepare they decryption key from game serial number + CreateKeyFromAuthCode(pStream->Key, AuthCodeArray[i]); + + // Try to decrypt with the given key + memcpy(FileHeader, EncryptedHeader, MPQE_CHUNK_SIZE); + DecryptFileChunk((LPDWORD)FileHeader, pStream->Key, ByteOffset, MPQE_CHUNK_SIZE); + + // We check the decrypted data + // All known encrypted MPQs have header at the begin of the file, + // so we check for MPQ signature there. + if(FileHeader[0] == 'M' && FileHeader[1] == 'P' && FileHeader[2] == 'Q') + { + // Update the stream size + pStream->StreamSize = pStream->Base.File.FileSize; + + // Fill the block information + pStream->BlockSize = MPQE_CHUNK_SIZE; + pStream->BlockCount = (DWORD)(pStream->Base.File.FileSize + MPQE_CHUNK_SIZE - 1) / MPQE_CHUNK_SIZE; + pStream->IsComplete = 1; + return true; + } + } + } + + // Key not found, sorry + return false; +} + +static bool MpqeStream_BlockRead( + TEncryptedStream * pStream, + ULONGLONG StartOffset, + ULONGLONG EndOffset, + LPBYTE BlockBuffer, + DWORD BytesNeeded, + bool bAvailable) +{ + DWORD dwBytesToRead; + + assert((StartOffset & (pStream->BlockSize - 1)) == 0); + assert(StartOffset < EndOffset); + assert(bAvailable != false); + BytesNeeded = BytesNeeded; + bAvailable = bAvailable; + + // Read the file from the stream as-is + // Limit the reading to number of blocks really needed + dwBytesToRead = (DWORD)(EndOffset - StartOffset); + if(!pStream->BaseRead(pStream, &StartOffset, BlockBuffer, dwBytesToRead)) + return false; + + // Decrypt the data + dwBytesToRead = (dwBytesToRead + MPQE_CHUNK_SIZE - 1) & ~(MPQE_CHUNK_SIZE - 1); + DecryptFileChunk((LPDWORD)BlockBuffer, pStream->Key, StartOffset, dwBytesToRead); + return true; +} + +static TFileStream * MpqeStream_Open(const TCHAR * szFileName, DWORD dwStreamFlags) +{ + TEncryptedStream * pStream; + + // Create new empty stream + pStream = (TEncryptedStream *)AllocateFileStream(szFileName, sizeof(TEncryptedStream), dwStreamFlags); + if(pStream == NULL) + return NULL; + + // Attempt to open the base stream + assert(pStream->BaseOpen != NULL); + if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags)) + return NULL; + + // Determine the encryption key for the MPQ + if(MpqeStream_DetectFileKey(pStream)) + { + // Set the stream position and size + assert(pStream->StreamSize != 0); + pStream->StreamPos = 0; + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; + + // Set new function pointers + pStream->StreamRead = (STREAM_READ)BlockStream_Read; + pStream->StreamGetPos = BlockStream_GetPos; + pStream->StreamGetSize = BlockStream_GetSize; + pStream->StreamClose = pStream->BaseClose; + + // Supply the block functions + pStream->BlockRead = (BLOCK_READ)MpqeStream_BlockRead; + return pStream; + } + + // Cleanup the stream and return + FileStream_Close(pStream); + SetLastError(ERROR_UNKNOWN_FILE_KEY); + return NULL; +} + +//----------------------------------------------------------------------------- +// Local functions - Block4 stream support + +#define BLOCK4_BLOCK_SIZE 0x4000 // Size of one block +#define BLOCK4_HASH_SIZE 0x20 // Size of MD5 hash that is after each block +#define BLOCK4_MAX_BLOCKS 0x00002000 // Maximum amount of blocks per file +#define BLOCK4_MAX_FSIZE 0x08040000 // Max size of one file + +static bool Block4Stream_BlockRead( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG StartOffset, + ULONGLONG EndOffset, + LPBYTE BlockBuffer, + DWORD BytesNeeded, + bool bAvailable) +{ + TBaseProviderData * BaseArray = (TBaseProviderData *)pStream->FileBitmap; + ULONGLONG ByteOffset; + DWORD BytesToRead; + DWORD StreamIndex; + DWORD BlockIndex; + bool bResult; + + // The starting offset must be aligned to size of the block + assert(pStream->FileBitmap != NULL); + assert((StartOffset & (pStream->BlockSize - 1)) == 0); + assert(StartOffset < EndOffset); + assert(bAvailable == true); + + // Keep compiler happy + bAvailable = bAvailable; + EndOffset = EndOffset; + + while(BytesNeeded != 0) + { + // Calculate the block index and the file index + StreamIndex = (DWORD)((StartOffset / pStream->BlockSize) / BLOCK4_MAX_BLOCKS); + BlockIndex = (DWORD)((StartOffset / pStream->BlockSize) % BLOCK4_MAX_BLOCKS); + if(StreamIndex > pStream->BitmapSize) + return false; + + // Calculate the block offset + ByteOffset = ((ULONGLONG)BlockIndex * (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE)); + BytesToRead = STORMLIB_MIN(BytesNeeded, BLOCK4_BLOCK_SIZE); + + // Read from the base stream + pStream->Base = BaseArray[StreamIndex]; + bResult = pStream->BaseRead(pStream, &ByteOffset, BlockBuffer, BytesToRead); + BaseArray[StreamIndex] = pStream->Base; + + // Did the result succeed? + if(bResult == false) + return false; + + // Move pointers + StartOffset += BytesToRead; + BlockBuffer += BytesToRead; + BytesNeeded -= BytesToRead; + } + + return true; +} + + +static void Block4Stream_Close(TBlockStream * pStream) +{ + TBaseProviderData * BaseArray = (TBaseProviderData *)pStream->FileBitmap; + + // If we have a non-zero count of base streams, + // we have to close them all + if(BaseArray != NULL) + { + // Close all base streams + for(DWORD i = 0; i < pStream->BitmapSize; i++) + { + memcpy(&pStream->Base, BaseArray + i, sizeof(TBaseProviderData)); + pStream->BaseClose(pStream); + } + } + + // Free the data map, if any + if(pStream->FileBitmap != NULL) + STORM_FREE(pStream->FileBitmap); + pStream->FileBitmap = NULL; + + // Do not call the BaseClose function, + // we closed all handles already + return; +} + +static TFileStream * Block4Stream_Open(const TCHAR * szFileName, DWORD dwStreamFlags) +{ + TBaseProviderData * NewBaseArray = NULL; + ULONGLONG RemainderBlock; + ULONGLONG BlockCount; + ULONGLONG FileSize; + TBlockStream * pStream; + TCHAR * szNameBuff; + size_t nNameLength; + DWORD dwBaseFiles = 0; + DWORD dwBaseFlags; + + // Create new empty stream + pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags); + if(pStream == NULL) + return NULL; + + // Sanity check + assert(pStream->BaseOpen != NULL); + + // Get the length of the file name without numeric suffix + nNameLength = _tcslen(pStream->szFileName); + if(pStream->szFileName[nNameLength - 2] == '.' && pStream->szFileName[nNameLength - 1] == '0') + nNameLength -= 2; + pStream->szFileName[nNameLength] = 0; + + // Supply the stream functions + pStream->StreamRead = (STREAM_READ)BlockStream_Read; + pStream->StreamGetSize = BlockStream_GetSize; + pStream->StreamGetPos = BlockStream_GetPos; + pStream->StreamClose = (STREAM_CLOSE)Block4Stream_Close; + pStream->BlockRead = (BLOCK_READ)Block4Stream_BlockRead; + + // Allocate work space for numeric names + szNameBuff = STORM_ALLOC(TCHAR, nNameLength + 4); + if(szNameBuff != NULL) + { + // Set the base flags + dwBaseFlags = (dwStreamFlags & STREAM_PROVIDERS_MASK) | STREAM_FLAG_READ_ONLY; + + // Go all suffixes from 0 to 30 + for(int nSuffix = 0; nSuffix < 30; nSuffix++) + { + // Open the n-th file + _stprintf(szNameBuff, _T("%s.%u"), pStream->szFileName, nSuffix); + if(!pStream->BaseOpen(pStream, szNameBuff, dwBaseFlags)) + break; + + // If the open succeeded, we re-allocate the base provider array + NewBaseArray = STORM_ALLOC(TBaseProviderData, dwBaseFiles + 1); + if(NewBaseArray == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + // Copy the old base data array to the new base data array + if(pStream->FileBitmap != NULL) + { + memcpy(NewBaseArray, pStream->FileBitmap, sizeof(TBaseProviderData) * dwBaseFiles); + STORM_FREE(pStream->FileBitmap); + } + + // Also copy the opened base array + memcpy(NewBaseArray + dwBaseFiles, &pStream->Base, sizeof(TBaseProviderData)); + pStream->FileBitmap = NewBaseArray; + dwBaseFiles++; + + // Get the size of the base stream + pStream->BaseGetSize(pStream, &FileSize); + assert(FileSize <= BLOCK4_MAX_FSIZE); + RemainderBlock = FileSize % (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE); + BlockCount = FileSize / (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE); + + // Increment the stream size and number of blocks + pStream->StreamSize += (BlockCount * BLOCK4_BLOCK_SIZE); + pStream->BlockCount += (DWORD)BlockCount; + + // Is this the last file? + if(FileSize < BLOCK4_MAX_FSIZE) + { + if(RemainderBlock) + { + pStream->StreamSize += (RemainderBlock - BLOCK4_HASH_SIZE); + pStream->BlockCount++; + } + break; + } + } + + // Fill the remainining block stream variables + pStream->BitmapSize = dwBaseFiles; + pStream->BlockSize = BLOCK4_BLOCK_SIZE; + pStream->IsComplete = 1; + pStream->IsModified = 0; + + // Fill the remaining stream variables + pStream->StreamPos = 0; + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; + + STORM_FREE(szNameBuff); + } + + // If we opened something, return success + if(dwBaseFiles == 0) + { + FileStream_Close(pStream); + SetLastError(ERROR_FILE_NOT_FOUND); + pStream = NULL; + } + + return pStream; +} + +//----------------------------------------------------------------------------- +// Public functions + +/** + * This function creates a new file for read-write access + * + * - If the current platform supports file sharing, + * the file must be created for read sharing (i.e. another application + * can open the file for read, but not for write) + * - If the file does not exist, the function must create new one + * - If the file exists, the function must rewrite it and set to zero size + * - The parameters of the function must be validate by the caller + * - The function must initialize all stream function pointers in TFileStream + * - If the function fails from any reason, it must close all handles + * and free all memory that has been allocated in the process of stream creation, + * including the TFileStream structure itself + * + * \a szFileName Name of the file to create + */ + +TFileStream * FileStream_CreateFile( + const TCHAR * szFileName, + DWORD dwStreamFlags) +{ + TFileStream * pStream; + + // We only support creation of flat, local file + if((dwStreamFlags & (STREAM_PROVIDERS_MASK)) != (STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE)) + { + SetLastError(ERROR_NOT_SUPPORTED); + return NULL; + } + + // Allocate file stream structure for flat stream + pStream = AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags); + if(pStream != NULL) + { + // Attempt to create the disk file + if(BaseFile_Create(pStream)) + { + // Fill the stream provider functions + pStream->StreamRead = pStream->BaseRead; + pStream->StreamWrite = pStream->BaseWrite; + pStream->StreamResize = pStream->BaseResize; + pStream->StreamGetSize = pStream->BaseGetSize; + pStream->StreamGetPos = pStream->BaseGetPos; + pStream->StreamClose = pStream->BaseClose; + return pStream; + } + + // File create failed, delete the stream + STORM_FREE(pStream); + pStream = NULL; + } + + // Return the stream + return pStream; +} + +/** + * This function opens an existing file for read or read-write access + * - If the current platform supports file sharing, + * the file must be open for read sharing (i.e. another application + * can open the file for read, but not for write) + * - If the file does not exist, the function must return NULL + * - If the file exists but cannot be open, then function must return NULL + * - The parameters of the function must be validate by the caller + * - The function must initialize all stream function pointers in TFileStream + * - If the function fails from any reason, it must close all handles + * and free all memory that has been allocated in the process of stream creation, + * including the TFileStream structure itself + * + * \a szFileName Name of the file to open + * \a dwStreamFlags specifies the provider and base storage type + */ + +TFileStream * FileStream_OpenFile( + const TCHAR * szFileName, + DWORD dwStreamFlags) +{ + DWORD dwProvider = dwStreamFlags & STREAM_PROVIDERS_MASK; + size_t nPrefixLength = FileStream_Prefix(szFileName, &dwProvider); + + // Re-assemble the stream flags + dwStreamFlags = (dwStreamFlags & STREAM_OPTIONS_MASK) | dwProvider; + szFileName += nPrefixLength; + + // Perform provider-specific open + switch(dwStreamFlags & STREAM_PROVIDER_MASK) + { + case STREAM_PROVIDER_FLAT: + return FlatStream_Open(szFileName, dwStreamFlags); + + case STREAM_PROVIDER_PARTIAL: + return PartStream_Open(szFileName, dwStreamFlags); + + case STREAM_PROVIDER_MPQE: + return MpqeStream_Open(szFileName, dwStreamFlags); + + case STREAM_PROVIDER_BLOCK4: + return Block4Stream_Open(szFileName, dwStreamFlags); + + default: + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } +} + +/** + * Returns the file name of the stream + * + * \a pStream Pointer to an open stream + */ +const TCHAR * FileStream_GetFileName(TFileStream * pStream) +{ + assert(pStream != NULL); + return pStream->szFileName; +} + +/** + * Returns the length of the provider prefix. Returns zero if no prefix + * + * \a szFileName Pointer to a stream name (file, mapped file, URL) + * \a pdwStreamProvider Pointer to a DWORD variable that receives stream provider (STREAM_PROVIDER_XXX) + */ + +size_t FileStream_Prefix(const TCHAR * szFileName, DWORD * pdwProvider) +{ + size_t nPrefixLength1 = 0; + size_t nPrefixLength2 = 0; + DWORD dwProvider = 0; + + if(szFileName != NULL) + { + // + // Determine the stream provider + // + + if(!_tcsnicmp(szFileName, _T("flat-"), 5)) + { + dwProvider |= STREAM_PROVIDER_FLAT; + nPrefixLength1 = 5; + } + + else if(!_tcsnicmp(szFileName, _T("part-"), 5)) + { + dwProvider |= STREAM_PROVIDER_PARTIAL; + nPrefixLength1 = 5; + } + + else if(!_tcsnicmp(szFileName, _T("mpqe-"), 5)) + { + dwProvider |= STREAM_PROVIDER_MPQE; + nPrefixLength1 = 5; + } + + else if(!_tcsnicmp(szFileName, _T("blk4-"), 5)) + { + dwProvider |= STREAM_PROVIDER_BLOCK4; + nPrefixLength1 = 5; + } + + // + // Determine the base provider + // + + if(!_tcsnicmp(szFileName+nPrefixLength1, _T("file:"), 5)) + { + dwProvider |= BASE_PROVIDER_FILE; + nPrefixLength2 = 5; + } + + else if(!_tcsnicmp(szFileName+nPrefixLength1, _T("map:"), 4)) + { + dwProvider |= BASE_PROVIDER_MAP; + nPrefixLength2 = 4; + } + + else if(!_tcsnicmp(szFileName+nPrefixLength1, _T("http:"), 5)) + { + dwProvider |= BASE_PROVIDER_HTTP; + nPrefixLength2 = 5; + } + + // Only accept stream provider if we recognized the base provider + if(nPrefixLength2 != 0) + { + // It is also allowed to put "//" after the base provider, e.g. "file://", "http://" + if(szFileName[nPrefixLength1+nPrefixLength2] == '/' && szFileName[nPrefixLength1+nPrefixLength2+1] == '/') + nPrefixLength2 += 2; + + if(pdwProvider != NULL) + *pdwProvider = dwProvider; + return nPrefixLength1 + nPrefixLength2; + } + } + + return 0; +} + +/** + * Sets a download callback. Whenever the stream needs to download one or more blocks + * from the server, the callback is called + * + * \a pStream Pointer to an open stream + * \a pfnCallback Pointer to callback function + * \a pvUserData Arbitrary user pointer passed to the download callback + */ + +bool FileStream_SetCallback(TFileStream * pStream, SFILE_DOWNLOAD_CALLBACK pfnCallback, void * pvUserData) +{ + TBlockStream * pBlockStream = (TBlockStream *)pStream; + + if(pStream->BlockRead == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return false; + } + + pBlockStream->pfnCallback = pfnCallback; + pBlockStream->UserData = pvUserData; + return true; +} + +/** + * This function gives the block map. The 'pvBitmap' pointer must point to a buffer + * of at least sizeof(STREAM_BLOCK_MAP) size. It can also have size of the complete + * block map (i.e. sizeof(STREAM_BLOCK_MAP) + BitmapSize). In that case, the function + * also copies the bit-based block map. + * + * \a pStream Pointer to an open stream + * \a pvBitmap Pointer to buffer where the block map will be stored + * \a cbBitmap Length of the buffer, of the block map + * \a cbLengthNeeded Length of the bitmap, in bytes + */ + +bool FileStream_GetBitmap(TFileStream * pStream, void * pvBitmap, DWORD cbBitmap, DWORD * pcbLengthNeeded) +{ + TStreamBitmap * pBitmap = (TStreamBitmap *)pvBitmap; + TBlockStream * pBlockStream = (TBlockStream *)pStream; + ULONGLONG BlockOffset; + LPBYTE Bitmap = (LPBYTE)(pBitmap + 1); + DWORD BitmapSize; + DWORD BlockCount; + DWORD BlockSize; + bool bResult = false; + + // Retrieve the size of one block + if(pStream->BlockCheck != NULL) + { + BlockCount = pBlockStream->BlockCount; + BlockSize = pBlockStream->BlockSize; + } + else + { + BlockCount = (DWORD)((pStream->StreamSize + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE); + BlockSize = DEFAULT_BLOCK_SIZE; + } + + // Fill-in the variables + BitmapSize = (BlockCount + 7) / 8; + + // Give the number of blocks + if(pcbLengthNeeded != NULL) + pcbLengthNeeded[0] = sizeof(TStreamBitmap) + BitmapSize; + + // If the length of the buffer is not enough + if(pvBitmap != NULL && cbBitmap != 0) + { + // Give the STREAM_BLOCK_MAP structure + if(cbBitmap >= sizeof(TStreamBitmap)) + { + pBitmap->StreamSize = pStream->StreamSize; + pBitmap->BitmapSize = BitmapSize; + pBitmap->BlockCount = BlockCount; + pBitmap->BlockSize = BlockSize; + pBitmap->IsComplete = (pStream->BlockCheck != NULL) ? pBlockStream->IsComplete : 1; + bResult = true; + } + + // Give the block bitmap, if enough space + if(cbBitmap >= sizeof(TStreamBitmap) + BitmapSize) + { + // Version with bitmap present + if(pStream->BlockCheck != NULL) + { + DWORD ByteIndex = 0; + BYTE BitMask = 0x01; + + // Initialize the map with zeros + memset(Bitmap, 0, BitmapSize); + + // Fill the map + for(BlockOffset = 0; BlockOffset < pStream->StreamSize; BlockOffset += BlockSize) + { + // Set the bit if the block is present + if(pBlockStream->BlockCheck(pStream, BlockOffset)) + Bitmap[ByteIndex] |= BitMask; + + // Move bit position + ByteIndex += (BitMask >> 0x07); + BitMask = (BitMask >> 0x07) | (BitMask << 0x01); + } + } + else + { + memset(Bitmap, 0xFF, BitmapSize); + } + } + } + + // Set last error value and return + if(bResult == false) + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return bResult; +} + +/** + * Reads data from the stream + * + * - Returns true if the read operation succeeded and all bytes have been read + * - Returns false if either read failed or not all bytes have been read + * - If the pByteOffset is NULL, the function must read the data from the current file position + * - The function can be called with dwBytesToRead = 0. In that case, pvBuffer is ignored + * and the function just adjusts file pointer. + * + * \a pStream Pointer to an open stream + * \a pByteOffset Pointer to file byte offset. If NULL, it reads from the current position + * \a pvBuffer Pointer to data to be read + * \a dwBytesToRead Number of bytes to read from the file + * + * \returns + * - If the function reads the required amount of bytes, it returns true. + * - If the function reads less than required bytes, it returns false and GetLastError() returns ERROR_HANDLE_EOF + * - If the function fails, it reads false and GetLastError() returns an error code different from ERROR_HANDLE_EOF + */ +bool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead) +{ + assert(pStream->StreamRead != NULL); + return pStream->StreamRead(pStream, pByteOffset, pvBuffer, dwBytesToRead); +} + +/** + * This function writes data to the stream + * + * - Returns true if the write operation succeeded and all bytes have been written + * - Returns false if either write failed or not all bytes have been written + * - If the pByteOffset is NULL, the function must write the data to the current file position + * + * \a pStream Pointer to an open stream + * \a pByteOffset Pointer to file byte offset. If NULL, it reads from the current position + * \a pvBuffer Pointer to data to be written + * \a dwBytesToWrite Number of bytes to write to the file + */ +bool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite) +{ + if(pStream->dwFlags & STREAM_FLAG_READ_ONLY) + { + SetLastError(ERROR_ACCESS_DENIED); + return false; + } + + assert(pStream->StreamWrite != NULL); + return pStream->StreamWrite(pStream, pByteOffset, pvBuffer, dwBytesToWrite); +} + +/** + * Returns the size of a file + * + * \a pStream Pointer to an open stream + * \a FileSize Pointer where to store the file size + */ +bool FileStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize) +{ + assert(pStream->StreamGetSize != NULL); + return pStream->StreamGetSize(pStream, pFileSize); +} + +/** + * Sets the size of a file + * + * \a pStream Pointer to an open stream + * \a NewFileSize File size to set + */ +bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize) +{ + if(pStream->dwFlags & STREAM_FLAG_READ_ONLY) + { + SetLastError(ERROR_ACCESS_DENIED); + return false; + } + + assert(pStream->StreamResize != NULL); + return pStream->StreamResize(pStream, NewFileSize); +} + +/** + * This function returns the current file position + * \a pStream + * \a pByteOffset + */ +bool FileStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset) +{ + assert(pStream->StreamGetPos != NULL); + return pStream->StreamGetPos(pStream, pByteOffset); +} + +/** + * Returns the last write time of a file + * + * \a pStream Pointer to an open stream + * \a pFileType Pointer where to store the file last write time + */ +bool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFileTime) +{ + // Just use the saved filetime value + *pFileTime = pStream->Base.File.FileTime; + return true; +} + +/** + * Returns the stream flags + * + * \a pStream Pointer to an open stream + * \a pdwStreamFlags Pointer where to store the stream flags + */ +bool FileStream_GetFlags(TFileStream * pStream, LPDWORD pdwStreamFlags) +{ + *pdwStreamFlags = pStream->dwFlags; + return true; +} + +/** + * Switches a stream with another. Used for final phase of archive compacting. + * Performs these steps: + * + * 1) Closes the handle to the existing MPQ + * 2) Renames the temporary MPQ to the original MPQ, overwrites existing one + * 3) Opens the MPQ stores the handle and stream position to the new stream structure + * + * \a pStream Pointer to an open stream + * \a pNewStream Temporary ("working") stream (created during archive compacting) + */ +bool FileStream_Replace(TFileStream * pStream, TFileStream * pNewStream) +{ + // Only supported on flat files + if((pStream->dwFlags & STREAM_PROVIDERS_MASK) != (STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE)) + { + SetLastError(ERROR_NOT_SUPPORTED); + return false; + } + + // Not supported on read-only streams + if(pStream->dwFlags & STREAM_FLAG_READ_ONLY) + { + SetLastError(ERROR_ACCESS_DENIED); + return false; + } + + // Close both stream's base providers + pNewStream->BaseClose(pNewStream); + pStream->BaseClose(pStream); + + // Now we have to delete the (now closed) old file and rename the new file + if(!BaseFile_Replace(pStream, pNewStream)) + return false; + + // Now open the base file again + if(!BaseFile_Open(pStream, pStream->szFileName, pStream->dwFlags)) + return false; + + // Cleanup the new stream + FileStream_Close(pNewStream); + return true; +} + +/** + * This function closes an archive file and frees any data buffers + * that have been allocated for stream management. The function must also + * support partially allocated structure, i.e. one or more buffers + * can be NULL, if there was an allocation failure during the process + * + * \a pStream Pointer to an open stream + */ +void FileStream_Close(TFileStream * pStream) +{ + // Check if the stream structure is allocated at all + if(pStream != NULL) + { + // Free the master stream, if any + if(pStream->pMaster != NULL) + FileStream_Close(pStream->pMaster); + pStream->pMaster = NULL; + + // Close the stream provider ... + if(pStream->StreamClose != NULL) + pStream->StreamClose(pStream); + + // ... or close base stream, if any + else if(pStream->BaseClose != NULL) + pStream->BaseClose(pStream); + + // Free the stream itself + STORM_FREE(pStream); + } +} diff --git a/3rdParty/StormLib/src/FileStream.h b/3rdParty/StormLib/src/FileStream.h new file mode 100644 index 000000000..44beeed91 --- /dev/null +++ b/3rdParty/StormLib/src/FileStream.h @@ -0,0 +1,217 @@ +/*****************************************************************************/ +/* FileStream.h Copyright (c) Ladislav Zezula 2012 */ +/*---------------------------------------------------------------------------*/ +/* Description: Definitions for FileStream object */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 14.04.12 1.00 Lad The first version of FileStream.h */ +/*****************************************************************************/ + +#ifndef __FILESTREAM_H__ +#define __FILESTREAM_H__ + +//----------------------------------------------------------------------------- +// Function prototypes + +typedef void (*STREAM_INIT)( + struct TFileStream * pStream // Pointer to an unopened stream +); + +typedef bool (*STREAM_CREATE)( + struct TFileStream * pStream // Pointer to an unopened stream + ); + +typedef bool (*STREAM_OPEN)( + struct TFileStream * pStream, // Pointer to an unopened stream + const TCHAR * szFileName, // Pointer to file name to be open + DWORD dwStreamFlags // Stream flags + ); + +typedef bool (*STREAM_READ)( + struct TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position + void * pvBuffer, // Pointer to data to be read + DWORD dwBytesToRead // Number of bytes to read from the file + ); + +typedef bool (*STREAM_WRITE)( + struct TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it writes to the current position + const void * pvBuffer, // Pointer to data to be written + DWORD dwBytesToWrite // Number of bytes to read from the file + ); + +typedef bool (*STREAM_RESIZE)( + struct TFileStream * pStream, // Pointer to an open stream + ULONGLONG FileSize // New size for the file, in bytes + ); + +typedef bool (*STREAM_GETSIZE)( + struct TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pFileSize // Receives the file size, in bytes + ); + +typedef bool (*STREAM_GETPOS)( + struct TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset // Pointer to store current file position + ); + +typedef void (*STREAM_CLOSE)( + struct TFileStream * pStream // Pointer to an open stream + ); + +typedef bool (*BLOCK_READ)( + struct TFileStream * pStream, // Pointer to a block-oriented stream + ULONGLONG StartOffset, // Byte offset of start of the block array + ULONGLONG EndOffset, // End offset (either end of the block or end of the file) + LPBYTE BlockBuffer, // Pointer to block-aligned buffer + DWORD BytesNeeded, // Number of bytes that are really needed + bool bAvailable // true if the block is available + ); + +typedef bool (*BLOCK_CHECK)( + struct TFileStream * pStream, // Pointer to a block-oriented stream + ULONGLONG BlockOffset // Offset of the file to check + ); + +typedef void (*BLOCK_SAVEMAP)( + struct TFileStream * pStream // Pointer to a block-oriented stream + ); + +//----------------------------------------------------------------------------- +// Local structures - partial file structure and bitmap footer + +#define ID_FILE_BITMAP_FOOTER 0x33767470 // Signature of the file bitmap footer ('ptv3') +#define DEFAULT_BLOCK_SIZE 0x00004000 // Default size of the stream block +#define DEFAULT_BUILD_NUMBER 10958 // Build number for newly created partial MPQs + +typedef struct _PART_FILE_HEADER +{ + DWORD PartialVersion; // Always set to 2 + char GameBuildNumber[0x20]; // Minimum build number of the game that can use this MPQ + DWORD Flags; // Flags (details unknown) + DWORD FileSizeLo; // Low 32 bits of the contained file size + DWORD FileSizeHi; // High 32 bits of the contained file size + DWORD BlockSize; // Size of one file block, in bytes + +} PART_FILE_HEADER, *PPART_FILE_HEADER; + +// Structure describing the block-to-file map entry +typedef struct _PART_FILE_MAP_ENTRY +{ + DWORD Flags; // 3 = the block is present in the file + DWORD BlockOffsLo; // Low 32 bits of the block position in the file + DWORD BlockOffsHi; // High 32 bits of the block position in the file + DWORD LargeValueLo; // 64-bit value, meaning is unknown + DWORD LargeValueHi; + +} PART_FILE_MAP_ENTRY, *PPART_FILE_MAP_ENTRY; + +typedef struct _FILE_BITMAP_FOOTER +{ + DWORD Signature; // 'ptv3' (ID_FILE_BITMAP_FOOTER) + DWORD Version; // Unknown, seems to always have value of 3 (version?) + DWORD BuildNumber; // Game build number for that MPQ + DWORD MapOffsetLo; // Low 32-bits of the offset of the bit map + DWORD MapOffsetHi; // High 32-bits of the offset of the bit map + DWORD BlockSize; // Size of one block (usually 0x4000 bytes) + +} FILE_BITMAP_FOOTER, *PFILE_BITMAP_FOOTER; + +//----------------------------------------------------------------------------- +// Structure for file stream + +union TBaseProviderData +{ + struct + { + ULONGLONG FileSize; // Size of the file + ULONGLONG FilePos; // Current file position + ULONGLONG FileTime; // Last write time + HANDLE hFile; // File handle + } File; + + struct + { + ULONGLONG FileSize; // Size of the file + ULONGLONG FilePos; // Current file position + ULONGLONG FileTime; // Last write time + LPBYTE pbFile; // Pointer to mapped view + } Map; + + struct + { + ULONGLONG FileSize; // Size of the file + ULONGLONG FilePos; // Current file position + ULONGLONG FileTime; // Last write time + HANDLE hInternet; // Internet handle + HANDLE hConnect; // Connection to the internet server + } Http; +}; + +struct TFileStream +{ + // Stream provider functions + STREAM_READ StreamRead; // Pointer to stream read function for this archive. Do not use directly. + STREAM_WRITE StreamWrite; // Pointer to stream write function for this archive. Do not use directly. + STREAM_RESIZE StreamResize; // Pointer to function changing file size + STREAM_GETSIZE StreamGetSize; // Pointer to function returning file size + STREAM_GETPOS StreamGetPos; // Pointer to function that returns current file position + STREAM_CLOSE StreamClose; // Pointer to function closing the stream + + // Block-oriented functions + BLOCK_READ BlockRead; // Pointer to function reading one or more blocks + BLOCK_CHECK BlockCheck; // Pointer to function checking whether the block is present + + // Base provider functions + STREAM_CREATE BaseCreate; // Pointer to base create function + STREAM_OPEN BaseOpen; // Pointer to base open function + STREAM_READ BaseRead; // Read from the stream + STREAM_WRITE BaseWrite; // Write to the stream + STREAM_RESIZE BaseResize; // Pointer to function changing file size + STREAM_GETSIZE BaseGetSize; // Pointer to function returning file size + STREAM_GETPOS BaseGetPos; // Pointer to function that returns current file position + STREAM_CLOSE BaseClose; // Pointer to function closing the stream + + // Base provider data (file size, file position) + TBaseProviderData Base; + + // Stream provider data + TFileStream * pMaster; // Master stream (e.g. MPQ on a web server) + TCHAR * szFileName; // File name (self-relative pointer) + + ULONGLONG StreamSize; // Stream size (can be less than file size) + ULONGLONG StreamPos; // Stream position + DWORD BuildNumber; // Game build number + DWORD dwFlags; // Stream flags + + // Followed by stream provider data, with variable length +}; + +//----------------------------------------------------------------------------- +// Structures for block-oriented stream + +struct TBlockStream : public TFileStream +{ + SFILE_DOWNLOAD_CALLBACK pfnCallback; // Callback for downloading + void * FileBitmap; // Array of bits for file blocks + void * UserData; // User data to be passed to the download callback + DWORD BitmapSize; // Size of the file bitmap (in bytes) + DWORD BlockSize; // Size of one block, in bytes + DWORD BlockCount; // Number of data blocks in the file + DWORD IsComplete; // If nonzero, no blocks are missing + DWORD IsModified; // nonzero if the bitmap has been modified +}; + +//----------------------------------------------------------------------------- +// Structure for encrypted stream + +#define MPQE_CHUNK_SIZE 0x40 // Size of one chunk to be decrypted + +struct TEncryptedStream : public TBlockStream +{ + BYTE Key[MPQE_CHUNK_SIZE]; // File key +}; + +#endif // __FILESTREAM_H__ diff --git a/3rdParty/StormLib/src/SBaseCommon.cpp b/3rdParty/StormLib/src/SBaseCommon.cpp new file mode 100644 index 000000000..83bd075f7 --- /dev/null +++ b/3rdParty/StormLib/src/SBaseCommon.cpp @@ -0,0 +1,1856 @@ +/*****************************************************************************/ +/* SBaseCommon.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Common functions for StormLib, used by all SFile*** modules */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 24.03.03 1.00 Lad The first version of SFileCommon.cpp */ +/* 19.11.03 1.01 Dan Big endian handling */ +/* 12.06.04 1.01 Lad Renamed to SCommon.cpp */ +/* 06.09.10 1.01 Lad Renamed to SBaseCommon.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +char StormLibCopyright[] = "StormLib v " STORMLIB_VERSION_STRING " Copyright Ladislav Zezula 1998-2014"; + +//----------------------------------------------------------------------------- +// Local variables + +LCID lcFileLocale = LANG_NEUTRAL; // File locale +USHORT wPlatform = 0; // File platform + +//----------------------------------------------------------------------------- +// Conversion to uppercase/lowercase + +// Converts ASCII characters to lowercase +// Converts slash (0x2F) to backslash (0x5C) +unsigned char AsciiToLowerTable[256] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x5C, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +// Converts ASCII characters to uppercase +// Converts slash (0x2F) to backslash (0x5C) +unsigned char AsciiToUpperTable[256] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x5C, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +// Converts ASCII characters to uppercase +// Does NOT convert slash (0x2F) to backslash (0x5C) +unsigned char AsciiToUpperTable_Slash[256] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +//----------------------------------------------------------------------------- +// Safe string functions (for ANSI builds) + +void StringCopy(char * szTarget, size_t cchTarget, const char * szSource) +{ + if(cchTarget > 0) + { + size_t cchSource = strlen(szSource); + + if(cchSource >= cchTarget) + cchSource = cchTarget - 1; + + memcpy(szTarget, szSource, cchSource); + szTarget[cchSource] = 0; + } +} + +void StringCat(char * szTarget, size_t cchTargetMax, const char * szSource) +{ + // Get the current length of the target + size_t cchTarget = strlen(szTarget); + + // Copy the string to the target + if(cchTarget < cchTargetMax) + { + StringCopy(szTarget + cchTarget, (cchTargetMax - cchTarget), szSource); + } +} + +//----------------------------------------------------------------------------- +// Utility functions (UNICODE) only exist in the ANSI version of the library +// In ANSI builds, TCHAR = char, so we don't need these functions implemented + +#ifdef _UNICODE +void StringCopy(TCHAR * szTarget, size_t cchTarget, const char * szSource) +{ + if(cchTarget > 0) + { + size_t cchSource = strlen(szSource); + + if(cchSource >= cchTarget) + cchSource = cchTarget - 1; + + mbstowcs(szTarget, szSource, cchSource); + szTarget[cchSource] = 0; + } +} + +void StringCopy(char * szTarget, size_t cchTarget, const TCHAR * szSource) +{ + if(cchTarget > 0) + { + size_t cchSource = _tcslen(szSource); + + if(cchSource >= cchTarget) + cchSource = cchTarget - 1; + + wcstombs(szTarget, szSource, cchSource); + szTarget[cchSource] = 0; + } +} + +void StringCopy(TCHAR * szTarget, size_t cchTarget, const TCHAR * szSource) +{ + if(cchTarget > 0) + { + size_t cchSource = _tcslen(szSource); + + if(cchSource >= cchTarget) + cchSource = cchTarget - 1; + + memcpy(szTarget, szSource, cchSource * sizeof(TCHAR)); + szTarget[cchSource] = 0; + } +} + +void StringCat(TCHAR * szTarget, size_t cchTargetMax, const TCHAR * szSource) +{ + // Get the current length of the target + size_t cchTarget = _tcslen(szTarget); + + // Copy the string to the target + if(cchTarget < cchTargetMax) + { + StringCopy(szTarget + cchTarget, (cchTargetMax - cchTarget), szSource); + } +} +#endif + +//----------------------------------------------------------------------------- +// Storm hashing functions + +#define STORM_BUFFER_SIZE 0x500 +#define HASH_INDEX_MASK(ha) (ha->pHeader->dwHashTableSize ? (ha->pHeader->dwHashTableSize - 1) : 0) + +static DWORD StormBuffer[STORM_BUFFER_SIZE]; // Buffer for the decryption engine +static bool bMpqCryptographyInitialized = false; + +void InitializeMpqCryptography() +{ + DWORD dwSeed = 0x00100001; + DWORD index1 = 0; + DWORD index2 = 0; + int i; + + // Initialize the decryption buffer. + // Do nothing if already done. + if(bMpqCryptographyInitialized == false) + { + for(index1 = 0; index1 < 0x100; index1++) + { + for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100) + { + DWORD temp1, temp2; + + dwSeed = (dwSeed * 125 + 3) % 0x2AAAAB; + temp1 = (dwSeed & 0xFFFF) << 0x10; + + dwSeed = (dwSeed * 125 + 3) % 0x2AAAAB; + temp2 = (dwSeed & 0xFFFF); + + StormBuffer[index2] = (temp1 | temp2); + } + } + +#ifdef FULL + // Also register both MD5 and SHA1 hash algorithms + register_hash(&md5_desc); + register_hash(&sha1_desc); + + // Use LibTomMath as support math library for LibTomCrypt + ltc_mp = ltm_desc; +#endif + // Don't do that again + bMpqCryptographyInitialized = true; + } +} + +// +// Note: Implementation of this function in WorldEdit.exe and storm.dll +// incorrectly treats the character as signed, which leads to the +// a buffer underflow if the character in the file name >= 0x80: +// The following steps happen when *pbKey == 0xBF and dwHashType == 0x0000 +// (calculating hash index) +// +// 1) Result of AsciiToUpperTable_Slash[*pbKey++] is sign-extended to 0xffffffbf +// 2) The "ch" is added to dwHashType (0xffffffbf + 0x0000 => 0xffffffbf) +// 3) The result is used as index to the StormBuffer table, +// thus dereferences a random value BEFORE the begin of StormBuffer. +// +// As result, MPQs containing files with non-ANSI characters will not work between +// various game versions and localizations. Even WorldEdit, after importing a file +// with Korean characters in the name, cannot open the file back. +// +DWORD HashString(const char * szFileName, DWORD dwHashType) +{ + LPBYTE pbKey = (BYTE *)szFileName; + DWORD dwSeed1 = 0x7FED7FED; + DWORD dwSeed2 = 0xEEEEEEEE; + DWORD ch; + + while(*pbKey != 0) + { + // Convert the input character to uppercase + // Convert slash (0x2F) to backslash (0x5C) + ch = AsciiToUpperTable[*pbKey++]; + + dwSeed1 = StormBuffer[dwHashType + ch] ^ (dwSeed1 + dwSeed2); + dwSeed2 = ch + dwSeed1 + dwSeed2 + (dwSeed2 << 5) + 3; + } + + return dwSeed1; +} + +DWORD HashStringSlash(const char * szFileName, DWORD dwHashType) +{ + LPBYTE pbKey = (BYTE *)szFileName; + DWORD dwSeed1 = 0x7FED7FED; + DWORD dwSeed2 = 0xEEEEEEEE; + DWORD ch; + + while(*pbKey != 0) + { + // Convert the input character to uppercase + // DON'T convert slash (0x2F) to backslash (0x5C) + ch = AsciiToUpperTable_Slash[*pbKey++]; + + dwSeed1 = StormBuffer[dwHashType + ch] ^ (dwSeed1 + dwSeed2); + dwSeed2 = ch + dwSeed1 + dwSeed2 + (dwSeed2 << 5) + 3; + } + + return dwSeed1; +} + +DWORD HashStringLower(const char * szFileName, DWORD dwHashType) +{ + LPBYTE pbKey = (BYTE *)szFileName; + DWORD dwSeed1 = 0x7FED7FED; + DWORD dwSeed2 = 0xEEEEEEEE; + DWORD ch; + + while(*pbKey != 0) + { + // Convert the input character to lower + // DON'T convert slash (0x2F) to backslash (0x5C) + ch = AsciiToLowerTable[*pbKey++]; + + dwSeed1 = StormBuffer[dwHashType + ch] ^ (dwSeed1 + dwSeed2); + dwSeed2 = ch + dwSeed1 + dwSeed2 + (dwSeed2 << 5) + 3; + } + + return dwSeed1; +} + +//----------------------------------------------------------------------------- +// Calculates the hash table size for a given amount of files + +// Returns the nearest higher power of two. +// If the value is already a power of two, returns the same value +DWORD GetNearestPowerOfTwo(DWORD dwFileCount) +{ + dwFileCount --; + + dwFileCount |= dwFileCount >> 1; + dwFileCount |= dwFileCount >> 2; + dwFileCount |= dwFileCount >> 4; + dwFileCount |= dwFileCount >> 8; + dwFileCount |= dwFileCount >> 16; + + return dwFileCount + 1; +} +/* +DWORD GetNearestPowerOfTwo(DWORD dwFileCount) +{ + DWORD dwPowerOfTwo = HASH_TABLE_SIZE_MIN; + + // For zero files, there is no hash table needed + if(dwFileCount == 0) + return 0; + + // Round the hash table size up to the nearest power of two + // Don't allow the hash table size go over allowed maximum + while(dwPowerOfTwo < HASH_TABLE_SIZE_MAX && dwPowerOfTwo < dwFileCount) + dwPowerOfTwo <<= 1; + return dwPowerOfTwo; +} +*/ + +#ifdef FULL +//----------------------------------------------------------------------------- +// Calculates a Jenkin's Encrypting and decrypting MPQ file data + +ULONGLONG HashStringJenkins(const char * szFileName) +{ + LPBYTE pbFileName = (LPBYTE)szFileName; + char szNameBuff[0x108]; + size_t nLength = 0; + unsigned int primary_hash = 1; + unsigned int secondary_hash = 2; + + // Normalize the file name - convert to uppercase, and convert "/" to "\\". + if(pbFileName != NULL) + { + char * szNamePtr = szNameBuff; + char * szNameEnd = szNamePtr + sizeof(szNameBuff); + + // Normalize the file name. Doesn't have to be zero terminated for hashing + while(szNamePtr < szNameEnd && pbFileName[0] != 0) + *szNamePtr++ = (char)AsciiToLowerTable[*pbFileName++]; + nLength = szNamePtr - szNameBuff; + } + + // Thanks Quantam for finding out what the algorithm is. + // I am really getting old for reversing large chunks of assembly + // that does hashing :-) + hashlittle2(szNameBuff, nLength, &secondary_hash, &primary_hash); + + // Combine those 2 together + return ((ULONGLONG)primary_hash << 0x20) | (ULONGLONG)secondary_hash; +} +#endif + +//----------------------------------------------------------------------------- +// Default flags for (attributes) and (listfile) + +DWORD GetDefaultSpecialFileFlags(DWORD dwFileSize, USHORT wFormatVersion) +{ + // Fixed for format 1.0 + if(wFormatVersion == MPQ_FORMAT_VERSION_1) + return MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY; + + // Size-dependent for formats 2.0-4.0 + return (dwFileSize > 0x4000) ? (MPQ_FILE_COMPRESS | MPQ_FILE_SECTOR_CRC) : (MPQ_FILE_COMPRESS | MPQ_FILE_SINGLE_UNIT); +} + + +//----------------------------------------------------------------------------- +// Encrypting/Decrypting MPQ data block + +void EncryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) +{ + LPDWORD DataBlock = (LPDWORD)pvDataBlock; + DWORD dwValue32; + DWORD dwKey2 = 0xEEEEEEEE; + + // Round to DWORDs + dwLength >>= 2; + + // Encrypt the data block at array of DWORDs + for(DWORD i = 0; i < dwLength; i++) + { + // Modify the second key + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + + dwValue32 = DataBlock[i]; + DataBlock[i] = DataBlock[i] ^ (dwKey1 + dwKey2); + + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; + } +} + +void DecryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) +{ + LPDWORD DataBlock = (LPDWORD)pvDataBlock; + DWORD dwValue32; + DWORD dwKey2 = 0xEEEEEEEE; + + // Round to DWORDs + dwLength >>= 2; + + // Decrypt the data block at array of DWORDs + for(DWORD i = 0; i < dwLength; i++) + { + // Modify the second key + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + + DataBlock[i] = DataBlock[i] ^ (dwKey1 + dwKey2); + dwValue32 = DataBlock[i]; + + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; + } +} + +/** + * Functions tries to get file decryption key. This comes from these facts + * + * - We know the decrypted value of the first DWORD in the encrypted data + * - We know the decrypted value of the second DWORD (at least aproximately) + * - There is only 256 variants of how the second key is modified + * + * The first iteration of dwKey1 and dwKey2 is this: + * + * dwKey2 = 0xEEEEEEEE + StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)] + * dwDecrypted0 = DataBlock[0] ^ (dwKey1 + dwKey2); + * + * This means: + * + * (dwKey1 + dwKey2) = DataBlock[0] ^ dwDecrypted0; + * + */ + +DWORD DetectFileKeyBySectorSize(LPDWORD EncryptedData, DWORD dwSectorSize, DWORD dwDecrypted0) +{ + DWORD dwDecrypted1Max = dwSectorSize + dwDecrypted0; + DWORD dwKey1PlusKey2; + DWORD DataBlock[2]; + + // We must have at least 2 DWORDs there to be able to decrypt something + if(dwSectorSize < 0x08) + return 0; + + // Get the value of the combined encryption key + dwKey1PlusKey2 = (EncryptedData[0] ^ dwDecrypted0) - 0xEEEEEEEE; + + // Try all 256 combinations of dwKey1 + for(DWORD i = 0; i < 0x100; i++) + { + DWORD dwSaveKey1; + DWORD dwKey1 = dwKey1PlusKey2 - StormBuffer[MPQ_HASH_KEY2_MIX + i]; + DWORD dwKey2 = 0xEEEEEEEE; + + // Modify the second key and decrypt the first DWORD + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + DataBlock[0] = EncryptedData[0] ^ (dwKey1 + dwKey2); + + // Did we obtain the same value like dwDecrypted0? + if(DataBlock[0] == dwDecrypted0) + { + // Save this key value. Increment by one because + // we are decrypting sector offset table + dwSaveKey1 = dwKey1 + 1; + + // Rotate both keys + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = DataBlock[0] + dwKey2 + (dwKey2 << 5) + 3; + + // Modify the second key again and decrypt the second DWORD + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + DataBlock[1] = EncryptedData[1] ^ (dwKey1 + dwKey2); + + // Now compare the results + if(DataBlock[1] <= dwDecrypted1Max) + return dwSaveKey1; + } + } + + // Key not found + return 0; +} + +// Function tries to detect file encryption key based on expected file content +// It is the same function like before, except that we know the value of the second DWORD +DWORD DetectFileKeyByKnownContent(void * pvEncryptedData, DWORD dwDecrypted0, DWORD dwDecrypted1) +{ + LPDWORD EncryptedData = (LPDWORD)pvEncryptedData; + DWORD dwKey1PlusKey2; + DWORD DataBlock[2]; + + // Get the value of the combined encryption key + dwKey1PlusKey2 = (EncryptedData[0] ^ dwDecrypted0) - 0xEEEEEEEE; + + // Try all 256 combinations of dwKey1 + for(DWORD i = 0; i < 0x100; i++) + { + DWORD dwSaveKey1; + DWORD dwKey1 = dwKey1PlusKey2 - StormBuffer[MPQ_HASH_KEY2_MIX + i]; + DWORD dwKey2 = 0xEEEEEEEE; + + // Modify the second key and decrypt the first DWORD + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + DataBlock[0] = EncryptedData[0] ^ (dwKey1 + dwKey2); + + // Did we obtain the same value like dwDecrypted0? + if(DataBlock[0] == dwDecrypted0) + { + // Save this key value + dwSaveKey1 = dwKey1; + + // Rotate both keys + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = DataBlock[0] + dwKey2 + (dwKey2 << 5) + 3; + + // Modify the second key again and decrypt the second DWORD + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + DataBlock[1] = EncryptedData[1] ^ (dwKey1 + dwKey2); + + // Now compare the results + if(DataBlock[1] == dwDecrypted1) + return dwSaveKey1; + } + } + + // Key not found + return 0; +} + +DWORD DetectFileKeyByContent(void * pvEncryptedData, DWORD dwSectorSize, DWORD dwFileSize) +{ + DWORD dwFileKey; + + // Try to break the file encryption key as if it was a WAVE file + if(dwSectorSize >= 0x0C) + { + dwFileKey = DetectFileKeyByKnownContent(pvEncryptedData, 0x46464952, dwFileSize - 8); + if(dwFileKey != 0) + return dwFileKey; + } + + // Try to break the encryption key as if it was an EXE file + if(dwSectorSize > 0x40) + { + dwFileKey = DetectFileKeyByKnownContent(pvEncryptedData, 0x00905A4D, 0x00000003); + if(dwFileKey != 0) + return dwFileKey; + } + + // Try to break the encryption key as if it was a XML file + if(dwSectorSize > 0x04) + { + dwFileKey = DetectFileKeyByKnownContent(pvEncryptedData, 0x6D783F3C, 0x6576206C); + if(dwFileKey != 0) + return dwFileKey; + } + + // Not detected, sorry + return 0; +} + +DWORD DecryptFileKey( + const char * szFileName, + ULONGLONG MpqPos, + DWORD dwFileSize, + DWORD dwFlags) +{ + DWORD dwFileKey; + DWORD dwMpqPos = (DWORD)MpqPos; + + // File key is calculated from plain name + szFileName = GetPlainFileName(szFileName); + dwFileKey = HashString(szFileName, MPQ_HASH_FILE_KEY); + + // Fix the key, if needed + if(dwFlags & MPQ_FILE_FIX_KEY) + dwFileKey = (dwFileKey + dwMpqPos) ^ dwFileSize; + + // Return the key + return dwFileKey; +} + +//----------------------------------------------------------------------------- +// Handle validation functions + +TMPQArchive * IsValidMpqHandle(HANDLE hMpq) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + + return (ha != NULL && ha->pHeader != NULL && ha->pHeader->dwID == ID_MPQ) ? ha : NULL; +} + +TMPQFile * IsValidFileHandle(HANDLE hFile) +{ + TMPQFile * hf = (TMPQFile *)hFile; + + // Must not be NULL + if(hf != NULL && hf->dwMagic == ID_MPQ_FILE) + { + // Local file handle? + if(hf->pStream != NULL) + return hf; + + // Also verify the MPQ handle within the file handle + if(IsValidMpqHandle(hf->ha)) + return hf; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Hash table and block table manipulation + +// Attempts to search a free hash entry, or an entry whose names and locale matches +TMPQHash * FindFreeHashEntry(TMPQArchive * ha, DWORD dwStartIndex, DWORD dwName1, DWORD dwName2, LCID lcLocale) +{ + TMPQHash * pDeletedEntry = NULL; // If a deleted entry was found in the continuous hash range + TMPQHash * pFreeEntry = NULL; // If a free entry was found in the continuous hash range + DWORD dwHashIndexMask = HASH_INDEX_MASK(ha); + DWORD dwIndex; + + // Set the initial index + dwStartIndex = dwIndex = (dwStartIndex & dwHashIndexMask); + + // Search the hash table and return the found entries in the following priority: + // 1) + // 2) + // 3) + // 4) NULL + for(;;) + { + TMPQHash * pHash = ha->pHashTable + dwIndex; + + // If we found a matching entry, return that one + if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->lcLocale == lcLocale) + return pHash; + + // If we found a deleted entry, remember it but keep searching + if(pHash->dwBlockIndex == HASH_ENTRY_DELETED && pDeletedEntry == NULL) + pDeletedEntry = pHash; + + // If we found a free entry, we need to stop searching + if(pHash->dwBlockIndex == HASH_ENTRY_FREE) + { + pFreeEntry = pHash; + break; + } + + // Move to the next hash entry. + // If we reached the starting entry, it's failure. + dwIndex = (dwIndex + 1) & dwHashIndexMask; + if(dwIndex == dwStartIndex) + break; + } + + // If we found a deleted entry, return that one preferentially + return (pDeletedEntry != NULL) ? pDeletedEntry : pFreeEntry; +} + +// Retrieves the first hash entry for the given file. +// Every locale version of a file has its own hash entry +TMPQHash * GetFirstHashEntry(TMPQArchive * ha, const char * szFileName) +{ + DWORD dwHashIndexMask = HASH_INDEX_MASK(ha); + DWORD dwStartIndex = ha->pfnHashString(szFileName, MPQ_HASH_TABLE_INDEX); + DWORD dwName1 = ha->pfnHashString(szFileName, MPQ_HASH_NAME_A); + DWORD dwName2 = ha->pfnHashString(szFileName, MPQ_HASH_NAME_B); + DWORD dwIndex; + + // Set the initial index + dwStartIndex = dwIndex = (dwStartIndex & dwHashIndexMask); + + // Search the hash table + for(;;) + { + TMPQHash * pHash = ha->pHashTable + dwIndex; + + // If the entry matches, we found it. + if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) + return pHash; + + // If that hash entry is a free entry, it means we haven't found the file + if(pHash->dwBlockIndex == HASH_ENTRY_FREE) + return NULL; + + // Move to the next hash entry. Stop searching + // if we got reached the original hash entry + dwIndex = (dwIndex + 1) & dwHashIndexMask; + if(dwIndex == dwStartIndex) + return NULL; + } +} + +TMPQHash * GetNextHashEntry(TMPQArchive * ha, TMPQHash * pFirstHash, TMPQHash * pHash) +{ + DWORD dwHashIndexMask = HASH_INDEX_MASK(ha); + DWORD dwStartIndex = (DWORD)(pFirstHash - ha->pHashTable); + DWORD dwName1 = pHash->dwName1; + DWORD dwName2 = pHash->dwName2; + DWORD dwIndex = (DWORD)(pHash - ha->pHashTable); + + // Now go for any next entry that follows the pHash, + // until either free hash entry was found, or the start entry was reached + for(;;) + { + // Move to the next hash entry. Stop searching + // if we got reached the original hash entry + dwIndex = (dwIndex + 1) & dwHashIndexMask; + if(dwIndex == dwStartIndex) + return NULL; + pHash = ha->pHashTable + dwIndex; + + // If the entry matches, we found it. + if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) + return pHash; + + // If that hash entry is a free entry, it means we haven't found the file + if(pHash->dwBlockIndex == HASH_ENTRY_FREE) + return NULL; + } +} + +// Allocates an entry in the hash table +TMPQHash * AllocateHashEntry( + TMPQArchive * ha, + TFileEntry * pFileEntry, + LCID lcLocale) +{ + TMPQHash * pHash; + DWORD dwStartIndex = ha->pfnHashString(pFileEntry->szFileName, MPQ_HASH_TABLE_INDEX); + DWORD dwName1 = ha->pfnHashString(pFileEntry->szFileName, MPQ_HASH_NAME_A); + DWORD dwName2 = ha->pfnHashString(pFileEntry->szFileName, MPQ_HASH_NAME_B); + + // Attempt to find a free hash entry + pHash = FindFreeHashEntry(ha, dwStartIndex, dwName1, dwName2, lcLocale); + if(pHash != NULL) + { + // Fill the free hash entry + pHash->dwName1 = dwName1; + pHash->dwName2 = dwName2; + pHash->lcLocale = (USHORT)lcLocale; + pHash->Platform = 0; + pHash->dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable); + } + + return pHash; +} + +// Finds a free space in the MPQ where to store next data +// The free space begins beyond the file that is stored at the fuhrtest +// position in the MPQ. (listfile), (attributes) and (signature) are ignored, +// unless the MPQ is being flushed. +ULONGLONG FindFreeMpqSpace(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + ULONGLONG FreeSpacePos = ha->pHeader->dwHeaderSize; + DWORD dwChunkCount; + + // Parse the entire block table + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Only take existing files with nonzero size + if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && (pFileEntry->dwCmpSize != 0)) + { + // If we are not saving MPQ tables, ignore internal MPQ files + if((ha->dwFlags & MPQ_FLAG_SAVING_TABLES) == 0 && IsInternalMpqFileName(pFileEntry->szFileName)) + continue; + + // If the end of the file is bigger than current MPQ table pos, update it + if((pFileEntry->ByteOffset + pFileEntry->dwCmpSize) > FreeSpacePos) + { + // Get the end of the file data + FreeSpacePos = pFileEntry->ByteOffset + pFileEntry->dwCmpSize; + + // Add the MD5 chunks, if present + if(pHeader->dwRawChunkSize != 0 && pFileEntry->dwCmpSize != 0) + { + dwChunkCount = ((pFileEntry->dwCmpSize - 1) / pHeader->dwRawChunkSize) + 1; + FreeSpacePos += dwChunkCount * MD5_DIGEST_SIZE; + } + } + } + } + + // Give the free space position to the caller + return FreeSpacePos; +} + +//----------------------------------------------------------------------------- +// Common functions - MPQ File + +TMPQFile * CreateFileHandle(TMPQArchive * ha, TFileEntry * pFileEntry) +{ + TMPQFile * hf; + + // Allocate space for TMPQFile + hf = STORM_ALLOC(TMPQFile, 1); + if(hf != NULL) + { + // Fill the file structure + memset(hf, 0, sizeof(TMPQFile)); + hf->dwMagic = ID_MPQ_FILE; + hf->pStream = NULL; + hf->ha = ha; + + // If the called entered a file entry, we also copy informations from the file entry + if(ha != NULL && pFileEntry != NULL) + { + // Set the raw position and MPQ position + hf->RawFilePos = FileOffsetFromMpqOffset(ha, pFileEntry->ByteOffset); + hf->MpqFilePos = pFileEntry->ByteOffset; + + // Set the data size + hf->dwDataSize = pFileEntry->dwFileSize; + hf->pFileEntry = pFileEntry; + } + } + + return hf; +} + +TMPQFile * CreateWritableHandle(TMPQArchive * ha, DWORD dwFileSize) +{ + ULONGLONG FreeMpqSpace; + ULONGLONG TempPos; + TMPQFile * hf; + + // We need to find the position in the MPQ where we save the file data + FreeMpqSpace = FindFreeMpqSpace(ha); + + // When format V1, the size of the archive cannot exceed 4 GB + if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) + { + TempPos = FreeMpqSpace + + dwFileSize + + (ha->pHeader->dwHashTableSize * sizeof(TMPQHash)) + + (ha->dwFileTableSize * sizeof(TMPQBlock)); + if((TempPos >> 32) != 0) + { + SetLastError(ERROR_DISK_FULL); + return NULL; + } + } + + // Allocate the file handle + hf = CreateFileHandle(ha, NULL); + if(hf == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + // We need to find the position in the MPQ where we save the file data + hf->MpqFilePos = FreeMpqSpace; + hf->bIsWriteHandle = true; + return hf; +} + +// Loads a table from MPQ. +// Can be used for hash table, block table, sector offset table or sector checksum table +void * LoadMpqTable( + TMPQArchive * ha, + ULONGLONG ByteOffset, + DWORD dwCompressedSize, + DWORD dwTableSize, + DWORD dwKey, + bool * pbTableIsCut) +{ + ULONGLONG FileSize = 0; + LPBYTE pbCompressed = NULL; + LPBYTE pbMpqTable; + LPBYTE pbToRead; + DWORD dwBytesToRead = dwCompressedSize; + int nError = ERROR_SUCCESS; + + // Allocate the MPQ table + pbMpqTable = pbToRead = STORM_ALLOC(BYTE, dwTableSize); + if(pbMpqTable != NULL) + { + // Check if the MPQ table is encrypted + if(dwCompressedSize < dwTableSize) + { + // Allocate temporary buffer for holding compressed data + pbCompressed = pbToRead = STORM_ALLOC(BYTE, dwCompressedSize); + if(pbCompressed == NULL) + { + STORM_FREE(pbMpqTable); + return NULL; + } + } + + // Get the file offset from which we will read the table + // Note: According to Storm.dll from Warcraft III (version 2002), + // if the hash table position is 0xFFFFFFFF, no SetFilePointer call is done + // and the table is loaded from the current file offset + if(ByteOffset == SFILE_INVALID_POS) + FileStream_GetPos(ha->pStream, &ByteOffset); + + // On archives v 1.0, hash table and block table can go beyond EOF. + // Storm.dll reads as much as possible, then fills the missing part with zeros. + // Abused by Spazzler map protector which sets hash table size to 0x00100000 + if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) + { + // Cut the table size + FileStream_GetSize(ha->pStream, &FileSize); + if((ByteOffset + dwBytesToRead) > FileSize) + { + // Fill the extra data with zeros + dwBytesToRead = (DWORD)(FileSize - ByteOffset); + memset(pbMpqTable + dwBytesToRead, 0, (dwTableSize - dwBytesToRead)); + + // Give the caller information that the table was cut + if(pbTableIsCut != NULL) + pbTableIsCut[0] = true; + } + } + + // If everything succeeded, read the raw table form the MPQ + if(FileStream_Read(ha->pStream, &ByteOffset, pbToRead, dwBytesToRead)) + { + // First of all, decrypt the table + if(dwKey != 0) + { + BSWAP_ARRAY32_UNSIGNED(pbToRead, dwCompressedSize); + DecryptMpqBlock(pbToRead, dwCompressedSize, dwKey); + BSWAP_ARRAY32_UNSIGNED(pbToRead, dwCompressedSize); + } + + // If the table is compressed, decompress it + if(dwCompressedSize < dwTableSize) + { + int cbOutBuffer = (int)dwTableSize; + int cbInBuffer = (int)dwCompressedSize; + + if(!SCompDecompress2(pbMpqTable, &cbOutBuffer, pbCompressed, cbInBuffer)) + nError = GetLastError(); + } + + // Make sure that the table is properly byte-swapped + BSWAP_ARRAY32_UNSIGNED(pbMpqTable, dwTableSize); + } + else + { + nError = GetLastError(); + } + + // If read failed, free the table and return + if(nError != ERROR_SUCCESS) + { + STORM_FREE(pbMpqTable); + pbMpqTable = NULL; + } + + // Free the compression buffer, if any + if(pbCompressed != NULL) + STORM_FREE(pbCompressed); + } + + // Return the MPQ table + return pbMpqTable; +} + +unsigned char * AllocateMd5Buffer( + DWORD dwRawDataSize, + DWORD dwChunkSize, + LPDWORD pcbMd5Size) +{ + unsigned char * md5_array; + DWORD cbMd5Size; + + // Sanity check + assert(dwRawDataSize != 0); + assert(dwChunkSize != 0); + + // Calculate how many MD5's we will calculate + cbMd5Size = (((dwRawDataSize - 1) / dwChunkSize) + 1) * MD5_DIGEST_SIZE; + + // Allocate space for array or MD5s + md5_array = STORM_ALLOC(BYTE, cbMd5Size); + + // Give the size of the MD5 array + if(pcbMd5Size != NULL) + *pcbMd5Size = cbMd5Size; + return md5_array; +} + +// Allocates sector buffer and sector offset table +int AllocateSectorBuffer(TMPQFile * hf) +{ + TMPQArchive * ha = hf->ha; + + // Caller of AllocateSectorBuffer must ensure these + assert(hf->pbFileSector == NULL); + assert(hf->pFileEntry != NULL); + assert(hf->ha != NULL); + + // Don't allocate anything if the file has zero size + if(hf->pFileEntry->dwFileSize == 0 || hf->dwDataSize == 0) + return ERROR_SUCCESS; + + // Determine the file sector size and allocate buffer for it + hf->dwSectorSize = (hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) ? hf->dwDataSize : ha->dwSectorSize; + hf->pbFileSector = STORM_ALLOC(BYTE, hf->dwSectorSize); + hf->dwSectorOffs = SFILE_INVALID_POS; + + // Return result + return (hf->pbFileSector != NULL) ? (int)ERROR_SUCCESS : (int)ERROR_NOT_ENOUGH_MEMORY; +} + +// Allocates sector offset table +int AllocatePatchInfo(TMPQFile * hf, bool bLoadFromFile) +{ + TMPQArchive * ha = hf->ha; + DWORD dwLength = sizeof(TPatchInfo); + + // The following conditions must be true + assert(hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE); + assert(hf->pPatchInfo == NULL); + +__AllocateAndLoadPatchInfo: + + // Allocate space for patch header. Start with default size, + // and if its size if bigger, then we reload them + hf->pPatchInfo = STORM_ALLOC(TPatchInfo, 1); + if(hf->pPatchInfo == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Do we have to load the patch header from the file ? + if(bLoadFromFile) + { + // Load the patch header + if(!FileStream_Read(ha->pStream, &hf->RawFilePos, hf->pPatchInfo, dwLength)) + { + // Free the patch info + STORM_FREE(hf->pPatchInfo); + hf->pPatchInfo = NULL; + return GetLastError(); + } + + // Perform necessary swapping + hf->pPatchInfo->dwLength = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwLength); + hf->pPatchInfo->dwFlags = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwFlags); + hf->pPatchInfo->dwDataSize = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwDataSize); + + // Verify the size of the patch header + // If it's not default size, we have to reload them + if(hf->pPatchInfo->dwLength > dwLength) + { + // Free the patch info + dwLength = hf->pPatchInfo->dwLength; + STORM_FREE(hf->pPatchInfo); + hf->pPatchInfo = NULL; + + // If the length is out of all possible ranges, fail the operation + if(dwLength > 0x400) + return ERROR_FILE_CORRUPT; + goto __AllocateAndLoadPatchInfo; + } + + // Patch file data size according to the patch header + hf->dwDataSize = hf->pPatchInfo->dwDataSize; + } + else + { + memset(hf->pPatchInfo, 0, dwLength); + } + + // Save the final length to the patch header + hf->pPatchInfo->dwLength = dwLength; + hf->pPatchInfo->dwFlags = 0x80000000; + return ERROR_SUCCESS; +} + +// Allocates sector offset table +int AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile) +{ + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + DWORD dwSectorOffsLen; + bool bSectorOffsetTableCorrupt = false; + + // Caller of AllocateSectorOffsets must ensure these + assert(hf->SectorOffsets == NULL); + assert(hf->pFileEntry != NULL); + assert(hf->dwDataSize != 0); + assert(hf->ha != NULL); + + // If the file is stored as single unit, just set number of sectors to 1 + if(pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) + { + hf->dwSectorCount = 1; + return ERROR_SUCCESS; + } + + // Calculate the number of data sectors + // Note that this doesn't work if the file size is zero + hf->dwSectorCount = ((hf->dwDataSize - 1) / hf->dwSectorSize) + 1; + + // Calculate the number of file sectors + dwSectorOffsLen = (hf->dwSectorCount + 1) * sizeof(DWORD); + + // If MPQ_FILE_SECTOR_CRC flag is set, there will either be extra DWORD + // or an array of MD5's. Either way, we read at least 4 bytes more + // in order to save additional read from the file. + if(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) + dwSectorOffsLen += sizeof(DWORD); + + // Only allocate and load the table if the file is compressed + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + __LoadSectorOffsets: + + // Allocate the sector offset table + hf->SectorOffsets = STORM_ALLOC(DWORD, (dwSectorOffsLen / sizeof(DWORD))); + if(hf->SectorOffsets == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Only read from the file if we are supposed to do so + if(bLoadFromFile) + { + ULONGLONG RawFilePos = hf->RawFilePos; + + // Append the length of the patch info, if any + if(hf->pPatchInfo != NULL) + { + if((RawFilePos + hf->pPatchInfo->dwLength) < RawFilePos) + return ERROR_FILE_CORRUPT; + RawFilePos += hf->pPatchInfo->dwLength; + } + + // Load the sector offsets from the file + if(!FileStream_Read(ha->pStream, &RawFilePos, hf->SectorOffsets, dwSectorOffsLen)) + { + // Free the sector offsets + STORM_FREE(hf->SectorOffsets); + hf->SectorOffsets = NULL; + return GetLastError(); + } + + // Swap the sector positions + BSWAP_ARRAY32_UNSIGNED(hf->SectorOffsets, dwSectorOffsLen); + + // Decrypt loaded sector positions if necessary + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + // If we don't know the file key, try to find it. + if(hf->dwFileKey == 0) + { + hf->dwFileKey = DetectFileKeyBySectorSize(hf->SectorOffsets, ha->dwSectorSize, dwSectorOffsLen); + if(hf->dwFileKey == 0) + { + STORM_FREE(hf->SectorOffsets); + hf->SectorOffsets = NULL; + return ERROR_UNKNOWN_FILE_KEY; + } + } + + // Decrypt sector positions + DecryptMpqBlock(hf->SectorOffsets, dwSectorOffsLen, hf->dwFileKey - 1); + } + + // + // Validate the sector offset table + // + // Note: Some MPQ protectors put the actual file data before the sector offset table. + // In this case, the sector offsets are negative (> 0x80000000). + // + + for(DWORD i = 0; i < hf->dwSectorCount; i++) + { + DWORD dwSectorOffset1 = hf->SectorOffsets[i+1]; + DWORD dwSectorOffset0 = hf->SectorOffsets[i]; + + // Every following sector offset must be bigger than the previous one + if(dwSectorOffset1 <= dwSectorOffset0) + { + bSectorOffsetTableCorrupt = true; + break; + } + + // The sector size must not be bigger than compressed file size + // Edit: Yes, but apparently, in original Storm.dll, the compressed + // size is not checked anywhere. However, we need to do this check + // in order to sector offset table malformed by MPQ protectors + if((dwSectorOffset1 - dwSectorOffset0) > ha->dwSectorSize) + { + bSectorOffsetTableCorrupt = true; + break; + } + } + + // If data corruption detected, free the sector offset table + if(bSectorOffsetTableCorrupt) + { + STORM_FREE(hf->SectorOffsets); + hf->SectorOffsets = NULL; + return ERROR_FILE_CORRUPT; + } + + // + // There may be various extra DWORDs loaded after the sector offset table. + // They are mostly empty on WoW release MPQs, but on MPQs from PTR, + // they contain random non-zero data. Their meaning is unknown. + // + // These extra values are, however, include in the dwCmpSize in the file + // table. We cannot ignore them, because compacting archive would fail + // + + if(hf->SectorOffsets[0] > dwSectorOffsLen) + { + // MPQ protectors put some ridiculous values there. We must limit the extra bytes + if(hf->SectorOffsets[0] > (dwSectorOffsLen + 0x400)) + return ERROR_FILE_CORRUPT; + + // Free the old sector offset table + dwSectorOffsLen = hf->SectorOffsets[0]; + STORM_FREE(hf->SectorOffsets); + goto __LoadSectorOffsets; + } + } + else + { + memset(hf->SectorOffsets, 0, dwSectorOffsLen); + hf->SectorOffsets[0] = dwSectorOffsLen; + } + } + + return ERROR_SUCCESS; +} + +int AllocateSectorChecksums(TMPQFile * hf, bool bLoadFromFile) +{ + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + ULONGLONG RawFilePos; + DWORD dwCompressedSize = 0; + DWORD dwExpectedSize; + DWORD dwCrcOffset; // Offset of the CRC table, relative to file offset in the MPQ + DWORD dwCrcSize; + + // Caller of AllocateSectorChecksums must ensure these + assert(hf->SectorChksums == NULL); + assert(hf->SectorOffsets != NULL); + assert(hf->pFileEntry != NULL); + assert(hf->ha != NULL); + + // Single unit files don't have sector checksums + if(pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) + return ERROR_SUCCESS; + + // Caller must ensure that we are only called when we have sector checksums + assert(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC); + + // + // Older MPQs store an array of CRC32's after + // the raw file data in the MPQ. + // + // In newer MPQs, the (since Cataclysm BETA) the (attributes) file + // contains additional 32-bit values beyond the sector table. + // Their number depends on size of the (attributes), but their + // meaning is unknown. They are usually zeroed in retail game files, + // but contain some sort of checksum in BETA MPQs + // + + // Does the size of the file table match with the CRC32-based checksums? + dwExpectedSize = (hf->dwSectorCount + 2) * sizeof(DWORD); + if(hf->SectorOffsets[0] != 0 && hf->SectorOffsets[0] == dwExpectedSize) + { + // If we are not loading from the MPQ file, we just allocate the sector table + // In that case, do not check any sizes + if(bLoadFromFile == false) + { + hf->SectorChksums = STORM_ALLOC(DWORD, hf->dwSectorCount); + if(hf->SectorChksums == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the checksum table with zeros + memset(hf->SectorChksums, 0, hf->dwSectorCount * sizeof(DWORD)); + return ERROR_SUCCESS; + } + else + { + // Is there valid size of the sector checksums? + if(hf->SectorOffsets[hf->dwSectorCount + 1] >= hf->SectorOffsets[hf->dwSectorCount]) + dwCompressedSize = hf->SectorOffsets[hf->dwSectorCount + 1] - hf->SectorOffsets[hf->dwSectorCount]; + + // Ignore cases when the length is too small or too big. + if(dwCompressedSize < sizeof(DWORD) || dwCompressedSize > hf->dwSectorSize) + return ERROR_SUCCESS; + + // Calculate offset of the CRC table + dwCrcSize = hf->dwSectorCount * sizeof(DWORD); + dwCrcOffset = hf->SectorOffsets[hf->dwSectorCount]; + RawFilePos = CalculateRawSectorOffset(hf, dwCrcOffset); + + // Now read the table from the MPQ + hf->SectorChksums = (DWORD *)LoadMpqTable(ha, RawFilePos, dwCompressedSize, dwCrcSize, 0, NULL); + if(hf->SectorChksums == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + } + } + + // If the size doesn't match, we ignore sector checksums +// assert(false); + return ERROR_SUCCESS; +} + +int WritePatchInfo(TMPQFile * hf) +{ + TMPQArchive * ha = hf->ha; + TPatchInfo * pPatchInfo = hf->pPatchInfo; + + // The caller must make sure that this function is only called + // when the following is true. + assert(hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE); + assert(pPatchInfo != NULL); + + BSWAP_ARRAY32_UNSIGNED(pPatchInfo, 3 * sizeof(DWORD)); + if(!FileStream_Write(ha->pStream, &hf->RawFilePos, pPatchInfo, sizeof(TPatchInfo))) + return GetLastError(); + + return ERROR_SUCCESS; +} + +int WriteSectorOffsets(TMPQFile * hf) +{ + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + ULONGLONG RawFilePos = hf->RawFilePos; + DWORD dwSectorOffsLen; + + // The caller must make sure that this function is only called + // when the following is true. + assert(hf->pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK); + assert(hf->SectorOffsets != NULL); + dwSectorOffsLen = hf->SectorOffsets[0]; + + // If file is encrypted, sector positions are also encrypted + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + EncryptMpqBlock(hf->SectorOffsets, dwSectorOffsLen, hf->dwFileKey - 1); + BSWAP_ARRAY32_UNSIGNED(hf->SectorOffsets, dwSectorOffsLen); + + // Adjust sector offset table position, if we also have patch info + if(hf->pPatchInfo != NULL) + RawFilePos += hf->pPatchInfo->dwLength; + + // Write sector offsets to the archive + if(!FileStream_Write(ha->pStream, &RawFilePos, hf->SectorOffsets, dwSectorOffsLen)) + return GetLastError(); + + // Not necessary, as the sector checksums + // are going to be freed when this is done. +// BSWAP_ARRAY32_UNSIGNED(hf->SectorOffsets, dwSectorOffsLen); + return ERROR_SUCCESS; +} + + +int WriteSectorChecksums(TMPQFile * hf) +{ + TMPQArchive * ha = hf->ha; + ULONGLONG RawFilePos; + TFileEntry * pFileEntry = hf->pFileEntry; + LPBYTE pbCompressed; + DWORD dwCompressedSize = 0; + DWORD dwCrcSize; + int nOutSize; + int nError = ERROR_SUCCESS; + + // The caller must make sure that this function is only called + // when the following is true. + assert(hf->pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC); + assert(hf->SectorOffsets != NULL); + assert(hf->SectorChksums != NULL); + + // If the MPQ has MD5 of each raw data chunk, + // we leave sector offsets empty + if(ha->pHeader->dwRawChunkSize != 0) + { + hf->SectorOffsets[hf->dwSectorCount + 1] = hf->SectorOffsets[hf->dwSectorCount]; + return ERROR_SUCCESS; + } + + // Calculate size of the checksum array + dwCrcSize = hf->dwSectorCount * sizeof(DWORD); + + // Allocate buffer for compressed sector CRCs. + pbCompressed = STORM_ALLOC(BYTE, dwCrcSize); + if(pbCompressed == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Perform the compression + BSWAP_ARRAY32_UNSIGNED(hf->SectorChksums, dwCrcSize); + + nOutSize = (int)dwCrcSize; + SCompCompress(pbCompressed, &nOutSize, hf->SectorChksums, (int)dwCrcSize, MPQ_COMPRESSION_ZLIB, 0, 0); + dwCompressedSize = (DWORD)nOutSize; + + // Write the sector CRCs to the archive + RawFilePos = hf->RawFilePos + hf->SectorOffsets[hf->dwSectorCount]; + if(hf->pPatchInfo != NULL) + RawFilePos += hf->pPatchInfo->dwLength; + if(!FileStream_Write(ha->pStream, &RawFilePos, pbCompressed, dwCompressedSize)) + nError = GetLastError(); + + // Not necessary, as the sector checksums + // are going to be freed when this is done. +// BSWAP_ARRAY32_UNSIGNED(hf->SectorChksums, dwCrcSize); + + // Store the sector CRCs + hf->SectorOffsets[hf->dwSectorCount + 1] = hf->SectorOffsets[hf->dwSectorCount] + dwCompressedSize; + pFileEntry->dwCmpSize += dwCompressedSize; + STORM_FREE(pbCompressed); + return nError; +} + +int WriteMemDataMD5( + TFileStream * pStream, + ULONGLONG RawDataOffs, + void * pvRawData, + DWORD dwRawDataSize, + DWORD dwChunkSize, + LPDWORD pcbTotalSize) +{ + unsigned char * md5_array; + unsigned char * md5; + LPBYTE pbRawData = (LPBYTE)pvRawData; + DWORD dwBytesRemaining = dwRawDataSize; + DWORD dwMd5ArraySize = 0; + int nError = ERROR_SUCCESS; + + // Allocate buffer for array of MD5 + md5_array = md5 = AllocateMd5Buffer(dwRawDataSize, dwChunkSize, &dwMd5ArraySize); + if(md5_array == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // For every file chunk, calculate MD5 + while(dwBytesRemaining != 0) + { + // Get the remaining number of bytes to read + dwChunkSize = STORMLIB_MIN(dwBytesRemaining, dwChunkSize); + + // Calculate MD5 + CalculateDataBlockHash(pbRawData, dwChunkSize, md5); + md5 += MD5_DIGEST_SIZE; + + // Move offset and size + dwBytesRemaining -= dwChunkSize; + pbRawData += dwChunkSize; + } + + // Write the array od MD5's to the file + RawDataOffs += dwRawDataSize; + if(!FileStream_Write(pStream, &RawDataOffs, md5_array, dwMd5ArraySize)) + nError = GetLastError(); + + // Give the caller the size of the MD5 array + if(pcbTotalSize != NULL) + *pcbTotalSize = dwRawDataSize + dwMd5ArraySize; + + // Free buffers and exit + STORM_FREE(md5_array); + return nError; +} + + +// Writes the MD5 for each chunk of the raw file data +int WriteMpqDataMD5( + TFileStream * pStream, + ULONGLONG RawDataOffs, + DWORD dwRawDataSize, + DWORD dwChunkSize) +{ + unsigned char * md5_array; + unsigned char * md5; + LPBYTE pbFileChunk; + DWORD dwMd5ArraySize = 0; + DWORD dwToRead = dwRawDataSize; + int nError = ERROR_SUCCESS; + + // Allocate buffer for array of MD5 + md5_array = md5 = AllocateMd5Buffer(dwRawDataSize, dwChunkSize, &dwMd5ArraySize); + if(md5_array == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Allocate space for file chunk + pbFileChunk = STORM_ALLOC(BYTE, dwChunkSize); + if(pbFileChunk == NULL) + { + STORM_FREE(md5_array); + return ERROR_NOT_ENOUGH_MEMORY; + } + + // For every file chunk, calculate MD5 + while(dwRawDataSize != 0) + { + // Get the remaining number of bytes to read + dwToRead = STORMLIB_MIN(dwRawDataSize, dwChunkSize); + + // Read the chunk + if(!FileStream_Read(pStream, &RawDataOffs, pbFileChunk, dwToRead)) + { + nError = GetLastError(); + break; + } + + // Calculate MD5 + CalculateDataBlockHash(pbFileChunk, dwToRead, md5); + md5 += MD5_DIGEST_SIZE; + + // Move offset and size + RawDataOffs += dwToRead; + dwRawDataSize -= dwToRead; + } + + // Write the array od MD5's to the file + if(nError == ERROR_SUCCESS) + { + if(!FileStream_Write(pStream, NULL, md5_array, dwMd5ArraySize)) + nError = GetLastError(); + } + + // Free buffers and exit + STORM_FREE(pbFileChunk); + STORM_FREE(md5_array); + return nError; +} + +// Frees the structure for MPQ file +void FreeFileHandle(TMPQFile *& hf) +{ + if(hf != NULL) + { + // If we have patch file attached to this one, free it first + if(hf->hfPatch != NULL) + FreeFileHandle(hf->hfPatch); + + // Then free all buffers allocated in the file structure + if(hf->pbFileData != NULL) + STORM_FREE(hf->pbFileData); + if(hf->pPatchInfo != NULL) + STORM_FREE(hf->pPatchInfo); + if(hf->SectorOffsets != NULL) + STORM_FREE(hf->SectorOffsets); + if(hf->SectorChksums != NULL) + STORM_FREE(hf->SectorChksums); + if(hf->pbFileSector != NULL) + STORM_FREE(hf->pbFileSector); + if(hf->pStream != NULL) + FileStream_Close(hf->pStream); + STORM_FREE(hf); + hf = NULL; + } +} + +// Frees the MPQ archive +void FreeArchiveHandle(TMPQArchive *& ha) +{ + if(ha != NULL) + { + // First of all, free the patch archive, if any + if(ha->haPatch != NULL) + FreeArchiveHandle(ha->haPatch); + + // Free the patch prefix, if any + if(ha->pPatchPrefix != NULL) + STORM_FREE(ha->pPatchPrefix); + + // Close the file stream + FileStream_Close(ha->pStream); + ha->pStream = NULL; + + // Free the file names from the file table + if(ha->pFileTable != NULL) + { + for(DWORD i = 0; i < ha->dwFileTableSize; i++) + { + if(ha->pFileTable[i].szFileName != NULL) + STORM_FREE(ha->pFileTable[i].szFileName); + ha->pFileTable[i].szFileName = NULL; + } + + // Then free all buffers allocated in the archive structure + STORM_FREE(ha->pFileTable); + } + + if(ha->pHashTable != NULL) + STORM_FREE(ha->pHashTable); +#ifdef FULL + if(ha->pHetTable != NULL) + FreeHetTable(ha->pHetTable); +#endif + STORM_FREE(ha); + ha = NULL; + } +} + +bool IsInternalMpqFileName(const char * szFileName) +{ + if(szFileName != NULL && szFileName[0] == '(') + { + if(!_stricmp(szFileName, LISTFILE_NAME) || + !_stricmp(szFileName, ATTRIBUTES_NAME) || + !_stricmp(szFileName, SIGNATURE_NAME)) + { + return true; + } + } + + return false; +} + +// Verifies if the file name is a pseudo-name +bool IsPseudoFileName(const char * szFileName, DWORD * pdwFileIndex) +{ + DWORD dwFileIndex = 0; + + if(szFileName != NULL) + { + // Must be "File########.ext" + if(!_strnicmp(szFileName, "File", 4)) + { + // Check 8 digits + for(int i = 4; i < 4+8; i++) + { + if(szFileName[i] < '0' || szFileName[i] > '9') + return false; + dwFileIndex = (dwFileIndex * 10) + (szFileName[i] - '0'); + } + + // An extension must follow + if(szFileName[12] == '.') + { + if(pdwFileIndex != NULL) + *pdwFileIndex = dwFileIndex; + return true; + } + } + } + + // Not a pseudo-name + return false; +} + +//----------------------------------------------------------------------------- +// Functions calculating and verifying the MD5 signature + +bool IsValidMD5(LPBYTE pbMd5) +{ + LPDWORD Md5 = (LPDWORD)pbMd5; + + return (Md5[0] | Md5[1] | Md5[2] | Md5[3]) ? true : false; +} + +bool IsValidSignature(LPBYTE pbSignature) +{ + LPDWORD Signature = (LPDWORD)pbSignature; + DWORD SigValid = 0; + + for(int i = 0; i < MPQ_WEAK_SIGNATURE_SIZE / sizeof(DWORD); i++) + SigValid |= Signature[i]; + + return (SigValid != 0) ? true : false; +} + + +bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5) +{ +#ifdef FULL + hash_state md5_state; + BYTE md5_digest[MD5_DIGEST_SIZE]; + + // Don't verify the block if the MD5 is not valid. + if(!IsValidMD5(expected_md5)) + return true; + + // Calculate the MD5 of the data block + md5_init(&md5_state); + md5_process(&md5_state, (unsigned char *)pvDataBlock, cbDataBlock); + md5_done(&md5_state, md5_digest); + + // Does the MD5's match? + return (memcmp(md5_digest, expected_md5, MD5_DIGEST_SIZE) == 0); +#else + assert(0); +#endif +} + +void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash) +{ +#ifdef FULL + hash_state md5_state; + + md5_init(&md5_state); + md5_process(&md5_state, (unsigned char *)pvDataBlock, cbDataBlock); + md5_done(&md5_state, md5_hash); +#else + assert(0); +#endif +} + + +//----------------------------------------------------------------------------- +// Swapping functions + +#ifndef PLATFORM_LITTLE_ENDIAN + +// +// Note that those functions are implemented for Mac operating system, +// as this is the only supported platform that uses big endian. +// + +// Swaps a signed 16-bit integer +int16_t SwapInt16(uint16_t data) +{ + return (int16_t)CFSwapInt16(data); +} + +// Swaps an unsigned 16-bit integer +uint16_t SwapUInt16(uint16_t data) +{ + return CFSwapInt16(data); +} + +// Swaps signed 32-bit integer +int32_t SwapInt32(uint32_t data) +{ + return (int32_t)CFSwapInt32(data); +} + +// Swaps an unsigned 32-bit integer +uint32_t SwapUInt32(uint32_t data) +{ + return CFSwapInt32(data); +} + +// Swaps signed 64-bit integer +int64_t SwapInt64(int64_t data) +{ + return (int64_t)CFSwapInt64(data); +} + +// Swaps an unsigned 64-bit integer +uint64_t SwapUInt64(uint64_t data) +{ + return CFSwapInt64(data); +} + +// Swaps array of unsigned 16-bit integers +void ConvertUInt16Buffer(void * ptr, size_t length) +{ + uint16_t * buffer = (uint16_t *)ptr; + uint32_t nElements = (uint32_t)(length / sizeof(uint16_t)); + + while(nElements-- > 0) + { + *buffer = SwapUInt16(*buffer); + buffer++; + } +} + +// Swaps array of unsigned 32-bit integers +void ConvertUInt32Buffer(void * ptr, size_t length) +{ + uint32_t * buffer = (uint32_t *)ptr; + uint32_t nElements = (uint32_t)(length / sizeof(uint32_t)); + + while(nElements-- > 0) + { + *buffer = SwapUInt32(*buffer); + buffer++; + } +} + +// Swaps array of unsigned 64-bit integers +void ConvertUInt64Buffer(void * ptr, size_t length) +{ + uint64_t * buffer = (uint64_t *)ptr; + uint32_t nElements = (uint32_t)(length / sizeof(uint64_t)); + + while(nElements-- > 0) + { + *buffer = SwapUInt64(*buffer); + buffer++; + } +} + +// Swaps the TMPQHeader structure +void ConvertTMPQHeader(void *header, uint16_t version) +{ + TMPQHeader * theHeader = (TMPQHeader *)header; + + // Swap header part version 1 + if(version == MPQ_FORMAT_VERSION_1) + { + theHeader->dwID = SwapUInt32(theHeader->dwID); + theHeader->dwHeaderSize = SwapUInt32(theHeader->dwHeaderSize); + theHeader->dwArchiveSize = SwapUInt32(theHeader->dwArchiveSize); + theHeader->wFormatVersion = SwapUInt16(theHeader->wFormatVersion); + theHeader->wSectorSize = SwapUInt16(theHeader->wSectorSize); + theHeader->dwHashTablePos = SwapUInt32(theHeader->dwHashTablePos); + theHeader->dwBlockTablePos = SwapUInt32(theHeader->dwBlockTablePos); + theHeader->dwHashTableSize = SwapUInt32(theHeader->dwHashTableSize); + theHeader->dwBlockTableSize = SwapUInt32(theHeader->dwBlockTableSize); + } + + if(version == MPQ_FORMAT_VERSION_2) + { + theHeader->HiBlockTablePos64 = SwapUInt64(theHeader->HiBlockTablePos64); + theHeader->wHashTablePosHi = SwapUInt16(theHeader->wHashTablePosHi); + theHeader->wBlockTablePosHi = SwapUInt16(theHeader->wBlockTablePosHi); + } + + if(version == MPQ_FORMAT_VERSION_3) + { + theHeader->ArchiveSize64 = SwapUInt64(theHeader->ArchiveSize64); + theHeader->BetTablePos64 = SwapUInt64(theHeader->BetTablePos64); + theHeader->HetTablePos64 = SwapUInt64(theHeader->HetTablePos64); + } + + if(version == MPQ_FORMAT_VERSION_4) + { + theHeader->HashTableSize64 = SwapUInt64(theHeader->HashTableSize64); + theHeader->BlockTableSize64 = SwapUInt64(theHeader->BlockTableSize64); + theHeader->HiBlockTableSize64 = SwapUInt64(theHeader->HiBlockTableSize64); + theHeader->HetTableSize64 = SwapUInt64(theHeader->HetTableSize64); + theHeader->BetTableSize64 = SwapUInt64(theHeader->BetTableSize64); + } +} + +#endif // PLATFORM_LITTLE_ENDIAN diff --git a/3rdParty/StormLib/src/SBaseFileTable.cpp b/3rdParty/StormLib/src/SBaseFileTable.cpp new file mode 100644 index 000000000..4abffbeee --- /dev/null +++ b/3rdParty/StormLib/src/SBaseFileTable.cpp @@ -0,0 +1,2962 @@ +/*****************************************************************************/ +/* SBaseFileTable.cpp Copyright (c) Ladislav Zezula 2010 */ +/*---------------------------------------------------------------------------*/ +/* Description: Common handler for classic and new hash&block tables */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 06.09.10 1.00 Lad The first version of SBaseFileTable.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local defines + +#define INVALID_FLAG_VALUE 0xCCCCCCCC +#define MAX_FLAG_INDEX 512 + +//----------------------------------------------------------------------------- +// Support for calculating bit sizes + +static void InitFileFlagArray(LPDWORD FlagArray) +{ + memset(FlagArray, 0xCC, MAX_FLAG_INDEX * sizeof(DWORD)); +} + +static DWORD GetFileFlagIndex(LPDWORD FlagArray, DWORD dwFlags) +{ + // Find free or equal entry in the flag array + for(DWORD dwFlagIndex = 0; dwFlagIndex < MAX_FLAG_INDEX; dwFlagIndex++) + { + if(FlagArray[dwFlagIndex] == INVALID_FLAG_VALUE || FlagArray[dwFlagIndex] == dwFlags) + { + FlagArray[dwFlagIndex] = dwFlags; + return dwFlagIndex; + } + } + + // This should never happen + assert(false); + return 0xFFFFFFFF; +} + +static DWORD GetNecessaryBitCount(ULONGLONG MaxValue) +{ + DWORD dwBitCount = 0; + + while(MaxValue > 0) + { + MaxValue >>= 1; + dwBitCount++; + } + + return dwBitCount; +} + +//----------------------------------------------------------------------------- +// Support functions for BIT_ARRAY + +static USHORT SetBitsMask[] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}; + +static TBitArray * CreateBitArray( + DWORD NumberOfBits, + BYTE FillValue) +{ + TBitArray * pBitArray; + size_t nSize = sizeof(TBitArray) + (NumberOfBits + 7) / 8; + + // Allocate the bit array + pBitArray = (TBitArray *)STORM_ALLOC(BYTE, nSize); + if(pBitArray != NULL) + { + memset(pBitArray, FillValue, nSize); + pBitArray->NumberOfBytes = (NumberOfBits + 7) / 8; + pBitArray->NumberOfBits = NumberOfBits; + } + + return pBitArray; +} + +void GetBits( + TBitArray * pArray, + unsigned int nBitPosition, + unsigned int nBitLength, + void * pvBuffer, + int nResultByteSize) +{ + unsigned char * pbBuffer = (unsigned char *)pvBuffer; + unsigned int nBytePosition0 = (nBitPosition / 8); + unsigned int nBytePosition1 = nBytePosition0 + 1; + unsigned int nByteLength = (nBitLength / 8); + unsigned int nBitOffset = (nBitPosition & 0x07); + unsigned char BitBuffer; + + // Keep compiler happy for platforms where nResultByteSize is not used + nResultByteSize = nResultByteSize; + +#ifdef _DEBUG + // Check if the target is properly zeroed + for(int i = 0; i < nResultByteSize; i++) + assert(pbBuffer[i] == 0); +#endif + +#ifndef PLATFORM_LITTLE_ENDIAN + // Adjust the buffer pointer for big endian platforms + pbBuffer += (nResultByteSize - 1); +#endif + + // Copy whole bytes, if any + while(nByteLength > 0) + { + // Is the current position in the Elements byte-aligned? + if(nBitOffset != 0) + { + BitBuffer = (unsigned char)((pArray->Elements[nBytePosition0] >> nBitOffset) | (pArray->Elements[nBytePosition1] << (0x08 - nBitOffset))); + } + else + { + BitBuffer = pArray->Elements[nBytePosition0]; + } + +#ifdef PLATFORM_LITTLE_ENDIAN + *pbBuffer++ = BitBuffer; +#else + *pbBuffer-- = BitBuffer; +#endif + + // Move byte positions and lengths + nBytePosition1++; + nBytePosition0++; + nByteLength--; + } + + // Get the rest of the bits + nBitLength = (nBitLength & 0x07); + if(nBitLength != 0) + { + *pbBuffer = (unsigned char)(pArray->Elements[nBytePosition0] >> nBitOffset); + + if(nBitLength > (8 - nBitOffset)) + *pbBuffer = (unsigned char)((pArray->Elements[nBytePosition1] << (8 - nBitOffset)) | (pArray->Elements[nBytePosition0] >> nBitOffset)); + + *pbBuffer &= (0x01 << nBitLength) - 1; + } +} + +void SetBits( + TBitArray * pArray, + unsigned int nBitPosition, + unsigned int nBitLength, + void * pvBuffer, + int nResultByteSize) +{ + unsigned char * pbBuffer = (unsigned char *)pvBuffer; + unsigned int nBytePosition = (nBitPosition / 8); + unsigned int nBitOffset = (nBitPosition & 0x07); + unsigned short BitBuffer = 0; + unsigned short AndMask = 0; + unsigned short OneByte = 0; + + // Keep compiler happy for platforms where nResultByteSize is not used + nResultByteSize = nResultByteSize; + +#ifndef PLATFORM_LITTLE_ENDIAN + // Adjust the buffer pointer for big endian platforms + pbBuffer += (nResultByteSize - 1); +#endif + + // Copy whole bytes, if any + while(nBitLength > 8) + { + // Reload the bit buffer +#ifdef PLATFORM_LITTLE_ENDIAN + OneByte = *pbBuffer++; +#else + OneByte = *pbBuffer--; +#endif + // Update the BitBuffer and AndMask for the bit array + BitBuffer = (BitBuffer >> 0x08) | (OneByte << nBitOffset); + AndMask = (AndMask >> 0x08) | (0x00FF << nBitOffset); + + // Update the byte in the array + pArray->Elements[nBytePosition] = (BYTE)((pArray->Elements[nBytePosition] & ~AndMask) | BitBuffer); + + // Move byte positions and lengths + nBytePosition++; + nBitLength -= 0x08; + } + + if(nBitLength != 0) + { + // Reload the bit buffer + OneByte = *pbBuffer; + + // Update the AND mask for the last bit + BitBuffer = (BitBuffer >> 0x08) | (OneByte << nBitOffset); + AndMask = (AndMask >> 0x08) | (SetBitsMask[nBitLength] << nBitOffset); + + // Update the byte in the array + pArray->Elements[nBytePosition] = (BYTE)((pArray->Elements[nBytePosition] & ~AndMask) | BitBuffer); + + // Update the next byte, if needed + if(AndMask & 0xFF00) + { + nBytePosition++; + BitBuffer >>= 0x08; + AndMask >>= 0x08; + + pArray->Elements[nBytePosition] = (BYTE)((pArray->Elements[nBytePosition] & ~AndMask) | BitBuffer); + } + } +} + +//----------------------------------------------------------------------------- +// Support for MPQ header + +static ULONGLONG DetermineArchiveSize_V1( + TMPQArchive * ha, + TMPQHeader * pHeader, + ULONGLONG MpqOffset, + ULONGLONG FileSize) +{ + ULONGLONG ByteOffset; + ULONGLONG EndOfMpq = FileSize; + DWORD SignatureHeader = 0; + DWORD dwArchiveSize32; + + // This could only be called for MPQs version 1.0 + assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1); + + // Check if we can rely on the archive size in the header + if(pHeader->dwBlockTablePos < pHeader->dwArchiveSize) + { + // The block table cannot be compressed, so the sizes must match + if((pHeader->dwArchiveSize - pHeader->dwBlockTablePos) == (pHeader->dwBlockTableSize * sizeof(TMPQBlock))) + return pHeader->dwArchiveSize; + + // If the archive size in the header is less than real file size + dwArchiveSize32 = (DWORD)(FileSize - MpqOffset); + if(pHeader->dwArchiveSize == dwArchiveSize32) + return pHeader->dwArchiveSize; + } + + // Check if there is a signature header + if((EndOfMpq - MpqOffset) > (MPQ_STRONG_SIGNATURE_SIZE + 4)) + { + ByteOffset = EndOfMpq - MPQ_STRONG_SIGNATURE_SIZE - 4; + if(FileStream_Read(ha->pStream, &ByteOffset, &SignatureHeader, sizeof(DWORD))) + { + if(BSWAP_INT32_UNSIGNED(SignatureHeader) == MPQ_STRONG_SIGNATURE_ID) + EndOfMpq = EndOfMpq - MPQ_STRONG_SIGNATURE_SIZE - 4; + } + } + + // Return the returned archive size + return (EndOfMpq - MpqOffset); +} + +static ULONGLONG DetermineArchiveSize_V2( + TMPQHeader * pHeader, + ULONGLONG MpqOffset, + ULONGLONG FileSize) +{ + ULONGLONG EndOfMpq = FileSize; + DWORD dwArchiveSize32; + + // This could only be called for MPQs version 2.0 + assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2); + + // Check if we can rely on the archive size in the header + if((FileSize >> 0x20) == 0) + { + if(pHeader->dwBlockTablePos < pHeader->dwArchiveSize) + { + if((pHeader->dwArchiveSize - pHeader->dwBlockTablePos) <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))) + return pHeader->dwArchiveSize; + + // If the archive size in the header is less than real file size + dwArchiveSize32 = (DWORD)(FileSize - MpqOffset); + if(pHeader->dwArchiveSize <= dwArchiveSize32) + return pHeader->dwArchiveSize; + } + } + + // Return the calculated archive size + return (EndOfMpq - MpqOffset); +} + +ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset) +{ + if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) + { + // For MPQ archive v1, any file offset is only 32-bit + return (ULONGLONG)((DWORD)ha->MpqPos + (DWORD)MpqOffset); + } + else + { + // For MPQ archive v2+, file offsets are full 64-bit + return ha->MpqPos + MpqOffset; + } +} + +ULONGLONG CalculateRawSectorOffset( + TMPQFile * hf, + DWORD dwSectorOffset) +{ + ULONGLONG RawFilePos; + + // Must be used for files within a MPQ + assert(hf->ha != NULL); + assert(hf->ha->pHeader != NULL); + + // + // Some MPQ protectors place the sector offset table after the actual file data. + // Sector offsets in the sector offset table are negative. When added + // to MPQ file offset from the block table entry, the result is a correct + // position of the file data in the MPQ. + // + // For MPQs version 1.0, the offset is purely 32-bit + // + + RawFilePos = hf->RawFilePos + dwSectorOffset; + if(hf->ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) + RawFilePos = (DWORD)hf->ha->MpqPos + (DWORD)hf->pFileEntry->ByteOffset + dwSectorOffset; + + // We also have to add patch header size, if patch header is present + if(hf->pPatchInfo != NULL) + RawFilePos += hf->pPatchInfo->dwLength; + + // Return the result offset + return RawFilePos; +} + +// This function converts the MPQ header so it always looks like version 4 +int ConvertMpqHeaderToFormat4( + TMPQArchive * ha, + ULONGLONG MpqOffset, + ULONGLONG FileSize, + DWORD dwFlags, + bool bIsWarcraft3Map) +{ + TMPQHeader * pHeader = (TMPQHeader *)ha->HeaderData; + ULONGLONG BlockTablePos64 = 0; + ULONGLONG HashTablePos64 = 0; + ULONGLONG BlockTableMask = (ULONGLONG)-1; + ULONGLONG ByteOffset; + USHORT wFormatVersion = BSWAP_INT16_UNSIGNED(pHeader->wFormatVersion); + int nError = ERROR_SUCCESS; + + // If version 1.0 is forced, then the format version is forced to be 1.0 + // Reason: Storm.dll in Warcraft III ignores format version value + if((dwFlags & MPQ_OPEN_FORCE_MPQ_V1) || bIsWarcraft3Map) + wFormatVersion = MPQ_FORMAT_VERSION_1; + + // Format-specific fixes + switch(wFormatVersion) + { + case MPQ_FORMAT_VERSION_1: + + // Check for malformed MPQ header version 1.0 + BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_1); + if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_1 || pHeader->dwHeaderSize != MPQ_HEADER_SIZE_V1) + { + pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1; + pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1; + ha->dwFlags |= MPQ_FLAG_MALFORMED; + } + + // + // Note: The value of "dwArchiveSize" member in the MPQ header + // is ignored by Storm.dll and can contain garbage value + // ("w3xmaster" protector). + // + + Label_ArchiveVersion1: + if(pHeader->dwBlockTableSize > 1) // Prevent empty MPQs being marked as malformed + { + if(pHeader->dwHashTablePos <= pHeader->dwHeaderSize || (pHeader->dwHashTablePos & 0x80000000)) + ha->dwFlags |= MPQ_FLAG_MALFORMED; + if(pHeader->dwBlockTablePos <= pHeader->dwHeaderSize || (pHeader->dwBlockTablePos & 0x80000000)) + ha->dwFlags |= MPQ_FLAG_MALFORMED; + } + + // Only low byte of sector size is really used + if(pHeader->wSectorSize & 0xFF00) + ha->dwFlags |= MPQ_FLAG_MALFORMED; + pHeader->wSectorSize = pHeader->wSectorSize & 0xFF; + + // Fill the rest of the header + memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V1, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V1); + pHeader->BlockTableSize64 = pHeader->dwBlockTableSize * sizeof(TMPQBlock); + pHeader->HashTableSize64 = pHeader->dwHashTableSize * sizeof(TMPQHash); + pHeader->ArchiveSize64 = pHeader->dwArchiveSize; + + // Block table position must be calculated as 32-bit value + // Note: BOBA protector puts block table before the MPQ header, so it is negative + BlockTablePos64 = (ULONGLONG)((DWORD)MpqOffset + pHeader->dwBlockTablePos); + BlockTableMask = 0xFFFFFFF0; + + // Determine the archive size on malformed MPQs + if(ha->dwFlags & MPQ_FLAG_MALFORMED) + { + // Calculate the archive size + pHeader->ArchiveSize64 = DetermineArchiveSize_V1(ha, pHeader, MpqOffset, FileSize); + pHeader->dwArchiveSize = (DWORD)pHeader->ArchiveSize64; + } + break; + + case MPQ_FORMAT_VERSION_2: + + // Check for malformed MPQ header version 1.0 + BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_2); + if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_2 || pHeader->dwHeaderSize != MPQ_HEADER_SIZE_V2) + { + pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1; + pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1; + ha->dwFlags |= MPQ_FLAG_MALFORMED; + goto Label_ArchiveVersion1; + } + + // Fill the rest of the header with zeros + memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V2, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V2); + + // Calculate the expected hash table size + pHeader->HashTableSize64 = (pHeader->dwHashTableSize * sizeof(TMPQHash)); + HashTablePos64 = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos); + + // Calculate the expected block table size + pHeader->BlockTableSize64 = (pHeader->dwBlockTableSize * sizeof(TMPQBlock)); + BlockTablePos64 = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); + + // We require the block table to follow hash table + if(BlockTablePos64 >= HashTablePos64) + { + // HashTableSize64 may be less than TblSize * sizeof(TMPQHash). + // That means that the hash table is compressed. + pHeader->HashTableSize64 = BlockTablePos64 - HashTablePos64; + + // Calculate the compressed block table size + if(pHeader->HiBlockTablePos64 != 0) + { + // BlockTableSize64 may be less than TblSize * sizeof(TMPQBlock). + // That means that the block table is compressed. + pHeader->BlockTableSize64 = pHeader->HiBlockTablePos64 - BlockTablePos64; + assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))); + + // Determine real archive size + pHeader->ArchiveSize64 = DetermineArchiveSize_V2(pHeader, MpqOffset, FileSize); + + // Calculate the size of the hi-block table + pHeader->HiBlockTableSize64 = pHeader->ArchiveSize64 - pHeader->HiBlockTablePos64; + assert(pHeader->HiBlockTableSize64 == (pHeader->dwBlockTableSize * sizeof(USHORT))); + } + else + { + // Determine real archive size + pHeader->ArchiveSize64 = DetermineArchiveSize_V2(pHeader, MpqOffset, FileSize); + + // Calculate size of the block table + pHeader->BlockTableSize64 = pHeader->ArchiveSize64 - BlockTablePos64; + assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))); + } + } + else + { + pHeader->ArchiveSize64 = pHeader->dwArchiveSize; + ha->dwFlags |= MPQ_FLAG_MALFORMED; + } + + // Add the MPQ Offset + BlockTablePos64 += MpqOffset; + break; + + case MPQ_FORMAT_VERSION_3: + + // In MPQ format 3.0, the entire header is optional + // and the size of the header can actually be identical + // to size of header 2.0 + BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_3); + if(pHeader->dwHeaderSize < MPQ_HEADER_SIZE_V3) + { + pHeader->ArchiveSize64 = pHeader->dwArchiveSize; + pHeader->HetTablePos64 = 0; + pHeader->BetTablePos64 = 0; + } + + // + // We need to calculate the compressed size of each table. We assume the following order: + // 1) HET table + // 2) BET table + // 3) Classic hash table + // 4) Classic block table + // 5) Hi-block table + // + + // Fill the rest of the header with zeros + memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V3, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V3); + BlockTablePos64 = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); + HashTablePos64 = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos); + ByteOffset = pHeader->ArchiveSize64; + + // Size of the hi-block table + if(pHeader->HiBlockTablePos64) + { + pHeader->HiBlockTableSize64 = ByteOffset - pHeader->HiBlockTablePos64; + ByteOffset = pHeader->HiBlockTablePos64; + } + + // Size of the block table + if(BlockTablePos64) + { + pHeader->BlockTableSize64 = ByteOffset - BlockTablePos64; + ByteOffset = BlockTablePos64; + } + + // Size of the hash table + if(HashTablePos64) + { + pHeader->HashTableSize64 = ByteOffset - HashTablePos64; + ByteOffset = HashTablePos64; + } + + // Size of the BET table + if(pHeader->BetTablePos64) + { + pHeader->BetTableSize64 = ByteOffset - pHeader->BetTablePos64; + ByteOffset = pHeader->BetTablePos64; + } + + // Size of the HET table + if(pHeader->HetTablePos64) + { + pHeader->HetTableSize64 = ByteOffset - pHeader->HetTablePos64; +// ByteOffset = pHeader->HetTablePos64; + } + + // Add the MPQ Offset + BlockTablePos64 += MpqOffset; + break; + + case MPQ_FORMAT_VERSION_4: + + // Verify header MD5. Header MD5 is calculated from the MPQ header since the 'MPQ\x1A' + // signature until the position of header MD5 at offset 0xC0 + BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_4); + if(!VerifyDataBlockHash(pHeader, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE, pHeader->MD5_MpqHeader)) + nError = ERROR_FILE_CORRUPT; + + // Calculate the block table position + BlockTablePos64 = MpqOffset + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); + break; + + default: + + // Check if it's a War of the Immortal data file (SQP) + // If not, we treat it as malformed MPQ version 1.0 + if(ConvertSqpHeaderToFormat4(ha, FileSize, dwFlags) != ERROR_SUCCESS) + { + pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1; + pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1; + ha->dwFlags |= MPQ_FLAG_MALFORMED; + goto Label_ArchiveVersion1; + } + + // Calculate the block table position + BlockTablePos64 = MpqOffset + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); + break; + } + + // Handle case when block table is placed before the MPQ header + // Used by BOBA protector + if(BlockTablePos64 < MpqOffset) + ha->dwFlags |= MPQ_FLAG_MALFORMED; + return nError; +} + +//----------------------------------------------------------------------------- +// Support for hash table + +// Hash entry verification when the file table does not exist yet +bool IsValidHashEntry(TMPQArchive * ha, TMPQHash * pHash) +{ + TFileEntry * pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash); + + return ((MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false; +} + +// Hash entry verification when the file table does not exist yet +static bool IsValidHashEntry1(TMPQArchive * ha, TMPQHash * pHash, TMPQBlock * pBlockTable) +{ + ULONGLONG ByteOffset; + TMPQBlock * pBlock; + + // The block index is considered valid if it's less than block table size + if(MPQ_BLOCK_INDEX(pHash) < ha->pHeader->dwBlockTableSize) + { + // Calculate the block table position + pBlock = pBlockTable + MPQ_BLOCK_INDEX(pHash); + + // Check whether this is an existing file + // Also we do not allow to be file size greater than 2GB + if((pBlock->dwFlags & MPQ_FILE_EXISTS) && (pBlock->dwFSize & 0x80000000) == 0) + { + // The begin of the file must be within the archive + ByteOffset = FileOffsetFromMpqOffset(ha, pBlock->dwFilePos); + return (ByteOffset < ha->FileSize); + } + } + + return false; +} + +// Returns a hash table entry in the following order: +// 1) A hash table entry with the preferred locale and platform +// 2) A hash table entry with the neutral|matching locale and neutral|matching platform +// 3) NULL +// Storm_2016.dll: 15020940 +static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale, BYTE Platform) +{ + TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName); + TMPQHash * pBestEntry = NULL; + TMPQHash * pHash = pFirstHash; + + // Parse the found hashes + while(pHash != NULL) + { + // Storm_2016.dll: 150209CB + // If the hash entry matches both locale and platform, return it immediately + // Note: We only succeed this check if the locale is non-neutral, because + // some Warcraft III maps have several items with neutral locale&platform, which leads + // to wrong item being returned + if((lcLocale || Platform) && pHash->lcLocale == lcLocale && pHash->Platform == Platform) + return pHash; + + // Storm_2016.dll: 150209D9 + // If (locale matches or is neutral) OR (platform matches or is neutral) + // remember this as the best entry + if(pHash->lcLocale == 0 || pHash->lcLocale == lcLocale) + { + if(pHash->Platform == 0 || pHash->Platform == Platform) + pBestEntry = pHash; + } + + // Get the next hash entry for that file + pHash = GetNextHashEntry(ha, pFirstHash, pHash); + } + + // At the end, return neutral hash (if found), otherwise NULL + return pBestEntry; +} + +// Returns a hash table entry in the following order: +// 1) A hash table entry with the preferred locale +// 2) NULL +static TMPQHash * GetHashEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale) +{ + TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName); + TMPQHash * pHash = pFirstHash; + + // Parse the found hashes + while(pHash != NULL) + { + // If the locales match, return it + if(pHash->lcLocale == lcLocale) + return pHash; + + // Get the next hash entry for that file + pHash = GetNextHashEntry(ha, pFirstHash, pHash); + } + + // Not found + return NULL; +} + +// Defragment the file table so it does not contain any gaps +// Note: As long as all values of all TMPQHash::dwBlockIndex +// are not HASH_ENTRY_FREE, the startup search index does not matter. +// Hash table is circular, so as long as there is no terminator, +// all entries will be found. +static TMPQHash * DefragmentHashTable( + TMPQArchive * ha, + TMPQHash * pHashTable, + TMPQBlock * pBlockTable) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPQHash * pHashTableEnd = pHashTable + pHeader->dwHashTableSize; + TMPQHash * pSource = pHashTable; + TMPQHash * pTarget = pHashTable; + DWORD dwFirstFreeEntry; + DWORD dwNewTableSize; + + // Sanity checks + assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1); + assert(pHeader->HiBlockTablePos64 == 0); + + // Parse the hash table and move the entries to the begin of it + for(pSource = pHashTable; pSource < pHashTableEnd; pSource++) + { + // Check whether this is a valid hash table entry + if(IsValidHashEntry1(ha, pSource, pBlockTable)) + { + // Copy the hash table entry back + if(pSource > pTarget) + pTarget[0] = pSource[0]; + + // Move the target + pTarget++; + } + } + + // Calculate how many entries in the hash table we really need + dwFirstFreeEntry = (DWORD)(pTarget - pHashTable); + dwNewTableSize = GetNearestPowerOfTwo(dwFirstFreeEntry); + + // Fill the rest with entries that look like deleted + pHashTableEnd = pHashTable + dwNewTableSize; + pSource = pHashTable + dwFirstFreeEntry; + memset(pSource, 0xFF, (dwNewTableSize - dwFirstFreeEntry) * sizeof(TMPQHash)); + + // Mark the block indexes as deleted + for(; pSource < pHashTableEnd; pSource++) + pSource->dwBlockIndex = HASH_ENTRY_DELETED; + + // Free some of the space occupied by the hash table + if(dwNewTableSize < pHeader->dwHashTableSize) + { + pHashTable = STORM_REALLOC(TMPQHash, pHashTable, dwNewTableSize); + ha->pHeader->BlockTableSize64 = dwNewTableSize * sizeof(TMPQHash); + ha->pHeader->dwHashTableSize = dwNewTableSize; + } + + return pHashTable; +} + +static int BuildFileTableFromBlockTable( + TMPQArchive * ha, + TMPQBlock * pBlockTable) +{ + TFileEntry * pFileEntry; + TMPQHeader * pHeader = ha->pHeader; + TMPQBlock * pBlock; + TMPQHash * pHashTableEnd; + TMPQHash * pHash; + LPDWORD DefragmentTable = NULL; + DWORD dwItemCount = 0; + DWORD dwFlagMask; + + // Sanity checks + assert(ha->pFileTable != NULL); + assert(ha->dwFileTableSize >= ha->dwMaxFileCount); + + // MPQs for Warcraft III doesn't know some flags, namely MPQ_FILE_SINGLE_UNIT and MPQ_FILE_PATCH_FILE + dwFlagMask = (ha->dwFlags & MPQ_FLAG_WAR3_MAP) ? MPQ_FILE_VALID_FLAGS_W3X : MPQ_FILE_VALID_FLAGS; + + // Defragment the hash table, if needed + if(ha->dwFlags & MPQ_FLAG_HASH_TABLE_CUT) + { + ha->pHashTable = DefragmentHashTable(ha, ha->pHashTable, pBlockTable); + ha->dwMaxFileCount = pHeader->dwHashTableSize; + } + + // If the hash table or block table is cut, + // we will defragment the block table + if(ha->dwFlags & (MPQ_FLAG_HASH_TABLE_CUT | MPQ_FLAG_BLOCK_TABLE_CUT)) + { + // Sanity checks + assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1); + assert(pHeader->HiBlockTablePos64 == 0); + + // Allocate the translation table + DefragmentTable = STORM_ALLOC(DWORD, pHeader->dwBlockTableSize); + if(DefragmentTable == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the translation table + memset(DefragmentTable, 0xFF, pHeader->dwBlockTableSize * sizeof(DWORD)); + } + + // Parse the entire hash table + pHashTableEnd = ha->pHashTable + pHeader->dwHashTableSize; + for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++) + { + // + // We need to properly handle these cases: + // - Multiple hash entries (same file name) point to the same block entry + // - Multiple hash entries (different file name) point to the same block entry + // + // Ignore all hash table entries where: + // - Block Index >= BlockTableSize + // - Flags of the appropriate block table entry + // + + if(IsValidHashEntry1(ha, pHash, pBlockTable)) + { + DWORD dwOldIndex = MPQ_BLOCK_INDEX(pHash); + DWORD dwNewIndex = MPQ_BLOCK_INDEX(pHash); + + // Determine the new block index + if(DefragmentTable != NULL) + { + // Need to handle case when multiple hash + // entries point to the same block entry + if(DefragmentTable[dwOldIndex] == HASH_ENTRY_FREE) + { + DefragmentTable[dwOldIndex] = dwItemCount; + dwNewIndex = dwItemCount++; + } + else + { + dwNewIndex = DefragmentTable[dwOldIndex]; + } + + // Fix the pointer in the hash entry + pHash->dwBlockIndex = dwNewIndex; + + // Dump the relocation entry +// printf("Relocating hash entry %08X-%08X: %08X -> %08X\n", pHash->dwName1, pHash->dwName2, dwBlockIndex, dwNewIndex); + } + + // Get the pointer to the file entry and the block entry + pFileEntry = ha->pFileTable + dwNewIndex; + pBlock = pBlockTable + dwOldIndex; + + // ByteOffset is only valid if file size is not zero + pFileEntry->ByteOffset = pBlock->dwFilePos; + if(pFileEntry->ByteOffset == 0 && pBlock->dwFSize == 0) + pFileEntry->ByteOffset = ha->pHeader->dwHeaderSize; + + // Fill the rest of the file entry + pFileEntry->dwFileSize = pBlock->dwFSize; + pFileEntry->dwCmpSize = pBlock->dwCSize; + pFileEntry->dwFlags = pBlock->dwFlags & dwFlagMask; + } + } + + // Free the translation table + if(DefragmentTable != NULL) + { + // If we defragmented the block table in the process, + // free some memory by shrinking the file table + if(ha->dwFileTableSize > ha->dwMaxFileCount) + { + ha->pFileTable = STORM_REALLOC(TFileEntry, ha->pFileTable, ha->dwMaxFileCount); + ha->pHeader->BlockTableSize64 = ha->dwMaxFileCount * sizeof(TMPQBlock); + ha->pHeader->dwBlockTableSize = ha->dwMaxFileCount; + ha->dwFileTableSize = ha->dwMaxFileCount; + } + +// DumpFileTable(ha->pFileTable, ha->dwFileTableSize); + + // Free the translation table + STORM_FREE(DefragmentTable); + } + + return ERROR_SUCCESS; +} + +static TMPQHash * TranslateHashTable( + TMPQArchive * ha, + ULONGLONG * pcbTableSize) +{ + TMPQHash * pHashTable; + size_t HashTableSize; + + // Allocate copy of the hash table + pHashTable = STORM_ALLOC(TMPQHash, ha->pHeader->dwHashTableSize); + if(pHashTable != NULL) + { + // Copy the hash table + HashTableSize = sizeof(TMPQHash) * ha->pHeader->dwHashTableSize; + memcpy(pHashTable, ha->pHashTable, HashTableSize); + + // Give the size to the caller + if(pcbTableSize != NULL) + { + *pcbTableSize = (ULONGLONG)HashTableSize; + } + } + + return pHashTable; +} + +// Also used in SFileGetFileInfo +TMPQBlock * TranslateBlockTable( + TMPQArchive * ha, + ULONGLONG * pcbTableSize, + bool * pbNeedHiBlockTable) +{ + TFileEntry * pFileEntry = ha->pFileTable; + TMPQBlock * pBlockTable; + TMPQBlock * pBlock; + DWORD NeedHiBlockTable = 0; + DWORD dwBlockTableSize = ha->pHeader->dwBlockTableSize; + + // Allocate copy of the hash table + pBlockTable = pBlock = STORM_ALLOC(TMPQBlock, dwBlockTableSize); + if(pBlockTable != NULL) + { + // Convert the block table + for(DWORD i = 0; i < dwBlockTableSize; i++) + { + NeedHiBlockTable |= (DWORD)(pFileEntry->ByteOffset >> 32); + pBlock->dwFilePos = (DWORD)pFileEntry->ByteOffset; + pBlock->dwFSize = pFileEntry->dwFileSize; + pBlock->dwCSize = pFileEntry->dwCmpSize; + pBlock->dwFlags = pFileEntry->dwFlags; + + pFileEntry++; + pBlock++; + } + + // Give the size to the caller + if(pcbTableSize != NULL) + *pcbTableSize = (ULONGLONG)dwBlockTableSize * sizeof(TMPQBlock); + + if(pbNeedHiBlockTable != NULL) + *pbNeedHiBlockTable = NeedHiBlockTable ? true : false; + } + + return pBlockTable; +} + +static USHORT * TranslateHiBlockTable( + TMPQArchive * ha, + ULONGLONG * pcbTableSize) +{ + TFileEntry * pFileEntry = ha->pFileTable; + USHORT * pHiBlockTable; + USHORT * pHiBlock; + DWORD dwBlockTableSize = ha->pHeader->dwBlockTableSize; + + // Allocate copy of the hash table + pHiBlockTable = pHiBlock = STORM_ALLOC(USHORT, dwBlockTableSize); + if(pHiBlockTable != NULL) + { + // Copy the block table + for(DWORD i = 0; i < dwBlockTableSize; i++) + pHiBlock[i] = (USHORT)(pFileEntry[i].ByteOffset >> 0x20); + + // Give the size to the caller + if(pcbTableSize != NULL) + *pcbTableSize = (ULONGLONG)dwBlockTableSize * sizeof(USHORT); + } + + return pHiBlockTable; +} + +//----------------------------------------------------------------------------- +// General EXT table functions + +TMPQExtHeader * LoadExtTable( + TMPQArchive * ha, + ULONGLONG ByteOffset, + size_t Size, + DWORD dwSignature, + DWORD dwKey) +{ + TMPQExtHeader * pCompressed = NULL; // Compressed table + TMPQExtHeader * pExtTable = NULL; // Uncompressed table + + // Do nothing if the size is zero + if(ByteOffset != 0 && Size != 0) + { + // Allocate size for the compressed table + pExtTable = (TMPQExtHeader *)STORM_ALLOC(BYTE, Size); + if(pExtTable != NULL) + { + // Load the table from the MPQ + ByteOffset += ha->MpqPos; + if(!FileStream_Read(ha->pStream, &ByteOffset, pExtTable, (DWORD)Size)) + { + STORM_FREE(pExtTable); + return NULL; + } + + // Swap the ext table header + BSWAP_ARRAY32_UNSIGNED(pExtTable, sizeof(TMPQExtHeader)); + if(pExtTable->dwSignature != dwSignature) + { + STORM_FREE(pExtTable); + return NULL; + } + + // Decrypt the block + BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize); + DecryptMpqBlock(pExtTable + 1, (DWORD)(Size - sizeof(TMPQExtHeader)), dwKey); + BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize); + + // If the table is compressed, decompress it + if((pExtTable->dwDataSize + sizeof(TMPQExtHeader)) > Size) + { + pCompressed = pExtTable; + pExtTable = (TMPQExtHeader *)STORM_ALLOC(BYTE, sizeof(TMPQExtHeader) + pCompressed->dwDataSize); + if(pExtTable != NULL) + { + int cbOutBuffer = (int)pCompressed->dwDataSize; + int cbInBuffer = (int)Size; + + // Decompress the extended table + pExtTable->dwSignature = pCompressed->dwSignature; + pExtTable->dwVersion = pCompressed->dwVersion; + pExtTable->dwDataSize = pCompressed->dwDataSize; + if(!SCompDecompress2(pExtTable + 1, &cbOutBuffer, pCompressed + 1, cbInBuffer)) + { + STORM_FREE(pExtTable); + pExtTable = NULL; + } + } + + // Free the compressed block + STORM_FREE(pCompressed); + } + } + } + + // Return the decompressed table to the caller + return pExtTable; +} + +static int SaveMpqTable( + TMPQArchive * ha, + void * pMpqTable, + ULONGLONG ByteOffset, + size_t Size, + unsigned char * md5, + DWORD dwKey, + bool bCompress) +{ + ULONGLONG FileOffset; + void * pCompressed = NULL; + int nError = ERROR_SUCCESS; + + // Do we have to compress the table? + if(bCompress) + { + int cbOutBuffer = (int)Size; + int cbInBuffer = (int)Size; + + // Allocate extra space for compressed table + pCompressed = STORM_ALLOC(BYTE, Size); + if(pCompressed == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Compress the table + SCompCompress(pCompressed, &cbOutBuffer, pMpqTable, cbInBuffer, MPQ_COMPRESSION_ZLIB, 0, 0); + + // If the compression failed, revert it. Otherwise, swap the tables + if(cbOutBuffer >= cbInBuffer) + { + STORM_FREE(pCompressed); + pCompressed = NULL; + } + else + { + pMpqTable = pCompressed; + } + } + + // Encrypt the table + if(dwKey != 0) + { + BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size); + EncryptMpqBlock(pMpqTable, (DWORD)Size, dwKey); + BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size); + } + + // Calculate the MD5 + if(md5 != NULL) + { + CalculateDataBlockHash(pMpqTable, (DWORD)Size, md5); + } + + // Save the table to the MPQ + BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size); + FileOffset = ha->MpqPos + ByteOffset; + if(!FileStream_Write(ha->pStream, &FileOffset, pMpqTable, (DWORD)Size)) + nError = GetLastError(); + + // Free the compressed table, if any + if(pCompressed != NULL) + STORM_FREE(pCompressed); + return nError; +} + +static int SaveExtTable( + TMPQArchive * ha, + TMPQExtHeader * pExtTable, + ULONGLONG ByteOffset, + DWORD dwTableSize, + unsigned char * md5, + DWORD dwKey, + bool bCompress, + LPDWORD pcbTotalSize) +{ + ULONGLONG FileOffset; + TMPQExtHeader * pCompressed = NULL; + DWORD cbTotalSize = 0; + int nError = ERROR_SUCCESS; + + // Do we have to compress the table? + if(bCompress) + { + int cbOutBuffer = (int)dwTableSize; + int cbInBuffer = (int)dwTableSize; + + // Allocate extra space for compressed table + pCompressed = (TMPQExtHeader *)STORM_ALLOC(BYTE, dwTableSize); + if(pCompressed == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Compress the table + pCompressed->dwSignature = pExtTable->dwSignature; + pCompressed->dwVersion = pExtTable->dwVersion; + pCompressed->dwDataSize = pExtTable->dwDataSize; + SCompCompress((pCompressed + 1), &cbOutBuffer, (pExtTable + 1), cbInBuffer, MPQ_COMPRESSION_ZLIB, 0, 0); + + // If the compression failed, revert it. Otherwise, swap the tables + if(cbOutBuffer >= cbInBuffer) + { + STORM_FREE(pCompressed); + pCompressed = NULL; + } + else + { + pExtTable = pCompressed; + } + } + + // Encrypt the table + if(dwKey != 0) + { + BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize); + EncryptMpqBlock(pExtTable + 1, (DWORD)(dwTableSize - sizeof(TMPQExtHeader)), dwKey); + BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize); + } + + // Calculate the MD5 of the table after + if(md5 != NULL) + { + CalculateDataBlockHash(pExtTable, dwTableSize, md5); + } + + // Save the table to the MPQ + FileOffset = ha->MpqPos + ByteOffset; + if(FileStream_Write(ha->pStream, &FileOffset, pExtTable, dwTableSize)) + cbTotalSize += dwTableSize; + else + nError = GetLastError(); + + // We have to write raw data MD5 + if(nError == ERROR_SUCCESS && ha->pHeader->dwRawChunkSize != 0) + { + nError = WriteMemDataMD5(ha->pStream, + FileOffset, + pExtTable, + dwTableSize, + ha->pHeader->dwRawChunkSize, + &cbTotalSize); + } + + // Give the total written size, if needed + if(pcbTotalSize != NULL) + *pcbTotalSize = cbTotalSize; + + // Free the compressed table, if any + if(pCompressed != NULL) + STORM_FREE(pCompressed); + return nError; +} + +#ifdef FULL +//----------------------------------------------------------------------------- +// Support for HET table + +static void CreateHetHeader( + TMPQHetTable * pHetTable, + TMPQHetHeader * pHetHeader) +{ + // Fill the common header + pHetHeader->ExtHdr.dwSignature = HET_TABLE_SIGNATURE; + pHetHeader->ExtHdr.dwVersion = 1; + pHetHeader->ExtHdr.dwDataSize = 0; + + // Fill the HET header + pHetHeader->dwEntryCount = pHetTable->dwEntryCount; + pHetHeader->dwTotalCount = pHetTable->dwTotalCount; + pHetHeader->dwNameHashBitSize = pHetTable->dwNameHashBitSize; + pHetHeader->dwIndexSizeTotal = pHetTable->dwIndexSizeTotal; + pHetHeader->dwIndexSizeExtra = pHetTable->dwIndexSizeExtra; + pHetHeader->dwIndexSize = pHetTable->dwIndexSize; + pHetHeader->dwIndexTableSize = ((pHetHeader->dwIndexSizeTotal * pHetTable->dwTotalCount) + 7) / 8; + + // Calculate the total size needed for holding HET table + pHetHeader->ExtHdr.dwDataSize = + pHetHeader->dwTableSize = sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader) + + pHetHeader->dwTotalCount + + pHetHeader->dwIndexTableSize; +} + +TMPQHetTable * CreateHetTable(DWORD dwEntryCount, DWORD dwTotalCount, DWORD dwNameHashBitSize, LPBYTE pbSrcData) +{ + TMPQHetTable * pHetTable; + + pHetTable = STORM_ALLOC(TMPQHetTable, 1); + if(pHetTable != NULL) + { + // Zero the HET table + memset(pHetTable, 0, sizeof(TMPQHetTable)); + + // Hash sizes less than 0x40 bits are not tested + assert(dwNameHashBitSize == 0x40); + + // Calculate masks + pHetTable->AndMask64 = ((dwNameHashBitSize != 0x40) ? ((ULONGLONG)1 << dwNameHashBitSize) : 0) - 1; + pHetTable->OrMask64 = (ULONGLONG)1 << (dwNameHashBitSize - 1); + + // If the total count is not entered, use default + if(dwTotalCount == 0) + dwTotalCount = (dwEntryCount * 4) / 3; + + // Store the HET table parameters + pHetTable->dwEntryCount = dwEntryCount; + pHetTable->dwTotalCount = dwTotalCount; + pHetTable->dwNameHashBitSize = dwNameHashBitSize; + pHetTable->dwIndexSizeTotal = GetNecessaryBitCount(dwEntryCount); + pHetTable->dwIndexSizeExtra = 0; + pHetTable->dwIndexSize = pHetTable->dwIndexSizeTotal; + + // Allocate array of hashes + pHetTable->pNameHashes = STORM_ALLOC(BYTE, dwTotalCount); + if(pHetTable->pNameHashes != NULL) + { + // Make sure the data are initialized + memset(pHetTable->pNameHashes, 0, dwTotalCount); + + // Allocate the bit array for file indexes + pHetTable->pBetIndexes = CreateBitArray(dwTotalCount * pHetTable->dwIndexSizeTotal, 0xFF); + if(pHetTable->pBetIndexes != NULL) + { + // Initialize the HET table from the source data (if given) + if(pbSrcData != NULL) + { + // Copy the name hashes + memcpy(pHetTable->pNameHashes, pbSrcData, dwTotalCount); + + // Copy the file indexes + memcpy(pHetTable->pBetIndexes->Elements, pbSrcData + dwTotalCount, pHetTable->pBetIndexes->NumberOfBytes); + } + + // Return the result HET table + return pHetTable; + } + + // Free the name hashes + STORM_FREE(pHetTable->pNameHashes); + } + + STORM_FREE(pHetTable); + } + + // Failed + return NULL; +} + +static int InsertHetEntry(TMPQHetTable * pHetTable, ULONGLONG FileNameHash, DWORD dwFileIndex) +{ + DWORD StartIndex; + DWORD Index; + BYTE NameHash1; + + // Get the start index and the high 8 bits of the name hash + StartIndex = Index = (DWORD)(FileNameHash % pHetTable->dwTotalCount); + NameHash1 = (BYTE)(FileNameHash >> (pHetTable->dwNameHashBitSize - 8)); + + // Find a place where to put it + for(;;) + { + // Did we find a free HET entry? + if(pHetTable->pNameHashes[Index] == HET_ENTRY_FREE) + { + // Set the entry in the name hash table + pHetTable->pNameHashes[Index] = NameHash1; + + // Set the entry in the file index table + SetBits(pHetTable->pBetIndexes, pHetTable->dwIndexSizeTotal * Index, + pHetTable->dwIndexSize, + &dwFileIndex, + 4); + return ERROR_SUCCESS; + } + + // Move to the next entry in the HET table + // If we came to the start index again, we are done + Index = (Index + 1) % pHetTable->dwTotalCount; + if(Index == StartIndex) + break; + } + + // No space in the HET table. Should never happen, + // because the HET table is created according to the number of files + assert(false); + return ERROR_DISK_FULL; +} + +static TMPQHetTable * TranslateHetTable(TMPQHetHeader * pHetHeader) +{ + TMPQHetTable * pHetTable = NULL; + LPBYTE pbSrcData = (LPBYTE)(pHetHeader + 1); + + // Sanity check + assert(pHetHeader->ExtHdr.dwSignature == HET_TABLE_SIGNATURE); + assert(pHetHeader->ExtHdr.dwVersion == 1); + + // Verify size of the HET table + if(pHetHeader->ExtHdr.dwDataSize >= (sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader))) + { + // Verify the size of the table in the header + if(pHetHeader->dwTableSize == pHetHeader->ExtHdr.dwDataSize) + { + // The size of the HET table must be sum of header, hash and index table size + assert((sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader) + pHetHeader->dwTotalCount + pHetHeader->dwIndexTableSize) == pHetHeader->dwTableSize); + + // So far, all MPQs with HET Table have had total number of entries equal to 4/3 of file count + // Exception: "2010 - Starcraft II\!maps\Tya's Zerg Defense (unprotected).SC2Map" +// assert(((pHetHeader->dwEntryCount * 4) / 3) == pHetHeader->dwTotalCount); + + // The size of one index is predictable as well + assert(GetNecessaryBitCount(pHetHeader->dwEntryCount) == pHetHeader->dwIndexSizeTotal); + + // The size of index table (in entries) is expected + // to be the same like the hash table size (in bytes) + assert(((pHetHeader->dwTotalCount * pHetHeader->dwIndexSizeTotal) + 7) / 8 == pHetHeader->dwIndexTableSize); + + // Create translated table + pHetTable = CreateHetTable(pHetHeader->dwEntryCount, pHetHeader->dwTotalCount, pHetHeader->dwNameHashBitSize, pbSrcData); + if(pHetTable != NULL) + { + // Now the sizes in the hash table should be already set + assert(pHetTable->dwEntryCount == pHetHeader->dwEntryCount); + assert(pHetTable->dwTotalCount == pHetHeader->dwTotalCount); + assert(pHetTable->dwIndexSizeTotal == pHetHeader->dwIndexSizeTotal); + + // Copy the missing variables + pHetTable->dwIndexSizeExtra = pHetHeader->dwIndexSizeExtra; + pHetTable->dwIndexSize = pHetHeader->dwIndexSize; + } + } + } + + return pHetTable; +} + +static TMPQExtHeader * TranslateHetTable(TMPQHetTable * pHetTable, ULONGLONG * pcbHetTable) +{ + TMPQHetHeader * pHetHeader = NULL; + TMPQHetHeader HetHeader; + LPBYTE pbLinearTable = NULL; + LPBYTE pbTrgData; + + // Prepare header of the HET table + CreateHetHeader(pHetTable, &HetHeader); + + // Allocate space for the linear table + pbLinearTable = STORM_ALLOC(BYTE, sizeof(TMPQExtHeader) + HetHeader.dwTableSize); + if(pbLinearTable != NULL) + { + // Copy the table header + pHetHeader = (TMPQHetHeader *)pbLinearTable; + memcpy(pHetHeader, &HetHeader, sizeof(TMPQHetHeader)); + pbTrgData = (LPBYTE)(pHetHeader + 1); + + // Copy the array of name hashes + memcpy(pbTrgData, pHetTable->pNameHashes, pHetTable->dwTotalCount); + pbTrgData += pHetTable->dwTotalCount; + + // Copy the bit array of BET indexes + memcpy(pbTrgData, pHetTable->pBetIndexes->Elements, HetHeader.dwIndexTableSize); + + // Calculate the total size of the table, including the TMPQExtHeader + if(pcbHetTable != NULL) + { + *pcbHetTable = (ULONGLONG)(sizeof(TMPQExtHeader) + HetHeader.dwTableSize); + } + } + + // Keep Coverity happy + assert((TMPQExtHeader *)&pHetHeader->ExtHdr == (TMPQExtHeader *)pbLinearTable); + return (TMPQExtHeader *)pbLinearTable; +} + + +static DWORD GetFileIndex_Het(TMPQArchive * ha, const char * szFileName) +{ + TMPQHetTable * pHetTable = ha->pHetTable; + ULONGLONG FileNameHash; + DWORD StartIndex; + DWORD Index; + BYTE NameHash1; // Upper 8 bits of the masked file name hash + + // If there are no entries in the HET table, do nothing + if(pHetTable->dwEntryCount == 0) + return HASH_ENTRY_FREE; + + // Do nothing if the MPQ has no HET table + assert(ha->pHetTable != NULL); + + // Calculate 64-bit hash of the file name + FileNameHash = (HashStringJenkins(szFileName) & pHetTable->AndMask64) | pHetTable->OrMask64; + + // Split the file name hash into two parts: + // NameHash1: The highest 8 bits of the name hash + // NameHash2: File name hash limited to hash size + // Note: Our file table contains full name hash, no need to cut the high 8 bits before comparison + NameHash1 = (BYTE)(FileNameHash >> (pHetTable->dwNameHashBitSize - 8)); + + // Calculate the starting index to the hash table + StartIndex = Index = (DWORD)(FileNameHash % pHetTable->dwTotalCount); + + // Go through HET table until we find a terminator + while(pHetTable->pNameHashes[Index] != HET_ENTRY_FREE) + { + // Did we find a match ? + if(pHetTable->pNameHashes[Index] == NameHash1) + { + DWORD dwFileIndex = 0; + + // Get the file index + GetBits(pHetTable->pBetIndexes, pHetTable->dwIndexSizeTotal * Index, + pHetTable->dwIndexSize, + &dwFileIndex, + sizeof(DWORD)); + + // Verify the FileNameHash against the entry in the table of name hashes + if(dwFileIndex <= ha->dwFileTableSize && ha->pFileTable[dwFileIndex].FileNameHash == FileNameHash) + { + return dwFileIndex; + } + } + + // Move to the next entry in the HET table + // If we came to the start index again, we are done + Index = (Index + 1) % pHetTable->dwTotalCount; + if(Index == StartIndex) + break; + } + + // File not found + return HASH_ENTRY_FREE; +} + +void FreeHetTable(TMPQHetTable * pHetTable) +{ + if(pHetTable != NULL) + { + if(pHetTable->pNameHashes != NULL) + STORM_FREE(pHetTable->pNameHashes); + if(pHetTable->pBetIndexes != NULL) + STORM_FREE(pHetTable->pBetIndexes); + + STORM_FREE(pHetTable); + } +} + +//----------------------------------------------------------------------------- +// Support for BET table + +static void CreateBetHeader( + TMPQArchive * ha, + TMPQBetHeader * pBetHeader) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + ULONGLONG MaxByteOffset = 0; + DWORD FlagArray[MAX_FLAG_INDEX]; + DWORD dwMaxFlagIndex = 0; + DWORD dwMaxFileSize = 0; + DWORD dwMaxCmpSize = 0; + DWORD dwFlagIndex; + + // Initialize array of flag combinations + InitFileFlagArray(FlagArray); + + // Fill the common header + pBetHeader->ExtHdr.dwSignature = BET_TABLE_SIGNATURE; + pBetHeader->ExtHdr.dwVersion = 1; + pBetHeader->ExtHdr.dwDataSize = 0; + + // Get the maximum values for the BET table + pFileTableEnd = ha->pFileTable + ha->pHeader->dwBlockTableSize; + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // + // Note: Deleted files must be counted as well + // + + // Highest file position in the MPQ + if(pFileEntry->ByteOffset > MaxByteOffset) + MaxByteOffset = pFileEntry->ByteOffset; + + // Biggest file size + if(pFileEntry->dwFileSize > dwMaxFileSize) + dwMaxFileSize = pFileEntry->dwFileSize; + + // Biggest compressed size + if(pFileEntry->dwCmpSize > dwMaxCmpSize) + dwMaxCmpSize = pFileEntry->dwCmpSize; + + // Check if this flag was there before + dwFlagIndex = GetFileFlagIndex(FlagArray, pFileEntry->dwFlags); + if(dwFlagIndex > dwMaxFlagIndex) + dwMaxFlagIndex = dwFlagIndex; + } + + // Now save bit count for every piece of file information + pBetHeader->dwBitIndex_FilePos = 0; + pBetHeader->dwBitCount_FilePos = GetNecessaryBitCount(MaxByteOffset); + + pBetHeader->dwBitIndex_FileSize = pBetHeader->dwBitIndex_FilePos + pBetHeader->dwBitCount_FilePos; + pBetHeader->dwBitCount_FileSize = GetNecessaryBitCount(dwMaxFileSize); + + pBetHeader->dwBitIndex_CmpSize = pBetHeader->dwBitIndex_FileSize + pBetHeader->dwBitCount_FileSize; + pBetHeader->dwBitCount_CmpSize = GetNecessaryBitCount(dwMaxCmpSize); + + pBetHeader->dwBitIndex_FlagIndex = pBetHeader->dwBitIndex_CmpSize + pBetHeader->dwBitCount_CmpSize; + pBetHeader->dwBitCount_FlagIndex = GetNecessaryBitCount(dwMaxFlagIndex + 1); + + pBetHeader->dwBitIndex_Unknown = pBetHeader->dwBitIndex_FlagIndex + pBetHeader->dwBitCount_FlagIndex; + pBetHeader->dwBitCount_Unknown = 0; + + // Calculate the total size of one entry + pBetHeader->dwTableEntrySize = pBetHeader->dwBitCount_FilePos + + pBetHeader->dwBitCount_FileSize + + pBetHeader->dwBitCount_CmpSize + + pBetHeader->dwBitCount_FlagIndex + + pBetHeader->dwBitCount_Unknown; + + // Save the file count and flag count + pBetHeader->dwEntryCount = ha->pHeader->dwBlockTableSize; + pBetHeader->dwFlagCount = dwMaxFlagIndex + 1; + pBetHeader->dwUnknown08 = 0x10; + + // Save the total size of the BET hash + pBetHeader->dwBitTotal_NameHash2 = ha->pHetTable->dwNameHashBitSize - 0x08; + pBetHeader->dwBitExtra_NameHash2 = 0; + pBetHeader->dwBitCount_NameHash2 = pBetHeader->dwBitTotal_NameHash2; + pBetHeader->dwNameHashArraySize = ((pBetHeader->dwBitTotal_NameHash2 * pBetHeader->dwEntryCount) + 7) / 8; + + // Save the total table size + pBetHeader->ExtHdr.dwDataSize = + pBetHeader->dwTableSize = sizeof(TMPQBetHeader) - sizeof(TMPQExtHeader) + + pBetHeader->dwFlagCount * sizeof(DWORD) + + ((pBetHeader->dwTableEntrySize * pBetHeader->dwEntryCount) + 7) / 8 + + pBetHeader->dwNameHashArraySize; +} + +TMPQBetTable * CreateBetTable(DWORD dwEntryCount) +{ + TMPQBetTable * pBetTable; + + // Allocate BET table + pBetTable = STORM_ALLOC(TMPQBetTable, 1); + if(pBetTable != NULL) + { + memset(pBetTable, 0, sizeof(TMPQBetTable)); + pBetTable->dwEntryCount = dwEntryCount; + } + + return pBetTable; +} + +static TMPQBetTable * TranslateBetTable( + TMPQArchive * ha, + TMPQBetHeader * pBetHeader) +{ + TMPQBetTable * pBetTable = NULL; + LPBYTE pbSrcData = (LPBYTE)(pBetHeader + 1); + DWORD LengthInBytes = 0; + + // Sanity check + assert(pBetHeader->ExtHdr.dwSignature == BET_TABLE_SIGNATURE); + assert(pBetHeader->ExtHdr.dwVersion == 1); + assert(ha->pHetTable != NULL); + ha = ha; + + // Verify size of the HET table + if(pBetHeader->ExtHdr.dwDataSize >= (sizeof(TMPQBetHeader) - sizeof(TMPQExtHeader))) + { + // Verify the size of the table in the header + if(pBetHeader->dwTableSize == pBetHeader->ExtHdr.dwDataSize) + { + // The number of entries in the BET table must be the same like number of entries in the block table + assert(pBetHeader->dwEntryCount == ha->pHeader->dwBlockTableSize); + assert(pBetHeader->dwEntryCount <= ha->dwMaxFileCount); + + // The number of entries in the BET table must be the same like number of entries in the HET table + // Note that if it's not, it is not a problem + //assert(pBetHeader->dwEntryCount == ha->pHetTable->dwEntryCount); + + // Create translated table + pBetTable = CreateBetTable(pBetHeader->dwEntryCount); + if(pBetTable != NULL) + { + // Copy the variables from the header to the BetTable + pBetTable->dwTableEntrySize = pBetHeader->dwTableEntrySize; + pBetTable->dwBitIndex_FilePos = pBetHeader->dwBitIndex_FilePos; + pBetTable->dwBitIndex_FileSize = pBetHeader->dwBitIndex_FileSize; + pBetTable->dwBitIndex_CmpSize = pBetHeader->dwBitIndex_CmpSize; + pBetTable->dwBitIndex_FlagIndex = pBetHeader->dwBitIndex_FlagIndex; + pBetTable->dwBitIndex_Unknown = pBetHeader->dwBitIndex_Unknown; + pBetTable->dwBitCount_FilePos = pBetHeader->dwBitCount_FilePos; + pBetTable->dwBitCount_FileSize = pBetHeader->dwBitCount_FileSize; + pBetTable->dwBitCount_CmpSize = pBetHeader->dwBitCount_CmpSize; + pBetTable->dwBitCount_FlagIndex = pBetHeader->dwBitCount_FlagIndex; + pBetTable->dwBitCount_Unknown = pBetHeader->dwBitCount_Unknown; + + // Since we don't know what the "unknown" is, we'll assert when it's zero + assert(pBetTable->dwBitCount_Unknown == 0); + + // Allocate array for flags + if(pBetHeader->dwFlagCount != 0) + { + // Allocate array for file flags and load it + pBetTable->pFileFlags = STORM_ALLOC(DWORD, pBetHeader->dwFlagCount); + if(pBetTable->pFileFlags != NULL) + { + LengthInBytes = pBetHeader->dwFlagCount * sizeof(DWORD); + memcpy(pBetTable->pFileFlags, pbSrcData, LengthInBytes); + BSWAP_ARRAY32_UNSIGNED(pBetTable->pFileFlags, LengthInBytes); + pbSrcData += LengthInBytes; + } + + // Save the number of flags + pBetTable->dwFlagCount = pBetHeader->dwFlagCount; + } + + // Load the bit-based file table + pBetTable->pFileTable = CreateBitArray(pBetTable->dwTableEntrySize * pBetHeader->dwEntryCount, 0); + if(pBetTable->pFileTable != NULL) + { + LengthInBytes = (pBetTable->pFileTable->NumberOfBits + 7) / 8; + memcpy(pBetTable->pFileTable->Elements, pbSrcData, LengthInBytes); + pbSrcData += LengthInBytes; + } + + // Fill the sizes of BET hash + pBetTable->dwBitTotal_NameHash2 = pBetHeader->dwBitTotal_NameHash2; + pBetTable->dwBitExtra_NameHash2 = pBetHeader->dwBitExtra_NameHash2; + pBetTable->dwBitCount_NameHash2 = pBetHeader->dwBitCount_NameHash2; + + // Create and load the array of BET hashes + pBetTable->pNameHashes = CreateBitArray(pBetTable->dwBitTotal_NameHash2 * pBetHeader->dwEntryCount, 0); + if(pBetTable->pNameHashes != NULL) + { + LengthInBytes = (pBetTable->pNameHashes->NumberOfBits + 7) / 8; + memcpy(pBetTable->pNameHashes->Elements, pbSrcData, LengthInBytes); +// pbSrcData += LengthInBytes; + } + + // Dump both tables +// DumpHetAndBetTable(ha->pHetTable, pBetTable); + } + } + } + + return pBetTable; +} + +TMPQExtHeader * TranslateBetTable( + TMPQArchive * ha, + ULONGLONG * pcbBetTable) +{ + TMPQBetHeader * pBetHeader = NULL; + TMPQBetHeader BetHeader; + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + TBitArray * pBitArray = NULL; + LPBYTE pbLinearTable = NULL; + LPBYTE pbTrgData; + DWORD LengthInBytes; + DWORD FlagArray[MAX_FLAG_INDEX]; + + // Calculate the bit sizes of various entries + InitFileFlagArray(FlagArray); + CreateBetHeader(ha, &BetHeader); + + // Allocate space + pbLinearTable = STORM_ALLOC(BYTE, sizeof(TMPQExtHeader) + BetHeader.dwTableSize); + if(pbLinearTable != NULL) + { + // Copy the BET header to the linear buffer + pBetHeader = (TMPQBetHeader *)pbLinearTable; + memcpy(pBetHeader, &BetHeader, sizeof(TMPQBetHeader)); + pbTrgData = (LPBYTE)(pBetHeader + 1); + + // Save the bit-based block table + pBitArray = CreateBitArray(BetHeader.dwEntryCount * BetHeader.dwTableEntrySize, 0); + if(pBitArray != NULL) + { + DWORD dwFlagIndex = 0; + DWORD nBitOffset = 0; + + // Construct the bit-based file table + pFileTableEnd = ha->pFileTable + BetHeader.dwEntryCount; + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // + // Note: Missing files must be included as well + // + + // Save the byte offset + SetBits(pBitArray, nBitOffset + BetHeader.dwBitIndex_FilePos, + BetHeader.dwBitCount_FilePos, + &pFileEntry->ByteOffset, + 8); + SetBits(pBitArray, nBitOffset + BetHeader.dwBitIndex_FileSize, + BetHeader.dwBitCount_FileSize, + &pFileEntry->dwFileSize, + 4); + SetBits(pBitArray, nBitOffset + BetHeader.dwBitIndex_CmpSize, + BetHeader.dwBitCount_CmpSize, + &pFileEntry->dwCmpSize, + 4); + + // Save the flag index + dwFlagIndex = GetFileFlagIndex(FlagArray, pFileEntry->dwFlags); + SetBits(pBitArray, nBitOffset + BetHeader.dwBitIndex_FlagIndex, + BetHeader.dwBitCount_FlagIndex, + &dwFlagIndex, + 4); + + // Move the bit offset + nBitOffset += BetHeader.dwTableEntrySize; + } + + // Write the array of flags + LengthInBytes = BetHeader.dwFlagCount * sizeof(DWORD); + memcpy(pbTrgData, FlagArray, LengthInBytes); + BSWAP_ARRAY32_UNSIGNED(pbTrgData, LengthInBytes); + pbTrgData += LengthInBytes; + + // Write the bit-based block table + LengthInBytes = (pBitArray->NumberOfBits + 7) / 8; + memcpy(pbTrgData, pBitArray->Elements, LengthInBytes); + pbTrgData += LengthInBytes; + + // Free the bit array + STORM_FREE(pBitArray); + } + + // Create bit array for name hashes + pBitArray = CreateBitArray(BetHeader.dwBitTotal_NameHash2 * BetHeader.dwEntryCount, 0); + if(pBitArray != NULL) + { + DWORD dwFileIndex = 0; + + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Insert the name hash to the bit array + SetBits(pBitArray, BetHeader.dwBitTotal_NameHash2 * dwFileIndex, + BetHeader.dwBitCount_NameHash2, + &pFileEntry->FileNameHash, + 8); + + assert(dwFileIndex < BetHeader.dwEntryCount); + dwFileIndex++; + } + + // Write the array of BET hashes + LengthInBytes = (pBitArray->NumberOfBits + 7) / 8; + memcpy(pbTrgData, pBitArray->Elements, LengthInBytes); +// pbTrgData += LengthInBytes; + + // Free the bit array + STORM_FREE(pBitArray); + } + + // Write the size of the BET table in the MPQ + if(pcbBetTable != NULL) + { + *pcbBetTable = (ULONGLONG)(sizeof(TMPQExtHeader) + BetHeader.dwTableSize); + } + } + + // Keep Coverity happy + assert((TMPQExtHeader *)&pBetHeader->ExtHdr == (TMPQExtHeader *)pbLinearTable); + return (TMPQExtHeader *)pbLinearTable; +} + +void FreeBetTable(TMPQBetTable * pBetTable) +{ + if(pBetTable != NULL) + { + if(pBetTable->pFileTable != NULL) + STORM_FREE(pBetTable->pFileTable); + if(pBetTable->pFileFlags != NULL) + STORM_FREE(pBetTable->pFileFlags); + if(pBetTable->pNameHashes != NULL) + STORM_FREE(pBetTable->pNameHashes); + + STORM_FREE(pBetTable); + } +} +#endif + +//----------------------------------------------------------------------------- +// Support for file table + +TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex) +{ + TMPQHash * pHash; + DWORD dwFileIndex; + + // First, we have to search the classic hash table + // This is because on renaming, deleting, or changing locale, + // we will need the pointer to hash table entry + if(ha->pHashTable != NULL) + { + pHash = GetHashEntryLocale(ha, szFileName, lcLocale, 0); + if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) + { + if(PtrHashIndex != NULL) + PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable); + return ha->pFileTable + MPQ_BLOCK_INDEX(pHash); + } + } + +#ifdef FULL + // If we have HET table in the MPQ, try to find the file in HET table + if(ha->pHetTable != NULL) + { + dwFileIndex = GetFileIndex_Het(ha, szFileName); + if(dwFileIndex != HASH_ENTRY_FREE) + return ha->pFileTable + dwFileIndex; + } +#endif + + // Not found + return NULL; +} + +TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale) +{ + return GetFileEntryLocale2(ha, szFileName, lcLocale, NULL); +} + +TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex) +{ + TMPQHash * pHash; + DWORD dwFileIndex; + + // If the hash table is present, find the entry from hash table + if(ha->pHashTable != NULL) + { + pHash = GetHashEntryExact(ha, szFileName, lcLocale); + if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) + { + if(PtrHashIndex != NULL) + PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable); + return ha->pFileTable + MPQ_BLOCK_INDEX(pHash); + } + } + +#ifdef FULL + // If we have HET table in the MPQ, try to find the file in HET table + if(ha->pHetTable != NULL) + { + dwFileIndex = GetFileIndex_Het(ha, szFileName); + if(dwFileIndex != HASH_ENTRY_FREE) + { + if(PtrHashIndex != NULL) + PtrHashIndex[0] = HASH_ENTRY_FREE; + return ha->pFileTable + dwFileIndex; + } + } +#endif + + // Not found + return NULL; +} + +void AllocateFileName(TMPQArchive * ha, TFileEntry * pFileEntry, const char * szFileName) +{ + // Sanity check + assert(pFileEntry != NULL); + + // If the file name is pseudo file name, free it at this point + if(IsPseudoFileName(pFileEntry->szFileName, NULL)) + { + if(pFileEntry->szFileName != NULL) + STORM_FREE(pFileEntry->szFileName); + pFileEntry->szFileName = NULL; + } + + // Only allocate new file name if it's not there yet + if(pFileEntry->szFileName == NULL) + { + pFileEntry->szFileName = STORM_ALLOC(char, strlen(szFileName) + 1); + if(pFileEntry->szFileName != NULL) + strcpy(pFileEntry->szFileName, szFileName); + } + +#ifdef FULL + // We also need to create the file name hash + if(ha->pHetTable != NULL) + { + ULONGLONG AndMask64 = ha->pHetTable->AndMask64; + ULONGLONG OrMask64 = ha->pHetTable->OrMask64; + + pFileEntry->FileNameHash = (HashStringJenkins(szFileName) & AndMask64) | OrMask64; + } +#endif +} + +TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFreeEntry = NULL; + TFileEntry * pFileEntry; + TMPQHash * pHash = NULL; + DWORD dwReservedFiles = ha->dwReservedFiles; + DWORD dwFreeCount = 0; + + // Sanity check: File table size must be greater or equal to max file count + assert(ha->dwFileTableSize >= ha->dwMaxFileCount); + + // If we are saving MPQ tables, we don't tale number of reserved files into account + dwReservedFiles = (ha->dwFlags & MPQ_FLAG_SAVING_TABLES) ? 0 : ha->dwReservedFiles; + + // Now find a free entry in the file table. + // Note that in the case when free entries are in the middle, + // we need to use these + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0) + { + // Remember the first free entry + if(pFreeEntry == NULL) + pFreeEntry = pFileEntry; + dwFreeCount++; + + // If the number of free items is greater than number + // of reserved items, We can add the file + if(dwFreeCount > dwReservedFiles) + break; + } + } + + // If the total number of free entries is less than number of reserved files, + // we cannot add the file to the archive + if(pFreeEntry == NULL || dwFreeCount <= dwReservedFiles) + return NULL; + + // Initialize the file entry and set its file name + memset(pFreeEntry, 0, sizeof(TFileEntry)); + AllocateFileName(ha, pFreeEntry, szFileName); + + // If the archive has a hash table, we need to first free entry there + if(ha->pHashTable != NULL) + { + // Make sure that the entry is not there yet + assert(GetHashEntryExact(ha, szFileName, lcLocale) == NULL); + + // Find a free hash table entry for the name + pHash = AllocateHashEntry(ha, pFreeEntry, lcLocale); + if(pHash == NULL) + return NULL; + + // Set the file index to the hash table + pHash->dwBlockIndex = (DWORD)(pFreeEntry - ha->pFileTable); + PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable); + } + +#ifdef FULL + // If the archive has a HET table, just do some checks + // Note: Don't bother modifying the HET table. It will be rebuilt from scratch after, anyway + if(ha->pHetTable != NULL) + { + assert(GetFileIndex_Het(ha, szFileName) == HASH_ENTRY_FREE); + } +#endif + + // Return the free table entry + return pFreeEntry; +} + +int RenameFileEntry( + TMPQArchive * ha, + TMPQFile * hf, + const char * szNewFileName) +{ + TFileEntry * pFileEntry = hf->pFileEntry; + TMPQHash * pHashEntry = hf->pHashEntry; + LCID lcLocale = 0; + + // If the archive hash hash table, we need to free the hash table entry + if(ha->pHashTable != NULL) + { + // The file must have hash table entry assigned + // Will exit if there are multiple HASH entries pointing to the same file entry + if(pHashEntry == NULL) + return ERROR_NOT_SUPPORTED; + + // Save the locale + lcLocale = pHashEntry->lcLocale; + + // Mark the hash table entry as deleted + pHashEntry->dwName1 = 0xFFFFFFFF; + pHashEntry->dwName2 = 0xFFFFFFFF; + pHashEntry->lcLocale = 0xFFFF; + pHashEntry->Platform = 0xFF; + pHashEntry->Reserved = 0xFF; + pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED; + } + + // Free the old file name + if(pFileEntry->szFileName != NULL) + STORM_FREE(pFileEntry->szFileName); + pFileEntry->szFileName = NULL; + + // Allocate new file name + AllocateFileName(ha, pFileEntry, szNewFileName); + + // Allocate new hash entry + if(ha->pHashTable != NULL) + { + // Since we freed one hash entry before, this must succeed + hf->pHashEntry = AllocateHashEntry(ha, pFileEntry, lcLocale); + assert(hf->pHashEntry != NULL); + } + + return ERROR_SUCCESS; +} + +int DeleteFileEntry(TMPQArchive * ha, TMPQFile * hf) +{ + TFileEntry * pFileEntry = hf->pFileEntry; + TMPQHash * pHashEntry = hf->pHashEntry; + + // If the archive hash hash table, we need to free the hash table entry + if(ha->pHashTable != NULL) + { + // The file must have hash table entry assigned + // Will exit if there are multiple HASH entries pointing to the same file entry + if(pHashEntry == NULL) + return ERROR_NOT_SUPPORTED; + + // Mark the hash table entry as deleted + pHashEntry->dwName1 = 0xFFFFFFFF; + pHashEntry->dwName2 = 0xFFFFFFFF; + pHashEntry->lcLocale = 0xFFFF; + pHashEntry->Platform = 0xFF; + pHashEntry->Reserved = 0xFF; + pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED; + } + + // Free the file name, and set the file entry as deleted + if(pFileEntry->szFileName != NULL) + STORM_FREE(pFileEntry->szFileName); + pFileEntry->szFileName = NULL; + + // + // Don't modify the HET table, because it gets recreated by the caller + // Don't decrement the number of entries in the file table + // Keep Byte Offset, file size, compressed size, CRC32 and MD5 + // Clear the file name hash and the MPQ_FILE_EXISTS bit + // + + pFileEntry->dwFlags &= ~MPQ_FILE_EXISTS; + pFileEntry->FileNameHash = 0; + return ERROR_SUCCESS; +} + +DWORD InvalidateInternalFile(TMPQArchive * ha, const char * szFileName, DWORD dwFlagNone, DWORD dwFlagNew) +{ + TMPQFile * hf = NULL; + DWORD dwFileFlags = 0; + int nError = ERROR_FILE_NOT_FOUND; + + // Open the file from the MPQ + if(SFileOpenFileEx((HANDLE)ha, szFileName, SFILE_OPEN_BASE_FILE, (HANDLE *)&hf)) + { + // Remember the file flags + dwFileFlags = hf->pFileEntry->dwFlags; + + // Delete the file entry + nError = DeleteFileEntry(ha, hf); + if(nError == ERROR_SUCCESS) + { + ha->dwFlags |= dwFlagNew; + ha->dwReservedFiles++; + } + + // Free the file entry + FreeFileHandle(hf); + } + + // If the deletion failed, set the "none" flag + ha->dwFlags |= (nError != ERROR_SUCCESS) ? dwFlagNone : 0; + return dwFileFlags; +} + +void InvalidateInternalFiles(TMPQArchive * ha) +{ + // Do nothing if we are in the middle of saving internal files + if(!(ha->dwFlags & MPQ_FLAG_SAVING_TABLES)) + { + // + // We clear the file entries for (listfile), (attributes) and (signature) + // For each internal file cleared, we increment the number + // of reserved entries in the file table. + // + + // Invalidate the (listfile), if not done yet + if((ha->dwFlags & (MPQ_FLAG_LISTFILE_NONE | MPQ_FLAG_LISTFILE_NEW)) == 0) + { + ha->dwFileFlags1 = InvalidateInternalFile(ha, LISTFILE_NAME, MPQ_FLAG_LISTFILE_NONE, MPQ_FLAG_LISTFILE_NEW); + } + + // Invalidate the (attributes), if not done yet + if((ha->dwFlags & (MPQ_FLAG_ATTRIBUTES_NONE | MPQ_FLAG_ATTRIBUTES_NEW)) == 0) + { + ha->dwFileFlags2 = InvalidateInternalFile(ha, ATTRIBUTES_NAME, MPQ_FLAG_ATTRIBUTES_NONE, MPQ_FLAG_ATTRIBUTES_NEW); + } + + // Invalidate the (signature), if not done yet + if((ha->dwFlags & (MPQ_FLAG_SIGNATURE_NONE | MPQ_FLAG_SIGNATURE_NEW)) == 0) + { + ha->dwFileFlags3 = InvalidateInternalFile(ha, SIGNATURE_NAME, MPQ_FLAG_SIGNATURE_NONE, MPQ_FLAG_SIGNATURE_NEW); + } + + // Remember that the MPQ has been changed + ha->dwFlags |= MPQ_FLAG_CHANGED; + } +} + +//----------------------------------------------------------------------------- +// Support for file tables - hash table, block table, hi-block table + +int CreateHashTable(TMPQArchive * ha, DWORD dwHashTableSize) +{ + TMPQHash * pHashTable; + + // Sanity checks + assert((dwHashTableSize & (dwHashTableSize - 1)) == 0); + assert(ha->pHashTable == NULL); + + // If the required hash table size is zero, don't create anything + if(dwHashTableSize == 0) + dwHashTableSize = HASH_TABLE_SIZE_DEFAULT; + + // Create the hash table + pHashTable = STORM_ALLOC(TMPQHash, dwHashTableSize); + if(pHashTable == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill it + memset(pHashTable, 0xFF, dwHashTableSize * sizeof(TMPQHash)); + ha->pHeader->dwHashTableSize = dwHashTableSize; + ha->dwMaxFileCount = dwHashTableSize; + ha->pHashTable = pHashTable; + return ERROR_SUCCESS; +} + +static TMPQHash * LoadHashTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + ULONGLONG ByteOffset; + TMPQHash * pHashTable = NULL; + DWORD dwTableSize; + DWORD dwCmpSize; + bool bHashTableIsCut = false; + + // Note: It is allowed to load hash table if it is at offset 0. + // Example: MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x +// if(pHeader->dwHashTablePos == 0 && pHeader->wHashTablePosHi == 0) +// return NULL; + + // If the hash table size is zero, do nothing + if(pHeader->dwHashTableSize == 0) + return NULL; + + // Load the hash table for MPQ variations + switch(ha->dwSubType) + { + case MPQ_SUBTYPE_MPQ: + + // Calculate the position and size of the hash table + ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos)); + dwTableSize = pHeader->dwHashTableSize * sizeof(TMPQHash); + dwCmpSize = (DWORD)pHeader->HashTableSize64; + + // Read, decrypt and uncompress the hash table + pHashTable = (TMPQHash *)LoadMpqTable(ha, ByteOffset, dwCmpSize, dwTableSize, MPQ_KEY_HASH_TABLE, &bHashTableIsCut); +// DumpHashTable(pHashTable, pHeader->dwHashTableSize); + + // If the hash table was cut, we can/have to defragment it + if(pHashTable != NULL && bHashTableIsCut) + ha->dwFlags |= (MPQ_FLAG_MALFORMED | MPQ_FLAG_HASH_TABLE_CUT); + break; + + case MPQ_SUBTYPE_SQP: + pHashTable = LoadSqpHashTable(ha); + break; + + case MPQ_SUBTYPE_MPK: + pHashTable = LoadMpkHashTable(ha); + break; + } + + // Remember the size of the hash table + return pHashTable; +} + +int CreateFileTable(TMPQArchive * ha, DWORD dwFileTableSize) +{ + ha->pFileTable = STORM_ALLOC(TFileEntry, dwFileTableSize); + if(ha->pFileTable == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + memset(ha->pFileTable, 0x00, sizeof(TFileEntry) * dwFileTableSize); + ha->dwFileTableSize = dwFileTableSize; + return ERROR_SUCCESS; +} + +TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool /* bDontFixEntries */) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPQBlock * pBlockTable = NULL; + ULONGLONG ByteOffset; + DWORD dwTableSize; + DWORD dwCmpSize; + bool bBlockTableIsCut = false; + + // Note: It is possible that the block table starts at offset 0 + // Example: MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x +// if(pHeader->dwBlockTablePos == 0 && pHeader->wBlockTablePosHi == 0) +// return NULL; + + // Do nothing if the block table size is zero + if(pHeader->dwBlockTableSize == 0) + return NULL; + + // Load the block table for MPQ variations + switch(ha->dwSubType) + { + case MPQ_SUBTYPE_MPQ: + + // Calculate byte position of the block table + ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos)); + dwTableSize = pHeader->dwBlockTableSize * sizeof(TMPQBlock); + dwCmpSize = (DWORD)pHeader->BlockTableSize64; + + // Read, decrypt and uncompress the block table + pBlockTable = (TMPQBlock * )LoadMpqTable(ha, ByteOffset, dwCmpSize, dwTableSize, MPQ_KEY_BLOCK_TABLE, &bBlockTableIsCut); + + // If the block table was cut, we need to remember it + if(pBlockTable != NULL && bBlockTableIsCut) + ha->dwFlags |= (MPQ_FLAG_MALFORMED | MPQ_FLAG_BLOCK_TABLE_CUT); + break; + + case MPQ_SUBTYPE_SQP: + + pBlockTable = LoadSqpBlockTable(ha); + break; + + case MPQ_SUBTYPE_MPK: + + pBlockTable = LoadMpkBlockTable(ha); + break; + } + + return pBlockTable; +} + +#ifdef FULL +TMPQHetTable * LoadHetTable(TMPQArchive * ha) +{ + TMPQExtHeader * pExtTable; + TMPQHetTable * pHetTable = NULL; + TMPQHeader * pHeader = ha->pHeader; + + // If the HET table position is not 0, we expect the table to be present + if(pHeader->HetTablePos64 != 0 && pHeader->HetTableSize64 != 0) + { + // Attempt to load the HET table (Hash Extended Table) + pExtTable = LoadExtTable(ha, pHeader->HetTablePos64, (size_t)pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE); + if(pExtTable != NULL) + { + // If loading HET table fails, we ignore the result. + pHetTable = TranslateHetTable((TMPQHetHeader *)pExtTable); + STORM_FREE(pExtTable); + } + } + + return pHetTable; +} + +TMPQBetTable * LoadBetTable(TMPQArchive * ha) +{ + TMPQExtHeader * pExtTable; + TMPQBetTable * pBetTable = NULL; + TMPQHeader * pHeader = ha->pHeader; + + // If the BET table position is not 0, we expect the table to be present + if(pHeader->BetTablePos64 != 0 && pHeader->BetTableSize64 != 0) + { + // Attempt to load the HET table (Hash Extended Table) + pExtTable = LoadExtTable(ha, pHeader->BetTablePos64, (size_t)pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE); + if(pExtTable != NULL) + { + // If succeeded, we translate the BET table + // to more readable form + pBetTable = TranslateBetTable(ha, (TMPQBetHeader *)pExtTable); + STORM_FREE(pExtTable); + } + } + + return pBetTable; +} +#endif + +int LoadAnyHashTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + + // If the MPQ archive is empty, don't bother trying to load anything + if(pHeader->dwHashTableSize == 0 && pHeader->HetTableSize64 == 0) + return CreateHashTable(ha, HASH_TABLE_SIZE_DEFAULT); + +#ifdef FULL + // Try to load HET table + if(pHeader->HetTablePos64 != 0) + ha->pHetTable = LoadHetTable(ha); +#endif + // Try to load classic hash table + if(pHeader->dwHashTableSize) + ha->pHashTable = LoadHashTable(ha); + + // At least one of the tables must be present + if(ha->pHetTable == NULL && ha->pHashTable == NULL) + return ERROR_FILE_CORRUPT; + + // Set the maximum file count to the size of the hash table. + // Note: We don't care about HET table limits, because HET table is rebuilt + // after each file add/rename/delete. + ha->dwMaxFileCount = (ha->pHashTable != NULL) ? pHeader->dwHashTableSize : HASH_TABLE_SIZE_MAX; + return ERROR_SUCCESS; +} + +static int BuildFileTable_Classic(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPQBlock * pBlockTable; + int nError = ERROR_SUCCESS; + + // Sanity checks + assert(ha->pHashTable != NULL); + assert(ha->pFileTable != NULL); + + // If the MPQ has no block table, do nothing + if(pHeader->dwBlockTableSize == 0) + return ERROR_SUCCESS; + assert(ha->dwFileTableSize >= pHeader->dwBlockTableSize); + + // Load the block table + // WARNING! ha->pFileTable can change in the process!! + pBlockTable = (TMPQBlock *)LoadBlockTable(ha); + if(pBlockTable != NULL) + { + nError = BuildFileTableFromBlockTable(ha, pBlockTable); + STORM_FREE(pBlockTable); + } + else + { + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Load the hi-block table + if(nError == ERROR_SUCCESS && pHeader->HiBlockTablePos64 != 0) + { + ULONGLONG ByteOffset; + USHORT * pHiBlockTable = NULL; + DWORD dwTableSize = pHeader->dwBlockTableSize * sizeof(USHORT); + + // Allocate space for the hi-block table + // Note: pHeader->dwBlockTableSize can be zero !!! + pHiBlockTable = STORM_ALLOC(USHORT, pHeader->dwBlockTableSize + 1); + if(pHiBlockTable != NULL) + { + // Load the hi-block table. It is not encrypted, nor compressed + ByteOffset = ha->MpqPos + pHeader->HiBlockTablePos64; + if(!FileStream_Read(ha->pStream, &ByteOffset, pHiBlockTable, dwTableSize)) + nError = GetLastError(); + + // Now merge the hi-block table to the file table + if(nError == ERROR_SUCCESS) + { + TFileEntry * pFileEntry = ha->pFileTable; + + // Swap the hi-block table + BSWAP_ARRAY16_UNSIGNED(pHiBlockTable, dwTableSize); + + // Add the high file offset to the base file offset. + for(DWORD i = 0; i < pHeader->dwBlockTableSize; i++, pFileEntry++) + pFileEntry->ByteOffset = MAKE_OFFSET64(pHiBlockTable[i], pFileEntry->ByteOffset); + } + + // Free the hi-block table + STORM_FREE(pHiBlockTable); + } + else + { + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + return nError; +} + +#ifdef FULL +static int BuildFileTable_HetBet(TMPQArchive * ha) +{ + TMPQHetTable * pHetTable = ha->pHetTable; + TMPQBetTable * pBetTable; + TFileEntry * pFileEntry = ha->pFileTable; + TBitArray * pBitArray; + DWORD dwBitPosition = 0; + DWORD i; + int nError = ERROR_FILE_CORRUPT; + + // Load the BET table from the MPQ + pBetTable = LoadBetTable(ha); + if(pBetTable != NULL) + { + // Verify the size of NameHash2 in the BET table. + // It has to be 8 bits less than the information in HET table + if((pBetTable->dwBitCount_NameHash2 + 8) != pHetTable->dwNameHashBitSize) + { + FreeBetTable(pBetTable); + return ERROR_FILE_CORRUPT; + } + + // Step one: Fill the name indexes + for(i = 0; i < pHetTable->dwTotalCount; i++) + { + DWORD dwFileIndex = 0; + + // Is the entry in the HET table occupied? + if(pHetTable->pNameHashes[i] != HET_ENTRY_FREE) + { + // Load the index to the BET table + GetBits(pHetTable->pBetIndexes, pHetTable->dwIndexSizeTotal * i, + pHetTable->dwIndexSize, + &dwFileIndex, + 4); + // Overflow test + if(dwFileIndex < pBetTable->dwEntryCount) + { + ULONGLONG NameHash1 = pHetTable->pNameHashes[i]; + ULONGLONG NameHash2 = 0; + + // Load the BET hash + GetBits(pBetTable->pNameHashes, pBetTable->dwBitTotal_NameHash2 * dwFileIndex, + pBetTable->dwBitCount_NameHash2, + &NameHash2, + 8); + + // Combine both part of the name hash and put it to the file table + pFileEntry = ha->pFileTable + dwFileIndex; + pFileEntry->FileNameHash = (NameHash1 << pBetTable->dwBitCount_NameHash2) | NameHash2; + } + } + } + + // Go through the entire BET table and convert it to the file table. + pFileEntry = ha->pFileTable; + pBitArray = pBetTable->pFileTable; + for(i = 0; i < pBetTable->dwEntryCount; i++) + { + DWORD dwFlagIndex = 0; + + // Read the file position + GetBits(pBitArray, dwBitPosition + pBetTable->dwBitIndex_FilePos, + pBetTable->dwBitCount_FilePos, + &pFileEntry->ByteOffset, + 8); + + // Read the file size + GetBits(pBitArray, dwBitPosition + pBetTable->dwBitIndex_FileSize, + pBetTable->dwBitCount_FileSize, + &pFileEntry->dwFileSize, + 4); + + // Read the compressed size + GetBits(pBitArray, dwBitPosition + pBetTable->dwBitIndex_CmpSize, + pBetTable->dwBitCount_CmpSize, + &pFileEntry->dwCmpSize, + 4); + + + // Read the flag index + if(pBetTable->dwFlagCount != 0) + { + GetBits(pBitArray, dwBitPosition + pBetTable->dwBitIndex_FlagIndex, + pBetTable->dwBitCount_FlagIndex, + &dwFlagIndex, + 4); + pFileEntry->dwFlags = pBetTable->pFileFlags[dwFlagIndex]; + } + + // + // TODO: Locale (?) + // + + // Move the current bit position + dwBitPosition += pBetTable->dwTableEntrySize; + pFileEntry++; + } + + // Set the current size of the file table + FreeBetTable(pBetTable); + nError = ERROR_SUCCESS; + } + else + { + nError = ERROR_FILE_CORRUPT; + } + + return nError; +} +#endif + +int BuildFileTable(TMPQArchive * ha) +{ + DWORD dwFileTableSize; + bool bFileTableCreated = false; + + // Sanity checks + assert(ha->pFileTable == NULL); + assert(ha->dwFileTableSize == 0); + assert(ha->dwMaxFileCount != 0); + + // Determine the allocation size for the file table + dwFileTableSize = STORMLIB_MAX(ha->pHeader->dwBlockTableSize, ha->dwMaxFileCount); + + // Allocate the file table with size determined before + ha->pFileTable = STORM_ALLOC(TFileEntry, dwFileTableSize); + if(ha->pFileTable == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the table with zeros + memset(ha->pFileTable, 0, dwFileTableSize * sizeof(TFileEntry)); + ha->dwFileTableSize = dwFileTableSize; + +#ifdef FULL + // If we have HET table, we load file table from the BET table + // Note: If BET table is corrupt or missing, we set the archive as read only + if(ha->pHetTable != NULL) + { + if(BuildFileTable_HetBet(ha) != ERROR_SUCCESS) + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + else + bFileTableCreated = true; + } +#endif + + // If we have hash table, we load the file table from the block table + // Note: If block table is corrupt or missing, we set the archive as read only + if(ha->pHashTable != NULL) + { + if(BuildFileTable_Classic(ha) != ERROR_SUCCESS) + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + else + bFileTableCreated = true; + } + + // Return result + return bFileTableCreated ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; +} + +/* +void UpdateBlockTableSize(TMPQArchive * ha) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + DWORD dwBlockTableSize = 0; + + // Calculate the number of files + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // If the source table entry is valid, + if(pFileEntry->dwFlags & MPQ_FILE_EXISTS) + dwBlockTableSize = (DWORD)(pFileEntry - ha->pFileTable) + 1; + } + + // Save the block table size to the MPQ header + ha->pHeader->dwBlockTableSize = ha->dwReservedFiles + dwBlockTableSize; +} +*/ + +#ifdef FULL +// Defragment the file table so it does not contain any gaps +int DefragmentFileTable(TMPQArchive * ha) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pSource = ha->pFileTable; + TFileEntry * pTarget = ha->pFileTable; + LPDWORD DefragmentTable; + DWORD dwBlockTableSize = 0; + DWORD dwSrcIndex; + DWORD dwTrgIndex; + + // Allocate brand new file table + DefragmentTable = STORM_ALLOC(DWORD, ha->dwFileTableSize); + if(DefragmentTable != NULL) + { + // Clear the file table + memset(DefragmentTable, 0xFF, sizeof(DWORD) * ha->dwFileTableSize); + + // Parse the entire file table and defragment it + for(; pSource < pFileTableEnd; pSource++) + { + // If the source table entry is valid, + if(pSource->dwFlags & MPQ_FILE_EXISTS) + { + // Remember the index conversion + dwSrcIndex = (DWORD)(pSource - ha->pFileTable); + dwTrgIndex = (DWORD)(pTarget - ha->pFileTable); + DefragmentTable[dwSrcIndex] = dwTrgIndex; + + // Move the entry, if needed + if(pTarget != pSource) + pTarget[0] = pSource[0]; + pTarget++; + + // Update the block table size + dwBlockTableSize = (DWORD)(pTarget - ha->pFileTable); + } + else + { + // If there is file name left, free it + if(pSource->szFileName != NULL) + STORM_FREE(pSource->szFileName); + pSource->szFileName = NULL; + } + } + + // Did we defragment something? + if(pTarget < pFileTableEnd) + { + // Clear the remaining file entries + memset(pTarget, 0, (pFileTableEnd - pTarget) * sizeof(TFileEntry)); + + // Go through the hash table and relocate the block indexes + if(ha->pHashTable != NULL) + { + TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; + TMPQHash * pHash; + DWORD dwNewBlockIndex; + + for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++) + { + if(MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) + { + // If that block entry is there, set it to the hash entry + // If not, set it as DELETED + dwNewBlockIndex = DefragmentTable[MPQ_BLOCK_INDEX(pHash)]; + pHash->dwBlockIndex = (dwNewBlockIndex != HASH_ENTRY_FREE) ? dwNewBlockIndex : HASH_ENTRY_DELETED; + } + } + } + } + + // Save the block table size + ha->pHeader->dwBlockTableSize = ha->dwReservedFiles + dwBlockTableSize; + + // Free the defragment table + STORM_FREE(DefragmentTable); + } + + return ERROR_SUCCESS; +} + +// Rebuilds the HET table from scratch based on the file table +// Used after a modifying operation (add, rename, delete) +int RebuildHetTable(TMPQArchive * ha) +{ + TMPQHetTable * pOldHetTable = ha->pHetTable; + TFileEntry * pFileTableEnd; + TFileEntry * pFileEntry; + DWORD dwBlockTableSize = ha->dwFileTableSize; + int nError = ERROR_SUCCESS; + + // If we are in the state of saving MPQ tables, the real size of block table + // must already have been calculated. Use that value instead + if(ha->dwFlags & MPQ_FLAG_SAVING_TABLES) + { + assert(ha->pHeader->dwBlockTableSize != 0); + dwBlockTableSize = ha->pHeader->dwBlockTableSize; + } + + // Create new HET table based on the total number of entries in the file table + // Note that if we fail to create it, we just stop using HET table + ha->pHetTable = CreateHetTable(dwBlockTableSize, 0, 0x40, NULL); + if(ha->pHetTable != NULL) + { + // Go through the file table again and insert all existing files + pFileTableEnd = ha->pFileTable + dwBlockTableSize; + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + if(pFileEntry->dwFlags & MPQ_FILE_EXISTS) + { + // Get the high + nError = InsertHetEntry(ha->pHetTable, pFileEntry->FileNameHash, (DWORD)(pFileEntry - ha->pFileTable)); + if(nError != ERROR_SUCCESS) + break; + } + } + } + + // Free the old HET table + FreeHetTable(pOldHetTable); + return nError; +} + +// Rebuilds the file table, removing all deleted file entries. +// Used when compacting the archive +int RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize) +{ + TFileEntry * pFileEntry; + TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; + TMPQHash * pOldHashTable = ha->pHashTable; + TMPQHash * pHashTable = NULL; + TMPQHash * pHash; + int nError = ERROR_SUCCESS; + + // The new hash table size must be greater or equal to the current hash table size + assert(dwNewHashTableSize >= ha->pHeader->dwHashTableSize); + assert(dwNewHashTableSize >= ha->dwMaxFileCount); + assert((dwNewHashTableSize & (dwNewHashTableSize - 1)) == 0); + assert(ha->pHashTable != NULL); + + // Reallocate the new file table, if needed + if(dwNewHashTableSize > ha->dwFileTableSize) + { + ha->pFileTable = STORM_REALLOC(TFileEntry, ha->pFileTable, dwNewHashTableSize); + if(ha->pFileTable == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + memset(ha->pFileTable + ha->dwFileTableSize, 0, (dwNewHashTableSize - ha->dwFileTableSize) * sizeof(TFileEntry)); + } + + // Allocate new hash table + if(nError == ERROR_SUCCESS) + { + pHashTable = STORM_ALLOC(TMPQHash, dwNewHashTableSize); + if(pHashTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // If both succeeded, we need to rebuild the file table + if(nError == ERROR_SUCCESS) + { + // Make sure that the hash table is properly filled + memset(pHashTable, 0xFF, sizeof(TMPQHash) * dwNewHashTableSize); + ha->pHashTable = pHashTable; + + // Set the new limits to the MPQ archive + ha->pHeader->dwHashTableSize = dwNewHashTableSize; + + // Parse the old hash table and copy all entries to the new table + for(pHash = pOldHashTable; pHash < pHashTableEnd; pHash++) + { + if(IsValidHashEntry(ha, pHash)) + { + pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash); + AllocateHashEntry(ha, pFileEntry, pHash->lcLocale); + } + } + + // Increment the max file count for the file + ha->dwFileTableSize = dwNewHashTableSize; + ha->dwMaxFileCount = dwNewHashTableSize; + ha->dwFlags |= MPQ_FLAG_CHANGED; + } + + // Now free the remaining entries + if(pOldHashTable != NULL) + STORM_FREE(pOldHashTable); + return nError; +} + +// Saves MPQ header, hash table, block table and hi-block table. +int SaveMPQTables(TMPQArchive * ha) +{ + TMPQExtHeader * pHetTable = NULL; + TMPQExtHeader * pBetTable = NULL; + TMPQHeader * pHeader = ha->pHeader; + TMPQBlock * pBlockTable = NULL; + TMPQHash * pHashTable = NULL; + ULONGLONG HetTableSize64 = 0; + ULONGLONG BetTableSize64 = 0; + ULONGLONG HashTableSize64 = 0; + ULONGLONG BlockTableSize64 = 0; + ULONGLONG HiBlockTableSize64 = 0; + ULONGLONG TablePos = 0; // A table position, relative to the begin of the MPQ + USHORT * pHiBlockTable = NULL; + DWORD cbTotalSize; + bool bNeedHiBlockTable = false; + int nError = ERROR_SUCCESS; + + // We expect this function to be called only when tables have been changed + assert(ha->dwFlags & MPQ_FLAG_CHANGED); + + // Find the space where the MPQ tables will be saved + TablePos = FindFreeMpqSpace(ha); + + // If the MPQ has HET table, we prepare a ready-to-save version + if(nError == ERROR_SUCCESS && ha->pHetTable != NULL) + { + pHetTable = TranslateHetTable(ha->pHetTable, &HetTableSize64); + if(pHetTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // If the MPQ has HET table, we also must create BET table to be saved + if(nError == ERROR_SUCCESS && ha->pHetTable != NULL) + { + pBetTable = TranslateBetTable(ha, &BetTableSize64); + if(pBetTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Now create hash table + if(nError == ERROR_SUCCESS && ha->pHashTable != NULL) + { + pHashTable = TranslateHashTable(ha, &HashTableSize64); + if(pHashTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Create block table + if(nError == ERROR_SUCCESS && ha->pFileTable != NULL) + { + pBlockTable = TranslateBlockTable(ha, &BlockTableSize64, &bNeedHiBlockTable); + if(pBlockTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Create hi-block table, if needed + if(nError == ERROR_SUCCESS && bNeedHiBlockTable) + { + pHiBlockTable = TranslateHiBlockTable(ha, &HiBlockTableSize64); + if(pHiBlockTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Write the HET table, if any + if(nError == ERROR_SUCCESS && pHetTable != NULL) + { + pHeader->HetTableSize64 = HetTableSize64; + pHeader->HetTablePos64 = TablePos; + nError = SaveExtTable(ha, pHetTable, TablePos, (DWORD)HetTableSize64, pHeader->MD5_HetTable, MPQ_KEY_HASH_TABLE, false, &cbTotalSize); + TablePos += cbTotalSize; + } + + // Write the BET table, if any + if(nError == ERROR_SUCCESS && pBetTable != NULL) + { + pHeader->BetTableSize64 = BetTableSize64; + pHeader->BetTablePos64 = TablePos; + nError = SaveExtTable(ha, pBetTable, TablePos, (DWORD)BetTableSize64, pHeader->MD5_BetTable, MPQ_KEY_BLOCK_TABLE, false, &cbTotalSize); + TablePos += cbTotalSize; + } + + // Write the hash table, if we have any + if(nError == ERROR_SUCCESS && pHashTable != NULL) + { + pHeader->HashTableSize64 = HashTableSize64; + pHeader->wHashTablePosHi = (USHORT)(TablePos >> 32); + pHeader->dwHashTableSize = (DWORD)(HashTableSize64 / sizeof(TMPQHash)); + pHeader->dwHashTablePos = (DWORD)TablePos; + nError = SaveMpqTable(ha, pHashTable, TablePos, (size_t)HashTableSize64, pHeader->MD5_HashTable, MPQ_KEY_HASH_TABLE, false); + TablePos += HashTableSize64; + } + + // Write the block table, if we have any + if(nError == ERROR_SUCCESS && pBlockTable != NULL) + { + pHeader->BlockTableSize64 = BlockTableSize64; + pHeader->wBlockTablePosHi = (USHORT)(TablePos >> 32); + pHeader->dwBlockTableSize = (DWORD)(BlockTableSize64 / sizeof(TMPQBlock)); + pHeader->dwBlockTablePos = (DWORD)TablePos; + nError = SaveMpqTable(ha, pBlockTable, TablePos, (size_t)BlockTableSize64, pHeader->MD5_BlockTable, MPQ_KEY_BLOCK_TABLE, false); + TablePos += BlockTableSize64; + } + + // Write the hi-block table, if we have any + if(nError == ERROR_SUCCESS && pHiBlockTable != NULL) + { + ULONGLONG ByteOffset = ha->MpqPos + TablePos; + + pHeader->HiBlockTableSize64 = HiBlockTableSize64; + pHeader->HiBlockTablePos64 = TablePos; + BSWAP_ARRAY16_UNSIGNED(pHiBlockTable, HiBlockTableSize64); + + if(!FileStream_Write(ha->pStream, &ByteOffset, pHiBlockTable, (DWORD)HiBlockTableSize64)) + nError = GetLastError(); + TablePos += HiBlockTableSize64; + } + + // Cut the MPQ + if(nError == ERROR_SUCCESS) + { + ULONGLONG FileSize = ha->MpqPos + TablePos; + + if(!FileStream_SetSize(ha->pStream, FileSize)) + nError = GetLastError(); + } + + // Write the MPQ header + if(nError == ERROR_SUCCESS) + { + TMPQHeader SaveMpqHeader; + + // Update the size of the archive + pHeader->ArchiveSize64 = TablePos; + pHeader->dwArchiveSize = (DWORD)TablePos; + + // Update the MD5 of the archive header + CalculateDataBlockHash(pHeader, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE, pHeader->MD5_MpqHeader); + + // Write the MPQ header to the file + memcpy(&SaveMpqHeader, pHeader, pHeader->dwHeaderSize); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_1); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_2); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_3); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_4); + if(!FileStream_Write(ha->pStream, &ha->MpqPos, &SaveMpqHeader, pHeader->dwHeaderSize)) + nError = GetLastError(); + } + + // Clear the changed flag + if(nError == ERROR_SUCCESS) + ha->dwFlags &= ~MPQ_FLAG_CHANGED; + + // Cleanup and exit + if(pHetTable != NULL) + STORM_FREE(pHetTable); + if(pBetTable != NULL) + STORM_FREE(pBetTable); + if(pHashTable != NULL) + STORM_FREE(pHashTable); + if(pBlockTable != NULL) + STORM_FREE(pBlockTable); + if(pHiBlockTable != NULL) + STORM_FREE(pHiBlockTable); + return nError; +} +#endif diff --git a/3rdParty/StormLib/src/SBaseSubTypes.cpp b/3rdParty/StormLib/src/SBaseSubTypes.cpp new file mode 100644 index 000000000..47c205e47 --- /dev/null +++ b/3rdParty/StormLib/src/SBaseSubTypes.cpp @@ -0,0 +1,618 @@ +/*****************************************************************************/ +/* SBaseSubTypes.cpp Copyright (c) Ladislav Zezula 2013 */ +/*---------------------------------------------------------------------------*/ +/* Conversion routines for archive formats that are similar to MPQ format */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 02.11.11 1.00 Lad The first version of SBaseSubTypes.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +/*****************************************************************************/ +/* */ +/* Support for SQP file format (War of the Immortals) */ +/* */ +/*****************************************************************************/ + +typedef struct _TSQPHeader +{ + // The ID_MPQ ('MPQ\x1A') signature + DWORD dwID; + + // Size of the archive header + DWORD dwHeaderSize; + + // 32-bit size of MPQ archive + DWORD dwArchiveSize; + + // Offset to the beginning of the hash table, relative to the beginning of the archive. + DWORD dwHashTablePos; + + // Offset to the beginning of the block table, relative to the beginning of the archive. + DWORD dwBlockTablePos; + + // Number of entries in the hash table. Must be a power of two, and must be less than 2^16 for + // the original MoPaQ format, or less than 2^20 for the Burning Crusade format. + DWORD dwHashTableSize; + + // Number of entries in the block table + DWORD dwBlockTableSize; + + // Must be zero for SQP files + USHORT wFormatVersion; + + // Power of two exponent specifying the number of 512-byte disk sectors in each file sector + // in the archive. The size of each file sector in the archive is 512 * 2 ^ wSectorSize. + USHORT wSectorSize; + +} TSQPHeader; + +typedef struct _TSQPHash +{ + // Most likely the lcLocale+wPlatform. + DWORD dwAlwaysZero; + + // If the hash table entry is valid, this is the index into the block table of the file. + // Otherwise, one of the following two values: + // - FFFFFFFFh: Hash table entry is empty, and has always been empty. + // Terminates searches for a given file. + // - FFFFFFFEh: Hash table entry is empty, but was valid at some point (a deleted file). + // Does not terminate searches for a given file. + DWORD dwBlockIndex; + + // The hash of the file path, using method A. + DWORD dwName1; + + // The hash of the file path, using method B. + DWORD dwName2; + +} TSQPHash; + +typedef struct _TSQPBlock +{ + // Offset of the beginning of the file, relative to the beginning of the archive. + DWORD dwFilePos; + + // Flags for the file. See MPQ_FILE_XXXX constants + DWORD dwFlags; + + // Compressed file size + DWORD dwCSize; + + // Uncompressed file size + DWORD dwFSize; + +} TSQPBlock; + +//----------------------------------------------------------------------------- +// Functions - SQP file format + +// This function converts SQP file header into MPQ file header +int ConvertSqpHeaderToFormat4( + TMPQArchive * ha, + ULONGLONG FileSize, + DWORD dwFlags) +{ + TSQPHeader * pSqpHeader = (TSQPHeader *)ha->HeaderData; + TMPQHeader Header; + + // SQP files from War of the Immortal use MPQ file format with slightly + // modified structure. These fields have different position: + // + // Offset TMPQHeader TSQPHeader + // ------ ---------- ----------- + // 000C wFormatVersion dwHashTablePos (lo) + // 000E wSectorSize dwHashTablePos (hi) + // 001C dwBlockTableSize (lo) wBlockSize + // 001E dwHashTableSize (hi) wFormatVersion + + // Can't open the archive with certain flags + if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1) + return ERROR_FILE_CORRUPT; + + // The file must not be greater than 4 GB + if((FileSize >> 0x20) != 0) + return ERROR_FILE_CORRUPT; + + // Translate the SQP header into a MPQ header + memset(&Header, 0, sizeof(TMPQHeader)); + Header.dwID = BSWAP_INT32_UNSIGNED(pSqpHeader->dwID); + Header.dwHeaderSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwHeaderSize); + Header.dwArchiveSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwArchiveSize); + Header.dwHashTablePos = BSWAP_INT32_UNSIGNED(pSqpHeader->dwHashTablePos); + Header.dwBlockTablePos = BSWAP_INT32_UNSIGNED(pSqpHeader->dwBlockTablePos); + Header.dwHashTableSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwHashTableSize); + Header.dwBlockTableSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwBlockTableSize); + Header.wFormatVersion = BSWAP_INT16_UNSIGNED(pSqpHeader->wFormatVersion); + Header.wSectorSize = BSWAP_INT16_UNSIGNED(pSqpHeader->wSectorSize); + + // Verify the SQP header + if(Header.dwID == ID_MPQ && Header.dwHeaderSize == sizeof(TSQPHeader) && Header.dwArchiveSize == FileSize) + { + // Check for fixed values of version and sector size + if(Header.wFormatVersion == MPQ_FORMAT_VERSION_1 && Header.wSectorSize == 3) + { + // Initialize the fields of 3.0 header + Header.ArchiveSize64 = Header.dwArchiveSize; + Header.HashTableSize64 = Header.dwHashTableSize * sizeof(TMPQHash); + Header.BlockTableSize64 = Header.dwBlockTableSize * sizeof(TMPQBlock); + + // Copy the converted MPQ header back + memcpy(ha->HeaderData, &Header, sizeof(TMPQHeader)); + + // Mark this file as SQP file + ha->pfnHashString = HashStringSlash; + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + ha->dwSubType = MPQ_SUBTYPE_SQP; + return ERROR_SUCCESS; + } + } + + return ERROR_FILE_CORRUPT; +} + +void * LoadSqpTable(TMPQArchive * ha, DWORD dwByteOffset, DWORD cbTableSize, DWORD dwKey) +{ + ULONGLONG ByteOffset; + LPBYTE pbSqpTable; + + // Allocate buffer for the table + pbSqpTable = STORM_ALLOC(BYTE, cbTableSize); + if(pbSqpTable != NULL) + { + // Load the table + ByteOffset = ha->MpqPos + dwByteOffset; + if(FileStream_Read(ha->pStream, &ByteOffset, pbSqpTable, cbTableSize)) + { + // Decrypt the SQP table + DecryptMpqBlock(pbSqpTable, cbTableSize, dwKey); + return pbSqpTable; + } + + // Free the table + STORM_FREE(pbSqpTable); + } + + return NULL; +} + +TMPQHash * LoadSqpHashTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TSQPHash * pSqpHashTable; + TSQPHash * pSqpHashEnd; + TSQPHash * pSqpHash; + TMPQHash * pMpqHash; + int nError = ERROR_SUCCESS; + + // Load the hash table + pSqpHashTable = (TSQPHash *)LoadSqpTable(ha, pHeader->dwHashTablePos, pHeader->dwHashTableSize * sizeof(TSQPHash), MPQ_KEY_HASH_TABLE); + if(pSqpHashTable != NULL) + { + // Parse the entire hash table and convert it to MPQ hash table + pSqpHashEnd = pSqpHashTable + pHeader->dwHashTableSize; + pMpqHash = (TMPQHash *)pSqpHashTable; + for(pSqpHash = pSqpHashTable; pSqpHash < pSqpHashEnd; pSqpHash++, pMpqHash++) + { + // Ignore free entries + if(pSqpHash->dwBlockIndex != HASH_ENTRY_FREE) + { + // Check block index against the size of the block table + if(pHeader->dwBlockTableSize <= MPQ_BLOCK_INDEX(pSqpHash) && pSqpHash->dwBlockIndex < HASH_ENTRY_DELETED) + nError = ERROR_FILE_CORRUPT; + + // We do not support nonzero locale and platform ID + if(pSqpHash->dwAlwaysZero != 0 && pSqpHash->dwAlwaysZero != HASH_ENTRY_FREE) + nError = ERROR_FILE_CORRUPT; + + // Store the file name hash + pMpqHash->dwName1 = pSqpHash->dwName1; + pMpqHash->dwName2 = pSqpHash->dwName2; + + // Store the rest. Note that this must be done last, + // because block index corresponds to pMpqHash->dwName2 + pMpqHash->dwBlockIndex = MPQ_BLOCK_INDEX(pSqpHash); + pMpqHash->Platform = 0; + pMpqHash->lcLocale = 0; + } + } + + // If an error occured, we need to free the hash table + if(nError != ERROR_SUCCESS) + { + STORM_FREE(pSqpHashTable); + pSqpHashTable = NULL; + } + } + + // Return the converted hash table (or NULL on failure) + return (TMPQHash *)pSqpHashTable; +} + +// Loads the SQP Block table and converts it to a MPQ block table +TMPQBlock * LoadSqpBlockTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TSQPBlock * pSqpBlockTable; + TSQPBlock * pSqpBlockEnd; + TSQPBlock * pSqpBlock; + TMPQBlock * pMpqBlock; + DWORD dwFlags; + int nError = ERROR_SUCCESS; + + // Load the hash table + pSqpBlockTable = (TSQPBlock *)LoadSqpTable(ha, pHeader->dwBlockTablePos, pHeader->dwBlockTableSize * sizeof(TSQPBlock), MPQ_KEY_BLOCK_TABLE); + if(pSqpBlockTable != NULL) + { + // Parse the entire hash table and convert it to MPQ hash table + pSqpBlockEnd = pSqpBlockTable + pHeader->dwBlockTableSize; + pMpqBlock = (TMPQBlock *)pSqpBlockTable; + for(pSqpBlock = pSqpBlockTable; pSqpBlock < pSqpBlockEnd; pSqpBlock++, pMpqBlock++) + { + // Check for valid flags + if(pSqpBlock->dwFlags & ~MPQ_FILE_VALID_FLAGS) + nError = ERROR_FILE_CORRUPT; + + // Convert SQP block table entry to MPQ block table entry + dwFlags = pSqpBlock->dwFlags; + pMpqBlock->dwCSize = pSqpBlock->dwCSize; + pMpqBlock->dwFSize = pSqpBlock->dwFSize; + pMpqBlock->dwFlags = dwFlags; + } + + // If an error occured, we need to free the hash table + if(nError != ERROR_SUCCESS) + { + STORM_FREE(pSqpBlockTable); + pSqpBlockTable = NULL; + } + } + + // Return the converted hash table (or NULL on failure) + return (TMPQBlock *)pSqpBlockTable; +} + +/*****************************************************************************/ +/* */ +/* Support for MPK file format (Longwu Online) */ +/* */ +/*****************************************************************************/ + +#define MPK_FILE_UNKNOWN_0001 0x00000001 // Seems to be always present +#define MPK_FILE_UNKNOWN_0010 0x00000010 // Seems to be always present +#define MPK_FILE_COMPRESSED 0x00000100 // Indicates a compressed file +#define MPK_FILE_UNKNOWN_2000 0x00002000 // Seems to be always present +#define MPK_FILE_EXISTS 0x01000000 // Seems to be always present + +typedef struct _TMPKHeader +{ + // The ID_MPK ('MPK\x1A') signature + DWORD dwID; + + // Contains '2000' + DWORD dwVersion; + + // 32-bit size of the archive + DWORD dwArchiveSize; + + // Size of the archive header + DWORD dwHeaderSize; + + DWORD dwHashTablePos; + DWORD dwHashTableSize; + DWORD dwBlockTablePos; + DWORD dwBlockTableSize; + DWORD dwUnknownPos; + DWORD dwUnknownSize; +} TMPKHeader; + + +typedef struct _TMPKHash +{ + // The hash of the file path, using method A. + DWORD dwName1; + + // The hash of the file path, using method B. + DWORD dwName2; + + // The hash of the file path, using method C. + DWORD dwName3; + + // If the hash table entry is valid, this is the index into the block table of the file. + // Otherwise, one of the following two values: + // - FFFFFFFFh: Hash table entry is empty, and has always been empty. + // Terminates searches for a given file. + // - FFFFFFFEh: Hash table entry is empty, but was valid at some point (a deleted file). + // Does not terminate searches for a given file. + DWORD dwBlockIndex; + +} TMPKHash; + +typedef struct _TMPKBlock +{ + DWORD dwFlags; // 0x1121 - Compressed , 0x1120 - Not compressed + DWORD dwFilePos; // Offset of the beginning of the file, relative to the beginning of the archive. + DWORD dwFSize; // Uncompressed file size + DWORD dwCSize; // Compressed file size + DWORD dwUnknown; // 0x86364E6D +} TMPKBlock; + +//----------------------------------------------------------------------------- +// Local variables - MPK file format + +static const unsigned char MpkDecryptionKey[512] = +{ + 0x60, 0x20, 0x29, 0xE1, 0x01, 0xCE, 0xAA, 0xFE, 0xA3, 0xAB, 0x8E, 0x30, 0xAF, 0x02, 0xD1, 0x7D, + 0x41, 0x24, 0x06, 0xBD, 0xAE, 0xBE, 0x43, 0xC3, 0xBA, 0xB7, 0x08, 0x13, 0x51, 0xCF, 0xF8, 0xF7, + 0x25, 0x42, 0xA5, 0x4A, 0xDA, 0x0F, 0x52, 0x1C, 0x90, 0x3B, 0x63, 0x49, 0x36, 0xF6, 0xDD, 0x1B, + 0xEA, 0x58, 0xD4, 0x40, 0x70, 0x61, 0x55, 0x09, 0xCD, 0x0B, 0xA2, 0x4B, 0x68, 0x2C, 0x8A, 0xF1, + 0x3C, 0x3A, 0x65, 0xBB, 0xA1, 0xA8, 0x23, 0x97, 0xFD, 0x15, 0x00, 0x94, 0x88, 0x33, 0x59, 0xE9, + 0xFB, 0x69, 0x21, 0xEF, 0x85, 0x5B, 0x57, 0x6C, 0xFA, 0xB5, 0xEE, 0xB8, 0x71, 0xDC, 0xB1, 0x38, + 0x0C, 0x0A, 0x5C, 0x56, 0xC9, 0xB4, 0x84, 0x17, 0x1E, 0xE5, 0xD3, 0x5A, 0xCC, 0xFC, 0x11, 0x86, + 0x7F, 0x45, 0x4F, 0x54, 0xC8, 0x8D, 0x73, 0x89, 0x79, 0x5D, 0xB3, 0xBF, 0xB9, 0xE3, 0x93, 0xE4, + 0x6F, 0x35, 0x2D, 0x46, 0xF2, 0x76, 0xC5, 0x7E, 0xE2, 0xA4, 0xE6, 0xD9, 0x6E, 0x48, 0x34, 0x2B, + 0xC6, 0x5F, 0xBC, 0xA0, 0x6D, 0x0D, 0x47, 0x6B, 0x95, 0x96, 0x92, 0x91, 0xB2, 0x27, 0xEB, 0x9E, + 0xEC, 0x8F, 0xDF, 0x9C, 0x74, 0x99, 0x64, 0xF5, 0xFF, 0x28, 0xB6, 0x37, 0xF3, 0x7C, 0x81, 0x03, + 0x44, 0x62, 0x1F, 0xDB, 0x04, 0x7B, 0xB0, 0x9B, 0x31, 0xA7, 0xDE, 0x78, 0x9F, 0xAD, 0x0E, 0x3F, + 0x3E, 0x4D, 0xC7, 0xD7, 0x39, 0x19, 0x5E, 0xC2, 0xD0, 0xAC, 0xE8, 0x1A, 0x87, 0x8B, 0x07, 0x05, + 0x22, 0xED, 0x72, 0x2E, 0x1D, 0xC1, 0xA9, 0xD6, 0xE0, 0x83, 0xD5, 0xD8, 0xCB, 0x80, 0xF0, 0x66, + 0x7A, 0x9D, 0x50, 0xF9, 0x10, 0x4E, 0x16, 0x14, 0x77, 0x75, 0x6A, 0x67, 0xD2, 0xC0, 0xA6, 0xC4, + 0x53, 0x8C, 0x32, 0xCA, 0x82, 0x2A, 0x18, 0x9A, 0xF4, 0x4C, 0x3D, 0x26, 0x12, 0xE7, 0x98, 0x2F, + 0x4A, 0x04, 0x0D, 0xAF, 0xB4, 0xCF, 0x12, 0xCE, 0x1A, 0x37, 0x61, 0x39, 0x60, 0x95, 0xBE, 0x25, + 0xE4, 0x6E, 0xFC, 0x1B, 0xE7, 0x49, 0xE6, 0x67, 0xF6, 0xC5, 0xCB, 0x2F, 0x27, 0xD4, 0x68, 0xB2, + 0x01, 0x52, 0xD0, 0x46, 0x11, 0x20, 0xFB, 0x9D, 0xA9, 0x02, 0xF5, 0x8F, 0x3D, 0x82, 0xD3, 0xFF, + 0x0B, 0xB8, 0xF2, 0x4D, 0x8E, 0x81, 0x2C, 0xAB, 0x5F, 0xC4, 0x41, 0x29, 0x40, 0xFA, 0xC0, 0xBF, + 0x33, 0x10, 0x21, 0x16, 0xB0, 0x71, 0x83, 0x96, 0x8D, 0x2B, 0x23, 0x3B, 0xF9, 0xC1, 0xE5, 0x72, + 0xE2, 0x1C, 0x26, 0xF0, 0x73, 0x36, 0x63, 0x56, 0x31, 0x4E, 0x6B, 0x55, 0x62, 0x79, 0xC6, 0x91, + 0x00, 0x35, 0xB1, 0x2A, 0xA6, 0x42, 0xDF, 0xEB, 0x3C, 0x51, 0xEA, 0x97, 0x57, 0x94, 0x8C, 0x80, + 0x34, 0x5C, 0xD2, 0x76, 0xA4, 0xE9, 0x85, 0xE8, 0xBB, 0x78, 0xE0, 0xB5, 0xAD, 0x0F, 0x87, 0x70, + 0xDD, 0xAE, 0xF4, 0xD9, 0x66, 0x54, 0x6F, 0xCC, 0x4C, 0x77, 0x3E, 0xCD, 0xF1, 0x75, 0x0A, 0xA1, + 0x28, 0x9B, 0x9A, 0x7E, 0x4B, 0x98, 0x99, 0x47, 0xFE, 0xA5, 0xF7, 0xB7, 0xA3, 0xE1, 0x9F, 0xBC, + 0x93, 0x44, 0x3A, 0x08, 0x89, 0x22, 0xEE, 0xB9, 0x45, 0xD6, 0x06, 0x09, 0xC9, 0xBD, 0x14, 0x0C, + 0xB6, 0x5E, 0x9C, 0x7A, 0x65, 0x59, 0xAA, 0x19, 0x5B, 0x7C, 0x18, 0x43, 0x92, 0x13, 0x15, 0x7B, + 0xED, 0xD5, 0xC7, 0x17, 0xEF, 0x86, 0x90, 0xC2, 0x74, 0x64, 0xF3, 0xDC, 0x6C, 0x38, 0x05, 0x1D, + 0xC8, 0x0E, 0xEC, 0x6A, 0x32, 0xDA, 0xD7, 0xC3, 0xDB, 0x8B, 0x24, 0xB3, 0x5D, 0x2E, 0xBA, 0xA2, + 0xD8, 0x03, 0x88, 0x7D, 0x7F, 0x69, 0x8A, 0xFD, 0xCA, 0x4F, 0x30, 0x9E, 0xA0, 0xD1, 0x5A, 0x53, + 0xDE, 0x3F, 0x84, 0xAC, 0xF8, 0xA7, 0x2D, 0x1F, 0x1E, 0xE3, 0x58, 0x50, 0x6D, 0x48, 0x07, 0xA8 +}; + +//----------------------------------------------------------------------------- +// Functions - MPK file format + +// This function converts MPK file header into MPQ file header +int ConvertMpkHeaderToFormat4( + TMPQArchive * ha, + ULONGLONG FileSize, + DWORD dwFlags) +{ + TMPKHeader * pMpkHeader = (TMPKHeader *)ha->HeaderData; + TMPQHeader Header; + + // Can't open the archive with certain flags + if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1) + return ERROR_FILE_CORRUPT; + + // Translate the MPK header into a MPQ header + // Note: Hash table size and block table size are in bytes, not in entries + memset(&Header, 0, sizeof(TMPQHeader)); + Header.dwID = BSWAP_INT32_UNSIGNED(pMpkHeader->dwID); + Header.dwArchiveSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwArchiveSize); + Header.dwHeaderSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHeaderSize); + Header.dwHashTablePos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHashTablePos); + Header.dwHashTableSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHashTableSize) / sizeof(TMPKHash); + Header.dwBlockTablePos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwBlockTablePos); + Header.dwBlockTableSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwBlockTableSize) / sizeof(TMPKBlock); +// Header.dwUnknownPos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwUnknownPos); +// Header.dwUnknownSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwUnknownSize); + assert(Header.dwHeaderSize == sizeof(TMPKHeader)); + + // Verify the MPK header + if(Header.dwID == ID_MPK && Header.dwHeaderSize == sizeof(TMPKHeader) && Header.dwArchiveSize == (DWORD)FileSize) + { + // The header ID must be ID_MPQ + Header.dwID = ID_MPQ; + Header.wFormatVersion = MPQ_FORMAT_VERSION_1; + Header.wSectorSize = 3; + + // Initialize the fields of 3.0 header + Header.ArchiveSize64 = Header.dwArchiveSize; + Header.HashTableSize64 = Header.dwHashTableSize * sizeof(TMPQHash); + Header.BlockTableSize64 = Header.dwBlockTableSize * sizeof(TMPQBlock); + + // Copy the converted MPQ header back + memcpy(ha->HeaderData, &Header, sizeof(TMPQHeader)); + + // Mark this file as MPK file + ha->pfnHashString = HashStringLower; + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + ha->dwSubType = MPQ_SUBTYPE_MPK; + return ERROR_SUCCESS; + } + return ERROR_FILE_CORRUPT; +} + +// Attempts to search a free hash entry in the hash table being converted. +// The created hash table must always be of nonzero size, +// should have no duplicated items and no deleted entries +TMPQHash * FindFreeHashEntry(TMPQHash * pHashTable, DWORD dwHashTableSize, DWORD dwStartIndex) +{ + TMPQHash * pHash; + DWORD dwIndex; + + // Set the initial index + dwStartIndex = dwIndex = (dwStartIndex & (dwHashTableSize - 1)); + assert(dwHashTableSize != 0); + + // Search the hash table and return the found entries in the following priority: + for(;;) + { + // We are not expecting to find matching entry in the hash table being built + // We are not expecting to find deleted entry either + pHash = pHashTable + dwIndex; + + // If we found a free entry, we need to stop searching + if(pHash->dwBlockIndex == HASH_ENTRY_FREE) + return pHash; + + // Move to the next hash entry. + // If we reached the starting entry, it's failure. + dwIndex = (dwIndex + 1) & (dwHashTableSize - 1); + if(dwIndex == dwStartIndex) + break; + } + + // We haven't found anything + assert(false); + return NULL; +} + +void DecryptMpkTable(void * pvMpkTable, size_t cbSize) +{ + LPBYTE pbMpkTable = (LPBYTE)pvMpkTable; + + for(size_t i = 0; i < cbSize; i++) + pbMpkTable[i] = MpkDecryptionKey[pbMpkTable[i]]; +} + +void * LoadMpkTable(TMPQArchive * ha, DWORD dwByteOffset, DWORD cbTableSize) +{ + ULONGLONG ByteOffset; + LPBYTE pbMpkTable = NULL; + + // Allocate space for the table + pbMpkTable = STORM_ALLOC(BYTE, cbTableSize); + if(pbMpkTable != NULL) + { + // Load and the MPK hash table + ByteOffset = ha->MpqPos + dwByteOffset; + if(FileStream_Read(ha->pStream, &ByteOffset, pbMpkTable, cbTableSize)) + { + // Decrypt the table + DecryptMpkTable(pbMpkTable, cbTableSize); + return pbMpkTable; + } + + // Free the MPK table + STORM_FREE(pbMpkTable); + pbMpkTable = NULL; + } + + // Return the table + return pbMpkTable; +} + +TMPQHash * LoadMpkHashTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPQHash * pHashTable = NULL; + TMPKHash * pMpkHash; + TMPQHash * pHash = NULL; + DWORD dwHashTableSize = pHeader->dwHashTableSize; + + // MPKs use different hash table searching. + // Instead of using MPQ_HASH_TABLE_INDEX hash as index, + // they store the value directly in the hash table. + // Also for faster searching, the hash table is sorted ascending by the value + + // Load and decrypt the MPK hash table. + pMpkHash = (TMPKHash *)LoadMpkTable(ha, pHeader->dwHashTablePos, pHeader->dwHashTableSize * sizeof(TMPKHash)); + if(pMpkHash != NULL) + { + // Calculate the hash table size as if it was real MPQ hash table + pHeader->dwHashTableSize = GetNearestPowerOfTwo(pHeader->dwHashTableSize); + pHeader->HashTableSize64 = pHeader->dwHashTableSize * sizeof(TMPQHash); + + // Now allocate table that will serve like a true MPQ hash table, + // so we translate the MPK hash table to MPQ hash table + pHashTable = STORM_ALLOC(TMPQHash, pHeader->dwHashTableSize); + if(pHashTable != NULL) + { + // Set the entire hash table to free + memset(pHashTable, 0xFF, (size_t)pHeader->HashTableSize64); + + // Copy the MPK hash table into MPQ hash table + for(DWORD i = 0; i < dwHashTableSize; i++) + { + // Finds the free hash entry in the hash table + // We don't expect any errors here, because we are putting files to empty hash table + pHash = FindFreeHashEntry(pHashTable, pHeader->dwHashTableSize, pMpkHash[i].dwName1); + assert(pHash->dwBlockIndex == HASH_ENTRY_FREE); + + // Copy the MPK hash entry to the hash table + pHash->dwBlockIndex = pMpkHash[i].dwBlockIndex; + pHash->Platform = 0; + pHash->lcLocale = 0; + pHash->dwName1 = pMpkHash[i].dwName2; + pHash->dwName2 = pMpkHash[i].dwName3; + } + } + + // Free the temporary hash table + STORM_FREE(pMpkHash); + } + + return pHashTable; +} + +static DWORD ConvertMpkFlagsToMpqFlags(DWORD dwMpkFlags) +{ + DWORD dwMpqFlags = MPQ_FILE_EXISTS; + + // Check for flags that are always present + assert((dwMpkFlags & MPK_FILE_UNKNOWN_0001) != 0); + assert((dwMpkFlags & MPK_FILE_UNKNOWN_0010) != 0); + assert((dwMpkFlags & MPK_FILE_UNKNOWN_2000) != 0); + assert((dwMpkFlags & MPK_FILE_EXISTS) != 0); + + // Append the compressed flag + dwMpqFlags |= (dwMpkFlags & MPK_FILE_COMPRESSED) ? MPQ_FILE_COMPRESS : 0; + + // All files in the MPQ seem to be single unit files + dwMpqFlags |= MPQ_FILE_ENCRYPTED | MPQ_FILE_SINGLE_UNIT; + + return dwMpqFlags; +} + +TMPQBlock * LoadMpkBlockTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPKBlock * pMpkBlockTable; + TMPKBlock * pMpkBlockEnd; + TMPQBlock * pBlockTable = NULL; + TMPKBlock * pMpkBlock; + TMPQBlock * pMpqBlock; + + // Load and decrypt the MPK block table + pMpkBlockTable = pMpkBlock = (TMPKBlock *)LoadMpkTable(ha, pHeader->dwBlockTablePos, pHeader->dwBlockTableSize * sizeof(TMPKBlock)); + if(pMpkBlockTable != NULL) + { + // Allocate buffer for MPQ-like block table + pBlockTable = pMpqBlock = STORM_ALLOC(TMPQBlock, pHeader->dwBlockTableSize); + if(pBlockTable != NULL) + { + // Convert the MPK block table to MPQ block table + pMpkBlockEnd = pMpkBlockTable + pHeader->dwBlockTableSize; + while(pMpkBlock < pMpkBlockEnd) + { + // Translate the MPK block table entry to MPQ block table entry + pMpqBlock->dwFilePos = pMpkBlock->dwFilePos; + pMpqBlock->dwCSize = pMpkBlock->dwCSize; + pMpqBlock->dwFSize = pMpkBlock->dwFSize; + pMpqBlock->dwFlags = ConvertMpkFlagsToMpqFlags(pMpkBlock->dwFlags); + + // Move both + pMpkBlock++; + pMpqBlock++; + } + } + + // Free the MPK block table + STORM_FREE(pMpkBlockTable); + } + + return pBlockTable; +} diff --git a/3rdParty/StormLib/src/SCompression.cpp b/3rdParty/StormLib/src/SCompression.cpp new file mode 100644 index 000000000..f488b4d59 --- /dev/null +++ b/3rdParty/StormLib/src/SCompression.cpp @@ -0,0 +1,1166 @@ +/*****************************************************************************/ +/* SCompression.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* This module serves as a bridge between StormLib code and (de)compression */ +/* functions. All (de)compression calls go (and should only go) through this */ +/* module. No system headers should be included in this module to prevent */ +/* compile-time problems. */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 01.04.03 1.00 Lad The first version of SCompression.cpp */ +/* 19.11.03 1.01 Dan Big endian handling */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local structures + +// Information about the input and output buffers for pklib +typedef struct +{ + unsigned char * pbInBuff; // Pointer to input data buffer + unsigned char * pbInBuffEnd; // End of the input buffer + unsigned char * pbOutBuff; // Pointer to output data buffer + unsigned char * pbOutBuffEnd; // Pointer to output data buffer +} TDataInfo; + +// Prototype of the compression function +// Function doesn't return an error. A success means that the size of compressed buffer +// is lower than size of uncompressed buffer. +typedef void (*COMPRESS)( + void * pvOutBuffer, // [out] Pointer to the buffer where the compressed data will be stored + int * pcbOutBuffer, // [in] Pointer to length of the buffer pointed by pvOutBuffer + void * pvInBuffer, // [in] Pointer to the buffer with data to compress + int cbInBuffer, // [in] Length of the buffer pointer by pvInBuffer + int * pCmpType, // [in] Compression-method specific value. ADPCM Setups this for the following Huffman compression + int nCmpLevel); // [in] Compression specific value. ADPCM uses this. Should be set to zero. + +// Prototype of the decompression function +// Returns 1 if success, 0 if failure +typedef int (*DECOMPRESS)( + void * pvOutBuffer, // [out] Pointer to the buffer where to store decompressed data + int * pcbOutBuffer, // [in] Pointer to total size of the buffer pointed by pvOutBuffer + // [out] Contains length of the decompressed data + void * pvInBuffer, // [in] Pointer to data to be decompressed + int cbInBuffer); // [in] Length of the data to be decompressed + +// Table of compression functions +typedef struct +{ + unsigned long uMask; // Compression mask + COMPRESS Compress; // Compression function +} TCompressTable; + +// Table of decompression functions +typedef struct +{ + unsigned long uMask; // Decompression bit + DECOMPRESS Decompress; // Decompression function +} TDecompressTable; + + +#ifdef FULL +/*****************************************************************************/ +/* */ +/* Support for Huffman compression (0x01) */ +/* */ +/*****************************************************************************/ + +void Compress_huff(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + THuffmannTree ht(true); + TOutputStream os(pvOutBuffer, *pcbOutBuffer); + + STORMLIB_UNUSED(nCmpLevel); + *pcbOutBuffer = ht.Compress(&os, pvInBuffer, cbInBuffer, *pCmpType); +} + +int Decompress_huff(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + THuffmannTree ht(false); + TInputStream is(pvInBuffer, cbInBuffer); + + *pcbOutBuffer = ht.Decompress(pvOutBuffer, *pcbOutBuffer, &is); + return (*pcbOutBuffer == 0) ? 0 : 1; +} + +/******************************************************************************/ +/* */ +/* Support for ZLIB compression (0x02) */ +/* */ +/******************************************************************************/ + +void Compress_ZLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + z_stream z; // Stream information for zlib + int windowBits; + int nResult; + + // Keep compilers happy + STORMLIB_UNUSED(pCmpType); + STORMLIB_UNUSED(nCmpLevel); + + // Fill the stream structure for zlib + z.next_in = (Bytef *)pvInBuffer; + z.avail_in = (uInt)cbInBuffer; + z.total_in = cbInBuffer; + z.next_out = (Bytef *)pvOutBuffer; + z.avail_out = *pcbOutBuffer; + z.total_out = 0; + z.zalloc = NULL; + z.zfree = NULL; + + // Determine the proper window bits (WoW.exe build 12694) + if(cbInBuffer <= 0x100) + windowBits = 8; + else if(cbInBuffer <= 0x200) + windowBits = 9; + else if(cbInBuffer <= 0x400) + windowBits = 10; + else if(cbInBuffer <= 0x800) + windowBits = 11; + else if(cbInBuffer <= 0x1000) + windowBits = 12; + else if(cbInBuffer <= 0x2000) + windowBits = 13; + else if(cbInBuffer <= 0x4000) + windowBits = 14; + else + windowBits = 15; + + // Initialize the compression. + // Storm.dll uses zlib version 1.1.3 + // Wow.exe uses zlib version 1.2.3 + nResult = deflateInit2(&z, + 6, // Compression level used by WoW MPQs + Z_DEFLATED, + windowBits, + 8, + Z_DEFAULT_STRATEGY); + if(nResult == Z_OK) + { + // Call zlib to compress the data + nResult = deflate(&z, Z_FINISH); + + if(nResult == Z_OK || nResult == Z_STREAM_END) + *pcbOutBuffer = z.total_out; + + deflateEnd(&z); + } +} + +int Decompress_ZLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + z_stream z; // Stream information for zlib + int nResult; + + // Fill the stream structure for zlib + z.next_in = (Bytef *)pvInBuffer; + z.avail_in = (uInt)cbInBuffer; + z.total_in = cbInBuffer; + z.next_out = (Bytef *)pvOutBuffer; + z.avail_out = *pcbOutBuffer; + z.total_out = 0; + z.zalloc = NULL; + z.zfree = NULL; + + // Initialize the decompression structure. Storm.dll uses zlib version 1.1.3 + if((nResult = inflateInit(&z)) == 0) + { + // Call zlib to decompress the data + nResult = inflate(&z, Z_FINISH); + *pcbOutBuffer = z.total_out; + inflateEnd(&z); + } + return nResult; +} +#endif + +/******************************************************************************/ +/* */ +/* Support functions for PKWARE Data Compression Library compression (0x08) */ +/* */ +/******************************************************************************/ + +// Function loads data from the input buffer. Used by Pklib's "implode" +// and "explode" function as user-defined callback +// Returns number of bytes loaded +// +// char * buf - Pointer to a buffer where to store loaded data +// unsigned int * size - Max. number of bytes to read +// void * param - Custom pointer, parameter of implode/explode + +static unsigned int ReadInputData(char * buf, unsigned int * size, void * param) +{ + TDataInfo * pInfo = (TDataInfo *)param; + unsigned int nMaxAvail = (unsigned int)(pInfo->pbInBuffEnd - pInfo->pbInBuff); + unsigned int nToRead = *size; + + // Check the case when not enough data available + if(nToRead > nMaxAvail) + nToRead = nMaxAvail; + + // Load data and increment offsets + memcpy(buf, pInfo->pbInBuff, nToRead); + pInfo->pbInBuff += nToRead; + assert(pInfo->pbInBuff <= pInfo->pbInBuffEnd); + return nToRead; +} + +// Function for store output data. Used by Pklib's "implode" and "explode" +// as user-defined callback +// +// char * buf - Pointer to data to be written +// unsigned int * size - Number of bytes to write +// void * param - Custom pointer, parameter of implode/explode + +static void WriteOutputData(char * buf, unsigned int * size, void * param) +{ + TDataInfo * pInfo = (TDataInfo *)param; + unsigned int nMaxWrite = (unsigned int)(pInfo->pbOutBuffEnd - pInfo->pbOutBuff); + unsigned int nToWrite = *size; + + // Check the case when not enough space in the output buffer + if(nToWrite > nMaxWrite) + nToWrite = nMaxWrite; + + // Write output data and increments offsets + memcpy(pInfo->pbOutBuff, buf, nToWrite); + pInfo->pbOutBuff += nToWrite; + assert(pInfo->pbOutBuff <= pInfo->pbOutBuffEnd); +} + +static void Compress_PKLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + TDataInfo Info; // Data information + char * work_buf = STORM_ALLOC(char, CMP_BUFFER_SIZE);// Pklib's work buffer + unsigned int dict_size; // Dictionary size + unsigned int ctype = CMP_BINARY; // Compression type + + // Keep compilers happy + STORMLIB_UNUSED(pCmpType); + STORMLIB_UNUSED(nCmpLevel); + + // Handle no-memory condition + if(work_buf != NULL) + { + // Fill data information structure + memset(work_buf, 0, CMP_BUFFER_SIZE); + Info.pbInBuff = (unsigned char *)pvInBuffer; + Info.pbInBuffEnd = (unsigned char *)pvInBuffer + cbInBuffer; + Info.pbOutBuff = (unsigned char *)pvOutBuffer; + Info.pbOutBuffEnd = (unsigned char *)pvOutBuffer + *pcbOutBuffer; + + // + // Set the dictionary size + // + // Diablo I uses fixed dictionary size of CMP_IMPLODE_DICT_SIZE3 + // Starcraft I uses the variable dictionary size based on algorithm below + // + + if (cbInBuffer < 0x600) + dict_size = CMP_IMPLODE_DICT_SIZE1; + else if(0x600 <= cbInBuffer && cbInBuffer < 0xC00) + dict_size = CMP_IMPLODE_DICT_SIZE2; + else + dict_size = CMP_IMPLODE_DICT_SIZE3; + + // Do the compression + if(implode(ReadInputData, WriteOutputData, work_buf, &Info, &ctype, &dict_size) == CMP_NO_ERROR) + *pcbOutBuffer = (int)(Info.pbOutBuff - (unsigned char *)pvOutBuffer); + + STORM_FREE(work_buf); + } +} + +static int Decompress_PKLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + TDataInfo Info; // Data information + char * work_buf = STORM_ALLOC(char, EXP_BUFFER_SIZE);// Pklib's work buffer + + // Handle no-memory condition + if(work_buf == NULL) + return 0; + + // Fill data information structure + memset(work_buf, 0, EXP_BUFFER_SIZE); + Info.pbInBuff = (unsigned char *)pvInBuffer; + Info.pbInBuffEnd = (unsigned char *)pvInBuffer + cbInBuffer; + Info.pbOutBuff = (unsigned char *)pvOutBuffer; + Info.pbOutBuffEnd = (unsigned char *)pvOutBuffer + *pcbOutBuffer; + + // Do the decompression + explode(ReadInputData, WriteOutputData, work_buf, &Info); + + // If PKLIB is unable to decompress the data, return 0; + if(Info.pbOutBuff == pvOutBuffer) + { + STORM_FREE(work_buf); + return 0; + } + + // Give away the number of decompressed bytes + *pcbOutBuffer = (int)(Info.pbOutBuff - (unsigned char *)pvOutBuffer); + STORM_FREE(work_buf); + return 1; +} + +#ifdef FULL +/******************************************************************************/ +/* */ +/* Support for Bzip2 compression (0x10) */ +/* */ +/******************************************************************************/ + +static void Compress_BZIP2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + bz_stream strm; + int blockSize100k = 9; + int workFactor = 30; + int bzError; + + // Keep compilers happy + STORMLIB_UNUSED(pCmpType); + STORMLIB_UNUSED(nCmpLevel); + + // Initialize the BZIP2 compression + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + + // Blizzard uses 9 as blockSize100k, (0x30 as workFactor) + // Last checked on Starcraft II + if(BZ2_bzCompressInit(&strm, blockSize100k, 0, workFactor) == BZ_OK) + { + strm.next_in = (char *)pvInBuffer; + strm.avail_in = cbInBuffer; + strm.next_out = (char *)pvOutBuffer; + strm.avail_out = *pcbOutBuffer; + + // Perform the compression + for(;;) + { + bzError = BZ2_bzCompress(&strm, (strm.avail_in != 0) ? BZ_RUN : BZ_FINISH); + if(bzError == BZ_STREAM_END || bzError < 0) + break; + } + + // Put the stream into idle state + BZ2_bzCompressEnd(&strm); + + if(bzError > 0) + *pcbOutBuffer = strm.total_out_lo32; + } +} + +static int Decompress_BZIP2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + bz_stream strm; + int nResult = BZ_OK; + + // Initialize the BZIP2 decompression + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + + // Initialize decompression + if(BZ2_bzDecompressInit(&strm, 0, 0) == BZ_OK) + { + strm.next_in = (char *)pvInBuffer; + strm.avail_in = cbInBuffer; + strm.next_out = (char *)pvOutBuffer; + strm.avail_out = *pcbOutBuffer; + + // Perform the decompression + while(nResult != BZ_STREAM_END) + { + nResult = BZ2_bzDecompress(&strm); + + // If any error there, break the loop + if(nResult < BZ_OK) + break; + } + + // Put the stream into idle state + BZ2_bzDecompressEnd(&strm); + + // If all succeeded, set the number of output bytes + if(nResult >= BZ_OK) + { + *pcbOutBuffer = strm.total_out_lo32; + return 1; + } + } + + // Something failed, so set number of output bytes to zero + *pcbOutBuffer = 0; + return 1; +} + +/******************************************************************************/ +/* */ +/* Support functions for LZMA compression (0x12) */ +/* */ +/******************************************************************************/ + +#define LZMA_HEADER_SIZE (1 + LZMA_PROPS_SIZE + 8) + +static SRes LZMA_Callback_Progress(void * /* p */, UInt64 /* inSize */, UInt64 /* outSize */) +{ + return SZ_OK; +} + +static void * LZMA_Callback_Alloc(void *p, size_t size) +{ + p = p; + return STORM_ALLOC(BYTE, size); +} + +/* address can be 0 */ +static void LZMA_Callback_Free(void *p, void *address) +{ + p = p; + if(address != NULL) + STORM_FREE(address); +} + +// +// Note: So far, I haven't seen any files compressed by LZMA. +// This code haven't been verified against code ripped from Starcraft II Beta, +// but we know that Starcraft LZMA decompression code is able to decompress +// the data compressed by StormLib. +// + +static void Compress_LZMA(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + ICompressProgress Progress; + CLzmaEncProps props; + ISzAlloc SzAlloc; + Byte * pbOutBuffer = (Byte *)pvOutBuffer; + Byte * destBuffer; + SizeT destLen = *pcbOutBuffer; + SizeT srcLen = cbInBuffer; + Byte encodedProps[LZMA_PROPS_SIZE]; + size_t encodedPropsSize = LZMA_PROPS_SIZE; + SRes nResult; + + // Keep compilers happy + STORMLIB_UNUSED(pCmpType); + STORMLIB_UNUSED(nCmpLevel); + + // Fill the callbacks in structures + Progress.Progress = LZMA_Callback_Progress; + SzAlloc.Alloc = LZMA_Callback_Alloc; + SzAlloc.Free = LZMA_Callback_Free; + + // Initialize properties + LzmaEncProps_Init(&props); + + // Perform compression + destBuffer = (Byte *)pvOutBuffer + LZMA_HEADER_SIZE; + destLen = *pcbOutBuffer - LZMA_HEADER_SIZE; + nResult = LzmaEncode(destBuffer, + &destLen, + (Byte *)pvInBuffer, + srcLen, + &props, + encodedProps, + &encodedPropsSize, + 0, + &Progress, + &SzAlloc, + &SzAlloc); + if(nResult != SZ_OK) + return; + + // If we failed to compress the data + if(destLen >= (SizeT)(*pcbOutBuffer - LZMA_HEADER_SIZE)) + return; + + // Write "useFilter" variable. Blizzard MPQ must not use filter. + *pbOutBuffer++ = 0; + + // Copy the encoded properties to the output buffer + memcpy(pvOutBuffer, encodedProps, encodedPropsSize); + pbOutBuffer += encodedPropsSize; + + // Copy the size of the data + *pbOutBuffer++ = (unsigned char)(srcLen >> 0x00); + *pbOutBuffer++ = (unsigned char)(srcLen >> 0x08); + *pbOutBuffer++ = (unsigned char)(srcLen >> 0x10); + *pbOutBuffer++ = (unsigned char)(srcLen >> 0x18); + *pbOutBuffer++ = 0; + *pbOutBuffer++ = 0; + *pbOutBuffer++ = 0; + *pbOutBuffer++ = 0; + + // Give the size of the data to the caller + *pcbOutBuffer = (unsigned int)(destLen + LZMA_HEADER_SIZE); +} + +static int Decompress_LZMA(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + ELzmaStatus LzmaStatus; + ISzAlloc SzAlloc; + Byte * destBuffer = (Byte *)pvOutBuffer; + Byte * srcBuffer = (Byte *)pvInBuffer; + SizeT destLen = *pcbOutBuffer; + SizeT srcLen = cbInBuffer; + SRes nResult; + + // There must be at least 0x0E bytes in the buffer + if(srcLen <= LZMA_HEADER_SIZE) + return 0; + + // We only accept blocks that have no filter used + if(*srcBuffer != 0) + return 0; + + // Fill the callbacks in structures + SzAlloc.Alloc = LZMA_Callback_Alloc; + SzAlloc.Free = LZMA_Callback_Free; + + // Perform compression + srcLen = cbInBuffer - LZMA_HEADER_SIZE; + nResult = LzmaDecode(destBuffer, + &destLen, + srcBuffer + LZMA_HEADER_SIZE, + &srcLen, + srcBuffer + 1, + LZMA_PROPS_SIZE, + LZMA_FINISH_END, + &LzmaStatus, + &SzAlloc); + if(nResult != SZ_OK) + return 0; + + *pcbOutBuffer = (unsigned int)destLen; + return 1; +} + +static int Decompress_LZMA_MPK(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + ELzmaStatus LzmaStatus; + ISzAlloc SzAlloc; + Byte * destBuffer = (Byte *)pvOutBuffer; + Byte * srcBuffer = (Byte *)pvInBuffer; + SizeT destLen = *pcbOutBuffer; + SizeT srcLen = cbInBuffer; + SRes nResult; + BYTE LZMA_Props[] = {0x5D, 0x00, 0x00, 0x00, 0x01}; + + // There must be at least 0x0E bytes in the buffer + if(srcLen <= sizeof(LZMA_Props)) + return 0; + + // Verify the props header + if(memcmp(pvInBuffer, LZMA_Props, sizeof(LZMA_Props))) + return 0; + + // Fill the callbacks in structures + SzAlloc.Alloc = LZMA_Callback_Alloc; + SzAlloc.Free = LZMA_Callback_Free; + + // Perform compression + srcLen = cbInBuffer - sizeof(LZMA_Props); + nResult = LzmaDecode(destBuffer, + &destLen, + srcBuffer + sizeof(LZMA_Props), + &srcLen, + srcBuffer, + sizeof(LZMA_Props), + LZMA_FINISH_END, + &LzmaStatus, + &SzAlloc); + if(nResult != SZ_OK) + return 0; + + *pcbOutBuffer = (unsigned int)destLen; + return 1; +} + +/******************************************************************************/ +/* */ +/* Support functions for SPARSE compression (0x20) */ +/* */ +/******************************************************************************/ + +void Compress_SPARSE(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + // Keep compilers happy + STORMLIB_UNUSED(pCmpType); + STORMLIB_UNUSED(nCmpLevel); + + CompressSparse(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer); +} + +int Decompress_SPARSE(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + return DecompressSparse(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer); +} + +/******************************************************************************/ +/* */ +/* Support for ADPCM mono compression (0x40) */ +/* */ +/******************************************************************************/ + +static void Compress_ADPCM_mono(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + // Prepare the compression level for Huffmann compression, + // which will be called as next step + if(0 < nCmpLevel && nCmpLevel <= 2) + { + nCmpLevel = 4; + *pCmpType = 6; + } + else if(nCmpLevel == 3) + { + nCmpLevel = 6; + *pCmpType = 8; + } + else + { + nCmpLevel = 5; + *pCmpType = 7; + } + *pcbOutBuffer = CompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 1, nCmpLevel); +} + +static int Decompress_ADPCM_mono(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + *pcbOutBuffer = DecompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 1); + return 1; +} + +/******************************************************************************/ +/* */ +/* Support for ADPCM stereo compression (0x80) */ +/* */ +/******************************************************************************/ + +static void Compress_ADPCM_stereo(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + // Prepare the compression level for Huffmann compression, + // which will be called as next step + if(0 < nCmpLevel && nCmpLevel <= 2) + { + nCmpLevel = 4; + *pCmpType = 6; + } + else if(nCmpLevel == 3) + { + nCmpLevel = 6; + *pCmpType = 8; + } + else + { + nCmpLevel = 5; + *pCmpType = 7; + } + *pcbOutBuffer = CompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 2, nCmpLevel); +} + +static int Decompress_ADPCM_stereo(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + *pcbOutBuffer = DecompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 2); + return 1; +} +#endif + +/*****************************************************************************/ +/* */ +/* SCompImplode */ +/* */ +/*****************************************************************************/ + +int WINAPI SCompImplode(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + int cbOutBuffer; + + // Check for valid parameters + if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pvOutBuffer || !pvInBuffer) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + // Perform the compression + cbOutBuffer = *pcbOutBuffer; + Compress_PKLIB(pvOutBuffer, &cbOutBuffer, pvInBuffer, cbInBuffer, NULL, 0); + + // If the compression was unsuccessful, copy the data as-is + if(cbOutBuffer >= *pcbOutBuffer) + { + memcpy(pvOutBuffer, pvInBuffer, cbInBuffer); + cbOutBuffer = *pcbOutBuffer; + } + + *pcbOutBuffer = cbOutBuffer; + return 1; +} + +/*****************************************************************************/ +/* */ +/* SCompExplode */ +/* */ +/*****************************************************************************/ + +int WINAPI SCompExplode(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + int cbOutBuffer; + + // Check for valid parameters + if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pvOutBuffer || !pvInBuffer) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + // If the input length is the same as output length, do nothing. + cbOutBuffer = *pcbOutBuffer; + if(cbInBuffer == cbOutBuffer) + { + // If the buffers are equal, don't copy anything. + if(pvInBuffer == pvOutBuffer) + return 1; + + memcpy(pvOutBuffer, pvInBuffer, cbInBuffer); + return 1; + } + + // Perform decompression + if(!Decompress_PKLIB(pvOutBuffer, &cbOutBuffer, pvInBuffer, cbInBuffer)) + { + SetLastError(ERROR_FILE_CORRUPT); + return 0; + } + + *pcbOutBuffer = cbOutBuffer; + return 1; +} + +/*****************************************************************************/ +/* */ +/* SCompCompress */ +/* */ +/*****************************************************************************/ + +// This table contains compress functions which can be applied to +// uncompressed data. Each bit means the corresponding +// compression method/function must be applied. +// +// WAVes compression Data compression +// ------------------ ------------------- +// 1st sector - 0x08 0x08 (D, HF, W2, SC, D2) +// Next sectors - 0x81 0x02 (W3) + +static TCompressTable cmp_table[] = +{ +#ifdef FULL + {MPQ_COMPRESSION_SPARSE, Compress_SPARSE}, // Sparse compression + {MPQ_COMPRESSION_ADPCM_MONO, Compress_ADPCM_mono}, // IMA ADPCM mono compression + {MPQ_COMPRESSION_ADPCM_STEREO, Compress_ADPCM_stereo}, // IMA ADPCM stereo compression + {MPQ_COMPRESSION_HUFFMANN, Compress_huff}, // Huffmann compression + {MPQ_COMPRESSION_ZLIB, Compress_ZLIB}, // Compression with the "zlib" library +#endif + {MPQ_COMPRESSION_PKWARE, Compress_PKLIB}, // Compression with Pkware DCL +#ifdef FULL + {MPQ_COMPRESSION_BZIP2, Compress_BZIP2} // Compression Bzip2 library +#endif +}; + +int WINAPI SCompCompress(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, unsigned uCompressionMask, int nCmpType, int nCmpLevel) +{ + COMPRESS CompressFuncArray[0x10]; // Array of compression functions, applied sequentially + unsigned char CompressByte[0x10]; // CompressByte for each method in the CompressFuncArray array + unsigned char * pbWorkBuffer = NULL; // Temporary storage for decompressed data + unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer; + unsigned char * pbOutput = (unsigned char *)pvOutBuffer;// Current output buffer + unsigned char * pbInput = (unsigned char *)pvInBuffer; // Current input buffer + int nCompressCount = 0; + int nCompressIndex = 0; + int nAtLeastOneCompressionDone = 0; + int cbOutBuffer = 0; + int cbInLength = cbInBuffer; + int nResult = 1; + + // Check for valid parameters + if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pvOutBuffer || !pvInBuffer) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + // Zero input length brings zero output length + if(cbInBuffer == 0) + { + *pcbOutBuffer = 0; + return true; + } + + // Setup the compression function array + if(uCompressionMask == MPQ_COMPRESSION_LZMA) + { +#ifdef FULL + CompressFuncArray[0] = Compress_LZMA; + CompressByte[0] = (char)uCompressionMask; + nCompressCount = 1; +#else + assert(0); +#endif + } + else + { + // Fill the compressions array + for(size_t i = 0; i < (sizeof(cmp_table) / sizeof(TCompressTable)); i++) + { + // If the mask agrees, insert the compression function to the array + if(uCompressionMask & cmp_table[i].uMask) + { + CompressFuncArray[nCompressCount] = cmp_table[i].Compress; + CompressByte[nCompressCount] = (unsigned char)cmp_table[i].uMask; + uCompressionMask &= ~cmp_table[i].uMask; + nCompressCount++; + } + } + + // If at least one of the compressions remaing unknown, return an error + if(uCompressionMask != 0) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + } + + // If there is at least one compression, do it + if(nCompressCount > 0) + { + // If we need to do more than 1 compression, allocate intermediate buffer + if(nCompressCount > 1) + { + pbWorkBuffer = STORM_ALLOC(unsigned char, *pcbOutBuffer); + if(pbWorkBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + } + + // Get the current compression index + nCompressIndex = nCompressCount - 1; + + // Perform all compressions in the array + for(int i = 0; i < nCompressCount; i++) + { + // Choose the proper output buffer + pbOutput = (nCompressIndex & 1) ? pbWorkBuffer : pbOutBuffer; + nCompressIndex--; + + // Perform the (next) compression + // Note that if the compression method is unable to compress the input data block + // by at least 2 bytes, we consider it as failure and will use source data instead + cbOutBuffer = *pcbOutBuffer - 1; + CompressFuncArray[i](pbOutput + 1, &cbOutBuffer, pbInput, cbInLength, &nCmpType, nCmpLevel); + + // If the compression failed, we copy the input buffer as-is. + // Note that there is one extra byte at the end of the intermediate buffer, so it should be OK + if(cbOutBuffer > (cbInLength - 2)) + { + memcpy(pbOutput + nAtLeastOneCompressionDone, pbInput, cbInLength); + cbOutBuffer = cbInLength; + } + else + { + // Remember that we have done at least one compression + nAtLeastOneCompressionDone = 1; + uCompressionMask |= CompressByte[i]; + } + + // Now point input buffer to the output buffer + pbInput = pbOutput + nAtLeastOneCompressionDone; + cbInLength = cbOutBuffer; + } + + // If at least one compression succeeded, put the compression + // mask to the begin of the output buffer + if(nAtLeastOneCompressionDone) + *pbOutBuffer = (unsigned char)uCompressionMask; + *pcbOutBuffer = cbOutBuffer + nAtLeastOneCompressionDone; + } + else + { + memcpy(pvOutBuffer, pvInBuffer, cbInBuffer); + *pcbOutBuffer = cbInBuffer; + } + + // Cleanup and return + if(pbWorkBuffer != NULL) + STORM_FREE(pbWorkBuffer); + return nResult; +} + +/*****************************************************************************/ +/* */ +/* SCompDecompress */ +/* */ +/*****************************************************************************/ + +// This table contains decompress functions which can be applied to +// uncompressed data. The compression mask is stored in the first byte +// of compressed data +static TDecompressTable dcmp_table[] = +{ +#ifdef FULL + {MPQ_COMPRESSION_BZIP2, Decompress_BZIP2}, // Decompression with Bzip2 library +#endif + {MPQ_COMPRESSION_PKWARE, Decompress_PKLIB}, // Decompression with Pkware Data Compression Library +#ifdef FULL + {MPQ_COMPRESSION_ZLIB, Decompress_ZLIB}, // Decompression with the "zlib" library + {MPQ_COMPRESSION_HUFFMANN, Decompress_huff}, // Huffmann decompression + {MPQ_COMPRESSION_ADPCM_STEREO, Decompress_ADPCM_stereo}, // IMA ADPCM stereo decompression + {MPQ_COMPRESSION_ADPCM_MONO, Decompress_ADPCM_mono}, // IMA ADPCM mono decompression + {MPQ_COMPRESSION_SPARSE, Decompress_SPARSE} // Sparse decompression +#endif +}; + +int WINAPI SCompDecompress(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + unsigned char * pbWorkBuffer = NULL; + unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer; + unsigned char * pbInBuffer = (unsigned char *)pvInBuffer; + unsigned char * pbOutput = (unsigned char *)pvOutBuffer; + unsigned char * pbInput; + unsigned uCompressionMask; // Decompressions applied to the data + unsigned uCompressionCopy; // Decompressions applied to the data + int cbOutBuffer = *pcbOutBuffer; // Current size of the output buffer + int cbInLength; // Current size of the input buffer + int nCompressCount = 0; // Number of compressions to be applied + int nCompressIndex = 0; + int nResult = 1; + + // Verify buffer sizes + if(cbOutBuffer < cbInBuffer || cbInBuffer < 1) + return 0; + + // If the input length is the same as output length, do nothing. + if(cbOutBuffer == cbInBuffer) + { + // If the buffers are equal, don't copy anything. + if(pvInBuffer != pvOutBuffer) + memcpy(pvOutBuffer, pvInBuffer, cbInBuffer); + return 1; + } + + // Get applied compression types and decrement data length + uCompressionMask = uCompressionCopy = (unsigned char)*pbInBuffer++; + cbInBuffer--; + + // Get current compressed data and length of it + pbInput = pbInBuffer; + cbInLength = cbInBuffer; + + // This compression function doesn't support LZMA + assert(uCompressionMask != MPQ_COMPRESSION_LZMA); + + // Parse the compression mask + for(size_t i = 0; i < (sizeof(dcmp_table) / sizeof(TDecompressTable)); i++) + { + // If the mask agrees, insert the compression function to the array + if(uCompressionMask & dcmp_table[i].uMask) + { + uCompressionCopy &= ~dcmp_table[i].uMask; + nCompressCount++; + } + } + + // If at least one of the compressions remaing unknown, return an error + if(nCompressCount == 0 || uCompressionCopy != 0) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + // If there is more than one compression, we have to allocate extra buffer + if(nCompressCount > 1) + { + pbWorkBuffer = STORM_ALLOC(unsigned char, cbOutBuffer); + if(pbWorkBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + } + + // Get the current compression index + nCompressIndex = nCompressCount - 1; + + // Apply all decompressions + for(size_t i = 0; i < (sizeof(dcmp_table) / sizeof(TDecompressTable)); i++) + { + // Perform the (next) decompression + if(uCompressionMask & dcmp_table[i].uMask) + { + // Get the correct output buffer + pbOutput = (nCompressIndex & 1) ? pbWorkBuffer : pbOutBuffer; + nCompressIndex--; + + // Perform the decompression + cbOutBuffer = *pcbOutBuffer; + nResult = dcmp_table[i].Decompress(pbOutput, &cbOutBuffer, pbInput, cbInLength); + if(nResult == 0 || cbOutBuffer == 0) + { + SetLastError(ERROR_FILE_CORRUPT); + nResult = 0; + break; + } + + // Switch buffers + cbInLength = cbOutBuffer; + pbInput = pbOutput; + } + } + + // Put the length of the decompressed data to the output buffer + *pcbOutBuffer = cbOutBuffer; + + // Cleanup and return + if(pbWorkBuffer != NULL) + STORM_FREE(pbWorkBuffer); + return nResult; +} + +int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + DECOMPRESS pfnDecompress1 = NULL; + DECOMPRESS pfnDecompress2 = NULL; + unsigned char * pbWorkBuffer = (unsigned char *)pvOutBuffer; + unsigned char * pbInBuffer = (unsigned char *)pvInBuffer; + int cbWorkBuffer = *pcbOutBuffer; + int nResult; + char CompressionMethod; + + // Verify buffer sizes + if(*pcbOutBuffer < cbInBuffer || cbInBuffer < 1) + return 0; + + // If the outputbuffer is as big as input buffer, just copy the block + if(*pcbOutBuffer == cbInBuffer) + { + if(pvOutBuffer != pvInBuffer) + memcpy(pvOutBuffer, pvInBuffer, cbInBuffer); + return 1; + } + + // Get the compression methods + CompressionMethod = *pbInBuffer++; + cbInBuffer--; + + // We only recognize a fixed set of compression methods + switch((unsigned char)CompressionMethod) + { +#ifdef FULL + case MPQ_COMPRESSION_ZLIB: + pfnDecompress1 = Decompress_ZLIB; + break; +#endif + + case MPQ_COMPRESSION_PKWARE: + pfnDecompress1 = Decompress_PKLIB; + break; + +#ifdef FULL + case MPQ_COMPRESSION_BZIP2: + pfnDecompress1 = Decompress_BZIP2; + break; + + case MPQ_COMPRESSION_LZMA: + pfnDecompress1 = Decompress_LZMA; + break; + + case MPQ_COMPRESSION_SPARSE: + pfnDecompress1 = Decompress_SPARSE; + break; + + case (MPQ_COMPRESSION_SPARSE | MPQ_COMPRESSION_ZLIB): + pfnDecompress1 = Decompress_ZLIB; + pfnDecompress2 = Decompress_SPARSE; + break; + + case (MPQ_COMPRESSION_SPARSE | MPQ_COMPRESSION_BZIP2): + pfnDecompress1 = Decompress_BZIP2; + pfnDecompress2 = Decompress_SPARSE; + break; + + // + // Note: Any combination including MPQ_COMPRESSION_ADPCM_MONO, + // MPQ_COMPRESSION_ADPCM_STEREO or MPQ_COMPRESSION_HUFFMANN + // is not supported by newer MPQs. + // + + case (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_HUFFMANN): + pfnDecompress1 = Decompress_huff; + pfnDecompress2 = Decompress_ADPCM_mono; + break; + + case (MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN): + pfnDecompress1 = Decompress_huff; + pfnDecompress2 = Decompress_ADPCM_stereo; + break; +#endif + default: + SetLastError(ERROR_FILE_CORRUPT); + return 0; + } + + // If we have to use two decompressions, allocate temporary buffer + if(pfnDecompress2 != NULL) + { + pbWorkBuffer = STORM_ALLOC(unsigned char, *pcbOutBuffer); + if(pbWorkBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + } + + // Apply the first decompression method + nResult = pfnDecompress1(pbWorkBuffer, &cbWorkBuffer, pbInBuffer, cbInBuffer); + + // Apply the second decompression method, if any + if(pfnDecompress2 != NULL && nResult != 0) + { + cbInBuffer = cbWorkBuffer; + cbWorkBuffer = *pcbOutBuffer; + nResult = pfnDecompress2(pvOutBuffer, &cbWorkBuffer, pbWorkBuffer, cbInBuffer); + } + + // Supply the output buffer size + *pcbOutBuffer = cbWorkBuffer; + + // Free temporary buffer + if(pbWorkBuffer != pvOutBuffer) + STORM_FREE(pbWorkBuffer); + + if(nResult == 0) + SetLastError(ERROR_FILE_CORRUPT); + return nResult; +} + +#ifdef FULL +/*****************************************************************************/ +/* */ +/* File decompression for MPK archives */ +/* */ +/*****************************************************************************/ + +int SCompDecompressMpk(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + return Decompress_LZMA_MPK(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer); +} +#endif + diff --git a/3rdParty/StormLib/src/SFileExtractFile.cpp b/3rdParty/StormLib/src/SFileExtractFile.cpp new file mode 100644 index 000000000..cabde4927 --- /dev/null +++ b/3rdParty/StormLib/src/SFileExtractFile.cpp @@ -0,0 +1,64 @@ +/*****************************************************************************/ +/* SFileExtractFile.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Simple extracting utility */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 20.06.03 1.00 Lad The first version of SFileExtractFile.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +bool WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const TCHAR * szExtracted, DWORD dwSearchScope) +{ + TFileStream * pLocalFile = NULL; + HANDLE hMpqFile = NULL; + int nError = ERROR_SUCCESS; + + // Open the MPQ file + if(nError == ERROR_SUCCESS) + { + if(!SFileOpenFileEx(hMpq, szToExtract, dwSearchScope, &hMpqFile)) + nError = GetLastError(); + } + + // Create the local file + if(nError == ERROR_SUCCESS) + { + pLocalFile = FileStream_CreateFile(szExtracted, 0); + if(pLocalFile == NULL) + nError = GetLastError(); + } + + // Copy the file's content + while(nError == ERROR_SUCCESS) + { + char szBuffer[0x1000]; + DWORD dwTransferred = 0; + + // dwTransferred is only set to nonzero if something has been read. + // nError can be ERROR_SUCCESS or ERROR_HANDLE_EOF + if(!SFileReadFile(hMpqFile, szBuffer, sizeof(szBuffer), &dwTransferred, NULL)) + nError = GetLastError(); + if(nError == ERROR_HANDLE_EOF) + nError = ERROR_SUCCESS; + if(dwTransferred == 0) + break; + + // If something has been actually read, write it + if(!FileStream_Write(pLocalFile, NULL, szBuffer, dwTransferred)) + nError = GetLastError(); + } + + // Close the files + if(hMpqFile != NULL) + SFileCloseFile(hMpqFile); + if(pLocalFile != NULL) + FileStream_Close(pLocalFile); + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} diff --git a/3rdParty/StormLib/src/SFileFindFile.cpp b/3rdParty/StormLib/src/SFileFindFile.cpp new file mode 100644 index 000000000..6b8b87ad6 --- /dev/null +++ b/3rdParty/StormLib/src/SFileFindFile.cpp @@ -0,0 +1,481 @@ +/*****************************************************************************/ +/* SFileFindFile.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* A module for file searching within MPQs */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 25.03.03 1.00 Lad The first version of SFileFindFile.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Private structure used for file search (search handle) + +// Used by searching in MPQ archives +struct TMPQSearch +{ + TMPQArchive * ha; // Handle to MPQ, where the search runs + TFileEntry ** pSearchTable; // Table for files that have been already found + DWORD dwSearchTableItems; // Number of items in the search table + DWORD dwNextIndex; // Next file index to be checked + DWORD dwFlagMask; // For checking flag mask + char szSearchMask[1]; // Search mask (variable length) +}; + +//----------------------------------------------------------------------------- +// Local functions + +static TMPQSearch * IsValidSearchHandle(HANDLE hFind) +{ + TMPQSearch * hs = (TMPQSearch *)hFind; + + if(hs != NULL && IsValidMpqHandle(hs->ha)) + return hs; + + return NULL; +} + +bool CheckWildCard(const char * szString, const char * szWildCard) +{ + const char * szWildCardPtr; + + for(;;) + { + // If there is '?' in the wildcard, we skip one char + while(szWildCard[0] == '?') + { + if(szString[0] == 0) + return false; + + szWildCard++; + szString++; + } + + // Handle '*' + szWildCardPtr = szWildCard; + if(szWildCardPtr[0] != 0) + { + if(szWildCardPtr[0] == '*') + { + szWildCardPtr++; + + if(szWildCardPtr[0] == '*') + continue; + + if(szWildCardPtr[0] == 0) + return true; + + if(AsciiToUpperTable[szWildCardPtr[0]] == AsciiToUpperTable[szString[0]]) + { + if(CheckWildCard(szString, szWildCardPtr)) + return true; + } + } + else + { + if(AsciiToUpperTable[szWildCardPtr[0]] != AsciiToUpperTable[szString[0]]) + return false; + + szWildCard = szWildCardPtr + 1; + } + + if(szString[0] == 0) + return false; + szString++; + } + else + { + return (szString[0] == 0) ? true : false; + } + } +} + +static DWORD GetSearchTableItems(TMPQArchive * ha) +{ + DWORD dwMergeItems = 0; + + // Loop over all patches + while(ha != NULL) + { + // Append the number of files + dwMergeItems += (ha->pHetTable != NULL) ? ha->pHetTable->dwEntryCount + : ha->pHeader->dwBlockTableSize; + // Move to the patched archive + ha = ha->haPatch; + } + + // Return the double size of number of items + return (dwMergeItems | 1); +} + +static bool FileWasFoundBefore( + TMPQArchive * ha, + TMPQSearch * hs, + TFileEntry * pFileEntry) +{ + TFileEntry * pEntry; + char * szRealFileName = pFileEntry->szFileName; + DWORD dwStartIndex; + DWORD dwNameHash; + DWORD dwIndex; + + if(hs->pSearchTable != NULL && szRealFileName != NULL) + { + // If we are in patch MPQ, we check if patch prefix matches + // and then trim the patch prefix + if(ha->pPatchPrefix != NULL) + { + // If the patch prefix doesn't fit, we pretend that the file + // was there before and it will be skipped + if(_strnicmp(szRealFileName, ha->pPatchPrefix->szPatchPrefix, ha->pPatchPrefix->nLength)) + return true; + + szRealFileName += ha->pPatchPrefix->nLength; + } + + // Calculate the hash to the table + dwNameHash = ha->pfnHashString(szRealFileName, MPQ_HASH_NAME_A); + dwStartIndex = dwIndex = (dwNameHash % hs->dwSearchTableItems); + + // The file might have been found before + // only if this is not the first MPQ being searched + if(ha->haBase != NULL) + { + // Enumerate all entries in the search table + for(;;) + { + // Get the file entry at that position + pEntry = hs->pSearchTable[dwIndex]; + if(pEntry == NULL) + break; + + if(pEntry->szFileName != NULL) + { + // Does the name match? + if(!_stricmp(pEntry->szFileName, szRealFileName)) + return true; + } + + // Move to the next entry + dwIndex = (dwIndex + 1) % hs->dwSearchTableItems; + if(dwIndex == dwStartIndex) + break; + } + } + + // Put the entry to the table for later use + hs->pSearchTable[dwIndex] = pFileEntry; + } + return false; +} + +static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry) +{ + TFileEntry * pPatchEntry = pFileEntry; + TFileEntry * pTempEntry; + char szFileName[MAX_PATH+1]; + + // Can't find patch entry for a file that doesn't have name + if(pFileEntry->szFileName != NULL && pFileEntry->szFileName[0] != 0) + { + // Go while there are patches + while(ha->haPatch != NULL) + { + // Move to the patch archive + ha = ha->haPatch; + szFileName[0] = 0; + + // Prepare the prefix for the file name + if(ha->pPatchPrefix && ha->pPatchPrefix->nLength) + StringCopy(szFileName, _countof(szFileName), ha->pPatchPrefix->szPatchPrefix); + StringCat(szFileName, _countof(szFileName), pFileEntry->szFileName); + + // Try to find the file there + pTempEntry = GetFileEntryExact(ha, szFileName, 0, NULL); + if(pTempEntry != NULL) + pPatchEntry = pTempEntry; + } + } + + // Return the found patch entry + return pPatchEntry; +} + +static bool DoMPQSearch_FileEntry( + TMPQSearch * hs, + SFILE_FIND_DATA * lpFindFileData, + TMPQArchive * ha, + TMPQHash * pHashEntry, + TFileEntry * pFileEntry) +{ + TFileEntry * pPatchEntry; + HANDLE hFile = NULL; + const char * szFileName; + size_t nPrefixLength = (ha->pPatchPrefix != NULL) ? ha->pPatchPrefix->nLength : 0; + DWORD dwBlockIndex; + char szNameBuff[MAX_PATH]; + + // Is it a file but not a patch file? + if((pFileEntry->dwFlags & hs->dwFlagMask) == MPQ_FILE_EXISTS) + { + // Now we have to check if this file was not enumerated before + if(!FileWasFoundBefore(ha, hs, pFileEntry)) + { +// if(pFileEntry != NULL && !_stricmp(pFileEntry->szFileName, "TriggerLibs\\NativeLib.galaxy")) +// DebugBreak(); + + // Find a patch to this file + // Note: This either succeeds or returns pFileEntry + pPatchEntry = FindPatchEntry(ha, pFileEntry); + + // Prepare the block index + dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable); + + // Get the file name. If it's not known, we will create pseudo-name + szFileName = pFileEntry->szFileName; + if(szFileName == NULL) + { + // Open the file by its pseudo-name. + sprintf(szNameBuff, "File%08u.xxx", (unsigned int)dwBlockIndex); + if(SFileOpenFileEx((HANDLE)hs->ha, szNameBuff, SFILE_OPEN_BASE_FILE, &hFile)) + { + SFileGetFileName(hFile, szNameBuff); + szFileName = szNameBuff; + SFileCloseFile(hFile); + } + } + + // If the file name is still NULL, we cannot include the file to search results + if(szFileName != NULL) + { + // Check the file name against the wildcard + if(CheckWildCard(szFileName + nPrefixLength, hs->szSearchMask)) + { + // Fill the found entry. hash entry and block index are taken from the base MPQ + lpFindFileData->dwHashIndex = HASH_ENTRY_FREE; + lpFindFileData->dwBlockIndex = dwBlockIndex; + lpFindFileData->dwFileSize = pPatchEntry->dwFileSize; + lpFindFileData->dwFileFlags = pPatchEntry->dwFlags; + lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize; + lpFindFileData->lcLocale = 0; // pPatchEntry->lcLocale; + + // Fill the filetime + lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32); + lpFindFileData->dwFileTimeLo = (DWORD)(pPatchEntry->FileTime); + + // Fill-in the entries from hash table entry, if given + if(pHashEntry != NULL) + { + lpFindFileData->dwHashIndex = (DWORD)(pHashEntry - ha->pHashTable); + lpFindFileData->lcLocale = pHashEntry->lcLocale; + } + + // Fill the file name and plain file name + StringCopy(lpFindFileData->cFileName, _countof(lpFindFileData->cFileName), szFileName + nPrefixLength); + lpFindFileData->szPlainName = (char *)GetPlainFileName(lpFindFileData->cFileName); + return true; + } + } + } + } + + // Either not a valid item or was found before + return false; +} + +static int DoMPQSearch_HashTable(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData, TMPQArchive * ha) +{ + TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; + TMPQHash * pHash; + + // Parse the file table + for(pHash = ha->pHashTable + hs->dwNextIndex; pHash < pHashTableEnd; pHash++) + { + // Increment the next index for subsequent search + hs->dwNextIndex++; + + // Does this hash table entry point to a proper block table entry? + if(IsValidHashEntry(ha, pHash)) + { + // Check if this file entry should be included in the search result + if(DoMPQSearch_FileEntry(hs, lpFindFileData, ha, pHash, ha->pFileTable + MPQ_BLOCK_INDEX(pHash))) + return ERROR_SUCCESS; + } + } + + // No more files + return ERROR_NO_MORE_FILES; +} + +static int DoMPQSearch_FileTable(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData, TMPQArchive * ha) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + + // Parse the file table + for(pFileEntry = ha->pFileTable + hs->dwNextIndex; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Increment the next index for subsequent search + hs->dwNextIndex++; + + // Check if this file entry should be included in the search result + if(DoMPQSearch_FileEntry(hs, lpFindFileData, ha, NULL, pFileEntry)) + return ERROR_SUCCESS; + } + + // No more files + return ERROR_NO_MORE_FILES; +} + +// Performs one MPQ search +static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData) +{ + TMPQArchive * ha = hs->ha; + int nError; + + // Start searching with base MPQ + while(ha != NULL) + { + // If the archive has hash table, we need to use hash table + // in order to catch hash table index and file locale. + // Note: If multiple hash table entries, point to the same block entry, + // we need, to report them all + nError = (ha->pHashTable != NULL) ? DoMPQSearch_HashTable(hs, lpFindFileData, ha) + : DoMPQSearch_FileTable(hs, lpFindFileData, ha); + if(nError == ERROR_SUCCESS) + return nError; + + // If there is no more patches in the chain, stop it. + // This also keeps hs->ha non-NULL, which is required + // for freeing the handle later + if(ha->haPatch == NULL) + break; + + // Move to the next patch in the patch chain + hs->ha = ha = ha->haPatch; + hs->dwNextIndex = 0; + } + + // No more files found, return error + return ERROR_NO_MORE_FILES; +} + +static void FreeMPQSearch(TMPQSearch *& hs) +{ + if(hs != NULL) + { + if(hs->pSearchTable != NULL) + STORM_FREE(hs->pSearchTable); + STORM_FREE(hs); + hs = NULL; + } +} + +//----------------------------------------------------------------------------- +// Public functions + +HANDLE WINAPI SFileFindFirstFile(HANDLE hMpq, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const TCHAR * szListFile) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + TMPQSearch * hs = NULL; + size_t nSize = 0; + int nError = ERROR_SUCCESS; + + // Check for the valid parameters + if(!IsValidMpqHandle(hMpq)) + nError = ERROR_INVALID_HANDLE; + if(szMask == NULL || lpFindFileData == NULL) + nError = ERROR_INVALID_PARAMETER; + +#ifdef FULL + // Include the listfile into the MPQ's internal listfile + // Note that if the listfile name is NULL, do nothing because the + // internal listfile is always included. + if(nError == ERROR_SUCCESS && szListFile != NULL && *szListFile != 0) + nError = SFileAddListFile((HANDLE)ha, szListFile); +#endif + + // Allocate the structure for MPQ search + if(nError == ERROR_SUCCESS) + { + nSize = sizeof(TMPQSearch) + strlen(szMask) + 1; + if((hs = (TMPQSearch *)STORM_ALLOC(char, nSize)) == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Perform the first search + if(nError == ERROR_SUCCESS) + { + memset(hs, 0, sizeof(TMPQSearch)); + strcpy(hs->szSearchMask, szMask); + hs->dwFlagMask = MPQ_FILE_EXISTS; + hs->ha = ha; + + // If the archive is patched archive, we have to create a merge table + // to prevent files being repeated + if(ha->haPatch != NULL) + { + hs->dwSearchTableItems = GetSearchTableItems(ha); + hs->pSearchTable = STORM_ALLOC(TFileEntry *, hs->dwSearchTableItems); + hs->dwFlagMask = MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE; + if(hs->pSearchTable != NULL) + memset(hs->pSearchTable, 0, hs->dwSearchTableItems * sizeof(TFileEntry *)); + else + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + // Perform first item searching + if(nError == ERROR_SUCCESS) + { + nError = DoMPQSearch(hs, lpFindFileData); + } + + // Cleanup + if(nError != ERROR_SUCCESS) + { + FreeMPQSearch(hs); + SetLastError(nError); + } + + // Return the result value + return (HANDLE)hs; +} + +bool WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData) +{ + TMPQSearch * hs = IsValidSearchHandle(hFind); + int nError = ERROR_SUCCESS; + + // Check the parameters + if(hs == NULL) + nError = ERROR_INVALID_HANDLE; + if(lpFindFileData == NULL) + nError = ERROR_INVALID_PARAMETER; + + if(nError == ERROR_SUCCESS) + nError = DoMPQSearch(hs, lpFindFileData); + + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +bool WINAPI SFileFindClose(HANDLE hFind) +{ + TMPQSearch * hs = IsValidSearchHandle(hFind); + + // Check the parameters + if(hs == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + FreeMPQSearch(hs); + return true; +} diff --git a/3rdParty/StormLib/src/SFileGetFileInfo.cpp b/3rdParty/StormLib/src/SFileGetFileInfo.cpp new file mode 100644 index 000000000..ebe2119de --- /dev/null +++ b/3rdParty/StormLib/src/SFileGetFileInfo.cpp @@ -0,0 +1,1010 @@ +/*****************************************************************************/ +/* SFileGetFileInfo.cpp Copyright (c) Ladislav Zezula 2013 */ +/*---------------------------------------------------------------------------*/ +/* Description: */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.11.13 1.00 Lad The first version of SFileGetFileInfo.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local defines + +// Information types for SFileGetFileInfo +#define SFILE_INFO_TYPE_INVALID_HANDLE 0 +#define SFILE_INFO_TYPE_NOT_FOUND 1 +#define SFILE_INFO_TYPE_DIRECT_POINTER 2 +#define SFILE_INFO_TYPE_ALLOCATED 3 +#define SFILE_INFO_TYPE_READ_FROM_FILE 4 +#define SFILE_INFO_TYPE_TABLE_POINTER 5 +#define SFILE_INFO_TYPE_FILE_ENTRY 6 + +//----------------------------------------------------------------------------- +// Local functions + +static void ConvertFileEntryToSelfRelative(TFileEntry * pFileEntry, TFileEntry * pSrcFileEntry) +{ + // Copy the file entry itself + memcpy(pFileEntry, pSrcFileEntry, sizeof(TFileEntry)); + + // If source is NULL, leave it NULL + if(pSrcFileEntry->szFileName != NULL) + { + // Set the file name pointer after the file entry + pFileEntry->szFileName = (char *)(pFileEntry + 1); + strcpy(pFileEntry->szFileName, pSrcFileEntry->szFileName); + } +} + + +static DWORD GetMpqFileCount(TMPQArchive * ha) +{ + TFileEntry * pFileTableEnd; + TFileEntry * pFileEntry; + DWORD dwFileCount = 0; + + // Go through all open MPQs, including patches + while(ha != NULL) + { + // Only count files that are not patch files + pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // If the file is patch file and this is not primary archive, skip it + // BUGBUG: This errorneously counts non-patch files that are in both + // base MPQ and in patches, and increases the number of files by cca 50% + if((pFileEntry->dwFlags & (MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE)) == MPQ_FILE_EXISTS) + dwFileCount++; + } + + // Move to the next patch archive + ha = ha->haPatch; + } + + return dwFileCount; +} + +static bool GetFilePatchChain(TMPQFile * hf, void * pvFileInfo, DWORD cbFileInfo, DWORD * pcbLengthNeeded) +{ + TMPQFile * hfTemp; + TCHAR * szFileInfo = (TCHAR *)pvFileInfo; + size_t cchCharsNeeded = 1; + size_t cchFileInfo = (cbFileInfo / sizeof(TCHAR)); + size_t nLength; + + // Patch chain is only supported on MPQ files. + if(hf->pStream != NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // Calculate the necessary length of the multi-string + for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch) + cchCharsNeeded += _tcslen(FileStream_GetFileName(hfTemp->ha->pStream)) + 1; + + // Give the caller the needed length + if(pcbLengthNeeded != NULL) + pcbLengthNeeded[0] = (DWORD)(cchCharsNeeded * sizeof(TCHAR)); + + // If the caller gave both buffer pointer and data length, + // try to copy the patch chain + if(szFileInfo != NULL && cchFileInfo != 0) + { + // If there is enough space in the buffer, copy the patch chain + if(cchCharsNeeded > cchFileInfo) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return false; + } + + // Copy each patch + for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch) + { + // Get the file name and its length + const TCHAR * szFileName = FileStream_GetFileName(hfTemp->ha->pStream); + nLength = _tcslen(szFileName) + 1; + + // Copy the file name + memcpy(szFileInfo, szFileName, nLength * sizeof(TCHAR)); + szFileInfo += nLength; + } + + // Make it multi-string + szFileInfo[0] = 0; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Retrieves an information about an archive or about a file within the archive +// +// hMpqOrFile - Handle to an MPQ archive or to a file +// InfoClass - Information to obtain +// pvFileInfo - Pointer to buffer to store the information +// cbFileInfo - Size of the buffer pointed by pvFileInfo +// pcbLengthNeeded - Receives number of bytes necessary to store the information + +bool WINAPI SFileGetFileInfo( + HANDLE hMpqOrFile, + SFileInfoClass InfoClass, + void * pvFileInfo, + DWORD cbFileInfo, + LPDWORD pcbLengthNeeded) +{ + MPQ_SIGNATURE_INFO SignatureInfo; + TMPQArchive * ha = NULL; + TFileEntry * pFileEntry = NULL; + ULONGLONG Int64Value = 0; + ULONGLONG ByteOffset = 0; + TMPQFile * hf = NULL; + void * pvSrcFileInfo = NULL; + DWORD cbSrcFileInfo = 0; + DWORD dwInt32Value = 0; + int nInfoType = SFILE_INFO_TYPE_INVALID_HANDLE; + int nError = ERROR_SUCCESS; + + switch(InfoClass) + { + case SFileMpqFileName: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = (void *)FileStream_GetFileName(ha->pStream); + cbSrcFileInfo = (DWORD)(_tcslen((TCHAR *)pvSrcFileInfo) + 1) * sizeof(TCHAR); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqStreamBitmap: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + return FileStream_GetBitmap(ha->pStream, pvFileInfo, cbFileInfo, pcbLengthNeeded); + break; + + case SFileMpqUserDataOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(ha->pUserData != NULL) + { + pvSrcFileInfo = &ha->UserDataPos; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + } + break; + + case SFileMpqUserDataHeader: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(ha->pUserData != NULL) + { + ByteOffset = ha->UserDataPos; + cbSrcFileInfo = sizeof(TMPQUserData); + nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; + } + } + break; + + case SFileMpqUserData: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(ha->pUserData != NULL) + { + ByteOffset = ha->UserDataPos + sizeof(TMPQUserData); + cbSrcFileInfo = ha->pUserData->dwHeaderOffs - sizeof(TMPQUserData); + nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; + } + } + break; + + case SFileMpqHeaderOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->MpqPos; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHeaderSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->dwHeaderSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHeader: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + ByteOffset = ha->MpqPos; + cbSrcFileInfo = ha->pHeader->dwHeaderSize; + nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; + } + break; + + case SFileMpqHetTableOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->HetTablePos64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + +#ifdef FULL + case SFileMpqHetTableSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->HetTableSize64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHetHeader: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + pvSrcFileInfo = LoadExtTable(ha, ha->pHeader->HetTablePos64, (size_t)ha->pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE); + if(pvSrcFileInfo != NULL) + { + cbSrcFileInfo = sizeof(TMPQHetHeader); + nInfoType = SFILE_INFO_TYPE_ALLOCATED; + } + } + break; + + case SFileMpqHetTable: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + pvSrcFileInfo = LoadHetTable(ha); + if(pvSrcFileInfo != NULL) + { + cbSrcFileInfo = sizeof(void *); + nInfoType = SFILE_INFO_TYPE_TABLE_POINTER; + } + } + break; + + case SFileMpqBetTableOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->BetTablePos64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBetTableSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->BetTableSize64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBetHeader: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + pvSrcFileInfo = LoadExtTable(ha, ha->pHeader->BetTablePos64, (size_t)ha->pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE); + if(pvSrcFileInfo != NULL) + { + // It is allowed for the caller to only require BET header. + cbSrcFileInfo = sizeof(TMPQBetHeader) + ((TMPQBetHeader *)pvSrcFileInfo)->dwFlagCount * sizeof(DWORD); + if(cbFileInfo == sizeof(TMPQBetHeader)) + cbSrcFileInfo = sizeof(TMPQBetHeader); + nInfoType = SFILE_INFO_TYPE_ALLOCATED; + } + } + break; + + case SFileMpqBetTable: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + pvSrcFileInfo = LoadBetTable(ha); + if(pvSrcFileInfo != NULL) + { + cbSrcFileInfo = sizeof(void *); + nInfoType = SFILE_INFO_TYPE_TABLE_POINTER; + } + } + break; +#endif + case SFileMpqHashTableOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + Int64Value = MAKE_OFFSET64(ha->pHeader->wHashTablePosHi, ha->pHeader->dwHashTablePos); + pvSrcFileInfo = &Int64Value; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHashTableSize64: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->HashTableSize64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHashTableSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->dwHashTableSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHashTable: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL && ha->pHashTable != NULL) + { + pvSrcFileInfo = ha->pHashTable; + cbSrcFileInfo = ha->pHeader->dwHashTableSize * sizeof(TMPQHash); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBlockTableOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + Int64Value = MAKE_OFFSET64(ha->pHeader->wBlockTablePosHi, ha->pHeader->dwBlockTablePos); + pvSrcFileInfo = &Int64Value; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBlockTableSize64: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->BlockTableSize64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBlockTableSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->dwBlockTableSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBlockTable: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(MAKE_OFFSET64(ha->pHeader->wBlockTablePosHi, ha->pHeader->dwBlockTablePos) < ha->FileSize) + { + cbSrcFileInfo = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock); + if(cbFileInfo >= cbSrcFileInfo) + pvSrcFileInfo = LoadBlockTable(ha, true); + nInfoType = SFILE_INFO_TYPE_ALLOCATED; + } + } + break; + + case SFileMpqHiBlockTableOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->HiBlockTablePos64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHiBlockTableSize64: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->HiBlockTableSize64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHiBlockTable: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(ha->pHeader->HiBlockTablePos64 && ha->pHeader->HiBlockTableSize64) + { + assert(false); + } + } + break; + +#ifdef FULL + case SFileMpqSignatures: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL && QueryMpqSignatureInfo(ha, &SignatureInfo)) + { + pvSrcFileInfo = &SignatureInfo.SignatureTypes; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqStrongSignatureOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) + { + pvSrcFileInfo = &SignatureInfo.EndMpqData; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + } + break; + + case SFileMpqStrongSignatureSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) + { + dwInt32Value = MPQ_STRONG_SIGNATURE_SIZE + 4; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + } + break; + + case SFileMpqStrongSignature: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) + { + pvSrcFileInfo = SignatureInfo.Signature; + cbSrcFileInfo = MPQ_STRONG_SIGNATURE_SIZE + 4; + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + } + break; +#endif + + case SFileMpqArchiveSize64: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->ArchiveSize64; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqArchiveSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->dwArchiveSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqMaxFileCount: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->dwMaxFileCount; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqFileTableSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->dwFileTableSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqSectorSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->dwSectorSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqNumberOfFiles: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + dwInt32Value = GetMpqFileCount(ha); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqRawChunkSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(ha->pHeader->dwRawChunkSize != 0) + { + pvSrcFileInfo = &ha->pHeader->dwRawChunkSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + } + break; + + case SFileMpqStreamFlags: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + FileStream_GetFlags(ha->pStream, &dwInt32Value); + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqFlags: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + dwInt32Value = ha->dwFlags; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoPatchChain: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL) + return GetFilePatchChain(hf, pvFileInfo, cbFileInfo, pcbLengthNeeded); + break; + + case SFileInfoFileEntry: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = pFileEntry = hf->pFileEntry; + cbSrcFileInfo = sizeof(TFileEntry); + if(pFileEntry->szFileName != NULL) + cbSrcFileInfo += (DWORD)strlen(pFileEntry->szFileName) + 1; + nInfoType = SFILE_INFO_TYPE_FILE_ENTRY; + } + break; + + case SFileInfoHashEntry: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pHashEntry != NULL) + { + pvSrcFileInfo = hf->pHashEntry; + cbSrcFileInfo = sizeof(TMPQHash); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoHashIndex: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pHashEntry != NULL) + { + pvSrcFileInfo = &hf->dwHashIndex; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoNameHash1: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pHashEntry != NULL) + { + dwInt32Value = hf->pHashEntry->dwName1; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoNameHash2: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pHashEntry != NULL) + { + dwInt32Value = hf->pHashEntry->dwName2; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoNameHash3: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->FileNameHash; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoLocale: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pHashEntry != NULL) + { + dwInt32Value = hf->pHashEntry->lcLocale; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoFileIndex: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->ha != NULL && hf->pFileEntry != NULL) + { + dwInt32Value = (DWORD)(hf->pFileEntry - hf->ha->pFileTable); + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoByteOffset: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->ByteOffset; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoFileTime: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->FileTime; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoFileSize: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->dwFileSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoCompressedSize: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->dwCmpSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoFlags: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->dwFlags; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoEncryptionKey: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL) + { + pvSrcFileInfo = &hf->dwFileKey; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoEncryptionKeyRaw: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + dwInt32Value = hf->dwFileKey; + if(hf->pFileEntry->dwFlags & MPQ_FILE_FIX_KEY) + dwInt32Value = (dwInt32Value ^ hf->pFileEntry->dwFileSize) - (DWORD)hf->MpqFilePos; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoCRC32: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + dwInt32Value = hf->pFileEntry->dwCrc32; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + default: // Invalid info class + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // If we validated the handle and info class, give as much info as possible + if(nInfoType >= SFILE_INFO_TYPE_DIRECT_POINTER) + { + // Give the length needed, if wanted + if(pcbLengthNeeded != NULL) + pcbLengthNeeded[0] = cbSrcFileInfo; + + // If the caller entered an output buffer, the output size must also be entered + if(pvFileInfo != NULL && cbFileInfo != 0) + { + // Check if there is enough space in the output buffer + if(cbSrcFileInfo <= cbFileInfo) + { + switch(nInfoType) + { + case SFILE_INFO_TYPE_DIRECT_POINTER: + case SFILE_INFO_TYPE_ALLOCATED: + assert(pvSrcFileInfo != NULL); + memcpy(pvFileInfo, pvSrcFileInfo, cbSrcFileInfo); + break; + + case SFILE_INFO_TYPE_READ_FROM_FILE: + if(!FileStream_Read(ha->pStream, &ByteOffset, pvFileInfo, cbSrcFileInfo)) + nError = GetLastError(); + break; + + case SFILE_INFO_TYPE_TABLE_POINTER: + assert(pvSrcFileInfo != NULL); + *(void **)pvFileInfo = pvSrcFileInfo; + pvSrcFileInfo = NULL; + break; + + case SFILE_INFO_TYPE_FILE_ENTRY: + assert(pFileEntry != NULL); + ConvertFileEntryToSelfRelative((TFileEntry *)pvFileInfo, pFileEntry); + break; + } + } + else + { + nError = ERROR_INSUFFICIENT_BUFFER; + } + } + + // Free the file info if needed + if(nInfoType == SFILE_INFO_TYPE_ALLOCATED && pvSrcFileInfo != NULL) + STORM_FREE(pvSrcFileInfo); +#ifdef FULL + if(nInfoType == SFILE_INFO_TYPE_TABLE_POINTER && pvSrcFileInfo != NULL) + SFileFreeFileInfo(pvSrcFileInfo, InfoClass); +#endif + } + else + { + // Handle error cases + if(nInfoType == SFILE_INFO_TYPE_INVALID_HANDLE) + nError = ERROR_INVALID_HANDLE; + if(nInfoType == SFILE_INFO_TYPE_NOT_FOUND) + nError = ERROR_FILE_NOT_FOUND; + } + + // Set the last error value, if needed + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +#ifdef FULL +bool WINAPI SFileFreeFileInfo(void * pvFileInfo, SFileInfoClass InfoClass) +{ + switch(InfoClass) + { + case SFileMpqHetTable: + FreeHetTable((TMPQHetTable *)pvFileInfo); + return true; + + case SFileMpqBetTable: + FreeBetTable((TMPQBetTable *)pvFileInfo); + return true; + + default: + break; + } + + SetLastError(ERROR_INVALID_PARAMETER); + return false; +} +#endif + +//----------------------------------------------------------------------------- +// Tries to retrieve the file name + +struct TFileHeader2Ext +{ + DWORD dwOffset00Data; // Required data at offset 00 (32-bits) + DWORD dwOffset00Mask; // Mask for data at offset 00 (32 bits). 0 = data are ignored + DWORD dwOffset04Data; // Required data at offset 04 (32-bits) + DWORD dwOffset04Mask; // Mask for data at offset 04 (32 bits). 0 = data are ignored + const char * szExt; // Supplied extension, if the condition is true +}; + +static TFileHeader2Ext data2ext[] = +{ + {0x00005A4D, 0x0000FFFF, 0x00000000, 0x00000000, "exe"}, // EXE files + {0x00000006, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, "dc6"}, // EXE files + {0x1A51504D, 0xFFFFFFFF, 0x00000000, 0x00000000, "mpq"}, // MPQ archive header ID ('MPQ\x1A') + {0x46464952, 0xFFFFFFFF, 0x00000000, 0x00000000, "wav"}, // WAVE header 'RIFF' + {0x324B4D53, 0xFFFFFFFF, 0x00000000, 0x00000000, "smk"}, // Old "Smacker Video" files 'SMK2' + {0x694B4942, 0xFFFFFFFF, 0x00000000, 0x00000000, "bik"}, // Bink video files (new) + {0x0801050A, 0xFFFFFFFF, 0x00000000, 0x00000000, "pcx"}, // PCX images used in Diablo I + {0x544E4F46, 0xFFFFFFFF, 0x00000000, 0x00000000, "fnt"}, // Font files used in Diablo II + {0x6D74683C, 0xFFFFFFFF, 0x00000000, 0x00000000, "html"}, // HTML 'ha->pFileTable), data2ext[i].szExt); + + // Save the pseudo-name in the file entry as well + AllocateFileName(hf->ha, pFileEntry, szPseudoName); + + // If the caller wants to copy the file name, do it + if(szFileName != NULL) + strcpy(szFileName, szPseudoName); + return ERROR_SUCCESS; + } + } + } + + return ERROR_CAN_NOT_COMPLETE; +} + +bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName) +{ + TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle + int nError = ERROR_INVALID_HANDLE; + + // Check valid parameters + if(IsValidFileHandle(hFile)) + { + TFileEntry * pFileEntry = hf->pFileEntry; + + // For MPQ files, retrieve the file name from the file entry + if(hf->pStream == NULL) + { + if(pFileEntry != NULL) + { + // If the file name is not there yet, create a pseudo name + if(pFileEntry->szFileName == NULL) + nError = CreatePseudoFileName(hFile, pFileEntry, szFileName); + + // Copy the file name to the output buffer, if any + if(pFileEntry->szFileName && szFileName) + { + strcpy(szFileName, pFileEntry->szFileName); + nError = ERROR_SUCCESS; + } + } + } + + // For local files, copy the file name from the stream + else + { + if(szFileName != NULL) + { + const TCHAR * szStreamName = FileStream_GetFileName(hf->pStream); + StringCopy(szFileName, MAX_PATH, szStreamName); + } + nError = ERROR_SUCCESS; + } + } + + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + diff --git a/3rdParty/StormLib/src/SFileOpenArchive.cpp b/3rdParty/StormLib/src/SFileOpenArchive.cpp new file mode 100644 index 000000000..1afaf5d4a --- /dev/null +++ b/3rdParty/StormLib/src/SFileOpenArchive.cpp @@ -0,0 +1,618 @@ +/*****************************************************************************/ +/* SFileOpenArchive.cpp Copyright Ladislav Zezula 1999 */ +/* */ +/* Author : Ladislav Zezula */ +/* E-mail : ladik@zezula.net */ +/* WWW : www.zezula.net */ +/*---------------------------------------------------------------------------*/ +/* Archive functions of Storm.dll */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.xx 1.00 Lad The first version of SFileOpenArchive.cpp */ +/* 19.11.03 1.01 Dan Big endian handling */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +#define HEADER_SEARCH_BUFFER_SIZE 0x1000 + +/*****************************************************************************/ +/* Local functions */ +/*****************************************************************************/ + +static bool IsAviFile(DWORD * HeaderData) +{ + DWORD DwordValue0 = BSWAP_INT32_UNSIGNED(HeaderData[0]); + DWORD DwordValue2 = BSWAP_INT32_UNSIGNED(HeaderData[2]); + DWORD DwordValue3 = BSWAP_INT32_UNSIGNED(HeaderData[3]); + + // Test for 'RIFF', 'AVI ' or 'LIST' + return (DwordValue0 == 0x46464952 && DwordValue2 == 0x20495641 && DwordValue3 == 0x5453494C); +} + +static bool IsWarcraft3Map(DWORD * HeaderData) +{ + DWORD DwordValue0 = BSWAP_INT32_UNSIGNED(HeaderData[0]); + DWORD DwordValue1 = BSWAP_INT32_UNSIGNED(HeaderData[1]); + + return (DwordValue0 == 0x57334D48 && DwordValue1 == 0x00000000); +} + +static TMPQUserData * IsValidMpqUserData(ULONGLONG ByteOffset, ULONGLONG FileSize, void * pvUserData) +{ + TMPQUserData * pUserData; + + // BSWAP the source data and copy them to our buffer + BSWAP_ARRAY32_UNSIGNED(&pvUserData, sizeof(TMPQUserData)); + pUserData = (TMPQUserData *)pvUserData; + + // Check the sizes + if(pUserData->cbUserDataHeader <= pUserData->cbUserDataSize && pUserData->cbUserDataSize <= pUserData->dwHeaderOffs) + { + // Move to the position given by the userdata + ByteOffset += pUserData->dwHeaderOffs; + + // The MPQ header should be within range of the file size + if((ByteOffset + MPQ_HEADER_SIZE_V1) < FileSize) + { + // Note: We should verify if there is the MPQ header. + // However, the header could be at any position below that + // that is multiplier of 0x200 + return (TMPQUserData *)pvUserData; + } + } + + return NULL; +} + +// This function gets the right positions of the hash table and the block table. +static int VerifyMpqTablePositions(TMPQArchive * ha, ULONGLONG FileSize) +{ + TMPQHeader * pHeader = ha->pHeader; + ULONGLONG ByteOffset; + + // Check the begin of HET table + if(pHeader->HetTablePos64) + { + ByteOffset = ha->MpqPos + pHeader->HetTablePos64; + if(ByteOffset > FileSize) + return ERROR_BAD_FORMAT; + } + + // Check the begin of BET table + if(pHeader->BetTablePos64) + { + ByteOffset = ha->MpqPos + pHeader->BetTablePos64; + if(ByteOffset > FileSize) + return ERROR_BAD_FORMAT; + } + + // Check the begin of hash table + if(pHeader->wHashTablePosHi || pHeader->dwHashTablePos) + { + ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos)); + if(ByteOffset > FileSize) + return ERROR_BAD_FORMAT; + } + + // Check the begin of block table + if(pHeader->wBlockTablePosHi || pHeader->dwBlockTablePos) + { + ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos)); + if(ByteOffset > FileSize) + return ERROR_BAD_FORMAT; + } + + // Check the begin of hi-block table + if(pHeader->HiBlockTablePos64 != 0) + { + ByteOffset = ha->MpqPos + pHeader->HiBlockTablePos64; + if(ByteOffset > FileSize) + return ERROR_BAD_FORMAT; + } + + // All OK. + return ERROR_SUCCESS; +} + + +/*****************************************************************************/ +/* Public functions */ +/*****************************************************************************/ + +//----------------------------------------------------------------------------- +// SFileGetLocale and SFileSetLocale +// Set the locale for all newly opened files + +LCID WINAPI SFileGetLocale() +{ + return lcFileLocale; +} + +LCID WINAPI SFileSetLocale(LCID lcNewLocale) +{ + lcFileLocale = lcNewLocale; + return lcFileLocale; +} + +//----------------------------------------------------------------------------- +// SFileOpenArchive +// +// szFileName - MPQ archive file name to open +// dwPriority - When SFileOpenFileEx called, this contains the search priority for searched archives +// dwFlags - See MPQ_OPEN_XXX in StormLib.h +// phMpq - Pointer to store open archive handle + +bool WINAPI SFileOpenArchive( + const TCHAR * szMpqName, + DWORD dwPriority, + DWORD dwFlags, + HANDLE * phMpq) +{ + TMPQUserData * pUserData; + TFileStream * pStream = NULL; // Open file stream + TMPQArchive * ha = NULL; // Archive handle + TFileEntry * pFileEntry; + ULONGLONG FileSize = 0; // Size of the file + LPBYTE pbHeaderBuffer = NULL; // Buffer for searching MPQ header + DWORD dwStreamFlags = (dwFlags & STREAM_FLAGS_MASK); + bool bIsWarcraft3Map = false; + int nError = ERROR_SUCCESS; + + // Verify the parameters + if(szMpqName == NULL || *szMpqName == 0 || phMpq == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // One time initialization of MPQ cryptography + InitializeMpqCryptography(); + dwPriority = dwPriority; + + // If not forcing MPQ v 1.0, also use file bitmap + dwStreamFlags |= (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) ? 0 : STREAM_FLAG_USE_BITMAP; + +#ifndef FULL + char translatedName[260]; + TranslateFileName(translatedName, sizeof(translatedName), szMpqName); +#endif + + // Open the MPQ archive file + pStream = FileStream_OpenFile(translatedName, dwStreamFlags); + if(pStream == NULL) + return false; + + // Check the file size. There must be at least 0x20 bytes + if(nError == ERROR_SUCCESS) + { + FileStream_GetSize(pStream, &FileSize); + if(FileSize < MPQ_HEADER_SIZE_V1) + nError = ERROR_BAD_FORMAT; + } + + // Allocate the MPQhandle + if(nError == ERROR_SUCCESS) + { + if((ha = STORM_ALLOC(TMPQArchive, 1)) == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Allocate buffer for searching MPQ header + if(nError == ERROR_SUCCESS) + { + pbHeaderBuffer = STORM_ALLOC(BYTE, HEADER_SEARCH_BUFFER_SIZE); + if(pbHeaderBuffer == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Find the position of MPQ header + if(nError == ERROR_SUCCESS) + { + ULONGLONG SearchOffset = 0; + ULONGLONG EndOfSearch = FileSize; + DWORD dwStrmFlags = 0; + DWORD dwHeaderSize; + DWORD dwHeaderID; + bool bSearchComplete = false; + + memset(ha, 0, sizeof(TMPQArchive)); + ha->pfnHashString = HashStringSlash; + ha->pStream = pStream; + pStream = NULL; + + // Set the archive read only if the stream is read-only + FileStream_GetFlags(ha->pStream, &dwStrmFlags); + ha->dwFlags |= (dwStrmFlags & STREAM_FLAG_READ_ONLY) ? MPQ_FLAG_READ_ONLY : 0; + + // Also remember if we shall check sector CRCs when reading file + ha->dwFlags |= (dwFlags & MPQ_OPEN_CHECK_SECTOR_CRC) ? MPQ_FLAG_CHECK_SECTOR_CRC : 0; + + // Also remember if this MPQ is a patch + ha->dwFlags |= (dwFlags & MPQ_OPEN_PATCH) ? MPQ_FLAG_PATCH : 0; + + // Limit the header searching to about 130 MB of data + if(EndOfSearch > 0x08000000) + EndOfSearch = 0x08000000; + + // Find the offset of MPQ header within the file + while(bSearchComplete == false && SearchOffset < EndOfSearch) + { + // Always read at least 0x1000 bytes for performance. + // This is what Storm.dll (2002) does. + DWORD dwBytesAvailable = HEADER_SEARCH_BUFFER_SIZE; + DWORD dwInBufferOffset = 0; + + // Cut the bytes available, if needed + if((FileSize - SearchOffset) < HEADER_SEARCH_BUFFER_SIZE) + dwBytesAvailable = (DWORD)(FileSize - SearchOffset); + + // Read the eventual MPQ header + if(!FileStream_Read(ha->pStream, &SearchOffset, pbHeaderBuffer, dwBytesAvailable)) + { + nError = GetLastError(); + break; + } + + // There are AVI files from Warcraft III with 'MPQ' extension. + if(SearchOffset == 0) + { + if(IsAviFile((DWORD *)pbHeaderBuffer)) + { + nError = ERROR_AVI_FILE; + break; + } + + bIsWarcraft3Map = IsWarcraft3Map((DWORD *)pbHeaderBuffer); + } + + // Search the header buffer + while(dwInBufferOffset < dwBytesAvailable) + { + // Copy the data from the potential header buffer to the MPQ header + memcpy(ha->HeaderData, pbHeaderBuffer + dwInBufferOffset, sizeof(ha->HeaderData)); + + // If there is the MPQ user data, process it + // Note that Warcraft III does not check for user data, which is abused by many map protectors + dwHeaderID = BSWAP_INT32_UNSIGNED(ha->HeaderData[0]); + if(bIsWarcraft3Map == false && (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0) + { + if(ha->pUserData == NULL && dwHeaderID == ID_MPQ_USERDATA) + { + // Verify if this looks like a valid user data + pUserData = IsValidMpqUserData(SearchOffset, FileSize, ha->HeaderData); + if(pUserData != NULL) + { + // Fill the user data header + ha->UserDataPos = SearchOffset; + ha->pUserData = &ha->UserData; + memcpy(ha->pUserData, pUserData, sizeof(TMPQUserData)); + + // Continue searching from that position + SearchOffset += ha->pUserData->dwHeaderOffs; + break; + } + } + } + + // There must be MPQ header signature. Note that STORM.dll from Warcraft III actually + // tests the MPQ header size. It must be at least 0x20 bytes in order to load it + // Abused by Spazzler Map protector. Note that the size check is not present + // in Storm.dll v 1.00, so Diablo I code would load the MPQ anyway. + dwHeaderSize = BSWAP_INT32_UNSIGNED(ha->HeaderData[1]); + if(dwHeaderID == ID_MPQ && dwHeaderSize >= MPQ_HEADER_SIZE_V1) + { + // Now convert the header to version 4 + nError = ConvertMpqHeaderToFormat4(ha, SearchOffset, FileSize, dwFlags, bIsWarcraft3Map); + bSearchComplete = true; + break; + } + + // Check for MPK archives (Longwu Online - MPQ fork) + if(bIsWarcraft3Map == false && dwHeaderID == ID_MPK) + { + // Now convert the MPK header to MPQ Header version 4 + nError = ConvertMpkHeaderToFormat4(ha, FileSize, dwFlags); + bSearchComplete = true; + break; + } + + // If searching for the MPQ header is disabled, return an error + if(dwFlags & MPQ_OPEN_NO_HEADER_SEARCH) + { + nError = ERROR_NOT_SUPPORTED; + bSearchComplete = true; + break; + } + + // Move the pointers + SearchOffset += 0x200; + dwInBufferOffset += 0x200; + } + } + + // Did we identify one of the supported headers? + if(nError == ERROR_SUCCESS) + { + // Set the user data position to the MPQ header, if none + if(ha->pUserData == NULL) + ha->UserDataPos = SearchOffset; + + // Set the position of the MPQ header + ha->pHeader = (TMPQHeader *)ha->HeaderData; + ha->MpqPos = SearchOffset; + ha->FileSize = FileSize; + + // Sector size must be nonzero. + if(SearchOffset >= FileSize || ha->pHeader->wSectorSize == 0) + nError = ERROR_BAD_FORMAT; + } + } + + // Fix table positions according to format + if(nError == ERROR_SUCCESS) + { + // Dump the header +// DumpMpqHeader(ha->pHeader); + + // W3x Map Protectors use the fact that War3's Storm.dll ignores the MPQ user data, + // and ignores the MPQ format version as well. The trick is to + // fake MPQ format 2, with an improper hi-word position of hash table and block table + // We can overcome such protectors by forcing opening the archive as MPQ v 1.0 + if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1) + { + ha->pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1; + ha->pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1; + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + ha->pUserData = NULL; + } + + // Anti-overflow. If the hash table size in the header is + // higher than 0x10000000, it would overflow in 32-bit version + // Observed in the malformed Warcraft III maps + // Example map: MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x + ha->pHeader->dwBlockTableSize = (ha->pHeader->dwBlockTableSize & BLOCK_INDEX_MASK); + ha->pHeader->dwHashTableSize = (ha->pHeader->dwHashTableSize & BLOCK_INDEX_MASK); + + // Both MPQ_OPEN_NO_LISTFILE or MPQ_OPEN_NO_ATTRIBUTES trigger read only mode + if(dwFlags & (MPQ_OPEN_NO_LISTFILE | MPQ_OPEN_NO_ATTRIBUTES)) + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + + // Remember whether whis is a map for Warcraft III + if(bIsWarcraft3Map) + ha->dwFlags |= MPQ_FLAG_WAR3_MAP; + + // Set the size of file sector + ha->dwSectorSize = (0x200 << ha->pHeader->wSectorSize); + + // Verify if any of the tables doesn't start beyond the end of the file + nError = VerifyMpqTablePositions(ha, FileSize); + } + + // Read the hash table. Ignore the result, as hash table is no longer required + // Read HET table. Ignore the result, as HET table is no longer required + if(nError == ERROR_SUCCESS) + { + nError = LoadAnyHashTable(ha); + } + + // Now, build the file table. It will be built by combining + // the block table, BET table, hi-block table, (attributes) and (listfile). + if(nError == ERROR_SUCCESS) + { + nError = BuildFileTable(ha); + } + +#ifdef FULL + // Load the internal listfile and include it to the file table + if(nError == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_LISTFILE) == 0) + { + // Quick check for (listfile) + pFileEntry = GetFileEntryLocale(ha, LISTFILE_NAME, LANG_NEUTRAL); + if(pFileEntry != NULL) + { + // Ignore result of the operation. (listfile) is optional. + SFileAddListFile((HANDLE)ha, NULL); + ha->dwFileFlags1 = pFileEntry->dwFlags; + } + } + + // Load the "(attributes)" file and merge it to the file table + if(nError == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_ATTRIBUTES) == 0 && (ha->dwFlags & MPQ_FLAG_BLOCK_TABLE_CUT) == 0) + { + // Quick check for (attributes) + pFileEntry = GetFileEntryLocale(ha, ATTRIBUTES_NAME, LANG_NEUTRAL); + if(pFileEntry != NULL) + { + // Ignore result of the operation. (attributes) is optional. + SAttrLoadAttributes(ha); + ha->dwFileFlags2 = pFileEntry->dwFlags; + } + } +#endif + + // Remember whether the archive has weak signature. Only for MPQs format 1.0. + if(nError == ERROR_SUCCESS) + { + // Quick check for (signature) + pFileEntry = GetFileEntryLocale(ha, SIGNATURE_NAME, LANG_NEUTRAL); + if(pFileEntry != NULL) + { + // Just remember that the archive is weak-signed + assert((pFileEntry->dwFlags & MPQ_FILE_EXISTS) != 0); + ha->dwFileFlags3 = pFileEntry->dwFlags; + } + + // Finally, set the MPQ_FLAG_READ_ONLY if the MPQ was found malformed + ha->dwFlags |= (ha->dwFlags & MPQ_FLAG_MALFORMED) ? MPQ_FLAG_READ_ONLY : 0; + } + + // Cleanup and exit + if(nError != ERROR_SUCCESS) + { + FileStream_Close(pStream); + FreeArchiveHandle(ha); + SetLastError(nError); + ha = NULL; + } + + // Free the header buffer + if(pbHeaderBuffer != NULL) + STORM_FREE(pbHeaderBuffer); + if(phMpq != NULL) + *phMpq = ha; + return (nError == ERROR_SUCCESS); +} + + +#ifdef FULL +//----------------------------------------------------------------------------- +// bool WINAPI SFileSetDownloadCallback(HANDLE, SFILE_DOWNLOAD_CALLBACK, void *); +// +// Sets a callback that is called when content is downloaded from the master MPQ +// + +bool WINAPI SFileSetDownloadCallback(HANDLE hMpq, SFILE_DOWNLOAD_CALLBACK DownloadCB, void * pvUserData) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + + // Do nothing if 'hMpq' is bad parameter + if(!IsValidMpqHandle(hMpq)) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + return FileStream_SetCallback(ha->pStream, DownloadCB, pvUserData); +} + +//----------------------------------------------------------------------------- +// bool SFileFlushArchive(HANDLE hMpq) +// +// Saves all dirty data into MPQ archive. +// Has similar effect like SFileCloseArchive, but the archive is not closed. +// Use on clients who keep MPQ archive open even for write operations, +// and terminating without calling SFileCloseArchive might corrupt the archive. +// + +bool WINAPI SFileFlushArchive(HANDLE hMpq) +{ + TMPQArchive * ha; + int nResultError = ERROR_SUCCESS; + int nError; + + // Do nothing if 'hMpq' is bad parameter + if((ha = IsValidMpqHandle(hMpq)) == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + // Only if the MPQ was changed + if(ha->dwFlags & MPQ_FLAG_CHANGED) + { + // Indicate that we are saving MPQ internal structures + ha->dwFlags |= MPQ_FLAG_SAVING_TABLES; + + // Defragment the file table. This will allow us to put the internal files to the end + DefragmentFileTable(ha); + + // + // Create each internal file + // Note that the (signature) file is usually before (listfile) in the file table + // + + if(ha->dwFlags & MPQ_FLAG_SIGNATURE_NEW) + { +#ifdef FULL + nError = SSignFileCreate(ha); + if(nError != ERROR_SUCCESS) + nResultError = nError; +#else + assert(0); +#endif + } + + if(ha->dwFlags & MPQ_FLAG_LISTFILE_NEW) + { + nError = SListFileSaveToMpq(ha); + if(nError != ERROR_SUCCESS) + nResultError = nError; + } + + if(ha->dwFlags & MPQ_FLAG_ATTRIBUTES_NEW) + { + nError = SAttrFileSaveToMpq(ha); + if(nError != ERROR_SUCCESS) + nResultError = nError; + } + + // Save HET table, BET table, hash table, block table, hi-block table + if(ha->dwFlags & MPQ_FLAG_CHANGED) + { + // Rebuild the HET table + if(ha->pHetTable != NULL) + RebuildHetTable(ha); + + // Save all MPQ tables first + nError = SaveMPQTables(ha); + if(nError != ERROR_SUCCESS) + nResultError = nError; + + // If the archive has weak signature, we need to finish it + if(ha->dwFileFlags3 != 0) + { +#ifdef FULL + nError = SSignFileFinish(ha); + if(nError != ERROR_SUCCESS) + nResultError = nError; +#else + assert(0); +#endif + } + } + + // We are no longer saving internal MPQ structures + ha->dwFlags &= ~MPQ_FLAG_SAVING_TABLES; + } + + // Return the error + if(nResultError != ERROR_SUCCESS) + SetLastError(nResultError); + return (nResultError == ERROR_SUCCESS); +} +#endif + +//----------------------------------------------------------------------------- +// bool SFileCloseArchive(HANDLE hMpq); +// + +bool WINAPI SFileCloseArchive(HANDLE hMpq) +{ + TMPQArchive * ha = IsValidMpqHandle(hMpq); + bool bResult = true; + + // Only if the handle is valid + if(ha == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + // Invalidate the add file callback so it won't be called + // when saving (listfile) and (attributes) + ha->pfnAddFileCB = NULL; + ha->pvAddFileUserData = NULL; + +#ifdef FULL + // Flush all unsaved data to the storage + bResult = SFileFlushArchive(hMpq); +#endif + + // Free all memory used by MPQ archive + FreeArchiveHandle(ha); + return bResult; +} diff --git a/3rdParty/StormLib/src/SFileOpenFileEx.cpp b/3rdParty/StormLib/src/SFileOpenFileEx.cpp new file mode 100644 index 000000000..c85eb7a58 --- /dev/null +++ b/3rdParty/StormLib/src/SFileOpenFileEx.cpp @@ -0,0 +1,398 @@ +/*****************************************************************************/ +/* SFileOpenFileEx.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Description : */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.99 1.00 Lad The first version of SFileOpenFileEx.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +/*****************************************************************************/ +/* Local functions */ +/*****************************************************************************/ + +static DWORD FindHashIndex(TMPQArchive * ha, DWORD dwFileIndex) +{ + TMPQHash * pHashTableEnd; + TMPQHash * pHash; + DWORD dwFirstIndex = HASH_ENTRY_FREE; + + // Should only be called if the archive has hash table + assert(ha->pHashTable != NULL); + + // Multiple hash table entries can point to the file table entry. + // We need to search all of them + pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; + for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++) + { + if(MPQ_BLOCK_INDEX(pHash) == dwFileIndex) + { + // Duplicate hash entry found + if(dwFirstIndex != HASH_ENTRY_FREE) + return HASH_ENTRY_FREE; + dwFirstIndex = (DWORD)(pHash - ha->pHashTable); + } + } + + // Return the hash table entry index + return dwFirstIndex; +} + +static const char * GetPatchFileName(TMPQArchive * ha, const char * szFileName, char * szBuffer) +{ + TMPQNamePrefix * pPrefix; + + // Are there patches in the current MPQ? + if(ha->dwFlags & MPQ_FLAG_PATCH) + { + // The patch prefix must be already known here + assert(ha->pPatchPrefix != NULL); + pPrefix = ha->pPatchPrefix; + + // The patch name for "OldWorld\\XXX\\YYY" is "Base\\XXX\YYY" + // We need to remove the "OldWorld\\" prefix + if(!_strnicmp(szFileName, "OldWorld\\", 9)) + szFileName += 9; + + // Create the file name from the known patch entry + memcpy(szBuffer, pPrefix->szPatchPrefix, pPrefix->nLength); + strcpy(szBuffer + pPrefix->nLength, szFileName); + szFileName = szBuffer; + } + + return szFileName; +} + +static bool OpenLocalFile(const char * szFileName, HANDLE * PtrFile) +{ + TFileStream * pStream; + TMPQFile * hf = NULL; + TCHAR szFileNameT[MAX_PATH]; + + // Convert the file name to UNICODE (if needed) + StringCopy(szFileNameT, _countof(szFileNameT), szFileName); + + // Open the file and create the TMPQFile structure + pStream = FileStream_OpenFile(szFileNameT, STREAM_FLAG_READ_ONLY); + if(pStream != NULL) + { + // Allocate and initialize file handle + hf = CreateFileHandle(NULL, NULL); + if(hf != NULL) + { + hf->pStream = pStream; + *PtrFile = hf; + return true; + } + else + { + FileStream_Close(pStream); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + } + } + *PtrFile = NULL; + return false; +} + +bool OpenPatchedFile(HANDLE hMpq, const char * szFileName, HANDLE * PtrFile) +{ + TMPQArchive * haBase = NULL; + TMPQArchive * ha = (TMPQArchive *)hMpq; + TFileEntry * pFileEntry; + TMPQFile * hfPatch; // Pointer to patch file + TMPQFile * hfBase = NULL; // Pointer to base open file + TMPQFile * hf = NULL; + HANDLE hPatchFile; + char szNameBuffer[MAX_PATH]; + + // First of all, find the latest archive where the file is in base version + // (i.e. where the original, unpatched version of the file exists) + while(ha != NULL) + { + // If the file is there, then we remember the archive + pFileEntry = GetFileEntryExact(ha, GetPatchFileName(ha, szFileName, szNameBuffer), 0, NULL); + if(pFileEntry != NULL && (pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) + haBase = ha; + + // Move to the patch archive + ha = ha->haPatch; + } + + // If we couldn't find the base file in any of the patches, it doesn't exist + if((ha = haBase) == NULL) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return false; + } + + // Now open the base file + if(SFileOpenFileEx((HANDLE)ha, GetPatchFileName(ha, szFileName, szNameBuffer), SFILE_OPEN_BASE_FILE, (HANDLE *)&hfBase)) + { + // The file must be a base file, i.e. without MPQ_FILE_PATCH_FILE + assert((hfBase->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0); + hf = hfBase; + + // Now open all patches and attach them on top of the base file + for(ha = ha->haPatch; ha != NULL; ha = ha->haPatch) + { + // Prepare the file name with a correct prefix + if(SFileOpenFileEx((HANDLE)ha, GetPatchFileName(ha, szFileName, szNameBuffer), SFILE_OPEN_BASE_FILE, &hPatchFile)) + { + // Remember the new version + hfPatch = (TMPQFile *)hPatchFile; + + // We should not find patch file + assert((hfPatch->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) != 0); + + // Attach the patch to the base file + hf->hfPatch = hfPatch; + hf = hfPatch; + } + } + } + + // Give the updated base MPQ + if(PtrFile != NULL) + *PtrFile = (HANDLE)hfBase; + return (hfBase != NULL); +} + +/*****************************************************************************/ +/* Public functions */ +/*****************************************************************************/ + +//----------------------------------------------------------------------------- +// SFileEnumLocales enums all locale versions within MPQ. +// Functions fills all available language identifiers on a file into the buffer +// pointed by plcLocales. There must be enough entries to copy the localed, +// otherwise the function returns ERROR_INSUFFICIENT_BUFFER. + +int WINAPI SFileEnumLocales( + HANDLE hMpq, + const char * szFileName, + LCID * PtrLocales, + LPDWORD PtrMaxLocales, + DWORD dwSearchScope) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + TMPQHash * pFirstHash; + TMPQHash * pHash; + DWORD dwFileIndex = 0; + DWORD dwMaxLocales; + DWORD dwLocales = 0; + + // Test the parameters + if(!IsValidMpqHandle(hMpq)) + return ERROR_INVALID_HANDLE; + if(szFileName == NULL || *szFileName == 0) + return ERROR_INVALID_PARAMETER; + if(ha->pHashTable == NULL) + return ERROR_NOT_SUPPORTED; + if(PtrMaxLocales == NULL) + return ERROR_INVALID_PARAMETER; + if(IsPseudoFileName(szFileName, &dwFileIndex)) + return ERROR_INVALID_PARAMETER; + + // Keep compiler happy + dwMaxLocales = PtrMaxLocales[0]; + dwSearchScope = dwSearchScope; + + // Parse all files with that name + pFirstHash = pHash = GetFirstHashEntry(ha, szFileName); + while(pHash != NULL) + { + // Put the locales to the buffer + if(PtrLocales != NULL && dwLocales < dwMaxLocales) + *PtrLocales++ = pHash->lcLocale; + dwLocales++; + + // Get the next locale + pHash = GetNextHashEntry(ha, pFirstHash, pHash); + } + + // Give the caller the number of locales and return + PtrMaxLocales[0] = dwLocales; + return (dwLocales <= dwMaxLocales) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER; +} + +//----------------------------------------------------------------------------- +// SFileOpenFileEx +// +// hMpq - Handle of opened MPQ archive +// szFileName - Name of file to open +// dwSearchScope - Where to search +// PtrFile - Pointer to store opened file handle + +bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * PtrFile) +{ + TMPQArchive * ha = IsValidMpqHandle(hMpq); + TFileEntry * pFileEntry = NULL; + TMPQFile * hf = NULL; + DWORD dwHashIndex = HASH_ENTRY_FREE; + DWORD dwFileIndex = 0; + bool bOpenByIndex = false; + int nError = ERROR_SUCCESS; + + // Don't accept NULL pointer to file handle + if(szFileName == NULL || *szFileName == 0) + nError = ERROR_INVALID_PARAMETER; + + // When opening a file from MPQ, the handle must be valid + if(dwSearchScope != SFILE_OPEN_LOCAL_FILE && ha == NULL) + nError = ERROR_INVALID_HANDLE; + + // When not checking for existence, the pointer to file handle must be valid + if(dwSearchScope != SFILE_OPEN_CHECK_EXISTS && PtrFile == NULL) + nError = ERROR_INVALID_PARAMETER; + + // Prepare the file opening + if(nError == ERROR_SUCCESS) + { + switch(dwSearchScope) + { + case SFILE_OPEN_FROM_MPQ: + case SFILE_OPEN_BASE_FILE: + case SFILE_OPEN_CHECK_EXISTS: + + // If this MPQ has no patches, open the file from this MPQ directly + if(ha->haPatch == NULL || dwSearchScope == SFILE_OPEN_BASE_FILE) + { + pFileEntry = GetFileEntryLocale2(ha, szFileName, lcFileLocale, &dwHashIndex); + } + + // If this MPQ is a patched archive, open the file as patched + else + { + return OpenPatchedFile(hMpq, szFileName, PtrFile); + } + break; + + case SFILE_OPEN_ANY_LOCALE: + + // This open option is reserved for opening MPQ internal listfile. + // No argument validation. Tries to open file with neutral locale first, + // then any other available. + pFileEntry = GetFileEntryLocale2(ha, szFileName, 0, &dwHashIndex); + break; + + case SFILE_OPEN_LOCAL_FILE: + + // Open a local file + return OpenLocalFile(szFileName, PtrFile); + + default: + + // Don't accept any other value + nError = ERROR_INVALID_PARAMETER; + break; + } + } + + // Check whether the file really exists in the MPQ + if(nError == ERROR_SUCCESS) + { + if(pFileEntry == NULL || (pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0) + { + // Check the pseudo-file name + if((bOpenByIndex = IsPseudoFileName(szFileName, &dwFileIndex)) == true) + { + // Get the file entry for the file + if(dwFileIndex < ha->dwFileTableSize) + { + pFileEntry = ha->pFileTable + dwFileIndex; + } + } + + nError = ERROR_FILE_NOT_FOUND; + } + + // Ignore unknown loading flags (example: MPQ_2016_v1_WME4_4.w3x) +// if(pFileEntry != NULL && pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS) +// nError = ERROR_NOT_SUPPORTED; + } + + // Did the caller just wanted to know if the file exists? + if(nError == ERROR_SUCCESS && dwSearchScope != SFILE_OPEN_CHECK_EXISTS) + { + // Allocate file handle + hf = CreateFileHandle(ha, pFileEntry); + if(hf != NULL) + + { + + // Get the hash index for the file + if(ha->pHashTable != NULL && dwHashIndex == HASH_ENTRY_FREE) + dwHashIndex = FindHashIndex(ha, dwFileIndex); + if(dwHashIndex != HASH_ENTRY_FREE) + hf->pHashEntry = ha->pHashTable + dwHashIndex; + hf->dwHashIndex = dwHashIndex; + + // If the MPQ has sector CRC enabled, enable if for the file + if(ha->dwFlags & MPQ_FLAG_CHECK_SECTOR_CRC) + hf->bCheckSectorCRCs = true; + + // If we know the real file name, copy it to the file entry + if(bOpenByIndex == false) + { + // If there is no file name yet, allocate it + AllocateFileName(ha, pFileEntry, szFileName); + + // If the file is encrypted, we should detect the file key + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + hf->dwFileKey = DecryptFileKey(szFileName, + pFileEntry->ByteOffset, + pFileEntry->dwFileSize, + pFileEntry->dwFlags); + } + } + } + else + { + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + // Give the file entry + if(PtrFile != NULL) + PtrFile[0] = hf; + + // Return error code + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +//----------------------------------------------------------------------------- +// SFileHasFile +// +// hMpq - Handle of opened MPQ archive +// szFileName - Name of file to look for + +bool WINAPI SFileHasFile(HANDLE hMpq, const char * szFileName) +{ + return SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_CHECK_EXISTS, NULL); +} + +//----------------------------------------------------------------------------- +// bool WINAPI SFileCloseFile(HANDLE hFile); + +bool WINAPI SFileCloseFile(HANDLE hFile) +{ + TMPQFile * hf = (TMPQFile *)hFile; + + if(!IsValidFileHandle(hFile)) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + // Free the structure + FreeFileHandle(hf); + return true; +} diff --git a/3rdParty/StormLib/src/SFileReadFile.cpp b/3rdParty/StormLib/src/SFileReadFile.cpp new file mode 100644 index 000000000..08761cdda --- /dev/null +++ b/3rdParty/StormLib/src/SFileReadFile.cpp @@ -0,0 +1,907 @@ +/*****************************************************************************/ +/* SFileReadFile.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Description : */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.99 1.00 Lad The first version of SFileReadFile.cpp */ +/* 24.03.99 1.00 Lad Added the SFileGetFileInfo function */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local functions + +// hf - MPQ File handle. +// pbBuffer - Pointer to target buffer to store sectors. +// dwByteOffset - Position of sector in the file (relative to file begin) +// dwBytesToRead - Number of bytes to read. Must be multiplier of sector size. +// pdwBytesRead - Stored number of bytes loaded +static int ReadMpqSectors(TMPQFile * hf, LPBYTE pbBuffer, DWORD dwByteOffset, DWORD dwBytesToRead, LPDWORD pdwBytesRead) +{ + ULONGLONG RawFilePos; + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + LPBYTE pbRawSector = NULL; + LPBYTE pbOutSector = pbBuffer; + LPBYTE pbInSector = pbBuffer; + DWORD dwRawBytesToRead; + DWORD dwRawSectorOffset = dwByteOffset; + DWORD dwSectorsToRead = dwBytesToRead / ha->dwSectorSize; + DWORD dwSectorIndex = dwByteOffset / ha->dwSectorSize; + DWORD dwSectorsDone = 0; + DWORD dwBytesRead = 0; + int nError = ERROR_SUCCESS; + + // Note that dwByteOffset must be aligned to size of one sector + // Note that dwBytesToRead must be a multiplier of one sector size + // This is local function, so we won't check if that's true. + // Note that files stored in single units are processed by a separate function + + // If there is not enough bytes remaining, cut dwBytesToRead + if((dwByteOffset + dwBytesToRead) > hf->dwDataSize) + dwBytesToRead = hf->dwDataSize - dwByteOffset; + dwRawBytesToRead = dwBytesToRead; + + // Perform all necessary work to do with compressed files + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + // If the sector positions are not loaded yet, do it + if(hf->SectorOffsets == NULL) + { + nError = AllocateSectorOffsets(hf, true); + if(nError != ERROR_SUCCESS || hf->SectorOffsets == NULL) + return nError; + } + + // If the sector checksums are not loaded yet, load them now. + if(hf->SectorChksums == NULL && (pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) && hf->bLoadedSectorCRCs == false) + { + // + // Sector CRCs is plain crap feature. It is almost never present, + // often it's empty, or the end offset of sector CRCs is zero. + // We only try to load sector CRCs once, and regardless if it fails + // or not, we won't try that again for the given file. + // + + AllocateSectorChecksums(hf, true); + hf->bLoadedSectorCRCs = true; + } + + // TODO: If the raw data MD5s are not loaded yet, load them now + // Only do it if the MPQ is of format 4.0 +// if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_4 && ha->pHeader->dwRawChunkSize != 0) +// { +// nError = AllocateRawMD5s(hf, true); +// if(nError != ERROR_SUCCESS) +// return nError; +// } + + // Assign the temporary buffer as target for read operation + dwRawSectorOffset = hf->SectorOffsets[dwSectorIndex]; + dwRawBytesToRead = hf->SectorOffsets[dwSectorIndex + dwSectorsToRead] - dwRawSectorOffset; + + // If the file is compressed, also allocate secondary buffer + pbInSector = pbRawSector = STORM_ALLOC(BYTE, dwRawBytesToRead); + if(pbRawSector == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Calculate raw file offset where the sector(s) are stored. + RawFilePos = CalculateRawSectorOffset(hf, dwRawSectorOffset); + + // Set file pointer and read all required sectors + if(FileStream_Read(ha->pStream, &RawFilePos, pbInSector, dwRawBytesToRead)) + { + // Now we have to decrypt and decompress all file sectors that have been loaded + for(DWORD i = 0; i < dwSectorsToRead; i++) + { + DWORD dwRawBytesInThisSector = ha->dwSectorSize; + DWORD dwBytesInThisSector = ha->dwSectorSize; + DWORD dwIndex = dwSectorIndex + i; + + // If there is not enough bytes in the last sector, + // cut the number of bytes in this sector + if(dwRawBytesInThisSector > dwBytesToRead) + dwRawBytesInThisSector = dwBytesToRead; + if(dwBytesInThisSector > dwBytesToRead) + dwBytesInThisSector = dwBytesToRead; + + // If the file is compressed, we have to adjust the raw sector size + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + dwRawBytesInThisSector = hf->SectorOffsets[dwIndex + 1] - hf->SectorOffsets[dwIndex]; + + // If the file is encrypted, we have to decrypt the sector + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector); + + // If we don't know the key, try to detect it by file content + if(hf->dwFileKey == 0) + { + hf->dwFileKey = DetectFileKeyByContent(pbInSector, dwBytesInThisSector, hf->dwDataSize); + if(hf->dwFileKey == 0) + { + nError = ERROR_UNKNOWN_FILE_KEY; + break; + } + } + + DecryptMpqBlock(pbInSector, dwRawBytesInThisSector, hf->dwFileKey + dwIndex); + BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector); + } + +#ifdef FULL + // If the file has sector CRC check turned on, perform it + if(hf->bCheckSectorCRCs && hf->SectorChksums != NULL) + { + DWORD dwAdlerExpected = hf->SectorChksums[dwIndex]; + DWORD dwAdlerValue = 0; + + // We can only check sector CRC when it's not zero + // Neither can we check it if it's 0xFFFFFFFF. + if(dwAdlerExpected != 0 && dwAdlerExpected != 0xFFFFFFFF) + { + dwAdlerValue = adler32(0, pbInSector, dwRawBytesInThisSector); + if(dwAdlerValue != dwAdlerExpected) + { + nError = ERROR_CHECKSUM_ERROR; + break; + } + } + } +#endif + + // If the sector is really compressed, decompress it. + // WARNING : Some sectors may not be compressed, it can be determined only + // by comparing uncompressed and compressed size !!! + if(dwRawBytesInThisSector < dwBytesInThisSector) + { + int cbOutSector = dwBytesInThisSector; + int cbInSector = dwRawBytesInThisSector; + int nResult = 0; + + // Is the file compressed by Blizzard's multiple compression ? + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS) + { + // Remember the last used compression + hf->dwCompression0 = pbInSector[0]; + + // Decompress the data + if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2) + nResult = SCompDecompress2(pbOutSector, &cbOutSector, pbInSector, cbInSector); + else + nResult = SCompDecompress(pbOutSector, &cbOutSector, pbInSector, cbInSector); + } + + // Is the file compressed by PKWARE Data Compression Library ? + else if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE) + { + nResult = SCompExplode(pbOutSector, &cbOutSector, pbInSector, cbInSector); + } + + // Did the decompression fail ? + if(nResult == 0) + { + nError = ERROR_FILE_CORRUPT; + break; + } + } + else + { + if(pbOutSector != pbInSector) + memcpy(pbOutSector, pbInSector, dwBytesInThisSector); + } + + // Move pointers + dwBytesToRead -= dwBytesInThisSector; + dwByteOffset += dwBytesInThisSector; + dwBytesRead += dwBytesInThisSector; + pbOutSector += dwBytesInThisSector; + pbInSector += dwRawBytesInThisSector; + dwSectorsDone++; + } + } + else + { + nError = GetLastError(); + } + + // Free all used buffers + if(pbRawSector != NULL) + STORM_FREE(pbRawSector); + + // Give the caller thenumber of bytes read + *pdwBytesRead = dwBytesRead; + return nError; +} + +static int ReadMpqFileSingleUnit(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead) +{ + ULONGLONG RawFilePos = hf->RawFilePos; + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + LPBYTE pbCompressed = NULL; + LPBYTE pbRawData; + int nError = ERROR_SUCCESS; + + // If the file buffer is not allocated yet, do it. + if(hf->pbFileSector == NULL) + { + nError = AllocateSectorBuffer(hf); + if(nError != ERROR_SUCCESS || hf->pbFileSector == NULL) + return nError; + } + + // If the file is a patch file, adjust raw data offset + if(hf->pPatchInfo != NULL) + RawFilePos += hf->pPatchInfo->dwLength; + pbRawData = hf->pbFileSector; + + // If the file sector is not loaded yet, do it + if(hf->dwSectorOffs != 0) + { + // Is the file compressed? + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + // Allocate space for compressed data + pbCompressed = STORM_ALLOC(BYTE, pFileEntry->dwCmpSize); + if(pbCompressed == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + pbRawData = pbCompressed; + } + + // Load the raw (compressed, encrypted) data + if(!FileStream_Read(ha->pStream, &RawFilePos, pbRawData, pFileEntry->dwCmpSize)) + { + STORM_FREE(pbCompressed); + return GetLastError(); + } + + // If the file is encrypted, we have to decrypt the data first + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + BSWAP_ARRAY32_UNSIGNED(pbRawData, pFileEntry->dwCmpSize); + DecryptMpqBlock(pbRawData, pFileEntry->dwCmpSize, hf->dwFileKey); + BSWAP_ARRAY32_UNSIGNED(pbRawData, pFileEntry->dwCmpSize); + } + + // If the file is compressed, we have to decompress it now + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + int cbOutBuffer = (int)hf->dwDataSize; + int cbInBuffer = (int)pFileEntry->dwCmpSize; + int nResult = 0; + + // + // If the file is an incremental patch, the size of compressed data + // is determined as pFileEntry->dwCmpSize - sizeof(TPatchInfo) + // + // In "wow-update-12694.MPQ" from Wow-Cataclysm BETA: + // + // File CmprSize DcmpSize DataSize Compressed? + // -------------------------------------- ---------- -------- -------- --------------- + // esES\DBFilesClient\LightSkyBox.dbc 0xBE->0xA2 0xBC 0xBC Yes + // deDE\DBFilesClient\MountCapability.dbc 0x93->0x77 0x77 0x77 No + // + + if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) + cbInBuffer = cbInBuffer - sizeof(TPatchInfo); + + // Is the file compressed by Blizzard's multiple compression ? + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS) + { + // Remember the last used compression + hf->dwCompression0 = pbRawData[0]; + + // Decompress the file + if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2) + nResult = SCompDecompress2(hf->pbFileSector, &cbOutBuffer, pbRawData, cbInBuffer); + else + nResult = SCompDecompress(hf->pbFileSector, &cbOutBuffer, pbRawData, cbInBuffer); + } + + // Is the file compressed by PKWARE Data Compression Library ? + // Note: Single unit files compressed with IMPLODE are not supported by Blizzard + else if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE) + nResult = SCompExplode(hf->pbFileSector, &cbOutBuffer, pbRawData, cbInBuffer); + + nError = (nResult != 0) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; + } + else + { + if(hf->pbFileSector != NULL && pbRawData != hf->pbFileSector) + memcpy(hf->pbFileSector, pbRawData, hf->dwDataSize); + } + + // Free the decompression buffer. + if(pbCompressed != NULL) + STORM_FREE(pbCompressed); + + // The file sector is now properly loaded + hf->dwSectorOffs = 0; + } + + // At this moment, we have the file loaded into the file buffer. + // Copy as much as the caller wants + if(nError == ERROR_SUCCESS && hf->dwSectorOffs == 0) + { + // File position is greater or equal to file size ? + if(dwFilePos >= hf->dwDataSize) + { + *pdwBytesRead = 0; + return ERROR_SUCCESS; + } + + // If not enough bytes remaining in the file, cut them + if((hf->dwDataSize - dwFilePos) < dwToRead) + dwToRead = (hf->dwDataSize - dwFilePos); + + // Copy the bytes + memcpy(pvBuffer, hf->pbFileSector + dwFilePos, dwToRead); + + // Give the number of bytes read + *pdwBytesRead = dwToRead; + return ERROR_SUCCESS; + } + + // An error, sorry + return ERROR_CAN_NOT_COMPLETE; +} + +static int ReadMpkFileSingleUnit(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead) +{ + ULONGLONG RawFilePos = hf->RawFilePos + 0x0C; // For some reason, MPK files start at position (hf->RawFilePos + 0x0C) + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + LPBYTE pbCompressed = NULL; + LPBYTE pbRawData = hf->pbFileSector; + int nError = ERROR_SUCCESS; + + // We do not support patch files in MPK archives + assert(hf->pPatchInfo == NULL); + + // If the file buffer is not allocated yet, do it. + if(hf->pbFileSector == NULL) + { + nError = AllocateSectorBuffer(hf); + if(nError != ERROR_SUCCESS || hf->pbFileSector == NULL) + return nError; + pbRawData = hf->pbFileSector; + } + + // If the file sector is not loaded yet, do it + if(hf->dwSectorOffs != 0) + { + // Is the file compressed? + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + // Allocate space for compressed data + pbCompressed = STORM_ALLOC(BYTE, pFileEntry->dwCmpSize); + if(pbCompressed == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + pbRawData = pbCompressed; + } + + // Load the raw (compressed, encrypted) data + if(!FileStream_Read(ha->pStream, &RawFilePos, pbRawData, pFileEntry->dwCmpSize)) + { + STORM_FREE(pbCompressed); + return GetLastError(); + } + + // If the file is encrypted, we have to decrypt the data first + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + DecryptMpkTable(pbRawData, pFileEntry->dwCmpSize); + } + + // If the file is compressed, we have to decompress it now + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { +#ifdef FULL + int cbOutBuffer = (int)hf->dwDataSize; + + hf->dwCompression0 = pbRawData[0]; + if(!SCompDecompressMpk(hf->pbFileSector, &cbOutBuffer, pbRawData, (int)pFileEntry->dwCmpSize)) + nError = ERROR_FILE_CORRUPT; +#else + assert(0); +#endif + } + else + { + if(pbRawData != hf->pbFileSector) + memcpy(hf->pbFileSector, pbRawData, hf->dwDataSize); + } + + // Free the decompression buffer. + if(pbCompressed != NULL) + STORM_FREE(pbCompressed); + + // The file sector is now properly loaded + hf->dwSectorOffs = 0; + } + + // At this moment, we have the file loaded into the file buffer. + // Copy as much as the caller wants + if(nError == ERROR_SUCCESS && hf->dwSectorOffs == 0) + { + // File position is greater or equal to file size ? + if(dwFilePos >= hf->dwDataSize) + { + *pdwBytesRead = 0; + return ERROR_SUCCESS; + } + + // If not enough bytes remaining in the file, cut them + if((hf->dwDataSize - dwFilePos) < dwToRead) + dwToRead = (hf->dwDataSize - dwFilePos); + + // Copy the bytes + memcpy(pvBuffer, hf->pbFileSector + dwFilePos, dwToRead); + + // Give the number of bytes read + *pdwBytesRead = dwToRead; + return ERROR_SUCCESS; + } + + // An error, sorry + return ERROR_CAN_NOT_COMPLETE; +} + + +static int ReadMpqFileSectorFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwBytesToRead, LPDWORD pdwBytesRead) +{ + TMPQArchive * ha = hf->ha; + LPBYTE pbBuffer = (BYTE *)pvBuffer; + DWORD dwTotalBytesRead = 0; // Total bytes read in all three parts + DWORD dwSectorSizeMask = ha->dwSectorSize - 1; // Mask for block size, usually 0x0FFF + DWORD dwFileSectorPos; // File offset of the loaded sector + DWORD dwBytesRead; // Number of bytes read (temporary variable) + int nError; + + // If the file position is at or beyond end of file, do nothing + if(dwFilePos >= hf->dwDataSize) + { + *pdwBytesRead = 0; + return ERROR_SUCCESS; + } + + // If not enough bytes in the file remaining, cut them + if(dwBytesToRead > (hf->dwDataSize - dwFilePos)) + dwBytesToRead = (hf->dwDataSize - dwFilePos); + + // Compute sector position in the file + dwFileSectorPos = dwFilePos & ~dwSectorSizeMask; // Position in the block + + // If the file sector buffer is not allocated yet, do it now + if(hf->pbFileSector == NULL) + { + nError = AllocateSectorBuffer(hf); + if(nError != ERROR_SUCCESS || hf->pbFileSector == NULL) + return nError; + } + + // Load the first (incomplete) file sector + if(dwFilePos & dwSectorSizeMask) + { + DWORD dwBytesInSector = ha->dwSectorSize; + DWORD dwBufferOffs = dwFilePos & dwSectorSizeMask; + DWORD dwToCopy; + + // Is the file sector already loaded ? + if(hf->dwSectorOffs != dwFileSectorPos) + { + // Load one MPQ sector into archive buffer + nError = ReadMpqSectors(hf, hf->pbFileSector, dwFileSectorPos, ha->dwSectorSize, &dwBytesInSector); + if(nError != ERROR_SUCCESS) + return nError; + + // Remember that the data loaded to the sector have new file offset + hf->dwSectorOffs = dwFileSectorPos; + } + else + { + if((dwFileSectorPos + dwBytesInSector) > hf->dwDataSize) + dwBytesInSector = hf->dwDataSize - dwFileSectorPos; + } + + // Copy the data from the offset in the loaded sector to the end of the sector + dwToCopy = dwBytesInSector - dwBufferOffs; + if(dwToCopy > dwBytesToRead) + dwToCopy = dwBytesToRead; + + // Copy data from sector buffer into target buffer + memcpy(pbBuffer, hf->pbFileSector + dwBufferOffs, dwToCopy); + + // Update pointers and byte counts + dwTotalBytesRead += dwToCopy; + dwFileSectorPos += dwBytesInSector; + pbBuffer += dwToCopy; + dwBytesToRead -= dwToCopy; + } + + // Load the whole ("middle") sectors only if there is at least one full sector to be read + if(dwBytesToRead >= ha->dwSectorSize) + { + DWORD dwBlockBytes = dwBytesToRead & ~dwSectorSizeMask; + + // Load all sectors to the output buffer + nError = ReadMpqSectors(hf, pbBuffer, dwFileSectorPos, dwBlockBytes, &dwBytesRead); + if(nError != ERROR_SUCCESS) + return nError; + + // Update pointers + dwTotalBytesRead += dwBytesRead; + dwFileSectorPos += dwBytesRead; + pbBuffer += dwBytesRead; + dwBytesToRead -= dwBytesRead; + } + + // Read the terminating sector + if(dwBytesToRead > 0) + { + DWORD dwToCopy = ha->dwSectorSize; + + // Is the file sector already loaded ? + if(hf->dwSectorOffs != dwFileSectorPos) + { + // Load one MPQ sector into archive buffer + nError = ReadMpqSectors(hf, hf->pbFileSector, dwFileSectorPos, ha->dwSectorSize, &dwBytesRead); + if(nError != ERROR_SUCCESS) + return nError; + + // Remember that the data loaded to the sector have new file offset + hf->dwSectorOffs = dwFileSectorPos; + } + + // Check number of bytes read + if(dwToCopy > dwBytesToRead) + dwToCopy = dwBytesToRead; + + // Copy the data from the cached last sector to the caller's buffer + memcpy(pbBuffer, hf->pbFileSector, dwToCopy); + + // Update pointers + dwTotalBytesRead += dwToCopy; + } + + // Store total number of bytes read to the caller + *pdwBytesRead = dwTotalBytesRead; + return ERROR_SUCCESS; +} + +#ifdef FULL +static int ReadMpqFilePatchFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead) +{ + TMPQPatcher Patcher; + DWORD dwBytesToRead = dwToRead; + DWORD dwBytesRead = 0; + int nError = ERROR_SUCCESS; + + // Make sure that the patch file is loaded completely + if(nError == ERROR_SUCCESS && hf->pbFileData == NULL) + { + // Initialize patching process and allocate data + nError = Patch_InitPatcher(&Patcher, hf); + if(nError != ERROR_SUCCESS) + return nError; + + // Set the current data size + Patcher.cbFileData = hf->pFileEntry->dwFileSize; + + // Initialize the patcher object with initial file data + if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) + nError = ReadMpqFileSingleUnit(hf, Patcher.pbFileData1, 0, Patcher.cbFileData, &dwBytesRead); + else + nError = ReadMpqFileSectorFile(hf, Patcher.pbFileData1, 0, Patcher.cbFileData, &dwBytesRead); + + // Perform the patching process + if(nError == ERROR_SUCCESS) + nError = Patch_Process(&Patcher, hf); + + // Finalize the patcher structure + Patch_Finalize(&Patcher); + dwBytesRead = 0; + } + + // If there is something to read, do it + if(nError == ERROR_SUCCESS) + { + if(dwFilePos < hf->cbFileData) + { + // Make sure we don't copy more than file size + if((dwFilePos + dwToRead) > hf->cbFileData) + dwToRead = hf->cbFileData - dwFilePos; + + // Copy the appropriate amount of the file data to the caller's buffer + memcpy(pvBuffer, hf->pbFileData + dwFilePos, dwToRead); + dwBytesRead = dwToRead; + } + + // Set the proper error code + nError = (dwBytesRead == dwBytesToRead) ? ERROR_SUCCESS : ERROR_HANDLE_EOF; + } + + // Give the result to the caller + if(pdwBytesRead != NULL) + *pdwBytesRead = dwBytesRead; + return nError; +} +#endif + +static int ReadMpqFileLocalFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead) +{ + ULONGLONG FilePosition1 = dwFilePos; + ULONGLONG FilePosition2; + DWORD dwBytesRead = 0; + int nError = ERROR_SUCCESS; + + assert(hf->pStream != NULL); + + // Because stream I/O functions are designed to read + // "all or nothing", we compare file position before and after, + // and if they differ, we assume that number of bytes read + // is the difference between them + + if(!FileStream_Read(hf->pStream, &FilePosition1, pvBuffer, dwToRead)) + { + // If not all bytes have been read, then return the number of bytes read + if((nError = GetLastError()) == ERROR_HANDLE_EOF) + { + FileStream_GetPos(hf->pStream, &FilePosition2); + dwBytesRead = (DWORD)(FilePosition2 - FilePosition1); + } + } + else + { + dwBytesRead = dwToRead; + } + + *pdwBytesRead = dwBytesRead; + return nError; +} + +//----------------------------------------------------------------------------- +// SFileReadFile + +bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped) +{ + TMPQFile * hf = (TMPQFile *)hFile; + DWORD dwBytesRead = 0; // Number of bytes read + int nError = ERROR_SUCCESS; + + // Always zero the result + if(pdwRead != NULL) + *pdwRead = 0; + lpOverlapped = lpOverlapped; + + // Check valid parameters + if(!IsValidFileHandle(hFile)) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + if(pvBuffer == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // If we didn't load the patch info yet, do it now + if(hf->pFileEntry != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) && hf->pPatchInfo == NULL) + { + nError = AllocatePatchInfo(hf, true); + if(nError != ERROR_SUCCESS || hf->pPatchInfo == NULL) + { + SetLastError(nError); + return false; + } + } + + // Clear the last used compression + hf->dwCompression0 = 0; + + // If the file is local file, read the data directly from the stream + if(hf->pStream != NULL) + { + nError = ReadMpqFileLocalFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); + } +#ifdef FULL + // If the file is a patch file, we have to read it special way + else if(hf->hfPatch != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) + { + nError = ReadMpqFilePatchFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); + } +#endif + // If the archive is a MPK archive, we need special way to read the file + else if(hf->ha->dwSubType == MPQ_SUBTYPE_MPK) + { + nError = ReadMpkFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); + } + + // If the file is single unit file, redirect it to read file + else if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) + { + nError = ReadMpqFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); + } + + // Otherwise read it as sector based MPQ file + else + { + nError = ReadMpqFileSectorFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); + } + + // Increment the file position + hf->dwFilePos += dwBytesRead; + + // Give the caller the number of bytes read + if(pdwRead != NULL) + *pdwRead = dwBytesRead; + + // If the read operation succeeded, but not full number of bytes was read, + // set the last error to ERROR_HANDLE_EOF + if(nError == ERROR_SUCCESS && (dwBytesRead < dwToRead)) + nError = ERROR_HANDLE_EOF; + + // If something failed, set the last error value + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +//----------------------------------------------------------------------------- +// SFileGetFileSize + +DWORD WINAPI SFileGetFileSize(HANDLE hFile, LPDWORD pdwFileSizeHigh) +{ + ULONGLONG FileSize; + TMPQFile * hf = (TMPQFile *)hFile; + + // Validate the file handle before we go on + if(IsValidFileHandle(hFile)) + { + // Make sure that the variable is initialized + FileSize = 0; + + // If the file is patched file, we have to get the size of the last version + if(hf->hfPatch != NULL) + { + // Walk through the entire patch chain, take the last version + while(hf != NULL) + { + // Get the size of the currently pointed version + FileSize = hf->pFileEntry->dwFileSize; + + // Move to the next patch file in the hierarchy + hf = hf->hfPatch; + } + } + else + { + // Is it a local file ? + if(hf->pStream != NULL) + { + FileStream_GetSize(hf->pStream, &FileSize); + } + else + { + FileSize = hf->dwDataSize; + } + } + + // If opened from archive, return file size + if(pdwFileSizeHigh != NULL) + *pdwFileSizeHigh = (DWORD)(FileSize >> 32); + return (DWORD)FileSize; + } + + SetLastError(ERROR_INVALID_HANDLE); + return SFILE_INVALID_SIZE; +} + +DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod) +{ + TMPQFile * hf = (TMPQFile *)hFile; + ULONGLONG OldPosition; + ULONGLONG NewPosition; + ULONGLONG FileSize; + ULONGLONG DeltaPos; + + // If the hFile is not a valid file handle, return an error. + if(!IsValidFileHandle(hFile)) + { + SetLastError(ERROR_INVALID_HANDLE); + return SFILE_INVALID_POS; + } + + // Retrieve the file size for handling the limits + if(hf->pStream != NULL) + { + FileStream_GetSize(hf->pStream, &FileSize); + } + else + { + FileSize = SFileGetFileSize(hFile, NULL); + } + + // Handle the NULL and non-NULL values of plFilePosHigh + // Non-NULL: The DeltaPos is combined from lFilePos and *lpFilePosHigh + // NULL: The DeltaPos is sign-extended value of lFilePos + DeltaPos = (plFilePosHigh != NULL) ? MAKE_OFFSET64(plFilePosHigh[0], lFilePos) : (ULONGLONG)(LONGLONG)lFilePos; + + // Get the relative point where to move from + switch(dwMoveMethod) + { + case FILE_BEGIN: + + // Move relative to the file begin. + OldPosition = 0; + break; + + case FILE_CURRENT: + + // Retrieve the current file position + if(hf->pStream != NULL) + { + FileStream_GetPos(hf->pStream, &OldPosition); + } + else + { + OldPosition = hf->dwFilePos; + } + break; + + case FILE_END: + + // Move relative to the end of the file + OldPosition = FileSize; + break; + + default: + SetLastError(ERROR_INVALID_PARAMETER); + return SFILE_INVALID_POS; + } + + // Calculate the new position + NewPosition = OldPosition + DeltaPos; + + // If moving backward, don't allow the new position go negative + if((LONGLONG)DeltaPos < 0) + { + if(NewPosition > FileSize) // Position is negative + { + SetLastError(ERROR_NEGATIVE_SEEK); + return SFILE_INVALID_POS; + } + } + + // If moving forward, don't allow the new position go past the end of the file + else + { + if(NewPosition > FileSize) + NewPosition = FileSize; + } + + // Now apply the file pointer to the file + if(hf->pStream != NULL) + { + if(!FileStream_Read(hf->pStream, &NewPosition, NULL, 0)) + return SFILE_INVALID_POS; + } + else + { + hf->dwFilePos = (DWORD)NewPosition; + } + + // Return the new file position + if(plFilePosHigh != NULL) + *plFilePosHigh = (LONG)(NewPosition >> 32); + return (DWORD)NewPosition; +} diff --git a/3rdParty/StormLib/src/StormCommon.h b/3rdParty/StormLib/src/StormCommon.h new file mode 100644 index 000000000..928875115 --- /dev/null +++ b/3rdParty/StormLib/src/StormCommon.h @@ -0,0 +1,387 @@ +/*****************************************************************************/ +/* SCommon.h Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Common functions for encryption/decryption from Storm.dll. Included by */ +/* SFile*** functions, do not include and do not use this file directly */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 24.03.03 1.00 Lad The first version of SFileCommon.h */ +/* 12.06.04 1.00 Lad Renamed to SCommon.h */ +/* 06.09.10 1.00 Lad Renamed to StormCommon.h */ +/*****************************************************************************/ + +#ifndef __STORMCOMMON_H__ +#define __STORMCOMMON_H__ + +//----------------------------------------------------------------------------- +// Compression support + +// Include functions from Pkware Data Compression Library +#include "3rdParty/PKWare/pkware.h" + +#ifdef FULL +// Include functions from Huffmann compression +#include "huffman/huff.h" + +// Include functions from IMA ADPCM compression +#include "adpcm/adpcm.h" + +// Include functions from SPARSE compression +#include "sparse/sparse.h" + +// Include functions from LZMA compression +#include "lzma/C/LzmaEnc.h" +#include "lzma/C/LzmaDec.h" + +// Include functions from zlib +#ifndef __SYS_ZLIB + #include "zlib/zlib.h" +#else + #include +#endif + +// Include functions from bzlib +#ifndef __SYS_BZLIB + #include "bzip2/bzlib.h" +#else + #include +#endif + +//----------------------------------------------------------------------------- +// Cryptography support + +// Headers from LibTomCrypt +#include "libtomcrypt/src/headers/tomcrypt.h" + +// For HashStringJenkins +#include "jenkins/lookup.h" +#endif + +//----------------------------------------------------------------------------- +// StormLib private defines + +#define ID_MPQ_FILE 0x46494c45 // Used internally for checking TMPQFile ('FILE') + +// Prevent problems with CRT "min" and "max" functions, +// as they are not defined on all platforms +#define STORMLIB_MIN(a, b) ((a < b) ? a : b) +#define STORMLIB_MAX(a, b) ((a > b) ? a : b) +#define STORMLIB_UNUSED(p) ((void)(p)) + +// Macro for building 64-bit file offset from two 32-bit +#define MAKE_OFFSET64(hi, lo) (((ULONGLONG)hi << 32) | (ULONGLONG)lo) + +//----------------------------------------------------------------------------- +// MPQ signature information + +// Size of each signature type +#define MPQ_WEAK_SIGNATURE_SIZE 64 +#define MPQ_STRONG_SIGNATURE_SIZE 256 +#define MPQ_STRONG_SIGNATURE_ID 0x5349474E // ID of the strong signature ("NGIS") +#define MPQ_SIGNATURE_FILE_SIZE (MPQ_WEAK_SIGNATURE_SIZE + 8) + +// MPQ signature info +typedef struct _MPQ_SIGNATURE_INFO +{ + ULONGLONG BeginMpqData; // File offset where the hashing starts + ULONGLONG BeginExclude; // Begin of the excluded area (used for (signature) file) + ULONGLONG EndExclude; // End of the excluded area (used for (signature) file) + ULONGLONG EndMpqData; // File offset where the hashing ends + ULONGLONG EndOfFile; // Size of the entire file + BYTE Signature[MPQ_STRONG_SIGNATURE_SIZE + 0x10]; + DWORD cbSignatureSize; // Length of the signature + DWORD SignatureTypes; // See SIGNATURE_TYPE_XXX + +} MPQ_SIGNATURE_INFO, *PMPQ_SIGNATURE_INFO; + +//----------------------------------------------------------------------------- +// Memory management +// +// We use our own macros for allocating/freeing memory. If you want +// to redefine them, please keep the following rules: +// +// - The memory allocation must return NULL if not enough memory +// (i.e not to throw exception) +// - The allocating function does not need to fill the allocated buffer with zeros +// - Memory freeing function doesn't have to test the pointer to NULL +// + +//#if defined(_MSC_VER) && defined(_DEBUG) +// +//#define STORM_ALLOC(type, nitems) (type *)HeapAlloc(GetProcessHeap(), 0, ((nitems) * sizeof(type))) +//#define STORM_REALLOC(type, ptr, nitems) (type *)HeapReAlloc(GetProcessHeap(), 0, ptr, ((nitems) * sizeof(type))) +//#define STORM_FREE(ptr) HeapFree(GetProcessHeap(), 0, ptr) +// +//#else + +#define STORM_ALLOC(type, nitems) (type *)malloc((nitems) * sizeof(type)) +#define STORM_REALLOC(type, ptr, nitems) (type *)realloc(ptr, ((nitems) * sizeof(type))) +#define STORM_FREE(ptr) free(ptr) + +//#endif + +//----------------------------------------------------------------------------- +// StormLib internal global variables + +extern LCID lcFileLocale; // Preferred file locale + +//----------------------------------------------------------------------------- +// Conversion to uppercase/lowercase (and "/" to "\") + +extern unsigned char AsciiToLowerTable[256]; +extern unsigned char AsciiToUpperTable[256]; + +//----------------------------------------------------------------------------- +// Safe string functions + +void StringCopy(char * szTarget, size_t cchTarget, const char * szSource); +void StringCat(char * szTarget, size_t cchTargetMax, const char * szSource); + +#ifdef _UNICODE +void StringCopy(TCHAR * szTarget, size_t cchTarget, const char * szSource); +void StringCopy(char * szTarget, size_t cchTarget, const TCHAR * szSource); +void StringCopy(TCHAR * szTarget, size_t cchTarget, const TCHAR * szSource); +void StringCat(TCHAR * szTarget, size_t cchTargetMax, const TCHAR * szSource); +#endif + +//----------------------------------------------------------------------------- +// Encryption and decryption functions + +#define MPQ_HASH_TABLE_INDEX 0x000 +#define MPQ_HASH_NAME_A 0x100 +#define MPQ_HASH_NAME_B 0x200 +#define MPQ_HASH_FILE_KEY 0x300 +#define MPQ_HASH_KEY2_MIX 0x400 + +DWORD HashString(const char * szFileName, DWORD dwHashType); +DWORD HashStringSlash(const char * szFileName, DWORD dwHashType); +DWORD HashStringLower(const char * szFileName, DWORD dwHashType); + +void InitializeMpqCryptography(); + +DWORD GetNearestPowerOfTwo(DWORD dwFileCount); + +bool IsPseudoFileName(const char * szFileName, LPDWORD pdwFileIndex); +ULONGLONG HashStringJenkins(const char * szFileName); + +DWORD GetDefaultSpecialFileFlags(DWORD dwFileSize, USHORT wFormatVersion); + +void EncryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey); +void DecryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey); + +DWORD DetectFileKeyBySectorSize(LPDWORD EncryptedData, DWORD dwSectorSize, DWORD dwSectorOffsLen); +DWORD DetectFileKeyByContent(void * pvEncryptedData, DWORD dwSectorSize, DWORD dwFileSize); +DWORD DecryptFileKey(const char * szFileName, ULONGLONG MpqPos, DWORD dwFileSize, DWORD dwFlags); + +bool IsValidMD5(LPBYTE pbMd5); +bool IsValidSignature(LPBYTE pbSignature); +bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5); +void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash); + +//----------------------------------------------------------------------------- +// Handle validation functions + +TMPQArchive * IsValidMpqHandle(HANDLE hMpq); +TMPQFile * IsValidFileHandle(HANDLE hFile); + +//----------------------------------------------------------------------------- +// Support for MPQ file tables + +ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset); +ULONGLONG CalculateRawSectorOffset(TMPQFile * hf, DWORD dwSectorOffset); + +int ConvertMpqHeaderToFormat4(TMPQArchive * ha, ULONGLONG MpqOffset, ULONGLONG FileSize, DWORD dwFlags, bool bIsWarcraft3Map); + +bool IsValidHashEntry(TMPQArchive * ha, TMPQHash * pHash); + +TMPQHash * FindFreeHashEntry(TMPQArchive * ha, DWORD dwStartIndex, DWORD dwName1, DWORD dwName2, LCID lcLocale); +TMPQHash * GetFirstHashEntry(TMPQArchive * ha, const char * szFileName); +TMPQHash * GetNextHashEntry(TMPQArchive * ha, TMPQHash * pFirstHash, TMPQHash * pPrevHash); +TMPQHash * AllocateHashEntry(TMPQArchive * ha, TFileEntry * pFileEntry, LCID lcLocale); + +TMPQExtHeader * LoadExtTable(TMPQArchive * ha, ULONGLONG ByteOffset, size_t Size, DWORD dwSignature, DWORD dwKey); +TMPQHetTable * LoadHetTable(TMPQArchive * ha); +TMPQBetTable * LoadBetTable(TMPQArchive * ha); + +TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool bDontFixEntries = false); +TMPQBlock * TranslateBlockTable(TMPQArchive * ha, ULONGLONG * pcbTableSize, bool * pbNeedHiBlockTable); + +ULONGLONG FindFreeMpqSpace(TMPQArchive * ha); + +// Functions that load the HET and BET tables +int CreateHashTable(TMPQArchive * ha, DWORD dwHashTableSize); +int LoadAnyHashTable(TMPQArchive * ha); +int BuildFileTable(TMPQArchive * ha); +int DefragmentFileTable(TMPQArchive * ha); + +int CreateFileTable(TMPQArchive * ha, DWORD dwFileTableSize); +int RebuildHetTable(TMPQArchive * ha); +int RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize); +int SaveMPQTables(TMPQArchive * ha); + +TMPQHetTable * CreateHetTable(DWORD dwEntryCount, DWORD dwTotalCount, DWORD dwHashBitSize, LPBYTE pbSrcData); +void FreeHetTable(TMPQHetTable * pHetTable); + +TMPQBetTable * CreateBetTable(DWORD dwMaxFileCount); +void FreeBetTable(TMPQBetTable * pBetTable); + +// Functions for finding files in the file table +TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex); +TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale); +TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex); + +// Allocates file name in the file entry +void AllocateFileName(TMPQArchive * ha, TFileEntry * pFileEntry, const char * szFileName); + +// Allocates new file entry in the MPQ tables. Reuses existing, if possible +TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex); +int RenameFileEntry(TMPQArchive * ha, TMPQFile * hf, const char * szNewFileName); +int DeleteFileEntry(TMPQArchive * ha, TMPQFile * hf); + +// Invalidates entries for (listfile) and (attributes) +void InvalidateInternalFiles(TMPQArchive * ha); + +// Retrieves information about the strong signature +bool QueryMpqSignatureInfo(TMPQArchive * ha, PMPQ_SIGNATURE_INFO pSignatureInfo); + +//----------------------------------------------------------------------------- +// Support for alternate file formats (SBaseSubTypes.cpp) + +int ConvertSqpHeaderToFormat4(TMPQArchive * ha, ULONGLONG FileSize, DWORD dwFlags); +TMPQHash * LoadSqpHashTable(TMPQArchive * ha); +TMPQBlock * LoadSqpBlockTable(TMPQArchive * ha); + +int ConvertMpkHeaderToFormat4(TMPQArchive * ha, ULONGLONG FileSize, DWORD dwFlags); +void DecryptMpkTable(void * pvMpkTable, size_t cbSize); +TMPQHash * LoadMpkHashTable(TMPQArchive * ha); +TMPQBlock * LoadMpkBlockTable(TMPQArchive * ha); +int SCompDecompressMpk(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); + +//----------------------------------------------------------------------------- +// Common functions - MPQ File + +TMPQFile * CreateFileHandle(TMPQArchive * ha, TFileEntry * pFileEntry); +TMPQFile * CreateWritableHandle(TMPQArchive * ha, DWORD dwFileSize); +void * LoadMpqTable(TMPQArchive * ha, ULONGLONG ByteOffset, DWORD dwCompressedSize, DWORD dwRealSize, DWORD dwKey, bool * pbTableIsCut); +int AllocateSectorBuffer(TMPQFile * hf); +int AllocatePatchInfo(TMPQFile * hf, bool bLoadFromFile); +int AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile); +int AllocateSectorChecksums(TMPQFile * hf, bool bLoadFromFile); +int WritePatchInfo(TMPQFile * hf); +int WriteSectorOffsets(TMPQFile * hf); +int WriteSectorChecksums(TMPQFile * hf); +int WriteMemDataMD5(TFileStream * pStream, ULONGLONG RawDataOffs, void * pvRawData, DWORD dwRawDataSize, DWORD dwChunkSize, LPDWORD pcbTotalSize); +int WriteMpqDataMD5(TFileStream * pStream, ULONGLONG RawDataOffs, DWORD dwRawDataSize, DWORD dwChunkSize); +void FreeFileHandle(TMPQFile *& hf); +void FreeArchiveHandle(TMPQArchive *& ha); + +//----------------------------------------------------------------------------- +// Patch functions + +// Structure used for the patching process +typedef struct _TMPQPatcher +{ + BYTE this_md5[MD5_DIGEST_SIZE]; // MD5 of the current file state + LPBYTE pbFileData1; // Primary working buffer + LPBYTE pbFileData2; // Secondary working buffer + DWORD cbMaxFileData; // Maximum allowed size of the patch data + DWORD cbFileData; // Current size of the result data + DWORD nCounter; // Counter of the patch process + +} TMPQPatcher; + +bool IsIncrementalPatchFile(const void * pvData, DWORD cbData, LPDWORD pdwPatchedFileSize); +int Patch_InitPatcher(TMPQPatcher * pPatcher, TMPQFile * hf); +int Patch_Process(TMPQPatcher * pPatcher, TMPQFile * hf); +void Patch_Finalize(TMPQPatcher * pPatcher); + +//----------------------------------------------------------------------------- +// Utility functions + +bool CheckWildCard(const char * szString, const char * szWildCard); +bool IsInternalMpqFileName(const char * szFileName); + +template +const XCHAR * GetPlainFileName(const XCHAR * szFileName) +{ + const XCHAR * szPlainName = szFileName; + + while(*szFileName != 0) + { + if(*szFileName == '\\' || *szFileName == '/') + szPlainName = szFileName + 1; + szFileName++; + } + + return szPlainName; +} + +//----------------------------------------------------------------------------- +// Internal support for MPQ modifications + +int SFileAddFile_Init( + TMPQArchive * ha, + const char * szArchivedName, + ULONGLONG ft, + DWORD dwFileSize, + LCID lcLocale, + DWORD dwFlags, + TMPQFile ** phf + ); + +int SFileAddFile_Init( + TMPQArchive * ha, + TMPQFile * hfSrc, + TMPQFile ** phf + ); + +int SFileAddFile_Write( + TMPQFile * hf, + const void * pvData, + DWORD dwSize, + DWORD dwCompression + ); + +int SFileAddFile_Finish( + TMPQFile * hf + ); + +//----------------------------------------------------------------------------- +// Attributes support + +int SAttrLoadAttributes(TMPQArchive * ha); +int SAttrFileSaveToMpq(TMPQArchive * ha); + +//----------------------------------------------------------------------------- +// Listfile functions + +int SListFileSaveToMpq(TMPQArchive * ha); + +//----------------------------------------------------------------------------- +// Weak signature support + +int SSignFileCreate(TMPQArchive * ha); +int SSignFileFinish(TMPQArchive * ha); + +//----------------------------------------------------------------------------- +// Dump data support + +#ifdef __STORMLIB_DUMP_DATA__ + +void DumpMpqHeader(TMPQHeader * pHeader); +void DumpHashTable(TMPQHash * pHashTable, DWORD dwHashTableSize); +void DumpHetAndBetTable(TMPQHetTable * pHetTable, TMPQBetTable * pBetTable); +void DumpFileTable(TFileEntry * pFileTable, DWORD dwFileTableSize); + +#else + +#define DumpMpqHeader(h) /* */ +#define DumpHashTable(t, s) /* */ +#define DumpHetAndBetTable(t, s) /* */ +#define DumpFileTable(t, s) /* */ + +#endif + +#endif // __STORMCOMMON_H__ + diff --git a/3rdParty/StormLib/src/StormLib.h b/3rdParty/StormLib/src/StormLib.h new file mode 100644 index 000000000..ff58d3539 --- /dev/null +++ b/3rdParty/StormLib/src/StormLib.h @@ -0,0 +1,1134 @@ +/*****************************************************************************/ +/* StormLib.h Copyright (c) Ladislav Zezula 1999-2017 */ +/*---------------------------------------------------------------------------*/ +/* StormLib library v 9.22 */ +/* */ +/* Author : Ladislav Zezula */ +/* E-mail : ladik@zezula.net */ +/* WWW : http://www.zezula.net */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.99 1.00 Lad Created */ +/* 24.03.03 2.50 Lad Version 2.50 */ +/* 02.04.03 3.00 Lad Version 3.00 with compression */ +/* 11.04.03 3.01 Lad Renamed to StormLib.h for compatibility with */ +/* original headers for Storm.dll */ +/* 10.05.03 3.02 Lad Added Pkware DCL compression */ +/* 26.05.03 4.00 Lad Completed all compressions */ +/* 18.06.03 4.01 Lad Added SFileSetFileLocale */ +/* Added SFileExtractFile */ +/* 26.07.03 4.02 Lad Implemented nameless rename and delete */ +/* 26.07.03 4.03 Lad Added support for protected MPQs */ +/* 28.08.03 4.10 Lad Fixed bugs that caused StormLib incorrectly work */ +/* with Diablo I savegames and with files having full */ +/* hash table */ +/* 08.12.03 4.11 DCH Fixed bug in reading file sector larger than 0x1000 */ +/* on certain files. */ +/* Fixed bug in AddFile with MPQ_FILE_REPLACE_EXISTING */ +/* (Thanx Daniel Chiamarello, dchiamarello@madvawes.com)*/ +/* 21.12.03 4.50 Lad Completed port for Mac */ +/* Fixed bug in compacting (if fsize is mul of 0x1000) */ +/* Fixed bug in SCompCompress */ +/* 27.05.04 4.51 Lad Changed memory management from new/delete to our */ +/* own macros */ +/* 22.06.04 4.60 Lad Optimized search. Support for multiple listfiles. */ +/* 30.09.04 4.61 Lad Fixed some bugs (Aaargh !!!) */ +/* Correctly works if HashTableSize > BlockTableSize */ +/* 29.12.04 4.70 Lad Fixed compatibility problem with MPQs from WoW */ +/* 14.07.05 5.00 Lad Added the BZLIB compression support */ +/* Added suport of files stored as single unit */ +/* 17.04.06 5.01 Lad Converted to MS Visual Studio 8.0 */ +/* Fixed issue with protected Warcraft 3 protected maps */ +/* 15.05.06 5.02 Lad Fixed issue with WoW 1.10+ */ +/* 07.09.06 5.10 Lad Fixed processing files longer than 2GB */ +/* 22.11.06 6.00 Lad Support for MPQ archives V2 */ +/* 12.06.07 6.10 Lad Support for (attributes) file */ +/* 10.09.07 6.12 Lad Support for MPQs protected by corrupting hash table */ +/* 03.12.07 6.13 Lad Support for MPQs with hash tbl size > block tbl size */ +/* 07.04.08 6.20 Lad Added SFileFlushArchive */ +/* 09.04.08 Lad Removed FilePointer variable from MPQ handle */ +/* structure, as it caused more problems than benefits */ +/* 12.05.08 6.22 Lad Support for w3xMaster map protector */ +/* 05.10.08 6.23 Lad Support for protectors who set negative values in */ +/* the table of file blocks */ +/* 26.05.09 6.24 Lad Fixed search for multiple lang files with deleted */ +/* entries */ +/* 03.09.09 6.25 Lad Fixed decompression bug in huffmann decompression */ +/* 22.03.10 6.50 Lad New compressions in Starcraft II (LZMA, sparse) */ +/* Fixed compacting MPQs that contain single unit files */ +/* 26.04.10 7.00 Lad Major rewrite */ +/* 08.06.10 7.10 Lad Support for partial MPQs */ +/* 08.07.10 7.11 Lad Support for MPQs v 3.0 */ +/* 20.08.10 7.20 Lad Support for opening multiple MPQs in patch mode */ +/* 20.09.10 8.00 Lad MPQs v 4, HET and BET tables */ +/* 07.01.11 8.01 Lad Write support for MPQs v 3 and 4 */ +/* 15.09.11 8.04 Lad Bug fixes, testing for Diablo III MPQs */ +/* 26.04.12 8.10 Lad Support for data map, added SFileGetArchiveBitmap */ +/* 29.05.12 8.20 Lad C-only interface */ +/* 14.01.13 8.21 Lad ADPCM and Huffmann (de)compression refactored */ +/* 04.12.13 9.00 Lad Unit tests, bug fixes */ +/* 27.08.14 9.10 Lad Signing archives with weak digital signature */ +/* 25.11.14 9.11 Lad Fixed bug reading & creating HET table */ +/* 18.09.15 9.20 Lad Release 9.20 */ +/* 12.12.16 9.21 Lad Release 9.21 */ +/* 10.11.17 9.22 Lad Release 9.22 */ +/*****************************************************************************/ + +#ifndef __STORMLIB_H__ +#define __STORMLIB_H__ + +#ifdef _MSC_VER +#pragma warning(disable:4668) // 'XXX' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' +#pragma warning(disable:4820) // 'XXX' : '2' bytes padding added after data member 'XXX::yyy' +#endif + +#include "StormPort.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------------- +// Use the apropriate library +// +// The library type is encoded in the library name as the following +// StormLibXYZ.lib +// +// X - D for Debug version, R for Release version +// Y - A for ANSI version, U for Unicode version +// Z - S for static-linked CRT library, D for multithreaded DLL CRT library +// + +#if defined(__STORMLIB_SELF__) && !defined(STORMLIB_NO_AUTO_LINK) +#define STORMLIB_NO_AUTO_LINK // Define this if you don't want to link using pragmas when using msvc +#endif + +#if defined(_MSC_VER) && !defined(STORMLIB_NO_AUTO_LINK) + #ifdef _DEBUG // DEBUG VERSIONS + #ifndef _UNICODE + #ifdef _DLL + #pragma comment(lib, "StormLibDAD.lib") // Debug Ansi CRT-DLL version + #else + #pragma comment(lib, "StormLibDAS.lib") // Debug Ansi CRT-LIB version + #endif + #else + #ifdef _DLL + #pragma comment(lib, "StormLibDUD.lib") // Debug Unicode CRT-DLL version + #else + #pragma comment(lib, "StormLibDUS.lib") // Debug Unicode CRT-LIB version + #endif + #endif + #else // RELEASE VERSIONS + #ifndef _UNICODE + #ifdef _DLL + #pragma comment(lib, "StormLibRAD.lib") // Release Ansi CRT-DLL version + #else + #pragma comment(lib, "StormLibRAS.lib") // Release Ansi CRT-LIB version + #endif + #else + #ifdef _DLL + #pragma comment(lib, "StormLibRUD.lib") // Release Unicode CRT-DLL version + #else + #pragma comment(lib, "StormLibRUS.lib") // Release Unicode CRT-LIB version + #endif + #endif + #endif + +#endif + +//----------------------------------------------------------------------------- +// Defines + +#define STORMLIB_VERSION 0x0916 // Current version of StormLib (9.21) +#define STORMLIB_VERSION_STRING "9.22" // String version of StormLib version + +#define ID_MPQ 0x1A51504D // MPQ archive header ID ('MPQ\x1A') +#define ID_MPQ_USERDATA 0x1B51504D // MPQ userdata entry ('MPQ\x1B') +#define ID_MPK 0x1A4B504D // MPK archive header ID ('MPK\x1A') + +#define ERROR_AVI_FILE 10000 // Not a MPQ file, but an AVI file. +#define ERROR_UNKNOWN_FILE_KEY 10001 // Returned by SFileReadFile when can't find file key +#define ERROR_CHECKSUM_ERROR 10002 // Returned by SFileReadFile when sector CRC doesn't match +#define ERROR_INTERNAL_FILE 10003 // The given operation is not allowed on internal file +#define ERROR_BASE_FILE_MISSING 10004 // The file is present as incremental patch file, but base file is missing +#define ERROR_MARKED_FOR_DELETE 10005 // The file was marked as "deleted" in the MPQ +#define ERROR_FILE_INCOMPLETE 10006 // The required file part is missing +#define ERROR_UNKNOWN_FILE_NAMES 10007 // A name of at least one file is unknown +#define ERROR_CANT_FIND_PATCH_PREFIX 10008 // StormLib was unable to find patch prefix for the patches + +// Values for SFileCreateArchive +#define HASH_TABLE_SIZE_MIN 0x00000004 // Verified: If there is 1 file, hash table size is 4 +#define HASH_TABLE_SIZE_DEFAULT 0x00001000 // Default hash table size for empty MPQs +#define HASH_TABLE_SIZE_MAX 0x00080000 // Maximum acceptable hash table size + +#define HASH_ENTRY_DELETED 0xFFFFFFFE // Block index for deleted entry in the hash table +#define HASH_ENTRY_FREE 0xFFFFFFFF // Block index for free entry in the hash table + +#define HET_ENTRY_DELETED 0x80 // NameHash1 value for a deleted entry +#define HET_ENTRY_FREE 0x00 // NameHash1 value for free entry + +#define HASH_STATE_SIZE 0x60 // Size of LibTomCrypt's hash_state structure + +// Values for SFileOpenArchive +#define SFILE_OPEN_HARD_DISK_FILE 2 // Open the archive on HDD +#define SFILE_OPEN_CDROM_FILE 3 // Open the archive only if it is on CDROM + +// Values for SFileOpenFile +#define SFILE_OPEN_FROM_MPQ 0x00000000 // Open the file from the MPQ archive +#define SFILE_OPEN_CHECK_EXISTS 0xFFFFFFFC // Only check whether the file exists +#define SFILE_OPEN_BASE_FILE 0xFFFFFFFD // Reserved for StormLib internal use +#define SFILE_OPEN_ANY_LOCALE 0xFFFFFFFE // Reserved for StormLib internal use +#define SFILE_OPEN_LOCAL_FILE 0xFFFFFFFF // Open a local file + +// Flags for TMPQArchive::dwFlags +#define MPQ_FLAG_READ_ONLY 0x00000001 // If set, the MPQ has been open for read-only access +#define MPQ_FLAG_CHANGED 0x00000002 // If set, the MPQ tables have been changed +#define MPQ_FLAG_MALFORMED 0x00000004 // Malformed data structure detected (W3M map protectors) +#define MPQ_FLAG_HASH_TABLE_CUT 0x00000008 // The hash table goes beyond EOF +#define MPQ_FLAG_BLOCK_TABLE_CUT 0x00000010 // The hash table goes beyond EOF +#define MPQ_FLAG_CHECK_SECTOR_CRC 0x00000020 // Checking sector CRC when reading files +#define MPQ_FLAG_SAVING_TABLES 0x00000040 // If set, we are saving MPQ internal files and MPQ tables +#define MPQ_FLAG_PATCH 0x00000080 // If set, this MPQ is a patch archive +#define MPQ_FLAG_WAR3_MAP 0x00000100 // If set, this MPQ is a map for Warcraft III +#define MPQ_FLAG_LISTFILE_NONE 0x00000200 // Set when no (listfile) was found in InvalidateInternalFiles +#define MPQ_FLAG_LISTFILE_NEW 0x00000400 // Set when (listfile) invalidated by InvalidateInternalFiles +#define MPQ_FLAG_ATTRIBUTES_NONE 0x00000800 // Set when no (attributes) was found in InvalidateInternalFiles +#define MPQ_FLAG_ATTRIBUTES_NEW 0x00001000 // Set when (attributes) invalidated by InvalidateInternalFiles +#define MPQ_FLAG_SIGNATURE_NONE 0x00002000 // Set when no (signature) was found in InvalidateInternalFiles +#define MPQ_FLAG_SIGNATURE_NEW 0x00004000 // Set when (signature) invalidated by InvalidateInternalFiles + +// Values for TMPQArchive::dwSubType +#define MPQ_SUBTYPE_MPQ 0x00000000 // The file is a MPQ file (Blizzard games) +#define MPQ_SUBTYPE_SQP 0x00000001 // The file is a SQP file (War of the Immortals) +#define MPQ_SUBTYPE_MPK 0x00000002 // The file is a MPK file (Longwu Online) + +// Return value for SFileGetFileSize and SFileSetFilePointer +#define SFILE_INVALID_SIZE 0xFFFFFFFF +#define SFILE_INVALID_POS 0xFFFFFFFF +#define SFILE_INVALID_ATTRIBUTES 0xFFFFFFFF + +// Flags for SFileAddFile +#define MPQ_FILE_IMPLODE 0x00000100 // Implode method (By PKWARE Data Compression Library) +#define MPQ_FILE_COMPRESS 0x00000200 // Compress methods (By multiple methods) +#define MPQ_FILE_ENCRYPTED 0x00010000 // Indicates whether file is encrypted +#define MPQ_FILE_FIX_KEY 0x00020000 // File decryption key has to be fixed +#define MPQ_FILE_PATCH_FILE 0x00100000 // The file is a patch file. Raw file data begin with TPatchInfo structure +#define MPQ_FILE_SINGLE_UNIT 0x01000000 // File is stored as a single unit, rather than split into sectors (Thx, Quantam) +#define MPQ_FILE_DELETE_MARKER 0x02000000 // File is a deletion marker. Used in MPQ patches, indicating that the file no longer exists. +#define MPQ_FILE_SECTOR_CRC 0x04000000 // File has checksums for each sector. + // Ignored if file is not compressed or imploded. +#define MPQ_FILE_SIGNATURE 0x10000000 // Present on STANDARD.SNP\(signature). The only occurence ever observed +#define MPQ_FILE_EXISTS 0x80000000 // Set if file exists, reset when the file was deleted +#define MPQ_FILE_REPLACEEXISTING 0x80000000 // Replace when the file exist (SFileAddFile) + +#define MPQ_FILE_COMPRESS_MASK 0x0000FF00 // Mask for a file being compressed + +#define MPQ_FILE_DEFAULT_INTERNAL 0xFFFFFFFF // Use default flags for internal files + +#define MPQ_FILE_VALID_FLAGS (MPQ_FILE_IMPLODE | \ + MPQ_FILE_COMPRESS | \ + MPQ_FILE_ENCRYPTED | \ + MPQ_FILE_FIX_KEY | \ + MPQ_FILE_PATCH_FILE | \ + MPQ_FILE_SINGLE_UNIT | \ + MPQ_FILE_DELETE_MARKER | \ + MPQ_FILE_SECTOR_CRC | \ + MPQ_FILE_SIGNATURE | \ + MPQ_FILE_EXISTS) + +#define MPQ_FILE_VALID_FLAGS_W3X (MPQ_FILE_IMPLODE | \ + MPQ_FILE_COMPRESS | \ + MPQ_FILE_ENCRYPTED | \ + MPQ_FILE_FIX_KEY | \ + MPQ_FILE_DELETE_MARKER | \ + MPQ_FILE_SECTOR_CRC | \ + MPQ_FILE_SIGNATURE | \ + MPQ_FILE_EXISTS) + +// We need to mask out the upper 4 bits of the block table index. +// This is because it gets shifted out when calculating block table offset +// BlockTableOffset = pHash->dwBlockIndex << 0x04 +// Malformed MPQ maps may contain block indexes like 0x40000001 or 0xF0000023 +#define BLOCK_INDEX_MASK 0x0FFFFFFF +#define MPQ_BLOCK_INDEX(pHash) (pHash->dwBlockIndex & BLOCK_INDEX_MASK) + +// Compression types for multiple compressions +#define MPQ_COMPRESSION_HUFFMANN 0x01 // Huffmann compression (used on WAVE files only) +#define MPQ_COMPRESSION_ZLIB 0x02 // ZLIB compression +#define MPQ_COMPRESSION_PKWARE 0x08 // PKWARE DCL compression +#define MPQ_COMPRESSION_BZIP2 0x10 // BZIP2 compression (added in Warcraft III) +#define MPQ_COMPRESSION_SPARSE 0x20 // Sparse compression (added in Starcraft 2) +#define MPQ_COMPRESSION_ADPCM_MONO 0x40 // IMA ADPCM compression (mono) +#define MPQ_COMPRESSION_ADPCM_STEREO 0x80 // IMA ADPCM compression (stereo) +#define MPQ_COMPRESSION_LZMA 0x12 // LZMA compression. Added in Starcraft 2. This value is NOT a combination of flags. +#define MPQ_COMPRESSION_NEXT_SAME 0xFFFFFFFF // Same compression + +// Constants for SFileAddWave +#define MPQ_WAVE_QUALITY_HIGH 0 // Best quality, the worst compression +#define MPQ_WAVE_QUALITY_MEDIUM 1 // Medium quality, medium compression +#define MPQ_WAVE_QUALITY_LOW 2 // Low quality, the best compression + +// Signatures for HET and BET table +#define HET_TABLE_SIGNATURE 0x1A544548 // 'HET\x1a' +#define BET_TABLE_SIGNATURE 0x1A544542 // 'BET\x1a' + +// Decryption keys for MPQ tables +#define MPQ_KEY_HASH_TABLE 0xC3AF3770 // Obtained by HashString("(hash table)", MPQ_HASH_FILE_KEY) +#define MPQ_KEY_BLOCK_TABLE 0xEC83B3A3 // Obtained by HashString("(block table)", MPQ_HASH_FILE_KEY) + +#define LISTFILE_NAME "(listfile)" // Name of internal listfile +#define SIGNATURE_NAME "(signature)" // Name of internal signature +#define ATTRIBUTES_NAME "(attributes)" // Name of internal attributes file +#define PATCH_METADATA_NAME "(patch_metadata)" + +#define MPQ_FORMAT_VERSION_1 0 // Up to The Burning Crusade +#define MPQ_FORMAT_VERSION_2 1 // The Burning Crusade and newer +#define MPQ_FORMAT_VERSION_3 2 // WoW Cataclysm Beta +#define MPQ_FORMAT_VERSION_4 3 // WoW Cataclysm and newer + +// Flags for MPQ attributes +#define MPQ_ATTRIBUTE_CRC32 0x00000001 // The "(attributes)" contains CRC32 for each file +#define MPQ_ATTRIBUTE_FILETIME 0x00000002 // The "(attributes)" contains file time for each file +#define MPQ_ATTRIBUTE_MD5 0x00000004 // The "(attributes)" contains MD5 for each file +#define MPQ_ATTRIBUTE_PATCH_BIT 0x00000008 // The "(attributes)" contains a patch bit for each file +#define MPQ_ATTRIBUTE_ALL 0x0000000F // Summary mask + +#define MPQ_ATTRIBUTES_V1 100 // (attributes) format version 1.00 + +// Flags for SFileOpenArchive +#define BASE_PROVIDER_FILE 0x00000000 // Base data source is a file +#define BASE_PROVIDER_MAP 0x00000001 // Base data source is memory-mapped file +#define BASE_PROVIDER_HTTP 0x00000002 // Base data source is a file on web server +#define BASE_PROVIDER_MASK 0x0000000F // Mask for base provider value + +#define STREAM_PROVIDER_FLAT 0x00000000 // Stream is linear with no offset mapping +#define STREAM_PROVIDER_PARTIAL 0x00000010 // Stream is partial file (.part) +#define STREAM_PROVIDER_MPQE 0x00000020 // Stream is an encrypted MPQ +#define STREAM_PROVIDER_BLOCK4 0x00000030 // 0x4000 per block, text MD5 after each block, max 0x2000 blocks per file +#define STREAM_PROVIDER_MASK 0x000000F0 // Mask for stream provider value + +#define STREAM_FLAG_READ_ONLY 0x00000100 // Stream is read only +#define STREAM_FLAG_WRITE_SHARE 0x00000200 // Allow write sharing when open for write +#define STREAM_FLAG_USE_BITMAP 0x00000400 // If the file has a file bitmap, load it and use it +#define STREAM_OPTIONS_MASK 0x0000FF00 // Mask for stream options + +#define STREAM_PROVIDERS_MASK 0x000000FF // Mask to get stream providers +#define STREAM_FLAGS_MASK 0x0000FFFF // Mask for all stream flags (providers+options) + +#define MPQ_OPEN_NO_LISTFILE 0x00010000 // Don't load the internal listfile +#define MPQ_OPEN_NO_ATTRIBUTES 0x00020000 // Don't open the attributes +#define MPQ_OPEN_NO_HEADER_SEARCH 0x00040000 // Don't search for the MPQ header past the begin of the file +#define MPQ_OPEN_FORCE_MPQ_V1 0x00080000 // Always open the archive as MPQ v 1.00, ignore the "wFormatVersion" variable in the header +#define MPQ_OPEN_CHECK_SECTOR_CRC 0x00100000 // On files with MPQ_FILE_SECTOR_CRC, the CRC will be checked when reading file +#define MPQ_OPEN_PATCH 0x00200000 // This archive is a patch MPQ. Used internally. +#define MPQ_OPEN_READ_ONLY STREAM_FLAG_READ_ONLY + +// Flags for SFileCreateArchive +#define MPQ_CREATE_LISTFILE 0x00100000 // Also add the (listfile) file +#define MPQ_CREATE_ATTRIBUTES 0x00200000 // Also add the (attributes) file +#define MPQ_CREATE_SIGNATURE 0x00400000 // Also add the (signature) file +#define MPQ_CREATE_ARCHIVE_V1 0x00000000 // Creates archive of version 1 (size up to 4GB) +#define MPQ_CREATE_ARCHIVE_V2 0x01000000 // Creates archive of version 2 (larger than 4 GB) +#define MPQ_CREATE_ARCHIVE_V3 0x02000000 // Creates archive of version 3 +#define MPQ_CREATE_ARCHIVE_V4 0x03000000 // Creates archive of version 4 +#define MPQ_CREATE_ARCHIVE_VMASK 0x0F000000 // Mask for archive version + +#define FLAGS_TO_FORMAT_SHIFT 24 // (MPQ_CREATE_ARCHIVE_V4 >> FLAGS_TO_FORMAT_SHIFT) => MPQ_FORMAT_VERSION_4 + +// Flags for SFileVerifyFile +#define SFILE_VERIFY_SECTOR_CRC 0x00000001 // Verify sector checksum for the file, if available +#define SFILE_VERIFY_FILE_CRC 0x00000002 // Verify file CRC, if available +#define SFILE_VERIFY_FILE_MD5 0x00000004 // Verify file MD5, if available +#define SFILE_VERIFY_RAW_MD5 0x00000008 // Verify raw file MD5, if available +#define SFILE_VERIFY_ALL 0x0000000F // Verify every checksum possible + +// Return values for SFileVerifyFile +#define VERIFY_OPEN_ERROR 0x0001 // Failed to open the file +#define VERIFY_READ_ERROR 0x0002 // Failed to read all data from the file +#define VERIFY_FILE_HAS_SECTOR_CRC 0x0004 // File has sector CRC +#define VERIFY_FILE_SECTOR_CRC_ERROR 0x0008 // Sector CRC check failed +#define VERIFY_FILE_HAS_CHECKSUM 0x0010 // File has CRC32 +#define VERIFY_FILE_CHECKSUM_ERROR 0x0020 // CRC32 check failed +#define VERIFY_FILE_HAS_MD5 0x0040 // File has data MD5 +#define VERIFY_FILE_MD5_ERROR 0x0080 // MD5 check failed +#define VERIFY_FILE_HAS_RAW_MD5 0x0100 // File has raw data MD5 +#define VERIFY_FILE_RAW_MD5_ERROR 0x0200 // Raw MD5 check failed +#define VERIFY_FILE_ERROR_MASK (VERIFY_OPEN_ERROR | VERIFY_READ_ERROR | VERIFY_FILE_SECTOR_CRC_ERROR | VERIFY_FILE_CHECKSUM_ERROR | VERIFY_FILE_MD5_ERROR | VERIFY_FILE_RAW_MD5_ERROR) + +// Flags for SFileVerifyRawData (for MPQs version 4.0 or higher) +#define SFILE_VERIFY_MPQ_HEADER 0x0001 // Verify raw MPQ header +#define SFILE_VERIFY_HET_TABLE 0x0002 // Verify raw data of the HET table +#define SFILE_VERIFY_BET_TABLE 0x0003 // Verify raw data of the BET table +#define SFILE_VERIFY_HASH_TABLE 0x0004 // Verify raw data of the hash table +#define SFILE_VERIFY_BLOCK_TABLE 0x0005 // Verify raw data of the block table +#define SFILE_VERIFY_HIBLOCK_TABLE 0x0006 // Verify raw data of the hi-block table +#define SFILE_VERIFY_FILE 0x0007 // Verify raw data of a file + +// Signature types +#define SIGNATURE_TYPE_NONE 0x0000 // The archive has no signature in it +#define SIGNATURE_TYPE_WEAK 0x0001 // The archive has weak signature +#define SIGNATURE_TYPE_STRONG 0x0002 // The archive has strong signature + +// Return values for SFileVerifyArchive +#define ERROR_NO_SIGNATURE 0 // There is no signature in the MPQ +#define ERROR_VERIFY_FAILED 1 // There was an error during verifying signature (like no memory) +#define ERROR_WEAK_SIGNATURE_OK 2 // There is a weak signature and sign check passed +#define ERROR_WEAK_SIGNATURE_ERROR 3 // There is a weak signature but sign check failed +#define ERROR_STRONG_SIGNATURE_OK 4 // There is a strong signature and sign check passed +#define ERROR_STRONG_SIGNATURE_ERROR 5 // There is a strong signature but sign check failed + +#ifndef MD5_DIGEST_SIZE +#define MD5_DIGEST_SIZE 0x10 +#endif + +#ifndef SHA1_DIGEST_SIZE +#define SHA1_DIGEST_SIZE 0x14 // 160 bits +#endif + +#ifndef LANG_NEUTRAL +#define LANG_NEUTRAL 0x00 // Neutral locale +#endif + +// Pointer to hashing function +typedef DWORD (*HASH_STRING)(const char * szFileName, DWORD dwHashType); + +//----------------------------------------------------------------------------- +// File information classes for SFileGetFileInfo and SFileFreeFileInfo + +typedef enum _SFileInfoClass +{ + // Info classes for archives + SFileMpqFileName, // Name of the archive file (TCHAR []) + SFileMpqStreamBitmap, // Array of bits, each bit means availability of one block (BYTE []) + SFileMpqUserDataOffset, // Offset of the user data header (ULONGLONG) + SFileMpqUserDataHeader, // Raw (unfixed) user data header (TMPQUserData) + SFileMpqUserData, // MPQ USer data, without the header (BYTE []) + SFileMpqHeaderOffset, // Offset of the MPQ header (ULONGLONG) + SFileMpqHeaderSize, // Fixed size of the MPQ header + SFileMpqHeader, // Raw (unfixed) archive header (TMPQHeader) + SFileMpqHetTableOffset, // Offset of the HET table, relative to MPQ header (ULONGLONG) + SFileMpqHetTableSize, // Compressed size of the HET table (ULONGLONG) + SFileMpqHetHeader, // HET table header (TMPQHetHeader) + SFileMpqHetTable, // HET table as pointer. Must be freed using SFileFreeFileInfo + SFileMpqBetTableOffset, // Offset of the BET table, relative to MPQ header (ULONGLONG) + SFileMpqBetTableSize, // Compressed size of the BET table (ULONGLONG) + SFileMpqBetHeader, // BET table header, followed by the flags (TMPQBetHeader + DWORD[]) + SFileMpqBetTable, // BET table as pointer. Must be freed using SFileFreeFileInfo + SFileMpqHashTableOffset, // Hash table offset, relative to MPQ header (ULONGLONG) + SFileMpqHashTableSize64, // Compressed size of the hash table (ULONGLONG) + SFileMpqHashTableSize, // Size of the hash table, in entries (DWORD) + SFileMpqHashTable, // Raw (unfixed) hash table (TMPQBlock []) + SFileMpqBlockTableOffset, // Block table offset, relative to MPQ header (ULONGLONG) + SFileMpqBlockTableSize64, // Compressed size of the block table (ULONGLONG) + SFileMpqBlockTableSize, // Size of the block table, in entries (DWORD) + SFileMpqBlockTable, // Raw (unfixed) block table (TMPQBlock []) + SFileMpqHiBlockTableOffset, // Hi-block table offset, relative to MPQ header (ULONGLONG) + SFileMpqHiBlockTableSize64, // Compressed size of the hi-block table (ULONGLONG) + SFileMpqHiBlockTable, // The hi-block table (USHORT []) + SFileMpqSignatures, // Signatures present in the MPQ (DWORD) + SFileMpqStrongSignatureOffset, // Byte offset of the strong signature, relative to begin of the file (ULONGLONG) + SFileMpqStrongSignatureSize, // Size of the strong signature (DWORD) + SFileMpqStrongSignature, // The strong signature (BYTE []) + SFileMpqArchiveSize64, // Archive size from the header (ULONGLONG) + SFileMpqArchiveSize, // Archive size from the header (DWORD) + SFileMpqMaxFileCount, // Max number of files in the archive (DWORD) + SFileMpqFileTableSize, // Number of entries in the file table (DWORD) + SFileMpqSectorSize, // Sector size (DWORD) + SFileMpqNumberOfFiles, // Number of files (DWORD) + SFileMpqRawChunkSize, // Size of the raw data chunk for MD5 + SFileMpqStreamFlags, // Stream flags (DWORD) + SFileMpqFlags, // Nonzero if the MPQ is read only (DWORD) + + // Info classes for files + SFileInfoPatchChain, // Chain of patches where the file is (TCHAR []) + SFileInfoFileEntry, // The file entry for the file (TFileEntry) + SFileInfoHashEntry, // Hash table entry for the file (TMPQHash) + SFileInfoHashIndex, // Index of the hash table entry (DWORD) + SFileInfoNameHash1, // The first name hash in the hash table (DWORD) + SFileInfoNameHash2, // The second name hash in the hash table (DWORD) + SFileInfoNameHash3, // 64-bit file name hash for the HET/BET tables (ULONGLONG) + SFileInfoLocale, // File locale (DWORD) + SFileInfoFileIndex, // Block index (DWORD) + SFileInfoByteOffset, // File position in the archive (ULONGLONG) + SFileInfoFileTime, // File time (ULONGLONG) + SFileInfoFileSize, // Size of the file (DWORD) + SFileInfoCompressedSize, // Compressed file size (DWORD) + SFileInfoFlags, // File flags from (DWORD) + SFileInfoEncryptionKey, // File encryption key + SFileInfoEncryptionKeyRaw, // Unfixed value of the file key + SFileInfoCRC32, // CRC32 of the file +} SFileInfoClass; + +//----------------------------------------------------------------------------- +// Callback functions + +// Values for compact callback +#define CCB_CHECKING_FILES 1 // Checking archive (dwParam1 = current, dwParam2 = total) +#define CCB_CHECKING_HASH_TABLE 2 // Checking hash table (dwParam1 = current, dwParam2 = total) +#define CCB_COPYING_NON_MPQ_DATA 3 // Copying non-MPQ data: No params used +#define CCB_COMPACTING_FILES 4 // Compacting archive (dwParam1 = current, dwParam2 = total) +#define CCB_CLOSING_ARCHIVE 5 // Closing archive: No params used + +typedef void (WINAPI * SFILE_DOWNLOAD_CALLBACK)(void * pvUserData, ULONGLONG ByteOffset, DWORD dwTotalBytes); +typedef void (WINAPI * SFILE_ADDFILE_CALLBACK)(void * pvUserData, DWORD dwBytesWritten, DWORD dwTotalBytes, bool bFinalCall); +typedef void (WINAPI * SFILE_COMPACT_CALLBACK)(void * pvUserData, DWORD dwWorkType, ULONGLONG BytesProcessed, ULONGLONG TotalBytes); + +typedef struct TFileStream TFileStream; + +//----------------------------------------------------------------------------- +// Structure for bit arrays used for HET and BET tables + +typedef struct _TBitArray +{ + DWORD NumberOfBytes; // Total number of bytes in "Elements" + DWORD NumberOfBits; // Total number of bits that are available + BYTE Elements[1]; // Array of elements (variable length) +} TBitArray; + +void GetBits(TBitArray * array, unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultSize); +void SetBits(TBitArray * array, unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultSize); + +//----------------------------------------------------------------------------- +// Structures related to MPQ format +// +// Note: All structures in this header file are supposed to remain private +// to StormLib. The structures may (and will) change over time, as the MPQ +// file format evolves. Programmers directly using these structures need to +// be aware of this. And the last, but not least, NEVER do any modifications +// to those structures directly, always use SFile* functions. +// + +#define MPQ_HEADER_SIZE_V1 0x20 +#define MPQ_HEADER_SIZE_V2 0x2C +#define MPQ_HEADER_SIZE_V3 0x44 +#define MPQ_HEADER_SIZE_V4 0xD0 +#define MPQ_HEADER_DWORDS (MPQ_HEADER_SIZE_V4 / 0x04) + +typedef struct _TMPQUserData +{ + // The ID_MPQ_USERDATA ('MPQ\x1B') signature + DWORD dwID; + + // Maximum size of the user data + DWORD cbUserDataSize; + + // Offset of the MPQ header, relative to the begin of this header + DWORD dwHeaderOffs; + + // Appears to be size of user data header (Starcraft II maps) + DWORD cbUserDataHeader; +} TMPQUserData; + +// MPQ file header +// +// We have to make sure that the header is packed OK. +// Reason: A 64-bit integer at the beginning of 3.0 part, +// which is offset 0x2C +#pragma pack(push, 1) +typedef struct _TMPQHeader +{ + // The ID_MPQ ('MPQ\x1A') signature + DWORD dwID; + + // Size of the archive header + DWORD dwHeaderSize; + + // 32-bit size of MPQ archive + // This field is deprecated in the Burning Crusade MoPaQ format, and the size of the archive + // is calculated as the size from the beginning of the archive to the end of the hash table, + // block table, or hi-block table (whichever is largest). + DWORD dwArchiveSize; + + // 0 = Format 1 (up to The Burning Crusade) + // 1 = Format 2 (The Burning Crusade and newer) + // 2 = Format 3 (WoW - Cataclysm beta or newer) + // 3 = Format 4 (WoW - Cataclysm beta or newer) + USHORT wFormatVersion; + + // Power of two exponent specifying the number of 512-byte disk sectors in each file sector + // in the archive. The size of each file sector in the archive is 512 * 2 ^ wSectorSize. + USHORT wSectorSize; + + // Offset to the beginning of the hash table, relative to the beginning of the archive. + DWORD dwHashTablePos; + + // Offset to the beginning of the block table, relative to the beginning of the archive. + DWORD dwBlockTablePos; + + // Number of entries in the hash table. Must be a power of two, and must be less than 2^16 for + // the original MoPaQ format, or less than 2^20 for the Burning Crusade format. + DWORD dwHashTableSize; + + // Number of entries in the block table + DWORD dwBlockTableSize; + + //-- MPQ HEADER v 2 ------------------------------------------- + + // Offset to the beginning of array of 16-bit high parts of file offsets. + ULONGLONG HiBlockTablePos64; + + // High 16 bits of the hash table offset for large archives. + USHORT wHashTablePosHi; + + // High 16 bits of the block table offset for large archives. + USHORT wBlockTablePosHi; + + //-- MPQ HEADER v 3 ------------------------------------------- + + // 64-bit version of the archive size + ULONGLONG ArchiveSize64; + + // 64-bit position of the BET table + ULONGLONG BetTablePos64; + + // 64-bit position of the HET table + ULONGLONG HetTablePos64; + + //-- MPQ HEADER v 4 ------------------------------------------- + + // Compressed size of the hash table + ULONGLONG HashTableSize64; + + // Compressed size of the block table + ULONGLONG BlockTableSize64; + + // Compressed size of the hi-block table + ULONGLONG HiBlockTableSize64; + + // Compressed size of the HET block + ULONGLONG HetTableSize64; + + // Compressed size of the BET block + ULONGLONG BetTableSize64; + + // Size of raw data chunk to calculate MD5. + // MD5 of each data chunk follows the raw file data. + DWORD dwRawChunkSize; + + // MD5 of MPQ tables + unsigned char MD5_BlockTable[MD5_DIGEST_SIZE]; // MD5 of the block table before decryption + unsigned char MD5_HashTable[MD5_DIGEST_SIZE]; // MD5 of the hash table before decryption + unsigned char MD5_HiBlockTable[MD5_DIGEST_SIZE]; // MD5 of the hi-block table + unsigned char MD5_BetTable[MD5_DIGEST_SIZE]; // MD5 of the BET table before decryption + unsigned char MD5_HetTable[MD5_DIGEST_SIZE]; // MD5 of the HET table before decryption + unsigned char MD5_MpqHeader[MD5_DIGEST_SIZE]; // MD5 of the MPQ header from signature to (including) MD5_HetTable +} TMPQHeader; +#pragma pack(pop) + +// Hash table entry. All files in the archive are searched by their hashes. +typedef struct _TMPQHash +{ + // The hash of the file path, using method A. + DWORD dwName1; + + // The hash of the file path, using method B. + DWORD dwName2; + +#ifdef PLATFORM_LITTLE_ENDIAN + + // The language of the file. This is a Windows LANGID data type, and uses the same values. + // 0 indicates the default language (American English), or that the file is language-neutral. + USHORT lcLocale; + + // The platform the file is used for. 0 indicates the default platform. + // No other values have been observed. + BYTE Platform; + BYTE Reserved; + +#else + + BYTE Platform; + BYTE Reserved; + USHORT lcLocale; + +#endif + + // If the hash table entry is valid, this is the index into the block table of the file. + // Otherwise, one of the following two values: + // - FFFFFFFFh: Hash table entry is empty, and has always been empty. + // Terminates searches for a given file. + // - FFFFFFFEh: Hash table entry is empty, but was valid at some point (a deleted file). + // Does not terminate searches for a given file. + DWORD dwBlockIndex; +} TMPQHash; + +// File description block contains informations about the file +typedef struct _TMPQBlock +{ + // Offset of the beginning of the file, relative to the beginning of the archive. + DWORD dwFilePos; + + // Compressed file size + DWORD dwCSize; + + // Only valid if the block is a file; otherwise meaningless, and should be 0. + // If the file is compressed, this is the size of the uncompressed file data. + DWORD dwFSize; + + // Flags for the file. See MPQ_FILE_XXXX constants + DWORD dwFlags; +} TMPQBlock; + +// Patch file information, preceding the sector offset table +typedef struct _TPatchInfo +{ + DWORD dwLength; // Length of patch info header, in bytes + DWORD dwFlags; // Flags. 0x80000000 = MD5 (?) + DWORD dwDataSize; // Uncompressed size of the patch file + BYTE md5[0x10]; // MD5 of the entire patch file after decompression + + // Followed by the sector table (variable length) +} TPatchInfo; + +// This is the combined file entry for maintaining file list in the MPQ. +// This structure is combined from block table, hi-block table, +// (attributes) file and from (listfile). +typedef struct _TFileEntry +{ + ULONGLONG FileNameHash; // Jenkins hash of the file name. Only used when the MPQ has BET table. + ULONGLONG ByteOffset; // Position of the file content in the MPQ, relative to the MPQ header + ULONGLONG FileTime; // FileTime from the (attributes) file. 0 if not present. + DWORD dwFileSize; // Decompressed size of the file + DWORD dwCmpSize; // Compressed size of the file (i.e., size of the file data in the MPQ) + DWORD dwFlags; // File flags (from block table) + DWORD dwCrc32; // CRC32 from (attributes) file. 0 if not present. + BYTE md5[MD5_DIGEST_SIZE]; // File MD5 from the (attributes) file. 0 if not present. + char * szFileName; // File name. NULL if not known. +} TFileEntry; + +// Common header for HET and BET tables +typedef struct _TMPQExtHeader +{ + DWORD dwSignature; // 'HET\x1A' or 'BET\x1A' + DWORD dwVersion; // Version. Seems to be always 1 + DWORD dwDataSize; // Size of the contained table + + // Followed by the table header + // Followed by the table data + +} TMPQExtHeader; + +// Structure for HET table header +typedef struct _TMPQHetHeader +{ + TMPQExtHeader ExtHdr; + + DWORD dwTableSize; // Size of the entire HET table, including HET_TABLE_HEADER (in bytes) + DWORD dwEntryCount; // Number of occupied entries in the HET table + DWORD dwTotalCount; // Total number of entries in the HET table + DWORD dwNameHashBitSize; // Size of the name hash entry (in bits) + DWORD dwIndexSizeTotal; // Total size of file index (in bits) + DWORD dwIndexSizeExtra; // Extra bits in the file index + DWORD dwIndexSize; // Effective size of the file index (in bits) + DWORD dwIndexTableSize; // Size of the block index subtable (in bytes) + +} TMPQHetHeader; + +// Structure for BET table header +typedef struct _TMPQBetHeader +{ + TMPQExtHeader ExtHdr; + + DWORD dwTableSize; // Size of the entire BET table, including the header (in bytes) + DWORD dwEntryCount; // Number of entries in the BET table. Must match HET_TABLE_HEADER::dwEntryCount + DWORD dwUnknown08; + DWORD dwTableEntrySize; // Size of one table entry (in bits) + DWORD dwBitIndex_FilePos; // Bit index of the file position (within the entry record) + DWORD dwBitIndex_FileSize; // Bit index of the file size (within the entry record) + DWORD dwBitIndex_CmpSize; // Bit index of the compressed size (within the entry record) + DWORD dwBitIndex_FlagIndex; // Bit index of the flag index (within the entry record) + DWORD dwBitIndex_Unknown; // Bit index of the ??? (within the entry record) + DWORD dwBitCount_FilePos; // Bit size of file position (in the entry record) + DWORD dwBitCount_FileSize; // Bit size of file size (in the entry record) + DWORD dwBitCount_CmpSize; // Bit size of compressed file size (in the entry record) + DWORD dwBitCount_FlagIndex; // Bit size of flags index (in the entry record) + DWORD dwBitCount_Unknown; // Bit size of ??? (in the entry record) + DWORD dwBitTotal_NameHash2; // Total bit size of the NameHash2 + DWORD dwBitExtra_NameHash2; // Extra bits in the NameHash2 + DWORD dwBitCount_NameHash2; // Effective size of NameHash2 (in bits) + DWORD dwNameHashArraySize; // Size of NameHash2 table, in bytes + DWORD dwFlagCount; // Number of flags in the following array + +} TMPQBetHeader; + +// Structure for parsed HET table +typedef struct _TMPQHetTable +{ + TBitArray * pBetIndexes; // Bit array of FileIndex values + LPBYTE pNameHashes; // Array of NameHash1 values (NameHash1 = upper 8 bits of FileName hashe) + ULONGLONG AndMask64; // AND mask used for calculating file name hash + ULONGLONG OrMask64; // OR mask used for setting the highest bit of the file name hash + + DWORD dwEntryCount; // Number of occupied entries in the HET table + DWORD dwTotalCount; // Number of entries in both NameHash and FileIndex table + DWORD dwNameHashBitSize; // Size of the name hash entry (in bits) + DWORD dwIndexSizeTotal; // Total size of one entry in pBetIndexes (in bits) + DWORD dwIndexSizeExtra; // Extra bits in the entry in pBetIndexes + DWORD dwIndexSize; // Effective size of one entry in pBetIndexes (in bits) +} TMPQHetTable; + +// Structure for parsed BET table +typedef struct _TMPQBetTable +{ + TBitArray * pNameHashes; // Array of NameHash2 entries (lower 24 bits of FileName hash) + TBitArray * pFileTable; // Bit-based file table + LPDWORD pFileFlags; // Array of file flags + + DWORD dwTableEntrySize; // Size of one table entry, in bits + DWORD dwBitIndex_FilePos; // Bit index of the file position in the table entry + DWORD dwBitIndex_FileSize; // Bit index of the file size in the table entry + DWORD dwBitIndex_CmpSize; // Bit index of the compressed size in the table entry + DWORD dwBitIndex_FlagIndex; // Bit index of the flag index in the table entry + DWORD dwBitIndex_Unknown; // Bit index of ??? in the table entry + DWORD dwBitCount_FilePos; // Size of file offset (in bits) within table entry + DWORD dwBitCount_FileSize; // Size of file size (in bits) within table entry + DWORD dwBitCount_CmpSize; // Size of compressed file size (in bits) within table entry + DWORD dwBitCount_FlagIndex; // Size of flag index (in bits) within table entry + DWORD dwBitCount_Unknown; // Size of ??? (in bits) within table entry + DWORD dwBitTotal_NameHash2; // Total size of the NameHash2 + DWORD dwBitExtra_NameHash2; // Extra bits in the NameHash2 + DWORD dwBitCount_NameHash2; // Effective size of the NameHash2 + DWORD dwEntryCount; // Number of entries + DWORD dwFlagCount; // Number of file flags in pFileFlags +} TMPQBetTable; + +// Structure for patch prefix +typedef struct _TMPQNamePrefix +{ + size_t nLength; // Length of this patch prefix. Can be 0 + char szPatchPrefix[1]; // Patch name prefix (variable length). If not empty, it always starts with backslash. +} TMPQNamePrefix; + +// Structure for name cache +typedef struct _TMPQNameCache +{ + DWORD FirstNameOffset; // Offset of the first name in the name list (in bytes) + DWORD FreeSpaceOffset; // Offset of the first free byte in the name cache (in bytes) + DWORD TotalCacheSize; // Size, in bytes, of the cache. Includes wildcard + DWORD SearchOffset; // Used by SListFileFindFirstFile + + // Followed by search mask (ASCIIZ, '\0' if none) + // Followed by name cache (ANSI multistring) + +} TMPQNameCache; + +// Archive handle structure +typedef struct _TMPQArchive +{ + TFileStream * pStream; // Open stream for the MPQ + + ULONGLONG UserDataPos; // Position of user data (relative to the begin of the file) + ULONGLONG MpqPos; // MPQ header offset (relative to the begin of the file) + ULONGLONG FileSize; // Size of the file at the moment of file open + + struct _TMPQArchive * haPatch; // Pointer to patch archive, if any + struct _TMPQArchive * haBase; // Pointer to base ("previous version") archive, if any + TMPQNamePrefix * pPatchPrefix; // Patch prefix to precede names of patch files + + TMPQUserData * pUserData; // MPQ user data (NULL if not present in the file) + TMPQHeader * pHeader; // MPQ file header + TMPQHash * pHashTable; // Hash table + TMPQHetTable * pHetTable; // HET table + TFileEntry * pFileTable; // File table + HASH_STRING pfnHashString; // Hashing function that will convert the file name into hash + + TMPQUserData UserData; // MPQ user data. Valid only when ID_MPQ_USERDATA has been found + DWORD HeaderData[MPQ_HEADER_DWORDS]; // Storage for MPQ header + + DWORD dwHETBlockSize; + DWORD dwBETBlockSize; + DWORD dwMaxFileCount; // Maximum number of files in the MPQ. Also total size of the file table. + DWORD dwFileTableSize; // Current size of the file table, e.g. index of the entry past the last occupied one + DWORD dwReservedFiles; // Number of entries reserved for internal MPQ files (listfile, attributes) + DWORD dwSectorSize; // Default size of one file sector + DWORD dwFileFlags1; // Flags for (listfile) + DWORD dwFileFlags2; // Flags for (attributes) + DWORD dwFileFlags3; // Flags for (signature) + DWORD dwAttrFlags; // Flags for the (attributes) file, see MPQ_ATTRIBUTE_XXX + DWORD dwFlags; // See MPQ_FLAG_XXXXX + DWORD dwSubType; // See MPQ_SUBTYPE_XXX + + SFILE_ADDFILE_CALLBACK pfnAddFileCB; // Callback function for adding files + void * pvAddFileUserData; // User data thats passed to the callback + + SFILE_COMPACT_CALLBACK pfnCompactCB; // Callback function for compacting the archive + ULONGLONG CompactBytesProcessed; // Amount of bytes that have been processed during a particular compact call + ULONGLONG CompactTotalBytes; // Total amount of bytes to be compacted + void * pvCompactUserData; // User data thats passed to the callback +} TMPQArchive; + +// File handle structure +typedef struct _TMPQFile +{ + TFileStream * pStream; // File stream. Only used on local files + TMPQArchive * ha; // Archive handle + TMPQHash * pHashEntry; // Pointer to hash table entry, if the file was open using hash table + TFileEntry * pFileEntry; // File entry for the file + ULONGLONG RawFilePos; // Offset in MPQ archive (relative to file begin) + ULONGLONG MpqFilePos; // Offset in MPQ archive (relative to MPQ header) + DWORD dwHashIndex; // Hash table index (0xFFFFFFFF if not used) + DWORD dwFileKey; // Decryption key + DWORD dwFilePos; // Current file position + DWORD dwMagic; // 'FILE' + + struct _TMPQFile * hfPatch; // Pointer to opened patch file + + TPatchInfo * pPatchInfo; // Patch info block, preceding the sector table + LPDWORD SectorOffsets; // Position of each file sector, relative to the begin of the file. Only for compressed files. + LPDWORD SectorChksums; // Array of sector checksums (either ADLER32 or MD5) values for each file sector + LPBYTE pbFileData; // Data of the file (single unit files, patched files) + DWORD cbFileData; // Size of file data + DWORD dwCompression0; // Compression that will be used on the first file sector + DWORD dwSectorCount; // Number of sectors in the file + DWORD dwPatchedFileSize; // Size of patched file. Used when saving patch file to the MPQ + DWORD dwDataSize; // Size of data in the file (on patch files, this differs from file size in block table entry) + + LPBYTE pbFileSector; // Last loaded file sector. For single unit files, entire file content + DWORD dwSectorOffs; // File position of currently loaded file sector + DWORD dwSectorSize; // Size of the file sector. For single unit files, this is equal to the file size + + unsigned char hctx[HASH_STATE_SIZE]; // Hash state for MD5. Used when saving file to MPQ + DWORD dwCrc32; // CRC32 value, used when saving file to MPQ + + int nAddFileError; // Result of the "Add File" operations + + bool bLoadedSectorCRCs; // If true, we already tried to load sector CRCs + bool bCheckSectorCRCs; // If true, then SFileReadFile will check sector CRCs when reading the file + bool bIsWriteHandle; // If true, this handle has been created by SFileCreateFile +} TMPQFile; + +// Structure for SFileFindFirstFile and SFileFindNextFile +typedef struct _SFILE_FIND_DATA +{ + char cFileName[MAX_PATH]; // Full name of the found file + char * szPlainName; // Plain name of the found file + DWORD dwHashIndex; // Hash table index for the file (HAH_ENTRY_FREE if no hash table) + DWORD dwBlockIndex; // Block table index for the file + DWORD dwFileSize; // File size in bytes + DWORD dwFileFlags; // MPQ file flags + DWORD dwCompSize; // Compressed file size + DWORD dwFileTimeLo; // Low 32-bits of the file time (0 if not present) + DWORD dwFileTimeHi; // High 32-bits of the file time (0 if not present) + LCID lcLocale; // Locale version + +} SFILE_FIND_DATA, *PSFILE_FIND_DATA; + +typedef struct _SFILE_CREATE_MPQ +{ + DWORD cbSize; // Size of this structure, in bytes + DWORD dwMpqVersion; // Version of the MPQ to be created + void *pvUserData; // Reserved, must be NULL + DWORD cbUserData; // Reserved, must be 0 + DWORD dwStreamFlags; // Stream flags for creating the MPQ + DWORD dwFileFlags1; // File flags for (listfile). Use MPQ_FILE_DEFAULT_INTERNAL to set default flags + DWORD dwFileFlags2; // File flags for (attributes). Use MPQ_FILE_DEFAULT_INTERNAL to set default flags + DWORD dwFileFlags3; // File flags for (signature). Use MPQ_FILE_DEFAULT_INTERNAL to set default flags + DWORD dwAttrFlags; // Flags for the (attributes) file. If 0, no attributes will be created + DWORD dwSectorSize; // Sector size for compressed files + DWORD dwRawChunkSize; // Size of raw data chunk + DWORD dwMaxFileCount; // File limit for the MPQ + +} SFILE_CREATE_MPQ, *PSFILE_CREATE_MPQ; + +//----------------------------------------------------------------------------- +// Stream support - functions + +// Structure used by FileStream_GetBitmap +typedef struct _TStreamBitmap +{ + ULONGLONG StreamSize; // Size of the stream, in bytes + DWORD BitmapSize; // Size of the block map, in bytes + DWORD BlockCount; // Number of blocks in the stream + DWORD BlockSize; // Size of one block + DWORD IsComplete; // Nonzero if the file is complete + + // Followed by the BYTE array, each bit means availability of one block + +} TStreamBitmap; + +// UNICODE versions of the file access functions +TFileStream * FileStream_CreateFile(const TCHAR * szFileName, DWORD dwStreamFlags); +TFileStream * FileStream_OpenFile(const TCHAR * szFileName, DWORD dwStreamFlags); +const TCHAR * FileStream_GetFileName(TFileStream * pStream); +size_t FileStream_Prefix(const TCHAR * szFileName, DWORD * pdwProvider); + +bool FileStream_SetCallback(TFileStream * pStream, SFILE_DOWNLOAD_CALLBACK pfnCallback, void * pvUserData); + +bool FileStream_GetBitmap(TFileStream * pStream, void * pvBitmap, DWORD cbBitmap, LPDWORD pcbLengthNeeded); +bool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead); +bool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite); +bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize); +bool FileStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize); +bool FileStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset); +bool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFT); +bool FileStream_GetFlags(TFileStream * pStream, LPDWORD pdwStreamFlags); +bool FileStream_Replace(TFileStream * pStream, TFileStream * pNewStream); +void FileStream_Close(TFileStream * pStream); + +//----------------------------------------------------------------------------- +// Functions prototypes for Storm.dll + +// Typedefs for functions exported by Storm.dll +typedef LCID (WINAPI * SFILESETLOCALE)(LCID); +typedef bool (WINAPI * SFILEOPENARCHIVE)(const char *, DWORD, DWORD, HANDLE *); +typedef bool (WINAPI * SFILECLOSEARCHIVE)(HANDLE); +typedef bool (WINAPI * SFILEOPENFILEEX)(HANDLE, const char *, DWORD, HANDLE *); +typedef bool (WINAPI * SFILECLOSEFILE)(HANDLE); +typedef DWORD (WINAPI * SFILEGETFILESIZE)(HANDLE, LPDWORD); +typedef DWORD (WINAPI * SFILESETFILEPOINTER)(HANDLE, LONG, LONG *, DWORD); +typedef bool (WINAPI * SFILEREADFILE)(HANDLE, void *, DWORD, LPDWORD, LPOVERLAPPED); + +//----------------------------------------------------------------------------- +// Functions for manipulation with StormLib global flags + +LCID WINAPI SFileGetLocale(); +LCID WINAPI SFileSetLocale(LCID lcNewLocale); + +//----------------------------------------------------------------------------- +// Functions for archive manipulation + +bool WINAPI SFileOpenArchive(const TCHAR * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMpq); +bool WINAPI SFileCreateArchive(const TCHAR * szMpqName, DWORD dwCreateFlags, DWORD dwMaxFileCount, HANDLE * phMpq); +bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCreateInfo, HANDLE * phMpq); + +bool WINAPI SFileSetDownloadCallback(HANDLE hMpq, SFILE_DOWNLOAD_CALLBACK DownloadCB, void * pvUserData); +bool WINAPI SFileFlushArchive(HANDLE hMpq); +bool WINAPI SFileCloseArchive(HANDLE hMpq); + +// Adds another listfile into MPQ. The currently added listfile(s) remain, +// so you can use this API to combining more listfiles. +// Note that this function is internally called by SFileFindFirstFile +int WINAPI SFileAddListFile(HANDLE hMpq, const TCHAR * szListFile); + +// Archive compacting +bool WINAPI SFileSetCompactCallback(HANDLE hMpq, SFILE_COMPACT_CALLBACK CompactCB, void * pvUserData); +bool WINAPI SFileCompactArchive(HANDLE hMpq, const TCHAR * szListFile, bool bReserved); + +// Changing the maximum file count +DWORD WINAPI SFileGetMaxFileCount(HANDLE hMpq); +bool WINAPI SFileSetMaxFileCount(HANDLE hMpq, DWORD dwMaxFileCount); + +// Changing (attributes) file +DWORD WINAPI SFileGetAttributes(HANDLE hMpq); +bool WINAPI SFileSetAttributes(HANDLE hMpq, DWORD dwFlags); +bool WINAPI SFileUpdateFileAttributes(HANDLE hMpq, const char * szFileName); + +//----------------------------------------------------------------------------- +// Functions for manipulation with patch archives + +bool WINAPI SFileOpenPatchArchive(HANDLE hMpq, const TCHAR * szPatchMpqName, const char * szPatchPathPrefix, DWORD dwFlags); +bool WINAPI SFileIsPatchedArchive(HANDLE hMpq); + +//----------------------------------------------------------------------------- +// Functions for file manipulation + +// Reading from MPQ file +bool WINAPI SFileHasFile(HANDLE hMpq, const char * szFileName); +bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile); +DWORD WINAPI SFileGetFileSize(HANDLE hFile, LPDWORD pdwFileSizeHigh); +DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod); +bool WINAPI SFileReadFile(HANDLE hFile, void * lpBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped); +bool WINAPI SFileCloseFile(HANDLE hFile); + +// Retrieving info about a file in the archive +bool WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, SFileInfoClass InfoClass, void * pvFileInfo, DWORD cbFileInfo, LPDWORD pcbLengthNeeded); +bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName); +bool WINAPI SFileFreeFileInfo(void * pvFileInfo, SFileInfoClass InfoClass); + +// High-level extract function +bool WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const TCHAR * szExtracted, DWORD dwSearchScope); + +//----------------------------------------------------------------------------- +// Functions for file and archive verification + +// Generates file CRC32 +bool WINAPI SFileGetFileChecksums(HANDLE hMpq, const char * szFileName, LPDWORD pdwCrc32, char * pMD5); + +// Verifies file against its checksums stored in (attributes) attributes (depending on dwFlags). +// For dwFlags, use one or more of MPQ_ATTRIBUTE_MD5 +DWORD WINAPI SFileVerifyFile(HANDLE hMpq, const char * szFileName, DWORD dwFlags); + +// Verifies raw data of the archive. Only works for MPQs version 4 or newer +int WINAPI SFileVerifyRawData(HANDLE hMpq, DWORD dwWhatToVerify, const char * szFileName); + +// Verifies the signature, if present +bool WINAPI SFileSignArchive(HANDLE hMpq, DWORD dwSignatureType); +DWORD WINAPI SFileVerifyArchive(HANDLE hMpq); + +//----------------------------------------------------------------------------- +// Functions for file searching + +HANDLE WINAPI SFileFindFirstFile(HANDLE hMpq, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const TCHAR * szListFile); +bool WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData); +bool WINAPI SFileFindClose(HANDLE hFind); + +HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const TCHAR * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData); +bool WINAPI SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData); +bool WINAPI SListFileFindClose(HANDLE hFind); + +// Locale support +int WINAPI SFileEnumLocales(HANDLE hMpq, const char * szFileName, LCID * plcLocales, LPDWORD pdwMaxLocales, DWORD dwSearchScope); + +//----------------------------------------------------------------------------- +// Support for adding files to the MPQ + +bool WINAPI SFileCreateFile(HANDLE hMpq, const char * szArchivedName, ULONGLONG FileTime, DWORD dwFileSize, LCID lcLocale, DWORD dwFlags, HANDLE * phFile); +bool WINAPI SFileWriteFile(HANDLE hFile, const void * pvData, DWORD dwSize, DWORD dwCompression); +bool WINAPI SFileFinishFile(HANDLE hFile); + +bool WINAPI SFileAddFileEx(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwCompression, DWORD dwCompressionNext = MPQ_COMPRESSION_NEXT_SAME); +bool WINAPI SFileAddFile(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags); +bool WINAPI SFileAddWave(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality); +bool WINAPI SFileRemoveFile(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope); +bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szOldFileName, const char * szNewFileName); +bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale); +bool WINAPI SFileSetDataCompression(DWORD DataCompression); + +bool WINAPI SFileSetAddFileCallback(HANDLE hMpq, SFILE_ADDFILE_CALLBACK AddFileCB, void * pvUserData); + +//----------------------------------------------------------------------------- +// Compression and decompression + +int WINAPI SCompImplode (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); +int WINAPI SCompExplode (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); +int WINAPI SCompCompress (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, unsigned uCompressionMask, int nCmpType, int nCmpLevel); +int WINAPI SCompDecompress (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); +int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); + +//----------------------------------------------------------------------------- +// Non-Windows support for SetLastError/GetLastError + +#ifdef FULL +#ifndef PLATFORM_WINDOWS + +void SetLastError(DWORD err); +DWORD GetLastError(); + +#endif +#else + +extern DWORD nLastError; + +DWORD WINAPI SErrGetLastError(); +void WINAPI SErrSetLastError(DWORD dwErrCode); + +#define SetLastError SErrSetLastError +#define GetLastError SErrGetLastError + +#endif + +//----------------------------------------------------------------------------- +// Functions from Storm.dll. They use slightly different names for keeping +// possibility to use them together with StormLib (StormXXX instead of SFileXXX) + +#ifdef __LINK_STORM_DLL__ + #define STORM_ALTERNATE_NAMES // Force storm_dll.h to use alternate fnc names + #include "..\storm_dll\storm_dll.h" +#endif // __LINK_STORM_DLL__ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __STORMLIB_H__ diff --git a/3rdParty/StormLib/src/StormPort.h b/3rdParty/StormLib/src/StormPort.h new file mode 100644 index 000000000..956360554 --- /dev/null +++ b/3rdParty/StormLib/src/StormPort.h @@ -0,0 +1,304 @@ +/*****************************************************************************/ +/* StormPort.h Copyright (c) Marko Friedemann 2001 */ +/*---------------------------------------------------------------------------*/ +/* Portability module for the StormLib library. Contains a wrapper symbols */ +/* to make the compilation under Linux work */ +/* */ +/* Author: Marko Friedemann */ +/* Created at: Mon Jan 29 18:26:01 CEST 2001 */ +/* Computer: whiplash.flachland-chemnitz.de */ +/* System: Linux 2.4.0 on i686 */ +/* */ +/* Author: Sam Wilkins */ +/* System: Mac OS X and port to big endian processor */ +/* */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 29.01.01 1.00 Mar Created */ +/* 24.03.03 1.01 Lad Some cosmetic changes */ +/* 12.11.03 1.02 Dan Macintosh compatibility */ +/* 24.07.04 1.03 Sam Mac OS X compatibility */ +/* 22.11.06 1.04 Sam Mac OS X compatibility (for StormLib 6.0) */ +/* 31.12.06 1.05 XPinguin Full GNU/Linux compatibility */ +/* 17.10.12 1.05 Lad Moved error codes so they don't overlap with errno.h */ +/*****************************************************************************/ + +#ifndef __STORMPORT_H__ +#define __STORMPORT_H__ + +#ifndef __cplusplus + #define bool char + #define true 1 + #define false 0 +#endif + +//----------------------------------------------------------------------------- +// Defines for Windows + +#if !defined(PLATFORM_DEFINED) && defined(_WIN32) + + // In MSVC 8.0, there are some functions declared as deprecated. + #if _MSC_VER >= 1400 + #define _CRT_SECURE_NO_DEPRECATE + #define _CRT_NON_CONFORMING_SWPRINTFS + #endif + + #include + #include + #include + #include + #include + #include + #define PLATFORM_LITTLE_ENDIAN + + #ifdef _WIN64 + #define PLATFORM_64BIT + #else + #define PLATFORM_32BIT + #endif + + #define PLATFORM_WINDOWS + #define PLATFORM_DEFINED // The platform is known now + +#endif + +//----------------------------------------------------------------------------- +// Defines for Mac + +#if !defined(PLATFORM_DEFINED) && defined(__APPLE__) // Mac BSD API + + // Macintosh + #include + #include + #include + #include + #include + #include + #include + + // Support for PowerPC on Max OS X + #if (__ppc__ == 1) || (__POWERPC__ == 1) || (_ARCH_PPC == 1) + #include + #include + #endif + + #define PKEXPORT + #define __SYS_ZLIB + #define __SYS_BZLIB + + #ifndef __BIG_ENDIAN__ + #define PLATFORM_LITTLE_ENDIAN + #endif + + #define PLATFORM_MAC + #define PLATFORM_DEFINED // The platform is known now + +#endif + +//----------------------------------------------------------------------------- +// Assumption: we are not on Windows nor Macintosh, so this must be linux *grin* + +#if !defined(PLATFORM_DEFINED) + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #define PLATFORM_LITTLE_ENDIAN + #define PLATFORM_LINUX + #define PLATFORM_DEFINED + +#endif + +//----------------------------------------------------------------------------- +// Definition of Windows-specific types for non-Windows platforms + +#ifndef PLATFORM_WINDOWS + #if __LP64__ + #define PLATFORM_64BIT + #else + #define PLATFORM_32BIT + #endif + + // Typedefs for ANSI C + typedef unsigned char BYTE; + typedef unsigned short USHORT; + typedef int LONG; + typedef unsigned int DWORD; + typedef unsigned long DWORD_PTR; + typedef long LONG_PTR; + typedef long INT_PTR; + typedef long long LONGLONG; + typedef unsigned long long ULONGLONG; + typedef void * HANDLE; + typedef void * LPOVERLAPPED; // Unsupported on Linux and Mac + typedef char TCHAR; + typedef unsigned int LCID; + typedef LONG * PLONG; + typedef DWORD * LPDWORD; + typedef BYTE * LPBYTE; + typedef const char * LPCTSTR; + typedef const char * LPCSTR; + typedef char * LPTSTR; + typedef char * LPSTR; + + #ifdef PLATFORM_32BIT + #define _LZMA_UINT32_IS_ULONG + #endif + + // Some Windows-specific defines + #ifndef MAX_PATH + #define MAX_PATH 1024 + #endif + + #ifndef _countof + #define _countof(x) (sizeof(x) / sizeof(x[0])) + #endif + + #define WINAPI + + #define FILE_BEGIN SEEK_SET + #define FILE_CURRENT SEEK_CUR + #define FILE_END SEEK_END + + #define _T(x) x + #define _tcslen strlen + #define _tcscpy strcpy + #define _tcscat strcat + #define _tcschr strchr + #define _tcsrchr strrchr + #define _tcsstr strstr + #define _tcsnicmp strncasecmp + #define _tprintf printf + #define _stprintf sprintf + #define _tremove remove + #define _tmain main + + #define _stricmp strcasecmp + #define _strnicmp strncasecmp + #define _tcsicmp strcasecmp + #define _tcsnicmp strncasecmp + +#endif // !PLATFORM_WINDOWS + +// 64-bit calls are supplied by "normal" calls on Mac +#if defined(PLATFORM_MAC) + #define stat64 stat + #define fstat64 fstat + #define lseek64 lseek + #define ftruncate64 ftruncate + #define off64_t off_t + #define O_LARGEFILE 0 +#endif + +// Platform-specific error codes for UNIX-based platforms +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + #define ERROR_SUCCESS 0 + #define ERROR_FILE_NOT_FOUND ENOENT + #define ERROR_ACCESS_DENIED EPERM + #define ERROR_INVALID_HANDLE EBADF + #define ERROR_NOT_ENOUGH_MEMORY ENOMEM + #define ERROR_NOT_SUPPORTED ENOTSUP + #define ERROR_INVALID_PARAMETER EINVAL + #define ERROR_NEGATIVE_SEEK EINVAL + #define ERROR_DISK_FULL ENOSPC + #define ERROR_ALREADY_EXISTS EEXIST + #define ERROR_INSUFFICIENT_BUFFER ENOBUFS + #define ERROR_BAD_FORMAT 1000 // No such error code under Linux + #define ERROR_NO_MORE_FILES 1001 // No such error code under Linux + #define ERROR_HANDLE_EOF 1002 // No such error code under Linux + #define ERROR_CAN_NOT_COMPLETE 1003 // No such error code under Linux + #define ERROR_FILE_CORRUPT 1004 // No such error code under Linux +#endif + +//----------------------------------------------------------------------------- +// Swapping functions + +#ifdef PLATFORM_LITTLE_ENDIAN + #define BSWAP_INT16_UNSIGNED(a) (a) + #define BSWAP_INT16_SIGNED(a) (a) + #define BSWAP_INT32_UNSIGNED(a) (a) + #define BSWAP_INT32_SIGNED(a) (a) + #define BSWAP_INT64_SIGNED(a) (a) + #define BSWAP_INT64_UNSIGNED(a) (a) + #define BSWAP_ARRAY16_UNSIGNED(a,b) {} + #define BSWAP_ARRAY32_UNSIGNED(a,b) {} + #define BSWAP_ARRAY64_UNSIGNED(a,b) {} + #define BSWAP_PART_HEADER(a) {} + #define BSWAP_TMPQHEADER(a,b) {} + #define BSWAP_TMPKHEADER(a) {} +#else + +#ifdef __cplusplus + extern "C" { +#endif + int16_t SwapInt16(uint16_t); + uint16_t SwapUInt16(uint16_t); + int32_t SwapInt32(uint32_t); + uint32_t SwapUInt32(uint32_t); + int64_t SwapInt64(uint64_t); + uint64_t SwapUInt64(uint64_t); + void ConvertUInt16Buffer(void * ptr, size_t length); + void ConvertUInt32Buffer(void * ptr, size_t length); + void ConvertUInt64Buffer(void * ptr, size_t length); + void ConvertTMPQUserData(void *userData); + void ConvertTMPQHeader(void *header, uint16_t wPart); + void ConvertTMPKHeader(void *header); +#ifdef __cplusplus + } +#endif + #define BSWAP_INT16_SIGNED(a) SwapInt16((a)) + #define BSWAP_INT16_UNSIGNED(a) SwapUInt16((a)) + #define BSWAP_INT32_SIGNED(a) SwapInt32((a)) + #define BSWAP_INT32_UNSIGNED(a) SwapUInt32((a)) + #define BSWAP_INT64_SIGNED(a) SwapInt64((a)) + #define BSWAP_INT64_UNSIGNED(a) SwapUInt64((a)) + #define BSWAP_ARRAY16_UNSIGNED(a,b) ConvertUInt16Buffer((a),(b)) + #define BSWAP_ARRAY32_UNSIGNED(a,b) ConvertUInt32Buffer((a),(b)) + #define BSWAP_ARRAY64_UNSIGNED(a,b) ConvertUInt64Buffer((a),(b)) + #define BSWAP_TMPQHEADER(a,b) ConvertTMPQHeader((a),(b)) + #define BSWAP_TMPKHEADER(a) ConvertTMPKHeader((a)) +#endif + +//----------------------------------------------------------------------------- +// Macro for deprecated symbols + +/* +#ifdef _MSC_VER + #if _MSC_FULL_VER >= 140050320 + #define STORMLIB_DEPRECATED(_Text) __declspec(deprecated(_Text)) + #else + #define STORMLIB_DEPRECATED(_Text) __declspec(deprecated) + #endif +#else + #ifdef __GNUC__ + #define STORMLIB_DEPRECATED(_Text) __attribute__((deprecated)) + #else + #define STORMLIB_DEPRECATED(_Text) __attribute__((deprecated(_Text))) + #endif +#endif + +// When a flag is deprecated, use this macro +#ifndef _STORMLIB_NO_DEPRECATE + #define STORMLIB_DEPRECATED_FLAG(type, oldflag, newflag) \ + const STORMLIB_DEPRECATED(#oldflag " is deprecated. Use " #newflag ". To supress this warning, define _STORMLIB_NO_DEPRECATE") static type oldflag = (type)newflag; +#else +#define STORMLIB_DEPRECATED_FLAG(type, oldflag, newflag) static type oldflag = (type)newflag; +#endif +*/ + +#define bool int +void TranslateFileName(char* dst, int dstLen, const char* src); + +#endif // __STORMPORT_H__ diff --git a/CMake/32bit.cmake b/CMake/32bit.cmake new file mode 100644 index 000000000..b8d8c27fb --- /dev/null +++ b/CMake/32bit.cmake @@ -0,0 +1,16 @@ +message(STATUS "Using 32-bit toolchain") + +set(CMAKE_CXX_FLAGS -m32 CACHE STRING "") + +set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS TRUE) + +find_path(DIR NAMES cmake PATHS /usr/lib32 /usr/lib/i386-linux-gnu NO_DEFAULT_PATH) + +if(DIR) + message(STATUS "Using 32-bit libraries from ${DIR}") + # Read CMake modules from 32-bit packages + set(CMAKE_FIND_ROOT_PATH ${DIR}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() diff --git a/CMake/SDL2_fixed.cmake b/CMake/SDL2_fixed.cmake new file mode 100644 index 000000000..5e89ec19b --- /dev/null +++ b/CMake/SDL2_fixed.cmake @@ -0,0 +1,9 @@ +find_package(SDL2 REQUIRED) +# WORKAROUND: Arch Linux SDL2 cmake config not setting this variable +if(NOT SDL2_LIBRARIES) + # Note: you will probably need to install multilib/lib32-dbus on Arch + set(SDL2_LIBRARIES SDL2::SDL2) +endif() + +# WORKAROUND: Issue with Ubuntu 16.04 having whitespace (CMP0004) +string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES) \ No newline at end of file diff --git a/CMake/out_of_tree.cmake b/CMake/out_of_tree.cmake new file mode 100644 index 000000000..88b5b25a0 --- /dev/null +++ b/CMake/out_of_tree.cmake @@ -0,0 +1,3 @@ +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(WARNING [[In-source build detected, please eg. create a new directory and use `cmake ..`]]) +endif() diff --git a/CMake/sanitize.cmake b/CMake/sanitize.cmake new file mode 100644 index 000000000..1920b394b --- /dev/null +++ b/CMake/sanitize.cmake @@ -0,0 +1,8 @@ +include(CheckCXXCompilerFlag) + +set(SANITIZE_OPTIONS -fsanitize=null -fsanitize=return) + +check_cxx_compiler_flag(HAS_SANITIZE_ADDRESS -fsanitize-recover=address) +if(HAS_SANITIZE_ADDRESS) + list(APPEND SANITIZE_OPTIONS -fsanitize=address -fsanitize-recover=address) +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..0f52d1326 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,147 @@ +cmake_minimum_required(VERSION 3.5) + +include(CMake/out_of_tree.cmake) + +# This must be included before project() +include(CMake/32bit.cmake) + +set(CMAKE_CXX_STANDARD 11) + + +project(devil-miniwin + VERSION 0.0.1 + LANGUAGES CXX +) + +if(NOT CMAKE_SIZEOF_VOID_P EQUAL 4) + message(WARNING "sizeof(void*) == ${CMAKE_SIZEOF_VOID_P}.") + message(FATAL_ERROR [[This project can only be compiled in 32-bit mode.]]) +endif() + +set(SOURCES + Source/automap.cpp + Source/codec.cpp + Source/control.cpp + Source/cursor.cpp + Source/dead.cpp + Source/debug.cpp + Source/diablo.cpp + Source/doom.cpp + Source/drlg_l1.cpp + Source/drlg_l2.cpp + Source/drlg_l3.cpp + Source/drlg_l4.cpp +# Source/effects.cpp + Source/encrypt.cpp + Source/engine.cpp + Source/error.cpp + Source/gamemenu.cpp + Source/gendung.cpp + Source/gmenu.cpp + Source/help.cpp + Source/interfac.cpp + Source/inv.cpp + Source/items.cpp + Source/lighting.cpp + Source/loadsave.cpp + Source/mainmenu.cpp + Source/minitext.cpp + Source/missiles.cpp + Source/monster.cpp + Source/mpqapi.cpp + Source/msgcmd.cpp + Source/msg.cpp + Source/multi.cpp + Source/objects.cpp + Source/pack.cpp + Source/palette.cpp + Source/path.cpp + Source/pfile.cpp + Source/player.cpp + Source/plrmsg.cpp + Source/portal.cpp + Source/quests.cpp + Source/render.cpp + Source/scrollrt.cpp + Source/setmaps.cpp + Source/sha.cpp + Source/spells.cpp + Source/stores.cpp + Source/sync.cpp + Source/textdat.cpp + Source/themes.cpp + Source/tmsg.cpp + Source/town.cpp + Source/towners.cpp + Source/track.cpp + Source/trigs.cpp + Source/wave.cpp + + 3rdParty/PKWare/explode.cpp + 3rdParty/PKWare/implode.cpp +) + +# Completely stubbed out sources, for reference +set(REPLACED_SOURCES + Source/capture.cpp + Source/appfat.cpp + Source/dthread.cpp + Source/dx.cpp + Source/fault.cpp + Source/init.cpp + Source/logging.cpp + Source/movie.cpp + Source/nthread.cpp + Source/restrict.cpp + Source/sound.cpp + Source/effects.cpp # There is a function here that references Dx3d and lead to crash. +) + +set(STUB_SOURCES + Stub/miniwin.cpp + Stub/miniwin_rand.cpp + Stub/appfat.cpp + Stub/capture.cpp + Stub/dthread.cpp + Stub/dx.cpp + Stub/effects.cpp + Stub/fault.cpp + Stub/init.cpp + Stub/movie.cpp + Stub/nthread.cpp + Stub/restrict.cpp + Stub/sound.cpp + Stub/storm.cpp + Stub/diabloui.cpp + Stub/miniwin_io.cpp + Stub/miniwin_sdl.cpp + Stub/storm_net.cpp + Stub/sdlrender.cpp + Stub/SDL_FontCache.cpp + + 3rdParty/StormLib/src/FileStream.cpp + 3rdParty/StormLib/src/SBaseCommon.cpp + 3rdParty/StormLib/src/SBaseFileTable.cpp + 3rdParty/StormLib/src/SBaseSubTypes.cpp + 3rdParty/StormLib/src/SCompression.cpp + 3rdParty/StormLib/src/SFileExtractFile.cpp + 3rdParty/StormLib/src/SFileFindFile.cpp + 3rdParty/StormLib/src/SFileGetFileInfo.cpp + 3rdParty/StormLib/src/SFileOpenArchive.cpp + 3rdParty/StormLib/src/SFileOpenFileEx.cpp + 3rdParty/StormLib/src/SFileReadFile.cpp +) + +include(CMake/SDL2_fixed.cmake) +include(CMake/sanitize.cmake) + +include_directories(${SDL2_INCLUDE_DIRS}) + +include_directories(. Stub) +# FUTURE: use add_compile_definitions() +add_definitions(-DMINIWIN -D_DEBUG -DFASTER) +add_compile_options(-g -fpermissive -Wno-write-strings -Wno-multichar) + +add_executable(devil-test ${SOURCES} ${STUB_SOURCES} Stub/main_test.cpp) +target_compile_options(devil-test PRIVATE ${SANITIZE_OPTIONS}) +target_link_libraries(devil-test PUBLIC m ${SDL2_LIBRARIES} ${SANITIZE_OPTIONS}) diff --git a/Diablo.dsp b/Diablo.dsp new file mode 100644 index 000000000..dd454eee2 --- /dev/null +++ b/Diablo.dsp @@ -0,0 +1,431 @@ +# Microsoft Developer Studio Project File - Name="Diablo" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=Diablo - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Diablo.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Diablo.mak" CFG="Diablo - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Diablo - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "Diablo - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "Diablo - Win32 Release with PDB" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Diablo - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Source/WinRel" +# PROP BASE Intermediate_Dir "Source/WinRel" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bld/WinRel" +# PROP Intermediate_Dir "Source/WinRel" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# SUBTRACT CPP /WX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 DiabloUI/WinRel/DiabloUI.lib 3rdParty/Storm/Source/WinRel/Storm.lib kernel32.lib user32.lib gdi32.lib advapi32.lib shell32.lib version.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "Diablo - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Diablo__" +# PROP BASE Intermediate_Dir "Diablo__" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "bld/WinDebug" +# PROP Intermediate_Dir "Source/WinDebug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /Gm /GX /Zi /O1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "NDEBUG" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /D "NDEBUG" /mktyplib203 /o "NUL" /win32 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "NDEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib user32.lib gdi32.lib advapi32.lib shell32.lib version.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib shell32.lib version.lib /nologo /subsystem:windows /machine:I386 + /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "Diablo - Win32 Release with PDB" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Diablo___Win32_Release_with_PDB" +# PROP BASE Intermediate_Dir "Diablo___Win32_Release_with_PDB" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bld/WinRel" +# PROP Intermediate_Dir "Source/WinRel" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# SUBTRACT BASE CPP /WX +# ADD CPP /nologo /MT /W3 /GX /Zi /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# SUBTRACT CPP /WX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 DiabloUI/WinRel/DiabloUI.lib 3rdParty/Storm/Source/WinRel/Storm.lib kernel32.lib user32.lib gdi32.lib advapi32.lib shell32.lib version.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 DiabloUI/WinRel/DiabloUI.lib 3rdParty/Storm/Source/WinRel/Storm.lib kernel32.lib user32.lib gdi32.lib advapi32.lib shell32.lib version.lib /nologo /subsystem:windows /debug /machine:I386 + +!ENDIF + +# Begin Target + +# Name "Diablo - Win32 Release" +# Name "Diablo - Win32 Debug" +# Name "Diablo - Win32 Release with PDB" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\Source\appfat.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\automap.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\capture.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\codec.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\control.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\cursor.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\dead.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\debug.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\diablo.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\doom.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\drlg_l1.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\drlg_l2.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\drlg_l3.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\drlg_l4.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\dthread.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\dx.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\effects.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\encrypt.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\engine.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\error.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\fault.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\gamemenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\gendung.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\gmenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\help.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\init.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\interfac.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\inv.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\items.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\lighting.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\loadsave.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\logging.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\mainmenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\minitext.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\missiles.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\monster.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\movie.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\mpqapi.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\msg.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\msgcmd.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\multi.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\nthread.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\objects.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\pack.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\palette.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\path.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\pfile.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\player.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\plrmsg.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\portal.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\quests.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\restrict.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\scrollrt.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\setmaps.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\sha.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\sound.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\spells.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\stores.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\sync.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\textdat.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\themes.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\tmsg.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\town.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\towners.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\track.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\trigs.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\wave.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\render.cpp +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\Diablo.ico +# End Source File +# Begin Source File + +SOURCE=.\Diablo.rc +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# End Group +# Begin Group "PKWare" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\3rdParty\PKWare\explode.cpp +# End Source File +# Begin Source File + +SOURCE=.\3rdParty\PKWare\implode.cpp +# End Source File +# End Group +# End Target +# End Project diff --git a/Diablo.dsw b/Diablo.dsw new file mode 100644 index 000000000..acc01938d --- /dev/null +++ b/Diablo.dsw @@ -0,0 +1,59 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Diablo"=".\Diablo.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DiabloUI + End Project Dependency + Begin Project Dependency + Project_Dep_Name Storm + End Project Dependency +}}} + +############################################################################### + +Project: "DiabloUI"=".\DiabloUI\DiabloUI.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "Storm"=".\3rdParty\Storm\Source\Storm.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Diablo.ico b/Diablo.ico new file mode 100644 index 000000000..81c3a4a03 Binary files /dev/null and b/Diablo.ico differ diff --git a/Diablo.rc b/Diablo.rc new file mode 100644 index 000000000..17a071120 --- /dev/null +++ b/Diablo.rc @@ -0,0 +1,291 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "Diablo.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 250, 241 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Direct Draw Error" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",1,193,220,50,14 + LTEXT "Diablo was unable to properly initialize your video card using DirectX. Please try the following solutions to correct the problem:", + -1,7,7,236,18 + LTEXT "Use the Diablo setup program ""SETUP.EXE"" provided on the Diablo CD-ROM to install DirectX 3.0.", + -1,19,26,210,18 + LTEXT "Install the most recent DirectX video drivers provided by the manufacturer of your video card. A list of video card manufactuers can be found at: http://www.blizzard.com/support/vendors.htm", + -1,19,48,210,27 + LTEXT "The error encountered while trying to initialize the video card was:", + -1,7,175,236,9 + LTEXT "unknown error",1000,19,186,210,27 + LTEXT "If you continue to have problems, we have also included Microsoft DirectX 2.0 drivers on the Diablo CD-ROM. This older version of DirectX may work in cases where DirectX 3.0 does not.", + -1,7,79,236,27 + LTEXT "USA telephone: 1-800-426-9400\nInternational telephone: 206-882-8080\nhttp://www.microsoft.com", + -1,19,137,210,27 + LTEXT "If you continue to have problems with DirectX, please contact Microsoft's Technical Support at:", + -1,7,116,236,18 +END + +IDD_DIALOG2 DIALOG DISCARDABLE 0, 0, 250, 213 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Out of Memory Error" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",1,193,192,50,14 + LTEXT "Diablo has exhausted all the memory on your system. This problem can likely be corrected by changing the virtual memory settings for Windows. Ensure that your system has at least 10 megabytes of free disk space, then check your virtual memory settings:", + -1,7,7,236,36 + LTEXT "Select ""Settings - Control Panel"" from the ""Start"" menu\nRun the ""System"" control panel applet\nSelect the ""Performance"" tab, and press ""Virtual Memory""\nUse the ""Let Windows manage my virtual memory..."" option", + -1,23,54,197,36 + LTEXT "The error encountered was:",-1,7,146,236,11 + LTEXT "unknown location",1000,20,157,210,27 + LTEXT "For Windows 95:",-1,7,45,236,9 + LTEXT "Select ""Settings - Control Panel"" from the ""Start"" menu\nRun the ""System"" control panel applet\nSelect the ""Performance"" tab\nPress ""Change"" in ""Virtual Memory"" settings\nEnsure that the virtual memory file is at least 32 megabytes", + -1,17,98,197,45 + LTEXT "For Windows NT:",-1,7,89,236,9 +END + +IDD_DIALOG3 DIALOG DISCARDABLE 0, 0, 265, 114 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Data File Error" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",1,208,93,50,14 + LTEXT "Diablo was unable to open a required file. Please ensure that the Diablo disc is in the CDROM drive. If this problem persists, try uninstalling and reinstalling Diablo using the program ""SETUP.EXE"" on the Diablo CD-ROM.", + -1,7,7,251,36 + LTEXT "The problem occurred while trying to load a file",-1,7, + 48,232,9 + LTEXT "unknown file",1000,20,59,210,27 +END + +IDD_DIALOG4 DIALOG DISCARDABLE 0, 0, 250, 161 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Direct Draw Error" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",1,193,140,50,14 + LTEXT "Diablo was unable to find the file ""ddraw.dll"", which is a component of Microsoft DirectX. Please run the program ""SETUP.EXE"" on the Diablo CD-ROM and install Microsoft DirectX.", + -1,7,7,236,27 + LTEXT "The error encountered while trying to initialize DirectX was:", + -1,7,95,236,9 + LTEXT "unknown error",1000,19,106,210,29 + LTEXT "USA telephone: 1-800-426-9400\nInternational telephone: 206-882-8080\nhttp://www.microsoft.com", + -1,19,60,210,27 + LTEXT "If you continue to have problems with DirectX, please contact Microsoft's Technical Support at:", + -1,7,39,236,18 +END + +IDD_DIALOG5 DIALOG DISCARDABLE 0, 0, 250, 161 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Direct Sound Error" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",1,193,140,50,14 + LTEXT "Diablo was unable to find the file ""dsound.dll"", which is a component of Microsoft DirectX. Please run the program ""SETUP.EXE"" on the Diablo CD-ROM and install Microsoft DirectX.", + -1,7,7,236,27 + LTEXT "The error encountered while trying to initialize DirectX was:", + -1,7,95,236,9 + LTEXT "unknown error",1000,19,106,210,27 + LTEXT "USA telephone: 1-800-426-9400\nInternational telephone: 206-882-8080\nhttp://www.microsoft.com", + -1,19,60,210,27 + LTEXT "If you continue to have problems with DirectX, please contact Microsoft's Technical Support at:", + -1,7,39,236,18 +END + +/* IDD_DIALOG6 DIALOG DISCARDABLE 0, 0, 250, 92 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "System warning" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "&OK",1,130,71,50,14 + LTEXT "Diablo requires an Intel Pentium-class processor to run properly. Your system does not appear to have a Pentium-class processor installed.", + -1,7,7,236,18 + LTEXT "You may still be able to play Diablo if your processor has the performance characteristics of a Pentium.", + -1,7,30,236,18 + LTEXT "Press ""OK"" to proceed, otherwise press ""Cancel"" to exit this program.", + -1,7,53,236,9 + PUSHBUTTON "&Cancel",2,193,71,50,14 +END */ + +IDD_DIALOG7 DIALOG DISCARDABLE 0, 0, 250, 100 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Out of Disk Space" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",1,193,79,50,14 + LTEXT "Diablo requires at least 10 megabytes of free disk space to run properly. The disk:", + -1,7,7,236,18 + LTEXT "",-1,7,43,232,9 + LTEXT "unknown drive",1000,7,33,210,9 + LTEXT "has less than 10 megabytes of free space left. Please free some space on your drive and run Diablo again.", + -1,7,52,236,18 +END + +IDD_DIALOG8 DIALOG DISCARDABLE 0, 0, 250, 161 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Direct Draw Error" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",1,193,140,50,14 + LTEXT "Diablo was unable to switch video modes. This is a common problem for computers with more than one video card. To correct this problem, please set your video resolution to 640 x 480 and try running Diablo again.", + -1,7,7,236,27 + LTEXT "The error encountered while trying to switch video modes was:", + -1,7,95,236,9 + LTEXT "unknown error",1000,19,106,210,27 + LTEXT "Select ""Settings - Control Panel"" from the ""Start"" menu\nRun the ""Display"" control panel applet\nSelect the ""Settings"" tab\nSet the ""Desktop Area"" to ""640 x 480 pixels""", + -1,23,50,197,36 + LTEXT "For Windows 95 and Windows NT",-1,7,41,236,9 +END + +IDD_DIALOG9 DIALOG DISCARDABLE 0, 0, 250, 92 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Data File Error" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",1,136,71,50,14 + LTEXT "Diablo cannot read a required data file. Your Diablo CD may not be in the CDROM drive. Please ensure that the Diablo disc is in the CDROM drive and press OK. To leave the program, press Exit.", + -1,7,7,236,27 + LTEXT "unknown file",1000,20,37,210,27 + PUSHBUTTON "Exit",2,193,71,50,14 +END + +IDD_DIALOG10 DIALOG DISCARDABLE 0, 0, 223, 116 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Windows 2000 Restricted User Advisory" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",1,166,95,50,14 + LTEXT "In order to install, play or patch Diablo using the Windows 2000 operating system, you will need to log in as either an Administrator or as a Power User.", + -1,7,7,209,28 + LTEXT "Users, also known as Restricted Users, do not have sufficient access to install or play the game properly.", + -1,7,39,209,20 + LTEXT "If you have further questions regarding User Rights in Windows 2000, please refer to your Windows 2000 documentation or contact your system administrator.", + -1,7,63,209,28 +END + +IDD_DIALOG11 DIALOG DISCARDABLE 0, 0, 220, 121 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Read-Only Directory Error" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",1,163,100,50,14 + LTEXT "Diablo is being run from:",-1,7,7,206,10 + LTEXT "unknown directory",1000,17,20,186,20 + LTEXT "Diablo or the current user does not seem to have write privilages in this directory. Contact your system administrator.\n\nNote that Windows 2000 Restricted Users can not write to the Windows or Program Files directory hierarchies.", + -1,7,44,206,50 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2001,5,18,1 + PRODUCTVERSION 1,0,9,2 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Blizzard Entertainment\0" + VALUE "FileDescription", "Diablo\0" + VALUE "FileVersion", "2001, 5, 18, 1\0" + VALUE "InternalName", "Diablo\0" + VALUE "LegalCopyright", "Copyright © 1996-2001\0" + VALUE "OriginalFilename", "Diablo.exe\0" + VALUE "ProductName", "Blizzard Entertainment Diablo\0" + VALUE "ProductVersion", "1, 0, 9, 2\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Diablo.sln b/Diablo.sln new file mode 100644 index 000000000..72ba556b8 --- /dev/null +++ b/Diablo.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2035 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Diablo", "Diablo.vcxproj", "{23114A83-7D81-4F17-A6B8-2FC51F3D72F2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DiabloUI", "DiabloUI\DiabloUI.vcxproj", "{8408E35E-3CF5-4D4E-B873-AF3952CDABD4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Storm", "3rdParty\Storm\Source\Storm.vcxproj", "{B28F69CE-15A1-424D-BBB5-2727258D675B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {23114A83-7D81-4F17-A6B8-2FC51F3D72F2}.Debug|x86.ActiveCfg = Debug|Win32 + {23114A83-7D81-4F17-A6B8-2FC51F3D72F2}.Debug|x86.Build.0 = Debug|Win32 + {23114A83-7D81-4F17-A6B8-2FC51F3D72F2}.Release|x86.ActiveCfg = Release|Win32 + {23114A83-7D81-4F17-A6B8-2FC51F3D72F2}.Release|x86.Build.0 = Release|Win32 + {8408E35E-3CF5-4D4E-B873-AF3952CDABD4}.Debug|x86.ActiveCfg = Debug|Win32 + {8408E35E-3CF5-4D4E-B873-AF3952CDABD4}.Debug|x86.Build.0 = Debug|Win32 + {8408E35E-3CF5-4D4E-B873-AF3952CDABD4}.Release|x86.ActiveCfg = Release|Win32 + {8408E35E-3CF5-4D4E-B873-AF3952CDABD4}.Release|x86.Build.0 = Release|Win32 + {B28F69CE-15A1-424D-BBB5-2727258D675B}.Debug|x86.ActiveCfg = Debug|Win32 + {B28F69CE-15A1-424D-BBB5-2727258D675B}.Debug|x86.Build.0 = Debug|Win32 + {B28F69CE-15A1-424D-BBB5-2727258D675B}.Release|x86.ActiveCfg = Release|Win32 + {B28F69CE-15A1-424D-BBB5-2727258D675B}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6252549D-BED6-405B-9D6D-42C9074D0684} + EndGlobalSection +EndGlobal diff --git a/Diablo.vcxproj b/Diablo.vcxproj new file mode 100644 index 000000000..9dfebcf2d --- /dev/null +++ b/Diablo.vcxproj @@ -0,0 +1,293 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + {23114A83-7D81-4F17-A6B8-2FC51F3D72F2} + 8.1 + + + + Application + v141 + + + Application + v141 + + + + + + + + + + + + + + + .\Source/WinRel\ + .\Source/WinRel\ + + + .\Source/WinDebug\ + .\Source/WinDebug\ + + + + MultiThreaded + Default + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\Source/WinRel\ + .\Source/WinRel\ + .\Source/WinRel\ + 4996 + true + true + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Source/WinRel\Diablo.tlb + true + NUL + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + .\Source/WinRel\Diablo.bsc + + + Windows + .\Source/WinRel\Diablo.exe + DiabloUI/WinRel/DiabloUI.lib;3rdParty/Storm/Source/WinRel/Storm.lib;version.lib;%(AdditionalDependencies) + false + false + + + + + MultiThreadedDebug + OnlyExplicitInline + Disabled + true + Level3 + EditAndContinue + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\Source/WinDebug\ + .\Source/WinDebug\ + .\Source/WinDebug\ + 4996 + true + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Source/WinDebug\Diablo.tlb + true + NUL + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + .\Source/WinDebug\Diablo.bsc + + + true + Windows + .\Source/WinDebug\Diablo.exe + DiabloUI/WinDebug/DiabloUI.lib;3rdParty/Storm/Source/WinDebug/Storm.lib;version.lib;%(AdditionalDependencies) + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {b28f69ce-15a1-424d-bbb5-2727258d675b} + false + + + {8408e35e-3cf5-4d4e-b873-af3952cdabd4} + false + + + + + + \ No newline at end of file diff --git a/Diablo.vcxproj.filters b/Diablo.vcxproj.filters new file mode 100644 index 000000000..5fb895af3 --- /dev/null +++ b/Diablo.vcxproj.filters @@ -0,0 +1,467 @@ + + + + + {0fb229f0-d459-4ec9-b897-317b016e0a57} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {52f34be1-947a-42ee-b303-4a46566a14a7} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {8003aed2-27a6-444b-8fb0-bb8a59530005} + h;hpp;hxx;hm;inl + + + {5dbacde9-4fc8-4776-ba59-92912e0c8ab5} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + PKWare + + + PKWare + + + + + Resource Files + + + + + Resource Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + PKWare + + + diff --git a/DiabloUI/DiabloUI.dsp b/DiabloUI/DiabloUI.dsp new file mode 100644 index 000000000..97c0c0d1c --- /dev/null +++ b/DiabloUI/DiabloUI.dsp @@ -0,0 +1,93 @@ +# Microsoft Developer Studio Project File - Name="DiabloUI" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=DiabloUI - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "DiabloUI.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "DiabloUI.mak" CFG="DiabloUI - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "DiabloUI - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "DiabloUI - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "DiabloUI - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /def:"diabloui.def" + +!ELSEIF "$(CFG)" == "DiabloUI - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /O1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:"diabloui.def" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "DiabloUI - Win32 Release" +# Name "DiabloUI - Win32 Debug" +# Begin Source File + +SOURCE=.\diabloui.cpp +# End Source File +# End Target +# End Project diff --git a/DiabloUI/DiabloUI.vcxproj b/DiabloUI/DiabloUI.vcxproj new file mode 100644 index 000000000..e40bf9ddf --- /dev/null +++ b/DiabloUI/DiabloUI.vcxproj @@ -0,0 +1,146 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + {8408E35E-3CF5-4D4E-B873-AF3952CDABD4} + + + + DynamicLibrary + v141 + false + + + DynamicLibrary + v141 + false + + + + + + + + + + + + + + + .\WinRel\ + .\WinRel\ + false + + + .\WinDebug\ + .\WinDebug\ + true + + + + MultiThreaded + Default + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\WinRel\ + .\WinRel\DiabloUI.pch + .\WinRel\ + .\WinRel\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\WinRel\DiabloUI.tlb + true + NUL + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\WinRel\DiabloUI.bsc + + + true + true + Windows + diabloui.def + .\WinRel\DiabloUI.dll + .\WinRel\DiabloUI.lib + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreadedDebug + Default + Disabled + true + Level3 + true + EditAndContinue + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\WinDebug\ + .\WinDebug\DiabloUI.pch + .\WinDebug\ + .\WinDebug\ + + + true + _DEBUG;%(PreprocessorDefinitions) + .\WinDebug\DiabloUI.tlb + true + NUL + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\WinDebug\DiabloUI.bsc + + + true + true + true + Windows + diabloui.def + .\WinDebug\DiabloUI.dll + .\WinDebug\DiabloUI.lib + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DiabloUI/diabloui.cpp b/DiabloUI/diabloui.cpp new file mode 100644 index 000000000..0058a00de --- /dev/null +++ b/DiabloUI/diabloui.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning (disable : 4018) // signed/unsigned mismatch +#endif + +#include "..\defs.h" +#include "..\enums.h" +#include "..\structs.h" +#include "diabloui.h" + +BOOL APIENTRY DllMain( HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +void __cdecl UiDestroy() { return; } +void __stdcall UiTitleDialog(int a1) { return; } +void __cdecl UiInitialize() { return; } +void __stdcall UiCopyProtError(int a1) { return; } +void __stdcall UiAppActivate(int a1) { return; } +int __stdcall UiValidPlayerName(char *a1) { return 0; } +int __stdcall UiSelHeroMultDialog(void *fninfo, void *fncreate, void *fnremove, void *fnstats, int *a5, int *a6, char *name) { return 0; } +int __stdcall UiSelHeroSingDialog(void *fninfo, void *fncreate, void *fnremove, void *fnstats, int *a5, char *name, int *difficulty) { return 0; } +void __stdcall UiCreditsDialog(int a1) { return; } +int __stdcall UiMainMenuDialog(char *name, int *a2, void *fnSound, int a4) { return 0; } +int __stdcall UiProgressDialog(HWND window, char *msg, int a3, void *fnfunc, int a5) { return 0; } +int __cdecl UiProfileGetString() { return 0; } +void __cdecl UiProfileCallback() { return; } +void __cdecl UiProfileDraw() { return; } +void __cdecl UiCategoryCallback() { return; } +void __cdecl UiGetDataCallback() { return; } +void __cdecl UiAuthCallback() { return; } +void __cdecl UiSoundCallback() { return; } +void __cdecl UiMessageBoxCallback() { return; } +void __cdecl UiDrawDescCallback() { return; } +void __cdecl UiCreateGameCallback() { return; } +void __cdecl UiArtCallback() { return; } +int __stdcall UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, _SNETVERSIONDATA *file_info, int *a6) { return 0; } +int __stdcall UiSelectProvider(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, _SNETVERSIONDATA *file_info, int *type) { return 0; } +int __stdcall UiCreatePlayerDescription(_uiheroinfo *info, int mode, char *desc) { return 0; } +int __stdcall UiSetupPlayerInfo(char *str, _uiheroinfo *info, int mode) { return 0; } diff --git a/DiabloUI/diabloui.def b/DiabloUI/diabloui.def new file mode 100644 index 000000000..cd7e66bcf --- /dev/null +++ b/DiabloUI/diabloui.def @@ -0,0 +1,29 @@ +LIBRARY "DiabloUI" + +EXPORTS + UiDestroy + UiTitleDialog + UiInitialize + UiCopyProtError + UiAppActivate + UiValidPlayerName + UiSelHeroMultDialog + UiSelHeroSingDialog + UiCreditsDialog + UiMainMenuDialog + UiProgressDialog + UiProfileGetString + UiProfileCallback + UiProfileDraw + UiCategoryCallback + UiGetDataCallback + UiAuthCallback + UiSoundCallback + UiMessageBoxCallback + UiDrawDescCallback + UiCreateGameCallback + UiArtCallback + UiSelectGame + UiSelectProvider + UiCreatePlayerDescription + UiSetupPlayerInfo diff --git a/DiabloUI/diabloui.h b/DiabloUI/diabloui.h new file mode 100644 index 000000000..f36ee1a1b --- /dev/null +++ b/DiabloUI/diabloui.h @@ -0,0 +1,40 @@ +//HEADER_GOES_HERE +#ifndef __DIABLOUI_H__ +#define __DIABLOUI_H__ + +#ifdef __GNUC__ +extern "C" { +#endif + +void __cdecl UiDestroy(); +void __stdcall UiTitleDialog(int a1); +void __cdecl UiInitialize(); +void __stdcall UiCopyProtError(int a1); +void __stdcall UiAppActivate(int a1); +int __stdcall UiValidPlayerName(char *a1); +int __stdcall UiSelHeroMultDialog(void *fninfo, void *fncreate, void *fnremove, void *fnstats, int *a5, int *a6, char *name); +int __stdcall UiSelHeroSingDialog(void (*fninfo)(void (__stdcall *ui_add_hero_info)(_uiheroinfo *)), void (*fncreate)(_uiheroinfo *heroinfo), void (*fnremove)(), void (*fnstats)(), int *a5, char *name, int *difficulty); +void __stdcall UiCreditsDialog(int a1); +int __stdcall UiMainMenuDialog(char *name, int *a2, void *fnSound, int a4); +int __stdcall UiProgressDialog(HWND window, char *msg, int a3, void *fnfunc, int a5); +int __cdecl UiProfileGetString(); +void __cdecl UiProfileCallback(); +void __cdecl UiProfileDraw(); +void __cdecl UiCategoryCallback(); +void __cdecl UiGetDataCallback(); +void __cdecl UiAuthCallback(); +void __cdecl UiSoundCallback(); +void __cdecl UiMessageBoxCallback(); +void __cdecl UiDrawDescCallback(); +void __cdecl UiCreateGameCallback(); +void __cdecl UiArtCallback(); +int __stdcall UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, _SNETVERSIONDATA *file_info, int *a6); +int __stdcall UiSelectProvider(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, _SNETVERSIONDATA *file_info, int *type); +int __stdcall UiCreatePlayerDescription(_uiheroinfo *info, int mode, char *desc); +int __stdcall UiSetupPlayerInfo(char *str, _uiheroinfo *info, int mode); + +#ifdef __GNUC__ +} +#endif + +#endif /* __DIABLOUI_H__ */ diff --git a/DiabloUI/diabloui_gcc.def b/DiabloUI/diabloui_gcc.def new file mode 100644 index 000000000..ce7536d14 --- /dev/null +++ b/DiabloUI/diabloui_gcc.def @@ -0,0 +1,48 @@ +LIBRARY "DiabloUI" + +EXPORTS + UiValidPlayerName @1 NONAME + UiValidPlayerName@4 @1 NONAME + UiAppActivate @2 NONAME + UiAppActivate@4 @2 NONAME + UiArtCallback @3 NONAME + UiAuthCallback @4 NONAME + UiBetaDisclaimer @5 NONAME + UiCategoryCallback @6 NONAME + UiCopyProtError @7 NONAME + UiCreateGameCallback @8 NONAME + UiCreateGameCriteria @9 NONAME + UiCreatePlayerDescription @10 NONAME + UiCreatePlayerDescription@12 @10 NONAME + UiCreditsDialog @11 NONAME + UiCreditsDialog@4 @11 NONAME + UiDestroy @12 NONAME + UiDrawDescCallback @13 NONAME + UiGetDataCallback @14 NONAME + UiGetDefaultStats @15 NONAME + UiInitialize @16 NONAME + UiMainMenuDialog @17 NONAME + UiMainMenuDialog@16 @17 NONAME + UiMessageBoxCallback @18 NONAME + UiOnPaint @19 NONAME + UiProfileCallback @20 NONAME + UiProfileDraw @21 NONAME + UiProfileGetString @22 NONAME + UiProgressDialog @23 NONAME + UiProgressDialog@20 @23 NONAME + UiSelHeroMultDialog @24 NONAME + UiSelHeroMultDialog@28 @24 NONAME + UiSelHeroSingDialog @25 NONAME + UiSelHeroSingDialog@28 @25 NONAME + UiSelectGame @26 NONAME + UiSelectGame@24 @26 NONAME + UiSelectProvider @27 NONAME + UiSelectProvider@24 @27 NONAME + UiSelectRegion @28 NONAME + UiSetBackgroundBitmap @29 NONAME + UiSetSpawned @30 NONAME + UiSetupPlayerInfo @31 NONAME + UiSetupPlayerInfo@12 @31 NONAME + UiSoundCallback @32 NONAME + UiTitleDialog @33 NONAME + UiTitleDialog@4 @33 NONAME diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..cf1ab25da --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..d2867df56 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +# mingw32 and mingw64 have different executables +ifdef MINGW32 + CXX=mingw32-g++ + DLLTOOL=dlltool + WINDRES=windres +else + CXX=i686-w64-mingw32-g++ + DLLTOOL=i686-w64-mingw32-dlltool + WINDRES=i686-w64-mingw32-windres +endif + +# Clang doesn't understand permissive compilation, we need to "fix" invalid +# casts from a pointer type there using +# static_cast(reinterpret_cast(ptr)) +# instead of +# (NEW_TYPE)(ptr) +CXXFLAGS=-fpermissive -Wno-write-strings +CPPFLAGS=-MMD -MF $*.d +LDLIBS=-lgdi32 -lversion -ldiabloui -lstorm +LDFLAGS=-L./ -static-libgcc -mwindows + +all: devilution.exe + +debug: CXXFLAGS += -D_DEBUG +debug: CPPFLAGS += -D_DEBUG +debug: devilution.exe + +DIABLO_SRC=$(wildcard Source/*.cpp) +OBJS=$(DIABLO_SRC:.cpp=.o) + +PKWARE_SRC=$(wildcard 3rdParty/PKWare/*.cpp) +PKWARE_OBJS=$(PKWARE_SRC:.cpp=.o) + +devilution.exe: $(OBJS) $(PKWARE_OBJS) diabres.o diabloui.lib storm.lib + $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +diabres.o: Diablo.rc + $(WINDRES) $< $@ + +diabloui.lib: diabloui.dll DiabloUI/diabloui_gcc.def + $(DLLTOOL) -d DiabloUI/diabloui_gcc.def -D $< -l $@ + +diabloui.dll: +# $(error Please copy diabloui.dll (version 1.09[b]) here) + +storm.lib: storm.dll 3rdParty/Storm/Source/storm_gcc.def + $(DLLTOOL) -d 3rdParty/Storm/Source/storm_gcc.def -D $< -l $@ + +storm.dll: +# $(error Please copy storm.dll (version 1.09[b]) here) + +clean: + @$(RM) -v $(OBJS) $(OBJS:.o=.d) $(PKWARE_OBJS) $(PKWARE_OBJS:.o=d) diabres.o storm.lib diabloui.lib devilution.exe + +.PHONY: clean all diff --git a/MakefileVC b/MakefileVC new file mode 100644 index 000000000..ad7fb331d --- /dev/null +++ b/MakefileVC @@ -0,0 +1,83 @@ +VC5_DIR ?= $(HOME)/DevStudio_5.10/VC + +# The $(VS6_DIR) directory is a copy of the "Microsoft Visual Studio" directory. +# +# To get a working setup on Linux or other "portable" copies of VS, +# the following DLLs have to be compied to the +# $(VS6_DIR)/VC98/Bin directory. +# +# - $(VS6_DIR)/Common/MSDev98/Bin/MSPDB60.DLL +VS6_DIR ?= $(HOME)/VS6 + +VC6_DIR = $(VS6_DIR)/VC98 + +VC6_BIN_DIR = $(VC6_DIR)/Bin +VC6_INC_DIR = $(VC6_DIR)/Include +VC6_LIB_DIR = $(VC6_DIR)/Lib + +VC5_LIB_DIR = $(VC5_DIR)/lib + +IDE_DIR ?= $(VS6_DIR)/Common/MSDev98 +IDE_BIN_DIR = $(IDE_DIR)/bin +ifeq ($(OS),Windows_NT) + CL = $(VC6_BIN_DIR)/CL.EXE + RC = $(IDE_BIN_DIR)/RC.EXE + VC5_LINK = $(VC5_DIR)/bin/link.exe + VC6_LINK = $(VC6_BIN_DIR)/link.exe +else + CL = wine $(VC6_BIN_DIR)/CL.EXE + RC = wine $(IDE_BIN_DIR)/RC.EXE + VC5_LINK = wine $(VC5_DIR)/bin/link.exe + VC6_LINK = wine $(VC6_BIN_DIR)/link.exe +endif + +CFLAGS=/nologo /c /GX /W3 /O1 /I $(VC6_INC_DIR) /FD /MT /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fp"Diablo.pch" /YX /Gm /Zi +LINKFLAGS=/nologo /subsystem:windows /machine:I386 /incremental:no + +ifeq ($(MAKE_BUILD),pdb) + VC_LINK = $(VC6_LINK) + LINKFLAGS += /pdb:"Diablo.pdb" /LIBPATH:$(VC6_LIB_DIR) /debug +else + VC_LINK=$(VC5_LINK) + LINKFLAGS+= /LIBPATH:$(VC5_LIB_DIR) +endif + +all: Diablo.exe + +# fix compilation order to match the VC6 workspace files +DIABLO_SRC=$(sort $(filter-out Source/render.cpp, $(wildcard Source/*.cpp))) +DIABLO_SRC += Source/render.cpp +OBJS=$(DIABLO_SRC:.cpp=.obj) + +PKWARE_SRC=$(sort $(wildcard 3rdParty/PKWare/*.cpp)) +PKWARE_OBJS=$(PKWARE_SRC:.cpp=.obj) + +STORM_SRC=$(sort $(wildcard 3rdParty/Storm/Source/*.cpp)) +STORM_OBJS=$(STORM_SRC:.cpp=.obj) + +DIABLOUI_SRC=$(sort $(wildcard DiabloUI/*.cpp)) +DIABLOUI_OBJS=$(DIABLOUI_SRC:.cpp=.obj) + +Diablo.exe: main_files $(PKWARE_OBJS) diablo.res DiabloUI/diabloui.lib 3rdParty/Storm/Source/storm.lib + $(VC_LINK) /OUT:$@ $(LINKFLAGS) $(OBJS) $(PKWARE_OBJS) diablo.res advapi32.lib gdi32.lib shell32.lib user32.lib version.lib DiabloUI/diabloui.lib 3rdParty/Storm/Source/storm.lib + +DiabloUI/diabloui.lib: $(DIABLOUI_OBJS) + $(CL) $^ /link /LINK50COMPAT /nologo /dll /subsystem:windows /machine:I386 /LIBPATH:$(VC6_LIB_DIR) /def:"DiabloUI/diabloui.def" /out:DiabloUI/diabloui.dll + +3rdParty/Storm/Source/storm.lib: $(STORM_OBJS) + $(CL) $^ /link /LINK50COMPAT /nologo /dll /subsystem:windows /machine:I386 /LIBPATH:$(VC6_LIB_DIR) /def:"3rdParty/Storm/Source/storm.def" /out:3rdParty/Storm/Source/storm.dll + +# compiles all main source files with once compiler call +main_files: + $(CL) $(CFLAGS) /FoSource/ $(DIABLO_SRC) + +%.obj: %.cpp + $(CL) $(CFLAGS) /Fo$@ $< + +diablo.res: Diablo.rc + $(RC) /i $(VC6_INC_DIR) /i $(VC6_DIR)/MFC/Include /l 0x409 /fo $@ $< + +clean: + @$(RM) -v $(OBJS) $(PKWARE_OBJS) $(STORM_OBJS) $(DIABLOUI_OBJS) DiabloUI/diabloui.{exp,lib,dll} 3rdParty/Storm/Source/storm.{exp,lib,dll} + +.PHONY: clean all diff --git a/README.md b/README.md new file mode 100644 index 000000000..05f651bcd --- /dev/null +++ b/README.md @@ -0,0 +1,152 @@ +Devilution: [![Build Status](https://travis-ci.org/diasurgical/devilution.svg?branch=master)](https://travis-ci.org/diasurgical/devilution) +[![Build status](https://ci.appveyor.com/api/projects/status/ssk0xjhoka1uu940?svg=true)](https://ci.appveyor.com/project/galaxyhaxz/devilution) + +Nightly: [![Build Status](https://travis-ci.com/diasurgical/devil-nightly.svg?branch=master)](https://travis-ci.com/diasurgical/devil-nightly) + +[Discord](https://discord.gg/XEKDxHK) + +# Devilution +Diablo devolved - magic behind the 1996 computer game + +Reverse engineered by GalaXyHaXz in 2018 + +# Introduction +While most titles from Blizzard receive years of love and support, Diablo stayed in the shadows. Abandoned in favor of a sequel, it remained full of bugs and unfinished potential. The game was last patched in 2001 before being discontinued altogether, a problem I wanted to fix. I played Diablo extensively as a teenager, but as time passed it became difficult to run the game on newer hardware. The lack of many improvements found in the sequel also kept it from aging well. At first the game appeared to be a lost cause, but thankfully a little oversight in 1997 made it not so. + +With Diablo's development team moving on the source code was given to **Synergistic Software** to handle the expansion. Less known however is that it was also given to **Climax Studios** to create a PlayStation port. Now Sony has long been known for letting things slide; _especially_ in Japan. Anything from leaking prototypes to full source code and Diablo was no exception. Symbolic information was accidentally left on the Japanese port. Normally used for debugging, a symbol file contains a map of everything generated during compile time. This includes file names, functions, structures, variables, and more! To top it all off a special build is hidden on the PC release in `DIABDAT.MPQ -> D1221A.MPQ -> DIABLO.EXE`! This build contains debug tools and assert strings further giving away code information. + +After months of piecing these mistakes together, Devilution was born. I present to you a reconstructed form of Diablo's original source code! Once more shall the heroes of Sanctuary return to the depths below! + +# Purpose +Having the source code makes Diablo much easier to update and maintain. For years mod-makers had to rely on tedious code editing and memory injection. A few even went further and reversed most or all of the game. The problem is that they rarely shared their work. Usually being a one-person job, they move on with their lives due to the amount of time required or lack of interest. This brings us back to square one having to do countless hours of work all over again. Devilution aims to fix this by finally making the source code open to the community. + +In order to ensure that everything is preserved, Devilution keeps everything as it was originally designed. This goes as far as bugs and badly written code in the original game. With that it serves as a base for developers to work with making it much easier than before to update, fix, and port the game to other platforms. + +As a side goal Devilution tries to document the unused and cut content from the final game. Development of Diablo was rushed near the end--many ideas were scrapped and multiplayer was quickly hacked in. By examining the source, we can see various quirks of planned development. + +# Compiling +Diablo was developed on Windows 95 using Visual C++ 4.20 and later 5.10 and 6 for newer patches. Devilution is optimized for the same tools originally used but is also compatible with modern setups. + +### Building with Visual C++ 6 +- Open the project workspace `Diablo.dsw`, choose `Debug` or `Release`, and then `Build Diablo.exe`. + +To build a binary with functions compiled as close as possible to the original, use [Visual C++ 6](https://winworldpc.com/product/visual-c/6x) with Service Pack 5 and the [Processor Pack](https://download.microsoft.com/download/vb60ent/update/6/w9x2kxp/en-us/vcpp5.exe) (**important for proper code genration!**) + +If you aim to build a binary as close as possible to the original one you will also need [Visual C++ 5](https://winworldpc.com/product/visual-c/5x) with [Service Pack 3](http://www.mediafire.com/file/jw4j4sd5dnzze4p/VS97SP3.zip), since the original binary as linked with the older linker from that. Sadly, you cannot use the old linker right out of VC6, so you'll need to link manually or via the `MakefileVC` in the project root. + +### Building with Visual Studio 2010-2017 +- Open the project solution `Diablo.sln`, choose `Debug` or `Release`, and then `Build Solution`. + +Make sure to disable Data Execution Prevention. `Storm.dll` uses dynamic compilation to improve rendering performance but fails to mark the resulting memory page as executable, leading to a protection fault when trying to draw. +- Configuration options -> Linker -> Advanced -> Data Execution Prevention (DEP). +- Set this value to: No (/NXCOMPAT: NO). + +You will also need the following dependencies installed if you are using Visual Studio 2017. +Make sure to enable these when installing (or modify your installation): +- Requires "Windows 8.1 SDK" (Target Platform) +- Requires "Visual C++ MFC for x86 and x64" (For afxres.h) +- Requires "Windows Universal CRT SDK" (For ctype.h) + +### Building XDiablo (For Linux) +Install the following libs on your machine. +- apt-get install g++-multilib libc6-dev-i386 +- apt-get install libsdl2-dev:i386 +- apt-get install libsdl2-ttf-dev:i386 +- apt-get install libsdl2-image-dev:i386 +- apt-get install libsdl2-mixer-dev:i386 +- apt-get install cmake + +Edit File that is linking all the LIBS for CMAKE. +For me it was located in... +/usr/lib/i386-linux-gnu/cmake/SDL2/sdl2-config.cmake + +The last line will have something like... + set(SDL2_LIBRARIES "-L${SDL2_LIBDIR} -lSDL2 +Change it to ... +set(SDL2_LIBRARIES "-L${SDL2_LIBDIR} -lSDL2 -lSDL2_image -lSDL2_mixer -lSDL2_ttf ") + + +Copy the "diablodat.mpq" from your Diablo CD to the Diablo Directory and make sure it is LOWERCASE. +Copy the Xresources and fonts file to your Diablo Directory. + + +Keep in mind please that this is still being worked on and is missing parts of UI and SoundEffects are not properly playing now. + + + + + + +### Building with MinGW +- Execute `make MINGW32=1` for **MinGW32** or `make` for **MinGW64**. Optionally add `debug` to build with debug features. + +To compile with MinGW64 on different platforms, refer to the respective documentation: [Linux](Support/INSTALL_linux.md) | [Windows](Support/INSTALL_windows.md) | [Mac](Support/INSTALL_mac.md). + +[Debug Build Features](Support/debug.md) +| [Compatibility Matrix](Support/compatibility_matrix.md) +| [Troubleshooting](Support/troubleshooting.md) + +# Installing +Once compiled, the Devilution binary will serve as a replacement for `Diablo.exe`. The following files from the original game patched to 1.09(b) need to be present: `DIABDAT.MPQ`, `DiabloUI.dll`, `SmackW32.dll`, `Standard.snp`, and `Storm.dll`. If `COPYPROT` was defined when compiling, the Diablo CD will also be required. + +Additionally, Strange Bytes' [DirectDraw patch](http://www.strangebytes.com/index.php/projects/1-diablo-1-windows-7-vista-patch) is recommended to help fix compatibility issues and run the game in windowed mode. + +# Multiplayer +TODO + +# Contributing +[Guidelines](Support/CONTRIBUTING.md) + +# Modding +Here are some screenshots of a few things I tinkered around with, to demonstrate the relative ease of improving the game: + +![Screenshot 1: Monster lifebar+items](https://s33.postimg.cc/6xnnhhlmn/diabuimon.png "Monster lifebar+items") + +![Screenshot 2: New trade screen](https://s22.postimg.cc/5i5k91vht/diabstore.png "New trade screen, items that couldn't spawn") + +# F.A.Q. +> Wow, does this mean I can download and play Diablo for free now? + +No, you'll need access to the data from the original game. Blizzard has discontinued Diablo, but there's plenty of used copies floating around. (I'm still using an original 1996-disc in 2018 without problems) +> Cool, so I fired your mod up, but there's no 1080p or new features? + +Devilution aims to keep the original code unaltered, for documentation purposes. +> So will you ever add cross-platform support or new features in the future? + +Yes! However, this will be a **_side project_** based on Devilution. I have yet to announce the project. +> When and what can I expect from the upcoming project? + +Honestly I have no idea. More than 1,200 hours went into creating Devilution, and I have other things going on right now. Maybe in 6-12 months? The goal is to create a native Linux port, convert to OpenGL, modernize the UI, etc. you get the drill. There has to be some surprises. ;) +> Ok, so I'm playing Devilution now and all the sudden it crashed. NOW WHAT?? + +Open an issue and provide as much information as possible (OS version, etc.) including any crash logs. +> I thought I'd fix the crash myself, but after looking at the code its a disaster. Do you speak v2-34-v8? + +That is the result of decompiled code. Whenever a program is compiled, much of the source is optimized and stripped away, so it's nearly impossible to decompile it back. Have patience. Everything will be cleaned up eventually. :) +> Will you be reverse engineering Diablo II next? Ooooh please! + +Absolutely not. Diablo II would require far more work and is still supported by Blizzard. Setting that aside, there are rumors that the game will be remastered which takes the point out of it. +> Are you interested in working for me? I have this game I want you to reverse... + +Sorry, but no. This project is time consuming enough as it is, and it's just a hobby. +> I think that's about all, but is Devilution even legal? + +That's a tricky question. Under the DMCA, reverse-engineering has exceptions for the purpose of documentation and interoperability. Devilution provides the necessary documentation needed to achieve the latter. However, it falls into an entirely gray area. The real question is whether or not Blizzard deems it necessary to take action. + +# Credits +- [sanctuary](https://github.com/sanctuary) - extensively documenting Diablo's game engine +- [BWAPI Team](https://github.com/bwapi) - providing library API to work with Storm +- [Ladislav Zezula](https://github.com/ladislav-zezula) - reversing PKWARE library, further documenting Storm +- [fearedbliss](https://github.com/fearedbliss) - being awe-inspiring +- Climax Studios & Sony - secretly helping with their undercover QA :P +- Blizzard North - wait, this was a typo! +- Depression - reason to waste four months of my life doing this ;) + +# Legal +This software is being released to the Public Domain. No assets of Diablo are being provided. You must own a copy of Diablo and have access to the assets beforehand in order to use this software. + +Battle.net(R) - Copyright (C) 1996 Blizzard Entertainment, Inc. All rights reserved. Battle.net and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. + +Diablo(R) - Copyright (C) 1996 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. + +This software is in no way associated with or endorsed by Blizzard Entertainment(R). diff --git a/Source/appfat.cpp b/Source/appfat.cpp new file mode 100644 index 000000000..f8709396e --- /dev/null +++ b/Source/appfat.cpp @@ -0,0 +1,437 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +// +Infinity after initialization of appfat.cpp. +float appfat_cpp_init_value; + +#ifndef NO_GLOBALS +char sz_error_buf[256]; +int terminating; // weak +int cleanup_thread_id; // weak +#endif + +char empty_string; + +// appfat_cpp_init initializes the C++ runtime of appfat.cpp. +struct appfat_cpp_init { + appfat_cpp_init() { + appfat_cpp_init_value = INFINITY; + } +} appfat_cpp_init; + +// delete overloads the delete operator. +void operator delete(void *ptr) { + if (ptr != NULL) { + SMemFree(ptr, "delete", -1, 0); + } +} + +char *__fastcall GetErrorStr(int error_code) +{ + int v1; // edi + unsigned int v2; // eax + signed int v4; // eax + char *i; // ecx + + v1 = error_code; + v2 = ((unsigned int)error_code >> 16) & 0x1FFF; + if ( v2 == 0x0878 ) + { + TraceErrorDS(error_code, sz_error_buf, 256); + } + else if ( v2 == 0x0876 ) + { + TraceErrorDD(error_code, sz_error_buf, 256); + } + else + { + if ( !SErrGetErrorStr(error_code, sz_error_buf, 256) && !FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, v1, 0x400u, sz_error_buf, 0x100u, NULL) ) + wsprintf(sz_error_buf, "unknown error 0x%08x", v1); + } + v4 = strlen(sz_error_buf); + for ( i = &sz_error_buf[v4-1]; v4 > 0; *i = 0 ) + { + --v4; + --i; + if ( *i != '\r' && *i != '\n' ) + break; + } + return sz_error_buf; +} + +#define CASE_ERROR(v, errName) case errName: v = #errName; break; + +void __fastcall TraceErrorDD(int error_code, char *error_buf, int error_buf_len) +{ + const char *v3; // eax + char v4[20]; // [esp+0h] [ebp-14h] + + switch (error_code) { + CASE_ERROR(v3, DDERR_CANTPAGEUNLOCK); + CASE_ERROR(v3, DDERR_NOTPAGELOCKED); + CASE_ERROR(v3, DD_OK); + CASE_ERROR(v3, DDERR_CANTPAGELOCK); + CASE_ERROR(v3, DDERR_BLTFASTCANTCLIP); + CASE_ERROR(v3, DDERR_NOBLTHW); + CASE_ERROR(v3, DDERR_NODDROPSHW); + CASE_ERROR(v3, DDERR_OVERLAYNOTVISIBLE); + CASE_ERROR(v3, DDERR_NOOVERLAYDEST); + CASE_ERROR(v3, DDERR_INVALIDPOSITION); + CASE_ERROR(v3, DDERR_NOTAOVERLAYSURFACE); + CASE_ERROR(v3, DDERR_EXCLUSIVEMODEALREADYSET); + CASE_ERROR(v3, DDERR_NOTFLIPPABLE); + CASE_ERROR(v3, DDERR_CANTDUPLICATE); + CASE_ERROR(v3, DDERR_NOTLOCKED); + CASE_ERROR(v3, DDERR_CANTCREATEDC); + CASE_ERROR(v3, DDERR_NODC); + CASE_ERROR(v3, DDERR_WRONGMODE); + CASE_ERROR(v3, DDERR_IMPLICITLYCREATED); + CASE_ERROR(v3, DDERR_NOTPALETTIZED); + CASE_ERROR(v3, DDERR_NOMIPMAPHW); + CASE_ERROR(v3, DDERR_INVALIDSURFACETYPE); + CASE_ERROR(v3, DDERR_DCALREADYCREATED); + CASE_ERROR(v3, DDERR_NOPALETTEHW); + CASE_ERROR(v3, DDERR_DIRECTDRAWALREADYCREATED); + CASE_ERROR(v3, DDERR_NODIRECTDRAWHW); + CASE_ERROR(v3, DDERR_PRIMARYSURFACEALREADYEXISTS); + CASE_ERROR(v3, DDERR_NOEMULATION); + CASE_ERROR(v3, DDERR_REGIONTOOSMALL); + CASE_ERROR(v3, DDERR_CLIPPERISUSINGHWND); + CASE_ERROR(v3, DDERR_NOCLIPPERATTACHED); + CASE_ERROR(v3, DDERR_NOHWND); + CASE_ERROR(v3, DDERR_HWNDSUBCLASSED); + CASE_ERROR(v3, DDERR_HWNDALREADYSET); + CASE_ERROR(v3, DDERR_NOPALETTEATTACHED); + CASE_ERROR(v3, DDERR_INVALIDDIRECTDRAWGUID); + CASE_ERROR(v3, DDERR_UNSUPPORTEDFORMAT); + CASE_ERROR(v3, DDERR_UNSUPPORTEDMASK); + CASE_ERROR(v3, DDERR_VERTICALBLANKINPROGRESS); + CASE_ERROR(v3, DDERR_WASSTILLDRAWING); + CASE_ERROR(v3, DDERR_XALIGN); + CASE_ERROR(v3, DDERR_TOOBIGWIDTH); + CASE_ERROR(v3, DDERR_CANTLOCKSURFACE); + CASE_ERROR(v3, DDERR_SURFACEISOBSCURED); + CASE_ERROR(v3, DDERR_SURFACELOST); + CASE_ERROR(v3, DDERR_SURFACENOTATTACHED); + CASE_ERROR(v3, DDERR_TOOBIGHEIGHT); + CASE_ERROR(v3, DDERR_TOOBIGSIZE); + CASE_ERROR(v3, DDERR_SURFACEBUSY); + CASE_ERROR(v3, DDERR_OVERLAYCOLORKEYONLYONEACTIVE); + CASE_ERROR(v3, DDERR_PALETTEBUSY); + CASE_ERROR(v3, DDERR_COLORKEYNOTSET); + CASE_ERROR(v3, DDERR_SURFACEALREADYATTACHED); + CASE_ERROR(v3, DDERR_SURFACEALREADYDEPENDENT); + CASE_ERROR(v3, DDERR_OVERLAYCANTCLIP); + CASE_ERROR(v3, DDERR_NOVSYNCHW); + CASE_ERROR(v3, DDERR_NOZBUFFERHW); + CASE_ERROR(v3, DDERR_NOZOVERLAYHW); + CASE_ERROR(v3, DDERR_OUTOFCAPS); + CASE_ERROR(v3, DDERR_OUTOFVIDEOMEMORY); + CASE_ERROR(v3, DDERR_NOTEXTUREHW); + CASE_ERROR(v3, DDERR_NOROTATIONHW); + CASE_ERROR(v3, DDERR_NOSTRETCHHW); + CASE_ERROR(v3, DDERR_NOT4BITCOLOR); + CASE_ERROR(v3, DDERR_NOT4BITCOLORINDEX); + CASE_ERROR(v3, DDERR_NOT8BITCOLOR); + CASE_ERROR(v3, DDERR_NORASTEROPHW); + CASE_ERROR(v3, DDERR_NOEXCLUSIVEMODE); + CASE_ERROR(v3, DDERR_NOFLIPHW); + CASE_ERROR(v3, DDERR_NOGDI); + CASE_ERROR(v3, DDERR_NOMIRRORHW); + CASE_ERROR(v3, DDERR_NOTFOUND); + CASE_ERROR(v3, DDERR_NOOVERLAYHW); + CASE_ERROR(v3, DDERR_NOCOLORKEYHW); + CASE_ERROR(v3, DDERR_NOALPHAHW); + CASE_ERROR(v3, DDERR_NOCLIPLIST); + CASE_ERROR(v3, DDERR_NOCOLORCONVHW); + CASE_ERROR(v3, DDERR_NOCOOPERATIVELEVELSET); + CASE_ERROR(v3, DDERR_NOCOLORKEY); + CASE_ERROR(v3, DDERR_NO3D); + CASE_ERROR(v3, DDERR_INVALIDMODE); + CASE_ERROR(v3, DDERR_INVALIDOBJECT); + CASE_ERROR(v3, DDERR_INVALIDPIXELFORMAT); + CASE_ERROR(v3, DDERR_INVALIDRECT); + CASE_ERROR(v3, DDERR_LOCKEDSURFACES); + CASE_ERROR(v3, DDERR_INVALIDCLIPLIST); + CASE_ERROR(v3, DDERR_CURRENTLYNOTAVAIL); + CASE_ERROR(v3, DDERR_EXCEPTION); + CASE_ERROR(v3, DDERR_HEIGHTALIGN); + CASE_ERROR(v3, DDERR_INCOMPATIBLEPRIMARY); + CASE_ERROR(v3, DDERR_INVALIDCAPS); + CASE_ERROR(v3, DDERR_CANNOTDETACHSURFACE); + CASE_ERROR(v3, DDERR_UNSUPPORTED); + CASE_ERROR(v3, DDERR_GENERIC); + CASE_ERROR(v3, DDERR_OUTOFMEMORY); + CASE_ERROR(v3, DDERR_INVALIDPARAMS); + CASE_ERROR(v3, DDERR_ALREADYINITIALIZED); + CASE_ERROR(v3, DDERR_CANNOTATTACHSURFACE); + default: + strcpy(v4, "DDERR unknown 0x%x"); + sprintf(error_buf, v4, error_code); + return; + } + strncpy(error_buf, v3, error_buf_len); +} + +void __fastcall TraceErrorDS(int error_code, char *error_buf, int error_buf_len) +{ + const char *v3; // eax + char v4[20]; // [esp+0h] [ebp-14h] + + switch (error_code) { + CASE_ERROR(v3, DSERR_PRIOLEVELNEEDED); + CASE_ERROR(v3, DSERR_BADFORMAT); + CASE_ERROR(v3, DSERR_NODRIVER); + CASE_ERROR(v3, DSERR_ALREADYINITIALIZED); + CASE_ERROR(v3, DSERR_BUFFERLOST); + CASE_ERROR(v3, DS_OK); + CASE_ERROR(v3, DSERR_INVALIDCALL); + CASE_ERROR(v3, E_NOINTERFACE); + CASE_ERROR(v3, DSERR_NOAGGREGATION); + CASE_ERROR(v3, DSERR_OUTOFMEMORY); + CASE_ERROR(v3, DSERR_INVALIDPARAM); + CASE_ERROR(v3, DSERR_ALLOCATED); + CASE_ERROR(v3, DSERR_CONTROLUNAVAIL); + default: + strcpy(v4, "DSERR unknown 0x%x"); + sprintf(error_buf, v4, error_code); + return; + } + strncpy(error_buf, v3, error_buf_len); +} + +char *__cdecl TraceLastError() +{ + int v0; // eax + + v0 = GetLastError(); + return GetErrorStr(v0); +} + +void TermMsg(char *pszFmt, ...) +{ + va_list arglist; // [esp+8h] [ebp+8h] + + va_start(arglist, pszFmt); + FreeDlg(); + if ( pszFmt ) + MsgBox(pszFmt, arglist); + init_cleanup(0); + exit(1); +} + +void __fastcall MsgBox(char *pszFmt, va_list va) +{ + char Text[256]; // [esp+0h] [ebp-100h] + + wvsprintf(Text, pszFmt, va); + if ( ghMainWnd ) + SetWindowPos(ghMainWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE); + MessageBox(ghMainWnd, Text, "ERROR", MB_TASKMODAL|MB_ICONHAND); +} + +void __cdecl FreeDlg() +{ + if ( terminating && cleanup_thread_id != GetCurrentThreadId() ) + Sleep(20000u); + terminating = 1; + cleanup_thread_id = GetCurrentThreadId(); + dx_cleanup(); + if ( (unsigned char)gbMaxPlayers > 1u ) + { + if ( SNetLeaveGame(3) ) + Sleep(2000u); + } + SNetDestroy(); + ShowCursor(1); +} +// 4B7A34: using guessed type int terminating; +// 4B7A38: using guessed type int cleanup_thread_id; +// 679660: using guessed type char gbMaxPlayers; + +void DrawDlg(char *pszFmt, ...) +{ + char text[256]; // [esp+0h] [ebp-100h] + va_list arglist; // [esp+10Ch] [ebp+Ch] + + va_start(arglist, pszFmt); + wvsprintf(text, pszFmt, arglist); + SDrawMessageBox(text, "Diablo", MB_TASKMODAL|MB_ICONEXCLAMATION); +} + +void __fastcall DDErrMsg(int error_code, int log_line_nr, char *log_file_path) +{ + int v3; // esi + char *v4; // eax + + v3 = log_line_nr; + if ( error_code ) + { + v4 = GetErrorStr(error_code); + TermMsg("Direct draw error (%s:%d)\n%s", log_file_path, v3, v4); + } +} + +void __fastcall DSErrMsg(int error_code, int log_line_nr, char *log_file_path) +{ + int v3; // esi + char *v4; // eax + + v3 = log_line_nr; + if ( error_code ) + { + v4 = GetErrorStr(error_code); + TermMsg("Direct sound error (%s:%d)\n%s", log_file_path, v3, v4); + } +} + +void __fastcall center_window(HWND hDlg) +{ + LONG v1; // esi + LONG v2; // edi + int v3; // ebx + char *v4; // eax + struct tagRECT Rect; // [esp+Ch] [ebp-1Ch] + int v6; // [esp+1Ch] [ebp-Ch] + HDC hdc; // [esp+20h] [ebp-8h] + HWND hWnd; // [esp+24h] [ebp-4h] + + hWnd = hDlg; + GetWindowRect(hDlg, &Rect); + v1 = Rect.right - Rect.left; + v2 = Rect.bottom - Rect.top; + hdc = GetDC(hWnd); + v6 = GetDeviceCaps(hdc, HORZRES); + v3 = GetDeviceCaps(hdc, VERTRES); + ReleaseDC(hWnd, hdc); + if ( !SetWindowPos(hWnd, HWND_TOP, (v6 - v1) / 2, (v3 - v2) / 2, 0, 0, SWP_NOZORDER|SWP_NOSIZE) ) + { + v4 = TraceLastError(); + TermMsg("center_window: %s", v4); + } +} + +void __fastcall ErrDlg(int template_id, int error_code, char *log_file_path, int log_line_nr) +{ + int v4; // ebx + int v5; // edi + char *v6; // esi + char *v7; // eax + char *v8; // eax + LPARAM dwInitParam[128]; // [esp+Ch] [ebp-200h] + + v4 = error_code; + v5 = template_id; + FreeDlg(); + v6 = log_file_path; + v7 = strrchr(log_file_path, '\\'); + if ( v7 ) + v6 = v7 + 1; + v8 = GetErrorStr(v4); + wsprintf((LPSTR)dwInitParam, "%s\nat: %s line %d", v8, v6, log_line_nr); + if ( DialogBoxParam(ghInst, MAKEINTRESOURCE(v5), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)dwInitParam) == -1 ) + TermMsg("ErrDlg: %d", v5); + TermMsg(0); +} + +BOOL __stdcall FuncDlg(HWND hDlg, UINT uMsg, WPARAM wParam, char *text) +{ + if ( uMsg == WM_INITDIALOG ) + { + TextDlg(hDlg, text); + } + else + { + if ( uMsg != WM_COMMAND ) + return 0; + if ( (_WORD)wParam == 1 ) + { + EndDialog(hDlg, 1); + } + else if ( (_WORD)wParam == 2 ) + { + EndDialog(hDlg, 0); + } + } + return 1; +} + +void __fastcall TextDlg(HWND hDlg, char *text) +{ + char *v2; // esi + HWND v3; // edi + + v2 = text; + v3 = hDlg; + center_window(hDlg); + if ( v2 ) + SetDlgItemText(v3, 1000, v2); +} + +void __fastcall ErrOkDlg(int template_id, int error_code, char *log_file_path, int log_line_nr) +{ + char *v4; // esi + int v5; // edi + unsigned short v6; // bx + char *v7; // eax + char *v8; // eax + LPARAM dwInitParam[128]; // [esp+Ch] [ebp-200h] + + v4 = log_file_path; + v5 = error_code; + v6 = template_id; + v7 = strrchr(log_file_path, '\\'); + if ( v7 ) + v4 = v7 + 1; + v8 = GetErrorStr(v5); + wsprintf((LPSTR)dwInitParam, "%s\nat: %s line %d", v8, v4, log_line_nr); + DialogBoxParam(ghInst, MAKEINTRESOURCE(v6), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)dwInitParam); +} + +void __fastcall FileErrDlg(char *error) +{ + char *v1; // esi + + v1 = error; + FreeDlg(); + if ( !v1 ) + v1 = &empty_string; + if ( DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_DIALOG3), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)v1) == -1 ) + TermMsg("FileErrDlg"); + TermMsg(0); +} + +void __fastcall DiskFreeDlg(char *error) +{ + char *v1; // esi + + v1 = error; + FreeDlg(); + if ( DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_DIALOG7), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)v1) == -1 ) + TermMsg("DiskFreeDlg"); + TermMsg(0); +} + +bool __cdecl InsertCDDlg() +{ + int v0; // edi + + ShowCursor(1); + v0 = DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_DIALOG9), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)&empty_string); + if ( v0 == -1 ) + TermMsg("InsertCDDlg"); + ShowCursor(0); + return v0 == 1; +} + +void __fastcall DirErrorDlg(char *error) +{ + char *v1; // esi + + v1 = error; + FreeDlg(); + if ( DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_DIALOG11), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)v1) == -1 ) + TermMsg("DirErrorDlg"); + TermMsg(0); +} diff --git a/Source/appfat.h b/Source/appfat.h new file mode 100644 index 000000000..d0542b40e --- /dev/null +++ b/Source/appfat.h @@ -0,0 +1,30 @@ +//HEADER_GOES_HERE +#ifndef __APPFAT_H__ +#define __APPFAT_H__ + +extern char sz_error_buf[256]; +extern int terminating; // weak +extern int cleanup_thread_id; // weak +extern char empty_string; + +char *__fastcall GetErrorStr(int error_code); +void __fastcall TraceErrorDD(int error_code, char *error_buf, int error_buf_len); +void __fastcall TraceErrorDS(int error_code, char *error_buf, int error_buf_len); +char *__cdecl TraceLastError(); +void TermMsg(char *pszFmt, ...); +void __fastcall MsgBox(char *pszFmt, va_list va); +void __cdecl FreeDlg(); +void DrawDlg(char *pszFmt, ...); +void __fastcall DDErrMsg(int error_code, int log_line_nr, char *log_file_path); +void __fastcall DSErrMsg(int error_code, int log_line_nr, char *log_file_path); +void __fastcall center_window(HWND hDlg); +void __fastcall ErrDlg(int template_id, int error_code, char *log_file_path, int log_line_nr); +BOOL __stdcall FuncDlg(HWND hDlg, UINT uMsg, WPARAM wParam, char *text); +void __fastcall TextDlg(HWND hDlg, char *text); +void __fastcall ErrOkDlg(int template_id, int error_code, char *log_file_path, int log_line_nr); +void __fastcall FileErrDlg(char *error); +void __fastcall DiskFreeDlg(char *error); +bool __cdecl InsertCDDlg(); +void __fastcall DirErrorDlg(char *error); + +#endif /* __APPFAT_H__ */ diff --git a/Source/automap.cpp b/Source/automap.cpp new file mode 100644 index 000000000..4e7190679 --- /dev/null +++ b/Source/automap.cpp @@ -0,0 +1,943 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +short automaptype[512]; +int AMdword_4B7E40; // weak +int AMdword_4B7E44; // weak +bool automapflag; // idb +char AMbyte_4B7E4C[32]; +char automapview[DMAXX][DMAXY]; +int AutoMapScale; // idb +int AutoMapXOfs; // weak +int AutoMapYOfs; // weak +int AutoMapPosBits; // weak +int AutoMapXPos; // weak +int AutoMapYPos; // weak +int AMPlayerX; // weak +int AMPlayerY; // weak +#endif + +void __cdecl InitAutomapOnce() +{ + automapflag = 0; + AutoMapScale = 50; + AutoMapPosBits = 32; + AutoMapXPos = 16; + AutoMapYPos = 8; + AMPlayerX = 4; + AMPlayerY = 2; +} +// 4B84B8: using guessed type int AutoMapPosBits; +// 4B84BC: using guessed type int AutoMapXPos; +// 4B84C0: using guessed type int AutoMapYPos; +// 4B84C4: using guessed type int AMPlayerX; +// 4B84C8: using guessed type int AMPlayerY; + +void __cdecl InitAutomap() +{ + signed int v0; // edi + signed int v1; // ecx + int v2; // esi + char v3; // al + int v4; // esi + char v5; // al + char *v6; // ecx + unsigned char *v7; // eax + int v8; // ecx + unsigned char *v9; // edx + unsigned int i; // esi + unsigned char v11; // bl + _BYTE *v12; // edx + signed int v13; // ecx + _BYTE *v14; // eax + signed int v15; // edx + int size; // [esp+Ch] [ebp-4h] + + v0 = 50; + v1 = 0; + do + { + v2 = (v0 << 6) / 100; + v3 = 2 * (320 / v2); + v4 = 320 % v2; + v5 = v3 + 1; + AMbyte_4B7E4C[v1] = v5; + if ( v4 ) + AMbyte_4B7E4C[v1] = v5 + 1; + if ( v4 >= 32 * v0 / 100 ) + ++AMbyte_4B7E4C[v1]; + v0 += 5; + ++v1; + } + while ( v1 < 31 ); + memset(automaptype, 0, 0x400u); + switch ( leveltype ) + { + case DTYPE_CATHEDRAL: + v6 = "Levels\\L1Data\\L1.AMP"; + break; + case DTYPE_CATACOMBS: + v6 = "Levels\\L2Data\\L2.AMP"; + break; + case DTYPE_CAVES: + v6 = "Levels\\L3Data\\L3.AMP"; + break; + case DTYPE_HELL: + v6 = "Levels\\L4Data\\L4.AMP"; + break; + default: + return; + } + v7 = LoadFileInMem(v6, &size); + size = (unsigned int)size >> 1; + v9 = v7; + for ( i = 1; i <= size; ++i ) + { + v11 = *v9; + v12 = v9 + 1; + _LOWORD(v0) = v11; + _LOBYTE(v8) = *v12; + v9 = v12 + 1; + _LOWORD(v8) = (unsigned char)v8; + v8 = v0 + (v8 << 8); + automaptype[i] = v8; + } + mem_free_dbg(v7); + memset(automapview, 0, 0x640u); + v13 = 0; + do + { + v14 = (unsigned char *)dFlags + v13; + v15 = 112; + do + { + *v14 &= 0x7Fu; + v14 += 112; + --v15; + } + while ( v15 ); + ++v13; + } + while ( v13 < 112 ); +} +// 5BB1ED: using guessed type char leveltype; + +void __cdecl StartAutomap() +{ + AutoMapXOfs = 0; + AutoMapYOfs = 0; + automapflag = 1; +} +// 4B84B0: using guessed type int AutoMapXOfs; +// 4B84B4: using guessed type int AutoMapYOfs; + +void __cdecl AutomapUp() +{ + --AutoMapXOfs; + --AutoMapYOfs; +} +// 4B84B0: using guessed type int AutoMapXOfs; +// 4B84B4: using guessed type int AutoMapYOfs; + +void __cdecl AutomapDown() +{ + ++AutoMapXOfs; + ++AutoMapYOfs; +} +// 4B84B0: using guessed type int AutoMapXOfs; +// 4B84B4: using guessed type int AutoMapYOfs; + +void __cdecl AutomapLeft() +{ + --AutoMapXOfs; + ++AutoMapYOfs; +} +// 4B84B0: using guessed type int AutoMapXOfs; +// 4B84B4: using guessed type int AutoMapYOfs; + +void __cdecl AutomapRight() +{ + ++AutoMapXOfs; + --AutoMapYOfs; +} +// 4B84B0: using guessed type int AutoMapXOfs; +// 4B84B4: using guessed type int AutoMapYOfs; + +void __cdecl AutomapZoomIn() +{ + if ( AutoMapScale < 200 ) + { + AutoMapScale += 5; + AutoMapPosBits = (AutoMapScale << 6) / 100; + AutoMapXPos = AutoMapPosBits >> 1; + AutoMapYPos = AutoMapPosBits >> 2; + AMPlayerX = AutoMapPosBits >> 3; + AMPlayerY = AutoMapPosBits >> 4; + } +} +// 4B84B8: using guessed type int AutoMapPosBits; +// 4B84BC: using guessed type int AutoMapXPos; +// 4B84C0: using guessed type int AutoMapYPos; +// 4B84C4: using guessed type int AMPlayerX; +// 4B84C8: using guessed type int AMPlayerY; + +void __cdecl AutomapZoomOut() +{ + if ( AutoMapScale > 50 ) + { + AutoMapScale -= 5; + AutoMapPosBits = (AutoMapScale << 6) / 100; + AutoMapXPos = AutoMapPosBits >> 1; + AutoMapYPos = AutoMapPosBits >> 2; + AMPlayerX = AutoMapPosBits >> 3; + AMPlayerY = AutoMapPosBits >> 4; + } +} +// 4B84B8: using guessed type int AutoMapPosBits; +// 4B84BC: using guessed type int AutoMapXPos; +// 4B84C0: using guessed type int AutoMapYPos; +// 4B84C4: using guessed type int AMPlayerX; +// 4B84C8: using guessed type int AMPlayerY; + +void __cdecl DrawAutomap() +{ + int v0; // eax + int v1; // ecx + int v2; // edx + int v3; // edx + int v4; // ecx + int v5; // eax + int v6; // esi + int v7; // edx + int v8; // edx + int v9; // esi + int v10; // ebx + int v11; // edi + int v12; // esi + int v13; // edi + int v14; // esi + int v15; // ebp + short v16; // ax + int v17; // ebp + short v18; // ax + int v19; // [esp+0h] [ebp-18h] + int screen_x; // [esp+4h] [ebp-14h] + int screen_xa; // [esp+4h] [ebp-14h] + int v22; // [esp+8h] [ebp-10h] + int ty; // [esp+Ch] [ebp-Ch] + int tya; // [esp+Ch] [ebp-Ch] + int v25; // [esp+10h] [ebp-8h] + int screen_y; // [esp+14h] [ebp-4h] + + if ( leveltype != DTYPE_TOWN ) + { + gpBufEnd = (unsigned char *)&gpBuffer->row[352]; + v0 = AutoMapXOfs; + v1 = (ViewX - 16) >> 1; + v2 = AutoMapXOfs + v1; + if ( AutoMapXOfs + v1 < 0 ) + { + do + { + ++v0; + ++v2; + } + while ( v2 < 0 ); + AutoMapXOfs = v0; + } + v3 = v0 + v1; + if ( v0 + v1 >= 40 ) + { + do + { + --v0; + --v3; + } + while ( v3 >= 40 ); + AutoMapXOfs = v0; + } + v4 = v0 + v1; + AMdword_4B7E40 = v4; + v5 = AutoMapYOfs; + v6 = (ViewY - 16) >> 1; + v7 = AutoMapYOfs + v6; + if ( AutoMapYOfs + v6 < 0 ) + { + do + { + ++v5; + ++v7; + } + while ( v7 < 0 ); + AutoMapYOfs = v5; + } + v8 = v5 + v6; + if ( v5 + v6 >= 40 ) + { + do + { + --v5; + --v8; + } + while ( v8 >= 40 ); + AutoMapYOfs = v5; + } + v9 = v5 + v6; + AMdword_4B7E44 = v9; + v10 = AMbyte_4B7E4C[(AutoMapScale - 50) / 5]; + if ( ScrollInfo._sxoff + ScrollInfo._syoff ) + ++v10; + v22 = v4 - v10; + v19 = v9 - 1; + if ( v10 & 1 ) + { + v11 = 384 - AutoMapPosBits * ((v10 - 1) >> 1); + v12 = 336 - AutoMapXPos * ((v10 + 1) >> 1); + } + else + { + v11 = AutoMapXPos - AutoMapPosBits * (v10 >> 1) + 384; + v12 = 336 - AutoMapXPos * (v10 >> 1) - AutoMapYPos; + } + if ( ViewX & 1 ) + { + v11 -= AutoMapYPos; + v12 -= AMPlayerX; + } + if ( ViewY & 1 ) + { + v11 += AutoMapYPos; + v12 -= AMPlayerX; + } + v13 = (AutoMapScale * ScrollInfo._sxoff / 100 >> 1) + v11; + v14 = (AutoMapScale * ScrollInfo._syoff / 100 >> 1) + v12; + if ( invflag || sbookflag ) + v13 -= 160; + if ( chrflag || questlog ) + v13 += 160; + if ( v10 + 1 >= 0 ) + { + v25 = v10 + 2; + do + { + v15 = 0; + screen_x = v13; + if ( v10 > 0 ) + { + ty = v19; + do + { + v16 = GetAutomapType(v22 + v15, ty, 1); + if ( v16 ) + DrawAutomapType(screen_x, v14, v16); + screen_x += AutoMapPosBits; + ++v15; + --ty; + } + while ( v15 < v10 ); + } + ++v19; + screen_xa = 0; + v17 = v13 - AutoMapXPos; + screen_y = v14 + AutoMapYPos; + if ( v10 >= 0 ) + { + tya = v19; + do + { + v18 = GetAutomapType(v22 + screen_xa, tya, 1); + if ( v18 ) + DrawAutomapType(v17, screen_y, v18); + v17 += AutoMapPosBits; + ++screen_xa; + --tya; + } + while ( screen_xa <= v10 ); + } + ++v22; + v14 += AutoMapXPos; + --v25; + } + while ( v25 ); + } + DrawAutomapPlr(); + DrawAutomapGame(); + } + else + { + DrawAutomapGame(); + } +} +// 4B7E40: using guessed type int AMdword_4B7E40; +// 4B7E44: using guessed type int AMdword_4B7E44; +// 4B84B0: using guessed type int AutoMapXOfs; +// 4B84B4: using guessed type int AutoMapYOfs; +// 4B84B8: using guessed type int AutoMapPosBits; +// 4B84BC: using guessed type int AutoMapXPos; +// 4B84C0: using guessed type int AutoMapYPos; +// 4B84C4: using guessed type int AMPlayerX; +// 4B8968: using guessed type int sbookflag; +// 5BB1ED: using guessed type char leveltype; +// 69BD04: using guessed type int questlog; +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall DrawAutomapType(int screen_x, int screen_y, short automap_type) +{ + short v3; // al + int v4; // ebx + int v5; // edi + int a3; // ST2C_4 + int a1; // ST28_4 + int a2; // ST24_4 + int v9; // edx + int v10; // ST28_4 + int v11; // ST2C_4 + int v12; // ST24_4 + int v13; // ST2C_4 + int v14; // ST28_4 + int v15; // ST24_4 + int v16; // ST28_4 + int v17; // ST24_4 + int v18; // ST2C_4 + int v19; // ST2C_4 + int v20; // ST28_4 + int v21; // ST24_4 + int v22; // ST28_4 + int v23; // ST2C_4 + int v24; // ST24_4 + int v25; // ST28_4 + int v26; // ST24_4 + int v27; // ST2C_4 + int v28; // [esp-Ch] [ebp-34h] + int v29; // [esp-8h] [ebp-30h] + signed int v30; // [esp+Ch] [ebp-1Ch] + signed int v31; // [esp+10h] [ebp-18h] + signed int v32; // [esp+14h] [ebp-14h] + char v33; // [esp+27h] [ebp-1h] + int automap_typea; // [esp+30h] [ebp+8h] + int automap_typeb; // [esp+30h] [ebp+8h] + int automap_typec; // [esp+30h] [ebp+8h] + int automap_typed; // [esp+30h] [ebp+8h] + int automap_typee; // [esp+30h] [ebp+8h] + int automap_typef; // [esp+30h] [ebp+8h] + int automap_typeg; // [esp+30h] [ebp+8h] + + v3 = automap_type; + v4 = screen_x; + v5 = screen_y; + v33 = _HIBYTE(automap_type); + if ( automap_type & 0x4000 ) + { + ENG_set_pixel(screen_x, screen_y, 200); + ENG_set_pixel(v4 - AMPlayerX, v5 - AMPlayerY, 200); + ENG_set_pixel(v4 - AMPlayerX, AMPlayerY + v5, 200); + ENG_set_pixel(AMPlayerX + v4, v5 - AMPlayerY, 200); + ENG_set_pixel(AMPlayerX + v4, AMPlayerY + v5, 200); + ENG_set_pixel(v4 - AutoMapYPos, v5, 200); + ENG_set_pixel(AutoMapYPos + v4, v5, 200); + ENG_set_pixel(v4, v5 - AMPlayerX, 200); + ENG_set_pixel(v4, AMPlayerX + v5, 200); + ENG_set_pixel(v4 + AMPlayerX - AutoMapXPos, AMPlayerY + v5, 200); + ENG_set_pixel(v4 + AutoMapXPos - AMPlayerX, AMPlayerY + v5, 200); + ENG_set_pixel(v4 - AutoMapYPos, AMPlayerX + v5, 200); + ENG_set_pixel(AutoMapYPos + v4, AMPlayerX + v5, 200); + ENG_set_pixel(v4 - AMPlayerX, v5 + AutoMapYPos - AMPlayerY, 200); + ENG_set_pixel(AMPlayerX + v4, v5 + AutoMapYPos - AMPlayerY, 200); + ENG_set_pixel(v4, AutoMapYPos + v5, 200); + v3 = automap_type; + } + if ( automap_type < 0 ) + { + DrawLine(v4 - AMPlayerX, v5 - AMPlayerX - AMPlayerY, v4 + AMPlayerX + AutoMapYPos, AMPlayerY + v5, 144); + DrawLine(v4 - AutoMapYPos, v5 - AMPlayerX, AutoMapYPos + v4, AMPlayerX + v5, 144); + DrawLine(v4 - AutoMapYPos - AMPlayerX, v5 - AMPlayerY, AMPlayerX + v4, v5 + AMPlayerX + AMPlayerY, 144); + DrawLine(v4 - AutoMapXPos, v5, v4, v5 + AutoMapYPos, 144); + v3 = automap_type; + } + v31 = 0; + v30 = 0; + v32 = 0; + switch ( v3 & 0xF ) + { + case 1: + a3 = v4 - AutoMapYPos + AutoMapXPos; + a1 = v4 - AutoMapYPos; + a2 = v5 - AutoMapYPos; + automap_typea = v5 - AMPlayerX; + DrawLine(v4, v5 - AutoMapYPos, v4 - AutoMapYPos, v5 - AMPlayerX, 200); + DrawLine(v4, a2, a3, automap_typea, 200); + DrawLine(v4, v5, a1, automap_typea, 200); + v9 = v5; + v29 = automap_typea; + v28 = a3; + goto LABEL_36; + case 2: + case 5: + goto LABEL_8; + case 3: + case 6: + goto LABEL_17; + case 4: + v31 = 1; + goto LABEL_8; + case 7: + goto LABEL_25; + case 8: + v30 = 1; +LABEL_8: + if ( automap_type & 0x100 ) + { + v10 = v4 - AutoMapXPos; + v11 = v4 - AutoMapYPos; + v12 = v5 - AutoMapYPos; + automap_typeb = v5 - AMPlayerX; + DrawLine(v4, v5 - AutoMapYPos, v4 - AMPlayerX, v5 - AutoMapYPos + AMPlayerY, 200); + DrawLine(v10, v5, v10 + AMPlayerX, v5 - AMPlayerY, 200); + DrawLine(v11, v12, v10, automap_typeb, 144); + DrawLine(v11, v12, v4, automap_typeb, 144); + DrawLine(v11, v5, v10, automap_typeb, 144); + DrawLine(v11, v5, v4, automap_typeb, 144); + } + if ( v33 & 0x10 ) + { + DrawLine(v4 - AutoMapYPos, v5 - AMPlayerX, v4 - AutoMapXPos, v5, 200); + v33 |= 4u; + } + if ( v33 & 4 ) + { + v13 = v4 - AutoMapYPos + AutoMapXPos; + v14 = v4 - AutoMapYPos; + v15 = v5 - AutoMapYPos; + automap_typec = v5 - AMPlayerX; + DrawLine(v4, v5 - AutoMapYPos, v4 - AutoMapYPos, v5 - AMPlayerX, 200); + DrawLine(v4, v15, v13, automap_typec, 200); + DrawLine(v4, v5, v14, automap_typec, 200); + DrawLine(v4, v5, v13, automap_typec, 200); + } + if ( !(v33 & 0x15) ) + DrawLine(v4, v5 - AutoMapYPos, v4 - AutoMapXPos, v5, 200); + if ( v31 ) + goto LABEL_17; + goto LABEL_25; + case 9: + v32 = 1; +LABEL_17: + if ( v33 & 2 ) + { + v16 = AutoMapYPos + v4; + v17 = v5 - AutoMapYPos; + v18 = v4 + AutoMapXPos; + automap_typed = v5 - AMPlayerX; + DrawLine(v4, v5 - AutoMapYPos, v4 + AMPlayerX, v5 - AutoMapYPos + AMPlayerY, 200); + DrawLine(v18, v5, v18 - AMPlayerX, v5 - AMPlayerY, 200); + DrawLine(v16, v17, v4, automap_typed, 144); + DrawLine(v16, v17, v18, automap_typed, 144); + DrawLine(v16, v5, v4, automap_typed, 144); + DrawLine(v16, v5, v18, automap_typed, 144); + } + if ( v33 & 0x20 ) + { + DrawLine(AutoMapYPos + v4, v5 - AMPlayerX, v4 + AutoMapXPos, v5, 200); + v33 |= 8u; + } + if ( v33 & 8 ) + { + v19 = v4 - AutoMapYPos + AutoMapXPos; + v20 = v4 - AutoMapYPos; + v21 = v5 - AutoMapYPos; + automap_typee = v5 - AMPlayerX; + DrawLine(v4, v5 - AutoMapYPos, v4 - AutoMapYPos, v5 - AMPlayerX, 200); + DrawLine(v4, v21, v19, automap_typee, 200); + DrawLine(v4, v5, v20, automap_typee, 200); + DrawLine(v4, v5, v19, automap_typee, 200); + } + if ( !(v33 & 0x2A) ) + DrawLine(v4, v5 - AutoMapYPos, v4 + AutoMapXPos, v5, 200); +LABEL_25: + if ( v30 ) + goto LABEL_26; + goto LABEL_32; + case 0xA: + goto LABEL_26; + case 0xB: + goto LABEL_33; + case 0xC: + v32 = 1; +LABEL_26: + if ( v33 & 1 ) + { + v22 = v4 - AutoMapXPos; + v23 = v4 - AutoMapYPos; + v24 = AutoMapYPos + v5; + automap_typef = AMPlayerX + v5; + DrawLine(v4, AutoMapYPos + v5, v4 - AMPlayerX, AutoMapYPos + v5 - AMPlayerY, 200); + DrawLine(v22, v5, v22 + AMPlayerX, v5 + AMPlayerY, 200); + DrawLine(v23, v24, v22, automap_typef, 144); + DrawLine(v23, v24, v4, automap_typef, 144); + DrawLine(v23, v5, v22, automap_typef, 144); + DrawLine(v23, v5, v4, automap_typef, 144); + } + else + { + DrawLine(v4, AutoMapYPos + v5, v4 - AutoMapXPos, v5, 200); + } +LABEL_32: + if ( v32 ) + { +LABEL_33: + if ( v33 & 2 ) + { + v25 = AutoMapYPos + v4; + v26 = AutoMapYPos + v5; + v27 = v4 + AutoMapXPos; + automap_typeg = AMPlayerX + v5; + DrawLine(v4, AutoMapYPos + v5, v4 + AMPlayerX, AutoMapYPos + v5 - AMPlayerY, 200); + DrawLine(v27, v5, v27 - AMPlayerX, v5 + AMPlayerY, 200); + DrawLine(v25, v26, v4, automap_typeg, 144); + DrawLine(v25, v26, v27, automap_typeg, 144); + DrawLine(v25, v5, v4, automap_typeg, 144); + DrawLine(v25, v5, v27, automap_typeg, 144); + } + else + { + v29 = v5; + v28 = v4 + AutoMapXPos; + v9 = AutoMapYPos + v5; +LABEL_36: + DrawLine(v4, v9, v28, v29, 200); + } + } + break; + default: + return; + } +} +// 4B84BC: using guessed type int AutoMapXPos; +// 4B84C0: using guessed type int AutoMapYPos; +// 4B84C4: using guessed type int AMPlayerX; +// 4B84C8: using guessed type int AMPlayerY; + +void __cdecl DrawAutomapPlr() +{ + int v0; // ebx + int v1; // eax + int v2; // ecx + int v3; // esi + int v4; // edi + int v5; // edx + int v6; // ecx + int v7; // eax + int v8; // ecx + int v9; // [esp-Ch] [ebp-20h] + int v10; // [esp-8h] [ebp-1Ch] + int v11; // [esp+Ch] [ebp-8h] + int v12; // [esp+10h] [ebp-4h] + + v0 = myplr; + if ( plr[myplr]._pmode == PM_WALK3 ) + { + v1 = plr[v0]._px; + v2 = plr[v0]._py; + if ( plr[v0]._pdir == 2 ) + ++v1; + else + ++v2; + } + else + { + v1 = plr[v0].WorldX; + v2 = plr[v0].WorldY; + } + v11 = v1 - 2 * AutoMapXOfs - ViewX; + v12 = v2 - 2 * AutoMapYOfs - ViewY; + v3 = (AutoMapScale * ScrollInfo._sxoff / 100 >> 1) + + (AutoMapScale * plr[v0]._pxoff / 100 >> 1) + + AutoMapYPos * (v11 - v12) + + 384; + if ( invflag || sbookflag ) + v3 = (AutoMapScale * ScrollInfo._sxoff / 100 >> 1) + + (AutoMapScale * plr[v0]._pxoff / 100 >> 1) + + AutoMapYPos * (v11 - v12) + + 224; + if ( chrflag || questlog ) + v3 += 160; + v4 = AMPlayerX * (v12 + v11) + + (AutoMapScale * ScrollInfo._syoff / 100 >> 1) + + (AutoMapScale * plr[v0]._pyoff / 100 >> 1) + + 336 + - AMPlayerX; + switch ( plr[v0]._pdir ) + { + case DIR_S: + DrawLine(v3, v4, v3, v4 + AutoMapYPos, 153); + DrawLine(v3, AutoMapYPos + v4, v3 + AMPlayerY, v4 + AMPlayerX, 153); + v10 = v4 + AMPlayerX; + v9 = v3 - AMPlayerY; + v5 = AutoMapYPos + v4; + goto LABEL_19; + case DIR_SW: + DrawLine( + v3, + AMPlayerX * (v12 + v11) + + (AutoMapScale * ScrollInfo._syoff / 100 >> 1) + + (AutoMapScale * plr[v0]._pyoff / 100 >> 1) + + 336 + - AMPlayerX, + v3 - AutoMapYPos, + AMPlayerX * (v12 + v11) + + (AutoMapScale * ScrollInfo._syoff / 100 >> 1) + + (AutoMapScale * plr[v0]._pyoff / 100 >> 1) + + 336, + 153); + DrawLine(v3 - AutoMapYPos, AMPlayerX + v4, v3 - AMPlayerY - AMPlayerX, v4, 153); + v7 = AMPlayerX; + v8 = v3; + v5 = AMPlayerX + v4; + v10 = AMPlayerX + v4; + goto LABEL_23; + case DIR_W: + DrawLine(v3, v4, v3 - AutoMapYPos, v4, 153); + DrawLine(v3 - AutoMapYPos, v4, v3 - AMPlayerX, v4 - AMPlayerY, 153); + v5 = v4; + v10 = v4 + AMPlayerY; + v9 = v3 - AMPlayerX; + goto LABEL_24; + case DIR_NW: + DrawLine(v3, v4, v3 - AutoMapYPos, v4 - AMPlayerX, 153); + DrawLine(v3 - AutoMapYPos, v4 - AMPlayerX, v3 - AMPlayerX, v4 - AMPlayerX, 153); + v7 = AMPlayerX; + v8 = v3 - AMPlayerY; + v10 = v4; + v5 = v4 - AMPlayerX; +LABEL_23: + v9 = v8 - v7; +LABEL_24: + v6 = v3 - AutoMapYPos; + goto LABEL_25; + case DIR_N: + DrawLine(v3, v4, v3, v4 - AutoMapYPos, 153); + DrawLine(v3, v4 - AutoMapYPos, v3 - AMPlayerY, v4 - AMPlayerX, 153); + v10 = v4 - AMPlayerX; + v5 = v4 - AutoMapYPos; + v9 = v3 + AMPlayerY; +LABEL_19: + v6 = v3; + goto LABEL_25; + case DIR_NE: + DrawLine(v3, v4, v3 + AutoMapYPos, v4 - AMPlayerX, 153); + DrawLine(AutoMapYPos + v3, v4 - AMPlayerX, v3 + AMPlayerX, v4 - AMPlayerX, 153); + v10 = v4; + v9 = v3 + AMPlayerX + AMPlayerY; + v5 = v4 - AMPlayerX; + goto LABEL_17; + case DIR_E: + DrawLine(v3, v4, v3 + AutoMapYPos, v4, 153); + DrawLine(AutoMapYPos + v3, v4, v3 + AMPlayerX, v4 - AMPlayerY, 153); + DrawLine(AutoMapYPos + v3, v4, v3 + AMPlayerX, v4 + AMPlayerY, 153); + break; + case DIR_SE: + DrawLine( + v3, + AMPlayerX * (v12 + v11) + + (AutoMapScale * ScrollInfo._syoff / 100 >> 1) + + (AutoMapScale * plr[v0]._pyoff / 100 >> 1) + + 336 + - AMPlayerX, + v3 + AutoMapYPos, + AMPlayerX * (v12 + v11) + + (AutoMapScale * ScrollInfo._syoff / 100 >> 1) + + (AutoMapScale * plr[v0]._pyoff / 100 >> 1) + + 336, + 153); + DrawLine(AutoMapYPos + v3, AMPlayerX + v4, v3 + AMPlayerX + AMPlayerY, v4, 153); + v5 = AMPlayerX + v4; + v10 = AMPlayerX + v4; + v9 = v3 + AMPlayerX; +LABEL_17: + v6 = AutoMapYPos + v3; +LABEL_25: + DrawLine(v6, v5, v9, v10, 153); + break; + default: + return; + } +} +// 4B84B0: using guessed type int AutoMapXOfs; +// 4B84B4: using guessed type int AutoMapYOfs; +// 4B84C0: using guessed type int AutoMapYPos; +// 4B84C4: using guessed type int AMPlayerX; +// 4B84C8: using guessed type int AMPlayerY; +// 4B8968: using guessed type int sbookflag; +// 69BD04: using guessed type int questlog; + +short __fastcall GetAutomapType(int x, int y, BOOL view) +{ + int v3; // edi + int v4; // esi + int v6; // eax + short v7; // bp + + v3 = y; + v4 = x; + if ( view ) + { + if ( x == -1 && y >= 0 && y < 40 && automapview[0][y] ) + { + x = 0; + return ~GetAutomapType(x, y, 0) & 0x4000; + } + if ( y == -1 ) + { + if ( x < 0 ) + return 0; + if ( x < 40 && automapview[x][0] ) + { + y = 0; + return ~GetAutomapType(x, y, 0) & 0x4000; + } + } + } + if ( x < 0 ) + return 0; + if ( x >= 40 ) + return 0; + if ( y < 0 ) + return 0; + if ( y >= 40 ) + return 0; + v6 = y + 40 * x; + if ( !automapview[0][v6] && view ) + return 0; + v7 = automaptype[(unsigned char)dungeon[0][v6]]; + if ( v7 == 7 && ((unsigned short)GetAutomapType(x - 1, y, 0) >> 8) & 8 ) + { + if ( ((unsigned short)GetAutomapType(v4, v3 - 1, 0) >> 8) & 4 ) + v7 = 1; + } + return v7; +} + +void __cdecl DrawAutomapGame() +{ + int v0; // esi + char *v1; // eax + char *v2; // eax + char v3[256]; // [esp+4h] [ebp-100h] + + v0 = 20; + if ( (unsigned char)gbMaxPlayers > 1u ) + { + v1 = strcpy(v3, "game: "); + strcat(v1, szPlayerName); + PrintGameStr(8, 20, v3, 3); + v0 = 35; + if ( szPlayerDescript[0] ) + { + v2 = strcpy(v3, "password: "); + strcat(v2, szPlayerDescript); + PrintGameStr(8, 35, v3, 3); + v0 = 50; + } + } + if ( setlevel ) + { + PrintGameStr(8, v0, quest_level_names[(unsigned char)setlvlnum], 3); + } + else if ( currlevel ) + { + sprintf(v3, "Level: %i", currlevel); + PrintGameStr(8, v0, v3, 3); + } +} +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall SetAutomapView(int x, int y) +{ + int xx = (x - 16) >> 1; + int yy = (y - 16) >> 1; + + if ( xx < 0 || xx >= DMAXX || yy < 0 || yy >= DMAXY ) { + return; + } + + automapview[xx][yy] = 1; + + USHORT maptype = GetAutomapType(xx, yy, FALSE); + USHORT solid = maptype & 0x4000; + + switch ( maptype & 0xF ) { + case 2: + if ( solid ) { + if ( GetAutomapType(xx, yy + 1, FALSE) == 0x4007 ) + automapview[xx][yy + 1] = 1; + } + else if ( GetAutomapType(xx - 1, yy, FALSE) & 0x4000 ) + automapview[xx - 1][yy] = 1; + break; + case 3: + if ( solid ) { + if ( GetAutomapType(xx + 1, yy, FALSE) == 0x4007 ) + automapview[xx + 1][yy] = 1; + } + else if ( GetAutomapType(xx, yy - 1, FALSE) & 0x4000 ) + automapview[xx][yy - 1] = 1; + break; + case 4: + if ( solid ) { + if ( GetAutomapType(xx, yy + 1, FALSE) == 0x4007 ) + automapview[xx][yy + 1] = 1; + if ( GetAutomapType(xx + 1, yy, FALSE) == 0x4007 ) + automapview[xx + 1][yy] = 1; + } + else { + if ( GetAutomapType(xx - 1, yy, FALSE) & 0x4000 ) + automapview[xx - 1][yy] = 1; + if ( GetAutomapType(xx, yy - 1, FALSE) & 0x4000 ) + automapview[xx][yy - 1] = 1; + if ( GetAutomapType(xx - 1, yy - 1, FALSE) & 0x4000 ) + automapview[xx - 1][yy - 1] = 1; + } + break; + case 5: + if ( solid ) { + if ( GetAutomapType(xx, yy - 1, FALSE) & 0x4000 ) + automapview[xx][yy - 1] = 1; + if ( GetAutomapType(xx, yy + 1, FALSE) == 0x4007 ) + automapview[xx][yy + 1] = 1; + } + else if ( GetAutomapType(xx - 1, yy, FALSE) & 0x4000 ) + automapview[xx - 1][yy] = 1; + break; + case 6: + if ( solid ) { + if ( GetAutomapType(xx - 1, yy, FALSE) & 0x4000 ) + automapview[xx - 1][yy] = 1; + if ( GetAutomapType(xx + 1, yy, FALSE) == 0x4007 ) + automapview[xx + 1][yy] = 1; + } + else if ( GetAutomapType(xx, yy - 1, FALSE) & 0x4000 ) + automapview[xx][yy - 1] = 1; + } +} + +void __cdecl AutomapZoomReset() +{ + AutoMapXOfs = 0; + AutoMapYOfs = 0; + AutoMapPosBits = (AutoMapScale << 6) / 100; + AutoMapXPos = AutoMapPosBits >> 1; + AutoMapYPos = AutoMapPosBits >> 2; + AMPlayerX = AutoMapPosBits >> 3; + AMPlayerY = AutoMapPosBits >> 4; +} +// 4B84B0: using guessed type int AutoMapXOfs; +// 4B84B4: using guessed type int AutoMapYOfs; +// 4B84B8: using guessed type int AutoMapPosBits; +// 4B84BC: using guessed type int AutoMapXPos; +// 4B84C0: using guessed type int AutoMapYPos; +// 4B84C4: using guessed type int AMPlayerX; +// 4B84C8: using guessed type int AMPlayerY; diff --git a/Source/automap.h b/Source/automap.h new file mode 100644 index 000000000..b91b17387 --- /dev/null +++ b/Source/automap.h @@ -0,0 +1,37 @@ +//HEADER_GOES_HERE +#ifndef __AUTOMAP_H__ +#define __AUTOMAP_H__ + +extern short automaptype[512]; +extern int AMdword_4B7E40; // weak +extern int AMdword_4B7E44; // weak +extern bool automapflag; // idb +extern char AMbyte_4B7E4C[32]; +extern char automapview[DMAXX][DMAXY]; +extern int AutoMapScale; // idb +extern int AutoMapXOfs; // weak +extern int AutoMapYOfs; // weak +extern int AutoMapPosBits; // weak +extern int AutoMapXPos; // weak +extern int AutoMapYPos; // weak +extern int AMPlayerX; // weak +extern int AMPlayerY; // weak + +void __cdecl InitAutomapOnce(); +void __cdecl InitAutomap(); +void __cdecl StartAutomap(); +void __cdecl AutomapUp(); +void __cdecl AutomapDown(); +void __cdecl AutomapLeft(); +void __cdecl AutomapRight(); +void __cdecl AutomapZoomIn(); +void __cdecl AutomapZoomOut(); +void __cdecl DrawAutomap(); +void __fastcall DrawAutomapType(int screen_x, int screen_y, short automap_type); +void __cdecl DrawAutomapPlr(); +short __fastcall GetAutomapType(int x, int y, BOOL view); +void __cdecl DrawAutomapGame(); +void __fastcall SetAutomapView(int x, int y); +void __cdecl AutomapZoomReset(); + +#endif /* __AUTOMAP_H__ */ diff --git a/Source/capture.cpp b/Source/capture.cpp new file mode 100644 index 000000000..e81bf021f --- /dev/null +++ b/Source/capture.cpp @@ -0,0 +1,173 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +void __cdecl CaptureScreen() +{ + PALETTEENTRY palette[256]; + char FileName[MAX_PATH]; + + HANDLE hObject = CaptureFile(FileName); + if ( hObject != INVALID_HANDLE_VALUE) + { + DrawAndBlit(); + lpDDPalette->GetEntries(0, 0, 256, palette); + RedPalette(palette); + + lock_buf_priv(); + bool success = CaptureHdr(hObject, 640, 480); + if (success) + { + success = CapturePix(hObject, 640, 480, 768, (BYTE*)gpBuffer->row[0].pixels); + if (success) + { + success = CapturePal(hObject, palette); + } + } + unlock_buf_priv(); + CloseHandle(hObject); + + if (!success) + DeleteFile(FileName); + + Sleep(300); + lpDDPalette->SetEntries(0, 0, 256, palette); + } +} + +bool __fastcall CaptureHdr(HANDLE hFile, short width, short height) +{ + PCXHeader Buffer; + memset(&Buffer, 0, sizeof(Buffer)); + + Buffer.xmax = width - 1; + Buffer.vertRes = height; + Buffer.manufacturer = 10; + Buffer.version = 5; + Buffer.encoding = 1; + Buffer.bitsPerPixel = 8; + Buffer.ymax = height - 1; + Buffer.horzRes = width; + Buffer.numColorPlanes = 1; + Buffer.bytesPerScanLine = width; + + DWORD lpNumBytes; + return WriteFile(hFile, &Buffer, sizeof(Buffer), &lpNumBytes, NULL) && lpNumBytes == sizeof(Buffer); +} + +bool __fastcall CapturePal(HANDLE hFile, PALETTEENTRY *palette) +{ + char *v3; + char Buffer[769]; + + Buffer[0] = 12; + v3 = &Buffer[1]; + for (int i = 256; i != 0; --i) + { + v3[0] = palette->peRed; + v3[1] = palette->peGreen; + v3[2] = palette->peBlue; + + palette++; + v3 += 3; + } + + DWORD lpNumBytes; + return WriteFile(hFile, Buffer, sizeof(Buffer), &lpNumBytes, NULL) && lpNumBytes == sizeof(Buffer); +} + +bool __fastcall CapturePix(HANDLE hFile, WORD width, WORD height, WORD stride, BYTE *pixels) +{ + int writeSize; + DWORD lpNumBytes; + + BYTE *pBuffer = (BYTE *)DiabloAllocPtr(2 * width); + do + { + if ( !height ) + { + mem_free_dbg(pBuffer); + return 1; + } + height--; + BYTE *pBufferEnd = CaptureEnc(pixels, pBuffer, width); + pixels += stride; + writeSize = pBufferEnd - pBuffer; + } + while (WriteFile(hFile, pBuffer, writeSize, &lpNumBytes, 0) && lpNumBytes == writeSize); + return 0; +} + +BYTE *__fastcall CaptureEnc(BYTE *src, BYTE *dst, int width) +{ + do + { + BYTE rlePixel = *src++; + --width; + + int rleLength = 1; + while (rlePixel == *src) + { + if (rleLength >= 63) + break; + if (!width) + break; + ++rleLength; + + --width; + ++src; + } + + if (rlePixel > 0xBF || rleLength > 1) + { + *dst++ = rleLength | 0xC0; + } + *dst++ = rlePixel; + } while (width); + return dst; +} + +HANDLE __fastcall CaptureFile(char *dst_path) +{ + bool num_used[100] = { false }; + + _finddata_t finder; + int hFind = _findfirst("screen??.PCX", &finder); + if (hFind != -1) + { + do + { + if (isdigit(finder.name[6]) && isdigit(finder.name[7])) + { + num_used[10 * (finder.name[6] - '0') + (finder.name[7] - '0')] = true; + } + } + while (_findnext(hFind, &finder) == 0); + } + + int free_num = 0; + while (num_used[free_num]) + { + ++free_num; + if (free_num >= 100) + return INVALID_HANDLE_VALUE; + } + + sprintf(dst_path, "screen%02d.PCX", free_num); + return CreateFile(dst_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); +} + +void __fastcall RedPalette(PALETTEENTRY *pal) +{ + PALETTEENTRY red[256]; + + for(int i = 0; i < 256; i++) + { + red[i].peRed = pal[i].peRed; + red[i].peGreen = 0; + red[i].peBlue = 0; + red[i].peFlags = 0; + } + + lpDDPalette->SetEntries(0, 0, 256, red); +} diff --git a/Source/capture.h b/Source/capture.h new file mode 100644 index 000000000..4c82cb4b6 --- /dev/null +++ b/Source/capture.h @@ -0,0 +1,13 @@ +//HEADER_GOES_HERE +#ifndef __CAPTURE_H__ +#define __CAPTURE_H__ + +void __cdecl CaptureScreen(); +bool __fastcall CaptureHdr(HANDLE hFile, short width, short height); +bool __fastcall CapturePal(HANDLE hFile, PALETTEENTRY *palette); +bool __fastcall CapturePix(HANDLE hFile, WORD width, WORD height, WORD stride, BYTE *pixels); +BYTE *__fastcall CaptureEnc(BYTE *src, BYTE *dst, int width); +HANDLE __fastcall CaptureFile(char *dst_path); +void __fastcall RedPalette(PALETTEENTRY *pal); + +#endif /* __CAPTURE_H__ */ diff --git a/Source/codec.cpp b/Source/codec.cpp new file mode 100644 index 000000000..ff65c02b7 --- /dev/null +++ b/Source/codec.cpp @@ -0,0 +1,191 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifdef MINIWIN +#define srand srand_miniwin +#define rand rand_miniwin +#endif + +int __fastcall codec_decode(void *pbSrcDst, int size, char *pszPassword) +{ + unsigned int v3; // ebx + char *v4; // esi + int v5; // ebx + signed int v7; // ecx + int v8; // esi + char v9[128]; // [esp+8h] [ebp-98h] + char dst[20]; // [esp+88h] [ebp-18h] + int v11; // [esp+9Ch] [ebp-4h] + char *passworda; // [esp+A8h] [ebp+8h] + + v3 = size; + v4 = (char *)pbSrcDst; + codec_init_key(0, pszPassword); + if ( v3 <= 8 ) + return 0; + v5 = v3 - 8; + v11 = v5; + if ( v5 & 0x3F ) + return 0; + passworda = (char *)v5; + if ( v5 ) + { + do + { + memcpy(v9, v4, 0x40u); + SHA1Result(0, dst); + v7 = 0; + do + { + v9[v7] ^= dst[v7 % 20]; + ++v7; + } + while ( v7 < 64 ); + SHA1Calculate(0, v9, 0); + memset(dst, 0, 0x14u); + memcpy(v4, v9, 0x40u); + v4 += 64; + passworda -= 64; + } + while ( passworda ); + v5 = v11; + } + memset(v9, 0, 0x80u); + if ( !v4[4] ) + { + SHA1Result(0, dst); + if ( *(_DWORD *)v4 == *(_DWORD *)dst ) + { + v8 = v5 + (unsigned char)v4[5] - 64; + goto LABEL_14; + } + memset(dst, 0, 0x14u); + } + v8 = 0; +LABEL_14: + SHA1Clear(); + return v8; +} +// 4034D9: using guessed type char var_98[128]; + +void __fastcall codec_init_key(int unused, char *pszPassword) +{ + char *v2; // edi + char *v3; // esi + int v4; // eax + signed int v5; // ecx + char v6; // dl + unsigned int v7; // ecx + signed int v8; // esi + char v9[136]; // [esp+Ch] [ebp-E0h] + char v10[64]; // [esp+94h] [ebp-58h] + char dst[20]; // [esp+D4h] [ebp-18h] + int v12; // [esp+E8h] [ebp-4h] + + v2 = pszPassword; + srand(0x7058u); + v3 = v9; + v12 = 136; + do + { + *v3++ = rand(); + --v12; + } + while ( v12 ); + v4 = 0; + v5 = 0; + do + { + if ( !v2[v4] ) + v4 = 0; + v6 = v2[v4++]; + v10[v5++] = v6; + } + while ( v5 < 64 ); + SHA1Reset(0); + SHA1Calculate(0, v10, dst); + SHA1Clear(); + v7 = 0; + do + { + v9[v7] ^= dst[(signed int)v7 % 20]; + ++v7; + } + while ( v7 < 0x88 ); + memset(v10, 0, 0x40u); + memset(dst, 0, 0x14u); + v8 = 0; + do + { + SHA1Reset(v8); + SHA1Calculate(v8++, &v9[72], 0); + } + while ( v8 < 3 ); + memset(v9, 0, 0x88u); +} +// 4035DB: using guessed type char var_E0[72]; +// 4035DB: using guessed type char var_58[64]; +// 4035DB: using guessed type char dst[20]; + +int __fastcall codec_get_encoded_len(int dwSrcBytes) +{ + if ( dwSrcBytes & 0x3F ) + dwSrcBytes += 64 - (dwSrcBytes & 0x3F); + return dwSrcBytes + 8; +} + +void __fastcall codec_encode(void *pbSrcDst, int size, int size_64, char *pszPassword) +{ + char *v4; // esi + char v5; // bl + size_t v6; // edi + signed int v7; // ecx + char v9[128]; // [esp+8h] [ebp-ACh] + char v10[20]; // [esp+88h] [ebp-2Ch] + char dst[20]; // [esp+9Ch] [ebp-18h] + size_t v12; // [esp+B0h] [ebp-4h] + + v4 = (char *)pbSrcDst; + v12 = size; + if ( size_64 != codec_get_encoded_len(size) ) + TermMsg("Invalid encode parameters"); + codec_init_key(1, pszPassword); + v5 = 0; + if ( v12 ) + { + do + { + v6 = v12; + if ( v12 >= 0x40 ) + v6 = 64; + memcpy(v9, v4, v6); + if ( v6 < 0x40 ) + memset(&v9[v6], 0, 64 - v6); + SHA1Result(0, dst); + SHA1Calculate(0, v9, 0); + v7 = 0; + do + { + v9[v7] ^= dst[v7 % 20]; + ++v7; + } + while ( v7 < 64 ); + memset(dst, 0, 0x14u); + memcpy(v4, v9, 0x40u); + v4 += 64; + v12 -= v6; + } + while ( v12 ); + v5 = v6; + } + memset(v9, 0, 0x80u); + SHA1Result(0, v10); + v4[4] = 0; + *((_WORD *)v4 + 3) = 0; + *(_DWORD *)v4 = *(_DWORD *)v10; + v4[5] = v5; + SHA1Clear(); +} +// 4036BE: using guessed type char var_AC[128]; +// 4036BE: using guessed type char dst[20]; diff --git a/Source/codec.h b/Source/codec.h new file mode 100644 index 000000000..3d271fbb8 --- /dev/null +++ b/Source/codec.h @@ -0,0 +1,10 @@ +//HEADER_GOES_HERE +#ifndef __CODEC_H__ +#define __CODEC_H__ + +int __fastcall codec_decode(void *pbSrcDst, int size, char *pszPassword); +void __fastcall codec_init_key(int unused, char *pszPassword); +int __fastcall codec_get_encoded_len(int dwSrcBytes); +void __fastcall codec_encode(void *pbSrcDst, int size, int size_64, char *pszPassword); + +#endif /* __CODEC_H__ */ diff --git a/Source/control.cpp b/Source/control.cpp new file mode 100644 index 000000000..6adf14422 --- /dev/null +++ b/Source/control.cpp @@ -0,0 +1,3431 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +char sgbNextTalkSave; // weak +char sgbTalkSavePos; // weak +void *pDurIcons; +void *pChrButtons; +int drawhpflag; // idb +int dropGoldFlag; // weak +int panbtn[8]; +int chrbtn[4]; +void *pMultiBtns; +void *pPanelButtons; +void *pChrPanel; +int lvlbtndown; // weak +char sgszTalkSave[8][80]; +int dropGoldValue; // idb +int drawmanaflag; // idb +int chrbtnactive; // weak +char sgszTalkMsg[80]; +void *pPanelText; +int frame_4B8800; // idb +void *pLifeBuff; +void *pBtmBuff; +void *pTalkBtns; +int pstrjust[4]; +int pnumlines; // idb +int pinfoflag; // weak +int talkbtndown[3]; +int pSpell; // weak +void *pManaBuff; +int infoclr; // weak +int sgbPlrTalkTbl; // weak // should be char [4] +void *pGBoxBuff; +void *pSBkBtnCel; +char tempstr[260]; +int sbooktab; // weak +int pSplType; // weak +int frame; // idb +int initialDropGoldIndex; // idb +int talkflag; // weak +void *pSBkIconCels; +int sbookflag; // weak +int chrflag; +int drawbtnflag; // idb +void *pSpellBkCel; +char infostr[260]; +int numpanbtns; // weak +void *pStatusPanel; +char panelstr[256]; +int panelflag; // weak +char byte_4B8B88[256]; +int initialDropGoldValue; // idb +void *pSpellCels; +int panbtndown; // weak +void *pTalkPanel; // idb +int spselflag; // weak +#endif + +const unsigned char fontframe[127] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 54, 44, 57, 58, 56, 55, 47, + 40, 41, 59, 39, 50, 37, 51, 52, 36, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 48, 49, + 60, 38, 61, 53, 62, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 42, 63, 43, 64, 65, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 40, 66, 41, 67 +}; +const unsigned char fontkern[68] = +{ + 8, 10, 7, 9, 8, 7, 6, 8, 8, 3, + 3, 8, 6, 11, 9, 10, 6, 9, 9, 6, + 9, 11, 10, 13, 10, 11, 7, 5, 7, 7, + 8, 7, 7, 7, 7, 7, 10, 4, 5, 6, + 3, 3, 4, 3, 6, 6, 3, 3, 3, 3, + 3, 2, 7, 6, 3, 10, 10, 6, 6, 7, + 4, 4, 9, 6, 6, 12, 3, 7 +}; +const int lineoffset[25] = +{ + 456433, + 24576, + 24576, + 24576, + 24756, + 447217, + 465649, + 24576, + 24576, + 24576, + 442609, + 456433, + 470257, + 24576, + 24576, + 439537, + 451057, + 461809, + 473329, + 24576, + 438001, + 447217, + 456433, + 465649, + 474097 +}; +const unsigned char fontidx[256] = +{ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 1, 67, 117, + 101, 97, 97, 97, 97, 99, 101, 101, 101, 105, + 105, 105, 65, 65, 69, 97, 65, 111, 111, 111, + 117, 117, 121, 79, 85, 99, 76, 89, 80, 102, + 97, 105, 111, 117, 110, 78, 97, 111, 63, 1, + 1, 1, 1, 33, 60, 62, 111, 43, 50, 51, + 39, 117, 80, 46, 44, 49, 48, 62, 1, 1, + 1, 63, 65, 65, 65, 65, 65, 65, 65, 67, + 69, 69, 69, 69, 73, 73, 73, 73, 68, 78, + 79, 79, 79, 79, 79, 88, 48, 85, 85, 85, + 85, 89, 98, 66, 97, 97, 97, 97, 97, 97, + 97, 99, 101, 101, 101, 101, 105, 105, 105, 105, + 111, 110, 111, 111, 111, 111, 111, 47, 48, 117, + 117, 117, 117, 121, 98, 121 +}; + +/* data */ + +unsigned char SpellITbl[37] = +{ + 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 28, 13, 12, 18, 16, 14, 18, 19, 11, 20, + 15, 21, 23, 24, 25, 22, 26, 29, 37, 38, + 39, 42, 41, 40, 10, 36, 30 +}; +int PanBtnPos[8][5] = +{ + { 9, 361, 71, 19, 1 }, + { 9, 387, 71, 19, 0 }, + { 9, 427, 71, 19, 1 }, + { 9, 453, 71, 19, 0 }, + { 560, 361, 71, 19, 1 }, + { 560, 387, 71, 19, 0 }, + { 87, 443, 33, 32, 1 }, + { 527, 443, 33, 32, 1 } +}; +char *PanBtnHotKey[8] = { "'c'", "'q'", "Tab", "Esc", "'i'", "'b'", "Enter", NULL }; +char *PanBtnStr[8] = +{ + "Character Information", + "Quests log", + "Automap", + "Main Menu", + "Inventory", + "Spell book", + "Send Message", + "Player Attack" +}; +int attribute_inc_rects[4][4] = +{ + { 137, 138, 41, 22 }, + { 137, 166, 41, 22 }, + { 137, 195, 41, 22 }, + { 137, 223, 41, 22 } +}; + +int SpellPages[6][7] = +{ + { SPL_NULL, SPL_FIREBOLT, SPL_CBOLT, SPL_HBOLT, SPL_HEAL, SPL_HEALOTHER, SPL_FLAME }, + { SPL_RESURRECT, SPL_FIREWALL, SPL_TELEKINESIS, SPL_LIGHTNING, SPL_TOWN, SPL_FLASH, SPL_STONE }, + { SPL_RNDTELEPORT, SPL_MANASHIELD, SPL_ELEMENT, SPL_FIREBALL, SPL_WAVE, SPL_CHAIN, SPL_GUARDIAN }, + { SPL_NOVA, SPL_GOLEM, SPL_TELEPORT, SPL_APOCA, SPL_BONESPIRIT, SPL_FLARE, SPL_ETHEREALIZE }, + { -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1 } +}; + +void __fastcall DrawSpellCel(int xp, int yp, char *Trans, int nCel, int w) +{ + char *v5; // ebx + char *v6; // esi + char *v7; // edi + int v9; // edx + unsigned int v10; // eax + unsigned int v11; // ecx + char v14; // cf + unsigned int v15; // ecx + int v18; // [esp+Ch] [ebp-Ch] + int _EAX; + char *_EBX; + + v5 = &Trans[4 * nCel]; + v6 = &Trans[*(_DWORD *)v5]; + v7 = (char *)gpBuffer + screen_y_times_768[yp] + xp; + v18 = (int)&v6[*((_DWORD *)v5 + 1) - *(_DWORD *)v5]; + _EBX = byte_4B8B88; + do + { + v9 = w; + do + { + while ( 1 ) + { + v10 = (unsigned char)*v6++; + if ( (v10 & 0x80u) == 0 ) + break; + _LOBYTE(v10) = -(char)v10; + v7 += v10; + v9 -= v10; + if ( !v9 ) + goto LABEL_12; + } + v9 -= v10; + v11 = v10 >> 1; + if ( v10 & 1 ) + { + _EAX = *v6++; + ASM_XLAT(_EAX,_EBX); + *v7++ = _EAX; + if ( !v11 ) + continue; + } + v14 = v11 & 1; + v15 = v11 >> 1; + if ( !v14 ) + goto LABEL_15; + _EAX = *(_WORD *)v6; + v6 += 2; + ASM_XLAT(_EAX,_EBX); + _EAX = __ROR2__(_EAX, 8); + ASM_XLAT(_EAX,_EBX); + *(_WORD *)v7 = __ROR2__(_EAX, 8); + v7 += 2; + if ( v15 ) + { +LABEL_15: + do + { + _EAX = *(_DWORD *)v6; + v6 += 4; + ASM_XLAT(_EAX,_EBX); + _EAX = __ROR4__(_EAX, 8); + ASM_XLAT(_EAX,_EBX); + _EAX = __ROR4__(_EAX, 8); + ASM_XLAT(_EAX,_EBX); + _EAX = __ROR4__(_EAX, 8); + ASM_XLAT(_EAX,_EBX); + *(_DWORD *)v7 = __ROR4__(_EAX, 8); + v7 += 4; + --v15; + } + while ( v15 ); + } + } + while ( v9 ); +LABEL_12: + v7 = &v7[-w - 768]; + } + while ( v6 != (char *)v18 ); +} + +void __fastcall SetSpellTrans(char t) +{ + signed int v1; // eax + signed int v2; // eax + signed int v3; // eax + char *v4; // ecx + signed int v5; // eax + char *v6; // ecx + signed int v7; // eax + char *v8; // ecx + signed int v9; // eax + char *v10; // ecx + + if ( !t ) + { + v1 = 0; + do + { + byte_4B8B88[v1] = v1; + ++v1; + } + while ( v1 < 128 ); + } + v2 = 128; + do + { + byte_4B8B88[v2] = v2; + ++v2; + } + while ( v2 < 256 ); + byte_4B8B88[255] = 0; + switch ( t ) + { + case 1: + byte_4B8B88[144] = -79; + byte_4B8B88[145] = -77; + byte_4B8B88[146] = -75; + v9 = 176; + do + { + v10 = &byte_4B8B88[v9 + 32]; + byte_4B8B88[v9 - 16] = v9; + *(v10 - 16) = v9; + *v10 = v9++; + } + while ( v9 < 192 ); + break; + case 2: + byte_4B8B88[144] = -95; + byte_4B8B88[145] = -93; + byte_4B8B88[146] = -91; + v7 = 160; + do + { + v8 = &byte_4B8B88[v7 + 48]; + *(v8 - 16) = v7; + *v8 = v7++; + } + while ( v7 < 176 ); + break; + case 3: + byte_4B8B88[144] = -47; + byte_4B8B88[145] = -45; + byte_4B8B88[146] = -43; + v5 = 208; + do + { + v6 = &byte_4B8B88[v5 - 16]; + *(v6 - 32) = v5; + *v6 = v5++; + } + while ( v5 < 224 ); + break; + case 4: + byte_4B8B88[144] = -15; + byte_4B8B88[145] = -13; + byte_4B8B88[146] = -11; + v3 = 240; + do + { + v4 = &byte_4B8B88[v3 - 48]; + *(v4 - 32) = v3; + *v4 = v3; + v4[16] = v3++; + } + while ( v3 < 255 ); + byte_4B8B88[175] = 0; + byte_4B8B88[207] = 0; + byte_4B8B88[223] = 0; + break; + } +} + +void __cdecl DrawSpell() +{ + int v0; // ebp + char v1; // cl + char v2; // bl + int v3; // edi + int v4; // esi + char v6; // [esp+Fh] [ebp-5h] + + v0 = myplr; + v1 = plr[myplr]._pRSpell; + v2 = plr[myplr]._pRSplType; + v3 = v1; + v6 = plr[myplr]._pRSpell; + v4 = plr[myplr]._pISplLvlAdd + plr[myplr]._pSplLvl[v1]; + if ( v2 == 1 && v1 != -1 ) + { + if ( !CheckSpell(myplr, v1, 1, 1) ) + v2 = 4; + v0 = myplr; + if ( v4 <= 0 ) + v2 = 4; + } + if ( !currlevel && v2 != 4 && !*(_DWORD *)&spelldata[v3].sTownSpell ) + v2 = 4; + if ( plr[v0]._pRSpell < 0 ) + v2 = 4; + SetSpellTrans(v2); + if ( v6 == -1 ) + DrawSpellCel(629, 631, (char *)pSpellCels, 27, 56); + else + DrawSpellCel(629, 631, (char *)pSpellCels, (char)SpellITbl[v3], 56); +} + +void __cdecl DrawSpellList() +{ + int v0; // esi + signed int v1; // edi + int v2; // ecx + int v3; // eax + signed int v4; // ebp + int v5; // eax + int v6; // esi + int v7; // eax + bool v8; // sf + int v9; // esi + int v10; // eax + int v11; // ebp + int v12; // edx + int *v13; // ecx + int *v14; // eax + signed int v15; // edx + signed int v16; // edi + int v17; // [esp+Ch] [ebp-34h] + __int32 xp; // [esp+10h] [ebp-30h] + __int32 yp; // [esp+14h] [ebp-2Ch] + unsigned char *v20; // [esp+18h] [ebp-28h] + __int32 nCel; // [esp+1Ch] [ebp-24h] + int v22; // [esp+20h] [ebp-20h] + __int32 v23; // [esp+24h] [ebp-1Ch] + signed int v24; // [esp+28h] [ebp-18h] + unsigned __int64 v25; // [esp+2Ch] [ebp-14h] + signed __int64 v26; // [esp+34h] [ebp-Ch] + + pSpell = -1; + infostr[0] = 0; + v17 = 636; + xp = 495; + ClearPanel(); + v0 = myplr; + v1 = 0; + v24 = 0; + do + { + switch ( v1 ) + { + case RSPLTYPE_SKILL: + SetSpellTrans(0); + yp = 46; + v2 = plr[v0]._pAblSpells[0]; + v3 = plr[v0]._pAblSpells[1]; + goto LABEL_10; + case RSPLTYPE_SPELL: + yp = 47; + v2 = plr[v0]._pMemSpells[0]; + v3 = plr[v0]._pMemSpells[1]; + goto LABEL_10; + case RSPLTYPE_SCROLL: + SetSpellTrans(2); + yp = 44; + v2 = plr[v0]._pScrlSpells[0]; + v3 = plr[v0]._pScrlSpells[1]; + goto LABEL_10; + case RSPLTYPE_CHARGES: + SetSpellTrans(3); + yp = 45; + v2 = plr[v0]._pISpells[0]; + v3 = plr[v0]._pISpells[1]; +LABEL_10: + v25 = __PAIR__(v3, v2); + break; + } + v20 = &spelldata[1].sTownSpell; + v4 = 1; + v26 = (__int64)1; + v23 = 1; + v22 = xp - 216; + do + { + if ( !(v25 & v26) ) + goto LABEL_68; + if ( v1 == RSPLTYPE_SPELL ) + { + v5 = v0; + v6 = plr[v0]._pSplLvl[v4]; + v7 = plr[v5]._pISplLvlAdd; + v8 = v7 + v6 < 0; + v9 = v7 + v6; + nCel = v9; + if ( v8 ) + { + nCel = 0; + v9 = 0; + } + SetSpellTrans(v9 <= 0 ? 4 : 1); + } + else + { + v9 = nCel; + } + if ( !currlevel && !*(_DWORD *)v20 ) + SetSpellTrans(4); + DrawSpellCel(v17, xp, (char *)pSpellCels, (char)SpellITbl[v4], 56); + if ( MouseX >= v17 - 64 && MouseX < v17 - 64 + 56 && MouseY >= v22 && MouseY < v22 + 56 ) + { + pSpell = v4; + pSplType = v1; + DrawSpellCel(v17, xp, (char *)pSpellCels, yp, 56); + if ( v1 ) + { + switch ( v1 ) + { + case RSPLTYPE_SPELL: + sprintf(infostr, "%s Spell", spelldata[pSpell].sNameText); + if ( pSpell == 31 ) + { + sprintf(tempstr, "Damages undead only"); + AddPanelString(tempstr, 1); + } + if ( v9 ) + sprintf(tempstr, "Spell Level %i", v9); + else + sprintf(tempstr, "Spell Level 0 - Unusable"); +LABEL_32: + AddPanelString(tempstr, 1); + break; + case RSPLTYPE_SCROLL: + sprintf(infostr, "Scroll of %s", spelldata[pSpell].sNameText); + v10 = myplr; + v11 = 0; + v12 = plr[myplr]._pNumInv; + if ( v12 > 0 ) + { + v13 = &plr[v10].InvList[0]._iMiscId; + do + { + if ( *(v13 - 53) != -1 + && (*v13 == IMISC_SCROLL || *v13 == IMISC_SCROLLT) + && v13[1] == pSpell ) + { + ++v11; + } + v13 += 92; + --v12; + } + while ( v12 ); + } + v14 = &plr[v10].SpdList[0]._iMiscId; + v15 = 8; + do + { + if ( *(v14 - 53) != -1 + && (*v14 == IMISC_SCROLL || *v14 == IMISC_SCROLLT) + && v14[1] == pSpell ) + { + ++v11; + } + v14 += 92; + --v15; + } + while ( v15 ); + if ( v11 == 1 ) + strcpy(tempstr, "1 Scroll"); + else + sprintf(tempstr, "%i Scrolls", v11); + AddPanelString(tempstr, 1); + v4 = v23; + break; + case RSPLTYPE_CHARGES: + sprintf(infostr, "Staff of %s", spelldata[pSpell].sNameText); + if ( plr[myplr].InvBody[4]._iCharges == 1 ) + strcpy(tempstr, "1 Charge"); + else + sprintf(tempstr, "%i Charges", plr[myplr].InvBody[4]._iCharges); + goto LABEL_32; + } + } + else + { + sprintf(infostr, "%s Skill", spelldata[pSpell].sSkillText); + } + v0 = myplr; + v16 = 0; + do + { + if ( plr[0]._pSplHotKey[v16 + 5430 * v0] == pSpell && plr[v0]._pSplTHotKey[v16] == pSplType ) + { + DrawSpellCel(v17, xp, (char *)pSpellCels, v16 + 48, 56); + sprintf(tempstr, "Spell Hot Key #F%i", v16 + 5); + AddPanelString(tempstr, 1); + v0 = myplr; + } + ++v16; + } + while ( v16 < 4 ); + v1 = v24; + goto LABEL_66; + } + v0 = myplr; +LABEL_66: + v17 -= 56; + if ( v17 == 20 ) + { + xp -= 56; + v22 -= 56; + v17 = 636; + } +LABEL_68: + v20 += 56; + ++v4; + v26 *= (__int64)2; + v23 = v4; + } + while ( (signed int)v20 < (signed int)&spelldata[37].sTownSpell ); + if ( v25 && v17 != 636 ) + v17 -= 56; + if ( v17 == 20 ) + { + xp -= 56; + v17 = 636; + } + v24 = ++v1; + } + while ( v1 < 4 ); +} +// 4B8834: using guessed type int pSpell; +// 4B8954: using guessed type int pSplType; + +void __cdecl SetSpell() +{ + int v0; // eax + + spselflag = 0; + if ( pSpell != -1 ) + { + ClearPanel(); + v0 = myplr; + drawpanflag = 255; + plr[v0]._pRSpell = pSpell; + _LOBYTE(plr[v0]._pRSplType) = pSplType; + } +} +// 4B8834: using guessed type int pSpell; +// 4B8954: using guessed type int pSplType; +// 4B8C98: using guessed type int spselflag; +// 52571C: using guessed type int drawpanflag; + +void __fastcall SetSpeedSpell(int slot) +{ + int v1; // esi + int v2; // eax + signed int v3; // ebp + int v4; // edx + int v5; // ebx + int *v6; // edi + + v1 = pSpell; + if ( pSpell != -1 ) + { + v2 = myplr; + v3 = 0; + v4 = myplr; + v5 = pSplType; + v6 = plr[myplr]._pSplHotKey; + do + { + if ( *v6 == v1 && plr[v4]._pSplTHotKey[v3] == v5 ) + *v6 = -1; + ++v3; + ++v6; + } + while ( v3 < 4 ); + plr[0]._pSplHotKey[slot + 5430 * v2] = v1; + plr[v4]._pSplTHotKey[slot] = v5; + } +} +// 4B8834: using guessed type int pSpell; +// 4B8954: using guessed type int pSplType; + +void __fastcall ToggleSpell(int slot) +{ + int v1; // eax + int v2; // edx + int v3; // esi + char *v4; // eax + int v5; // eax + int v6; // eax + int v7; // eax + int v8; // ebx + int v9; // edi + //int v10; // [esp+4h] [ebp-Ch] + char *v11; // [esp+8h] [ebp-8h] + int v12; // [esp+Ch] [ebp-4h] + + v1 = slot + 5430 * myplr; + v2 = plr[0]._pSplHotKey[v1]; + v12 = plr[0]._pSplHotKey[v1]; + if ( v2 != -1 ) + { + v3 = myplr; + v4 = &plr[myplr]._pSplTHotKey[slot]; + v11 = v4; + v5 = *v4; + if ( v5 ) + { + v6 = v5 - 1; + if ( v6 ) + { + v7 = v6 - 1; + if ( v7 ) + { + if ( v7 == 1 ) + { + v8 = plr[v3]._pISpells[0]; + v9 = plr[v3]._pISpells[1]; + } + else + { + v9 = (int)v11; + v8 = plr[myplr]._pSplHotKey[slot]; /* check */ + } + } + else + { + v8 = plr[v3]._pScrlSpells[0]; + v9 = plr[v3]._pScrlSpells[1]; + } + } + else + { + v8 = plr[v3]._pMemSpells[0]; + v9 = plr[v3]._pMemSpells[1]; + } + } + else + { + v8 = plr[v3]._pAblSpells[0]; + v9 = plr[v3]._pAblSpells[1]; + } + if ( v9 & ((unsigned __int64)((__int64)1 << ((unsigned char)v2 - 1)) >> 32) | v8 & (unsigned int)((__int64)1 << ((unsigned char)v2 - 1)) ) + { + drawpanflag = 255; + plr[v3]._pRSpell = v12; + _LOBYTE(plr[v3]._pRSplType) = *v11; + } + } +} +// 52571C: using guessed type int drawpanflag; + +void __fastcall CPrintString(int No, unsigned char pszStr, int Just) +{ + int *v3; // ebx + char *v4; // esi + char *v5; // edi + int v6; // ebx + signed int v7; // edx + unsigned int v8; // eax + unsigned int v9; // ecx + char v10; // cf + unsigned int v11; // ecx + signed int v12; // edx + int v13; // eax + int v14; // ecx + char v15; // al + signed int v16; // edx + int v17; // eax + int v18; // ecx + char v19; // al + signed int v20; // edx + int v21; // eax + int v22; // ecx + char v23; // al + + v3 = (int *)((char *)pPanelText + 4 * pszStr); + v4 = (char *)pPanelText + *v3; + v5 = (char *)gpBuffer + No; + v6 = (int)&v4[v3[1] - *v3]; + if ( (_BYTE)Just ) + { + if ( (unsigned char)Just == 1 ) + { + do + { + v12 = 13; + do + { + while ( 1 ) + { + v13 = (unsigned char)*v4++; + if ( (v13 & 0x80u) == 0 ) + break; + _LOBYTE(v13) = -(char)v13; + v5 += v13; + v12 -= v13; + if ( !v12 ) + goto LABEL_28; + } + v12 -= v13; + v14 = v13; + do + { + v15 = *v4++; + if ( (unsigned char)v15 > 0xFDu ) + { + v15 = -65; + } + else if ( (unsigned char)v15 >= 0xF0u ) + { + v15 -= 62; + } + *v5++ = v15; + --v14; + } + while ( v14 ); + } + while ( v12 ); +LABEL_28: + v5 -= 781; + } + while ( (char *)v6 != v4 ); + } + else if ( (unsigned char)Just == 2 ) + { + do + { + v16 = 13; + do + { + while ( 1 ) + { + v17 = (unsigned char)*v4++; + if ( (v17 & 0x80u) == 0 ) + break; + _LOBYTE(v17) = -(char)v17; + v5 += v17; + v16 -= v17; + if ( !v16 ) + goto LABEL_39; + } + v16 -= v17; + v18 = v17; + do + { + v19 = *v4++; + if ( (unsigned char)v19 >= 0xF0u ) + v19 -= 16; + *v5++ = v19; + --v18; + } + while ( v18 ); + } + while ( v16 ); +LABEL_39: + v5 -= 781; + } + while ( (char *)v6 != v4 ); + } + else + { + do + { + v20 = 13; + do + { + while ( 1 ) + { + v21 = (unsigned char)*v4++; + if ( (v21 & 0x80u) == 0 ) + break; + _LOBYTE(v21) = -(char)v21; + v5 += v21; + v20 -= v21; + if ( !v20 ) + goto LABEL_52; + } + v20 -= v21; + v22 = v21; + do + { + v23 = *v4++; + if ( (unsigned char)v23 >= 0xF0u ) + { + if ( (unsigned char)v23 >= 0xFEu ) + v23 = -49; + else + v23 -= 46; + } + *v5++ = v23; + --v22; + } + while ( v22 ); + } + while ( v20 ); +LABEL_52: + v5 -= 781; + } + while ( (char *)v6 != v4 ); + } + } + else + { + do + { + v7 = 13; + do + { + while ( 1 ) + { + v8 = (unsigned char)*v4++; + if ( (v8 & 0x80u) == 0 ) + break; + _LOBYTE(v8) = -(char)v8; + v5 += v8; + v7 -= v8; + if ( !v7 ) + goto LABEL_15; + } + v7 -= v8; + v9 = v8 >> 1; + if ( v8 & 1 ) + { + *v5++ = *v4++; + if ( !v9 ) + continue; + } + v10 = v9 & 1; + v11 = v8 >> 2; + if ( v10 ) + { + *(_WORD *)v5 = *(_WORD *)v4; + v4 += 2; + v5 += 2; + if ( !v11 ) + continue; + } + qmemcpy(v5, v4, 4 * v11); + v4 += 4 * v11; + v5 += 4 * v11; + } + while ( v7 ); +LABEL_15: + v5 -= 781; + } + while ( (char *)v6 != v4 ); + } +} + +void __fastcall AddPanelString(char *str, int just) +{ + strcpy(&panelstr[64 * pnumlines], str); + pstrjust[pnumlines] = just; + + if ( pnumlines < 4 ) + pnumlines++; +} + +void __cdecl ClearPanel() +{ + pnumlines = 0; + pinfoflag = 0; +} +// 4B8824: using guessed type int pinfoflag; + +void __fastcall DrawPanelBox(int x, int y, int w, int h, int sx, int sy) +{ + char *v6; // esi + char *v7; // edi + int v8; // edx + unsigned int v9; // ecx + char v10; // cf + unsigned int v11; // ecx + + v6 = (char *)pBtmBuff + 640 * y + x; + v7 = &gpBuffer->row_unused_1[sy].col_unused_1[sx]; + v8 = h; + do + { + v9 = w >> 1; + if ( !(w & 1) || (*v7 = *v6, ++v6, ++v7, v9) ) + { + v10 = v9 & 1; + v11 = w >> 2; + if ( !v10 || (*(_WORD *)v7 = *(_WORD *)v6, v6 += 2, v7 += 2, v11) ) + { + qmemcpy(v7, v6, 4 * v11); + v6 += 4 * v11; + v7 += 4 * v11; + } + } + v6 = &v6[-w + 640]; + v7 = &v7[-w + 768]; + --v8; + } + while ( v8 ); +} + +void __fastcall SetFlaskHeight(char *buf, int min, int max, int c, int r) +{ + char *v5; // esi + char *v6; // edi + int v7; // edx + + v5 = &buf[88 * min]; + v6 = &gpBuffer->row_unused_1[r].col_unused_1[c]; + v7 = max - min; + do + { + qmemcpy(v6, v5, 0x58u); + v5 += 88; + v6 += 768; + --v7; + } + while ( v7 ); +} + +void __fastcall DrawFlask(void *a1, int a2, int a3, void *a4, int a5, int a6) +{ + char *v6; // esi + _BYTE *v7; // edi + int v8; // edx + signed int v9; // ecx + char v10; // al + int v11; // [esp+Ch] [ebp-4h] + + v11 = a2; + v6 = (char *)a1 + a3; + v7 = (unsigned char *)a4 + a5; + v8 = a6; + do + { + v9 = 59; + do + { + v10 = *v6++; + if ( v10 ) + *v7 = v10; + ++v7; + --v9; + } + while ( v9 ); + v6 = &v6[v11 - 59]; + v7 += 709; + --v8; + } + while ( v8 ); +} + +void __cdecl DrawLifeFlask() +{ + signed __int64 v0; // rax + signed int v1; // esi + int v2; // esi + + v0 = (signed __int64)((double)plr[myplr]._pHitPoints / (double)plr[myplr]._pMaxHP * 80.0); + plr[myplr]._pHPPer = v0; + if ( (signed int)v0 > 80 ) + LODWORD(v0) = 80; + v1 = 80 - v0; + if ( 80 - (signed int)v0 > 11 ) + v1 = 11; + v2 = v1 + 2; + DrawFlask(pLifeBuff, 88, 277, gpBuffer, 383405, v2); + if ( v2 != 13 ) + DrawFlask(pBtmBuff, 640, 640 * v2 + 2029, gpBuffer, 768 * v2 + 383405, 13 - v2); +} + +void __cdecl UpdateLifeFlask() +{ + signed __int64 v0; // rax + signed int v1; // edi + + v0 = (signed __int64)((double)plr[myplr]._pHitPoints / (double)plr[myplr]._pMaxHP * 80.0); + v1 = v0; + plr[myplr]._pHPPer = v0; + if ( (signed int)v0 > 69 ) + { + v1 = 69; +LABEL_8: + DrawPanelBox(96, 85 - v1, 0x58u, v1, 160, 581 - v1); + return; + } + if ( (signed int)v0 < 0 ) + v1 = 0; + if ( v1 != 69 ) + SetFlaskHeight((char *)pLifeBuff, 16, 85 - v1, 160, 512); + if ( v1 ) + goto LABEL_8; +} + +void __cdecl DrawManaFlask() +{ + int v0; // eax + int v1; // esi + int v2; // esi + + v0 = plr[myplr]._pManaPer; + if ( v0 > 80 ) + v0 = 80; + v1 = 80 - v0; + if ( 80 - v0 > 11 ) + v1 = 11; + v2 = v1 + 2; + DrawFlask(pManaBuff, 88, 277, gpBuffer, 383771, v2); + if ( v2 != 13 ) + DrawFlask(pBtmBuff, 640, 640 * v2 + 2395, gpBuffer, 768 * v2 + 383771, 13 - v2); +} + +void __cdecl control_update_life_mana() +{ + int v0; // esi + signed __int64 v1; // rax + int v2; // [esp+4h] [ebp-8h] + int v3; // [esp+8h] [ebp-4h] + + v0 = myplr; + v3 = plr[myplr]._pMaxMana; + v2 = plr[myplr]._pMana; + if ( plr[myplr]._pMaxMana < 0 ) + v3 = 0; + if ( plr[myplr]._pMana < 0 ) + v2 = 0; + if ( v3 ) + v1 = (signed __int64)((double)v2 / (double)v3 * 80.0); + else + LODWORD(v1) = 0; + plr[v0]._pManaPer = v1; + plr[v0]._pHPPer = (signed __int64)((double)plr[v0]._pHitPoints / (double)plr[v0]._pMaxHP * 80.0); +} + +void __cdecl UpdateManaFlask() +{ + signed int v0; // edi + int v1; // [esp+8h] [ebp-8h] + int v2; // [esp+Ch] [ebp-4h] + + v2 = plr[myplr]._pMaxMana; + v1 = plr[myplr]._pMana; + if ( plr[myplr]._pMaxMana < 0 ) + v2 = 0; + if ( plr[myplr]._pMana < 0 ) + v1 = 0; + if ( v2 ) + v0 = (signed __int64)((double)v1 / (double)v2 * 80.0); + else + v0 = 0; + plr[myplr]._pManaPer = v0; + if ( v0 > 69 ) + v0 = 69; + if ( v0 != 69 ) + SetFlaskHeight((char *)pManaBuff, 16, 85 - v0, 528, 512); + if ( v0 ) + DrawPanelBox(464, 85 - v0, 0x58u, v0, 528, 581 - v0); + DrawSpell(); +} + +void __cdecl InitControlPan() +{ + size_t v0; // esi + void *v1; // ecx + void *v2; // ecx + void *v3; // ecx + char v4; // al + unsigned char *v5; // eax + + v0 = 0x16800; + if ( gbMaxPlayers != 1 ) + v0 = 0x2D000; + pBtmBuff = DiabloAllocPtr(v0); + memset(pBtmBuff, 0, v0); + pManaBuff = DiabloAllocPtr(0x1E40); + memset(pManaBuff, 0, 0x1E40u); + pLifeBuff = DiabloAllocPtr(0x1E40); + memset(pLifeBuff, 0, 0x1E40u); + pPanelText = LoadFileInMem("CtrlPan\\SmalText.CEL", 0); + pChrPanel = LoadFileInMem("Data\\Char.CEL", 0); + pSpellCels = LoadFileInMem("CtrlPan\\SpelIcon.CEL", 0); + SetSpellTrans(0); + pStatusPanel = LoadFileInMem("CtrlPan\\Panel8.CEL", 0); + CelDecodeRect((char *)pBtmBuff, 0, 143, 640, (char *)pStatusPanel, 1, 640); + v1 = pStatusPanel; + pStatusPanel = 0; + mem_free_dbg(v1); + pStatusPanel = LoadFileInMem("CtrlPan\\P8Bulbs.CEL", 0); + CelDecodeRect((char *)pLifeBuff, 0, 87, 88, (char *)pStatusPanel, 1, 88); + CelDecodeRect((char *)pManaBuff, 0, 87, 88, (char *)pStatusPanel, 2, 88); + v2 = pStatusPanel; + pStatusPanel = 0; + mem_free_dbg(v2); + talkflag = 0; + if ( gbMaxPlayers != 1 ) + { + pTalkPanel = LoadFileInMem("CtrlPan\\TalkPanl.CEL", 0); + CelDecodeRect((char *)pBtmBuff, 0, 287, 640, (char *)pTalkPanel, 1, 640); + v3 = pTalkPanel; + pTalkPanel = 0; + mem_free_dbg(v3); + pMultiBtns = LoadFileInMem("CtrlPan\\P8But2.CEL", 0); + pTalkBtns = LoadFileInMem("CtrlPan\\TalkButt.CEL", 0); + sgbPlrTalkTbl = 0; + *(_DWORD *)&tempstr[256] = 0x1010101; + talkbtndown[0] = 0; + talkbtndown[1] = 0; + sgszTalkMsg[0] = 0; + talkbtndown[2] = 0; + } + panelflag = 0; + lvlbtndown = 0; + pPanelButtons = LoadFileInMem("CtrlPan\\Panel8bu.CEL", 0); + memset(panbtn, 0, sizeof(panbtn)); + panbtndown = 0; + numpanbtns = 2 * (gbMaxPlayers != 1) + 6; + pChrButtons = LoadFileInMem("Data\\CharBut.CEL", 0); + chrbtn[0] = 0; + chrbtn[1] = 0; + chrbtn[2] = 0; + chrbtnactive = 0; + chrbtn[3] = 0; + pDurIcons = LoadFileInMem("Items\\DurIcons.CEL", 0); + strcpy(infostr, &empty_string); + ClearPanel(); + drawhpflag = 1; + drawmanaflag = 1; + chrflag = 0; + spselflag = 0; + pSpellBkCel = LoadFileInMem("Data\\SpellBk.CEL", 0); + pSBkBtnCel = LoadFileInMem("Data\\SpellBkB.CEL", 0); + pSBkIconCels = LoadFileInMem("Data\\SpellI2.CEL", 0); + sbooktab = 0; + sbookflag = 0; + v4 = plr[myplr]._pClass; + if ( v4 ) + { + if ( v4 == UI_ROGUE ) + { + SpellPages[0][0] = SPL_DISARM; + } + else if ( v4 == UI_SORCERER ) + { + SpellPages[0][0] = SPL_RECHARGE; + } + } + else + { + SpellPages[0][0] = SPL_REPAIR; + } + pQLogCel = LoadFileInMem("Data\\Quest.CEL", 0); + v5 = LoadFileInMem("CtrlPan\\Golddrop.cel", 0); + frame_4B8800 = 1; + dropGoldFlag = 0; + dropGoldValue = 0; + initialDropGoldValue = 0; + initialDropGoldIndex = 0; + pGBoxBuff = v5; +} +// 4B84DC: using guessed type int dropGoldFlag; +// 4B851C: using guessed type int lvlbtndown; +// 4B87A8: using guessed type int chrbtnactive; +// 4B8840: using guessed type int sgbPlrTalkTbl; +// 4B8950: using guessed type int sbooktab; +// 4B8960: using guessed type int talkflag; +// 4B8968: using guessed type int sbookflag; +// 4B8A7C: using guessed type int numpanbtns; +// 4B8B84: using guessed type int panelflag; +// 4B8C90: using guessed type int panbtndown; +// 4B8C98: using guessed type int spselflag; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl ClearCtrlPan() +{ + DrawPanelBox(0, sgbPlrTalkTbl + 16, 0x280u, 0x80u, 64, 512); + DrawInfoBox(); +} +// 4B8840: using guessed type int sgbPlrTalkTbl; + +void __cdecl DrawCtrlPan() +{ + signed int v0; // edi + int *v1; // esi + int v2; // ecx + int v3; // eax + + v0 = 0; + v1 = (int *)PanBtnPos; + do + { + v2 = *v1; + if ( panbtn[v0] ) + CelDecodeOnly(v2 + 64, v1[1] + 178, pPanelButtons, v0 + 1, 71); + else + DrawPanelBox(v2, v1[1] - 336, 0x47u, 0x14u, v2 + 64, v1[1] + 160); + ++v0; + v1 += 5; + } + while ( v0 < 6 ); + if ( numpanbtns == 8 ) + { + CelDecodeOnly(151, 634, pMultiBtns, panbtn[6] + 1, 33); + if ( FriendlyMode ) + v3 = panbtn[7] + 3; + else + v3 = panbtn[7] + 5; + CelDecodeOnly(591, 634, pMultiBtns, v3, 33); + } +} +// 484368: using guessed type int FriendlyMode; +// 4B8A7C: using guessed type int numpanbtns; + +void __cdecl DoSpeedBook() +{ + int v0; // eax + signed int v1; // ebx + bool v2; // zf + unsigned __int64 v3; // rdi + unsigned int v4; // ecx + //unsigned int v5; // [esp+4h] [ebp-20h] + //unsigned int v6; // [esp+8h] [ebp-1Ch] + unsigned int v7; // [esp+8h] [ebp-1Ch] + int X; // [esp+Ch] [ebp-18h] + int Y; // [esp+10h] [ebp-14h] + signed int v10; // [esp+14h] [ebp-10h] + int v11; // [esp+18h] [ebp-Ch] + signed int v12; // [esp+1Ch] [ebp-8h] + signed int v13; // [esp+20h] [ebp-4h] + + v0 = myplr; + v13 = 636; + v1 = 1; + v2 = plr[myplr]._pRSpell == -1; + spselflag = 1; + v12 = 495; + X = 600; + Y = 307; + if ( !v2 ) + { + v11 = 0; + //v3 = __PAIR__(v5, v6); + while ( 1 ) + { + if ( v11 ) + { + switch ( v11 ) + { + case RSPLTYPE_SPELL: + HIDWORD(v3) = plr[v0]._pMemSpells[0]; + LODWORD(v3) = plr[v0]._pMemSpells[1]; + break; + case RSPLTYPE_SCROLL: + HIDWORD(v3) = plr[v0]._pScrlSpells[0]; + LODWORD(v3) = plr[v0]._pScrlSpells[1]; + break; + case RSPLTYPE_CHARGES: + HIDWORD(v3) = plr[v0]._pISpells[0]; + LODWORD(v3) = plr[v0]._pISpells[1]; + break; + } + } + else + { + HIDWORD(v3) = plr[v0]._pAblSpells[0]; + LODWORD(v3) = plr[v0]._pAblSpells[1]; + } + v7 = 0; + v10 = 1; + do + { + if ( (unsigned int)v3 & v7 | HIDWORD(v3) & v1 ) + { + if ( v10 == plr[v0]._pRSpell && v11 == SLOBYTE(plr[v0]._pRSplType) ) + { + X = v13 - 36; + Y = v12 - 188; + } + v13 -= 56; + if ( v13 == 20 ) + { + v12 -= 56; + v13 = 636; + } + } + v4 = __PAIR__(v7, v1) >> 31; + v1 *= 2; + ++v10; + v7 = v4; + } + while ( v10 < 37 ); + if ( v3 && v13 != 636 ) + v13 -= 56; + if ( v13 == 20 ) + { + v12 -= 56; + v13 = 636; + } + if ( ++v11 >= 4 ) + break; + v1 = 1; + } + } + SetCursorPos(X, Y); +} +// 4B8C98: using guessed type int spselflag; + +void __cdecl DoPanBtn() +{ + int v0; // edx + int v1; // ebx + int v2; // edi + int v3; // esi + int (*v4)[5]; // eax + int v5; // ecx + + v0 = MouseX; + v1 = MouseY; + v2 = numpanbtns; + v3 = 0; + if ( numpanbtns > 0 ) + { + v4 = PanBtnPos; + do + { + if ( v0 >= (*v4)[0] && v0 <= (*v4)[0] + (*v4)[2] ) + { + v5 = (*v4)[1]; + if ( v1 >= v5 && v1 <= v5 + (*v4)[3] ) + { + panbtn[v3] = 1; + drawbtnflag = 1; + panbtndown = 1; + } + } + ++v3; + ++v4; + } + while ( v3 < v2 ); + } + if ( !spselflag && v0 >= 565 && v0 < 621 && v1 >= 416 && v1 < 472 ) + { + DoSpeedBook(); + gamemenu_off(); + } +} +// 4B8A7C: using guessed type int numpanbtns; +// 4B8C90: using guessed type int panbtndown; +// 4B8C98: using guessed type int spselflag; + +void __fastcall control_set_button_down(int btn_id) +{ + panbtn[btn_id] = 1; + drawbtnflag = 1; + panbtndown = 1; +} +// 4B8C90: using guessed type int panbtndown; + +void __cdecl control_check_btn_press() +{ + int v0; // edx + int v1; // esi + + v0 = MouseX; + v1 = MouseY; + if ( MouseX >= PanBtnPos[3][0] + && MouseX <= PanBtnPos[3][0] + PanBtnPos[3][2] + && MouseY >= PanBtnPos[3][1] + && MouseY <= PanBtnPos[3][1] + PanBtnPos[3][3] ) + { + control_set_button_down(3); + } + if ( v0 >= PanBtnPos[6][0] + && v0 <= PanBtnPos[6][0] + PanBtnPos[6][2] + && v1 >= PanBtnPos[6][1] + && v1 <= PanBtnPos[6][1] + PanBtnPos[6][3] ) + { + control_set_button_down(6); + } +} + +void __cdecl DoAutoMap() +{ + if ( currlevel || gbMaxPlayers != 1 ) + { + if ( automapflag ) + automapflag = 0; + else + StartAutomap(); + } + else + { + InitDiabloMsg(1); + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl CheckPanelInfo() +{ + int v0; // edi + int v1; // eax + int v2; // ecx + int v3; // ecx + int v4; // edi + int v5; // eax + int *v6; // edx + int v7; // ebx + int v8; // ebx + int *v9; // eax + signed int v10; // edx + int v11; // ecx + int v12; // [esp+10h] [ebp-4h] + + v0 = 0; + panelflag = 0; + ClearPanel(); + if ( numpanbtns > 0 ) + { + do + { + v1 = v0; + v2 = PanBtnPos[v0][0]; + if ( MouseX >= v2 && MouseX <= v2 + PanBtnPos[v1][2] ) + { + v3 = PanBtnPos[v1][1]; + if ( MouseY >= v3 && MouseY <= v3 + PanBtnPos[v1][3] ) + { + if ( v0 == 7 ) + { + if ( FriendlyMode ) + strcpy(infostr, "Player friendly"); + else + strcpy(infostr, "Player attack"); + } + else + { + strcpy(infostr, PanBtnStr[v0]); + } + if ( PanBtnHotKey[v0] ) + { + sprintf(tempstr, "Hotkey : %s", PanBtnHotKey[v0]); + AddPanelString(tempstr, 1); + } + _LOBYTE(infoclr) = 0; + panelflag = 1; + pinfoflag = 1; + } + } + ++v0; + } + while ( v0 < numpanbtns ); + } + if ( !spselflag && MouseX >= 565 && MouseX < 621 && MouseY >= 416 && MouseY < 472 ) + { + strcpy(infostr, "Select current spell button"); + _LOBYTE(infoclr) = 0; + panelflag = 1; + pinfoflag = 1; + strcpy(tempstr, "Hotkey : 's'"); + AddPanelString(tempstr, 1); + v4 = plr[myplr]._pRSpell; + if ( v4 != -1 ) + { + switch ( _LOBYTE(plr[myplr]._pRSplType) ) + { + case RSPLTYPE_SKILL: + sprintf(tempstr, "%s Skill", spelldata[v4].sSkillText); +LABEL_54: + AddPanelString(tempstr, 1); + break; + case RSPLTYPE_SPELL: + sprintf(tempstr, "%s Spell", spelldata[v4].sNameText); + AddPanelString(tempstr, 1); + v11 = plr[myplr]._pISplLvlAdd + plr[myplr]._pSplLvl[v4]; + if ( v11 < 0 ) + v11 = 0; + if ( v11 ) + sprintf(tempstr, "Spell Level %i", v11); + else + sprintf(tempstr, "Spell Level 0 - Unusable"); + goto LABEL_54; + case RSPLTYPE_SCROLL: + sprintf(tempstr, "Scroll of %s", spelldata[v4].sNameText); + AddPanelString(tempstr, 1); + v12 = 0; + v5 = myplr; + if ( plr[myplr]._pNumInv > 0 ) + { + v6 = &plr[v5].InvList[0]._iMiscId; + v7 = plr[myplr]._pNumInv; + do + { + if ( *(v6 - 53) != -1 && (*v6 == IMISC_SCROLL || *v6 == IMISC_SCROLLT) && v6[1] == v4 ) + ++v12; + v6 += 92; + --v7; + } + while ( v7 ); + } + v8 = v12; + v9 = &plr[v5].SpdList[0]._iMiscId; + v10 = 8; + do + { + if ( *(v9 - 53) != -1 && (*v9 == IMISC_SCROLL || *v9 == IMISC_SCROLLT) && v9[1] == v4 ) + ++v8; + v9 += 92; + --v10; + } + while ( v10 ); + if ( v8 == 1 ) + strcpy(tempstr, "1 Scroll"); + else + sprintf(tempstr, "%i Scrolls", v8); + goto LABEL_54; + case RSPLTYPE_CHARGES: + sprintf(tempstr, "Staff of %s", spelldata[v4].sNameText); + AddPanelString(tempstr, 1); + if ( plr[myplr].InvBody[4]._iCharges == 1 ) + strcpy(tempstr, "1 Charge"); + else + sprintf(tempstr, "%i Charges", plr[myplr].InvBody[4]._iCharges); + goto LABEL_54; + } + } + } + if ( MouseX > 190 && MouseX < 437 && MouseY > 356 && MouseY < 385 ) + pcursinvitem = CheckInvHLight(); +} +// 484368: using guessed type int FriendlyMode; +// 4B8824: using guessed type int pinfoflag; +// 4B883C: using guessed type int infoclr; +// 4B8A7C: using guessed type int numpanbtns; +// 4B8B84: using guessed type int panelflag; +// 4B8C98: using guessed type int spselflag; +// 4B8CB8: using guessed type char pcursinvitem; + +void __cdecl CheckBtnUp() +{ + signed int v0; // esi + int *v1; // eax + int v2; // edx + signed int v3; // eax + int v4; // ecx + int v5; // ecx + char v6; // [esp+Fh] [ebp-1h] + + v6 = 1; + drawbtnflag = 1; + panbtndown = 0; + v0 = 0; + do + { + v1 = &panbtn[v0]; + if ( *v1 ) + { + v2 = MouseX; + *v1 = 0; + v3 = v0; + v4 = PanBtnPos[v0][0]; + if ( v2 >= v4 && v2 <= v4 + PanBtnPos[v3][2] ) + { + v5 = PanBtnPos[v3][1]; + if ( MouseY >= v5 && MouseY <= v5 + PanBtnPos[v3][3] ) + { + switch ( v0 ) + { + case PANBTN_CHARINFO: + questlog = 0; + chrflag = chrflag == 0; + break; + case PANBTN_QLOG: + chrflag = 0; + if ( questlog ) + questlog = 0; + else + StartQuestlog(); + break; + case PANBTN_AUTOMAP: + DoAutoMap(); + break; + case PANBTN_MAINMENU: + qtextflag = 0; + gamemenu_handle_previous(); + v6 = 0; + break; + case PANBTN_INVENTORY: + sbookflag = 0; + invflag = invflag == 0; + if ( dropGoldFlag ) + { + dropGoldFlag = 0; + dropGoldValue = 0; + } + break; + case PANBTN_SPELLBOOK: + invflag = 0; + if ( dropGoldFlag ) + { + dropGoldFlag = 0; + dropGoldValue = 0; + } + sbookflag = sbookflag == 0; + break; + case PANBTN_SENDMSG: + if ( talkflag ) + control_reset_talk(); + else + control_type_message(); + break; + case PANBTN_FRIENDLY: + FriendlyMode = FriendlyMode == 0; + break; + default: + break; + } + } + } + } + ++v0; + } + while ( v0 < 8 ); + if ( v6 ) + gamemenu_off(); +} +// 484368: using guessed type int FriendlyMode; +// 4B84DC: using guessed type int dropGoldFlag; +// 4B8960: using guessed type int talkflag; +// 4B8968: using guessed type int sbookflag; +// 4B8C90: using guessed type int panbtndown; +// 646D00: using guessed type char qtextflag; +// 69BD04: using guessed type int questlog; + +void __cdecl FreeControlPan() +{ + void *v0; // ecx + void *v1; // ecx + void *v2; // ecx + void *v3; // ecx + void *v4; // ecx + void *v5; // ecx + void *v6; // ecx + void *v7; // ecx + void *v8; // ecx + void *v9; // ecx + void *v10; // ecx + void *v11; // ecx + void *v12; // ecx + void *v13; // ecx + void *v14; // ecx + void *v15; // ecx + + v0 = pBtmBuff; + pBtmBuff = 0; + mem_free_dbg(v0); + v1 = pManaBuff; + pManaBuff = 0; + mem_free_dbg(v1); + v2 = pLifeBuff; + pLifeBuff = 0; + mem_free_dbg(v2); + v3 = pPanelText; + pPanelText = 0; + mem_free_dbg(v3); + v4 = pChrPanel; + pChrPanel = 0; + mem_free_dbg(v4); + v5 = pSpellCels; + pSpellCels = 0; + mem_free_dbg(v5); + v6 = pPanelButtons; + pPanelButtons = 0; + mem_free_dbg(v6); + v7 = pMultiBtns; + pMultiBtns = 0; + mem_free_dbg(v7); + v8 = pTalkBtns; + pTalkBtns = 0; + mem_free_dbg(v8); + v9 = pChrButtons; + pChrButtons = 0; + mem_free_dbg(v9); + v10 = pDurIcons; + pDurIcons = 0; + mem_free_dbg(v10); + v11 = pQLogCel; + pQLogCel = 0; + mem_free_dbg(v11); + v12 = pSpellBkCel; + pSpellBkCel = 0; + mem_free_dbg(v12); + v13 = pSBkBtnCel; + pSBkBtnCel = 0; + mem_free_dbg(v13); + v14 = pSBkIconCels; + pSBkIconCels = 0; + mem_free_dbg(v14); + v15 = pGBoxBuff; + pGBoxBuff = 0; + mem_free_dbg(v15); +} + +int __fastcall control_WriteStringToBuffer(char *str) +{ + signed int v1; // edx + unsigned char v2; // al + + v1 = 0; + do + { + v2 = *str; + if ( !*str ) + return 1; + ++str; + v1 += fontkern[fontframe[fontidx[v2]]]; + } + while ( v1 < 125 ); + return 0; +} + +void __cdecl DrawInfoBox() +{ + int v0; // ecx + int v1; // eax + int v2; // eax + int v3; // esi + char *v4; // eax + const char *v5; // eax + char v6; // al + signed int v7; // edi + signed int v8; // ebp + int v9; // esi + char *v10; // ebx + + DrawPanelBox(177, 62, 0x120u, 0x3Cu, 241, 558); + v0 = trigflag[3]; + v1 = spselflag; + if ( !panelflag && !trigflag[3] && pcursinvitem == -1 ) + { + if ( spselflag ) + { +LABEL_32: + _LOBYTE(infoclr) = 0; + goto LABEL_33; + } + infostr[0] = 0; + _LOBYTE(infoclr) = 0; + ClearPanel(); + } + if ( v1 || v0 ) + goto LABEL_32; + if ( pcurs < CURSOR_FIRSTITEM ) + { + if ( pcursitem != -1 ) + GetItemStr(pcursitem); + if ( pcursobj != -1 ) + GetObjectStr(pcursobj); + if ( pcursmonst != -1 ) + { + if ( leveltype != DTYPE_TOWN) + { + _LOBYTE(infoclr) = 0; + strcpy(infostr, monster[pcursmonst].mName); + ClearPanel(); + if ( monster[pcursmonst]._uniqtype ) + { + _LOBYTE(infoclr) = 3; + PrintUniqueHistory(); + } + else + { + PrintMonstHistory(monster[pcursmonst].MType->mtype); + } + } + else + { + strcpy(infostr, towner[pcursmonst]._tName); + } + } + if ( pcursplr != -1 ) + { + _LOBYTE(infoclr) = 3; + strcpy(infostr, plr[pcursplr]._pName); + ClearPanel(); + sprintf(tempstr, "Level : %i", plr[pcursplr]._pLevel); + AddPanelString(tempstr, 1); + sprintf(tempstr, "Hit Points %i of %i", plr[pcursplr]._pHitPoints >> 6, plr[pcursplr]._pMaxHP >> 6); + AddPanelString(tempstr, 1); + } + } + else + { + v2 = myplr; + if ( plr[myplr].HoldItem._itype == ITYPE_GOLD ) + { + v3 = plr[v2].HoldItem._ivalue; + v4 = get_pieces_str(plr[v2].HoldItem._ivalue); + sprintf(infostr, "%i gold %s", v3, v4); + } + else if ( plr[v2].HoldItem._iStatFlag ) + { + if ( plr[v2].HoldItem._iIdentified ) + v5 = plr[v2].HoldItem._iIName; + else + v5 = plr[v2].HoldItem._iName; + strcpy(infostr, v5); + v6 = plr[myplr].HoldItem._iMagical; + if ( v6 == 1 ) + _LOBYTE(infoclr) = 1; + if ( v6 == 2 ) + _LOBYTE(infoclr) = 3; + } + else + { + ClearPanel(); + AddPanelString("Requirements not met", 1); + pinfoflag = 1; + } + } +LABEL_33: + if ( (infostr[0] || pnumlines) && !talkflag ) + { + v7 = 0; + v8 = 1; + if ( infostr[0] ) + { + control_print_info_str(0, infostr, 1, pnumlines); + v7 = 1; + v8 = 0; + } + v9 = 0; + if ( pnumlines > 0 ) + { + v10 = panelstr; + do + { + control_print_info_str(v9 + v7, v10, pstrjust[v9], pnumlines - v8); + ++v9; + v10 += 64; + } + while ( v9 < pnumlines ); + } + } +} +// 4B8824: using guessed type int pinfoflag; +// 4B883C: using guessed type int infoclr; +// 4B8960: using guessed type int talkflag; +// 4B8B84: using guessed type int panelflag; +// 4B8C98: using guessed type int spselflag; +// 4B8CB8: using guessed type char pcursinvitem; +// 4B8CC0: using guessed type char pcursitem; +// 4B8CC1: using guessed type char pcursobj; +// 4B8CC2: using guessed type char pcursplr; +// 5BB1ED: using guessed type char leveltype; + +void __fastcall control_print_info_str(int y, char *str, bool center, int lines) +{ + int v4; // edi + char *v5; // ebx + unsigned char v6; // cl + signed int v7; // eax + char *v8; // esi + int v9; // eax + unsigned char v10; // esi + unsigned char v11; // al + int width; // [esp+18h] [ebp+Ch] + + v4 = 0; + v5 = str; + width = lineoffset[y + 4 * lines + lines]; + if ( center == 1 ) + { + v6 = *str; + v7 = 0; + v8 = str; + if ( !*str ) + goto LABEL_14; + do + { + ++v8; + v7 += fontkern[fontframe[fontidx[v6]]] + 2; + v6 = *v8; + } + while ( *v8 ); + if ( v7 < 288 ) +LABEL_14: + v4 = (288 - v7) >> 1; + width += v4; + } + while ( 1 ) + { + v11 = *v5; + if ( !*v5 ) + break; + ++v5; + v9 = fontidx[v11]; + _LOBYTE(v9) = fontframe[v9]; + v10 = (unsigned char)v9; + v4 += fontkern[(unsigned char)v9] + 2; + if ( (_BYTE)v9 ) + { + if ( v4 < 288 ) + { + _LOBYTE(v9) = infoclr; + CPrintString(width, v10, v9); + } + } + width += fontkern[v10] + 2; + } +} +// 4B883C: using guessed type int infoclr; + +void __fastcall PrintGameStr(int x, int y, char *str, int color) +{ + char *v4; // edi + int v5; // esi + unsigned char i; // al + unsigned char v7; // bl + + v4 = str; + v5 = screen_y_times_768[y + 160] + x + 64; + for ( i = *str; *v4; i = *v4 ) + { + ++v4; + v7 = fontframe[fontidx[i]]; + if ( v7 ) + CPrintString(v5, v7, color); + v5 += fontkern[v7] + 1; + } +} + +void __cdecl DrawChr() +{ + char v0; // al + int v1; // ecx + int v2; // ecx + int v3; // eax + int v4; // eax + bool v5; // zf + int v6; // eax + int v7; // edi + int v8; // edi + char v9; // al + char v10; // al + char v11; // al + int v12; // ecx + int v13; // eax + int v14; // ecx + int v15; // eax + int v16; // ecx + int v17; // eax + int v18; // ecx + int v19; // eax + int *v20; // edi + int v21; // edi + int v22; // edi + int v23; // ecx + int v24; // eax + int v25; // ecx + int v26; // ecx + char a4[64]; // [esp+Ch] [ebp-50h] + int v28; // [esp+4Ch] [ebp-10h] + int v29; // [esp+50h] [ebp-Ch] + int v30; // [esp+54h] [ebp-8h] + char a5[4]; // [esp+58h] [ebp-4h] + + CelDecodeOnly(64, 511, pChrPanel, 1, 320); + ADD_PlrStringXY(20, 32, 151, plr[myplr]._pName, 0); + v0 = plr[myplr]._pClass; + if ( v0 ) + { + if ( v0 == 1 ) + { + ADD_PlrStringXY(168, 32, 299, "Rogue", 0); /* should use ClassStrTbl ? */ + } + else if ( v0 == 2 ) + { + ADD_PlrStringXY(168, 32, 299, "Sorceror", 0); + } + } + else + { + ADD_PlrStringXY(168, 32, 299, "Warrior", 0); + } + sprintf(a4, "%i", plr[myplr]._pLevel); + ADD_PlrStringXY(66, 69, 109, a4, 0); + sprintf(a4, "%li", plr[myplr]._pExperience); + ADD_PlrStringXY(216, 69, 300, a4, 0); + if ( plr[myplr]._pLevel == 50 ) + { + strcpy(a4, "None"); + a5[0] = 3; + } + else + { + sprintf(a4, "%li", plr[myplr]._pNextExper); + a5[0] = 0; + } + ADD_PlrStringXY(216, 97, 300, a4, a5[0]); + sprintf(a4, "%i", plr[myplr]._pGold); + ADD_PlrStringXY(216, 146, 300, a4, 0); + a5[0] = 0; + v29 = plr[myplr]._pIBonusAC; + if ( v29 > 0 ) + a5[0] = 1; + if ( v29 < 0 ) + a5[0] = 2; + sprintf(a4, "%i", v29 + plr[myplr]._pIAC + plr[myplr]._pDexterity / 5); + ADD_PlrStringXY(258, 183, 301, a4, a5[0]); + a5[0] = 0; + v1 = plr[myplr]._pIBonusToHit; + if ( v1 > 0 ) + a5[0] = 1; + if ( v1 < 0 ) + a5[0] = 2; + sprintf(a4, "%i%%", (plr[myplr]._pDexterity >> 1) + v1 + 50); + ADD_PlrStringXY(258, 211, 301, a4, a5[0]); + a5[0] = 0; + v2 = myplr; + v3 = plr[myplr]._pIBonusDam; + if ( v3 > 0 ) + a5[0] = 1; + if ( v3 < 0 ) + a5[0] = 2; + v30 = plr[v2]._pIMinDam; + v30 += plr[v2]._pIBonusDamMod + v30 * v3 / 100; + v4 = plr[v2]._pDamageMod; + v5 = plr[v2].InvBody[4]._itype == ITYPE_BOW; + v29 = plr[v2]._pDamageMod; + if ( v5 && _LOBYTE(plr[v2]._pClass) != 1 ) + v4 >>= 1; + v30 += v4; + v6 = plr[v2]._pIBonusDam; + v28 = plr[v2]._pIMaxDam; + v7 = plr[v2]._pIBonusDamMod + v28 * v6 / 100 + v28; + if ( plr[v2].InvBody[4]._itype != ITYPE_BOW || _LOBYTE(plr[v2]._pClass) == 1 ) + v8 = v29 + v7; + else + v8 = (v29 >> 1) + v7; + sprintf(a4, "%i-%i", v30, v8); + if ( v30 >= 100 || v8 >= 100 ) + MY_PlrStringXY(254, 239, 305, a4, a5[0], -1); + else + MY_PlrStringXY(258, 239, 301, a4, a5[0], 0); + v9 = plr[myplr]._pMagResist; + a5[0] = v9 != 0; + if ( v9 >= 75 ) + { + a5[0] = 3; + sprintf(a4, "MAX"); + } + else + { + sprintf(a4, "%i%%", v9); + } + ADD_PlrStringXY(257, 276, 300, a4, a5[0]); + v10 = plr[myplr]._pFireResist; + a5[0] = v10 != 0; + if ( v10 >= 75 ) + { + a5[0] = 3; + sprintf(a4, "MAX"); + } + else + { + sprintf(a4, "%i%%", v10); + } + ADD_PlrStringXY(257, 304, 300, a4, a5[0]); + v11 = plr[myplr]._pLghtResist; + a5[0] = v11 != 0; + if ( v11 >= 75 ) + { + a5[0] = 3; + sprintf(a4, "MAX"); + } + else + { + sprintf(a4, "%i%%", v11); + } + ADD_PlrStringXY(257, 332, 300, a4, a5[0]); + a5[0] = 0; + sprintf(a4, "%i", plr[myplr]._pBaseStr); + if ( MaxStats[SLOBYTE(plr[myplr]._pClass)][0] == plr[myplr]._pBaseStr ) + a5[0] = 3; + ADD_PlrStringXY(95, 155, 126, a4, a5[0]); + a5[0] = 0; + sprintf(a4, "%i", plr[myplr]._pBaseMag); + if ( MaxStats[SLOBYTE(plr[myplr]._pClass)][1] == plr[myplr]._pBaseMag ) + a5[0] = 3; + ADD_PlrStringXY(95, 183, 126, a4, a5[0]); + a5[0] = 0; + sprintf(a4, "%i", plr[myplr]._pBaseDex); + if ( MaxStats[SLOBYTE(plr[myplr]._pClass)][2] == plr[myplr]._pBaseDex ) + a5[0] = 3; + ADD_PlrStringXY(95, 211, 126, a4, a5[0]); + a5[0] = 0; + sprintf(a4, "%i", plr[myplr]._pBaseVit); + if ( MaxStats[SLOBYTE(plr[myplr]._pClass)][3] == plr[myplr]._pBaseVit ) + a5[0] = 3; + ADD_PlrStringXY(95, 239, 126, a4, a5[0]); + a5[0] = 0; + v12 = plr[myplr]._pStrength; + v13 = plr[myplr]._pBaseStr; + if ( v12 > v13 ) + a5[0] = 1; + if ( v12 < v13 ) + a5[0] = 2; + sprintf(a4, "%i", v12); + ADD_PlrStringXY(143, 155, 173, a4, a5[0]); + a5[0] = 0; + v14 = plr[myplr]._pMagic; + v15 = plr[myplr]._pBaseMag; + if ( v14 > v15 ) + a5[0] = 1; + if ( v14 < v15 ) + a5[0] = 2; + sprintf(a4, "%i", v14); + ADD_PlrStringXY(143, 183, 173, a4, a5[0]); + a5[0] = 0; + v16 = plr[myplr]._pDexterity; + v17 = plr[myplr]._pBaseDex; + if ( v16 > v17 ) + a5[0] = 1; + if ( v16 < v17 ) + a5[0] = 2; + sprintf(a4, "%i", v16); + ADD_PlrStringXY(143, 211, 173, a4, a5[0]); + a5[0] = 0; + v18 = plr[myplr]._pVitality; + v19 = plr[myplr]._pBaseVit; + if ( v18 > v19 ) + a5[0] = 1; + if ( v18 < v19 ) + a5[0] = 2; + sprintf(a4, "%i", v18); + ADD_PlrStringXY(143, 239, 173, a4, a5[0]); + v20 = &plr[myplr]._pStatPts; + if ( *v20 > 0 ) + { + v20 = &plr[myplr]._pStatPts; + if ( CalcStatDiff(myplr) < *v20 ) + { + v20 = &plr[myplr]._pStatPts; + *v20 = CalcStatDiff(myplr); + } + } + v21 = *v20; + if ( v21 > 0 ) + { + sprintf(a4, "%i", v21); + ADD_PlrStringXY(95, 266, 126, a4, 2); + v22 = SLOBYTE(plr[myplr]._pClass); + if ( plr[myplr]._pBaseStr < MaxStats[v22][0] ) + CelDecodeOnly(201, 319, pChrButtons, chrbtn[0] + 2, 41); + if ( plr[myplr]._pBaseMag < MaxStats[v22][1] ) + CelDecodeOnly(201, 347, pChrButtons, chrbtn[1] + 4, 41); + if ( plr[myplr]._pBaseDex < MaxStats[v22][2] ) + CelDecodeOnly(201, 376, pChrButtons, chrbtn[2] + 6, 41); + if ( plr[myplr]._pBaseVit < MaxStats[v22][3] ) + CelDecodeOnly(201, 404, pChrButtons, chrbtn[3] + 8, 41); + } + v23 = plr[myplr]._pMaxHP; + a5[0] = v23 > plr[myplr]._pMaxHPBase; + sprintf(a4, "%i", v23 >> 6); + ADD_PlrStringXY(95, 304, 126, a4, a5[0]); + v24 = plr[myplr]._pHitPoints; + if ( v24 != plr[myplr]._pMaxHP ) + a5[0] = 2; + sprintf(a4, "%i", v24 >> 6); + ADD_PlrStringXY(143, 304, 174, a4, a5[0]); + v25 = plr[myplr]._pMaxMana; + a5[0] = v25 > plr[myplr]._pMaxManaBase; + sprintf(a4, "%i", v25 >> 6); + ADD_PlrStringXY(95, 332, 126, a4, a5[0]); + v26 = plr[myplr]._pMana; + if ( v26 != plr[myplr]._pMaxMana ) + a5[0] = 2; + sprintf(a4, "%i", v26 >> 6); + ADD_PlrStringXY(143, 332, 174, a4, a5[0]); +} + +void __fastcall ADD_PlrStringXY(int x, int y, int width, char *pszStr, char col) +{ + int v5; // eax + char *v6; // edx + unsigned char v7; // al + int v8; // esi + int v9; // edi + int v10; // ecx + unsigned char v11; // bl + unsigned char v12; // al + int v13; // ebx + int widtha; // [esp+Ch] [ebp-4h] + int widthb; // [esp+Ch] [ebp-4h] + + v5 = screen_y_times_768[y + 160]; + v6 = pszStr; + widtha = v5 + x + 64; + v7 = *pszStr; + v8 = width - x + 1; + v9 = 0; + v10 = 0; + if ( *pszStr ) + { + v11 = *pszStr; + do + { + ++v6; + v10 += fontkern[fontframe[fontidx[v11]]] + 1; + v11 = *v6; + } + while ( *v6 ); + } + if ( v10 < v8 ) + v9 = (v8 - v10) >> 1; + widthb = v9 + widtha; + while ( v7 ) + { + ++pszStr; + v12 = fontframe[fontidx[v7]]; + v13 = v12; + v9 += fontkern[v12] + 1; + if ( v12 ) + { + if ( v9 < v8 ) + CPrintString(widthb, v12, col); + } + widthb += fontkern[v13] + 1; + v7 = *pszStr; + } +} + +void __fastcall MY_PlrStringXY(int x, int y, int width, char *pszStr, char col, int base) +{ + char *v6; // ebx + unsigned char v7; // al + int v8; // edx + int v9; // esi + char *v10; // edi + unsigned char v11; // cl + unsigned char v12; // al + int v13; // edi + int widtha; // [esp+Ch] [ebp-4h] + int widthb; // [esp+Ch] [ebp-4h] + int v16; // [esp+18h] [ebp+8h] + + v6 = pszStr; + widtha = screen_y_times_768[y + 160] + x + 64; + v7 = *pszStr; + v8 = 0; + v9 = width - x + 1; + v16 = 0; + v10 = pszStr; + if ( *pszStr ) + { + v11 = *pszStr; + do + { + ++v10; + v8 += base + fontkern[fontframe[fontidx[v11]]]; + v11 = *v10; + } + while ( *v10 ); + } + if ( v8 < v9 ) + v16 = (v9 - v8) >> 1; + widthb = v16 + widtha; + while ( v7 ) + { + ++v6; + v12 = fontframe[fontidx[v7]]; + v13 = v12; + v16 += base + fontkern[v12]; + if ( v12 ) + { + if ( v16 < v9 ) + CPrintString(widthb, v12, col); + } + widthb += base + fontkern[v13]; + v7 = *v6; + } +} + +void __cdecl CheckLvlBtn() +{ + if ( !lvlbtndown && MouseX >= 40 && MouseX <= 81 && MouseY >= 313 && MouseY <= 335 ) + lvlbtndown = 1; +} +// 4B851C: using guessed type int lvlbtndown; + +void __cdecl ReleaseLvlBtn() +{ + if ( MouseX >= 40 && MouseX <= 81 && MouseY >= 313 && MouseY <= 335 ) + chrflag = 1; + lvlbtndown = 0; +} +// 4B851C: using guessed type int lvlbtndown; + +void __cdecl DrawLevelUpIcon() +{ + int v0; // esi + + if ( !stextflag ) + { + v0 = (lvlbtndown != 0) + 2; + ADD_PlrStringXY(0, 303, 120, "Level Up", 0); + CelDecodeOnly(104, 495, pChrButtons, v0, 41); + } +} +// 4B851C: using guessed type int lvlbtndown; +// 6AA705: using guessed type char stextflag; + +void __cdecl CheckChrBtns() +{ + int v0; // esi + int v1; // ecx + int v2; // ebx + int v3; // edi + int v4; // edx + bool v5; // sf + unsigned char v6; // of + int v7; // edx + int v8; // edx + int v9; // edx + int v10; // eax + int v11; // edx + int v12; // edx + + v0 = 0; + if ( !chrbtnactive ) + { + v1 = myplr; + if ( plr[myplr]._pStatPts ) + { + v2 = MouseX; + v3 = SLOBYTE(plr[v1]._pClass); + while ( 1 ) + { + if ( !v0 ) + { + v9 = plr[v1]._pBaseStr; + v6 = __OFSUB__(v9, MaxStats[v3][0]); + v5 = v9 - MaxStats[v3][0] < 0; + goto LABEL_12; + } + if ( v0 == 1 ) + { + v8 = plr[v1]._pBaseMag; + v6 = __OFSUB__(v8, MaxStats[v3][1]); + v5 = v8 - MaxStats[v3][1] < 0; + goto LABEL_12; + } + if ( v0 == 2 ) + break; + if ( v0 == 3 ) + { + v4 = plr[v1]._pBaseVit; + v6 = __OFSUB__(v4, MaxStats[v3][3]); + v5 = v4 - MaxStats[v3][3] < 0; +LABEL_12: + if ( v5 ^ v6 ) + { + v10 = v0; + v11 = attribute_inc_rects[v0][0]; + if ( v2 >= v11 && v2 <= v11 + attribute_inc_rects[v10][2] ) + { + v12 = attribute_inc_rects[v10][1]; + if ( MouseY >= v12 && MouseY <= v12 + attribute_inc_rects[v10][3] ) + { + chrbtn[v0] = 1; + chrbtnactive = 1; + } + } + } + } + if ( ++v0 >= 4 ) + return; + } + v7 = plr[v1]._pBaseDex; + v6 = __OFSUB__(v7, MaxStats[v3][2]); + v5 = v7 - MaxStats[v3][2] < 0; + goto LABEL_12; + } + } +} +// 4B87A8: using guessed type int chrbtnactive; + +void __cdecl ReleaseChrBtns() +{ + signed int v0; // esi + int *v1; // eax + signed int v2; // eax + int v3; // ecx + int v4; // ecx + unsigned char v5; // dl + + chrbtnactive = 0; + v0 = 0; + do + { + v1 = &chrbtn[v0]; + if ( *v1 ) + { + *v1 = 0; + v2 = v0; + v3 = attribute_inc_rects[v0][0]; + if ( MouseX >= v3 && MouseX <= v3 + attribute_inc_rects[v2][2] ) + { + v4 = attribute_inc_rects[v2][1]; + if ( MouseY >= v4 && MouseY <= v4 + attribute_inc_rects[v2][3] ) + { + if ( v0 ) + { + switch ( v0 ) + { + case ATTRIB_MAG: + v5 = CMD_ADDMAG; + break; + case ATTRIB_DEX: + v5 = CMD_ADDDEX; + break; + case ATTRIB_VIT: + v5 = CMD_ADDVIT; + break; + default: + goto LABEL_16; + } + } + else + { + v5 = CMD_ADDSTR; + } + NetSendCmdParam1(1u, v5, 1u); + --plr[myplr]._pStatPts; + } + } + } +LABEL_16: + ++v0; + } + while ( v0 < 4 ); +} +// 4B87A8: using guessed type int chrbtnactive; + +void __cdecl DrawDurIcon() +{ + int v0; // edx + PlayerStruct *v1; // esi + int v2; // eax + int v3; // eax + int v4; // eax + + if ( !chrflag && !questlog || !invflag && !sbookflag ) + { + v0 = 656; + if ( invflag || sbookflag ) + v0 = 336; + v1 = &plr[myplr]; + v2 = DrawDurIcon4Item(v1->InvBody, v0, 4); + v3 = DrawDurIcon4Item(&v1->InvBody[6], v2, 3); + v4 = DrawDurIcon4Item(&v1->InvBody[4], v3, 0); + DrawDurIcon4Item(&v1->InvBody[5], v4, 0); + } +} +// 4B8968: using guessed type int sbookflag; +// 69BD04: using guessed type int questlog; + +int __fastcall DrawDurIcon4Item(ItemStruct *pItem, int x, int c) +{ + int v3; // eax + int v4; // edi + int v5; // esi + signed int v7; // edx + int v8; // eax + int v9; // eax + int v10; // eax + int v11; // eax + signed int v12; // [esp-4h] [ebp-Ch] + + v3 = pItem->_itype; + v4 = x; + if ( v3 == -1 ) + return x; + v5 = pItem->_iDurability; + if ( v5 > 5 ) + return x; + v7 = c; + if ( !c ) + { + if ( pItem->_iClass != 1 ) + { + v7 = 1; + goto LABEL_18; + } + v8 = v3 - 1; + if ( !v8 ) + { + v12 = 2; + goto LABEL_15; + } + v9 = v8 - 1; + if ( !v9 ) + { + v12 = 6; + goto LABEL_15; + } + v10 = v9 - 1; + if ( !v10 ) + { + v12 = 7; + goto LABEL_15; + } + v11 = v10 - 1; + if ( !v11 ) + { + v12 = 5; + goto LABEL_15; + } + if ( v11 == 6 ) + { + v12 = 8; +LABEL_15: + v7 = v12; + goto LABEL_18; + } + } +LABEL_18: + if ( v5 > 2 ) + v7 += 8; + CelDecodeOnly(v4, 495, pDurIcons, v7, 32); + return v4 - 40; +} + +void __cdecl RedBack() +{ + int v0; // eax + char *v1; // edi + signed int v3; // edx + signed int v4; // ecx + char *v7; // edi + signed int v9; // edx + signed int v10; // ecx + int v12; // [esp+8h] [ebp-4h] + int _EAX; + char *_EBX; + + v0 = -(light4flag != 0); + _LOWORD(v0) = v0 & 0xF400; + v12 = v0 + 0x1200; + if ( leveltype == DTYPE_HELL ) + { + v7 = gpBuffer->row[0].pixels; + _EBX = &pLightTbl[v12]; + v9 = 352; + do + { + v10 = 640; + do + { + _EAX = *v7; + if ( (unsigned char)*v7 >= 0x20u ) + ASM_XLAT(_EAX,_EBX); + *v7++ = _EAX; + --v10; + } + while ( v10 ); + v7 += 128; + --v9; + } + while ( v9 ); + } + else + { + v1 = gpBuffer->row[0].pixels; + _EBX = &pLightTbl[v12]; + v3 = 352; + do + { + v4 = 640; + do + { + _EAX = *v1; + ASM_XLAT(_EAX,_EBX); + *v1++ = _EAX; + --v4; + } + while ( v4 ); + v1 += 128; + --v3; + } + while ( v3 ); + } +} +// 525728: using guessed type int light4flag; +// 5BB1ED: using guessed type char leveltype; + +int __fastcall GetSBookTrans(int ii, unsigned char townok) +{ + int v2; // edi + int v3; // esi + int result; // eax + char v6; // [esp+13h] [ebp-5h] + int v7; // [esp+14h] [ebp-4h] + + v2 = ii; + v7 = townok; + v6 = 1; + v3 = myplr; + if ( ((unsigned __int64)((__int64)1 << ((unsigned char)ii - 1)) >> 32) & plr[v3]._pISpells[1] | (unsigned int)((__int64)1 << ((unsigned char)ii - 1)) & plr[v3]._pISpells[0] ) + v6 = 3; + result = plr[v3]._pAblSpells[1] & (1 << (ii - 1) >> 31) | plr[v3]._pAblSpells[0] & (1 << (ii - 1)); + if ( result ) + v6 = 0; + if ( v6 == 1 ) + { + if ( !CheckSpell(myplr, ii, 1, 1) ) + v6 = 4; + result = 21720 * myplr; + if ( (char)(plr[myplr]._pISplLvlAdd + plr[myplr]._pSplLvl[v2]) <= 0 ) + v6 = 4; + } + if ( v7 && !currlevel && v6 != 4 && !*(_DWORD *)&spelldata[v2].sTownSpell ) + v6 = 4; + _LOBYTE(result) = v6; + return result; +} + +void __cdecl DrawSpellBook() +{ + __int64 v0; // edi + __int64 v1; // ebp + int v2; // esi + char v3; // al + int v4; // eax + int v5; // ebx + int v6; // ecx + char v7; // [esp+Bh] [ebp-1Dh] + int v8; // [esp+Ch] [ebp-1Ch] + signed int v9; // [esp+10h] [ebp-18h] + int sel; // [esp+14h] [ebp-14h] + int v11; // [esp+18h] [ebp-10h] + int v12; // [esp+1Ch] [ebp-Ch] + + CelDecodeOnly(384, 511, pSpellBkCel, 1, 320); + CelDecodeOnly(76 * sbooktab + 391, 508, pSBkBtnCel, sbooktab + 1, 76); + v9 = 1; + v8 = 214; + v0 = plr[myplr]._pISpells64 | plr[myplr]._pMemSpells64 | plr[myplr]._pAblSpells64; + do + { + v2 = SpellPages[0][v9 + 7 * sbooktab - 1]; // *(&attribute_inc_rects[3].h + v9 + 7 * sbooktab); /* check */ + v1 = (__int64)1 << (v2 - 1); + if ( v2 != -1 && (v1 & v0) ) + { + v7 = GetSBookTrans(v2, 1u); + SetSpellTrans(v7); + DrawSpellCel(395, v8 + 1, (char *)pSBkIconCels, (char)SpellITbl[v2], 37); + if ( v2 == plr[myplr]._pRSpell && v7 == _LOBYTE(plr[myplr]._pRSplType) ) + { + SetSpellTrans(0); + DrawSpellCel(395, v8 + 1, (char *)pSBkIconCels, 43, 37); + } + PrintSBookStr(10, v8 - 22, 0, spelldata[v2].sNameText, 0); + v3 = GetSBookTrans(v2, 0); + if ( v3 ) + { + if ( v3 == 3 ) + { + sprintf(tempstr, "Staff (%i charges)", plr[myplr].InvBody[4]._iCharges); + } + else + { + v4 = GetManaAmount(myplr, v2); + v5 = v4 >> 6; + v12 = v4 >> 6; + GetDamageAmt(v2, &sel, &v11); + if ( sel == -1 ) + sprintf(tempstr, "Mana: %i Dam: n/a", v5); + else + sprintf(tempstr, "Mana: %i Dam: %i - %i", v5, sel, v11); + if ( v2 == SPL_BONESPIRIT ) + sprintf(tempstr, "Mana: %i Dam: 1/3 tgt hp", v12); + PrintSBookStr(10, v8, 0, tempstr, 0); + v6 = plr[myplr]._pISplLvlAdd + plr[myplr]._pSplLvl[v2]; + if ( v6 < 0 ) + v6 = 0; + if ( v6 ) + sprintf(tempstr, "Spell Level %i", v6); + else + sprintf(tempstr, "Spell Level 0 - Unusable"); + } + } + else + { + strcpy(tempstr, "Skill"); + } + PrintSBookStr(10, v8 - 11, 0, tempstr, 0); + } + v8 += 43; + ++v9; + } + while ( v9 < 8 ); +} +// 4B8950: using guessed type int sbooktab; + +void __fastcall PrintSBookStr(int x, int y, bool cjustflag, char *pszStr, int bright) +{ + char *v5; // ebx + signed int v6; // eax + int v7; // edi + unsigned char v8; // cl + char *v9; // esi + unsigned char v10; // al + int v11; // esi + unsigned char v12; // al + int width; // [esp+Ch] [ebp-4h] + + v5 = pszStr; + width = screen_y_times_768[y] + x + 440; + v6 = 0; + v7 = 0; + if ( cjustflag ) + { + v8 = *pszStr; + v9 = pszStr; + if ( !*pszStr ) + goto LABEL_14; + do + { + ++v9; + v6 += fontkern[fontframe[fontidx[v8]]] + 1; + v8 = *v9; + } + while ( *v9 ); + if ( v6 < 222 ) +LABEL_14: + v7 = (222 - v6) >> 1; + width += v7; + } + while ( 1 ) + { + v12 = *v5; + if ( !*v5 ) + break; + ++v5; + v10 = fontframe[fontidx[v12]]; + v11 = v10; + v7 += fontkern[v10] + 1; + if ( v10 ) + { + if ( v7 <= 222 ) + CPrintString(width, v10, bright); + } + width += fontkern[v11] + 1; + } +} + +void __cdecl CheckSBook() +{ + signed int v0; // ecx + signed int v1; // esi + int v2; // eax + int v3; // esi + signed __int64 v4; // rax + char v5; // cl + __int64 v6; // [esp+8h] [ebp-10h] + int v7; // [esp+10h] [ebp-8h] + + v0 = MouseY; + v1 = MouseX; + if ( MouseX >= 331 && MouseX < 368 && MouseY >= 18 && MouseY < 314 ) + { + v2 = SpellPages[0][7 * sbooktab + (MouseY - 18) / 43]; + v7 = SpellPages[0][7 * sbooktab + (MouseY - 18) / 43]; + if ( v2 != -1 ) + { + v3 = myplr; + LODWORD(v6) = plr[myplr]._pAblSpells[0]; + HIDWORD(v6) = plr[myplr]._pAblSpells[1]; + v4 = (__int64)1 << ((unsigned char)v2 - 1); + if ( HIDWORD(v4) & (HIDWORD(v6) | plr[myplr]._pISpells[1] | plr[myplr]._pMemSpells[1]) | (unsigned int)v4 & ((unsigned int)v6 | plr[myplr]._pISpells[0] | plr[myplr]._pMemSpells[0]) ) + { + v5 = 3; + if ( !(plr[v3]._pISpells[1] & HIDWORD(v4) | plr[v3]._pISpells[0] & (unsigned int)v4) ) + v5 = 1; + if ( v6 & v4 ) + v5 = 0; + drawpanflag = 255; + plr[v3]._pRSpell = v7; + _LOBYTE(plr[v3]._pRSplType) = v5; + } + v1 = MouseX; + v0 = MouseY; + } + } + if ( v1 >= 327 && v1 < 633 && v0 >= 320 && v0 < 349 ) /// BUGFIX: change `< 633` to `< 631` + sbooktab = (v1 - 327) / 76; +} +// 4B8950: using guessed type int sbooktab; +// 52571C: using guessed type int drawpanflag; + +char *__fastcall get_pieces_str(int nGold) +{ + char *result; // eax + + result = "piece"; + if ( nGold != 1 ) + result = "pieces"; + return result; +} + +void __fastcall DrawGoldSplit(int amount) +{ + int v1; // ebp + char *v2; // eax + char v3; // cl + signed int i; // eax + int screen_x; // [esp+10h] [ebp-4h] + int screen_xa; // [esp+10h] [ebp-4h] + + screen_x = 0; + v1 = amount; + CelDecodeOnly(415, 338, pGBoxBuff, 1, 261); + sprintf(tempstr, "You have %u gold", initialDropGoldValue); + ADD_PlrStringXY(366, 87, 600, tempstr, 3); + v2 = get_pieces_str(initialDropGoldValue); + sprintf(tempstr, "%s. How many do", v2); + ADD_PlrStringXY(366, 103, 600, tempstr, 3); + ADD_PlrStringXY(366, 121, 600, "you want to remove?", 3); + if ( v1 <= 0 ) + { + screen_xa = 450; + } + else + { + sprintf(tempstr, "%u", v1); + PrintGameStr(388, 140, tempstr, 0); + v3 = tempstr[0]; + for ( i = 0; i < v3; v3 = tempstr[i] ) + { + ++i; + screen_x += fontkern[fontframe[fontidx[(unsigned char)v3]]] + 1; + } + screen_xa = screen_x + 452; + } + CelDecodeOnly(screen_xa, 300, pCelBuff, frame_4B8800, 12); + frame_4B8800 = (frame_4B8800 & 7) + 1; +} + +void __fastcall control_drop_gold(int vkey) +{ + char v1; // bl + int v2; // eax + int v3; // eax + size_t v4; // esi + char v6[6]; // [esp+8h] [ebp-8h] + + v1 = vkey; + if ( (signed int)(plr[myplr]._pHitPoints & 0xFFFFFFC0) <= 0 ) + { + dropGoldFlag = 0; + dropGoldValue = 0; + return; + } + memset(v6, 0, 6u); + _itoa(dropGoldValue, v6, 10); + if ( v1 != VK_RETURN ) + { + if ( v1 == VK_ESCAPE ) + { + dropGoldFlag = 0; + dropGoldValue = 0; + return; + } + if ( v1 == VK_BACK ) + { + v6[strlen(v6) - 1] = '\0'; + v2 = atoi(v6); + } + else + { + v3 = v1 - '0'; + if ( v3 < 0 || v3 > 9 ) + return; + if ( dropGoldValue || atoi(v6) <= initialDropGoldValue ) + { + v6[strlen(v6)] = v1; + if ( atoi(v6) > initialDropGoldValue ) + return; + v4 = strlen(v6); + if ( v4 > strlen(v6) ) + return; + } + else + { + v6[0] = v1; + } + v2 = atoi(v6); + } + dropGoldValue = v2; + return; + } + if ( dropGoldValue > 0 ) + control_remove_gold(myplr, initialDropGoldIndex); + dropGoldFlag = 0; +} +// 4B84DC: using guessed type int dropGoldFlag; +// 406C40: using guessed type char var_8[8]; + +void __fastcall control_remove_gold(int pnum, int gold_index) +{ + int v2; // edi + int v3; // esi + int v4; // edx + _DWORD *v5; // eax + int v6; // edx + _DWORD *v7; // eax + int v8; // eax + + v2 = pnum; + v3 = pnum; + if ( gold_index > 46 ) + { + v6 = gold_index - 47; + v7 = (unsigned int *)((char *)&plr[0].SpdList[v6]._ivalue + v3 * 21720); + *v7 -= dropGoldValue; + if ( *v7 <= 0 ) + RemoveSpdBarItem(pnum, v6); + else + SetSpdbarGoldCurs(pnum, v6); + } + else + { + v4 = gold_index - 7; + v5 = (unsigned int *)((char *)&plr[0].InvList[v4]._ivalue + v3 * 21720); + *v5 -= dropGoldValue; + if ( *v5 <= 0 ) + RemoveInvItem(pnum, v4); + else + SetGoldCurs(pnum, v4); + } + SetPlrHandItem(&plr[v3].HoldItem, IDI_GOLD); + GetGoldSeed(v2, &plr[v3].HoldItem); + plr[v3].HoldItem._ivalue = dropGoldValue; + plr[v3].HoldItem._iStatFlag = 1; + control_set_gold_curs(v2); + v8 = CalculateGold(v2); + dropGoldValue = 0; + plr[v3]._pGold = v8; +} + +void __fastcall control_set_gold_curs(int pnum) +{ + int v1; // ecx + int v2; // eax + int *v3; // eax + bool v4; // zf + bool v5; // sf + unsigned char v6; // of + + v1 = pnum; + v2 = plr[v1].HoldItem._ivalue; + if ( v2 < 2500 ) + { + v6 = __OFSUB__(v2, 1000); + v4 = v2 == 1000; + v5 = v2 - 1000 < 0; + v3 = &plr[v1].HoldItem._iCurs; + if ( (unsigned char)(v5 ^ v6) | v4 ) + *v3 = 4; + else + *v3 = 5; + } + else + { + v3 = &plr[v1].HoldItem._iCurs; + plr[v1].HoldItem._iCurs = 6; + } + SetCursor(*v3 + 12); +} + +void __cdecl DrawTalkPan() +{ + int v0; // esi + signed int v1; // edi + signed int v2; // esi + char *v3; // eax + int v4; // esi + int v5; // esi + int v6; // ebx + int v7; // eax + int a4; // [esp+4h] [ebp-Ch] + char *a1; // [esp+8h] [ebp-8h] + int v10; // [esp+Ch] [ebp-4h] + + v0 = 0; + if ( talkflag ) + { + DrawPanelBox(175, sgbPlrTalkTbl + 20, 0x126u, 5u, 239, 516); + v1 = 293; + do + { + DrawPanelBox((v0 >> 1) + 175, sgbPlrTalkTbl + v0 + 25, v1, 1u, (v0 >> 1) + 239, v0 + 521); + ++v0; + --v1; + } + while ( v1 > 283 ); + DrawPanelBox(185, sgbPlrTalkTbl + 35, 0x112u, 0x1Eu, 249, 531); + DrawPanelBox(180, sgbPlrTalkTbl + 65, 0x11Cu, 5u, 244, 561); + v2 = 0; + do + { + DrawPanelBox(180, sgbPlrTalkTbl + v2 + 70, v2 + 284, 1u, 244, v2 + 566); + ++v2; + } + while ( v2 < 10 ); + DrawPanelBox(170, sgbPlrTalkTbl + 80, 0x136u, 0x37u, 234, 576); + v3 = sgszTalkMsg; + v4 = 0; + do + { + v3 = control_print_talk_msg(v3, 0, v4, &a4, 0); + if ( !v3 ) + goto LABEL_10; + v4 += 13; + } + while ( v4 < 39 ); + *v3 = 0; +LABEL_10: + CelDecDatOnly((char *)gpBuffer + a4, (char *)pCelBuff, frame, 12); + v5 = 0; + a1 = plr[0]._pName; + v10 = 0; + frame = (frame & 7) + 1; + while ( v10 == myplr ) + { +LABEL_21: + a1 += 21720; + ++v10; + if ( (signed int)a1 >= (signed int)&plr[4]._pName ) + return; + } + if ( tempstr[v10 + 256] ) + { + v6 = 3; + if ( !talkbtndown[v5] ) + { +LABEL_18: + if ( *(a1 - 291) ) + control_print_talk_msg(a1, 46, 18 * v5 + 60, &a4, v6); + ++v5; + goto LABEL_21; + } + v7 = (v5 != 0) + 3; + } + else + { + v7 = (v5 != 0) + 1; + v6 = 2; + if ( talkbtndown[v5] ) + v7 = (v5 != 0) + 5; + } + CelDecodeOnly(236, 18 * v5 + 596, pTalkBtns, v7, 61); + goto LABEL_18; + } +} +// 4B8840: using guessed type int sgbPlrTalkTbl; +// 4B8960: using guessed type int talkflag; + +char *__fastcall control_print_talk_msg(char *msg, int x, int y, int *a4, int just) +{ + int v5; // edx + char *v6; // ebx + unsigned char v7; // al + int v8; // ecx + unsigned char v10; // dl + int v11; // edi + int a3; // [esp+14h] [ebp+8h] + + v5 = x + 264; + v6 = msg; + *a4 = v5 + screen_y_times_768[y + 534]; + v7 = *msg; + v8 = v5; + if ( !v7 ) + return 0; + while ( 1 ) + { + v10 = fontframe[fontidx[v7]]; + v11 = v10; + a3 = v8 + fontkern[v10] + 1; + if ( a3 > 514 ) + break; + ++v6; + if ( v10 ) + CPrintString(*a4, v10, just); + *a4 += fontkern[v11] + 1; + v7 = *v6; + if ( !*v6 ) + return 0; + v8 = a3; + } + return v6; +} + +int __cdecl control_check_talk_btn() +{ + int v0; // ecx + int result; // eax + + if ( !talkflag ) + return 0; + if ( MouseX < 172 ) + return 0; + v0 = MouseY; + if ( MouseY < 421 || MouseX > 233 ) + return 0; + result = 0; + if ( MouseY <= 475 ) + { + talkbtndown[0] = 0; + talkbtndown[1] = 0; + talkbtndown[2] = 0; + talkbtndown[(v0 - 421) / 18] = 1; + result = 1; + } + return result; +} +// 4B8960: using guessed type int talkflag; + +void __cdecl control_release_talk_btn() +{ + signed int v0; // ecx + int v1; // eax + signed int v2; // ecx + + if ( talkflag ) + { + v0 = MouseX; + talkbtndown[0] = 0; + talkbtndown[1] = 0; + talkbtndown[2] = 0; + if ( v0 >= 172 && MouseY >= 421 && v0 <= 233 && MouseY <= 475 ) + { + v1 = (MouseY - 421) / 18; + v2 = 0; + do + { + if ( v1 == -1 ) + break; + if ( v2 != myplr ) + --v1; + ++v2; + } + while ( v2 < 4 ); + if ( v2 <= 4 ) + tempstr[v2 + 255] = tempstr[v2 + 255] == 0; + } + } +} +// 4B8960: using guessed type int talkflag; + +void __cdecl control_reset_talk_msg() +{ + int v0; // edi + signed int v1; // ecx + + v0 = 0; + v1 = 0; + do + { + if ( tempstr[v1 + 256] ) + v0 |= 1 << v1; + ++v1; + } + while ( v1 < 4 ); + if ( !msgcmd_add_server_cmd_W(sgszTalkMsg) ) + NetSendCmdString(v0, sgszTalkMsg); +} + +void __cdecl control_type_message() +{ + if ( gbMaxPlayers != 1 ) + { + sgszTalkMsg[0] = 0; + talkflag = 1; + frame = 1; + talkbtndown[0] = 0; + talkbtndown[1] = 0; + talkbtndown[2] = 0; + sgbPlrTalkTbl = 144; + drawpanflag = 255; + sgbTalkSavePos = sgbNextTalkSave; + } +} +// 4B84CC: using guessed type char sgbNextTalkSave; +// 4B84CD: using guessed type char sgbTalkSavePos; +// 4B8840: using guessed type int sgbPlrTalkTbl; +// 4B8960: using guessed type int talkflag; +// 52571C: using guessed type int drawpanflag; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl control_reset_talk() +{ + talkflag = 0; + sgbPlrTalkTbl = 0; + drawpanflag = 255; +} +// 4B8840: using guessed type int sgbPlrTalkTbl; +// 4B8960: using guessed type int talkflag; +// 52571C: using guessed type int drawpanflag; + +int __fastcall control_talk_last_key(int a1) +{ + char v1; // bl + signed int v3; // eax + + v1 = a1; + if ( gbMaxPlayers == 1 || !talkflag || (unsigned int)a1 < VK_SPACE ) + return 0; + v3 = strlen(sgszTalkMsg); + if ( v3 < 78 ) + { + sgszTalkMsg[v3 + 1] = 0; + sgszTalkMsg[v3] = v1; + } + return 1; +} +// 4B8960: using guessed type int talkflag; +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall control_presskeys(int a1) +{ + signed int v1; // eax + char v2; // cl + + if ( gbMaxPlayers != 1 && talkflag ) + { + switch ( a1 ) + { + case VK_SPACE: + return 1; + case VK_ESCAPE: + control_reset_talk(); + return 1; + case VK_RETURN: + control_press_enter(); + return 1; + case VK_BACK: + v1 = strlen(sgszTalkMsg); + if ( v1 > 0 ) + sgszTalkMsg[v1 - 1] = '\0'; + return 1; + case VK_DOWN: + v2 = 1; +LABEL_15: + control_up_down(v2); + return 1; + case VK_UP: + v2 = -1; + goto LABEL_15; + } + } + return 0; +} +// 4B87A8: using guessed type int chrbtnactive; +// 4B8960: using guessed type int talkflag; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl control_press_enter() +{ + signed int v0; // esi + char (*v1)[80]; // ebp + char v2; // al + int v3; // ecx + char *v4; // ebp + + if ( sgszTalkMsg[0] ) + { + control_reset_talk_msg(); + v0 = 0; + v1 = sgszTalkSave; + do + { + if ( !strcmp((const char *)v1, sgszTalkMsg) ) + break; + ++v1; + ++v0; + } + while ( (signed int)v1 < (signed int)&sgszTalkSave[8] ); + if ( v0 < 8 ) + { + v2 = sgbNextTalkSave; + v3 = (sgbNextTalkSave - 1) & 7; + if ( v0 != v3 ) + { + v4 = sgszTalkSave[v3]; + strcpy(sgszTalkSave[v0], sgszTalkSave[v3]); + strcpy(v4, sgszTalkMsg); + v2 = sgbNextTalkSave; + } + } + else + { + strcpy(sgszTalkSave[(unsigned char)sgbNextTalkSave], sgszTalkMsg); + v2 = (sgbNextTalkSave + 1) & 7; + sgbNextTalkSave = (sgbNextTalkSave + 1) & 7; + } + sgszTalkMsg[0] = 0; + sgbTalkSavePos = v2; + } + control_reset_talk(); +} +// 4B84CC: using guessed type char sgbNextTalkSave; +// 4B84CD: using guessed type char sgbTalkSavePos; + +void __fastcall control_up_down(char a1) +{ + unsigned char v1; // al + int v2; // esi + + v1 = sgbTalkSavePos; + v2 = 0; + while ( 1 ) + { + v1 = (a1 + v1) & 7; + sgbTalkSavePos = v1; + if ( sgszTalkSave[v1][0] ) + break; + if ( ++v2 >= 8 ) + return; + } + strcpy(sgszTalkMsg, sgszTalkSave[v1]); +} +// 4B84CD: using guessed type char sgbTalkSavePos; diff --git a/Source/control.h b/Source/control.h new file mode 100644 index 000000000..c8fceaec4 --- /dev/null +++ b/Source/control.h @@ -0,0 +1,141 @@ +//HEADER_GOES_HERE +#ifndef __CONTROL_H__ +#define __CONTROL_H__ + +extern char sgbNextTalkSave; // weak +extern char sgbTalkSavePos; // weak +extern void *pDurIcons; +extern void *pChrButtons; +extern int drawhpflag; // idb +extern int dropGoldFlag; // weak +extern int panbtn[8]; +extern int chrbtn[4]; +extern void *pMultiBtns; +extern void *pPanelButtons; +extern void *pChrPanel; +extern int lvlbtndown; // weak +extern char sgszTalkSave[8][80]; +extern int dropGoldValue; // idb +extern int drawmanaflag; // idb +extern int chrbtnactive; // weak +extern char sgszTalkMsg[80]; +extern void *pPanelText; +extern int frame_4B8800; // idb +extern void *pLifeBuff; +extern void *pBtmBuff; +extern void *pTalkBtns; +extern int pstrjust[4]; +extern int pnumlines; // idb +extern int pinfoflag; // weak +extern int talkbtndown[3]; +extern int pSpell; // weak +extern void *pManaBuff; +extern int infoclr; // weak +extern int sgbPlrTalkTbl; // weak // should be char [4] +extern void *pGBoxBuff; +extern void *pSBkBtnCel; +extern char tempstr[260]; +extern int sbooktab; // weak +extern int pSplType; // weak +extern int frame; // idb +extern int initialDropGoldIndex; // idb +extern int talkflag; // weak +extern void *pSBkIconCels; +extern int sbookflag; // weak +extern int chrflag; +extern int drawbtnflag; // idb +extern void *pSpellBkCel; +extern char infostr[260]; +extern int numpanbtns; // weak +extern void *pStatusPanel; +extern char panelstr[256]; +extern int panelflag; // weak +extern char byte_4B8B88[256]; +extern int initialDropGoldValue; // idb +extern void *pSpellCels; +extern int panbtndown; // weak +extern void *pTalkPanel; // idb +extern int spselflag; // weak + +void __fastcall DrawSpellCel(int xp, int yp, char *Trans, int nCel, int w); +void __fastcall SetSpellTrans(char t); +void __cdecl DrawSpell(); +void __cdecl DrawSpellList(); +void __cdecl SetSpell(); +void __fastcall SetSpeedSpell(int slot); +void __fastcall ToggleSpell(int slot); +void __fastcall CPrintString(int No, unsigned char pszStr, int Just); /* check arg names */ +void __fastcall AddPanelString(char *str, int just); +void __cdecl ClearPanel(); +void __fastcall DrawPanelBox(int x, int y, int w, int h, int sx, int sy); +void __cdecl InitPanelStr(); +void __fastcall SetFlaskHeight(char *buf, int min, int max, int c, int r); +void __fastcall DrawFlask(void *a1, int a2, int a3, void *a4, int a5, int a6); +void __cdecl DrawLifeFlask(); +void __cdecl UpdateLifeFlask(); +void __cdecl DrawManaFlask(); +void __cdecl control_update_life_mana(); +void __cdecl UpdateManaFlask(); +void __cdecl InitControlPan(); +void __cdecl ClearCtrlPan(); +void __cdecl DrawCtrlPan(); +void __cdecl DoSpeedBook(); +void __cdecl DoPanBtn(); +void __fastcall control_set_button_down(int btn_id); +void __cdecl control_check_btn_press(); +void __cdecl DoAutoMap(); +void __cdecl CheckPanelInfo(); +void __cdecl CheckBtnUp(); +void __cdecl FreeControlPan(); +int __fastcall control_WriteStringToBuffer(char *str); +void __cdecl DrawInfoBox(); +void __fastcall control_print_info_str(int y, char *str, bool center, int lines); +void __fastcall PrintGameStr(int x, int y, char *str, int color); +void __cdecl DrawChr(); +void __fastcall ADD_PlrStringXY(int x, int y, int width, char *pszStr, char col); +void __fastcall MY_PlrStringXY(int x, int y, int width, char *pszStr, char col, int base); +void __cdecl CheckLvlBtn(); +void __cdecl ReleaseLvlBtn(); +void __cdecl DrawLevelUpIcon(); +void __cdecl CheckChrBtns(); +void __cdecl ReleaseChrBtns(); +void __cdecl DrawDurIcon(); +int __fastcall DrawDurIcon4Item(ItemStruct *pItem, int x, int c); +void __cdecl RedBack(); +int __fastcall GetSBookTrans(int ii, unsigned char townok); +void __cdecl DrawSpellBook(); +void __fastcall PrintSBookStr(int x, int y, bool cjustflag, char *pszStr, int bright); +void __cdecl CheckSBook(); +char *__fastcall get_pieces_str(int nGold); +void __fastcall DrawGoldSplit(int amount); +void __fastcall control_drop_gold(int vkey); +void __fastcall control_remove_gold(int pnum, int gold_index); +void __fastcall control_set_gold_curs(int pnum); +void __cdecl DrawTalkPan(); +char *__fastcall control_print_talk_msg(char *msg, int x, int y, int *a4, int just); +int __cdecl control_check_talk_btn(); +void __cdecl control_release_talk_btn(); +void __cdecl control_reset_talk_msg(); +void __cdecl control_type_message(); +void __cdecl control_reset_talk(); +int __fastcall control_talk_last_key(int a1); +int __fastcall control_presskeys(int a1); +void __cdecl control_press_enter(); +void __fastcall control_up_down(char a1); + +/* rdata */ +extern const unsigned char fontframe[127]; +extern const unsigned char fontkern[68]; +extern const int lineoffset[25]; +extern const unsigned char fontidx[256]; + +/* data */ + +extern unsigned char SpellITbl[37]; +extern int PanBtnPos[8][5]; +extern char *PanBtnHotKey[8]; +extern char *PanBtnStr[8]; +extern int attribute_inc_rects[4][4]; +extern int SpellPages[6][7]; + +#endif /* __CONTROL_H__ */ diff --git a/Source/cursor.cpp b/Source/cursor.cpp new file mode 100644 index 000000000..015cdfce9 --- /dev/null +++ b/Source/cursor.cpp @@ -0,0 +1,1300 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int cursH; // weak +int icursH28; // idb +int cursW; // idb +int pcursmonst; // idb +int icursW28; // idb +void *pCursCels; +int icursH; // weak + +// inv_item value +char pcursinvitem; // weak +int icursW; // weak +char pcursitem; // weak +char pcursobj; // weak +char pcursplr; // weak +int cursmx; +int cursmy; +int dword_4B8CCC; // weak +int pcurs; // idb +#endif + +/* rdata */ +const int InvItemWidth[180] = +{ + 0, + 33, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 23, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56 +}; +const int InvItemHeight[180] = +{ + 0, + 29, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 35, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 56, + 56, + 56, + 56, + 56, + 56, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84 +}; + +void __cdecl InitCursor() +{ + pCursCels = LoadFileInMem("Data\\Inv\\Objcurs.CEL", 0); + ClearCursor(); +} + +void __cdecl FreeCursor() +{ + void *v0; // ecx + + v0 = pCursCels; + pCursCels = 0; + mem_free_dbg(v0); + ClearCursor(); +} + +void __fastcall SetICursor(int i) +{ + int v1; // ecx + + v1 = i; + icursW = InvItemWidth[v1]; + icursH = InvItemHeight[v1]; + icursW28 = icursW / 28; + icursH28 = icursH / 28; +} +// 4B8CB4: using guessed type int icursH; +// 4B8CBC: using guessed type int icursW; + +void __fastcall SetCursor(int i) +{ + int v1; // eax + + v1 = InvItemWidth[i]; + pcurs = i; + cursW = v1; + cursH = InvItemHeight[i]; + SetICursor(i); +} +// 4B8C9C: using guessed type int cursH; + +void __fastcall NewCursor(int i) { + SetCursor(i); +} + +void __cdecl InitLevelCursor() +{ + SetCursor(CURSOR_HAND); + cursmx = ViewX; + cursmy = ViewY; + dword_4B8CCC = -1; + pcursmonst = -1; + pcursobj = -1; + pcursitem = -1; + pcursplr = -1; + ClearCursor(); +} +// 4B8CC0: using guessed type char pcursitem; +// 4B8CC1: using guessed type char pcursobj; +// 4B8CC2: using guessed type char pcursplr; +// 4B8CCC: using guessed type int dword_4B8CCC; + +void __cdecl CheckTown() +{ + int v0; // ecx + int v1; // eax + int v2; // esi + int v3; // edx + int v4; // ebx + int v5; // [esp+0h] [ebp-4h] + + v5 = 0; + if ( nummissiles > 0 ) + { + v0 = cursmx; + v1 = cursmy; + do + { + v2 = missileactive[v5]; + if ( missile[v2]._mitype == MIS_TOWN ) + { + if ( (v3 = missile[v2]._mix, v4 = v3 - 1, v0 == v3 - 1) && v1 == missile[v2]._miy + || v0 == v3 && v1 == missile[v2]._miy - 1 + || v0 == v4 && v1 == missile[v2]._miy - 1 + || v0 == v3 - 2 && (v1 == missile[v2]._miy - 1 || v0 == v3 - 2 && v1 == missile[v2]._miy - 2) + || v0 == v4 && v1 == missile[v2]._miy - 2 + || v0 == v3 && v1 == missile[v2]._miy ) + { + trigflag[3] = 1; + ClearPanel(); + strcpy(infostr, "Town Portal"); + sprintf(tempstr, "from %s", plr[missile[v2]._misource]._pName); + AddPanelString(tempstr, 1); + v0 = missile[v2]._mix; + v1 = missile[v2]._miy; + cursmx = missile[v2]._mix; + cursmy = v1; + } + } + ++v5; + } + while ( v5 < nummissiles ); + } +} + +void __cdecl CheckRportal() +{ + int v0; // ecx + int v1; // eax + int v2; // esi + int v3; // edx + int v4; // ebx + int v5; // [esp+0h] [ebp-4h] + + v5 = 0; + if ( nummissiles > 0 ) + { + v0 = cursmx; + v1 = cursmy; + do + { + v2 = missileactive[v5]; + if ( missile[v2]._mitype == MIS_RPORTAL ) + { + if ( (v3 = missile[v2]._mix, v4 = v3 - 1, v0 == v3 - 1) && v1 == missile[v2]._miy + || v0 == v3 && v1 == missile[v2]._miy - 1 + || v0 == v4 && v1 == missile[v2]._miy - 1 + || v0 == v3 - 2 && (v1 == missile[v2]._miy - 1 || v0 == v3 - 2 && v1 == missile[v2]._miy - 2) + || v0 == v4 && v1 == missile[v2]._miy - 2 + || v0 == v3 && v1 == missile[v2]._miy ) + { + trigflag[3] = 1; + ClearPanel(); + strcpy(infostr, "Portal to"); + if ( setlevel ) + strcpy(tempstr, "level 15"); + else + strcpy(tempstr, "The Unholy Altar"); + AddPanelString(tempstr, 1); + v0 = missile[v2]._mix; + v1 = missile[v2]._miy; + cursmx = missile[v2]._mix; + cursmy = v1; + } + } + ++v5; + } + while ( v5 < nummissiles ); + } +} +// 5CF31D: using guessed type char setlevel; + +void __cdecl CheckCursMove() +{ + int v0; // esi + signed int v1; // edi + int v2; // esi + int v3; // edi + int v4; // edx + int v5; // ebx + int v6; // edi + int v7; // eax + int v8; // esi + BOOL v9; // eax + int v10; // ecx + int v11; // edx + int v12; // ecx + int v13; // ebx + int v14; // ebx + int v15; // eax + bool v16; // zf + int v17; // ecx + int v18; // eax + int v19; // ecx + int v20; // eax + int v21; // ecx + int v22; // eax + int v23; // eax + int v24; // ecx + int v25; // eax + int v26; // ecx + int v27; // ebx + int v28; // edx + int v29; // eax + int v30; // ecx + int v31; // eax + int v32; // eax + int v33; // eax + int v34; // ecx + int v35; // eax + int v36; // ecx + int v37; // eax + int v38; // eax + int v39; // ecx + int v40; // eax + int v41; // ecx + signed int v42; // eax + int v43; // ecx + int v44; // eax + int v45; // eax + int v46; // eax + int v47; // eax + char v48; // al + char v49; // cl + char v50; // al + char v51; // al + char v52; // cl + int v53; // ecx + int *v54; // eax + int v55; // edx + int *v56; // ecx + char v57; // al + char v58; // cl + signed int v59; // edx + char v60; // al + char v61; // cl + char v62; // al + char v63; // al + char v64; // cl + char v65; // al + char v66; // al + char v67; // cl + char v68; // al + char v69; // al + char v70; // al + char v71; // al + char v72; // al + char v73; // cl + char v74; // al + char v75; // al + int v76; // [esp+Ch] [ebp-18h] + char *v77; // [esp+Ch] [ebp-18h] + int v78; // [esp+10h] [ebp-14h] + signed int v79; // [esp+14h] [ebp-10h] + signed int v80; // [esp+18h] [ebp-Ch] + int v81; // [esp+1Ch] [ebp-8h] + int v82; // [esp+1Ch] [ebp-8h] + signed int v83; // [esp+20h] [ebp-4h] + + v0 = MouseX; + v1 = MouseY; + if ( chrflag || questlog ) + { + if ( MouseX >= 160 ) + { + v0 = MouseX - 160; + goto LABEL_10; + } + goto LABEL_9; + } + if ( invflag || sbookflag ) + { + if ( MouseX <= 320 ) + { + v0 = MouseX + 160; + goto LABEL_10; + } +LABEL_9: + v0 = 0; + } +LABEL_10: + if ( MouseY > 351 && track_isscrolling() ) + v1 = 351; + if ( !zoomflag ) + { + v0 >>= 1; + v1 >>= 1; + } + v2 = v0 - ScrollInfo._sxoff; + v3 = v1 - ScrollInfo._syoff; + if ( ScrollInfo._sdir ) + { + v2 += ((plr[myplr]._pVar6 + plr[myplr]._pxvel) >> 8) - (plr[myplr]._pVar6 >> 8); + v3 += ((plr[myplr]._pVar7 + plr[myplr]._pyvel) >> 8) - (plr[myplr]._pVar7 >> 8); + } + if ( v2 < 0 ) + v2 = 0; + if ( v2 >= 640 ) + v2 = 640; + if ( v3 < 0 ) + v3 = 0; + if ( v3 >= 480 ) + v3 = 480; + v4 = v3 >> 5; + v5 = v3 & 0x1F; + v76 = v2 & 0x3F; + v6 = (v2 >> 6) + (v3 >> 5) + ViewX - (zoomflag != 0 ? 10 : 5); + v7 = v76 >> 1; + v8 = v4 + ViewY - (v2 >> 6); + if ( v5 < v76 >> 1 ) + --v8; + v9 = v5 >= 32 - v7; + if ( v9 ) + ++v6; + if ( v6 < 0 ) + v6 = 0; + if ( v6 >= 112 ) + v6 = 111; + if ( v8 < 0 ) + v8 = 0; + if ( v8 >= 112 ) + v8 = 111; + if ( v5 >= v76 >> 1 ) + { + if ( !v9 ) + goto LABEL_49; + goto LABEL_48; + } + if ( !v9 ) + { +LABEL_48: + if ( v76 < 32 ) + goto LABEL_39; +LABEL_49: + v83 = 0; + goto LABEL_40; + } +LABEL_39: + v83 = 1; +LABEL_40: + v10 = pcursmonst; + pcursobj = -1; + pcursitem = -1; + v11 = -1; + dword_4B8CCC = pcursmonst; + pcursmonst = -1; + if ( pcursinvitem != -1 ) + drawsbarflag = 1; + pcursinvitem = -1; + pcursplr = -1; + v16 = plr[myplr]._pInvincible == 0; + uitemflag = 0; + panelflag = 0; + trigflag[3] = 0; + if ( !v16 ) + return; + if ( pcurs >= CURSOR_FIRSTITEM || spselflag ) + { + cursmx = v6; + cursmy = v8; + return; + } + if ( MouseY > 352 ) + { + CheckPanelInfo(); + return; + } + if ( doomflag ) + return; + if ( invflag && MouseX > 320 ) + { + pcursinvitem = CheckInvHLight(); + return; + } + if ( sbookflag && MouseX > 320 || (chrflag || questlog) && MouseX < 320 ) + return; + if ( leveltype == DTYPE_TOWN ) + { + if ( v83 ) + { + v27 = 112 * v6; + v78 = 112 * v6; + v43 = 112 * v6 + v8; + v45 = dMonster[0][v43 + 1]; + if ( v45 <= 0 ) + goto LABEL_200; + v11 = v45 - 1; + cursmx = v6; + cursmy = v8 + 1; + } + else + { + v27 = 112 * v6; + v78 = 112 * v6; + v43 = 112 * v6 + v8; + v44 = dMonster[1][v43]; + if ( v44 <= 0 ) + goto LABEL_200; + v11 = v44 - 1; + cursmx = v6 + 1; + cursmy = v8; + } + pcursmonst = v11; +LABEL_200: + v46 = dMonster[0][v43]; + if ( v46 > 0 ) + { + v11 = v46 - 1; + cursmx = v6; + pcursmonst = v46 - 1; + cursmy = v8; + } + v47 = dMonster[1][v43 + 1]; + if ( v47 > 0 ) + { + v11 = v47 - 1; + cursmx = v6 + 1; + pcursmonst = v47 - 1; + cursmy = v8 + 1; + } + if ( !towner[v11]._tSelFlag ) +LABEL_205: + pcursmonst = -1; +LABEL_206: + if ( pcursmonst != -1 ) + { +LABEL_305: + v59 = pcursmonst; + goto LABEL_306; + } +LABEL_207: + if ( v83 ) + { + v50 = dPlayer[0][v27 + 1 + v8]; + if ( v50 ) + { + v49 = v50 <= 0 ? -1 - v50 : v50 - 1; + if ( v49 != myplr && plr[v49]._pHitPoints ) + { + cursmx = v6; + cursmy = v8 + 1; + goto LABEL_222; + } + } + } + else + { + v48 = dPlayer[1][v27 + v8]; + if ( v48 ) + { + v49 = v48 <= 0 ? -1 - v48 : v48 - 1; + if ( v49 != myplr && plr[v49]._pHitPoints ) + { + cursmy = v8; + cursmx = v6 + 1; +LABEL_222: + pcursplr = v49; + goto LABEL_223; + } + } + } +LABEL_223: + v51 = dPlayer[0][v27 + v8]; + if ( v51 ) + { + v52 = v51 <= 0 ? -1 - v51 : v51 - 1; + if ( v52 != myplr ) + { + cursmx = v6; + cursmy = v8; + pcursplr = v52; + } + } + if ( dFlags[0][v27 + v8] & 4 ) + { + v53 = 0; + v54 = &plr[0].WorldY; + do + { + if ( *(v54 - 1) == v6 && *v54 == v8 && v53 != myplr ) + { + cursmx = v6; + cursmy = v8; + pcursplr = v53; + } + v54 += 5430; + ++v53; + } + while ( (signed int)v54 < (signed int)&plr[4].WorldY ); + } + if ( pcurs == CURSOR_RESURRECT ) + { + v79 = -1; + v77 = &dFlags[-1][v27 + v8]; /* v77 = &nBlockTable[v27 + 1944 + v8]; check */ + do + { + v80 = -1; + v55 = v8 - 1; + do + { + if ( v77[v80] & 4 ) + { + v82 = 0; + v56 = &plr[0].WorldY; + do + { + if ( *(v56 - 1) == v6 + v79 && *v56 == v55 && v82 != myplr ) + { + cursmx = v6 + v79; + cursmy = v55; + pcursplr = v82; + } + ++v82; + v56 += 5430; + } + while ( (signed int)v56 < (signed int)&plr[4].WorldY ); + } + ++v80; + ++v55; + } + while ( v80 < 2 ); + ++v79; + v77 += 112; + } + while ( v79 < 2 ); + v27 = v78; + } + v57 = dPlayer[1][v27 + 1 + v8]; + if ( v57 ) + { + v58 = v57 <= 0 ? -1 - v57 : v57 - 1; + if ( v58 != myplr && plr[v58]._pHitPoints ) + { + pcursplr = v58; + cursmx = v6 + 1; + cursmy = v8 + 1; + } + } + v59 = pcursmonst; + if ( pcursmonst != -1 ) + { +LABEL_285: + if ( pcursplr == -1 ) + goto LABEL_286; +LABEL_306: + if ( pcurs == CURSOR_IDENTIFY ) + { + pcursobj = -1; + v59 = -1; + pcursitem = -1; + pcursmonst = -1; + cursmx = v6; + cursmy = v8; + } + if ( v59 != -1 ) + { + if ( monster[v59]._mFlags & 0x20 ) + pcursmonst = -1; + } + return; + } + if ( pcursplr != pcursmonst ) /* check in future */ + goto LABEL_306; + if ( v83 ) + { + v62 = dObject[0][v27 + 1 + v8]; + if ( !v62 ) + goto LABEL_272; + v61 = v62 <= 0 ? -1 - v62 : v62 - 1; + if ( object[v61]._oSelFlag < 2 ) + goto LABEL_272; + cursmx = v6; + cursmy = v8 + 1; + } + else + { + v60 = dObject[1][v27 + v8]; + if ( !v60 ) + goto LABEL_272; + v61 = v60 <= 0 ? -1 - v60 : v60 - 1; + if ( object[v61]._oSelFlag < 2 ) + goto LABEL_272; + cursmy = v8; + cursmx = v6 + 1; + } + pcursobj = v61; +LABEL_272: + v63 = dObject[0][v27 + v8]; + if ( v63 ) + { + v64 = v63 <= 0 ? -1 - v63 : v63 - 1; + v65 = object[v64]._oSelFlag; + if ( v65 == 1 || v65 == 3 ) + { + cursmx = v6; + cursmy = v8; + pcursobj = v64; + } + } + v66 = dObject[1][v27 + 1 + v8]; + if ( !v66 || (v66 <= 0 ? (v67 = -1 - v66) : (v67 = v66 - 1), object[v67]._oSelFlag < 2) ) + { +LABEL_286: + if ( pcursobj != -1 || pcursmonst != -1 ) + goto LABEL_306; + if ( v83 ) + { + v70 = dItem[0][v27 + 1 + v8]; + if ( v70 <= 0 ) + goto LABEL_296; + v69 = v70 - 1; + if ( item[v69]._iSelFlag < 2 ) + goto LABEL_296; + cursmx = v6; + cursmy = v8 + 1; + } + else + { + v68 = dItem[1][v27 + v8]; + if ( v68 <= 0 ) + goto LABEL_296; + v69 = v68 - 1; + if ( item[v69]._iSelFlag < 2 ) + goto LABEL_296; + cursmy = v8; + cursmx = v6 + 1; + } + pcursitem = v69; +LABEL_296: + v71 = dItem[0][v27 + v8]; + if ( v71 > 0 ) + { + v72 = v71 - 1; + v73 = item[v72]._iSelFlag; + if ( v73 == 1 || v73 == 3 ) + { + cursmx = v6; + cursmy = v8; + pcursitem = v72; + } + } + v74 = dItem[1][v27 + 1 + v8]; + if ( v74 > 0 ) + { + v75 = v74 - 1; + if ( item[v75]._iSelFlag >= 2 ) + { + pcursitem = v75; + cursmx = v6 + 1; + cursmy = v8 + 1; + } + } + if ( pcursitem != -1 ) + goto LABEL_306; + cursmx = v6; + cursmy = v8; + CheckTrigForce(); + CheckTown(); + CheckRportal(); + goto LABEL_305; + } + pcursobj = v67; + cursmx = v6 + 1; + cursmy = v8 + 1; + goto LABEL_285; + } + if ( v10 == -1 ) + goto LABEL_128; + v12 = 112 * v6 + v8; + v81 = 112 * v6 + v8; + v13 = 112 * v6 + v8; + if ( v83 ) + { + v14 = v13; + v15 = dMonster[1][v14 + 2]; + if ( !v15 ) + goto LABEL_74; + v16 = (dFlags[1][v12 + 2] & 0x40) == 0; + } + else + { + v14 = v13; + v15 = dMonster[2][v14 + 1]; + if ( !v15 ) + goto LABEL_74; + v16 = (dFlags[2][v12 + 1] & 0x40) == 0; + } + if ( !v16 ) + { + v17 = v15 <= 0 ? -1 - v15 : v15 - 1; + if ( v17 == dword_4B8CCC + && (signed int)(monster[v17]._mhitpoints & 0xFFFFFFC0) > 0 + && monster[v17].MData->mSelFlag & 4 ) + { + v11 = v17; + cursmx = v6 + 1; + cursmy = v8 + 2; + pcursmonst = v17; + } + } +LABEL_74: + v18 = dMonster[2][v14 + 2]; + if ( v18 && dFlags[2][v81 + 2] & 0x40 ) + { + v19 = v18 <= 0 ? -1 - v18 : v18 - 1; + if ( v19 == dword_4B8CCC + && (signed int)(monster[v19]._mhitpoints & 0xFFFFFFC0) > 0 + && monster[v19].MData->mSelFlag & 4 ) + { + v11 = v19; + cursmx = v6 + 2; + cursmy = v8 + 2; + pcursmonst = v19; + } + } + if ( v83 ) + { + v22 = dMonster[0][v14 + 1]; + if ( v22 && dFlags[0][v81 + 1] & 0x40 ) + { + v21 = v22 <= 0 ? -1 - v22 : v22 - 1; + if ( v21 == dword_4B8CCC + && (signed int)(monster[v21]._mhitpoints & 0xFFFFFFC0) > 0 + && monster[v21].MData->mSelFlag & 2 ) + { + cursmx = v6; + cursmy = v8 + 1; + goto LABEL_102; + } + } + } + else + { + v20 = dMonster[1][v14]; + if ( v20 && dFlags[1][v81] & 0x40 ) + { + v21 = v20 <= 0 ? -1 - v20 : v20 - 1; + if ( v21 == dword_4B8CCC + && (signed int)(monster[v21]._mhitpoints & 0xFFFFFFC0) > 0 + && monster[v21].MData->mSelFlag & 2 ) + { + cursmy = v8; + cursmx = v6 + 1; +LABEL_102: + v11 = v21; + pcursmonst = v21; + goto LABEL_103; + } + } + } +LABEL_103: + v23 = dMonster[0][v14]; + if ( v23 && dFlags[0][v81] & 0x40 ) + { + v24 = v23 <= 0 ? -1 - v23 : v23 - 1; + if ( v24 == dword_4B8CCC + && (signed int)(monster[v24]._mhitpoints & 0xFFFFFFC0) > 0 + && monster[v24].MData->mSelFlag & 1 ) + { + v11 = v24; + cursmx = v6; + cursmy = v8; + pcursmonst = v24; + } + } + v25 = dMonster[1][v14 + 1]; + if ( v25 && dFlags[1][v81 + 1] & 0x40 ) + { + v26 = v25 <= 0 ? -1 - v25 : v25 - 1; + if ( v26 == dword_4B8CCC + && (signed int)(monster[v26]._mhitpoints & 0xFFFFFFC0) > 0 + && monster[v26].MData->mSelFlag & 2 ) + { + v11 = v26; + cursmx = v6 + 1; + cursmy = v8 + 1; + pcursmonst = v26; + } + } + if ( v11 == -1 ) + goto LABEL_128; + if ( monster[v11]._mFlags & 1 ) + { + v11 = -1; + cursmx = v6; + pcursmonst = -1; + cursmy = v8; + } + if ( v11 == -1 ) + goto LABEL_128; + if ( monster[v11]._mFlags & 0x20 ) + { + v11 = -1; + pcursmonst = -1; + } + if ( v11 == -1 ) + { +LABEL_128: + v27 = 112 * v6; + v78 = 112 * v6; + if ( v83 ) + { + v28 = v27 + v8; + v32 = dMonster[1][v28 + 2]; + if ( v32 && dFlags[1][v27 + 2 + v8] & 0x40 ) + { + v30 = v32 <= 0 ? -1 - v32 : v32 - 1; + if ( (signed int)(monster[v30]._mhitpoints & 0xFFFFFFC0) > 0 && monster[v30].MData->mSelFlag & 4 ) + { + cursmx = v6 + 1; + v31 = v8 + 2; + goto LABEL_145; + } + } + } + else + { + v28 = v27 + v8; + v29 = dMonster[2][v28 + 1]; + if ( v29 && dFlags[2][v27 + 1 + v8] & 0x40 ) + { + v30 = v29 <= 0 ? -1 - v29 : v29 - 1; + if ( (signed int)(monster[v30]._mhitpoints & 0xFFFFFFC0) > 0 && monster[v30].MData->mSelFlag & 4 ) + { + cursmx = v6 + 2; + v31 = v8 + 1; +LABEL_145: + cursmy = v31; + pcursmonst = v30; + goto LABEL_146; + } + } + } +LABEL_146: + v33 = dMonster[2][v28 + 2]; + if ( v33 && dFlags[2][v27 + 2 + v8] & 0x40 ) + { + v34 = v33 <= 0 ? -1 - v33 : v33 - 1; + if ( (signed int)(monster[v34]._mhitpoints & 0xFFFFFFC0) > 0 && monster[v34].MData->mSelFlag & 4 ) + { + pcursmonst = v34; + cursmx = v6 + 2; + cursmy = v8 + 2; + } + } + if ( v83 ) + { + v37 = dMonster[0][v28 + 1]; + if ( v37 && dFlags[0][v27 + 1 + v8] & 0x40 ) + { + v36 = v37 <= 0 ? -1 - v37 : v37 - 1; + if ( (signed int)(monster[v36]._mhitpoints & 0xFFFFFFC0) > 0 && monster[v36].MData->mSelFlag & 2 ) + { + cursmx = v6; + cursmy = v8 + 1; + goto LABEL_171; + } + } + } + else + { + v35 = dMonster[1][v28]; + if ( v35 && dFlags[1][v27 + v8] & 0x40 ) + { + v36 = v35 <= 0 ? -1 - v35 : v35 - 1; + if ( (signed int)(monster[v36]._mhitpoints & 0xFFFFFFC0) > 0 && monster[v36].MData->mSelFlag & 2 ) + { + cursmy = v8; + cursmx = v6 + 1; +LABEL_171: + pcursmonst = v36; + goto LABEL_172; + } + } + } +LABEL_172: + v38 = dMonster[0][v28]; + if ( v38 && dFlags[0][v27 + v8] & 0x40 ) + { + v39 = v38 <= 0 ? -1 - v38 : v38 - 1; + if ( (signed int)(monster[v39]._mhitpoints & 0xFFFFFFC0) > 0 && monster[v39].MData->mSelFlag & 1 ) + { + cursmx = v6; + cursmy = v8; + pcursmonst = v39; + } + } + v40 = dMonster[1][v28 + 1]; + if ( v40 && dFlags[1][v27 + 1 + v8] & 0x40 ) + { + v41 = v40 <= 0 ? -1 - v40 : v40 - 1; + if ( (signed int)(monster[v41]._mhitpoints & 0xFFFFFFC0) > 0 && monster[v41].MData->mSelFlag & 2 ) + { + pcursmonst = v41; + cursmx = v6 + 1; + cursmy = v8 + 1; + } + } + v42 = pcursmonst; + if ( pcursmonst == -1 ) + goto LABEL_207; + if ( monster[pcursmonst]._mFlags & 1 ) + { + v42 = -1; + cursmx = v6; + pcursmonst = -1; + cursmy = v8; + } + if ( v42 == -1 ) + goto LABEL_207; + if ( monster[v42]._mFlags & 0x20 ) + goto LABEL_205; + goto LABEL_206; + } +} +// 4B8968: using guessed type int sbookflag; +// 4B8B84: using guessed type int panelflag; +// 4B8C98: using guessed type int spselflag; +// 4B8CB8: using guessed type char pcursinvitem; +// 4B8CC0: using guessed type char pcursitem; +// 4B8CC1: using guessed type char pcursobj; +// 4B8CC2: using guessed type char pcursplr; +// 4B8CCC: using guessed type int dword_4B8CCC; +// 52569C: using guessed type int zoomflag; +// 52575C: using guessed type int doomflag; +// 5BB1ED: using guessed type char leveltype; +// 69BD04: using guessed type int questlog; diff --git a/Source/cursor.h b/Source/cursor.h new file mode 100644 index 000000000..17ba85249 --- /dev/null +++ b/Source/cursor.h @@ -0,0 +1,36 @@ +//HEADER_GOES_HERE +#ifndef __CURSOR_H__ +#define __CURSOR_H__ + +extern int cursH; // weak +extern int icursH28; // idb +extern int cursW; // idb +extern int pcursmonst; // idb +extern int icursW28; // idb +extern void *pCursCels; +extern int icursH; // weak +extern char pcursinvitem; // weak +extern int icursW; // weak +extern char pcursitem; // weak +extern char pcursobj; // weak +extern char pcursplr; // weak +extern int cursmx; +extern int cursmy; +extern int dword_4B8CCC; // weak +extern int pcurs; // idb + +void __cdecl InitCursor(); +void __cdecl FreeCursor(); +void __fastcall SetICursor(int i); +void __fastcall SetCursor(int i); +void __fastcall NewCursor(int i); +void __cdecl InitLevelCursor(); +void __cdecl CheckTown(); +void __cdecl CheckRportal(); +void __cdecl CheckCursMove(); + +/* rdata */ +extern const int InvItemWidth[180]; +extern const int InvItemHeight[180]; + +#endif /* __CURSOR_H__ */ diff --git a/Source/dead.cpp b/Source/dead.cpp new file mode 100644 index 000000000..e280cf997 --- /dev/null +++ b/Source/dead.cpp @@ -0,0 +1,151 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int spurtndx; // weak +DeadStruct dead[MAXDEAD]; +int stonendx; +#endif + +void __cdecl InitDead() +{ + int v0; // ebx + int *v1; // edx + int *v2; // eax + int v3; // ecx + int v4; // edx + int v5; // eax + int v6; // edx + int v7; // esi + int *v8; // eax + int v9; // edx + CMonster *v10; // ecx + char *v11; // edi + int *v12; // ebx + int mtypes[MAXMONSTERS]; // [esp+Ch] [ebp-330h] + int *v14; // [esp+32Ch] [ebp-10h] + int *v15; // [esp+330h] [ebp-Ch] + int v16; // [esp+334h] [ebp-8h] + int v17; // [esp+338h] [ebp-4h] + + memset(mtypes, 0, sizeof(mtypes)); + v0 = 0; + if ( nummtypes > 0 ) + { + v1 = &dead[0]._deadFrame; + v2 = &Monsters[0].Anims[4].Rate; + v17 = nummtypes; + do + { + v15 = &mtypes[*((unsigned char *)v2 - 216)]; + if ( !*v15 ) + { + qmemcpy(v1 - 8, v2 - 8, 0x20u); + v3 = *v2; + *((_BYTE *)v1 + 12) = 0; + *v1 = v3; + v1[1] = v2[21]; + v1[2] = v2[22]; + *((_BYTE *)v2 + 101) = ++v0; + v1 += 12; + *v15 = v0; + } + v2 += 82; + --v17; + } + while ( v17 ); + } + v16 = 0; + v4 = v0; + memset32(&dead[v0], (unsigned int)misfiledata[16].mAnimData[0], 8u); + _LOBYTE(dead[v4]._deadtrans) = 0; + dead[v4]._deadFrame = 8; + v5 = (unsigned int)misfiledata[18].mAnimData[0]; + dead[v4]._deadWidth = 128; + dead[v4]._deadWidth2 = 32; + v6 = v0 + 1; + spurtndx = v0 + 1; + memset32(&dead[v6], v5, 8u); + _LOBYTE(dead[v6]._deadtrans) = 0; + stonendx = v0 + 2; + v7 = nummonsters; + dead[v6]._deadFrame = 12; + dead[v6]._deadWidth = 128; + dead[v6]._deadWidth2 = 32; + v17 = v0 + 2; + if ( v7 > 0 ) + { + v8 = &dead[v0 + 2]._deadFrame; + do + { + v9 = monstactive[v16]; + if ( monster[v9]._uniqtype ) + { + v10 = monster[v9].MType; + v11 = (char *)(v8 - 8); + v15 = (int *)8; + v14 = (int *)v10->Anims[4].Frames; + do + { + v12 = v14; + ++v14; + *(_DWORD *)v11 = *v12; + v11 += 4; + v15 = (int *)((char *)v15 - 1); + } + while ( v15 ); + *v8 = v10->Anims[4].Rate; + v8[1] = v10->flags_1; + v8[2] = v10->flags_2; + *((_BYTE *)v8 + 12) = monster[v9]._uniqtrans + 4; + monster[v9]._udeadval = ++v17; + v8 += 12; + } + ++v16; + } + while ( v16 < v7 ); + } +} +// 4B8CD8: using guessed type int spurtndx; + +void __fastcall AddDead(int dx, int dy, char dv, int ddir) +{ + dDead[dx][dy] = (dv & 0x1F) + 32 * ddir; +} + +void __cdecl SetDead() +{ + int v0; // eax + int v1; // esi + int v2; // ebp + char (*v3)[112]; // ebx + int v4; // edi + int i; // [esp+0h] [ebp-4h] + + v0 = 0; + for ( i = 0; i < nummonsters; ++i ) + { + v1 = monstactive[v0]; + if ( monster[v1]._uniqtype ) + { + v2 = 0; + v3 = dDead; + do + { + v4 = 0; + do + { + if ( ((*v3)[v4] & 0x1F) == monster[v1]._udeadval ) + ChangeLightXY((unsigned char)monster[v1].mlid, v2, v4); + ++v4; + } + while ( v4 < 112 ); + ++v3; + ++v2; + } + while ( (signed int)v3 < (signed int)&dDead[112][0] ); + } + v0 = i + 1; + } +} diff --git a/Source/dead.h b/Source/dead.h new file mode 100644 index 000000000..cc482e1aa --- /dev/null +++ b/Source/dead.h @@ -0,0 +1,13 @@ +//HEADER_GOES_HERE +#ifndef __DEAD_H__ +#define __DEAD_H__ + +extern int spurtndx; // weak +extern DeadStruct dead[MAXDEAD]; +extern int stonendx; + +void __cdecl InitDead(); +void __fastcall AddDead(int dx, int dy, char dv, int ddir); +void __cdecl SetDead(); + +#endif /* __DEAD_H__ */ diff --git a/Source/debug.cpp b/Source/debug.cpp new file mode 100644 index 000000000..ce4ca1dd2 --- /dev/null +++ b/Source/debug.cpp @@ -0,0 +1,247 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +void *pSquareCel; +char dMonsDbg[NUMLEVELS][MAXDUNX][MAXDUNY]; +char dFlagDbg[NUMLEVELS][MAXDUNX][MAXDUNY]; +#endif + +void __cdecl LoadDebugGFX() +{ + if ( visiondebug ) + pSquareCel = LoadFileInMem("Data\\Square.CEL", 0); +} +// 525720: using guessed type int visiondebug; + +void __cdecl FreeDebugGFX() +{ + void *v0; // ecx + + v0 = pSquareCel; + pSquareCel = 0; + mem_free_dbg(v0); +} + +void __cdecl CheckDungeonClear() +{ + int i; + int j; + + for(i = 0; i < MAXDUNX; i++) + { + for(j = 0; j < MAXDUNY; j++) + { + if ( dMonster[i][j] ) + TermMsg("Monsters not cleared"); + if ( dPlayer[i][j] ) + TermMsg("Players not cleared"); + + dMonsDbg[currlevel][i][j] = dFlags[i][j] & 2; + dFlagDbg[currlevel][i][j] = dFlags[i][j] & 8; + } + } +} + +#ifdef _DEBUG +void __cdecl GiveGoldCheat() +{ + int i; // esi + int ni; // ebp + + for(i = 0; i < 40; i++) + { + if ( !plr[myplr].InvGrid[i] ) + { + ni = plr[myplr]._pNumInv++; + SetPlrHandItem(&plr[myplr].InvList[ni], IDI_GOLD); + GetPlrHandSeed(&plr[myplr].InvList[ni]); + plr[myplr].InvList[ni]._ivalue = 5000; + plr[myplr].InvList[ni]._iCurs = 6; + plr[myplr]._pGold += 5000; + plr[myplr].InvGrid[i] = plr[myplr]._pNumInv; + } + } +} + +void __cdecl StoresCheat() +{ + int i; // eax + + numpremium = 0; + + for(i = 0; i < 6; i++) + premiumitem[i]._itype = -1; + + SpawnPremium(30); + + for(i = 0; i < 20; i++) + witchitem[i]._itype = -1; + + SpawnWitch(30); +} + +void __cdecl TakeGoldCheat() +{ + int i; // esi + char ig; // cl + + for(i = 0; i < 40; i++) + { + ig = plr[myplr].InvGrid[i]; + if ( ig > 0 && plr[myplr].InvList[ig - 1]._itype == ITYPE_GOLD ) + RemoveInvItem(myplr, ig - 1); + } + + for(i = 0; i < 8; i++) + { + if ( plr[myplr].SpdList[i]._itype == ITYPE_GOLD ) + plr[myplr].SpdList[i]._itype = -1; + } + + plr[myplr]._pGold = 0; +} + +void __cdecl MaxSpellsCheat() +{ + int i; // ebp + + for(i = 1; i < 37; i++) + { + if ( spelldata[i].sBookLvl != -1 ) + { + *(_QWORD *)plr[myplr]._pMemSpells |= (__int64)1 << (i - 1); + plr[myplr]._pSplLvl[i] = 10; + } + } +} + +void __fastcall SetSpellLevelCheat(char spl, int spllvl) +{ + *(_QWORD *)plr[myplr]._pMemSpells |= (__int64)1 << (spl - 1); + plr[myplr]._pSplLvl[spl] = spllvl; +} + +void __cdecl SetAllSpellsCheat() +{ + SetSpellLevelCheat(SPL_FIREBOLT, 8); + SetSpellLevelCheat(SPL_CBOLT, 11); + SetSpellLevelCheat(SPL_HBOLT, 10); + SetSpellLevelCheat(SPL_HEAL, 7); + SetSpellLevelCheat(SPL_HEALOTHER, 5); + SetSpellLevelCheat(SPL_LIGHTNING, 9); + SetSpellLevelCheat(SPL_FIREWALL, 5); + SetSpellLevelCheat(SPL_TELEKINESIS, 3); + SetSpellLevelCheat(SPL_TOWN, 3); + SetSpellLevelCheat(SPL_FLASH, 3); + SetSpellLevelCheat(SPL_RNDTELEPORT, 2); + SetSpellLevelCheat(SPL_MANASHIELD, 2); + SetSpellLevelCheat(SPL_WAVE, 4); + SetSpellLevelCheat(SPL_FIREBALL, 3); + SetSpellLevelCheat(SPL_STONE, 1); + SetSpellLevelCheat(SPL_CHAIN, 1); + SetSpellLevelCheat(SPL_GUARDIAN, 4); + SetSpellLevelCheat(SPL_ELEMENT, 3); + SetSpellLevelCheat(SPL_NOVA, 1); + SetSpellLevelCheat(SPL_GOLEM, 2); + SetSpellLevelCheat(SPL_FLARE, 1); + SetSpellLevelCheat(SPL_BONESPIRIT, 1); +} + +void __fastcall PrintDebugPlayer(bool bNextPlayer) +{ + char dstr[128]; // [esp+Ch] [ebp-80h] + + if ( bNextPlayer ) + dbgplr = ((_BYTE)dbgplr + 1) & 3; + + sprintf(dstr, "Plr %i : Active = %i", dbgplr, plr[dbgplr].plractive); + NetSendCmdString(1 << myplr, dstr); + + if ( plr[dbgplr].plractive ) + { + sprintf(dstr, " Plr %i is %s", dbgplr, plr[dbgplr]._pName); + NetSendCmdString(1 << myplr, dstr); + sprintf(dstr, " Lvl = %i : Change = %i", plr[dbgplr].plrlevel, plr[dbgplr]._pLvlChanging); + NetSendCmdString(1 << myplr, dstr); + sprintf(dstr, " x = %i, y = %i : tx = %i, ty = %i", plr[dbgplr].WorldX, plr[dbgplr].WorldY, plr[dbgplr]._ptargx, plr[dbgplr]._ptargy); + NetSendCmdString(1 << myplr, dstr); + sprintf(dstr, " mode = %i : daction = %i : walk[0] = %i", plr[dbgplr]._pmode, plr[dbgplr].destAction, plr[dbgplr].walkpath[0]); + NetSendCmdString(1 << myplr, dstr); + sprintf(dstr, " inv = %i : hp = %i", plr[dbgplr]._pInvincible, plr[dbgplr]._pHitPoints); + NetSendCmdString(1 << myplr, dstr); + } +} + +void __cdecl PrintDebugQuest() +{ + char dstr[128]; // [esp+0h] [ebp-80h] + + sprintf(dstr, "Quest %i : Active = %i, Var1 = %i", dbgqst, quests[dbgqst]._qactive, quests[dbgqst]._qvar1); + NetSendCmdString(1 << myplr, dstr); + if ( ++dbgqst == MAXQUESTS ) + dbgqst = 0; +} + +void __fastcall PrintDebugMonster(int m) +{ + bool bActive; // ecx + int i; // eax + char dstr[128]; // [esp+Ch] [ebp-80h] + + sprintf(dstr, "Monster %i = %s", m, monster[m].mName); + NetSendCmdString(1 << myplr, dstr); + sprintf(dstr, "X = %i, Y = %i", monster[m]._mx, monster[m]._my); + NetSendCmdString(1 << myplr, dstr); + sprintf(dstr, "Enemy = %i, HP = %i", monster[m]._menemy, monster[m]._mhitpoints); + NetSendCmdString(1 << myplr, dstr); + sprintf(dstr, "Mode = %i, Var1 = %i", monster[m]._mmode, monster[m]._mVar1); + NetSendCmdString(1 << myplr, dstr); + + bActive = 0; + + for(i = 0; i < nummonsters; i++) + { + if ( monstactive[i] == m ) + bActive = 1; + } + + sprintf(dstr, "Active List = %i, Squelch = %i", bActive, monster[m]._msquelch); + NetSendCmdString(1 << myplr, dstr); +} + +void __cdecl GetDebugMonster() +{ + int v0; // ecx + int v1; // eax + + v0 = pcursmonst; + if ( pcursmonst == -1 ) + { + v1 = dMonster[cursmx][cursmy]; + if ( v1 ) + { + v0 = v1 - 1; + if ( v1 <= 0 ) + v0 = -1 - v1; + } + else + { + v0 = dbgmon; + } + } + PrintDebugMonster(v0); +} + +void __cdecl NextDebugMonster() +{ + char dstr[128]; // [esp+0h] [ebp-80h] + + if ( dbgmon++ == MAXMONSTERS ) + dbgmon = 0; + + sprintf(dstr, "Current debug monster = %i", dbgmon); + NetSendCmdString(1 << myplr, dstr); +} +#endif diff --git a/Source/debug.h b/Source/debug.h new file mode 100644 index 000000000..165e6fe2c --- /dev/null +++ b/Source/debug.h @@ -0,0 +1,26 @@ +//HEADER_GOES_HERE +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +extern void *pSquareCel; +extern char dMonsDbg[NUMLEVELS][MAXDUNX][MAXDUNY]; +extern char dFlagDbg[NUMLEVELS][MAXDUNX][MAXDUNY]; + +void __cdecl LoadDebugGFX(); +void __cdecl FreeDebugGFX(); +void __cdecl CheckDungeonClear(); +#ifdef _DEBUG +void __cdecl GiveGoldCheat(); +void __cdecl StoresCheat(); +void __cdecl TakeGoldCheat(); +void __cdecl MaxSpellsCheat(); +void __fastcall SetSpellLevelCheat(char spl, int spllvl); +void __cdecl SetAllSpellsCheat(); +void __fastcall PrintDebugPlayer(bool bNextPlayer); +void __cdecl PrintDebugQuest(); +void __fastcall PrintDebugMonster(int m); +void __cdecl GetDebugMonster(); +void __cdecl NextDebugMonster(); +#endif + +#endif /* __DEBUG_H__ */ diff --git a/Source/diablo.cpp b/Source/diablo.cpp new file mode 100644 index 000000000..52730d105 --- /dev/null +++ b/Source/diablo.cpp @@ -0,0 +1,2303 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int diablo_cpp_init_value; // weak + +#ifndef NO_GLOBALS +HWND ghMainWnd; +int glMid1Seed[NUMLEVELS]; +int glMid2Seed[NUMLEVELS]; +int gnLevelTypeTbl[NUMLEVELS]; +int MouseY; // idb +int MouseX; // idb +bool gbGameLoopStartup; // idb +int glSeedTbl[NUMLEVELS]; +int gbRunGame; // weak +int glMid3Seed[NUMLEVELS]; +int gbRunGameResult; // weak +int zoomflag; // weak +int gbProcessPlayers; // weak +int glEndSeed[NUMLEVELS]; +int dword_5256E8; // weak +HINSTANCE ghInst; // idb +int DebugMonsters[10]; +char cineflag; // weak +int drawpanflag; // weak +int visiondebug; // weak +int scrollflag; /* unused */ +int light4flag; // weak +int leveldebug; // weak +int monstdebug; // weak +int trigdebug; /* unused */ +int setseed; // weak +int debugmonsttypes; // weak +int PauseMode; // weak +int sgnTimeoutCurs; +char sgbMouseDown; // weak +int color_cycle_timer; // weak +#endif + +int diablo_inf = 0x7F800000; // weak + +/* rdata */ + +int fullscreen = 1; // weak +#ifdef _DEBUG +int showintrodebug = 1; +int questdebug = -1; +int debug_mode_key_s; +int debug_mode_key_w; +int debug_mode_key_inverted_v; +int debug_mode_dollar_sign; +int debug_mode_key_d; +int debug_mode_key_i; +int dbgplr; +int dbgqst; +int dbgmon; +int arrowdebug; +int frameflag; +int frameend; +int framerate; +int framestart; +#endif +int FriendlyMode = 1; // weak + +char *spszMsgTbl[4] = +{ + "I need help! Come Here!", + "Follow me.", + "Here's something for you.", + "Now you DIE!" +}; // weak +char *spszMsgKeyTbl[4] = { "F9", "F10", "F11", "F12" }; // weak + +struct diablo_cpp_init +{ + diablo_cpp_init() + { + diablo_cpp_init_value = diablo_inf; + } +} _diablo_cpp_init; +// 479BF8: using guessed type int diablo_inf; +// 525514: using guessed type int diablo_cpp_init_value; + +void __cdecl FreeGameMem() +{ + void *v0; // ecx + void *v1; // ecx + void *v2; // ecx + void *v3; // ecx + void *v4; // ecx + + music_stop(); + v0 = pDungeonCels; + pDungeonCels = 0; + mem_free_dbg(v0); + v1 = pMegaTiles; + pMegaTiles = 0; + mem_free_dbg(v1); + v2 = pLevelPieces; + pLevelPieces = 0; + mem_free_dbg(v2); + v3 = level_special_cel; + level_special_cel = 0; + mem_free_dbg(v3); + v4 = pSpeedCels; + pSpeedCels = 0; + mem_free_dbg(v4); + FreeMissiles(); + FreeMonsters(); + FreeObjectGFX(); + FreeEffects(); + FreeTownerGFX(); +} + +int __fastcall diablo_init_menu(int a1, int bSinglePlayer) +{ + int v2; // esi + int v3; // edi + int v4; // ecx + int pfExitProgram; // [esp+Ch] [ebp-4h] + + v2 = bSinglePlayer; + v3 = a1; + byte_678640 = 1; + while ( 1 ) + { + pfExitProgram = 0; + dword_5256E8 = 0; + if ( !NetInit(v2, &pfExitProgram) ) + break; + byte_678640 = 0; + if ( (v3 || !*(_DWORD *)&gbValidSaveFile) + && (InitLevels(), InitQuests(), InitPortals(), InitDungMsgs(myplr), !*(_DWORD *)&gbValidSaveFile) + || (v4 = WM_DIABLOADGAME, !dword_5256E8) ) + { + v4 = WM_DIABNEWGAME; + } + run_game_loop(v4); + NetClose(); + pfile_create_player_description(0, 0); + if ( !gbRunGameResult ) + goto LABEL_11; + } + gbRunGameResult = pfExitProgram == 0; +LABEL_11: + SNetDestroy(); + return gbRunGameResult; +} +// 525698: using guessed type int gbRunGameResult; +// 5256E8: using guessed type int dword_5256E8; +// 678640: using guessed type char byte_678640; + +void __fastcall run_game_loop(int uMsg) +{ + //int v3; // eax + bool v5; // zf + //int v6; // eax + signed int v7; // [esp+8h] [ebp-24h] + WNDPROC saveProc; // [esp+Ch] [ebp-20h] + struct tagMSG msg; // [esp+10h] [ebp-1Ch] + + nthread_ignore_mutex(1); + start_game(uMsg); + saveProc = SetWindowProc(GM_Game); + control_update_life_mana(); + msg_process_net_packets(); + gbRunGame = 1; + gbProcessPlayers = 1; + gbRunGameResult = 1; + drawpanflag = 255; + DrawAndBlit(); + PaletteFadeIn(8); + drawpanflag = 255; + gbGameLoopStartup = 1; + nthread_ignore_mutex(0); + while ( gbRunGame ){ + /*printf("In Main Loop\n"); */ + IsPlayMusic(); + diablo_color_cyc_logic(); + if ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) + { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) + { + if ( msg.message == WM_QUIT ) + { + gbRunGameResult = 0; + gbRunGame = 0; + break; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if ( !gbRunGame || (v7 = 1, !nthread_has_500ms_passed()) ) + v7 = 0; + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); + v5 = v7 == 0; + } + else + { + //_LOBYTE(v6) = nthread_has_500ms_passed(); + v5 = nthread_has_500ms_passed() == 0; + } + if ( !v5 ) + { + multi_process_network_packets(); + game_loop(gbGameLoopStartup); + msgcmd_send_chat(); + gbGameLoopStartup = 0; + DrawAndBlit(); + } +#ifdef SLEEP + Sleep(1); +#endif + } + if ( (unsigned char)gbMaxPlayers > 1u ) + pfile_write_hero(); + pfile_flush_W(); + PaletteFadeOut(8); + SetCursor(0); + ClearScreenBuffer(); + drawpanflag = 255; + scrollrt_draw_game_screen(1); + SetWindowProc(saveProc); + free_game(); + if ( cineflag ) + { + cineflag = 0; + DoEnding(); + } +} +// 525650: using guessed type int gbRunGame; +// 525698: using guessed type int gbRunGameResult; +// 5256A0: using guessed type int gbProcessPlayers; +// 525718: using guessed type char cineflag; +// 52571C: using guessed type int drawpanflag; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall start_game(int uMsg) +{ + cineflag = 0; + zoomflag = 1; + InitCursor(); + InitLightTable(); + LoadDebugGFX(); + music_stop(); + ShowProgress(uMsg); + gmenu_init_menu(); + InitLevelCursor(); + sgnTimeoutCurs = 0; + sgbMouseDown = 0; + track_repeat_walk(0); +} +// 52569C: using guessed type int zoomflag; +// 525718: using guessed type char cineflag; +// 525748: using guessed type char sgbMouseDown; + +void __cdecl free_game() +{ + int i; // esi + + FreeControlPan(); + FreeInvGFX(); + FreeGMenu(); + FreeQuestText(); + FreeStoreMem(); + + for(i = 0; i < MAX_PLRS; i++) + FreePlayerGFX(i); + + FreeItemGFX(); + FreeCursor(); + FreeLightTable(); + FreeDebugGFX(); + FreeGameMem(); +} + +bool __cdecl diablo_get_not_running() +{ + SetLastError(0); + CreateEvent(NULL, FALSE, FALSE, "DiabloEvent"); + return GetLastError() != ERROR_ALREADY_EXISTS; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + HINSTANCE v4; // esi + //int v11; // ecx + char Filename[260]; // [esp+8h] [ebp-10Ch] + char value_name[8]; // [esp+10Ch] [ebp-8h] + + v4 = hInstance; +#ifndef DEBUGGER + diablo_reload_process(hInstance); +#endif + ghInst = v4; + if ( RestrictedTest() ) + ErrOkDlg(IDD_DIALOG10, 0, "C:\\Src\\Diablo\\Source\\DIABLO.CPP", 877); + if ( ReadOnlyTest() ) + { + if ( !GetModuleFileName(ghInst, Filename, 0x104u) ) + *Filename = '\0'; + DirErrorDlg(Filename); + } + ShowCursor(FALSE); + srand(GetTickCount()); + encrypt_init_lookup_table(); + exception_get_filter(); + if ( !diablo_find_window("DIABLO") && diablo_get_not_running() ) + { + diablo_init_screen(); + diablo_parse_flags(lpCmdLine); + init_create_window(nCmdShow); + sound_init(); + UiInitialize(); +#ifdef _DEBUG + if ( showintrodebug ) + play_movie("gendata\\logo.smk", 1); +#else + play_movie("gendata\\logo.smk", 1); +#endif + strcpy(value_name, "Intro"); + if ( !SRegLoadValue("Diablo", value_name, 0, (int *)&hInstance) ) + hInstance = (HINSTANCE)1; + if ( hInstance ) + play_movie("gendata\\diablo1.smk", 1); + SRegSaveValue("Diablo", value_name, 0, 0); +#ifdef _DEBUG + if ( showintrodebug ) + { + UiTitleDialog(7); + BlackPalette(); + } +#else + UiTitleDialog(7); + BlackPalette(); +#endif + mainmenu_action(0); /* v11 fix unused arg */ + UiDestroy(); + SaveGamma(); + if ( ghMainWnd ) + { +#ifndef FASTER + Sleep(300); +#endif + DestroyWindow(ghMainWnd); + } + } + return 0; +} + +void __fastcall diablo_parse_flags(char *args) +{ +#ifdef _DEBUG + int n; // edi + int v15; // eax +#endif + while ( *args ) + { + for ( ; isspace(*args); ++args ) + ; + if ( !_strcmpi("dd_emulate", args) ) + { + gbEmulate = 1; + args += strlen("dd_emulate"); + } + else if ( !_strcmpi("dd_backbuf", args) ) + { + gbBackBuf = 1; + args += strlen("dd_backbuf"); + } + else if ( !_strcmpi("ds_noduplicates", args) ) + { + gbDupSounds = 0; + args += strlen("ds_noduplicates"); + } + else + { +#ifdef _DEBUG + switch ( tolower(*args++) ) + { + case '^': // god mod with all spells as skills + debug_mode_key_inverted_v = 1; + break; + case '$': // demi-god + debug_mode_dollar_sign = 1; + break; + /*case 'b': // enable drop log + debug_mode_key_b = 1; + break;*/ + case 'd': // no startup video+??? + showintrodebug = 0; + debug_mode_key_d = 1; + break; + case 'f': // draw fps + EnableFrameCount(); + break; + case 'i': // disable network timeout + debug_mode_key_i = 1; + break; + /*case 'j': // : init trigger at level + for ( ; isspace(*args); ++args ) + ; + for ( n = 0; isdigit(*args); n = v15 + 10 * n - 48 ) + v15 = *args++; + debug_mode_key_J_trigger = n; + break;*/ + case 'l': // : start in level as type + setlevel = 0; + for ( leveldebug = 1; isspace(*args); ++args ) + ; + for ( n = 0; isdigit(*args); n = v15 + 10 * n - 48 ) + v15 = *args++; + for ( leveltype = n; isspace(*args); ++args ) + ; + for ( n = 0; isdigit(*args); n = v15 + 10 * n - 48 ) + v15 = *args++; + currlevel = n; + plr[0].plrlevel = n; + break; + case 'm': // : add debug monster, up to 10 allowed + for ( monstdebug = 1; isspace(*args); ++args ) + ; + for ( n = 0; isdigit(*args); n = v15 + 10 * n - 48 ) + v15 = *args++; + DebugMonsters[debugmonsttypes++] = n; + break; + case 'n': // disable startup video + showintrodebug = 0; + break; + case 'q': // : force a certain quest + for ( ; isspace(*args); ++args ) + ; + for ( n = 0; isdigit(*args); n = v15 + 10 * n - 48 ) + v15 = *args++; + questdebug = n; + break; + case 'r': // : set map seed to + for ( ; isspace(*args); ++args ) + ; + for ( n = 0; isdigit(*args); n = v15 + 10 * n - 48 ) + v15 = *args++; + setseed = n; + break; + case 's': // unused + debug_mode_key_s = 1; + break; + case 't': // : sets current quest level + leveldebug = 1; + for ( setlevel = 1; isspace(*args); ++args ) + ; + for ( n = 0; isdigit(*args); n = v15 + 10 * n - 48 ) + v15 = *args++; + setlvlnum = n; + break; + case 'v': // draw yellow debug tiles + visiondebug = 1; + break; + case 'w': // rest of the cheats, some only in town + debug_mode_key_w = 1; + break; + case 'x': + fullscreen = 0; + break; + default: + break; + } +#else + tolower(*args++); +#endif + } + } +} +// 4A22D6: using guessed type char gbDupSounds; +// 52A548: using guessed type char gbBackBuf; +// 52A549: using guessed type char gbEmulate; + +void __cdecl diablo_init_screen() +{ + int v0; // ecx + int *v1; // eax + + v0 = 0; + MouseX = 320; + MouseY = 240; + ScrollInfo._sdx = 0; + ScrollInfo._sdy = 0; + ScrollInfo._sxoff = 0; + ScrollInfo._syoff = 0; + ScrollInfo._sdir = 0; + v1 = screen_y_times_768; + do + { + *v1 = v0; + ++v1; + v0 += 768; + } + while ( (signed int)v1 < (signed int)&screen_y_times_768[1024] ); + ClrDiabloMsg(); +} +// 69CEFC: using guessed type int scrollrt_cpp_init_value; + +BOOL __fastcall diablo_find_window(LPCSTR lpClassName) +{ + HWND result; // eax + HWND v2; // esi + HWND v3; // eax + HWND v4; // edi + + result = FindWindow(lpClassName, 0); + v2 = result; + if ( !result ) + return 0; + + v3 = GetLastActivePopup(result); + if ( v3 ) + v2 = v3; + v4 = GetTopWindow(v2); + if ( !v4 ) + v4 = v2; + SetForegroundWindow(v2); + SetFocus(v4); + return 1; +} + +void __fastcall diablo_reload_process(HMODULE hModule) +{ + char *i; // eax + DWORD dwSize; // esi + BOOL v3; // edi + _DWORD *v4; // eax + _DWORD *v5; // esi + HWND v6; // eax + char Name[276]; // [esp+Ch] [ebp-29Ch] + char Filename[260]; // [esp+120h] [ebp-188h] + STARTUPINFOA si; // [esp+224h] [ebp-84h] + SYSTEM_INFO sinf; // [esp+268h] [ebp-40h] + PROCESS_INFORMATION pi; // [esp+28Ch] [ebp-1Ch] + DWORD dwProcessId; // [esp+29Ch] [ebp-Ch] + HANDLE hMap; // [esp+2A0h] [ebp-8h] + HWND hWnd; // [esp+2A4h] [ebp-4h] + + *Filename = empty_string; + memset(Filename + 1, 0, sizeof(Filename) - 1); +// *(_WORD *)&Filename[257] = 0; +// Filename[259] = 0; + GetModuleFileName(hModule, Filename, 0x104u); + wsprintf(Name, "Reload-%s", Filename); + for ( i = Name; *i; ++i ) + { + if ( *i == '\\' ) + *i = '/'; + } + GetSystemInfo(&sinf); + dwSize = sinf.dwPageSize; + if ( sinf.dwPageSize < 4096 ) + dwSize = 4096; + hMap = CreateFileMapping((HANDLE)0xFFFFFFFF, NULL, SEC_COMMIT|PAGE_READWRITE, 0, dwSize, Name); + v3 = GetLastError() != ERROR_ALREADY_EXISTS; + if ( hMap ) + { + v4 = (unsigned int *)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, dwSize); + v5 = v4; + if ( v4 ) + { + if ( v3 ) + { + *v4 = -1; + v4[1] = 0; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + CreateProcess(Filename, NULL, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi); + WaitForInputIdle(pi.hProcess, 0xFFFFFFFF); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + while ( *v5 < 0 ) + Sleep(1000); + UnmapViewOfFile(v5); + CloseHandle(hMap); + ExitProcess(0); + } + if ( InterlockedIncrement((long *)v4) ) + { + v6 = GetForegroundWindow(); + do + { + hWnd = v6; + v6 = GetWindow(v6, 3u); + } + while ( v6 ); + while ( 1 ) + { + GetWindowThreadProcessId(hWnd, &dwProcessId); + if ( dwProcessId == v5[1] ) + break; + hWnd = GetWindow(hWnd, 2u); + if ( !hWnd ) + goto LABEL_23; + } + SetForegroundWindow(hWnd); +LABEL_23: + UnmapViewOfFile(v5); + CloseHandle(hMap); + ExitProcess(0); + } + v5[1] = GetCurrentProcessId(); + } + } +} + +int __cdecl PressEscKey() +{ + int result; // eax + + result = 0; + if ( doomflag ) + { + doom_close(); + result = 1; + } + if ( helpflag ) + { + helpflag = 0; + result = 1; + } + if ( qtextflag ) + { + qtextflag = 0; + sfx_stop(); + } + else + { + if ( !stextflag ) + goto LABEL_10; + STextESC(); + } + result = 1; +LABEL_10: + if ( msgflag ) + { + msgdelay = 0; + result = 1; + } + if ( talkflag ) + { + control_reset_talk(); + result = 1; + } + if ( dropGoldFlag ) + { + control_drop_gold(VK_ESCAPE); + result = 1; + } + if ( spselflag ) + { + spselflag = 0; + result = 1; + } + return result; +} +// 4B84DC: using guessed type int dropGoldFlag; +// 4B8960: using guessed type int talkflag; +// 4B8C98: using guessed type int spselflag; +// 52575C: using guessed type int doomflag; +// 52B9F0: using guessed type char msgdelay; +// 52B9F1: using guessed type char msgflag; +// 646D00: using guessed type char qtextflag; +// 6AA705: using guessed type char stextflag; + +LRESULT __stdcall DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + bool v5; // zf + + if ( uMsg <= WM_LBUTTONDOWN ) + { + if ( uMsg != WM_LBUTTONDOWN ) + { + if ( uMsg >= WM_KEYFIRST + && (uMsg <= WM_CHAR + || uMsg == WM_SYSKEYDOWN + || uMsg == WM_SYSCOMMAND + || uMsg == WM_MOUSEFIRST) ) + { + return 0; + } + return MainWndProc(hWnd, uMsg, wParam, lParam); + } + if ( !sgbMouseDown ) + { + sgbMouseDown = 1; +LABEL_21: + SetCapture(hWnd); + return 0; + } + return 0; + } + if ( uMsg == WM_LBUTTONUP ) + { + v5 = sgbMouseDown == 1; + goto LABEL_23; + } + if ( uMsg != WM_RBUTTONDOWN ) + { + if ( uMsg != WM_RBUTTONUP ) + { + if ( uMsg == WM_CAPTURECHANGED ) + { + if ( hWnd != (HWND)lParam ) + sgbMouseDown = 0; + return 0; + } + return MainWndProc(hWnd, uMsg, wParam, lParam); + } + v5 = sgbMouseDown == 2; +LABEL_23: + if ( v5 ) + { + sgbMouseDown = 0; + ReleaseCapture(); + } + return 0; + } + if ( !sgbMouseDown ) + { + sgbMouseDown = 2; + goto LABEL_21; + } + return 0; +} +// 525748: using guessed type char sgbMouseDown; + +LRESULT __stdcall GM_Game(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if ( uMsg > WM_LBUTTONDOWN ) + { + if ( uMsg == WM_LBUTTONUP ) + { + MouseX = (unsigned short)lParam; + MouseY = (unsigned int)lParam >> 16; + if ( sgbMouseDown != 1 ) + return 0; + sgbMouseDown = 0; + LeftMouseUp(); + track_repeat_walk(0); + } + else + { + if ( uMsg == WM_RBUTTONDOWN ) + { + MouseX = (unsigned short)lParam; + MouseY = (unsigned int)lParam >> 16; + if ( !sgbMouseDown ) + { + sgbMouseDown = 2; + SetCapture(hWnd); + RightMouseDown(); + } + return 0; + } + if ( uMsg != WM_RBUTTONUP ) + { + if ( uMsg == WM_CAPTURECHANGED ) + { + if ( hWnd != (HWND)lParam ) + { + sgbMouseDown = 0; + track_repeat_walk(0); + } + } + else if ( uMsg > WM_DIAB && uMsg <= WM_DIABRETOWN ) + { + if ( (unsigned char)gbMaxPlayers > 1u ) + pfile_write_hero(); + nthread_ignore_mutex(1); + PaletteFadeOut(8); + FreeMonsterSnd(); + music_stop(); + track_repeat_walk(0); + sgbMouseDown = 0; + ReleaseCapture(); + ShowProgress(uMsg); + drawpanflag = 255; + DrawAndBlit(); + if ( gbRunGame ) + PaletteFadeIn(8); + nthread_ignore_mutex(0); + gbGameLoopStartup = 1; + return 0; + } + return MainWndProc(hWnd, uMsg, wParam, lParam); + } + MouseX = (unsigned short)lParam; + MouseY = (unsigned int)lParam >> 16; + if ( sgbMouseDown != 2 ) + return 0; + sgbMouseDown = 0; + } + ReleaseCapture(); + return 0; + } + switch ( uMsg ) + { + case WM_LBUTTONDOWN: + MouseX = (unsigned short)lParam; + MouseY = (unsigned int)lParam >> 16; + if ( !sgbMouseDown ) + { + sgbMouseDown = 1; + SetCapture(hWnd); + track_repeat_walk(LeftMouseDown(wParam)); + } + return 0; + case WM_KEYFIRST: + PressKey(wParam); + return 0; + case WM_KEYUP: + ReleaseKey(wParam); + return 0; + case WM_CHAR: + PressChar(wParam); + return 0; + case WM_SYSKEYDOWN: + if ( PressSysKey(wParam) ) + return 0; + return MainWndProc(hWnd, uMsg, wParam, lParam); + case WM_SYSCOMMAND: + if ( wParam == SC_CLOSE ) + { + gbRunGame = 0; + gbRunGameResult = 0; + return 0; + } + return MainWndProc(hWnd, uMsg, wParam, lParam); + } + if ( uMsg != WM_MOUSEFIRST ) + return MainWndProc(hWnd, uMsg, wParam, lParam); + MouseX = (unsigned short)lParam; + MouseY = (unsigned int)lParam >> 16; + gmenu_on_mouse_move((unsigned short)lParam); + return 0; +} +// 525650: using guessed type int gbRunGame; +// 525698: using guessed type int gbRunGameResult; +// 52571C: using guessed type int drawpanflag; +// 525748: using guessed type char sgbMouseDown; +// 679660: using guessed type char gbMaxPlayers; + +bool __fastcall LeftMouseDown(int a1) +{ + int v1; // edi + int v3; // eax + bool v6; // zf + int v7; // ecx + int v8; // eax + unsigned char v9; // dl + unsigned char v11; // dl + unsigned short v12; // ax + unsigned char v13; // dl + unsigned short v15; // [esp-8h] [ebp-10h] + + v1 = a1; + if ( gmenu_left_mouse(1) || control_check_talk_btn() || sgnTimeoutCurs ) + return 0; + if ( deathflag ) + { + control_check_btn_press(); + return 0; + } + if ( PauseMode == 2 ) + return 0; + if ( doomflag ) + { + doom_close(); + return 0; + } + if ( spselflag ) + { + SetSpell(); + return 0; + } + if ( stextflag ) + { + CheckStoreBtn(); + return 0; + } + if ( MouseY >= 352 ) + { + if ( !talkflag && !dropGoldFlag ) + { + if ( !gmenu_exception() ) + CheckInvScrn(); + } + DoPanBtn(); + if ( pcurs <= 1 || pcurs >= 12 ) + return 0; + goto LABEL_48; + } + if ( gmenu_exception() || TryIconCurs() ) + return 0; + if ( questlog && MouseX > 32 && MouseX < 288 && MouseY > 32 && MouseY < 308 ) + { + QuestlogESC(); + return 0; + } + if ( qtextflag ) + { + qtextflag = 0; + sfx_stop(); + return 0; + } + if ( chrflag && MouseX < 320 ) + { + CheckChrBtns(); + return 0; + } + if ( invflag && MouseX > 320 ) + { + if ( !dropGoldFlag ) + CheckInvItem(); + return 0; + } + if ( sbookflag && MouseX > 320 ) + { + CheckSBook(); + return 0; + } + if ( pcurs >= CURSOR_FIRSTITEM ) + { + if ( !TryInvPut() ) + return 0; + NetSendCmdPItem(1u, CMD_PUTITEM, cursmx, cursmy); +LABEL_48: + SetCursor(CURSOR_HAND); + return 0; + } + v3 = 21720 * myplr; + if ( plr[myplr]._pStatPts && !spselflag ) + CheckLvlBtn(); + if ( lvlbtndown ) + return 0; + if ( leveltype != DTYPE_TOWN ) + { + v7 = abs(plr[myplr].WorldX - cursmx) < 2 && abs(plr[myplr].WorldY - cursmy) < 2; + _HIWORD(v8) = _HIWORD(pcurs); + if ( pcursitem != -1 && pcurs == 1 && v1 != 5 ) + { + _LOWORD(v8) = pcursitem; + NetSendCmdLocParam1(1u, (invflag == 0) + CMD_GOTOGETITEM, cursmx, cursmy, v8); +LABEL_96: + if ( pcursitem != -1 ) + return 0; + v6 = pcursobj == -1; + goto LABEL_98; + } + if ( pcursobj != -1 ) + { + if ( v1 != 5 || v7 && object[pcursobj]._oBreak == 1 ) + { + NetSendCmdLocParam1(1u, (pcurs == 5) + CMD_OPOBJXY, cursmx, cursmy, pcursobj); + goto LABEL_95; + } + } + if ( plr[myplr]._pwtype == 1 ) + { + if ( v1 == 5 ) + { + v9 = CMD_RATTACKXY; +LABEL_84: + NetSendCmdLoc(1u, v9, cursmx, cursmy); + goto LABEL_95; + } + if ( pcursmonst != -1 ) + { + v15 = pcursmonst; + if ( !CanTalkToMonst(pcursmonst) ) + { + v11 = CMD_RATTACKID; +LABEL_89: + NetSendCmdParam1(1u, v11, v15); + goto LABEL_96; + } +LABEL_88: + v11 = CMD_ATTACKID; + goto LABEL_89; + } + _LOBYTE(v12) = pcursplr; + if ( pcursplr == -1 || FriendlyMode ) + goto LABEL_96; + v13 = CMD_RATTACKPID; + } + else + { + if ( v1 == 5 ) + { + if ( pcursmonst == -1 || !CanTalkToMonst(pcursmonst) ) + { + v9 = CMD_SATTACKXY; + goto LABEL_84; + } + v12 = pcursmonst; + v13 = CMD_ATTACKID; +LABEL_94: + NetSendCmdParam1(1u, v13, v12); +LABEL_95: + if ( v1 == 5 ) + return 0; + goto LABEL_96; + } + if ( pcursmonst != -1 ) + { + v15 = pcursmonst; + goto LABEL_88; + } + _LOBYTE(v12) = pcursplr; + if ( pcursplr == -1 || FriendlyMode ) + goto LABEL_96; + v13 = CMD_ATTACKPID; + } + v12 = (char)v12; + goto LABEL_94; + } + if ( pcursitem != -1 && pcurs == 1 ) + { + _LOWORD(v3) = pcursitem; + NetSendCmdLocParam1(1u, (invflag == 0) + CMD_GOTOGETITEM, cursmx, cursmy, v3); + } + if ( pcursmonst != -1 ) + NetSendCmdLocParam1(1u, CMD_TALKXY, cursmx, cursmy, pcursmonst); + v6 = pcursitem == -1; +LABEL_98: + if ( v6 && pcursmonst == -1 && pcursplr == -1 ) + return 1; + return 0; +} +// 484368: using guessed type int FriendlyMode; +// 4B84DC: using guessed type int dropGoldFlag; +// 4B851C: using guessed type int lvlbtndown; +// 4B8960: using guessed type int talkflag; +// 4B8968: using guessed type int sbookflag; +// 4B8C98: using guessed type int spselflag; +// 4B8CC0: using guessed type char pcursitem; +// 4B8CC1: using guessed type char pcursobj; +// 4B8CC2: using guessed type char pcursplr; +// 525740: using guessed type int PauseMode; +// 52575C: using guessed type int doomflag; +// 5BB1ED: using guessed type char leveltype; +// 646D00: using guessed type char qtextflag; +// 69BD04: using guessed type int questlog; +// 6AA705: using guessed type char stextflag; + +bool __cdecl TryIconCurs() +{ + unsigned char v0; // dl + int v1; // edx + int v2; // eax + int v3; // eax + int v4; // ST0C_4 + int v5; // eax + + switch ( pcurs ) + { + case CURSOR_RESURRECT: + v0 = CMD_RESURRECT; +LABEL_3: + NetSendCmdParam1(1u, v0, pcursplr); + return 1; + case CURSOR_HEALOTHER: + v0 = CMD_HEALOTHER; + goto LABEL_3; + case CURSOR_TELEKINESIS: + DoTelekinesis(); + return 1; + case CURSOR_IDENTIFY: + if ( pcursinvitem != -1 ) + { + CheckIdentify(myplr, pcursinvitem); + return 1; + } +LABEL_26: + SetCursor(CURSOR_HAND); + return 1; + case CURSOR_REPAIR: + if ( pcursinvitem != -1 ) + { + DoRepair(myplr, pcursinvitem); + return 1; + } + goto LABEL_26; + case CURSOR_RECHARGE: + if ( pcursinvitem != -1 ) + { + DoRecharge(myplr, pcursinvitem); + return 1; + } + goto LABEL_26; + case CURSOR_TELEPORT: + v1 = plr[myplr]._pTSpell; + if ( pcursmonst == -1 ) + { + if ( pcursplr == -1 ) + { + v4 = GetSpellLevel(myplr, v1); + v5 = 21720 * myplr; + _LOWORD(v5) = plr[myplr]._pTSpell; + NetSendCmdLocParam2(1u, CMD_TSPELLXY, cursmx, cursmy, v5, v4); + } + else + { + v3 = GetSpellLevel(myplr, v1); + NetSendCmdParam3(1u, CMD_TSPELLPID, pcursplr, plr[myplr]._pTSpell, v3); + } + } + else + { + v2 = GetSpellLevel(myplr, v1); + NetSendCmdParam3(1u, CMD_TSPELLID, pcursmonst, plr[myplr]._pTSpell, v2); + } + goto LABEL_26; + } + if ( pcurs == CURSOR_DISARM && pcursobj == -1 ) + goto LABEL_26; + return 0; +} +// 4B8CB8: using guessed type char pcursinvitem; +// 4B8CC1: using guessed type char pcursobj; +// 4B8CC2: using guessed type char pcursplr; + +void __cdecl LeftMouseUp() +{ + gmenu_left_mouse(0); + control_release_talk_btn(); + if ( panbtndown ) + CheckBtnUp(); + if ( chrbtnactive ) + ReleaseChrBtns(); + if ( lvlbtndown ) + ReleaseLvlBtn(); + if ( stextflag ) + ReleaseStoreBtn(); +} +// 4B851C: using guessed type int lvlbtndown; +// 4B87A8: using guessed type int chrbtnactive; +// 4B8C90: using guessed type int panbtndown; +// 6AA705: using guessed type char stextflag; + +void __cdecl RightMouseDown() +{ + if ( !gmenu_exception() && sgnTimeoutCurs == CURSOR_NONE && PauseMode != 2 && !plr[myplr]._pInvincible ) + { + if ( doomflag ) + { + doom_close(); + } + else if ( !stextflag ) + { + if ( spselflag ) + { + SetSpell(); + } + else if ( MouseY >= 352 + || (!sbookflag || MouseX <= 320) + && !TryIconCurs() + && (pcursinvitem == -1 || !UseInvItem(myplr, pcursinvitem)) ) + { + if ( pcurs == 1 ) + { + if ( pcursinvitem == -1 || !UseInvItem(myplr, pcursinvitem) ) + CheckPlrSpell(); + } + else if ( pcurs > 1 && pcurs < 12 ) + { + SetCursor(CURSOR_HAND); + } + } + } + } +} +// 4B8968: using guessed type int sbookflag; +// 4B8C98: using guessed type int spselflag; +// 4B8CB8: using guessed type char pcursinvitem; +// 525740: using guessed type int PauseMode; +// 52575C: using guessed type int doomflag; +// 6AA705: using guessed type char stextflag; + +bool __fastcall PressSysKey(int wParam) +{ + if ( gmenu_exception() || wParam != VK_F10 ) + return 0; + diablo_hotkey_msg(1); + return 1; +} + +void __fastcall diablo_hotkey_msg(int dwMsg) +{ + int v1; // esi + char *v2; // eax + char Filename[260]; // [esp+4h] [ebp-154h] + char ReturnedString[80]; // [esp+108h] [ebp-50h] + + v1 = dwMsg; + if ( gbMaxPlayers != 1 ) + { + if ( !GetModuleFileName(ghInst, Filename, 0x104u) ) + TermMsg("Can't get program name"); + v2 = strrchr(Filename, '\\'); + if ( v2 ) + *v2 = 0; + strcat(Filename, "\\Diablo.ini"); + GetPrivateProfileString("NetMsg", spszMsgKeyTbl[v1], spszMsgTbl[v1], ReturnedString, 0x50u, Filename); + NetSendCmdString(-1, ReturnedString); + } +} +// 48436C: using guessed type char *spszMsgTbl[4]; +// 48437C: using guessed type char *spszMsgKeyTbl[4]; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall ReleaseKey(int vkey) +{ + if ( vkey == VK_SNAPSHOT ) + CaptureScreen(); +} + +void __fastcall PressKey(int vkey) +{ + int v1; // esi + int v2; // ecx + int v3; // ecx + signed int v4; // eax + + v1 = vkey; + if ( !gmenu_presskeys(vkey) && !control_presskeys(v1) ) + { + if ( !deathflag ) + goto LABEL_113; + if ( sgnTimeoutCurs == CURSOR_NONE ) + { + if ( v1 == VK_F9 ) + diablo_hotkey_msg(0); + if ( v1 == VK_F10 ) + diablo_hotkey_msg(1); + if ( v1 == VK_F11 ) + diablo_hotkey_msg(2); + if ( v1 == VK_F12 ) + diablo_hotkey_msg(3); + if ( v1 == VK_RETURN ) + control_type_message(); + if ( v1 == VK_ESCAPE ) + { +LABEL_113: + if ( v1 == VK_ESCAPE ) + { + if ( !PressEscKey() ) + { + track_repeat_walk(0); + gamemenu_previous(); + } + return; + } + if ( sgnTimeoutCurs == CURSOR_NONE && !dropGoldFlag ) + { + if ( v1 == VK_PAUSE ) + { + diablo_pause_game(); + return; + } + if ( PauseMode != 2 ) + { + switch ( v1 ) + { + case VK_RETURN: + if ( stextflag ) + { + STextEnter(); + } + else if ( questlog ) + { + QuestlogEnter(); + } + else + { + control_type_message(); + } + return; + case VK_F1: + if ( helpflag ) + { + helpflag = 0; + return; + } + if ( stextflag ) + { + ClearPanel(); + AddPanelString("No help available", 1); + AddPanelString("while in stores", 1); + track_repeat_walk(0); + return; + } + invflag = 0; + chrflag = 0; + sbookflag = 0; + spselflag = 0; + if ( qtextflag && leveltype == DTYPE_TOWN) + { + qtextflag = 0; + sfx_stop(); + } + questlog = 0; + automapflag = 0; + msgdelay = 0; + gamemenu_off(); + DisplayHelp(); +LABEL_110: + doom_close(); + return; +#ifdef _DEBUG + case VK_F3: + if ( pcursitem != -1 ) + { + sprintf(tempstr, "IDX = %i : Seed = %i : CF = %i", item[pcursitem].IDidx, item[pcursitem]._iSeed, item[pcursitem]._iCreateInfo); + NetSendCmdString(1 << myplr, tempstr); + } + sprintf(tempstr, "Numitems : %i", numitems); + NetSendCmdString(1 << myplr, tempstr); + return; + case VK_F4: + PrintDebugQuest(); + return; +#endif + case VK_F5: + v2 = 0; + goto LABEL_48; + case VK_F6: + v2 = 1; + goto LABEL_48; + case VK_F7: + v2 = 2; + goto LABEL_48; + case VK_F8: + v2 = 3; +LABEL_48: + if ( spselflag ) + SetSpeedSpell(v2); + else + ToggleSpell(v2); + return; + case VK_F9: + v3 = 0; +LABEL_59: + diablo_hotkey_msg(v3); + return; + case VK_F10: + v3 = 1; + goto LABEL_59; + case VK_F11: + v3 = 2; + goto LABEL_59; + case VK_F12: + v3 = 3; + goto LABEL_59; + case VK_UP: + if ( stextflag ) + { + STextUp(); + } + else if ( questlog ) + { + QuestlogUp(); + } + else if ( helpflag ) + { + HelpScrollUp(); + } + else if ( automapflag ) + { + AutomapUp(); + } + return; + case VK_DOWN: + if ( stextflag ) + { + STextDown(); + } + else if ( questlog ) + { + QuestlogDown(); + } + else if ( helpflag ) + { + HelpScrollDown(); + } + else if ( automapflag ) + { + AutomapDown(); + } + return; + case VK_PRIOR: + if ( stextflag ) + STextPrior(); + return; + case VK_NEXT: + if ( stextflag ) + STextNext(); + return; + case VK_LEFT: + if ( automapflag && !talkflag ) + AutomapLeft(); + return; + case VK_RIGHT: + if ( automapflag && !talkflag ) + AutomapRight(); + return; + case VK_TAB: + DoAutoMap(); + return; + case VK_SPACE: + if ( !chrflag ) + { + if ( !invflag ) + { +LABEL_106: + helpflag = 0; + invflag = 0; + chrflag = 0; + sbookflag = 0; + spselflag = 0; + if ( qtextflag && leveltype == DTYPE_TOWN ) + { + qtextflag = 0; + sfx_stop(); + } + questlog = 0; + automapflag = 0; + msgdelay = 0; + gamemenu_off(); + goto LABEL_110; + } + v4 = MouseX; + if ( MouseX >= 480 || MouseY >= 352 ) + { +LABEL_101: + if ( !invflag && chrflag && v4 > 160 && MouseY < 352 ) + SetCursorPos(v4 - 160, MouseY); + goto LABEL_106; + } + SetCursorPos(MouseX + 160, MouseY); + } + v4 = MouseX; + goto LABEL_101; + } + } + } + } + } + } +} +// 4B84DC: using guessed type int dropGoldFlag; +// 4B8960: using guessed type int talkflag; +// 4B8968: using guessed type int sbookflag; +// 4B8C98: using guessed type int spselflag; +// 525740: using guessed type int PauseMode; +// 52B9F0: using guessed type char msgdelay; +// 5BB1ED: using guessed type char leveltype; +// 646D00: using guessed type char qtextflag; +// 69BD04: using guessed type int questlog; +// 6AA705: using guessed type char stextflag; + +void __cdecl diablo_pause_game() +{ + if ( (unsigned char)gbMaxPlayers <= 1u ) + { + if ( PauseMode ) + { + PauseMode = 0; + } + else + { + PauseMode = 2; + FreeMonsterSnd(); + track_repeat_walk(0); + } + drawpanflag = 255; + } +} +// 52571C: using guessed type int drawpanflag; +// 525740: using guessed type int PauseMode; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall PressChar(int vkey) +{ + int v1; // ebx + BOOL v4; // ecx + int v5; // ecx + int v6; // eax + BOOL v7; // ecx + int v9; // ecx + int v10; // eax + int v11; // eax + int v12; // eax + int v13; // eax + int v14; // eax + int v15; // eax + int v16; // eax + int v18; // [esp-4h] [ebp-8h] + + v1 = vkey; + if ( !gmenu_exception() && !control_talk_last_key(v1) && sgnTimeoutCurs == CURSOR_NONE && !deathflag ) + { + if ( (_BYTE)v1 == 'p' || (_BYTE)v1 == 'P' ) + { + diablo_pause_game(); + } + else if ( PauseMode != 2 ) + { + if ( doomflag ) + { + doom_close(); + return; + } + if ( dropGoldFlag ) + { + control_drop_gold(v1); + return; + } + switch ( v1 ) + { + case '!': + case '1': + v9 = myplr; + v10 = plr[myplr].SpdList[0]._itype; + if ( v10 != -1 && v10 != 11 ) + { + v18 = 47; + goto LABEL_72; + } + return; + case '#': + case '3': + v9 = myplr; + v12 = plr[myplr].SpdList[2]._itype; + if ( v12 != -1 && v12 != 11 ) + { + v18 = 49; + goto LABEL_72; + } + return; + case '$': + case '4': + v9 = myplr; + v13 = plr[myplr].SpdList[3]._itype; + if ( v13 != -1 && v13 != 11 ) + { + v18 = 50; + goto LABEL_72; + } + return; + case '%': + case '5': + v9 = myplr; + v14 = plr[myplr].SpdList[4]._itype; + if ( v14 != -1 && v14 != 11 ) + { + v18 = 51; + goto LABEL_72; + } + return; + case '&': + case '7': + v9 = myplr; + v16 = plr[myplr].SpdList[6]._itype; + if ( v16 != -1 && v16 != 11 ) + { + v18 = 53; + goto LABEL_72; + } + return; + case '*': + case '8': +#ifdef _DEBUG + if ( debug_mode_key_inverted_v || debug_mode_key_w ) + { + NetSendCmd(1, CMD_CHEAT_EXPERIENCE); + return; + } +#endif + v9 = myplr; + if ( plr[myplr].SpdList[7]._itype != -1 + && plr[myplr].SpdList[7]._itype != 11 ) + { + v18 = 54; + goto LABEL_72; + } + return; + case '+': + case '=': + if ( automapflag ) + AutomapZoomIn(); + return; + case '-': + case '_': + if ( automapflag ) + AutomapZoomOut(); + return; + case '2': + case '@': + v9 = myplr; + v11 = plr[myplr].SpdList[1]._itype; + if ( v11 != -1 && v11 != 11 ) + { + v18 = 48; + goto LABEL_72; + } + return; + case '6': + case '^': + v9 = myplr; + v15 = plr[myplr].SpdList[5]._itype; + if ( v15 != -1 && v15 != 11 ) + { + v18 = 52; +LABEL_72: + UseInvItem(v9, v18); + } + return; + case 'B': + case 'b': + if ( !stextflag ) + { + invflag = 0; + sbookflag = sbookflag == 0; + } + return; + case 'C': + case 'c': + if ( !stextflag ) + { + questlog = 0; + v7 = chrflag == 0; + chrflag = chrflag == 0; + if ( !v7 || invflag ) + goto LABEL_18; + goto LABEL_24; + } + return; + case 'F': + case 'f': + IncreaseGamma(); + return; + case 'G': + case 'g': + DecreaseGamma(); + return; + case 'I': + case 'i': + if ( stextflag ) + return; + sbookflag = 0; + v4 = invflag == 0; + invflag = invflag == 0; + if ( !v4 || chrflag ) + { +LABEL_24: + if ( MouseX < 480 ) + { + v5 = MouseY; + if ( MouseY < 352 ) + { + v6 = MouseX + 160; + goto LABEL_27; + } + } + } + else + { +LABEL_18: + if ( MouseX > 160 ) + { + v5 = MouseY; + if ( MouseY < 352 ) + { + v6 = MouseX - 160; +LABEL_27: + SetCursorPos(v6, v5); + return; + } + } + } + break; + case 'Q': + case 'q': + if ( !stextflag ) + { + chrflag = 0; + if ( questlog ) + questlog = 0; + else + StartQuestlog(); + } + return; + case 'S': + case 's': + if ( !stextflag ) + { + invflag = 0; + if ( spselflag ) + spselflag = 0; + else + DoSpeedBook(); + track_repeat_walk(0); + } + return; + case 'V': + NetSendCmdString(1 << myplr, gszVersionNumber); + return; + case 'v': + NetSendCmdString(1 << myplr, gszProductName); + return; + case 'Z': + case 'z': + zoomflag = zoomflag == 0; + return; +#ifdef _DEBUG + case ')': + case '0': + if ( debug_mode_key_inverted_v ) + { + if ( arrowdebug > 2 ) + arrowdebug = 0; + if ( !arrowdebug ) + { + plr[myplr]._pIFlags &= ~ISPL_FIRE_ARROWS; + plr[myplr]._pIFlags &= ~ISPL_LIGHT_ARROWS; + } + if ( arrowdebug == 1 ) + plr[myplr]._pIFlags |= ISPL_FIRE_ARROWS; + if ( arrowdebug == 2 ) + plr[myplr]._pIFlags |= ISPL_LIGHT_ARROWS; + arrowdebug++; + } + return; + case ':': + if ( !currlevel && debug_mode_key_w ) + SetAllSpellsCheat(); + return; + case '[': + if ( !currlevel && debug_mode_key_w ) + TakeGoldCheat(); + return; + case ']': + if ( !currlevel && debug_mode_key_w ) + MaxSpellsCheat(); + return; + case 'a': + if ( debug_mode_key_inverted_v ) + { + spelldata[SPL_TELEPORT].sTownSpell = 1; + plr[myplr]._pSplLvl[plr[myplr]._pSpell]++; + } + return; + case 'D': + PrintDebugPlayer(1); + return; + case 'd': + PrintDebugPlayer(0); + return; + case 'e': + if ( debug_mode_key_d ) + { + sprintf(tempstr, "EFlag = %i", plr[myplr]._peflag); + NetSendCmdString(1 << myplr, tempstr); + } + return; + case 'L': + case 'l': + if ( debug_mode_key_inverted_v ) + ToggleLighting(); + return; + case 'M': + NextDebugMonster(); + return; + case 'm': + GetDebugMonster(); + return; + case 'R': + case 'r': + sprintf(tempstr, "seed = %i", glSeedTbl[currlevel]); + NetSendCmdString(1 << myplr, tempstr); + sprintf(tempstr, "Mid1 = %i : Mid2 = %i : Mid3 = %i", glMid1Seed[currlevel], glMid2Seed[currlevel], glMid3Seed[currlevel]); + NetSendCmdString(1 << myplr, tempstr); + sprintf(tempstr, "End = %i", glEndSeed[currlevel]); + NetSendCmdString(1 << myplr, tempstr); + return; + case 'T': + case 't': + if ( debug_mode_key_inverted_v ) + { + sprintf(tempstr, "PX = %i PY = %i", plr[myplr].WorldX, plr[myplr].WorldY); + NetSendCmdString(1 << myplr, tempstr); + sprintf(tempstr, "CX = %i CY = %i DP = %i", cursmx, cursmy, dungeon[cursmx][cursmy]); + NetSendCmdString(1 << myplr, tempstr); + } + return; + case '|': + if ( !currlevel && debug_mode_key_w ) + GiveGoldCheat(); + return; + case '~': + if ( !currlevel && debug_mode_key_w ) + StoresCheat(); + return; +#endif + default: + return; + } + } + } +} +// 4B84DC: using guessed type int dropGoldFlag; +// 4B8968: using guessed type int sbookflag; +// 4B8C98: using guessed type int spselflag; +// 52569C: using guessed type int zoomflag; +// 525740: using guessed type int PauseMode; +// 52575C: using guessed type int doomflag; +// 69BD04: using guessed type int questlog; +// 6AA705: using guessed type char stextflag; + +void __cdecl LoadLvlGFX() +{ + switch(leveltype) + { + case DTYPE_TOWN: + pDungeonCels = LoadFileInMem("Levels\\TownData\\Town.CEL", 0); + pMegaTiles = LoadFileInMem("Levels\\TownData\\Town.TIL", 0); + pLevelPieces = LoadFileInMem("Levels\\TownData\\Town.MIN", 0); + level_special_cel = LoadFileInMem("Levels\\TownData\\TownS.CEL", 0); + break; + case DTYPE_CATHEDRAL: + pDungeonCels = LoadFileInMem("Levels\\L1Data\\L1.CEL", 0); + pMegaTiles = LoadFileInMem("Levels\\L1Data\\L1.TIL", 0); + pLevelPieces = LoadFileInMem("Levels\\L1Data\\L1.MIN", 0); + level_special_cel = LoadFileInMem("Levels\\L1Data\\L1S.CEL", 0); + break; + case DTYPE_CATACOMBS: + pDungeonCels = LoadFileInMem("Levels\\L2Data\\L2.CEL", 0); + pMegaTiles = LoadFileInMem("Levels\\L2Data\\L2.TIL", 0); + pLevelPieces = LoadFileInMem("Levels\\L2Data\\L2.MIN", 0); + level_special_cel = LoadFileInMem("Levels\\L2Data\\L2S.CEL", 0); + break; + case DTYPE_CAVES: + pDungeonCels = LoadFileInMem("Levels\\L3Data\\L3.CEL", 0); + pMegaTiles = LoadFileInMem("Levels\\L3Data\\L3.TIL", 0); + pLevelPieces = LoadFileInMem("Levels\\L3Data\\L3.MIN", 0); + level_special_cel = LoadFileInMem("Levels\\L1Data\\L1S.CEL", 0); + break; + case DTYPE_HELL: + pDungeonCels = LoadFileInMem("Levels\\L4Data\\L4.CEL", 0); + pMegaTiles = LoadFileInMem("Levels\\L4Data\\L4.TIL", 0); + pLevelPieces = LoadFileInMem("Levels\\L4Data\\L4.MIN", 0); + level_special_cel = LoadFileInMem("Levels\\L2Data\\L2S.CEL", 0); + break; + default: + TermMsg("LoadLvlGFX"); + return; + } +} +// 5BB1ED: using guessed type char leveltype; + +void __cdecl LoadAllGFX() +{ + pSpeedCels = DiabloAllocPtr(0x100000); + IncProgress(); + IncProgress(); + InitObjectGFX(); + IncProgress(); + InitMissileGFX(); + IncProgress(); +} + +void __fastcall CreateLevel(int lvldir) +{ + int hnd; // cl + + switch ( leveltype ) + { + case DTYPE_TOWN: + CreateTown(lvldir); + InitTownTriggers(); + hnd = 0; + break; + case DTYPE_CATHEDRAL: + CreateL5Dungeon(glSeedTbl[currlevel], lvldir); + InitL1Triggers(); + Freeupstairs(); + hnd = 1; + break; + case DTYPE_CATACOMBS: + CreateL2Dungeon(glSeedTbl[currlevel], lvldir); + InitL2Triggers(); + Freeupstairs(); + hnd = 2; + break; + case DTYPE_CAVES: + CreateL3Dungeon(glSeedTbl[currlevel], lvldir); + InitL3Triggers(); + Freeupstairs(); + hnd = 3; + break; + case DTYPE_HELL: + CreateL4Dungeon(glSeedTbl[currlevel], lvldir); + InitL4Triggers(); + Freeupstairs(); + hnd = 4; + break; + default: + TermMsg("CreateLevel"); + return; + } + + LoadRndLvlPal(hnd); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall LoadGameLevel(BOOL firstflag, int lvldir) +{ + int v2; // ebp + bool visited; // edx + int i; // ecx + int j; // eax + + v2 = 0; + if ( setseed ) + glSeedTbl[currlevel] = setseed; + music_stop(); + SetCursor(CURSOR_HAND); + SetRndSeed(glSeedTbl[currlevel]); + IncProgress(); + MakeLightTable(); + LoadLvlGFX(); + IncProgress(); + if ( firstflag ) + { + InitInv(); + InitItemGFX(); + InitQuestText(); + + if ( gbMaxPlayers ) + { + for(i = 0; i < gbMaxPlayers; i++) + InitPlrGFXMem(i); + } + + InitStores(); + InitAutomapOnce(); + InitHelp(); + } + SetRndSeed(glSeedTbl[currlevel]); + if ( leveltype == DTYPE_TOWN) + SetupTownStores(); + IncProgress(); + InitAutomap(); + if ( leveltype != DTYPE_TOWN && lvldir != 4 ) + { + InitLighting(); + InitVision(); + } + InitLevelMonsters(); + IncProgress(); + if ( !setlevel ) + { + CreateLevel(lvldir); + IncProgress(); + FillSolidBlockTbls(); + SetRndSeed(glSeedTbl[currlevel]); + if ( leveltype != DTYPE_TOWN ) + { + GetLevelMTypes(); + InitThemes(); + LoadAllGFX(); + } + else + { + InitMissileGFX(); + } + IncProgress(); + if ( lvldir == 3 ) + GetReturnLvlPos(); + if ( lvldir == 5 ) + GetPortalLvlPos(); + IncProgress(); + + for(i = 0; i < MAX_PLRS; i++) + { + if ( plr[i].plractive ) + { + if ( currlevel == plr[i].plrlevel ) + { + InitPlayerGFX(v2); + if ( lvldir != 4 ) + InitPlayer(v2, firstflag); + } + } + ++v2; + } + + PlayDungMsgs(); + InitMultiView(); + IncProgress(); + + visited = 0; + if ( gbMaxPlayers > 0 ) + { + for(i = 0; i < gbMaxPlayers; i++) + { + if ( plr[i].plractive ) + visited = visited || plr[i]._pLvlVisited[currlevel]; + } + } + SetRndSeed(glSeedTbl[currlevel]); + if ( leveltype != DTYPE_TOWN) + { + if ( firstflag || lvldir == 4 || !plr[myplr]._pLvlVisited[currlevel] || gbMaxPlayers != 1 ) + { + HoldThemeRooms(); + glMid1Seed[currlevel] = GetRndSeed(); + InitMonsters(); + glMid2Seed[currlevel] = GetRndSeed(); + InitObjects(); + InitItems(); + CreateThemeRooms(); + glMid3Seed[currlevel] = GetRndSeed(); + InitMissiles(); + InitDead(); + glEndSeed[currlevel] = GetRndSeed(); + if ( gbMaxPlayers != 1 ) + DeltaLoadLevel(); + IncProgress(); + SavePreLighting(); + goto LABEL_55; + } + InitMonsters(); + InitMissiles(); + InitDead(); + IncProgress(); + LoadLevel(); +LABEL_54: + IncProgress(); +LABEL_55: + if ( gbMaxPlayers == 1 ) + ResyncQuests(); + else + ResyncMPQuests(); + goto LABEL_72; + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + dFlags[i][j] |= 0x40; + } + + InitTowners(); + InitItems(); + InitMissiles(); + IncProgress(); + if ( !firstflag && lvldir != 4 && plr[myplr]._pLvlVisited[currlevel] ) + { + if ( gbMaxPlayers != 1 ) + goto LABEL_53; + LoadLevel(); + } + if ( gbMaxPlayers == 1 ) + goto LABEL_54; +LABEL_53: + DeltaLoadLevel(); + goto LABEL_54; + } + pSpeedCels = DiabloAllocPtr(0x100000); + LoadSetMap(); + IncProgress(); + GetLevelMTypes(); + InitMonsters(); + InitMissileGFX(); + InitDead(); + FillSolidBlockTbls(); + IncProgress(); + if ( lvldir == 5 ) + GetPortalLvlPos(); + + for(i = 0; i < MAX_PLRS; i++) + { + if ( plr[i].plractive ) + { + if ( currlevel == plr[i].plrlevel ) + { + InitPlayerGFX(v2); + if ( lvldir != 4 ) + InitPlayer(v2, firstflag); + } + } + ++v2; + } + + InitMultiView(); + IncProgress(); + if ( firstflag || lvldir == 4 || !plr[myplr]._pSLvlVisited[(unsigned char)setlvlnum] ) + { + InitItems(); + SavePreLighting(); + } + else + { + LoadLevel(); + } + InitMissiles(); + IncProgress(); +LABEL_72: + SyncPortals(); + + for(i = 0; i < MAX_PLRS; i++) + { + if ( plr[i].plractive && plr[i].plrlevel == currlevel && (!plr[i]._pLvlChanging || i == myplr) ) + { + if ( plr[i]._pHitPoints <= 0 ) + dFlags[plr[i].WorldX][plr[i].WorldY] |= 4; + else if ( gbMaxPlayers == 1 ) + dPlayer[plr[i].WorldX][plr[i].WorldY] = i + 1; + else + SyncInitPlrPos(i); + } + } + + if ( leveltype != DTYPE_TOWN ) + SetDungeonMicros(); + InitLightMax(); + IncProgress(); + IncProgress(); + if ( firstflag ) + { + InitControlPan(); + IncProgress(); + } + if ( leveltype != DTYPE_TOWN) + { + ProcessLightList(); + ProcessVisionList(); + } + music_start((unsigned char)leveltype); + //do + // _LOBYTE(v19) = IncProgress(); + while ( !IncProgress() ); + if ( setlevel && setlvlnum == SL_SKELKING && quests[12]._qactive == 2 ) + PlaySFX(USFX_SKING1); +} +// 525738: using guessed type int setseed; +// 5BB1ED: using guessed type char leveltype; +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall game_loop(bool bStartup) +{ + int v1; // ecx + int v2; // esi + + v1 = bStartup != 0 ? 0x39 : 0; + v2 = v1 + 3; + if ( v1 != -3 ) + { + while ( 1 ) + { + --v2; + if ( !multi_handle_delta() ) + break; + timeout_cursor(0); + game_logic(); + if ( gbRunGame ) + { + if ( gbMaxPlayers != 1 ) + { + if ( nthread_has_500ms_passed() ) + { + if ( v2 ) + continue; + } + } + } + return; + } + timeout_cursor(1); + } +} +// 525650: using guessed type int gbRunGame; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl game_logic() +{ + if ( PauseMode != 2 ) + { + if ( PauseMode == 1 ) + PauseMode = 2; + if ( gbMaxPlayers == 1 && gmenu_exception() ) + { + drawpanflag |= 1u; + } + else + { + if ( !gmenu_exception() && sgnTimeoutCurs == CURSOR_NONE ) + { + CheckCursMove(); + track_process(); + } + if ( gbProcessPlayers ) + ProcessPlayers(); + if ( leveltype != DTYPE_TOWN ) + { + ProcessMonsters(); + ProcessObjects(); + ProcessMissiles(); + ProcessItems(); + ProcessLightList(); + ProcessVisionList(); + } + else + { + ProcessTowners(); + ProcessItems(); + ProcessMissiles(); + } +#ifdef _DEBUG + if ( debug_mode_key_inverted_v ) + { + if ( GetAsyncKeyState(VK_SHIFT) & 0x8000 ) + ScrollView(); + } +#endif + sound_update(); + ClearPlrMsg(); + CheckTriggers(); + CheckQuests(); + drawpanflag |= 1u; + pfile_update(0); + } + } +} +// 5256A0: using guessed type int gbProcessPlayers; +// 525718: using guessed type char cineflag; +// 52571C: using guessed type int drawpanflag; +// 525740: using guessed type int PauseMode; +// 5BB1ED: using guessed type char leveltype; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall timeout_cursor(bool bTimeout) +{ + if ( bTimeout ) + { + if ( sgnTimeoutCurs == CURSOR_NONE && !sgbMouseDown ) + { + sgnTimeoutCurs = pcurs; + multi_net_ping(); + ClearPanel(); + AddPanelString("-- Network timeout --", 1); + AddPanelString("-- Waiting for players --", 1); + SetCursor(CURSOR_HOURGLASS); + drawpanflag = 255; + } + scrollrt_draw_game_screen(1); + } + else if ( sgnTimeoutCurs ) + { + SetCursor(sgnTimeoutCurs); + sgnTimeoutCurs = 0; + ClearPanel(); + drawpanflag = 255; + } +} +// 52571C: using guessed type int drawpanflag; +// 525748: using guessed type char sgbMouseDown; + +void __cdecl diablo_color_cyc_logic() +{ + DWORD v0; // eax + + v0 = GetTickCount(); + if ( v0 - color_cycle_timer >= 0x32 ) + { + color_cycle_timer = v0; + if ( palette_get_colour_cycling() ) + { + if ( leveltype == DTYPE_HELL ) + { + lighting_color_cycling(); + } + else if ( leveltype == DTYPE_CAVES ) + { + if ( fullscreen ) + palette_update_caves(); + } + } + } +} +// 484364: using guessed type int fullscreen; +// 52574C: using guessed type int color_cycle_timer; +// 5BB1ED: using guessed type char leveltype; diff --git a/Source/diablo.h b/Source/diablo.h new file mode 100644 index 000000000..fca909111 --- /dev/null +++ b/Source/diablo.h @@ -0,0 +1,102 @@ +//HEADER_GOES_HERE +#ifndef __DIABLO_H__ +#define __DIABLO_H__ + +extern int diablo_cpp_init_value; // weak +extern HWND ghMainWnd; +extern int glMid1Seed[NUMLEVELS]; +extern int glMid2Seed[NUMLEVELS]; +extern int gnLevelTypeTbl[NUMLEVELS]; +extern int MouseY; // idb +extern int MouseX; // idb +extern bool gbGameLoopStartup; // idb +extern int glSeedTbl[NUMLEVELS]; +extern int gbRunGame; // weak +extern int glMid3Seed[NUMLEVELS]; +extern int gbRunGameResult; // weak +extern int zoomflag; // weak +extern int gbProcessPlayers; // weak +extern int glEndSeed[NUMLEVELS]; +extern int dword_5256E8; // weak +extern HINSTANCE ghInst; // idb +extern int DebugMonsters[10]; +extern char cineflag; // weak +extern int drawpanflag; // weak +extern int visiondebug; // weak +extern int scrollflag; /* unused */ +extern int light4flag; // weak +extern int leveldebug; // weak +extern int monstdebug; // weak +extern int trigdebug; /* unused */ +extern int setseed; // weak +extern int debugmonsttypes; // weak +extern int PauseMode; // weak +extern int sgnTimeoutCurs; +extern char sgbMouseDown; // weak +extern int color_cycle_timer; // weak + +void __cdecl diablo_cpp_init(); +void __cdecl FreeGameMem(); +int __fastcall diablo_init_menu(int a1, int bSinglePlayer); +void __fastcall run_game_loop(int uMsg); +void __fastcall start_game(int uMsg); +void __cdecl free_game(); +bool __cdecl diablo_get_not_running(); +int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd); +void __fastcall diablo_parse_flags(char *args); +void __cdecl diablo_init_screen(); +BOOL __fastcall diablo_find_window(LPCSTR lpClassName); +void __fastcall diablo_reload_process(HMODULE hModule); +int __cdecl PressEscKey(); +LRESULT __stdcall DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +LRESULT __stdcall GM_Game(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +bool __fastcall LeftMouseDown(int a1); +bool __cdecl TryIconCurs(); +void __cdecl LeftMouseUp(); +void __cdecl RightMouseDown(); +void __fastcall j_gmenu_on_mouse_move(LPARAM lParam); +bool __fastcall PressSysKey(int wParam); +void __fastcall diablo_hotkey_msg(int dwMsg); +void __fastcall ReleaseKey(int vkey); +void __fastcall PressKey(int vkey); +void __cdecl diablo_pause_game(); +void __fastcall PressChar(int vkey); +void __cdecl LoadLvlGFX(); +void __cdecl LoadAllGFX(); +void __fastcall CreateLevel(int lvldir); +void __fastcall LoadGameLevel(BOOL firstflag, int lvldir); +void __fastcall game_loop(bool bStartup); +void __cdecl game_logic(); +void __fastcall timeout_cursor(bool bTimeout); +void __cdecl diablo_color_cyc_logic(); + +/* data */ + +extern int diablo_inf; // weak + +/* rdata */ + +extern int fullscreen; // weak +#ifdef _DEBUG +extern int showintrodebug; +extern int questdebug; +extern int debug_mode_key_s; +extern int debug_mode_key_w; +extern int debug_mode_key_inverted_v; +extern int debug_mode_dollar_sign; +extern int debug_mode_key_d; +extern int debug_mode_key_i; +extern int dbgplr; +extern int dbgqst; +extern int dbgmon; +extern int arrowdebug; +extern int frameflag; +extern int frameend; +extern int framerate; +extern int framestart; +#endif +extern int FriendlyMode; // weak +extern char *spszMsgTbl[4]; // weak +extern char *spszMsgKeyTbl[4]; // weak + +#endif /* __DIABLO_H__ */ diff --git a/Source/doom.cpp b/Source/doom.cpp new file mode 100644 index 000000000..e20455e8c --- /dev/null +++ b/Source/doom.cpp @@ -0,0 +1,113 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int doom_quest_time; // weak +int doom_stars_drawn; // weak +void *pDoomCel; +int doomflag; // weak +int DoomQuestState; // idb +#endif + +/* +void __cdecl doom_reset_state() +{ + if ( DoomQuestState <= 0 ) { + DoomQuestState = 0; + } +} + +void __cdecl doom_play_movie() +{ + if ( DoomQuestState < 36001 ) { + DoomQuestState++; + if ( DoomQuestState == 36001 ) { + PlayInGameMovie("gendata\\doom.smk"); + DoomQuestState++; + } + } +} +*/ + +int __cdecl doom_get_frame_from_time() +{ + if ( DoomQuestState == 36001 ) { + return 31; + } + + return DoomQuestState / 1200; +} + +void __cdecl doom_alloc_cel() +{ + pDoomCel = DiabloAllocPtr(229376); +} + +void __cdecl doom_cleanup() +{ + void *ptr = pDoomCel; + pDoomCel = NULL; + mem_free_dbg(ptr); +} + +void __cdecl doom_load_graphics() +{ + if ( doom_quest_time == 31 ) + { + strcpy(tempstr, "Items\\Map\\MapZDoom.CEL"); + } + else if ( doom_quest_time < 10 ) + { + sprintf(tempstr, "Items\\Map\\MapZ000%i.CEL", doom_quest_time); + } + else + { + sprintf(tempstr, "Items\\Map\\MapZ00%i.CEL", doom_quest_time); + } + LoadFileWithMem(tempstr, pDoomCel); +} +// 525750: using guessed type int doom_quest_time; + +void __cdecl doom_init() +{ + doomflag = 1; + doom_alloc_cel(); + doom_quest_time = doom_get_frame_from_time() == 31 ? 31 : 0; + doom_load_graphics(); +} +// 525750: using guessed type int doom_quest_time; +// 52575C: using guessed type int doomflag; + +void __cdecl doom_close() +{ + if ( doomflag ) { + doomflag = 0; + doom_cleanup(); + } +} +// 52575C: using guessed type int doomflag; + +void __cdecl doom_draw() +{ + if ( !doomflag ) { + return; + } + + if ( doom_quest_time != 31 ) { + doom_stars_drawn++; + if ( doom_stars_drawn >= 5 ) { + doom_stars_drawn = 0; + doom_quest_time++; + if ( doom_quest_time > doom_get_frame_from_time() ) { + doom_quest_time = 0; + } + doom_load_graphics(); + } + } + + CelDecodeOnly(64, 511, pDoomCel, 1, 640); +} +// 525750: using guessed type int doom_quest_time; +// 525754: using guessed type int doom_stars_drawn; +// 52575C: using guessed type int doomflag; diff --git a/Source/doom.h b/Source/doom.h new file mode 100644 index 000000000..fe13d5289 --- /dev/null +++ b/Source/doom.h @@ -0,0 +1,23 @@ +//HEADER_GOES_HERE +#ifndef __DOOM_H__ +#define __DOOM_H__ + +extern int doom_quest_time; // weak +extern int doom_stars_drawn; // weak +extern void *pDoomCel; +extern int doomflag; // weak +extern int DoomQuestState; // idb + +/* +void __cdecl doom_reset_state(); +void __cdecl doom_play_movie(); +*/ +int __cdecl doom_get_frame_from_time(); +void __cdecl doom_alloc_cel(); +void __cdecl doom_cleanup(); +void __cdecl doom_load_graphics(); +void __cdecl doom_init(); +void __cdecl doom_close(); +void __cdecl doom_draw(); + +#endif /* __DOOM_H__ */ diff --git a/Source/drlg_l1.cpp b/Source/drlg_l1.cpp new file mode 100644 index 000000000..4dfcf881c --- /dev/null +++ b/Source/drlg_l1.cpp @@ -0,0 +1,2910 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +char L5dungeon[80][80]; +char mydflags[40][40]; +int setloadflag; // weak +int HR1; +int HR2; +int HR3; +int VR1; +int VR2; +int VR3; +void *pSetPiece; // idb +#endif + +const ShadowStruct SPATS[37] = +{ + { 7, 13, 0, 13, 144, 0, 142 }, + { 16, 13, 0, 13, 144, 0, 142 }, + { 15, 13, 0, 13, 145, 0, 142 }, + { 5, 13, 13, 13, 152, 140, 139 }, + { 5, 13, 1, 13, 143, 146, 139 }, + { 5, 13, 13, 2, 143, 140, 148 }, + { 5, 0, 1, 2, 0, 146, 148 }, + { 5, 13, 11, 13, 143, 147, 139 }, + { 5, 13, 13, 12, 143, 140, 149 }, + { 5, 13, 11, 12, 150, 147, 149 }, + { 5, 13, 1, 12, 143, 146, 149 }, + { 5, 13, 11, 2, 143, 147, 148 }, + { 9, 13, 13, 13, 144, 140, 142 }, + { 9, 13, 1, 13, 144, 146, 142 }, + { 9, 13, 11, 13, 151, 147, 142 }, + { 8, 13, 0, 13, 144, 0, 139 }, + { 8, 13, 0, 12, 143, 0, 149 }, + { 8, 0, 0, 2, 0, 0, 148 }, + { 11, 0, 0, 13, 0, 0, 139 }, + { 11, 13, 0, 13, 139, 0, 139 }, + { 11, 2, 0, 13, 148, 0, 139 }, + { 11, 12, 0, 13, 149, 0, 139 }, + { 11, 13, 11, 12, 139, 0, 149 }, + { 14, 0, 0, 13, 0, 0, 139 }, + { 14, 13, 0, 13, 139, 0, 139 }, + { 14, 2, 0, 13, 148, 0, 139 }, + { 14, 12, 0, 13, 149, 0, 139 }, + { 14, 13, 11, 12, 139, 0, 149 }, + { 10, 0, 13, 0, 0, 140, 0 }, + { 10, 13, 13, 0, 140, 140, 0 }, + { 10, 0, 1, 0, 0, 146, 0 }, + { 10, 13, 11, 0, 140, 147, 0 }, + { 12, 0, 13, 0, 0, 140, 0 }, + { 12, 13, 13, 0, 140, 140, 0 }, + { 12, 0, 1, 0, 0, 146, 0 }, + { 12, 13, 11, 0, 140, 147, 0 }, + { 3, 13, 11, 12, 150, 0, 0 } +}; +const unsigned char BSTYPES[206] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 10, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 14, 5, 14, + 10, 4, 14, 4, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 3, 4, 1, 6, 7, 16, 17, 2, 1, + 1, 2, 2, 1, 1, 2, 2, 2, 2, 2, + 1, 1, 11, 1, 13, 13, 13, 1, 2, 1, + 2, 1, 2, 1, 2, 2, 2, 2, 12, 0, + 0, 11, 1, 11, 1, 13, 0, 0, 0, 0, + 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 1, 11, 2, 12, + 13, 13, 13, 12, 2, 1, 2, 2, 4, 14, + 4, 10, 13, 13, 4, 4, 1, 1, 4, 2, + 2, 13, 13, 13, 13, 25, 26, 28, 30, 31, + 41, 43, 40, 41, 42, 43, 25, 41, 43, 28, + 28, 1, 2, 25, 26, 22, 22, 25, 26, 0, + 0, 0, 0, 0, 0, 0 +}; +const unsigned char L5BTYPES[206] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 0, 0, + 0, 0, 0, 0, 0, 25, 26, 0, 28, 0, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 40, 41, 42, 43, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, + 80, 0, 82, 0, 0, 0, 0, 0, 0, 79, + 0, 80, 0, 0, 79, 80, 0, 2, 2, 2, + 1, 1, 11, 25, 13, 13, 13, 1, 2, 1, + 2, 1, 2, 1, 2, 2, 2, 2, 12, 0, + 0, 11, 1, 11, 1, 13, 0, 0, 0, 0, + 0, 0, 0, 13, 13, 13, 13, 13, 13, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 +}; +const unsigned char STAIRSUP[] = { 4, 4, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 0, 66, 6, 0, 63, 64, 65, 0, 0, 67, 68, 0, 0, 0, 0, 0 }; +const unsigned char L5STAIRSUP[] = { 4, 4, 22, 22, 22, 22, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 0, 66, 23, 0, 63, 64, 65, 0, 0, 67, 68, 0, 0, 0, 0, 0 }; +const unsigned char STAIRSDOWN[] = { 4, 3, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 62, 57, 58, 0, 61, 59, 60, 0, 0, 0, 0, 0 }; +const unsigned char LAMPS[] = { 2, 2, 13, 0, 13, 13, 129, 0, 130, 128 }; +const unsigned char PWATERIN[] = { 6, 6, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 202, 200, 200, 84, 0, 0, 199, 203, 203, 83, 0, 0, 85, 206, 80, 81, 0, 0, 0, 134, 135, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* data */ +unsigned char L5ConvTbl[16] = { 22u, 13u, 1u, 13u, 2u, 13u, 13u, 13u, 4u, 13u, 1u, 13u, 2u, 13u, 16u, 13u }; + +void __cdecl DRLG_Init_Globals() +{ + char v0; // al + + memset(dFlags, 0, 0x3100u); + memset(dPlayer, 0, 0x3100u); + memset(dMonster, 0, 0xC400u); + memset(dDead, 0, 0x3100u); + memset(dObject, 0, 0x3100u); + memset(dItem, 0, 0x3100u); + memset(dMissile, 0, 0x3100u); + memset(dArch, 0, 0x3100u); + if ( lightflag ) + v0 = 0; + else + v0 = light4flag == 0 ? 15 : 3; + memset(dTransVal, v0, 0x3100u); +} +// 525728: using guessed type int light4flag; +// 646A28: using guessed type int lightflag; + +void __fastcall LoadL1Dungeon(char *sFileName, int vx, int vy) +{ + char *v3; // esi + unsigned char *v4; // esi + signed int v5; // ecx + signed int v6; // eax + signed int v7; // edx + int v8; // edi + int v9; // ebx + char *v10; // eax + int v11; // ecx + char v12; // dl + int v13; // [esp+Ch] [ebp-Ch] + int v14; // [esp+10h] [ebp-8h] + int v15; // [esp+14h] [ebp-4h] + + v13 = vx; + dminx = 16; + dminy = 16; + v3 = sFileName; + dmaxx = 96; + dmaxy = 96; + DRLG_InitTrans(); + v4 = LoadFileInMem(v3, 0); + v5 = 0; + do + { + v6 = v5; + v7 = 40; + do + { + mydflags[0][v6] = 0; + dungeon[0][v6] = 22; + v6 += 40; + --v7; + } + while ( v7 ); + ++v5; + } + while ( v5 < 40 ); + v15 = 0; + v8 = *v4; + v9 = v4[2]; + v10 = (char *)(v4 + 4); + if ( v9 > 0 ) + { + do + { + if ( v8 > 0 ) + { + v11 = v15; + v14 = v8; + do + { + v12 = *v10; + if ( *v10 ) + { + mydflags[0][v11] |= 0x80u; + dungeon[0][v11] = v12; + } + else + { + dungeon[0][v11] = 13; + } + v11 += 40; + v10 += 2; + --v14; + } + while ( v14 ); + } + ++v15; + } + while ( v15 < v9 ); + } + DRLG_L1Floor(); + ViewX = v13; + ViewY = vy; + DRLG_L1Pass3(); + DRLG_Init_Globals(); + DRLG_InitL1Vals(); + SetMapMonsters(v4, 0, 0); + SetMapObjects(v4, 0, 0); + mem_free_dbg(v4); +} +// 5CF328: using guessed type int dmaxx; +// 5CF32C: using guessed type int dmaxy; +// 5D2458: using guessed type int dminx; +// 5D245C: using guessed type int dminy; + +void __cdecl DRLG_L1Floor() +{ + signed int i; // edi + signed int v1; // esi + signed int j; // ebx + int rv; // eax + + i = 0; + do + { + v1 = i; + j = 40; + do + { + if ( !mydflags[0][v1] && dungeon[0][v1] == 13 ) + { + rv = random(0, 3); + if ( rv == 1 ) + dungeon[0][v1] = -94; + if ( rv == 2 ) + dungeon[0][v1] = -93; + } + v1 += 40; + --j; + } + while ( j ); + ++i; + } + while ( i < 40 ); +} + +void __cdecl DRLG_L1Pass3() +{ + int v0; // eax + int *v1; // edx + int *v2; // eax + signed int v3; // ecx + signed int v4; // ebx + int *v5; // ecx + unsigned char *v6; // edx + unsigned short *v7; // esi + unsigned short v8; // ax + int v9; // eax + int v10; // ST24_4 + int v11; // ST20_4 + int v12; // ST1C_4 + signed int v13; // [esp+Ch] [ebp-1Ch] + int *v14; // [esp+10h] [ebp-18h] + int v15; // [esp+14h] [ebp-14h] + int v16; // [esp+18h] [ebp-10h] + int v17; // [esp+1Ch] [ebp-Ch] + int v18; // [esp+20h] [ebp-8h] + + v0 = *((unsigned short *)pMegaTiles + 84) + 1; + v18 = *((unsigned short *)pMegaTiles + 84) + 1; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 85); + v17 = ++v0; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 86); + v16 = ++v0; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 87); + v15 = v0 + 1; + v1 = dPiece[1]; + do + { + v2 = v1; + v3 = 56; + do + { + *(v2 - 112) = v18; + *v2 = v17; + *(v2 - 111) = v16; + v2[1] = v15; + v2 += 224; + --v3; + } + while ( v3 ); + v1 += 2; + } + while ( (signed int)v1 < (signed int)dPiece[2] ); + v4 = 0; + v14 = &dPiece[17][16]; /* check */ + do + { + v5 = v14; + v6 = (unsigned char *)dungeon + v4; + v13 = 40; + do + { + v7 = (unsigned short *)((char *)pMegaTiles + 8 * (*v6 - 1)); + v8 = *v7; + ++v7; + v9 = v8 + 1; + v10 = v9; + _LOWORD(v9) = *v7; + ++v7; + v11 = ++v9; + _LOWORD(v9) = *v7; + v12 = ++v9; + _LOWORD(v9) = v7[1]; + v6 += 40; + *(v5 - 112) = v10; + *v5 = v11; + *(v5 - 111) = v12; + v5[1] = v9 + 1; + v5 += 224; + --v13; + } + while ( v13 ); + v14 += 2; + ++v4; + } + while ( v4 < 40 ); +} + +void __cdecl DRLG_InitL1Vals() +{ + int v0; // esi + int (*v1)[112]; // edx + char *v2; // ecx + int v3; // eax + char v4; // al + char v5; // [esp-4h] [ebp-18h] + signed int v6; // [esp+Ch] [ebp-8h] + int (*v7)[112]; // [esp+10h] [ebp-4h] + + v0 = 0; + v7 = dPiece; + do + { + v1 = v7; + v2 = (char *)dArch + v0; + v6 = 112; + do + { + v3 = (*v1)[0]; + if ( (*v1)[0] != 12 ) + { + if ( v3 == 11 ) + goto LABEL_21; + if ( v3 != 71 ) + { + if ( v3 == 259 ) + { + v5 = 5; +LABEL_9: + v4 = v5; + goto LABEL_22; + } + if ( v3 == 249 || v3 == 325 ) + goto LABEL_21; + if ( v3 != 321 ) + { + if ( v3 == 255 ) + { + v5 = 4; + goto LABEL_9; + } + if ( v3 != 211 ) + { + if ( v3 == 344 ) + goto LABEL_21; + if ( v3 != 341 ) + { + if ( v3 == 331 ) + goto LABEL_21; + if ( v3 != 418 ) + { + if ( v3 != 421 ) + goto LABEL_23; +LABEL_21: + v4 = 2; + goto LABEL_22; + } + } + } + } + } + } + v4 = 1; +LABEL_22: + *v2 = v4; +LABEL_23: + ++v1; + v2 += 112; + --v6; + } + while ( v6 ); + v7 = (int (*)[112])((char *)v7 + 4); + ++v0; + } + while ( (signed int)v7 < (signed int)dPiece[1] ); +} + +void __fastcall LoadPreL1Dungeon(char *sFileName, int vx, int vy) +{ + unsigned char *v3; // ebx + signed int v4; // ecx + signed int v5; // eax + signed int v6; // edx + int v7; // esi + int v8; // edi + char *v9; // eax + int v10; // ecx + char v11; // dl + signed int v12; // esi + signed int v13; // eax + signed int v14; // edi + int v15; // [esp+Ch] [ebp-8h] + int v16; // [esp+10h] [ebp-4h] + + dminx = 16; + dminy = 16; + dmaxx = 96; + dmaxy = 96; + v3 = LoadFileInMem(sFileName, 0); + v4 = 0; + do + { + v5 = v4; + v6 = 40; + do + { + mydflags[0][v5] = 0; + dungeon[0][v5] = 22; + v5 += 40; + --v6; + } + while ( v6 ); + ++v4; + } + while ( v4 < 40 ); + v16 = 0; + v7 = *v3; + v8 = v3[2]; + v9 = (char *)(v3 + 4); + if ( v8 > 0 ) + { + do + { + if ( v7 > 0 ) + { + v10 = v16; + v15 = v7; + do + { + v11 = *v9; + if ( *v9 ) + { + mydflags[0][v10] |= 0x80u; + dungeon[0][v10] = v11; + } + else + { + dungeon[0][v10] = 13; + } + v10 += 40; + v9 += 2; + --v15; + } + while ( v15 ); + } + ++v16; + } + while ( v16 < v8 ); + } + DRLG_L1Floor(); + v12 = 0; + do + { + v13 = v12; + v14 = 40; + do + { + pdungeon[0][v13] = dungeon[0][v13]; + v13 += 40; + --v14; + } + while ( v14 ); + ++v12; + } + while ( v12 < 40 ); + mem_free_dbg(v3); +} +// 5CF328: using guessed type int dmaxx; +// 5CF32C: using guessed type int dmaxy; +// 5D2458: using guessed type int dminx; +// 5D245C: using guessed type int dminy; + +void __fastcall CreateL5Dungeon(int rseed, int entry) +{ + int v2; // esi + + v2 = entry; + SetRndSeed(rseed); + dminx = 16; + dminy = 16; + dmaxx = 96; + dmaxy = 96; + DRLG_InitTrans(); + DRLG_InitSetPC(); + DRLG_LoadL1SP(); + DRLG_L5(v2); + DRLG_L1Pass3(); + DRLG_FreeL1SP(); + DRLG_InitL1Vals(); + DRLG_SetPC(); +} +// 5CF328: using guessed type int dmaxx; +// 5CF32C: using guessed type int dmaxy; +// 5D2458: using guessed type int dminx; +// 5D245C: using guessed type int dminy; + +void __cdecl DRLG_LoadL1SP() +{ + setloadflag = 0; + if ( QuestStatus(6) ) + { + pSetPiece = LoadFileInMem("Levels\\L1Data\\rnd6.DUN", 0); + setloadflag = 1; + } + if ( QuestStatus(12) && gbMaxPlayers == 1 ) + { + pSetPiece = LoadFileInMem("Levels\\L1Data\\SKngDO.DUN", 0); + setloadflag = 1; + } + if ( QuestStatus(7) ) + { + pSetPiece = LoadFileInMem("Levels\\L1Data\\Banner2.DUN", 0); + setloadflag = 1; + } +} +// 5276A4: using guessed type int setloadflag; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl DRLG_FreeL1SP() +{ + void *v0; // ecx + + v0 = pSetPiece; + pSetPiece = 0; + mem_free_dbg(v0); +} + +void __fastcall DRLG_L5(int entry) +{ + signed int v1; // esi + signed int v2; // edi + int v5; // eax + int v6; // ebx + int v7; // edi + int v8; // edi + int v9; // ebp + _BYTE *v10; // ebx + signed int v11; // eax + signed int v12; // ecx + int v13; // [esp+10h] [ebp-8h] + int v14; // [esp+10h] [ebp-8h] + int v15; // [esp+14h] [ebp-4h] + _BYTE *v16; // [esp+14h] [ebp-4h] + + v13 = entry; + if ( currlevel == 1 ) + { + v15 = 533; + } + else if ( currlevel == 2 ) + { + v15 = 693; + } + else if ( currlevel > 2u && currlevel <= 4u ) + { + v15 = 761; + } + v1 = 0; + while ( 1 ) + { + DRLG_InitTrans(); + do + { + InitL5Dungeon(); + L5firstRoom(); + } + while ( L5GetArea() < v15 ); + L5makeDungeon(); + L5makeDmt(); + L5FillChambers(); + L5tileFix(); + L5AddWall(); + L5ClearFlags(); + DRLG_L5FloodTVal(); + v2 = 1; + if ( QuestStatus(13) ) + { + if ( v13 ) + { + if ( DRLG_PlaceMiniSet(PWATERIN, 1, 1, 0, 0, 0, -1, 0) < 0 ) + v2 = 0; + --ViewY; + } + else if ( DRLG_PlaceMiniSet(PWATERIN, 1, 1, 0, 0, 1, -1, 0) < 0 ) + { + v2 = 0; + } + } + if ( QuestStatus(7) ) + { + if ( !v13 ) + { + v5 = DRLG_PlaceMiniSet(STAIRSUP, 1, 1, 0, 0, 1, -1, 0); + goto LABEL_21; + } + if ( DRLG_PlaceMiniSet(STAIRSUP, 1, 1, 0, 0, 0, -1, 0) < 0 ) + v2 = 0; + if ( v13 == 1 ) + { + ViewX = 2 * setpc_x + 20; + ViewY = 2 * setpc_y + 28; + goto LABEL_34; + } +LABEL_33: + --ViewY; + goto LABEL_34; + } + if ( v13 ) + { + if ( DRLG_PlaceMiniSet(L5STAIRSUP, 1, 1, 0, 0, 0, -1, 0) < 0 + || DRLG_PlaceMiniSet(STAIRSDOWN, 1, 1, 0, 0, 1, -1, 1) < 0 ) + { + v2 = 0; + } + goto LABEL_33; + } + if ( DRLG_PlaceMiniSet(L5STAIRSUP, 1, 1, 0, 0, 1, -1, 0) >= 0 ) + { + v5 = DRLG_PlaceMiniSet(STAIRSDOWN, 1, 1, 0, 0, 0, -1, 1); +LABEL_21: + if ( v5 < 0 ) + v2 = 0; +LABEL_34: + if ( v2 ) + break; + } + } + v14 = 0; + v6 = 16; + do + { + v7 = 16; + v16 = (unsigned char *)dungeon + v14; + do + { + if ( *v16 == 64 ) + { + DRLG_CopyTrans(v7, v6 + 1, v7, v6); + DRLG_CopyTrans(v7 + 1, v6 + 1, v7 + 1, v6); + } + v16 += 40; + v7 += 2; + } + while ( v7 < 96 ); + ++v14; + v6 += 2; + } + while ( v6 < 96 ); + DRLG_L5TransFix(); + DRLG_L5DirtFix(); + DRLG_L5CornerFix(); + v8 = 0; + do + { + v9 = 0; + v10 = (unsigned char *)mydflags + v8; + do + { + if ( *v10 & 0x7F ) + DRLG_PlaceDoor(v9, v8); + ++v9; + v10 += 40; + } + while ( v9 < 40 ); + ++v8; + } + while ( v8 < 40 ); + DRLG_L5Subs(); + DRLG_L1Shadows(); + DRLG_PlaceMiniSet(LAMPS, 5, 10, 0, 0, 0, -1, 4); + DRLG_L1Floor(); + do + { + v11 = v1; + v12 = 40; + do + { + pdungeon[0][v11] = dungeon[0][v11]; + v11 += 40; + --v12; + } + while ( v12 ); + ++v1; + } + while ( v1 < 40 ); + DRLG_Init_Globals(); + DRLG_CheckQuests(setpc_x, setpc_y); +} + +void __fastcall DRLG_PlaceDoor(int x, int y) +{ + int v2; // edi + char *v3; // eax + char v4; // al + char v5; // dl + char *v6; // eax + char v7; // bl + char *v8; // [esp+Ch] [ebp-8h] + + v2 = y; + v3 = &mydflags[x][y]; + v8 = v3; + v4 = *v3; + if ( v4 < 0 ) + goto LABEL_57; + v5 = v4 & 0x7F; + v6 = &dungeon[x][v2]; + v7 = *v6; + if ( v5 == 1 ) + { + if ( v2 != 1 ) + { + if ( v7 == 2 ) + *v6 = 26; + if ( v7 == 7 ) + *v6 = 31; + if ( v7 == 14 ) + *v6 = 42; + if ( v7 == 4 ) + *v6 = 43; + } + if ( x == 1 ) + goto LABEL_57; + if ( v7 == 1 ) + *v6 = 25; + if ( v7 == 10 ) + *v6 = 40; + if ( v7 != 6 ) + goto LABEL_57; + *v6 = 30; + } + if ( v5 != 2 ) + goto LABEL_36; + if ( x != 1 ) + { + if ( v7 == 1 ) + *v6 = 25; + if ( v7 == 6 ) + *v6 = 30; + if ( v7 == 10 ) + *v6 = 40; + if ( v7 == 4 ) + *v6 = 41; + } + if ( v2 != 1 ) + { + if ( v7 == 2 ) + *v6 = 26; + if ( v7 == 14 ) + *v6 = 42; + if ( v7 == 7 ) + { + *v6 = 31; +LABEL_36: + if ( v5 == 3 ) + { + if ( x != 1 ) + { + if ( v2 != 1 && v7 == 4 ) + *v6 = 28; + if ( v7 == 10 ) + *v6 = 40; + } + if ( v2 != 1 ) + { + if ( v7 == 14 ) + *v6 = 42; + if ( v7 == 2 ) + *v6 = 26; + } + if ( x != 1 && v7 == 1 ) + *v6 = 25; + if ( v2 != 1 && v7 == 7 ) + *v6 = 31; + if ( x != 1 && v7 == 6 ) + *v6 = 30; + } + goto LABEL_57; + } + } +LABEL_57: + *v8 = -128; +} + +void __cdecl DRLG_L1Shadows() +{ + signed int v0; // ebx + char *v1; // eax + signed int v2; // edx + unsigned char *v3; // esi + signed int v4; // edi + char v5; // cl + char v6; // cl + char v7; // cl + char v8; // cl + char v9; // cl + signed int v10; // edi + signed int v11; // eax + signed int v12; // esi + char v13; // cl + char v14; // dl + char v15; // cl + char v16; // dl + char v17; // cl + char v18; // dl + unsigned char sd[2][2]; + + v0 = 1; + do + { + v1 = &dungeon[0][v0 + 39]; + v2 = 1; + do + { + v3 = (unsigned char *)&SPATS[0].s1; + sd[0][0] = BSTYPES[(unsigned char)v1[1]]; + sd[1][0] = BSTYPES[(unsigned char)*(v1 - 39)]; + sd[0][1] = BSTYPES[(unsigned char)*v1]; + sd[1][1] = BSTYPES[(unsigned char)*(v1 - 40)]; + do + { + if ( *(v3 - 1) == sd[0][0] ) + { + v4 = 1; + if ( *v3 && *v3 != sd[1][1] ) + v4 = 0; + v5 = v3[1]; + if ( v5 && v5 != sd[0][1] ) + v4 = 0; + v6 = v3[2]; + if ( v6 && v6 != sd[1][0] ) + v4 = 0; + if ( v4 == 1 ) + { + v7 = v3[3]; + if ( v7 && !mydflags[v2 - 1][v0 - 1] ) /* !L5dungeon[79][v2 + 39 + v0] ) */ + *(v1 - 40) = v7; + v8 = v3[4]; + if ( v8 && !mydflags[v2][v0 - 1] ) /* !L5dungeon[79][v2 + 79 + v0] ) */ + *v1 = v8; + v9 = v3[5]; + if ( v9 && !mydflags[v2 - 1][v0] ) /* !L5dungeon[79][v2 + 40 + v0] ) */ + *(v1 - 39) = v9; + } + } + v3 += 7; + } + while ( (signed int)v3 < (signed int)&SPATS[37].s1 ); + ++v2; + v1 += 40; + } + while ( v2 < 40 ); + ++v0; + } + while ( v0 < 40 ); + v10 = 1; + do + { + v11 = v10; + v12 = 39; + do + { + if ( dungeon[0][v11] == -117 && !mydflags[0][v11] ) + { + v13 = dungeon[1][v11]; + v14 = -117; + if ( v13 == 29 ) + v14 = -115; + if ( v13 == 32 ) + v14 = -115; + if ( v13 == 35 ) + v14 = -115; + if ( v13 == 37 ) + v14 = -115; + if ( v13 == 38 ) + v14 = -115; + if ( v13 == 39 ) + v14 = -115; + dungeon[0][v11] = v14; + } + if ( dungeon[0][v11] == -107 && !mydflags[0][v11] ) + { + v15 = dungeon[1][v11]; + v16 = -107; + if ( v15 == 29 ) + v16 = -103; + if ( v15 == 32 ) + v16 = -103; + if ( v15 == 35 ) + v16 = -103; + if ( v15 == 37 ) + v16 = -103; + if ( v15 == 38 ) + v16 = -103; + if ( v15 == 39 ) + v16 = -103; + dungeon[0][v11] = v16; + } + if ( dungeon[0][v11] == -108 && !mydflags[0][v11] ) + { + v17 = dungeon[1][v11]; + v18 = -108; + if ( v17 == 29 ) + v18 = -102; + if ( v17 == 32 ) + v18 = -102; + if ( v17 == 35 ) + v18 = -102; + if ( v17 == 37 ) + v18 = -102; + if ( v17 == 38 ) + v18 = -102; + if ( v17 == 39 ) + v18 = -102; + dungeon[0][v11] = v18; + } + v11 += 40; + --v12; + } + while ( v12 ); + ++v10; + } + while ( v10 < 40 ); +} + +int __fastcall DRLG_PlaceMiniSet(const unsigned char *miniset, int tmin, int tmax, int cx, int cy, bool setview, int noquad, int ldir) +{ + unsigned char *v8; // ebx + int v9; // edi + int v10; // esi + int v11; // edx + int v12; // esi + int v13; // edi + int v14; // ebx + signed int v15; // edx + int v16; // eax + unsigned char v17; // cl + int v18; // ebx + int result; // eax + int v20; // eax + char *v21; // ecx + char v22; // dl + char v23; // bl + bool v24; // zf + bool v25; // sf + unsigned char v26; // of + int v27; // [esp-4h] [ebp-34h] + int v28; // [esp+Ch] [ebp-24h] + const unsigned char *v29; // [esp+10h] [ebp-20h] + int v30; // [esp+14h] [ebp-1Ch] + int v31; // [esp+18h] [ebp-18h] + int v32; // [esp+1Ch] [ebp-14h] + int v33; // [esp+20h] [ebp-10h] + int max; // [esp+24h] [ebp-Ch] + int v35; // [esp+28h] [ebp-8h] + int v36; // [esp+2Ch] [ebp-4h] + int tmaxa; // [esp+38h] [ebp+8h] + int tmaxb; // [esp+38h] [ebp+8h] + + v8 = (unsigned char *)miniset; + v9 = *miniset; + v10 = tmin; + v11 = tmax - tmin; + v29 = miniset; + v35 = *miniset; + v36 = miniset[1]; + if ( v11 ) + v30 = v10 + random(0, v11); + else + v30 = 1; + v31 = 0; + if ( v30 > 0 ) + { + max = 40 - v9; + v28 = 40 - v36; + while ( 1 ) + { + v12 = random(0, max); + v32 = 0; + v13 = random(0, v28); + while ( 1 ) + { + tmaxa = 1; + if ( cx != -1 && v12 >= cx - v35 && v12 <= cx + 12 ) + { + ++v12; + tmaxa = 0; + } + if ( cy != -1 && v13 >= cy - v36 && v13 <= cy + 12 ) + { + ++v13; + tmaxa = 0; + } + v14 = 0; + switch ( noquad ) + { + case 0: + if ( v12 >= cx ) + goto LABEL_29; + goto LABEL_27; + case 1: + if ( v12 <= cx ) + goto LABEL_29; +LABEL_27: + if ( v13 >= cy ) + goto LABEL_29; +LABEL_28: + tmaxa = 0; + goto LABEL_29; + case 2: + if ( v12 >= cx ) + goto LABEL_29; +LABEL_22: + if ( v13 <= cy ) + goto LABEL_29; + goto LABEL_28; + } + if ( noquad == 3 && v12 > cx ) + goto LABEL_22; +LABEL_29: + v15 = 2; + if ( v36 > 0 ) + { + do + { + if ( tmaxa != 1 ) + break; + v33 = 0; + if ( v35 > 0 ) + { + v16 = v13 + v14 + 40 * v12; + do + { + if ( tmaxa != 1 ) + break; + v17 = v29[v15]; + if ( v17 && dungeon[0][v16] != v17 ) + tmaxa = 0; + if ( mydflags[0][v16] ) + tmaxa = 0; + ++v15; + ++v33; + v16 += 40; + } + while ( v33 < v35 ); + } + ++v14; + } + while ( v14 < v36 ); + } + v18 = 0; + if ( tmaxa ) + break; + if ( ++v12 == max ) + { + v12 = 0; + if ( ++v13 == v28 ) + v13 = 0; + } + if ( ++v32 > 4000 ) + return -1; + } + v20 = v35 * v36 + 2; + if ( v36 > 0 ) + { + do + { + if ( v35 > 0 ) + { + tmaxb = v35; + v21 = &dungeon[v12][v18 + v13]; + do + { + v22 = v29[v20]; + if ( v22 ) + *v21 = v22; + ++v20; + v21 += 40; + --tmaxb; + } + while ( tmaxb ); + } + ++v18; + } + while ( v18 < v36 ); + } + if ( ++v31 >= v30 ) + { + v8 = (unsigned char *)v29; + goto LABEL_57; + } + } + } + v12 = cx; + v13 = cx; +LABEL_57: + if ( v8 == PWATERIN ) + { + v23 = TransVal; + TransVal = 0; + DRLG_MRectTrans(v12, v13 + 2, v12 + 5, v13 + 4); + TransVal = v23; + quests[13]._qtx = 2 * v12 + 21; + quests[13]._qty = 2 * v13 + 22; + } + result = 1; + if ( setview == 1 ) + { + ViewX = 2 * v12 + 19; + ViewY = 2 * v13 + 20; + } + if ( !ldir ) + { + LvlViewX = 2 * v12 + 19; + LvlViewY = 2 * v13 + 20; + } + v26 = __OFSUB__(v12, cx); + v24 = v12 == cx; + v25 = v12 - cx < 0; + if ( v12 < cx ) + { + if ( v13 < cy ) + return 0; + v26 = __OFSUB__(v12, cx); + v24 = v12 == cx; + v25 = v12 - cx < 0; + } + if ( (unsigned char)(v25 ^ v26) | v24 || v13 >= cy ) + { + if ( v12 >= cx || v13 <= cy ) + v27 = 3; + else + v27 = 2; + result = v27; + } + return result; +} +// 5A5590: using guessed type char TransVal; +// 5CF320: using guessed type int LvlViewY; +// 5CF324: using guessed type int LvlViewX; + +void __cdecl InitL5Dungeon() +{ + signed int v0; // edx + signed int v1; // eax + signed int v2; // ecx + + v0 = 0; + do + { + v1 = v0; + v2 = 40; + do + { + dungeon[0][v1] = 0; + mydflags[0][v1] = 0; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl L5ClearFlags() +{ + signed int v0; // ecx + _BYTE *v1; // eax + signed int v2; // edx + + v0 = 0; + do + { + v1 = (unsigned char *)mydflags + v0; + v2 = 40; + do + { + *v1 &= 0xBFu; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl L5firstRoom() +{ + signed int v0; // ebx + signed int v1; // ebp + signed int i; // ecx + char *v3; // eax + signed int v4; // ebp + signed int v5; // ebx + int v6; // ebp + char *v7; // eax + + if ( random(0, 2) ) + { + v4 = 39; + v5 = 1; + HR1 = random(0, 2); + HR2 = random(0, 2); + HR3 = random(0, 2); + if ( HR1 + HR3 <= 1 ) + HR2 = 1; + if ( HR1 ) + L5drawRoom(1, 15, 10, 10); + else + v5 = 18; + if ( HR2 ) + L5drawRoom(15, 15, 10, 10); + if ( HR3 ) + L5drawRoom(29, 15, 10, 10); + else + v4 = 22; + if ( v5 < v4 ) + { + v6 = v4 - v5; + v7 = &dungeon[v5][18]; + do + { + *(v7 - 1) = 1; + *v7 = 1; + v7[1] = 1; + v7[2] = 1; + v7[3] = 1; + v7[4] = 1; + v7 += 40; + --v6; + } + while ( v6 ); + } + if ( HR1 ) + L5roomGen(1, 15, 10, 10, 1); + if ( HR2 ) + L5roomGen(15, 15, 10, 10, 1); + if ( HR3 ) + L5roomGen(29, 15, 10, 10, 1); + VR3 = 0; + VR2 = 0; + VR1 = 0; + } + else + { + v0 = 39; + v1 = 1; + VR1 = random(0, 2); + VR2 = random(0, 2); + VR3 = random(0, 2); + if ( VR1 + VR3 <= 1 ) + VR2 = 1; + if ( VR1 ) + L5drawRoom(15, 1, 10, 10); + else + v1 = 18; + if ( VR2 ) + L5drawRoom(15, 15, 10, 10); + if ( VR3 ) + L5drawRoom(15, 29, 10, 10); + else + v0 = 22; + for ( i = v1; i < v0; v3[160] = 1 ) + { + v3 = &dungeon[18][i++]; + *(v3 - 40) = 1; + *v3 = 1; + v3[40] = 1; + v3[80] = 1; + v3[120] = 1; + } + if ( VR1 ) + L5roomGen(15, 1, 10, 10, 0); + if ( VR2 ) + L5roomGen(15, 15, 10, 10, 0); + if ( VR3 ) + L5roomGen(15, 29, 10, 10, 0); + HR3 = 0; + HR2 = 0; + HR1 = 0; + } +} + +void __fastcall L5drawRoom(int x, int y, int w, int h) +{ + int i; // esi + int v5; // edi + char *v6; // eax + + for ( i = 0; i < h; ++i ) + { + if ( w > 0 ) + { + v5 = w; + v6 = &dungeon[x][i + y]; + do + { + *v6 = 1; + v6 += 40; + --v5; + } + while ( v5 ); + } + } +} + +void __fastcall L5roomGen(int x, int y, int w, int h, BOOL dir) +{ + int v5; // eax + BOOL v6; // ecx + BOOL v7; // eax + int v8; // ecx + int v9; // eax + int v11; // esi + int v12; // edi + int v13; // ebx + int v14; // eax + int v15; // eax + int v16; // eax + int v18; // esi + int v19; // edi + int v20; // ebx + int v21; // eax + int v22; // eax + int tya; // [esp+Ch] [ebp-10h] + int tyb; // [esp+Ch] [ebp-10h] + int v25; // [esp+10h] [ebp-Ch] + int v26; // [esp+10h] [ebp-Ch] + int txa; // [esp+14h] [ebp-8h] + int txb; // [esp+14h] [ebp-8h] + int v29; // [esp+18h] [ebp-4h] + int twa; // [esp+24h] [ebp+8h] + int tha; // [esp+28h] [ebp+Ch] + int thb; // [esp+28h] [ebp+Ch] + int thc; // [esp+28h] [ebp+Ch] + signed int dir_horiza; // [esp+2Ch] [ebp+10h] + signed int dir_horizb; // [esp+2Ch] [ebp+10h] + + v29 = y; + txa = x; + while ( 1 ) + { + while ( 1 ) + { + v5 = random(0, 4); + v6 = 0; + v6 = dir == 1 ? v5 != 0 : v5 == 0; + v7 = v6; + v8 = 0; + if ( !v7 ) + break; + if ( v7 != 1 ) + return; + dir_horiza = 0; + twa = w / 2; + do + { + v9 = random(0, 5); + v11 = (v9 + 2) & 0xFFFFFFFE; + v12 = (random(0, 5) + 2) & 0xFFFFFFFE; + v13 = txa + twa - v11 / 2; + tya = v29 - v12; + v14 = L5checkRoom(v13 - 1, v29 - v12 - 1, v11 + 2, v12 + 1); + ++dir_horiza; + v25 = v14; + } + while ( !v14 && dir_horiza < 20 ); + if ( v14 == 1 ) + L5drawRoom(v13, tya, v11, v12); + txb = v29 + h; + v15 = L5checkRoom(v13 - 1, v29 + h, v11 + 2, v12 + 1); + tha = v15; + if ( v15 == 1 ) + L5drawRoom(v13, txb, v11, v12); + if ( v25 == 1 ) + L5roomGen(v13, tya, v11, v12, 0); + if ( tha != 1 ) + return; + dir = 0; + h = v12; + w = v11; + v29 = txb; + txa = v13; + } + dir_horizb = 0; + thb = h / 2; + do + { + v16 = random(0, 5); + v18 = (v16 + 2) & 0xFFFFFFFE; + v19 = (random(0, 5) + 2) & 0xFFFFFFFE; + v20 = v29 + thb - v19 / 2; + tyb = txa - v18; + v21 = L5checkRoom(txa - v18 - 1, v20 - 1, v19 + 2, v18 + 1); + ++dir_horizb; + v26 = v21; + } + while ( !v21 && dir_horizb < 20 ); + if ( v21 == 1 ) + L5drawRoom(tyb, v20, v18, v19); + txa += w; + v22 = L5checkRoom(txa, v20 - 1, v18 + 1, v19 + 2); + thc = v22; + if ( v22 == 1 ) + L5drawRoom(txa, v20, v18, v19); + if ( v26 == 1 ) + L5roomGen(tyb, v20, v18, v19, 1); + if ( thc != 1 ) + break; + dir = 1; + h = v19; + w = v18; + v29 = v20; + } +} + +bool __fastcall L5checkRoom(int x, int y, int width, int height) +{ + int v4; // eax + int v5; // ebx + char *v6; // edi + int v8; // [esp+Ch] [ebp-4h] + + v4 = 0; + if ( height <= 0 ) + return 1; + while ( 1 ) + { + v8 = 0; + if ( width > 0 ) + break; +LABEL_10: + if ( ++v4 >= height ) + return 1; + } + v5 = x; + v6 = &dungeon[x][v4 + y]; + while ( v5 >= 0 && v5 < 40 && v4 + y >= 0 && v4 + y < 40 && !*v6 ) + { + ++v8; + v6 += 40; + ++v5; + if ( v8 >= width ) + goto LABEL_10; + } + return 0; +} + +int __cdecl L5GetArea() +{ + int rv; // eax + signed int i; // edx + _BYTE *v2; // ecx + signed int j; // esi + + rv = 0; + i = 0; + do + { + v2 = (unsigned char *)dungeon + i; + j = 40; + do + { + if ( *v2 == 1 ) + ++rv; + v2 += 40; + --j; + } + while ( j ); + ++i; + } + while ( i < 40 ); + return rv; +} + +void __cdecl L5makeDungeon() +{ + signed int v0; // edi + signed int v1; // esi + char *v2; // edx + char v3; // cl + int v4; // eax + int v5; // eax + + v0 = 0; + do + { + v1 = 0; + v2 = (char *)dungeon + v0; + do + { + v3 = *v2; + v2 += 40; + v4 = 160 * v1++; + v5 = v4 + 2 * v0; + L5dungeon[0][v5] = v3; + L5dungeon[0][v5 + 1] = v3; + L5dungeon[1][v5] = v3; + L5dungeon[1][v5 + 1] = v3; + } + while ( v1 < 40 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl L5makeDmt() +{ + signed int v0; // ecx + _BYTE *v1; // eax + signed int v2; // edx + signed int v3; // esi + char (*v4)[40]; // ecx + char *v5; // eax + signed int v6; // edi + int v7; // edx + int v8; // ebx + char (*v9)[40]; // [esp+0h] [ebp-4h] + + v0 = 0; + do + { + v1 = (unsigned char *)dungeon + v0; + v2 = 40; + do + { + *v1 = 22; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); + v3 = 1; + v9 = dungeon; + do + { + v4 = v9; + v5 = &L5dungeon[1][v3 + 1]; + v6 = 39; + do + { + v7 = (unsigned char)v5[80]; + v8 = (unsigned char)*v5; + v5 += 160; + *(_BYTE *)v4 = L5ConvTbl[2 * ((unsigned char)*(v5 - 81) + 2 * (v8 + 2 * v7)) + + (unsigned char)*(v5 - 161)]; + ++v4; + --v6; + } + while ( v6 ); + v9 = (char (*)[40])((char *)v9 + 1); + v3 += 2; + } + while ( v3 <= 77 ); +} + +void __cdecl L5AddWall() +{ + int v0; // edi + int v1; // esi + int v2; // ebx + int v3; // eax + int v4; // eax + int v5; // eax + int v6; // eax + int v7; // eax + int v8; // eax + + v0 = 0; + do + { + v1 = 0; + v2 = v0; + do + { + if ( !mydflags[0][v2] ) + { + if ( dungeon[0][v2] == 3 ) + { + if ( random(0, 100) < 100 ) + { + v3 = L5HWallOk(v1, v0); + if ( v3 != -1 ) + L5HorizWall(v1, v0, 2, v3); + } + if ( dungeon[0][v2] == 3 && random(0, 100) < 100 ) + { + v4 = L5VWallOk(v1, v0); + if ( v4 != -1 ) + L5VertWall(v1, v0, 1, v4); + } + } + if ( dungeon[0][v2] == 6 && random(0, 100) < 100 ) + { + v5 = L5HWallOk(v1, v0); + if ( v5 != -1 ) + L5HorizWall(v1, v0, 4, v5); + } + if ( dungeon[0][v2] == 7 && random(0, 100) < 100 ) + { + v6 = L5VWallOk(v1, v0); + if ( v6 != -1 ) + L5VertWall(v1, v0, 4, v6); + } + if ( dungeon[0][v2] == 2 && random(0, 100) < 100 ) + { + v7 = L5HWallOk(v1, v0); + if ( v7 != -1 ) + L5HorizWall(v1, v0, 2, v7); + } + if ( dungeon[0][v2] == 1 && random(0, 100) < 100 ) + { + v8 = L5VWallOk(v1, v0); + if ( v8 != -1 ) + L5VertWall(v1, v0, 1, v8); + } + } + ++v1; + v2 += 40; + } + while ( v1 < 40 ); + ++v0; + } + while ( v0 < 40 ); +} + +int __fastcall L5HWallOk(int i, int j) +{ + int v2; // esi + char *v3; // edi + int v4; // eax + char *v5; // ebx + signed int wallok; // eax + char v7; // dl + int result; // eax + int v9; // [esp+8h] [ebp-4h] + + v2 = 8 * (5 * i + 5); + v9 = 1; + v3 = (char *)dungeon + v2 + j; + if ( *v3 == 13 ) + { + v4 = 8 * (5 * i + 5); + v5 = &dungeon[i + 1][j]; + do + { + if ( *(v3 - 1) != 13 ) + break; + if ( dungeon[0][v2 + 1 + j] != 13 ) + break; + if ( mydflags[0][v2 + j] ) + break; + ++v9; + v5 += 40; + v4 += 40; + v3 = v5; + v2 = v4; + } + while ( *v5 == 13 ); + } + wallok = 0; + v7 = dungeon[v9 + i][j]; + if ( (unsigned char)v7 >= 3u && (unsigned char)v7 <= 7u ) + wallok = 1; + if ( (unsigned char)v7 >= 0x10u && (unsigned char)v7 <= 0x18u ) + wallok = 1; + if ( v7 == 22 ) + wallok = 0; + if ( v9 == 1 ) + wallok = 0; + if ( wallok ) + result = v9; + else + result = -1; + return result; +} + +int __fastcall L5VWallOk(int i, int j) +{ + int v2; // ecx + int result; // eax + char *v4; // esi + signed int wallok; // esi + char v6; // dl + + v2 = i; + result = 1; + if ( dungeon[v2][j + 1] == 13 ) + { + v4 = &dungeon[v2][j]; + do + { + if ( v4[result - 40] != 13 ) + break; + if ( dungeon[v2 + 1][result + j] != 13 ) + break; + if ( mydflags[v2][result + j] ) + break; + ++result; + } + while ( v4[result] == 13 ); + } + wallok = 0; + v6 = dungeon[0][result + v2 * 40 + j]; + if ( (unsigned char)v6 >= 3u && (unsigned char)v6 <= 7u ) + wallok = 1; + if ( (unsigned char)v6 >= 0x10u && (unsigned char)v6 <= 0x18u ) + wallok = 1; + if ( v6 == 22 ) + wallok = 0; + if ( result == 1 ) + wallok = 0; + if ( !wallok ) + result = -1; + return result; +} + +void __fastcall L5HorizWall(int i, int j, char p, int dx) +{ + int v4; // edi + int v5; // esi + int v6; // eax + char v8; // bl + int v9; // eax + int v10; // ecx + char *v11; // edi + int v12; // eax + int v13; // eax + int v14; // eax + int v15; // [esp+8h] [ebp-8h] + char v16; // [esp+Fh] [ebp-1h] + + v4 = j; + v5 = i; + v15 = j; + v6 = random(0, 4); + if ( v6 >= 0 ) + { + if ( v6 <= 1 ) + { + v16 = 2; + } + else if ( v6 == 2 ) + { + v16 = 12; + if ( p == 2 ) + _LOBYTE(p) = 12; + if ( p == 4 ) + _LOBYTE(p) = 10; + } + else if ( v6 == 3 ) + { + v16 = 36; + if ( p == 2 ) + _LOBYTE(p) = 36; + if ( p == 4 ) + _LOBYTE(p) = 27; + } + } + v8 = random(0, 6) != 5 ? 26 : 12; + if ( v16 == 12 ) + v8 = 12; + v9 = v4 + 40 * v5; + dungeon[0][v9] = p; + v10 = dx; + if ( dx > 1 ) + { + v11 = &dungeon[1][v9]; + v12 = dx - 1; + do + { + *v11 = v16; + v11 += 40; + --v12; + } + while ( v12 ); + v4 = v15; + } + v13 = random(0, dx - 1) + 1; + if ( v8 == 12 ) + { + dungeon[v5 + v13][v4] = 12; + } + else + { + v14 = v4 + 40 * (v5 + v13); + mydflags[0][v14] |= 1u; + dungeon[0][v14] = 2; + } +} + +void __fastcall L5VertWall(int i, int j, char p, int dy) +{ + int v4; // edi + int v5; // esi + int v6; // eax + int v8; // eax + int v9; // ebx + int v10; // esi + int v11; // ecx + char *v12; // edi + int v13; // eax + unsigned int v14; // ecx + int v15; // edx + int v16; // eax + int v17; // eax + int v18; // [esp+8h] [ebp-8h] + char v19; // [esp+Eh] [ebp-2h] + char v20; // [esp+Fh] [ebp-1h] + + v4 = j; + v5 = i; + v18 = j; + v6 = random(0, 4); + if ( v6 >= 0 ) + { + if ( v6 <= 1 ) + { + v20 = 1; + } + else if ( v6 == 2 ) + { + v20 = 11; + if ( p == 1 ) + _LOBYTE(p) = 11; + if ( p == 4 ) + _LOBYTE(p) = 14; + } + else if ( v6 == 3 ) + { + v20 = 35; + if ( p == 1 ) + _LOBYTE(p) = 35; + if ( p == 4 ) + _LOBYTE(p) = 37; + } + } + v8 = random(0, 6); + v9 = 5 - v8; + _LOBYTE(v9) = v8 != 5 ? 25 : 11; + v19 = v8 != 5 ? 25 : 11; + if ( v20 == 11 ) + { + _LOBYTE(v9) = 11; + v19 = 11; + } + v10 = v5; + dungeon[v10][v4] = p; + v11 = dy; + if ( dy > 1 ) + { + v12 = &dungeon[v10][v4 + 1]; + _LOBYTE(v9) = v20; + BYTE1(v9) = v20; + v13 = v9 << 16; + _LOWORD(v13) = v9; + _LOBYTE(v9) = v19; + v14 = (unsigned int)(dy - 1) >> 2; + memset32(v12, v13, v14); + memset(&v12[4 * v14], v13, ((_BYTE)dy - 1) & 3); + v11 = dy; + v4 = v18; + } + v15 = v11 - 1; + v16 = random(0, v15) + 1; + if ( (_BYTE)v9 == 11 ) + { + dungeon[0][v16 + v10 * 40 + v4] = 11; + } + else + { + v17 = v16 + v10 * 40 + v4; + mydflags[0][v17] |= 2u; + dungeon[0][v17] = 1; + } +} + +void __cdecl L5tileFix() +{ + signed int v0; // esi + char *v1; // eax + signed int v2; // edx + char v3; // cl + signed int v4; // ecx + signed int v5; // edi + signed int v6; // eax + char *v7; // esi + char v8; // bl + char *v9; // edx + char *v10; // edx + char *v11; // edx + char *v12; // edx + char *v13; // edx + char *v14; // edx + char *v15; // edx + char *v16; // edx + char *v17; // edx + char *v18; // edx + char *v19; // edx + char *v20; // edx + char *v21; // edx + char *v22; // edx + char *v23; // edx + char *v24; // edx + char *v25; // edx + char *v26; // edx + char *v27; // edx + char *v28; // edx + char *v29; // edx + char *v30; // edx + char *v31; // edx + char *v32; // edx + char *v33; // edx + char *v34; // eax + signed int v35; // edx + char *v36; // eax + signed int v37; // esi + char v38; // cl + + v0 = 0; + do + { + v1 = &dungeon[1][v0]; + v2 = 40; + do + { + v3 = *(v1 - 40); + if ( v3 == 2 && *v1 == 22 ) + *v1 = 23; + if ( v3 == 13 ) + { + if ( *v1 == 22 ) + *v1 = 18; + if ( *v1 == 2 ) + *v1 = 7; + } + if ( v3 == 6 && *v1 == 22 ) + *v1 = 24; + if ( v3 == 1 && *(v1 - 39) == 22 ) + *(v1 - 39) = 24; + if ( v3 == 13 ) + { + if ( *(v1 - 39) == 1 ) + *(v1 - 39) = 6; + if ( *(v1 - 39) == 22 ) + *(v1 - 39) = 19; + } + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); + v4 = 0; + do + { + v5 = 0; + do + { + v6 = v5; + v7 = &dungeon[v5][v4]; + v8 = *v7; + if ( *v7 == 13 ) + { + v9 = &dungeon[v6 + 1][v4]; + if ( *v9 == 19 ) + *v9 = 21; + v10 = &dungeon[v6 + 1][v4]; + if ( *v10 == 22 ) + *v10 = 20; + } + if ( v8 == 7 ) + { + v11 = &dungeon[v6 + 1][v4]; + if ( *v11 == 22 ) + *v11 = 23; + } + if ( v8 == 13 ) + { + v12 = &dungeon[v6 + 1][v4]; + if ( *v12 == 24 ) + *v12 = 21; + } + if ( v8 == 19 ) + { + v13 = &dungeon[v6 + 1][v4]; + if ( *v13 == 22 ) + *v13 = 20; + } + if ( v8 == 2 ) + { + v14 = &dungeon[v6 + 1][v4]; + if ( *v14 == 19 ) + *v14 = 21; + } + if ( v8 == 19 ) + { + v15 = &dungeon[v6 + 1][v4]; + if ( *v15 == 1 ) + *v15 = 6; + } + if ( v8 == 7 ) + { + v16 = &dungeon[v6 + 1][v4]; + if ( *v16 == 19 ) + *v16 = 21; + } + if ( v8 == 2 ) + { + v17 = &dungeon[v6 + 1][v4]; + if ( *v17 == 1 ) + *v17 = 6; + } + if ( v8 == 3 ) + { + v18 = &dungeon[v6 + 1][v4]; + if ( *v18 == 22 ) + *v18 = 24; + } + if ( v8 == 21 ) + { + v19 = &dungeon[v6 + 1][v4]; + if ( *v19 == 1 ) + *v19 = 6; + } + if ( v8 == 7 ) + { + v20 = &dungeon[v6 + 1][v4]; + if ( *v20 == 1 ) + *v20 = 6; + v21 = &dungeon[v6 + 1][v4]; + if ( *v21 == 24 ) + *v21 = 21; + } + if ( v8 == 4 ) + { + v22 = &dungeon[v6 + 1][v4]; + if ( *v22 == 16 ) + *v22 = 17; + } + if ( v8 == 7 ) + { + v23 = &dungeon[v6 + 1][v4]; + if ( *v23 == 13 ) + *v23 = 17; + } + if ( v8 == 2 ) + { + v24 = &dungeon[v6 + 1][v4]; + if ( *v24 == 24 ) + *v24 = 21; + v25 = &dungeon[v6 + 1][v4]; + if ( *v25 == 13 ) + *v25 = 17; + } + if ( v8 == 23 && *(v7 - 40) == 22 ) + *(v7 - 40) = 19; + if ( v8 == 19 && *(v7 - 40) == 23 ) + *(v7 - 40) = 21; + if ( v8 == 6 ) + { + if ( *(v7 - 40) == 22 ) + *(v7 - 40) = 24; + if ( *(v7 - 40) == 23 ) + *(v7 - 40) = 21; + } + if ( v8 == 1 ) + { + v26 = &dungeon[v6][v4 + 1]; + if ( *v26 == 2 ) + *v26 = 7; + } + if ( v8 == 6 ) + { + v27 = &dungeon[v6][v4 + 1]; + if ( *v27 == 18 ) + *v27 = 21; + } + if ( v8 == 18 ) + { + v28 = &dungeon[v6][v4 + 1]; + if ( *v28 == 2 ) + *v28 = 7; + } + if ( v8 == 6 ) + { + v29 = &dungeon[v6][v4 + 1]; + if ( *v29 == 2 ) + *v29 = 7; + } + if ( v8 == 21 ) + { + v30 = &dungeon[v6][v4 + 1]; + if ( *v30 == 2 ) + *v30 = 7; + } + if ( v8 == 6 ) + { + v31 = &dungeon[v6][v4 + 1]; + if ( *v31 == 22 ) + *v31 = 24; + v32 = &dungeon[v6][v4 + 1]; + if ( *v32 == 13 ) + *v32 = 16; + } + if ( v8 == 1 ) + { + v33 = &dungeon[v6][v4 + 1]; + if ( *v33 == 13 ) + *v33 = 16; + } + if ( v8 == 13 ) + { + v34 = &dungeon[v6][v4 + 1]; + if ( *v34 == 16 ) + *v34 = 17; + } + if ( v8 == 6 ) + { + if ( *(v7 - 1) == 22 ) + *(v7 - 1) = 7; + if ( *(v7 - 1) == 22 ) + *(v7 - 1) = 24; + } + if ( v8 == 7 && *(v7 - 1) == 24 ) + *(v7 - 1) = 21; + if ( v8 == 18 && *(v7 - 1) == 24 ) + *(v7 - 1) = 21; + ++v5; + } + while ( v5 < 40 ); + ++v4; + } + while ( v4 < 40 ); + v35 = 0; + do + { + v36 = (char *)dungeon + v35; + v37 = 40; + do + { + v38 = *v36; + if ( *v36 == 4 && v36[1] == 2 ) + v36[1] = 7; + if ( v38 == 2 && v36[40] == 19 ) + v36[40] = 21; + if ( v38 == 18 && v36[1] == 22 ) + v36[1] = 20; + v36 += 40; + --v37; + } + while ( v37 ); + ++v35; + } + while ( v35 < 40 ); +} + +void __cdecl DRLG_L5Subs() +{ + signed int v0; // edi + int v1; // esi + unsigned char v2; // bl + int v3; // eax + signed int v4; // ecx + signed int v5; // [esp+Ch] [ebp-4h] + + v0 = 0; + do + { + v1 = v0 - 1; + v5 = 40; + do + { + if ( !random(0, 4) ) + { + v2 = L5BTYPES[(unsigned char)dungeon[0][v1 + 1]]; + if ( v2 ) + { + if ( !mydflags[0][v1 + 1] ) + { + v3 = random(0, 16); + v4 = -1; + if ( v3 >= 0 ) + { + do + { + if ( ++v4 == 206 ) + v4 = 0; + if ( v2 == L5BTYPES[v4] ) + --v3; + } + while ( v3 >= 0 ); + if ( v4 == 89 ) + { + if ( L5BTYPES[(unsigned char)dungeon[0][v1]] == 79 && !mydflags[0][v1] ) + { + dungeon[0][v1] = 90; + goto LABEL_22; + } + v4 = 79; + } + if ( v4 == 91 ) + { + if ( L5BTYPES[(unsigned char)dungeon[1][v1 + 1]] != 80 || mydflags[1][v1 + 1] ) + _LOBYTE(v4) = 80; + else + dungeon[1][v1 + 1] = 92; + } + } +LABEL_22: + dungeon[0][v1 + 1] = v4; + goto LABEL_23; + } + } + } +LABEL_23: + v1 += 40; + --v5; + } + while ( v5 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl L5FillChambers() +{ + int v0; // edi + int v1; // edi + int v2; // edx + int v3; // ecx + int v4; // edi + signed int v5; // [esp-4h] [ebp-10h] + + v0 = 1; + if ( HR1 ) + DRLG_L5GChamber(0, 14, 0, 0, 0, 1); + if ( !HR2 ) + goto LABEL_16; + if ( HR1 ) + { + if ( !HR3 ) + DRLG_L5GChamber(14, 14, 0, 0, 1, 0); + if ( HR1 ) + goto LABEL_111; + } + if ( HR3 ) + DRLG_L5GChamber(14, 14, 0, 0, 0, 1); + if ( HR1 ) + { +LABEL_111: + if ( HR3 ) + DRLG_L5GChamber(14, 14, 0, 0, 1, 1); + if ( HR1 ) + { +LABEL_16: + if ( !HR3 ) + goto LABEL_18; + goto LABEL_17; + } + } + if ( !HR3 ) + { + DRLG_L5GChamber(14, 14, 0, 0, 0, 0); + goto LABEL_16; + } +LABEL_17: + DRLG_L5GChamber(28, 14, 0, 0, 1, 0); +LABEL_18: + if ( HR1 ) + { + if ( !HR2 ) + goto LABEL_24; + DRLG_L5GHall(12, 18, 14, 18); + } + if ( HR2 && HR3 ) + DRLG_L5GHall(26, 18, 28, 18); +LABEL_24: + if ( HR1 && !HR2 && HR3 ) + DRLG_L5GHall(12, 18, 28, 18); + if ( VR1 ) + DRLG_L5GChamber(14, 0, 0, 1, 0, 0); + if ( !VR2 ) + goto LABEL_43; + if ( VR1 ) + { + if ( !VR3 ) + DRLG_L5GChamber(14, 14, 1, 0, 0, 0); + if ( VR1 ) + goto LABEL_112; + } + if ( VR3 ) + DRLG_L5GChamber(14, 14, 0, 1, 0, 0); + if ( VR1 ) + { +LABEL_112: + if ( VR3 ) + DRLG_L5GChamber(14, 14, 1, 1, 0, 0); + if ( VR1 ) + { +LABEL_43: + if ( !VR3 ) + goto LABEL_45; + goto LABEL_44; + } + } + if ( !VR3 ) + { + DRLG_L5GChamber(14, 14, 0, 0, 0, 0); + goto LABEL_43; + } +LABEL_44: + DRLG_L5GChamber(14, 28, 1, 0, 0, 0); +LABEL_45: + if ( VR1 ) + { + if ( !VR2 ) + goto LABEL_51; + DRLG_L5GHall(18, 12, 18, 14); + } + if ( VR2 && VR3 ) + DRLG_L5GHall(18, 26, 18, 28); +LABEL_51: + if ( VR1 && !VR2 && VR3 ) + DRLG_L5GHall(18, 12, 18, 28); + if ( setloadflag ) + { + if ( !VR1 && !VR2 && !VR3 ) + { + if ( HR1 ) + goto LABEL_113; + if ( HR2 && HR3 ) + { + if ( random(0, 2) ) + v0 = 2; + if ( HR1 ) + { +LABEL_113: + if ( HR2 && !HR3 && random(0, 2) ) + v0 = 0; + if ( HR1 ) + { + if ( !HR2 && HR3 ) + v0 = random(0, 2) != 0 ? 0 : 2; + if ( HR1 && HR2 ) + { + if ( HR3 ) + v0 = random(0, 3); + } + } + } + } + if ( !v0 ) + { + v3 = 2; + v2 = 16; + goto LABEL_108; + } + v1 = v0 - 1; + if ( v1 ) + { + if ( v1 != 1 ) + return; + v2 = 16; + v5 = 30; + goto LABEL_107; + } +LABEL_81: + v3 = 16; + v2 = 16; +LABEL_108: + DRLG_L5SetRoom(v3, v2); + return; + } + if ( VR1 ) + goto LABEL_114; + if ( VR2 && VR3 ) + { + if ( random(0, 2) ) + v0 = 2; + if ( VR1 ) + { +LABEL_114: + if ( VR2 && !VR3 && random(0, 2) ) + v0 = 0; + if ( VR1 ) + { + if ( !VR2 && VR3 ) + v0 = random(0, 2) != 0 ? 0 : 2; + if ( VR1 && VR2 && VR3 ) + v0 = random(0, 3); + } + } + } + if ( v0 ) + { + v4 = v0 - 1; + if ( !v4 ) + goto LABEL_81; + if ( v4 != 1 ) + return; + v2 = 30; + } + else + { + v2 = 2; + } + v5 = 16; +LABEL_107: + v3 = v5; + goto LABEL_108; + } +} +// 5276A4: using guessed type int setloadflag; + +void __fastcall DRLG_L5GChamber(int sx, int sy, bool topflag, bool bottomflag, bool leftflag, bool rightflag) +{ + int v6; // eax + int v7; // edx + int v8; // eax + char *v9; // eax + int v10; // eax + int v11; // ecx + int v12; // eax + char *v13; // eax + signed int v14; // edi + int v15; // eax + int v16; // edx + int v17; // ecx + signed int v18; // esi + + if ( topflag == 1 ) + { + v6 = sy + 40 * sx; + dungeon[2][v6] = 12; + dungeon[3][v6] = 12; + dungeon[4][v6] = 3; + dungeon[7][v6] = 9; + dungeon[8][v6] = 12; + dungeon[9][v6] = 2; + } + if ( bottomflag == 1 ) + { + v7 = sy + 11; + v8 = v7 + 40 * sx; + dungeon[2][v8] = 10; + dungeon[3][v8] = 12; + dungeon[4][v8] = 8; + dungeon[7][v8] = 5; + dungeon[8][v8] = 12; + v9 = &dungeon[9][v8]; + if ( *v9 != 4 ) + *v9 = 21; + sy = v7 - 11; + } + if ( leftflag == 1 ) + { + v10 = sy + 40 * sx; + dungeon[0][v10 + 2] = 11; + dungeon[0][v10 + 3] = 11; + dungeon[0][v10 + 4] = 3; + dungeon[0][v10 + 7] = 8; + dungeon[0][v10 + 8] = 11; + dungeon[0][v10 + 9] = 1; + } + if ( rightflag == 1 ) + { + v11 = sx + 11; + v12 = sy + 40 * v11; + dungeon[0][v12 + 2] = 14; + dungeon[0][v12 + 3] = 11; + dungeon[0][v12 + 4] = 9; + dungeon[0][v12 + 7] = 5; + dungeon[0][v12 + 8] = 11; + v13 = &dungeon[0][v12 + 9]; + if ( *v13 != 4 ) + *v13 = 21; + sx = v11 - 11; + } + v14 = 10; + v15 = sy + 40 * sx; + v16 = v15 + 1; + do + { + v17 = v16; + v18 = 10; + do + { + mydflags[1][v17] |= 0x40u; + dungeon[1][v17] = 13; + v17 += 40; + --v18; + } + while ( v18 ); + ++v16; + --v14; + } + while ( v14 ); + dungeon[4][v15 + 4] = 15; + dungeon[7][v15 + 4] = 15; + dungeon[4][v15 + 7] = 15; + dungeon[7][v15 + 7] = 15; +} + +void __fastcall DRLG_L5GHall(int x1, int y1, int x2, int y2) +{ + int v4; // eax + char *v5; // edx + int v6; // eax + char *v7; // ecx + + if ( y1 == y2 ) + { + if ( x1 < x2 ) + { + v4 = x2 - x1; + v5 = &dungeon[x1][y1 + 3]; + do + { + *(v5 - 3) = 12; + *v5 = 12; + v5 += 40; + --v4; + } + while ( v4 ); + } + } + else + { + v6 = y1; + if ( y1 < y2 ) + { + v7 = dungeon[x1 + 3]; + do + { + v7[v6 - 120] = 11; + v7[v6++] = 11; + } + while ( v6 < y2 ); + } + } +} + +void __fastcall DRLG_L5SetRoom(int rx1, int ry1) +{ + int v2; // edi + int v3; // esi + int v4; // eax + char v5; // bl + int v6; // [esp+8h] [ebp-Ch] + char *v7; // [esp+Ch] [ebp-8h] + int v8; // [esp+10h] [ebp-4h] + + v8 = 0; + v2 = *((unsigned char *)pSetPiece + 2); + v3 = *(unsigned char *)pSetPiece; + setpc_x = rx1; + setpc_y = ry1; + setpc_w = v3; + setpc_h = v2; + v7 = (char *)pSetPiece + 4; + if ( v2 > 0 ) + { + do + { + if ( v3 > 0 ) + { + v6 = v3; + v4 = ry1 + v8 + 40 * rx1; + do + { + v5 = *v7; + if ( *v7 ) + { + mydflags[0][v4] |= 0x80u; + dungeon[0][v4] = v5; + } + else + { + dungeon[0][v4] = 13; + } + v7 += 2; + v4 += 40; + --v6; + } + while ( v6 ); + } + ++v8; + } + while ( v8 < v2 ); + } +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __cdecl DRLG_L5FloodTVal() +{ + int v0; // ebx + int v1; // esi + char *v2; // edi + _BYTE *v3; // [esp+Ch] [ebp-Ch] + signed int x; // [esp+10h] [ebp-8h] + signed int tx; // [esp+14h] [ebp-4h] + + v0 = 16; + v1 = 0; + do + { + tx = 0; + x = 16; + v2 = &dung_map[16][v0]; + v3 = (unsigned char *)dungeon + v1; + do + { + if ( *v3 == 13 && !*v2 ) + { + DRLG_L5FTVR(tx, v1, x, v0, 0); + ++TransVal; + } + x += 2; + v3 += 40; + v2 += 224; + ++tx; + } + while ( tx < 40 ); + v0 += 2; + ++v1; + } + while ( v1 < 40 ); +} +// 5A5590: using guessed type char TransVal; + +void __fastcall DRLG_L5FTVR(int i, int j, int x, int y, int d) +{ + int v5; // ebx + int v6; // esi + int v7; // edi + int v8; // edx + int v9; // ecx + int v10; // ebx + int v11; // eax + int v12; // edi + char v13; // al + char v14; // al + int v15; // ecx + int v16; // ecx + int v17; // ecx + int v18; // ecx + int v19; // [esp+Ch] [ebp-14h] + int v20; // [esp+10h] [ebp-10h] + int v21; // [esp+14h] [ebp-Ch] + int tya; // [esp+18h] [ebp-8h] + int txa; // [esp+1Ch] [ebp-4h] + int ya; // [esp+2Ch] [ebp+Ch] + + v5 = x; + v6 = y; + v7 = j; + v8 = i; + v9 = 112 * x + y; + tya = v7; + v21 = v8; + if ( !dung_map[0][v9] ) + { + v19 = x; + txa = v8 - 1; + v10 = x - 2; + v11 = 40 * v8; + ya = v7 - 1; + v12 = v6 - 2; + for ( v20 = 40 * v8; dungeon[0][v11 + tya] == 13; v11 = v20 ) + { + v13 = TransVal; + dung_map[0][v9] = TransVal; + dung_map[1][v9] = v13; + dung_map[0][v9 + 1] = v13; + dung_map[1][v9 + 1] = v13; + DRLG_L5FTVR(txa + 2, tya, v10 + 4, v6, 1); + DRLG_L5FTVR(txa, tya, v10, v6, 2); + DRLG_L5FTVR(v21, ya + 2, x, v12 + 4, 3); + DRLG_L5FTVR(v21, ya, x, v12, 4); + DRLG_L5FTVR(txa, ya, v10, v12, 5); + DRLG_L5FTVR(txa + 2, ya, v10 + 4, v12, 6); + DRLG_L5FTVR(txa, ya + 2, v10, v12 + 4, 7); + v19 += 2; + v20 += 40; + d = 8; + x += 2; + v6 += 2; + v12 += 2; + v10 += 2; + ++tya; + ++ya; + ++v21; + ++txa; + v9 = v19 * 112 + v6; + if ( dung_map[v19][v6] ) + break; + } + v5 = x; + } + v14 = TransVal; + if ( d == 1 ) + { + v15 = v6 + 112 * v5; + dung_map[0][v15] = TransVal; + dung_map[0][v15 + 1] = v14; + } + if ( d == 2 ) + { + v16 = v6 + 112 * v5; + dung_map[1][v16] = v14; + dung_map[1][v16 + 1] = v14; + } + if ( d == 3 ) + { + v17 = v6 + 112 * v5; + dung_map[0][v17] = v14; + dung_map[1][v17] = v14; + } + if ( d == 4 ) + { + v18 = v6 + 112 * v5; + dung_map[0][v18 + 1] = v14; + dung_map[1][v18 + 1] = v14; + } + if ( d == 5 ) + dung_map[v5 + 1][v6 + 1] = v14; + if ( d == 6 ) + dung_map[v5][v6 + 1] = v14; + if ( d == 7 ) + dung_map[v5 + 1][v6] = v14; + if ( d == 8 ) + dung_map[v5][v6] = v14; +} +// 5A5590: using guessed type char TransVal; + +void __cdecl DRLG_L5TransFix() +{ + signed int v0; // esi + char *v1; // eax + char *v2; // ecx + signed int v3; // edi + char v4; // bl + char v5; // dl + char v6; // dl + char v7; // dl + char v8; // dl + char v9; // dl + char *v10; // [esp+Ch] [ebp-4h] + + v0 = 0; + v10 = &dung_map[16][16]; /* check */ + do + { + v1 = v10; + v2 = (char *)dungeon + v0; + v3 = 40; + do + { + v4 = *v2; + if ( *v2 == 23 && *(v2 - 1) == 18 ) + { + v5 = *v1; + v1[112] = *v1; + v1[113] = v5; + } + if ( v4 == 24 && v2[40] == 19 ) + { + v6 = *v1; + v1[1] = *v1; + v1[113] = v6; + } + if ( v4 == 18 ) + { + v7 = *v1; + v1[112] = *v1; + v1[113] = v7; + } + if ( v4 == 19 ) + { + v8 = *v1; + v1[1] = *v1; + v1[113] = v8; + } + if ( v4 == 20 ) + { + v9 = *v1; + v1[112] = *v1; + v1[1] = v9; + v1[113] = v9; + } + v1 += 224; + v2 += 40; + --v3; + } + while ( v3 ); + v10 += 2; + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl DRLG_L5DirtFix() +{ + signed int v0; // ecx + char *v1; // eax + signed int v2; // edx + + v0 = 0; + do + { + v1 = (char *)dungeon + v0; + v2 = 40; + do + { + if ( *v1 == 21 && v1[40] != 19 ) + *v1 = -54; + if ( *v1 == 19 && v1[40] != 19 ) + *v1 = -56; + if ( *v1 == 24 && v1[40] != 19 ) + *v1 = -51; + if ( *v1 == 18 && v1[1] != 18 ) + *v1 = -57; + if ( *v1 == 21 && v1[1] != 18 ) + *v1 = -54; + if ( *v1 == 23 && v1[1] != 18 ) + *v1 = -52; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl DRLG_L5CornerFix() +{ + signed int v0; // esi + signed int v1; // eax + signed int v2; // edi + + v0 = 1; + do + { + v1 = v0; + v2 = 38; + do + { + if ( mydflags[1][v1] >= 0 && dungeon[1][v1] == 17 && dungeon[0][v1] == 13 && dungeon[0][v1 + 39] == 1 ) + { + mydflags[0][v1 + 39] &= 0x80u; + dungeon[1][v1] = 16; + } + if ( dungeon[1][v1] == -54 && dungeon[2][v1] == 13 && dungeon[1][v1 + 1] == 1 ) + dungeon[1][v1] = 8; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 39 ); +} diff --git a/Source/drlg_l1.h b/Source/drlg_l1.h new file mode 100644 index 000000000..cccf6c72e --- /dev/null +++ b/Source/drlg_l1.h @@ -0,0 +1,68 @@ +//HEADER_GOES_HERE +#ifndef __DRLG_L1_H__ +#define __DRLG_L1_H__ + +extern char L5dungeon[80][80]; +extern char mydflags[40][40]; +extern int setloadflag; // weak +extern int HR1; +extern int HR2; +extern int HR3; +extern int VR1; +extern int VR2; +extern int VR3; +extern void *pSetPiece; // idb + +void __cdecl DRLG_Init_Globals(); +void __fastcall LoadL1Dungeon(char *sFileName, int vx, int vy); +void __cdecl DRLG_L1Floor(); +void __cdecl DRLG_L1Pass3(); +void __cdecl DRLG_InitL1Vals(); +void __fastcall LoadPreL1Dungeon(char *sFileName, int vx, int vy); +void __fastcall CreateL5Dungeon(int rseed, int entry); +void __cdecl DRLG_LoadL1SP(); +void __cdecl DRLG_FreeL1SP(); +void __fastcall DRLG_L5(int entry); +void __fastcall DRLG_PlaceDoor(int x, int y); +void __cdecl DRLG_L1Shadows(); +int __fastcall DRLG_PlaceMiniSet(const unsigned char *miniset, int tmin, int tmax, int cx, int cy, bool setview, int noquad, int ldir); +void __cdecl InitL5Dungeon(); +void __cdecl L5ClearFlags(); +void __cdecl L5firstRoom(); +void __fastcall L5drawRoom(int x, int y, int w, int h); +void __fastcall L5roomGen(int x, int y, int w, int h, BOOL dir); +bool __fastcall L5checkRoom(int x, int y, int width, int height); +int __cdecl L5GetArea(); +void __cdecl L5makeDungeon(); +void __cdecl L5makeDmt(); +void __cdecl L5AddWall(); +int __fastcall L5HWallOk(int i, int j); +int __fastcall L5VWallOk(int i, int j); +void __fastcall L5HorizWall(int i, int j, char p, int dx); +void __fastcall L5VertWall(int i, int j, char p, int dy); +void __cdecl L5tileFix(); +void __cdecl DRLG_L5Subs(); +void __cdecl L5FillChambers(); +void __fastcall DRLG_L5GChamber(int sx, int sy, bool topflag, bool bottomflag, bool leftflag, bool rightflag); +void __fastcall DRLG_L5GHall(int x1, int y1, int x2, int y2); +void __fastcall DRLG_L5SetRoom(int rx1, int ry1); +void __cdecl DRLG_L5FloodTVal(); +void __fastcall DRLG_L5FTVR(int i, int j, int x, int y, int d); +void __cdecl DRLG_L5TransFix(); +void __cdecl DRLG_L5DirtFix(); +void __cdecl DRLG_L5CornerFix(); + +/* rdata */ +extern const ShadowStruct SPATS[37]; +extern const unsigned char BSTYPES[206]; +extern const unsigned char L5BTYPES[206]; +extern const unsigned char STAIRSUP[]; +extern const unsigned char L5STAIRSUP[]; +extern const unsigned char STAIRSDOWN[]; +extern const unsigned char LAMPS[]; +extern const unsigned char PWATERIN[]; + +/* data */ +extern unsigned char L5ConvTbl[16]; + +#endif /* __DRLG_L1_H__ */ diff --git a/Source/drlg_l2.cpp b/Source/drlg_l2.cpp new file mode 100644 index 000000000..c9175f14f --- /dev/null +++ b/Source/drlg_l2.cpp @@ -0,0 +1,3376 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int nSx1; +int nSx2; // weak +int nSy1; +int nSy2; // weak +int nRoomCnt; +char predungeon[40][40]; +ROOMNODE RoomList[81]; +HALLNODE *pHallList; +#endif + +int Area_Min = 2; // weak +int Room_Max = 10; // weak +int Room_Min = 4; // weak +int Dir_Xadd[5] = { 0, 0, 1, 0, -1 }; +int Dir_Yadd[5] = { 0, -1, 0, 1, 0 }; +ShadowStruct SPATSL2[2] = { { 6u, 3u, 0u, 3u, 48u, 0u, 50u }, { 9u, 3u, 0u, 3u, 48u, 0u, 50u } }; +//short word_48489A = 0; // weak +unsigned char BTYPESL2[161] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 17, 18, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 2, 2, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +unsigned char BSTYPESL2[161] = { 0, 1, 2, 3, 0, 0, 6, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 6, 6, 6, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 2, 2, 2, 0, 0, 0, 1, 1, 1, 1, 6, 2, 2, 2, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 2, 2, 3, 3, 3, 3, 1, 1, 2, 2, 3, 3, 3, 3, 1, 1, 3, 3, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +unsigned char VARCH1[] = { 2, 4, 3, 0, 3, 1, 3, 4, 0, 7, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH2[] = { 2, 4, 3, 0, 3, 1, 3, 4, 0, 8, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH3[] = { 2, 4, 3, 0, 3, 1, 3, 4, 0, 6, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH4[] = { 2, 4, 3, 0, 3, 1, 3, 4, 0, 9, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH5[] = { 2, 4, 3, 0, 3, 1, 3, 4, 0, 14, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH6[] = { 2, 4, 3, 0, 3, 1, 3, 4, 0, 13, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH7[] = { 2, 4, 3, 0, 3, 1, 3, 4, 0, 16, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH8[] = { 2, 4, 3, 0, 3, 1, 3, 4, 0, 15, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH9[] = { 2, 4, 3, 0, 3, 8, 3, 4, 0, 7, 48, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH10[] = { 2, 4, 3, 0, 3, 8, 3, 4, 0, 8, 48, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH11[] = { 2, 4, 3, 0, 3, 8, 3, 4, 0, 6, 48, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH12[] = { 2, 4, 3, 0, 3, 8, 3, 4, 0, 9, 48, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH13[] = { 2, 4, 3, 0, 3, 8, 3, 4, 0, 14, 48, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH14[] = { 2, 4, 3, 0, 3, 8, 3, 4, 0, 13, 48, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH15[] = { 2, 4, 3, 0, 3, 8, 3, 4, 0, 16, 48, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH16[] = { 2, 4, 3, 0, 3, 8, 3, 4, 0, 15, 48, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH17[] = { 2, 3, 2, 7, 3, 4, 0, 7, 141, 39, 47, 44, 0, 0 }; +unsigned char VARCH18[] = { 2, 3, 2, 7, 3, 4, 0, 8, 141, 39, 47, 44, 0, 0 }; +unsigned char VARCH19[] = { 2, 3, 2, 7, 3, 4, 0, 6, 141, 39, 47, 44, 0, 0 }; +unsigned char VARCH20[] = { 2, 3, 2, 7, 3, 4, 0, 9, 141, 39, 47, 44, 0, 0 }; +unsigned char VARCH21[] = { 2, 3, 2, 7, 3, 4, 0, 14, 141, 39, 47, 44, 0, 0 }; +unsigned char VARCH22[] = { 2, 3, 2, 7, 3, 4, 0, 13, 141, 39, 47, 44, 0, 0 }; +unsigned char VARCH23[] = { 2, 3, 2, 7, 3, 4, 0, 16, 141, 39, 47, 44, 0, 0 }; +unsigned char VARCH24[] = { 2, 3, 2, 7, 3, 4, 0, 15, 141, 39, 47, 44, 0, 0 }; +unsigned char VARCH25[] = { 2, 4, 3, 0, 3, 4, 3, 1, 0, 7, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH26[] = { 2, 4, 3, 0, 3, 4, 3, 1, 0, 8, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH27[] = { 2, 4, 3, 0, 3, 4, 3, 1, 0, 6, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH28[] = { 2, 4, 3, 0, 3, 4, 3, 1, 0, 9, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH29[] = { 2, 4, 3, 0, 3, 4, 3, 1, 0, 14, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH30[] = { 2, 4, 3, 0, 3, 4, 3, 1, 0, 13, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH31[] = { 2, 4, 3, 0, 3, 4, 3, 1, 0, 16, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH32[] = { 2, 4, 3, 0, 3, 4, 3, 1, 0, 15, 48, 0, 51, 39, 47, 44, 0, 0 }; +unsigned char VARCH33[] = { 2, 4, 2, 0, 3, 8, 3, 4, 0, 7, 142, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH34[] = { 2, 4, 2, 0, 3, 8, 3, 4, 0, 8, 142, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH35[] = { 2, 4, 2, 0, 3, 8, 3, 4, 0, 6, 142, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH36[] = { 2, 4, 2, 0, 3, 8, 3, 4, 0, 9, 142, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH37[] = { 2, 4, 2, 0, 3, 8, 3, 4, 0, 14, 142, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH38[] = { 2, 4, 2, 0, 3, 8, 3, 4, 0, 13, 142, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH39[] = { 2, 4, 2, 0, 3, 8, 3, 4, 0, 16, 142, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char VARCH40[] = { 2, 4, 2, 0, 3, 8, 3, 4, 0, 15, 142, 0, 51, 42, 47, 44, 0, 0 }; +unsigned char HARCH1[] = { 3, 2, 3, 3, 0, 2, 5, 9, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH2[] = { 3, 2, 3, 3, 0, 2, 5, 6, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH3[] = { 3, 2, 3, 3, 0, 2, 5, 8, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH4[] = { 3, 2, 3, 3, 0, 2, 5, 7, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH5[] = { 3, 2, 3, 3, 0, 2, 5, 15, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH6[] = { 3, 2, 3, 3, 0, 2, 5, 16, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH7[] = { 3, 2, 3, 3, 0, 2, 5, 13, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH8[] = { 3, 2, 3, 3, 0, 2, 5, 14, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH9[] = { 3, 2, 3, 3, 0, 8, 5, 9, 49, 46, 0, 43, 45, 0 }; +unsigned char HARCH10[] = { 3, 2, 3, 3, 0, 8, 5, 6, 49, 46, 0, 43, 45, 0 }; +unsigned char HARCH11[] = { 3, 2, 3, 3, 0, 8, 5, 8, 49, 46, 0, 43, 45, 0 }; +unsigned char HARCH12[] = { 3, 2, 3, 3, 0, 8, 5, 7, 49, 46, 0, 43, 45, 0 }; +unsigned char HARCH13[] = { 3, 2, 3, 3, 0, 8, 5, 15, 49, 46, 0, 43, 45, 0 }; +unsigned char HARCH14[] = { 3, 2, 3, 3, 0, 8, 5, 16, 49, 46, 0, 43, 45, 0 }; +unsigned char HARCH15[] = { 3, 2, 3, 3, 0, 8, 5, 13, 49, 46, 0, 43, 45, 0 }; +unsigned char HARCH16[] = { 3, 2, 3, 3, 0, 8, 5, 14, 49, 46, 0, 43, 45, 0 }; +unsigned char HARCH17[] = { 3, 2, 1, 3, 0, 8, 5, 9, 140, 46, 0, 43, 45, 0 }; +unsigned char HARCH18[] = { 3, 2, 1, 3, 0, 8, 5, 6, 140, 46, 0, 43, 45, 0 }; +unsigned char HARCH19[] = { 3, 2, 1, 3, 0, 8, 5, 8, 140, 46, 0, 43, 45, 0 }; +unsigned char HARCH20[] = { 3, 2, 1, 3, 0, 8, 5, 7, 140, 46, 0, 43, 45, 0 }; +unsigned char HARCH21[] = { 3, 2, 1, 3, 0, 8, 5, 15, 140, 46, 0, 43, 45, 0 }; +unsigned char HARCH22[] = { 3, 2, 1, 3, 0, 8, 5, 16, 140, 46, 0, 43, 45, 0 }; +unsigned char HARCH23[] = { 3, 2, 1, 3, 0, 8, 5, 13, 140, 46, 0, 43, 45, 0 }; +unsigned char HARCH24[] = { 3, 2, 1, 3, 0, 8, 5, 14, 140, 46, 0, 43, 45, 0 }; +unsigned char HARCH25[] = { 3, 2, 3, 3, 0, 5, 2, 9, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH26[] = { 3, 2, 3, 3, 0, 5, 2, 6, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH27[] = { 3, 2, 3, 3, 0, 5, 2, 8, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH28[] = { 3, 2, 3, 3, 0, 5, 2, 7, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH29[] = { 3, 2, 3, 3, 0, 5, 2, 15, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH30[] = { 3, 2, 3, 3, 0, 5, 2, 16, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH31[] = { 3, 2, 3, 3, 0, 5, 2, 13, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH32[] = { 3, 2, 3, 3, 0, 5, 2, 14, 49, 46, 0, 40, 45, 0 }; +unsigned char HARCH33[] = { 3, 2, 1, 3, 0, 9, 5, 9, 140, 46, 0, 40, 45, 0 }; +unsigned char HARCH34[] = { 3, 2, 1, 3, 0, 9, 5, 6, 140, 46, 0, 40, 45, 0 }; +unsigned char HARCH35[] = { 3, 2, 1, 3, 0, 9, 5, 8, 140, 46, 0, 40, 45, 0 }; +unsigned char HARCH36[] = { 3, 2, 1, 3, 0, 9, 5, 7, 140, 46, 0, 40, 45, 0 }; +unsigned char HARCH37[] = { 3, 2, 1, 3, 0, 9, 5, 15, 140, 46, 0, 40, 45, 0 }; +unsigned char HARCH38[] = { 3, 2, 1, 3, 0, 9, 5, 16, 140, 46, 0, 40, 45, 0 }; +unsigned char HARCH39[] = { 3, 2, 1, 3, 0, 9, 5, 13, 140, 46, 0, 40, 45, 0 }; +unsigned char HARCH40[] = { 3, 2, 1, 3, 0, 9, 5, 14, 140, 46, 0, 40, 45, 0 }; +unsigned char USTAIRS[] = { 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 72, 77, 0, 0, 76, 0, 0, 0, 0, 0, 0 }; +unsigned char DSTAIRS[] = { 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 48, 71, 0, 0, 50, 78, 0, 0, 0, 0, 0 }; +unsigned char WARPSTAIRS[] = { 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 158, 160, 0, 0, 159, 0, 0, 0, 0, 0, 0 }; +unsigned char CRUSHCOL[] = { 3, 3, 3, 1, 3, 2, 6, 3, 3, 3, 3, 0, 0, 0, 0, 83, 0, 0, 0, 0 }; +unsigned char BIG1[] = { 2, 2, 3, 3, 3, 3, 113, 0, 112, 0 }; +unsigned char BIG2[] = { 2, 2, 3, 3, 3, 3, 114, 115, 0, 0 }; +unsigned char BIG3[] = { 1, 2, 1, 1, 117, 116 }; +unsigned char BIG4[] = { 2, 1, 2, 2, 118, 119 }; +unsigned char BIG5[] = { 2, 2, 3, 3, 3, 3, 120, 122, 121, 123 }; +unsigned char BIG6[] = { 1, 2, 1, 1, 125, 124 }; +unsigned char BIG7[] = { 2, 1, 2, 2, 126, 127 }; +unsigned char BIG8[] = { 2, 2, 3, 3, 3, 3, 128, 130, 129, 131 }; +unsigned char BIG9[] = { 2, 2, 1, 3, 1, 3, 133, 135, 132, 134 }; +unsigned char BIG10[] = { 2, 2, 2, 2, 3, 3, 136, 137, 3, 3 }; +unsigned char RUINS1[] = { 1, 1, 1, 80 }; +unsigned char RUINS2[] = { 1, 1, 1, 81 }; +unsigned char RUINS3[] = { 1, 1, 1, 82 }; +unsigned char RUINS4[] = { 1, 1, 2, 84 }; +unsigned char RUINS5[] = { 1, 1, 2, 85 }; +unsigned char RUINS6[] = { 1, 1, 2, 86 }; +unsigned char RUINS7[] = { 1, 1, 8, 87 }; +unsigned char PANCREAS1[] = { 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0 }; +unsigned char PANCREAS2[] = { 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0 }; +unsigned char CTRDOOR1[] = { 3, 3, 3, 1, 3, 0, 4, 0, 0, 9, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0 }; +unsigned char CTRDOOR2[] = { 3, 3, 3, 1, 3, 0, 4, 0, 0, 8, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0 }; +unsigned char CTRDOOR3[] = { 3, 3, 3, 1, 3, 0, 4, 0, 0, 6, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0 }; +unsigned char CTRDOOR4[] = { 3, 3, 3, 1, 3, 0, 4, 0, 0, 7, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0 }; +unsigned char CTRDOOR5[] = { 3, 3, 3, 1, 3, 0, 4, 0, 0, 15, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0 }; +unsigned char CTRDOOR6[] = { 3, 3, 3, 1, 3, 0, 4, 0, 0, 13, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0 }; +unsigned char CTRDOOR7[] = { 3, 3, 3, 1, 3, 0, 4, 0, 0, 16, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0 }; +unsigned char CTRDOOR8[] = { 3, 3, 3, 1, 3, 0, 4, 0, 0, 14, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0 }; +int Patterns[100][10] = +{ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 }, + { 0, 0, 0, 0, 2, 0, 0, 0, 0, 3 }, + { 0, 7, 0, 0, 1, 0, 0, 5, 0, 2 }, + { 0, 5, 0, 0, 1, 0, 0, 7, 0, 2 }, + { 0, 0, 0, 7, 1, 5, 0, 0, 0, 1 }, + { 0, 0, 0, 5, 1, 7, 0, 0, 0, 1 }, + { 0, 1, 0, 0, 3, 0, 0, 1, 0, 4 }, + { 0, 0, 0, 1, 3, 1, 0, 0, 0, 5 }, + { 0, 6, 0, 6, 1, 0, 0, 0, 0, 6 }, + { 0, 6, 0, 0, 1, 6, 0, 0, 0, 9 }, + { 0, 0, 0, 6, 1, 0, 0, 6, 0, 7 }, + { 0, 0, 0, 0, 1, 6, 0, 6, 0, 8 }, + { 0, 6, 0, 6, 6, 0, 8, 6, 0, 7 }, + { 0, 6, 8, 6, 6, 6, 0, 0, 0, 9 }, + { 0, 6, 0, 0, 6, 6, 0, 6, 8, 8 }, + { 6, 6, 6, 6, 6, 6, 0, 6, 0, 8 }, + { 2, 6, 6, 6, 6, 6, 0, 6, 0, 8 }, + { 7, 7, 7, 6, 6, 6, 0, 6, 0, 8 }, + { 6, 6, 2, 6, 6, 6, 0, 6, 0, 8 }, + { 6, 2, 6, 6, 6, 6, 0, 6, 0, 8 }, + { 2, 6, 6, 6, 6, 6, 0, 6, 0, 8 }, + { 6, 7, 7, 6, 6, 6, 0, 6, 0, 8 }, + { 4, 4, 6, 6, 6, 6, 2, 6, 2, 8 }, + { 2, 2, 2, 2, 6, 2, 2, 6, 2, 7 }, + { 2, 2, 2, 2, 6, 2, 6, 6, 6, 7 }, + { 2, 2, 6, 2, 6, 6, 2, 2, 6, 9 }, + { 2, 6, 2, 2, 6, 2, 2, 2, 2, 6 }, + { 2, 2, 2, 2, 6, 6, 2, 2, 2, 9 }, + { 2, 2, 2, 6, 6, 2, 2, 2, 2, 6 }, + { 2, 2, 0, 2, 6, 6, 2, 2, 0, 9 }, + { 0, 0, 0, 0, 4, 0, 0, 0, 0, 12 }, + { 0, 1, 0, 0, 1, 4, 0, 1, 0, 10 }, + { 0, 0, 0, 1, 1, 1, 0, 4, 0, 11 }, + { 0, 0, 0, 6, 1, 4, 0, 1, 0, 14 }, + { 0, 6, 0, 1, 1, 0, 0, 4, 0, 16 }, + { 0, 6, 0, 0, 1, 1, 0, 4, 0, 15 }, + { 0, 0, 0, 0, 1, 1, 0, 1, 4, 13 }, + { 8, 8, 8, 8, 1, 1, 0, 1, 1, 13 }, + { 8, 8, 4, 8, 1, 1, 0, 1, 1, 10 }, + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 11 }, + { 1, 1, 1, 1, 1, 1, 2, 2, 8, 2 }, + { 0, 1, 0, 1, 1, 4, 1, 1, 0, 16 }, + { 0, 0, 0, 1, 1, 1, 1, 1, 4, 11 }, + { 1, 1, 4, 1, 1, 1, 0, 2, 2, 2 }, + { 1, 1, 1, 1, 1, 1, 6, 2, 6, 2 }, + { 4, 1, 1, 1, 1, 1, 6, 2, 6, 2 }, + { 2, 2, 2, 1, 1, 1, 4, 1, 1, 11 }, + { 4, 1, 1, 1, 1, 1, 2, 2, 2, 2 }, + { 1, 1, 4, 1, 1, 1, 2, 2, 1, 2 }, + { 4, 1, 1, 1, 1, 1, 1, 2, 2, 2 }, + { 2, 2, 6, 1, 1, 1, 4, 1, 1, 11 }, + { 4, 1, 1, 1, 1, 1, 2, 2, 6, 2 }, + { 1, 2, 2, 1, 1, 1, 4, 1, 1, 11 }, + { 0, 1, 1, 0, 1, 1, 0, 1, 1, 10 }, + { 2, 1, 1, 3, 1, 1, 2, 1, 1, 14 }, + { 1, 1, 0, 1, 1, 2, 1, 1, 0, 1 }, + { 0, 4, 0, 1, 1, 1, 0, 1, 1, 14 }, + { 4, 1, 0, 1, 1, 0, 1, 1, 0, 1 }, + { 0, 1, 0, 4, 1, 1, 0, 1, 1, 15 }, + { 1, 1, 1, 1, 1, 1, 0, 2, 2, 2 }, + { 0, 1, 1, 2, 1, 1, 2, 1, 4, 10 }, + { 2, 1, 1, 1, 1, 1, 0, 4, 0, 16 }, + { 1, 1, 4, 1, 1, 2, 0, 1, 2, 1 }, + { 2, 1, 1, 2, 1, 1, 1, 1, 4, 10 }, + { 1, 1, 2, 1, 1, 2, 4, 1, 8, 1 }, + { 2, 1, 4, 1, 1, 1, 4, 4, 1, 16 }, + { 2, 1, 1, 1, 1, 1, 1, 1, 1, 16 }, + { 1, 1, 2, 1, 1, 1, 1, 1, 1, 15 }, + { 1, 1, 1, 1, 1, 1, 2, 1, 1, 14 }, + { 4, 1, 1, 1, 1, 1, 2, 1, 1, 14 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 2, 8 }, + { 0, 0, 0, 0, 255, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +void __cdecl InitDungeon() +{ + signed int v0; // edx + signed int v1; // eax + signed int v2; // ecx + + v0 = 0; + do + { + v1 = v0; + v2 = 40; + do + { + dflags[0][v1] = 0; + predungeon[0][v1] = 32; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl L2LockoutFix() +{ + signed int v0; // ecx + char *v1; // eax + signed int v2; // edx + signed int v3; // ecx + signed int v4; // edi + signed int v5; // eax + char *v6; // esi + signed int v7; // edx + char v8; // al + unsigned int v9; // ecx + signed int v10; // eax + char v11; // dl + signed int v12; // esi + char v13; // bl + char *v14; // edx + + v0 = 0; + do + { + v1 = (char *)dungeon + v0; + v2 = 40; + do + { + if ( *v1 == 4 && *(v1 - 40) != 3 ) + *v1 = 1; + if ( *v1 == 5 && *(v1 - 1) != 3 ) + *v1 = 2; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); + v3 = 1; + do + { + v4 = 1; + do + { + v5 = v4; + if ( dflags[v4][v3] >= 0 ) + { + v6 = &dungeon[v5][v3]; + if ( (*v6 == 2 || *v6 == 5) && *(v6 - 1) == 3 && dungeon[v5][v3 + 1] == 3 ) + { + v7 = 0; + while ( 1 ) + { + v8 = *v6; + if ( *v6 != 2 && v8 != 5 ) + break; + if ( *(v6 - 1) != 3 || v6[1] != 3 ) + break; + if ( v8 == 5 ) + v7 = 1; + ++v4; + v6 += 40; + } + if ( !v7 && dflags[v4 - 1][v3] >= 0 ) // dflags[-1][] + dungeon[v4 - 1][v3] = 5; // dungeon[-1][] + } + } + ++v4; + } + while ( v4 < 39 ); + ++v3; + } + while ( v3 < 39 ); + v9 = 1; + do + { + v10 = 1; + do + { + if ( dflags[v9][v10] >= 0 ) + { + v11 = dungeon[v9][v10]; + if ( (v11 == 1 || v11 == 4) + && dungeon[v9 - 1][v10] == 3 // dungeon[-1][] + && dungeon[v9 + 1][v10] == 3 ) + { + v12 = 0; + while ( 1 ) + { + v13 = dungeon[v9][v10]; + if ( v13 != 1 && v13 != 4 ) + break; + v14 = &dungeon[v9 + 1][v10]; + if ( *(v14 - 80) != 3 || *v14 != 3 ) + break; + if ( v13 == 4 ) + v12 = 1; + ++v10; + } + if ( !v12 && dflags[v9][v10 - 1] >= 0 ) // dflags[][-1] + dungeon[v9][v10 - 1] = 4; // dungeon[][-1] + } + } + ++v10; + } + while ( v10 < 39 ); + ++v9; + } + while ( v9 < 39 ); +} + +void __cdecl L2DoorFix() +{ + signed int v0; // ecx + char *v1; // eax + signed int v2; // edx + + v0 = 1; + do + { + v1 = &dungeon[1][v0]; + v2 = 39; + do + { + if ( *v1 == 4 && *(v1 - 1) == 3 ) + *v1 = 7; + if ( *v1 == 5 && *(v1 - 40) == 3 ) + *v1 = 9; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __fastcall LoadL2Dungeon(char *sFileName, int vx, int vy) +{ + char *v3; // esi + unsigned char *v4; // edi + signed int v5; // edx + signed int v6; // eax + signed int v7; // ecx + int v8; // esi + int v9; // eax + int v10; // ebx + int v11; // edi + char *v12; // eax + int v13; // ecx + char v14; // dl + signed int v15; // ecx + _BYTE *v16; // eax + signed int v17; // edx + int v18; // ebx + int (*v19)[112]; // esi + char *v20; // ecx + signed int v21; // edi + int v22; // edx + char v23; // al + int v24; // ecx + int (*v25)[112]; // edi + char *v26; // eax + int (*v27)[112]; // edx + signed int v28; // ebx + int v29; // esi + int v30; // [esp+Ch] [ebp-Ch] + char *ptr; // [esp+10h] [ebp-8h] + int v32; // [esp+14h] [ebp-4h] + int (*v33)[112]; // [esp+14h] [ebp-4h] + + v30 = vx; + v3 = sFileName; + InitDungeon(); + DRLG_InitTrans(); + v4 = LoadFileInMem(v3, 0); + v5 = 0; + ptr = (char *)v4; + do + { + v6 = v5; + v7 = 40; + do + { + dflags[0][v6] = 0; + dungeon[0][v6] = 12; + v6 += 40; + --v7; + } + while ( v7 ); + ++v5; + } + while ( v5 < 40 ); + v8 = *v4; + v9 = (int)(v4 + 2); + v10 = 0; + v11 = v4[2]; + v12 = (char *)(v9 + 2); + if ( v11 > 0 ) + { + do + { + if ( v8 > 0 ) + { + v13 = v10; + v32 = v8; + do + { + v14 = *v12; + if ( *v12 ) + { + dflags[0][v13] |= 0x80u; + dungeon[0][v13] = v14; + } + else + { + dungeon[0][v13] = 3; + } + v13 += 40; + v12 += 2; + --v32; + } + while ( v32 ); + } + ++v10; + } + while ( v10 < v11 ); + } + v15 = 0; + do + { + v16 = (unsigned char *)dungeon + v15; + v17 = 40; + do + { + if ( !*v16 ) + *v16 = 12; + v16 += 40; + --v17; + } + while ( v17 ); + ++v15; + } + while ( v15 < 40 ); + DRLG_L2Pass3(); + DRLG_Init_Globals(); + v18 = 0; + v33 = dPiece; + do + { + v19 = v33; + v20 = (char *)dArch + v18; + v21 = 112; + do + { + v22 = (*v19)[0]; + v23 = 0; + if ( (*v19)[0] == 541 ) + v23 = 5; + if ( v22 == 178 ) + v23 = 5; + if ( v22 == 551 ) + v23 = 5; + if ( v22 == 542 ) + v23 = 6; + if ( v22 == 553 ) + v23 = 6; + if ( v22 == 13 ) + v23 = 5; + if ( v22 == 17 ) + v23 = 6; + *v20 = v23; + ++v19; + v20 += 112; + --v21; + } + while ( v21 ); + v33 = (int (*)[112])((char *)v33 + 4); + ++v18; + } + while ( (signed int)v33 < (signed int)dPiece[1] ); + v24 = 0; + v25 = dPiece; + do + { + v26 = &dArch[0][v24 + 2]; + v27 = v25; + v28 = 112; + do + { + v29 = (*v27)[0]; + if ( (*v27)[0] == 132 ) + { + *(v26 - 1) = 2; + *v26 = 1; + } + else if ( v29 == 135 || v29 == 139 ) + { + v26[110] = 3; + v26[222] = 4; + } + ++v27; + v26 += 112; + --v28; + } + while ( v28 ); + v25 = (int (*)[112])((char *)v25 + 4); + ++v24; + } + while ( (signed int)v25 < (signed int)dPiece[1] ); + ViewX = v30; + ViewY = vy; + SetMapMonsters((unsigned char *)ptr, 0, 0); + SetMapObjects((unsigned char *)ptr, 0, 0); + mem_free_dbg(ptr); +} + +void __cdecl DRLG_L2Pass3() +{ + int v0; // eax + int *v1; // edx + int *v2; // eax + signed int v3; // ecx + signed int v4; // ebx + int *v5; // ecx + unsigned char *v6; // edx + unsigned short *v7; // esi + unsigned short v8; // ax + int v9; // eax + int v10; // ST24_4 + int v11; // ST20_4 + int v12; // ST1C_4 + signed int v13; // [esp+Ch] [ebp-1Ch] + int *v14; // [esp+10h] [ebp-18h] + int v15; // [esp+14h] [ebp-14h] + int v16; // [esp+18h] [ebp-10h] + int v17; // [esp+1Ch] [ebp-Ch] + int v18; // [esp+20h] [ebp-8h] + + v0 = *((unsigned short *)pMegaTiles + 44) + 1; + v18 = *((unsigned short *)pMegaTiles + 44) + 1; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 45); + v17 = ++v0; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 46); + v16 = ++v0; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 47); + v15 = v0 + 1; + v1 = dPiece[1]; + do + { + v2 = v1; + v3 = 56; + do + { + *(v2 - 112) = v18; + *v2 = v17; + *(v2 - 111) = v16; + v2[1] = v15; + v2 += 224; + --v3; + } + while ( v3 ); + v1 += 2; + } + while ( (signed int)v1 < (signed int)dPiece[2] ); + v4 = 0; + v14 = &dPiece[17][16]; + do + { + v5 = v14; + v6 = (unsigned char *)dungeon + v4; + v13 = 40; + do + { + v7 = (unsigned short *)((char *)pMegaTiles + 8 * (*v6 - 1)); + v8 = *v7; + ++v7; + v9 = v8 + 1; + v10 = v9; + _LOWORD(v9) = *v7; + ++v7; + v11 = ++v9; + _LOWORD(v9) = *v7; + v12 = ++v9; + _LOWORD(v9) = v7[1]; + v6 += 40; + *(v5 - 112) = v10; + *v5 = v11; + *(v5 - 111) = v12; + v5[1] = v9 + 1; + v5 += 224; + --v13; + } + while ( v13 ); + v14 += 2; + ++v4; + } + while ( v4 < 40 ); +} + +void __fastcall LoadPreL2Dungeon(char *sFileName, int vx, int vy) +{ + char *v3; // esi + unsigned char *v4; // ebx + signed int v5; // esi + signed int v6; // edx + signed int v7; // eax + int v8; // eax + int v9; // edi + char *v10; // edx + int v11; // esi + char v12; // bl + signed int v13; // eax + _BYTE *v14; // edx + signed int v15; // esi + signed int v16; // eax + signed int v17; // edx + signed int v18; // esi + unsigned char *ptr; // [esp+8h] [ebp-Ch] + int v20; // [esp+Ch] [ebp-8h] + int v21; // [esp+10h] [ebp-4h] + + v3 = sFileName; + InitDungeon(); + DRLG_InitTrans(); + v4 = LoadFileInMem(v3, 0); + v5 = 0; + ptr = v4; + do + { + v6 = v5; + v7 = 40; + do + { + dflags[0][v6] = 0; + dungeon[0][v6] = 12; + v6 += 40; + --v7; + } + while ( v7 ); + ++v5; + } + while ( v5 < 40 ); + v21 = 0; + v8 = v4[2]; + v9 = *v4; + v10 = (char *)(v4 + 4); + if ( v8 > 0 ) + { + do + { + if ( v9 > 0 ) + { + v11 = v21; + v20 = v9; + do + { + v12 = *v10; + if ( *v10 ) + { + dflags[0][v11] |= 0x80u; + dungeon[0][v11] = v12; + } + else + { + dungeon[0][v11] = 3; + } + v11 += 40; + v10 += 2; + --v20; + } + while ( v20 ); + } + ++v21; + } + while ( v21 < v8 ); + } + v13 = 0; + do + { + v14 = (unsigned char *)dungeon + v13; + v15 = 40; + do + { + if ( !*v14 ) + *v14 = 12; + v14 += 40; + --v15; + } + while ( v15 ); + ++v13; + } + while ( v13 < 40 ); + v16 = 0; + do + { + v17 = v16; + v18 = 40; + do + { + pdungeon[0][v17] = dungeon[0][v17]; + v17 += 40; + --v18; + } + while ( v18 ); + ++v16; + } + while ( v16 < 40 ); + mem_free_dbg(ptr); +} + +void __fastcall CreateL2Dungeon(int rseed, int entry) +{ + int v2; // esi + int v3; // edi + int v4; // ecx + + v2 = entry; + v3 = rseed; + if ( gbMaxPlayers == 1 ) + { + if ( currlevel == 7 ) + { + if ( quests[8]._qactive ) + goto LABEL_10; + currlevel = 6; + CreateL2Dungeon(glSeedTbl[6], 4); + currlevel = 7; + } + if ( currlevel == 8 ) + { + if ( quests[8]._qactive ) + { + v4 = glSeedTbl[7]; + currlevel = 7; + } + else + { + v4 = glSeedTbl[6]; + currlevel = 6; + } + CreateL2Dungeon(v4, 4); + currlevel = 8; + } + } +LABEL_10: + SetRndSeed(v3); + dminx = 16; + dminy = 16; + dmaxx = 96; + dmaxy = 96; + DRLG_InitTrans(); + DRLG_InitSetPC(); + DRLG_LoadL2SP(); + DRLG_L2(v2); + DRLG_L2Pass3(); + DRLG_FreeL2SP(); + DRLG_InitL2Vals(); + DRLG_SetPC(); +} +// 5CF328: using guessed type int dmaxx; +// 5CF32C: using guessed type int dmaxy; +// 5D2458: using guessed type int dminx; +// 5D245C: using guessed type int dminy; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl DRLG_LoadL2SP() +{ + char *v1; // ecx + + setloadflag_2 = 0; + if ( QuestStatus(8) ) + { + v1 = "Levels\\L2Data\\Blind2.DUN"; + } + else + { + if ( QuestStatus(9) ) + { + v1 = "Levels\\L2Data\\Blood1.DUN"; + } + else + { + if ( !QuestStatus(14) ) + return; + v1 = "Levels\\L2Data\\Bonestr2.DUN"; + } + } + pSetPiece_2 = (char *)LoadFileInMem(v1, 0); + setloadflag_2 = 1; +} +// 5B50D8: using guessed type int setloadflag_2; + +void __cdecl DRLG_FreeL2SP() +{ + char *v0; // ecx + + v0 = pSetPiece_2; + pSetPiece_2 = 0; + mem_free_dbg(v0); +} + +void __fastcall DRLG_L2(int entry) +{ + int v1; // esi + int v2; // eax + int v3; // eax + int v4; // eax + int v5; // eax + int v6; // eax + int v7; // eax + int v8; // eax + int v9; // eax + signed int v10; // ecx + signed int v11; // eax + signed int v12; // esi + int v13; // [esp+10h] [ebp-4h] + + v1 = 0; + v13 = entry; + do + { + nRoomCnt = 0; + InitDungeon(); + DRLG_InitTrans(); + v2 = CreateDungeon(); + if ( !v2 ) + continue; + L2TileFix(); + if ( setloadflag_2 ) + DRLG_L2SetRoom(nSx1, nSy1); + DRLG_L2FloodTVal(); + DRLG_L2TransFix(); + if ( !v13 ) + { + v3 = DRLG_L2PlaceMiniSet(USTAIRS, 1, 1, -1, -1, 1, 0); + v1 = v3; + if ( !v3 ) + goto LABEL_21; + v4 = DRLG_L2PlaceMiniSet(DSTAIRS, 1, 1, -1, -1, 0, 1); + v1 = v4; + if ( !v4 || currlevel != 5 ) + goto LABEL_21; + v5 = DRLG_L2PlaceMiniSet(WARPSTAIRS, 1, 1, -1, -1, 0, 6); +LABEL_20: + v1 = v5; +LABEL_21: + ViewY -= 2; + continue; + } + v6 = DRLG_L2PlaceMiniSet(USTAIRS, 1, 1, -1, -1, 0, 0); + v1 = v6; + if ( v13 != 1 ) + { + if ( !v6 ) + goto LABEL_21; + v9 = DRLG_L2PlaceMiniSet(DSTAIRS, 1, 1, -1, -1, 0, 1); + v1 = v9; + if ( !v9 || currlevel != 5 ) + goto LABEL_21; + v5 = DRLG_L2PlaceMiniSet(WARPSTAIRS, 1, 1, -1, -1, 1, 6); + goto LABEL_20; + } + if ( v6 ) + { + v7 = DRLG_L2PlaceMiniSet(DSTAIRS, 1, 1, -1, -1, 1, 1); + v1 = v7; + if ( v7 ) + { + if ( currlevel == 5 ) + { + v8 = DRLG_L2PlaceMiniSet(WARPSTAIRS, 1, 1, -1, -1, 0, 6); + v1 = v8; + } + } + } + --ViewX; + } + while ( !v1 ); + L2LockoutFix(); + L2DoorFix(); + L2DirtFix(); + DRLG_PlaceThemeRooms(6, 10, 3, 0, 0); + DRLG_L2PlaceRndSet(CTRDOOR1, 100); + DRLG_L2PlaceRndSet(CTRDOOR2, 100); + DRLG_L2PlaceRndSet(CTRDOOR3, 100); + DRLG_L2PlaceRndSet(CTRDOOR4, 100); + DRLG_L2PlaceRndSet(CTRDOOR5, 100); + DRLG_L2PlaceRndSet(CTRDOOR6, 100); + DRLG_L2PlaceRndSet(CTRDOOR7, 100); + DRLG_L2PlaceRndSet(CTRDOOR8, 100); + DRLG_L2PlaceRndSet(VARCH33, 100); + DRLG_L2PlaceRndSet(VARCH34, 100); + DRLG_L2PlaceRndSet(VARCH35, 100); + DRLG_L2PlaceRndSet(VARCH36, 100); + DRLG_L2PlaceRndSet(VARCH37, 100); + DRLG_L2PlaceRndSet(VARCH38, 100); + DRLG_L2PlaceRndSet(VARCH39, 100); + DRLG_L2PlaceRndSet(VARCH40, 100); + DRLG_L2PlaceRndSet(VARCH1, 100); + DRLG_L2PlaceRndSet(VARCH2, 100); + DRLG_L2PlaceRndSet(VARCH3, 100); + DRLG_L2PlaceRndSet(VARCH4, 100); + DRLG_L2PlaceRndSet(VARCH5, 100); + DRLG_L2PlaceRndSet(VARCH6, 100); + DRLG_L2PlaceRndSet(VARCH7, 100); + DRLG_L2PlaceRndSet(VARCH8, 100); + DRLG_L2PlaceRndSet(VARCH9, 100); + DRLG_L2PlaceRndSet(VARCH10, 100); + DRLG_L2PlaceRndSet(VARCH11, 100); + DRLG_L2PlaceRndSet(VARCH12, 100); + DRLG_L2PlaceRndSet(VARCH13, 100); + DRLG_L2PlaceRndSet(VARCH14, 100); + DRLG_L2PlaceRndSet(VARCH15, 100); + DRLG_L2PlaceRndSet(VARCH16, 100); + DRLG_L2PlaceRndSet(VARCH17, 100); + DRLG_L2PlaceRndSet(VARCH18, 100); + DRLG_L2PlaceRndSet(VARCH19, 100); + DRLG_L2PlaceRndSet(VARCH20, 100); + DRLG_L2PlaceRndSet(VARCH21, 100); + DRLG_L2PlaceRndSet(VARCH22, 100); + DRLG_L2PlaceRndSet(VARCH23, 100); + DRLG_L2PlaceRndSet(VARCH24, 100); + DRLG_L2PlaceRndSet(VARCH25, 100); + DRLG_L2PlaceRndSet(VARCH26, 100); + DRLG_L2PlaceRndSet(VARCH27, 100); + DRLG_L2PlaceRndSet(VARCH28, 100); + DRLG_L2PlaceRndSet(VARCH29, 100); + DRLG_L2PlaceRndSet(VARCH30, 100); + DRLG_L2PlaceRndSet(VARCH31, 100); + DRLG_L2PlaceRndSet(VARCH32, 100); + DRLG_L2PlaceRndSet(HARCH1, 100); + DRLG_L2PlaceRndSet(HARCH2, 100); + DRLG_L2PlaceRndSet(HARCH3, 100); + DRLG_L2PlaceRndSet(HARCH4, 100); + DRLG_L2PlaceRndSet(HARCH5, 100); + DRLG_L2PlaceRndSet(HARCH6, 100); + DRLG_L2PlaceRndSet(HARCH7, 100); + DRLG_L2PlaceRndSet(HARCH8, 100); + DRLG_L2PlaceRndSet(HARCH9, 100); + DRLG_L2PlaceRndSet(HARCH10, 100); + DRLG_L2PlaceRndSet(HARCH11, 100); + DRLG_L2PlaceRndSet(HARCH12, 100); + DRLG_L2PlaceRndSet(HARCH13, 100); + DRLG_L2PlaceRndSet(HARCH14, 100); + DRLG_L2PlaceRndSet(HARCH15, 100); + DRLG_L2PlaceRndSet(HARCH16, 100); + DRLG_L2PlaceRndSet(HARCH17, 100); + DRLG_L2PlaceRndSet(HARCH18, 100); + DRLG_L2PlaceRndSet(HARCH19, 100); + DRLG_L2PlaceRndSet(HARCH20, 100); + DRLG_L2PlaceRndSet(HARCH21, 100); + DRLG_L2PlaceRndSet(HARCH22, 100); + DRLG_L2PlaceRndSet(HARCH23, 100); + DRLG_L2PlaceRndSet(HARCH24, 100); + DRLG_L2PlaceRndSet(HARCH25, 100); + DRLG_L2PlaceRndSet(HARCH26, 100); + DRLG_L2PlaceRndSet(HARCH27, 100); + DRLG_L2PlaceRndSet(HARCH28, 100); + DRLG_L2PlaceRndSet(HARCH29, 100); + DRLG_L2PlaceRndSet(HARCH30, 100); + DRLG_L2PlaceRndSet(HARCH31, 100); + DRLG_L2PlaceRndSet(HARCH32, 100); + DRLG_L2PlaceRndSet(HARCH33, 100); + DRLG_L2PlaceRndSet(HARCH34, 100); + DRLG_L2PlaceRndSet(HARCH35, 100); + DRLG_L2PlaceRndSet(HARCH36, 100); + DRLG_L2PlaceRndSet(HARCH37, 100); + DRLG_L2PlaceRndSet(HARCH38, 100); + DRLG_L2PlaceRndSet(HARCH39, 100); + DRLG_L2PlaceRndSet(HARCH40, 100); + DRLG_L2PlaceRndSet(CRUSHCOL, 99); + DRLG_L2PlaceRndSet(RUINS1, 10); + DRLG_L2PlaceRndSet(RUINS2, 10); + DRLG_L2PlaceRndSet(RUINS3, 10); + DRLG_L2PlaceRndSet(RUINS4, 10); + DRLG_L2PlaceRndSet(RUINS5, 10); + DRLG_L2PlaceRndSet(RUINS6, 10); + DRLG_L2PlaceRndSet(RUINS7, 50); + DRLG_L2PlaceRndSet(PANCREAS1, 1); + DRLG_L2PlaceRndSet(PANCREAS2, 1); + DRLG_L2PlaceRndSet(BIG1, 3); + DRLG_L2PlaceRndSet(BIG2, 3); + DRLG_L2PlaceRndSet(BIG3, 3); + DRLG_L2PlaceRndSet(BIG4, 3); + DRLG_L2PlaceRndSet(BIG5, 3); + DRLG_L2PlaceRndSet(BIG6, 20); + DRLG_L2PlaceRndSet(BIG7, 20); + DRLG_L2PlaceRndSet(BIG8, 3); + DRLG_L2PlaceRndSet(BIG9, 20); + DRLG_L2PlaceRndSet(BIG10, 20); + DRLG_L2Subs(); + DRLG_L2Shadows(); + v10 = 0; + do + { + v11 = v10; + v12 = 40; + do + { + pdungeon[0][v11] = dungeon[0][v11]; + v11 += 40; + --v12; + } + while ( v12 ); + ++v10; + } + while ( v10 < 40 ); + DRLG_Init_Globals(); + DRLG_CheckQuests(nSx1, nSy1); +} +// 5B50D8: using guessed type int setloadflag_2; + +bool __fastcall DRLG_L2PlaceMiniSet(unsigned char *miniset, int tmin, int tmax, int cx, int cy, bool setview, int ldir) +{ + int v7; // ebx + int v8; // esi + int v9; // edi + int v10; // edx + int v11; // eax + int v13; // esi + int v14; // ebx + int v15; // ecx + int v16; // eax + int v18; // eax + int v20; // edi + signed int i; // eax + int v22; // ecx + unsigned char v23; // dl + int v24; // eax + int v25; // edi + char *v26; // edx + unsigned char v27; // bl + bool result; // al + unsigned char *v29; // [esp+Ch] [ebp-28h] + int v30; // [esp+10h] [ebp-24h] + int v31; // [esp+14h] [ebp-20h] + int v32; // [esp+18h] [ebp-1Ch] + signed int v33; // [esp+1Ch] [ebp-18h] + int v34; // [esp+20h] [ebp-14h] + int v35; // [esp+24h] [ebp-10h] + int v36; // [esp+28h] [ebp-Ch] + int max; // [esp+2Ch] [ebp-8h] + //int v38; // [esp+30h] [ebp-4h] + int v39; // [esp+30h] [ebp-4h] + int tmaxa; // [esp+3Ch] [ebp+8h] + + v7 = miniset[1]; + v8 = tmin; + v9 = *miniset; + v29 = miniset; + v10 = tmax - tmin; + v34 = *miniset; + v35 = miniset[1]; + if ( v10 ) + { + v30 = v8 + random(0, v10); + } + else + { + v30 = 1; + } + v31 = 0; + if ( v30 <= 0 ) + { + v13 = ldir; + v14 = 0; /* v38; check */ + } + else + { + max = 40 - v9; + v36 = 40 - v7; + do + { + v11 = random(0, max); + v13 = v11; + v33 = 0; + v14 = random(0, v36); + v39 = v14; + do + { + if ( v33 >= 200 ) + return 0; + tmaxa = 1; + if ( v13 >= nSx1 && v13 <= nSx2 && v14 >= nSy1 && v14 <= nSy2 ) + tmaxa = 0; + if ( cx != -1 ) + { + v15 = cx - v34; + if ( v13 >= cx - v34 && v13 <= cx + 12 ) + { + v16 = random(0, max); + v13 = v16; + tmaxa = 0; + v39 = random(0, v36); + v14 = v39; + } + } + if ( cy != -1 && v14 >= cy - v35 && v14 <= cy + 12 ) + { + v18 = random(0, max); /* cy - v35 */ + v13 = v18; + tmaxa = 0; + v39 = random(0, v36); + v14 = v39; + } + v20 = 0; + for ( i = 2; v20 < v35; ++v20 ) + { + if ( tmaxa != 1 ) + break; + v32 = 0; + if ( v34 > 0 ) + { + v22 = v14 + v20 + 40 * v13; + do + { + if ( tmaxa != 1 ) + break; + v23 = v29[i]; + if ( v23 && dungeon[0][v22] != v23 ) + tmaxa = 0; + if ( dflags[0][v22] ) + tmaxa = 0; + ++i; + ++v32; + v22 += 40; + } + while ( v32 < v34 ); + } + } + if ( !tmaxa && ++v13 == max ) + { + v13 = 0; + v39 = ++v14; + if ( v14 == v36 ) + { + v39 = 0; + v14 = 0; + } + } + ++v33; + } + while ( !tmaxa ); + if ( v33 >= 200 ) + return 0; + v24 = 0; + for ( miniset = (unsigned char *)(v34 * v35 + 2); v24 < v35; ++v24 ) + { + v25 = v34; + if ( v34 > 0 ) + { + v26 = &dungeon[v13][v24 + v14]; + do + { + v27 = v29[(_DWORD)miniset]; + if ( v27 ) + *v26 = v27; + ++miniset; + v26 += 40; + --v25; + } + while ( v25 ); + v14 = v39; + } + } + ++v31; + } + while ( v31 < v30 ); + } + result = 1; + if ( setview == 1 ) + { + ViewX = 2 * v13 + 21; + ViewY = 2 * v14 + 22; + } + if ( !ldir ) + { + LvlViewX = 2 * v13 + 21; + LvlViewY = 2 * v14 + 22; + } + if ( ldir == 6 ) + { + LvlViewX = 2 * v13 + 21; + LvlViewY = 2 * v14 + 22; + } + return result; +} +// 5276CC: using guessed type int nSx2; +// 5276D4: using guessed type int nSy2; +// 5CF320: using guessed type int LvlViewY; +// 5CF324: using guessed type int LvlViewX; + +void __fastcall DRLG_L2PlaceRndSet(unsigned char *miniset, int rndper) +{ + unsigned char *v2; // ebx + signed int v3; // esi + signed int v4; // ecx + int v5; // edx + signed int v6; // edi + signed int i; // edx + signed int v8; // esi + int v9; // eax + unsigned char v10; // cl + int v11; // edi + _BYTE *v12; // ecx + int v13; // esi + int v14; // eax + int v15; // eax + signed int j; // edx + signed int v17; // esi + unsigned char *v18; // eax + unsigned char v19; // cl + int v20; // [esp+8h] [ebp-3Ch] + unsigned char *v21; // [esp+10h] [ebp-34h] + int v22; // [esp+14h] [ebp-30h] + int v23; // [esp+18h] [ebp-2Ch] + int v24; // [esp+1Ch] [ebp-28h] + int v25; // [esp+20h] [ebp-24h] + int v26; // [esp+24h] [ebp-20h] + int v27; // [esp+28h] [ebp-1Ch] + int v28; // [esp+2Ch] [ebp-18h] + int v29; // [esp+30h] [ebp-14h] + signed int v30; // [esp+34h] [ebp-10h] + signed int v31; // [esp+38h] [ebp-Ch] + int v32; // [esp+3Ch] [ebp-8h] + signed int v33; // [esp+40h] [ebp-4h] + + v2 = miniset; + v32 = 0; + v20 = rndper; + v3 = miniset[1]; + v4 = *miniset; + v21 = v2; + v30 = v4; + v26 = 40 - v3; + v31 = v3; + if ( 40 - v3 > 0 ) + { + v27 = 40 - v4; + v23 = -v3; + while ( 1 ) + { + v5 = 0; + v25 = 0; + if ( v27 > 0 ) + { + v29 = -v4; + v22 = v4 * v3 + 2; + v28 = 0; + v24 = -40 * v4; + do + { + v33 = 1; + v6 = 2; + if ( v5 >= nSx1 && v5 <= nSx2 && v32 >= nSy1 && v32 <= nSy2 ) + v33 = 0; + for ( i = 0; i < v31; ++i ) + { + if ( v33 != 1 ) + break; + v8 = 0; + if ( v30 > 0 ) + { + v9 = v32 + i + v28; + do + { + if ( v33 != 1 ) + break; + v10 = v2[v6]; + if ( v10 && dungeon[0][v9] != v10 ) + v33 = 0; + if ( dflags[0][v9] ) + v33 = 0; + ++v6; + ++v8; + v9 += 40; + } + while ( v8 < v30 ); + } + } + v11 = v22; + if ( v33 == 1 ) + { + v12 = (_BYTE *)v31; + v13 = v23; + if ( v23 >= v32 + 2 * v31 ) + { +LABEL_34: + if ( random(0, 100) < v20 ) + { + for ( j = 0; j < v31; ++j ) + { + v17 = v30; + if ( v30 > 0 ) + { + v18 = (unsigned char *)dungeon + j + v28 + v32; + do + { + v19 = v2[v11]; + if ( v19 ) + *v18 = v19; + ++v11; + v18 += 40; + --v17; + } + while ( v17 ); + } + } + } + } + else + { + while ( v33 == 1 ) + { + v12 = (_BYTE *)v30; + v14 = v25 + 2 * v30; + if ( v29 < v14 ) + { + v15 = v14 - v29; + v12 = (unsigned char *)dungeon + v24 + v13; + do + { + if ( *v12 == v2[v22] ) + v33 = 0; + v12 += 40; + --v15; + } + while ( v15 ); + v2 = v21; + } + if ( ++v13 >= v32 + 2 * v31 ) + { + if ( v33 != 1 ) + break; + goto LABEL_34; + } + } + } + } + v24 += 40; + v28 += 40; + v5 = v25 + 1; + ++v29; + ++v25; + } + while ( v25 < v27 ); + } + ++v32; + ++v23; + if ( v32 >= v26 ) + break; + v4 = v30; + v3 = v31; + } + } +} +// 5276CC: using guessed type int nSx2; +// 5276D4: using guessed type int nSy2; + +void __cdecl DRLG_L2Subs() +{ + signed int v0; // edi + unsigned char v1; // bl + int v2; // eax + signed int v3; // edx + int v4; // esi + int i; // ebx + int j; // eax + signed int v7; // [esp+Ch] [ebp-10h] + char *v8; // [esp+10h] [ebp-Ch] + signed int v9; // [esp+14h] [ebp-8h] + int v10; // [esp+18h] [ebp-4h] + + v0 = 3; + v9 = -2; + v7 = 3; + do + { + v10 = 0; + v8 = &dungeon[0][v9 + 2]; + do + { + if ( (v10 < nSx1 || v10 > nSx2) && (v0 - 3 < nSy1 || v0 - 3 > nSy2) && !random(0, 4) ) + { + v1 = BTYPESL2[(unsigned char)*v8]; + if ( v1 ) + { + v2 = random(0, 16); + v3 = -1; + while ( v2 >= 0 ) + { + if ( ++v3 == 161 ) + v3 = 0; + if ( v1 == BTYPESL2[v3] ) + --v2; + } + v4 = v9; + for ( i = v0 - 1; v4 < i; ++v4 ) + { + for ( j = v10 - 2; j < v10 + 2; ++j ) + { + v0 = v7; + if ( (unsigned char)dungeon[j][v4] == v3 ) + { + v4 = v7; + j = v10 + 2; + } + } + } + if ( v4 < v0 ) + *v8 = v3; + } + } + ++v10; + v8 += 40; + } + while ( v10 < 40 ); + ++v9; + v7 = ++v0; + } + while ( v0 - 3 < 40 ); +} +// 5276CC: using guessed type int nSx2; +// 5276D4: using guessed type int nSy2; + +void __cdecl DRLG_L2Shadows() +{ + char *v0; // eax + unsigned char *v1; // esi + unsigned char v2; // dl + signed int v3; // edi + char v4; // cl + char v5; // cl + char v6; // cl + char v7; // cl + char v8; // cl + signed int v9; // [esp+8h] [ebp-Ch] + signed int v10; // [esp+Ch] [ebp-8h] + unsigned char v11; // [esp+11h] [ebp-3h] + unsigned char v12; // [esp+12h] [ebp-2h] + unsigned char v13; // [esp+13h] [ebp-1h] + + v10 = 1; + do + { + v9 = 39; + v0 = &dungeon[0][v10 + 39]; + do + { + v1 = &SPATSL2[0].s1; + v2 = BSTYPESL2[(unsigned char)v0[1]]; + v12 = BSTYPESL2[(unsigned char)*(v0 - 39)]; + v11 = BSTYPESL2[(unsigned char)*v0]; + v13 = BSTYPESL2[(unsigned char)*(v0 - 40)]; + do + { + if ( *(v1 - 1) == v2 ) + { + v3 = 1; + if ( *v1 && *v1 != v13 ) + v3 = 0; + v4 = v1[1]; + if ( v4 && v4 != v11 ) + v3 = 0; + v5 = v1[2]; + if ( v5 && v5 != v12 ) + v3 = 0; + if ( v3 == 1 ) + { + v6 = v1[3]; + if ( v6 ) + *(v0 - 40) = v6; + v7 = v1[4]; + if ( v7 ) + *v0 = v7; + v8 = v1[5]; + if ( v8 ) + *(v0 - 39) = v8; + } + } + v1 += 7; + } + while ( (signed int)v1 < (signed int)&SPATSL2[2].s1 ); + v0 += 40; + --v9; + } + while ( v9 ); + ++v10; + } + while ( v10 < 40 ); +} +// 48489A: using guessed type short word_48489A; + +void __fastcall DRLG_L2SetRoom(int rx1, int ry1) +{ + int v2; // edi + int v3; // esi + int v4; // eax + char v5; // bl + int v6; // [esp+8h] [ebp-Ch] + char *v7; // [esp+Ch] [ebp-8h] + int v8; // [esp+10h] [ebp-4h] + + v8 = 0; + v2 = (unsigned char)pSetPiece_2[2]; + v3 = (unsigned char)*pSetPiece_2; + setpc_x = rx1; + setpc_y = ry1; + setpc_w = v3; + setpc_h = v2; + v7 = pSetPiece_2 + 4; + if ( v2 > 0 ) + { + do + { + if ( v3 > 0 ) + { + v6 = v3; + v4 = ry1 + v8 + 40 * rx1; + do + { + v5 = *v7; + if ( *v7 ) + { + dflags[0][v4] |= 0x80u; + dungeon[0][v4] = v5; + } + else + { + dungeon[0][v4] = 3; + } + v7 += 2; + v4 += 40; + --v6; + } + while ( v6 ); + } + ++v8; + } + while ( v8 < v2 ); + } +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __cdecl L2TileFix() +{ + signed int v0; // edx + char *v1; // eax + signed int v2; // esi + char v3; // cl + + v0 = 0; + do + { + v1 = (char *)dungeon + v0; + v2 = 40; + do + { + v3 = *v1; + if ( *v1 == 1 && v1[1] == 3 ) + v1[1] = 1; + if ( v3 == 3 ) + { + if ( v1[1] == 1 ) + v1[1] = 3; + if ( v1[40] == 7 ) + v1[40] = 3; + } + if ( v3 == 2 && v1[40] == 3 ) + v1[40] = 2; + if ( v3 == 11 && v1[40] == 14 ) + v1[40] = 16; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +bool __cdecl CreateDungeon() +{ + int v0; // esi + int v1; // edx + int v2; // ecx + signed int v3; // esi + char *v4; // eax + signed int v5; // ebx + _BYTE *v6; // ecx + bool v7; // zf + bool v8; // eax + int v9; // edi + int v10; // esi + signed int v12; // [esp-4h] [ebp-20h] + int nX1; // [esp+8h] [ebp-14h] + int nY1; // [esp+Ch] [ebp-10h] + int nX2; // [esp+10h] [ebp-Ch] + int nY2; // [esp+14h] [ebp-8h] + int nHd; // [esp+18h] [ebp-4h] + + v0 = 0; + v1 = 0; + v2 = 0; + if ( currlevel == 5 ) + { + if ( !quests[9]._qactive ) + goto LABEL_12; + v1 = 20; + v0 = 14; + } + else + { + if ( currlevel == 6 ) + { + if ( !quests[14]._qactive ) + goto LABEL_12; + v12 = 10; + } + else + { + if ( currlevel != 7 || !quests[8]._qactive ) + goto LABEL_12; + v12 = 15; + } + v0 = v12; + v1 = v12; + } + v2 = 1; +LABEL_12: + CreateRoom(2, 2, 39, 39, 0, 0, v2, v1, v0); + while ( pHallList ) + { + GetHall(&nX1, &nY1, &nX2, &nY2, &nHd); + ConnectHall(nX1, nY1, nX2, nY2, nHd); + } + v3 = 0; + do + { + v4 = &predungeon[-1][v3]; + v5 = 41; + do + { + v6 = (unsigned char *)v4 + 40; + if ( v4[40] == 67 ) + *v6 = 35; + if ( *v6 == 66 ) + *v6 = 35; + if ( *v6 == 69 ) + *v6 = 35; + if ( *v6 == 65 ) + *v6 = 35; + if ( *v6 == 44 ) + { + v7 = *(v4 - 1) == 32; + *v6 = 46; + if ( v7 ) + *(v4 - 1) = 35; + if ( *v4 == 32 ) + *v4 = 35; + if ( v4[1] == 32 ) + v4[1] = 35; + if ( v4[79] == 32 ) + v4[79] = 35; + if ( v4[80] == 32 ) + v4[80] = 35; + if ( v4[81] == 32 ) + v4[81] = 35; + if ( v4[39] == 32 ) + v4[39] = 35; + if ( v4[41] == 32 ) + v4[41] = 35; + } + --v5; + v4 += 40; + } + while ( v5 ); + ++v3; + } + while ( v3 <= 40 ); + v8 = DL2_FillVoids(); + if ( v8 ) + { + v9 = 0; + do + { + v10 = 0; + do + DoPatternCheck(v10++, v9); + while ( v10 < 40 ); + ++v9; + } + while ( v9 < 40 ); + v8 = 1; + } + return v8; +} + +void __fastcall CreateRoom(int nX1, int nY1, int nX2, int nY2, int nRDest, int nHDir, int ForceHW, int nH, int nW) +{ + int v9; // esi + int v10; // ebx + int v11; // edx + int v12; // eax + int v13; // edx + int v14; // edx + int v15; // edi + int v17; // esi + int v18; // ebx + int v19; // edx + int v20; // ecx + int v21; // eax + int v23; // eax + int v24; // eax + int v26; // eax + int *v27; // ecx + int v28; // eax + int v29; // eax + int *v30; // ecx + int v31; // eax + int nX1a; // [esp+Ch] [ebp-30h] + int v33; // [esp+10h] [ebp-2Ch] + int v34; // [esp+14h] [ebp-28h] + int v35; // [esp+18h] [ebp-24h] + int v36; // [esp+1Ch] [ebp-20h] + int v37; // [esp+20h] [ebp-1Ch] + int nY1a; // [esp+24h] [ebp-18h] + int v39; // [esp+28h] [ebp-14h] + int v40; // [esp+2Ch] [ebp-10h] + int v41; // [esp+30h] [ebp-Ch] + int v42; // [esp+34h] [ebp-8h] + int v43; // [esp+38h] [ebp-4h] + int *ForceHWa; // [esp+54h] [ebp+18h] + int *ForceHWb; // [esp+54h] [ebp+18h] + + v39 = nY1; + v37 = nX1; + if ( nRoomCnt < 80 ) + { + v40 = nX2 - 2; + nY1a = nY1 + 2; + while ( 1 ) + { + v9 = nX2 - v37; + v10 = nY2 - v39; + if ( nX2 - v37 < Area_Min || v10 < Area_Min ) + return; + if ( v9 > Room_Max ) + break; + nX1 = Room_Min; + if ( v9 > Room_Min ) + { + v11 = v9 - Room_Min; + goto LABEL_7; + } + v41 = nX2 - v37; +LABEL_11: + v13 = Room_Max; + if ( v10 <= Room_Max ) + { + if ( v10 <= nX1 ) + { + v36 = nY2 - v39; + goto LABEL_16; + } + v13 = nY2 - v39; + } + v14 = v13 - nX1; + v36 = Room_Min + random(0, v14); +LABEL_16: + if ( ForceHW == 1 ) + { + v41 = nW; + v36 = nH; + } + v15 = v37 + random(0, v9); + v17 = v39 + random(0, v10); + v18 = v15 + v41; + v43 = v17 + v36; + if ( v15 + v41 > nX2 ) + { + v18 = nX2; + v15 = nX2 - v41; + } + if ( v17 + v36 > nY2 ) + { + v43 = nY2; + v17 = nY2 - v36; + } + if ( v15 >= 38 ) + v15 = 38; + if ( v17 >= 38 ) + v17 = 38; + if ( v15 <= 1 ) + v15 = 1; + if ( v17 <= 1 ) + v17 = 1; + if ( v18 >= 38 ) + v18 = 38; + if ( v43 >= 38 ) + v43 = 38; + if ( v18 <= 1 ) + v18 = 1; + if ( v43 <= 1 ) + v43 = 1; + DefineRoom(v15, v17, v18, v43, ForceHW); + if ( ForceHW == 1 ) + { + nSx2 = v18; + nSx1 = v15 + 2; + nSy1 = v17 + 2; + nSy2 = v43; + } + v19 = nRoomCnt; + v20 = nRDest; + v42 = nRoomCnt; + RoomList[nRoomCnt].nRoomDest = nRDest; + if ( nRDest ) + { + if ( nHDir == 1 ) + { + v21 = random(0, v18 - v15 - 2); + nX1a = v21 + v15 + 1; + v33 = v17; + v23 = random(0, RoomList[nRDest].nRoomx2 - RoomList[nRDest].nRoomx1 - 2); + v20 = 20 * nRDest; + v34 = v23 + RoomList[nRDest].nRoomx1 + 1; + v35 = RoomList[nRDest].nRoomy2; + } + if ( nHDir == 3 ) + { + v24 = random(0, v18 - v15 - 2); + nX1a = v24 + v15 + 1; + v33 = v43; + v26 = random(0, RoomList[nRDest].nRoomx2 - RoomList[nRDest].nRoomx1 - 2); + v20 = 20 * nRDest; + v34 = v26 + RoomList[nRDest].nRoomx1 + 1; + v35 = RoomList[nRDest].nRoomy1; + } + if ( nHDir == 2 ) + { + nX1a = v18; + v33 = random(0, v43 - v17 - 2) + v17 + 1; + v34 = RoomList[nRDest].nRoomx1; + v27 = &RoomList[nRDest].nRoomy1; + ForceHWa = v27; + v28 = RoomList[nRDest].nRoomy2 - *v27; + v29 = random(0, v28 - 2); + v20 = *ForceHWa; + v35 = v29 + *ForceHWa + 1; + } + if ( nHDir == 4 ) + { + nX1a = v15; + v33 = random(0, v43 - v17 - 2) + v17 + 1; + v34 = RoomList[nRDest].nRoomx2; + v30 = &RoomList[nRDest].nRoomy1; + ForceHWb = v30; + v31 = RoomList[nRDest].nRoomy2 - *v30; + v35 = random(0, v31 - 2) + *ForceHWb + 1; + } + AddHall(nX1a, v33, v34, v35, nHDir); + v19 = v42; + } + if ( v36 <= v41 ) + { + CreateRoom(v37 + 2, nY1a, v18 - 2, v17 - 2, v19, 3, 0, 0, 0); + CreateRoom(v15 + 2, v43 + 2, v40, nY2 - 2, v42, 1, 0, 0, 0); + CreateRoom(v37 + 2, v17 + 2, v15 - 2, nY2 - 2, v42, 2, 0, 0, 0); + nHDir = 4; + nW = 0; + nH = 0; + ForceHW = 0; + nRDest = v42; + nY2 = v43 - 2; + nX2 -= 2; + v40 -= 2; + v39 += 2; + nY1a += 2; + v37 = v18 + 2; + } + else + { + CreateRoom(v37 + 2, nY1a, v15 - 2, v43 - 2, v19, 2, 0, 0, 0); + CreateRoom(v18 + 2, v17 + 2, v40, nY2 - 2, v42, 4, 0, 0, 0); + CreateRoom(v37 + 2, v43 + 2, v18 - 2, nY2 - 2, v42, 1, 0, 0, 0); + nW = 0; + nH = 0; + ForceHW = 0; + nRDest = v42; + nHDir = 3; + nX2 -= 2; + v40 -= 2; + v39 += 2; + nY1a += 2; + nY2 = v17 - 2; + v37 = v15 + 2; + } + if ( nRoomCnt >= 80 ) + return; + } + v11 = Room_Max - Room_Min; +LABEL_7: + v12 = random(0, v11); + nX1 = Room_Min; + v41 = Room_Min + v12; + goto LABEL_11; + } +} +// 484858: using guessed type int Area_Min; +// 48485C: using guessed type int Room_Max; +// 484860: using guessed type int Room_Min; +// 5276CC: using guessed type int nSx2; +// 5276D4: using guessed type int nSy2; + +void __fastcall DefineRoom(int nX1, int nY1, int nX2, int nY2, int ForceHW) +{ + int v5; // esi + int v6; // edi + int v7; // eax + int i; // eax + bool v9; // zf + int v10; // ecx + char *v11; // eax + char *v12; // ebx + int v13; // eax + int v14; // [esp+10h] [ebp-4h] + int v15; // [esp+10h] [ebp-4h] + int nY2a; // [esp+20h] [ebp+Ch] + char *ForceHWa; // [esp+24h] [ebp+10h] + + v5 = nX1; + v6 = nX2; + predungeon[v5][nY1] = 67; + predungeon[v5][nY2] = 69; + predungeon[v6][nY1] = 66; + predungeon[v6][nY2] = 65; + v7 = nRoomCnt + 1; + nRoomCnt = v7; + v7 *= 20; + *(int *)((char *)&RoomList[0].nRoomx1 + v7) = nX1; + *(int *)((char *)&RoomList[0].nRoomx2 + v7) = nX2; + *(int *)((char *)&RoomList[0].nRoomy1 + v7) = nY1; + *(int *)((char *)&RoomList[0].nRoomy2 + v7) = nY2; + if ( ForceHW == 1 ) + { + for ( i = nX1; i < nX2; ++i ) + { + if ( i < nY2 ) + { + ForceHWa = &dflags[i][nY1]; + v14 = nY2 - i; + i = nY2; + do + { + *ForceHWa |= 0x80u; + v9 = v14-- == 1; + ForceHWa += 40; + } + while ( !v9 ); + } + } + } + v10 = nX1 + 1; + if ( v10 <= nX2 - 1 ) + { + v15 = nX2 - v10; + v11 = &predungeon[v10][nY2]; + do + { + v11[nY1 - nY2] = 35; + *v11 = 35; + v11 += 40; + --v15; + } + while ( v15 ); + } + nY2a = nY2 - 1; + while ( ++nY1 <= nY2a ) + { + predungeon[v5][nY1] = 35; + predungeon[v6][nY1] = 35; + if ( v10 < nX2 ) + { + v12 = &predungeon[v10][nY1]; + v13 = nX2 - v10; + do + { + *v12 = 46; + v12 += 40; + --v13; + } + while ( v13 ); + } + } +} + +void __fastcall AddHall(int nX1, int nY1, int nX2, int nY2, int nHd) +{ + int v5; // edi + int v6; // esi + HALLNODE *v7; // eax + HALLNODE *i; // ecx + + v5 = nX1; + v6 = nY1; + if ( pHallList ) + { + v7 = (HALLNODE *)DiabloAllocPtr(24); + v7->pNext = 0; + v7->nHallx2 = nX2; + v7->nHally2 = nY2; + v7->nHallx1 = v5; + v7->nHally1 = v6; + v7->nHalldir = nHd; + for ( i = pHallList; i->pNext; i = i->pNext ) + ; + i->pNext = v7; + } + else + { + pHallList = (HALLNODE *)DiabloAllocPtr(24); + pHallList->nHallx1 = v5; + pHallList->nHally1 = v6; + pHallList->nHallx2 = nX2; + pHallList->nHally2 = nY2; + pHallList->nHalldir = nHd; + pHallList->pNext = 0; + } +} + +void __fastcall GetHall(int *nX1, int *nY1, int *nX2, int *nY2, int *nHd) +{ + HALLNODE *v5; // esi + HALLNODE *v6; // ecx + + v5 = pHallList->pNext; + *nX1 = pHallList->nHallx1; + *nY1 = pHallList->nHally1; + *nX2 = pHallList->nHallx2; + *nY2 = pHallList->nHally2; + *nHd = pHallList->nHalldir; + v6 = pHallList; + pHallList = 0; + mem_free_dbg(v6); + pHallList = v5; +} + +void __fastcall ConnectHall(int nX1, int nY1, int nX2, int nY2, int nHd) +{ + int v5; // edi + signed int v6; // esi + int v7; // eax + int v9; // edi + int v10; // ebx + int v11; // ecx + char v12; // al + int v13; // eax + int v14; // ecx + char *v15; // ebx + int v16; // ecx + int v17; // edx + int v18; // ecx + int v19; // edx + int v20; // eax + //int v21; // ST04_4 + int v23; // ebx + int v24; // ebx + bool v25; // zf + signed int v26; // [esp-4h] [ebp-34h] + signed int v27; // [esp-4h] [ebp-34h] + signed int v28; // [esp-4h] [ebp-34h] + signed int v29; // [esp-4h] [ebp-34h] + int v30; // [esp+Ch] [ebp-24h] + int v31; // [esp+10h] [ebp-20h] + int v32; // [esp+14h] [ebp-1Ch] + signed int v33; // [esp+18h] [ebp-18h] + signed int v34; // [esp+1Ch] [ebp-14h] + signed int v35; // [esp+20h] [ebp-10h] + int v36; // [esp+24h] [ebp-Ch] + char *v37; // [esp+28h] [ebp-8h] + signed int nY; // [esp+2Ch] [ebp-4h] + int nX2a; // [esp+38h] [ebp+8h] + int nY2a; // [esp+3Ch] [ebp+Ch] + int nHda; // [esp+40h] [ebp+10h] + + v34 = 0; + v5 = nY1; + v6 = nX1; + nY = nY1; + v7 = random(0, 100); + v33 = v7; + v32 = random(0, 100); + v31 = v6; + v30 = v5; + CreateDoorType(v6, v5); + CreateDoorType(nX2, nY2); + abs(nX2 - v6); + abs(nY2 - v5); + v9 = nHd; + v10 = nX2 - Dir_Xadd[nHd]; + v11 = nY2 - Dir_Yadd[nHd]; + nHda = 0; + nY2a = v11; + nX2a = v10; + predungeon[v10][v11] = 44; + v37 = &predungeon[v6][nY]; + do + { + if ( v6 >= 38 && v9 == 2 ) + v9 = 4; + if ( nY >= 38 && v9 == 3 ) + v9 = 1; + if ( v6 <= 1 && v9 == 4 ) + v9 = 2; + if ( nY <= 1 && v9 == 1 ) + v9 = 3; + v12 = *v37; + if ( *v37 == 67 && (v9 == 1 || v9 == 4) ) + v9 = 2; + if ( v12 == 66 && (v9 == 1 || v9 == 2) ) + v9 = 3; + if ( v12 == 69 && (v9 == 4 || v9 == 3) ) + v9 = 1; + if ( v12 == 65 && (v9 == 2 || v9 == 3) ) + v9 = 4; + v13 = Dir_Xadd[v9]; + v14 = Dir_Yadd[v9]; + nY += v14; + v6 += v13; + v15 = &predungeon[v6][nY]; + v37 = v15; + if ( *v15 == 32 ) + { + if ( nHda ) + { + CreateDoorType(v6 - v13, nY - v14); + } + else + { + if ( v33 < 50 ) + { + if ( v9 == 1 || v9 == 3 ) + { + v17 = nY; + v16 = v6 - 1; + } + else + { + v16 = v6; + v17 = nY - 1; + } + PlaceHallExt(v16, v17); + } + if ( v32 < 50 ) + { + if ( v9 == 1 || v9 == 3 ) + { + v19 = nY; + v18 = v6 + 1; + } + else + { + v18 = v6; + v19 = nY + 1; + } + PlaceHallExt(v18, v19); + } + } + nHda = 0; + *v15 = 44; + } + else + { + if ( !nHda && *v15 == 35 ) + CreateDoorType(v6, nY); + if ( *v15 != 44 ) + nHda = 1; + } + v36 = abs(nX2a - v6); + v20 = abs(nY2a - nY); + //v22 = v21; + v35 = v20; + if ( v36 <= v20 ) + { + v24 = 5 * v20; + if ( 5 * v20 > 80 ) + v24 = 80; + if ( random(0, 100) < v24 ) + { + if ( nY2a <= nY || nY >= 40 ) + { + v9 = 1; + goto LABEL_67; + } + v26 = 3; + goto LABEL_58; + } + } + else + { + v23 = 2 * v36; + if ( 2 * v36 > 30 ) + v23 = 30; + if ( random(0, 100) < v23 ) + { + if ( nX2a <= v6 || v6 >= 40 ) + v26 = 4; + else + v26 = 2; +LABEL_58: + v9 = v26; + goto LABEL_67; + } + } +LABEL_67: + if ( v35 < 10 && v6 == nX2a && (v9 == 2 || v9 == 4) ) + { + if ( nY2a <= nY || nY >= 40 ) + v9 = 1; + else + v9 = 3; + } + if ( v36 < 10 && nY == nY2a && (v9 == 1 || v9 == 3) ) + { + if ( nX2a <= v6 || v6 >= 40 ) + v27 = 4; + else + v27 = 2; + v9 = v27; + } + if ( v35 == 1 ) + { + v25 = v36 == 1; + if ( v36 <= 1 ) + goto LABEL_94; + if ( v9 == 1 || v9 == 3 ) + { + if ( nX2a <= v6 || v6 >= 40 ) + v28 = 4; + else + v28 = 2; + v9 = v28; + } + } + v25 = v36 == 1; +LABEL_94: + if ( v25 ) + { + if ( v35 <= 1 || v9 != 2 && v9 != 4 ) + goto LABEL_109; + if ( nY2a > nY && v6 < 40 ) + goto LABEL_100; + v9 = 1; + } + if ( !v36 && *v37 != 32 && (v9 == 2 || v9 == 4) ) + { + if ( nX2a <= v31 || v6 >= 40 ) + { + v9 = 1; + goto LABEL_109; + } +LABEL_100: + v9 = 3; + } +LABEL_109: + if ( !v35 && *v37 != 32 && (v9 == 1 || v9 == 3) ) + { + if ( nY2a <= v30 || nY >= 40 ) + v29 = 4; + else + v29 = 2; + v9 = v29; + } + if ( v6 == nX2a && nY == nY2a ) + v34 = 1; + } + while ( !v34 ); +} + +void __fastcall CreateDoorType(int nX, int nY) +{ + int v2; // eax + signed int v3; // esi + char *v4; // ecx + char v5; // al + + v2 = nX; + v3 = 0; + v4 = &predungeon[nX][nY]; + if ( *(v4 - 40) == 68 ) + v3 = 1; + if ( predungeon[v2 + 1][nY] == 68 ) + v3 = 1; + if ( *(v4 - 1) == 68 ) + v3 = 1; + if ( predungeon[v2][nY + 1] == 68 ) + v3 = 1; + v5 = *v4; + if ( *v4 == 66 || v5 == 67 || v5 == 65 || v5 == 69 ) + v3 = 1; + if ( !v3 ) + *v4 = 68; +} + +void __fastcall PlaceHallExt(int nX, int nY) +{ + char *v2; // eax + + v2 = &predungeon[nX][nY]; + if ( *v2 == 32 ) + *v2 = 44; +} + +void __fastcall DoPatternCheck(int i, int j) +{ + int v2; // edx + signed int v3; // eax + signed int v4; // ebp + int v5; // esi + int v6; // ecx + bool v7; // zf + char v8; // bl + bool v9; // zf + char v10; // bl + int *v11; // [esp+0h] [ebp-10h] + int v12; // [esp+4h] [ebp-Ch] + int v13; // [esp+8h] [ebp-8h] + int v14; // [esp+Ch] [ebp-4h] + + v13 = j; + v14 = i; + if ( Patterns[0][4] != 255 ) + { + v12 = 0; + v2 = i - 1; + v11 = &Patterns[0][4]; + do + { + v3 = v2; + v4 = 254; + v5 = v13 - 1; + v6 = 0; + while ( v4 == 254 ) + { + v4 = 255; + if ( v6 == 3 || v6 == 6 ) + { + ++v5; + v3 = v2; + } + if ( v3 < 0 || v3 >= 40 || v5 < 0 || v5 >= 40 ) + { +LABEL_26: + v4 = 254; + } + else + { + switch ( Patterns[0][v6 + v12] ) + { + case 0: + goto LABEL_26; + case 1: + v7 = predungeon[v3][v5] == 35; + goto LABEL_25; + case 2: + v7 = predungeon[v3][v5] == 46; + goto LABEL_25; + case 3: + v7 = predungeon[v3][v5] == 68; + goto LABEL_25; + case 4: + v7 = predungeon[v3][v5] == 32; + goto LABEL_25; + case 5: + v8 = predungeon[v3][v5]; + v9 = v8 == 68; + goto LABEL_23; + case 6: + v10 = predungeon[v3][v5]; + if ( v10 == 68 ) + goto LABEL_26; + v7 = v10 == 35; + goto LABEL_25; + case 7: + v8 = predungeon[v3][v5]; + v9 = v8 == 32; + goto LABEL_23; + case 8: + v8 = predungeon[v3][v5]; + if ( v8 == 68 ) + goto LABEL_26; + v9 = v8 == 35; +LABEL_23: + if ( v9 ) + goto LABEL_26; + v7 = v8 == 46; +LABEL_25: + if ( v7 ) + goto LABEL_26; + break; + default: + break; + } + } + ++v3; + if ( ++v6 >= 9 ) + { + if ( v4 == 254 ) + dungeon[v14][v13] = *((_BYTE *)v11 + 20); + break; + } + } + v11 += 10; + v12 += 10; + } + while ( *v11 != 255 ); + } +} + +bool __cdecl DL2_FillVoids() +{ + int i; // eax + int v2; // eax + int v4; // edi + int v5; // eax + int v6; // ebx + int v7; // eax + int v8; // ecx + char v9; // dl + bool v10; // eax + int v11; // esi + signed int v12; // ecx + signed int v13; // edi + signed int v14; // edx + signed int v15; // eax + int v16; // ebx + char *v17; // eax + signed int v18; // edx + int k; // eax + int v20; // ebx + int v21; // ebx + char *v22; // eax + int v23; // ebx + signed int v24; // edx + int v25; // eax + int v26; // esi + int v27; // edx + int v28; // esi + int v29; // edx + int v30; // edx + signed int v31; // ebx + int v32; // edi + int v33; // ecx + char *v34; // eax + int v35; // edi + int v36; // edx + signed int v37; // ecx + signed int v38; // eax + int v39; // edx + int v40; // edx + int v41; // edx + signed int v42; // ebx + int j; // edi + int v44; // ecx + char *v45; // eax + int v46; // edi + int v47; // [esp-4h] [ebp-30h] + signed int v48; // [esp+Ch] [ebp-20h] + signed int y1f; // [esp+10h] [ebp-1Ch] + signed int y2f; // [esp+14h] [ebp-18h] + signed int x2f; // [esp+18h] [ebp-14h] + signed int x1f; // [esp+1Ch] [ebp-10h] + int x2; // [esp+20h] [ebp-Ch] + int x2a; // [esp+20h] [ebp-Ch] + int y1; // [esp+24h] [ebp-8h] + int y1a; // [esp+24h] [ebp-8h] + int y1b; // [esp+24h] [ebp-8h] + int y2; // [esp+28h] [ebp-4h] + int y2a; // [esp+28h] [ebp-4h] + int y2b; // [esp+28h] [ebp-4h] + + v48 = 0; + for ( i = DL2_NumNoChar(); i > 700 && v48 < 100; i = DL2_NumNoChar() ) + { + v2 = random(0, 38); + v4 = v2 + 1; + v5 = random(0, 38); + v6 = v5 + 1; + v7 = v5 + 1 + 40 * v4; + if ( predungeon[0][v7] != 35 ) + continue; + y2f = 0; + y1f = 0; + x2f = 0; + x1f = 0; + v8 = predungeon[-1][v7]; // *((unsigned char *)&VR1 + v7); + if ( (_BYTE)v8 == 32 && predungeon[1][v7] == 46 ) + { + if ( predungeon[0][v7 + 39] != 46 + || predungeon[1][v7 + 1] != 46 + || predungeon[-1][v7 - 1] != 32 // *((_BYTE *)&HR3 + v7 + 3) != 32 + || predungeon[-1][v7 + 1] != 32 ) // *((_BYTE *)&VR1 + v7 + 1) != 32 ) + { + goto LABEL_34; + } + y1f = 1; +LABEL_32: + x1f = 1; +LABEL_33: + y2f = 1; + goto LABEL_34; + } + if ( predungeon[1][v7] == 32 && (_BYTE)v8 == 46 ) + { + if ( predungeon[-1][v7 - 1] != 46 // *((_BYTE *)&HR3 + v7 + 3) != 46 + || predungeon[-1][v7 + 1] != 46 // *((_BYTE *)&VR1 + v7 + 1) != 46 + || predungeon[0][v7 + 39] != 32 + || predungeon[1][v7 + 1] != 32 ) + { + goto LABEL_34; + } + y1f = 1; + x2f = 1; + goto LABEL_33; + } + v9 = predungeon[0][v7 - 1]; /* *((_BYTE *)&nRoomCnt + v7 + 3); */ + if ( v9 != 32 || predungeon[0][v7 + 1] != 46 ) + { + if ( predungeon[0][v7 + 1] != 32 + || v9 != 46 + || predungeon[-1][v7 - 1] != 46 // *((_BYTE *)&HR3 + v7 + 3) != 46 + || predungeon[0][v7 + 39] != 46 + || predungeon[-1][v7 + 1] != 32 + || predungeon[1][v7 + 1] != 32 ) + { + goto LABEL_34; + } + x2f = 1; + goto LABEL_32; + } + if ( predungeon[-1][v7 + 1] == 46 + && predungeon[1][v7 + 1] == 46 + && predungeon[-1][v7 - 1] == 32 // *((_BYTE *)&HR3 + v7 + 3) == 32 + && predungeon[0][v7 + 39] == 32 ) + { + x2f = 1; + x1f = 1; + y1f = 1; + v10 = DL2_Cont(1, 1, 1, 0); + goto LABEL_35; + } +LABEL_34: + v10 = DL2_Cont(x1f, y1f, x2f, y2f); +LABEL_35: + if ( v10 ) + { + v11 = v4 - 1; + if ( !x1f ) + v11 = v4; + v12 = x2f; + if ( x2f ) + ++v4; + x2 = v4; + v13 = y1f; + if ( y1f ) + y1 = v6 - 1; + else + y1 = v6; + v14 = y2f; + if ( y2f ) + ++v6; + v15 = x1f; + y2 = v6; + if ( x1f ) + { + if ( x2f ) + { + if ( y1f ) + { + if ( y2f ) + goto LABEL_177; + v37 = x1f; + v38 = x2f; + v39 = x2; + while ( v37 || v38 ) + { + if ( !v11 ) + v37 = 0; + if ( v39 == 39 ) + v38 = 0; + if ( v39 - v11 >= 14 ) + { + v37 = 0; + v38 = 0; + } + if ( v37 ) + --v11; + if ( v38 ) + ++v39; + if ( predungeon[v11][y1] != 32 ) + v37 = 0; + if ( predungeon[v39][y1] != 32 ) + v38 = 0; + } + v28 = v11 + 2; + v40 = v39 - 2; + x2a = v40; + v41 = v40 - v28; + if ( v41 <= 5 ) + goto LABEL_177; + v42 = y1f; + for ( j = y1; ; --j ) + { + if ( !j ) + v42 = 0; + if ( y2 - j >= 12 ) + v42 = 0; + if ( v28 <= x2a ) + { + v44 = v41 + 1; + v45 = &predungeon[v28][j]; + do + { + if ( *v45 != 32 ) + v42 = 0; + v45 += 40; + --v44; + } + while ( v44 ); + } + if ( !v42 ) + break; + } + v46 = j + 2; + if ( y2 - v46 <= 5 ) + goto LABEL_177; + DL2_DrawRoom(v28, v46, x2a, y2); + v36 = v46; + v47 = y2; + } + else + { + v27 = x2; + while ( v15 || v12 ) + { + if ( !v11 ) + v15 = 0; + if ( v27 == 39 ) + v12 = 0; + if ( v27 - v11 >= 14 ) + { + v15 = 0; + v12 = 0; + } + if ( v15 ) + --v11; + if ( v12 ) + ++v27; + if ( predungeon[v11][v6] != 32 ) + v15 = 0; + if ( predungeon[v27][v6] != 32 ) + v12 = 0; + } + v28 = v11 + 2; + v29 = v27 - 2; + x2a = v29; + v30 = v29 - v28; + if ( v30 <= 5 ) + goto LABEL_177; + v31 = y2f; + v32 = y2; + if ( y2f ) + { + while ( 1 ) + { + if ( v32 == 39 ) + v31 = 0; + if ( v32 - y1 >= 12 ) + v31 = 0; + if ( v28 <= x2a ) + { + v33 = v30 + 1; + v34 = &predungeon[v28][v32]; + do + { + if ( *v34 != 32 ) + v31 = 0; + v34 += 40; + --v33; + } + while ( v33 ); + } + if ( !v31 ) + break; + ++v32; + } + } + v35 = v32 - 2; + if ( v35 - y1 <= 5 ) + goto LABEL_177; + DL2_DrawRoom(v28, y1, x2a, v35); + v36 = y1; + v47 = v35; + } + DL2_KnockWalls(v28, v36, x2a, v47); + } + else + { + v21 = y1; + while ( v13 || v14 ) + { + if ( !v21 ) + v13 = 0; + if ( y2 == 39 ) + v14 = 0; + if ( y2 - v21 >= 14 ) + { + v13 = 0; + v14 = 0; + } + if ( v13 ) + --v21; + if ( v14 ) + ++y2; + v22 = predungeon[v11]; + if ( v22[v21] != 32 ) + v13 = 0; + if ( v22[y2] != 32 ) + v14 = 0; + } + y2b = y2 - 2; + v23 = v21 + 2; + y1b = v23; + if ( y2b - v23 > 5 ) + { + v24 = x1f; + while ( 1 ) + { + if ( !v11 ) + v24 = 0; + if ( x2 - v11 >= 12 ) + v24 = 0; + v25 = v23; + if ( v23 <= y2b ) + { + do + { + if ( predungeon[v11][v25] != 32 ) + v24 = 0; + ++v25; + } + while ( v25 <= y2b ); + v23 = y1b; + } + if ( !v24 ) + break; + --v11; + } + v26 = v11 + 2; + if ( x2 - v26 > 5 ) + { + DL2_DrawRoom(v26, v23, x2, y2b); + DL2_KnockWalls(v26, v23, x2, y2b); + } + } + } + } + else + { + v16 = x2; + while ( v13 || v14 ) + { + if ( !y1 ) + v13 = 0; + if ( y2 == 39 ) + v14 = 0; + if ( y2 - y1 >= 14 ) + { + v13 = 0; + v14 = 0; + } + if ( v13 ) + --y1; + if ( v14 ) + ++y2; + v17 = predungeon[x2]; + if ( v17[y1] != 32 ) + v13 = 0; + if ( v17[y2] != 32 ) + v14 = 0; + } + y2a = y2 - 2; + y1a = y1 + 2; + if ( y2a - y1a > 5 ) + { + v18 = x2f; + if ( x2f ) + { + while ( 1 ) + { + if ( v16 == 39 ) + v18 = 0; + if ( v16 - v11 >= 12 ) + v18 = 0; + for ( k = y1a; k <= y2a; ++k ) + { + if ( predungeon[v16][k] != 32 ) + v18 = 0; + } + if ( !v18 ) + break; + ++v16; + } + } + v20 = v16 - 2; + if ( v20 - v11 > 5 ) + { + DL2_DrawRoom(v11, y1a, v20, y2a); + DL2_KnockWalls(v11, y1a, v20, y2a); + } + } + } + } +LABEL_177: + ++v48; + } + return DL2_NumNoChar() <= 700; +} + +bool __fastcall DL2_Cont(bool x1f, bool y1f, bool x2f, bool y2f) +{ + bool v4; // zf + + if ( x1f && x2f ) + { + if ( !y1f ) + goto LABEL_16; + if ( y2f ) + return 0; + if ( !y1f ) + { +LABEL_16: + v4 = y2f == 0; + goto LABEL_11; + } + return 1; + } + if ( !y1f || !y2f ) + return 0; + if ( x1f ) + return 1; + v4 = x2f == 0; +LABEL_11: + if ( !v4 ) + return 1; + return 0; +} + +int __cdecl DL2_NumNoChar() +{ + int result; // eax + signed int v1; // edx + _BYTE *v2; // ecx + signed int v3; // esi + + result = 0; + v1 = 0; + do + { + v2 = (unsigned char *)predungeon + v1; + v3 = 40; + do + { + if ( *v2 == 32 ) + ++result; + v2 += 40; + --v3; + } + while ( v3 ); + ++v1; + } + while ( v1 < 40 ); + return result; +} + +void __fastcall DL2_DrawRoom(int x1, int y1, int x2, int y2) +{ + int v4; // ebx + char *v5; // edx + int v6; // esi + int i; // esi + char *v8; // esi + int v9; // eax + int v10; // [esp+Ch] [ebp-4h] + + v4 = y1; + v10 = y1; + while ( v4 <= y2 ) + { + if ( x1 <= x2 ) + { + v5 = &predungeon[x1][v4]; + v6 = x2 - x1 + 1; + do + { + *v5 = 46; + v5 += 40; + --v6; + } + while ( v6 ); + } + ++v4; + } + for ( i = v10; i <= y2; ++i ) + { + predungeon[x1][i] = 35; + predungeon[x2][i] = 35; + } + if ( x1 <= x2 ) + { + v8 = &predungeon[x1][y2]; + v9 = x2 - x1 + 1; + do + { + v8[v10 - y2] = 35; + *v8 = 35; + v8 += 40; + --v9; + } + while ( v9 ); + } +} + +void __fastcall DL2_KnockWalls(int x1, int y1, int x2, int y2) +{ + int v4; // esi + char *v5; // ebx + char *v6; // eax + int v7; // edi + int v8; // eax + int v9; // ecx + char *v10; // edx + char *v11; // esi + + v4 = x1 + 1; + if ( x1 + 1 < x2 ) + { + v5 = &predungeon[v4][y2 + 1]; + v6 = &predungeon[v4][y1 - 1]; // (char *)&nRoomCnt + 40 * v4 + y1 + 3; /* check */ + v7 = x2 - v4; + do + { + if ( *v6 == 46 && v6[2] == 46 ) + v6[1] = 46; + if ( v6[y2 - y1] == 46 && *v5 == 46 ) + *(v5 - 1) = 46; + if ( *v6 == 68 ) + *v6 = 46; + if ( *v5 == 68 ) + *v5 = 46; + v6 += 40; + v5 += 40; + --v7; + } + while ( v7 ); + } + v8 = y1 + 1; + if ( y1 + 1 < y2 ) + { + v9 = x1; + v10 = predungeon[x2 + 1]; + do + { + v11 = &predungeon[v9 - 1][v8]; // (char *)&VR1 + v9 * 40 + v8; + if ( *v11 == 46 && predungeon[v9 + 1][v8] == 46 ) + predungeon[v9][v8] = 46; + if ( v10[v8 - 80] == 46 && v10[v8] == 46 ) + v10[v8 - 40] = 46; + if ( *v11 == 68 ) + *v11 = 46; + if ( v10[v8] == 68 ) + v10[v8] = 46; + ++v8; + } + while ( v8 < y2 ); + } +} + +void __cdecl DRLG_L2FloodTVal() +{ + int v0; // ebx + int v1; // esi + char *v2; // edi + _BYTE *v3; // [esp+Ch] [ebp-Ch] + signed int x; // [esp+10h] [ebp-8h] + signed int i; // [esp+14h] [ebp-4h] + + v0 = 16; + v1 = 0; + do + { + i = 0; + x = 16; + v2 = &dung_map[16][v0]; + v3 = (unsigned char *)dungeon + v1; + do + { + if ( *v3 == 3 && !*v2 ) + { + DRLG_L2FTVR(i, v1, x, v0, 0); + ++TransVal; + } + x += 2; + v3 += 40; + v2 += 224; + ++i; + } + while ( i < 40 ); + v0 += 2; + ++v1; + } + while ( v1 < 40 ); +} +// 5A5590: using guessed type char TransVal; + +void __fastcall DRLG_L2FTVR(int i, int j, int x, int y, int d) +{ + int v5; // ebx + int v6; // esi + int v7; // edi + int v8; // edx + int v9; // ecx + int v10; // ebx + int v11; // eax + int v12; // edi + char v13; // al + char v14; // al + int v15; // ecx + int v16; // ecx + int v17; // ecx + int v18; // ecx + int v19; // [esp+Ch] [ebp-14h] + int k; // [esp+10h] [ebp-10h] + int v21; // [esp+14h] [ebp-Ch] + int ja; // [esp+18h] [ebp-8h] + int ia; // [esp+1Ch] [ebp-4h] + int ya; // [esp+2Ch] [ebp+Ch] + + v5 = x; + v6 = y; + v7 = j; + v8 = i; + v9 = 112 * x + y; + ja = v7; + v21 = v8; + if ( !dung_map[0][v9] ) + { + v19 = x; + ia = v8 - 1; + v10 = x - 2; + v11 = 40 * v8; + ya = v7 - 1; + v12 = v6 - 2; + for ( k = 40 * v8; dungeon[0][v11 + ja] == 3; v11 = k ) + { + v13 = TransVal; + dung_map[0][v9] = TransVal; + dung_map[1][v9] = v13; + dung_map[0][v9 + 1] = v13; + dung_map[1][v9 + 1] = v13; + DRLG_L2FTVR(ia + 2, ja, v10 + 4, v6, 1); + DRLG_L2FTVR(ia, ja, v10, v6, 2); + DRLG_L2FTVR(v21, ya + 2, x, v12 + 4, 3); + DRLG_L2FTVR(v21, ya, x, v12, 4); + DRLG_L2FTVR(ia, ya, v10, v12, 5); + DRLG_L2FTVR(ia + 2, ya, v10 + 4, v12, 6); + DRLG_L2FTVR(ia, ya + 2, v10, v12 + 4, 7); + v19 += 2; + k += 40; + d = 8; + x += 2; + v6 += 2; + v12 += 2; + v10 += 2; + ++ja; + ++ya; + ++v21; + ++ia; + v9 = v19 * 112 + v6; + if ( dung_map[v19][v6] ) + break; + } + v5 = x; + } + v14 = TransVal; + if ( d == 1 ) + { + v15 = v6 + 112 * v5; + dung_map[0][v15] = TransVal; + dung_map[0][v15 + 1] = v14; + } + if ( d == 2 ) + { + v16 = v6 + 112 * v5; + dung_map[1][v16] = v14; + dung_map[1][v16 + 1] = v14; + } + if ( d == 3 ) + { + v17 = v6 + 112 * v5; + dung_map[0][v17] = v14; + dung_map[1][v17] = v14; + } + if ( d == 4 ) + { + v18 = v6 + 112 * v5; + dung_map[0][v18 + 1] = v14; + dung_map[1][v18 + 1] = v14; + } + if ( d == 5 ) + dung_map[v5 + 1][v6 + 1] = v14; + if ( d == 6 ) + dung_map[v5][v6 + 1] = v14; + if ( d == 7 ) + dung_map[v5 + 1][v6] = v14; + if ( d == 8 ) + dung_map[v5][v6] = v14; +} +// 5A5590: using guessed type char TransVal; + +void __cdecl DRLG_L2TransFix() +{ + signed int v0; // esi + char *v1; // eax + char *v2; // ecx + signed int v3; // edi + char v4; // bl + char v5; // dl + char v6; // dl + char v7; // dl + char v8; // dl + char v9; // dl + char *v10; // [esp+Ch] [ebp-4h] + + v0 = 0; + v10 = &dung_map[16][16]; + do + { + v1 = v10; + v2 = (char *)dungeon + v0; + v3 = 40; + do + { + v4 = *v2; + if ( *v2 == 14 && *(v2 - 1) == 10 ) + { + v5 = *v1; + v1[112] = *v1; + v1[113] = v5; + } + if ( v4 == 15 && v2[40] == 11 ) + { + v6 = *v1; + v1[1] = *v1; + v1[113] = v6; + } + if ( v4 == 10 ) + { + v7 = *v1; + v1[112] = *v1; + v1[113] = v7; + } + if ( v4 == 11 ) + { + v8 = *v1; + v1[1] = *v1; + v1[113] = v8; + } + if ( v4 == 16 ) + { + v9 = *v1; + v1[112] = *v1; + v1[1] = v9; + v1[113] = v9; + } + v1 += 224; + v2 += 40; + --v3; + } + while ( v3 ); + v10 += 2; + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl L2DirtFix() +{ + signed int v0; // ecx + char *v1; // eax + signed int v2; // edx + + v0 = 0; + do + { + v1 = (char *)dungeon + v0; + v2 = 40; + do + { + if ( *v1 == 13 && v1[40] != 11 ) + *v1 = -110; + if ( *v1 == 11 && v1[40] != 11 ) + *v1 = -112; + if ( *v1 == 15 && v1[40] != 11 ) + *v1 = -108; + if ( *v1 == 10 && v1[1] != 10 ) + *v1 = -113; + if ( *v1 == 13 && v1[1] != 10 ) + *v1 = -110; + if ( *v1 == 14 && v1[1] != 15 ) + *v1 = -109; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl DRLG_InitL2Vals() +{ + int v0; // edi + int (*v1)[112]; // ebx + char *v2; // ecx + int (*v3)[112]; // edx + signed int v4; // esi + int v5; // eax + int v6; // ecx + int (*v7)[112]; // esi + char *v8; // eax + int (*v9)[112]; // edx + signed int v10; // ebx + int v11; // edi + char v12; // [esp-4h] [ebp-14h] + + v0 = 0; + v1 = dPiece; + do + { + v2 = (char *)dArch + v0; + v3 = v1; + v4 = 112; + do + { + v5 = (*v3)[0]; + if ( (*v3)[0] != 541 && v5 != 178 && v5 != 551 ) + { + if ( v5 == 542 || v5 == 553 ) + goto LABEL_11; + if ( v5 != 13 ) + { + if ( v5 != 17 ) + goto LABEL_13; +LABEL_11: + v12 = 6; + goto LABEL_12; + } + } + v12 = 5; +LABEL_12: + *v2 = v12; +LABEL_13: + ++v3; + v2 += 112; + --v4; + } + while ( v4 ); + v1 = (int (*)[112])((char *)v1 + 4); + ++v0; + } + while ( (signed int)v1 < (signed int)dPiece[1] ); + v6 = 0; + v7 = dPiece; + do + { + v8 = &dArch[0][v6 + 2]; + v9 = v7; + v10 = 112; + do + { + v11 = (*v9)[0]; + if ( (*v9)[0] == 132 ) + { + *(v8 - 1) = 2; + *v8 = 1; + } + else if ( v11 == 135 || v11 == 139 ) + { + v8[110] = 3; + v8[222] = 4; + } + ++v9; + v8 += 112; + --v10; + } + while ( v10 ); + v7 = (int (*)[112])((char *)v7 + 4); + ++v6; + } + while ( (signed int)v7 < (signed int)dPiece[1] ); +} diff --git a/Source/drlg_l2.h b/Source/drlg_l2.h new file mode 100644 index 000000000..06220688e --- /dev/null +++ b/Source/drlg_l2.h @@ -0,0 +1,173 @@ +//HEADER_GOES_HERE +#ifndef __DRLG_L2_H__ +#define __DRLG_L2_H__ + +extern int nSx1; +extern int nSx2; // weak +extern int nSy1; +extern int nSy2; // weak +extern int nRoomCnt; +extern char predungeon[40][40]; +extern ROOMNODE RoomList[81]; +extern HALLNODE *pHallList; + +void __cdecl InitDungeon(); +void __cdecl L2LockoutFix(); +void __cdecl L2DoorFix(); +void __fastcall LoadL2Dungeon(char *sFileName, int vx, int vy); +void __cdecl DRLG_L2Pass3(); +void __fastcall LoadPreL2Dungeon(char *sFileName, int vx, int vy); +void __fastcall CreateL2Dungeon(int rseed, int entry); +void __cdecl DRLG_LoadL2SP(); +void __cdecl DRLG_FreeL2SP(); +void __fastcall DRLG_L2(int entry); +bool __fastcall DRLG_L2PlaceMiniSet(unsigned char *miniset, int tmin, int tmax, int cx, int cy, bool setview, int ldir); +void __fastcall DRLG_L2PlaceRndSet(unsigned char *miniset, int rndper); +void __cdecl DRLG_L2Subs(); +void __cdecl DRLG_L2Shadows(); +void __fastcall DRLG_L2SetRoom(int rx1, int ry1); +void __cdecl L2TileFix(); +bool __cdecl CreateDungeon(); +void __fastcall CreateRoom(int nX1, int nY1, int nX2, int nY2, int nRDest, int nHDir, int ForceHW, int nH, int nW); +void __fastcall DefineRoom(int nX1, int nY1, int nX2, int nY2, int ForceHW); +void __fastcall AddHall(int nX1, int nY1, int nX2, int nY2, int nHd); +void __fastcall GetHall(int *nX1, int *nY1, int *nX2, int *nY2, int *nHd); +void __fastcall ConnectHall(int nX1, int nY1, int nX2, int nY2, int nHd); +void __fastcall CreateDoorType(int nX, int nY); +void __fastcall PlaceHallExt(int nX, int nY); +void __fastcall DoPatternCheck(int i, int j); +bool __cdecl DL2_FillVoids(); +bool __fastcall DL2_Cont(bool x1f, bool y1f, bool x2f, bool y2f); +int __cdecl DL2_NumNoChar(); +void __fastcall DL2_DrawRoom(int x1, int y1, int x2, int y2); +void __fastcall DL2_KnockWalls(int x1, int y1, int x2, int y2); +void __cdecl DRLG_L2FloodTVal(); +void __fastcall DRLG_L2FTVR(int i, int j, int x, int y, int d); +void __cdecl DRLG_L2TransFix(); +void __cdecl L2DirtFix(); +void __cdecl DRLG_InitL2Vals(); + +/* rdata */ +extern int Area_Min; // weak +extern int Room_Max; // weak +extern int Room_Min; // weak +extern int Dir_Xadd[5]; +extern int Dir_Yadd[5]; +extern ShadowStruct SPATSL2[2]; +//short word_48489A; +extern unsigned char BTYPESL2[161]; +extern unsigned char BSTYPESL2[161]; +extern unsigned char VARCH1[]; +extern unsigned char VARCH2[]; +extern unsigned char VARCH3[]; +extern unsigned char VARCH4[]; +extern unsigned char VARCH5[]; +extern unsigned char VARCH6[]; +extern unsigned char VARCH7[]; +extern unsigned char VARCH8[]; +extern unsigned char VARCH9[]; +extern unsigned char VARCH10[]; +extern unsigned char VARCH11[]; +extern unsigned char VARCH12[]; +extern unsigned char VARCH13[]; +extern unsigned char VARCH14[]; +extern unsigned char VARCH15[]; +extern unsigned char VARCH16[]; +extern unsigned char VARCH17[]; +extern unsigned char VARCH18[]; +extern unsigned char VARCH19[]; +extern unsigned char VARCH20[]; +extern unsigned char VARCH21[]; +extern unsigned char VARCH22[]; +extern unsigned char VARCH23[]; +extern unsigned char VARCH24[]; +extern unsigned char VARCH25[]; +extern unsigned char VARCH26[]; +extern unsigned char VARCH27[]; +extern unsigned char VARCH28[]; +extern unsigned char VARCH29[]; +extern unsigned char VARCH30[]; +extern unsigned char VARCH31[]; +extern unsigned char VARCH32[]; +extern unsigned char VARCH33[]; +extern unsigned char VARCH34[]; +extern unsigned char VARCH35[]; +extern unsigned char VARCH36[]; +extern unsigned char VARCH37[]; +extern unsigned char VARCH38[]; +extern unsigned char VARCH39[]; +extern unsigned char VARCH40[]; +extern unsigned char HARCH1[]; +extern unsigned char HARCH2[]; +extern unsigned char HARCH3[]; +extern unsigned char HARCH4[]; +extern unsigned char HARCH5[]; +extern unsigned char HARCH6[]; +extern unsigned char HARCH7[]; +extern unsigned char HARCH8[]; +extern unsigned char HARCH9[]; +extern unsigned char HARCH10[]; +extern unsigned char HARCH11[]; +extern unsigned char HARCH12[]; +extern unsigned char HARCH13[]; +extern unsigned char HARCH14[]; +extern unsigned char HARCH15[]; +extern unsigned char HARCH16[]; +extern unsigned char HARCH17[]; +extern unsigned char HARCH18[]; +extern unsigned char HARCH19[]; +extern unsigned char HARCH20[]; +extern unsigned char HARCH21[]; +extern unsigned char HARCH22[]; +extern unsigned char HARCH23[]; +extern unsigned char HARCH24[]; +extern unsigned char HARCH25[]; +extern unsigned char HARCH26[]; +extern unsigned char HARCH27[]; +extern unsigned char HARCH28[]; +extern unsigned char HARCH29[]; +extern unsigned char HARCH30[]; +extern unsigned char HARCH31[]; +extern unsigned char HARCH32[]; +extern unsigned char HARCH33[]; +extern unsigned char HARCH34[]; +extern unsigned char HARCH35[]; +extern unsigned char HARCH36[]; +extern unsigned char HARCH37[]; +extern unsigned char HARCH38[]; +extern unsigned char HARCH39[]; +extern unsigned char HARCH40[]; +extern unsigned char USTAIRS[]; +extern unsigned char DSTAIRS[]; +extern unsigned char WARPSTAIRS[]; +extern unsigned char CRUSHCOL[]; +extern unsigned char BIG1[]; +extern unsigned char BIG2[]; +extern unsigned char BIG3[]; +extern unsigned char BIG4[]; +extern unsigned char BIG5[]; +extern unsigned char BIG6[]; +extern unsigned char BIG7[]; +extern unsigned char BIG8[]; +extern unsigned char BIG9[]; +extern unsigned char BIG10[]; +extern unsigned char RUINS1[]; +extern unsigned char RUINS2[]; +extern unsigned char RUINS3[]; +extern unsigned char RUINS4[]; +extern unsigned char RUINS5[]; +extern unsigned char RUINS6[]; +extern unsigned char RUINS7[]; +extern unsigned char PANCREAS1[]; +extern unsigned char PANCREAS2[]; +extern unsigned char CTRDOOR1[]; +extern unsigned char CTRDOOR2[]; +extern unsigned char CTRDOOR3[]; +extern unsigned char CTRDOOR4[]; +extern unsigned char CTRDOOR5[]; +extern unsigned char CTRDOOR6[]; +extern unsigned char CTRDOOR7[]; +extern unsigned char CTRDOOR8[]; +extern int Patterns[100][10]; + +#endif /* __DRLG_L2_H__ */ diff --git a/Source/drlg_l3.cpp b/Source/drlg_l3.cpp new file mode 100644 index 000000000..fd93caa84 --- /dev/null +++ b/Source/drlg_l3.cpp @@ -0,0 +1,2946 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +char lavapool; // weak +int abyssx; // weak +int lockoutcnt; // weak +char lockout[40][40]; +#endif + +const unsigned char L3ConvTbl[16] = { 8, 11, 3, 10, 1, 9, 12, 12, 6, 13, 4, 13, 2, 14, 5, 7 }; +const unsigned char L3UP[20] = { 3, 3, 8, 8, 0, 10, 10, 0, 7, 7, 0, 51, 50, 0, 48, 49, 0, 0, 0, 0 }; +const unsigned char L3DOWN[20] = { 3, 3, 8, 9, 7, 8, 9, 7, 0, 0, 0, 0, 47, 0, 0, 46, 0, 0, 0, 0 }; +const unsigned char L3HOLDWARP[20] = { 3, 3, 8, 8, 0, 10, 10, 0, 7, 7, 0, 125, 125, 0, 125, 125, 0, 0, 0, 0 }; +const unsigned char L3TITE1[34] = { 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 57, 58, 0, 0, 56, 55, 0, 0, 0, 0, 0 }; +const unsigned char L3TITE2[34] = { 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 61, 62, 0, 0, 60, 59, 0, 0, 0, 0, 0 }; +const unsigned char L3TITE3[34] = { 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 65, 66, 0, 0, 64, 63, 0, 0, 0, 0, 0 }; +const unsigned char L3TITE6[42] = { 5, 4, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 77, 78, 0, 0, 0, 76, 74, 75, 0, 0, 0, 0, 0, 0 }; +const unsigned char L3TITE7[42] = { 4, 5, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 83, 0, 0, 0, 82, 80, 0, 0, 81, 79, 0, 0, 0, 0, 0 }; +const unsigned char L3TITE8[20] = { 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 52, 0, 0, 0, 0 }; +const unsigned char L3TITE9[20] = { 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 53, 0, 0, 0, 0 }; +const unsigned char L3TITE10[20] = { 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 54, 0, 0, 0, 0 }; +const unsigned char L3TITE11[20] = { 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 67, 0, 0, 0, 0 }; +const unsigned char L3TITE12[6] = { 2u, 1u, 9u, 7u, 68u, 0u }; +const unsigned char L3TITE13[6] = { 1u, 2u, 10u, 7u, 69u, 0u }; +const unsigned char L3CREV1[6] = { 2u, 1u, 8u, 7u, 84u, 85u }; +const unsigned char L3CREV2[6] = { 2u, 1u, 8u, 11u, 86u, 87u }; +const unsigned char L3CREV3[6] = { 1u, 2u, 8u, 10u, 89u, 88u }; +const unsigned char L3CREV4[6] = { 2u, 1u, 8u, 7u, 90u, 91u }; +const unsigned char L3CREV5[6] = { 1u, 2u, 8u, 11u, 92u, 93u }; +const unsigned char L3CREV6[6] = { 1u, 2u, 8u, 10u, 95u, 94u }; +const unsigned char L3CREV7[6] = { 2u, 1u, 8u, 7u, 96u, 101u }; +const unsigned char L3CREV8[6] = { 1u, 2u, 2u, 8u, 102u, 97u }; +const unsigned char L3CREV9[6] = { 2u, 1u, 3u, 8u, 103u, 98u }; +const unsigned char L3CREV10[6] = { 2u, 1u, 4u, 8u, 104u, 99u }; +const unsigned char L3CREV11[6] = { 1u, 2u, 6u, 8u, 105u, 100u }; +const unsigned char L3ISLE1[14] = { 2u, 3u, 5u, 14u, 4u, 9u, 13u, 12u, 7u, 7u, 7u, 7u, 7u, 7u }; +const unsigned char L3ISLE2[14] = { 3u, 2u, 5u, 2u, 14u, 13u, 10u, 12u, 7u, 7u, 7u, 7u, 7u, 7u }; +const unsigned char L3ISLE3[14] = { 2u, 3u, 5u, 14u, 4u, 9u, 13u, 12u, 29u, 30u, 25u, 28u, 31u, 32u }; +const unsigned char L3ISLE4[14] = { 3u, 2u, 5u, 2u, 14u, 13u, 10u, 12u, 29u, 26u, 30u, 31u, 27u, 32u }; +const unsigned char L3ISLE5[10] = { 2u, 2u, 5u, 14u, 13u, 12u, 7u, 7u, 7u, 7u }; +const unsigned char L3XTRA1[4] = { 1u, 1u, 7u, 106u }; +const unsigned char L3XTRA2[4] = { 1u, 1u, 7u, 107u }; +const unsigned char L3XTRA3[4] = { 1u, 1u, 7u, 108u }; +const unsigned char L3XTRA4[4] = { 1u, 1u, 9u, 109u }; +const unsigned char L3XTRA5[4] = { 1u, 1u, 10u, 110u }; +const unsigned char L3ANVIL[244] = +{ + 11, 11, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 29, 26, 26, 26, + 26, 26, 30, 0, 0, 0, 29, 34, 33, 33, + 37, 36, 33, 35, 30, 0, 0, 25, 33, 37, + 27, 32, 31, 36, 33, 28, 0, 0, 25, 37, + 32, 7, 7, 7, 31, 27, 32, 0, 0, 25, + 28, 7, 7, 7, 7, 2, 2, 2, 0, 0, + 25, 35, 30, 7, 7, 7, 29, 26, 30, 0, + 0, 25, 33, 35, 26, 30, 29, 34, 33, 28, + 0, 0, 31, 36, 33, 33, 35, 34, 33, 37, + 32, 0, 0, 0, 31, 27, 27, 27, 27, 27, + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 +}; +const unsigned char L3SpawnTbl1[15] = { 0u, 10u, 67u, 5u, 44u, 6u, 9u, 0u, 0u, 28u, 131u, 6u, 9u, 10u, 5u }; /* local spawntable? */ +const unsigned char L3SpawnTbl2[15] = { 0u, 10u, 3u, 5u, 12u, 6u, 9u, 0u, 0u, 12u, 3u, 6u, 9u, 10u, 5u }; /* local spawntable? */ +const unsigned char L3PoolSub[15] = { 0u, 35u, 26u, 36u, 25u, 29u, 34u, 7u, 33u, 28u, 27u, 37u, 32u, 31u, 30u }; /* local poolsub? */ + +void __cdecl AddFenceDoors() +{ + signed int v0; // esi + char *v1; // eax + signed int v2; // ebx + unsigned char v3; // cl + char v4; // cl + char v5; // cl + + v0 = 0; + do + { + v1 = &dungeon[-1][v0 + 39]; + v2 = 40; + do + { + if ( v1[1] == 7 ) + { + v3 = *(v1 - 39); + if ( v3 > 0x98u + || v3 < 0x82u + || (v4 = v1[41], (unsigned char)v4 > 0x98u) + || (unsigned char)v4 < 0x82u ) + { + if ( (unsigned char)*v1 <= 0x98u && (unsigned char)*v1 >= 0x82u ) + { + v5 = v1[2]; + if ( (unsigned char)v5 <= 0x98u && (unsigned char)v5 >= 0x82u ) + v1[1] = -109; + } + } + else + { + v1[1] = -110; + } + } + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl FenceDoorFix() +{ + signed int v0; // edi + char *v1; // eax + signed int v2; // esi + char v3; // bl + char v4; // cl + unsigned char v5; // cl + char v6; // dl + char v7; // cl + char v8; // cl + char v9; // dl + + v0 = 0; + do + { + v1 = &dungeon[-1][v0 + 39]; + v2 = 40; + do + { + v3 = v1[1]; + if ( v3 == -110 + && ((v4 = v1[41], (unsigned char)v4 > 0x98u) + || (unsigned char)v4 < 0x82u + || (v5 = *(v1 - 39), v5 > 0x98u) + || v5 < 0x82u + || (v6 = v1[41], v6 != -126) + && v5 != -126 + && v6 != -124 + && v5 != -124 + && v6 != -123 + && v5 != -123 + && v6 != -122 + && v5 != -122 + && v6 != -120 + && v5 != -120 + && v6 != -118 + && v5 != -118 + && v6 != -116 + && v5 != -116) + || v3 == -109 + && ((v7 = v1[2], (unsigned char)v7 > 0x98u) + || (unsigned char)v7 < 0x82u + || (v8 = *v1, (unsigned char)*v1 > 0x98u) + || (unsigned char)v8 < 0x82u + || (v9 = v1[2], v9 != -125) + && v8 != -125 + && v9 != -124 + && v8 != -124 + && v9 != -123 + && v8 != -123 + && v9 != -121 + && v8 != -121 + && v9 != -119 + && v8 != -119 + && v9 != -118 + && v8 != -118 + && v9 != -117 + && v8 != -117) ) + { + v1[1] = 7; + } + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +int __cdecl DRLG_L3Anvil() +{ + int v0; // esi + signed int v1; // edi + signed int v2; // ebx + signed int v3; // eax + int v4; // ecx + unsigned char v5; // dl + signed int v7; // ebx + int v8; // edi + int v9; // ecx + signed int v10; // eax + unsigned char v11; // dl + signed int v12; // [esp+Ch] [ebp-Ch] + signed int v13; // [esp+Ch] [ebp-Ch] + signed int v14; // [esp+10h] [ebp-8h] + int v15; // [esp+14h] [ebp-4h] + + v0 = random(0, 29); + v1 = 0; + v15 = random(0, 29); + v12 = 0; + while ( 1 ) + { + if ( v12 >= 200 ) + return 1; + ++v12; + v14 = 1; + v2 = 2; + do + { + if ( v14 != 1 ) + break; + v3 = 0; + v4 = v15 + v1 + 40 * v0; + do + { + if ( v14 != 1 ) + break; + v5 = L3ANVIL[v2]; + if ( v5 && dungeon[0][v4] != v5 ) + v14 = 0; + if ( dflags[0][v4] ) + v14 = 0; + ++v2; + ++v3; + v4 += 40; + } + while ( v3 < 11 ); + ++v1; + } + while ( v1 < 11 ); + v1 = 0; + if ( v14 ) + break; + if ( ++v0 == 29 ) + { + v0 = 0; + if ( ++v15 == 29 ) + v15 = 0; + } + } + if ( v12 >= 200 ) + return 1; + v13 = 11; + v7 = 123; + v8 = v15 + 40 * v0; + do + { + v9 = v8; + v10 = 11; + do + { + v11 = L3ANVIL[v7]; + if ( v11 ) + dungeon[0][v9] = v11; + dflags[0][v9] |= 0x80u; + ++v7; + v9 += 40; + --v10; + } + while ( v10 ); + ++v8; + --v13; + } + while ( v13 ); + setpc_y = v15; + setpc_w = 11; + setpc_h = 11; + setpc_x = v0; + return 0; +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __cdecl FixL3Warp() +{ + int v0; // ecx + signed int v1; // esi + char *v2; // eax + char v3; // dl + signed int v4; // eax + + v0 = 0; + while ( 2 ) + { + v1 = 0; + v2 = &dungeon[1][v0 + 1]; + do + { + v3 = *(v2 - 41); + if ( v3 == 125 && *(v2 - 1) == 125 && *(v2 - 40) == 125 && *v2 == 125 ) + { + v4 = v1; + dungeon[v4][v0] = -100; + dungeon[v4 + 1][v0] = -101; + dungeon[v4][v0 + 1] = -103; + dungeon[v4 + 1][v0 + 1] = -102; + return; + } + if ( v3 == 5 && *v2 == 7 ) + *(v2 - 41) = 7; + ++v1; + v2 += 40; + } + while ( v1 < 40 ); + if ( ++v0 < 40 ) + continue; + break; + } +} + +void __cdecl FixL3HallofHeroes() +{ + signed int v0; // ecx + char *v1; // eax + signed int v2; // edx + signed int v3; // ecx + char *v4; // eax + signed int v5; // edx + + v0 = 0; + do + { + v1 = (char *)dungeon + v0; + v2 = 40; + do + { + if ( *v1 == 5 && v1[41] == 7 ) + *v1 = 7; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); + v3 = 0; + do + { + v4 = (char *)dungeon + v3; + v5 = 40; + do + { + if ( *v4 == 5 ) + { + if ( v4[41] == 12 && v4[40] == 7 ) + { + *v4 = 7; + v4[1] = 7; + v4[41] = 7; + } + if ( *v4 == 5 && v4[41] == 12 && v4[1] == 7 ) + { + *v4 = 7; + v4[40] = 7; + v4[41] = 7; + } + } + v4 += 40; + --v5; + } + while ( v5 ); + ++v3; + } + while ( v3 < 40 ); +} + +void __fastcall DRLG_L3LockRec(int x, int y) +{ + int v2; // esi + int v3; // edi + char *v4; // eax + char *v5; // ebp + + v2 = x; + v3 = y; + v4 = &lockout[x][y]; + if ( *v4 ) + { + v5 = &lockout[x][y]; + do + { + *v4 = 0; + ++lockoutcnt; + DRLG_L3LockRec(v2, v3 - 1); + DRLG_L3LockRec(v2, v3 + 1); + DRLG_L3LockRec(v2 - 1, v3); + v5 += 40; + ++v2; + v4 = v5; + } + while ( *v5 ); + } +} +// 528380: using guessed type int lockoutcnt; + +bool __cdecl DRLG_L3Lockout() +{ + int v0; // esi + signed int v1; // edx + signed int v2; // ecx + signed int v3; // eax + int x; // [esp+4h] [ebp-8h] + int y; // [esp+8h] [ebp-4h] + + v0 = 0; + v1 = 0; + do + { + v2 = 0; + v3 = v1; + do + { + if ( dungeon[0][v3] ) + { + lockout[0][v3] = 1; + x = v2; + y = v1; + ++v0; + } + else + { + lockout[0][v3] = 0; + } + ++v2; + v3 += 40; + } + while ( v2 < 40 ); + ++v1; + } + while ( v1 < 40 ); + lockoutcnt = 0; + DRLG_L3LockRec(x, y); + return v0 == lockoutcnt; +} +// 528380: using guessed type int lockoutcnt; + +void __fastcall CreateL3Dungeon(int rseed, int entry) +{ + int v2; // esi + int v3; // edi + int v4; // esi + signed int v5; // eax + signed int *v6; // [esp+8h] [ebp-8h] + int (*v7)[112]; // [esp+Ch] [ebp-4h] + + v2 = entry; + SetRndSeed(rseed); + dminx = 16; + dminy = 16; + dmaxx = 96; + dmaxy = 96; + DRLG_InitTrans(); + DRLG_InitSetPC(); + DRLG_L3(v2); + DRLG_L3Pass3(); + v3 = 0; + v7 = dPiece; + do + { + v4 = 0; + v6 = (signed int *)v7; + do + { + v5 = *v6; + if ( *v6 >= 56 && v5 <= 147 || v5 >= 154 && v5 <= 161 || v5 == 150 || v5 == 152 ) + DoLighting(v4, v3, 7, -1); + v6 += 112; + ++v4; + } + while ( v4 < 112 ); + v7 = (int (*)[112])((char *)v7 + 4); + ++v3; + } + while ( (signed int)v7 < (signed int)dPiece[1] ); + DRLG_SetPC(); +} +// 5CF328: using guessed type int dmaxx; +// 5CF32C: using guessed type int dmaxy; +// 5D2458: using guessed type int dminx; +// 5D245C: using guessed type int dminy; + +void __fastcall DRLG_L3(int entry) +{ + int x1; // esi + int y1; // eax + int x2; // edi + int y2; // eax + int found; // eax + int genok; // eax + signed int i; // ecx + signed int j; // esi + bool v24; // [esp-8h] [ebp-20h] + + lavapool = 0; + do + { + do + { + do + { + InitL3Dungeon(); + x1 = random(0, 20) + 10; + y1 = random(0, 20); + DRLG_L3FillRoom(x1, y1 + 10, x1 + 2, y1 + 12); + DRLG_L3CreateBlock(x1, y1 + 10, 2, 0); + DRLG_L3CreateBlock(x1 + 2, y1 + 10, 2, 1); + DRLG_L3CreateBlock(x1, y1 + 12, 2, 2); + DRLG_L3CreateBlock(x1, y1 + 10, 2, 3); + + if ( QuestStatus(10) ) + { + x2 = random(0, 10) + 10; + y2 = random(0, 10); + DRLG_L3FloorArea(x2, y2 + 10, x2 + 12, y2 + 22); + } + DRLG_L3FillDiags(); + DRLG_L3FillSingles(); + DRLG_L3FillStraights(); + DRLG_L3FillDiags(); + DRLG_L3Edges(); + if ( DRLG_L3GetFloorArea() < 600 ) + found = 0; + else + found = DRLG_L3Lockout(); + } + while ( !found ); + DRLG_L3MakeMegas(); + if ( !entry ) + { + genok = DRLG_L3PlaceMiniSet(L3UP, 1, 1, -1, -1, 1, 0); + if ( genok ) + continue; + genok = DRLG_L3PlaceMiniSet(L3DOWN, 1, 1, -1, -1, 0, 1); + if ( genok ) + continue; + if ( currlevel != 9 ) + goto LABEL_24; + genok = DRLG_L3PlaceMiniSet(L3HOLDWARP, 1, 1, -1, -1, 0, 6); + goto LABEL_23; + } + genok = DRLG_L3PlaceMiniSet(L3UP, 1, 1, -1, -1, 0, 0); + if ( entry == 1 ) + { + if ( genok ) + continue; + genok = DRLG_L3PlaceMiniSet(L3DOWN, 1, 1, -1, -1, 1, 1); + ViewX += 2; + ViewY -= 2; + if ( genok ) + continue; + if ( currlevel != 9 ) + goto LABEL_24; + v24 = 0; +LABEL_22: + genok = DRLG_L3PlaceMiniSet(L3HOLDWARP, 1, 1, -1, -1, v24, 6); +LABEL_23: + if ( genok ) + continue; + goto LABEL_24; + } + if ( genok ) + continue; + genok = DRLG_L3PlaceMiniSet(L3DOWN, 1, 1, -1, -1, 0, 1); + if ( genok ) + continue; + if ( currlevel == 9 ) + { + v24 = 1; + goto LABEL_22; + } +LABEL_24: + if ( !QuestStatus(10) ) + break; + genok = DRLG_L3Anvil(); + } + while ( genok == 1 ); + DRLG_L3Pool(); + } + while ( !lavapool ); + DRLG_L3PoolFix(); + FixL3Warp(); + DRLG_L3PlaceRndSet(L3ISLE1, 70); + DRLG_L3PlaceRndSet(L3ISLE2, 70); + DRLG_L3PlaceRndSet(L3ISLE3, 30); + DRLG_L3PlaceRndSet(L3ISLE4, 30); + DRLG_L3PlaceRndSet(L3ISLE1, 100); + DRLG_L3PlaceRndSet(L3ISLE2, 100); + DRLG_L3PlaceRndSet(L3ISLE5, 90); + FixL3HallofHeroes(); + DRLG_L3River(); + + if ( QuestStatus(10) ) + { + dungeon[setpc_x + 7][setpc_y + 5] = 7; + dungeon[setpc_x + 8][setpc_y + 5] = 7; + dungeon[setpc_x + 9][setpc_y + 5] = 7; + if ( dungeon[setpc_x + 10][setpc_y + 5] == 17 + || dungeon[setpc_x + 10][setpc_y + 5] == 18 ) + dungeon[setpc_x + 10][setpc_y + 5] = 45; + } + + DRLG_PlaceThemeRooms(5, 10, 7, 0, 0); + DRLG_L3Wood(); + DRLG_L3PlaceRndSet(L3TITE1, 10); + DRLG_L3PlaceRndSet(L3TITE2, 10); + DRLG_L3PlaceRndSet(L3TITE3, 10); + DRLG_L3PlaceRndSet(L3TITE6, 20); + DRLG_L3PlaceRndSet(L3TITE7, 20); + DRLG_L3PlaceRndSet(L3TITE8, 20); + DRLG_L3PlaceRndSet(L3TITE9, 20); + DRLG_L3PlaceRndSet(L3TITE10, 20); + DRLG_L3PlaceRndSet(L3TITE11, 30); + DRLG_L3PlaceRndSet(L3TITE12, 20); + DRLG_L3PlaceRndSet(L3TITE13, 20); + DRLG_L3PlaceRndSet(L3CREV1, 30); + DRLG_L3PlaceRndSet(L3CREV2, 30); + DRLG_L3PlaceRndSet(L3CREV3, 30); + DRLG_L3PlaceRndSet(L3CREV4, 30); + DRLG_L3PlaceRndSet(L3CREV5, 30); + DRLG_L3PlaceRndSet(L3CREV6, 30); + DRLG_L3PlaceRndSet(L3CREV7, 30); + DRLG_L3PlaceRndSet(L3CREV8, 30); + DRLG_L3PlaceRndSet(L3CREV9, 30); + DRLG_L3PlaceRndSet(L3CREV10, 30); + DRLG_L3PlaceRndSet(L3CREV11, 30); + DRLG_L3PlaceRndSet(L3XTRA1, 25); + DRLG_L3PlaceRndSet(L3XTRA2, 25); + DRLG_L3PlaceRndSet(L3XTRA3, 25); + DRLG_L3PlaceRndSet(L3XTRA4, 25); + DRLG_L3PlaceRndSet(L3XTRA5, 25); + + for(i = 0; i < 40; i++) + { + for(j = 0; j < 40; j++) + pdungeon[i][j] = dungeon[i][j]; + } + + DRLG_Init_Globals(); +} +// 528378: using guessed type char lavapool; + +void __cdecl InitL3Dungeon() +{ + int i; // edx + int j; // ecx + + memset(dungeon, 0, 0x640u); + + for(i = 0; i < 40; i++) + { + for(j = 0; j < 40; j++) + { + dungeon[i][j] = 0; + dflags[i][j] = 0; + } + } +} + +int __fastcall DRLG_L3FillRoom(int x1, int y1, int x2, int y2) +{ + int v4; // esi + int v5; // eax + int v6; // edi + int v7; // edx + int v8; // ecx + char *v9; // ecx + int v10; // eax + int v11; // ebx + char *v12; // edx + int v13; // eax + int i; // ebx + int v16; // ecx + char *v17; // ebx + int v18; // edi + int v21; // [esp+Ch] [ebp-4h] + int x2a; // [esp+18h] [ebp+8h] + int y2a; // [esp+1Ch] [ebp+Ch] + + v4 = x1; + v5 = y1; + v21 = y1; + if ( x1 <= 1 ) + return 0; + v6 = x2; + if ( x2 >= 34 || y1 <= 1 || y2 >= 38 ) + return 0; + v7 = 0; + v8 = v5; + x2a = v5; + if ( v5 <= y2 ) + { + do + { + if ( v4 <= v6 ) + { + v9 = &dungeon[v4][v8]; + v10 = v6 - v4 + 1; + do + { + v7 += (unsigned char)*v9; + v9 += 40; + --v10; + } + while ( v10 ); + } + v8 = x2a++ + 1; + } + while ( x2a <= y2 ); + if ( !v7 ) + { + v5 = v21; + goto LABEL_12; + } + return 0; + } +LABEL_12: + v11 = v5 + 1; + if ( v5 + 1 < y2 ) + { + v8 = v4 + 1; + do + { + if ( v8 < v6 ) + { + v12 = &dungeon[v8][v11]; + v13 = v6 - v8; + do + { + *v12 = 1; + v12 += 40; + --v13; + } + while ( v13 ); + } + ++v11; + } + while ( v11 < y2 ); + v5 = v21; + } + for ( i = v5; i <= y2; ++i ) + { + if ( random(0, 2) ) + dungeon[v4][i] = 1; + if ( random(0, 2) ) + dungeon[v6][i] = 1; + } + if ( v4 <= v6 ) + { + v16 = y2; + v17 = &dungeon[v4][y2]; + v18 = v6 - v4 + 1; + y2a = v21 - y2; + do + { + if ( random(0, 2) ) + v17[y2a] = 1; + if ( random(0, 2) ) + *v17 = 1; + v17 += 40; + --v18; + } + while ( v18 ); + } + return 1; +} + +void __fastcall DRLG_L3CreateBlock(int x, int y, int obs, int dir) +{ + int v4; // esi + int v5; // edi + int v6; // eax + int v9; // ebx + bool v10; // zf + bool v11; // zf + int y2; // [esp+Ch] [ebp-14h] + int x2; // [esp+10h] [ebp-10h] + int i; // [esp+14h] [ebp-Ch] + int v16; // [esp+18h] [ebp-8h] + int max; // [esp+1Ch] [ebp-4h] + + v4 = obs; + v5 = obs; + v16 = y; + for ( i = x; ; i = v4 ) + { + v6 = random(0, 2); + max = v6 + 3; + v9 = random(0, 2) + 3; + if ( !dir ) + { + y2 = v16 - 1; + v5 = v16 - 1 - v9; + if ( max < obs ) + { + v4 = i + random(0, max); + } + if ( max == obs ) + v4 = i; + if ( max > obs ) + { + v4 = i - random(0, max); + } + x2 = v4 + max; + } + if ( dir == 3 ) + { + x2 = i - 1; + v4 = i - 1 - max; + v10 = v9 == obs; + if ( v9 < obs ) + { + v5 = v16 + random(0, v9); + v10 = v9 == obs; + } + if ( v10 ) + v5 = v16; + if ( v9 > obs ) + { + v5 = v16 - random(0, v9); + } + y2 = v5 + v9; + } + if ( dir == 2 ) + { + v5 = v16 + 1; + y2 = v16 + 1 + v9; + if ( max < obs ) + { + v4 = i + random(0, max); + } + if ( max == obs ) + v4 = i; + if ( max > obs ) + { + v4 = i - random(0, max); + } + x2 = v4 + max; + } + if ( dir == 1 ) + { + v4 = i + 1; + v11 = v9 == obs; + x2 = i + 1 + max; + if ( v9 < obs ) + { + v5 = v16 + random(0, v9); + v11 = v9 == obs; + } + if ( v11 ) + v5 = v16; + if ( v9 > obs ) + { + v5 = v16 - random(0, v9); + } + y2 = v5 + v9; + } + if ( DRLG_L3FillRoom(v4, v5, x2, y2) != 1 ) + break; + if ( !random(0, 4) ) + break; + if ( dir != 2 ) + DRLG_L3CreateBlock(v4, v5, v9, 0); + if ( dir != 3 ) + DRLG_L3CreateBlock(x2, v5, max, 1); + if ( dir ) + DRLG_L3CreateBlock(v4, y2, v9, 2); + if ( dir == 1 ) + break; + dir = 3; + obs = max; + v16 = v5; + } +} + +void __fastcall DRLG_L3FloorArea(int x1, int y1, int x2, int y2) +{ + int i; // esi + char *v5; // edx + int v6; // eax + + for ( i = y1; i <= y2; ++i ) + { + if ( x1 <= x2 ) + { + v5 = &dungeon[x1][i]; + v6 = x2 - x1 + 1; + do + { + *v5 = 1; + v5 += 40; + --v6; + } + while ( v6 ); + } + } +} + +void __cdecl DRLG_L3FillDiags() +{ + signed int v0; // ebx + char *v1; // esi + signed int v2; // ebp + int v3; // ecx + int v4; // edi + + v0 = 0; + do + { + v1 = &dungeon[1][v0 + 1]; + v2 = 39; + do + { + v3 = (unsigned char)*v1; + v4 = v3 + + 2 * ((unsigned char)*(v1 - 40) + 2 * ((unsigned char)*(v1 - 1) + 2 * (unsigned char)*(v1 - 41))); + if ( v4 == 6 ) + { + if ( !random(0, 2) ) + { + *(v1 - 41) = 1; + goto LABEL_11; + } + *v1 = 1; + } + if ( v4 == 9 ) + { + if ( random(0, 2) ) + *(v1 - 40) = 1; + else + *(v1 - 1) = 1; + } +LABEL_11: + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 39 ); +} + +void __cdecl DRLG_L3FillSingles() +{ + signed int v0; // ecx + char *v1; // eax + signed int v2; // edx + + v0 = 1; + do + { + v1 = &dungeon[0][v0 + 39]; + v2 = 38; + do + { + if ( !v1[1] + && (unsigned char)*v1 + (unsigned char)v1[40] + (unsigned char)*(v1 - 40) == 3 + && (unsigned char)*(v1 - 39) + (unsigned char)v1[41] == 2 + && (unsigned char)v1[2] + (unsigned char)*(v1 - 38) + (unsigned char)v1[42] == 3 ) + { + v1[1] = 1; + } + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 39 ); +} + +void __cdecl DRLG_L3FillStraights() +{ + int v0; // esi + char *v1; // ecx + signed int v2; // eax + char *v3; // ebx + int v4; // edi + int v5; // ebx + char v6; // al + char *v7; // ecx + signed int v8; // eax + char *v9; // ebx + int v10; // edi + int v11; // ebx + char v12; // al + signed int v13; // ebx + signed int v14; // eax + signed int v15; // esi + signed int i; // edi + signed int v17; // ebx + signed int v18; // eax + signed int v19; // esi + signed int j; // edi + //int v21; // [esp+Ch] [ebp-14h] + char *v22; // [esp+Ch] [ebp-14h] + char *v23; // [esp+Ch] [ebp-14h] + char *v24; // [esp+10h] [ebp-10h] + signed int v25; // [esp+14h] [ebp-Ch] + signed int v26; // [esp+14h] [ebp-Ch] + signed int v27; // [esp+18h] [ebp-8h] + signed int v28; // [esp+18h] [ebp-8h] + int v29; // [esp+1Ch] [ebp-4h] + int v30; // [esp+1Ch] [ebp-4h] + + v27 = 0; + v0 = 0; /* v21 */ + do + { + v1 = (char *)v27; + v2 = 0; + v29 = 0; + v3 = &dungeon[0][v27 + 1]; + v4 = 40 * v0; + v25 = 0; + v22 = &dungeon[0][v27 + 1]; + do + { + if ( *(v3 - 1) || *v3 != 1 ) + { + if ( v2 > 3 ) + { + if ( random(0, 2) ) + { + if ( v0 < v29 ) + { + v5 = v29 - v0; + v24 = (char *)dungeon + v4 + v27; + do + { + v6 = random(0, 2); + v1 = v24; + v24 += 40; + --v5; + *v1 = v6; + } + while ( v5 ); + v3 = v22; + } + } + } + v2 = 0; + } + else + { + if ( !v2 ) + { + v0 = v29; + v4 = v25; + } + ++v2; + } + v25 += 40; + ++v29; + v3 += 40; + v22 = v3; + } + while ( v25 < 1480 ); + ++v27; + } + while ( v27 < 39 ); + v28 = 0; + do + { + v7 = (char *)v28; + v8 = 0; + v30 = 0; + v9 = &dungeon[0][v28 + 1]; + v26 = 0; + v10 = 40 * v0; + v23 = &dungeon[0][v28 + 1]; + do + { + if ( *(v9 - 1) != 1 || *v9 ) + { + if ( v8 > 3 ) + { + if ( random(0, 2) ) + { + if ( v0 < v30 ) + { + v11 = v30 - v0; + v24 = &dungeon[0][v10 + 1 + v28]; + do + { + v12 = random(0, 2); + v7 = v24; + v24 += 40; + --v11; + *v7 = v12; + } + while ( v11 ); + v9 = v23; + } + } + } + v8 = 0; + } + else + { + if ( !v8 ) + { + v0 = v30; + v10 = v26; + } + ++v8; + } + v26 += 40; + ++v30; + v9 += 40; + v23 = v9; + } + while ( v26 < 1480 ); + ++v28; + } + while ( v28 < 39 ); + v13 = 0; + do + { + v14 = 0; + v15 = 0; + do + { + if ( dungeon[v13][v15] || dungeon[v13 + 1][v15] != 1 ) + { + if ( v14 > 3 ) + { + if ( random(0, 2) ) + { + for ( i = (signed int)v24; i < v15; ++i ) + { + dungeon[v13][i] = random(0, 2); + } + } + } + v14 = 0; + } + else + { + if ( !v14 ) + v24 = (char *)v15; + ++v14; + } + ++v15; + } + while ( v15 < 37 ); + ++v13; + } + while ( v13 < 39 ); + v17 = 0; + do + { + v18 = 0; + v19 = 0; + do + { + if ( dungeon[v17][v19] != 1 || dungeon[v17 + 1][v19] ) + { + if ( v18 > 3 ) + { + if ( random(0, 2) ) + { + for ( j = (signed int)v24; j < v19; ++j ) + { + dungeon[v17 + 1][j] = random(0, 2); + } + } + } + v18 = 0; + } + else + { + if ( !v18 ) + v24 = (char *)v19; + ++v18; + } + ++v19; + } + while ( v19 < 37 ); + ++v17; + } + while ( v17 < 39 ); +} + +void __cdecl DRLG_L3Edges() +{ + char *v0; // eax + + memset(dungeon[39], 0, sizeof(char[40])); + v0 = &dungeon[0][39]; + do + { + *v0 = 0; + v0 += 40; + } + while ( (signed int)v0 < (signed int)&dungeon[40][39] ); +} + +int __cdecl DRLG_L3GetFloorArea() +{ + int gfa; // eax + int i; // edx + int j; // esi + + gfa = 0; + + for(i = 0; i < 40; i++) + { + for(j = 0; j < 40; j++) + gfa += dungeon[i][j]; + } + + return gfa; +} + +void __cdecl DRLG_L3MakeMegas() +{ + signed int v0; // edi + char *v1; // esi + signed int v2; // ebp + int v3; // ecx + int v4; // eax + char *v5; // eax + + v0 = 0; + do + { + v1 = &dungeon[0][v0 + 1]; + v2 = 39; + do + { + v3 = (unsigned char)v1[40]; + v4 = v3 + 2 * ((unsigned char)*v1 + 2 * ((unsigned char)v1[39] + 2 * (unsigned char)*(v1 - 1))); + if ( v4 == 6 ) + { + if ( !random(0, 2) ) + { + v4 = 12; + goto LABEL_9; + } + v4 = 5; + } + if ( v4 == 9 ) + { + v4 = (random(0, 2) != 0) + 13; + } +LABEL_9: + --v2; + *(v1 - 1) = L3ConvTbl[v4]; + v1 += 40; + } + while ( v2 ); + dungeon[39][v0++] = 8; + } + while ( v0 < 39 ); + v5 = &dungeon[0][39]; + do + { + *v5 = 8; + v5 += 40; + } + while ( (signed int)v5 < (signed int)&dungeon[40][39] ); +} + +void __cdecl DRLG_L3River() +{ + signed int v0; // ebx + int v1; // esi + int v2; // edi + char v3; // al + char v4; // al + signed int v5; // edx + int v6; // eax + int v7; // ebx + unsigned char v8; // al + unsigned char v9; // al + int v10; // eax + char *v11; // eax + signed int v12; // eax + int v13; // ecx + bool v14; // zf + int v15; // eax + signed int v16; // eax + int v17; // eax + signed int v18; // eax + signed int v19; // eax + signed int v20; // edi + int v21; // eax + int v22; // eax + int v23; // edx + int v24; // ecx + int v25; // ecx + int v26; // esi + int v27; // ecx + int v28; // edx + int v29; // ecx + int v30; // edx + int v31; // ecx + int v32; // edx + bool v33; // sf + unsigned char v34; // of + int river[3][100]; // [esp+Ch] [ebp-4E8h] + int v36; // [esp+4BCh] [ebp-38h] + int v37; // [esp+4C0h] [ebp-34h] + int v38; // [esp+4C4h] [ebp-30h] + int v39; // [esp+4C8h] [ebp-2Ch] + int v40; // [esp+4CCh] [ebp-28h] + int v41; // [esp+4D0h] [ebp-24h] + int v42; // [esp+4D4h] [ebp-20h] + int v43; // [esp+4D8h] [ebp-1Ch] + int v44; // [esp+4DCh] [ebp-18h] + int v45; // [esp+4E0h] [ebp-14h] + int v46; // [esp+4E4h] [ebp-10h] + int v47; // [esp+4E8h] [ebp-Ch] + int v48; // [esp+4ECh] [ebp-8h] + int max; // [esp+4F0h] [ebp-4h] + + v0 = 0; + v39 = 0; + v41 = 0; + while ( v39 < 4 ) + { + v47 = 0; + do + { + if ( v41 >= 200 ) + { + v5 = max; + break; + } + ++v41; + v1 = 0; + v2 = 0; + while ( 1 ) + { + v3 = dungeon[v1][v2]; + if ( (unsigned char)v3 >= 0x19u && (unsigned char)v3 <= 0x1Cu ) + break; + if ( v0 >= 100 ) + return; + v1 = random(0, 40); + v2 = random(0, 40); + ++v0; + while ( 1 ) + { + v4 = dungeon[v1][v2]; + if ( (unsigned char)v4 >= 0x19u && (unsigned char)v4 <= 0x1Cu ) + break; + if ( v2 >= 40 ) + break; + if ( ++v1 >= 40 ) + { + v1 = 0; + ++v2; + } + } + } + if ( v0 >= 100 ) + return; + switch ( dungeon[v1][v2] ) + { + case 0x19: + v48 = 3; + v42 = 2; + river[2][0] = 40; + break; + case 0x1A: + v48 = 0; + v42 = 1; + river[2][0] = 38; + break; + case 0x1B: + v42 = 0; + v48 = 1; + river[2][0] = 41; + break; + case 0x1C: + v48 = 2; + v42 = 3; + river[2][0] = 39; + break; + } + v43 = 0; + max = 1; + v5 = 1; + river[0][0] = v1; + river[1][0] = v2; + v46 = 4; + v45 = 40 * v1; + while ( v5 < 100 ) + { + v38 = v1; + v36 = v45; + v37 = v2; + if ( v43 ) + { + v48 = ((_BYTE)v48 + 1) & 3; + v7 = v48; + } + else + { + v6 = random(0, 4); + v5 = max; + v7 = v6; + v48 = v6; + } + while ( 1 ) + { + ++v43; + if ( v7 != v42 && v7 != v46 ) + break; + v7 = ((_BYTE)v7 + 1) & 3; + } + v48 = v7; + if ( !v7 ) + { + if ( v2 <= 0 ) + goto LABEL_44; + --v2; + } + if ( v7 == 1 ) + { + if ( v2 >= 40 ) + goto LABEL_44; + ++v2; + } + if ( v7 != 2 ) + goto LABEL_41; + if ( v1 < 40 ) + { + ++v1; + v45 += 40; +LABEL_41: + if ( v7 == 3 && v1 > 0 ) + { + --v1; + v45 -= 40; + } + } +LABEL_44: + if ( dungeon[0][v45 + v2] == 7 ) + { + v43 = 0; + if ( v7 < 2 ) + { + v8 = random(0, 2); + v5 = max; + river[2][max] = v8 + 17; + } + if ( v7 > 1 ) + { + v9 = random(0, 2); + v5 = max; + river[2][max] = v9 + 15; + } + v10 = v40; + river[0][v5] = v1; + river[1][v5++] = v2; + max = v5; + if ( v7 || v10 != 2 ) + { + if ( v7 != 3 ) + goto LABEL_58; + if ( v10 != 1 ) + goto LABEL_70; + } + if ( v5 > 2 ) + river[1][v5 + 98] = 22; + if ( !v7 ) + { + v46 = 1; +LABEL_59: + if ( v10 == 3 ) + goto LABEL_62; + goto LABEL_60; + } + v46 = 2; +LABEL_58: + if ( !v7 ) + goto LABEL_59; +LABEL_60: + if ( v7 != 2 ) + goto LABEL_67; + if ( v10 != 1 ) + goto LABEL_79; +LABEL_62: + if ( v5 > 2 ) + river[1][v5 + 98] = 21; + if ( !v7 ) + { + v46 = 1; + goto LABEL_83; + } + v46 = 3; +LABEL_67: + if ( v7 != 1 || v10 != 2 ) + { + if ( v7 != 3 ) + goto LABEL_76; +LABEL_70: + if ( v10 ) + goto LABEL_83; + } + if ( v5 > 2 ) + river[1][v5 + 98] = 20; + if ( v7 == 1 ) + { + v46 = 0; + goto LABEL_77; + } + v46 = 2; +LABEL_76: + if ( v7 != 1 ) + goto LABEL_78; +LABEL_77: + if ( v10 != 3 ) + { +LABEL_78: + if ( v7 != 2 ) + goto LABEL_83; +LABEL_79: + if ( v10 ) + goto LABEL_83; + } + if ( v5 > 2 ) + river[1][v5 + 98] = 19; + v46 = v7 != 1 ? 3 : 0; +LABEL_83: + v40 = v7; + } + else + { + v1 = v38; + v2 = v37; + v45 = v36; + if ( v43 >= 4 ) + break; + } + } + if ( v48 ) + { + v13 = v40; + goto LABEL_94; + } + v11 = &dungeon[v1][v2]; + if ( *(v11 - 1) == 10 && *(v11 - 2) == 8 ) + { + v12 = v5; + river[1][v12] = v2 - 1; + v13 = v40; + v14 = v40 == 2; + river[0][v12] = v1; + river[2][v12] = 24; + if ( v14 ) + river[1][v12 + 99] = 22; + if ( v13 == 3 ) + river[1][v12 + 99] = 21; + v47 = 1; +LABEL_94: + if ( v48 == 1 ) + { + v15 = v2 + 40 * v1; + if ( dungeon[0][v15 + 1] == 2 && dungeon[0][v15 + 2] == 8 ) + { + v16 = v5; + river[0][v16] = v1; + river[1][v16] = v2 + 1; + river[2][v16] = 42; + if ( v13 == 2 ) + river[1][v16 + 99] = 20; + if ( v13 == 3 ) + river[1][v16 + 99] = 19; + v47 = 1; + goto LABEL_102; + } + } + else + { +LABEL_102: + if ( v48 == 2 ) + { + v17 = v2 + 40 * v1; + if ( dungeon[1][v17] != 4 || dungeon[2][v17] != 8 ) + goto LABEL_118; + v18 = v5; + river[0][v18] = v1 + 1; + river[1][v18] = v2; + river[2][v18] = 43; + if ( !v13 ) + river[1][v18 + 99] = 19; + if ( v13 == 1 ) + river[1][v18 + 99] = 21; + v47 = 1; + } + if ( v48 == 3 + && dungeon[v1-1][v2] == 9 // *((_BYTE *)&dMonster[111][10 * v1 + 102] + v2) == 9 /* check */ + && dungeon[0][8 * (5 * v1 - 10) + v2] == 8 ) + { + v19 = v5; + river[0][v19] = v1 - 1; + river[1][v19] = v2; + river[2][v19] = 23; + if ( !v13 ) + river[1][v19 + 99] = 20; + if ( v13 == 1 ) + river[1][v19 + 99] = 22; + v47 = 1; + } + } + } +LABEL_118: + v0 = 0; + } + while ( !v47 ); + if ( v47 == 1 && v5 >= 7 ) + { + v20 = 0; + v47 = 0; +LABEL_124: + while ( v47 < 30 ) + { + ++v47; + v21 = random(0, max); + v44 = v21; + v22 = v21; + v23 = river[2][v22]; + if ( v23 == 15 || v23 == 16 ) + { + v24 = river[1][v22] + 40 * river[0][v22]; + if ( dungeon[0][v24 - 1] == 7 && dungeon[0][v24 + 1] == 7 ) /* *((_BYTE *)&dMonster[111][111] + v24 + 3) check */ + v20 = 1; + } + if ( v23 == 17 || v23 == 18 ) + { + v25 = river[1][v22] + 40 * river[0][v22]; + if ( dungeon[-1][v25] == 7 && dungeon[1][v25] == 7 ) /* *((_BYTE *)&dMonster[111][102] + v25) check */ + v20 = 2; + } + v26 = 0; + if ( max > 0 ) + { + while ( 1 ) + { + if ( !v20 ) + goto LABEL_124; + if ( v20 != 1 ) + goto LABEL_142; + v27 = river[1][v22]; + v28 = river[1][v26]; + if ( (v27 - 1 == v28 || v27 + 1 == v28) && river[0][v22] == river[0][v26] ) + break; +LABEL_147: + if ( ++v26 >= max ) + goto LABEL_148; + } + v20 = 0; +LABEL_142: + if ( v20 == 2 ) + { + v29 = river[0][v22]; + v30 = river[0][v26]; + if ( (v29 - 1 == v30 || v29 + 1 == v30) && river[1][v22] == river[1][v26] ) + v20 = 0; + } + goto LABEL_147; + } +LABEL_148: + if ( v20 ) + break; + } + v0 = 0; + if ( v20 ) + { + river[2][v44] = v20 == 1 ? 44 : 45; + v31 = max; + ++v39; + v44 = 0; + if ( max >= 0 ) + { + do + { + v32 = v44++; + v34 = __OFSUB__(v44, v31); + v14 = v44 == v31; + v33 = v44 - v31 < 0; + dungeon[river[0][v32]][river[1][v32]] = river[2][v32]; + } + while ( (unsigned char)(v33 ^ v34) | v14 ); + } + } + } + if ( v41 >= 200 ) + return; + } +} +// 410FAD: using guessed type int var_1C8[100]; +// 410FAD: using guessed type int var_4E8[100]; +// 410FAD: using guessed type int var_358[98]; + +void __cdecl DRLG_L3Pool() +{ + int v0; // ebx + _BYTE *v1; // ecx + int v2; // esi + int v3; // ecx + signed int v4; // eax + signed int v5; // eax + signed int v6; // eax + int v7; // eax + int v8; // edi + int v9; // ecx + int v10; // eax + int v11; // esi + char *v12; // edx + unsigned char v13; // al + unsigned char v14; // al + signed int v15; // [esp+Ch] [ebp-18h] + char *v16; // [esp+10h] [ebp-14h] + signed int v17; // [esp+14h] [ebp-10h] + int v18; // [esp+18h] [ebp-Ch] + int totarea; // [esp+1Ch] [ebp-8h] + int x; // [esp+20h] [ebp-4h] + + v0 = 0; + v18 = 0; + do + { + x = 0; + v1 = (unsigned char *)dungeon + v0; + v16 = (char *)dungeon + v0; + do + { + if ( *v1 == 8 ) + { + *v1 = -120; + v2 = x - 1; + totarea = 1; + v3 = x - 1 + 2; + v4 = v3 >= 40 ? 1 : DRLG_L3SpawnEdge(v3, v0, &totarea); + v5 = v2 <= 0 || v4 ? 1 : DRLG_L3SpawnEdge(v2, v0, &totarea); + v6 = v0 + 1 >= 40 || v5 ? 1 : DRLG_L3SpawnEdge(x, v0 + 1, &totarea); + v17 = v0 - 1 <= 0 || v6 ? 1 : DRLG_L3SpawnEdge(x, v0 - 1, &totarea); + v7 = random(0, 100); + v8 = totarea; + v15 = v7; + v9 = v0 - totarea; + if ( v0 - totarea < totarea + v0 ) + { + totarea = x - totarea; + v10 = v8 + x; + do + { + v11 = totarea; + if ( totarea < v10 ) + { + v12 = &dungeon[totarea][v9]; + do + { + if ( *v12 < 0 && v9 >= 0 && v9 < 40 && v11 >= 0 && v11 < 40 ) + { + v13 = *v12 & 0x7F; + *v12 = v13; + if ( v8 > 4 ) + { + if ( v15 < 25 && !v17 ) + { + v14 = L3PoolSub[v13]; + if ( v14 ) + { + if ( v14 <= 0x25u ) + *v12 = v14; + } + lavapool = 1; + } + v0 = v18; + } + } + ++v11; + v10 = v8 + x; + v12 += 40; + } + while ( v11 < v8 + x ); + } + ++v9; + } + while ( v9 < v8 + v0 ); + } + } + ++x; + v1 = (unsigned char *)v16 + 40; + v16 += 40; + } + while ( x < 40 ); + v18 = ++v0; + } + while ( v0 < 40 ); +} +// 528378: using guessed type char lavapool; + +int __fastcall DRLG_L3SpawnEdge(int x, int y, int *totarea) +{ + int *v3; // ebp + int v4; // edi + int v5; // esi + char *v6; // ecx + int *v7; // eax + int v8; // eax + int *totareaa; // [esp+14h] [ebp+4h] + + v3 = totarea; + v4 = y; + v5 = x; + if ( *totarea <= 40 && x >= 0 && y >= 0 && x < 40 && y < 40 ) + { + v6 = &dungeon[x][y]; + _LOBYTE(v7) = *v6; + if ( *v6 < 0 ) + return 0; + if ( (unsigned char)v7 <= 0xFu ) + { + *v6 = (unsigned char)v7 | 0x80; + ++*totarea; + if ( (_BYTE)v7 == 8 ) + { + if ( DRLG_L3SpawnEdge(v5 + 1, y, totarea) == 1 + || DRLG_L3SpawnEdge(v5 - 1, v4, totarea) == 1 + || DRLG_L3SpawnEdge(v5, v4 + 1, totarea) == 1 ) + { + return 1; + } + v8 = DRLG_L3SpawnEdge(v5, v4 - 1, totarea); +LABEL_24: + if ( v8 == 1 ) + return 1; + return 0; + } + v7 = (int *)(unsigned char)v7; + totareaa = v7; + if ( L3SpawnTbl2[(unsigned char)v7] & 8 ) + { + if ( DRLG_L3Spawn(v5, y - 1, v3) == 1 ) + return 1; + v7 = totareaa; + } + if ( L3SpawnTbl2[(_DWORD)v7] & 4 ) + { + if ( DRLG_L3Spawn(v5, v4 + 1, v3) == 1 ) + return 1; + v7 = totareaa; + } + if ( !(L3SpawnTbl2[(_DWORD)v7] & 2) ) + goto LABEL_18; + if ( DRLG_L3Spawn(v5 + 1, v4, v3) != 1 ) + { + v7 = totareaa; +LABEL_18: + if ( L3SpawnTbl2[(_DWORD)v7] & 1 ) + { + v8 = DRLG_L3Spawn(v5 - 1, v4, v3); + goto LABEL_24; + } + return 0; + } + return 1; + } + } + return 1; +} + +int __fastcall DRLG_L3Spawn(int x, int y, int *totarea) +{ + int v3; // edi + int v4; // esi + char *v5; // eax + unsigned char v6; // cl + int v7; // ebx + int result; // eax + + v3 = y; + v4 = x; + result = 1; + if ( *totarea <= 40 && x >= 0 && y >= 0 && x < 40 && y < 40 ) + { + v5 = &dungeon[x][y]; + v6 = *v5; + if ( *v5 < 0 + || v6 <= 0xFu + && ((v7 = v6, *v5 = v6 | 0x80, ++*totarea, !(L3SpawnTbl1[v6] & 8)) || DRLG_L3Spawn(v4, y - 1, totarea) != 1) + && (!(L3SpawnTbl1[v7] & 4) || DRLG_L3Spawn(v4, v3 + 1, totarea) != 1) + && (!(L3SpawnTbl1[v7] & 2) || DRLG_L3Spawn(v4 + 1, v3, totarea) != 1) + && (!(L3SpawnTbl1[v7] & 1) || DRLG_L3Spawn(v4 - 1, v3, totarea) != 1) + && ((L3SpawnTbl1[v7] & 0x80u) == 0 || DRLG_L3SpawnEdge(v4, v3 - 1, totarea) != 1) + && (!(L3SpawnTbl1[v7] & 0x40) || DRLG_L3SpawnEdge(v4, v3 + 1, totarea) != 1) + && (!(L3SpawnTbl1[v7] & 0x20) || DRLG_L3SpawnEdge(v4 + 1, v3, totarea) != 1) + && (!(L3SpawnTbl1[v7] & 0x10) || DRLG_L3SpawnEdge(v4 - 1, v3, totarea) != 1) ) + { + result = 0; + } + } + return result; +} + +void __cdecl DRLG_L3PoolFix() +{ + signed int v0; // esi + char *v1; // eax + char *v2; // edi + unsigned char v3; // cl + char v4; // cl + char v5; // cl + char v6; // cl + char v7; // cl + char v8; // cl + char v9; // al + bool v10; // zf + signed int v11; // [esp+10h] [ebp-4h] + + v0 = 0; + do + { + v1 = &dungeon[-1][v0]; + v11 = 40; + do + { + v2 = v1 + 40; + if ( v1[40] == 8 ) + { + v3 = *(v1 - 1); + if ( v3 >= 0x19u && v3 <= 0x29u && (unsigned char)*v1 >= 0x19u && (unsigned char)*v1 <= 0x29u ) + { + v4 = v1[1]; + if ( (unsigned char)v4 >= 0x19u && (unsigned char)v4 <= 0x29u ) + { + v5 = v1[39]; + if ( (unsigned char)v5 >= 0x19u && (unsigned char)v5 <= 0x29u ) + { + v6 = v1[41]; + if ( (unsigned char)v6 >= 0x19u && (unsigned char)v6 <= 0x29u ) + { + v7 = v1[79]; + if ( (unsigned char)v7 >= 0x19u && (unsigned char)v7 <= 0x29u ) + { + v8 = v1[80]; + if ( (unsigned char)v8 >= 0x19u && (unsigned char)v8 <= 0x29u ) + { + v9 = v1[81]; + if ( (unsigned char)v9 >= 0x19u && (unsigned char)v9 <= 0x29u ) + *v2 = 33; + } + } + } + } + } + } + } + v10 = v11-- == 1; + v1 = v2; + } + while ( !v10 ); + ++v0; + } + while ( v0 < 40 ); +} + +int __fastcall DRLG_L3PlaceMiniSet(const unsigned char *miniset, int tmin, int tmax, int cx, int cy, bool setview, int ldir) +{ + int v7; // ebx + int v8; // esi + int v9; // edi + int v10; // edx + int v11; // esi + signed int v12; // ebx + int v13; // edi + signed int i; // eax + int v15; // ecx + unsigned char v16; // dl + int v17; // eax + int v18; // ecx + int v19; // edi + char *v20; // edx + char v21; // bl + const unsigned char *v23; // [esp+Ch] [ebp-24h] + int v24; // [esp+10h] [ebp-20h] + int v25; // [esp+14h] [ebp-1Ch] + int v26; // [esp+18h] [ebp-18h] + signed int v27; // [esp+1Ch] [ebp-14h] + int v28; // [esp+20h] [ebp-10h] + int v29; // [esp+24h] [ebp-Ch] + int v30; // [esp+28h] [ebp-8h] + int max; // [esp+2Ch] [ebp-4h] + + v7 = miniset[1]; + v8 = tmin; + v9 = *miniset; + v23 = miniset; + v10 = tmax - tmin; + v28 = *miniset; + v29 = miniset[1]; + if ( v10 ) + v24 = v8 + random(0, v10); + else + v24 = 1; + v25 = 0; + if ( v24 <= 0 ) + { + v11 = tmax; + } + else + { + max = 40 - v9; + v30 = 40 - v7; + do + { + v11 = random(0, max); + v27 = 0; + tmax = random(0, v30); + while ( 1 ) + { + if ( v27 >= 200 ) + return 1; + ++v27; + v12 = 1; + if ( cx != -1 && v11 >= cx - v28 && v11 <= cx + 12 ) + { + v11 = random(0, max); + tmax = random(0, v30); + v12 = 0; + } + if ( cy != -1 && tmax >= cy - v29 && tmax <= cy + 12 ) + { + v11 = random(0, max); + tmax = random(0, v30); + v12 = 0; + } + v13 = 0; + for ( i = 2; v13 < v29; ++v13 ) + { + if ( v12 != 1 ) + break; + v26 = 0; + if ( v28 > 0 ) + { + v15 = tmax + v13 + 40 * v11; + do + { + if ( v12 != 1 ) + break; + v16 = v23[i]; + if ( v16 && dungeon[0][v15] != v16 ) + v12 = 0; + if ( dflags[0][v15] ) + v12 = 0; + ++i; + ++v26; + v15 += 40; + } + while ( v26 < v28 ); + } + } + v17 = 0; + if ( v12 ) + break; + if ( ++v11 == max ) + { + v11 = 0; + if ( ++tmax == v30 ) + tmax = 0; + } + } + if ( v27 >= 200 ) + return 1; + v18 = v28 * v29 + 2; + if ( v29 > 0 ) + { + do + { + v19 = v28; + if ( v28 > 0 ) + { + v20 = &dungeon[v11][v17 + tmax]; + do + { + v21 = v23[v18]; + if ( v21 ) + *v20 = v21; + ++v18; + v20 += 40; + --v19; + } + while ( v19 ); + } + ++v17; + } + while ( v17 < v29 ); + } + ++v25; + } + while ( v25 < v24 ); + } + if ( setview == 1 ) + { + ViewX = 2 * v11 + 17; + ViewY = 2 * tmax + 19; + } + if ( !ldir ) + { + LvlViewX = 2 * v11 + 17; + LvlViewY = 2 * tmax + 19; + } + return 0; +} +// 5CF320: using guessed type int LvlViewY; +// 5CF324: using guessed type int LvlViewX; + +void __fastcall DRLG_L3PlaceRndSet(const unsigned char *miniset, int rndper) +{ + const unsigned char *v2; // ebx + int v3; // ecx + int v4; // eax + char *v5; // ecx + int v6; // esi + signed int i; // edx + int v8; // edi + int v9; // eax + unsigned char v10; // cl + int v11; // edi + unsigned char v12; // al + char v13; // al + int j; // edx + int v15; // esi + unsigned char *v16; // eax + unsigned char v17; // cl + bool v18; // zf + int v19; // [esp+8h] [ebp-30h] + int v20; // [esp+10h] [ebp-28h] + char *v21; // [esp+14h] [ebp-24h] + int v22; // [esp+18h] [ebp-20h] + int v23; // [esp+1Ch] [ebp-1Ch] + int v24; // [esp+20h] [ebp-18h] + int v25; // [esp+24h] [ebp-14h] + int v26; // [esp+28h] [ebp-10h] + int v27; // [esp+2Ch] [ebp-Ch] + int v28; // [esp+30h] [ebp-8h] + signed int v29; // [esp+34h] [ebp-4h] + + v2 = miniset; + v19 = rndper; + v3 = miniset[1]; + v4 = 0; + v23 = 40 - v3; + v27 = *v2; + v28 = v3; + v24 = 0; + if ( 40 - v3 > 0 ) + { + v22 = 40 - *v2; + v21 = dungeon[-1]; + while ( v22 <= 0 ) + { +LABEL_44: + v4 = v24++ + 1; + if ( v24 >= v23 ) + return; + } + v26 = 0; + v20 = v22; + v5 = &v21[v4]; + v25 = (int)&v21[v4]; + while ( 1 ) + { + v6 = 0; + v29 = 1; + for ( i = 2; v6 < v28; ++v6 ) + { + if ( v29 != 1 ) + break; + v8 = 0; + if ( v27 > 0 ) + { + v9 = v24 + v6 + v26; + do + { + if ( v29 != 1 ) + break; + v10 = v2[i]; + if ( v10 && dungeon[0][v9] != v10 ) + v29 = 0; + if ( dflags[0][v9] ) + v29 = 0; + ++i; + ++v8; + v9 += 40; + } + while ( v8 < v27 ); + v5 = (char *)v25; + } + } + v11 = v27 * v28 + 2; + v12 = v2[v11]; + if ( v12 < 0x54u || v12 > 0x64u ) + goto LABEL_33; + if ( v29 == 1 ) + break; +LABEL_43: + v26 += 40; + v5 += 40; + v18 = v20-- == 1; + v25 = (int)v5; + if ( v18 ) + goto LABEL_44; + } + v13 = *v5; + if ( (unsigned char)*v5 >= 0x54u && (unsigned char)v13 <= 0x64u ) + v29 = 0; + if ( (unsigned char)v5[80] >= 0x54u && (unsigned char)v13 <= 0x64u ) + v29 = 0; + if ( (unsigned char)v5[41] >= 0x54u && (unsigned char)v13 <= 0x64u ) + v29 = 0; + if ( (unsigned char)v5[39] >= 0x54u && (unsigned char)v13 <= 0x64u ) + v29 = 0; +LABEL_33: + if ( v29 == 1 ) + { + if ( random(0, 100) < v19 ) + { + for ( j = 0; j < v28; ++j ) + { + v15 = v27; + if ( v27 > 0 ) + { + v16 = (unsigned char *)dungeon + j + v26 + v24; + do + { + v17 = v2[v11]; + if ( v17 ) + *v16 = v17; + ++v11; + v16 += 40; + --v15; + } + while ( v15 ); + } + } + } + v5 = (char *)v25; + } + goto LABEL_43; + } +} + +void __cdecl DRLG_L3Wood() +{ + char *v0; // edi + int v1; // edx + _BYTE *v2; // eax + int v3; // edx + _BYTE *v4; // ebx + int v5; // esi + int v6; // esi + int v7; // ebx + int v8; // ebx + signed int v9; // esi + _BYTE *v10; // eax + int v11; // esi + int v12; // ebx + int v13; // eax + _BYTE *v14; // ecx + int v15; // ecx + int v16; // eax + int v17; // esi + int v18; // esi + //int v19; // eax + int v20; // edi + int v21; // esi + int i; // edx + int v23; // esi + int v24; // edi + signed int v25; // ecx + int v26; // ebx + char *v27; // esi + int v28; // ecx + int v29; // edi + int v30; // ecx + int v31; // edi + int v32; // ebx + int v33; // ebx + char *v34; // esi + signed int v35; // ecx + int v36; // [esp+Ch] [ebp-14h] + int v37; // [esp+10h] [ebp-10h] + int v38; // [esp+10h] [ebp-10h] + int v39; // [esp+10h] [ebp-10h] + int v40; // [esp+10h] [ebp-10h] + int v41; // [esp+10h] [ebp-10h] + int x; // [esp+14h] [ebp-Ch] + int xa; // [esp+14h] [ebp-Ch] + signed int v44; // [esp+18h] [ebp-8h] + signed int v45; // [esp+18h] [ebp-8h] + int y; // [esp+1Ch] [ebp-4h] + signed int ya; // [esp+1Ch] [ebp-4h] + + y = 0; + do + { + x = 0; + v44 = 1; + v0 = (char *)dungeon + y; + do + { + if ( *v0 == 10 && random(0, 2) ) + { + v1 = v44 - 1; + if ( *v0 == 10 ) + { + v2 = (unsigned char *)v0; + do + { + v2 += 40; + ++v1; + } + while ( *v2 == 10 ); + } + v3 = v1 - 1; + v37 = v3; + if ( v3 - (v44 - 1) > 0 ) + { + *v0 = 127; + if ( v44 < v3 ) + { + v4 = (unsigned char *)v0 + 40; + v5 = v3 - v44; + do + { + *v4 = random(0, 2) != 0 ? 126 : -127; + v4 += 40; + --v5; + } + while ( v5 ); + } + dungeon[v37][y] = -128; + } + } + if ( *v0 == 9 && random(0, 2) ) + { + v6 = y; + v7 = y; + if ( *v0 == 9 ) + { + do + ++v7; + while ( dungeon[x][v7] == 9 ); + } + v8 = v7 - 1; + if ( v8 - y > 0 ) + { + *v0 = 123; + while ( ++v6 < v8 ) + { + if ( random(0, 2) ) + dungeon[x][v6] = 121; + else + dungeon[x][v6] = 124; + } + dungeon[x][v8] = 122; + } + } + if ( *v0 == 11 && v0[40] == 10 && v0[1] == 9 && random(0, 2) ) + { + v9 = v44; + *v0 = 125; + if ( v0[40] == 10 ) + { + v10 = (unsigned char *)v0 + 40; + do + { + v10 += 40; + ++v9; + } + while ( *v10 == 10 ); + } + v11 = v9 - 1; + if ( v44 < v11 ) + { + v38 = (int)(v0 + 40); + v12 = v11 - v44; + do + { + v13 = random(0, 2); + v14 = (_BYTE *)v38; + v38 += 40; + --v12; + *v14 = v13 != 0 ? 126 : -127; + } + while ( v12 ); + } + v15 = v11; + v16 = y + 1; + v17 = v16; + for ( dungeon[v15][v16 - 1] = 128; dungeon[x][v17] == 9; ++v17 ) /* check *((_BYTE *)&dMonster[111][2 * v15 + 111] + v16 + 3) */ + ; + v18 = v17 - 1; + v39 = y + 1; + if ( v16 < v18 ) + { + do + { + if ( random(0, 2) ) + dungeon[x][v39] = 121; + else + dungeon[x][v39] = 124; + ++v39; + } + while ( v39 < v18 ); + } + dungeon[x][v18] = 122; + } + ++v44; + ++x; + v0 += 40; + } + while ( v44 - 1 < 39 ); + ++y; + } + while ( y < 39 ); + ya = 0; + do + { + xa = 0; + v45 = 0; + do + { + if ( dungeon[v45][ya] != 7 ) + goto LABEL_112; + if ( random(0, 1) ) + goto LABEL_112; + //_LOBYTE(v19) = SkipThemeRoom(xa, ya); + if ( !SkipThemeRoom(xa, ya) ) + goto LABEL_112; + v36 = random(0, 2); + if ( !v36 ) + { + v20 = ya; + v21 = ya; + for ( i = ya; WoodVertU(xa, i); i = v21 ) + --v21; + v23 = v21 + 1; + while ( WoodVertD(xa, v20) ) + ++v20; + v24 = v20 - 1; + v25 = 1; + if ( dungeon[v45][v23] == 7 ) + v25 = 0; + if ( dungeon[v45][v24] == 7 ) + v25 = 0; + if ( v24 - v23 <= 1 ) + goto LABEL_112; + if ( !v25 ) + goto LABEL_112; + v40 = random(0, v24 - v23 - 1) + v23 + 1; + v26 = v23; + if ( v23 > v24 ) + goto LABEL_112; + do + { + if ( v26 != v40 ) + { + v27 = &dungeon[v45][v26]; + if ( *v27 == 7 ) + *v27 = random(0, 2) != 0 ? -121 : -119; + if ( *v27 == 10 ) + *v27 = -125; + if ( *v27 == 126 ) + *v27 = -123; + if ( *v27 == -127 ) + *v27 = -123; + if ( *v27 == 2 ) + *v27 = -117; + if ( *v27 == -122 ) + *v27 = -118; + if ( *v27 == -120 ) + *v27 = -118; + } + ++v26; + } + while ( v26 <= v24 ); + } + if ( v36 == 1 ) + { + v28 = xa; + v29 = xa; + while ( WoodHorizL(v28, ya) ) + v28 = --v29; + v30 = xa; + v31 = v29 + 1; + v32 = xa; + while ( WoodHorizR(v30, ya) ) + v30 = ++v32; + v33 = v32 - 1; + v34 = &dungeon[v31][ya]; + v35 = 1; + if ( *v34 == 7 ) + v35 = 0; + if ( dungeon[v33][ya] == 7 ) + v35 = 0; + if ( v33 - v31 > 1 && v35 ) + { + v41 = random(0, v33 - v31 - 1) + v31 + 1; + while ( 1 ) + { + if ( v31 > v33 ) + break; + if ( v31 != v41 ) + { + if ( *v34 == 7 ) + { + if ( random(0, 2) ) + { + *v34 = -122; + goto LABEL_110; + } + *v34 = -120; + } + if ( *v34 == 9 ) + *v34 = -126; + if ( *v34 == 121 ) + *v34 = -124; + if ( *v34 == 124 ) + *v34 = -124; + if ( *v34 == 4 ) + *v34 = -116; + if ( *v34 == -121 ) + *v34 = -118; + if ( *v34 == -119 ) + *v34 = -118; + } +LABEL_110: + ++v31; + v34 += 40; + } + } + } +LABEL_112: + ++v45; + ++xa; + } + while ( v45 < 40 ); + ++ya; + } + while ( ya < 40 ); + AddFenceDoors(); + FenceDoorFix(); +} + +bool __fastcall WoodVertU(int i, int y) +{ + int v2; // eax + char v3; // cl + char *v4; // eax + unsigned char v5; // cl + char v6; // al + bool result; // eax + + v2 = i; + v3 = dungeon[i + 1][y]; + result = 0; + if ( (unsigned char)v3 > 0x98u || (unsigned char)v3 < 0x82u ) + { + v4 = &dungeon[v2][y]; + v5 = *(v4 - 40); + if ( v5 > 0x98u || v5 < 0x82u ) + { + v6 = *v4; + if ( v6 == 7 || v6 == 10 || v6 == 126 || v6 == -127 || v6 == -122 || v6 == -120 ) + result = 1; + } + } + return result; +} + +bool __fastcall WoodVertD(int i, int y) +{ + int v2; // eax + char v3; // cl + char *v4; // eax + unsigned char v5; // cl + char v6; // al + bool result; // eax + + v2 = i; + v3 = dungeon[i + 1][y]; + result = 0; + if ( (unsigned char)v3 > 0x98u || (unsigned char)v3 < 0x82u ) + { + v4 = &dungeon[v2][y]; + v5 = *(v4 - 40); + if ( v5 > 0x98u || v5 < 0x82u ) + { + v6 = *v4; + if ( v6 == 7 || v6 == 2 || v6 == -122 || v6 == -120 ) + result = 1; + } + } + return result; +} + +bool __fastcall WoodHorizL(int x, int j) +{ + int v2; // eax + char v3; // cl + char *v4; // eax + unsigned char v5; // cl + char v6; // al + bool result; // eax + + v2 = x; + v3 = dungeon[x][j + 1]; + result = 0; + if ( (unsigned char)v3 > 0x98u || (unsigned char)v3 < 0x82u ) + { + v4 = &dungeon[v2][j]; + v5 = *(v4 - 1); + if ( v5 > 0x98u || v5 < 0x82u ) + { + v6 = *v4; + if ( v6 == 7 || v6 == 9 || v6 == 121 || v6 == 124 || v6 == -121 || v6 == -119 ) + result = 1; + } + } + return result; +} + +bool __fastcall WoodHorizR(int x, int j) +{ + int v2; // eax + char v3; // cl + char *v4; // eax + unsigned char v5; // cl + char v6; // al + bool result; // eax + + v2 = x; + v3 = dungeon[x][j + 1]; + result = 0; + if ( (unsigned char)v3 > 0x98u || (unsigned char)v3 < 0x82u ) + { + v4 = &dungeon[v2][j]; + v5 = *(v4 - 1); + if ( v5 > 0x98u || v5 < 0x82u ) + { + v6 = *v4; + if ( v6 == 7 || v6 == 4 || v6 == -121 || v6 == -119 ) + result = 1; + } + } + return result; +} + +void __cdecl DRLG_L3Pass3() +{ + int v0; // eax + int *v1; // esi + int *v2; // eax + signed int v3; // ecx + signed int v4; // ebx + int *v5; // ecx + unsigned char *v6; // edi + unsigned short *v7; // esi + unsigned short v8; // ax + int v9; // eax + signed int v10; // [esp+Ch] [ebp-1Ch] + int *v11; // [esp+10h] [ebp-18h] + int v12; // [esp+14h] [ebp-14h] + int v13; // [esp+18h] [ebp-10h] + int v14; // [esp+18h] [ebp-10h] + int v15; // [esp+1Ch] [ebp-Ch] + int v16; // [esp+1Ch] [ebp-Ch] + int v17; // [esp+20h] [ebp-8h] + int v18; // [esp+20h] [ebp-8h] + int v19; // [esp+24h] [ebp-4h] + int v20; // [esp+24h] [ebp-4h] + + v0 = *((unsigned short *)pMegaTiles + 28) + 1; + v19 = *((unsigned short *)pMegaTiles + 28) + 1; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 29); + v17 = ++v0; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 30); + v15 = ++v0; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 31); + v13 = v0 + 1; + v1 = dPiece[1]; + do + { + v2 = v1; + v3 = 56; + do + { + *(v2 - 112) = v19; + *v2 = v17; + *(v2 - 111) = v15; + v2[1] = v13; + v2 += 224; + --v3; + } + while ( v3 ); + v1 += 2; + } + while ( (signed int)v1 < (signed int)dPiece[2] ); + v4 = 0; + v11 = &dPiece[17][16]; + do + { + v5 = v11; + v6 = (unsigned char *)dungeon + v4; + v10 = 40; + do + { + v12 = *v6 - 1; + if ( v12 < 0 ) + { + v20 = 0; + v18 = 0; + v16 = 0; + v14 = 0; + } + else + { + v7 = (unsigned short *)((char *)pMegaTiles + 8 * v12); + v8 = *v7; + ++v7; + v9 = v8 + 1; + v20 = v9; + _LOWORD(v9) = *v7; + ++v7; + v18 = ++v9; + _LOWORD(v9) = *v7; + v16 = ++v9; + _LOWORD(v9) = v7[1]; + v14 = v9 + 1; + } + v6 += 40; + *(v5 - 112) = v20; + *v5 = v18; + *(v5 - 111) = v16; + v5[1] = v14; + v5 += 224; + --v10; + } + while ( v10 ); + v11 += 2; + ++v4; + } + while ( v4 < 40 ); +} + +void __fastcall LoadL3Dungeon(char *sFileName, int vx, int vy) +{ + char *v3; // esi + unsigned char *v4; // eax + char *v5; // esi + int v6; // edi + int v7; // ecx + _BYTE *v8; // eax + _BYTE *v9; // edx + int v10; // ebx + signed int v11; // ecx + _BYTE *v12; // eax + signed int v13; // edx + int v14; // edi + signed int v15; // eax + int v16; // [esp+Ch] [ebp-8h] + signed int *v17; // [esp+Ch] [ebp-8h] + int v18; // [esp+10h] [ebp-4h] + int (*v19)[112]; // [esp+10h] [ebp-4h] + + v3 = sFileName; + InitL3Dungeon(); + dminx = 16; + dminy = 16; + dmaxx = 96; + dmaxy = 96; + DRLG_InitTrans(); + v4 = LoadFileInMem(v3, 0); + v5 = (char *)v4; + v18 = 0; + v6 = *v4; + v4 += 2; + v7 = *v4; + v8 = v4 + 2; + if ( v7 > 0 ) + { + do + { + if ( v6 > 0 ) + { + v16 = v6; + v9 = (unsigned char *)dungeon + v18; + do + { + if ( *v8 ) + *v9 = *v8; + else + *v9 = 7; + v9 += 40; + v8 += 2; + --v16; + } + while ( v16 ); + } + ++v18; + } + while ( v18 < v7 ); + } + v10 = 0; + v11 = 0; + do + { + v12 = (unsigned char *)dungeon + v11; + v13 = 40; + do + { + if ( !*v12 ) + *v12 = 8; + v12 += 40; + --v13; + } + while ( v13 ); + ++v11; + } + while ( v11 < 40 ); + abyssx = 112; + DRLG_L3Pass3(); + DRLG_Init_Globals(); + ViewX = 31; + ViewY = 83; + SetMapMonsters((unsigned char *)v5, 0, 0); + SetMapObjects((unsigned char *)v5, 0, 0); + v19 = dPiece; + do + { + v14 = 0; + v17 = (signed int *)v19; + do + { + v15 = *v17; + if ( *v17 >= 56 && v15 <= 147 || v15 >= 154 && v15 <= 161 || v15 == 150 || v15 == 152 ) + DoLighting(v14, v10, 7, -1); + v17 += 112; + ++v14; + } + while ( v14 < 112 ); + v19 = (int (*)[112])((char *)v19 + 4); + ++v10; + } + while ( (signed int)v19 < (signed int)dPiece[1] ); + mem_free_dbg(v5); +} +// 52837C: using guessed type int abyssx; +// 5CF328: using guessed type int dmaxx; +// 5CF32C: using guessed type int dmaxy; +// 5D2458: using guessed type int dminx; +// 5D245C: using guessed type int dminy; + +void __fastcall LoadPreL3Dungeon(char *sFileName, int vx, int vy) +{ + char *v3; // esi + unsigned char *v4; // eax + unsigned char *v5; // esi + int v6; // edx + int v7; // edi + _BYTE *v8; // eax + _BYTE *v9; // ecx + signed int v10; // ecx + _BYTE *v11; // eax + signed int v12; // edx + int v13; // [esp+8h] [ebp-8h] + int v14; // [esp+Ch] [ebp-4h] + + v3 = sFileName; + InitL3Dungeon(); + DRLG_InitTrans(); + v4 = LoadFileInMem(v3, 0); + v5 = v4; + v14 = 0; + v6 = *v4; + v4 += 2; + v7 = *v4; + v8 = v4 + 2; + if ( v7 > 0 ) + { + do + { + if ( v6 > 0 ) + { + v13 = v6; + v9 = (unsigned char *)dungeon + v14; + do + { + if ( *v8 ) + *v9 = *v8; + else + *v9 = 7; + v9 += 40; + v8 += 2; + --v13; + } + while ( v13 ); + } + ++v14; + } + while ( v14 < v7 ); + } + v10 = 0; + do + { + v11 = (unsigned char *)dungeon + v10; + v12 = 40; + do + { + if ( !*v11 ) + *v11 = 8; + v11 += 40; + --v12; + } + while ( v12 ); + ++v10; + } + while ( v10 < 40 ); + memcpy(pdungeon, dungeon, 0x640u); + mem_free_dbg(v5); +} diff --git a/Source/drlg_l3.h b/Source/drlg_l3.h new file mode 100644 index 000000000..2347fa98a --- /dev/null +++ b/Source/drlg_l3.h @@ -0,0 +1,87 @@ +//HEADER_GOES_HERE +#ifndef __DRLG_L3_H__ +#define __DRLG_L3_H__ + +extern char lavapool; // weak +extern int abyssx; // weak +extern int lockoutcnt; // weak +extern char lockout[40][40]; + +void __cdecl AddFenceDoors(); +void __cdecl FenceDoorFix(); +int __cdecl DRLG_L3Anvil(); +void __cdecl FixL3Warp(); +void __cdecl FixL3HallofHeroes(); +void __fastcall DRLG_L3LockRec(int x, int y); +bool __cdecl DRLG_L3Lockout(); +void __fastcall CreateL3Dungeon(int rseed, int entry); +void __fastcall DRLG_L3(int entry); +void __cdecl InitL3Dungeon(); +int __fastcall DRLG_L3FillRoom(int x1, int y1, int x2, int y2); +void __fastcall DRLG_L3CreateBlock(int x, int y, int obs, int dir); +void __fastcall DRLG_L3FloorArea(int x1, int y1, int x2, int y2); +void __cdecl DRLG_L3FillDiags(); +void __cdecl DRLG_L3FillSingles(); +void __cdecl DRLG_L3FillStraights(); +void __cdecl DRLG_L3Edges(); +int __cdecl DRLG_L3GetFloorArea(); +void __cdecl DRLG_L3MakeMegas(); +void __cdecl DRLG_L3River(); +void __cdecl DRLG_L3Pool(); +int __fastcall DRLG_L3SpawnEdge(int x, int y, int *totarea); +int __fastcall DRLG_L3Spawn(int x, int y, int *totarea); +void __cdecl DRLG_L3PoolFix(); +int __fastcall DRLG_L3PlaceMiniSet(const unsigned char *miniset, int tmin, int tmax, int cx, int cy, bool setview, int ldir); +void __fastcall DRLG_L3PlaceRndSet(const unsigned char *miniset, int rndper); +void __cdecl DRLG_L3Wood(); +bool __fastcall WoodVertU(int i, int y); +bool __fastcall WoodVertD(int i, int y); +bool __fastcall WoodHorizL(int x, int j); +bool __fastcall WoodHorizR(int x, int j); +void __cdecl DRLG_L3Pass3(); +void __fastcall LoadL3Dungeon(char *sFileName, int vx, int vy); +void __fastcall LoadPreL3Dungeon(char *sFileName, int vx, int vy); + +/* rdata */ +extern const unsigned char L3ConvTbl[16]; +extern const unsigned char L3UP[20]; +extern const unsigned char L3DOWN[20]; +extern const unsigned char L3HOLDWARP[20]; +extern const unsigned char L3TITE1[34]; +extern const unsigned char L3TITE2[34]; +extern const unsigned char L3TITE3[34]; +extern const unsigned char L3TITE6[42]; +extern const unsigned char L3TITE7[42]; +extern const unsigned char L3TITE8[20]; +extern const unsigned char L3TITE9[20]; +extern const unsigned char L3TITE10[20]; +extern const unsigned char L3TITE11[20]; +extern const unsigned char L3TITE12[6]; +extern const unsigned char L3TITE13[6]; +extern const unsigned char L3CREV1[6]; +extern const unsigned char L3CREV2[6]; +extern const unsigned char L3CREV3[6]; +extern const unsigned char L3CREV4[6]; +extern const unsigned char L3CREV5[6]; +extern const unsigned char L3CREV6[6]; +extern const unsigned char L3CREV7[6]; +extern const unsigned char L3CREV8[6]; +extern const unsigned char L3CREV9[6]; +extern const unsigned char L3CREV10[6]; +extern const unsigned char L3CREV11[6]; +extern const unsigned char L3ISLE1[14]; +extern const unsigned char L3ISLE2[14]; +extern const unsigned char L3ISLE3[14]; +extern const unsigned char L3ISLE4[14]; +extern const unsigned char L3ISLE5[10]; +extern const unsigned char L3XTRA1[4]; +extern const unsigned char L3XTRA2[4]; +extern const unsigned char L3XTRA3[4]; +extern const unsigned char L3XTRA4[4]; +extern const unsigned char L3XTRA5[4]; +extern const unsigned char L3ANVIL[244]; +extern const unsigned char L3SpawnTbl1[15]; /* local spawntable? */ +extern const unsigned char L3SpawnTbl2[15]; /* local spawntable? */ +extern const unsigned char L3PoolSub[15]; /* local poolsub? */ + +#endif /* __DRLG_L3_H__ */ diff --git a/Source/drlg_l4.cpp b/Source/drlg_l4.cpp new file mode 100644 index 000000000..4c8ff9ec2 --- /dev/null +++ b/Source/drlg_l4.cpp @@ -0,0 +1,3339 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int diabquad1x; // weak +int diabquad1y; // weak +int diabquad3x; // idb +int diabquad3y; // idb +int diabquad2x; // idb +int diabquad2y; // idb +int diabquad4x; // idb +int diabquad4y; // idb +int hallok[20]; +int l4holdx; // weak +int l4holdy; // weak +int SP4x1; // idb +int SP4x2; // weak +int SP4y1; // idb +int SP4y2; // weak +char L4dungeon[80][80]; +char dung[20][20]; +//int dword_52A4DC; // weak +#endif + +const unsigned char L4ConvTbl[16] = { 30u, 6u, 1u, 6u, 2u, 6u, 6u, 6u, 9u, 6u, 1u, 6u, 2u, 6u, 3u, 6u }; +const unsigned char L4USTAIRS[42] = +{ + 4u, + 5u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 0u, + 0u, + 0u, + 0u, + 36u, + 38u, + 35u, + 0u, + 37u, + 34u, + 33u, + 32u, + 0u, + 0u, + 31u, + 0u, + 0u, + 0u, + 0u, + 0u +}; +const unsigned char L4TWARP[42] = +{ + 4u, + 5u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 0u, + 0u, + 0u, + 0u, + 134u, + 136u, + 133u, + 0u, + 135u, + 132u, + 131u, + 130u, + 0u, + 0u, + 129u, + 0u, + 0u, + 0u, + 0u, + 0u +}; +const unsigned char L4DSTAIRS[52] = +{ + 5u, + 5u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 0u, + 0u, + 0u, + 0u, + 0u, + 0u, + 0u, + 45u, + 41u, + 0u, + 0u, + 44u, + 43u, + 40u, + 0u, + 0u, + 46u, + 42u, + 39u, + 0u, + 0u, + 0u, + 0u, + 0u, + 0u +}; +const unsigned char L4PENTA[52] = +{ + 5u, + 5u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 0u, + 0u, + 0u, + 0u, + 0u, + 0u, + 98u, + 100u, + 103u, + 0u, + 0u, + 99u, + 102u, + 105u, + 0u, + 0u, + 101u, + 104u, + 106u, + 0u, + 0u, + 0u, + 0u, + 0u, + 0u +}; +const unsigned char L4PENTA2[52] = +{ + 5u, + 5u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 6u, + 0u, + 0u, + 0u, + 0u, + 0u, + 0u, + 107u, + 109u, + 112u, + 0u, + 0u, + 108u, + 111u, + 114u, + 0u, + 0u, + 110u, + 113u, + 115u, + 0u, + 0u, + 0u, + 0u, + 0u, + 0u +}; +const unsigned char L4BTYPES[140] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, + 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 1, 2, 1, 2, 1, 1, 2, + 2, 0, 0, 0, 0, 0, 0, 15, 16, 9, + 12, 4, 5, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void __cdecl DRLG_LoadL4SP() +{ + setloadflag_2 = 0; + if ( QuestStatus(11) ) + { + pSetPiece_2 = (char *)LoadFileInMem("Levels\\L4Data\\Warlord.DUN", 0); + setloadflag_2 = 1; + } + if ( currlevel == 15 && gbMaxPlayers != 1 ) + { + pSetPiece_2 = (char *)LoadFileInMem("Levels\\L4Data\\Vile1.DUN", 0); + setloadflag_2 = 1; + } +} +// 5B50D8: using guessed type int setloadflag_2; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl DRLG_FreeL4SP() +{ + char *v0; // ecx + + v0 = pSetPiece_2; + pSetPiece_2 = 0; + mem_free_dbg(v0); +} + +void __fastcall DRLG_L4SetSPRoom(int rx1, int ry1) +{ + int v2; // edi + int v3; // esi + int v4; // eax + char v5; // bl + int v6; // [esp+8h] [ebp-Ch] + char *v7; // [esp+Ch] [ebp-8h] + int v8; // [esp+10h] [ebp-4h] + + v8 = 0; + v2 = (unsigned char)pSetPiece_2[2]; + v3 = (unsigned char)*pSetPiece_2; + setpc_x = rx1; + setpc_y = ry1; + setpc_w = v3; + setpc_h = v2; + v7 = pSetPiece_2 + 4; + if ( v2 > 0 ) + { + do + { + if ( v3 > 0 ) + { + v6 = v3; + v4 = ry1 + v8 + 40 * rx1; + do + { + v5 = *v7; + if ( *v7 ) + { + dflags[0][v4] |= 0x80u; + dungeon[0][v4] = v5; + } + else + { + dungeon[0][v4] = 6; + } + v7 += 2; + v4 += 40; + --v6; + } + while ( v6 ); + } + ++v8; + } + while ( v8 < v2 ); + } +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __cdecl L4SaveQuads() +{ + char *v0; // esi + char *v1; // edx + char *v2; // edi + char *v3; // eax + char *v4; // ecx + char *v5; // ebx + signed int v6; // [esp+Ch] [ebp-14h] + signed int v7; // [esp+10h] [ebp-10h] + char *v8; // [esp+14h] [ebp-Ch] + char *v9; // [esp+18h] [ebp-8h] + char *v10; // [esp+1Ch] [ebp-4h] + + v0 = &dflags[39][l4holdy - 40 * l4holdx]; /* check */ + v1 = &dflags[39][-l4holdy + 39 + -40 * l4holdx]; + v9 = &dflags[l4holdx][l4holdy]; + v8 = &dflags[0][40 * l4holdx - l4holdy + 39]; + v6 = 14; + do + { + v2 = v1; + v10 = v8; + v3 = v9; + v4 = v0; + v7 = 14; + do + { + v5 = v10; + v10 += 40; + *v3 = 1; + *v4 = 1; + *v5 = 1; + *v2 = 1; + v4 -= 40; + v2 -= 40; + v3 += 40; + --v7; + } + while ( v7 ); + ++v9; + --v8; + --v1; + ++v0; + --v6; + } + while ( v6 ); +} +// 528A34: using guessed type int l4holdx; +// 528A38: using guessed type int l4holdy; + +void __fastcall DRLG_L4SetRoom(unsigned char *pSetPiece, int rx1, int ry1) +{ + int v3; // ebx + int v4; // edi + unsigned char *v5; // esi + int v6; // eax + char v7; // cl + int v8; // [esp+Ch] [ebp-8h] + int v9; // [esp+10h] [ebp-4h] + + v3 = *pSetPiece; + v4 = 0; + v8 = pSetPiece[2]; + v5 = pSetPiece + 4; + if ( v8 > 0 ) + { + do + { + if ( v3 > 0 ) + { + v9 = v3; + v6 = ry1 + v4 + 40 * rx1; + do + { + v7 = *v5; + if ( *v5 ) + { + dflags[0][v6] |= 0x80u; + dungeon[0][v6] = v7; + } + else + { + dungeon[0][v6] = 6; + } + v6 += 40; + v5 += 2; + --v9; + } + while ( v9 ); + } + ++v4; + } + while ( v4 < v8 ); + } +} + +void __fastcall DRLG_LoadDiabQuads(bool preflag) +{ + bool v1; // esi + unsigned char *v2; // edi + char *v3; // ecx + unsigned char *v4; // edi + char *v5; // ecx + unsigned char *v6; // edi + char *v7; // ecx + unsigned char *v8; // esi + + v1 = preflag; + v2 = LoadFileInMem("Levels\\L4Data\\diab1.DUN", 0); + diabquad1x = l4holdx + 4; + diabquad1y = l4holdy + 4; + DRLG_L4SetRoom(v2, l4holdx + 4, l4holdy + 4); + mem_free_dbg(v2); + v3 = "Levels\\L4Data\\diab2b.DUN"; + if ( !v1 ) + v3 = "Levels\\L4Data\\diab2a.DUN"; + v4 = LoadFileInMem(v3, 0); + diabquad2y = l4holdy + 1; + diabquad2x = 27 - l4holdx; + DRLG_L4SetRoom(v4, 27 - l4holdx, l4holdy + 1); + mem_free_dbg(v4); + v5 = "Levels\\L4Data\\diab3b.DUN"; + if ( !v1 ) + v5 = "Levels\\L4Data\\diab3a.DUN"; + v6 = LoadFileInMem(v5, 0); + diabquad3x = l4holdx + 1; + diabquad3y = 27 - l4holdy; + DRLG_L4SetRoom(v6, l4holdx + 1, 27 - l4holdy); + mem_free_dbg(v6); + v7 = "Levels\\L4Data\\diab4b.DUN"; + if ( !v1 ) + v7 = "Levels\\L4Data\\diab4a.DUN"; + v8 = LoadFileInMem(v7, 0); + diabquad4y = 28 - l4holdy; + diabquad4x = 28 - l4holdx; + DRLG_L4SetRoom(v8, 28 - l4holdx, 28 - l4holdy); + mem_free_dbg(v8); +} +// 5289C4: using guessed type int diabquad1x; +// 5289C8: using guessed type int diabquad1y; +// 528A34: using guessed type int l4holdx; +// 528A38: using guessed type int l4holdy; + +bool __fastcall IsDURWall(char d) +{ + bool result; // al + + if ( d == 25 || d == 28 ) + result = 1; + else + result = d == 23; + return result; +} + +bool __fastcall IsDLLWall(char dd) +{ + bool result; // al + + if ( dd == 27 || dd == 26 ) + result = 1; + else + result = dd == 22; + return result; +} + +void __cdecl L4FixRim() +{ + char (*v0)[20]; // eax + + v0 = dung; + do + { + *(_BYTE *)v0 = 0; + ++v0; + } + while ( (signed int)v0 < (signed int)&dung[20][0] ); + *(_DWORD *)&dung[0][0] = 0; + *(_DWORD *)&dung[0][4] = 0; + *(_DWORD *)&dung[0][8] = 0; + *(_DWORD *)&dung[0][12] = 0; + *(_DWORD *)&dung[0][16] = 0; +} +// 52A4DC: using guessed type int dword_52A4DC; + +void __cdecl DRLG_L4GeneralFix() +{ + signed int v0; // ecx + char *v1; // eax + signed int v2; // esi + + v0 = 0; + do + { + v1 = (char *)dungeon + v0; + v2 = 39; + do + { + if ( (*v1 == 24 || *v1 == 122) && v1[40] == 2 && v1[1] == 5 ) + *v1 = 17; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 39 ); +} + +void __fastcall CreateL4Dungeon(int rseed, int entry) +{ + int v2; // esi + + v2 = entry; + SetRndSeed(rseed); + dminx = 16; + dminy = 16; + dmaxx = 96; + dmaxy = 96; + ViewX = 40; + ViewY = 40; + DRLG_InitSetPC(); + DRLG_LoadL4SP(); + DRLG_L4(v2); + DRLG_L4Pass3(); + DRLG_FreeL4SP(); + DRLG_SetPC(); +} +// 5CF328: using guessed type int dmaxx; +// 5CF32C: using guessed type int dmaxy; +// 5D2458: using guessed type int dminx; +// 5D245C: using guessed type int dminy; + +void __fastcall DRLG_L4(int entry) +{ + signed int v1; // ebp + //int v2; // eax + int v3; // edx + char *v4; // edi + char v5; // bp + unsigned int v6; // ecx + char *v7; // edi + int v8; // ecx + //int v9; // eax + int v10; // eax + unsigned char *v11; // ecx + unsigned char *v12; // ecx + //int v13; // eax + signed int v14; // eax + signed int v15; // ecx + int v16; // ebx + int v17; // edi + char *v18; // ebp + signed int v19; // ecx + signed int v20; // eax + signed int v21; // esi + int v22; // [esp-8h] [ebp-20h] + int v23; // [esp+10h] [ebp-8h] + int v24; // [esp+14h] [ebp-4h] + + v1 = 0; + v23 = entry; + do + { + DRLG_InitTrans(); + do + { + InitL4Dungeon(); + L4firstRoom(); + L4FixRim(); + } + while ( GetArea() < 173 ); + uShape(); + L4makeDungeon(); + L4makeDmt(); + L4tileFix(); + if ( currlevel == 16 ) + L4SaveQuads(); + //_LOBYTE(v2) = QuestStatus(11); + if ( (QuestStatus(11) || currlevel == quests[15]._qlevel && gbMaxPlayers != 1) && SP4x1 < SP4x2 ) + { + v3 = SP4x1; + v24 = SP4x2 - SP4x1; + do + { + if ( SP4y1 < SP4y2 ) + { + v4 = &dflags[v3][SP4y1]; + v5 = SP4y2 - SP4y1; + v6 = (unsigned int)(SP4y2 - SP4y1) >> 2; + memset(v4, 1u, 4 * v6); + v7 = &v4[4 * v6]; + v8 = v5 & 3; + v1 = 0; + memset(v7, 1, v8); + } + ++v3; + --v24; + } + while ( v24 ); + } + L4AddWall(); + DRLG_L4FloodTVal(); + DRLG_L4TransFix(); + if ( setloadflag_2 ) + DRLG_L4SetSPRoom(SP4x1, SP4y1); + if ( currlevel == 16 ) + DRLG_LoadDiabQuads(1); + //_LOBYTE(v9) = QuestStatus(11); + if ( !QuestStatus(11) ) + { + if ( currlevel == 15 ) + { + if ( !v23 ) + { + v10 = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, 1, 0); + if ( v10 ) + { + if ( gbMaxPlayers != 1 || (v11 = (unsigned char *)L4PENTA, quests[5]._qactive == 2) ) + v11 = (unsigned char *)L4PENTA2; + v10 = DRLG_L4PlaceMiniSet(v11, 1, 1, -1, -1, 0, 1); + } + goto LABEL_35; + } + v10 = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, 0, 0); + if ( v10 ) + { + if ( gbMaxPlayers != 1 || (v12 = (unsigned char *)L4PENTA, quests[5]._qactive == 2) ) + v12 = (unsigned char *)L4PENTA2; + v10 = DRLG_L4PlaceMiniSet(v12, 1, 1, -1, -1, 1, 1); + } + } + else + { + if ( !v23 ) + { + v10 = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, 1, 0); + if ( v10 ) + { + if ( currlevel != 16 ) + v10 = DRLG_L4PlaceMiniSet(L4DSTAIRS, 1, 1, -1, -1, 0, 1); + goto LABEL_31; + } +LABEL_35: + ++ViewX; + continue; + } + v10 = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, 0, 0); + if ( v23 != 1 ) + { + if ( v10 ) + { + if ( currlevel != 16 ) + v10 = DRLG_L4PlaceMiniSet(L4DSTAIRS, 1, 1, -1, -1, 0, 1); +LABEL_46: + if ( v10 ) + { + if ( currlevel == 13 ) + { + v22 = 1; +LABEL_34: + v10 = DRLG_L4PlaceMiniSet(L4TWARP, 1, 1, -1, -1, v22, 6); + goto LABEL_35; + } + } + } + goto LABEL_35; + } + if ( v10 ) + { + if ( currlevel != 16 ) + v10 = DRLG_L4PlaceMiniSet(L4DSTAIRS, 1, 1, -1, -1, 1, 1); + if ( v10 && currlevel == 13 ) + v10 = DRLG_L4PlaceMiniSet(L4TWARP, 1, 1, -1, -1, 0, 6); + } + } + ++ViewY; + continue; + } + if ( !v23 ) + { + v10 = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, 1, 0); +LABEL_31: + if ( !v10 || currlevel != 13 ) + goto LABEL_35; + v22 = 0; + goto LABEL_34; + } + v10 = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, 0, 0); + if ( v23 != 1 ) + goto LABEL_46; + if ( v10 && currlevel == 13 ) + v10 = DRLG_L4PlaceMiniSet(L4TWARP, 1, 1, -1, -1, 0, 6); + ViewX = 2 * setpc_x + 22; + ViewY = 2 * setpc_y + 22; + } + while ( !v10 ); + DRLG_L4GeneralFix(); + if ( currlevel != 16 ) + DRLG_PlaceThemeRooms(7, 10, 6, 8, 1); + DRLG_L4Shadows(); + DRLG_L4Corners(); + DRLG_L4Subs(); + DRLG_Init_Globals(); + //_LOBYTE(v13) = QuestStatus(11); + if ( QuestStatus(11) ) + { + do + { + v14 = v1; + v15 = 40; + do + { + pdungeon[0][v14] = dungeon[0][v14]; + v14 += 40; + --v15; + } + while ( v15 ); + ++v1; + } + while ( v1 < 40 ); + } + DRLG_CheckQuests(SP4x1, SP4y1); + if ( currlevel == 15 ) + { + v16 = -1; + do + { + v17 = -1; + v18 = &dungeon[0][v16 + 1]; + do + { + if ( *v18 == 98 ) + Make_SetPC(v17, v16, 5, 5); + if ( *v18 == 107 ) + Make_SetPC(v17, v16, 5, 5); + v18 += 40; + ++v17; + } + while ( v17 + 1 < 40 ); + ++v16; + } + while ( v16 < 39 ); + } + if ( currlevel == 16 ) + { + v19 = 0; + do + { + v20 = v19; + v21 = 40; + do + { + pdungeon[0][v20] = dungeon[0][v20]; + v20 += 40; + --v21; + } + while ( v21 ); + ++v19; + } + while ( v19 < 40 ); + DRLG_LoadDiabQuads(0); + } +} +// 528A40: using guessed type int SP4x2; +// 528A48: using guessed type int SP4y2; +// 5B50D8: using guessed type int setloadflag_2; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl DRLG_L4Shadows() +{ + signed int v0; // esi + char *v1; // eax + signed int v2; // edi + char v3; // dl + signed int v4; // ecx + + v0 = 1; + do + { + v1 = &dungeon[1][v0]; + v2 = 39; + do + { + v3 = *v1; + v4 = 0; + if ( *v1 == 3 ) + v4 = 1; + if ( v3 == 4 ) + v4 = 1; + if ( v3 == 8 ) + v4 = 1; + if ( v3 == 15 ) + v4 = 1; + if ( v4 ) + { + if ( *(v1 - 40) == 6 ) + *(v1 - 40) = 47; + if ( *(v1 - 41) == 6 ) + *(v1 - 41) = 48; + } + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl InitL4Dungeon() +{ + signed int v0; // edx + signed int v1; // eax + signed int v2; // ecx + + memset(dung, 0, 0x190u); + memset(L4dungeon, 0, 0x1900u); + v0 = 0; + do + { + v1 = v0; + v2 = 40; + do + { + dflags[0][v1] = 0; + dungeon[0][v1] = 30; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl L4makeDmt() +{ + signed int v0; // ecx + char (*v1)[40]; // ebp + char (*v2)[40]; // esi + char *v3; // eax + signed int v4; // edi + int v5; // edx + int v6; // ebx + + v0 = 1; + v1 = dungeon; + do + { + v2 = v1; + v3 = &L4dungeon[1][v0 + 1]; + v4 = 39; + do + { + v5 = (unsigned char)v3[80]; + v6 = (unsigned char)*v3; + v3 += 160; + *(_BYTE *)v2 = L4ConvTbl[2 * ((unsigned char)*(v3 - 81) + 2 * (v6 + 2 * v5)) + + (unsigned char)*(v3 - 161)]; + ++v2; + --v4; + } + while ( v4 ); + v1 = (char (*)[40])((char *)v1 + 1); + v0 += 2; + } + while ( v0 <= 77 ); +} + +void __cdecl L4AddWall() +{ + int v0; // edi + int v1; // esi + int v2; // ebx + int v3; // eax + int v4; // eax + int v5; // eax + int v6; // eax + int v7; // eax + int v8; // eax + int v9; // eax + int v10; // eax + int v11; // eax + int v12; // eax + int v13; // eax + int v14; // eax + int v15; // eax + int v16; // eax + int v17; // eax + + v0 = 0; + do + { + v1 = 0; + v2 = v0; + do + { + if ( !dflags[0][v2] ) + { + if ( dungeon[0][v2] == 10 && random(0, 100) < 100 ) + { + v3 = L4HWallOk(v1, v0); + if ( v3 != -1 ) + L4HorizWall(v1, v0, v3); + } + if ( dungeon[0][v2] == 12 && random(0, 100) < 100 ) + { + v4 = L4HWallOk(v1, v0); + if ( v4 != -1 ) + L4HorizWall(v1, v0, v4); + } + if ( dungeon[0][v2] == 13 && random(0, 100) < 100 ) + { + v5 = L4HWallOk(v1, v0); + if ( v5 != -1 ) + L4HorizWall(v1, v0, v5); + } + if ( dungeon[0][v2] == 15 && random(0, 100) < 100 ) + { + v6 = L4HWallOk(v1, v0); + if ( v6 != -1 ) + L4HorizWall(v1, v0, v6); + } + if ( dungeon[0][v2] == 16 && random(0, 100) < 100 ) + { + v7 = L4HWallOk(v1, v0); + if ( v7 != -1 ) + L4HorizWall(v1, v0, v7); + } + if ( dungeon[0][v2] == 21 && random(0, 100) < 100 ) + { + v8 = L4HWallOk(v1, v0); + if ( v8 != -1 ) + L4HorizWall(v1, v0, v8); + } + if ( dungeon[0][v2] == 22 && random(0, 100) < 100 ) + { + v9 = L4HWallOk(v1, v0); + if ( v9 != -1 ) + L4HorizWall(v1, v0, v9); + } + if ( dungeon[0][v2] == 8 && random(0, 100) < 100 ) + { + v10 = L4VWallOk(v1, v0); + if ( v10 != -1 ) + L4VertWall(v1, v0, v10); + } + if ( dungeon[0][v2] == 9 && random(0, 100) < 100 ) + { + v11 = L4VWallOk(v1, v0); + if ( v11 != -1 ) + L4VertWall(v1, v0, v11); + } + if ( dungeon[0][v2] == 11 && random(0, 100) < 100 ) + { + v12 = L4VWallOk(v1, v0); + if ( v12 != -1 ) + L4VertWall(v1, v0, v12); + } + if ( dungeon[0][v2] == 14 && random(0, 100) < 100 ) + { + v13 = L4VWallOk(v1, v0); + if ( v13 != -1 ) + L4VertWall(v1, v0, v13); + } + if ( dungeon[0][v2] == 15 && random(0, 100) < 100 ) + { + v14 = L4VWallOk(v1, v0); + if ( v14 != -1 ) + L4VertWall(v1, v0, v14); + } + if ( dungeon[0][v2] == 16 && random(0, 100) < 100 ) + { + v15 = L4VWallOk(v1, v0); + if ( v15 != -1 ) + L4VertWall(v1, v0, v15); + } + if ( dungeon[0][v2] == 21 && random(0, 100) < 100 ) + { + v16 = L4VWallOk(v1, v0); + if ( v16 != -1 ) + L4VertWall(v1, v0, v16); + } + if ( dungeon[0][v2] == 23 && random(0, 100) < 100 ) + { + v17 = L4VWallOk(v1, v0); + if ( v17 != -1 ) + L4VertWall(v1, v0, v17); + } + } + ++v1; + v2 += 40; + } + while ( v1 < 40 ); + ++v0; + } + while ( v0 < 40 ); +} + +int __fastcall L4HWallOk(int i, int j) +{ + int v2; // esi + int v3; // edi + char *v4; // ebx + int result; // eax + signed int v6; // esi + char v7; // dl + int v8; // [esp+8h] [ebp-4h] + + v2 = 8 * (5 * i + 5); + v8 = 1; + if ( dungeon[0][v2 + j] == 6 ) + { + v3 = 8 * (5 * i + 5); + v4 = &dungeon[i + 1][j]; + do + { + if ( dflags[0][v3 + j] ) + break; + if ( dungeon[0][v3 + j - 1] != 6 ) // *((_BYTE *)&dMonster[111][111] + v3 + j + 3) != 6 ) /* check */ + break; + if ( dungeon[0][v3 + 1 + j] != 6 ) + break; + ++v8; + v4 += 40; + v2 += 40; + v3 = v2; + } + while ( *v4 == 6 ); + } + result = v8; + v6 = 0; + v7 = dungeon[v8 + i][j]; + if ( v7 == 10 ) + v6 = 1; + if ( v7 == 12 ) + v6 = 1; + if ( v7 == 13 ) + v6 = 1; + if ( v7 == 15 ) + v6 = 1; + if ( v7 == 16 ) + v6 = 1; + if ( v7 == 21 ) + v6 = 1; + if ( v7 == 22 ) + v6 = 1; + if ( v8 <= 3 ) + v6 = 0; + if ( !v6 ) + result = -1; + return result; +} + +int __fastcall L4VWallOk(int i, int j) +{ + int v2; // ecx + int result; // eax + char *v4; // esi + signed int v5; // esi + char v6; // dl + + v2 = i; + result = 1; + if ( dungeon[v2][j + 1] == 6 ) + { + do + { + if ( dflags[v2][j + result] ) + break; + v4 = &dungeon[v2][j]; + if ( v4[result - 40] != 6 ) + break; + if ( dungeon[v2 + 1][result + j] != 6 ) + break; + ++result; + } + while ( v4[result] == 6 ); + } + v5 = 0; + v6 = dungeon[0][result + v2 * 40 + j]; + if ( v6 == 8 ) + v5 = 1; + if ( v6 == 9 ) + v5 = 1; + if ( v6 == 11 ) + v5 = 1; + if ( v6 == 14 ) + v5 = 1; + if ( v6 == 15 ) + v5 = 1; + if ( v6 == 16 ) + v5 = 1; + if ( v6 == 21 ) + v5 = 1; + if ( v6 == 23 ) + v5 = 1; + if ( result <= 3 ) + v5 = 0; + if ( !v5 ) + result = -1; + return result; +} + +void __fastcall L4HorizWall(int i, int j, int dx) +{ + int v3; // esi + int v4; // edi + int v5; // eax + int v6; // ecx + char *v7; // eax + int v8; // edx + char *v9; // eax + int v10; // eax + bool v11; // zf + char *v12; // eax + + v3 = i; + v4 = j; + v5 = j + 40 * i; + if ( dungeon[0][v5] == 13 ) + dungeon[0][v5] = 17; + if ( dungeon[0][v5] == 16 ) + dungeon[0][v5] = 11; + if ( dungeon[0][v5] == 12 ) + dungeon[0][v5] = 14; + v6 = dx; + if ( dx > 1 ) + { + v7 = &dungeon[1][v5]; + v8 = dx - 1; + do + { + *v7 = 2; + v7 += 40; + --v8; + } + while ( v8 ); + } + v9 = &dungeon[v3 + dx][v4]; + if ( *v9 == 15 ) + *v9 = 14; + if ( *v9 == 10 ) + *v9 = 17; + if ( *v9 == 21 ) + *v9 = 23; + if ( *v9 == 22 ) + *v9 = 29; + v10 = v4 + 40 * (v3 + random(0, dx - 3) + 1); + dungeon[2][v10] = 56; + dungeon[1][v10] = 60; + v11 = dungeon[0][v10 - 1] == 6; + dungeon[0][v10] = 57; + if ( v11 ) + dungeon[0][v10 - 1] = 58; + v12 = &dungeon[0][v10 + 39]; + if ( *v12 == 6 ) + *v12 = 59; +} + +void __fastcall L4VertWall(int i, int j, int dy) +{ + int v3; // edi + int v4; // esi + int v5; // edx + int v6; // ecx + _BYTE *v7; // eax + int v8; // edx + int v9; // eax + char *v10; // ecx + bool v11; // zf + int v12; // [esp+8h] [ebp-4h] + + v3 = j; + v4 = 40 * i; + v12 = j; + v5 = 40 * i + j; + if ( dungeon[0][v5] == 14 ) + dungeon[0][v5] = 17; + if ( dungeon[0][v5] == 8 ) + dungeon[0][v5] = 9; + if ( dungeon[0][v5] == 15 ) + dungeon[0][v5] = 10; + v6 = dy; + if ( dy > 1 ) + { + memset(&dungeon[0][v5 + 1], 1u, dy - 1); + v3 = v12; + v6 = dy; + } + v7 = (unsigned char *)dungeon + v5 + v6; + if ( *v7 == 11 ) + *v7 = 17; + if ( *v7 == 9 ) + *v7 = 10; + if ( *v7 == 16 ) + *v7 = 13; + if ( *v7 == 21 ) + *v7 = 22; + if ( *v7 == 23 ) + *v7 = 29; + v8 = v6 - 3; + v9 = random(0, v8) + 1 + v4 + v3; + v10 = (char *)dungeon + v9; + dungeon[0][v9 + 2] = 52; + dungeon[0][v9 + 1] = 6; + v11 = dungeon[-1][v9] == 6; + dungeon[0][v9] = 53; + if ( v11 ) + *(v10 - 40) = 54; + if ( *(v10 - 41) == 6 ) + *(v10 - 41) = 55; +} + +void __cdecl L4tileFix() +{ + signed int v0; // edx + char *v1; // eax + signed int v2; // esi + char v3; // cl + signed int v4; // edx + char *v5; // eax + signed int v6; // esi + char v7; // cl + signed int v8; // ecx + int v9; // eax + int v10; // eax + char *v11; // esi + char v12; // bl + char *v13; // edx + char *v14; // edx + char *v15; // edx + char *v16; // edx + char *v17; // edx + char *v18; // edx + char *v19; // edx + char *v20; // edx + char *v21; // edx + char *v22; // edx + char *v23; // edx + char *v24; // edx + char *v25; // edx + char *v26; // edx + char *v27; // edx + char *v28; // edx + char *v29; // edx + char *v30; // edx + char *v31; // edx + char *v32; // edx + char *v33; // edx + char *v34; // edx + char *v35; // edx + char *v36; // edx + char *v37; // edx + char *v38; // edx + char *v39; // edx + char *v40; // edx + char *v41; // edx + char *v42; // edx + char *v43; // edx + char *v44; // edx + char *v45; // edx + char *v46; // edx + char *v47; // edx + char *v48; // edx + char *v49; // edx + char *v50; // edx + char *v51; // edx + char *v52; // edx + char *v53; // edx + char *v54; // edx + char *v55; // edx + char *v56; // edx + char *v57; // edx + char *v58; // edx + char *v59; // edx + char *v60; // edx + char *v61; // edx + char *v62; // edx + char *v63; // edx + char *v64; // edx + char *v65; // edx + char *v66; // edx + char *v67; // edx + char *v68; // edx + char *v69; // edx + char *v70; // edx + char *v71; // edx + char *v72; // edx + char *v73; // edx + char *v74; // edx + char *v75; // edx + char *v76; // edx + char *v77; // edx + char *v78; // edx + char *v79; // edx + char *v80; // edx + char *v81; // edx + char *v82; // edx + char *v83; // edx + char *v84; // edx + char *v85; // edx + char *v86; // edx + char *v87; // edx + char *v88; // edx + char *v89; // edx + char *v90; // edx + char *v91; // edx + char *v92; // edx + char *v93; // edx + char *v94; // edx + char *v95; // edx + signed int v96; // ecx + signed int v97; // edi + signed int v98; // eax + char *v99; // esi + char v100; // bl + char *v101; // edx + char *v102; // edx + char *v103; // edx + char *v104; // edx + char *v105; // edx + char *v106; // edx + char *v107; // edx + char *v108; // edx + char *v109; // edx + char *v110; // edx + char *v111; // edx + char *v112; // edx + char *v113; // edx + char *v114; // edx + char *v115; // edx + char *v116; // edx + char *v117; // edx + char *v118; // edx + char *v119; // edx + char *v120; // edx + char *v121; // edx + char *v122; // edx + char *v123; // edx + char *v124; // edx + char *v125; // edx + char *v126; // edx + char *v127; // edx + char *v128; // edx + char *v129; // edx + char *v130; // edx + signed int v131; // edx + char *v132; // eax + signed int v133; // esi + char v134; // cl + signed int v135; // edx + char *v136; // eax + signed int v137; // esi + char v138; // cl + signed int v139; // [esp+8h] [ebp-4h] + + v0 = 0; + do + { + v1 = &dungeon[1][v0]; + v2 = 40; + do + { + v3 = *(v1 - 40); + if ( v3 == 2 ) + { + if ( *v1 == 6 ) + *v1 = 5; + if ( *v1 == 1 ) + *v1 = 13; + } + if ( v3 == 1 && *(v1 - 39) == 2 ) + *(v1 - 39) = 14; + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); + v4 = 0; + do + { + v5 = &dungeon[1][v4]; + v6 = 40; + do + { + v7 = *(v5 - 40); + if ( v7 == 2 ) + { + if ( *v5 == 6 ) + *v5 = 2; + if ( *v5 == 9 ) + *v5 = 11; + } + if ( v7 == 9 && *v5 == 6 ) + *v5 = 12; + if ( v7 == 14 && *v5 == 1 ) + *v5 = 13; + if ( v7 == 6 ) + { + if ( *v5 == 14 ) + *v5 = 15; + if ( *(v5 - 39) == 13 ) + *(v5 - 39) = 16; + } + if ( v7 == 1 && *(v5 - 39) == 9 ) + *(v5 - 39) = 10; + if ( v7 == 6 && *(v5 - 41) == 1 ) + *(v5 - 41) = 1; + v5 += 40; + --v6; + } + while ( v6 ); + ++v4; + } + while ( v4 < 40 ); + v8 = 0; + do + { + v9 = 0; + v139 = 0; + do + { + v10 = v9; + v11 = &dungeon[v10][v8]; + v12 = *v11; + if ( *v11 == 13 ) + { + v13 = &dungeon[v10][v8 + 1]; + if ( *v13 == 30 ) + *v13 = 27; + } + if ( v12 == 27 ) + { + v14 = &dungeon[v10 + 1][v8]; + if ( *v14 == 30 ) + *v14 = 19; + } + if ( v12 == 1 ) + { + v15 = &dungeon[v10][v8 + 1]; + if ( *v15 == 30 ) + *v15 = 27; + } + if ( v12 == 27 ) + { + v16 = &dungeon[v10 + 1][v8]; + if ( *v16 == 1 ) + *v16 = 16; + } + if ( v12 == 19 ) + { + v17 = &dungeon[v10 + 1][v8]; + if ( *v17 == 27 ) + *v17 = 26; + } + if ( v12 == 27 ) + { + v18 = &dungeon[v10 + 1][v8]; + if ( *v18 == 30 ) + *v18 = 19; + } + if ( v12 == 2 ) + { + v19 = &dungeon[v10 + 1][v8]; + if ( *v19 == 15 ) + *v19 = 14; + } + if ( v12 == 14 ) + { + v20 = &dungeon[v10 + 1][v8]; + if ( *v20 == 15 ) + *v20 = 14; + } + if ( v12 == 22 ) + { + v21 = &dungeon[v10 + 1][v8]; + if ( *v21 == 1 ) + *v21 = 16; + } + if ( v12 == 27 ) + { + v22 = &dungeon[v10 + 1][v8]; + if ( *v22 == 1 ) + *v22 = 16; + } + if ( v12 == 6 ) + { + v23 = &dungeon[v10 + 1][v8]; + if ( *v23 == 27 ) + { + if ( dungeon[v10 + 1][v8 + 1] ) + *v23 = 22; + } + } + if ( v12 == 22 ) + { + v24 = &dungeon[v10 + 1][v8]; + if ( *v24 == 30 ) + *v24 = 19; + } + if ( v12 == 21 ) + { + v25 = &dungeon[v10 + 1][v8]; + if ( *v25 == 1 && dungeon[v10][v8 + 39] == 1 ) + *v25 = 13; + } + if ( v12 == 14 ) + { + v26 = &dungeon[v10 + 1][v8]; + if ( *v26 == 30 && dungeon[v10][v8 + 1] == 6 ) + *v26 = 28; + } + if ( v12 == 16 ) + { + if ( dungeon[v10 + 1][v8] == 6 ) + { + v27 = &dungeon[v10][v8 + 1]; + if ( *v27 == 30 ) + *v27 = 27; + } + v28 = &dungeon[v10][v8 + 1]; + if ( *v28 == 30 && dungeon[v10 + 1][v8 + 1] == 30 ) + *v28 = 27; + } + if ( v12 == 6 ) + { + v29 = &dungeon[v10 + 1][v8]; + if ( *v29 == 30 && dungeon[v10][v8 + 39] == 6 ) + *v29 = 21; + } + if ( v12 == 2 ) + { + v30 = &dungeon[v10 + 1][v8]; + if ( *v30 == 27 && dungeon[v10 + 1][v8 + 1] == 9 ) + *v30 = 29; + } + if ( v12 == 9 ) + { + v31 = &dungeon[v10 + 1][v8]; + if ( *v31 == 15 ) + *v31 = 14; + } + if ( v12 == 15 ) + { + v32 = &dungeon[v10 + 1][v8]; + if ( *v32 == 27 && dungeon[v10 + 1][v8 + 1] == 2 ) + *v32 = 29; + } + if ( v12 == 19 ) + { + v33 = &dungeon[v10 + 1][v8]; + if ( *v33 == 18 ) + *v33 = 24; + } + if ( v12 == 9 ) + { + v34 = &dungeon[v10 + 1][v8]; + if ( *v34 == 15 ) + *v34 = 14; + } + if ( v12 == 19 ) + { + v35 = &dungeon[v10 + 1][v8]; + if ( *v35 == 19 && dungeon[v10][v8 + 39] == 30 ) + *v35 = 24; + } + if ( v12 == 24 && *(v11 - 1) == 30 && *(v11 - 2) == 6 ) + *(v11 - 1) = 21; + if ( v12 == 2 ) + { + v36 = &dungeon[v10 + 1][v8]; + if ( *v36 == 30 ) + *v36 = 28; + } + if ( v12 == 15 ) + { + v37 = &dungeon[v10 + 1][v8]; + if ( *v37 == 30 ) + *v37 = 28; + } + if ( v12 == 28 ) + { + v38 = &dungeon[v10][v8 + 1]; + if ( *v38 == 30 ) + *v38 = 18; + v39 = &dungeon[v10][v8 + 1]; + if ( *v39 == 2 ) + *v39 = 15; + } + if ( v12 == 19 ) + { + if ( dungeon[v10 + 2][v8] == 2 && dungeon[v10][v8 + 39] == 18 && dungeon[v10 + 1][v8 + 1] == 1 ) + dungeon[v10 + 1][v8] = 17; + if ( dungeon[v10 + 2][v8] == 2 && dungeon[v10][v8 + 39] == 22 && dungeon[v10 + 1][v8 + 1] == 1 ) + dungeon[v10 + 1][v8] = 17; + if ( dungeon[v10 + 2][v8] == 2 && dungeon[v10][v8 + 39] == 18 && dungeon[v10 + 1][v8 + 1] == 13 ) + dungeon[v10 + 1][v8] = 17; + } + if ( v12 == 21 ) + { + if ( dungeon[v10 + 2][v8] == 2 && dungeon[v10][v8 + 39] == 18 && dungeon[v10 + 1][v8 + 1] == 1 ) + dungeon[v10 + 1][v8] = 17; + if ( dungeon[v10 + 1][v8 + 1] == 1 && dungeon[v10][v8 + 39] == 22 && dungeon[v10 + 2][v8] == 3 ) + dungeon[v10 + 1][v8] = 17; + } + if ( v12 == 15 ) + { + v40 = &dungeon[v10 + 1][v8]; + if ( *v40 == 28 && dungeon[v10 + 2][v8] == 30 && dungeon[v10][v8 + 39] == 6 ) + *v40 = 23; + } + if ( v12 == 14 ) + { + v41 = &dungeon[v10 + 1][v8]; + if ( *v41 == 28 && dungeon[v10 + 2][v8] == 1 ) + *v41 = 23; + } + if ( v12 == 15 ) + { + v42 = &dungeon[v10 + 1][v8]; + if ( *v42 == 27 && dungeon[v10 + 1][v8 + 1] == 30 ) + *v42 = 29; + } + if ( v12 == 28 ) + { + v43 = &dungeon[v10][v8 + 1]; + if ( *v43 == 9 ) + *v43 = 15; + } + if ( v12 == 21 && dungeon[v10][v8 + 39] == 21 ) + dungeon[v10 + 1][v8] = 24; + if ( v12 == 2 ) + { + v44 = &dungeon[v10 + 1][v8]; + if ( *v44 == 27 && dungeon[v10 + 1][v8 + 1] == 30 ) + *v44 = 29; + v45 = &dungeon[v10 + 1][v8]; + if ( *v45 == 18 ) + *v45 = 25; + } + if ( v12 == 21 ) + { + v46 = &dungeon[v10 + 1][v8]; + if ( *v46 == 9 && dungeon[v10 + 2][v8] == 2 ) + *v46 = 11; + } + if ( v12 == 19 ) + { + v47 = &dungeon[v10 + 1][v8]; + if ( *v47 == 10 ) + *v47 = 17; + } + if ( v12 == 15 ) + { + v48 = &dungeon[v10][v8 + 1]; + if ( *v48 == 3 ) + *v48 = 4; + } + if ( v12 == 22 ) + { + v49 = &dungeon[v10][v8 + 1]; + if ( *v49 == 9 ) + *v49 = 15; + } + if ( v12 == 18 ) + { + v50 = &dungeon[v10][v8 + 1]; + if ( *v50 == 30 ) + *v50 = 18; + } + if ( v12 == 24 && *(v11 - 40) == 30 ) + *(v11 - 40) = 19; + if ( v12 == 21 ) + { + v51 = &dungeon[v10][v8 + 1]; + if ( *v51 == 2 ) + *v51 = 15; + v52 = &dungeon[v10][v8 + 1]; + if ( *v52 == 9 ) + *v52 = 10; + } + if ( v12 == 22 ) + { + v53 = &dungeon[v10][v8 + 1]; + if ( *v53 == 30 ) + *v53 = 18; + } + if ( v12 == 21 ) + { + v54 = &dungeon[v10][v8 + 1]; + if ( *v54 == 30 ) + *v54 = 18; + } + if ( v12 == 16 ) + { + v55 = &dungeon[v10][v8 + 1]; + if ( *v55 == 2 ) + *v55 = 15; + } + if ( v12 == 13 ) + { + v56 = &dungeon[v10][v8 + 1]; + if ( *v56 == 2 ) + *v56 = 15; + } + if ( v12 == 22 ) + { + v57 = &dungeon[v10][v8 + 1]; + if ( *v57 == 2 ) + *v57 = 15; + } + if ( v12 == 21 ) + { + v58 = &dungeon[v10 + 1][v8]; + if ( *v58 == 18 && dungeon[v10 + 2][v8] == 30 ) + *v58 = 24; + v59 = &dungeon[v10 + 1][v8]; + if ( *v59 == 9 && dungeon[v10 + 1][v8 + 1] == 1 ) + *v59 = 16; + } + if ( v12 == 2 ) + { + v60 = &dungeon[v10 + 1][v8]; + if ( *v60 == 27 && dungeon[v10 + 1][v8 + 1] == 2 ) + *v60 = 29; + } + if ( v12 == 23 ) + { + v61 = &dungeon[v10][v8 + 1]; + if ( *v61 == 2 ) + *v61 = 15; + v62 = &dungeon[v10][v8 + 1]; + if ( *v62 == 9 ) + *v62 = 15; + } + if ( v12 == 25 ) + { + v63 = &dungeon[v10][v8 + 1]; + if ( *v63 == 2 ) + *v63 = 15; + } + if ( v12 == 22 ) + { + v64 = &dungeon[v10 + 1][v8]; + if ( *v64 == 9 ) + *v64 = 11; + } + if ( v12 == 23 ) + { + v65 = &dungeon[v10 + 1][v8]; + if ( *v65 == 9 ) + *v65 = 11; + } + if ( v12 == 15 ) + { + v66 = &dungeon[v10 + 1][v8]; + if ( *v66 == 1 ) + *v66 = 16; + } + if ( v12 == 11 ) + { + v67 = &dungeon[v10 + 1][v8]; + if ( *v67 == 15 ) + *v67 = 14; + } + if ( v12 == 23 ) + { + v68 = &dungeon[v10 + 1][v8]; + if ( *v68 == 1 ) + *v68 = 16; + } + if ( v12 == 21 ) + { + v69 = &dungeon[v10 + 1][v8]; + if ( *v69 == 27 ) + *v69 = 26; + v70 = &dungeon[v10 + 1][v8]; + if ( *v70 == 18 ) + *v70 = 24; + } + if ( v12 == 26 ) + { + v71 = &dungeon[v10 + 1][v8]; + if ( *v71 == 1 ) + *v71 = 16; + } + if ( v12 == 29 ) + { + v72 = &dungeon[v10 + 1][v8]; + if ( *v72 == 1 ) + *v72 = 16; + v73 = &dungeon[v10][v8 + 1]; + if ( *v73 == 2 ) + *v73 = 15; + } + if ( v12 == 1 && *(v11 - 1) == 15 ) + *(v11 - 1) = 10; + if ( v12 == 18 ) + { + v74 = &dungeon[v10][v8 + 1]; + if ( *v74 == 2 ) + *v74 = 15; + } + if ( v12 == 23 ) + { + v75 = &dungeon[v10][v8 + 1]; + if ( *v75 == 30 ) + *v75 = 18; + } + if ( v12 == 18 ) + { + v76 = &dungeon[v10][v8 + 1]; + if ( *v76 == 9 ) + *v76 = 10; + } + if ( v12 == 14 ) + { + v77 = &dungeon[v10 + 1][v8]; + if ( *v77 == 30 && dungeon[v10 + 1][v8 + 1] == 30 ) + *v77 = 23; + } + if ( v12 == 2 ) + { + v78 = &dungeon[v10 + 1][v8]; + if ( *v78 == 28 && dungeon[v10][v8 + 39] == 6 ) + *v78 = 23; + } + if ( v12 == 23 ) + { + v79 = &dungeon[v10 + 1][v8]; + if ( *v79 == 18 && *(v11 - 1) == 6 ) + *v79 = 24; + } + if ( v12 == 14 ) + { + v80 = &dungeon[v10 + 1][v8]; + if ( *v80 == 23 && dungeon[v10 + 2][v8] == 30 ) + *v80 = 28; + v81 = &dungeon[v10 + 1][v8]; + if ( *v81 == 28 && dungeon[v10 + 2][v8] == 30 && dungeon[v10][v8 + 39] == 6 ) + *v81 = 23; + } + if ( v12 == 23 ) + { + v82 = &dungeon[v10 + 1][v8]; + if ( *v82 == 30 ) + *v82 = 19; + } + if ( v12 == 29 ) + { + v83 = &dungeon[v10 + 1][v8]; + if ( *v83 == 30 ) + *v83 = 19; + v84 = &dungeon[v10][v8 + 1]; + if ( *v84 == 30 ) + *v84 = 18; + } + if ( v12 == 19 ) + { + v85 = &dungeon[v10 + 1][v8]; + if ( *v85 == 30 ) + *v85 = 19; + } + if ( v12 == 21 ) + { + v86 = &dungeon[v10 + 1][v8]; + if ( *v86 == 30 ) + *v86 = 19; + } + if ( v12 == 26 ) + { + v87 = &dungeon[v10 + 1][v8]; + if ( *v87 == 30 ) + *v87 = 19; + } + if ( v12 == 16 ) + { + v88 = &dungeon[v10][v8 + 1]; + if ( *v88 == 30 ) + *v88 = 18; + } + if ( v12 == 13 ) + { + v89 = &dungeon[v10][v8 + 1]; + if ( *v89 == 9 ) + *v89 = 10; + } + if ( v12 == 25 ) + { + v90 = &dungeon[v10][v8 + 1]; + if ( *v90 == 30 ) + *v90 = 18; + } + if ( v12 == 18 ) + { + v91 = &dungeon[v10][v8 + 1]; + if ( *v91 == 2 ) + *v91 = 15; + } + if ( v12 == 11 ) + { + v92 = &dungeon[v10 + 1][v8]; + if ( *v92 == 3 ) + *v92 = 5; + } + if ( v12 == 19 ) + { + v93 = &dungeon[v10 + 1][v8]; + if ( *v93 == 9 ) + *v93 = 11; + v94 = &dungeon[v10 + 1][v8]; + if ( *v94 == 1 ) + *v94 = 13; + v95 = &dungeon[v10 + 1][v8]; + if ( *v95 == 13 && dungeon[v10][v8 + 39] == 6 ) + *v95 = 16; + } + v9 = v139++ + 1; + } + while ( v139 < 40 ); + ++v8; + } + while ( v8 < 40 ); + v96 = 0; + do + { + v97 = 0; + do + { + v98 = v97; + v99 = &dungeon[v97][v96]; + v100 = *v99; + if ( *v99 == 21 ) + { + v101 = &dungeon[v98][v96 + 1]; + if ( *v101 == 24 && dungeon[v98][v96 + 2] == 1 ) + *v101 = 17; + } + if ( v100 == 15 + && dungeon[v98 + 1][v96 + 1] == 9 + && dungeon[v98][v96 + 39] == 1 + && dungeon[v98 + 2][v96] == 16 ) + { + dungeon[v98 + 1][v96] = 29; + } + if ( v100 == 2 && *(v99 - 40) == 6 ) + *(v99 - 40) = 8; + if ( v100 == 1 && *(v99 - 1) == 6 ) + *(v99 - 1) = 7; + if ( v100 == 6 ) + { + v102 = &dungeon[v98 + 1][v96]; + if ( *v102 == 15 && dungeon[v98 + 1][v96 + 1] == 4 ) + *v102 = 10; + } + if ( v100 == 1 ) + { + v103 = &dungeon[v98][v96 + 1]; + if ( *v103 == 3 ) + *v103 = 4; + v104 = &dungeon[v98][v96 + 1]; + if ( *v104 == 6 ) + *v104 = 4; + } + if ( v100 == 9 ) + { + v105 = &dungeon[v98][v96 + 1]; + if ( *v105 == 3 ) + *v105 = 4; + } + if ( v100 == 10 ) + { + v106 = &dungeon[v98][v96 + 1]; + if ( *v106 == 3 ) + *v106 = 4; + } + if ( v100 == 13 ) + { + v107 = &dungeon[v98][v96 + 1]; + if ( *v107 == 3 ) + *v107 = 4; + } + if ( v100 == 1 ) + { + v108 = &dungeon[v98][v96 + 1]; + if ( *v108 == 5 ) + *v108 = 12; + v109 = &dungeon[v98][v96 + 1]; + if ( *v109 == 16 ) + *v109 = 13; + } + if ( v100 == 6 ) + { + v110 = &dungeon[v98][v96 + 1]; + if ( *v110 == 13 ) + *v110 = 16; + } + if ( v100 == 25 ) + { + v111 = &dungeon[v98][v96 + 1]; + if ( *v111 == 9 ) + *v111 = 10; + } + if ( v100 == 13 ) + { + v112 = &dungeon[v98][v96 + 1]; + if ( *v112 == 5 ) + *v112 = 12; + } + if ( v100 == 28 && *(v99 - 1) == 6 ) + { + v113 = &dungeon[v98 + 1][v96]; + if ( *v113 == 1 ) + *v113 = 23; + } + if ( v100 == 19 ) + { + v114 = &dungeon[v98 + 1][v96]; + if ( *v114 == 10 ) + *v114 = 17; + } + if ( v100 == 21 ) + { + v115 = &dungeon[v98 + 1][v96]; + if ( *v115 == 9 ) + *v115 = 11; + } + if ( v100 == 11 ) + { + v116 = &dungeon[v98 + 1][v96]; + if ( *v116 == 3 ) + *v116 = 5; + } + if ( v100 == 10 ) + { + v117 = &dungeon[v98 + 1][v96]; + if ( *v117 == 4 ) + *v117 = 12; + } + if ( v100 == 14 ) + { + v118 = &dungeon[v98 + 1][v96]; + if ( *v118 == 4 ) + *v118 = 12; + } + if ( v100 == 27 ) + { + v119 = &dungeon[v98 + 1][v96]; + if ( *v119 == 9 ) + *v119 = 11; + } + if ( v100 == 15 ) + { + v120 = &dungeon[v98 + 1][v96]; + if ( *v120 == 4 ) + *v120 = 12; + } + if ( v100 == 21 ) + { + v121 = &dungeon[v98 + 1][v96]; + if ( *v121 == 1 ) + *v121 = 16; + } + if ( v100 == 11 ) + { + v122 = &dungeon[v98 + 1][v96]; + if ( *v122 == 4 ) + *v122 = 12; + } + if ( v100 == 2 ) + { + v123 = &dungeon[v98 + 1][v96]; + if ( *v123 == 3 ) + *v123 = 5; + } + if ( v100 == 9 ) + { + v124 = &dungeon[v98 + 1][v96]; + if ( *v124 == 3 ) + *v124 = 5; + } + if ( v100 == 14 ) + { + v125 = &dungeon[v98 + 1][v96]; + if ( *v125 == 3 ) + *v125 = 5; + } + if ( v100 == 15 ) + { + v126 = &dungeon[v98 + 1][v96]; + if ( *v126 == 3 ) + *v126 = 5; + } + if ( v100 == 2 ) + { + v127 = &dungeon[v98 + 1][v96]; + if ( *v127 == 5 && dungeon[v98][v96 + 39] == 16 ) + *v127 = 12; + v128 = &dungeon[v98 + 1][v96]; + if ( *v128 == 4 ) + *v128 = 12; + } + if ( v100 == 9 ) + { + v129 = &dungeon[v98 + 1][v96]; + if ( *v129 == 4 ) + *v129 = 12; + } + if ( v100 == 1 && *(v99 - 1) == 8 ) + *(v99 - 1) = 9; + if ( v100 == 28 ) + { + v130 = &dungeon[v98 + 1][v96]; + if ( *v130 == 23 && dungeon[v98 + 1][v96 + 1] == 3 ) + *v130 = 16; + } + ++v97; + } + while ( v97 < 40 ); + ++v96; + } + while ( v96 < 40 ); + v131 = 0; + do + { + v132 = &dungeon[0][v131 + 1]; + v133 = 40; + do + { + v134 = *(v132 - 1); + if ( v134 == 21 && v132[39] == 10 ) + v132[39] = 17; + if ( v134 == 17 && v132[39] == 4 ) + v132[39] = 12; + if ( v134 == 10 && v132[39] == 4 ) + v132[39] = 12; + if ( v134 == 17 && *v132 == 5 ) + *v132 = 12; + if ( v134 == 29 && *v132 == 9 ) + *v132 = 10; + if ( v134 == 13 && *v132 == 5 ) + *v132 = 12; + if ( v134 == 9 && *v132 == 16 ) + *v132 = 13; + if ( v134 == 10 && *v132 == 16 ) + *v132 = 13; + if ( v134 == 16 && *v132 == 3 ) + *v132 = 4; + if ( v134 == 11 && *v132 == 5 ) + *v132 = 12; + if ( v134 == 10 && v132[39] == 3 && v132[38] == 16 ) + v132[39] = 12; + if ( v134 == 16 && *v132 == 5 ) + *v132 = 12; + if ( v134 == 1 && *v132 == 6 ) + *v132 = 4; + if ( v134 == 21 && v132[39] == 13 && *v132 == 10 ) + v132[40] = 12; + if ( v134 == 15 && v132[39] == 10 ) + v132[39] = 17; + if ( v134 == 22 && *v132 == 11 ) + *v132 = 17; + if ( v134 == 15 && v132[39] == 28 && v132[79] == 16 ) + v132[39] = 23; + if ( v134 == 28 && v132[39] == 23 && v132[40] == 1 && v132[79] == 6 ) + v132[39] = 16; + v132 += 40; + --v133; + } + while ( v133 ); + ++v131; + } + while ( v131 < 40 ); + v135 = 0; + do + { + v136 = (char *)dungeon + v135; + v137 = 40; + do + { + v138 = *v136; + if ( *v136 == 15 && v136[40] == 28 && v136[80] == 16 ) + v136[40] = 23; + if ( v138 == 21 && v136[39] == 21 && v136[41] == 13 && v136[80] == 2 ) + v136[40] = 17; + if ( v138 == 19 && v136[40] == 15 && v136[41] == 12 ) + v136[40] = 17; + v136 += 40; + --v137; + } + while ( v137 ); + ++v135; + } + while ( v135 < 40 ); +} + +void __cdecl DRLG_L4Subs() +{ + signed int v0; // edi + signed int v1; // esi + signed int v2; // ebp + unsigned char v3; // bl + int v4; // eax + signed int v5; // ecx + signed int v6; // edi + signed int v7; // esi + signed int v8; // ebx + + v0 = 0; + do + { + v1 = v0; + v2 = 40; + do + { + if ( !random(0, 3) ) + { + v3 = L4BTYPES[(unsigned char)dungeon[0][v1]]; + if ( v3 ) + { + if ( !dflags[0][v1] ) + { + v4 = random(0, 16); + v5 = -1; + while ( v4 >= 0 ) + { + if ( ++v5 == 140 ) + v5 = 0; + if ( v3 == L4BTYPES[v5] ) + --v4; + } + dungeon[0][v1] = v5; + } + } + } + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 40 ); + v6 = 0; + do + { + v7 = v6; + v8 = 40; + do + { + if ( !random(0, 10) && L4BTYPES[(unsigned char)dungeon[0][v7]] == 6 && !dflags[0][v7] ) + dungeon[0][v7] = random(0, 3) + 95; + v7 += 40; + --v8; + } + while ( v8 ); + ++v6; + } + while ( v6 < 40 ); +} + +void __cdecl L4makeDungeon() +{ + signed int v0; // ebx + signed int v1; // esi + char *v2; // edx + char v3; // cl + int v4; // eax + int v5; // eax + int v6; // ebx + char *v7; // esi + signed int v8; // edx + char v9; // cl + int v10; // eax + int v11; // eax + signed int v12; // ebx + signed int v13; // esi + char *v14; // edx + char v15; // cl + int v16; // eax + int v17; // eax + int v18; // ebx + char *v19; // esi + signed int v20; // edx + char v21; // cl + int v22; // eax + int v23; // eax + signed int v24; // [esp+Ch] [ebp-8h] + char *v25; // [esp+10h] [ebp-4h] + char *v26; // [esp+10h] [ebp-4h] + + v0 = 0; + do + { + v1 = 0; + v2 = (char *)dung + v0; + do + { + v3 = *v2; + v2 += 20; + v4 = 160 * v1++; + v5 = v4 + 2 * v0; + L4dungeon[0][v5] = v3; + L4dungeon[0][v5 + 1] = v3; + L4dungeon[1][v5] = v3; + L4dungeon[1][v5 + 1] = v3; + } + while ( v1 < 20 ); + ++v0; + } + while ( v0 < 20 ); + v6 = 0; + v25 = &dung[0][19]; + v24 = 20; + do + { + v7 = v25; + v8 = 0; + do + { + v9 = *v7; + v7 += 20; + v10 = 160 * v8++; + v11 = v10 + 2 * v6; + L4dungeon[0][v11 + 40] = v9; + L4dungeon[0][v11 + 41] = v9; + L4dungeon[1][v11 + 40] = v9; + L4dungeon[1][v11 + 41] = v9; + } + while ( v8 < 20 ); + ++v6; + --v25; + --v24; + } + while ( v24 ); + v12 = 0; + do + { + v13 = 0; + v14 = &dung[19][v12]; + do + { + v15 = *v14; + v14 -= 20; + v16 = 160 * v13++; + v17 = v16 + 2 * v12; + L4dungeon[40][v17] = v15; + L4dungeon[40][v17 + 1] = v15; + L4dungeon[41][v17] = v15; + L4dungeon[41][v17 + 1] = v15; + } + while ( v13 < 20 ); + ++v12; + } + while ( v12 < 20 ); + v18 = 0; + v26 = &dung[19][19]; + do + { + v19 = v26; + v20 = 0; + do + { + v21 = *v19; + v19 -= 20; + v22 = 160 * v20++; + v23 = v22 + 2 * v18; + L4dungeon[40][v23 + 40] = v21; + L4dungeon[40][v23 + 41] = v21; + L4dungeon[41][v23 + 40] = v21; + L4dungeon[41][v23 + 41] = v21; + } + while ( v20 < 20 ); + ++v18; + --v26; + } + while ( (signed int)v26 > (signed int)&dung[18][19] ); +} + +void __cdecl uShape() +{ + int v0; // ecx + signed int v1; // esi + signed int v2; // eax + char v3; // dl + int v4; // eax + signed int v5; // esi + int v6; // ecx + int v7; // ecx + int *v8; // esi + signed int v9; // eax + char v10; // dl + int v11; // eax + signed int v12; // esi + char *v13; // edx + + v0 = 19; + do + { + v1 = 19; + do + { + v2 = v1; + v3 = dung[v1][v0]; + if ( v3 == 1 || (hallok[v0] = 0, v3 == 1) ) + { + hallok[v0] = dung[v2][v0 + 1] == 1 && !dung[v2 + 1][v0 + 1]; + v1 = 0; + } + --v1; + } + while ( v1 >= 0 ); + --v0; + } + while ( v0 >= 0 ); + v4 = random(0, 19) + 1; + do + { + if ( hallok[v4] ) + { + v5 = 19; + do + { + v6 = v4 + 20 * v5; + if ( dung[0][v6] == 1 ) + { + v5 = -1; + v4 = 0; + } + else + { + dung[0][v6] = 1; + dung[0][v6 + 1] = 1; + } + --v5; + } + while ( v5 >= 0 ); + } + else if ( ++v4 == 20 ) + { + v4 = 1; + } + } + while ( v4 ); + v7 = 380; + v8 = &hallok[19]; + do + { + v9 = 19; + do + { + v10 = dung[0][v7 + v9]; + if ( v10 == 1 || (*v8 = 0, v10 == 1) ) + { + *v8 = dung[1][v7 + v9] == 1 && !dung[1][v7 + 1 + v9]; + v9 = 0; + } + --v9; + } + while ( v9 >= 0 ); + --v8; + v7 -= 20; + } + while ( (signed int)v8 >= (signed int)hallok ); + v11 = random(0, 19) + 1; + do + { + if ( hallok[v11] ) + { + v12 = 19; + do + { + v13 = &dung[v11][v12]; + if ( *v13 == 1 ) + { + v12 = -1; + v11 = 0; + } + else + { + *v13 = 1; + dung[v11 + 1][v12] = 1; + } + --v12; + } + while ( v12 >= 0 ); + } + else if ( ++v11 == 20 ) + { + v11 = 1; + } + } + while ( v11 ); +} + +int __cdecl GetArea() +{ + int result; // eax + signed int v1; // edx + _BYTE *v2; // ecx + signed int v3; // esi + + result = 0; + v1 = 0; + do + { + v2 = (unsigned char *)dung + v1; + v3 = 20; + do + { + if ( *v2 == 1 ) + ++result; + v2 += 20; + --v3; + } + while ( v3 ); + ++v1; + } + while ( v1 < 20 ); + return result; +} + +void __cdecl L4firstRoom() +{ + int v0; // esi + int v1; // edi + int v2; // ebx + int v3; // eax + int v4; // eax + int v5; // ebp + //int v6; // eax + int v7; // eax + int v8; // eax + signed int v9; // [esp-4h] [ebp-18h] + + if ( currlevel == 16 ) + { + v9 = 14; + } + else + { + if ( (currlevel != quests[11]._qlevel || !quests[11]._qactive) + && (currlevel != quests[15]._qlevel || gbMaxPlayers == 1) ) + { + v0 = random(0, 5) + 2; + v1 = random(0, 5) + 2; + goto LABEL_10; + } + v9 = 11; + } + v1 = v9; + v0 = v9; +LABEL_10: + v2 = 20 - v0; + v3 = ((20 - v0) >> 1) + random(0, 20 - ((20 - v0) >> 1) - v0); + if ( v3 + v0 <= 19 ) + v2 = v3; + v4 = ((20 - v1) >> 1) + random(0, 20 - ((20 - v1) >> 1) - v1); + v5 = 20 - v1; + if ( v4 + v1 <= 19 ) + v5 = v4; + if ( currlevel == 16 ) + { + l4holdx = v2; + l4holdy = v5; + } + //_LOBYTE(v6) = QuestStatus(11); + if ( QuestStatus(11) || currlevel == quests[15]._qlevel && gbMaxPlayers != 1 ) + { + SP4x1 = v2 + 1; + SP4y1 = v5 + 1; + v7 = v0 + v2 + 1; + SP4y2 = v1 + v5 + 1; + } + else + { + v7 = 0; + SP4x1 = 0; + SP4y1 = 0; + SP4y2 = 0; + } + SP4x2 = v7; + L4drawRoom(v2, v5, v0, v1); + v8 = random(0, 2); + L4roomGen(v2, v5, v0, v1, v8); +} +// 528A34: using guessed type int l4holdx; +// 528A38: using guessed type int l4holdy; +// 528A40: using guessed type int SP4x2; +// 528A48: using guessed type int SP4y2; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall L4drawRoom(int x, int y, int width, int height) +{ + int i; // esi + int v5; // edi + char *v6; // eax + + for ( i = 0; i < height; ++i ) + { + if ( width > 0 ) + { + v5 = width; + v6 = &dung[x][i + y]; + do + { + *v6 = 1; + v6 += 20; + --v5; + } + while ( v5 ); + } + } +} + +void __fastcall L4roomGen(int x, int y, int w, int h, int dir) +{ + int v5; // eax + int v6; // ecx + int v7; // eax + int v8; // ecx + int v9; // eax + int v11; // esi + int v12; // edi + int v13; // ebx + int v14; // eax + int v15; // eax + int v17; // esi + int v18; // edi + int v19; // ebx + int v20; // eax + int ya; // [esp+Ch] [ebp-10h] + int yb; // [esp+Ch] [ebp-10h] + int v23; // [esp+10h] [ebp-Ch] + int v24; // [esp+10h] [ebp-Ch] + int xa; // [esp+14h] [ebp-8h] + int xb; // [esp+14h] [ebp-8h] + int v27; // [esp+18h] [ebp-4h] + int wa; // [esp+24h] [ebp+8h] + int ha; // [esp+28h] [ebp+Ch] + int hb; // [esp+28h] [ebp+Ch] + int hc; // [esp+28h] [ebp+Ch] + int dira; // [esp+2Ch] [ebp+10h] + int dirb; // [esp+2Ch] [ebp+10h] + + v27 = y; + xa = x; + while ( 1 ) + { + while ( 1 ) + { + v5 = random(0, 4); + v6 = 0; + _LOBYTE(v6) = dir == 1 ? v5 != 0 : v5 == 0; + v7 = v6; + v8 = 0; + if ( !v7 ) + break; + if ( v7 != 1 ) + return; + dira = 0; + wa = w / 2; + do + { + v9 = random(0, 5); + v11 = (v9 + 2) & 0xFFFFFFFE; + v12 = (random(0, 5) + 2) & 0xFFFFFFFE; + v13 = xa + wa - v11 / 2; + ya = v27 - v12; + v14 = L4checkRoom(v13 - 1, v27 - v12 - 1, v11 + 2, v12 + 1); + ++dira; + v23 = v14; + } + while ( !v14 && dira < 20 ); + if ( v14 == 1 ) + L4drawRoom(v13, ya, v11, v12); + xb = v27 + h; + ha = L4checkRoom(v13 - 1, v27 + h, v11 + 2, v12 + 1); + if ( ha == 1 ) + L4drawRoom(v13, xb, v11, v12); + if ( v23 == 1 ) + L4roomGen(v13, ya, v11, v12, 0); + if ( ha != 1 ) + return; + dir = 0; + h = v12; + w = v11; + v27 = xb; + xa = v13; + } + dirb = 0; + hb = h / 2; + do + { + v15 = random(0, 5); + v17 = (v15 + 2) & 0xFFFFFFFE; + v18 = (random(0, 5) + 2) & 0xFFFFFFFE; + v19 = v27 + hb - v18 / 2; + yb = xa - v17; + v20 = L4checkRoom(xa - v17 - 1, v19 - 1, v18 + 2, v17 + 1); + ++dirb; + v24 = v20; + } + while ( !v20 && dirb < 20 ); + if ( v20 == 1 ) + L4drawRoom(yb, v19, v17, v18); + xa += w; + hc = L4checkRoom(xa, v19 - 1, v17 + 1, v18 + 2); + if ( hc == 1 ) + L4drawRoom(xa, v19, v17, v18); + if ( v24 == 1 ) + L4roomGen(yb, v19, v17, v18, 1); + if ( hc != 1 ) + break; + dir = 1; + h = v18; + w = v17; + v27 = v19; + } +} + +bool __fastcall L4checkRoom(int x, int y, int width, int height) +{ + int v4; // esi + int v5; // ebx + char *v6; // edi + int v8; // [esp+Ch] [ebp-4h] + + v4 = 0; + if ( x > 0 && y > 0 ) + { + if ( height <= 0 ) + return 1; + while ( 1 ) + { + v8 = 0; + if ( width > 0 ) + break; +LABEL_12: + if ( ++v4 >= height ) + return 1; + } + v5 = x; + v6 = &dung[x][v4 + y]; + while ( v5 >= 0 && v5 < 20 && v4 + y >= 0 && v4 + y < 20 && !*v6 ) + { + ++v8; + v6 += 20; + ++v5; + if ( v8 >= width ) + goto LABEL_12; + } + } + return 0; +} + +bool __fastcall DRLG_L4PlaceMiniSet(const unsigned char *miniset, int tmin, int tmax, int cx, int cy, int setview, int ldir) +{ + int v7; // ebx + int v8; // esi + int v9; // edi + int v10; // edx + int v11; // esi + int v12; // ebx + int v13; // edi + signed int i; // eax + int v15; // ecx + unsigned char v16; // dl + int v17; // eax + int j; // ecx + int v19; // edi + int v20; // edx + char v21; // bl + bool result; // al + const unsigned char *v23; // [esp+Ch] [ebp-28h] + int v24; // [esp+10h] [ebp-24h] + int v25; // [esp+14h] [ebp-20h] + int v26; // [esp+18h] [ebp-1Ch] + signed int v27; // [esp+1Ch] [ebp-18h] + int v28; // [esp+20h] [ebp-14h] + int v29; // [esp+24h] [ebp-10h] + int v30; // [esp+28h] [ebp-Ch] + int max; // [esp+2Ch] [ebp-8h] + //int v32; // [esp+30h] [ebp-4h] + int v33; // [esp+30h] [ebp-4h] + int tmaxa; // [esp+3Ch] [ebp+8h] + + v7 = miniset[1]; + v8 = tmin; + v9 = *miniset; + v23 = miniset; + v10 = tmax - tmin; + v28 = *miniset; + v29 = miniset[1]; + if ( v10 ) + v24 = v8 + random(0, v10); + else + v24 = 1; + v25 = 0; + if ( v24 <= 0 ) + { + v11 = tmax; + v12 = 0; /* v32 */ + } + else + { + max = 40 - v9; + v30 = 40 - v7; + do + { + v11 = random(0, max); + v27 = 0; + v12 = random(0, v30); + v33 = v12; + do + { + if ( v27 >= 200 ) + return 0; + tmaxa = 1; + if ( v11 >= SP4x1 && v11 <= SP4x2 && v12 >= SP4y1 && v12 <= SP4y2 ) + tmaxa = 0; + if ( cx != -1 && v11 >= cx - v28 && v11 <= cx + 12 ) + { + v11 = random(0, max); + tmaxa = 0; + v33 = random(0, v30); + v12 = v33; + } + if ( cy != -1 && v12 >= cy - v29 && v12 <= cy + 12 ) + { + v11 = random(0, max); + tmaxa = 0; + v33 = random(0, v30); + v12 = v33; + } + v13 = 0; + for ( i = 2; v13 < v29; ++v13 ) + { + if ( tmaxa != 1 ) + break; + v26 = 0; + if ( v28 > 0 ) + { + v15 = v12 + v13 + 40 * v11; + do + { + if ( tmaxa != 1 ) + break; + v16 = v23[i]; + if ( v16 && dungeon[0][v15] != v16 ) + tmaxa = 0; + if ( dflags[0][v15] ) + tmaxa = 0; + ++i; + ++v26; + v15 += 40; + } + while ( v26 < v28 ); + } + } + if ( !tmaxa && ++v11 == max ) + { + v11 = 0; + v33 = ++v12; + if ( v12 == v30 ) + { + v33 = 0; + v12 = 0; + } + } + ++v27; + } + while ( !tmaxa ); + if ( v27 >= 200 ) + return 0; + v17 = 0; + for ( j = v28 * v29 + 2; v17 < v29; ++v17 ) + { + v19 = v28; + if ( v28 > 0 ) + { + v20 = v12 + v17 + 40 * v11; + do + { + v21 = v23[j]; + if ( v21 ) + { + dflags[0][v20] |= 8u; + dungeon[0][v20] = v21; + } + ++j; + v20 += 40; + --v19; + } + while ( v19 ); + v12 = v33; + } + } + ++v25; + } + while ( v25 < v24 ); + } + if ( currlevel == 15 ) + { + quests[15]._qtx = v11 + 1; + quests[15]._qty = v12 + 1; + } + result = 1; + if ( setview == 1 ) + { + ViewX = 2 * v11 + 21; + ViewY = 2 * v12 + 22; + } + if ( !ldir ) + { + LvlViewX = 2 * v11 + 21; + LvlViewY = 2 * v12 + 22; + } + return result; +} +// 528A40: using guessed type int SP4x2; +// 528A48: using guessed type int SP4y2; +// 5CF320: using guessed type int LvlViewY; +// 5CF324: using guessed type int LvlViewX; + +void __cdecl DRLG_L4FloodTVal() +{ + int v0; // ebx + int v1; // esi + char *v2; // edi + _BYTE *v3; // [esp+Ch] [ebp-Ch] + signed int x; // [esp+10h] [ebp-8h] + signed int i; // [esp+14h] [ebp-4h] + + v0 = 16; + v1 = 0; + do + { + i = 0; + x = 16; + v2 = &dung_map[16][v0]; + v3 = (unsigned char *)dungeon + v1; + do + { + if ( *v3 == 6 && !*v2 ) + { + DRLG_L4FTVR(i, v1, x, v0, 0); + ++TransVal; + } + x += 2; + v3 += 40; + v2 += 224; + ++i; + } + while ( i < 40 ); + v0 += 2; + ++v1; + } + while ( v1 < 40 ); +} +// 5A5590: using guessed type char TransVal; + +void __fastcall DRLG_L4FTVR(int i, int j, int x, int y, int d) +{ + int v5; // ebx + int v6; // esi + int v7; // edi + int v8; // edx + int v9; // ecx + int v10; // ebx + int v11; // eax + int v12; // edi + char v13; // al + char v14; // al + int v15; // ecx + int v16; // ecx + int v17; // ecx + int v18; // ecx + int v19; // [esp+Ch] [ebp-14h] + int k; // [esp+10h] [ebp-10h] + int v21; // [esp+14h] [ebp-Ch] + int ja; // [esp+18h] [ebp-8h] + int ia; // [esp+1Ch] [ebp-4h] + int ya; // [esp+2Ch] [ebp+Ch] + + v5 = x; + v6 = y; + v7 = j; + v8 = i; + v9 = 112 * x + y; + ja = v7; + v21 = v8; + if ( !dung_map[0][v9] ) + { + v19 = x; + ia = v8 - 1; + v10 = x - 2; + v11 = 40 * v8; + ya = v7 - 1; + v12 = v6 - 2; + for ( k = 40 * v8; dungeon[0][v11 + ja] == 6; v11 = k ) + { + v13 = TransVal; + dung_map[0][v9] = TransVal; + dung_map[1][v9] = v13; + dung_map[0][v9 + 1] = v13; + dung_map[1][v9 + 1] = v13; + DRLG_L4FTVR(ia + 2, ja, v10 + 4, v6, 1); + DRLG_L4FTVR(ia, ja, v10, v6, 2); + DRLG_L4FTVR(v21, ya + 2, x, v12 + 4, 3); + DRLG_L4FTVR(v21, ya, x, v12, 4); + DRLG_L4FTVR(ia, ya, v10, v12, 5); + DRLG_L4FTVR(ia + 2, ya, v10 + 4, v12, 6); + DRLG_L4FTVR(ia, ya + 2, v10, v12 + 4, 7); + v19 += 2; + k += 40; + d = 8; + x += 2; + v6 += 2; + v12 += 2; + v10 += 2; + ++ja; + ++ya; + ++v21; + ++ia; + v9 = v19 * 112 + v6; + if ( dung_map[v19][v6] ) + break; + } + v5 = x; + } + v14 = TransVal; + if ( d == 1 ) + { + v15 = v6 + 112 * v5; + dung_map[0][v15] = TransVal; + dung_map[0][v15 + 1] = v14; + } + if ( d == 2 ) + { + v16 = v6 + 112 * v5; + dung_map[1][v16] = v14; + dung_map[1][v16 + 1] = v14; + } + if ( d == 3 ) + { + v17 = v6 + 112 * v5; + dung_map[0][v17] = v14; + dung_map[1][v17] = v14; + } + if ( d == 4 ) + { + v18 = v6 + 112 * v5; + dung_map[0][v18 + 1] = v14; + dung_map[1][v18 + 1] = v14; + } + if ( d == 5 ) + dung_map[v5 + 1][v6 + 1] = v14; + if ( d == 6 ) + dung_map[v5][v6 + 1] = v14; + if ( d == 7 ) + dung_map[v5 + 1][v6] = v14; + if ( d == 8 ) + dung_map[v5][v6] = v14; +} +// 5A5590: using guessed type char TransVal; + +void __cdecl DRLG_L4TransFix() +{ + signed int v0; // ebx + char *v1; // esi + char *v2; // edi + char v3; // al + signed int v4; // [esp+Ch] [ebp-8h] + char *v5; // [esp+10h] [ebp-4h] + + v0 = 0; + v5 = &dung_map[16][16]; + do + { + v1 = v5; + v2 = (char *)dungeon + v0; + v4 = 40; + do + { + if ( IsDURWall(*v2) && *(v2 - 1) == 18 ) + { + v1[112] = *v1; + v1[113] = *v1; + } + if ( IsDLLWall(*v2) && v2[40] == 19 ) + { + v1[1] = *v1; + v1[113] = *v1; + } + v3 = *v2; + if ( *v2 == 18 ) + { + v1[112] = *v1; + v1[113] = *v1; + } + if ( v3 == 19 ) + { + v1[1] = *v1; + v1[113] = *v1; + } + if ( v3 == 24 ) + { + v1[112] = *v1; + v1[1] = *v1; + v1[113] = *v1; + } + if ( v3 == 57 ) + { + *(v1 - 112) = v1[1]; + *v1 = v1[1]; + } + if ( v3 == 53 ) + { + *(v1 - 1) = v1[112]; + *v1 = v1[112]; + } + v1 += 224; + v2 += 40; + --v4; + } + while ( v4 ); + v5 += 2; + ++v0; + } + while ( v0 < 40 ); +} + +void __cdecl DRLG_L4Corners() +{ + signed int v0; // edx + char *v1; // ecx + signed int v2; // esi + char v3; // al + + v0 = 1; + do + { + v1 = &dungeon[1][v0]; + v2 = 38; + do + { + v3 = *v1; + if ( (unsigned char)*v1 >= 0x12u + && (unsigned char)v3 <= 0x1Eu + && ((unsigned char)v1[40] < 0x12u || (unsigned char)v1[1] < 0x12u) ) + { + *v1 = v3 + 98; + } + v1 += 40; + --v2; + } + while ( v2 ); + ++v0; + } + while ( v0 < 39 ); +} + +void __cdecl DRLG_L4Pass3() +{ + int v0; // eax + int *v1; // esi + int *v2; // eax + signed int v3; // ecx + signed int v4; // ebx + int *v5; // ecx + unsigned char *v6; // edi + unsigned short *v7; // esi + unsigned short v8; // ax + int v9; // eax + signed int v10; // [esp+Ch] [ebp-1Ch] + int *v11; // [esp+10h] [ebp-18h] + int v12; // [esp+14h] [ebp-14h] + int v13; // [esp+18h] [ebp-10h] + int v14; // [esp+18h] [ebp-10h] + int v15; // [esp+1Ch] [ebp-Ch] + int v16; // [esp+1Ch] [ebp-Ch] + int v17; // [esp+20h] [ebp-8h] + int v18; // [esp+20h] [ebp-8h] + int v19; // [esp+24h] [ebp-4h] + int v20; // [esp+24h] [ebp-4h] + + v0 = *((unsigned short *)pMegaTiles + 116) + 1; + v19 = *((unsigned short *)pMegaTiles + 116) + 1; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 117); + v17 = ++v0; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 118); + v15 = ++v0; + _LOWORD(v0) = *((_WORD *)pMegaTiles + 119); + v13 = v0 + 1; + v1 = dPiece[1]; + do + { + v2 = v1; + v3 = 56; + do + { + *(v2 - 112) = v19; + *v2 = v17; + *(v2 - 111) = v15; + v2[1] = v13; + v2 += 224; + --v3; + } + while ( v3 ); + v1 += 2; + } + while ( (signed int)v1 < (signed int)dPiece[2] ); + v4 = 0; + v11 = &dPiece[17][16]; + do + { + v5 = v11; + v6 = (unsigned char *)dungeon + v4; + v10 = 40; + do + { + v12 = *v6 - 1; + if ( v12 < 0 ) + { + v20 = 0; + v18 = 0; + v16 = 0; + v14 = 0; + } + else + { + v7 = (unsigned short *)((char *)pMegaTiles + 8 * v12); + v8 = *v7; + ++v7; + v9 = v8 + 1; + v20 = v9; + _LOWORD(v9) = *v7; + ++v7; + v18 = ++v9; + _LOWORD(v9) = *v7; + v16 = ++v9; + _LOWORD(v9) = v7[1]; + v14 = v9 + 1; + } + v6 += 40; + *(v5 - 112) = v20; + *v5 = v18; + *(v5 - 111) = v16; + v5[1] = v14; + v5 += 224; + --v10; + } + while ( v10 ); + v11 += 2; + ++v4; + } + while ( v4 < 40 ); +} diff --git a/Source/drlg_l4.h b/Source/drlg_l4.h new file mode 100644 index 000000000..4f453f051 --- /dev/null +++ b/Source/drlg_l4.h @@ -0,0 +1,69 @@ +//HEADER_GOES_HERE +#ifndef __DRLG_L4_H__ +#define __DRLG_L4_H__ + +extern int diabquad1x; // weak +extern int diabquad1y; // weak +extern int diabquad3x; // idb +extern int diabquad3y; // idb +extern int diabquad2x; // idb +extern int diabquad2y; // idb +extern int diabquad4x; // idb +extern int diabquad4y; // idb +extern int hallok[20]; +extern int l4holdx; // weak +extern int l4holdy; // weak +extern int SP4x1; // idb +extern int SP4x2; // weak +extern int SP4y1; // idb +extern int SP4y2; // weak +extern char L4dungeon[80][80]; +extern char dung[20][20]; +//int dword_52A4DC; // weak + +void __cdecl DRLG_LoadL4SP(); +void __cdecl DRLG_FreeL4SP(); +void __fastcall DRLG_L4SetSPRoom(int rx1, int ry1); +void __cdecl L4SaveQuads(); +void __fastcall DRLG_L4SetRoom(unsigned char *pSetPiece, int rx1, int ry1); +void __fastcall DRLG_LoadDiabQuads(bool preflag); +bool __fastcall IsDURWall(char d); +bool __fastcall IsDLLWall(char dd); +void __cdecl L4FixRim(); +void __cdecl DRLG_L4GeneralFix(); +void __fastcall CreateL4Dungeon(int rseed, int entry); +void __fastcall DRLG_L4(int entry); +void __cdecl DRLG_L4Shadows(); +void __cdecl InitL4Dungeon(); +void __cdecl L4makeDmt(); +void __cdecl L4AddWall(); +int __fastcall L4HWallOk(int i, int j); +int __fastcall L4VWallOk(int i, int j); +void __fastcall L4HorizWall(int i, int j, int dx); +void __fastcall L4VertWall(int i, int j, int dy); +void __cdecl L4tileFix(); +void __cdecl DRLG_L4Subs(); +void __cdecl L4makeDungeon(); +void __cdecl uShape(); +int __cdecl GetArea(); +void __cdecl L4firstRoom(); +void __fastcall L4drawRoom(int x, int y, int width, int height); +void __fastcall L4roomGen(int x, int y, int w, int h, int dir); +bool __fastcall L4checkRoom(int x, int y, int width, int height); +bool __fastcall DRLG_L4PlaceMiniSet(const unsigned char *miniset, int tmin, int tmax, int cx, int cy, int setview, int ldir); +void __cdecl DRLG_L4FloodTVal(); +void __fastcall DRLG_L4FTVR(int i, int j, int x, int y, int d); +void __cdecl DRLG_L4TransFix(); +void __cdecl DRLG_L4Corners(); +void __cdecl DRLG_L4Pass3(); + +/* rdata */ +extern const unsigned char L4ConvTbl[16]; +extern const unsigned char L4USTAIRS[42]; +extern const unsigned char L4TWARP[42]; +extern const unsigned char L4DSTAIRS[52]; +extern const unsigned char L4PENTA[52]; +extern const unsigned char L4PENTA2[52]; +extern const unsigned char L4BTYPES[140]; + +#endif /* __DRLG_L4_H__ */ diff --git a/Source/dthread.cpp b/Source/dthread.cpp new file mode 100644 index 000000000..7fbc66050 --- /dev/null +++ b/Source/dthread.cpp @@ -0,0 +1,200 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int dthread_cpp_init_value; // weak +static CRITICAL_SECTION sgMemCrit; // idb +unsigned int glpDThreadId; // idb +TMegaPkt *sgpInfoHead; /* may not be right struct */ +char byte_52A508; // weak +HANDLE sghWorkToDoEvent; // idb + +int dthread_inf = 0x7F800000; // weak + +/* rdata */ +static HANDLE sghThread = (HANDLE)0xFFFFFFFF; // idb + +struct dthread_cpp_init_1 +{ + dthread_cpp_init_1() + { + dthread_cpp_init_value = dthread_inf; + } +} _dthread_cpp_init_1; +// 47A460: using guessed type int dthread_inf; +// 52A4E0: using guessed type int dthread_cpp_init_value; + +struct dthread_cpp_init_2 +{ + dthread_cpp_init_2() + { + dthread_init_mutex(); + dthread_cleanup_mutex_atexit(); + } +} _dthread_cpp_init_2; + +void __cdecl dthread_init_mutex() +{ + InitializeCriticalSection(&sgMemCrit); +} + +void __cdecl dthread_cleanup_mutex_atexit() +{ + atexit(dthread_cleanup_mutex); +} + +void __cdecl dthread_cleanup_mutex() +{ + DeleteCriticalSection(&sgMemCrit); +} + +void __fastcall dthread_remove_player(int pnum) +{ + int v1; // edi + TMegaPkt *i; // eax + + v1 = pnum; + EnterCriticalSection(&sgMemCrit); + for ( i = sgpInfoHead; i; i = i->pNext ) + { + if ( i->dwSpaceLeft == v1 ) + i->dwSpaceLeft = 4; + } + LeaveCriticalSection(&sgMemCrit); +} + +void __fastcall dthread_send_delta(int pnum, char cmd, void *pbSrc, int dwLen) +{ + TMegaPkt *v5; // eax + TMegaPkt *v6; // esi + TMegaPkt *v7; // eax + TMegaPkt **v8; // ecx + int v9; // [esp+4h] [ebp-4h] + + v9 = pnum; + if ( gbMaxPlayers != 1 ) + { + v5 = (TMegaPkt *)DiabloAllocPtr(dwLen + 20); + v6 = v5; + v5->pNext = 0; + v5->dwSpaceLeft = v9; + v5->data[0] = cmd; + *(_DWORD *)&v5->data[4] = dwLen; + memcpy(&v5->data[8], pbSrc, dwLen); + EnterCriticalSection(&sgMemCrit); + v7 = sgpInfoHead; + v8 = &sgpInfoHead; + while ( v7 ) + { + v8 = &v7->pNext; + v7 = v7->pNext; + } + *v8 = v6; + SetEvent(sghWorkToDoEvent); + LeaveCriticalSection(&sgMemCrit); + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl dthread_start() +{ + char *v0; // eax + char *v1; // eax + + if ( gbMaxPlayers != 1 ) + { + sghWorkToDoEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if ( !sghWorkToDoEvent ) + { + v0 = TraceLastError(); + TermMsg("dthread:1\n%s", v0); + } + byte_52A508 = 1; + sghThread = (HANDLE)_beginthreadex(NULL, 0, dthread_handler, NULL, 0, &glpDThreadId); + if ( sghThread == (HANDLE)-1 ) + { + v1 = TraceLastError(); + TermMsg("dthread2:\n%s", v1); + } + } +} +// 52A508: using guessed type char byte_52A508; +// 679660: using guessed type char gbMaxPlayers; + +unsigned int __stdcall dthread_handler(void *a1) +{ + char *v1; // eax + TMegaPkt *v2; // esi + int v3; // ecx + unsigned int v4; // edi + + while ( byte_52A508 ) + { + if ( !sgpInfoHead && WaitForSingleObject(sghWorkToDoEvent, 0xFFFFFFFF) == -1 ) + { + v1 = TraceLastError(); + TermMsg("dthread4:\n%s", v1); + } + EnterCriticalSection(&sgMemCrit); + v2 = sgpInfoHead; + if ( sgpInfoHead ) + sgpInfoHead = sgpInfoHead->pNext; + else + ResetEvent(sghWorkToDoEvent); + LeaveCriticalSection(&sgMemCrit); + if ( v2 ) + { + v3 = v2->dwSpaceLeft; + if ( v3 != 4 ) + multi_send_zero_packet(v3, v2->data[0], &v2->data[8], *(_DWORD *)&v2->data[4]); + v4 = 1000 * *(_DWORD *)&v2->data[4] / (unsigned int)gdwDeltaBytesSec; + if ( v4 >= 1 ) + v4 = 1; + mem_free_dbg(v2); + if ( v4 ) + Sleep(v4); + } + } + return 0; +} +// 52A508: using guessed type char byte_52A508; +// 679730: using guessed type int gdwDeltaBytesSec; + +void __cdecl dthread_cleanup() +{ + char *v0; // eax + TMegaPkt *v1; // eax + TMegaPkt *v2; // esi + + if ( sghWorkToDoEvent ) + { + byte_52A508 = 0; + SetEvent(sghWorkToDoEvent); + if ( sghThread != (HANDLE)-1 && glpDThreadId != GetCurrentThreadId() ) + { + if ( WaitForSingleObject(sghThread, 0xFFFFFFFF) == -1 ) + { + v0 = TraceLastError(); + TermMsg("dthread3:\n(%s)", v0); + } + CloseHandle(sghThread); + sghThread = (HANDLE)-1; + } + CloseHandle(sghWorkToDoEvent); + v1 = sgpInfoHead; + sghWorkToDoEvent = 0; + if ( sgpInfoHead ) + { + do + { + v2 = v1->pNext; + sgpInfoHead = 0; + mem_free_dbg(v1); + v1 = v2; + sgpInfoHead = v2; + } + while ( v2 ); + } + } +} +// 52A508: using guessed type char byte_52A508; diff --git a/Source/dthread.h b/Source/dthread.h new file mode 100644 index 000000000..143b1bacf --- /dev/null +++ b/Source/dthread.h @@ -0,0 +1,25 @@ +//HEADER_GOES_HERE +#ifndef __DTHREAD_H__ +#define __DTHREAD_H__ + +extern int dthread_cpp_init_value; // weak +extern unsigned int glpDThreadId; // idb +extern TMegaPkt *sgpInfoHead; /* may not be right struct */ +extern char byte_52A508; // weak +extern HANDLE sghWorkToDoEvent; // idb + +void __cdecl dthread_cpp_init_1(); +void __cdecl dthread_cpp_init_2(); +void __cdecl dthread_init_mutex(); +void __cdecl dthread_cleanup_mutex_atexit(); +void __cdecl dthread_cleanup_mutex(); +void __fastcall dthread_remove_player(int pnum); +void __fastcall dthread_send_delta(int pnum, char cmd, void *pbSrc, int dwLen); +void __cdecl dthread_start(); +unsigned int __stdcall dthread_handler(void *a1); +void __cdecl dthread_cleanup(); + +/* data */ +extern int dthread_inf; // weak + +#endif /* __DTHREAD_H__ */ diff --git a/Source/dx.cpp b/Source/dx.cpp new file mode 100644 index 000000000..fdd5e4d27 --- /dev/null +++ b/Source/dx.cpp @@ -0,0 +1,298 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +void *sgpBackBuf; +int dx_cpp_init_value; // weak +IDirectDraw *lpDDInterface; +IDirectDrawPalette *lpDDPalette; // idb +int sgdwLockCount; +Screen *gpBuffer; +IDirectDrawSurface *lpDDSBackBuf; +IDirectDrawSurface *lpDDSPrimary; +static CRITICAL_SECTION sgMemCrit; +char gbBackBuf; // weak +char gbEmulate; // weak +HMODULE ghDiabMod; // idb + +int dx_inf = 0x7F800000; // weak + +struct dx_cpp_init_1 +{ + dx_cpp_init_1() + { + dx_cpp_init_value = dx_inf; + } +} _dx_cpp_init_1; +// 47A464: using guessed type int dx_inf; +// 52A514: using guessed type int dx_cpp_init_value; + +struct dx_cpp_init_2 +{ + dx_cpp_init_2() + { + dx_init_mutex(); + dx_cleanup_mutex_atexit(); + } +} _dx_cpp_init_2; + +void __cdecl dx_init_mutex() +{ + InitializeCriticalSection(&sgMemCrit); +} + +void __cdecl dx_cleanup_mutex_atexit() +{ + atexit(dx_cleanup_mutex); +} + +void __cdecl dx_cleanup_mutex() +{ + DeleteCriticalSection(&sgMemCrit); +} + +void __fastcall dx_init(HWND hWnd) +{ + HWND v1; // esi + GUID *v2; // ecx + int v3; // eax + int v4; // eax + //int v5; // ecx + int v6; // edi + int v7; // eax + int v8; // eax + HWND hWnda; // [esp+1Ch] [ebp-4h] + + v1 = hWnd; + hWnda = hWnd; + SetFocus(hWnd); + ShowWindow(v1, SW_SHOWNORMAL); + v2 = NULL; + if ( gbEmulate ) + v2 = (GUID *)DDCREATE_EMULATIONONLY; + v3 = dx_DirectDrawCreate(v2, &lpDDInterface, NULL); + if ( v3 ) + ErrDlg(IDD_DIALOG1, v3, "C:\\Src\\Diablo\\Source\\dx.cpp", 149); + fullscreen = 1; + v4 = lpDDInterface->SetCooperativeLevel(v1, DDSCL_EXCLUSIVE|DDSCL_ALLOWREBOOT|DDSCL_FULLSCREEN); + if ( v4 == DDERR_EXCLUSIVEMODEALREADYSET ) + { + MI_Dummy(0); // v5 + } + else if ( v4 ) + { + ErrDlg(IDD_DIALOG1, v4, "C:\\Src\\Diablo\\Source\\dx.cpp", 170); + } + if ( lpDDInterface->SetDisplayMode(640, 480, 8) ) + { + v6 = GetSystemMetrics(SM_CXSCREEN); + v7 = GetSystemMetrics(SM_CYSCREEN); + v8 = lpDDInterface->SetDisplayMode(v6, v7, 8); + if ( v8 ) + ErrDlg(IDD_DIALOG1, v8, "C:\\Src\\Diablo\\Source\\dx.cpp", 183); + } + dx_create_primary_surface(); + palette_init(); + GdiSetBatchLimit(1); + dx_create_back_buffer(); + SDrawManualInitialize(hWnda, lpDDInterface, lpDDSPrimary, 0, 0, lpDDSBackBuf, lpDDPalette, 0); +} +// 484364: using guessed type int fullscreen; +// 52A549: using guessed type char gbEmulate; + +void __cdecl dx_create_back_buffer() +{ + int v0; // eax + int v1; // eax + int v2; // eax + int v3; // eax + DDSURFACEDESC v4; // [esp+Ch] [ebp-70h] + DDSCAPS v5; // [esp+78h] [ebp-4h] + + v0 = lpDDSPrimary->GetCaps(&v5); + if ( v0 ) + DDErrMsg(v0, 59, "C:\\Src\\Diablo\\Source\\dx.cpp"); + if ( !gbBackBuf ) + { + v4.dwSize = 108; + v1 = lpDDSPrimary->Lock(NULL, &v4, DDLOCK_WRITEONLY|DDLOCK_WAIT, NULL); + if ( !v1 ) + { + lpDDSPrimary->Unlock(NULL); + sgpBackBuf = DiabloAllocPtr(0x7B000); + return; + } + if ( v1 != DDERR_CANTLOCKSURFACE ) + ErrDlg(IDD_DIALOG1, v1, "C:\\Src\\Diablo\\Source\\dx.cpp", 81); + } + memset(&v4, 0, 0x6Cu); + v4.dwWidth = 768; + v4.lPitch = 768; + v4.dwSize = 108; + v4.dwFlags = DDSD_PIXELFORMAT|DDSD_PITCH|DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS; + v4.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY|DDSCAPS_OFFSCREENPLAIN; + v4.dwHeight = 656; + v4.ddpfPixelFormat.dwSize = 32; + v2 = lpDDSPrimary->GetPixelFormat(&v4.ddpfPixelFormat); + if ( v2 ) + ErrDlg(IDD_DIALOG1, v2, "C:\\Src\\Diablo\\Source\\dx.cpp", 94); + v3 = lpDDInterface->CreateSurface(&v4, &lpDDSBackBuf, NULL); + if ( v3 ) + ErrDlg(IDD_DIALOG1, v3, "C:\\Src\\Diablo\\Source\\dx.cpp", 96); +} +// 52A548: using guessed type char gbBackBuf; + +void __cdecl dx_create_primary_surface() +{ + int v0; // eax + DDSURFACEDESC v1; // [esp+0h] [ebp-6Ch] + + memset(&v1, 0, 0x6Cu); + v1.dwSize = 108; + v1.dwFlags = DDSD_CAPS; + v1.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + v0 = lpDDInterface->CreateSurface(&v1, &lpDDSPrimary, NULL); + if ( v0 ) + ErrDlg(IDD_DIALOG1, v0, "C:\\Src\\Diablo\\Source\\dx.cpp", 109); +} + +HRESULT __fastcall dx_DirectDrawCreate(GUID *guid, IDirectDraw **DD, void *unknown) +{ + IDirectDraw **v3; // ebp + int v4; // eax + FARPROC v5; // ebx + int v6; // eax + GUID *v8; // [esp+10h] [ebp-4h] + + v3 = DD; + v8 = guid; + if ( !ghDiabMod ) + { + ghDiabMod = LoadLibrary("ddraw.dll"); + if ( !ghDiabMod ) + { + v4 = GetLastError(); + ErrDlg(IDD_DIALOG4, v4, "C:\\Src\\Diablo\\Source\\dx.cpp", 122); + } + } + v5 = GetProcAddress(ghDiabMod, "DirectDrawCreate"); + if ( !v5 ) + { + v6 = GetLastError(); + ErrDlg(IDD_DIALOG4, v6, "C:\\Src\\Diablo\\Source\\dx.cpp", 127); + } + return ((int (__stdcall *)(GUID *, IDirectDraw **, void *))v5)(v8, v3, unknown); +} + +void __cdecl lock_buf_priv() +{ + Screen *v0; // eax + int v1; // eax + DDSURFACEDESC v2; // [esp+0h] [ebp-6Ch] + + EnterCriticalSection(&sgMemCrit); + v0 = (Screen *)sgpBackBuf; + if ( sgpBackBuf ) + goto LABEL_8; + if ( lpDDSBackBuf ) + { + if ( sgdwLockCount ) + goto LABEL_9; + v2.dwSize = 108; + v1 = lpDDSBackBuf->Lock(NULL, &v2, DDLOCK_WAIT, NULL); + if ( v1 ) + DDErrMsg(v1, 235, "C:\\Src\\Diablo\\Source\\dx.cpp"); + v0 = (Screen *)v2.lpSurface; + gpBufEnd += (unsigned int)v2.lpSurface; +LABEL_8: + gpBuffer = v0; + goto LABEL_9; + } + Sleep(20000); + TermMsg("lock_buf_priv"); +LABEL_9: + ++sgdwLockCount; +} +// 69CF0C: using guessed type int gpBufEnd; + +void __cdecl unlock_buf_priv() +{ + Screen *v0; // eax + int v1; // eax + + if ( !sgdwLockCount ) + TermMsg("draw main unlock error"); + if ( !gpBuffer ) + TermMsg("draw consistency error"); + if ( !--sgdwLockCount ) + { + v0 = gpBuffer; + gpBuffer = 0; + gpBufEnd -= (signed int)v0; + if ( !sgpBackBuf ) + { + v1 = lpDDSBackBuf->Unlock(NULL); + if ( v1 ) + DDErrMsg(v1, 273, "C:\\Src\\Diablo\\Source\\dx.cpp"); + } + } + LeaveCriticalSection(&sgMemCrit); +} +// 69CF0C: using guessed type int gpBufEnd; + +void __cdecl dx_cleanup() +{ + void *v0; // ecx + + if ( ghMainWnd ) + ShowWindow(ghMainWnd, SW_HIDE); + SDrawDestroy(); + EnterCriticalSection(&sgMemCrit); + if ( sgpBackBuf ) + { + v0 = sgpBackBuf; + sgpBackBuf = 0; + mem_free_dbg(v0); + } + else if ( lpDDSBackBuf ) + { + lpDDSBackBuf->Release(); + lpDDSBackBuf = 0; + } + sgdwLockCount = 0; + gpBuffer = 0; + LeaveCriticalSection(&sgMemCrit); + if ( lpDDSPrimary ) + { + lpDDSPrimary->Release(); + lpDDSPrimary = 0; + } + if ( lpDDPalette ) + { + lpDDPalette->Release(); + lpDDPalette = 0; + } + if ( lpDDInterface ) + { + lpDDInterface->Release(); + lpDDInterface = 0; + } +} + +void __cdecl dx_reinit() +{ + int v0; // esi + + EnterCriticalSection(&sgMemCrit); + ClearCursor(); + v0 = sgdwLockCount; + while ( sgdwLockCount ) + unlock_buf_priv(); + dx_cleanup(); + drawpanflag = 255; + dx_init(ghMainWnd); + for ( ; v0; --v0 ) + lock_buf_priv(); + LeaveCriticalSection(&sgMemCrit); +} +// 52571C: using guessed type int drawpanflag; diff --git a/Source/dx.h b/Source/dx.h new file mode 100644 index 000000000..ddf5e5be2 --- /dev/null +++ b/Source/dx.h @@ -0,0 +1,38 @@ +//HEADER_GOES_HERE +#ifndef __DX_H__ +#define __DX_H__ + +extern void *sgpBackBuf; +extern int dx_cpp_init_value; // weak +extern IDirectDraw *lpDDInterface; +extern IDirectDrawPalette *lpDDPalette; // idb +extern int sgdwLockCount; +extern Screen *gpBuffer; +extern IDirectDrawSurface *lpDDSBackBuf; +extern IDirectDrawSurface *lpDDSPrimary; +extern char gbBackBuf; // weak +extern char gbEmulate; // weak +extern HMODULE ghDiabMod; // idb + +void __cdecl dx_cpp_init_1(); +void __cdecl dx_cpp_init_2(); +void __cdecl dx_init_mutex(); +void __cdecl dx_cleanup_mutex_atexit(); +void __cdecl dx_cleanup_mutex(); +void __fastcall dx_init(HWND hWnd); +void __cdecl dx_create_back_buffer(); +void __cdecl dx_create_primary_surface(); +HRESULT __fastcall dx_DirectDrawCreate(GUID *guid, IDirectDraw **DD, void *unknown); +void __cdecl j_lock_buf_priv(); +void __cdecl lock_buf_priv(); +void __cdecl j_unlock_buf_priv(); +void __cdecl unlock_buf_priv(); +void __cdecl dx_cleanup(); +void __cdecl dx_reinit(); +void __cdecl j_dx_reinit(); + +/* data */ + +extern int dx_inf; // weak + +#endif /* __DX_H__ */ diff --git a/Source/effects.cpp b/Source/effects.cpp new file mode 100644 index 000000000..1d23c1426 --- /dev/null +++ b/Source/effects.cpp @@ -0,0 +1,1426 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int effects_cpp_init_value; // weak + +#ifndef NO_GLOBALS +int sfxdelay; // weak +int sfxdnum; +void *sfx_stream; +TSFX *sfx_data_cur; +#endif + +const int effects_inf = 0x7F800000; // weak +const char monster_action_sounds[] = { 'a', 'h', 'd', 's' }; // idb + +/* data */ + +TSFX sgSFX[NUM_SFX] = +{ + { 2u, "Sfx\\Misc\\Walk1.wav", NULL }, + { 2u, "Sfx\\Misc\\Walk2.wav", NULL }, + { 2u, "Sfx\\Misc\\Walk3.wav", NULL }, + { 2u, "Sfx\\Misc\\Walk4.wav", NULL }, + { 2u, "Sfx\\Misc\\BFire.wav", NULL }, + { 2u, "Sfx\\Misc\\Fmag.wav", NULL }, + { 2u, "Sfx\\Misc\\Tmag.wav", NULL }, + { 2u, "Sfx\\Misc\\Lghit.wav", NULL }, + { 2u, "Sfx\\Misc\\Lghit1.wav", NULL }, + { 2u, "Sfx\\Misc\\Swing.wav", NULL }, + { 2u, "Sfx\\Misc\\Swing2.wav", NULL }, + { 2u, "Sfx\\Misc\\Dead.wav", NULL }, + { 1u, "Sfx\\Misc\\Questdon.wav", NULL }, + { 2u, "Sfx\\Items\\Armrfkd.wav", NULL }, + { 2u, "Sfx\\Items\\Barlfire.wav", NULL }, + { 2u, "Sfx\\Items\\Barrel.wav", NULL }, + { 2u, "Sfx\\Items\\Bhit.wav", NULL }, + { 2u, "Sfx\\Items\\Bhit1.wav", NULL }, + { 2u, "Sfx\\Items\\Chest.wav", NULL }, + { 2u, "Sfx\\Items\\Doorclos.wav", NULL }, + { 2u, "Sfx\\Items\\Dooropen.wav", NULL }, + { 2u, "Sfx\\Items\\Flipanvl.wav", NULL }, + { 2u, "Sfx\\Items\\Flipaxe.wav", NULL }, + { 2u, "Sfx\\Items\\Flipblst.wav", NULL }, + { 2u, "Sfx\\Items\\Flipbody.wav", NULL }, + { 2u, "Sfx\\Items\\Flipbook.wav", NULL }, + { 2u, "Sfx\\Items\\Flipbow.wav", NULL }, + { 2u, "Sfx\\Items\\Flipcap.wav", NULL }, + { 2u, "Sfx\\Items\\Flipharm.wav", NULL }, + { 2u, "Sfx\\Items\\Fliplarm.wav", NULL }, + { 2u, "Sfx\\Items\\Flipmag.wav", NULL }, + { 2u, "Sfx\\Items\\Flipmag1.wav", NULL }, + { 2u, "Sfx\\Items\\Flipmush.wav", NULL }, + { 2u, "Sfx\\Items\\Flippot.wav", NULL }, + { 2u, "Sfx\\Items\\Flipring.wav", NULL }, + { 2u, "Sfx\\Items\\Fliprock.wav", NULL }, + { 2u, "Sfx\\Items\\Flipscrl.wav", NULL }, + { 2u, "Sfx\\Items\\Flipshld.wav", NULL }, + { 2u, "Sfx\\Items\\Flipsign.wav", NULL }, + { 2u, "Sfx\\Items\\Flipstaf.wav", NULL }, + { 2u, "Sfx\\Items\\Flipswor.wav", NULL }, + { 2u, "Sfx\\Items\\Gold.wav", NULL }, + { 2u, "Sfx\\Items\\Hlmtfkd.wav", NULL }, + { 2u, "Sfx\\Items\\Invanvl.wav", NULL }, + { 2u, "Sfx\\Items\\Invaxe.wav", NULL }, + { 2u, "Sfx\\Items\\Invblst.wav", NULL }, + { 2u, "Sfx\\Items\\Invbody.wav", NULL }, + { 2u, "Sfx\\Items\\Invbook.wav", NULL }, + { 2u, "Sfx\\Items\\Invbow.wav", NULL }, + { 2u, "Sfx\\Items\\Invcap.wav", NULL }, + { 2u, "Sfx\\Items\\Invgrab.wav", NULL }, + { 2u, "Sfx\\Items\\Invharm.wav", NULL }, + { 2u, "Sfx\\Items\\Invlarm.wav", NULL }, + { 2u, "Sfx\\Items\\Invmush.wav", NULL }, + { 2u, "Sfx\\Items\\Invpot.wav", NULL }, + { 2u, "Sfx\\Items\\Invring.wav", NULL }, + { 2u, "Sfx\\Items\\Invrock.wav", NULL }, + { 2u, "Sfx\\Items\\Invscrol.wav", NULL }, + { 2u, "Sfx\\Items\\Invshiel.wav", NULL }, + { 2u, "Sfx\\Items\\Invsign.wav", NULL }, + { 2u, "Sfx\\Items\\Invstaf.wav", NULL }, + { 2u, "Sfx\\Items\\Invsword.wav", NULL }, + { 2u, "Sfx\\Items\\Lever.wav", NULL }, + { 2u, "Sfx\\Items\\Magic.wav", NULL }, + { 2u, "Sfx\\Items\\Magic1.wav", NULL }, + { 2u, "Sfx\\Items\\Readbook.wav", NULL }, + { 2u, "Sfx\\Items\\Sarc.wav", NULL }, + { 2u, "Sfx\\Items\\Shielfkd.wav", NULL }, + { 2u, "Sfx\\Items\\Swrdfkd.wav", NULL }, + { 4u, "Sfx\\Items\\Titlemov.wav", NULL }, + { 4u, "Sfx\\Items\\Titlslct.wav", NULL }, + { 4u, "Sfx\\Misc\\blank.wav", NULL }, + { 2u, "Sfx\\Items\\Trap.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast1.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast10.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast12.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast2.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast3.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast4.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast5.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast6.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast7.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast8.wav", NULL }, + { 2u, "Sfx\\Misc\\Cast9.wav", NULL }, + { 2u, "Sfx\\Misc\\Healing.wav", NULL }, + { 2u, "Sfx\\Misc\\Repair.wav", NULL }, + { 2u, "Sfx\\Misc\\Acids1.wav", NULL }, + { 2u, "Sfx\\Misc\\Acids2.wav", NULL }, + { 2u, "Sfx\\Misc\\Apoc.wav", NULL }, + { 2u, "Sfx\\Misc\\Arrowall.wav", NULL }, + { 2u, "Sfx\\Misc\\Bldboil.wav", NULL }, + { 2u, "Sfx\\Misc\\Blodstar.wav", NULL }, + { 2u, "Sfx\\Misc\\Blsimpt.wav", NULL }, + { 2u, "Sfx\\Misc\\Bonesp.wav", NULL }, + { 2u, "Sfx\\Misc\\Bsimpct.wav", NULL }, + { 2u, "Sfx\\Misc\\Caldron.wav", NULL }, + { 2u, "Sfx\\Misc\\Cbolt.wav", NULL }, + { 2u, "Sfx\\Misc\\Chltning.wav", NULL }, + { 2u, "Sfx\\Misc\\DSerp.wav", NULL }, + { 2u, "Sfx\\Misc\\Elecimp1.wav", NULL }, + { 2u, "Sfx\\Misc\\Elementl.wav", NULL }, + { 2u, "Sfx\\Misc\\Ethereal.wav", NULL }, + { 2u, "Sfx\\Misc\\Fball.wav", NULL }, + { 2u, "Sfx\\Misc\\Fbolt1.wav", NULL }, + { 2u, "Sfx\\Misc\\Fbolt2.wav", NULL }, + { 2u, "Sfx\\Misc\\Firimp1.wav", NULL }, + { 2u, "Sfx\\Misc\\Firimp2.wav", NULL }, + { 2u, "Sfx\\Misc\\Flamwave.wav", NULL }, + { 2u, "Sfx\\Misc\\Flash.wav", NULL }, + { 2u, "Sfx\\Misc\\Fountain.wav", NULL }, + { 2u, "Sfx\\Misc\\Golum.wav", NULL }, + { 2u, "Sfx\\Misc\\Golumded.wav", NULL }, + { 2u, "Sfx\\Misc\\Gshrine.wav", NULL }, + { 2u, "Sfx\\Misc\\Guard.wav", NULL }, + { 2u, "Sfx\\Misc\\Grdlanch.wav", NULL }, + { 2u, "Sfx\\Misc\\Holybolt.wav", NULL }, + { 2u, "Sfx\\Misc\\Hyper.wav", NULL }, + { 2u, "Sfx\\Misc\\Infravis.wav", NULL }, + { 2u, "Sfx\\Misc\\Invisibl.wav", NULL }, + { 2u, "Sfx\\Misc\\Invpot.wav", NULL }, + { 2u, "Sfx\\Misc\\Lning1.wav", NULL }, + { 2u, "Sfx\\Misc\\Ltning.wav", NULL }, + { 2u, "Sfx\\Misc\\Mshield.wav", NULL }, + { 2u, "Sfx\\Misc\\Nova.wav", NULL }, + { 2u, "Sfx\\Misc\\Portal.wav", NULL }, + { 2u, "Sfx\\Misc\\Puddle.wav", NULL }, + { 2u, "Sfx\\Misc\\Resur.wav", NULL }, + { 2u, "Sfx\\Misc\\Scurse.wav", NULL }, + { 2u, "Sfx\\Misc\\Scurimp.wav", NULL }, + { 2u, "Sfx\\Misc\\Sentinel.wav", NULL }, + { 2u, "Sfx\\Misc\\Shatter.wav", NULL }, + { 2u, "Sfx\\Misc\\Soulfire.wav", NULL }, + { 2u, "Sfx\\Misc\\Spoutlop.wav", NULL }, + { 2u, "Sfx\\Misc\\Spoutstr.wav", NULL }, + { 2u, "Sfx\\Misc\\Storm.wav", NULL }, + { 2u, "Sfx\\Misc\\Trapdis.wav", NULL }, + { 2u, "Sfx\\Misc\\Teleport.wav", NULL }, + { 2u, "Sfx\\Misc\\Vtheft.wav", NULL }, + { 2u, "Sfx\\Misc\\Wallloop.wav", NULL }, + { 2u, "Sfx\\Misc\\Wallstrt.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid01.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid02.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid03.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid04.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid05.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid06.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid07.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid08.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid09.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid10.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid11.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid12.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid13.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid14.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid15.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid16.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid17.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid18.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid19.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid20.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid21.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid22.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid23.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid24.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid25.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid26.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid27.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid28.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid29.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid30.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid31.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid32.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid33.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid34.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid35.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid36.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid37.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid38.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid39.wav", NULL }, + { 1u, "Sfx\\Towners\\Bmaid40.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith01.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith02.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith03.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith04.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith05.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith06.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith07.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith08.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith09.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith10.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith11.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith12.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith13.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith14.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith15.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith16.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith17.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith18.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith19.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith20.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith21.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith22.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith23.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith24.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith25.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith26.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith27.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith28.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith29.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith30.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith31.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith32.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith33.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith34.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith35.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith36.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith37.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith38.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith39.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith40.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith41.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith42.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith43.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith44.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith45.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith46.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith47.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith48.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith49.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith50.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith51.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith52.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith53.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith54.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith55.wav", NULL }, + { 1u, "Sfx\\Towners\\Bsmith56.wav", NULL }, + { 0u, "Sfx\\Towners\\Cow1.wav", NULL }, + { 0u, "Sfx\\Towners\\Cow2.wav", NULL }, + { 1u, "Sfx\\Towners\\Deadguy2.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk01.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk02.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk03.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk04.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk05.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk06.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk07.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk08.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk09.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk10.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk11.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk12.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk13.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk14.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk15.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk16.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk17.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk18.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk19.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk20.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk21.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk22.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk23.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk24.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk25.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk26.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk27.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk28.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk29.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk30.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk31.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk32.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk33.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk34.wav", NULL }, + { 1u, "Sfx\\Towners\\Drunk35.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer01.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer02.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer03.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer04.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer05.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer06.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer07.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer08.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer09.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer10.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer11.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer12.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer13.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer14.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer15.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer16.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer17.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer18.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer19.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer20.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer21.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer22.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer23.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer24.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer25.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer26.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer27.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer28.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer29.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer30.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer31.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer32.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer33.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer34.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer35.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer36.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer37.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer38.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer39.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer40.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer41.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer42.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer43.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer44.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer45.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer46.wav", NULL }, + { 1u, "Sfx\\Towners\\Healer47.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy01.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy02.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy03.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy04.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy05.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy06.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy07.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy08.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy09.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy10.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy11.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy12.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy13.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy14.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy15.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy16.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy17.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy18.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy19.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy20.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy21.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy22.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy23.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy24.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy25.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy26.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy27.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy28.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy29.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy30.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy31.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy32.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy33.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy34.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy35.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy36.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy37.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy38.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy39.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy40.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy41.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy42.wav", NULL }, + { 1u, "Sfx\\Towners\\Pegboy43.wav", NULL }, + { 1u, "Sfx\\Towners\\Priest00.wav", NULL }, + { 1u, "Sfx\\Towners\\Priest01.wav", NULL }, + { 1u, "Sfx\\Towners\\Priest02.wav", NULL }, + { 1u, "Sfx\\Towners\\Priest03.wav", NULL }, + { 1u, "Sfx\\Towners\\Priest04.wav", NULL }, + { 1u, "Sfx\\Towners\\Priest05.wav", NULL }, + { 1u, "Sfx\\Towners\\Priest06.wav", NULL }, + { 1u, "Sfx\\Towners\\Priest07.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt00.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt01.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt02.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt03.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt04.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt05.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt06.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt07.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt08.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt09.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt10.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt11.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt12.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt13.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt14.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt15.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt16.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt17.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt18.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt19.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt20.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt21.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt22.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt23.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt24.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt25.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt26.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt27.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt28.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt29.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt30.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt31.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt32.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt33.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt34.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt35.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt36.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt37.wav", NULL }, + { 1u, "Sfx\\Towners\\Storyt38.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown00.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown01.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown02.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown03.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown04.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown05.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown06.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown07.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown08.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown09.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown10.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown11.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown12.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown13.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown14.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown15.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown16.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown17.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown18.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown19.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown20.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown21.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown22.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown23.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown24.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown25.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown26.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown27.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown28.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown29.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown30.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown31.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown32.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown33.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown34.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown35.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown36.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown37.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown38.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown39.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown40.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown41.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown42.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown43.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown44.wav", NULL }, + { 1u, "Sfx\\Towners\\Tavown45.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch01.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch02.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch03.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch04.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch05.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch06.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch07.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch08.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch09.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch10.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch11.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch12.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch13.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch14.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch15.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch16.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch17.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch18.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch19.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch20.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch21.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch22.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch23.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch24.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch25.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch26.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch27.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch28.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch29.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch30.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch31.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch32.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch33.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch34.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch35.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch36.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch37.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch38.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch39.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch40.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch41.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch42.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch43.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch44.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch45.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch46.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch47.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch48.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch49.wav", NULL }, + { 1u, "Sfx\\Towners\\Witch50.wav", NULL }, + { 1u, "Sfx\\Towners\\Wound01.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage01.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage02.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage03.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage04.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage05.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage06.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage07.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage08.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage09.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage10.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage11.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage12.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage13.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage14.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage15.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage16.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage17.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage18.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage19.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage20.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage21.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage22.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage23.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage24.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage25.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage26.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage27.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage28.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage29.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage30.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage31.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage32.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage33.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage34.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage35.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage36.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage37.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage38.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage39.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage40.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage41.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage42.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage43.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage44.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage45.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage46.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage47.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage48.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage49.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage50.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage51.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage52.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage53.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage54.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage55.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage56.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage57.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage58.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage59.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage60.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage61.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage62.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage63.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage64.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage65.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage66.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage67.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage68.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage69.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage69b.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage70.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage71.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage72.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage73.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage74.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage75.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage76.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage77.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage78.wav", NULL }, + { 64u, "Sfx\\Sorceror\\Mage79.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage80.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage81.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage82.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage83.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage84.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage85.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage86.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage87.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage88.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage89.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage90.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage91.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage92.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage93.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage94.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage95.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage96.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage97.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage98.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage99.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage100.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage101.wav", NULL }, + { 65u, "Sfx\\Sorceror\\Mage102.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue01.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue02.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue03.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue04.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue05.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue06.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue07.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue08.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue09.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue10.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue11.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue12.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue13.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue14.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue15.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue16.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue17.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue18.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue19.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue20.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue21.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue22.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue23.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue24.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue25.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue26.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue27.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue28.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue29.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue30.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue31.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue32.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue33.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue34.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue35.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue36.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue37.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue38.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue39.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue40.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue41.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue42.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue43.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue44.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue45.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue46.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue47.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue48.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue49.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue50.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue51.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue52.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue53.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue54.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue55.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue56.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue57.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue58.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue59.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue60.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue61.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue62.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue63.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue64.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue65.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue66.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue67.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue68.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue69.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue69b.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue70.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue71.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue72.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue73.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue74.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue75.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue76.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue77.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue78.wav", NULL }, + { 16u, "Sfx\\Rogue\\Rogue79.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue80.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue81.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue82.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue83.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue84.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue85.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue86.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue87.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue88.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue89.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue90.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue91.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue92.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue93.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue94.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue95.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue96.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue97.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue98.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue99.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue100.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue101.wav", NULL }, + { 17u, "Sfx\\Rogue\\Rogue102.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior01.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior02.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior03.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior04.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior05.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior06.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior07.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior08.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior09.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior10.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior11.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior12.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior13.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior14.wav", NULL }, + { 32u, "Sfx\\Warrior\\Wario14b.wav", NULL }, + { 32u, "Sfx\\Warrior\\Wario14c.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior15.wav", NULL }, + { 32u, "Sfx\\Warrior\\Wario15b.wav", NULL }, + { 32u, "Sfx\\Warrior\\Wario15c.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior16.wav", NULL }, + { 32u, "Sfx\\Warrior\\Wario16b.wav", NULL }, + { 32u, "Sfx\\Warrior\\Wario16c.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior17.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior18.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior19.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior20.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior21.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior22.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior23.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior24.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior25.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior26.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior27.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior28.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior29.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior30.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior31.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior32.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior33.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior34.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior35.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior36.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior37.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior38.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior39.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior40.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior41.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior42.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior43.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior44.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior45.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior46.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior47.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior48.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior49.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior50.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior51.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior52.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior53.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior54.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior55.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior56.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior57.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior58.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior59.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior60.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior61.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior62.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior63.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior64.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior65.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior66.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior67.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior68.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior69.wav", NULL }, + { 32u, "Sfx\\Warrior\\Wario69b.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior70.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior71.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior72.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior73.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior74.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior75.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior76.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior77.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior78.wav", NULL }, + { 32u, "Sfx\\Warrior\\Warior79.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior80.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior81.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior82.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior83.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior84.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior85.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior86.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior87.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior88.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior89.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior90.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior91.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior92.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior93.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior94.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior95.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario95b.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario95c.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario95d.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario95e.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario95f.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario96b.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario97.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario98.wav", NULL }, + { 33u, "Sfx\\Warrior\\Warior99.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario100.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario101.wav", NULL }, + { 33u, "Sfx\\Warrior\\Wario102.wav", NULL }, + { 1u, "Sfx\\Narrator\\Nar01.wav", NULL }, + { 1u, "Sfx\\Narrator\\Nar02.wav", NULL }, + { 1u, "Sfx\\Narrator\\Nar03.wav", NULL }, + { 1u, "Sfx\\Narrator\\Nar04.wav", NULL }, + { 1u, "Sfx\\Narrator\\Nar05.wav", NULL }, + { 1u, "Sfx\\Narrator\\Nar06.wav", NULL }, + { 1u, "Sfx\\Narrator\\Nar07.wav", NULL }, + { 1u, "Sfx\\Narrator\\Nar08.wav", NULL }, + { 1u, "Sfx\\Narrator\\Nar09.wav", NULL }, + { 1u, "Sfx\\Misc\\Lvl16int.wav", NULL }, + { 1u, "Sfx\\Monsters\\Butcher.wav", NULL }, + { 1u, "Sfx\\Monsters\\Garbud01.wav", NULL }, + { 1u, "Sfx\\Monsters\\Garbud02.wav", NULL }, + { 1u, "Sfx\\Monsters\\Garbud03.wav", NULL }, + { 1u, "Sfx\\Monsters\\Garbud04.wav", NULL }, + { 1u, "Sfx\\Monsters\\Izual01.wav", NULL }, + { 1u, "Sfx\\Monsters\\Lach01.wav", NULL }, + { 1u, "Sfx\\Monsters\\Lach02.wav", NULL }, + { 1u, "Sfx\\Monsters\\Lach03.wav", NULL }, + { 1u, "Sfx\\Monsters\\Laz01.wav", NULL }, + { 1u, "Sfx\\Monsters\\Laz02.wav", NULL }, + { 1u, "Sfx\\Monsters\\Sking01.wav", NULL }, + { 1u, "Sfx\\Monsters\\Snot01.wav", NULL }, + { 1u, "Sfx\\Monsters\\Snot02.wav", NULL }, + { 1u, "Sfx\\Monsters\\Snot03.wav", NULL }, + { 1u, "Sfx\\Monsters\\Warlrd01.wav", NULL }, + { 1u, "Sfx\\Monsters\\Wlock01.wav", NULL }, + { 1u, "Sfx\\Monsters\\Zhar01.wav", NULL }, + { 1u, "Sfx\\Monsters\\Zhar02.wav", NULL }, + { 1u, "Sfx\\Monsters\\DiabloD.wav", NULL } +}; + +struct effects_cpp_init +{ + effects_cpp_init() + { + effects_cpp_init_value = effects_inf; + } +} _effects_cpp_init; +// 47A468: using guessed type int effects_inf; +// 52A550: using guessed type int effects_cpp_init_value; + +bool __fastcall effect_is_playing(int nSFX) +{ + TSFX *v1; // eax + TSnd *v2; // ecx + + + + v1 = &sgSFX[nSFX]; + v2 = v1->pSnd; + if ( v2 ) + return snd_playing(v2); + if ( v1->bFlags & 1 ) + return v1 == sfx_data_cur; + return 0; +} + +void __cdecl sfx_stop() +{ + if ( sfx_stream ) + { + SFileDdaEnd(sfx_stream); + SFileCloseFile(sfx_stream); + sfx_stream = 0; + sfx_data_cur = 0; + } +} + +void __fastcall InitMonsterSND(int monst) +{ + signed int v1; // ebx + int v2; // eax + TSnd **v3; // esi + int v4; // edi + size_t v5; // eax + TSnd *v6; // eax + char v7[260]; // [esp+0h] [ebp-110h] + int v8; // [esp+104h] [ebp-Ch] + int v9; // [esp+108h] [ebp-8h] + char *ptr; // [esp+10Ch] [ebp-4h] + + v8 = monst; + if ( gbSndInited ) + { + v1 = 0; + v9 = Monsters[monst].mtype << 7; + do + { + if ( monster_action_sounds[v1] != 's' || *(int *)((char *)&monsterdata[0].snd_special + v9) ) + { + v2 = 0; + v3 = &Monsters[0].Snds[2 * (v1 + 41 * v8)]; + do + { + v4 = v2 + 1; + sprintf( + v7, + *(const char **)((char *)&monsterdata[0].sndfile + v9), + monster_action_sounds[v1], + v2 + 1); + v5 = strlen(v7); + ptr = (char *)DiabloAllocPtr(v5 + 1); + strcpy(ptr, v7); + + v6 = sound_file_load(ptr); + *v3 = v6; + if ( !v6 ) + mem_free_dbg(ptr); + v2 = v4; + ++v3; + } + while ( v4 < 2 ); + } + ++v1; + } + while ( v1 < 4 ); + } +} + +void __cdecl FreeEffects() +{ + TSnd **v0; // esi + signed int v1; // ebp + signed int v2; // ebx + TSnd *v3; // ecx + void *v4; // edi + TSnd **v5; // [esp+0h] [ebp-8h] + int v6; // [esp+4h] [ebp-4h] + + v6 = 0; + if ( nummtypes > 0 ) + { + v5 = Monsters[0].Snds; + do + { + v0 = v5; + v1 = 4; + do + { + v2 = 2; + do + { + v3 = *v0; + if ( *v0 ) + { + *v0 = 0; + v4 = (void *)v3->sound_path; + v3->sound_path = 0; + sound_file_cleanup(v3); + mem_free_dbg(v4); + } + ++v0; + --v2; + } + while ( v2 ); + --v1; + } + while ( v1 ); + ++v6; + v5 += 82; + } + while ( v6 < nummtypes ); + } +} + +void __fastcall PlayEffect(int i, int mode) +{ + int v2; // edi + int v3; // esi + int v4; // eax + int v5; // esi + int v6; // eax + TSnd *v7; // edi + //int v8; // eax + int volume_delta; // [esp+8h] [ebp-8h] + int pan; // [esp+Ch] [ebp-4h] + + + + v2 = mode; + v3 = i; + if ( !plr[myplr].pLvlLoad ) + { + v4 = random(164, 2); + if ( gbSndInited ) + { + if ( gbSoundOn ) + { + if ( !gbBufferMsgs ) + { + v5 = v3; + v6 = v4 + 2 * (v2 + 41 * monster[v5]._mMTidx); + v7 = Monsters[0].Snds[v6]; + if ( v7 ) + { + //_LOBYTE(v8) = snd_playing(Monsters[0].Snds[v6]); + if ( !snd_playing(Monsters[0].Snds[v6]) ) + { + if ( calc_snd_position(monster[v5]._mx, monster[v5]._my, &volume_delta, &pan) ) + snd_play_snd(v7, volume_delta, pan); + } + } + } + } + } + } +} +// 4A22D5: using guessed type char gbSoundOn; +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall calc_snd_position(int x, int y, int *plVolume, int *plPan) +{ + int v4; // edi + int v5; // esi + int v6; // eax + int v7; // ebx + int v8; // eax + int v9; // eax + + v4 = x - plr[myplr].WorldX; + v5 = y - plr[myplr].WorldY; + v6 = (v4 - v5) << 8; + *plPan = v6; + if ( abs(v6) > 6400 ) + return 0; + v7 = abs(v4); + v8 = v7 <= abs(v5) ? abs(v5) : abs(v4); + v9 = v8 << 6; + *plVolume = v9; + if ( v9 >= 6400 ) + return 0; + *plVolume = -v9; + return 1; +} + +void __fastcall PlaySFX(int psfx) +{ + int v1; // eax + printf("1091\n"); + v1 = RndSFX(psfx); + PlaySFX_priv(&sgSFX[v1], 0, 0, 0); +} + +void __fastcall PlaySFX_priv(TSFX *pSFX, char loc, int x, int y) +{ + int v4; // edi + TSFX *v5; // esi + TSnd *v6; // ecx + //int v7; // eax + TSnd *v8; // ecx + int volume_delta; // [esp+Ch] [ebp-8h] + int pan; // [esp+10h] [ebp-4h] + + + v4 = loc; + v5 = pSFX; + if ( !plr[myplr].pLvlLoad || gbMaxPlayers == 1 ) + { + if ( gbSndInited ) + { + if ( gbSoundOn ) + { + if ( !gbBufferMsgs ) + { + if ( pSFX->bFlags & 3 || (v6 = pSFX->pSnd) == 0 || !snd_playing(v6) ) + { + pan = 0; + volume_delta = 0; + if ( !v4 || calc_snd_position(x, y, &volume_delta, &pan) ) + { + if ( v5->bFlags & 1 ) + { + + // stream_play(v5, volume_delta, pan); // Debuf + } + else + { + if ( !v5->pSnd ) + v5->pSnd = sound_file_load(v5->pszName); + v8 = v5->pSnd; + if ( v8 ) + + snd_play_snd(v8, volume_delta, pan); + } + } + } + } + } + } + } +} +// 4A22D5: using guessed type char gbSoundOn; +// 676194: using guessed type char gbBufferMsgs; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall stream_play(TSFX *pSFX, int lVolume, int lPan) +{ + printf("stream_play\n"); + int v3; // esi + TSFX *v4; // edi + int v5; // esi + //int v6; // eax + //int v7; // eax + + v3 = lVolume; + v4 = pSFX; + sfx_stop(); + v5 = sound_get_or_set_sound_volume(1) + v3; + if ( v5 >= -1600 ) + { + if ( v5 > 0 ) + v5 = 0; + //_LOBYTE(v6) = SFileOpenFile(v4->pszName, &sfx_stream); + if ( SFileOpenFile(v4->pszName, &sfx_stream) ) + { + //_LOBYTE(v7) = SFileDdaBeginEx(sfx_stream, 0x40000, 0, 0, v5, lPan, 0); + if ( SFileDdaBeginEx(sfx_stream, 0x40000, 0, 0, v5, lPan, 0) )// This shouldn't be called but it does get called + sfx_data_cur = v4; + else + sfx_stop(); + } + else + { + sfx_stream = 0; + } + } +} + +int __fastcall RndSFX(int psfx) +{ + int v1; // esi + int v3; // [esp-4h] [ebp-8h] + + v1 = psfx; + switch ( psfx ) + { + case PS_WARR69: + goto LABEL_12; + case PS_WARR14: + case PS_WARR15: + case PS_WARR16: + goto LABEL_19; + case PS_MAGE69: + case PS_ROGUE69: + case PS_SWING: + case LS_ACID: + case IS_FMAG: + case IS_MAGIC: + case IS_BHIT: +LABEL_12: + v3 = 2; +LABEL_15: + return v1 + random(165, v3); + case PS_WARR2: +LABEL_19: + v3 = 3; + goto LABEL_15; + } + return psfx; +} + +void __fastcall PlaySfxLoc(int psfx, int x, int y) +{ + int v3; // esi + int v4; // eax + TSnd *v5; // ecx + + v3 = x; + v4 = RndSFX(psfx);// Crash here.... + // if ( v4 >= 0 && v4 <= 3 ) + // { + // v5 = sgSFX[v4].pSnd; + // if ( v5 ) + // v5->start_tc = 0; + // } + // PlaySFX_priv(&sgSFX[v4], 1, v3, y); +} + +void __cdecl FreeMonsterSnd() +{ + TSnd **v0; // esi + signed int v1; // ebx + signed int v2; // edi + int v3; // [esp+0h] [ebp-8h] + TSnd **v4; // [esp+4h] [ebp-4h] + + snd_update(1); + sfx_stop(); + sound_stop(); + v3 = 0; + if ( nummtypes > 0 ) + { + v4 = Monsters[0].Snds; + do + { + v0 = v4; + v1 = 4; + do + { + v2 = 2; + do + { + snd_stop_snd(*v0); + ++v0; + --v2; + } + while ( v2 ); + --v1; + } + while ( v1 ); + ++v3; + v4 += 82; + } + while ( v3 < nummtypes ); + } +} + +void __cdecl sound_stop() +{ + + int i; // edi + + for(i = 0; i < NUM_SFX; i++) + { + if ( sgSFX[i].pSnd ) + snd_stop_snd(sgSFX[i].pSnd); + } +} + +void __cdecl sound_update() +{ + //int v0; // ebp + //unsigned int v1; // ecx +// int v2; // eax + unsigned int v3; // [esp-Ch] [ebp-Ch] + unsigned int v4; // [esp-8h] [ebp-8h] + //int v5; // [esp-4h] [ebp-4h] + + if ( gbSndInited ) + { + snd_update(0); + //v5 = v0; + //v4 = v1; + //v3 = v1; + if ( sfx_stream ) + { + //_LOBYTE(v2) = SFileDdaGetPos(sfx_stream, (int)&v4, (int)&v3); + if ( SFileDdaGetPos(sfx_stream, (int)&v4, (int)&v3) ) + { + if ( v4 >= v3 ) + sfx_stop(); + } + } + } +} +// 415DBA: could not find valid save-restore pair for ebp + +void __cdecl effects_cleanup_sfx() +{ + unsigned int v0; // edi + TSnd *v1; // ecx + + FreeMonsterSnd(); + v0 = 0; + do + { + v1 = sgSFX[v0].pSnd; + if ( v1 ) + { + sound_file_cleanup(v1); + sgSFX[v0].pSnd = 0; + } + ++v0; + } + while ( v0 < NUM_SFX ); +} + +void __cdecl stream_update() +{ + char v0; // bl + char v1; // al + + v0 = 0; + if ( (unsigned char)gbMaxPlayers <= 1u ) + { + v1 = plr[myplr]._pClass; + if ( v1 ) + { + if ( v1 == 1 ) + { + v0 = 16; + } + else if ( v1 == 2 ) + { + v0 = 64; + } + else + { + TermMsg("effects:1"); + } + } + else + { + v0 = 32; + } + } + else + { + v0 = 112; + } + priv_sound_init(v0); +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall priv_sound_init(int bLoadMask) +{ + unsigned char v1; // bl + unsigned char v2; // cl + unsigned int v3; // esi + unsigned char v4; // al + TSnd *v5; // eax + unsigned char v6; // [esp+0h] [ebp-4h] + + if ( gbSndInited ) + { + v1 = bLoadMask & 0x70; + v2 = bLoadMask & 0x70 ^ bLoadMask; + v3 = 0; + v6 = v2; + do + { + if ( !sgSFX[v3].pSnd ) + { + v4 = sgSFX[v3].bFlags; + if ( !(v4 & 1) && (!v2 || v4 & v2) && (!(v4 & 0x70) || v4 & v1) ) + { + v5 = sound_file_load(sgSFX[v3].pszName); + v2 = v6; + sgSFX[v3].pSnd = v5; + } + } + ++v3; + } + while ( v3 < NUM_SFX ); + } +} + +void __cdecl sound_init() +{ + priv_sound_init(4); +} + +void __stdcall effects_play_sound(char *snd_file) +{ + int v1; // edi + unsigned int v2; // esi + TSnd **v3; // esi + //int v4; // eax + + if ( gbSndInited && gbSoundOn ) + { + v1 = 0; + v2 = 0; + while ( _strcmpi(sgSFX[v2].pszName, snd_file) || !sgSFX[v2].pSnd ) + { + ++v2; + ++v1; + if ( v2 >= NUM_SFX ) + return; + } + v3 = &sgSFX[v1].pSnd; + //_LOBYTE(v4) = snd_playing(*v3); + if ( !snd_playing(*v3) ) + snd_play_snd(*v3, 0, 0); + } +} +// 4A22D5: using guessed type char gbSoundOn; diff --git a/Source/effects.h b/Source/effects.h new file mode 100644 index 000000000..75483260e --- /dev/null +++ b/Source/effects.h @@ -0,0 +1,41 @@ +//HEADER_GOES_HERE +#ifndef __EFFECTS_H__ +#define __EFFECTS_H__ + +extern int effects_cpp_init_value; // weak +extern int sfxdelay; // weak +extern int sfxdnum; +extern void *sfx_stream; +extern TSFX *sfx_data_cur; + +void __cdecl effects_cpp_init(); +bool __fastcall effect_is_playing(int nSFX); +void __cdecl sfx_stop(); +void __fastcall InitMonsterSND(int monst); +void __cdecl FreeEffects(); +void __fastcall PlayEffect(int i, int mode); +int __fastcall calc_snd_position(int x, int y, int *plVolume, int *plPan); +void __fastcall PlaySFX(int psfx); +void __fastcall PlaySFX_priv(TSFX *pSFX, char loc, int x, int y); +void __fastcall stream_play(TSFX *pSFX, int lVolume, int lPan); +int __fastcall RndSFX(int psfx); +void __fastcall PlaySfxLoc(int psfx, int x, int y); +void __cdecl FreeMonsterSnd(); +void __cdecl sound_stop(); +void __cdecl sound_update(); +void __cdecl effects_cleanup_sfx(); +void __cdecl stream_update(); +void __fastcall priv_sound_init(int bLoadMask); +void __cdecl sound_init(); +void __stdcall effects_play_sound(char *snd_file); + +/* rdata */ + +extern const int effects_inf; // weak +extern const char monster_action_sounds[]; // idb + +/* data */ + +extern TSFX sgSFX[NUM_SFX]; + +#endif /* __EFFECTS_H__ */ diff --git a/Source/encrypt.cpp b/Source/encrypt.cpp new file mode 100644 index 000000000..db6e46b28 --- /dev/null +++ b/Source/encrypt.cpp @@ -0,0 +1,210 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int encrypt_table[1280]; +#endif + +void __fastcall encrypt_decrypt_block(void *block, int size, int key) // DecryptMPQBlock +{ + unsigned int v3; // edx + int v4; // eax + unsigned int v5; // edi + unsigned int v6; // edx + int v7; // eax + int v8; // esi + + v3 = (unsigned int)size >> 2; + v4 = 0xEEEEEEEE; + if ( v3 ) + { + v5 = v3; + v6 = key; + do + { + v7 = encrypt_table[(unsigned char)v6 + 1024] + v4; + *(_DWORD *)block ^= v7 + v6; + v8 = *(_DWORD *)block; + block = (char *)block + 4; + v4 = 33 * v7 + v8 + 3; + v6 = ((~v6 << 21) + 0x11111111) | (v6 >> 11); + --v5; + } + while ( v5 ); + } +} + +void __fastcall encrypt_encrypt_block(void *block, int size, int key) // EncryptMPQBlock +{ + unsigned int v3; // edx + int v4; // eax + unsigned int v5; // edi + unsigned int v6; // edx + int v7; // eax + int v8; // ebx + + v3 = (unsigned int)size >> 2; + v4 = 0xEEEEEEEE; + if ( v3 ) + { + v5 = v3; + v6 = key; + do + { + v7 = encrypt_table[(unsigned char)v6 + 1024] + v4; + v8 = *(_DWORD *)block ^ (v7 + v6); + v4 = 33 * v7 + *(_DWORD *)block + 3; + *(_DWORD *)block = v8; + block = (char *)block + 4; + v6 = ((~v6 << 21) + 0x11111111) | (v6 >> 11); + --v5; + } + while ( v5 ); + } +} + +int __fastcall encrypt_hash(char *s, int type) // HashStringSlash +{ + int v2; // ebp + char *v3; // ebx + signed int v4; // esi + int v5; // edi + int v6; // ST00_4 + char v7; // al + + v2 = type; + v3 = s; + v4 = 0x7FED7FED; + v5 = 0xEEEEEEEE; + while ( v3 && *v3 ) + { + v6 = *v3++; + v7 = toupper(v6); + v4 = (v5 + v4) ^ encrypt_table[v7 + (v2 << 8)]; + v5 = v7 + 33 * v5 + v4 + 3; + } + return v4; +} + +void __cdecl encrypt_init_lookup_table() // InitScratchSpace +{ + unsigned int v0; // eax + int *v1; // edi + unsigned int v2; // eax + int v3; // ecx + signed int v4; // [esp+Ch] [ebp-8h] + int *v5; // [esp+10h] [ebp-4h] + + v0 = 0x100001; + v5 = encrypt_table; + do + { + v1 = v5; + v4 = 5; + do + { + v2 = (125 * v0 + 3) % 0x2AAAAB; + v3 = (unsigned short)v2 << 16; + v0 = (125 * v2 + 3) % 0x2AAAAB; + *v1 = (unsigned short)v0 | v3; + v1 += 256; + --v4; + } + while ( v4 ); + ++v5; + } + while ( (signed int)v5 < (signed int)&encrypt_table[256] ); +} + +int __fastcall encrypt_compress(void *buf, int size) // MPQCompress_PKWare +{ + unsigned char *v2; // ebx + unsigned char *v3; // esi + int v4; // ecx + unsigned char *v5; // edi + TDataInfo param; // [esp+Ch] [ebp-20h] + unsigned int type; // [esp+20h] [ebp-Ch] + unsigned int dsize; // [esp+24h] [ebp-8h] + char *ptr; // [esp+28h] [ebp-4h] + + v2 = (unsigned char *)buf; + v3 = (unsigned char *)size; + ptr = (char *)DiabloAllocPtr(CMP_BUFFER_SIZE); // 36312 + v4 = 2 * (_DWORD)v3; + if ( (unsigned int)(2 * (_DWORD)v3) < 0x2000 ) + v4 = 0x2000; + v5 = (unsigned char *)DiabloAllocPtr(v4); + param.pbInBuffEnd = 0; + param.pbOutBuffEnd = 0; + type = 0; + param.pbInBuff = v2; + param.pbOutBuff = v5; + param.pbSize = v3; + dsize = 4096; + implode( + encrypt_pkware_read, + encrypt_pkware_write, + ptr, + ¶m, + &type, + &dsize); + if ( param.pbOutBuffEnd < v3 ) + { + memcpy(v2, v5, (size_t)param.pbOutBuffEnd); + v3 = param.pbOutBuffEnd; + } + mem_free_dbg(ptr); + mem_free_dbg(v5); + return (int)v3; +} + +unsigned int __cdecl encrypt_pkware_read(char *buf, unsigned int *size, void *param) // ReadPKWare +{ + TDataInfo * pInfo = (TDataInfo *)param; + int v3; // edi + unsigned char *v4; // ecx + + v3 = *size; + v4 = pInfo->pbInBuffEnd; + if ( *size >= (unsigned int)(pInfo->pbSize - v4) ) + v3 = pInfo->pbSize - v4; + memcpy(buf, &v4[(unsigned int)pInfo->pbInBuff], v3); + pInfo->pbInBuffEnd += v3; + return v3; +} + +void __cdecl encrypt_pkware_write(char *buf, unsigned int *size, void *param) // WritePKWare +{ + TDataInfo * pInfo = (TDataInfo *)param; + + memcpy(&pInfo->pbOutBuffEnd[(unsigned int)pInfo->pbOutBuff], buf, *size); + pInfo->pbOutBuffEnd += *size; +} + +void __fastcall encrypt_decompress(void *param, int recv_size, int dwMaxBytes) // MPQDecompress_PKWare +{ + unsigned char *v3; // edi + unsigned char *v4; // ebx + unsigned char *v5; // esi + TDataInfo info; // [esp+Ch] [ebp-18h] + char *ptr; // [esp+20h] [ebp-4h] + + v3 = (unsigned char *)param; + v4 = (unsigned char *)recv_size; + ptr = (char *)DiabloAllocPtr(CMP_BUFFER_SIZE); // 36312 + v5 = (unsigned char *)DiabloAllocPtr(dwMaxBytes); + info.pbInBuffEnd = 0; + info.pbOutBuffEnd = 0; + info.pbInBuff = v3; + info.pbOutBuff = v5; + info.pbSize = v4; + explode( + encrypt_pkware_read, + encrypt_pkware_write, + ptr, + &info); + memcpy(v3, v5, (size_t)info.pbOutBuffEnd); + mem_free_dbg(ptr); + mem_free_dbg(v5); +} diff --git a/Source/encrypt.h b/Source/encrypt.h new file mode 100644 index 000000000..f3c150b84 --- /dev/null +++ b/Source/encrypt.h @@ -0,0 +1,17 @@ +//HEADER_GOES_HERE +#ifndef __ENCRYPT_H__ +#define __ENCRYPT_H__ + +extern int encrypt_table[1280]; +//int encrypt_52B564[257]; + +void __fastcall encrypt_decrypt_block(void *block, int size, int key); +void __fastcall encrypt_encrypt_block(void *block, int size, int key); +int __fastcall encrypt_hash(char *s, int type); +void __cdecl encrypt_init_lookup_table(); +int __fastcall encrypt_compress(void *buf, int size); +unsigned int __cdecl encrypt_pkware_read(char *buf, unsigned int *size, void *param); +void __cdecl encrypt_pkware_write(char *buf, unsigned int *size, void *param); +void __fastcall encrypt_decompress(void *param, int recv_size, int dwMaxBytes); + +#endif /* __ENCRYPT_H__ */ diff --git a/Source/engine.cpp b/Source/engine.cpp new file mode 100644 index 000000000..896b5c07b --- /dev/null +++ b/Source/engine.cpp @@ -0,0 +1,2920 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int engine_cpp_init_value; // weak + +#ifndef NO_GLOBALS +char gbPixelCol; // automap pixel color 8-bit (palette entry) +int dword_52B970; // bool flip - if y < x +int orgseed; // weak +int sgnWidth; +int sglGameSeed; // weak +static CRITICAL_SECTION sgMemCrit; +int SeedCount; // weak +int dword_52B99C; // bool valid - if x/y are in bounds +#endif + +const int engine_inf = 0x7F800000; // weak +const int rand_increment = 1; // unused +const int rand_multiplier = 0x015A4E35; // unused + +struct engine_cpp_init_1 +{ + engine_cpp_init_1() + { + engine_cpp_init_value = engine_inf; + } +} _engine_cpp_init_1; +// 47A474: using guessed type int engine_inf; +// 52B968: using guessed type int engine_cpp_init_value; + +void __fastcall CelDrawDatOnly(char *pDecodeTo, char *pRLEBytes, int dwRLESize, int dwRLEWdt) +{ + char *v4; // esi + char *v5; // edi + int v6; // edx + unsigned int v7; // eax + unsigned int v8; // ecx + char v9; // cf + unsigned int v10; // ecx + char *v11; // [esp+4h] [ebp-8h] + + v11 = pRLEBytes; + if ( pDecodeTo && pRLEBytes ) + { + v4 = pRLEBytes; + v5 = pDecodeTo; + do + { + v6 = dwRLEWdt; + do + { + while ( 1 ) + { + v7 = (unsigned char)*v4++; + if ( (v7 & 0x80u) == 0 ) + break; + _LOBYTE(v7) = -(char)v7; + v5 += v7; + v6 -= v7; + if ( !v6 ) + goto LABEL_14; + } + v6 -= v7; + v8 = v7 >> 1; + if ( v7 & 1 ) + { + *v5++ = *v4++; + if ( !v8 ) + continue; + } + v9 = v8 & 1; + v10 = v7 >> 2; + if ( v9 ) + { + *(_WORD *)v5 = *(_WORD *)v4; + v4 += 2; + v5 += 2; + if ( !v10 ) + continue; + } + qmemcpy(v5, v4, 4 * v10); + v4 += 4 * v10; + v5 += 4 * v10; + } + while ( v6 ); +LABEL_14: + v5 += -dwRLEWdt - 768; + } + while ( &v11[dwRLESize] != v4 ); + } +} + +void __fastcall CelDecodeOnly(int screen_x, int screen_y, void *pCelBuff, int frame, int frame_width) +{ + if ( gpBuffer ) + { + if ( pCelBuff ) + CelDrawDatOnly( + (char *)gpBuffer + screen_y_times_768[screen_y] + screen_x, + (char *)pCelBuff + *((_DWORD *)pCelBuff + frame), + *((_DWORD *)pCelBuff + frame + 1) - *((_DWORD *)pCelBuff + frame), + frame_width); + } +} + +void __fastcall CelDecDatOnly(char *pBuff, char *pCelBuff, int frame, int frame_width) +{ + if ( pCelBuff ) + { + if ( pBuff ) + CelDrawDatOnly( + pBuff, + &pCelBuff[*(_DWORD *)&pCelBuff[4 * frame]], + *(_DWORD *)&pCelBuff[4 * frame + 4] - *(_DWORD *)&pCelBuff[4 * frame], + frame_width); + } +} + +void __fastcall CelDrawHdrOnly(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int always_0, int direction) +{ + int v7; // edx + char *v8; // eax + int v9; // edi + int v10; // ecx + int v11; // [esp+Ch] [ebp-8h] + int v12; // [esp+10h] [ebp-4h] + + v12 = screen_y; + v11 = screen_x; + if ( gpBuffer ) + { + if ( pCelBuff ) + { + v7 = *(_DWORD *)&pCelBuff[4 * frame]; + v8 = &pCelBuff[v7]; + v9 = *(unsigned short *)&pCelBuff[v7 + always_0]; + if ( *(_WORD *)&pCelBuff[v7 + always_0] ) + { + if ( direction != 8 && *(_WORD *)&v8[direction] ) + v10 = *(unsigned short *)&v8[direction] - v9; + else + v10 = *(_DWORD *)&pCelBuff[4 * frame + 4] - v7 - v9; + CelDrawDatOnly( + (char *)gpBuffer + screen_y_times_768[v12 - 16 * always_0] + v11, + &v8[v9], + v10, + frame_width); + } + } + } +} + +void __fastcall CelDecodeHdrOnly(char *pBuff, char *pCelBuff, int frame, int frame_width, int always_0, int direction) +{ + int v6; // esi + char *v7; // eax + int v8; // ebx + int v9; // edx + int v10; // edx + + if ( pCelBuff ) + { + if ( pBuff ) + { + v6 = *(_DWORD *)&pCelBuff[4 * frame]; + v7 = &pCelBuff[v6]; + v8 = *(unsigned short *)&pCelBuff[v6 + always_0]; + if ( *(_WORD *)&pCelBuff[v6 + always_0] ) + { + v9 = *(_DWORD *)&pCelBuff[4 * frame + 4] - v6; + if ( direction != 8 && *(_WORD *)&v7[direction] ) + v10 = *(unsigned short *)&v7[direction] - v8; + else + v10 = v9 - v8; + CelDrawDatOnly(pBuff, &v7[v8], v10, frame_width); + } + } + } +} + +void __fastcall CelDecDatLightOnly(char *pDecodeTo, char *pRLEBytes, int frame_content_size, int frame_width) +{ + char *v4; // esi + char *v5; // edi + char *v6; // ebx + int v7; // edx + int v8; // eax + int v9; // ST00_4 + char *a3; // [esp+Ch] [ebp-10h] + + if ( pDecodeTo && pRLEBytes ) + { + a3 = &pLightTbl[256 * light_table_index]; + v4 = pRLEBytes; + v5 = pDecodeTo; + v6 = &pRLEBytes[frame_content_size]; + do + { + v7 = frame_width; + do + { + while ( 1 ) + { + v8 = (unsigned char)*v4++; + if ( (v8 & 0x80u) != 0 ) /* check sign */ + break; + v9 = v7 - v8; + CelDecDatLightEntry(v8, a3, v5, v4); + v7 = v9; + if ( !v9 ) + goto LABEL_9; + } + _LOBYTE(v8) = -(char)v8; + v5 += v8; + v7 -= v8; + } + while ( v7 ); +LABEL_9: + v5 += -frame_width - 768; + } + while ( v6 != v4 ); + } +} +// 69BEF8: using guessed type int light_table_index; + +void __fastcall CelDecDatLightEntry(unsigned char shift, char *LightIndex, char *&pDecodeTo, char *&pRLEBytes) +{ + char v5; // cf + unsigned char v6; // cl + char v7; // cl + int v8; // eax + char v9; // ch + int tmp; // eax + char v11; // ch + char v12; // ch + unsigned char a1; + + v5 = shift & 1; + v6 = shift >> 1; + if ( v5 ) + { + a1 = *pRLEBytes; + *pDecodeTo = LightIndex[a1]; + ++pRLEBytes; + ++pDecodeTo; + } + v5 = v6 & 1; + v7 = v6 >> 1; + if ( v5 ) + { + a1 = *pRLEBytes; + *pDecodeTo = LightIndex[a1]; + a1 = pRLEBytes[1]; + pDecodeTo[1] = LightIndex[a1]; + pRLEBytes += 2; + pDecodeTo += 2; + } + for ( ; v7; --v7 ) + { + v8 = *(_DWORD *)pRLEBytes; + pRLEBytes += 4; + a1 = v8; + v9 = LightIndex[a1]; + a1 = BYTE1(v8); + tmp = __ROR4__(v8, 16); + *pDecodeTo = v9; + v11 = LightIndex[a1]; + a1 = tmp; + pDecodeTo[1] = v11; + v12 = LightIndex[a1]; + a1 = BYTE1(tmp); + pDecodeTo[2] = v12; + pDecodeTo[3] = LightIndex[a1]; + pDecodeTo += 4; + } +} + +void __fastcall CelDecDatLightTrans(char *pDecodeTo, char *pRLEBytes, int frame_content_size, int frame_width) +{ + char *v4; // esi + int v5; // edi + char *v6; // ebx + int v7; // edx + unsigned int v8; // eax + unsigned int v10; // ecx + char v11; // cf + unsigned int v12; // ecx + char *v13; // esi + _BYTE *v14; // edi + _BYTE *v18; // edi + unsigned int v21; // ecx + _BYTE *v25; // edi + char *v26; // [esp-4h] [ebp-24h] + char *v27; // [esp+Ch] [ebp-14h] + int v28; // [esp+14h] [ebp-Ch] + int _EAX; + char *_EBX; + + if ( pDecodeTo && pRLEBytes ) + { + v27 = &pLightTbl[256 * light_table_index]; + v4 = pRLEBytes; + v5 = (int)pDecodeTo; + v6 = &pRLEBytes[frame_content_size]; + v28 = (unsigned char)pDecodeTo & 1; + do + { + v7 = frame_width; + do + { + while ( 1 ) + { + v8 = (unsigned char)*v4++; + if ( (v8 & 0x80u) != 0 ) + break; + v26 = v6; + _EBX = v27; + v7 -= v8; + if ( (v5 & 1) == v28 ) + { + v10 = v8 >> 1; + if ( !(v8 & 1) ) + goto LABEL_10; + ++v4; + ++v5; + if ( v10 ) + { +LABEL_17: + v11 = v10 & 1; + v21 = v10 >> 1; + if ( !v11 ) + goto LABEL_26; + _EAX = *v4; + ASM_XLAT(_EAX,_EBX); + *(_BYTE *)v5 = _EAX; + v4 += 2; + v5 += 2; + if ( v21 ) + { +LABEL_26: + do + { + _EAX = *(_DWORD *)v4; + v4 += 4; + ASM_XLAT(_EAX,_EBX); + *(_BYTE *)v5 = _EAX; + v25 = (_BYTE *)(v5 + 2); + _EAX = __ROR4__(_EAX, 16); + ASM_XLAT(_EAX,_EBX); + *v25 = _EAX; + v5 = (int)(v25 + 2); + --v21; + } + while ( v21 ); + } + goto LABEL_20; + } + } + else + { + v10 = v8 >> 1; + if ( !(v8 & 1) ) + goto LABEL_17; + _EAX = *v4++; + ASM_XLAT(_EAX,_EBX); + *(_BYTE *)v5++ = _EAX; + if ( v10 ) + { +LABEL_10: + v11 = v10 & 1; + v12 = v10 >> 1; + if ( !v11 ) + goto LABEL_27; + v13 = v4 + 1; + v14 = (_BYTE *)(v5 + 1); + _EAX = *v13; + v4 = v13 + 1; + ASM_XLAT(_EAX,_EBX); + *v14 = _EAX; + v5 = (int)(v14 + 1); + if ( v12 ) + { +LABEL_27: + do + { + _EAX = *(_DWORD *)v4; + v4 += 4; + v18 = (_BYTE *)(v5 + 1); + _EAX = __ROR4__(_EAX, 8); + ASM_XLAT(_EAX,_EBX); + *v18 = _EAX; + _EAX = __ROR4__(_EAX, 16); + v18 += 2; + ASM_XLAT(_EAX,_EBX); + *v18 = _EAX; + v5 = (int)(v18 + 1); + --v12; + } + while ( v12 ); + } + goto LABEL_20; + } + } +LABEL_20: + v6 = v26; + if ( !v7 ) + goto LABEL_23; + } + _LOBYTE(v8) = -(char)v8; + v5 += v8; + v7 -= v8; + } + while ( v7 ); +LABEL_23: + v5 -= frame_width + 768; + v28 = ((_BYTE)v28 + 1) & 1; + } + while ( v6 != v4 ); + } +} +// 69BEF8: using guessed type int light_table_index; + +void __fastcall CelDecodeLightOnly(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width) +{ + int v5; // ebx + int v6; // esi + char *v7; // edx + char *v8; // ecx + int v9; // [esp-8h] [ebp-14h] + + v5 = screen_y; + if ( gpBuffer && pCelBuff ) + { + v6 = *(_DWORD *)&pCelBuff[4 * frame]; + v7 = &pCelBuff[v6]; + v8 = (char *)gpBuffer + screen_y_times_768[v5] + screen_x; + v9 = *(_DWORD *)&pCelBuff[4 * frame + 4] - v6; + if ( light_table_index ) + CelDecDatLightOnly(v8, v7, v9, frame_width); + else + CelDrawDatOnly(v8, v7, v9, frame_width); + } +} +// 69BEF8: using guessed type int light_table_index; + +void __fastcall CelDecodeHdrLightOnly(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int always_0, int direction) +{ + int v7; // esi + char *v8; // ecx + int v9; // edi + char *v10; // edx + int v11; // ebx + int v12; // ebx + char *v13; // edx + char *v14; // ecx + int v15; // [esp+Ch] [ebp-4h] + char *cel_buf; // [esp+18h] [ebp+8h] + + v7 = screen_y; + v15 = screen_x; + if ( gpBuffer ) + { + v8 = pCelBuff; + if ( pCelBuff ) + { + v9 = *(_DWORD *)&pCelBuff[4 * frame]; + v10 = &pCelBuff[v9]; + v11 = *(unsigned short *)&pCelBuff[v9 + always_0]; + cel_buf = (char *)*(unsigned short *)&pCelBuff[v9 + always_0]; + if ( v11 ) + { + if ( direction != 8 && *(_WORD *)&v10[direction] ) + v12 = *(unsigned short *)&v10[direction] - (_DWORD)cel_buf; + else + v12 = *(_DWORD *)&v8[4 * frame + 4] - v9 - (_DWORD)cel_buf; + v13 = &v10[(_DWORD)cel_buf]; + v14 = (char *)gpBuffer + screen_y_times_768[v7 - 16 * always_0] + v15; + if ( light_table_index ) + CelDecDatLightOnly(v14, v13, v12, frame_width); + else + CelDrawDatOnly(v14, v13, v12, frame_width); + } + } + } +} +// 69BEF8: using guessed type int light_table_index; + +void __fastcall CelDecodeHdrLightTrans(char *pBuff, char *pCelBuff, int frame, int frame_width, int always_0, int direction) +{ + char *v6; // eax + int v7; // esi + char *v8; // edx + int v9; // ebx + int v10; // eax + int v11; // eax + char *v12; // edx + + v6 = pCelBuff; + if ( pCelBuff ) + { + if ( pBuff ) + { + v7 = *(_DWORD *)&pCelBuff[4 * frame]; + v8 = &pCelBuff[v7]; + v9 = *(unsigned short *)&v6[v7 + always_0]; + if ( *(_WORD *)&v6[v7 + always_0] ) + { + v10 = *(_DWORD *)&v6[4 * frame + 4] - v7; + if ( direction != 8 && *(_WORD *)&v8[direction] ) + v11 = *(unsigned short *)&v8[direction] - v9; + else + v11 = v10 - v9; + v12 = &v8[v9]; + if ( cel_transparency_active ) + { + CelDecDatLightTrans(pBuff, v12, v11, frame_width); + } + else if ( light_table_index ) + { + CelDecDatLightOnly(pBuff, v12, v11, frame_width); + } + else + { + CelDrawDatOnly(pBuff, v12, v11, frame_width); + } + } + } + } +} +// 69BEF8: using guessed type int light_table_index; +// 69CF94: using guessed type int cel_transparency_active; + +void __fastcall CelDrawHdrLightRed(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int always_0, int direction, char always_1) +{ + char *v8; // esi + int v9; // ebx + int v10; // eax + char *v11; // edi + int v12; // ecx + int v13; // esi + int v14; // eax + int v15; // eax + _BYTE *v16; // esi + char *v17; // edi + int v18; // edx + int v19; // eax + int v20; // ecx + int v21; // [esp+Ch] [ebp-4h] + char *v22; // [esp+Ch] [ebp-4h] + char *cel_buf; // [esp+18h] [ebp+8h] + char *cel_bufa; // [esp+18h] [ebp+8h] + int framea; // [esp+1Ch] [ebp+Ch] + int always_0a; // [esp+24h] [ebp+14h] + int directiona; // [esp+28h] [ebp+18h] + + v21 = screen_x; + if ( gpBuffer ) + { + v8 = pCelBuff; + if ( pCelBuff ) + { + v9 = *(_DWORD *)&pCelBuff[4 * frame]; + v10 = always_0; + v11 = &pCelBuff[v9]; + v12 = *(unsigned short *)&pCelBuff[v9 + always_0]; + cel_buf = (char *)*(unsigned short *)&pCelBuff[v9 + always_0]; + if ( v12 ) + { + v13 = *(_DWORD *)&v8[4 * frame + 4] - v9; + if ( direction != 8 && *(_WORD *)&v11[direction] ) + always_0a = *(unsigned short *)&v11[direction] - (_DWORD)cel_buf; + else + always_0a = v13 - (_DWORD)cel_buf; + directiona = (int)&v11[(_DWORD)cel_buf]; + cel_bufa = (char *)gpBuffer + screen_y_times_768[screen_y - 16 * v10] + v21; + v14 = -(light4flag != 0); + _LOWORD(v14) = v14 & 0xF400; + v15 = v14 + 4096; + framea = v15; + if ( always_1 == 2 ) + { + v15 += 256; + framea = v15; + } + if ( always_1 >= 4 ) + framea = v15 + (always_1 << 8) - 256; + v22 = &pLightTbl[framea]; + v16 = (_BYTE *)directiona; + v17 = cel_bufa; + do + { + v18 = frame_width; + do + { + while ( 1 ) + { + v19 = (unsigned char)*v16++; + if ( (v19 & 0x80u) == 0 ) + break; + _LOBYTE(v19) = -(char)v19; + v17 += v19; + v18 -= v19; + if ( !v18 ) + goto LABEL_20; + } + v18 -= v19; + v20 = v19; + do + { + _LOBYTE(v19) = *v16++; + *v17 = v22[v19]; + --v20; + ++v17; + } + while ( v20 ); + } + while ( v18 ); +LABEL_20: + v17 += -frame_width - 768; + } + while ( (_BYTE *)(directiona + always_0a) != v16 ); + } + } + } +} +// 525728: using guessed type int light4flag; + +void __fastcall Cel2DecDatOnly(char *pDecodeTo, char *pRLEBytes, int frame_content_size, int frame_width) +{ + char *v4; // esi + char *v5; // edi + int v6; // edx + unsigned int v7; // eax + unsigned int v8; // ecx + char v9; // cf + unsigned int v10; // ecx + char *v11; // [esp+4h] [ebp-8h] + + v11 = pRLEBytes; + if ( pDecodeTo && pRLEBytes && gpBuffer ) + { + v4 = pRLEBytes; + v5 = pDecodeTo; + do + { + v6 = frame_width; + do + { + while ( 1 ) + { + v7 = (unsigned char)*v4++; + if ( (v7 & 0x80u) == 0 ) + break; + _LOBYTE(v7) = -(char)v7; + v5 += v7; + v6 -= v7; + if ( !v6 ) + goto LABEL_17; + } + v6 -= v7; + if ( v5 < (char *)gpBufEnd ) + { + v8 = v7 >> 1; + if ( !(v7 & 1) || (*v5 = *v4, ++v4, ++v5, v8) ) + { + v9 = v8 & 1; + v10 = v7 >> 2; + if ( !v9 || (*(_WORD *)v5 = *(_WORD *)v4, v4 += 2, v5 += 2, v10) ) + { + qmemcpy(v5, v4, 4 * v10); + v4 += 4 * v10; + v5 += 4 * v10; + } + } + } + else + { + v4 += v7; + v5 += v7; + } + } + while ( v6 ); +LABEL_17: + v5 += -frame_width - 768; + } + while ( &v11[frame_content_size] != v4 ); + } +} +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall Cel2DrawHdrOnly(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int a6, int direction) +{ + int v7; // edx + char *v8; // eax + int v9; // edi + int v10; // ecx + int v11; // [esp+Ch] [ebp-8h] + int v12; // [esp+10h] [ebp-4h] + + v12 = screen_y; + v11 = screen_x; + if ( gpBuffer ) + { + if ( pCelBuff ) + { + v7 = *(_DWORD *)&pCelBuff[4 * frame]; + v8 = &pCelBuff[v7]; + v9 = *(unsigned short *)&pCelBuff[v7 + a6]; + if ( *(_WORD *)&pCelBuff[v7 + a6] ) + { + if ( direction != 8 && *(_WORD *)&v8[direction] ) + v10 = *(unsigned short *)&v8[direction] - v9; + else + v10 = *(_DWORD *)&pCelBuff[4 * frame + 4] - v7 - v9; + Cel2DecDatOnly( + (char *)gpBuffer + screen_y_times_768[v12 - 16 * a6] + v11, + &v8[v9], + v10, + frame_width); + } + } + } +} + +void __fastcall Cel2DecodeHdrOnly(char *pBuff, char *pCelBuff, int frame, int frame_width, int a5, int direction) +{ + int v6; // edi + char *v7; // esi + int v8; // ebx + int v9; // eax + int v10; // edx + int v11; // eax + + if ( pCelBuff ) + { + if ( pBuff ) + { + v6 = *(_DWORD *)&pCelBuff[4 * frame]; + v7 = &pCelBuff[v6]; + v8 = *(unsigned short *)&pCelBuff[v6 + a5]; + if ( *(_WORD *)&pCelBuff[v6 + a5] ) + { + v9 = *(_DWORD *)&pCelBuff[4 * frame + 4] - v6; + v10 = *(unsigned short *)&v7[direction]; + if ( direction == 8 ) + v10 = 0; + if ( v10 ) + v11 = v10 - v8; + else + v11 = v9 - v8; + Cel2DecDatOnly(pBuff, &v7[v8], v11, frame_width); + } + } + } +} + +void __fastcall Cel2DecDatLightOnly(char *pDecodeTo, char *pRLEBytes, int frame_content_size, int frame_width) +{ + char *v4; // esi + char *v5; // edi + char *v6; // ebx + int v7; // edx + int v8; // eax + int v9; // ST00_4 + char *a3; // [esp+Ch] [ebp-10h] + + if ( pDecodeTo && pRLEBytes && gpBuffer ) + { + a3 = &pLightTbl[256 * light_table_index]; + v4 = pRLEBytes; + v5 = pDecodeTo; + v6 = &pRLEBytes[frame_content_size]; + do + { + v7 = frame_width; + do + { + while ( 1 ) + { + v8 = (unsigned __int8)*v4++; + if ( (v8 & 0x80u) == 0 ) /* check sign */ + break; + _LOBYTE(v8) = -(char)v8; + v5 += v8; + v7 -= v8; + if ( !v7 ) + goto LABEL_13; + } + v7 -= v8; + if ( v5 < (char *)gpBufEnd ) + { + v9 = v7; + Cel2DecDatLightEntry(v8, a3, v5, v4); + v7 = v9; + } + else + { + v4 += v8; + v5 += v8; + } + } + while ( v7 ); +LABEL_13: + v5 += -frame_width - 768; + } + while ( v6 != v4 ); + } +} +// 69BEF8: using guessed type int light_table_index; +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall Cel2DecDatLightEntry(unsigned char shift, char *LightIndex, char *&pDecodeTo, char *&pRLEBytes) +{ + char v5; // cf + unsigned char v6; // cl + char v7; // cl + int v8; // eax + char v9; // ch + int tmp; // eax + char v11; // ch + char v12; // ch + unsigned char a1; + + v5 = shift & 1; + v6 = shift >> 1; + if ( v5 ) + { + a1 = *pRLEBytes; + *pDecodeTo = LightIndex[a1]; + ++pRLEBytes; + ++pDecodeTo; + } + v5 = v6 & 1; + v7 = v6 >> 1; + if ( v5 ) + { + a1 = *pRLEBytes; + *pDecodeTo = LightIndex[a1]; + a1 = pRLEBytes[1]; + pDecodeTo[1] = LightIndex[a1]; + pRLEBytes += 2; + pDecodeTo += 2; + } + for ( ; v7; --v7 ) + { + v8 = *(_DWORD *)pRLEBytes; + pRLEBytes += 4; + a1 = v8; + v9 = LightIndex[a1]; + a1 = BYTE1(v8); + tmp = __ROR4__(v8, 16); + *pDecodeTo = v9; + v11 = LightIndex[a1]; + a1 = tmp; + pDecodeTo[1] = v11; + v12 = LightIndex[a1]; + a1 = BYTE1(tmp); + pDecodeTo[2] = v12; + pDecodeTo[3] = LightIndex[a1]; + pDecodeTo += 4; + } +} + +void __fastcall Cel2DecDatLightTrans(char *pDecodeTo, char *pRLEBytes, int frame_content_size, int frame_width) +{ + char *v4; // esi + unsigned int v5; // edi + char *v6; // ebx + int v7; // edx + unsigned int v8; // eax + unsigned int v10; // ecx + char v11; // cf + unsigned int v12; // ecx + char *v13; // esi + _BYTE *v14; // edi + _BYTE *v18; // edi + unsigned int v21; // ecx + _BYTE *v25; // edi + char *v26; // [esp-4h] [ebp-24h] + char *v27; // [esp+Ch] [ebp-14h] + int v28; // [esp+14h] [ebp-Ch] + int _EAX; + char *_EBX; + + if ( pDecodeTo && pRLEBytes && gpBuffer ) + { + v27 = &pLightTbl[256 * light_table_index]; + v4 = pRLEBytes; + v5 = (unsigned int)pDecodeTo; + v6 = &pRLEBytes[frame_content_size]; + v28 = (unsigned char)pDecodeTo & 1; + do + { + v7 = frame_width; + do + { + while ( 1 ) + { + v8 = (unsigned char)*v4++; + if ( (v8 & 0x80u) != 0 ) + break; + v26 = v6; + _EBX = v27; + v7 -= v8; + if ( v5 < (unsigned int)gpBufEnd ) + { + if ( (v5 & 1) == v28 ) + { + v10 = v8 >> 1; + if ( !(v8 & 1) ) + goto LABEL_13; + ++v4; + ++v5; + if ( v10 ) + { +LABEL_20: + v11 = v10 & 1; + v21 = v10 >> 1; + if ( !v11 ) + goto LABEL_29; + _EAX = *v4; + ASM_XLAT(_EAX,_EBX); + *(_BYTE *)v5 = _EAX; + v4 += 2; + v5 += 2; + if ( v21 ) + { +LABEL_29: + do + { + _EAX = *(_DWORD *)v4; + v4 += 4; + ASM_XLAT(_EAX,_EBX); + *(_BYTE *)v5 = _EAX; + v25 = (_BYTE *)(v5 + 2); + _EAX = __ROR4__(_EAX, 16); + ASM_XLAT(_EAX,_EBX); + *v25 = _EAX; + v5 = (unsigned int)(v25 + 2); + --v21; + } + while ( v21 ); + } + goto LABEL_23; + } + } + else + { + v10 = v8 >> 1; + if ( !(v8 & 1) ) + goto LABEL_20; + _EAX = *v4++; + ASM_XLAT(_EAX,_EBX); + *(_BYTE *)v5++ = _EAX; + if ( v10 ) + { +LABEL_13: + v11 = v10 & 1; + v12 = v10 >> 1; + if ( !v11 ) + goto LABEL_30; + v13 = v4 + 1; + v14 = (_BYTE *)(v5 + 1); + _EAX = *v13; + v4 = v13 + 1; + ASM_XLAT(_EAX,_EBX); + *v14 = _EAX; + v5 = (unsigned int)(v14 + 1); + if ( v12 ) + { +LABEL_30: + do + { + _EAX = *(_DWORD *)v4; + v4 += 4; + v18 = (_BYTE *)(v5 + 1); + _EAX = __ROR4__(_EAX, 8); + ASM_XLAT(_EAX,_EBX); + *v18 = _EAX; + _EAX = __ROR4__(_EAX, 16); + v18 += 2; + ASM_XLAT(_EAX,_EBX); + *v18 = _EAX; + v5 = (unsigned int)(v18 + 1); + --v12; + } + while ( v12 ); + } + goto LABEL_23; + } + } + } + else + { + v4 += v8; + v5 += v8; + } +LABEL_23: + v6 = v26; + if ( !v7 ) + goto LABEL_26; + } + _LOBYTE(v8) = -(char)v8; + v5 += v8; + v7 -= v8; + } + while ( v7 ); +LABEL_26: + v5 -= frame_width + 768; + v28 = ((_BYTE)v28 + 1) & 1; + } + while ( v6 != v4 ); + } +} +// 69BEF8: using guessed type int light_table_index; +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall Cel2DecodeHdrLight(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int a6, int direction) +{ + int v7; // esi + char *v8; // eax + int v9; // edi + char *v10; // edx + int v11; // ebx + int v12; // eax + int v13; // edi + int v14; // eax + char *v15; // edx + char *v16; // ecx + char *cel_buf; // [esp+18h] [ebp+8h] + + v7 = screen_y; + if ( gpBuffer ) + { + v8 = pCelBuff; + if ( pCelBuff ) + { + v9 = *(_DWORD *)&pCelBuff[4 * frame]; + v10 = &pCelBuff[v9]; + v11 = *(unsigned short *)&pCelBuff[v9 + a6]; + cel_buf = (char *)*(unsigned short *)&pCelBuff[v9 + a6]; + if ( v11 ) + { + v12 = *(_DWORD *)&v8[4 * frame + 4] - v9; + v13 = *(unsigned short *)&v10[direction]; + if ( direction == 8 ) + v13 = 0; + if ( v13 ) + v14 = v13 - (_DWORD)cel_buf; + else + v14 = v12 - (_DWORD)cel_buf; + v15 = &v10[(_DWORD)cel_buf]; + v16 = (char *)gpBuffer + screen_y_times_768[v7 - 16 * a6] + screen_x; + if ( light_table_index ) + Cel2DecDatLightOnly(v16, v15, v14, frame_width); + else + Cel2DecDatOnly(v16, v15, v14, frame_width); + } + } + } +} +// 69BEF8: using guessed type int light_table_index; + +void __fastcall Cel2DecodeLightTrans(char *dst_buf, char *pCelBuff, int frame, int frame_width, int a5, int direction) +{ + char *v6; // eax + int v7; // esi + char *v8; // edx + int v9; // ebx + int v10; // eax + int v11; // esi + int v12; // eax + char *v13; // edx + + v6 = pCelBuff; + if ( pCelBuff ) + { + v7 = *(_DWORD *)&pCelBuff[4 * frame]; + v8 = &pCelBuff[v7]; + v9 = *(unsigned short *)&v6[v7 + a5]; + if ( *(_WORD *)&v6[v7 + a5] ) + { + v10 = *(_DWORD *)&v6[4 * frame + 4] - v7; + v11 = *(unsigned short *)&v8[direction]; + if ( direction == 8 ) + v11 = 0; + if ( v11 ) + v12 = v11 - v9; + else + v12 = v10 - v9; + v13 = &v8[v9]; + if ( cel_transparency_active ) + { + Cel2DecDatLightTrans(dst_buf, v13, v12, frame_width); + } + else if ( light_table_index ) + { + Cel2DecDatLightOnly(dst_buf, v13, v12, frame_width); + } + else + { + Cel2DecDatOnly(dst_buf, v13, v12, frame_width); + } + } + } +} +// 69BEF8: using guessed type int light_table_index; +// 69CF94: using guessed type int cel_transparency_active; + +void __fastcall Cel2DrawHdrLightRed(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int always_0, int direction, char always_1) +{ + char *v8; // esi + int v9; // ebx + char *v10; // edi + int v11; // ecx + int v12; // esi + int v13; // eax + int v14; // eax + _BYTE *v15; // esi + _BYTE *v16; // edi + int v17; // ecx + int v18; // edx + int v19; // ecx + int v20; // eax + _BYTE *v21; // [esp-4h] [ebp-14h] + int v22; // [esp+Ch] [ebp-4h] + char *cel_buf; // [esp+18h] [ebp+8h] + char *cel_bufa; // [esp+18h] [ebp+8h] + int framea; // [esp+1Ch] [ebp+Ch] + char *always_0a; // [esp+24h] [ebp+14h] + int directiona; // [esp+28h] [ebp+18h] + + v22 = screen_x; + if ( gpBuffer ) + { + v8 = pCelBuff; + if ( pCelBuff ) + { + v9 = *(_DWORD *)&pCelBuff[4 * frame]; + v10 = &pCelBuff[v9]; + v11 = *(unsigned short *)&pCelBuff[v9 + always_0]; + cel_buf = (char *)*(unsigned short *)&pCelBuff[v9 + always_0]; + if ( v11 ) + { + v12 = *(_DWORD *)&v8[4 * frame + 4] - v9; + if ( direction != 8 && *(_WORD *)&v10[direction] ) + framea = *(unsigned short *)&v10[direction] - (_DWORD)cel_buf; + else + framea = v12 - (_DWORD)cel_buf; + directiona = (int)&v10[(_DWORD)cel_buf]; + always_0a = (char *)gpBuffer + screen_y_times_768[screen_y - 16 * always_0] + v22; + v13 = -(light4flag != 0); + _LOWORD(v13) = v13 & 0xF400; + v14 = v13 + 4096; + if ( always_1 == 2 ) + v14 += 256; + if ( always_1 >= 4 ) + v14 = v14 + (always_1 << 8) - 256; + cel_bufa = &pLightTbl[v14]; + v15 = (_BYTE *)directiona; + v16 = (unsigned char *)always_0a; + v17 = directiona + framea; + do + { + v21 = (_BYTE *)v17; + v18 = frame_width; + v19 = 0; + do + { + while ( 1 ) + { + v20 = (unsigned char)*v15++; + if ( (v20 & 0x80u) == 0 ) + break; + _LOBYTE(v20) = -(char)v20; + v16 += v20; + v18 -= v20; + if ( !v18 ) + goto LABEL_21; + } + v18 -= v20; + if ( v16 < gpBufEnd ) + { + do + { + _LOBYTE(v19) = *v15++; + *v16 = cel_bufa[v19]; + --v20; + ++v16; + } + while ( v20 ); + } + else + { + v15 += v20; + v16 += v20; + } + } + while ( v18 ); +LABEL_21: + v17 = (int)v21; + v16 += -frame_width - 768; + } + while ( v21 != v15 ); + } + } + } +} +// 525728: using guessed type int light4flag; +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall CelDecodeRect(char *pBuff, int always_0, int dst_height, int dst_width, char *pCelBuff, int frame, int frame_width) +{ + char *v7; // ebx + char *v8; // esi + char *v9; // edi + int v10; // ebx + int v11; // edx + unsigned int v12; // eax + unsigned int v13; // ecx + char v14; // cf + unsigned int v15; // ecx + int dst_widtha; // [esp+14h] [ebp+Ch] + + if ( pCelBuff && pBuff ) + { + v7 = &pCelBuff[4 * frame]; + v8 = &pCelBuff[*(_DWORD *)v7]; + v9 = &pBuff[dst_width * dst_height + always_0]; + dst_widtha = frame_width + dst_width; + v10 = (int)&v8[*((_DWORD *)v7 + 1) - *(_DWORD *)v7]; + do + { + v11 = frame_width; + do + { + while ( 1 ) + { + v12 = (unsigned char)*v8++; + if ( (v12 & 0x80u) == 0 ) + break; + _LOBYTE(v12) = -(char)v12; + v9 += v12; + v11 -= v12; + if ( !v11 ) + goto LABEL_14; + } + v11 -= v12; + v13 = v12 >> 1; + if ( v12 & 1 ) + { + *v9++ = *v8++; + if ( !v13 ) + continue; + } + v14 = v13 & 1; + v15 = v12 >> 2; + if ( v14 ) + { + *(_WORD *)v9 = *(_WORD *)v8; + v8 += 2; + v9 += 2; + if ( !v15 ) + continue; + } + qmemcpy(v9, v8, 4 * v15); + v8 += 4 * v15; + v9 += 4 * v15; + } + while ( v11 ); +LABEL_14: + v9 -= dst_widtha; + } + while ( (char *)v10 != v8 ); + } +} + +void __fastcall CelDecodeClr(BYTE colour, int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int a7, int direction) +{ + char *v8; // ebx + int v9; // eax + char *v10; // esi + char *v11; // edi + int v12; // edx + int v13; // eax + int v14; // ecx + char v15; // al + int v16; // [esp+Ch] [ebp-10h] + char *v17; // [esp+10h] [ebp-Ch] + int v18; // [esp+14h] [ebp-8h] + char v19; // [esp+18h] [ebp-4h] + + v19 = colour; + if ( pCelBuff ) + { + if ( gpBuffer ) + { + v8 = &pCelBuff[4 * frame]; + v17 = &pCelBuff[*(_DWORD *)v8]; + v16 = *(unsigned short *)&v17[a7]; + if ( *(_WORD *)&v17[a7] ) + { + if ( direction == 8 ) + v9 = 0; + else + v9 = *(unsigned short *)&v17[direction]; + if ( v9 ) + v18 = v9 - v16; + else + v18 = *((_DWORD *)v8 + 1) - *(_DWORD *)v8 - v16; + v10 = &v17[v16]; + v11 = (char *)gpBuffer + screen_y_times_768[screen_y - 16 * a7] + screen_x; + do + { + v12 = frame_width; + do + { + while ( 1 ) + { + v13 = (unsigned char)*v10++; + if ( (v13 & 0x80u) == 0 ) + break; + _LOBYTE(v13) = -(char)v13; + v11 += v13; + v12 -= v13; + if ( !v12 ) + goto LABEL_20; + } + v12 -= v13; + v14 = v13; + do + { + v15 = *v10++; + if ( v15 ) + { + *(v11 - 768) = v19; + *(v11 - 1) = v19; + v11[1] = v19; + v11[768] = v19; + } + ++v11; + --v14; + } + while ( v14 ); + } + while ( v12 ); +LABEL_20: + v11 += -frame_width - 768; + } + while ( &v17[v16 + v18] != v10 ); + } + } + } +} + +void __fastcall CelDrawHdrClrHL(char colour, int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int a7, int direction) +{ + char *v8; // ebx + int v9; // eax + char *v10; // esi + char *v11; // edi + int v12; // edx + int v13; // eax + int v14; // ecx + char v15; // al + int v16; // ecx + char v17; // al + int v18; // [esp+Ch] [ebp-10h] + char *v19; // [esp+10h] [ebp-Ch] + int v20; // [esp+14h] [ebp-8h] + char v21; // [esp+18h] [ebp-4h] + + v21 = colour; + if ( pCelBuff ) + { + if ( gpBuffer ) + { + v8 = &pCelBuff[4 * frame]; + v19 = &pCelBuff[*(_DWORD *)v8]; + v18 = *(unsigned short *)&v19[a7]; + if ( *(_WORD *)&v19[a7] ) + { + if ( direction == 8 ) + v9 = 0; + else + v9 = *(unsigned short *)&v19[direction]; + if ( v9 ) + v20 = v9 - v18; + else + v20 = *((_DWORD *)v8 + 1) - *(_DWORD *)v8 - v18; + v10 = &v19[v18]; + v11 = (char *)gpBuffer + screen_y_times_768[screen_y - 16 * a7] + screen_x; + do + { + v12 = frame_width; + do + { + while ( 1 ) + { + v13 = (unsigned char)*v10++; + if ( (v13 & 0x80u) == 0 ) + break; + _LOBYTE(v13) = -(char)v13; + v11 += v13; + v12 -= v13; + if ( !v12 ) + goto LABEL_28; + } + v12 -= v13; + if ( v11 < (char *)gpBufEnd ) + { + if ( v11 >= (char *)gpBufEnd - 768 ) + { + v16 = v13; + do + { + v17 = *v10++; + if ( v17 ) + { + *(v11 - 768) = v21; + *(v11 - 1) = v21; + v11[1] = v21; + } + ++v11; + --v16; + } + while ( v16 ); + } + else + { + v14 = v13; + do + { + v15 = *v10++; + if ( v15 ) + { + *(v11 - 768) = v21; + *(v11 - 1) = v21; + v11[1] = v21; + v11[768] = v21; + } + ++v11; + --v14; + } + while ( v14 ); + } + } + else + { + v10 += v13; + v11 += v13; + } + } + while ( v12 ); +LABEL_28: + v11 += -frame_width - 768; + } + while ( &v19[v18 + v20] != v10 ); + } + } + } +} +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall ENG_set_pixel(int screen_x, int screen_y, char pixel) +{ + char *v3; // edi + + if ( screen_y >= 0 && screen_y < 640 && screen_x >= 64 && screen_x < 704 ) + { + v3 = (char *)gpBuffer + screen_y_times_768[screen_y] + screen_x; + if ( v3 < (char *)gpBufEnd ) + *v3 = pixel; + } +} +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall engine_draw_pixel(int x, int y) +{ + _BYTE *v2; // eax + + if ( dword_52B970 ) + { + if ( !dword_52B99C || x >= 0 && x < 640 && y >= 64 && y < 704 ) + { + v2 = (unsigned char *)gpBuffer + screen_y_times_768[x] + y; + goto LABEL_14; + } + } + else if ( !dword_52B99C || y >= 0 && y < 640 && x >= 64 && x < 704 ) + { + v2 = (unsigned char *)gpBuffer + screen_y_times_768[y] + x; +LABEL_14: + if ( v2 < gpBufEnd ) + *v2 = gbPixelCol; + return; + } +} +// 52B96C: using guessed type char gbPixelCol; +// 52B970: using guessed type int dword_52B970; +// 52B99C: using guessed type int dword_52B99C; +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall DrawLine(int x0, int y0, int x1, int y1, char col) +{ + int v5; // ST18_4 + int v6; // ST2C_4 + int v7; // ST20_4 + int v8; // [esp+Ch] [ebp-48h] + int v9; // [esp+10h] [ebp-44h] + int v10; // [esp+14h] [ebp-40h] + int v11; // [esp+18h] [ebp-3Ch] + signed int v12; // [esp+1Ch] [ebp-38h] + int v13; // [esp+20h] [ebp-34h] + int v14; // [esp+24h] [ebp-30h] + int v15; // [esp+28h] [ebp-2Ch] + int y; // [esp+2Ch] [ebp-28h] + int ya; // [esp+2Ch] [ebp-28h] + int yb; // [esp+2Ch] [ebp-28h] + int yc; // [esp+2Ch] [ebp-28h] + int j; // [esp+30h] [ebp-24h] + int i; // [esp+30h] [ebp-24h] + int x; // [esp+34h] [ebp-20h] + int xa; // [esp+34h] [ebp-20h] + int xb; // [esp+34h] [ebp-20h] + int xc; // [esp+34h] [ebp-20h] + int xd; // [esp+34h] [ebp-20h] + int xe; // [esp+34h] [ebp-20h] + int xf; // [esp+34h] [ebp-20h] + int xg; // [esp+34h] [ebp-20h] + int xh; // [esp+34h] [ebp-20h] + int v31; // [esp+38h] [ebp-1Ch] + int v32; // [esp+3Ch] [ebp-18h] + int v33; // [esp+3Ch] [ebp-18h] + int v34; // [esp+3Ch] [ebp-18h] + signed int v35; // [esp+40h] [ebp-14h] + signed int v36; // [esp+44h] [ebp-10h] + int v37; // [esp+48h] [ebp-Ch] + int v38; // [esp+48h] [ebp-Ch] + int v39; // [esp+4Ch] [ebp-8h] + int v40; // [esp+4Ch] [ebp-8h] + int v41; // [esp+50h] [ebp-4h] + int x2a; // [esp+5Ch] [ebp+8h] + + v8 = y0; + v9 = x0; + gbPixelCol = col; + dword_52B99C = 0; + if ( x0 < 64 || x0 >= 704 ) + dword_52B99C = 1; + if ( x1 < 64 || x1 >= 704 ) + dword_52B99C = 1; + if ( y0 < 160 || y0 >= 512 ) + dword_52B99C = 1; + if ( y1 < 160 || y1 >= 512 ) + dword_52B99C = 1; + if ( x1 - x0 < 0 ) + v36 = -1; + else + v36 = 1; + v11 = v36 * (x1 - x0); + if ( y1 - y0 < 0 ) + v35 = -1; + else + v35 = 1; + v10 = v35 * (y1 - y0); + if ( v35 == v36 ) + v12 = 1; + else + v12 = -1; + if ( v11 >= v10 ) + { + dword_52B970 = 0; + } + else + { + v8 = y0 ^ x0 ^ y0; + v9 = v8 ^ y0 ^ x0; + x2a = y1 ^ x1; + y1 ^= x2a; + x1 = y1 ^ x2a; + v5 = v10 ^ v11; + v10 ^= v5; + v11 = v10 ^ v5; + dword_52B970 = 1; + } + if ( x1 >= v9 ) + { + x = v9; + y = v8; + v32 = x1; + v13 = y1; + } + else + { + x = x1; + y = y1; + v32 = v9; + v13 = v8; + } + v31 = (v11 - 1) / 4; + v41 = (v11 - 1) % 4; /* (((v11 - 1) >> 31) ^ abs(v11 - 1) & 3) - ((v11 - 1) >> 31) */ + engine_draw_pixel(x, y); + engine_draw_pixel(v32, v13); + v14 = 4 * v10 - 2 * v11; + if ( v14 >= 0 ) + { + v40 = 2 * (v10 - v11); + v15 = 4 * (v10 - v11); + v38 = v15 + v11; + for ( i = 0; i < v31; ++i ) + { + xe = x + 1; + v34 = v32 - 1; + if ( v38 <= 0 ) + { + if ( v40 <= v38 ) + { + y += v12; + engine_draw_pixel(xe, y); + x = xe + 1; + engine_draw_pixel(x, y); + v13 -= v12; + engine_draw_pixel(v34, v13); + } + else + { + engine_draw_pixel(xe, y); + y += v12; + x = xe + 1; + engine_draw_pixel(x, y); + engine_draw_pixel(v34, v13); + v13 -= v12; + } + v32 = v34 - 1; + engine_draw_pixel(v32, v13); + v38 += v14; + } + else + { + v6 = v12 + y; + engine_draw_pixel(xe, v6); + y = v12 + v6; + x = xe + 1; + engine_draw_pixel(x, y); + v7 = v13 - v12; + engine_draw_pixel(v34, v7); + v13 = v7 - v12; + v32 = v34 - 1; + engine_draw_pixel(v32, v13); + v38 += v15; + } + } + if ( v41 ) + { + if ( v38 <= 0 ) + { + if ( v40 <= v38 ) + { + yc = v12 + y; + xh = x + 1; + engine_draw_pixel(xh, yc); + if ( v41 > 1 ) + engine_draw_pixel(xh + 1, yc); + if ( v41 > 2 ) + { + if ( v40 >= v38 ) + engine_draw_pixel(v32 - 1, v13); + else + engine_draw_pixel(v32 - 1, v13 - v12); + } + } + else + { + xg = x + 1; + engine_draw_pixel(xg, y); + if ( v41 > 1 ) + engine_draw_pixel(xg + 1, v12 + y); + if ( v41 > 2 ) + engine_draw_pixel(v32 - 1, v13); + } + } + else + { + yb = v12 + y; + xf = x + 1; + engine_draw_pixel(xf, yb); + if ( v41 > 1 ) + engine_draw_pixel(xf + 1, v12 + yb); + if ( v41 > 2 ) + engine_draw_pixel(v32 - 1, v13 - v12); + } + } + } + else + { + v39 = 2 * v10; + v37 = 4 * v10 - v11; + for ( j = 0; j < v31; ++j ) + { + xa = x + 1; + v33 = v32 - 1; + if ( v37 >= 0 ) + { + if ( v39 <= v37 ) + { + y += v12; + engine_draw_pixel(xa, y); + x = xa + 1; + engine_draw_pixel(x, y); + v13 -= v12; + engine_draw_pixel(v33, v13); + } + else + { + engine_draw_pixel(xa, y); + y += v12; + x = xa + 1; + engine_draw_pixel(x, y); + engine_draw_pixel(v33, v13); + v13 -= v12; + } + v32 = v33 - 1; + engine_draw_pixel(v32, v13); + v37 += v14; + } + else + { + engine_draw_pixel(xa, y); + x = xa + 1; + engine_draw_pixel(x, y); + engine_draw_pixel(v33, v13); + v32 = v33 - 1; + engine_draw_pixel(v32, v13); + v37 += 4 * v10; + } + } + if ( v41 ) + { + if ( v37 >= 0 ) + { + if ( v39 <= v37 ) + { + ya = v12 + y; + xd = x + 1; + engine_draw_pixel(xd, ya); + if ( v41 > 1 ) + engine_draw_pixel(xd + 1, ya); + if ( v41 > 2 ) + engine_draw_pixel(v32 - 1, v13 - v12); + } + else + { + xc = x + 1; + engine_draw_pixel(xc, y); + if ( v41 > 1 ) + engine_draw_pixel(xc + 1, v12 + y); + if ( v41 > 2 ) + engine_draw_pixel(v32 - 1, v13); + } + } + else + { + xb = x + 1; + engine_draw_pixel(xb, y); + if ( v41 > 1 ) + engine_draw_pixel(xb + 1, y); + if ( v41 > 2 ) + engine_draw_pixel(v32 - 1, v13); + } + } + } +} +// 52B96C: using guessed type char gbPixelCol; +// 52B970: using guessed type int dword_52B970; +// 52B99C: using guessed type int dword_52B99C; + +int __fastcall GetDirection(int x1, int y1, int x2, int y2) +{ + int v4; // esi + int v5; // ecx + int v6; // edx + int result; // eax + int v8; // esi + int v9; // edx + + v4 = x2 - x1; + v5 = y2 - y1; + if ( v4 < 0 ) + { + v8 = -v4; + v9 = 2 * v8; + if ( v5 < 0 ) + { + v5 = -v5; + result = 4; + if ( v9 < v5 ) + result = 5; + } + else + { + result = 2; + if ( v9 < v5 ) + result = 1; + } + if ( 2 * v5 < v8 ) + return 3; + } + else + { + v6 = 2 * v4; + if ( v5 < 0 ) + { + v5 = -v5; + result = 6; + if ( v6 < v5 ) + result = 5; + } + else + { + result = 0; + if ( v6 < v5 ) + result = 1; + } + if ( 2 * v5 < v4 ) + return 7; + } + return result; +} + +void __fastcall SetRndSeed(int s) +{ + SeedCount = 0; + sglGameSeed = s; + orgseed = s; +} +// 52B974: using guessed type int orgseed; +// 52B97C: using guessed type int sglGameSeed; +// 52B998: using guessed type int SeedCount; + +int __cdecl GetRndSeed() +{ + ++SeedCount; + sglGameSeed = 0x015A4E35 * sglGameSeed + 1; + return abs(sglGameSeed); +} +// 52B97C: using guessed type int sglGameSeed; +// 52B998: using guessed type int SeedCount; + +int __fastcall random(BYTE idx, int v) +{ + if ( v <= 0 ) + return 0; + if ( v >= 0xFFFF ) + return GetRndSeed() % v; + return (GetRndSeed() >> 16) % v; +} + +#ifndef MINIWIN +struct engine_cpp_init_2 +{ + engine_cpp_init_2() + { + mem_init_mutex(); + mem_atexit_mutex(); + } +} _engine_cpp_init_2; +#endif + +void __cdecl mem_init_mutex() +{ + InitializeCriticalSection(&sgMemCrit); +} + +void __cdecl mem_atexit_mutex() +{ + atexit(mem_free_mutex); +} + +void __cdecl mem_free_mutex() +{ + DeleteCriticalSection(&sgMemCrit); +} + +unsigned char *__fastcall DiabloAllocPtr(int dwBytes) +{ + int v1; // ebx + unsigned char *v2; // ebx + int v3; // eax + + v1 = dwBytes; + EnterCriticalSection(&sgMemCrit); + v2 = (unsigned char *)SMemAlloc(v1, "C:\\Src\\Diablo\\Source\\ENGINE.CPP", 2236, 0); + LeaveCriticalSection(&sgMemCrit); + if ( !v2 ) + { + v3 = GetLastError(); + ErrDlg(IDD_DIALOG2, v3, "C:\\Src\\Diablo\\Source\\ENGINE.CPP", 2269); + } + return v2; +} + +void __fastcall mem_free_dbg(void *p) +{ + void *v1; // edi + + v1 = p; + if ( p ) + { + EnterCriticalSection(&sgMemCrit); + SMemFree(v1, "C:\\Src\\Diablo\\Source\\ENGINE.CPP", 2317, 0); + LeaveCriticalSection(&sgMemCrit); + } +} + +unsigned char *__fastcall LoadFileInMem(char *pszName, int *pdwFileLen) +{ + int *v2; // edi + char *v3; // ebx + int v4; // eax + int v5; // esi + char *v6; // edi + void *a1; // [esp+Ch] [ebp-4h] + + v2 = pdwFileLen; + v3 = pszName; + WOpenFile(pszName, &a1, 0); + v4 = WGetFileSize(a1, 0); + v5 = v4; + if ( v2 ) + *v2 = v4; + if ( !v4 ) + TermMsg("Zero length SFILE:\n%s", v3); + v6 = (char *)DiabloAllocPtr(v5); + WReadFile(a1, v6, v5); + WCloseFile(a1); + return (unsigned char *)v6; +} + +void __fastcall LoadFileWithMem(char *pszName, void *buf) +{ + char *v2; // ebx + char *v3; // edi + int v4; // esi + void *a1; // [esp+Ch] [ebp-4h] + + v2 = (char *)buf; + v3 = pszName; + if ( !buf ) + TermMsg("LoadFileWithMem(NULL):\n%s", pszName); + WOpenFile(v3, &a1, 0); + v4 = WGetFileSize(a1, 0); + if ( !v4 ) + TermMsg("Zero length SFILE:\n%s", v3); + WReadFile(a1, v2, v4); + WCloseFile(a1); +} + +void __fastcall Cl2ApplyTrans(unsigned char *p, unsigned char *ttbl, int last_frame) +{ + int v3; // eax + int v4; // edi + int v5; // esi + unsigned char *v6; // eax + char v7; // bl + unsigned char v8; // bl + int v9; // edi + int i; // [esp+0h] [ebp-4h] + + v3 = 1; + for ( i = 1; i <= last_frame; ++i ) + { + v4 = *(_DWORD *)&p[4 * v3]; + v5 = *(_DWORD *)&p[4 * v3 + 4] - v4 - 10; + v6 = &p[v4 + 10]; + while ( v5 ) + { + v7 = *v6++; + --v5; + if ( v7 < 0 ) + { + v8 = -v7; + if ( (char)v8 <= 65 ) + { + v5 -= (char)v8; + if ( v8 ) + { + v9 = v8; + do + { + *v6 = ttbl[*v6]; + ++v6; + --v9; + } + while ( v9 ); + } + } + else + { + --v5; + *v6 = ttbl[*v6]; + ++v6; + } + } + } + v3 = i + 1; + } +} + +void __fastcall Cl2DecodeFrm1(int x, int y, char *pCelBuff, int nCel, int width, int dir1, int dir2) +{ + char *v8; // edx + char *v9; // ecx + int v10; // ecx + int v11; // eax + char *pCelBuffa; // [esp+18h] [ebp+8h] + + if ( gpBuffer ) + { + v8 = pCelBuff; + if ( pCelBuff ) + { + if ( nCel > 0 ) + { + v9 = *(char **)&pCelBuff[4 * nCel]; + pCelBuffa = v9; + v10 = (int)&v9[(_DWORD)v8]; + if ( *(_WORD *)(v10 + dir1) ) + { + if ( dir2 == 8 || (v11 = *(unsigned short *)(v10 + dir2), !*(_WORD *)(v10 + dir2)) ) + v11 = *((_DWORD *)v8 + nCel + 1) - (_DWORD)pCelBuffa; + Cl2DecDatFrm1( + (char *)gpBuffer + screen_y_times_768[y - 16 * dir1] + x, + (char *)(*(unsigned short *)(v10 + dir1) + v10), + v11 - *(unsigned short *)(v10 + dir1), + width); + } + } + } + } +} + +void __fastcall Cl2DecDatFrm1(char *buffer, char *frame_content, int a3, int width) /* fix */ +{ + char *v4; // esi + char *v5; // edi + int v6; // eax + int v7; // ebx + int v8; // ecx + char v9; // dl + char v10; // dl + int v11; // edx + + v4 = frame_content; + v5 = buffer; + v6 = 0; + v7 = width; + v8 = a3; + do + { + _LOBYTE(v6) = *v4++; + --v8; + if ( (v6 & 0x80u) == 0 ) + { + do + { + if ( v6 <= v7 ) + { + v11 = v6; + v5 += v6; + v6 = 0; + } + else + { + v11 = v7; + v5 += v7; + v6 -= v7; + } + v7 -= v11; + if ( !v7 ) + { + v7 = width; + v5 = &v5[-width - 768]; + } + } + while ( v6 ); + } + else + { + _LOBYTE(v6) = -(char)v6; + if ( (char)v6 <= 65 ) + { + v8 -= v6; + v7 -= v6; + do + { + v10 = *v4++; + *v5 = v10; + --v6; + ++v5; + } + while ( v6 ); + } + else + { + _LOBYTE(v6) = v6 - 65; + --v8; + v9 = *v4++; + v7 -= v6; + do + { + *v5 = v9; + --v6; + ++v5; + } + while ( v6 ); + } + if ( !v7 ) + { + v7 = width; + v5 = &v5[-width - 768]; + } + } + } + while ( v8 ); +} + +void __fastcall Cl2DecodeFrm2(char colour, int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a7, int a8) +{ + int v8; // ebx + char *v9; // edx + int v10; // eax + int v11; // [esp+Ch] [ebp-8h] + + v11 = screen_x; + if ( gpBuffer ) + { + if ( pCelBuff ) + { + if ( nCel > 0 ) + { + v8 = *(_DWORD *)&pCelBuff[4 * nCel]; + v9 = &pCelBuff[v8]; + if ( *(_WORD *)&pCelBuff[v8 + a7] ) + { + if ( a8 == 8 || (v10 = *(unsigned short *)&v9[a8], !*(_WORD *)&v9[a8]) ) + v10 = *(_DWORD *)&pCelBuff[4 * nCel + 4] - v8; + Cl2DecDatFrm2( + (char *)gpBuffer + screen_y_times_768[screen_y - 16 * a7] + v11, + &v9[*(unsigned short *)&pCelBuff[v8 + a7]], + v10 - *(unsigned short *)&pCelBuff[v8 + a7], + frame_width, + colour); + } + } + } + } +} + +void __fastcall Cl2DecDatFrm2(char *buffer, char *frame_content, int a3, int frame_width, char colour) +{ + char *v5; // esi + char *v6; // edi + int v7; // eax + int v8; // ebx + int v9; // ecx + char v10; // dl + char v11; // dh + char v12; // dh + int v13; // edx + + v5 = frame_content; + v6 = buffer; + v7 = 0; + v8 = frame_width; + v9 = a3; + v10 = colour; + do + { + _LOBYTE(v7) = *v5++; + --v9; + if ( (v7 & 0x80u) != 0 ) + { + _LOBYTE(v7) = -(char)v7; + if ( (char)v7 <= 65 ) + { + v9 -= v7; + v8 -= v7; + do + { + v12 = *v5++; + if ( v12 ) + { + *(v6 - 1) = v10; + v6[1] = v10; + *(v6 - 768) = v10; + v6[768] = v10; + } + --v7; + ++v6; + } + while ( v7 ); + goto LABEL_12; + } + _LOBYTE(v7) = v7 - 65; + --v9; + v11 = *v5++; + if ( v11 ) + { + *(v6 - 1) = v10; + v8 -= v7; + v6[v7] = v10; + do + { + *(v6 - 768) = v10; + v6[768] = v10; + --v7; + ++v6; + } + while ( v7 ); +LABEL_12: + if ( !v8 ) + { + v8 = frame_width; + v6 = &v6[-frame_width - 768]; + } + continue; + } + } + do + { + if ( v7 <= v8 ) + { + v13 = v7; + v6 += v7; + v7 = 0; + } + else + { + v13 = v8; + v6 += v8; + v7 -= v8; + } + v8 -= v13; + if ( !v8 ) + { + v8 = frame_width; + v6 = &v6[-frame_width - 768]; + } + } + while ( v7 ); + v10 = colour; + } + while ( v9 ); +} + +void __fastcall Cl2DecodeFrm3(int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a6, int a7, char a8) +{ + char *v8; // edi + int v9; // ebx + char *v10; // esi + int v11; // eax + int v12; // eax + char *v13; // esi + int v14; // edi + int v15; // eax + int v16; // eax + char *pCelBuffa; // [esp+18h] [ebp+8h] + + if ( gpBuffer ) + { + v8 = pCelBuff; + if ( pCelBuff ) + { + if ( nCel > 0 ) + { + v9 = *(_DWORD *)&pCelBuff[4 * nCel]; + v10 = &pCelBuff[v9]; + v11 = *(unsigned short *)&pCelBuff[v9 + a6]; + pCelBuffa = (char *)*(unsigned short *)&pCelBuff[v9 + a6]; + if ( v11 ) + { + if ( a7 == 8 || (v12 = *(unsigned short *)&v10[a7], !*(_WORD *)&v10[a7]) ) + v12 = *(_DWORD *)&v8[4 * nCel + 4] - v9; + v13 = &v10[(_DWORD)pCelBuffa]; + v14 = v12 - (_DWORD)pCelBuffa; + v15 = -(light4flag != 0); + _LOWORD(v15) = v15 & 0xF400; + v16 = v15 + 4096; + if ( a8 == 2 ) + v16 += 256; + if ( a8 >= 4 ) + v16 = v16 + (a8 << 8) - 256; + Cl2DecDatLightTbl1( + (char *)gpBuffer + screen_y_times_768[screen_y - 16 * a6] + screen_x, + v13, + v14, + frame_width, + &pLightTbl[v16]); + } + } + } + } +} +// 525728: using guessed type int light4flag; + +void __fastcall Cl2DecDatLightTbl1(char *a1, char *a2, int a3, int a4, char *unused_lindex) /* check 5th arg */ +{ + char *v5; // esi + char *v6; // edi + int v7; // ebx + int v8; // ecx + int v9; // eax + int v10; // edx + char v11; // dl + + v5 = a2; + v6 = a1; + v7 = a4; + v8 = a3; + sgnWidth = a4; + v9 = 0; + v10 = 0; + do + { + _LOBYTE(v9) = *v5++; + --v8; + if ( (v9 & 0x80u) == 0 ) + { + do + { + if ( v9 <= v7 ) + { + v10 = v9; + v6 += v9; + v9 = 0; + } + else + { + v10 = v7; + v6 += v7; + v9 -= v7; + } + v7 -= v10; + if ( !v7 ) + { + v7 = sgnWidth; + v6 = &v6[-sgnWidth - 768]; + } + } + while ( v9 ); + } + else + { + _LOBYTE(v9) = -(char)v9; + if ( (char)v9 <= 65 ) + { + v8 -= v9; + v7 -= v9; + do + { + _LOBYTE(v10) = *v5++; + *v6 = unused_lindex[v10]; + --v9; + ++v6; + } + while ( v9 ); + } + else + { + _LOBYTE(v9) = v9 - 65; + --v8; + v7 -= v9; + _LOBYTE(v10) = *v5++; + v11 = unused_lindex[v10]; + do + { + *v6 = v11; + --v9; + ++v6; + } + while ( v9 ); + } + if ( !v7 ) + { + v7 = sgnWidth; + v6 = &v6[-sgnWidth - 768]; + } + } + } + while ( v8 ); +} +// 52B978: using guessed type int sgnWidth; + +void __fastcall Cl2DecodeLightTbl(int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a6, int a7) +{ + int v7; // esi + char *v8; // edi + int v9; // ebx + char *v10; // edx + int v11; // eax + int v12; // eax + int v13; // eax + char *v14; // edx + char *v15; // ecx + char *pCelBuffa; // [esp+18h] [ebp+8h] + + v7 = screen_y; + if ( gpBuffer ) + { + v8 = pCelBuff; + if ( pCelBuff ) + { + if ( nCel > 0 ) + { + v9 = *(_DWORD *)&pCelBuff[4 * nCel]; + v10 = &pCelBuff[v9]; + v11 = *(unsigned short *)&pCelBuff[v9 + a6]; + pCelBuffa = (char *)*(unsigned short *)&pCelBuff[v9 + a6]; + if ( v11 ) + { + if ( a7 == 8 || (v12 = *(unsigned short *)&v10[a7], !*(_WORD *)&v10[a7]) ) + v12 = *(_DWORD *)&v8[4 * nCel + 4] - v9; + v13 = v12 - (_DWORD)pCelBuffa; + v14 = &v10[(_DWORD)pCelBuffa]; + v15 = (char *)gpBuffer + screen_y_times_768[v7 - 16 * a6] + screen_x; + if ( light_table_index ) + Cl2DecDatLightTbl1( + v15, + v14, + v13, + frame_width, + &pLightTbl[256 * light_table_index]); + else + Cl2DecDatFrm1(v15, v14, v13, frame_width); + } + } + } + } +} +// 69BEF8: using guessed type int light_table_index; + +void __fastcall Cl2DecodeFrm4(int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a6, int a7) +{ + int v7; // ebx + char *v8; // edx + char *v9; // ecx + int v10; // ecx + int v11; // eax + int v12; // [esp+Ch] [ebp-4h] + char *pCelBuffa; // [esp+18h] [ebp+8h] + + v7 = screen_y; + v12 = screen_x; + if ( gpBuffer ) + { + v8 = pCelBuff; + if ( pCelBuff ) + { + if ( nCel > 0 ) + { + v9 = *(char **)&pCelBuff[4 * nCel]; + pCelBuffa = v9; + v10 = (int)&v9[(_DWORD)v8]; + if ( *(_WORD *)(v10 + a6) ) + { + if ( a7 == 8 || (v11 = *(unsigned short *)(v10 + a7), !*(_WORD *)(v10 + a7)) ) + v11 = *(_DWORD *)&v8[4 * nCel + 4] - (_DWORD)pCelBuffa; + Cl2DecDatFrm4( + (char *)gpBuffer + screen_y_times_768[v7 - 16 * a6] + v12, + (char *)(*(unsigned short *)(v10 + a6) + v10), + v11 - *(unsigned short *)(v10 + a6), + frame_width); + } + } + } + } +} + +void __fastcall Cl2DecDatFrm4(char *buffer, char *a2, int a3, int frame_width) +{ + char *v4; // esi + char *v5; // edi + int v6; // eax + int v7; // ebx + int v8; // ecx + char v9; // dl + char v10; // dl + int v11; // edx + + v4 = a2; + v5 = buffer; + v6 = 0; + v7 = frame_width; + v8 = a3; + do + { + _LOBYTE(v6) = *v4++; + --v8; + if ( (v6 & 0x80u) != 0 ) + { + _LOBYTE(v6) = -(char)v6; + if ( (char)v6 <= 65 ) + { + v8 -= v6; + if ( v5 < (char *)gpBufEnd ) + { + v7 -= v6; + do + { + v10 = *v4++; + *v5 = v10; + --v6; + ++v5; + } + while ( v6 ); + goto LABEL_12; + } + v4 += v6; + } + else + { + _LOBYTE(v6) = v6 - 65; + --v8; + v9 = *v4++; + if ( v5 < (char *)gpBufEnd ) + { + v7 -= v6; + do + { + *v5 = v9; + --v6; + ++v5; + } + while ( v6 ); +LABEL_12: + if ( !v7 ) + { + v7 = frame_width; + v5 = &v5[-frame_width - 768]; + } + continue; + } + } + } + do + { + if ( v6 <= v7 ) + { + v11 = v6; + v5 += v6; + v6 = 0; + } + else + { + v11 = v7; + v5 += v7; + v6 -= v7; + } + v7 -= v11; + if ( !v7 ) + { + v7 = frame_width; + v5 = &v5[-frame_width - 768]; + } + } + while ( v6 ); + } + while ( v8 ); +} +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall Cl2DecodeClrHL(char colour, int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a7, int a8) +{ + int v8; // ebx + char *v9; // edx + int v10; // ecx + int v11; // eax + int v12; // [esp+Ch] [ebp-8h] + char a5; // [esp+10h] [ebp-4h] + + v12 = screen_x; + a5 = colour; + if ( gpBuffer ) + { + if ( pCelBuff ) + { + if ( nCel > 0 ) + { + v8 = *(_DWORD *)&pCelBuff[4 * nCel]; + v9 = &pCelBuff[v8]; + v10 = *(unsigned short *)&pCelBuff[v8 + a7]; + if ( *(_WORD *)&pCelBuff[v8 + a7] ) + { + if ( a8 == 8 || (v11 = *(unsigned short *)&v9[a8], !*(_WORD *)&v9[a8]) ) + v11 = *(_DWORD *)&pCelBuff[4 * nCel + 4] - v8; + gpBufEnd -= 768; + Cl2DecDatClrHL( + (char *)gpBuffer + screen_y_times_768[screen_y - 16 * a7] + v12, + &v9[v10], + v11 - v10, + frame_width, + a5); + gpBufEnd += 768; + } + } + } + } +} +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall Cl2DecDatClrHL(char *dst_buf, char *frame_content, int a3, int frame_width, char colour) +{ + char *v5; // esi + char *v6; // edi + int v7; // eax + int v8; // ebx + int v9; // ecx + char v10; // dl + char v11; // dh + char v12; // dh + int v13; // edx + + v5 = frame_content; + v6 = dst_buf; + v7 = 0; + v8 = frame_width; + v9 = a3; + v10 = colour; + do + { + _LOBYTE(v7) = *v5++; + --v9; + if ( (v7 & 0x80u) != 0 ) + { + _LOBYTE(v7) = -(char)v7; + if ( (char)v7 <= 65 ) + { + v9 -= v7; + if ( v6 < (char *)gpBufEnd ) + { + v8 -= v7; + do + { + v12 = *v5++; + if ( v12 ) + { + *(v6 - 1) = v10; + v6[1] = v10; + *(v6 - 768) = v10; + v6[768] = v10; + } + --v7; + ++v6; + } + while ( v7 ); + goto LABEL_15; + } + v5 += v7; + } + else + { + _LOBYTE(v7) = v7 - 65; + --v9; + v11 = *v5++; + if ( v11 && v6 < (char *)gpBufEnd ) + { + *(v6 - 1) = v10; + v8 -= v7; + v6[v7] = v10; + do + { + *(v6 - 768) = v10; + v6[768] = v10; + --v7; + ++v6; + } + while ( v7 ); +LABEL_15: + if ( !v8 ) + { + v8 = frame_width; + v6 = &v6[-frame_width - 768]; + } + continue; + } + } + } + do + { + if ( v7 <= v8 ) + { + v13 = v7; + v6 += v7; + v7 = 0; + } + else + { + v13 = v8; + v6 += v8; + v7 -= v8; + } + v8 -= v13; + if ( !v8 ) + { + v8 = frame_width; + v6 = &v6[-frame_width - 768]; + } + } + while ( v7 ); + v10 = colour; + } + while ( v9 ); +} +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall Cl2DecodeFrm5(int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a6, int a7, char a8) +{ + char *v8; // edi + int v9; // ebx + char *v10; // esi + int v11; // eax + int v12; // eax + char *v13; // esi + int v14; // edi + int v15; // eax + int v16; // eax + char *pCelBuffa; // [esp+18h] [ebp+8h] + + if ( gpBuffer ) + { + v8 = pCelBuff; + if ( pCelBuff ) + { + if ( nCel > 0 ) + { + v9 = *(_DWORD *)&pCelBuff[4 * nCel]; + v10 = &pCelBuff[v9]; + v11 = *(unsigned __int16 *)&pCelBuff[v9 + a6]; + pCelBuffa = (char *)*(unsigned __int16 *)&pCelBuff[v9 + a6]; + if ( v11 ) + { + if ( a7 == 8 || (v12 = *(unsigned __int16 *)&v10[a7], !*(_WORD *)&v10[a7]) ) + v12 = *(_DWORD *)&v8[4 * nCel + 4] - v9; + v13 = &v10[(_DWORD)pCelBuffa]; + v14 = v12 - (_DWORD)pCelBuffa; + v15 = -(light4flag != 0); + _LOWORD(v15) = v15 & 0xF400; + v16 = v15 + 4096; + if ( a8 == 2 ) + v16 += 256; + if ( a8 >= 4 ) + v16 = v16 + (a8 << 8) - 256; + Cl2DecDatLightTbl2( + (char *)gpBuffer + screen_y_times_768[screen_y - 16 * a6] + screen_x, + v13, + v14, + frame_width, + &pLightTbl[v16]); + } + } + } + } +} +// 525728: using guessed type int light4flag; + +void __fastcall Cl2DecDatLightTbl2(char *dst_buf, char *a2, int a3, int frame_width, char *a5) /* check 5th arg */ +{ + char *v5; // esi + char *v6; // edi + int v7; // ebx + int v8; // ecx + int v9; // eax + int v10; // edx + char v11; // dl + + v5 = a2; + v6 = dst_buf; + v7 = frame_width; + v8 = a3; + sgnWidth = frame_width; + v9 = 0; + v10 = 0; + do + { + _LOBYTE(v9) = *v5++; + --v8; + if ( (v9 & 0x80u) != 0 ) + { + _LOBYTE(v9) = -(char)v9; + if ( (char)v9 <= 65 ) + { + v8 -= v9; + if ( v6 < (char *)gpBufEnd ) + { + v7 -= v9; + do + { + _LOBYTE(v10) = *v5++; + *v6 = a5[v10]; + --v9; + ++v6; + } + while ( v9 ); + goto LABEL_12; + } + v5 += v9; + } + else + { + _LOBYTE(v9) = v9 - 65; + --v8; + _LOBYTE(v10) = *v5++; + v11 = a5[v10]; + if ( v6 < (char *)gpBufEnd ) + { + v7 -= v9; + do + { + *v6 = v11; + --v9; + ++v6; + } + while ( v9 ); +LABEL_12: + if ( !v7 ) + { + v7 = sgnWidth; + v6 = &v6[-sgnWidth - 768]; + } + continue; + } + } + } + do + { + if ( v9 <= v7 ) + { + v10 = v9; + v6 += v9; + v9 = 0; + } + else + { + v10 = v7; + v6 += v7; + v9 -= v7; + } + v7 -= v10; + if ( !v7 ) + { + v7 = sgnWidth; + v6 = &v6[-sgnWidth - 768]; + } + } + while ( v9 ); + } + while ( v8 ); +} +// 52B978: using guessed type int sgnWidth; +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall Cl2DecodeFrm6(int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a6, int a7) +{ + int v7; // esi + char *v8; // edi + int v9; // ebx + char *v10; // edx + int v11; // eax + int v12; // eax + int v13; // eax + char *v14; // edx + char *v15; // ecx + char *pCelBuffa; // [esp+18h] [ebp+8h] + + v7 = screen_y; + if ( gpBuffer ) + { + v8 = pCelBuff; + if ( pCelBuff ) + { + if ( nCel > 0 ) + { + v9 = *(_DWORD *)&pCelBuff[4 * nCel]; + v10 = &pCelBuff[v9]; + v11 = *(unsigned short *)&pCelBuff[v9 + a6]; + pCelBuffa = (char *)*(unsigned short *)&pCelBuff[v9 + a6]; + if ( v11 ) + { + if ( a7 == 8 || (v12 = *(unsigned short *)&v10[a7], !*(_WORD *)&v10[a7]) ) + v12 = *(_DWORD *)&v8[4 * nCel + 4] - v9; + v13 = v12 - (_DWORD)pCelBuffa; + v14 = &v10[(_DWORD)pCelBuffa]; + v15 = (char *)gpBuffer + screen_y_times_768[v7 - 16 * a6] + screen_x; + if ( light_table_index ) + Cl2DecDatLightTbl2(v15, v14, v13, frame_width, &pLightTbl[256 * light_table_index]); + else + Cl2DecDatFrm4(v15, v14, v13, frame_width); + } + } + } + } +} +// 69BEF8: using guessed type int light_table_index; + +void __fastcall PlayInGameMovie(char *pszMovie) +{ + char *v1; // esi + + v1 = pszMovie; + PaletteFadeOut(8); + play_movie(v1, 0); + ClearScreenBuffer(); + drawpanflag = 255; + scrollrt_draw_game_screen(1); + PaletteFadeIn(8); + drawpanflag = 255; +} +// 52571C: using guessed type int drawpanflag; diff --git a/Source/engine.h b/Source/engine.h new file mode 100644 index 000000000..01c01078f --- /dev/null +++ b/Source/engine.h @@ -0,0 +1,80 @@ +//HEADER_GOES_HERE +#ifndef __ENGINE_H__ +#define __ENGINE_H__ + +//offset 0 +//pCelBuff->pFrameTable[0] + +extern int engine_cpp_init_value; // weak +extern char gbPixelCol; // automap pixel color 8-bit (palette entry) +extern int dword_52B970; // bool flip - if y < x +extern int orgseed; // weak +extern int sgnWidth; +extern int sglGameSeed; // weak +extern int SeedCount; // weak +extern int dword_52B99C; // bool valid - if x/y are in bounds + +void __cdecl engine_cpp_init_1(); +void __fastcall CelDrawDatOnly(char *pDecodeTo, char *pRLEBytes, int dwRLESize, int dwRLEWdt); +void __fastcall CelDecodeOnly(int screen_x, int screen_y, void *pCelBuff, int frame, int frame_width); +void __fastcall CelDecDatOnly(char *pBuff, char *pCelBuff, int frame, int frame_width); +void __fastcall CelDrawHdrOnly(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int always_0, int direction); +void __fastcall CelDecodeHdrOnly(char *pBuff, char *pCelBuff, int frame, int frame_width, int always_0, int direction); +void __fastcall CelDecDatLightOnly(char *pDecodeTo, char *pRLEBytes, int frame_content_size, int frame_width); +void __fastcall CelDecDatLightEntry(unsigned char shift, char *LightIndex, char *&pDecodeTo, char *&pRLEBytes); /* __usercall a1@ a2@ a3@ a4@ */ +void __fastcall CelDecDatLightTrans(char *pDecodeTo, char *pRLEBytes, int frame_content_size, int frame_width); +void __fastcall CelDecodeLightOnly(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width); +void __fastcall CelDecodeHdrLightOnly(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int always_0, int direction); +void __fastcall CelDecodeHdrLightTrans(char *pBuff, char *pCelBuff, int frame, int frame_width, int always_0, int direction); +void __fastcall CelDrawHdrLightRed(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int always_0, int direction, char always_1); +void __fastcall Cel2DecDatOnly(char *pDecodeTo, char *pRLEBytes, int frame_content_size, int frame_width); +void __fastcall Cel2DrawHdrOnly(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int a6, int direction); +void __fastcall Cel2DecodeHdrOnly(char *pBuff, char *pCelBuff, int frame, int frame_width, int a5, int direction); +void __fastcall Cel2DecDatLightOnly(char *pDecodeTo, char *pRLEBytes, int frame_content_size, int frame_width); +void __fastcall Cel2DecDatLightEntry(unsigned char shift, char *LightIndex, char *&pDecodeTo, char *&pRLEBytes); /* __usercall a1@ a2@ a3@ a4@ */ +void __fastcall Cel2DecDatLightTrans(char *pDecodeTo, char *pRLEBytes, int frame_content_size, int frame_width); +void __fastcall Cel2DecodeHdrLight(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int a6, int direction); +void __fastcall Cel2DecodeLightTrans(char *dst_buf, char *pCelBuff, int frame, int frame_width, int a5, int direction); +void __fastcall Cel2DrawHdrLightRed(int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int always_0, int direction, char always_1); +void __fastcall CelDecodeRect(char *pBuff, int always_0, int dst_height, int dst_width, char *pCelBuff, int frame, int frame_width); +void __fastcall CelDecodeClr(BYTE colour, int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int a7, int direction); +void __fastcall CelDrawHdrClrHL(char colour, int screen_x, int screen_y, char *pCelBuff, int frame, int frame_width, int a7, int direction); +void __fastcall ENG_set_pixel(int screen_x, int screen_y, char pixel); +void __fastcall engine_draw_pixel(int x, int y); +void __fastcall DrawLine(int x0, int y0, int x1, int y1, char col); +int __fastcall GetDirection(int x1, int y1, int x2, int y2); +void __fastcall SetRndSeed(int s); +int __cdecl GetRndSeed(); +int __fastcall random(BYTE idx, int v); +void __cdecl engine_cpp_init_2(); +void __cdecl mem_init_mutex(); +void __cdecl mem_atexit_mutex(); +void __cdecl mem_free_mutex(); +unsigned char *__fastcall DiabloAllocPtr(int dwBytes); +void __fastcall mem_free_dbg(void *p); +unsigned char *__fastcall LoadFileInMem(char *pszName, int *pdwFileLen); +void __fastcall LoadFileWithMem(char *pszName, void *buf); +void __fastcall Cl2ApplyTrans(unsigned char *p, unsigned char *ttbl, int last_frame); +void __fastcall Cl2DecodeFrm1(int x, int y, char *pCelBuff, int nCel, int width, int dir1, int dir2); +void __fastcall Cl2DecDatFrm1(char *buffer, char *frame_content, int a3, int width); +void __fastcall Cl2DecodeFrm2(char colour, int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a7, int a8); +void __fastcall Cl2DecDatFrm2(char *buffer, char *a2, int a3, int a4, char a5); +void __fastcall Cl2DecodeFrm3(int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a6, int a7, char a8); +void __fastcall Cl2DecDatLightTbl1(char *a1, char *a2, int a3, int a4, char *unused_lindex); +void __fastcall Cl2DecodeLightTbl(int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a6, int a7); +void __fastcall Cl2DecodeFrm4(int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a6, int a7); +void __fastcall Cl2DecDatFrm4(char *buffer, char *a2, int a3, int frame_width); +void __fastcall Cl2DecodeClrHL(char colour, int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a7, int a8); +void __fastcall Cl2DecDatClrHL(char *dst_buf, char *frame_content, int a3, int frame_width, char colour); +void __fastcall Cl2DecodeFrm5(int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a6, int a7, char a8); +void __fastcall Cl2DecDatLightTbl2(char *dst_buf, char *a2, int a3, int frame_width, char *a5); +void __fastcall Cl2DecodeFrm6(int screen_x, int screen_y, char *pCelBuff, int nCel, int frame_width, int a6, int a7); +void __fastcall PlayInGameMovie(char *pszMovie); + +/* rdata */ + +extern const int engine_inf; // weak +extern const int rand_increment; // unused +extern const int rand_multiplier; // unused + +#endif /* __ENGINE_H__ */ diff --git a/Source/error.cpp b/Source/error.cpp new file mode 100644 index 000000000..5f775897b --- /dev/null +++ b/Source/error.cpp @@ -0,0 +1,217 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +char msgtable[80]; +char msgdelay; // weak +char msgflag; // weak +char msgcnt; // weak +#endif + +char *MsgStrings[44] = +{ + &empty_string, + "No automap available in town", + "No multiplayer functions in demo", + "Direct Sound Creation Failed", + "Not available in shareware version", + "Not enough space to save", + "No Pause in town", + "Copying to a hard disk is recommended", + "Multiplayer sync problem", + "No pause in multiplayer", + "Loading...", + "Saving...", + "Some are weakened as one grows strong", + "New strength is forged through destruction", + "Those who defend seldom attack", + "The sword of justice is swift and sharp", + "While the spirit is vigilant the body thrives", + "The powers of mana refocused renews", + "Time cannot diminish the power of steel", + "Magic is not always what it seems to be", + "What once was opened now is closed", + "Intensity comes at the cost of wisdom", + "Arcane power brings destruction", + "That which cannot be held cannot be harmed", + "Crimson and Azure become as the sun", + "Knowledge and wisdom at the cost of self", + "Drink and be refreshed", + "Wherever you go, there you are", + "Energy comes at the cost of wisdom", + "Riches abound when least expected", + "Where avarice fails, patience gains reward", + "Blessed by a benevolent companion!", + "The hands of men may be guided by fate", + "Strength is bolstered by heavenly faith", + "The essence of life flows from within", + "The way is made clear when viewed from above", + "Salvation comes at the cost of wisdom", + "Mysteries are revealed in the light of reason", + "Those who are last may yet be first", + "Generosity brings its own rewards", + "You must be at least level 8 to use this.", + "You must be at least level 13 to use this.", + "You must be at least level 17 to use this.", + "Arcane knowledge gained!" +}; + +void __fastcall InitDiabloMsg(char e) +{ + int i; // edx + bool v2; // sf + unsigned char v3; // of + + i = 0; + if ( msgcnt <= 0 ) + { +LABEL_4: + v3 = __OFSUB__(msgcnt, 80); + v2 = (char)(msgcnt - 80) < 0; + msgtable[msgcnt] = e; + if ( v2 ^ v3 ) + ++msgcnt; + msgdelay = 70; + msgflag = msgtable[0]; + } + else + { + while ( msgtable[i] != e ) + { + if ( ++i >= msgcnt ) + goto LABEL_4; + } + } +} +// 52B9F0: using guessed type char msgdelay; +// 52B9F1: using guessed type char msgflag; +// 52B9F2: using guessed type char msgcnt; + +void __cdecl ClrDiabloMsg() +{ + msgflag = 0; + msgcnt = 0; + memset(msgtable, 0, sizeof(msgtable)); +} +// 52B9F1: using guessed type char msgflag; +// 52B9F2: using guessed type char msgcnt; + +void __cdecl DrawDiabloMsg() +{ + int v0; // esi + signed int v1; // edi + char *v2; // edi + signed int v3; // edx + signed int v4; // ecx + int v5; // edi + signed int v6; // ecx + _BYTE *v7; // edi + int v8; // edi + signed int v9; // ebx + signed int v10; // eax + signed int v11; // ecx + int v12; // esi + signed int v13; // esi + unsigned char v14; // bl + bool v15; // zf + signed int v16; // [esp+Ch] [ebp-8h] + signed int v17; // [esp+Ch] [ebp-8h] + signed int screen_x; // [esp+10h] [ebp-4h] + + CelDecodeOnly(165, 318, pSTextSlidCels, 1, 12); + CelDecodeOnly(591, 318, pSTextSlidCels, 4, 12); + CelDecodeOnly(165, 366, pSTextSlidCels, 2, 12); + CelDecodeOnly(591, 366, pSTextSlidCels, 3, 12); + screen_x = 173; + v16 = 35; + do + { + CelDecodeOnly(screen_x, 318, pSTextSlidCels, 5, 12); + CelDecodeOnly(screen_x, 366, pSTextSlidCels, 7, 12); + screen_x += 12; + --v16; + } + while ( v16 ); + v0 = 330; + v1 = 3; + do + { + CelDecodeOnly(165, v0, pSTextSlidCels, 6, 12); + CelDecodeOnly(591, v0, pSTextSlidCels, 8, 12); + v0 += 12; + --v1; + } + while ( v1 ); + v2 = &gpBuffer->row[203].pixels[104]; + v3 = 27; + do + { + v4 = 216; + do + { + *v2 = 0; + v2 += 2; + --v4; + } + while ( v4 ); + v5 = (int)(v2 - 1200); + v6 = 216; + do + { + v7 = (_BYTE *)(v5 + 1); + *v7 = 0; + v5 = (int)(v7 + 1); + --v6; + } + while ( v6 ); + v2 = (char *)(v5 - 1200); + --v3; + } + while ( v3 ); + strcpy(tempstr, MsgStrings[msgflag]); + v8 = screen_y_times_768[342] + 165; + v9 = strlen(tempstr); + v10 = 0; + v11 = 0; + v17 = v9; + if ( v9 <= 0 ) + goto LABEL_27; + do + { + v12 = (unsigned char)tempstr[v11++]; + v10 += fontkern[fontframe[fontidx[v12]]] + 1; + } + while ( v11 < v9 ); + if ( v10 < 442 ) +LABEL_27: + v8 += (442 - v10) >> 1; + v13 = 0; + if ( v9 > 0 ) + { + do + { + v14 = fontframe[fontidx[(unsigned char)tempstr[v13]]]; + if ( v14 ) + CPrintString(v8, v14, 3); + ++v13; + v8 += fontkern[v14] + 1; + } + while ( v13 < v17 ); + } + v15 = msgdelay == 0; + if ( msgdelay > 0 ) + v15 = --msgdelay == 0; + if ( v15 ) + { + v15 = msgcnt-- == 1; + msgdelay = 70; + if ( v15 ) + msgflag = 0; + else + msgflag = msgtable[msgcnt]; + } +} +// 52B9F0: using guessed type char msgdelay; +// 52B9F1: using guessed type char msgflag; +// 52B9F2: using guessed type char msgcnt; diff --git a/Source/error.h b/Source/error.h new file mode 100644 index 000000000..21c6aee26 --- /dev/null +++ b/Source/error.h @@ -0,0 +1,17 @@ +//HEADER_GOES_HERE +#ifndef __ERROR_H__ +#define __ERROR_H__ + +extern char msgtable[80]; +extern char msgdelay; // weak +extern char msgflag; // weak +extern char msgcnt; // weak + +void __fastcall InitDiabloMsg(char e); +void __cdecl ClrDiabloMsg(); +void __cdecl DrawDiabloMsg(); + +/* data */ +extern char *MsgStrings[44]; + +#endif /* __ERROR_H__ */ diff --git a/Source/fault.cpp b/Source/fault.cpp new file mode 100644 index 000000000..d0fbc07c8 --- /dev/null +++ b/Source/fault.cpp @@ -0,0 +1,248 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter; // idb + +struct exception_cpp_init +{ + exception_cpp_init() + { + exception_install_filter(); + j_exception_init_filter(); + } +} _exception_cpp_init; + +void __cdecl exception_install_filter() +{ + exception_set_filter(); +} + +void __cdecl j_exception_init_filter() +{ + atexit(exception_init_filter); +} + +void __cdecl exception_init_filter() +{ + exception_set_filter_ptr(); +} + +LONG __stdcall TopLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) +{ + log_dump_computer_info(); + PEXCEPTION_RECORD xcpt = ExceptionInfo->ExceptionRecord; + + char szExceptionNameBuf[MAX_PATH]; // [esp+Ch] [ebp-210h] + char *pszExceptionName = exception_get_error_type(ExceptionInfo->ExceptionRecord->ExceptionCode, szExceptionNameBuf, sizeof(szExceptionNameBuf)); + log_printf("Exception code: %08X %s\r\n", xcpt->ExceptionCode, pszExceptionName); + + char szModuleName[MAX_PATH]; + int sectionNumber, sectionOffset; + exception_unknown_module(xcpt->ExceptionAddress, szModuleName, MAX_PATH, §ionNumber, §ionOffset); + log_printf("Fault address:\t%08X %02X:%08X %s\r\n", xcpt->ExceptionAddress, sectionNumber, sectionOffset, szModuleName); + + PCONTEXT ctx = ExceptionInfo->ContextRecord; + + log_printf("\r\nRegisters:\r\n"); + log_printf( + "EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n", + ctx->Eax, + ctx->Ebx, + ctx->Ecx, + ctx->Edx, + ctx->Esi, + ctx->Edi); + log_printf("CS:EIP:%04X:%08X\r\n", ctx->SegCs, ctx->Eip); + log_printf("SS:ESP:%04X:%08X EBP:%08X\r\n", ctx->SegSs, ctx->Esp, ctx->Ebp); + log_printf("DS:%04X ES:%04X FS:%04X GS:%04X\r\n", ctx->SegDs, ctx->SegEs, ctx->SegFs, ctx->SegGs); + + log_printf("Flags:%08X\r\n", ctx->EFlags); + exception_call_stack((void *)ctx->Eip, (STACK_FRAME*)ctx->Ebp); + + log_printf("Stack bytes:\r\n"); + exception_hex_format((BYTE *)ctx->Esp, 0); + + log_printf("Code bytes:\r\n"); + exception_hex_format((BYTE *)ctx->Eip, 16); + + log_printf("\r\n"); + log_flush(1); + + if ( lpTopLevelExceptionFilter ) + return lpTopLevelExceptionFilter(ExceptionInfo); + return EXCEPTION_CONTINUE_SEARCH; +} + +void __fastcall exception_hex_format(BYTE *ptr, unsigned int numBytes) +{ + int i; + + while (numBytes > 0) + { + unsigned int bytesRead = 16; + if (numBytes < 16 ) + bytesRead = numBytes; + + if ( IsBadReadPtr(ptr, bytesRead) ) + break; + + log_printf("0x%08x: ", ptr); + + for (i = 0; i < 16; ++i) + { + const char *fmt = "%02x "; + if (i >= bytesRead) + fmt = " "; + log_printf(fmt, ptr[i]); + if (i % 4 == 3) + log_printf(" "); + } + + for (i = 0; i < bytesRead; ++i) + { + char c; + if (isprint(ptr[i])) + c = ptr[i]; + else + c = '.'; + log_printf("%c", c); + } + + log_printf("\r\n"); + ptr += bytesRead; + numBytes -= bytesRead; + } + log_printf("\r\n"); +} + +void __fastcall exception_unknown_module(LPCVOID lpAddress, LPSTR lpModuleName, int iMaxLength, int *sectionNum, int *sectionOffset) +{ + lstrcpyn(lpModuleName, "*unknown*", iMaxLength); + *sectionNum = 0; + *sectionOffset = 0; + + MEMORY_BASIC_INFORMATION memInfo; // [esp+Ch] [ebp-24h] + if (!VirtualQuery(lpAddress, &memInfo, sizeof(memInfo))) + return; + + PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)memInfo.AllocationBase; + if ( !memInfo.AllocationBase ) + dosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(0); + + if (!GetModuleFileName((HMODULE)dosHeader, lpModuleName, iMaxLength)) + { + lstrcpyn(lpModuleName, "*unknown*", iMaxLength); + return; + } + + if (dosHeader && dosHeader->e_magic == IMAGE_DOS_SIGNATURE) + { + LONG ntOffset = dosHeader->e_lfanew; + if (ntOffset) + { + PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader + ntOffset); + if (ntHeader->Signature == IMAGE_NT_SIGNATURE) + { + DWORD numSections = ntHeader->FileHeader.NumberOfSections; + DWORD moduleOffset = (_BYTE *)lpAddress - (_BYTE *)dosHeader; + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeader); + for (int i = 0; i < numSections; ++i, ++section) + { + DWORD sectionSize = section->SizeOfRawData; + DWORD sectionAddress = section->VirtualAddress; + if (section->SizeOfRawData <= section->Misc.VirtualSize) + sectionSize = section->Misc.VirtualSize; + + if (moduleOffset >= sectionAddress && moduleOffset <= sectionAddress + sectionSize) + { + *sectionNum = i + 1; + *sectionOffset = moduleOffset - sectionAddress; + return; + } + } + } + } + } +} + +void __fastcall exception_call_stack(void *instr, STACK_FRAME *stackFrame) +{ + STACK_FRAME *oldStackFrame; + + log_printf("Call stack:\r\nAddress Frame Logical addr Module\r\n"); + do + { + char szModuleName[MAX_PATH]; + int sectionNumber, sectionOffset; + exception_unknown_module(instr, szModuleName, MAX_PATH, §ionNumber, §ionOffset); + log_printf("%08X %08X %04X:%08X %s\r\n", instr, stackFrame, sectionNumber, sectionOffset, szModuleName); + + if ( IsBadWritePtr(stackFrame, 8u) ) + break; + + instr = stackFrame->pCallRet; + oldStackFrame = stackFrame; + stackFrame = stackFrame->pNext; + + if ((int)stackFrame % 4 != 0) + break; + } + while (stackFrame > oldStackFrame && !IsBadWritePtr(stackFrame, 8u) ); + + log_printf("\r\n"); +} + +#define CASE_EXCEPTION(v, errName) case EXCEPTION_ ## errName: v = #errName; break; +char *__fastcall exception_get_error_type(DWORD dwMessageId, LPSTR lpString1, DWORD nSize) +{ + const char *v4; // eax + + switch (dwMessageId) { + CASE_EXCEPTION(v4, STACK_OVERFLOW); + CASE_EXCEPTION(v4, FLT_DIVIDE_BY_ZERO); + CASE_EXCEPTION(v4, FLT_INEXACT_RESULT); + CASE_EXCEPTION(v4, FLT_INVALID_OPERATION); + CASE_EXCEPTION(v4, FLT_OVERFLOW); + CASE_EXCEPTION(v4, FLT_STACK_CHECK); + CASE_EXCEPTION(v4, FLT_UNDERFLOW); + CASE_EXCEPTION(v4, INT_DIVIDE_BY_ZERO); + CASE_EXCEPTION(v4, INT_OVERFLOW); + CASE_EXCEPTION(v4, PRIV_INSTRUCTION); + CASE_EXCEPTION(v4, FLT_DENORMAL_OPERAND); + CASE_EXCEPTION(v4, INVALID_HANDLE); + CASE_EXCEPTION(v4, ILLEGAL_INSTRUCTION); + CASE_EXCEPTION(v4, NONCONTINUABLE_EXCEPTION); + CASE_EXCEPTION(v4, INVALID_DISPOSITION); + CASE_EXCEPTION(v4, ARRAY_BOUNDS_EXCEEDED); + CASE_EXCEPTION(v4, IN_PAGE_ERROR); + CASE_EXCEPTION(v4, GUARD_PAGE); + CASE_EXCEPTION(v4, DATATYPE_MISALIGNMENT); + CASE_EXCEPTION(v4, BREAKPOINT); + CASE_EXCEPTION(v4, SINGLE_STEP); + CASE_EXCEPTION(v4, ACCESS_VIOLATION); + default: + HMODULE ntdll = GetModuleHandle("NTDLL.DLL"); + if (!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, ntdll, dwMessageId, 0, lpString1, nSize, NULL)) + { + v4 = "*unknown*"; + } + } + lstrcpyn(lpString1, v4, nSize); + return lpString1; +} + +void __fastcall exception_set_filter() +{ + lpTopLevelExceptionFilter = SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)TopLevelExceptionFilter); +} + +LPTOP_LEVEL_EXCEPTION_FILTER __cdecl exception_set_filter_ptr() +{ + return SetUnhandledExceptionFilter(lpTopLevelExceptionFilter); +} + +LPTOP_LEVEL_EXCEPTION_FILTER __cdecl exception_get_filter() +{ + return lpTopLevelExceptionFilter; +} diff --git a/Source/fault.h b/Source/fault.h new file mode 100644 index 000000000..e0194d243 --- /dev/null +++ b/Source/fault.h @@ -0,0 +1,26 @@ +//HEADER_GOES_HERE +#ifndef __FAULT_H__ +#define __FAULT_H__ + +struct STACK_FRAME { + STACK_FRAME *pNext; + void *pCallRet; +}; + +//int dword_52B9F4; +extern LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter; // idb + +void __cdecl exception_cpp_init(); +void __cdecl exception_install_filter(); +void __cdecl j_exception_init_filter(); +void __cdecl exception_init_filter(); +LONG __stdcall TopLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo); +void __fastcall exception_hex_format(BYTE *ptr, unsigned int numBytes); +void __fastcall exception_unknown_module(LPCVOID lpAddress, LPSTR lpModuleName, int iMaxLength, int *sectionNum, int *sectionOffset); +void __fastcall exception_call_stack(void *instr, STACK_FRAME *stackAddr); +char *__fastcall exception_get_error_type(DWORD dwMessageId, LPSTR lpString1, DWORD nSize); +void __fastcall exception_set_filter(); +LPTOP_LEVEL_EXCEPTION_FILTER __cdecl exception_set_filter_ptr(); +LPTOP_LEVEL_EXCEPTION_FILTER __cdecl exception_get_filter(); + +#endif /* __FAULT_H__ */ diff --git a/Source/gamemenu.cpp b/Source/gamemenu.cpp new file mode 100644 index 000000000..60cfcfddb --- /dev/null +++ b/Source/gamemenu.cpp @@ -0,0 +1,327 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +TMenuItem sgSingleMenu[6] = +{ + { 0x80000000, "Save Game", &gamemenu_save_game }, + { 0x80000000, "Options", &gamemenu_options }, + { 0x80000000, "New Game", &gamemenu_new_game }, + { 0x80000000, "Load Game", &gamemenu_load_game }, + { 0x80000000, "Quit Diablo", &gamemenu_quit_game }, + { 0x80000000, NULL, NULL } +}; +TMenuItem sgMultiMenu[5] = +{ + { 0x80000000, "Options", &gamemenu_options }, + { 0x80000000, "New Game", &gamemenu_new_game }, + { 0x80000000, "Restart In Town", &gamemenu_restart_town }, + { 0x80000000, "Quit Diablo", &gamemenu_quit_game }, + { 0x80000000, NULL, NULL } +}; +TMenuItem sgOptionMenu[6] = +{ + { 0xC0000000, NULL, (void (__cdecl *)(void))&gamemenu_music_volume }, + { 0xC0000000, NULL, (void (__cdecl *)(void))&gamemenu_sound_volume }, + { 0xC0000000, "Gamma", (void (__cdecl *)(void))&gamemenu_gamma }, + { 0x80000000, NULL, &gamemenu_color_cycling }, + { 0x80000000, "Previous Menu", &gamemenu_previous }, + { 0x80000000, NULL, NULL } +}; +char *music_toggle_names[] = { "Music", "Music Disabled" }; +char *sound_toggle_names[] = { "Sound", "Sound Disabled" }; +char *color_cycling_toggle_names[] = { "Color Cycling Off", "Color Cycling On" }; + +void __cdecl gamemenu_previous() +{ + void (__cdecl *v0)(); // edx + TMenuItem *v1; // ecx + + if ( gbMaxPlayers == 1 ) + { + v0 = gamemenu_enable_single; + v1 = sgSingleMenu; + } + else + { + v0 = gamemenu_enable_multi; + v1 = sgMultiMenu; + } + gmenu_call_proc(v1, v0); + PressEscKey(); +} +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl gamemenu_enable_single() +{ + bool v0; // dl + + gmenu_enable(&sgSingleMenu[3], gbValidSaveFile); + v0 = 0; + if ( plr[myplr]._pmode != PM_DEATH && !deathflag ) + v0 = 1; + gmenu_enable(sgSingleMenu, v0); +} + +void __cdecl gamemenu_enable_multi() +{ + gmenu_enable(&sgMultiMenu[2], deathflag); +} + +void __cdecl gamemenu_off() +{ + gmenu_call_proc(0, 0); +} + +void __cdecl gamemenu_handle_previous() +{ + if ( gmenu_exception() ) + gamemenu_off(); + else + gamemenu_previous(); +} + +void __cdecl gamemenu_new_game() +{ + int i; // eax + + for(i = 0; i < 4; i++) + { + plr[i]._pmode = PM_QUIT; + plr[i]._pInvincible = 1; + } + + deathflag = 0; + drawpanflag = 255; + scrollrt_draw_game_screen(1); + gbRunGame = 0; + gamemenu_off(); +} +// 525650: using guessed type int gbRunGame; +// 52571C: using guessed type int drawpanflag; + +void __cdecl gamemenu_quit_game() +{ + gamemenu_new_game(); + gbRunGameResult = 0; +} +// 525698: using guessed type int gbRunGameResult; + +void __cdecl gamemenu_load_game() +{ + WNDPROC saveProc; // edi + + saveProc = SetWindowProc(DisableInputWndProc); + gamemenu_off(); + SetCursor(0); + InitDiabloMsg(10); + drawpanflag = 255; + DrawAndBlit(); + LoadGame(FALSE); + ClrDiabloMsg(); + PaletteFadeOut(8); + deathflag = 0; + drawpanflag = 255; + DrawAndBlit(); + PaletteFadeIn(8); + SetCursor(CURSOR_HAND); + interface_msg_pump(); + SetWindowProc(saveProc); +} +// 52571C: using guessed type int drawpanflag; + +void __cdecl gamemenu_save_game() +{ + WNDPROC saveProc; // edi + + if ( pcurs == CURSOR_HAND ) + { + if ( plr[myplr]._pmode == PM_DEATH || deathflag ) + { + gamemenu_off(); + } + else + { + saveProc = SetWindowProc(DisableInputWndProc); + SetCursor(0); + gamemenu_off(); + InitDiabloMsg(11); + drawpanflag = 255; + DrawAndBlit(); + SaveGame(); + ClrDiabloMsg(); + drawpanflag = 255; + SetCursor(CURSOR_HAND); + interface_msg_pump(); + SetWindowProc(saveProc); + } + } +} +// 52571C: using guessed type int drawpanflag; + +void __cdecl gamemenu_restart_town() +{ + NetSendCmd(1u, CMD_RETOWN); +} + +void __cdecl gamemenu_options() +{ + gamemenu_get_music(); + gamemenu_get_sound(); + gamemenu_get_gamma(); + gamemenu_get_color_cycling(); + gmenu_call_proc(sgOptionMenu, 0); +} + +void __cdecl gamemenu_get_music() +{ + gamemenu_sound_music_toggle(music_toggle_names, sgOptionMenu, sound_get_or_set_music_volume(1)); +} + +void __fastcall gamemenu_sound_music_toggle(char **names, TMenuItem *menu_item, int gamma) +{ + if ( gbSndInited ) + { + menu_item->dwFlags |= 0xC0000000; + menu_item->pszStr = *names; + gmenu_slider_3(menu_item, 17); + gmenu_slider_1(menu_item, -1600, 0, gamma); + } + else + { + menu_item->dwFlags &= 0x3F000000; + menu_item->pszStr = names[1]; + } +} + +void __cdecl gamemenu_get_sound() +{ + gamemenu_sound_music_toggle(sound_toggle_names, &sgOptionMenu[1], sound_get_or_set_sound_volume(1)); +} + +void __cdecl gamemenu_get_color_cycling() +{ + sgOptionMenu[3].pszStr = color_cycling_toggle_names[palette_get_colour_cycling()]; +} + +void __cdecl gamemenu_get_gamma() +{ + gmenu_slider_3(&sgOptionMenu[2], 15); + gmenu_slider_1(&sgOptionMenu[2], 30, 100, UpdateGamma(0)); +} + +void __fastcall gamemenu_music_volume(int a1) +{ + int v1; // esi + + if ( a1 ) + { + if ( gbMusicOn ) + { + gbMusicOn = 0; + music_stop(); + sound_get_or_set_music_volume(-1600); + goto LABEL_11; + } + gbMusicOn = 1; + sound_get_or_set_music_volume(0); +LABEL_10: + music_start((unsigned char)leveltype); + goto LABEL_11; + } + v1 = gamemenu_slider_music_sound(sgOptionMenu); + sound_get_or_set_music_volume(v1); + if ( v1 != -1600 ) + { + if ( gbMusicOn ) + goto LABEL_11; + gbMusicOn = 1; + goto LABEL_10; + } + if ( gbMusicOn ) + { + gbMusicOn = 0; + music_stop(); + } +LABEL_11: + gamemenu_get_music(); +} +// 4A22D4: using guessed type char gbMusicOn; +// 5BB1ED: using guessed type char leveltype; + +int __fastcall gamemenu_slider_music_sound(TMenuItem *menu_item) +{ + return gmenu_slider_get(menu_item, -1600, 0); +} + +void __fastcall gamemenu_sound_volume(int a1) +{ + int v1; // ecx + int v2; // esi + + if ( a1 ) + { + if ( gbSoundOn ) + { + gbSoundOn = 0; + FreeMonsterSnd(); + v1 = -1600; + } + else + { + gbSoundOn = 1; + v1 = 0; + } + sound_get_or_set_sound_volume(v1); + } + else + { + v2 = gamemenu_slider_music_sound(&sgOptionMenu[1]); + sound_get_or_set_sound_volume(v2); + if ( v2 == -1600 ) + { + if ( gbSoundOn ) + { + gbSoundOn = 0; + FreeMonsterSnd(); + } + } + else if ( !gbSoundOn ) + { + gbSoundOn = 1; + } + } + PlaySFX(IS_TITLEMOV); + gamemenu_get_sound(); +} +// 4A22D5: using guessed type char gbSoundOn; + +void __fastcall gamemenu_gamma(int a1) +{ + int v1; // eax + int v2; // eax + + if ( a1 ) + { + v1 = -(UpdateGamma(0) != 30); + _LOBYTE(v1) = v1 & 0xBA; + v2 = v1 + 100; + } + else + { + v2 = gamemenu_slider_gamma(); + } + UpdateGamma(v2); + gamemenu_get_gamma(); +} + +int __cdecl gamemenu_slider_gamma() +{ + return gmenu_slider_get(&sgOptionMenu[2], 30, 100); +} + +void __cdecl gamemenu_color_cycling() +{ + palette_set_color_cycling(palette_get_colour_cycling() == 0); + sgOptionMenu[3].pszStr = color_cycling_toggle_names[palette_get_colour_cycling() & 1]; +} diff --git a/Source/gamemenu.h b/Source/gamemenu.h new file mode 100644 index 000000000..192a09308 --- /dev/null +++ b/Source/gamemenu.h @@ -0,0 +1,36 @@ +//HEADER_GOES_HERE +#ifndef __GAMEMENU_H__ +#define __GAMEMENU_H__ + +void __cdecl gamemenu_previous(); +void __cdecl gamemenu_enable_single(); +void __cdecl gamemenu_enable_multi(); +void __cdecl gamemenu_off(); +void __cdecl gamemenu_handle_previous(); +void __cdecl gamemenu_new_game(); +void __cdecl gamemenu_quit_game(); +void __cdecl gamemenu_load_game(); // should have 1-2 args +void __cdecl gamemenu_save_game(); // should have 1-2 args +void __cdecl gamemenu_restart_town(); +void __cdecl gamemenu_options(); +void __cdecl gamemenu_get_music(); +void __fastcall gamemenu_sound_music_toggle(char **names, TMenuItem *menu_item, int gamma); +void __cdecl gamemenu_get_sound(); +void __cdecl gamemenu_get_color_cycling(); +void __cdecl gamemenu_get_gamma(); +void __fastcall gamemenu_music_volume(int a1); +int __fastcall gamemenu_slider_music_sound(TMenuItem *menu_item); +void __fastcall gamemenu_sound_volume(int a1); +void __fastcall gamemenu_gamma(int a1); +int __cdecl gamemenu_slider_gamma(); +void __cdecl gamemenu_color_cycling(); + +/* rdata */ +extern TMenuItem sgSingleMenu[6]; +extern TMenuItem sgMultiMenu[5]; +extern TMenuItem sgOptionMenu[6]; +extern char *music_toggle_names[]; +extern char *sound_toggle_names[]; +extern char *color_cycling_toggle_names[]; + +#endif /* __GAMEMENU_H__ */ diff --git a/Source/gendung.cpp b/Source/gendung.cpp new file mode 100644 index 000000000..65107d466 --- /dev/null +++ b/Source/gendung.cpp @@ -0,0 +1,1441 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +short level_frame_types[2048]; +int themeCount; +char nTransTable[2049]; +//int dword_52D204; +int dMonster[MAXDUNX][MAXDUNY]; +char dungeon[40][40]; +char dObject[MAXDUNX][MAXDUNY]; +void *pSpeedCels; +int nlevel_frames; // weak +char pdungeon[40][40]; +char dDead[MAXDUNX][MAXDUNY]; +short dpiece_defs_map_1[16][MAXDUNX][MAXDUNY]; +char dTransVal2[MAXDUNX][MAXDUNY]; +char TransVal; // weak +int dword_5A5594; +char dflags[40][40]; +int dPiece[MAXDUNX][MAXDUNY]; +char dTransVal[MAXDUNX][MAXDUNY]; +int setloadflag_2; // weak +int tile_defs[2048]; +void *pMegaTiles; +void *pLevelPieces; +int gnDifficulty; // idb +char block_lvid[2049]; +//char byte_5B78EB; +char dung_map[MAXDUNX][MAXDUNY]; +char nTrapTable[2049]; +char leveltype; // weak +unsigned char currlevel; // idb +char TransList[256]; +UCHAR nSolidTable[2049]; +int level_frame_count[2048]; +ScrollStruct ScrollInfo; +void *pDungeonCels; +int speed_cel_frame_num_from_light_index_frame_num[16][128]; +THEME_LOC themeLoc[MAXTHEMES]; +char dPlayer[MAXDUNX][MAXDUNY]; +int dword_5C2FF8; // weak +int dword_5C2FFC; // weak +int scr_pix_width; // weak +int scr_pix_height; // weak +char dArch[MAXDUNX][MAXDUNY]; +char nBlockTable[2049]; +void *level_special_cel; +char dFlags[MAXDUNX][MAXDUNY]; +char dItem[MAXDUNX][MAXDUNY]; +char setlvlnum; // weak +int level_frame_sizes[2048]; +char nMissileTable[2049]; +char *pSetPiece_2; +char setlvltype; // weak +char setlevel; // weak +int LvlViewY; // weak +int LvlViewX; // weak +int dmaxx; // weak +int dmaxy; // weak +int setpc_h; // weak +int setpc_w; // weak +int setpc_x; // idb +int ViewX; // idb +int ViewY; // idb +int setpc_y; // idb +char dMissile[MAXDUNX][MAXDUNY]; +int dminx; // weak +int dminy; // weak +short dpiece_defs_map_2[16][MAXDUNX][MAXDUNY]; +#endif + +void __cdecl FillSolidBlockTbls() +{ + unsigned char *v0; // eax + char *v1; // ecx + unsigned char *v2; // esi + int v3; // edx + unsigned char v4; // bl + int size; // [esp+8h] [ebp-4h] + + memset(nBlockTable, 0, 0x801u); + memset(nSolidTable, 0, 0x801u); + memset(nTransTable, 0, 0x801u); + memset(nMissileTable, 0, 0x801u); + memset(nTrapTable, 0, 0x801u); + if ( leveltype != DTYPE_TOWN ) + { + switch ( leveltype ) + { + case DTYPE_CATHEDRAL: + v1 = "Levels\\L1Data\\L1.SOL"; + break; + case DTYPE_CATACOMBS: + v1 = "Levels\\L2Data\\L2.SOL"; + break; + case DTYPE_CAVES: + v1 = "Levels\\L3Data\\L3.SOL"; + break; + case DTYPE_HELL: + v1 = "Levels\\L4Data\\L4.SOL"; + break; + default: + TermMsg("FillSolidBlockTbls"); + // v0 = (unsigned char *)size; /* check error */ + goto LABEL_13; + } + } + else + { + v1 = "Levels\\TownData\\Town.SOL"; + } + v0 = LoadFileInMem(v1, &size); +LABEL_13: + v2 = v0; + if ( (unsigned int)size >= 1 ) + { + v3 = 0; + do + { + v4 = *v2++; + if ( v4 & 1 ) + nSolidTable[v3 + 1] = 1; + if ( v4 & 2 ) + nBlockTable[v3 + 1] = 1; + if ( v4 & 4 ) + nMissileTable[v3 + 1] = 1; + if ( v4 & 8 ) + nTransTable[v3 + 1] = 1; + if ( (v4 & 0x80u) != 0 ) + nTrapTable[v3 + 1] = 1; + block_lvid[v3++ + 1] = (v4 >> 4) & 7; + } + while ( v3 + 1 <= (unsigned int)size ); + } + mem_free_dbg(v0); +} +// 5BB1ED: using guessed type char leveltype; + +void __cdecl gendung_418D91() +{ + signed int v0; // edx + short (*v1)[112][112]; // edi + short (*v2)[112][112]; // esi + signed int v3; // ebx + int i; // edx + short v5; // ax + int v6; // ecx + signed int v7; // edx + int v8; // eax + int v9; // edi + char *v10; // esi + int j; // ecx + unsigned char v12; // al + unsigned char *v13; // esi + int v14; // ecx + signed int v15; // edx + int v16; // eax + int v17; // ecx + unsigned char v18; // al + signed int v19; // ecx + int v20; // edi + int v21; // edx + int v22; // edi + int v23; // eax + int v24; // eax + bool v25; // zf + int v26; // edx + char *v27; // esi + char *v28; // edi + int k; // ecx + char *v33; // esi + char *v34; // edi + int v36; // ecx + signed int v37; // edx + int v38; // eax + int v39; // ecx + short (*v42)[112][112]; // esi + short v43; // ax + unsigned short v44; // dx + short v45; // ax + int v46; // [esp-4h] [ebp-38h] + int v47; // [esp-4h] [ebp-38h] + int v48; // [esp+Ch] [ebp-28h] + int (*v49)[128]; // [esp+10h] [ebp-24h] + int (*v50)[112]; // [esp+10h] [ebp-24h] + int v51; // [esp+14h] [ebp-20h] + short (*v52)[112][112]; // [esp+14h] [ebp-20h] + signed int v53; // [esp+18h] [ebp-1Ch] + int v54; // [esp+18h] [ebp-1Ch] + short (*v55)[112][112]; // [esp+18h] [ebp-1Ch] + int v56; // [esp+1Ch] [ebp-18h] + int (*v57)[112]; // [esp+1Ch] [ebp-18h] + signed int v58; // [esp+20h] [ebp-14h] + int v59; // [esp+20h] [ebp-14h] + int v60; // [esp+24h] [ebp-10h] + signed int v61; // [esp+24h] [ebp-10h] + int v62; // [esp+28h] [ebp-Ch] + int v63; // [esp+2Ch] [ebp-8h] + signed int v64; // [esp+30h] [ebp-4h] + signed int v65; // [esp+30h] [ebp-4h] + int _EAX; + char *_EBX; + + v0 = 0; + memset(level_frame_types, 0, sizeof(level_frame_types)); + memset(level_frame_count, 0, sizeof(level_frame_count)); + do + { + tile_defs[v0] = v0; + ++v0; + } + while ( v0 < 2048 ); + v1 = dpiece_defs_map_2; + v48 = 2 * (leveltype == DTYPE_HELL) + 10; + do + { + v2 = v1; + v3 = 112; + do + { + for ( i = 0; i < v48; ++i ) + { + v5 = (*v2)[0][i]; + if ( (*v2)[0][i] ) + { + v6 = v5 & 0xFFF; + ++level_frame_count[v6]; + level_frame_types[v6] = v5 & 0x7000; + } + } + v2 = (short (*)[112][112])((char *)v2 + 3584); + --v3; + } + while ( v3 ); + v1 = (short (*)[112][112])((char *)v1 + 32); + } + while ( (signed int)v1 < (signed int)dpiece_defs_map_2[0][16] ); /* check */ + v7 = 1; + nlevel_frames = *(_DWORD *)pDungeonCels & 0xFFFF; + v8 = nlevel_frames; + if ( nlevel_frames > 1 ) + { + do + { + level_frame_sizes[v7] = (*((_DWORD *)pDungeonCels + v7 + 1) - *((_DWORD *)pDungeonCels + v7)) & 0xFFFF; + v8 = nlevel_frames; + ++v7; + } + while ( v7 < nlevel_frames ); + } + v9 = 0; + level_frame_sizes[0] = 0; + if ( leveltype == DTYPE_HELL && v8 > 0 ) + { + do + { + if ( !v9 ) + level_frame_count[0] = 0; + v53 = 1; + if ( level_frame_count[v9] ) + { + if ( level_frame_types[v9] == 4096 ) + { + v13 = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + v9); + v14 = 32; + do + { + v46 = v14; + v15 = 32; + do + { + while ( 1 ) + { + v16 = *v13++; + if ( (v16 & 0x80u) == 0 ) + break; + _LOBYTE(v16) = -(char)v16; + v15 -= v16; + if ( !v15 ) + goto LABEL_36; + } + v15 -= v16; + v17 = v16; + do + { + v18 = *v13++; + if ( v18 && v18 < 0x20u ) + v53 = 0; + --v17; + } + while ( v17 ); + } + while ( v15 ); +LABEL_36: + v14 = v46 - 1; + } + while ( v46 != 1 ); + } + else + { + v10 = (char *)pDungeonCels + *((_DWORD *)pDungeonCels + v9); + for ( j = level_frame_sizes[v9]; j; --j ) + { + v12 = *v10++; + if ( v12 && v12 < 0x20u ) + v53 = 0; + } + } + if ( !v53 ) + level_frame_count[v9] = 0; + } + ++v9; + } + while ( v9 < nlevel_frames ); + } + gendung_4191BF(2047); + v19 = 0; + v20 = 0; + if ( light4flag ) + { + do + { + v21 = level_frame_sizes[v20++]; + v19 += 2 * v21; + } + while ( v19 < 0x100000 ); + } + else + { + do + v19 += 14 * level_frame_sizes[v20++]; + while ( v19 < 0x100000 ); + } + v22 = v20 - 1; + v58 = v22; + if ( v22 > 128 ) + { + v58 = 128; + v22 = 128; + } + v23 = -(light4flag != 0); + v63 = 0; + _LOBYTE(v23) = v23 & 0xF4; + v54 = 0; + v60 = v23 + 15; + if ( v22 > 0 ) + { + v56 = 0; + v49 = speed_cel_frame_num_from_light_index_frame_num; + do + { + v24 = v54; + v25 = level_frame_types[v54] == 4096; + v62 = tile_defs[v54]; + (*v49)[0] = v62; + if ( v25 ) + { + v65 = 1; + if ( v60 > 1 ) + { + do + { + speed_cel_frame_num_from_light_index_frame_num[0][v65 + v56] = v63; + v33 = (char *)pDungeonCels + *((_DWORD *)pDungeonCels + v62); + v34 = (char *)pSpeedCels + v63; + _EBX = &pLightTbl[256 * v65]; + v36 = 32; + do + { + v47 = v36; + v37 = 32; + do + { + while ( 1 ) + { + v38 = (unsigned char)*v33++; + *v34++ = v38; + if ( (v38 & 0x80u) == 0 ) + break; + _LOBYTE(v38) = -(char)v38; + v37 -= v38; + if ( !v37 ) + goto LABEL_63; + } + v37 -= v38; + v39 = v38; + do + { + _EAX = *v33++; + ASM_XLAT(_EAX,_EBX); + *v34++ = _EAX; + --v39; + } + while ( v39 ); + } + while ( v37 ); +LABEL_63: + v36 = v47 - 1; + } + while ( v47 != 1 ); + v63 += level_frame_sizes[v54]; + ++v65; + } + while ( v65 < v60 ); + goto LABEL_65; + } + } + else + { + v26 = level_frame_sizes[v24]; + v51 = level_frame_sizes[v24]; + v64 = 1; + if ( v60 > 1 ) + { + do + { + speed_cel_frame_num_from_light_index_frame_num[0][v64 + v56] = v63; + v27 = (char *)pDungeonCels + *((_DWORD *)pDungeonCels + v62); + v28 = (char *)pSpeedCels + v63; + _EBX = &pLightTbl[256 * v64]; + for ( k = v51; k; --k ) + { + _EAX = *v27++; + ASM_XLAT(_EAX,_EBX); + *v28++ = _EAX; + } + v63 += v26; + ++v64; + } + while ( v64 < v60 ); +LABEL_65: + v22 = v58; + goto LABEL_66; + } + } +LABEL_66: + ++v54; + v49 = (int (*)[128])((char *)v49 + 64); + v56 += 16; + } + while ( v54 < v22 ); + } + v57 = dPiece; + v55 = dpiece_defs_map_2; + do + { + v61 = 112; + v52 = v55; + v50 = v57; + do + { + if ( (*v50)[0] && v48 > 0 ) + { + v42 = v52; + v59 = v48; + do + { + v43 = *(_WORD *)v42; + if ( *(_WORD *)v42 ) + { + v44 = 0; + if ( v22 > 0 ) + { + do + { + if ( (v43 & 0xFFF) == tile_defs[v44] ) + { + v45 = v44 + level_frame_types[v44]; + v44 = v22; + v43 = v45 + -32768; + } + ++v44; + } + while ( v44 < v22 ); + *(_WORD *)v42 = v43; + } + } + v42 = (short (*)[112][112])((char *)v42 + 2); + --v59; + } + while ( v59 ); + } + ++v50; + v52 = (short (*)[112][112])((char *)v52 + 3584); + --v61; + } + while ( v61 ); + v55 = (short (*)[112][112])((char *)v55 + 32); + v57 = (int (*)[112])((char *)v57 + 4); + } + while ( (signed int)v55 < (signed int)dpiece_defs_map_2[0][16] ); /* check */ +} +// 525728: using guessed type int light4flag; +// 53CD4C: using guessed type int nlevel_frames; +// 5BB1ED: using guessed type char leveltype; + +void __fastcall gendung_4191BF(int frames) +{ + int v1; // edi + signed int v2; // eax + int i; // esi + + v1 = frames; + v2 = 0; + while ( v1 > 0 && !v2 ) + { + v2 = 1; + for ( i = 0; i < v1; ++i ) + { + if ( level_frame_count[i] < level_frame_count[i + 1] ) + { + gendung_4191FB(i, i + 1); + v2 = 0; + } + } + --v1; + } +} + +void __fastcall gendung_4191FB(int a1, int a2) +{ + int v2; // esi + int *v3; // edi + short *v4; // edx + int v5; // ST10_4 + int *v6; // edi + int *v7; // eax + int v8; // ST10_4 + short *v9; // ecx + int v10; // edx + + v2 = a2; + v3 = &level_frame_count[a1]; + v4 = &level_frame_types[a2]; + v2 *= 4; + v5 = *v3; + *v3 = *(int *)((char *)level_frame_count + v2); + v6 = &tile_defs[a1]; + *(int *)((char *)level_frame_count + v2) = v5; + v7 = &level_frame_sizes[a1]; + v8 = *v6; + *v6 = *(int *)((char *)tile_defs + v2); + *(int *)((char *)tile_defs + v2) = v8; + v9 = &level_frame_types[a1]; + _LOWORD(v6) = *v9; + *v9 = *v4; + *v4 = (signed short)v6; + v10 = *v7; + *v7 = *(int *)((char *)level_frame_sizes + v2); + *(int *)((char *)level_frame_sizes + v2) = v10; +} + +int __fastcall gendung_get_dpiece_num_from_coord(int x, int y) +{ + __int64 v3; // rax + + if ( x < 112 - y ) + return (y * (y + 1) + x * (x + 2 * y + 3)) / 2; + v3 = (111 - y) * (111 - y + 1) + (111 - x) * (111 - x + 2 * (111 - y) + 3); + return 12543 - (((signed int)v3 - HIDWORD(v3)) >> 1); +} + +void __cdecl gendung_4192C2() +{ + short (*v0)[112][112]; // ebx + int v1; // ebp + short (*v2)[112][112]; // esi + char *v3; // edi + int x; // [esp+10h] [ebp-4h] + + x = 0; + v0 = dpiece_defs_map_2; + do + { + v1 = 0; + do + { + v2 = v0; + v3 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(x, v1++); + v0 = (short (*)[112][112])((char *)v0 + 32); + qmemcpy(v3, v2, 0x20u); + } + while ( v1 < 112 ); + ++x; + } + while ( (signed int)v0 < (signed int)&dpiece_defs_map_2[16][0][0] ); +} + +void __cdecl SetDungeonMicros() +{ + signed int v0; // esi + short (*v1)[112][112]; // edx + int (*v2)[112]; // ebp + int v3; // eax + char *v4; // eax + signed int i; // ecx + _WORD *v6; // edi + int j; // ecx + short (*v8)[112][112]; // [esp+8h] [ebp-Ch] + int (*v9)[112]; // [esp+Ch] [ebp-8h] + signed int v10; // [esp+10h] [ebp-4h] + + if ( leveltype == DTYPE_HELL ) + { + dword_5A5594 = 12; + v0 = 16; + } + else + { + dword_5A5594 = 10; + v0 = 10; + } + v9 = dPiece; + v8 = dpiece_defs_map_2; + do + { + v1 = v8; + v2 = v9; + v10 = 112; + do + { + if ( (*v2)[0] ) + { + v3 = (*v2)[0] - 1; + if ( leveltype == DTYPE_HELL ) + v4 = (char *)pLevelPieces + 32 * v3; + else + v4 = (char *)pLevelPieces + 20 * v3; + for ( i = 0; i < v0; ++i ) + (*v1)[0][i] = *(_WORD *)&v4[2 * (v0 + (i & 1) - (i & 0xE)) - 4]; + } + else if ( v0 > 0 ) + { + memset(v1, 0, 4 * ((unsigned int)v0 >> 1)); + v6 = (_WORD *)((char *)v1 + 4 * ((unsigned int)v0 >> 1)); + for ( j = v0 & 1; j; --j ) + { + *v6 = 0; + ++v6; + } + } + ++v2; + v1 = (short (*)[112][112])((char *)v1 + 3584); + --v10; + } + while ( v10 ); + v8 = (short (*)[112][112])((char *)v8 + 32); + v9 = (int (*)[112])((char *)v9 + 4); + } + while ( (signed int)v8 < (signed int)dpiece_defs_map_2[0][16] ); /* check */ + gendung_418D91(); + gendung_4192C2(); + if ( zoomflag ) + { + scr_pix_width = 640; + scr_pix_height = 352; + dword_5C2FF8 = 10; + dword_5C2FFC = 11; + } + else + { + scr_pix_width = 384; + scr_pix_height = 224; + dword_5C2FF8 = 6; + dword_5C2FFC = 7; + } +} +// 52569C: using guessed type int zoomflag; +// 5BB1ED: using guessed type char leveltype; +// 5C2FF8: using guessed type int dword_5C2FF8; +// 5C2FFC: using guessed type int dword_5C2FFC; +// 5C3000: using guessed type int scr_pix_width; +// 5C3004: using guessed type int scr_pix_height; + +void __cdecl DRLG_InitTrans() +{ + memset(dung_map, 0, 0x3100u); + memset(TransList, 0, 0x100u); + TransVal = 1; +} +// 5A5590: using guessed type char TransVal; + +void __fastcall DRLG_MRectTrans(int x1, int y1, int x2, int y2) +{ + int v4; // esi + int v5; // edi + int i; // eax + char *v7; // edx + int j; // ecx + int ty_enda; // [esp+10h] [ebp+8h] + + v4 = 2 * x1 + 17; + v5 = 2 * x2 + 16; + i = 2 * y1 + 17; + for ( ty_enda = 2 * y2 + 16; i <= ty_enda; ++i ) + { + if ( v4 <= v5 ) + { + v7 = &dung_map[v4][i]; + j = v5 - v4 + 1; + do + { + *v7 = TransVal; + v7 += 112; + --j; + } + while ( j ); + } + } + ++TransVal; +} +// 5A5590: using guessed type char TransVal; + +void __fastcall DRLG_RectTrans(int x1, int y1, int x2, int y2) +{ + int i; // esi + char *v5; // edx + int j; // eax + + for ( i = y1; i <= y2; ++i ) + { + if ( x1 <= x2 ) + { + v5 = &dung_map[x1][i]; + j = x2 - x1 + 1; + do + { + *v5 = TransVal; + v5 += 112; + --j; + } + while ( j ); + } + } + ++TransVal; +} +// 5A5590: using guessed type char TransVal; + +void __fastcall DRLG_CopyTrans(int sx, int sy, int dx, int dy) +{ + dung_map[dx][dy] = dung_map[sx][sy]; +} + +void __fastcall DRLG_ListTrans(int num, unsigned char *List) +{ + unsigned char *v2; // esi + int v3; // edi + unsigned char v4; // al + unsigned char *v5; // esi + unsigned char v6; // cl + unsigned char v7; // dl + unsigned char v8; // bl + + v2 = List; + if ( num > 0 ) + { + v3 = num; + do + { + v4 = *v2; + v5 = v2 + 1; + v6 = *v5++; + v7 = *v5++; + v8 = *v5; + v2 = v5 + 1; + DRLG_RectTrans(v4, v6, v7, v8); + --v3; + } + while ( v3 ); + } +} + +void __fastcall DRLG_AreaTrans(int num, unsigned char *List) +{ + unsigned char *v2; // esi + int v3; // edi + unsigned char v4; // al + unsigned char *v5; // esi + unsigned char v6; // cl + unsigned char v7; // dl + unsigned char v8; // bl + + v2 = List; + if ( num > 0 ) + { + v3 = num; + do + { + v4 = *v2; + v5 = v2 + 1; + v6 = *v5++; + v7 = *v5++; + v8 = *v5; + v2 = v5 + 1; + DRLG_RectTrans(v4, v6, v7, v8); + --TransVal; + --v3; + } + while ( v3 ); + } + ++TransVal; +} +// 5A5590: using guessed type char TransVal; + +void __cdecl DRLG_InitSetPC() +{ + setpc_x = 0; + setpc_y = 0; + setpc_w = 0; + setpc_h = 0; +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __cdecl DRLG_SetPC() +{ + int v0; // ebx + int v1; // edx + int v2; // ecx + int v3; // esi + int i; // eax + int v5; // ebp + char *v6; // edi + + v0 = 0; + v1 = 2 * setpc_w; + v2 = 2 * setpc_h; + v3 = 2 * setpc_x + 16; + for ( i = 2 * setpc_y + 16; v0 < v2; ++v0 ) + { + if ( v1 > 0 ) + { + v5 = v1; + v6 = &dFlags[v3][v0 + i]; + do + { + *v6 |= 8u; + v6 += 112; + --v5; + } + while ( v5 ); + } + } +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __fastcall Make_SetPC(int x, int y, int w, int h) +{ + int v4; // eax + int v5; // esi + int v6; // ebx + int i; // eax + int v8; // edx + char *v9; // ecx + int wa; // [esp+14h] [ebp+8h] + + v4 = w; + wa = 0; + v5 = 2 * v4; + v6 = 2 * x + 16; + for ( i = 2 * y + 16; wa < 2 * h; ++wa ) + { + if ( v5 > 0 ) + { + v8 = v5; + v9 = &dFlags[v6][wa + i]; + do + { + *v9 |= 8u; + v9 += 112; + --v8; + } + while ( v8 ); + } + } +} + +bool __fastcall DRLG_WillThemeRoomFit(int floor, int x, int y, int minSize, int maxSize, int *width, int *height) +{ + int v7; // esi + int v8; // edi + int v10; // ebx + int v11; // edx + unsigned char *v12; // eax + int v13; // eax + int i; // eax + int v15; // eax + int v16; // esi + int v17; // eax + int v18; // edx + int v19; // ecx + int v21; // eax + int v22; // esi + int yArray[20]; // [esp+8h] [ebp-BCh] + int xArray[20]; // [esp+58h] [ebp-6Ch] + int v25; // [esp+A8h] [ebp-1Ch] + int v26; // [esp+ACh] [ebp-18h] + int v27; // [esp+B0h] [ebp-14h] + int v28; // [esp+B4h] [ebp-10h] + char *v29; // [esp+B8h] [ebp-Ch] + int v30; // [esp+BCh] [ebp-8h] + int v31; // [esp+C0h] [ebp-4h] + + v28 = 1; + v27 = 1; + v7 = x; + v8 = 0; + v25 = floor; + v31 = 0; + v30 = 0; + if ( x > 40 - maxSize && y > 40 - maxSize ) + return 0; + if ( !SkipThemeRoom(x, y) ) + return 0; + memset(xArray, 0, 0x50u); + memset(yArray, 0, 0x50u); + if ( maxSize > 0 ) + { + v10 = 40 * v7; + v26 = 40 * v7; + v29 = dungeon[v7]; + do + { + if ( v27 ) + { + v11 = v7; + if ( v7 < v7 + maxSize ) + { + v12 = (unsigned char *)dungeon + v8 + v10 + y; + do + { + if ( *v12 == v25 ) + { + ++v31; + } + else + { + if ( v11 >= minSize ) + break; + v27 = 0; + } + ++v11; + v12 += 40; + } + while ( v11 < v7 + maxSize ); + v10 = v26; + } + if ( v27 ) + { + v13 = v31; + v31 = 0; + xArray[v8] = v13; + } + } + if ( v28 ) + { + for ( i = y; i < y + maxSize; ++i ) + { + if ( (unsigned char)v29[i] == v25 ) + { + ++v30; + } + else + { + if ( i >= minSize ) + break; + v28 = 0; + } + } + if ( v28 ) + { + v15 = v30; + v30 = 0; + yArray[v8] = v15; + } + } + v29 += 40; + ++v8; + } + while ( v8 < maxSize ); + v8 = 0; + } + v16 = minSize; + v17 = 0; + if ( minSize > 0 ) + { + while ( xArray[v17] >= minSize && yArray[v17] >= minSize ) + { + if ( ++v17 >= minSize ) + goto LABEL_32; + } + return 0; + } +LABEL_32: + v18 = xArray[0]; + v19 = yArray[0]; + if ( maxSize > 0 ) + { + while ( 1 ) + { + v21 = xArray[v8]; + if ( v21 < v16 ) + break; + v22 = yArray[v8]; + if ( v22 < minSize ) + break; + if ( v21 < v18 ) + v18 = xArray[v8]; + if ( v22 < v19 ) + v19 = yArray[v8]; + if ( ++v8 >= maxSize ) + break; + v16 = minSize; + } + } + *width = v18 - 2; + *height = v19 - 2; + return 1; +} +// 41965B: using guessed type int var_6C[20]; +// 41965B: using guessed type int var_BC[20]; + +void __fastcall DRLG_CreateThemeRoom(int themeIndex) +{ + int v1; // esi + int v2; // eax + int v3; // edi + int v4; // ebx + int v5; // ecx + int v6; // ecx + int v7; // ebx + int v8; // edx + int v9; // ebx + int v10; // edx + int v11; // ebx + int v12; // edx + int v13; // eax + int v14; // eax + int v15; // eax + int v16; // ecx + char *v17; // eax + int v18; // ecx + char *v19; // eax + int v20; // [esp+Ch] [ebp-8h] + char *v21; // [esp+10h] [ebp-4h] + + v1 = themeIndex; + v2 = themeLoc[themeIndex].y; + v3 = themeLoc[themeIndex].height; + v4 = v2; + v5 = v3 + v2; + if ( v2 < v3 + v2 ) + { + v20 = themeLoc[v1].x + themeLoc[v1].width; + while ( 1 ) + { + v6 = themeLoc[v1].x; + if ( v6 < v20 ) + break; +LABEL_52: + ++v4; + v5 = v3 + v2; + if ( v4 >= v3 + v2 ) + goto LABEL_53; + } + v21 = &dungeon[v6][v4]; + while ( 1 ) + { + if ( leveltype != DTYPE_CATACOMBS ) + goto LABEL_21; + if ( v4 == v2 && v6 >= themeLoc[v1].x && v6 <= v20 ) + goto LABEL_12; + if ( v4 != v3 + v2 - 1 ) + goto LABEL_13; + if ( v6 >= themeLoc[v1].x ) + break; +LABEL_16: + if ( v6 == v20 - 1 && v4 >= v2 && v4 <= v3 + v2 ) + goto LABEL_19; + *v21 = 3; +LABEL_21: + if ( leveltype == DTYPE_CAVES ) + { + if ( v4 == v2 && v6 >= themeLoc[v1].x && v6 <= v20 ) + { +LABEL_28: + *v21 = -122; + goto LABEL_51; + } + if ( v4 == v3 + v2 - 1 ) + { + if ( v6 >= themeLoc[v1].x ) + { + if ( v6 <= v20 ) + goto LABEL_28; + goto LABEL_29; + } + } + else + { +LABEL_29: + if ( v6 == themeLoc[v1].x && v4 >= v2 && v4 <= v3 + v2 ) + { +LABEL_35: + *v21 = -119; + goto LABEL_51; + } + } + if ( v6 == v20 - 1 && v4 >= v2 && v4 <= v3 + v2 ) + goto LABEL_35; + *v21 = 7; + } + if ( leveltype != DTYPE_HELL ) + goto LABEL_51; + if ( v4 != v2 || v6 < themeLoc[v1].x || v6 > v20 ) + { + if ( v4 != v3 + v2 - 1 ) + goto LABEL_44; + if ( v6 < themeLoc[v1].x ) + goto LABEL_47; + if ( v6 > v20 ) + { +LABEL_44: + if ( v6 != themeLoc[v1].x || v4 < v2 || v4 > v3 + v2 ) + { +LABEL_47: + if ( v6 != v20 - 1 || v4 < v2 || v4 > v3 + v2 ) + { + *v21 = 6; + goto LABEL_51; + } + } +LABEL_19: + *v21 = 1; + goto LABEL_51; + } + } +LABEL_12: + *v21 = 2; +LABEL_51: + v21 += 40; + if ( ++v6 >= v20 ) + goto LABEL_52; + } + if ( v6 <= v20 ) + goto LABEL_12; +LABEL_13: + if ( v6 == themeLoc[v1].x && v4 >= v2 && v4 <= v3 + v2 ) + goto LABEL_19; + goto LABEL_16; + } +LABEL_53: + if ( leveltype == DTYPE_CATACOMBS ) + { + v7 = themeLoc[v1].x; + v8 = 10 * (v7 + themeLoc[v1].width); + dungeon[v7][v2] = 8; + v5 = v3 + 40 * v7; + dungeon[-1][v8 * 4 + v2] = 7; // *((_BYTE *)&dMonster[111][v8 + 102] + v2) = 7; /* check */ + dungeon[0][v5 + v2 - 1] = 9; // *((_BYTE *)&dMonster[111][111] + v5 + v2 + 3) = 9; + dungeon[-1][v3 + v8 * 4 + v2 - 1] = 6; // *((_BYTE *)&dMonster[111][101] + v3 + v8 * 4 + v2 + 3) = 6; + } + if ( leveltype == DTYPE_CAVES ) + { + v9 = themeLoc[v1].x; + v10 = 10 * (v9 + themeLoc[v1].width); + dungeon[v9][v2] = 150; + v5 = v3 + 40 * v9; + dungeon[-1][v10 * 4 + v2] = 151; // *((_BYTE *)&dMonster[111][v10 + 102] + v2) = -105; + dungeon[0][v5 + v2 - 1] = 152; // *((_BYTE *)&dMonster[111][111] + v5 + v2 + 3) = -104; + dungeon[-1][v3 + v10 * 4 + v2 - 1] = 138; // *((_BYTE *)&dMonster[111][101] + v3 + v10 * 4 + v2 + 3) = -118; + } + if ( leveltype == DTYPE_HELL ) + { + v11 = themeLoc[v1].x; + v12 = 10 * (v11 + themeLoc[v1].width); + dungeon[v11][v2] = 9; + v5 = v3 + 40 * v11; + dungeon[-1][v12 * 4 + v2] = 16; // *((_BYTE *)&dMonster[111][v12 + 102] + v2) = 16; + dungeon[0][v5 + v2 - 1] = 15; // *((_BYTE *)&dMonster[111][111] + v5 + v2 + 3) = 15; + dungeon[-1][v3 + v12 * 4 + v2 - 1] = 12; // *((_BYTE *)&dMonster[111][101] + v3 + v12 * 4 + v2 + 3) = 12; + } + if ( leveltype == DTYPE_CATACOMBS ) + { + v13 = random(0, 2); + if ( v13 ) + { + if ( v13 == 1 ) + { + v5 = themeLoc[v1].height; + dungeon[themeLoc[v1].x + themeLoc[v1].width / 2][themeLoc[v1].y + v5 - 1] = 5; /* + *((_BYTE *)&dMonster[111][10 * (themeLoc[v1].x + themeLoc[v1].width / 2) + 111] + themeLoc[v1].y + + v5 + + 3) = 5; */ + } + } + else + { + v5 = themeLoc[v1].y; + dungeon[themeLoc[v1].x + themeLoc[v1].width -1][themeLoc[v1].height / 2 + v5] = 4; + // *((_BYTE *)&dMonster[111][10 * (themeLoc[v1].x + themeLoc[v1].width) + 102] + themeLoc[v1].height / 2 + v5) = 4; + } + } + if ( leveltype == DTYPE_CAVES ) + { + v14 = random(0, 2); + if ( v14 ) + { + if ( v14 == 1 ) + { + v5 = themeLoc[v1].height; + dungeon[themeLoc[v1].x + themeLoc[v1].width / 2][themeLoc[v1].y + v5 - 1] = 146; /* + *((_BYTE *)&dMonster[111][10 * (themeLoc[v1].x + themeLoc[v1].width / 2) + 111] + themeLoc[v1].y + + v5 + + 3) = -110; */ + } + } + else + { + v5 = themeLoc[v1].y; + dungeon[themeLoc[v1].x + themeLoc[v1].width -1][themeLoc[v1].height / 2 + v5] = 147; + // *((_BYTE *)&dMonster[111][10 * (themeLoc[v1].x + themeLoc[v1].width) + 102] + themeLoc[v1].height / 2 + v5) = -109; + } + } + if ( leveltype == DTYPE_HELL ) + { + v15 = random(0, 2); + if ( v15 ) + { + if ( v15 == 1 ) + { + v16 = themeLoc[v1].y + 40 * (themeLoc[v1].x + themeLoc[v1].width / 2) + themeLoc[v1].height; + v17 = (char *)dungeon + v16; + *(v17 - 41) = 57; + *(v17 - 1) = 6; + dungeon[0][v16 + 39] = 56; + *(v17 - 2) = 59; + *(v17 - 42) = 58; + } + } + else + { + v18 = themeLoc[v1].height / 2 + 40 * (themeLoc[v1].x + themeLoc[v1].width) + themeLoc[v1].y; + v19 = (char *)dungeon + v18; + *(v19 - 41) = 53; + *(v19 - 40) = 6; + dungeon[0][v18 - 39] = 52; // *((_BYTE *)&dMonster[111][102] + v18 + 1) = 52; + *(v19 - 81) = 54; + } + } +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall DRLG_PlaceThemeRooms(int minSize, int maxSize, int floor, int freq, int rndSize) +{ + int v5; // ebx + //int v7; // eax + int v8; // esi + int v9; // edi + int v10; // eax + int v12; // eax + int v14; // eax + int v16; // eax + int v17; // edi + int v18; // esi + int v19; // ecx + int v20; // ecx + int v21; // eax + int minSize2; // [esp+10h] [ebp-1Ch] + int maxSize2; // [esp+14h] [ebp-18h] + unsigned char *v24; // [esp+18h] [ebp-14h] + signed int x_start; // [esp+1Ch] [ebp-10h] + int x; // [esp+20h] [ebp-Ch] + int width; // [esp+24h] [ebp-8h] + int height; // [esp+28h] [ebp-4h] + + v5 = 0; + maxSize2 = maxSize; + minSize2 = minSize; + themeCount = 0; + memset(themeLoc, 0, 0x14u); + do + { + x = 0; + x_start = 20; + v24 = (unsigned char *)dungeon + v5; + do + { + if ( *v24 == floor ) + { + if ( !random(0, freq) ) + { + //_LOBYTE(v7) = DRLG_WillThemeRoomFit(floor, x, v5, minSize2, maxSize2, &width, &height); + if ( DRLG_WillThemeRoomFit(floor, x, v5, minSize2, maxSize2, &width, &height) ) + { + if ( rndSize ) + { + v8 = minSize2 - 2; + v9 = maxSize2 - 2; + v10 = random(0, width - (minSize2 - 2) + 1); + v12 = minSize2 - 2 + random(0, v10); + if ( v12 < minSize2 - 2 || (width = v12, v12 > v9) ) + width = minSize2 - 2; + v14 = random(0, height - v8 + 1); + v16 = v8 + random(0, v14); + if ( v16 < v8 || v16 > v9 ) + v16 = minSize2 - 2; + height = v16; + } + else + { + v16 = height; + } + v17 = themeCount; + v18 = themeCount; + themeLoc[v18].x = x + 1; + themeLoc[v18].y = v5 + 1; + v19 = width; + themeLoc[v18].width = width; + themeLoc[v18].height = v16; + v20 = x + v19; + v21 = v5 + v16; + if ( leveltype == DTYPE_CAVES ) + DRLG_RectTrans(x_start, 2 * v5 + 20, 2 * v20 + 15, 2 * v21 + 15); + else + DRLG_MRectTrans(x + 1, v5 + 1, v20, v21); + themeLoc[v18].ttval = TransVal - 1; + DRLG_CreateThemeRoom(v17); + ++themeCount; + } + } + } + x_start += 2; + ++x; + v24 += 40; + } + while ( x_start < 100 ); + ++v5; + } + while ( v5 < 40 ); +} +// 5A5590: using guessed type char TransVal; +// 5BB1ED: using guessed type char leveltype; + +void __cdecl DRLG_HoldThemeRooms() +{ + int *v0; // esi + int v1; // edi + int v2; // edx + int v3; // ebx + int v4; // edi + int v5; // ecx + int v6; // eax + int v7; // [esp+0h] [ebp-Ch] + int v8; // [esp+4h] [ebp-8h] + int v9; // [esp+8h] [ebp-4h] + + if ( themeCount > 0 ) + { + v0 = &themeLoc[0].height; + v8 = themeCount; + do + { + v1 = *(v0 - 3); + if ( v1 < v1 + *v0 - 1 ) + { + v2 = *(v0 - 4); + v3 = 2 * v1 + 16; + v7 = v2 + *(v0 - 1) - 1; + v9 = *v0 - 1; + do + { + if ( v2 < v7 ) + { + v4 = 224 * (v2 + 8); + v5 = v7 - v2; + do + { + v6 = v3 + v4; + v4 += 224; + dFlags[0][v6] |= 8u; + dFlags[1][v6] |= 8u; + dFlags[0][v6 + 1] |= 8u; + dFlags[1][v6 + 1] |= 8u; + --v5; + } + while ( v5 ); + } + v3 += 2; + --v9; + } + while ( v9 ); + } + v0 += 5; + --v8; + } + while ( v8 ); + } +} + +bool __fastcall SkipThemeRoom(int x, int y) +{ + int i; // ebx + THEME_LOC *v3; // eax + int v4; // esi + + i = 0; + if ( themeCount <= 0 ) + return 1; + v3 = themeLoc; + while ( 1 ) + { + if ( x >= v3->x - 2 && x <= v3->x + v3->width + 2 ) + { + v4 = v3->y; + if ( y >= v4 - 2 && y <= v4 + v3->height + 2 ) + break; + } + ++i; + ++v3; + if ( i >= themeCount ) + return 1; + } + return 0; +} + +void __cdecl InitLevels() +{ + if ( !leveldebug ) + { + currlevel = 0; + leveltype = 0; + setlevel = 0; + } +} +// 52572C: using guessed type int leveldebug; +// 5BB1ED: using guessed type char leveltype; +// 5CF31D: using guessed type char setlevel; diff --git a/Source/gendung.h b/Source/gendung.h new file mode 100644 index 000000000..f95d93b0e --- /dev/null +++ b/Source/gendung.h @@ -0,0 +1,95 @@ +//HEADER_GOES_HERE +#ifndef __GENDUNG_H__ +#define __GENDUNG_H__ + +extern short level_frame_types[2048]; +extern int themeCount; +extern char nTransTable[2049]; +//int dword_52D204; +extern int dMonster[MAXDUNX][MAXDUNY]; +extern char dungeon[40][40]; +extern char dObject[MAXDUNX][MAXDUNY]; +extern void *pSpeedCels; +extern int nlevel_frames; // weak +extern char pdungeon[40][40]; +extern char dDead[MAXDUNX][MAXDUNY]; +extern short dpiece_defs_map_1[16][MAXDUNX][MAXDUNY]; +extern char dTransVal2[MAXDUNX][MAXDUNY]; +extern char TransVal; // weak +extern int dword_5A5594; +extern char dflags[40][40]; +extern int dPiece[MAXDUNX][MAXDUNY]; +extern char dTransVal[MAXDUNX][MAXDUNY]; +extern int setloadflag_2; // weak +extern int tile_defs[2048]; +extern void *pMegaTiles; +extern void *pLevelPieces; +extern int gnDifficulty; // idb +extern char block_lvid[2049]; +//char byte_5B78EB; +extern char dung_map[MAXDUNX][MAXDUNY]; +extern char nTrapTable[2049]; +extern char leveltype; // weak +extern unsigned char currlevel; // idb +extern char TransList[256]; +extern UCHAR nSolidTable[2049]; +extern int level_frame_count[2048]; +extern ScrollStruct ScrollInfo; +extern void *pDungeonCels; +extern int speed_cel_frame_num_from_light_index_frame_num[16][128]; +extern THEME_LOC themeLoc[MAXTHEMES]; +extern char dPlayer[MAXDUNX][MAXDUNY]; +extern int dword_5C2FF8; // weak +extern int dword_5C2FFC; // weak +extern int scr_pix_width; // weak +extern int scr_pix_height; // weak +extern char dArch[MAXDUNX][MAXDUNY]; +extern char nBlockTable[2049]; +extern void *level_special_cel; +extern char dFlags[MAXDUNX][MAXDUNY]; +extern char dItem[MAXDUNX][MAXDUNY]; +extern char setlvlnum; // weak +extern int level_frame_sizes[2048]; +extern char nMissileTable[2049]; +extern char *pSetPiece_2; +extern char setlvltype; // weak +extern char setlevel; // weak +extern int LvlViewY; // weak +extern int LvlViewX; // weak +extern int dmaxx; // weak +extern int dmaxy; // weak +extern int setpc_h; // weak +extern int setpc_w; // weak +extern int setpc_x; // idb +extern int ViewX; // idb +extern int ViewY; // idb +extern int setpc_y; // idb +extern char dMissile[MAXDUNX][MAXDUNY]; +extern int dminx; // weak +extern int dminy; // weak +extern short dpiece_defs_map_2[16][MAXDUNX][MAXDUNY]; + +void __cdecl FillSolidBlockTbls(); +void __cdecl gendung_418D91(); +void __fastcall gendung_4191BF(int frames); +void __fastcall gendung_4191FB(int a1, int a2); +int __fastcall gendung_get_dpiece_num_from_coord(int x, int y); +void __cdecl gendung_4192C2(); +void __cdecl SetDungeonMicros(); +void __cdecl DRLG_InitTrans(); +void __fastcall DRLG_MRectTrans(int x1, int y1, int x2, int y2); +void __fastcall DRLG_RectTrans(int x1, int y1, int x2, int y2); +void __fastcall DRLG_CopyTrans(int sx, int sy, int dx, int dy); +void __fastcall DRLG_ListTrans(int num, unsigned char *List); +void __fastcall DRLG_AreaTrans(int num, unsigned char *List); +void __cdecl DRLG_InitSetPC(); +void __cdecl DRLG_SetPC(); +void __fastcall Make_SetPC(int x, int y, int w, int h); +bool __fastcall DRLG_WillThemeRoomFit(int floor, int x, int y, int minSize, int maxSize, int *width, int *height); +void __fastcall DRLG_CreateThemeRoom(int themeIndex); +void __fastcall DRLG_PlaceThemeRooms(int minSize, int maxSize, int floor, int freq, int rndSize); +void __cdecl DRLG_HoldThemeRooms(); +bool __fastcall SkipThemeRoom(int x, int y); +void __cdecl InitLevels(); + +#endif /* __GENDUNG_H__ */ diff --git a/Source/gmenu.cpp b/Source/gmenu.cpp new file mode 100644 index 000000000..df197817d --- /dev/null +++ b/Source/gmenu.cpp @@ -0,0 +1,511 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +void *optbar_cel; +bool byte_634464; // weak +void *PentSpin_cel; +TMenuItem *sgpCurrItem; +void *BigTGold_cel; +int dword_634474; // weak +char byte_634478; // weak +void (__cdecl *dword_63447C)(); +TMenuItem *dword_634480; // idb +void *option_cel; +void *sgpLogo; +int dword_63448C; // weak +#endif + +const unsigned char lfontframe[127] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 49, 38, 0, 39, 40, 47, + 42, 43, 41, 45, 52, 44, 53, 55, 36, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 51, 50, + 0, 46, 0, 54, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 42, 0, 43, 0, 0, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 20, 0, 21, 0 +}; +const unsigned char lfontkern[56] = +{ + 18, 33, 21, 26, 28, 19, 19, 26, 25, 11, + 12, 25, 19, 34, 28, 32, 20, 32, 28, 20, + 28, 36, 35, 46, 33, 33, 24, 11, 23, 22, + 22, 21, 22, 21, 21, 21, 32, 10, 20, 36, + 31, 17, 13, 12, 13, 18, 16, 11, 20, 21, + 11, 10, 12, 11, 21, 23 +}; + +void __cdecl gmenu_draw_pause() +{ + if ( currlevel ) + RedBack(); + if ( !dword_634480 ) + { + light_table_index = 0; + gmenu_print_text(316, 336, "Pause"); + } +} +// 69BEF8: using guessed type int light_table_index; + +void __fastcall gmenu_print_text(int x, int y, char *pszStr) +{ + char *v3; // edi + int v4; // ebp + int v5; // esi + unsigned char i; // al + unsigned char v7; // bl + + v3 = pszStr; + v4 = y; + v5 = x; + for ( i = *pszStr; *v3; i = *v3 ) + { + ++v3; + v7 = lfontframe[fontidx[i]]; + if ( v7 ) + CelDecodeLightOnly(v5, v4, (char *)BigTGold_cel, v7, 46); + v5 += lfontkern[v7] + 2; + } +} + +void __cdecl FreeGMenu() +{ + void *v0; // ecx + void *v1; // ecx + void *v2; // ecx + void *v3; // ecx + void *v4; // ecx + + v0 = sgpLogo; + sgpLogo = 0; + mem_free_dbg(v0); + v1 = BigTGold_cel; + BigTGold_cel = 0; + mem_free_dbg(v1); + v2 = PentSpin_cel; + PentSpin_cel = 0; + mem_free_dbg(v2); + v3 = option_cel; + option_cel = 0; + mem_free_dbg(v3); + v4 = optbar_cel; + optbar_cel = 0; + mem_free_dbg(v4); +} + +void __cdecl gmenu_init_menu() +{ + byte_634478 = 1; + dword_634480 = 0; + sgpCurrItem = 0; + dword_63447C = 0; + dword_63448C = 0; + byte_634464 = 0; + sgpLogo = LoadFileInMem("Data\\Diabsmal.CEL", 0); + BigTGold_cel = LoadFileInMem("Data\\BigTGold.CEL", 0); + PentSpin_cel = LoadFileInMem("Data\\PentSpin.CEL", 0); + option_cel = LoadFileInMem("Data\\option.CEL", 0); + optbar_cel = LoadFileInMem("Data\\optbar.CEL", 0); +} +// 634464: using guessed type char byte_634464; +// 634478: using guessed type char byte_634478; +// 63448C: using guessed type int dword_63448C; + +bool __cdecl gmenu_exception() +{ + return dword_634480 != 0; +} + +void __fastcall gmenu_call_proc(TMenuItem *pItem, void (__cdecl *gmFunc)()) +{ + TMenuItem *v2; // eax + int v3; // ecx + void (__cdecl **v4)(); // edx + + PauseMode = 0; + byte_634464 = 0; + v2 = pItem; + dword_63447C = gmFunc; + dword_634480 = pItem; + if ( gmFunc ) + { + gmFunc(); + v2 = dword_634480; + } + v3 = 0; + dword_63448C = 0; + if ( v2 ) + { + v4 = &v2->fnMenu; + while ( *v4 ) + { + ++v3; + v4 += 3; + dword_63448C = v3; + } + } + sgpCurrItem = &v2[v3 - 1]; + gmenu_up_down(1); +} +// 525740: using guessed type int PauseMode; +// 634464: using guessed type char byte_634464; +// 63448C: using guessed type int dword_63448C; + +void __fastcall gmenu_up_down(int a1) +{ + TMenuItem *v1; // eax + int v2; // edi + + v1 = sgpCurrItem; + if ( sgpCurrItem ) + { + byte_634464 = 0; + v2 = dword_63448C; + while ( v2 ) + { + --v2; + if ( a1 ) + { + ++v1; + sgpCurrItem = v1; + if ( v1->fnMenu ) + goto LABEL_10; + v1 = dword_634480; + } + else + { + if ( v1 == dword_634480 ) + v1 = &dword_634480[dword_63448C]; + --v1; + } + sgpCurrItem = v1; +LABEL_10: + if ( (v1->dwFlags & 0x80000000) != 0 ) + { + if ( v2 ) + PlaySFX(IS_TITLEMOV); + return; + } + } + } +} +// 634464: using guessed type char byte_634464; +// 63448C: using guessed type int dword_63448C; + +void __cdecl gmenu_draw() +{ + int v0; // edi + TMenuItem *i; // esi + DWORD v2; // eax + + if ( dword_634480 ) + { + if ( dword_63447C ) + dword_63447C(); + CelDecodeOnly(236, 262, sgpLogo, 1, 296); + v0 = 320; + for ( i = dword_634480; i->fnMenu; v0 += 45 ) + { + gmenu_draw_menu_item(i, v0); + ++i; + } + v2 = GetTickCount(); + if ( (signed int)(v2 - dword_634474) > 25 ) + { + if ( ++byte_634478 == 9 ) + byte_634478 = 1; + dword_634474 = v2; + } + } +} +// 634474: using guessed type int dword_634474; +// 634478: using guessed type char byte_634478; + +void __fastcall gmenu_draw_menu_item(TMenuItem *pItem, int a2) +{ + int v2; // edi + TMenuItem *v3; // ebx + unsigned int v4; // eax + unsigned int v5; // ebp + int v6; // esi + unsigned int v7; // ecx + unsigned int v8; // eax + int v9; // ecx + unsigned int v10; // ebp + int v11; // esi + int v12; // eax + int v13; // edi + unsigned int v14; // [esp+10h] [ebp-4h] + + v2 = a2; + v3 = pItem; + v4 = gmenu_get_lfont(pItem); + v5 = v4; + v14 = v4; + if ( v3->dwFlags & 0x40000000 ) + { + v6 = (v4 >> 1) + 80; + CelDecodeOnly(v6, v2 - 10, optbar_cel, 1, 287); + v7 = (v3->dwFlags >> 12) & 0xFFF; + if ( v7 < 2 ) + v7 = 2; + v8 = ((v3->dwFlags & 0xFFF) << 8) / v7; + v9 = (v5 >> 1) + 82; + v10 = v8; + gmenu_clear_buffer(v9, v2 - 12, v8 + 13, 28); + CelDecodeOnly(v6 + v10 + 2, v2 - 12, option_cel, 1, 27); + v5 = v14; + } + v11 = 384 - (v5 >> 1); + v12 = -((v3->dwFlags & 0x80000000) != 0); + _LOBYTE(v12) = v12 & 0xF1; + light_table_index = v12 + 15; + gmenu_print_text(384 - (v5 >> 1), v2, v3->pszStr); + if ( v3 == sgpCurrItem ) + { + v13 = v2 + 1; + CelDecodeOnly(v11 - 54, v13, PentSpin_cel, (unsigned char)byte_634478, 48); + CelDecodeOnly(v11 + v5 + 4, v13, PentSpin_cel, (unsigned char)byte_634478, 48); + } +} +// 634478: using guessed type char byte_634478; +// 69BEF8: using guessed type int light_table_index; + +void __fastcall gmenu_clear_buffer(int x, int y, int width, int height) +{ + int v4; // edi + char *i; // esi + + v4 = height; + for ( i = (char *)gpBuffer + screen_y_times_768[y] + x; v4; --v4 ) + { + memset(i, 205, width); + i -= 768; + } +} + +int __fastcall gmenu_get_lfont(TMenuItem *pItem) +{ + char *v2; // eax + int i; // edx + unsigned char v4; // cl + + if ( pItem->dwFlags & 0x40000000 ) + return 490; + v2 = pItem->pszStr; + for ( i = 0; ; i += lfontkern[lfontframe[fontidx[v4]]] + 2 ) + { + v4 = *v2; + if ( !*v2 ) + break; + ++v2; + } + return i - 2; +} + +int __fastcall gmenu_presskeys(int a1) +{ + int v1; // ecx + int v2; // ecx + + if ( !dword_634480 ) + return 0; + switch ( a1 ) + { + case VK_RETURN: + if ( (sgpCurrItem->dwFlags & 0x80000000) != 0 ) + { + PlaySFX(IS_TITLEMOV); + ((void (__fastcall *)(signed int))sgpCurrItem->fnMenu)(1); + } + return 1; + case VK_ESCAPE: + PlaySFX(IS_TITLEMOV); + gmenu_call_proc(0, 0); + return 1; + case VK_SPACE: + return 0; + case VK_LEFT: + v2 = 0; + goto LABEL_12; + case VK_UP: + v1 = 0; + goto LABEL_10; + case VK_RIGHT: + v2 = 1; +LABEL_12: + gmenu_left_right(v2); + return 1; + case VK_DOWN: + v1 = 1; +LABEL_10: + gmenu_up_down(v1); + break; + } + return 1; +} + +void __fastcall gmenu_left_right(int a1) +{ + signed int v1; // edx + unsigned int v2; // eax + int v3; // eax + + v1 = sgpCurrItem->dwFlags; + if ( sgpCurrItem->dwFlags & 0x40000000 ) + { + v2 = sgpCurrItem->dwFlags & 0xFFF; + if ( a1 ) + { + if ( v2 == ((v1 >> 12) & 0xFFF) ) + return; + v3 = v2 + 1; + } + else + { + if ( !(v1 & 0xFFF) ) + return; + v3 = v2 - 1; + } + _LOWORD(v1) = v1 & 0xF000; + sgpCurrItem->dwFlags = v1; + sgpCurrItem->dwFlags |= v3; + ((void (__fastcall *)(_DWORD))sgpCurrItem->fnMenu)(0); + } +} + +int __fastcall gmenu_on_mouse_move(LPARAM lParam) +{ + int v2; // edx + int a1; // [esp+0h] [ebp-4h] + + a1 = lParam; + if ( !byte_634464 ) + return 0; + gmenu_valid_mouse_pos(&a1); + v2 = a1 * ((sgpCurrItem->dwFlags >> 12) & 0xFFF) % 256; + a1 = a1 * ((sgpCurrItem->dwFlags >> 12) & 0xFFF) / 256; + _LOWORD(sgpCurrItem->dwFlags) &= 0xF000u; + sgpCurrItem->dwFlags |= a1; + ((void (__fastcall *)(_DWORD, int))sgpCurrItem->fnMenu)(0, v2); + return 1; +} +// 41A37A: could not find valid save-restore pair for esi +// 634464: using guessed type char byte_634464; + +bool __fastcall gmenu_valid_mouse_pos(int *plOffset) +{ + *plOffset = 282; + if ( MouseX < 282 ) + { + *plOffset = 0; + return 0; + } + if ( MouseX > 538 ) + { + *plOffset = 256; + return 0; + } + *plOffset = MouseX - 282; + return 1; +} + +int __fastcall gmenu_left_mouse(int a1) +{ + int result; // eax + unsigned int v2; // eax + unsigned int v3; // eax + TMenuItem *v4; // esi + unsigned int v5; // eax + //LPARAM v6; // ecx + int a1a; // [esp+4h] [ebp-4h] + + if ( a1 ) + { + if ( !dword_634480 || MouseY >= 352 ) + return 0; + if ( MouseY - 117 >= 0 ) + { + v2 = (MouseY - 117) / 45; + if ( v2 < dword_63448C ) + { + v3 = v2; + v4 = &dword_634480[v3]; + if ( (v4->dwFlags & 0x80000000) != 0 ) + { + v5 = (unsigned int)gmenu_get_lfont(&dword_634480[v3]) >> 1; + if ( MouseX >= 320 - v5 && MouseX <= v5 + 320 ) + { + sgpCurrItem = v4; + PlaySFX(IS_TITLEMOV); + if ( v4->dwFlags & 0x40000000 ) + { + byte_634464 = gmenu_valid_mouse_pos(&a1a); + gmenu_on_mouse_move(a1); /* v6 */ + } + else + { + ((void (__fastcall *)(signed int))sgpCurrItem->fnMenu)(1); + } + } + } + } + } + } + else + { + result = 0; + if ( !byte_634464 ) + return result; + byte_634464 = 0; + } + return 1; +} +// 634464: using guessed type char byte_634464; +// 63448C: using guessed type int dword_63448C; + +void __fastcall gmenu_enable(TMenuItem *pMenuItem, bool enable) +{ + if ( enable ) + pMenuItem->dwFlags |= 0x80000000; + else + pMenuItem->dwFlags &= 0x7F000000; +} + +void __fastcall gmenu_slider_1(TMenuItem *pItem, int min, int max, int gamma) +{ + unsigned int v4; // esi + int v5; // eax + + v4 = pItem->dwFlags; + v5 = (pItem->dwFlags >> 12) & 0xFFF; + if ( v5 < 2 ) + v5 = 2; + _LOWORD(v4) = v4 & 0xF000; + pItem->dwFlags = v4 | (v5 * (gamma - min) + (max - min - 1) / 2) / (max - min); +} + +int __fastcall gmenu_slider_get(TMenuItem *pItem, int min, int max) +{ + int v3; // eax + unsigned int v4; // ecx + + v3 = (pItem->dwFlags >> 12) & 0xFFF; + v4 = pItem->dwFlags & 0xFFF; + if ( v3 < 2 ) + v3 = 2; + return min + (v4 * (max - min) + (v3 - 1) / 2) / v3; +} + +void __fastcall gmenu_slider_3(TMenuItem *pItem, int dwTicks) +{ + pItem->dwFlags ^= (pItem->dwFlags ^ (dwTicks << 12)) & 0xFFF000; +} diff --git a/Source/gmenu.h b/Source/gmenu.h new file mode 100644 index 000000000..5350d7c8e --- /dev/null +++ b/Source/gmenu.h @@ -0,0 +1,44 @@ +//HEADER_GOES_HERE +#ifndef __GMENU_H__ +#define __GMENU_H__ + +extern void *optbar_cel; +extern bool byte_634464; // weak +extern void *PentSpin_cel; +extern TMenuItem *sgpCurrItem; +extern void *BigTGold_cel; +extern int dword_634474; // weak +extern char byte_634478; // weak +extern void (__cdecl *dword_63447C)(); +extern TMenuItem *dword_634480; // idb +extern void *option_cel; +extern void *sgpLogo; +extern int dword_63448C; // weak + +void __cdecl gmenu_draw_pause(); +void __fastcall gmenu_print_text(int x, int y, char *pszStr); +void __cdecl FreeGMenu(); +void __cdecl gmenu_init_menu(); +bool __cdecl gmenu_exception(); +void __fastcall gmenu_call_proc(TMenuItem *pItem, void (__cdecl *gmFunc)()); +void __fastcall gmenu_up_down(int a1); +void __cdecl gmenu_draw(); +void __fastcall gmenu_draw_menu_item(TMenuItem *pItem, int a2); +void __fastcall gmenu_clear_buffer(int x, int y, int width, int height); +int __fastcall gmenu_get_lfont(TMenuItem *pItem); +int __fastcall gmenu_presskeys(int a1); +void __fastcall gmenu_left_right(int a1); +int __fastcall gmenu_on_mouse_move(LPARAM lParam); +bool __fastcall gmenu_valid_mouse_pos(int *plOffset); +int __fastcall gmenu_left_mouse(int a1); +void __fastcall gmenu_enable(TMenuItem *pMenuItem, bool enable); +void __fastcall gmenu_slider_1(TMenuItem *pItem, int min, int max, int gamma); +int __fastcall gmenu_slider_get(TMenuItem *pItem, int min, int max); +void __fastcall gmenu_slider_3(TMenuItem *pItem, int dwTicks); + +/* rdata */ + +extern const unsigned char lfontframe[127]; +extern const unsigned char lfontkern[56]; + +#endif /* __GMENU_H__ */ diff --git a/Source/help.cpp b/Source/help.cpp new file mode 100644 index 000000000..72b81c195 --- /dev/null +++ b/Source/help.cpp @@ -0,0 +1,272 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int help_select_line; // weak +int dword_634494; // weak +int helpflag; +int displayinghelp[22]; /* check, does nothing? */ +int HelpTop; // weak +#endif + +const char gszHelpText[] = +{ + "$Keyboard Shortcuts:|" + "F1: Open Help Screen|" + "Esc: Display Main Menu|" + "Tab: Display Auto-map|" + "Space: Hide all info screens|" + "S: Open Speedbook|" + "B: Open Spellbook|" + "I: Open Inventory screen|" + "C: Open Character screen|" + "Q: Open Quest log|" + "F: Reduce screen brightness|" + "G: Increase screen brightness|" + "Z: Zoom Game Screen|" + "+ / -: Zoom Automap|" + "1 - 8: Use Belt item|" + "F5, F6, F7, F8: Set hot key for skill or spell|" + "Shift + Left Click: Attack without moving|" + "|" + "$Movement:|" + "If you hold the mouse button down while moving, the character " + "will continue to move in that direction.|" + "|" + "$Combat:|" + "Holding down the shift key and then left-clicking allows the " + "character to attack without moving.|" + "|" + "$Auto-map:|" + "To access the auto-map, click the 'MAP' button on the " + "Information Bar or press 'TAB' on the keyboard. Zooming in and " + "out of the map is done with the + and - keys. Scrolling the map " + "uses the arrow keys.|" + "|" + "$Picking up Objects:|" + "Useable items that are small in size, such as potions or scrolls, " + "are automatically placed in your 'belt' located at the top of " + "the Interface bar . When an item is placed in the belt, a small " + "number appears in that box. Items may be used by either pressing " + "the corresponding number or right-clicking on the item.|" + "|" + "$Gold|" + "You can select a specific amount of gold to drop by right " + "clicking on a pile of gold in your inventory.|" + "|" + "$Skills & Spells:|" + "You can access your list of skills and spells by left-clicking on " + "the 'SPELLS' button in the interface bar. Memorized spells and " + "those available through staffs are listed here. Left-clicking on " + "the spell you wish to cast will ready the spell. A readied spell " + "may be cast by simply right-clicking in the play area.|" + "|" + "$Using the Speedbook for Spells|" + "Left-clicking on the 'readied spell' button will open the 'Speedbook' " + "which allows you to select a skill or spell for immediate use. " + "To use a readied skill or spell, simply right-click in the main play " + "area.|" + "|" + "$Setting Spell Hotkeys|" + "You can assign up to four Hot Keys for skills, spells or scrolls. " + "Start by opening the 'speedbook' as described in the section above. " + "Press the F5, F6, F7 or F8 keys after highlighting the spell you " + "wish to assign.|" + "|" + "$Spell Books|" + "Reading more than one book increases your knowledge of that " + "spell, allowing you to cast the spell more effectively.|" + "&" +}; + +void __cdecl InitHelp() +{ + helpflag = 0; + dword_634494 = 0; + displayinghelp[0] = 0; +} +// 634494: using guessed type int dword_634494; + +void __cdecl DrawHelp() +{ + int v0; // edi + const char *v1; // esi + int v2; // edx + signed int v3; // ecx + char v4; // al + unsigned char v5; // al + _BYTE *i; // eax + int v7; // eax + signed int v8; // edx + char v9; // cl + unsigned char v10; // cl + text_color color; // [esp+Ch] [ebp-8h] + int help_line_nr; // [esp+10h] [ebp-4h] + signed int help_line_nra; // [esp+10h] [ebp-4h] + + DrawSTextHelp(); + DrawQTextBack(); + PrintSString(0, 2, 1u, "Diablo Help", COL_GOLD, 0); + DrawSLine(5); + v0 = help_select_line; + v1 = gszHelpText; + if ( help_select_line > 0 ) + { + help_line_nr = help_select_line; + do + { + v2 = 0; + v3 = 0; + while ( !*v1 ) + ++v1; + if ( *v1 == '$' ) + ++v1; + v4 = *v1; + if ( *v1 != '&' ) + { + if ( v4 == ('|') ) + goto LABEL_47; + while ( v3 < 577 ) + { + if ( !v4 ) + { + do + ++v1; + while ( !*v1 ); + } + v5 = *v1; + tempstr[v2++] = *v1++; + v3 += fontkern[fontframe[fontidx[v5]]] + 1; + v4 = *v1; + if ( *v1 == ('|') ) + { + if ( v3 < 577 ) + goto LABEL_18; + break; + } + } + for ( i = (unsigned char *)&tempstr[v2]-1; *i != ' '; --i ) + --v1; +LABEL_18: + if ( *v1 == ('|') ) +LABEL_47: + ++v1; + } + --help_line_nr; + } + while ( help_line_nr ); + } + help_line_nra = 7; + do + { + v7 = 0; + v8 = 0; + while ( !*v1 ) + ++v1; + if ( *v1 == '$' ) + { + ++v1; + _LOBYTE(color) = COL_RED; + } + else + { + _LOBYTE(color) = COL_WHITE; + } + v9 = *v1; + if ( *v1 == '&' ) + { + HelpTop = v0; + } + else + { + if ( v9 == ('|') ) + goto LABEL_48; + while ( v8 < 577 ) + { + if ( !v9 ) + { + do + ++v1; + while ( !*v1 ); + } + v10 = *v1; + tempstr[v7++] = *v1++; + v8 += fontkern[fontframe[fontidx[v10]]] + 1; + v9 = *v1; + if ( *v1 == ('|') ) + { + if ( v8 < 577 ) + goto LABEL_39; + break; + } + } + while ( tempstr[--v7] != ' ' ) + --v1; +LABEL_39: + if ( v7 ) + { + tempstr[v7] = 0; + DrawHelpLine(0, help_line_nra, tempstr, color); + v0 = help_select_line; + } + if ( *v1 == ('|') ) +LABEL_48: + ++v1; + } + ++help_line_nra; + } + while ( help_line_nra < 22 ); + PrintSString(0, 23, 1u, "Press ESC to end or the arrow keys to scroll.", COL_GOLD, 0); +} +// 634490: using guessed type int help_select_line; +// 634960: using guessed type int HelpTop; + +void __fastcall DrawHelpLine(int always_0, int help_line_nr, char *text, text_color color) +{ + signed int v4; // ebx + int v5; // edi + unsigned char i; // al + unsigned char v7; // al + int v8; // esi + + v4 = 0; + v5 = screen_y_times_768[SStringY[help_line_nr] + 204] + always_0 + 96; + for ( i = *text; *text; i = *text ) + { + ++text; + v7 = fontframe[fontidx[i]]; + v8 = v7; + v4 += fontkern[v7] + 1; + if ( v7 ) + { + if ( v4 <= 577 ) + CPrintString(v5, v7, color); + } + v5 += fontkern[v8] + 1; + } +} + +void __cdecl DisplayHelp() +{ + help_select_line = 0; + helpflag = 1; + HelpTop = 5000; +} +// 634490: using guessed type int help_select_line; +// 634960: using guessed type int HelpTop; + +void __cdecl HelpScrollUp() +{ + if ( help_select_line > 0 ) + --help_select_line; +} +// 634490: using guessed type int help_select_line; + +void __cdecl HelpScrollDown() +{ + if ( help_select_line < HelpTop ) + ++help_select_line; +} +// 634490: using guessed type int help_select_line; +// 634960: using guessed type int HelpTop; diff --git a/Source/help.h b/Source/help.h new file mode 100644 index 000000000..62532870a --- /dev/null +++ b/Source/help.h @@ -0,0 +1,21 @@ +//HEADER_GOES_HERE +#ifndef __HELP_H__ +#define __HELP_H__ + +extern int help_select_line; // weak +extern int dword_634494; // weak +extern int helpflag; +extern int displayinghelp[22]; +extern int HelpTop; // weak + +void __cdecl InitHelp(); +void __cdecl DrawHelp(); +void __fastcall DrawHelpLine(int always_0, int help_line_nr, char *text, text_color color); +void __cdecl DisplayHelp(); +void __cdecl HelpScrollUp(); +void __cdecl HelpScrollDown(); + +/* rdata */ +extern const char gszHelpText[]; + +#endif /* __HELP_H__ */ diff --git a/Source/init.cpp b/Source/init.cpp new file mode 100644 index 000000000..35fb1e500 --- /dev/null +++ b/Source/init.cpp @@ -0,0 +1,530 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +_SNETVERSIONDATA fileinfo; +int init_cpp_init_value; // weak +int gbActive; // weak +char diablo_exe_path[260]; +void *unused_mpq; +char patch_rt_mpq_path[260]; +WNDPROC CurrentProc; +void *diabdat_mpq; +char diabdat_mpq_path[260]; +void *patch_rt_mpq; +int killed_mom_parent; // weak +bool screensaver_enabled_prev; + +const int init_inf = 0x7F800000; // weak + +/* data */ + +char gszVersionNumber[260] = "internal version unknown"; +char gszProductName[260] = "Diablo v1.09"; + +struct init_cpp_init +{ + init_cpp_init() + { + init_cpp_init_value = init_inf; + } +} _init_cpp_init; +// 47AE20: using guessed type int init_inf; +// 63497C: using guessed type int init_cpp_init_value; + +void __fastcall init_cleanup(bool show_cursor) +{ + int v1; // edi + + v1 = show_cursor; + pfile_flush_W(); + init_disable_screensaver(0); + init_run_office_from_start_menu(); + if ( diabdat_mpq ) + { + SFileCloseArchive(diabdat_mpq); + diabdat_mpq = 0; + } + if ( patch_rt_mpq ) + { + SFileCloseArchive(patch_rt_mpq); + patch_rt_mpq = 0; + } + if ( unused_mpq ) + { + SFileCloseArchive(unused_mpq); + unused_mpq = 0; + } + UiDestroy(); + effects_cleanup_sfx(); + sound_cleanup(); + NetClose(); + dx_cleanup(); + MI_Dummy(v1); + StormDestroy(); + if ( v1 ) + ShowCursor(1); +} + +void __cdecl init_run_office_from_start_menu() +{ + HWND v0; // eax + char pszPath[256]; // [esp+0h] [ebp-104h] + LPITEMIDLIST ppidl; // [esp+100h] [ebp-4h] + + if ( killed_mom_parent ) + { + *pszPath = empty_string; + killed_mom_parent = 0; + memset(pszPath + 1, 0, sizeof(pszPath) - 1); + // *(_WORD *)&pszPath[253] = 0; + //pszPath[255] = 0; + ppidl = 0; + v0 = GetDesktopWindow(); + if ( !SHGetSpecialFolderLocation(v0, CSIDL_STARTMENU, &ppidl) ) + { + SHGetPathFromIDList(ppidl, pszPath); + init_run_office(pszPath); + } + } +} +// 634CA0: using guessed type int killed_mom_parent; + +void __fastcall init_run_office(char *dir) +{ + char *v1; // esi + HANDLE v2; // ebx + bool v3; // zf + HWND v4; // eax + char Directory[260]; // [esp+8h] [ebp-348h] + char FileName[260]; // [esp+10Ch] [ebp-244h] + struct _WIN32_FIND_DATAA FindFileData; // [esp+210h] [ebp-140h] + + v1 = dir; + strcpy(FileName, dir); + if ( FileName[0] && Directory[strlen(FileName) + 259] == '\\' ) + strcat(FileName, "*"); + else + strcat(FileName, "\\*"); + v2 = FindFirstFile(FileName, &FindFileData); + if ( v2 != (HANDLE)-1 ) + { + do + { + if ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + if ( strcmp(FindFileData.cFileName, ".") && strcmp(FindFileData.cFileName, "..") ) + { + *Directory = empty_string; + memset(Directory + 1, 0, sizeof(Directory) - 1); + v3 = *v1 == 0; + // *(_WORD *)&Directory[257] = 0; + //Directory[259] = 0; + if ( v3 || v1[strlen(v1) - 1] != '\\' ) + sprintf(Directory, "%s\\%s\\", v1, FindFileData.cFileName); + else + sprintf(Directory, "%s%s\\", v1, FindFileData.cFileName); + init_run_office(Directory); + } + } + else if ( !_strcmpi(FindFileData.cFileName, "Microsoft Office Shortcut Bar.lnk") ) + { + v4 = GetDesktopWindow(); + ShellExecute(v4, "open", FindFileData.cFileName, &empty_string, v1, SW_SHOWNORMAL); + } + } + while ( FindNextFile(v2, &FindFileData) ); + FindClose(v2); + } +} + +void __fastcall init_disable_screensaver(bool disable) +{ + bool v1; // al + char Data[16]; // [esp+4h] [ebp-20h] + DWORD Type; // [esp+14h] [ebp-10h] + DWORD cbData; // [esp+18h] [ebp-Ch] + HKEY phkResult; // [esp+1Ch] [ebp-8h] + bool v6; // [esp+20h] [ebp-4h] + + // BUGFIX: this is probably the worst possible way to do this. Alternatives: ExtEscape() with SETPOWERMANAGEMENT, + // SystemParametersInfo() with SPI_SETSCREENSAVEACTIVE/SPI_SETPOWEROFFACTIVE/SPI_SETLOWPOWERACTIVE + + v6 = disable; + if ( !RegOpenKeyEx(HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, KEY_READ|KEY_WRITE, &phkResult) ) + { + if ( v6 ) + { + cbData = 16; + if ( !RegQueryValueEx(phkResult, "ScreenSaveActive", 0, &Type, (LPBYTE)Data, &cbData) ) + screensaver_enabled_prev = Data[0] != '0'; + v1 = 0; + } + else + { + v1 = screensaver_enabled_prev; + } + Data[1] = 0; + Data[0] = (v1 != 0) + '0'; + RegSetValueEx(phkResult, "ScreenSaveActive", 0, REG_SZ, (const BYTE *)Data, 2u); + RegCloseKey(phkResult); + } +} + +void __fastcall init_create_window(int nCmdShow) +{ + + + int nHeight; // eax + HWND hWnd; // esi + WNDCLASSEXA wcex; // [esp+8h] [ebp-34h] + int nWidth; // [esp+38h] [ebp-4h] + + init_kill_mom_parent(); + pfile_init_save_directory(); + memset(&wcex, 0, sizeof(wcex)); + wcex.cbSize = sizeof(wcex); + wcex.style = CS_HREDRAW|CS_VREDRAW; + wcex.lpfnWndProc = WindowProc; + wcex.hInstance = ghInst; + wcex.hIcon = LoadIcon(ghInst, MAKEINTRESOURCE(IDI_ICON1)); + wcex.hCursor = LoadCursor(0, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wcex.lpszMenuName = "DIABLO"; + wcex.lpszClassName = "DIABLO"; + wcex.hIconSm = (HICON)LoadImage(ghInst, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + if ( !RegisterClassEx(&wcex) ) + TermMsg("Unable to register window class"); + if ( GetSystemMetrics(SM_CXSCREEN) >= 640 ) + nWidth = GetSystemMetrics(SM_CXSCREEN); + else + nWidth = 640; + if ( GetSystemMetrics(SM_CYSCREEN) >= 480 ) + nHeight = GetSystemMetrics(SM_CYSCREEN); + else + nHeight = 480; + hWnd = CreateWindowEx(0, "DIABLO", "DIABLO", WS_POPUP, 0, 0, nWidth, nHeight, NULL, NULL, ghInst, NULL); + if ( !hWnd ) + TermMsg("Unable to create main window"); + ShowWindow(hWnd, SW_SHOWNORMAL); // nCmdShow used only in beta: ShowWindow(hWnd, nCmdShow) + UpdateWindow(hWnd); + init_await_mom_parent_exit(); + dx_init(hWnd); + BlackPalette(); + snd_init(hWnd); + init_archives(); + init_disable_screensaver(1); +} + +void __cdecl init_kill_mom_parent() +{ + HWND v0; // eax + + v0 = init_find_mom_parent(); + if ( v0 ) + { + PostMessage(v0, WM_CLOSE, 0, 0); + killed_mom_parent = 1; + } +} +// 634CA0: using guessed type int killed_mom_parent; + +HWND __cdecl init_find_mom_parent() +{ + HWND i; // eax + HWND v1; // esi + char ClassName[256]; // [esp+4h] [ebp-100h] + + for ( i = GetForegroundWindow(); ; i = GetWindow(v1, GW_HWNDNEXT) ) + { + v1 = i; + if ( !i ) + break; + GetClassName(i, ClassName, 255); + if ( !_strcmpi(ClassName, "MOM Parent") ) + break; + } + return v1; +} + +void __cdecl init_await_mom_parent_exit() +{ + DWORD v0; // edi + + v0 = GetTickCount(); + do + { + if ( !init_find_mom_parent() ) + break; + Sleep(250); + } + while ( GetTickCount() - v0 <= 4000 ); +} + +void __cdecl init_archives() +{ + void *a1; // [esp+8h] [ebp-8h] +#ifdef COPYPROT + int v1; // [esp+Ch] [ebp-4h] +#endif + + fileinfo.size = 20; + fileinfo.versionstring = gszVersionNumber; + fileinfo.executablefile = diablo_exe_path; + fileinfo.originalarchivefile = diabdat_mpq_path; + fileinfo.patcharchivefile = patch_rt_mpq_path; + init_get_file_info(); +#ifdef COPYPROT + while ( 1 ) + { +#endif + diabdat_mpq = init_test_access(diabdat_mpq_path, "\\diabdat.mpq", "DiabloCD", 1000, 1); +#ifdef COPYPROT + if ( diabdat_mpq ) + break; + UiCopyProtError((int)&v1); + if ( v1 == COPYPROT_CANCEL ) + FileErrDlg("diabdat.mpq"); + } +#endif + if ( !WOpenFile("ui_art\\title.pcx", &a1, 1) ) + FileErrDlg("Main program archive: diabdat.mpq"); + WCloseFile(a1); + patch_rt_mpq = init_test_access(patch_rt_mpq_path, "\\patch_rt.mpq", "DiabloInstall", 2000, 0); +} + +void *__fastcall init_test_access(char *mpq_path, char *mpq_name, char *reg_loc, int flags, bool on_cd) +{ + char *v5; // esi + char *v7; // eax + char Filename[260]; // [esp+Ch] [ebp-314h] + char Buffer[260]; // [esp+110h] [ebp-210h] + char v15[260]; // [esp+214h] [ebp-10Ch] + char *mpq_namea; // [esp+318h] [ebp-8h] + void *archive; // [esp+31Ch] [ebp-4h] + + mpq_namea = mpq_name; + v5 = mpq_path; + if ( !GetCurrentDirectory(0x104u, Buffer) ) + TermMsg("Can't get program path"); + init_strip_trailing_slash(Buffer); + if ( !SFileSetBasePath(Buffer) ) + TermMsg("SFileSetBasePath"); + if ( !GetModuleFileName(ghInst, Filename, 0x104u) ) + TermMsg("Can't get program name"); + v7 = strrchr(Filename, '\\'); + if ( v7 ) + *v7 = 0; + init_strip_trailing_slash(Filename); + strcpy(v5, Buffer); + strcat(v5, mpq_namea); +#ifdef COPYPROT + if ( SFileOpenArchive(v5, flags, on_cd, &archive) ) +#else + if ( SFileOpenArchive(v5, flags, 0, &archive) ) +#endif + return archive; + if ( strcmp(Filename, Buffer) ) + { + strcpy(v5, Filename); + strcat(v5, mpq_namea); +#ifdef COPYPROT + if ( SFileOpenArchive(v5, flags, on_cd, &archive) ) +#else + if ( SFileOpenArchive(v5, flags, 0, &archive) ) +#endif + return archive; + } + v15[0] = 0; + if ( reg_loc ) + { + if ( SRegLoadString("Archives", (const char *)reg_loc, 0, v15, 260) ) + { + init_strip_trailing_slash(v15); + strcpy(v5, v15); + strcat(v5, mpq_namea); +#ifdef COPYPROT + if ( SFileOpenArchive(v5, flags, on_cd, &archive) ) +#else + if ( SFileOpenArchive(v5, flags, 0, &archive) ) +#endif + return archive; + } + } + if ( on_cd && init_read_test_file(v15, mpq_namea, flags, &archive) ) + { + strcpy(v5, v15); + return archive; + } + return 0; +} + +char *__fastcall init_strip_trailing_slash(char *path) +{ + char *result; // eax + + result = strrchr(path, '\\'); + if ( result ) + { + if ( !result[1] ) + *result = 0; + } + return result; +} + +int __fastcall init_read_test_file(char *mpq_path, char *mpq_name, int flags, void **archive) +{ + char *v4; // edi + DWORD v5; // eax + const char *v7; // ebx + const char *v8; // esi + char Buffer[260]; // [esp+Ch] [ebp-108h] + char *mpq_patha; // [esp+110h] [ebp-4h] + + v4 = mpq_name; + mpq_patha = mpq_path; + v5 = GetLogicalDriveStrings(0x104u, Buffer); + if ( !v5 || v5 > 0x104 ) + return 0; + while ( *v4 == '\\' ) + ++v4; + v7 = Buffer; + if ( !Buffer[0] ) + return 0; + while ( 1 ) + { + v8 = v7; + v7 += strlen(v7) + 1; + if ( GetDriveType(v8) == DRIVE_CDROM ) + { + strcpy(mpq_patha, v8); + strcat(mpq_patha, v4); + if ( SFileOpenArchive(mpq_patha, flags, 1, archive) ) + break; + } + if ( !*v7 ) + return 0; + } + return 1; +} + +void __cdecl init_get_file_info() +{ + int v0; // eax + DWORD v1; // edi + void *v2; // ebx + unsigned int uBytes; // [esp+8h] [ebp-Ch] + DWORD dwHandle; // [esp+Ch] [ebp-8h] + VS_FIXEDFILEINFO *lpBuffer; // [esp+10h] [ebp-4h] + + if ( GetModuleFileName(ghInst, diablo_exe_path, 0x104u) ) + { + v0 = GetFileVersionInfoSize(diablo_exe_path, &dwHandle); + v1 = v0; + if ( v0 ) + { + v2 = DiabloAllocPtr(v0); + if ( GetFileVersionInfo(diablo_exe_path, 0, v1, v2) ) + { + if ( VerQueryValue(v2, "\\", (LPVOID *)&lpBuffer, &uBytes) ) + sprintf( + gszVersionNumber, + "version %d.%d.%d.%d", + lpBuffer->dwProductVersionMS >> 16, + lpBuffer->dwProductVersionMS & 0xFFFF, + lpBuffer->dwProductVersionLS >> 16, + lpBuffer->dwProductVersionLS & 0xFFFF); + } + mem_free_dbg(v2); + } + } +} + +LRESULT __stdcall MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + if ( Msg > WM_ERASEBKGND ) + { + if ( Msg == WM_ACTIVATEAPP ) + { + init_activate_window(hWnd, wParam); + } + else + { + if ( Msg == WM_QUERYNEWPALETTE ) + { + SDrawRealizePalette(); + return 1; + } + if ( Msg == WM_PALETTECHANGED && (HWND)wParam != hWnd ) + SDrawRealizePalette(); + } + } + else + { + switch ( Msg ) + { + case WM_ERASEBKGND: + return 0; + case WM_CREATE: + ghMainWnd = hWnd; + break; + case WM_DESTROY: + init_cleanup(1); + ghMainWnd = 0; + PostQuitMessage(0); + break; + case WM_PAINT: + drawpanflag = 255; + break; + case WM_CLOSE: + return 0; + } + } + return DefWindowProc(hWnd, Msg, wParam, lParam); +} +// 52571C: using guessed type int drawpanflag; + +void __fastcall init_activate_window(HWND hWnd, bool bActive) +{ + LONG dwNewLong; // eax + + gbActive = bActive; + UiAppActivate(bActive); + dwNewLong = GetWindowLong(hWnd, GWL_STYLE); + + if ( gbActive && fullscreen ) + dwNewLong &= ~WS_SYSMENU; + else + dwNewLong |= WS_SYSMENU; + + SetWindowLong(hWnd, GWL_STYLE, dwNewLong); + + if ( gbActive ) + { + drawpanflag = 255; + ResetPal(); + } +} +// 484364: using guessed type int fullscreen; +// 52571C: using guessed type int drawpanflag; +// 634980: using guessed type int gbActive; + +LRESULT __stdcall WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT result; // eax + + if ( CurrentProc ) + result = CurrentProc(hWnd, Msg, wParam, lParam); + else + result = MainWndProc(hWnd, Msg, wParam, lParam); + return result; +} + +WNDPROC __stdcall SetWindowProc(WNDPROC NewProc) +{ + WNDPROC OldProc; // eax + + OldProc = CurrentProc; + CurrentProc = NewProc; + return OldProc; +} diff --git a/Source/init.h b/Source/init.h new file mode 100644 index 000000000..9a629b02f --- /dev/null +++ b/Source/init.h @@ -0,0 +1,45 @@ +//HEADER_GOES_HERE +#ifndef __INIT_H__ +#define __INIT_H__ + +extern _SNETVERSIONDATA fileinfo; +extern int init_cpp_init_value; // weak +extern int gbActive; // weak +extern char diablo_exe_path[260]; +extern void *unused_mpq; +extern char patch_rt_mpq_path[260]; +extern WNDPROC CurrentProc; +extern void *diabdat_mpq; +extern char diabdat_mpq_path[260]; +extern void *patch_rt_mpq; +extern int killed_mom_parent; // weak +extern bool screensaver_enabled_prev; + +void __cdecl init_cpp_init(); +void __fastcall init_cleanup(bool show_cursor); +void __cdecl init_run_office_from_start_menu(); +void __fastcall init_run_office(char *dir); +void __fastcall init_disable_screensaver(bool disable); +void __fastcall init_create_window(int nCmdShow); +void __cdecl init_kill_mom_parent(); +HWND __cdecl init_find_mom_parent(); +void __cdecl init_await_mom_parent_exit(); +void __cdecl init_archives(); +void *__fastcall init_test_access(char *mpq_path, char *mpq_name, char *reg_loc, int flags, bool on_cd); +char *__fastcall init_strip_trailing_slash(char *path); +int __fastcall init_read_test_file(char *mpq_path, char *mpq_name, int flags, void **archive); +void __cdecl init_get_file_info(); +LRESULT __stdcall MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +void __fastcall init_activate_window(HWND hWnd, bool bActive); +LRESULT __stdcall WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +WNDPROC __stdcall SetWindowProc(WNDPROC NewProc); + +/* rdata */ +extern const int init_inf; // weak + +/* data */ + +extern char gszVersionNumber[260]; +extern char gszProductName[260]; + +#endif /* __INIT_H__ */ diff --git a/Source/interfac.cpp b/Source/interfac.cpp new file mode 100644 index 000000000..8b9b67a0e --- /dev/null +++ b/Source/interfac.cpp @@ -0,0 +1,385 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +void *sgpBackCel; +float interfac_cpp_init_value; +int sgdwProgress; +int progress_id; // idb +#endif + +const int interfac_inf = 0x7F800000; // weak +const unsigned char progress_bar_colours[3] = { 138u, 43u, 254u }; +const int progress_bar_screen_pos[3][2] = { { 53, 37 }, { 53, 421 }, { 53, 37 } }; + +struct interfac_cpp_init +{ + interfac_cpp_init() + { + interfac_cpp_init_value = interfac_inf; + } +} _interfac_cpp_init; +// 47AE40: using guessed type int interfac_inf; + +void __cdecl interface_msg_pump() +{ + MSG Msg; // [esp+8h] [ebp-1Ch] + + while ( PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) ) + { + if ( Msg.message != WM_QUIT ) + { + TranslateMessage(&Msg); + DispatchMessage(&Msg); + } + } +} + +bool __cdecl IncProgress() +{ + interface_msg_pump(); + sgdwProgress += 15; + if ( (unsigned int)sgdwProgress > 0x216 ) + sgdwProgress = 534; + if ( sgpBackCel ) + DrawCutscene(); + return (unsigned int)sgdwProgress >= 0x216; +} + +void __cdecl DrawCutscene() +{ + unsigned int v0; // esi + + lock_buf_priv(); + CelDecodeOnly(64, 639, sgpBackCel, 1, 640); + v0 = 0; + if ( sgdwProgress ) + { + do + DrawProgress( + progress_bar_screen_pos[progress_id][0] + v0++ + 64, + progress_bar_screen_pos[progress_id][1] + 160, + progress_id); + while ( v0 < sgdwProgress ); + } + unlock_buf_priv(); + drawpanflag = 255; + scrollrt_draw_game_screen(0); +} +// 52571C: using guessed type int drawpanflag; + +void __fastcall DrawProgress(int screen_x, int screen_y, int progress_id) +{ + _BYTE *v3; // eax + signed int v4; // ecx + + v3 = (unsigned char *)gpBuffer + screen_y_times_768[screen_y] + screen_x; + v4 = 22; + do + { + *v3 = progress_bar_colours[progress_id]; + v3 += 768; + --v4; + } + while ( v4 ); +} + +void __fastcall ShowProgress(int uMsg) +{ + WNDPROC saveProc; // edi + BOOL v3; // cl + int v4; // eax + int v5; // edx + signed int v7; // [esp-4h] [ebp-10h] + + gbSomebodyWonGameKludge = 0; + plrmsg_delay(1); + saveProc = SetWindowProc(DisableInputWndProc); + interface_msg_pump(); + ClearScreenBuffer(); + scrollrt_draw_game_screen(1); + InitCutscene(uMsg); + BlackPalette(); + DrawCutscene(); + PaletteFadeIn(8); + IncProgress(); + stream_update(); + IncProgress(); + switch ( uMsg ) + { + case WM_DIABNEXTLVL: + IncProgress(); + if ( gbMaxPlayers == 1 ) + SaveLevel(); + else + DeltaSaveLevel(); + FreeGameMem(); + v4 = ++currlevel; + goto LABEL_38; + case WM_DIABPREVLVL: + IncProgress(); + if ( gbMaxPlayers == 1 ) + SaveLevel(); + else + DeltaSaveLevel(); + IncProgress(); + FreeGameMem(); + leveltype = gnLevelTypeTbl[--currlevel]; + IncProgress(); + v5 = 1; + goto LABEL_33; + case WM_DIABRTNLVL: + if ( gbMaxPlayers == 1 ) + SaveLevel(); + else + DeltaSaveLevel(); + setlevel = 0; + FreeGameMem(); + IncProgress(); + GetReturnLvlPos(); + v7 = 3; + goto LABEL_32; + case WM_DIABSETLVL: + SetReturnLvlPos(); + if ( gbMaxPlayers == 1 ) + SaveLevel(); + else + DeltaSaveLevel(); + setlevel = 1; + leveltype = setlvltype; + FreeGameMem(); + IncProgress(); + v7 = 2; + goto LABEL_32; + case WM_DIABWARPLVL: + IncProgress(); + if ( gbMaxPlayers == 1 ) + SaveLevel(); + else + DeltaSaveLevel(); + FreeGameMem(); + GetPortalLevel(); + IncProgress(); + v7 = 5; + goto LABEL_32; + case WM_DIABTOWNWARP: + IncProgress(); + if ( gbMaxPlayers == 1 ) + SaveLevel(); + else + DeltaSaveLevel(); + FreeGameMem(); + currlevel = plr[myplr].plrlevel; + leveltype = gnLevelTypeTbl[currlevel]; + IncProgress(); + v7 = 6; + goto LABEL_32; + case WM_DIABTWARPUP: + IncProgress(); + if ( gbMaxPlayers == 1 ) + SaveLevel(); + else + DeltaSaveLevel(); + FreeGameMem(); + currlevel = plr[myplr].plrlevel; + leveltype = gnLevelTypeTbl[currlevel]; + IncProgress(); + v7 = 7; +LABEL_32: + v5 = v7; +LABEL_33: + v3 = FALSE; + goto LABEL_40; + case WM_DIABRETOWN: + IncProgress(); + if ( gbMaxPlayers == 1 ) + SaveLevel(); + else + DeltaSaveLevel(); + FreeGameMem(); + currlevel = plr[myplr].plrlevel; + v4 = currlevel; +LABEL_38: + leveltype = gnLevelTypeTbl[v4]; + IncProgress(); + v3 = FALSE; + goto LABEL_39; + case WM_DIABNEWGAME: + IncProgress(); + FreeGameMem(); + IncProgress(); +// pfile_remove_temp_files(); + v3 = TRUE; +LABEL_39: + v5 = 0; +LABEL_40: + LoadGameLevel(v3, v5); + goto LABEL_41; + case WM_DIABLOADGAME: + IncProgress(); + LoadGame(TRUE); +LABEL_41: + IncProgress(); + break; + default: + break; + } + PaletteFadeOut(8); + FreeInterface(); + SetWindowProc(saveProc); + NetSendCmdLocParam1(1u, CMD_PLAYER_JOINLEVEL, plr[myplr].WorldX, plr[myplr].WorldY, plr[myplr].plrlevel); + plrmsg_delay(0); + ResetPal(); + if ( gbSomebodyWonGameKludge && plr[myplr].plrlevel == 16 ) + PrepDoEnding(); + gbSomebodyWonGameKludge = 0; +} +// 5BB1ED: using guessed type char leveltype; +// 5CF31C: using guessed type char setlvltype; +// 5CF31D: using guessed type char setlevel; +// 6761B8: using guessed type char gbSomebodyWonGameKludge; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl FreeInterface() +{ + void *v0; // ecx + + v0 = sgpBackCel; + sgpBackCel = 0; + mem_free_dbg(v0); +} + +void __fastcall InitCutscene(int uMsg) +{ + int v1; // eax + int v2; // eax + int v3; // eax + int v4; // eax + unsigned char *v5; // eax + char *v6; // ecx + int *v7; // eax + int v8; // eax + int v9; // eax + int v10; // eax + int v11; // eax + int v12; // eax + int v13; // eax + int v14; // eax + + switch ( uMsg ) + { + case WM_DIABNEXTLVL: + v1 = gnLevelTypeTbl[currlevel]; + if ( !v1 ) + goto LABEL_31; + v2 = v1 - 1; + if ( !v2 ) + goto LABEL_10; + v3 = v2 - 1; + if ( !v3 ) + goto LABEL_9; + v4 = v3 - 1; + if ( !v4 ) + goto LABEL_29; + if ( v4 != 1 ) + goto LABEL_10; + if ( currlevel < 0xFu ) + goto LABEL_28; + v5 = LoadFileInMem("Gendata\\Cutgate.CEL", 0); + v6 = "Gendata\\Cutgate.pal"; + goto LABEL_30; + case WM_DIABPREVLVL: + v7 = &gnLevelTypeTbl[currlevel]; + if ( !*(v7 - 1) ) + goto LABEL_31; + v8 = *v7; + if ( !v8 ) + goto LABEL_31; + v9 = v8 - 1; + if ( !v9 ) + goto LABEL_10; + v10 = v9 - 1; + if ( !v10 ) + { +LABEL_9: + sgpBackCel = LoadFileInMem("Gendata\\Cut2.CEL", 0); + LoadPalette("Gendata\\Cut2.pal"); + progress_id = 2; + goto LABEL_33; + } + v11 = v10 - 1; + if ( !v11 ) + goto LABEL_29; + if ( v11 == 1 ) + goto LABEL_28; +LABEL_10: + sgpBackCel = LoadFileInMem("Gendata\\Cutl1d.CEL", 0); + LoadPalette("Gendata\\Cutl1d.pal"); + progress_id = 0; + goto LABEL_33; + case WM_DIABRTNLVL: + case WM_DIABSETLVL: + if ( setlvlnum == SL_BONECHAMB ) + goto LABEL_21; + if ( setlvlnum != SL_VILEBETRAYER ) + goto LABEL_10; + v5 = LoadFileInMem("Gendata\\Cutportr.CEL", 0); + v6 = "Gendata\\Cutportr.pal"; + goto LABEL_30; + case WM_DIABWARPLVL: + v5 = LoadFileInMem("Gendata\\Cutportl.CEL", 0); + v6 = "Gendata\\Cutportl.pal"; + goto LABEL_30; + case WM_DIABTOWNWARP: + case WM_DIABTWARPUP: + v12 = gnLevelTypeTbl[plr[myplr].plrlevel]; + if ( !v12 ) + goto LABEL_31; + v13 = v12 - 2; + if ( !v13 ) + { +LABEL_21: + sgpBackCel = LoadFileInMem("Gendata\\Cut2.CEL", 0); + LoadPalette("Gendata\\Cut2.pal"); + progress_id = SL_BONECHAMB; + goto LABEL_33; + } + v14 = v13 - 1; + if ( v14 ) + { + if ( v14 != 1 ) + goto LABEL_33; +LABEL_28: + v5 = LoadFileInMem("Gendata\\Cut4.CEL", 0); + v6 = "Gendata\\Cut4.pal"; + } + else + { +LABEL_29: + v5 = LoadFileInMem("Gendata\\Cut3.CEL", 0); + v6 = "Gendata\\Cut3.pal"; + } +LABEL_30: + sgpBackCel = v5; + LoadPalette(v6); + progress_id = 1; +LABEL_33: + sgdwProgress = 0; + return; + case WM_DIABRETOWN: +LABEL_31: + v5 = LoadFileInMem("Gendata\\Cuttt.CEL", 0); + v6 = "Gendata\\Cuttt.pal"; + goto LABEL_30; + case WM_DIABNEWGAME: + case WM_DIABLOADGAME: + v5 = LoadFileInMem("Gendata\\Cutstart.CEL", 0); + v6 = "Gendata\\Cutstart.pal"; + goto LABEL_30; + default: + TermMsg("Unknown progress mode"); + goto LABEL_33; + } +} +// 5CCB10: using guessed type char setlvlnum; diff --git a/Source/interfac.h b/Source/interfac.h new file mode 100644 index 000000000..e7dbcefec --- /dev/null +++ b/Source/interfac.h @@ -0,0 +1,25 @@ +//HEADER_GOES_HERE +#ifndef __INTERFAC_H__ +#define __INTERFAC_H__ + +extern void *sgpBackCel; +extern float interfac_cpp_init_value; +extern int sgdwProgress; +extern int progress_id; // idb + +void __cdecl interfac_cpp_init(); +void __cdecl interface_msg_pump(); +bool __cdecl IncProgress(); +void __cdecl DrawCutscene(); +void __fastcall DrawProgress(int screen_x, int screen_y, int progress_id); +void __fastcall ShowProgress(int uMsg); +void __cdecl FreeInterface(); +void __fastcall InitCutscene(int uMsg); + +/* rdata */ + +extern const int interfac_inf; // weak +extern const unsigned char progress_bar_colours[3]; +extern const int progress_bar_screen_pos[3][2]; + +#endif /* __INTERFAC_H__ */ diff --git a/Source/inv.cpp b/Source/inv.cpp new file mode 100644 index 000000000..c1cc66ad2 --- /dev/null +++ b/Source/inv.cpp @@ -0,0 +1,3350 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int invflag; +void *pInvCels; +int drawsbarflag; // idb +int sgdwLastTime; // check name +#endif + +const InvXY InvRect[73] = +{ + { 452, 31 }, // helmet + { 480, 31 }, // helmet + { 452, 59 }, // helmet + { 480, 59 }, // helmet + { 365, 205 }, // left ring + { 567, 205 }, // right ring + { 524, 59 }, // amulet + { 337, 104 }, // left hand + { 366, 104 }, // left hand + { 337, 132 }, // left hand + { 366, 132 }, // left hand + { 337, 160 }, // left hand + { 366, 160 }, // left hand + { 567, 104 }, // right hand + { 596, 104 }, // right hand + { 567, 132 }, // right hand + { 596, 132 }, // right hand + { 567, 160 }, // right hand + { 596, 160 }, // right hand + { 452, 104 }, // chest + { 480, 104 }, // chest + { 452, 132 }, // chest + { 480, 132 }, // chest + { 452, 160 }, // chest + { 480, 160 }, // chest + { 337, 250 }, // inv row 1 + { 366, 250 }, // inv row 1 + { 394, 250 }, // inv row 1 + { 423, 250 }, // inv row 1 + { 451, 250 }, // inv row 1 + { 480, 250 }, // inv row 1 + { 509, 250 }, // inv row 1 + { 538, 250 }, // inv row 1 + { 567, 250 }, // inv row 1 + { 596, 250 }, // inv row 1 + { 337, 279 }, // inv row 2 + { 366, 279 }, // inv row 2 + { 394, 279 }, // inv row 2 + { 423, 279 }, // inv row 2 + { 451, 279 }, // inv row 2 + { 480, 279 }, // inv row 2 + { 509, 279 }, // inv row 2 + { 538, 279 }, // inv row 2 + { 567, 279 }, // inv row 2 + { 596, 279 }, // inv row 2 + { 337, 308 }, // inv row 3 + { 366, 308 }, // inv row 3 + { 394, 308 }, // inv row 3 + { 423, 308 }, // inv row 3 + { 451, 308 }, // inv row 3 + { 480, 308 }, // inv row 3 + { 509, 308 }, // inv row 3 + { 538, 308 }, // inv row 3 + { 567, 308 }, // inv row 3 + { 596, 308 }, // inv row 3 + { 337, 336 }, // inv row 4 + { 366, 336 }, // inv row 4 + { 394, 336 }, // inv row 4 + { 423, 336 }, // inv row 4 + { 451, 336 }, // inv row 4 + { 480, 336 }, // inv row 4 + { 509, 336 }, // inv row 4 + { 538, 336 }, // inv row 4 + { 567, 336 }, // inv row 4 + { 596, 336 }, // inv row 4 + { 205, 385 }, // belt + { 234, 385 }, // belt + { 263, 385 }, // belt + { 292, 385 }, // belt + { 321, 385 }, // belt + { 350, 385 }, // belt + { 379, 385 }, // belt + { 408, 385 } // belt +}; + +/* data */ + +int AP2x2Tbl[10] = { 8, 28, 6, 26, 4, 24, 2, 22, 0, 20 }; // weak + +void __cdecl FreeInvGFX() +{ + void *invCels = pInvCels; + + pInvCels = NULL; + mem_free_dbg(invCels); +} + +void __cdecl InitInv() +{ + if ( plr[myplr]._pClass == PC_WARRIOR ) + { + pInvCels = LoadFileInMem("Data\\Inv\\Inv.CEL", 0); + } + else if ( plr[myplr]._pClass == PC_ROGUE ) + { + pInvCels = LoadFileInMem("Data\\Inv\\Inv_rog.CEL", 0); + } + else if ( plr[myplr]._pClass == PC_SORCERER ) + { + pInvCels = LoadFileInMem("Data\\Inv\\Inv_Sor.CEL", 0); + } + + invflag = 0; + drawsbarflag = 0; +} + +void __fastcall InvDrawSlotBack(int X, int Y, int W, int H) +{ + unsigned char *v4; // edi + int v5; // edx + int v6; // ecx + unsigned char v7; // al + unsigned char v8; // al + + v4 = (unsigned char *)gpBuffer + screen_y_times_768[Y] + X; + v5 = (unsigned short)H; + do + { + v6 = (unsigned short)W; + do + { + v7 = *v4; + if ( *v4 < 0xB0u ) + goto LABEL_9; + if ( v7 > 0xBFu ) + { + if ( v7 < 0xF0u ) + goto LABEL_9; + v8 = v7 - 80; + } + else + { + v8 = v7 - 16; + } + *v4 = v8; +LABEL_9: + ++v4; + --v6; + } + while ( v6 ); + v4 = &v4[-(unsigned short)W - 768]; + --v5; + } + while ( v5 ); +} + +void __cdecl DrawInv() +{ + BOOL invtest[40]; + + CelDecodeOnly(384, 511, pInvCels, 1, 320); + + if ( plr[myplr].InvBody[INVLOC_HEAD]._itype != ITYPE_NONE ) + { + InvDrawSlotBack(517, 219, 2 * INV_SLOT_SIZE_PX, 2 * INV_SLOT_SIZE_PX); + + int frame = plr[myplr].InvBody[INVLOC_HEAD]._iCurs + 12; + int frame_width = InvItemWidth[frame]; + + if ( pcursinvitem == INVITEM_HEAD ) + { + int colour = 197; + if ( plr[myplr].InvBody[INVLOC_HEAD]._iMagical ) + { + colour = 181; + } + if ( !plr[myplr].InvBody[INVLOC_HEAD]._iStatFlag ) + { + colour = 229; + } + CelDecodeClr(colour, 517, 219, (char *)pCursCels, frame, frame_width, 0, 8); + } + + if ( plr[myplr].InvBody[INVLOC_HEAD]._iStatFlag ) + { + CelDrawHdrOnly(517, 219, (char *)pCursCels, frame, frame_width, 0, 8); + } + else + { + CelDrawHdrLightRed(517, 219, (char *)pCursCels, frame, frame_width, 0, 8, 1); + } + } + + if ( plr[myplr].InvBody[INVLOC_RING_LEFT]._itype != ITYPE_NONE ) + { + InvDrawSlotBack(432, 365, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX); + + int frame = plr[myplr].InvBody[INVLOC_RING_LEFT]._iCurs + 12; + int frame_width = InvItemWidth[frame]; + + if ( pcursinvitem == INVITEM_RING_LEFT ) + { + int colour = 197; + if ( plr[myplr].InvBody[INVLOC_RING_LEFT]._iMagical ) + { + colour = 181; + } + if ( !plr[myplr].InvBody[INVLOC_RING_LEFT]._iStatFlag ) + { + colour = 229; + } + CelDecodeClr(colour, 432, 365, (char *)pCursCels, frame, frame_width, 0, 8); + } + + if ( plr[myplr].InvBody[INVLOC_RING_LEFT]._iStatFlag ) + { + CelDrawHdrOnly(432, 365, (char *)pCursCels, frame, frame_width, 0, 8); + } + else + { + CelDrawHdrLightRed(432, 365, (char *)pCursCels, frame, frame_width, 0, 8, 1); + } + } + + if ( plr[myplr].InvBody[INVLOC_RING_RIGHT]._itype != ITYPE_NONE ) + { + InvDrawSlotBack(633, 365, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX); + + int frame = plr[myplr].InvBody[INVLOC_RING_RIGHT]._iCurs + 12; + int frame_width = InvItemWidth[frame]; + + if ( pcursinvitem == INVITEM_RING_RIGHT ) + { + int colour = 197; + if ( plr[myplr].InvBody[INVLOC_RING_RIGHT]._iMagical ) + { + colour = 181; + } + if ( !plr[myplr].InvBody[INVLOC_RING_RIGHT]._iStatFlag ) + { + colour = 229; + } + CelDecodeClr(colour, 633, 365, (char *)pCursCels, frame, frame_width, 0, 8); + } + + if ( plr[myplr].InvBody[INVLOC_RING_RIGHT]._iStatFlag ) + { + CelDrawHdrOnly(633, 365, (char *)pCursCels, frame, frame_width, 0, 8); + } + else + { + CelDrawHdrLightRed(633, 365, (char *)pCursCels, frame, frame_width, 0, 8, 1); + } + } + + if ( plr[myplr].InvBody[INVLOC_AMULET]._itype != ITYPE_NONE ) + { + InvDrawSlotBack(589, 220, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX); + + int frame = plr[myplr].InvBody[INVLOC_AMULET]._iCurs + 12; + int frame_width = InvItemWidth[frame]; + + if ( pcursinvitem == INVITEM_AMULET ) + { + int colour = 197; + if ( plr[myplr].InvBody[INVLOC_AMULET]._iMagical ) + { + colour = 181; + } + if ( !plr[myplr].InvBody[INVLOC_AMULET]._iStatFlag ) + { + colour = 229; + } + CelDecodeClr(colour, 589, 220, (char *)pCursCels, frame, frame_width, 0, 8); + } + + if ( plr[myplr].InvBody[INVLOC_AMULET]._iStatFlag ) + { + CelDrawHdrOnly(589, 220, (char *)pCursCels, frame, frame_width, 0, 8); + } + else + { + CelDrawHdrLightRed(589, 220, (char *)pCursCels, frame, frame_width, 0, 8, 1); + } + } + + if ( plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE ) + { + InvDrawSlotBack(401, 320, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX); + + int frame = plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCurs + 12; + int frame_width = InvItemWidth[frame]; + // calc item offsets for weapons smaller than 2x3 slots + int screen_x = frame_width == INV_SLOT_SIZE_PX ? 415 : 401; + int screen_y = InvItemHeight[frame] == (3 * INV_SLOT_SIZE_PX) ? 320 : 306; + + if ( pcursinvitem == INVITEM_HAND_LEFT ) + { + int colour = 197; + if ( plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMagical ) + { + colour = 181; + } + if ( !plr[myplr].InvBody[INVLOC_HAND_LEFT]._iStatFlag ) + { + colour = 229; + } + CelDecodeClr(colour, screen_x, screen_y, (char *)pCursCels, frame, frame_width, 0, 8); + } + + if ( plr[myplr].InvBody[INVLOC_HAND_LEFT]._iStatFlag ) + { + CelDrawHdrOnly(screen_x, screen_y, (char *)pCursCels, frame, frame_width, 0, 8); + } + else + { + CelDrawHdrLightRed(screen_x, screen_y, (char *)pCursCels, frame, frame_width, 0, 8, 1); + } + + if ( plr[myplr].InvBody[INVLOC_HAND_LEFT]._iLoc == ILOC_TWOHAND ) + { + InvDrawSlotBack(631, 320, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX); + light_table_index = 0; + cel_transparency_active = 1; + + CelDecodeHdrLightTrans( + frame_width == INV_SLOT_SIZE_PX + ? &gpBuffer->row[160].pixels[581] + : &gpBuffer->row[160].pixels[567], + (char *)pCursCels, frame, frame_width, 0, 8); + + cel_transparency_active = 0; + } + } + if ( plr[myplr].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE ) + { + InvDrawSlotBack(631, 320, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX); + + int frame = plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iCurs + 12; + int frame_width = InvItemWidth[frame]; + // calc item offsets for weapons smaller than 2x3 slots + int screen_x = frame_width == INV_SLOT_SIZE_PX ? 645 : 633; + int screen_y = InvItemHeight[frame] == 3 * INV_SLOT_SIZE_PX ? 320 : 306; + + if ( pcursinvitem == INVITEM_HAND_RIGHT ) + { + int colour = 197; + if ( plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iMagical ) + { + colour = 181; + } + if ( !plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iStatFlag ) + { + colour = 229; + } + CelDecodeClr(colour, screen_x, screen_y, (char *)pCursCels, frame, frame_width, 0, 8); + } + + if ( plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iStatFlag ) + { + CelDrawHdrOnly(screen_x, screen_y, (char *)pCursCels, frame, frame_width, 0, 8); + } + else + { + CelDrawHdrLightRed(screen_x, screen_y, (char *)pCursCels, frame, frame_width, 0, 8, 1); + } + } + + + if ( plr[myplr].InvBody[INVLOC_CHEST]._itype != ITYPE_NONE ) + { + InvDrawSlotBack(517, 320, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX); + + int frame = plr[myplr].InvBody[INVLOC_CHEST]._iCurs + 12; + int frame_width = InvItemWidth[frame]; + + if ( pcursinvitem == INVITEM_CHEST ) + { + int colour = 197; + if ( plr[myplr].InvBody[INVLOC_CHEST]._iMagical ) + { + colour = 181; + } + if ( !plr[myplr].InvBody[INVLOC_CHEST]._iStatFlag ) + { + colour = 229; + } + CelDecodeClr(colour, 517, 320, (char *)pCursCels, frame, frame_width, 0, 8); + } + + if ( plr[myplr].InvBody[INVLOC_CHEST]._iStatFlag ) + { + CelDrawHdrOnly(517, 320, (char *)pCursCels, frame, frame_width, 0, 8); + } + else + { + CelDrawHdrLightRed(517, 320, (char *)pCursCels, frame, frame_width, 0, 8, 1); + } + } + + for ( int i = 0; i < NUM_INV_GRID_ELEM; i++ ) + { + if ( plr[myplr].InvGrid[i] != 0 ) + { + InvDrawSlotBack( + InvRect[i + SLOTXY_INV_FIRST].X + 64, + InvRect[i + SLOTXY_INV_FIRST].Y + 159, + INV_SLOT_SIZE_PX, + INV_SLOT_SIZE_PX); + } + } + + for ( int j = 0; j < NUM_INV_GRID_ELEM; j++ ) + { + if ( plr[myplr].InvGrid[j] > 0 ) // first slot of an item + { + int ii = plr[myplr].InvGrid[j] - 1; + + invtest[j] = TRUE; + + int frame = plr[myplr].InvList[ii]._iCurs + 12; + int frame_width = InvItemWidth[frame]; + if ( pcursinvitem == ii + INVITEM_INV_FIRST ) + { + int colour = 197; + if ( plr[myplr].InvList[ii]._iMagical ) + { + colour = 181; + } + if ( !plr[myplr].InvList[ii]._iStatFlag ) + { + colour = 229; + } + CelDecodeClr( + colour, + InvRect[j + SLOTXY_INV_FIRST].X + 64, + InvRect[j + SLOTXY_INV_FIRST].Y + 159, + (char *)pCursCels, frame, frame_width, 0, 8); + } + + if ( plr[myplr].InvList[ii]._iStatFlag ) + { + CelDrawHdrOnly( + InvRect[j + SLOTXY_INV_FIRST].X + 64, + InvRect[j + SLOTXY_INV_FIRST].Y + 159, + (char *)pCursCels, frame, frame_width, 0, 8); + } + else + { + CelDrawHdrLightRed( + InvRect[j + SLOTXY_INV_FIRST].X + 64, + InvRect[j + SLOTXY_INV_FIRST].Y + 159, + (char *)pCursCels, frame, frame_width, 0, 8, 1); + } + } + } +} +// 4B8CB8: using guessed type char pcursinvitem; +// 69BEF8: using guessed type int light_table_index; +// 69CF94: using guessed type int cel_transparency_active; +// 41B8C4: using guessed type int var_A0[40]; + +void __cdecl DrawInvBelt() +{ + int v0; // ebx + signed int v1; // esi + int v2; // ecx + int v3; // eax + int v4; // edi + char v5; // cl + int v6; // edx + bool v7; // zf + int v8; // ecx + int v9; // eax + unsigned char v10; // edx + signed int v11; // [esp+4h] [ebp-Ch] + int frame_width; // [esp+8h] [ebp-8h] + int v13; // [esp+Ch] [ebp-4h] + + v0 = 0; + if ( !talkflag ) + { + DrawPanelBox(205, 21, 0xE8u, 0x1Cu, 269, 517); + v11 = 0; + v13 = 0; + do + { + if ( *(int *)((char *)&plr[myplr].SpdList[0]._itype + v0) != -1 ) + { + v1 = v11; + InvDrawSlotBack(InvRect[v11 + 65].X + 64, InvRect[v11 + 65].Y + 159, 28, 28); + v2 = myplr; + v3 = v0 + 21720 * myplr; + v4 = *(int *)((char *)&plr[0].SpdList[0]._iCurs + v3) + 12; + frame_width = InvItemWidth[v4]; + if ( pcursinvitem == v11 + 47 ) + { + v5 = -59; + if ( *(&plr[0].SpdList[0]._iMagical + v3) ) + v5 = -75; + if ( !*(int *)((char *)&plr[0].SpdList[0]._iStatFlag + v3) ) + v5 = -27; + CelDecodeClr( + v5, + InvRect[v1 + 65].X + 64, + InvRect[v1 + 65].Y + 159, + (char *)pCursCels, + v4, + frame_width, + 0, + 8); + v2 = myplr; + } + v0 = v13; + v6 = InvRect[v1 + 65].Y + 159; + v7 = *(int *)((char *)&plr[v2].SpdList[0]._iStatFlag + v13) == 0; + v8 = InvRect[v1 + 65].X; + if ( v7 ) + CelDrawHdrLightRed(v8 + 64, v6, (char *)pCursCels, v4, frame_width, 0, 8, 1); + else + CelDrawHdrOnly(v8 + 64, v6, (char *)pCursCels, v4, frame_width, 0, 8); + v9 = v13 + 21720 * myplr; + if ( AllItemsList[*(int *)((char *)&plr[0].SpdList[0].IDidx + v9)].iUsable + && *(int *)((char *)&plr[0].SpdList[0]._iStatFlag + v9) + && *(int *)((char *)&plr[0].SpdList[0]._itype + v9) != 11 ) + { + v10 = fontframe[fontidx[(unsigned char)(v11 + 49)]]; + CPrintString( + screen_y_times_768[InvRect[v1 + 65].Y + 159] + - fontkern[v10] + + InvRect[v1 + 65].X + + 92, + v10, + 0); + } + } + ++v11; + v0 += 368; + v13 = v0; + } + while ( v11 < 8 ); + } +} +// 4B8960: using guessed type int talkflag; +// 4B8CB8: using guessed type char pcursinvitem; + +int __fastcall AutoPlace(int pnum, int ii, int sx, int sy, int saveflag) +{ + __int64 v5; // rax + int v6; // ebx + signed int v7; // edx + signed int v8; // eax + signed int v9; // esi + int j; // edi + int v11; // eax + signed int v12; // esi + signed int v13; // ecx + int v14; // edi + char *v15; // ecx + char v16; // dl + signed int v18; // [esp+Ch] [ebp-Ch] + int p; // [esp+10h] [ebp-8h] + int v20; // [esp+14h] [ebp-4h] + int i; // [esp+14h] [ebp-4h] + + p = pnum; + v5 = ii; + v6 = 1; + v18 = v5 % 10; + v7 = 10 * (unsigned __int64)(v5 / 10); + v8 = v7; + if ( v7 < 0 ) + v8 = 0; + v20 = 0; + if ( sy <= 0 ) + { +LABEL_16: + if ( saveflag ) + { + v11 = pnum; + qmemcpy( + &plr[pnum].InvList[plr[pnum]._pNumInv], + &plr[pnum].HoldItem, + sizeof(plr[pnum].InvList[plr[pnum]._pNumInv])); + ++plr[v11]._pNumInv; + v12 = v7; + if ( v7 < 0 ) + v12 = 0; + for ( i = 0; i < sy; ++i ) + { + v13 = v18; + if ( v18 < 0 ) + v13 = 0; + v14 = 0; + if ( sx > 0 ) + { + v15 = &plr[v11].InvGrid[v13 + v12]; + do + { + if ( v14 || i != sy - 1 ) + v16 = -_LOBYTE(plr[v11]._pNumInv); + else + v16 = plr[v11]._pNumInv; + *v15++ = v16; + ++v14; + } + while ( v14 < sx ); + } + v12 += 10; + } + CalcPlrScrolls(p); + } + } + else + { + while ( v6 ) + { + if ( v8 >= 40 ) + v6 = 0; + v9 = v18; + if ( v18 < 0 ) + v9 = 0; + for ( j = 0; j < sx; ++j ) + { + if ( !v6 ) + break; + v6 = 0; + if ( v9 < 10 ) + _LOBYTE(v6) = plr[pnum].InvGrid[v9 + v8] == 0; + ++v9; + } + v8 += 10; + if ( ++v20 >= sy ) + { + if ( !v6 ) + return v6; + goto LABEL_16; + } + } + } + return v6; +} + +int __fastcall SpecialAutoPlace(int pnum, int ii, int sx, int sy, int saveflag) +{ + __int64 v5; // rax + int v6; // ebx + signed int v7; // edx + signed int v8; // eax + signed int v9; // esi + int j; // edi + signed int v11; // ecx + int *v12; // eax + int v13; // eax + signed int v14; // esi + signed int v15; // ecx + int v16; // edi + char *v17; // ecx + char v18; // dl + signed int v20; // [esp+Ch] [ebp-Ch] + int p; // [esp+10h] [ebp-8h] + int v22; // [esp+14h] [ebp-4h] + int i; // [esp+14h] [ebp-4h] + + p = pnum; + v5 = ii; + v6 = 1; + v20 = v5 % 10; + v7 = 10 * (unsigned __int64)(v5 / 10); + v8 = v7; + if ( v7 < 0 ) + v8 = 0; + v22 = 0; + if ( sy <= 0 ) + { +LABEL_25: + if ( saveflag ) + { + v13 = p; + qmemcpy(&plr[p].InvList[plr[p]._pNumInv], &plr[p].HoldItem, sizeof(plr[p].InvList[plr[p]._pNumInv])); + ++plr[v13]._pNumInv; + v14 = v7; + if ( v7 < 0 ) + v14 = 0; + for ( i = 0; i < sy; ++i ) + { + v15 = v20; + if ( v20 < 0 ) + v15 = 0; + v16 = 0; + if ( sx > 0 ) + { + v17 = &plr[v13].InvGrid[v15 + v14]; + do + { + if ( v16 || i != sy - 1 ) + v18 = -_LOBYTE(plr[v13]._pNumInv); + else + v18 = plr[v13]._pNumInv; + *v17++ = v18; + ++v16; + } + while ( v16 < sx ); + } + v14 += 10; + } + CalcPlrScrolls(p); + } + return v6; + } + while ( v6 ) + { + if ( v8 >= 40 ) + v6 = 0; + v9 = v20; + if ( v20 < 0 ) + v9 = 0; + for ( j = 0; j < sx; ++j ) + { + if ( !v6 ) + break; + v6 = 0; + if ( v9 < 10 ) + _LOBYTE(v6) = plr[pnum].InvGrid[v9 + v8] == 0; + ++v9; + } + v8 += 10; + if ( ++v22 >= sy ) + { + if ( v6 ) + goto LABEL_25; + break; + } + } + if ( sx <= 1 && sy <= 1 ) + { + v11 = 0; + v12 = &plr[p].SpdList[0]._itype; + while ( *v12 != -1 ) + { + ++v11; + v12 += 92; + if ( v11 >= 8 ) + goto LABEL_24; + } + v6 = 1; + goto LABEL_25; + } + v6 = 0; +LABEL_24: + if ( v6 ) + goto LABEL_25; + return v6; +} + +int __fastcall GoldAutoPlace(int pnum) +{ + int v1; // ebp + int v2; // edi + int v3; // ecx + int *v4; // esi + int v5; // eax + int v6; // edi + int *v7; // esi + int v8; // eax + signed int v9; // ebx + char *v10; // edx + int v11; // eax + int v12; // ecx + int pnuma; // [esp+10h] [ebp-4h] + + pnuma = pnum; + v1 = pnum; + v2 = 0; + v3 = 0; + if ( plr[v1]._pNumInv <= 0 ) + { +LABEL_14: + v6 = 0; + if ( plr[v1]._pNumInv <= 0 ) + { +LABEL_28: + v9 = 39; + do + { + if ( v3 ) + break; + v10 = &plr[0].InvGrid[10 * (v9 / 10) + v1 * 21720 + v9 % 10]; + if ( !*v10 ) + { + v11 = v1 * 21720 + 368 * plr[v1]._pNumInv; + qmemcpy((char *)plr[0].InvList + v11, &plr[v1].HoldItem, 0x170u); + ++plr[v1]._pNumInv; + *v10 = plr[v1]._pNumInv; + v12 = plr[v1].HoldItem._ivalue; + if ( v12 < 2500 ) + { + if ( v12 > 1000 ) + *(int *)((char *)&plr[0].InvList[0]._iCurs + v11) = 5; + else + *(int *)((char *)&plr[0].InvList[0]._iCurs + v11) = 4; + } + else + { + *(int *)((char *)&plr[0].InvList[0]._iCurs + v11) = 6; + } + plr[v1]._pGold = CalculateGold(pnuma); + v3 = 1; + } + --v9; + } + while ( v9 >= 0 ); + } + else + { + v7 = &plr[v1].InvList[0]._ivalue; + while ( !v3 ) + { + if ( *(v7 - 47) == 11 && *v7 < 5000 ) + { + v8 = plr[v1].HoldItem._ivalue + *v7; + if ( v8 <= 5000 ) + { + *v7 = v8; + if ( v8 < 2500 ) + { + if ( v8 > 1000 ) + *(v7 - 1) = 5; + else + *(v7 - 1) = 4; + } + else + { + *(v7 - 1) = 6; + } + plr[v1]._pGold = CalculateGold(pnuma); + v3 = 1; + } + } + ++v6; + v7 += 92; + if ( v6 >= plr[v1]._pNumInv ) + { + if ( v3 ) + return v3; + goto LABEL_28; + } + } + } + } + else + { + v4 = &plr[v1].InvList[0]._ivalue; + while ( !v3 ) + { + if ( *(v4 - 47) == 11 ) + { + v5 = *v4 + plr[v1].HoldItem._ivalue; + if ( v5 <= 5000 ) + { + *v4 = v5; + if ( v5 < 2500 ) + { + if ( v5 > 1000 ) + *(v4 - 1) = 5; + else + *(v4 - 1) = 4; + } + else + { + *(v4 - 1) = 6; + } + plr[v1]._pGold = CalculateGold(pnuma); + v3 = 1; + } + } + ++v2; + v4 += 92; + if ( v2 >= plr[v1]._pNumInv ) + { + if ( v3 ) + return v3; + goto LABEL_14; + } + } + } + return v3; +} + +int __fastcall WeaponAutoPlace(int pnum) +{ + int v1; // edi + int v2; // eax + int v3; // ecx + ItemStruct *v4; // esi + ItemStruct *v5; // edi + int result; // eax + + v1 = pnum; + if ( plr[pnum].HoldItem._iLoc == ILOC_TWOHAND ) + { + if ( plr[v1].InvBody[4]._itype != -1 || plr[v1].InvBody[5]._itype != -1 ) + return 0; +LABEL_12: + NetSendCmdChItem(1u, 4u); + v4 = &plr[v1].HoldItem; + v5 = &plr[v1].InvBody[4]; + goto LABEL_13; + } + v2 = plr[v1].InvBody[4]._itype; + if ( v2 != -1 && plr[v1].InvBody[4]._iClass == 1 ) + return 0; + v3 = plr[v1].InvBody[5]._itype; + if ( v3 != -1 && plr[v1].InvBody[5]._iClass == 1 ) + return 0; + if ( v2 == -1 ) + goto LABEL_12; + if ( v3 == -1 && plr[v1].InvBody[4]._iLoc != ILOC_TWOHAND ) + { + NetSendCmdChItem(1u, 5u); + v4 = &plr[v1].HoldItem; + v5 = &plr[v1].InvBody[5]; +LABEL_13: + result = 1; + qmemcpy(v5, v4, sizeof(ItemStruct)); + return result; + } + return 0; +} + +int __fastcall SwapItem(ItemStruct *a, ItemStruct *b) +{ + int v2; // eax + ItemStruct h; // [esp+8h] [ebp-170h] + + qmemcpy(&h, a, sizeof(h)); + v2 = h._iCurs; + qmemcpy(a, b, sizeof(ItemStruct)); + qmemcpy(b, &h, sizeof(ItemStruct)); + return v2 + 12; +} + +void __fastcall CheckInvPaste(int pnum, int mx, int my) +{ + int v3; // ebx + int v4; // edi + int v5; // eax + int v6; // esi + signed int v7; // edi + int v8; // edx + int v9; // edx + signed int v10; // edi + char v11; // al + signed int v12; // ecx + int v13; // eax + int v14; // eax + char *v15; // edi + int v16; // esi + int v17; // ecx + int v18; // edx + char v19; // al + int v20; // ecx + int v21; // esi + ItemStruct *v22; // edi + ItemStruct *v23; // ecx + int v24; // eax + int v25; // eax + int v26; // edx + ItemStruct *v27; // esi + int v28; // eax + int v29; // ecx + int v30; // esi + int v31; // eax + int v32; // eax + int v33; // ecx + int v34; // eax + int v35; // ecx + char *v36; // eax + int v37; // edx + int v38; // ecx + int v39; // edi + int v40; // esi + int v41; // ebx + int v42; // edx + int v43; // eax + int v44; // eax + signed int v45; // ecx + int v46; // edx + char *v47; // eax + int v48; // edi + int v49; // eax + int v50; // ecx + char *v51; // esi + char v52; // cl + int v53; // ecx + int v54; // eax + int v55; // edi + int v56; // edx + int v57; // esi + int v58; // ebx + int v59; // eax + int v60; // esi + ItemStruct tempitem; // [esp+Ch] [ebp-190h] + int v62; // [esp+17Ch] [ebp-20h] + int p; // [esp+180h] [ebp-1Ch] + int v64; // [esp+184h] [ebp-18h] + int v65; // [esp+188h] [ebp-14h] + int v66; // [esp+18Ch] [ebp-10h] + int v67; // [esp+190h] [ebp-Ch] + int v68; // [esp+194h] [ebp-8h] + int v69; // [esp+198h] [ebp-4h] + int cursor_id; // [esp+1A4h] [ebp+8h] + int cursor_ida; // [esp+1A4h] [ebp+8h] + + p = pnum; + v3 = pnum; + v4 = mx; + SetICursor(plr[pnum].HoldItem._iCurs + 12); + v5 = my + (icursH >> 1); + v6 = v4 + (icursW >> 1); + v64 = icursW28; + v7 = 0; + v67 = icursH28; + v68 = 0; + do + { + if ( v7 ) + goto LABEL_18; + v8 = InvRect[v68].X; + if ( v6 >= v8 && v6 < v8 + 28 ) + { + v9 = InvRect[v68].Y; + if ( v5 >= v9 - 29 && v5 < v9 ) + { + v7 = 1; + --v68; + } + } + if ( v68 != 24 ) + goto LABEL_13; + if ( !(v64 & 1) ) + v6 -= 14; + if ( !(v67 & 1) ) + { + v5 -= 14; +LABEL_13: + if ( v68 == 64 && !(v67 & 1) ) + v5 += 14; + } + ++v68; + } + while ( (unsigned int)v68 < 0x49 ); + if ( !v7 ) + return; +LABEL_18: + v10 = v68; + v69 = ILOC_UNEQUIPABLE; + if ( v68 >= 0 && v68 <= ILOC_ARMOR ) + v69 = ILOC_HELM; + if ( v68 >= ILOC_HELM && v68 <= ILOC_RING ) + v69 = ILOC_RING; + if ( v68 == ILOC_AMULET ) + v69 = ILOC_AMULET; + if ( v68 >= ILOC_UNEQUIPABLE && v68 <= 18 ) + v69 = ILOC_ONEHAND; + if ( v68 >= 19 && v68 <= 24 ) + v69 = ILOC_ARMOR; + if ( v68 >= 65 && v68 <= 72 ) + v69 = ILOC_BELT; + v11 = plr[v3].HoldItem._iLoc; + v12 = 0; + if ( (char)v11 == v69 ) + v12 = 1; + if ( v69 == 1 && v11 == ILOC_TWOHAND ) + { + v69 = ILOC_TWOHAND; + v12 = 1; + } + if ( v11 != 7 || v69 != ILOC_BELT ) + { +LABEL_50: + if ( v69 != ILOC_UNEQUIPABLE ) + goto LABEL_81; + v66 = 0; + cursor_id = 1; + v13 = (v68 - 25) / 10; + if ( plr[v3].HoldItem._itype == ITYPE_GOLD ) + { + _LOBYTE(v13) = plr[0].InvGrid[10 * v13 + v3 * 21720 + (v68 - 25) % 10]; + if ( !(_BYTE)v13 ) + goto LABEL_93; + v13 = (char)v13; + if ( (char)v13 <= 0 ) + { + v13 = -v13; + } + else if ( *(int *)((char *)&plr[0].InvBody[v13 + 6]._itype + v3 * 21720) == ITYPE_GOLD ) + { + goto LABEL_93; + } + v66 = v13; +LABEL_93: + v21 = p; + if ( p == myplr ) + { + PlaySFX(ItemInvSnds[ItemCAnimTbl[plr[v3].HoldItem._iCurs]]); + v10 = v68; + } + cursor_ida = 1; + switch ( v69 ) + { + case ILOC_ONEHAND: + if ( v10 > 12 ) + { + if ( plr[v3].InvBody[5]._itype == ITYPE_NONE ) + { + v25 = plr[v3].InvBody[4]._itype; + if ( v25 == ITYPE_NONE ) + goto LABEL_232; + if ( plr[v3].InvBody[4]._iLoc == ILOC_TWOHAND ) + { + NetSendCmdDelItem(0, 4u); + NetSendCmdChItem(0, 5u); + SwapItem(&plr[v3].InvBody[5], &plr[v3].InvBody[4]); + v23 = &plr[v3].InvBody[5]; +LABEL_99: + v24 = SwapItem(v23, &plr[v3].HoldItem); +LABEL_172: + cursor_ida = v24; + goto LABEL_226; + } + if ( v25 == ITYPE_NONE || plr[v3].InvBody[4]._iClass != plr[v3].HoldItem._iClass ) + { +LABEL_232: + NetSendCmdChItem(0, 5u); + v22 = &plr[v3].InvBody[5]; +LABEL_158: + qmemcpy(v22, &plr[v3].HoldItem, sizeof(ItemStruct)); + goto LABEL_226; + } + } + else if ( plr[v3].InvBody[4]._itype == ITYPE_NONE + || plr[v3].InvBody[4]._iClass != plr[v3].HoldItem._iClass ) + { + goto LABEL_114; + } + } + else + { + if ( plr[v3].InvBody[4]._itype == ITYPE_NONE ) + { + if ( plr[v3].InvBody[5]._itype != ITYPE_NONE + && plr[v3].InvBody[5]._iClass == plr[v3].HoldItem._iClass ) + { +LABEL_114: + NetSendCmdChItem(0, 5u); + v23 = &plr[v3].InvBody[5]; + goto LABEL_99; + } + NetSendCmdChItem(0, 4u); + v22 = &plr[v3].InvBody[4]; + goto LABEL_158; + } + if ( plr[v3].InvBody[5]._itype != ITYPE_NONE + && plr[v3].InvBody[5]._iClass == plr[v3].HoldItem._iClass ) + { + goto LABEL_114; + } + } + NetSendCmdChItem(0, 4u); + v23 = &plr[v3].InvBody[4]; + goto LABEL_99; + case ILOC_TWOHAND: + NetSendCmdDelItem(0, 5u); + if ( plr[v3].InvBody[4]._itype == ITYPE_NONE ) + goto LABEL_147; + v26 = plr[v3].InvBody[5]._itype; + if ( v26 == -1 ) + goto LABEL_146; + qmemcpy(&tempitem, &plr[v3].HoldItem, sizeof(tempitem)); + v27 = &plr[v3].InvBody[5]; + if ( v26 != 5 ) + v27 = &plr[v3].InvBody[4]; + v28 = p; + qmemcpy(&plr[v3].HoldItem, v27, sizeof(plr[v3].HoldItem)); + v29 = plr[v3].HoldItem._iCurs + 12; + if ( v28 == myplr ) + SetCursor(v29); + else + SetICursor(v29); + v67 = 0; + v30 = 0; + do + { + if ( v67 ) + break; + v31 = AutoPlace(p, v30++, icursW28, icursH28, 1); + v67 = v31; + } + while ( v30 < 40 ); + v32 = p; + qmemcpy(&plr[v3].HoldItem, &tempitem, sizeof(plr[v3].HoldItem)); + v33 = plr[v3].HoldItem._iCurs + 12; + if ( v32 == myplr ) + SetCursor(v33); + else + SetICursor(v33); + if ( !v67 ) + return; + if ( plr[v3].InvBody[5]._itype == ITYPE_SHIELD ) + plr[v3].InvBody[5]._itype = ITYPE_NONE; + else + plr[v3].InvBody[4]._itype = ITYPE_NONE; +LABEL_146: + if ( plr[v3].InvBody[4]._itype != ITYPE_NONE ) + goto LABEL_149; +LABEL_147: + if ( plr[v3].InvBody[5]._itype == ITYPE_NONE ) + { + NetSendCmdChItem(0, 4u); + qmemcpy(&plr[v3].InvBody[4], &plr[v3].HoldItem, sizeof(plr[v3].InvBody[4])); + } + else + { +LABEL_149: + NetSendCmdChItem(0, 4u); + if ( plr[v3].InvBody[4]._itype == ITYPE_NONE ) + SwapItem(&plr[v3].InvBody[4], &plr[v3].InvBody[5]); + cursor_ida = SwapItem(&plr[v3].InvBody[4], &plr[v3].HoldItem); + } + if ( plr[v3].InvBody[4]._itype == ITYPE_STAFF ) + { + v34 = plr[v3].InvBody[4]._iSpell; + if ( v34 ) + { + if ( plr[v3].InvBody[4]._iCharges > 0 ) + { + plr[v3]._pRSpell = v34; + _LOBYTE(plr[v3]._pRSplType) = 3; + drawpanflag = 255; + } + } + } + goto LABEL_226; + case ILOC_ARMOR: + NetSendCmdChItem(0, 6u); + if ( plr[v3].InvBody[6]._itype == ITYPE_NONE ) + { + v22 = &plr[v3].InvBody[6]; + goto LABEL_158; + } + v23 = &plr[v3].InvBody[6]; + goto LABEL_99; + case ILOC_HELM: + NetSendCmdChItem(0, 0); + if ( plr[v3].InvBody[0]._itype == ITYPE_NONE ) + { + v22 = plr[v3].InvBody; + goto LABEL_158; + } + v23 = plr[v3].InvBody; + goto LABEL_99; + case ILOC_RING: + if ( v10 == 4 ) + { + NetSendCmdChItem(0, 1u); + if ( plr[v3].InvBody[1]._itype == ITYPE_NONE ) + { + v22 = &plr[v3].InvBody[1]; + goto LABEL_158; + } + v23 = &plr[v3].InvBody[1]; + } + else + { + NetSendCmdChItem(0, 2u); + if ( plr[v3].InvBody[2]._itype == ITYPE_NONE ) + { + v22 = &plr[v3].InvBody[2]; + goto LABEL_158; + } + v23 = &plr[v3].InvBody[2]; + } + goto LABEL_99; + case ILOC_AMULET: + NetSendCmdChItem(0, 3u); + if ( plr[v3].InvBody[3]._itype == ITYPE_NONE ) + { + v22 = &plr[v3].InvBody[3]; + goto LABEL_158; + } + v23 = &plr[v3].InvBody[3]; + goto LABEL_99; + case ILOC_UNEQUIPABLE: + v35 = plr[v3].HoldItem._itype; + if ( v35 == 11 ) + { + if ( !v66 ) + { + v36 = &plr[0].InvGrid[10 * ((v68 - 25) / 10) + v3 * 21720 + (v68 - 25) % 10]; + if ( *v36 <= 0 ) + { + v42 = 368 * plr[v3]._pNumInv + v3 * 21720; + qmemcpy((char *)plr[0].InvList + v42, &plr[v3].HoldItem, 0x170u); + ++plr[v3]._pNumInv; + *v36 = plr[v3]._pNumInv; + v43 = plr[v3].HoldItem._ivalue; + plr[v3]._pGold += v43; + if ( v43 <= 5000 ) + { + if ( v43 < 2500 ) + { + if ( v43 > 1000 ) + *(int *)((char *)&plr[0].InvList[0]._iCurs + v42) = 5; + else + *(int *)((char *)&plr[0].InvList[0]._iCurs + v42) = 4; + } + else + { + *(int *)((char *)&plr[0].InvList[0]._iCurs + v42) = 6; + } + } + goto LABEL_226; + } + v37 = plr[v3].HoldItem._ivalue; + v38 = 368 * (*v36 - 1) + v3 * 21720; + v39 = *(int *)((char *)&plr[0].InvList[0]._ivalue + v38); + v40 = v37 + v39; + if ( v37 + v39 <= 5000 ) + { + *(int *)((char *)&plr[0].InvList[0]._ivalue + v38) = v40; + plr[v3]._pGold += plr[v3].HoldItem._ivalue; + if ( v40 < 2500 ) + { + if ( v40 > 1000 ) + *(int *)((char *)&plr[0].InvList[0]._iCurs + v38) = 5; + else + *(int *)((char *)&plr[0].InvList[0]._iCurs + v38) = 4; + } + else + { + *(int *)((char *)&plr[0].InvList[0]._iCurs + v38) = 6; + } + goto LABEL_226; + } + plr[v3]._pGold += 5000 - v39; + plr[v3].HoldItem._ivalue = v37 - (5000 - v39); + *(int *)((char *)&plr[0].InvList[0]._ivalue + v38) = 5000; + *(int *)((char *)&plr[0].InvList[0]._iCurs + v38) = 6; + v41 = plr[v3].HoldItem._ivalue; + if ( v41 >= 2500 ) + { + cursor_ida = 18; + goto LABEL_226; + } + v24 = (v41 > 1000) + 16; + goto LABEL_172; + } + } + else if ( !v66 ) + { + qmemcpy((char *)&plr[0].InvList[plr[v3]._pNumInv++] + v3 * 21720, &plr[v3].HoldItem, 0x170u); + v66 = plr[v3]._pNumInv; +LABEL_191: + v48 = v67; + v49 = 10 * ((v68 - 25) / 10 - ((v67 - 1) >> 1)); + if ( v49 < 0 ) + v49 = 0; + v65 = 0; + if ( v67 > 0 ) + { + v69 = (v68 - 25) % 10 - ((v64 - 1) >> 1); + do + { + v50 = v69; + if ( v69 < 0 ) + v50 = 0; + v67 = 0; + if ( v64 > 0 ) + { + v51 = &plr[v3].InvGrid[v50 + v49]; + do + { + if ( v67 || v65 != v48 - 1 ) + v52 = -(char)v66; + else + v52 = v66; + *v51++ = v52; + ++v67; + } + while ( v67 < v64 ); + } + v49 += 10; + ++v65; + } + while ( v65 < v48 ); + } + goto LABEL_226; + } + v44 = v66 - 1; + if ( v35 == 11 ) + plr[v3]._pGold += plr[v3].HoldItem._ivalue; + cursor_ida = SwapItem((ItemStruct *)((char *)&plr[0].InvList[v44] + v3 * 21720), &plr[v3].HoldItem); + if ( plr[v3].HoldItem._itype == ITYPE_GOLD ) + plr[v3]._pGold = CalculateGold(v21); + v45 = 0; + v46 = -v66; + do + { + v47 = &plr[v3].InvGrid[v45]; + if ( *v47 == v66 ) + *v47 = 0; + if ( *v47 == v46 ) + *v47 = 0; + ++v45; + } + while ( v45 < 40 ); + goto LABEL_191; + case ILOC_BELT: + v53 = v3 * 21720 + 368 * (v68 - 65); + if ( plr[v3].HoldItem._itype != ITYPE_GOLD ) + { + if ( *(int *)((char *)&plr[0].SpdList[0]._itype + v53) == ITYPE_NONE ) + { + qmemcpy((char *)plr[0].SpdList + v53, &plr[v3].HoldItem, 0x170u); + } + else + { + cursor_ida = SwapItem((ItemStruct *)((char *)plr[0].SpdList + v53), &plr[v3].HoldItem); + if ( plr[v3].HoldItem._itype == ITYPE_GOLD ) + plr[v3]._pGold = CalculateGold(p); + } + goto LABEL_225; + } + v54 = *(int *)((char *)&plr[0].SpdList[0]._itype + v53); + if ( v54 != -1 ) + { + if ( v54 == 11 ) + { + v55 = *(int *)((char *)&plr[0].SpdList[0]._ivalue + v53); + v56 = plr[v3].HoldItem._ivalue; + v57 = v55 + v56; + if ( v55 + v56 <= 5000 ) + { + *(int *)((char *)&plr[0].SpdList[0]._ivalue + v53) = v57; + plr[v3]._pGold += plr[v3].HoldItem._ivalue; + if ( v57 < 2500 ) + { + if ( v57 > 1000 ) + *(int *)((char *)&plr[0].SpdList[0]._iCurs + v53) = 5; + else + *(int *)((char *)&plr[0].SpdList[0]._iCurs + v53) = 4; + } + else + { + *(int *)((char *)&plr[0].SpdList[0]._iCurs + v53) = 6; + } + goto LABEL_225; + } + plr[v3]._pGold += 5000 - v55; + plr[v3].HoldItem._ivalue = v56 - (5000 - v55); + *(int *)((char *)&plr[0].SpdList[0]._ivalue + v53) = 5000; + *(int *)((char *)&plr[0].SpdList[0]._iCurs + v53) = 6; + v58 = plr[v3].HoldItem._ivalue; + if ( v58 >= 2500 ) + { + cursor_ida = 18; + goto LABEL_225; + } + v59 = (v58 > 1000) + 16; + } + else + { + plr[v3]._pGold += plr[v3].HoldItem._ivalue; + v59 = SwapItem((ItemStruct *)((char *)plr[0].SpdList + v53), &plr[v3].HoldItem); + } + cursor_ida = v59; + goto LABEL_225; + } + qmemcpy((char *)plr[0].SpdList + v53, &plr[v3].HoldItem, 0x170u); + plr[v3]._pGold += plr[v3].HoldItem._ivalue; +LABEL_225: + drawsbarflag = 1; +LABEL_226: + v60 = p; + CalcPlrInv(p, 1u); + if ( v60 == myplr ) + { + if ( cursor_ida == 1 ) + SetCursorPos(MouseX + (cursW >> 1), MouseY + (cursH >> 1)); + SetCursor(cursor_ida); + } + return; + default: + goto LABEL_226; + } + } + v62 = (v68 - 25) % 10; + v14 = 10 * (v13 - ((v67 - 1) >> 1)); + if ( v14 < 0 ) + v14 = 0; + v65 = 0; + if ( v67 <= 0 ) + goto LABEL_93; + v15 = &plr[v3].InvGrid[v14]; + while ( 1 ) + { + if ( cursor_id == CURSOR_NONE ) + return; + if ( v14 >= 40 ) + cursor_id = 0; + v16 = v62 - ((v64 - 1) >> 1); + if ( v16 < 0 ) + v16 = 0; + v17 = 0; + if ( v64 > 0 ) + break; +LABEL_79: + v14 += 10; + v15 += 10; + if ( ++v65 >= v67 ) + { + v12 = cursor_id; + v10 = v68; + goto LABEL_81; + } + } + while ( 1 ) + { + if ( cursor_id == CURSOR_NONE ) + goto LABEL_79; + if ( v16 >= 10 ) + goto LABEL_233; + _LOBYTE(v18) = v15[v16]; + if ( (_BYTE)v18 ) + { + v18 = (char)v18; + if ( (v18 & 0x80u) != 0 ) + v18 = -v18; + if ( !v66 ) + { + v66 = v18; + goto LABEL_78; + } + if ( v66 != v18 ) +LABEL_233: + cursor_id = 0; + } +LABEL_78: + ++v16; + if ( ++v17 >= v64 ) + goto LABEL_79; + } + } + if ( v64 == 1 && v67 == 1 ) + { + v12 = 1; + if ( !AllItemsList[plr[v3].HoldItem.IDidx].iUsable ) + v12 = 0; + if ( !plr[v3].HoldItem._iStatFlag ) + v12 = 0; + if ( plr[v3].HoldItem._itype == ITYPE_GOLD ) + { + v12 = 0; + goto LABEL_50; + } + } +LABEL_81: + if ( !v12 ) + return; + if ( v69 == ILOC_UNEQUIPABLE || v69 == ILOC_BELT || plr[v3].HoldItem._iStatFlag ) + goto LABEL_92; + v19 = plr[v3]._pClass; + if ( !v19 ) + { + v20 = PS_WARR13; + goto LABEL_89; + } + if ( v19 != 1 ) + { + if ( v19 != 2 ) + return; + PlaySFX(PS_MAGE13); + v12 = 0; + v10 = v68; +LABEL_92: + if ( !v12 ) + return; + goto LABEL_93; + } + v20 = PS_ROGUE13; +LABEL_89: + PlaySFX(v20); +} +// 4B8C9C: using guessed type int cursH; +// 4B8CB4: using guessed type int icursH; +// 4B8CBC: using guessed type int icursW; +// 52571C: using guessed type int drawpanflag; + +void __fastcall CheckInvSwap(int pnum, BYTE bLoc, int idx, WORD wCI, int seed, BOOL bId) +{ + RecreateItem(MAXITEMS, idx, wCI, seed, 0); + + PlayerStruct *p = &plr[pnum]; + p->HoldItem = item[MAXITEMS]; + + if ( bId ) + { + p->HoldItem._iIdentified = TRUE; + } + + if ( bLoc < NUM_INVLOC ) + { + p->InvBody[bLoc] = p->HoldItem; + + if ( bLoc == INVLOC_HAND_LEFT && p->HoldItem._iLoc == ILOC_TWOHAND ) + { + p->InvBody[INVLOC_HAND_RIGHT]._itype = ITYPE_NONE; + } + else if ( bLoc == INVLOC_HAND_RIGHT && p->HoldItem._iLoc == ILOC_TWOHAND ) + { + p->InvBody[INVLOC_HAND_LEFT]._itype = ITYPE_NONE; + } + } + + CalcPlrInv(pnum, TRUE); +} + +void __fastcall CheckInvCut(int pnum, int mx, int my) +{ + if ( plr[pnum]._pmode > PM_WALK3 ) + { + return; + } + + if ( dropGoldFlag ) + { + dropGoldFlag = 0; + dropGoldValue = 0; + } + + int r; + BOOL done = FALSE; + + // TODO: this loop is compiled differently (via InvRect pointers) + for ( r = 0; (DWORD)r < NUM_XY_SLOTS && !done; r++ ) + { + // check which inventory rectangle the mouse is in, if any + if ( mx >= InvRect[r].X + && mx < InvRect[r].X + (INV_SLOT_SIZE_PX + 1) + && my >= InvRect[r].Y - (INV_SLOT_SIZE_PX + 1) + && my < InvRect[r].Y ) + { + done = TRUE; + r--; + } + } + + if ( !done ) + { + // not on an inventory slot rectangle + return; + } + + plr[pnum].HoldItem._itype = ITYPE_NONE; + + if ( + r >= SLOTXY_HEAD_FIRST + && r <= SLOTXY_HEAD_LAST + && plr[pnum].InvBody[INVLOC_HEAD]._itype != ITYPE_NONE ) + { + NetSendCmdDelItem(FALSE, INVLOC_HEAD); + plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_HEAD]; + plr[pnum].InvBody[INVLOC_HEAD]._itype = ITYPE_NONE; + } + + if ( + r == SLOTXY_RING_LEFT + && plr[pnum].InvBody[INVLOC_RING_LEFT]._itype != ITYPE_NONE ) + { + NetSendCmdDelItem(FALSE, INVLOC_RING_LEFT); + plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_RING_LEFT]; + plr[pnum].InvBody[INVLOC_RING_LEFT]._itype = ITYPE_NONE; + } + + if ( + r == SLOTXY_RING_RIGHT + && plr[pnum].InvBody[INVLOC_RING_RIGHT]._itype != ITYPE_NONE ) + { + NetSendCmdDelItem(FALSE, INVLOC_RING_RIGHT); + plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_RING_RIGHT]; + plr[pnum].InvBody[INVLOC_RING_RIGHT]._itype = ITYPE_NONE; + } + + if ( + r == SLOTXY_AMULET + && plr[pnum].InvBody[INVLOC_AMULET]._itype != ITYPE_NONE ) + { + NetSendCmdDelItem(FALSE, INVLOC_AMULET); + plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_AMULET]; + plr[pnum].InvBody[INVLOC_AMULET]._itype = ITYPE_NONE; + } + + if ( + r >= SLOTXY_HAND_LEFT_FIRST + && r <= SLOTXY_HAND_LEFT_LAST + && plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE ) + { + NetSendCmdDelItem(FALSE, INVLOC_HAND_LEFT); + plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_HAND_LEFT]; + plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype = ITYPE_NONE; + } + + if ( + r >= SLOTXY_HAND_RIGHT_FIRST + && r <= SLOTXY_HAND_RIGHT_LAST + && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE ) + { + NetSendCmdDelItem(FALSE, INVLOC_HAND_RIGHT); + plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_HAND_RIGHT]; + plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype = ITYPE_NONE; + } + + if ( + r >= SLOTXY_CHEST_FIRST + && r <= SLOTXY_CHEST_LAST + && plr[pnum].InvBody[INVLOC_CHEST]._itype != ITYPE_NONE ) + { + NetSendCmdDelItem(FALSE, INVLOC_CHEST); + plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_CHEST]; + plr[pnum].InvBody[INVLOC_CHEST]._itype = ITYPE_NONE; + } + + if ( r >= SLOTXY_INV_FIRST && r <= SLOTXY_INV_LAST ) + { + char ii = plr[pnum].InvGrid[r - SLOTXY_INV_FIRST]; + if ( ii ) + { + int iv = ii; + if ( ii <= 0 ) + { + iv = -ii; + } + + for ( int i = 0; i < NUM_INV_GRID_ELEM; i++ ) + { + if ( plr[pnum].InvGrid[i] == iv || plr[pnum].InvGrid[i] == -iv ) + { + plr[pnum].InvGrid[i] = 0; + } + } + + iv--; + + plr[pnum].HoldItem = plr[pnum].InvList[iv]; + plr[pnum]._pNumInv--; + + if ( plr[pnum]._pNumInv > 0 && plr[pnum]._pNumInv != iv ) + { + plr[pnum].InvList[iv] = plr[pnum].InvList[plr[pnum]._pNumInv]; + + for ( int j = 0; j < NUM_INV_GRID_ELEM; j++ ) + { + if ( plr[pnum].InvGrid[j] == plr[pnum]._pNumInv + 1 ) + { + plr[pnum].InvGrid[j] = iv + 1; + } + if ( plr[pnum].InvGrid[j] == -(plr[pnum]._pNumInv + 1) ) + { + plr[pnum].InvGrid[j] = -iv - 1; + } + } + } + } + } + + if ( r >= SLOTXY_BELT_FIRST ) + { + int offs = r - SLOTXY_BELT_FIRST; + if ( plr[pnum].SpdList[offs]._itype != ITYPE_NONE ) + { + plr[pnum].HoldItem = plr[pnum].SpdList[offs]; + plr[pnum].SpdList[offs]._itype = ITYPE_NONE; + drawsbarflag = 1; + } + } + + + if ( plr[pnum].HoldItem._itype != ITYPE_NONE ) + { + if ( plr[pnum].HoldItem._itype == ITYPE_GOLD ) + { + plr[pnum]._pGold = CalculateGold(pnum); + } + + CalcPlrInv(pnum, TRUE); + CheckItemStats(pnum); + + if ( pnum == myplr ) + { + PlaySFX(IS_IGRAB); + SetCursor(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM); + SetCursorPos(mx - (cursW >> 1), MouseY - (cursH >> 1)); + } + } +} + +void __fastcall inv_update_rem_item(int pnum, BYTE iv) +{ + if ( iv < NUM_INVLOC ) + { + plr[pnum].InvBody[iv]._itype = ITYPE_NONE; + } + + BOOL Loadgfx = FALSE; + + if ( plr[pnum]._pmode != PM_DEATH ) + { + Loadgfx = TRUE; + } + + CalcPlrInv(pnum, Loadgfx); +} + +void __fastcall RemoveInvItem(int pnum, int iv) +{ + iv++; + + for ( int i = 0; i < NUM_INV_GRID_ELEM; i++ ) + { + if ( plr[pnum].InvGrid[i] == iv || plr[pnum].InvGrid[i] == -iv ) + { + plr[pnum].InvGrid[i] = 0; + } + } + + iv--; + plr[pnum]._pNumInv--; + + if ( plr[pnum]._pNumInv > 0 && plr[pnum]._pNumInv != iv ) + { + plr[pnum].InvList[iv] = plr[pnum].InvList[plr[pnum]._pNumInv]; + + for ( int j = 0; j < NUM_INV_GRID_ELEM; j++ ) + { + if ( plr[pnum].InvGrid[j] == plr[pnum]._pNumInv + 1 ) + { + plr[pnum].InvGrid[j] = iv + 1; + } + if ( plr[pnum].InvGrid[j] == -(plr[pnum]._pNumInv + 1) ) + { + plr[pnum].InvGrid[j] = -(iv + 1); + } + } + } + + CalcPlrScrolls(pnum); + + if ( plr[pnum]._pRSplType == RSPLTYPE_SCROLL ) + { + if ( plr[pnum]._pRSpell != SPL_INVALID ) + { + // BUGFIX: Cast the literal `1` to `UINT64` to make that bitshift 64bit + // this causes the last 4 skills to not reset correctly after use + if ( !( + plr[pnum]._pScrlSpells64 + & (1 << (plr[pnum]._pRSpell - 1))) ) + { + plr[pnum]._pRSpell = SPL_INVALID; + } + + drawpanflag = 255; + } + } +} + +void __fastcall RemoveSpdBarItem(int pnum, int iv) +{ + plr[pnum].SpdList[iv]._itype = ITYPE_NONE; + + CalcPlrScrolls(pnum); + + if ( plr[pnum]._pRSplType == RSPLTYPE_SCROLL ) + { + if ( plr[pnum]._pRSpell != SPL_INVALID ) + { + // BUGFIX: Cast the literal `1` to `UINT64` to make that bitshift 64bit + // this causes the last 4 skills to not reset correctly after use + if ( !( + plr[pnum]._pScrlSpells64 + & (1 << (plr[pnum]._pRSpell - 1))) ) + { + plr[pnum]._pRSpell = SPL_INVALID; + } + + } + } + drawpanflag = 255; +} + +void __cdecl CheckInvItem() +{ + if ( pcurs >= CURSOR_FIRSTITEM ) + { + CheckInvPaste(myplr, MouseX, MouseY); + } + else + { + CheckInvCut(myplr, MouseX, MouseY); + } +} + +void __cdecl CheckInvScrn() +{ + if ( MouseX > 190 && MouseX < 437 + && MouseY > 352 && MouseY < 385 ) + { + CheckInvItem(); + } +} + +void __fastcall CheckItemStats(int pnum) +{ + PlayerStruct *p = &plr[pnum]; + + p->HoldItem._iStatFlag = FALSE; + + if ( p->_pStrength >= p->HoldItem._iMinStr + && p->_pMagic >= p->HoldItem._iMinMag + && p->_pDexterity >= p->HoldItem._iMinDex ) + { + p->HoldItem._iStatFlag = TRUE; + } +} + +void __fastcall CheckBookLevel(int pnum) +{ + int v1; // ecx + int v2; // eax + unsigned char v3; // bl + int v4; // edi + + v1 = pnum; + if ( plr[v1].HoldItem._iMiscId == IMISC_BOOK ) + { + v2 = plr[v1].HoldItem._iSpell; + v3 = spelldata[plr[v1].HoldItem._iSpell].sMinInt; + plr[v1].HoldItem._iMinMag = v3; + v4 = plr[0]._pSplLvl[v2 + v1 * 21720]; + if ( plr[0]._pSplLvl[v2 + v1 * 21720] ) + { + do + { + v3 += 20 * v3 / 100; + --v4; + if ( v3 + 20 * v3 / 100 > 255 ) + { + v3 = -1; + v4 = 0; + } + } + while ( v4 ); + plr[v1].HoldItem._iMinMag = v3; + } + } +} + +void __fastcall CheckQuestItem(int pnum) +{ + int v1; // ecx + int v2; // esi + char v3; // cl + char v4; // cl + char v5; // cl + char v6; // cl + char v7; // al + + v1 = pnum; + v2 = plr[v1].HoldItem.IDidx; + if ( v2 == IDI_OPTAMULET ) + quests[8]._qactive = 3; + if ( v2 == IDI_MUSHROOM && quests[1]._qactive == 2 && quests[1]._qvar1 == 3 ) + { + v3 = plr[v1]._pClass; + sfxdelay = IDI_OPTAMULET; + if ( v3 ) + { + if ( v3 == 1 ) + { + sfxdnum = PS_ROGUE95; + } + else if ( v3 == 2 ) + { + sfxdnum = PS_MAGE95; + } + } + else + { + sfxdnum = PS_WARR95; + } + quests[1]._qvar1 = 4; + } + if ( v2 == IDI_ANVIL ) + { + if ( quests[10]._qactive == 1 ) + { + quests[10]._qactive = 2; + quests[10]._qvar1 = 1; + } + if ( quests[10]._qlog == 1 ) + { + sfxdelay = IDI_OPTAMULET; + v4 = plr[myplr]._pClass; + if ( v4 ) + { + if ( v4 == 1 ) + { + sfxdnum = PS_ROGUE89; + } + else if ( v4 == 2 ) + { + sfxdnum = PS_MAGE89; + } + } + else + { + sfxdnum = PS_WARR89; + } + } + } + if ( v2 == IDI_GLDNELIX ) + { + sfxdelay = 30; + v5 = plr[myplr]._pClass; + if ( v5 ) + { + if ( v5 == 1 ) + { + sfxdnum = PS_ROGUE88; + } + else if ( v5 == 2 ) + { + sfxdnum = PS_MAGE88; + } + } + else + { + sfxdnum = PS_WARR88; + } + } + if ( v2 == IDI_ROCK ) + { + if ( quests[0]._qactive == 1 ) + { + quests[0]._qactive = 2; + quests[0]._qvar1 = 1; + } + if ( quests[0]._qlog == 1 ) + { + sfxdelay = IDI_OPTAMULET; + v6 = plr[myplr]._pClass; + if ( v6 ) + { + if ( v6 == 1 ) + { + sfxdnum = PS_ROGUE87; + } + else if ( v6 == 2 ) + { + sfxdnum = PS_MAGE87; + } + } + else + { + sfxdnum = PS_WARR87; + } + } + } + if ( v2 == IDI_ARMOFVAL ) + { + quests[9]._qactive = 3; + sfxdelay = 20; + v7 = plr[myplr]._pClass; + if ( v7 ) + { + if ( v7 == 1 ) + { + sfxdnum = PS_ROGUE91; + } + else if ( v7 == 2 ) + { + sfxdnum = PS_MAGE91; + } + } + else + { + sfxdnum = PS_WARR91; + } + } +} +// 52A554: using guessed type int sfxdelay; + +void __fastcall InvGetItem(int pnum, int ii) +{ + int v2; // ebp + int v3; // edx + int v4; // ecx + int v5; // ecx + int pnuma; // [esp+4h] [ebp-8h] + int v7; // [esp+8h] [ebp-4h] + + v7 = ii; + pnuma = pnum; + if ( dropGoldFlag ) + { + dropGoldFlag = 0; + dropGoldValue = 0; + } + v2 = ii; + if ( dItem[item[ii]._ix][item[ii]._iy] ) + { + if ( myplr == pnum && pcurs >= CURSOR_FIRSTITEM ) + NetSendCmdPItem(1u, CMD_SYNCPUTITEM, plr[myplr].WorldX, plr[myplr].WorldY); + _HIBYTE(item[v2]._iCreateInfo) &= 0x7Fu; + qmemcpy(&plr[pnuma].HoldItem, &item[v2], sizeof(plr[pnuma].HoldItem)); + CheckQuestItem(pnuma); + CheckBookLevel(pnuma); + CheckItemStats(pnuma); + v3 = 0; + dItem[item[v2]._ix][item[v2]._iy] = 0; + while ( v3 < numitems ) + { + v4 = itemactive[v3]; + if ( v4 == v7 ) + { + DeleteItem(v4, v3); + v3 = 0; + } + else + { + ++v3; + } + } + v5 = plr[pnuma].HoldItem._iCurs; + pcursitem = -1; + SetCursor(v5 + 12); + } +} +// 4B84DC: using guessed type int dropGoldFlag; +// 4B8CC0: using guessed type char pcursitem; + +void __fastcall AutoGetItem(int pnum, int ii) +{ + int v2; // ebx + int v3; // ebp + int v4; // eax + int v5; // ecx + int v6; // edi + int v7; // edi + int v8; // edi + int v9; // edi + int v10; // edx + int v11; // ecx + char v12; // al + int v13; // ecx + int iia; // [esp+10h] [ebp-18h] + signed int iib; // [esp+10h] [ebp-18h] + signed int iic; // [esp+10h] [ebp-18h] + signed int iid; // [esp+10h] [ebp-18h] + signed int iie; // [esp+10h] [ebp-18h] + signed int iif; // [esp+10h] [ebp-18h] + signed int iig; // [esp+10h] [ebp-18h] + signed int iih; // [esp+10h] [ebp-18h] + signed int iii; // [esp+10h] [ebp-18h] + signed int iij; // [esp+10h] [ebp-18h] + ItemStruct *v24; // [esp+14h] [ebp-14h] + int *v25; // [esp+14h] [ebp-14h] + int v26; // [esp+18h] [ebp-10h] + int i; // [esp+1Ch] [ebp-Ch] + int v28; // [esp+20h] [ebp-8h] + int v29; // [esp+24h] [ebp-4h] + + v2 = pnum; + i = ii; + if ( dropGoldFlag ) + { + dropGoldFlag = 0; + dropGoldValue = 0; + } + if ( ii == 127 || dItem[item[ii]._ix][item[ii]._iy] ) + { + v3 = pnum; + _HIBYTE(item[ii]._iCreateInfo) &= 0x7Fu; + v28 = ii; + qmemcpy(&plr[pnum].HoldItem, &item[ii], sizeof(plr[pnum].HoldItem)); + CheckQuestItem(pnum); + CheckBookLevel(v2); + CheckItemStats(v2); + SetICursor(plr[v2].HoldItem._iCurs + 12); + if ( plr[v2].HoldItem._itype == ITYPE_GOLD ) + { + v4 = GoldAutoPlace(v2); + } + else + { + v4 = 0; + if ( (!(plr[v3]._pgfxnum & 0xF) || (plr[v3]._pgfxnum & 0xF) == 1) && plr[v3]._pmode <= PM_WALK3 ) + { + if ( plr[v3].HoldItem._iStatFlag ) + { + if ( plr[v3].HoldItem._iClass == 1 ) + { + v4 = WeaponAutoPlace(v2); + if ( v4 ) + { + CalcPlrInv(v2, 1u); + goto LABEL_71; + } + } + } + } + v5 = icursW28; + v29 = icursW28; + v26 = icursH28; + if ( icursW28 == 1 ) + { + if ( icursH28 == 1 ) + { + if ( plr[v3].HoldItem._iStatFlag && AllItemsList[plr[v3].HoldItem.IDidx].iUsable ) + { + iia = 0; + v24 = plr[v3].SpdList; + do + { + if ( v4 ) + break; + if ( v24->_itype == -1 ) + { + qmemcpy(v24, &plr[v3].HoldItem, sizeof(ItemStruct)); + CalcPlrScrolls(v2); + v4 = 1; + drawsbarflag = 1; + } + ++iia; + ++v24; + } + while ( iia < 8 ); + } + v6 = 30; + do + { + if ( v4 ) + break; + v4 = AutoPlace(v2, v6++, 1, 1, 1); + } + while ( v6 <= 39 ); + v7 = 20; + do + { + if ( v4 ) + break; + v4 = AutoPlace(v2, v7++, 1, 1, 1); + } + while ( v7 <= 29 ); + v8 = 10; + do + { + if ( v4 ) + break; + v4 = AutoPlace(v2, v8++, 1, 1, 1); + } + while ( v8 <= 19 ); + v9 = 0; + while ( !v4 ) + { + v4 = AutoPlace(v2, v9++, 1, 1, 1); + if ( v9 > 9 ) + goto LABEL_35; + } + goto LABEL_71; + } +LABEL_35: + if ( v26 == 2 ) + { + iib = 29; + do + { + if ( v4 ) + break; + v4 = AutoPlace(v2, iib--, 1, 2, 1); + } + while ( iib >= 20 ); + iic = 9; + do + { + if ( v4 ) + break; + v4 = AutoPlace(v2, iic--, 1, 2, 1); + } + while ( iic >= 0 ); + iid = 19; + while ( !v4 ) + { + v4 = AutoPlace(v2, iid--, 1, 2, 1); + if ( iid < 10 ) + goto LABEL_45; + } + goto LABEL_71; + } +LABEL_45: + if ( v26 == 3 ) + { + iie = 0; + while ( !v4 ) + { + v4 = AutoPlace(v2, iie++, 1, 3, 1); + if ( iie >= 20 ) + goto LABEL_49; + } + goto LABEL_71; + } + } + else + { +LABEL_49: + if ( v29 == 2 ) + { + if ( v26 == 2 ) + { + v25 = AP2x2Tbl; + do + { + if ( v4 ) + break; + v4 = AutoPlace(v2, *v25, 2, 2, 1); + ++v25; + } + while ( (signed int)v25 < (signed int)&AP2x2Tbl[10] ); + iif = 21; + do + { + if ( v4 ) + break; + v4 = AutoPlace(v2, iif, 2, 2, 1); + iif += 2; + } + while ( iif < 29 ); + iig = 1; + do + { + if ( v4 ) + break; + v4 = AutoPlace(v2, iig, 2, 2, 1); + iig += 2; + } + while ( iig < 9 ); + iih = 10; + while ( !v4 ) + { + v4 = AutoPlace(v2, iih++, 2, 2, 1); + if ( iih >= 19 ) + goto LABEL_63; + } + goto LABEL_71; + } +LABEL_63: + if ( v26 == 3 ) + { + iii = 0; + do + { + if ( v4 ) + break; + v4 = AutoPlace(v2, iii++, 2, 3, 1); + } + while ( iii < 9 ); + iij = 10; + while ( !v4 ) + { + v4 = AutoPlace(v2, iij++, 2, 3, 1); + if ( iij >= 19 ) + goto LABEL_70; + } + goto LABEL_71; + } + } + } + } +LABEL_70: + if ( v4 ) + { +LABEL_71: + v10 = 0; + dItem[item[v28]._ix][item[v28]._iy] = 0; + while ( v10 < numitems ) + { + v11 = itemactive[v10]; + if ( v11 == i ) + { + DeleteItem(v11, v10); + v10 = 0; + } + else + { + ++v10; + } + } + return; + } + if ( v2 == myplr ) + { + v12 = plr[v3]._pClass; + switch ( v12 ) + { + case UI_WARRIOR: + v13 = random(0, 3) + PS_WARR14; +LABEL_84: + PlaySFX(v13); + break; + case UI_ROGUE: + v13 = random(0, 3) + PS_ROGUE14; + goto LABEL_84; + case UI_SORCERER: + v13 = random(0, 3) + PS_MAGE14; + goto LABEL_84; + } + } + qmemcpy(&plr[v3].HoldItem, &item[v28], sizeof(plr[v3].HoldItem)); + RespawnItem(i, 1); + NetSendCmdPItem(1u, CMD_RESPAWNITEM, item[v28]._ix, item[v28]._iy); + plr[v3].HoldItem._itype = ITYPE_NONE; + } +} +// 48E9A8: using guessed type int AP2x2Tbl[10]; +// 4B84DC: using guessed type int dropGoldFlag; + +int __fastcall FindGetItem(int indx, unsigned short ci, int iseed) +{ + int i; // ebx + int ii; // esi + + i = 0; + if ( numitems <= 0 ) + return -1; + while ( 1 ) + { + ii = itemactive[i]; + if ( item[ii].IDidx == indx && item[ii]._iSeed == iseed && item[ii]._iCreateInfo == ci ) + break; + if ( ++i >= numitems ) + return -1; + } + return ii; +} + +void __fastcall SyncGetItem(int x, int y, int idx, unsigned short ci, int iseed) +{ + char v5; // cl + int v6; // esi + int v7; // eax + int v8; // edx + int v9; // ecx + //int v10; // ecx + + v5 = dItem[x][y]; + if ( v5 + && (v6 = v5 - 1, v7 = v6, item[v7].IDidx == idx) + && item[v7]._iSeed == iseed + && item[v7]._iCreateInfo == ci ) + { + FindGetItem(idx, ci, iseed); + } + else + { + v6 = FindGetItem(idx, ci, iseed); + } + if ( v6 != -1 ) + { + v8 = 0; + dItem[item[v6]._ix][item[v6]._iy] = 0; + while ( v8 < numitems ) + { + v9 = itemactive[v8]; + if ( v9 == v6 ) + { + DeleteItem(v9, v8); + FindGetItem(idx, ci, iseed); + FindGetItem(idx, ci, iseed); /* check idx */ + v8 = 0; + } + else + { + ++v8; + } + } + FindGetItem(idx, ci, iseed); + } +} + +int __fastcall CanPut(int i, int j) +{ + int v2; // ecx + int v3; // esi + char v4; // al + int v5; // eax + char v6; // al + bool v7; // sf + char v8; // al + char v9; // cl + + v2 = i; + if ( dItem[v2][j] ) + return 0; + v3 = v2 * 112 + j; + if ( nSolidTable[dPiece[0][v3]] ) + return 0; + v4 = dObject[v2][j]; + if ( v4 ) + { + v5 = v4 <= 0 ? -1 - v4 : v4 - 1; + if ( object[v5]._oSolidFlag ) + return 0; + } + v6 = dObject[v2 + 1][j + 1]; + v7 = v6 < 0; + if ( v6 > 0 ) + { + if ( object[v6 - 1]._oSelFlag ) /* check */ + return 0; + v7 = v6 < 0; + } + if ( v7 && object[-(v6 + 1)]._oSelFlag ) + return 0; + v8 = dObject[v2 + 1][j]; + if ( v8 > 0 ) + { + v9 = dObject[v2][j + 1]; + if ( v9 > 0 && object[v8 - 1]._oSelFlag && object[v9 - 1]._oSelFlag ) + return 0; + } + if ( !currlevel && (dMonster[0][v3] || dMonster[1][v3 + 1]) ) + return 0; + return 1; +} + +int __cdecl TryInvPut() +{ + int result; // eax + int v1; // eax + char v2; // si + int v3; // edi + int v4; // ebx + int v5; // esi + + if ( numitems >= 127 ) + return 0; + v1 = GetDirection(plr[myplr].WorldX, plr[myplr].WorldY, cursmx, cursmy); + v2 = v1; + v3 = plr[myplr].WorldY; + v4 = plr[myplr].WorldX; + if ( CanPut(v4 + offset_x[v1], v3 + offset_y[v1]) + || (v5 = (v2 - 1) & 7, CanPut(v4 + offset_x[v5], v3 + offset_y[v5])) + || CanPut(v4 + offset_x[((_BYTE)v5 + 2) & 7], v3 + offset_y[((_BYTE)v5 + 2) & 7]) ) + { + result = 1; + } + else + { + result = CanPut(v4, v3); + } + return result; +} + +void __fastcall DrawInvMsg(char *msg) +{ + char *v1; // esi + int v2; // eax + + v1 = msg; + v2 = GetTickCount(); + if ( (unsigned int)(v2 - sgdwLastTime) >= 5000 ) + { + sgdwLastTime = v2; + ErrorPlrMsg(v1); + } +} + +int __fastcall InvPutItem(int pnum, int x, int y) +{ + int v3; // edi + int *v4; // esi + int v5; // ebx + int v6; // esi + int v7; // eax + int v8; // edi + int v9; // esi + int v10; // esi + int v11; // eax + int v12; // edx + int v13; // esi + int v15; // eax + int *v16; // edx + int v17; // edx + ItemStruct *v18; // [esp+Ch] [ebp-1Ch] + int v19; // [esp+10h] [ebp-18h] + signed int v20; // [esp+14h] [ebp-14h] + int v21; // [esp+18h] [ebp-10h] + int v22; // [esp+1Ch] [ebp-Ch] + signed int v23; // [esp+20h] [ebp-8h] + int xa; // [esp+24h] [ebp-4h] + int ya; // [esp+30h] [ebp+8h] + int yb; // [esp+30h] [ebp+8h] + int yc; // [esp+30h] [ebp+8h] + + xa = x; + if ( numitems >= 127 ) + return -1; + v3 = pnum; + _LOWORD(x) = plr[pnum].HoldItem._iCreateInfo; + v4 = &plr[pnum].HoldItem._iSeed; + v18 = &plr[pnum].HoldItem; + v5 = y; + if ( FindGetItem(plr[pnum].HoldItem.IDidx, x, plr[pnum].HoldItem._iSeed) != -1 ) + { + DrawInvMsg("A duplicate item has been detected. Destroying duplicate..."); + SyncGetItem(xa, y, plr[v3].HoldItem.IDidx, plr[v3].HoldItem._iCreateInfo, *v4); + } + ya = GetDirection(plr[v3].WorldX, plr[v3].WorldY, xa, y); + v6 = v5 - plr[v3].WorldY; + if ( abs(xa - plr[v3].WorldX) > 1 || abs(v6) > 1 ) + { + v5 = plr[v3].WorldY + offset_y[ya]; + xa = plr[v3].WorldX + offset_x[ya]; + } + if ( !CanPut(xa, v5) ) + { + v7 = plr[v3].WorldX; + v8 = plr[v3].WorldY; + v9 = ((_BYTE)ya - 1) & 7; + v19 = v7; + v5 = v8 + offset_y[v9]; + xa = v7 + offset_x[v9]; + if ( !CanPut(xa, v8 + offset_y[v9]) ) + { + v10 = ((_BYTE)v9 + 2) & 7; + v5 = v8 + offset_y[v10]; + xa = v19 + offset_x[v10]; + if ( !CanPut(xa, v8 + offset_y[v10]) ) + { + v23 = 0; + v11 = -1; + yb = 1; + v20 = -1; + while ( !v23 ) + { + v22 = v11; + while ( v11 <= yb && !v23 ) + { + v21 = v20; + v12 = v8 + v22; + v13 = v19 + v20; + do + { + if ( v23 ) + break; + if ( CanPut(v13, v12) ) + { + v23 = 1; + xa = v13; + v5 = v12; + } + ++v21; + ++v13; + } + while ( v21 <= yb ); + v11 = ++v22; + } + ++yb; + v11 = v20-- - 1; + if ( v20 <= -50 ) + { + if ( v23 ) + break; + return -1; + } + } + } + } + } + CanPut(xa, v5); + v15 = itemavail[0]; + dItem[xa][v5] = _LOBYTE(itemavail[0]) + 1; + yc = v15; + v16 = &itemavail[-numitems + 126]; + itemactive[numitems] = v15; + itemavail[0] = *v16; + v17 = v15; + qmemcpy(&item[v15], v18, sizeof(ItemStruct)); + item[v17]._iy = v5; + item[v17]._ix = xa; + RespawnItem(v15, 1); + ++numitems; + SetCursor(CURSOR_HAND); + return yc; +} + +int __fastcall SyncPutItem(int pnum, int x, int y, int idx, int icreateinfo, int iseed, int Id, int dur, int mdur, int ch, int mch, int ivalue, unsigned int ibuff) +{ + int v13; // ebx + int v14; // edi + int v15; // esi + int v17; // edi + int v18; // ecx + int v19; // edi + int v20; // eax + int v21; // eax + int v22; // eax + int v23; // edx + int v25; // ecx + int *v26; // edx + int v27; // eax + int v28; // eax + int v29; // [esp+Ch] [ebp-18h] + int v30; // [esp+Ch] [ebp-18h] + signed int v31; // [esp+10h] [ebp-14h] + int v32; // [esp+14h] [ebp-10h] + int v33; // [esp+18h] [ebp-Ch] + int o1; // [esp+1Ch] [ebp-8h] + signed int v35; // [esp+20h] [ebp-4h] + int i; // [esp+2Ch] [ebp+8h] + int ia; // [esp+2Ch] [ebp+8h] + int ib; // [esp+2Ch] [ebp+8h] + int ic; // [esp+2Ch] [ebp+8h] + + v13 = x; + v14 = pnum; + if ( numitems >= 127 ) + return -1; + v15 = y; + if ( FindGetItem(idx, icreateinfo, iseed) != -1 ) + { + DrawInvMsg("A duplicate item has been detected from another player."); + SyncGetItem(v13, y, idx, icreateinfo, iseed); + } + v17 = v14; + i = GetDirection(plr[v17].WorldX, plr[v17].WorldY, v13, y); + v29 = v15 - plr[v17].WorldY; + if ( abs(v13 - plr[v17].WorldX) > 1 || abs(v29) > 1 ) + { + v13 = plr[v17].WorldX + offset_x[i]; + v15 = plr[v17].WorldY + offset_y[i]; + } + if ( !CanPut(v13, v15) ) + { + v18 = plr[v17].WorldX; + v19 = plr[v17].WorldY; + v20 = ((_BYTE)i - 1) & 7; + v30 = v18; + ia = v20; + v20 *= 4; + v13 = v18 + *(int *)((char *)offset_x + v20); + v15 = v19 + *(int *)((char *)offset_y + v20); + if ( !CanPut(v18 + *(int *)((char *)offset_x + v20), v19 + *(int *)((char *)offset_y + v20)) ) + { + v21 = ((_BYTE)ia + 2) & 7; + v13 = v30 + offset_x[v21]; + v15 = v19 + offset_y[v21]; + if ( !CanPut(v30 + offset_x[v21], v19 + offset_y[v21]) ) + { + v35 = 0; + v22 = -1; + ib = 1; + v31 = -1; + while ( !v35 ) + { + v33 = v22; + while ( v22 <= ib && !v35 ) + { + v23 = v19 + v33; + v32 = v31; + o1 = v30 + v31; + do + { + if ( v35 ) + break; + if ( CanPut(o1, v23) ) + { + v13 = o1; + v35 = 1; + v15 = v23; + } + ++v32; + ++o1; + } + while ( v32 <= ib ); + v22 = ++v33; + } + ++ib; + v22 = v31-- - 1; + if ( v31 <= -50 ) + { + if ( v35 ) + break; + return -1; + } + } + } + } + } + CanPut(v13, v15); + v25 = itemavail[0]; + ic = itemavail[0]; + dItem[v13][v15] = _LOBYTE(itemavail[0]) + 1; + v26 = &itemavail[-numitems + 126]; + itemactive[numitems] = v25; + itemavail[0] = *v26; + if ( idx == IDI_EAR ) + { + RecreateEar(v25, icreateinfo, iseed, Id, dur, mdur, ch, mch, ivalue, ibuff); + } + else + { + RecreateItem(v25, idx, icreateinfo, iseed, ivalue); + if ( Id ) + item[ic]._iIdentified = 1; + v27 = ic; + item[v27]._iDurability = dur; + item[v27]._iMaxDur = mdur; + item[v27]._iCharges = ch; + item[v27]._iMaxCharges = mch; + } + v28 = ic; + item[v28]._ix = v13; + item[v28]._iy = v15; + RespawnItem(ic, 1); + ++numitems; + return ic; +} + +int __cdecl CheckInvHLight() +{ + signed int v0; // ebx + int result; // eax + ItemStruct *v2; // edi + PlayerStruct *v3; // esi + int v4; // eax + int v5; // ebx + int v6; // edi + char *v7; // eax + char v8; // al + char v9; // [esp+Fh] [ebp-1h] + + v0 = 0; + do + { + result = InvRect[v0].X; + if ( MouseX >= result ) + { + result += 29; + if ( MouseX < result ) + { + result = InvRect[v0].Y; + if ( MouseY >= result - 29 && MouseY < result ) + break; + } + } + ++v0; + } + while ( (unsigned int)v0 < 0x49 ); + if ( (unsigned int)v0 >= 0x49 ) + goto LABEL_37; + v9 = -1; + _LOBYTE(infoclr) = 0; + v2 = 0; + v3 = &plr[myplr]; + ClearPanel(); + if ( v0 >= 0 && v0 <= 3 ) + { + v9 = 0; + v2 = v3->InvBody; + goto LABEL_36; + } + switch ( v0 ) + { + case 4: + v9 = 1; + v2 = &v3->InvBody[1]; + goto LABEL_36; + case 5: + v9 = 2; + v2 = &v3->InvBody[2]; + goto LABEL_36; + case 6: + v9 = 3; + v2 = &v3->InvBody[3]; + goto LABEL_36; + } + if ( v0 >= 7 && v0 <= 12 ) + { + v9 = 4; + v2 = &v3->InvBody[4]; + goto LABEL_36; + } + if ( v0 < 13 || v0 > 18 ) + { + if ( v0 >= 19 && v0 <= 24 ) + { + v9 = 6; + v2 = &v3->InvBody[6]; + goto LABEL_36; + } + if ( v0 < 25 || v0 > 64 ) + { + if ( v0 < 65 ) + goto LABEL_36; + v5 = v0 - 65; + drawsbarflag = 1; + result = 368 * v5; + v2 = &v3->SpdList[v5]; + if ( v3->SpdList[v5]._itype != -1 ) + { + v9 = v5 + 47; + goto LABEL_36; + } + } + else + { + result = abs(v3->InvGrid[v0 - 25]); // abs(*((char *)&v3->InvList[39]._iVAdd2 + v0 + 3)); /* find right address */ + if ( result ) + { + v4 = result - 1; + v9 = v4 + 7; + v2 = &v3->InvList[v4]; + goto LABEL_36; + } + } +LABEL_37: + _LOBYTE(result) = -1; + return result; + } + v2 = &v3->InvBody[4]; + if ( v3->InvBody[4]._itype == -1 || v3->InvBody[4]._iLoc != 2 ) + { + v9 = 5; + v2 = &v3->InvBody[5]; + } + else + { + v9 = 4; + } +LABEL_36: + result = v2->_itype; + if ( result == ITYPE_NONE ) + goto LABEL_37; + if ( result == ITYPE_GOLD ) + { + v6 = v2->_ivalue; + v7 = get_pieces_str(v6); + result = sprintf(infostr, "%i gold %s", v6, v7); + } + else + { + v8 = v2->_iMagical; + if ( v8 == 1 ) + { + _LOBYTE(infoclr) = 1; + } + else if ( v8 == 2 ) + { + _LOBYTE(infoclr) = 3; + } + strcpy(infostr, v2->_iName); + if ( v2->_iIdentified ) + { + strcpy(infostr, v2->_iIName); + PrintItemDetails(v2); + } + else + { + PrintItemDur(v2); + } + } + _LOBYTE(result) = v9; + return result; +} +// 4B883C: using guessed type int infoclr; + +void __fastcall RemoveScroll(int pnum) +{ + int v1; // eax + int v2; // esi + int v3; // edx + int *v4; // ecx + int v5; // edx + int *v6; // ecx + int p; // [esp+Ch] [ebp-4h] + + p = pnum; + v1 = pnum; + v2 = plr[pnum]._pNumInv; + v3 = 0; + if ( v2 <= 0 ) + { +LABEL_8: + v5 = 0; + v6 = &plr[v1].SpdList[0]._iMiscId; + while ( *(v6 - 53) == -1 || *v6 != IMISC_SCROLL && *v6 != IMISC_SCROLLT || v6[1] != plr[v1]._pSpell ) + { + ++v5; + v6 += 92; + if ( v5 >= 8 ) + return; + } + RemoveSpdBarItem(p, v5); + } + else + { + v4 = &plr[v1].InvList[0]._iMiscId; + while ( *(v4 - 53) == -1 || *v4 != IMISC_SCROLL && *v4 != IMISC_SCROLLT || v4[1] != plr[v1]._pSpell ) + { + ++v3; + v4 += 92; + if ( v3 >= v2 ) + goto LABEL_8; + } + RemoveInvItem(p, v3); + } + CalcPlrScrolls(p); +} + +bool __cdecl UseScroll() +{ + int v0; // eax + int v1; // esi + int v2; // ecx + int *v3; // edx + signed int v4; // esi + int *v5; // ecx + + if ( pcurs != CURSOR_HAND || leveltype == DTYPE_TOWN && !*(_DWORD *)&spelldata[plr[myplr]._pRSpell].sTownSpell ) + return 0; + v0 = myplr; + v1 = 0; + v2 = plr[myplr]._pNumInv; + if ( v2 <= 0 ) + { +LABEL_11: + v4 = 0; + v5 = &plr[v0].SpdList[0]._iMiscId; + while ( *(v5 - 53) == -1 || *v5 != IMISC_SCROLL && *v5 != IMISC_SCROLLT || v5[1] != plr[v0]._pRSpell ) + { + ++v4; + v5 += 92; + if ( v4 >= 8 ) + return 0; + } + } + else + { + v3 = &plr[v0].InvList[0]._iMiscId; + while ( *(v3 - 53) == -1 || *v3 != IMISC_SCROLL && *v3 != IMISC_SCROLLT || v3[1] != plr[v0]._pRSpell ) + { + ++v1; + v3 += 92; + if ( v1 >= v2 ) + goto LABEL_11; + } + } + return 1; +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall UseStaffCharge(int pnum) +{ + int v1; // eax + int *v2; // eax + + v1 = pnum; + if ( plr[pnum].InvBody[4]._itype != ITYPE_NONE + && plr[v1].InvBody[4]._iMiscId == IMISC_STAFF + && plr[v1].InvBody[4]._iSpell == plr[v1]._pRSpell ) + { + v2 = &plr[v1].InvBody[4]._iCharges; + if ( *v2 > 0 ) + { + --*v2; + CalcPlrStaff(pnum); + } + } +} + +bool __cdecl UseStaff() +{ + int v0; // eax + bool result; // al + + result = 0; + if ( pcurs == CURSOR_HAND ) + { + v0 = myplr; + if ( plr[myplr].InvBody[4]._itype != ITYPE_NONE + && plr[v0].InvBody[4]._iMiscId == IMISC_STAFF + && plr[v0].InvBody[4]._iSpell == plr[v0]._pRSpell + && plr[v0].InvBody[4]._iCharges > 0 ) + { + result = 1; + } + } + return result; +} + +void __cdecl StartGoldDrop() +{ + int v0; // eax + + initialDropGoldIndex = pcursinvitem; + if ( pcursinvitem > 46 ) + v0 = plr[myplr].InvBody[pcursinvitem]._iMaxDur; + else + v0 = plr[myplr].InvBody[pcursinvitem]._ivalue; + dropGoldValue = 0; + initialDropGoldValue = v0; + dropGoldFlag = 1; + if ( talkflag ) + control_reset_talk(); +} +// 4B84DC: using guessed type int dropGoldFlag; +// 4B8960: using guessed type int talkflag; +// 4B8CB8: using guessed type char pcursinvitem; + +int __fastcall UseInvItem(int pnum, int cii) +{ + int v2; // esi + int result; // eax + int v4; // ebx + int v5; // ebp + _DWORD *v6; // edi + char v7; // al + int v8; // ecx + int v9; // eax + int v10; // ecx + char v11; // al + char v12; // al + int p; // [esp+10h] [ebp-8h] + signed int v14; // [esp+14h] [ebp-4h] + + v2 = pnum; + p = pnum; + if ( plr[pnum]._pInvincible && !plr[v2]._pHitPoints && pnum == myplr ) + return 1; + result = 1; + if ( pcurs == 1 && !stextflag ) + { + if ( cii <= 5 ) + return 0; + if ( cii > 46 ) + { + if ( talkflag ) + return result; + v4 = cii - 47; + v14 = 1; + v5 = 368 * (cii - 47) + v2 * 21720; + v6 = (_DWORD *)((char *)plr[0].SpdList + v5); + } + else + { + v4 = cii - 7; + v14 = 0; + v5 = 368 * (cii - 7) + v2 * 21720; + v6 = (_DWORD *)((char *)plr[0].InvList + v5); + } + if ( v6[90] == 17 ) + { + v12 = plr[v2]._pClass; + sfxdelay = 10; + if ( v12 ) + { + if ( v12 == 1 ) + { + sfxdnum = PS_ROGUE95; + } + else if ( v12 == 2 ) + { + sfxdnum = PS_MAGE95; + } + } + else + { + sfxdnum = PS_WARR95; + } + return 1; + } + if ( v6[90] == 19 ) + { + PlaySFX(IS_IBOOK); + v11 = plr[v2]._pClass; + sfxdelay = 10; + if ( v11 ) + { + if ( v11 == 1 ) + { + sfxdnum = PS_ROGUE29; + } + else if ( v11 == 2 ) + { + sfxdnum = PS_MAGE29; + } + } + else + { + sfxdnum = PS_WARR29; + } + return 1; + } + if ( !AllItemsList[v6[90]].iUsable ) + return 0; + if ( !v6[89] ) + { + v7 = plr[v2]._pClass; + if ( v7 ) + { + if ( v7 == 1 ) + { + v8 = PS_ROGUE13; + } + else + { + if ( v7 != 2 ) + return 1; + v8 = PS_MAGE13; + } + } + else + { + v8 = PS_WARR13; + } + PlaySFX(v8); + return 1; + } + v9 = v6[55]; + if ( !v9 && v6[2] == 11 ) + { + StartGoldDrop(); + return 1; + } + if ( dropGoldFlag ) + { + dropGoldFlag = 0; + dropGoldValue = 0; + } + if ( v9 == 21 && !currlevel && !*(_DWORD *)&spelldata[v6[56]].sTownSpell + || v9 == 22 && !currlevel && !*(_DWORD *)&spelldata[v6[56]].sTownSpell ) + { + return 1; + } + if ( v9 == 24 ) + { + v10 = 65; + } + else + { + if ( pnum != myplr ) + goto LABEL_39; + v10 = ItemInvSnds[ItemCAnimTbl[v6[48]]]; + } + PlaySFX(v10); +LABEL_39: + UseItem(p, v6[55], v6[56]); + if ( v14 ) + { + RemoveSpdBarItem(p, v4); + } + else if ( *(int *)((char *)&plr[0].InvList[0]._iMiscId + v5) != IMISC_MAPOFDOOM ) + { + RemoveInvItem(p, v4); + } + return 1; + } + return result; +} +// 4B84DC: using guessed type int dropGoldFlag; +// 4B8960: using guessed type int talkflag; +// 52A554: using guessed type int sfxdelay; +// 6AA705: using guessed type char stextflag; + +void __cdecl DoTelekinesis() +{ + if ( pcursobj != -1 ) + NetSendCmdParam1(1u, CMD_OPOBJT, pcursobj); + if ( pcursitem != -1 ) + NetSendCmdGItem(1u, CMD_REQUESTAGITEM, myplr, myplr, pcursitem); + if ( pcursmonst != -1 && !M_Talker(pcursmonst) && !monster[pcursmonst].mtalkmsg ) + NetSendCmdParam1(1u, CMD_KNOCKBACK, pcursmonst); + SetCursor(CURSOR_HAND); +} +// 4B8CC0: using guessed type char pcursitem; +// 4B8CC1: using guessed type char pcursobj; + +int __fastcall CalculateGold(int pnum) +{ + int result; // eax + int v2; // ecx + int *v3; // edx + signed int v4; // esi + int v5; // edx + int *v6; // ecx + + result = 0; + v2 = pnum; + v3 = &plr[v2].SpdList[0]._ivalue; + v4 = 8; + do + { + if ( *(v3 - 47) == 11 ) + { + result += *v3; + drawpanflag = 255; + } + v3 += 92; + --v4; + } + while ( v4 ); + v5 = plr[v2]._pNumInv; + if ( v5 > 0 ) + { + v6 = &plr[v2].InvList[0]._ivalue; + do + { + if ( *(v6 - 47) == 11 ) + result += *v6; + v6 += 92; + --v5; + } + while ( v5 ); + } + return result; +} +// 52571C: using guessed type int drawpanflag; + +int __cdecl DropItemBeforeTrig() +{ + if ( !TryInvPut() ) + return 0; + NetSendCmdPItem(1u, CMD_PUTITEM, cursmx, cursmy); + SetCursor(CURSOR_HAND); + return 1; +} diff --git a/Source/inv.h b/Source/inv.h new file mode 100644 index 000000000..3a67572b3 --- /dev/null +++ b/Source/inv.h @@ -0,0 +1,59 @@ +//HEADER_GOES_HERE +#ifndef __INV_H__ +#define __INV_H__ + +extern int invflag; +extern void *pInvCels; +extern int drawsbarflag; // idb +extern int sgdwLastTime; // check name + +void __cdecl FreeInvGFX(); +void __cdecl InitInv(); +void __fastcall InvDrawSlotBack(int X, int Y, int W, int H); +void __cdecl DrawInv(); +void __cdecl DrawInvBelt(); +int __fastcall AutoPlace(int pnum, int ii, int sx, int sy, int saveflag); +int __fastcall SpecialAutoPlace(int pnum, int ii, int sx, int sy, int saveflag); +int __fastcall GoldAutoPlace(int pnum); +int __fastcall WeaponAutoPlace(int pnum); +int __fastcall SwapItem(ItemStruct *a, ItemStruct *b); +void __fastcall CheckInvPaste(int pnum, int mx, int my); +void __fastcall CheckInvSwap(int pnum, BYTE bLoc, int idx, WORD wCI, int seed, BOOL bId); +void __fastcall CheckInvCut(int pnum, int mx, int my); +void __fastcall inv_update_rem_item(int pnum, BYTE iv); +void __fastcall RemoveInvItem(int pnum, int iv); +void __fastcall RemoveSpdBarItem(int pnum, int iv); +void __cdecl CheckInvItem(); +void __cdecl CheckInvScrn(); +void __fastcall CheckItemStats(int pnum); +void __fastcall CheckBookLevel(int pnum); +void __fastcall CheckQuestItem(int pnum); +void __fastcall InvGetItem(int pnum, int ii); +void __fastcall AutoGetItem(int pnum, int ii); +int __fastcall FindGetItem(int indx, unsigned short ci, int iseed); +void __fastcall SyncGetItem(int x, int y, int idx, unsigned short ci, int iseed); +int __fastcall CanPut(int i, int j); +int __cdecl TryInvPut(); +void __fastcall DrawInvMsg(char *msg); +int __fastcall InvPutItem(int pnum, int x, int y); +int __fastcall SyncPutItem(int pnum, int x, int y, int idx, int icreateinfo, int iseed, int Id, int dur, int mdur, int ch, int mch, int ivalue, unsigned int ibuff); +int __cdecl CheckInvHLight(); +void __fastcall RemoveScroll(int pnum); +bool __cdecl UseScroll(); +void __fastcall UseStaffCharge(int pnum); +bool __cdecl UseStaff(); +void __cdecl StartGoldDrop(); +int __fastcall UseInvItem(int pnum, int cii); +void __cdecl DoTelekinesis(); +int __fastcall CalculateGold(int pnum); +int __cdecl DropItemBeforeTrig(); + +/* rdata */ + +extern const InvXY InvRect[73]; + +/* data */ + +extern int AP2x2Tbl[10]; // weak + +#endif /* __INV_H__ */ diff --git a/Source/items.cpp b/Source/items.cpp new file mode 100644 index 000000000..e30ce08fc --- /dev/null +++ b/Source/items.cpp @@ -0,0 +1,5692 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int itemactive[MAXITEMS]; +int uitemflag; +int itemavail[MAXITEMS]; +ItemStruct curruitem; +ItemGetRecordStruct itemrecord[MAXITEMS]; +ItemStruct item[MAXITEMS+1]; +BOOL itemhold[3][3]; +unsigned char *Item2Frm[35]; +int UniqueItemFlag[128]; +int numitems; +int gnNumGetRecords; +#endif + +const PLStruct PL_Prefix[84] = +{ + { "Tin", IPL_TOHIT_CURSE, 6, 10, 3, PLT_WEAP|PLT_BOW|PLT_MISC, 0, 1, 0, 0, 0, -3 }, + { "Brass", IPL_TOHIT_CURSE, 1, 5, 1, PLT_WEAP|PLT_BOW|PLT_MISC, 0, 1, 0, 0, 0, -2 }, + { "Bronze", IPL_TOHIT, 1, 5, 1, PLT_WEAP|PLT_BOW|PLT_MISC, 0, 1, 1, 100, 500, 2 }, + { "Iron", IPL_TOHIT, 6, 10, 4, PLT_WEAP|PLT_BOW|PLT_MISC, 0, 1, 1, 600, 1000, 3 }, + { "Steel", IPL_TOHIT, 11, 15, 6, PLT_WEAP|PLT_BOW|PLT_MISC, 0, 1, 1, 1100, 1500, 5 }, + { "Silver", IPL_TOHIT, 16, 20, 9, PLT_WEAP|PLT_BOW|PLT_MISC, 16, 1, 1, 1600, 2000, 7 }, + { "Gold", IPL_TOHIT, 21, 30, 12, PLT_WEAP|PLT_BOW|PLT_MISC, 16, 1, 1, 2100, 3000, 9 }, + { "Platinum", IPL_TOHIT, 31, 40, 16, PLT_WEAP|PLT_BOW, 16, 1, 1, 3100, 4000, 11 }, + { "Mithril", IPL_TOHIT, 41, 60, 20, PLT_WEAP|PLT_BOW, 16, 1, 1, 4100, 6000, 13 }, + { "Meteoric", IPL_TOHIT, 61, 80, 23, PLT_WEAP|PLT_BOW, 0, 1, 1, 6100, 10000, 15 }, + { "Weird", IPL_TOHIT, 81, 100, 35, PLT_WEAP|PLT_BOW, 0, 1, 1, 10100, 14000, 17 }, + { "Strange", IPL_TOHIT, 101, 150, 60, PLT_WEAP|PLT_BOW, 0, 1, 1, 14100, 20000, 20 }, + { "Useless", IPL_DAMP_CURSE, 100, 100, 5, PLT_WEAP|PLT_BOW, 0, 1, 0, 0, 0, -8 }, + { "Bent", IPL_DAMP_CURSE, 50, 75, 3, PLT_WEAP|PLT_BOW, 0, 1, 0, 0, 0, -4 }, + { "Weak", IPL_DAMP_CURSE, 25, 45, 1, PLT_WEAP|PLT_BOW, 0, 1, 0, 0, 0, -3 }, + { "Jagged", IPL_DAMP, 20, 35, 4, PLT_WEAP|PLT_BOW, 0, 1, 1, 250, 450, 3 }, + { "Deadly", IPL_DAMP, 36, 50, 6, PLT_WEAP|PLT_BOW, 0, 1, 1, 500, 700, 4 }, + { "Heavy", IPL_DAMP, 51, 65, 9, PLT_WEAP|PLT_BOW, 0, 1, 1, 750, 950, 5 }, + { "Vicious", IPL_DAMP, 66, 80, 12, PLT_WEAP|PLT_BOW, 1, 1, 1, 1000, 1450, 8 }, + { "Brutal", IPL_DAMP, 81, 95, 16, PLT_WEAP|PLT_BOW, 0, 1, 1, 1500, 1950, 10 }, + { "Massive", IPL_DAMP, 96, 110, 20, PLT_WEAP|PLT_BOW, 0, 1, 1, 2000, 2450, 13 }, + { "Savage", IPL_DAMP, 111, 125, 23, PLT_WEAP|PLT_BOW, 0, 1, 1, 2500, 3000, 15 }, + { "Ruthless", IPL_DAMP, 126, 150, 35, PLT_WEAP|PLT_BOW, 0, 1, 1, 10100, 15000, 17 }, + { "Merciless", IPL_DAMP, 151, 175, 60, PLT_WEAP|PLT_BOW, 0, 1, 1, 15000, 20000, 20 }, + { "Clumsy", IPL_TOHIT_DAMP_CURSE, 50, 75, 5, PLT_WEAP|PLT_STAFF|PLT_BOW, 0, 1, 0, 0, 0, -7 }, + { "Dull", IPL_TOHIT_DAMP_CURSE, 25, 45, 1, PLT_WEAP|PLT_STAFF|PLT_BOW, 0, 1, 0, 0, 0, -5 }, + { "Sharp", IPL_TOHIT_DAMP, 20, 35, 1, PLT_WEAP|PLT_STAFF|PLT_BOW, 0, 1, 0, 350, 950, 5 }, + { "Fine", IPL_TOHIT_DAMP, 36, 50, 6, PLT_WEAP|PLT_STAFF|PLT_BOW, 0, 1, 1, 1100, 1700, 7 }, + { "Warrior's", IPL_TOHIT_DAMP, 51, 65, 10, PLT_WEAP|PLT_STAFF|PLT_BOW, 0, 1, 1, 1850, 2450, 13 }, + { "Soldier's", IPL_TOHIT_DAMP, 66, 80, 15, PLT_WEAP|PLT_STAFF, 0, 1, 1, 2600, 3950, 17 }, + { "Lord's", IPL_TOHIT_DAMP, 81, 95, 19, PLT_WEAP|PLT_STAFF, 0, 1, 1, 4100, 5950, 21 }, + { "Knight's", IPL_TOHIT_DAMP, 96, 110, 23, PLT_WEAP|PLT_STAFF, 0, 1, 1, 6100, 8450, 26 }, + { "Master's", IPL_TOHIT_DAMP, 111, 125, 28, PLT_WEAP|PLT_STAFF, 0, 1, 1, 8600, 13000, 30 }, + { "Champion's", IPL_TOHIT_DAMP, 126, 150, 40, PLT_WEAP|PLT_STAFF, 0, 1, 1, 15200, 24000, 33 }, + { "King's", IPL_TOHIT_DAMP, 151, 175, 28, PLT_WEAP|PLT_STAFF, 0, 1, 1, 24100, 35000, 38 }, + { "Vulnerable", IPL_ACP_CURSE, 51, 100, 3, PLT_ARMO|PLT_SHLD, 0, 1, 0, 0, 0, -3 }, + { "Rusted", IPL_ACP_CURSE, 25, 50, 1, PLT_ARMO|PLT_SHLD, 0, 1, 0, 0, 0, -2 }, + { "Fine", IPL_ACP, 20, 30, 1, PLT_ARMO|PLT_SHLD, 0, 1, 1, 20, 100, 2 }, + { "Strong", IPL_ACP, 31, 40, 3, PLT_ARMO|PLT_SHLD, 0, 1, 1, 120, 200, 3 }, + { "Grand", IPL_ACP, 41, 55, 6, PLT_ARMO|PLT_SHLD, 0, 1, 1, 220, 300, 5 }, + { "Valiant", IPL_ACP, 56, 70, 10, PLT_ARMO|PLT_SHLD, 0, 1, 1, 320, 400, 7 }, + { "Glorious", IPL_ACP, 71, 90, 14, PLT_ARMO|PLT_SHLD, 16, 1, 1, 420, 600, 9 }, + { "Blessed", IPL_ACP, 91, 110, 19, PLT_ARMO|PLT_SHLD, 16, 1, 1, 620, 800, 11 }, + { "Saintly", IPL_ACP, 111, 130, 24, PLT_ARMO|PLT_SHLD, 16, 1, 1, 820, 1200, 13 }, + { "Awesome", IPL_ACP, 131, 150, 28, PLT_ARMO|PLT_SHLD, 16, 1, 1, 1220, 2000, 15 }, + { "Holy", IPL_ACP, 151, 170, 35, PLT_ARMO|PLT_SHLD, 16, 1, 1, 5200, 6000, 17 }, + { "Godly", IPL_ACP, 171, 200, 60, PLT_ARMO|PLT_SHLD, 16, 1, 1, 6200, 7000, 20 }, + { "Red", IPL_FIRERES, 10, 20, 4, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 500, 1500, 2 }, + { "Crimson", IPL_FIRERES, 21, 30, 10, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 2100, 3000, 2 }, + { "Crimson", IPL_FIRERES, 31, 40, 16, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 3100, 4000, 2 }, + { "Garnet", IPL_FIRERES, 41, 50, 20, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 8200, 12000, 3 }, + { "Ruby", IPL_FIRERES, 51, 60, 26, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 17100, 20000, 5 }, + { "Blue", IPL_LIGHTRES, 10, 20, 4, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 500, 1500, 2 }, + { "Azure", IPL_LIGHTRES, 21, 30, 10, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 2100, 3000, 2 }, + { "Lapis", IPL_LIGHTRES, 31, 40, 16, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 3100, 4000, 2 }, + { "Cobalt", IPL_LIGHTRES, 41, 50, 20, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 8200, 12000, 3 }, + { "Sapphire", IPL_LIGHTRES, 51, 60, 26, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 17100, 20000, 5 }, + { "White", IPL_MAGICRES, 10, 20, 4, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 500, 1500, 2 }, + { "Pearl", IPL_MAGICRES, 21, 30, 10, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 2100, 3000, 2 }, + { "Ivory", IPL_MAGICRES, 31, 40, 16, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 3100, 4000, 2 }, + { "Crystal", IPL_MAGICRES, 41, 50, 20, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 8200, 12000, 3 }, + { "Diamond", IPL_MAGICRES, 51, 60, 26, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 17100, 20000, 5 }, + { "Topaz", IPL_ALLRES, 10, 15, 8, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 2000, 5000, 3 }, + { "Amber", IPL_ALLRES, 16, 20, 12, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 7400, 10000, 3 }, + { "Jade", IPL_ALLRES, 21, 30, 18, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 11000, 15000, 3 }, + { "Obsidian", IPL_ALLRES, 31, 40, 24, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 24000, 40000, 4 }, + { "Emerald", IPL_ALLRES, 41, 50, 31, PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW, 0, 0, 1, 61000, 75000, 7 }, + { "Hyena's", IPL_MANA_CURSE, 11, 25, 4, PLT_STAFF|PLT_MISC, 0, 0, 0, 100, 1000, -2 }, + { "Frog's", IPL_MANA_CURSE, 1, 10, 1, PLT_STAFF|PLT_MISC, 1, 0, 0, 0, 0, -2 }, + { "Spider's", IPL_MANA, 10, 15, 1, PLT_STAFF|PLT_MISC, 1, 0, 1, 500, 1000, 2 }, + { "Raven's", IPL_MANA, 15, 20, 5, PLT_STAFF|PLT_MISC, 0, 0, 1, 1100, 2000, 3 }, + { "Snake's", IPL_MANA, 21, 30, 9, PLT_STAFF|PLT_MISC, 0, 0, 1, 2100, 4000, 5 }, + { "Serpent's", IPL_MANA, 30, 40, 15, PLT_STAFF|PLT_MISC, 0, 0, 1, 4100, 6000, 7 }, + { "Drake's", IPL_MANA, 41, 50, 21, PLT_STAFF|PLT_MISC, 0, 0, 1, 6100, 10000, 9 }, + { "Dragon's", IPL_MANA, 51, 60, 27, PLT_STAFF|PLT_MISC, 0, 0, 1, 10100, 15000, 11 }, + { "Wyrm's", IPL_MANA, 61, 80, 35, PLT_STAFF, 0, 0, 1, 15100, 19000, 12 }, + { "Hydra's", IPL_MANA, 81, 100, 60, PLT_STAFF, 0, 0, 1, 19100, 30000, 13 }, + { "Angel's", IPL_SPLLVLADD, 1, 1, 15, PLT_STAFF, 16, 0, 1, 25000, 25000, 2 }, + { "Arch-Angel's", IPL_SPLLVLADD, 2, 2, 25, PLT_STAFF, 16, 0, 1, 50000, 50000, 3 }, + { "Plentiful", IPL_CHARGES, 2, 2, 4, PLT_STAFF, 0, 0, 1, 2000, 2000, 2 }, + { "Bountiful", IPL_CHARGES, 3, 3, 9, PLT_STAFF, 0, 0, 1, 3000, 3000, 3 }, + { "Flaming", IPL_FIREDAM, 1, 10, 7, PLT_WEAP|PLT_STAFF, 0, 0, 1, 5000, 5000, 2 }, + { "Lightning", IPL_LIGHTDAM, 2, 20, 18, PLT_WEAP|PLT_STAFF, 0, 0, 1, 10000, 10000, 2 }, + { &empty_string, IPL_INVALID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; +const PLStruct PL_Suffix[96] = +{ + { "quality", IPL_DAMMOD, 1, 2, 2, PLT_WEAP|PLT_BOW, 0, 0, 1, 100, 200, 2 }, + { "maiming", IPL_DAMMOD, 3, 5, 7, PLT_WEAP|PLT_BOW, 0, 0, 1, 1300, 1500, 3 }, + { "slaying", IPL_DAMMOD, 6, 8, 15, PLT_WEAP, 0, 0, 1, 2600, 3000, 5 }, + { "gore", IPL_DAMMOD, 9, 12, 25, PLT_WEAP, 0, 0, 1, 4100, 5000, 8 }, + { "carnage", IPL_DAMMOD, 13, 16, 35, PLT_WEAP, 0, 0, 1, 5100, 10000, 10 }, + { "slaughter", IPL_DAMMOD, 17, 20, 60, PLT_WEAP, 0, 0, 1, 10100, 15000, 13 }, + { "pain", IPL_GETHIT_CURSE, 2, 4, 4, PLT_ARMO|PLT_SHLD|PLT_MISC, 1, 0, 0, 0, 0, -4 }, + { "tears", IPL_GETHIT_CURSE, 1, 1, 2, PLT_ARMO|PLT_SHLD|PLT_MISC, 1, 0, 0, 0, 0, -2 }, + { "health", IPL_GETHIT, 1, 1, 2, PLT_ARMO|PLT_SHLD|PLT_MISC, 16, 0, 1, 200, 200, 2 }, + { "protection", IPL_GETHIT, 2, 2, 6, PLT_ARMO|PLT_SHLD, 16, 0, 1, 400, 800, 4 }, + { "absorption", IPL_GETHIT, 3, 3, 12, PLT_ARMO|PLT_SHLD, 16, 0, 1, 1001, 2500, 10 }, + { "deflection", IPL_GETHIT, 4, 4, 20, PLT_ARMO, 16, 0, 1, 2500, 6500, 15 }, + { "osmosis", IPL_GETHIT, 5, 6, 50, PLT_ARMO, 16, 0, 1, 7500, 10000, 20 }, + { "frailty", IPL_STR_CURSE, 6, 10, 3, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 1, 0, 0, 0, 0, -3 }, + { "weakness", IPL_STR_CURSE, 1, 5, 1, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 1, 0, 0, 0, 0, -2 }, + { "strength", IPL_STR, 1, 5, 1, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 200, 1000, 2 }, + { "might", IPL_STR, 6, 10, 5, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 1200, 2000, 3 }, + { "power", IPL_STR, 11, 15, 11, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 2200, 3000, 4 }, + { "giants", IPL_STR, 16, 20, 17, PLT_ARMO|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 3200, 5000, 7 }, + { "titans", IPL_STR, 21, 30, 23, PLT_WEAP|PLT_MISC, 0, 0, 1, 5200, 10000, 10 }, + { "paralysis", IPL_DEX_CURSE, 6, 10, 3, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 1, 0, 0, 0, 0, -3 }, + { "atrophy", IPL_DEX_CURSE, 1, 5, 1, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 1, 0, 0, 0, 0, -2 }, + { "dexterity", IPL_DEX, 1, 5, 1, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 200, 1000, 2 }, + { "skill", IPL_DEX, 6, 10, 5, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 1200, 2000, 3 }, + { "accuracy", IPL_DEX, 11, 15, 11, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 2200, 3000, 4 }, + { "precision", IPL_DEX, 16, 20, 17, PLT_ARMO|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 3200, 5000, 7 }, + { "perfection", IPL_DEX, 21, 30, 23, PLT_BOW|PLT_MISC, 0, 0, 1, 5200, 10000, 10 }, + { "the fool", IPL_MAG_CURSE, 6, 10, 3, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 1, 0, 0, 0, 0, -3 }, + { "dyslexia", IPL_MAG_CURSE, 1, 5, 1, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 1, 0, 0, 0, 0, -2 }, + { "magic", IPL_MAG, 1, 5, 1, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 200, 1000, 2 }, + { "the mind", IPL_MAG, 6, 10, 5, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 1200, 2000, 3 }, + { "brilliance", IPL_MAG, 11, 15, 11, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 2200, 3000, 4 }, + { "sorcery", IPL_MAG, 16, 20, 17, PLT_ARMO|PLT_WEAP|PLT_STAFF|PLT_BOW|PLT_MISC, 0, 0, 1, 3200, 5000, 7 }, + { "wizardry", IPL_MAG, 21, 30, 23, PLT_STAFF|PLT_MISC, 0, 0, 1, 5200, 10000, 10 }, + { "illness", IPL_VIT_CURSE, 6, 10, 3, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 1, 0, 0, 0, 0, -3 }, + { "disease", IPL_VIT_CURSE, 1, 5, 1, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 1, 0, 0, 0, 0, -2 }, + { "vitality", IPL_VIT, 1, 5, 1, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 16, 0, 1, 200, 1000, 2 }, + { "zest", IPL_VIT, 6, 10, 5, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 16, 0, 1, 1200, 2000, 3 }, + { "vim", IPL_VIT, 11, 15, 11, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 16, 0, 1, 2200, 3000, 4 }, + { "vigor", IPL_VIT, 16, 20, 17, PLT_ARMO|PLT_WEAP|PLT_BOW|PLT_MISC, 16, 0, 1, 3200, 5000, 7 }, + { "life", IPL_VIT, 21, 30, 23, PLT_MISC, 16, 0, 1, 5200, 10000, 10 }, + { "trouble", IPL_ATTRIBS_CURSE, 6, 10, 12, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 1, 0, 0, 0, 0, -10 }, + { "the pit", IPL_ATTRIBS_CURSE, 1, 5, 5, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 1, 0, 0, 0, 0, -5 }, + { "the sky", IPL_ATTRIBS, 1, 3, 5, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 800, 4000, 5 }, + { "the moon", IPL_ATTRIBS, 4, 7, 11, PLT_ARMO|PLT_SHLD|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 4800, 8000, 10 }, + { "the stars", IPL_ATTRIBS, 8, 11, 17, PLT_ARMO|PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 8800, 12000, 15 }, + { "the heavens", IPL_ATTRIBS, 12, 15, 25, PLT_WEAP|PLT_BOW|PLT_MISC, 0, 0, 1, 12800, 20000, 20 }, + { "the zodiac", IPL_ATTRIBS, 16, 20, 30, PLT_MISC, 0, 0, 1, 20800, 40000, 30 }, + { "the vulture", IPL_LIFE_CURSE, 11, 25, 4, PLT_ARMO|PLT_SHLD|PLT_MISC, 1, 0, 0, 0, 0, -4 }, + { "the jackal", IPL_LIFE_CURSE, 1, 10, 1, PLT_ARMO|PLT_SHLD|PLT_MISC, 1, 0, 0, 0, 0, -2 }, + { "the fox", IPL_LIFE, 10, 15, 1, PLT_ARMO|PLT_SHLD|PLT_MISC, 0, 0, 1, 100, 1000, 2 }, + { "the jaguar", IPL_LIFE, 16, 20, 5, PLT_ARMO|PLT_SHLD|PLT_MISC, 0, 0, 1, 1100, 2000, 3 }, + { "the eagle", IPL_LIFE, 21, 30, 9, PLT_ARMO|PLT_SHLD|PLT_MISC, 0, 0, 1, 2100, 4000, 5 }, + { "the wolf", IPL_LIFE, 30, 40, 15, PLT_ARMO|PLT_SHLD|PLT_MISC, 0, 0, 1, 4100, 6000, 7 }, + { "the tiger", IPL_LIFE, 41, 50, 21, PLT_ARMO|PLT_SHLD|PLT_MISC, 0, 0, 1, 6100, 10000, 9 }, + { "the lion", IPL_LIFE, 51, 60, 27, PLT_ARMO|PLT_MISC, 0, 0, 1, 10100, 15000, 11 }, + { "the mammoth", IPL_LIFE, 61, 80, 35, PLT_ARMO, 0, 0, 1, 15100, 19000, 12 }, + { "the whale", IPL_LIFE, 81, 100, 60, PLT_ARMO, 0, 0, 1, 19100, 30000, 13 }, + { "fragility", IPL_DUR_CURSE, 100, 100, 3, PLT_ARMO|PLT_SHLD|PLT_WEAP, 1, 0, 0, 0, 0, -4 }, + { "brittleness", IPL_DUR_CURSE, 26, 75, 1, PLT_ARMO|PLT_SHLD|PLT_WEAP, 1, 0, 0, 0, 0, -2 }, + { "sturdiness", IPL_DUR, 26, 75, 1, PLT_ARMO|PLT_SHLD|PLT_WEAP, 0, 0, 1, 100, 100, 2 }, + { "craftsmanship", IPL_DUR, 51, 100, 6, PLT_ARMO|PLT_SHLD|PLT_WEAP, 0, 0, 1, 200, 200, 2 }, + { "structure", IPL_DUR, 101, 200, 12, PLT_ARMO|PLT_SHLD|PLT_WEAP, 0, 0, 1, 300, 300, 2 }, + { "the ages", IPL_INDESTRUCTIBLE, 0, 0, 25, PLT_ARMO|PLT_SHLD|PLT_WEAP, 0, 0, 1, 600, 600, 5 }, + { "the dark", IPL_LIGHT_CURSE, 4, 4, 6, PLT_ARMO|PLT_WEAP|PLT_MISC, 1, 0, 0, 0, 0, -3 }, + { "the night", IPL_LIGHT_CURSE, 2, 2, 3, PLT_ARMO|PLT_WEAP|PLT_MISC, 1, 0, 0, 0, 0, -2 }, + { "light", IPL_LIGHT, 2, 2, 4, PLT_ARMO|PLT_WEAP|PLT_MISC, 16, 0, 1, 750, 750, 2 }, + { "radiance", IPL_LIGHT, 4, 4, 8, PLT_ARMO|PLT_WEAP|PLT_MISC, 16, 0, 1, 1500, 1500, 3 }, + { "flame", IPL_FIRE_ARROWS, 1, 3, 1, PLT_BOW, 0, 0, 1, 2000, 2000, 2 }, + { "fire", IPL_FIRE_ARROWS, 1, 6, 11, PLT_BOW, 0, 0, 1, 4000, 4000, 4 }, + { "burning", IPL_FIRE_ARROWS, 1, 16, 35, PLT_BOW, 0, 0, 1, 6000, 6000, 6 }, + { "shock", IPL_LIGHT_ARROWS, 1, 6, 13, PLT_BOW, 0, 0, 1, 6000, 6000, 2 }, + { "lightning", IPL_LIGHT_ARROWS, 1, 10, 21, PLT_BOW, 0, 0, 1, 8000, 8000, 4 }, + { "thunder", IPL_LIGHT_ARROWS, 1, 20, 60, PLT_BOW, 0, 0, 1, 12000, 12000, 6 }, + { "many", IPL_DUR, 100, 100, 3, PLT_BOW, 0, 0, 1, 750, 750, 2 }, + { "plenty", IPL_DUR, 200, 200, 7, PLT_BOW, 0, 0, 1, 1500, 1500, 3 }, + { "thorns", IPL_THORNS, 1, 3, 1, PLT_ARMO|PLT_SHLD, 0, 0, 1, 500, 500, 2 }, + { "corruption", IPL_NOMANA, 0, 0, 5, PLT_ARMO|PLT_SHLD|PLT_WEAP, 1, 0, 0, -1000, -1000, 2 }, + { "thieves", IPL_ABSHALFTRAP, 0, 0, 11, PLT_ARMO|PLT_SHLD|PLT_MISC, 0, 0, 1, 1500, 1500, 2 }, + { "the bear", IPL_KNOCKBACK, 0, 0, 5, PLT_WEAP|PLT_STAFF|PLT_BOW, 1, 0, 1, 750, 750, 2 }, + { "the bat", IPL_STEALMANA, 3, 3, 8, PLT_WEAP, 0, 0, 1, 7500, 7500, 3 }, + { "vampires", IPL_STEALMANA, 5, 5, 19, PLT_WEAP, 0, 0, 1, 15000, 15000, 3 }, + { "the leech", IPL_STEALLIFE, 3, 3, 8, PLT_WEAP, 0, 0, 1, 7500, 7500, 3 }, + { "blood", IPL_STEALLIFE, 5, 5, 19, PLT_WEAP, 0, 0, 1, 15000, 15000, 3 }, + { "piercing", IPL_TARGAC, 2, 6, 1, PLT_WEAP|PLT_BOW, 0, 0, 1, 1000, 1000, 3 }, + { "puncturing", IPL_TARGAC, 4, 12, 9, PLT_WEAP|PLT_BOW, 0, 0, 1, 2000, 2000, 6 }, + { "bashing", IPL_TARGAC, 8, 24, 17, PLT_WEAP, 0, 0, 1, 4000, 4000, 12 }, + { "readiness", IPL_FASTATTACK, 1, 1, 1, PLT_WEAP|PLT_STAFF|PLT_BOW, 0, 0, 1, 2000, 2000, 2 }, + { "swiftness", IPL_FASTATTACK, 2, 2, 10, PLT_WEAP|PLT_STAFF|PLT_BOW, 0, 0, 1, 4000, 4000, 4 }, + { "speed", IPL_FASTATTACK, 3, 3, 19, PLT_WEAP|PLT_STAFF, 0, 0, 1, 8000, 8000, 8 }, + { "haste", IPL_FASTATTACK, 4, 4, 27, PLT_WEAP|PLT_STAFF, 0, 0, 1, 16000, 16000, 16 }, + { "balance", IPL_FASTRECOVER, 1, 1, 1, PLT_ARMO|PLT_MISC, 0, 0, 1, 2000, 2000, 2 }, + { "stability", IPL_FASTRECOVER, 2, 2, 10, PLT_ARMO|PLT_MISC, 0, 0, 1, 4000, 4000, 4 }, + { "harmony", IPL_FASTRECOVER, 3, 3, 20, PLT_ARMO|PLT_MISC, 0, 0, 1, 8000, 8000, 8 }, + { "blocking", IPL_FASTBLOCK, 1, 1, 5, PLT_SHLD, 0, 0, 1, 4000, 4000, 4 }, + { &empty_string, IPL_INVALID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; +const UItemStruct UniqueItemList[91] = +{ + { "The Butcher's Cleaver", UITYPE_CLEAVER, 1u, 3u, 3650, IPL_STR, 10, 10, IPL_SETDAM, 4, 24, IPL_SETDUR, 10, 10, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "The Undead Crown", UITYPE_SKCROWN, 1u, 3u, 16650, IPL_RNDSTEALLIFE, 0, 0, IPL_SETAC, 8, 8, IPL_INVCURS, 77, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Empyrean Band", UITYPE_INFRARING, 1u, 4u, 8000, IPL_ATTRIBS, 2, 2, IPL_LIGHT, 2, 2, IPL_FASTRECOVER, 1, 1, IPL_ABSHALFTRAP, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Optic Amulet", UITYPE_OPTAMULET, 1u, 5u, 9750, IPL_LIGHT, 2, 2, IPL_LIGHTRES, 20, 20, IPL_GETHIT, 1, 1, IPL_MAG, 5, 5, IPL_INVCURS, 44, 0, IPL_TOHIT, 0, 0 }, + { "Ring of Truth", UITYPE_TRING, 1u, 4u, 9100, IPL_LIFE, 10, 10, IPL_GETHIT, 1, 1, IPL_ALLRES, 10, 10, IPL_INVCURS, 10, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Harlequin Crest", UITYPE_HARCREST, 1u, 6u, 4000, IPL_AC_CURSE, 3, 3, IPL_GETHIT, 1, 1, IPL_ATTRIBS, 2, 2, IPL_LIFE, 7, 7, IPL_MANA, 7, 7, IPL_INVCURS, 81, 0 }, + { "Veil of Steel", UITYPE_STEELVEIL, 1u, 6u, 63800, IPL_ALLRES, 50, 50, IPL_LIGHT_CURSE, 2, 2, IPL_ACP, 60, 60, IPL_MANA_CURSE, 30, 30, IPL_STR, 15, 15, IPL_VIT, 15, 15 }, + { "Arkaine's Valor", UITYPE_ARMOFVAL, 1u, 4u, 42000, IPL_SETAC, 25, 25, IPL_VIT, 10, 10, IPL_GETHIT, 3, 3, IPL_FASTRECOVER, 3, 3, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Griswold's Edge", UITYPE_GRISWOLD, 1u, 6u, 42000, IPL_FIREDAM, 1, 10, IPL_TOHIT, 25, 25, IPL_FASTATTACK, 2, 2, IPL_KNOCKBACK, 0, 0, IPL_MANA, 20, 20, IPL_LIFE_CURSE, 20, 20 }, + { "Lightforge", UITYPE_MACE, 1u, 6u, 26675, IPL_LIGHT, 4, 4, IPL_DAMP, 150, 150, IPL_TOHIT, 25, 25, IPL_FIREDAM, 10, 20, IPL_INDESTRUCTIBLE, 0, 0, IPL_ATTRIBS, 8, 8 }, + { "The Rift Bow", UITYPE_SHORTBOW, 1u, 3u, 1800, IPL_RNDARROWVEL, 0, 0, IPL_DAMMOD, 2, 2, IPL_DEX_CURSE, 3, 3, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "The Needler", UITYPE_SHORTBOW, 2u, 4u, 8900, IPL_TOHIT, 50, 50, IPL_SETDAM, 1, 3, IPL_FASTATTACK, 2, 2, IPL_INVCURS, 158, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "The Celestial Bow", UITYPE_LONGBOW, 2u, 4u, 1200, IPL_NOMINSTR, 0, 0, IPL_DAMMOD, 2, 2, IPL_SETAC, 5, 5, IPL_INVCURS, 133, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Deadly Hunter", UITYPE_COMPBOW, 3u, 4u, 8750, IPL_3XDAMVDEM, 10, 10, IPL_TOHIT, 20, 20, IPL_MAG_CURSE, 5, 5, IPL_INVCURS, 108, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Bow of the Dead", UITYPE_COMPBOW, 5u, 6u, 2500, IPL_TOHIT, 10, 10, IPL_DEX, 4, 4, IPL_VIT_CURSE, 3, 3, IPL_LIGHT_CURSE, 2, 2, IPL_SETDUR, 30, 30, IPL_INVCURS, 108, 0 }, + { "The Blackoak Bow", UITYPE_LONGBOW, 5u, 4u, 2500, IPL_DEX, 10, 10, IPL_VIT_CURSE, 10, 10, IPL_DAMP, 50, 50, IPL_LIGHT_CURSE, 1, 1, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Flamedart", UITYPE_HUNTBOW, 10u, 4u, 14250, IPL_FIRE_ARROWS, 0, 0, IPL_FIREDAM, 1, 6, IPL_TOHIT, 20, 20, IPL_FIRERES, 40, 40, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Fleshstinger", UITYPE_LONGBOW, 13u, 4u, 16500, IPL_DEX, 15, 15, IPL_TOHIT, 40, 40, IPL_DAMP, 80, 80, IPL_DUR, 6, 6, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Windforce", UITYPE_WARBOW, 17u, 4u, 37750, IPL_STR, 5, 5, IPL_DAMP, 200, 200, IPL_KNOCKBACK, 0, 0, IPL_INVCURS, 164, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Eaglehorn", UITYPE_BATTLEBOW, 26u, 5u, 42500, IPL_DEX, 20, 20, IPL_TOHIT, 50, 50, IPL_DAMP, 100, 100, IPL_INDESTRUCTIBLE, 0, 0, IPL_INVCURS, 108, 0, IPL_TOHIT, 0, 0 }, + { "Gonnagal's Dirk", UITYPE_DAGGER, 1u, 5u, 7040, IPL_DEX_CURSE, 5, 5, IPL_DAMMOD, 4, 4, IPL_FASTATTACK, 2, 2, IPL_FIRERES, 25, 25, IPL_INVCURS, 54, 0, IPL_TOHIT, 0, 0 }, + { "The Defender", UITYPE_SABRE, 1u, 3u, 2000, IPL_SETAC, 5, 5, IPL_VIT, 5, 5, IPL_TOHIT_CURSE, 5, 5, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Gryphons Claw", UITYPE_FALCHION, 1u, 4u, 1000, IPL_DAMP, 100, 100, IPL_MAG_CURSE, 2, 2, IPL_DEX_CURSE, 5, 5, IPL_INVCURS, 68, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Black Razor", UITYPE_DAGGER, 1u, 4u, 2000, IPL_DAMP, 150, 150, IPL_VIT, 2, 2, IPL_SETDUR, 5, 5, IPL_INVCURS, 53, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Gibbous Moon", UITYPE_BROADSWR, 2u, 4u, 6660, IPL_ATTRIBS, 2, 2, IPL_DAMP, 25, 25, IPL_MANA, 15, 15, IPL_LIGHT_CURSE, 3, 3, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Ice Shank", UITYPE_LONGSWR, 3u, 3u, 5250, IPL_FIRERES, 40, 40, IPL_SETDUR, 15, 15, IPL_STR, 5, 10, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "The Executioner's Blade", UITYPE_FALCHION, 3u, 5u, 7080, IPL_DAMP, 150, 150, IPL_LIFE_CURSE, 10, 10, IPL_LIGHT_CURSE, 1, 1, IPL_DUR, 200, 200, IPL_INVCURS, 58, 0, IPL_TOHIT, 0, 0 }, + { "The Bonesaw", UITYPE_CLAYMORE, 6u, 6u, 4400, IPL_DAMMOD, 10, 10, IPL_STR, 10, 10, IPL_MAG_CURSE, 5, 5, IPL_DEX_CURSE, 5, 5, IPL_LIFE, 10, 10, IPL_MANA_CURSE, 10, 10 }, + { "Shadowhawk", UITYPE_BROADSWR, 8u, 4u, 13750, IPL_LIGHT_CURSE, 2, 2, IPL_STEALLIFE, 5, 5, IPL_TOHIT, 15, 15, IPL_ALLRES, 5, 5, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Wizardspike", UITYPE_DAGGER, 11u, 5u, 12920, IPL_MAG, 15, 15, IPL_MANA, 35, 35, IPL_TOHIT, 25, 25, IPL_ALLRES, 15, 15, IPL_INVCURS, 50, 0, IPL_TOHIT, 0, 0 }, + { "Lightsabre", UITYPE_SABRE, 13u, 4u, 19150, IPL_LIGHT, 2, 2, IPL_LIGHTDAM, 1, 10, IPL_TOHIT, 20, 20, IPL_LIGHTRES, 50, 50, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "The Falcon's Talon", UITYPE_SCIMITAR, 15u, 5u, 7867, IPL_FASTATTACK, 4, 4, IPL_TOHIT, 20, 20, IPL_DAMP_CURSE, 33, 33, IPL_DEX, 10, 10, IPL_INVCURS, 68, 0, IPL_TOHIT, 0, 0 }, + { "Inferno", UITYPE_LONGSWR, 17u, 4u, 34600, IPL_FIREDAM, 2, 12, IPL_LIGHT, 3, 3, IPL_MANA, 20, 20, IPL_FIRERES, 80, 80, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Doombringer", UITYPE_BASTARDSWR, 19u, 5u, 18250, IPL_TOHIT, 25, 25, IPL_DAMP, 250, 250, IPL_ATTRIBS_CURSE, 5, 5, IPL_LIFE_CURSE, 25, 25, IPL_LIGHT_CURSE, 2, 2, IPL_TOHIT, 0, 0 }, + { "The Grizzly", UITYPE_TWOHANDSWR, 23u, 6u, 50000, IPL_STR, 20, 20, IPL_VIT_CURSE, 5, 5, IPL_DAMP, 200, 200, IPL_KNOCKBACK, 0, 0, IPL_DUR, 100, 100, IPL_INVCURS, 160, 0 }, + { "The Grandfather", UITYPE_GREATSWR, 27u, 6u, 119800, IPL_ONEHAND, 0, 0, IPL_ATTRIBS, 5, 5, IPL_TOHIT, 20, 20, IPL_DAMP, 70, 70, IPL_LIFE, 20, 20, IPL_INVCURS, 161, 0 }, + { "The Mangler", UITYPE_LARGEAXE, 2u, 5u, 2850, IPL_DAMP, 200, 200, IPL_DEX_CURSE, 5, 5, IPL_MAG_CURSE, 5, 5, IPL_MANA_CURSE, 10, 10, IPL_INVCURS, 144, 0, IPL_TOHIT, 0, 0 }, + { "Sharp Beak", UITYPE_LARGEAXE, 2u, 4u, 2850, IPL_LIFE, 20, 20, IPL_MAG_CURSE, 10, 10, IPL_MANA_CURSE, 10, 10, IPL_INVCURS, 143, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "BloodSlayer", UITYPE_BROADAXE, 3u, 5u, 2500, IPL_DAMP, 100, 100, IPL_3XDAMVDEM, 50, 50, IPL_ATTRIBS_CURSE, 5, 5, IPL_SPLLVLADD, -1, -1, IPL_INVCURS, 144, 0, IPL_TOHIT, 0, 0 }, + { "The Celestial Axe", UITYPE_BATTLEAXE, 4u, 4u, 14100, IPL_NOMINSTR, 0, 0, IPL_TOHIT, 15, 15, IPL_LIFE, 15, 15, IPL_STR_CURSE, 15, 15, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Wicked Axe", UITYPE_LARGEAXE, 5u, 6u, 31150, IPL_TOHIT, 30, 30, IPL_DEX, 10, 10, IPL_VIT_CURSE, 10, 10, IPL_GETHIT, 1, 6, IPL_INDESTRUCTIBLE, 0, 0, IPL_INVCURS, 143, 0 }, + { "Stonecleaver", UITYPE_BROADAXE, 7u, 5u, 23900, IPL_LIFE, 30, 30, IPL_TOHIT, 20, 20, IPL_DAMP, 50, 50, IPL_LIGHTRES, 40, 40, IPL_INVCURS, 104, 0, IPL_TOHIT, 0, 0 }, + { "Aguinara's Hatchet", UITYPE_SMALLAXE, 12u, 3u, 24800, IPL_SPLLVLADD, 1, 1, IPL_MAG, 10, 10, IPL_MAGICRES, 80, 80, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Hellslayer", UITYPE_BATTLEAXE, 15u, 5u, 26200, IPL_STR, 8, 8, IPL_VIT, 8, 8, IPL_DAMP, 100, 100, IPL_LIFE, 25, 25, IPL_MANA_CURSE, 25, 25, IPL_TOHIT, 0, 0 }, + { "Messerschmidt's Reaver", UITYPE_GREATAXE, 25u, 6u, 58000, IPL_DAMP, 200, 200, IPL_DAMMOD, 15, 15, IPL_ATTRIBS, 5, 5, IPL_LIFE_CURSE, 50, 50, IPL_FIREDAM, 2, 12, IPL_INVCURS, 163, 0 }, + { "Crackrust", UITYPE_MACE, 1u, 5u, 11375, IPL_ATTRIBS, 2, 2, IPL_INDESTRUCTIBLE, 0, 0, IPL_ALLRES, 15, 15, IPL_DAMP, 50, 50, IPL_SPLLVLADD, -1, -1, IPL_TOHIT, 0, 0 }, + { "Hammer of Jholm", UITYPE_MAUL, 1u, 4u, 8700, IPL_DAMP, 4, 10, IPL_INDESTRUCTIBLE, 0, 0, IPL_STR, 3, 3, IPL_TOHIT, 15, 15, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Civerb's Cudgel", UITYPE_MACE, 1u, 3u, 2000, IPL_3XDAMVDEM, 35, 35, IPL_DEX_CURSE, 5, 5, IPL_MAG_CURSE, 2, 2, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "The Celestial Star", UITYPE_FLAIL, 2u, 5u, 7810, IPL_NOMINSTR, 0, 0, IPL_LIGHT, 2, 2, IPL_DAMMOD, 10, 10, IPL_AC_CURSE, 8, 8, IPL_INVCURS, 131, 0, IPL_TOHIT, 0, 0 }, + { "Baranar's Star", UITYPE_MORNSTAR, 5u, 6u, 6850, IPL_TOHIT, 12, 12, IPL_DAMP, 80, 80, IPL_FASTATTACK, 1, 1, IPL_VIT, 4, 4, IPL_DEX_CURSE, 4, 4, IPL_SETDUR, 60, 60 }, + { "Gnarled Root", UITYPE_SPIKCLUB, 9u, 6u, 9820, IPL_TOHIT, 20, 20, IPL_DAMP, 300, 300, IPL_DEX, 10, 10, IPL_MAG, 5, 5, IPL_ALLRES, 10, 10, IPL_AC_CURSE, 10, 10 }, + { "The Cranium Basher", UITYPE_MAUL, 12u, 6u, 36500, IPL_DAMMOD, 20, 20, IPL_STR, 15, 15, IPL_INDESTRUCTIBLE, 0, 0, IPL_MANA_CURSE, 150, 150, IPL_ALLRES, 5, 5, IPL_INVCURS, 122, 0 }, + { "Schaefer's Hammer", UITYPE_WARHAMMER, 16u, 6u, 56125, IPL_DAMP_CURSE, 100, 100, IPL_LIGHTDAM, 1, 50, IPL_LIFE, 50, 50, IPL_TOHIT, 30, 30, IPL_LIGHTRES, 80, 80, IPL_LIGHT, 1, 1 }, + { "Dreamflange", UITYPE_MACE, 26u, 5u, 26450, IPL_MAG, 30, 30, IPL_MANA, 50, 50, IPL_MAGICRES, 50, 50, IPL_LIGHT, 2, 2, IPL_SPLLVLADD, 1, 1, IPL_TOHIT, 0, 0 }, + { "Staff of Shadows", UITYPE_LONGSTAFF, 2u, 5u, 1250, IPL_MAG_CURSE, 10, 10, IPL_TOHIT, 10, 10, IPL_DAMP, 60, 60, IPL_LIGHT_CURSE, 2, 2, IPL_FASTATTACK, 1, 1, IPL_TOHIT, 0, 0 }, + { "Immolator", UITYPE_LONGSTAFF, 4u, 4u, 3900, IPL_FIRERES, 20, 20, IPL_FIREDAM, 4, 4, IPL_MANA, 10, 10, IPL_VIT_CURSE, 5, 5, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Storm Spire", UITYPE_WARSTAFF, 8u, 4u, 22500, IPL_LIGHTRES, 50, 50, IPL_LIGHTDAM, 2, 8, IPL_STR, 10, 10, IPL_MAG_CURSE, 10, 10, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Gleamsong", UITYPE_SHORTSTAFF, 8u, 4u, 6520, IPL_MANA, 25, 25, IPL_STR_CURSE, 3, 3, IPL_VIT_CURSE, 3, 3, IPL_SPELL, 10, 76, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Thundercall", UITYPE_COMPSTAFF, 14u, 5u, 22250, IPL_TOHIT, 35, 35, IPL_LIGHTDAM, 1, 10, IPL_SPELL, 3, 76, IPL_LIGHTRES, 30, 30, IPL_LIGHT, 2, 2, IPL_TOHIT, 0, 0 }, + { "The Protector", UITYPE_SHORTSTAFF, 16u, 6u, 17240, IPL_VIT, 5, 5, IPL_GETHIT, 5, 5, IPL_SETAC, 40, 40, IPL_SPELL, 2, 86, IPL_THORNS, 1, 3, IPL_INVCURS, 162, 0 }, + { "Naj's Puzzler", UITYPE_LONGSTAFF, 18u, 5u, 34000, IPL_MAG, 20, 20, IPL_DEX, 10, 10, IPL_ALLRES, 20, 20, IPL_SPELL, 23, 57, IPL_LIFE_CURSE, 25, 25, IPL_TOHIT, 0, 0 }, + { "Mindcry", UITYPE_QUARSTAFF, 20u, 4u, 41500, IPL_MAG, 15, 15, IPL_SPELL, 13, 69, IPL_ALLRES, 15, 15, IPL_SPLLVLADD, 1, 1, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Rod of Onan", UITYPE_WARSTAFF, 22u, 3u, 44167, IPL_SPELL, 21, 50, IPL_DAMP, 100, 100, IPL_ATTRIBS, 5, 5, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Helm of Sprits", UITYPE_HELM, 1u, 2u, 7525, IPL_STEALLIFE, 5, 5, IPL_INVCURS, 77, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Thinking Cap", UITYPE_SKULLCAP, 6u, 5u, 2020, IPL_MANA, 30, 30, IPL_SPLLVLADD, 2, 2, IPL_ALLRES, 20, 20, IPL_SETDUR, 1, 1, IPL_INVCURS, 93, 0, IPL_TOHIT, 0, 0 }, + { "OverLord's Helm", UITYPE_HELM, 7u, 6u, 12500, IPL_STR, 20, 20, IPL_DEX, 15, 15, IPL_VIT, 5, 5, IPL_MAG_CURSE, 20, 20, IPL_SETDUR, 15, 15, IPL_INVCURS, 99, 0 }, + { "Fool's Crest", UITYPE_HELM, 12u, 5u, 10150, IPL_ATTRIBS_CURSE, 4, 4, IPL_LIFE, 100, 100, IPL_GETHIT_CURSE, 1, 6, IPL_THORNS, 1, 3, IPL_INVCURS, 80, 0, IPL_TOHIT, 0, 0 }, + { "Gotterdamerung", UITYPE_GREATHELM, 21u, 6u, 54900, IPL_ATTRIBS, 20, 20, IPL_SETAC, 60, 60, IPL_GETHIT, 4, 4, IPL_ALLRESZERO, 0, 0, IPL_LIGHT_CURSE, 4, 4, IPL_INVCURS, 85, 0 }, + { "Royal Circlet", UITYPE_CROWN, 27u, 5u, 24875, IPL_ATTRIBS, 10, 10, IPL_MANA, 40, 40, IPL_SETAC, 40, 40, IPL_LIGHT, 1, 1, IPL_INVCURS, 79, 0, IPL_TOHIT, 0, 0 }, + { "Torn Flesh of Souls", UITYPE_RAGS, 2u, 5u, 4825, IPL_SETAC, 8, 8, IPL_VIT, 10, 10, IPL_GETHIT, 1, 1, IPL_INDESTRUCTIBLE, 0, 0, IPL_INVCURS, 92, 0, IPL_TOHIT, 0, 0 }, + { "The Gladiator's Bane", UITYPE_STUDARMOR, 6u, 4u, 3450, IPL_SETAC, 25, 25, IPL_GETHIT, 2, 2, IPL_DUR, 200, 200, IPL_ATTRIBS_CURSE, 3, 3, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "The Rainbow Cloak", UITYPE_CLOAK, 2u, 6u, 4900, IPL_SETAC, 10, 10, IPL_ATTRIBS, 1, 1, IPL_ALLRES, 10, 10, IPL_LIFE, 5, 5, IPL_DUR, 50, 50, IPL_INVCURS, 138, 0 }, + { "Leather of Aut", UITYPE_LEATHARMOR, 4u, 5u, 10550, IPL_SETAC, 15, 15, IPL_STR, 5, 5, IPL_MAG_CURSE, 5, 5, IPL_DEX, 5, 5, IPL_INDESTRUCTIBLE, 0, 0, IPL_TOHIT, 0, 0 }, + { "Wisdom's Wrap", UITYPE_ROBE, 5u, 6u, 6200, IPL_MAG, 5, 5, IPL_MANA, 10, 10, IPL_LIGHTRES, 25, 25, IPL_SETAC, 15, 15, IPL_GETHIT, 1, 1, IPL_INVCURS, 138, 0 }, + { "Sparking Mail", UITYPE_CHAINMAIL, 9u, 2u, 15750, IPL_SETAC, 30, 30, IPL_LIGHTDAM, 1, 10, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Scavenger Carapace", UITYPE_BREASTPLATE, 13u, 4u, 14000, IPL_GETHIT, 15, 15, IPL_AC_CURSE, 30, 30, IPL_DEX, 5, 5, IPL_LIGHTRES, 40, 40, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Nightscape", UITYPE_CAPE, 16u, 6u, 11600, IPL_FASTRECOVER, 2, 2, IPL_LIGHT_CURSE, 4, 4, IPL_SETAC, 15, 15, IPL_DEX, 3, 3, IPL_ALLRES, 20, 20, IPL_INVCURS, 138, 0 }, + { "Naj's Light Plate", UITYPE_PLATEMAIL, 19u, 6u, 78700, IPL_NOMINSTR, 0, 0, IPL_MAG, 5, 5, IPL_MANA, 20, 20, IPL_ALLRES, 20, 20, IPL_SPLLVLADD, 1, 1, IPL_INVCURS, 159, 0 }, + { "Demonspike Coat", UITYPE_FULLPLATE, 25u, 5u, 251175, IPL_SETAC, 100, 100, IPL_GETHIT, 6, 6, IPL_STR, 10, 10, IPL_INDESTRUCTIBLE, 0, 0, IPL_FIRERES, 50, 50, IPL_TOHIT, 0, 0 }, + { "The Deflector", UITYPE_BUCKLER, 1u, 5u, 1500, IPL_SETAC, 7, 7, IPL_ALLRES, 10, 10, IPL_DAMP_CURSE, 20, 20, IPL_TOHIT_CURSE, 5, 5, IPL_INVCURS, 83, 0, IPL_TOHIT, 0, 0 }, + { "Split Skull Shield", UITYPE_BUCKLER, 1u, 6u, 2025, IPL_SETAC, 10, 10, IPL_LIFE, 10, 10, IPL_STR, 2, 2, IPL_LIGHT_CURSE, 1, 1, IPL_SETDUR, 15, 15, IPL_INVCURS, 116, 0 }, + { "Dragon's Breach", UITYPE_KITESHIELD, 2u, 6u, 19200, IPL_FIRERES, 25, 25, IPL_STR, 5, 5, IPL_SETAC, 20, 20, IPL_MAG_CURSE, 5, 5, IPL_INDESTRUCTIBLE, 0, 0, IPL_INVCURS, 117, 0 }, + { "Blackoak Shield", UITYPE_SMALLSHIELD, 4u, 6u, 5725, IPL_DEX, 10, 10, IPL_VIT_CURSE, 10, 10, IPL_SETAC, 18, 18, IPL_LIGHT_CURSE, 1, 1, IPL_DUR, 150, 150, IPL_INVCURS, 146, 0 }, + { "Holy Defender", UITYPE_LARGESHIELD, 10u, 6u, 13800, IPL_SETAC, 15, 15, IPL_GETHIT, 2, 2, IPL_FIRERES, 20, 20, IPL_DUR, 200, 200, IPL_FASTBLOCK, 1, 1, IPL_INVCURS, 146, 0 }, + { "Stormshield", UITYPE_GOTHSHIELD, 24u, 6u, 49000, IPL_SETAC, 40, 40, IPL_GETHIT_CURSE, 4, 4, IPL_STR, 10, 10, IPL_INDESTRUCTIBLE, 0, 0, IPL_FASTBLOCK, 1, 1, IPL_INVCURS, 148, 0 }, + { "Bramble", UITYPE_RING, 1u, 4u, 1000, IPL_ATTRIBS_CURSE, 2, 2, IPL_DAMMOD, 3, 3, IPL_MANA, 10, 10, IPL_INVCURS, 9, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Ring of Regha", UITYPE_RING, 1u, 6u, 4175, IPL_MAG, 10, 10, IPL_MAGICRES, 10, 10, IPL_LIGHT, 1, 1, IPL_STR_CURSE, 3, 3, IPL_DEX_CURSE, 3, 3, IPL_INVCURS, 11, 0 }, + { "The Bleeder", UITYPE_RING, 2u, 4u, 8500, IPL_MAGICRES, 20, 20, IPL_MANA, 30, 30, IPL_LIFE_CURSE, 10, 10, IPL_INVCURS, 8, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Constricting Ring", UITYPE_RING, 5u, 3u, 62000, IPL_ALLRES, 75, 75, IPL_DRAINLIFE, 0, 0, IPL_INVCURS, 14, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, + { "Ring of Engagement", UITYPE_RING, 11u, 5u, 12476, IPL_GETHIT, 1, 2, IPL_THORNS, 1, 3, IPL_SETAC, 5, 5, IPL_TARGAC, 4, 12, IPL_INVCURS, 13, 0, IPL_TOHIT, 0, 0 }, + { &empty_string, UITYPE_INVALID, 0u, 0u, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 } +}; + +/* data */ + + +ItemDataStruct AllItemsList[157] = +{ + { IDROP_REGULAR, ICLASS_GOLD, ILOC_UNEQUIPABLE, 168, 11u, UITYPE_NONE, "Gold", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 1, 0, 0 }, + { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, 64, 1u, UITYPE_NONE, "Short Sword", NULL, 2, 20, 2, 6, 0, 0, 18u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 50, 50 }, + { IDROP_NEVER, ICLASS_ARMOR, ILOC_ONEHAND, 83, 5u, UITYPE_NONE, "Buckler", NULL, 2, 10, 0, 0, 3, 3, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 50, 50 }, + { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, 66, 4u, UITYPE_SPIKCLUB, "Club", NULL, 1, 20, 1, 6, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 20, 20 }, + { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, 118, 3u, UITYPE_NONE, "Short Bow", NULL, 1, 30, 1, 4, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 100, 100 }, + { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, 109, 10u, UITYPE_NONE, "Short Staff of Charged Bolt", NULL, 1, 25, 2, 4, 0, 0, 0u, 20u, 0u, ISPL_NONE, IMISC_STAFF, SPL_CBOLT, 0, 520, 520 }, + { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, 106, 2u, UITYPE_CLEAVER, "Cleaver", NULL, 10, 10, 4, 24, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, 0, 2000, 2000 }, + { IDROP_NEVER, ICLASS_ARMOR, ILOC_HELM, 78, 7u, UITYPE_SKCROWN, "The Undead Crown", NULL, 0, 50, 0, 0, 15, 15, 0u, 0u, 0u, ISPL_RNDSTEALLIFE, IMISC_UNIQUE, SPL_NULL, 0, 10000, 10000 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_RING, 18, 12u, UITYPE_INFRARING, "Empyrean Band", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, 0, 8000, 8000 }, + { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, 76, 0u, UITYPE_NONE, "Magic Rock", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_AMULET, 44, 13u, UITYPE_OPTAMULET, "Optic Amulet", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, 0, 5000, 5000 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_RING, 10, 12u, UITYPE_TRING, "Ring of Truth", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, 0, 1000, 1000 }, + { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, 126, 0u, UITYPE_NONE, "Tavern Sign", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_ARMOR, ILOC_HELM, 93, 7u, UITYPE_HARCREST, "Harlequin Crest", NULL, 0, 15, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, 0, 15, 20 }, + { IDROP_NEVER, ICLASS_ARMOR, ILOC_HELM, 85, 7u, UITYPE_STEELVEIL, "Veil of Steel", NULL, 0, 60, 0, 0, 18, 18, 0u, 0u, 0u, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 17, 0u, UITYPE_ELIXIR, "Golden Elixir", NULL, 15, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, 140, 0u, UITYPE_NONE, "Anvil of Fury", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, 89, 0u, UITYPE_NONE, "Black Mushroom", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, 40, 0u, UITYPE_NONE, "Brain", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, 97, 0u, UITYPE_NONE, "Fungal Tome", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 15, 0u, UITYPE_ELIXIR, "Spectral Elixir", NULL, 15, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_SPECELIX, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, 25, 0u, UITYPE_NONE, "Blood Stone", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, 96, 0u, UITYPE_MAPOFDOOM, "Map of the Stars", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_MAPOFDOOM, SPL_NULL, 1, 0, 0 }, + { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, 19, 0u, UITYPE_NONE, "Heart", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_EAR, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 32, 0u, UITYPE_NONE, "Potion of Healing", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_HEAL, SPL_NULL, 1, 50, 50 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 39, 0u, UITYPE_NONE, "Potion of Mana", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_MANA, SPL_NULL, 1, 50, 50 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Identify", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_IDENTIFY, 1, 200, 200 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Town Portal", NULL, 4, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_TOWN, 1, 200, 200 }, + { IDROP_NEVER, ICLASS_ARMOR, ILOC_ARMOR, 157, 8u, UITYPE_ARMOFVAL, "Arkaine's Valor", NULL, 0, 40, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 35, 0u, UITYPE_NONE, "Potion of Full Healing", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_FULLHEAL, SPL_NULL, 1, 150, 150 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 0, 0u, UITYPE_NONE, "Potion of Full Mana", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_FULLMANA, SPL_NULL, 1, 150, 150 }, + { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, 61, 1u, UITYPE_GRISWOLD, "Griswold's Edge", NULL, 8, 50, 4, 12, 0, 0, 40u, 0u, 0u, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, 0, 750, 750 }, + { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, 59, 4u, UITYPE_LGTFORGE, "Lightforge", NULL, 2, 32, 1, 8, 0, 0, 16u, 0u, 0u, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, 0, 200, 200 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 155, 0u, UITYPE_LAZSTAFF, "Staff of Lazarus", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Resurrect", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_RESURRECT, 1, 250, 250 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, 91, 7u, UITYPE_NONE, "Cap", "Cap", 1, 15, 0, 0, 1, 3, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 15, 20 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, 90, 7u, UITYPE_SKULLCAP, "Skull Cap", "Cap", 4, 20, 0, 0, 2, 4, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 25, 30 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, 82, 7u, UITYPE_HELM, "Helm", "Helm", 8, 30, 0, 0, 4, 6, 25u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 40, 70 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, 75, 7u, UITYPE_NONE, "Full Helm", "Helm", 12, 35, 0, 0, 6, 8, 35u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 90, 130 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, 95, 7u, UITYPE_CROWN, "Crown", "Crown", 16, 40, 0, 0, 8, 12, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 200, 300 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, 98, 7u, UITYPE_GREATHELM, "Great Helm", "Helm", 20, 60, 0, 0, 10, 15, 50u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 400, 500 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 150, 6u, UITYPE_CAPE, "Cape", "Cape", 1, 12, 0, 0, 1, 5, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 10, 50 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 128, 6u, UITYPE_RAGS, "Rags", "Rags", 1, 6, 0, 0, 2, 6, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 5, 25 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 149, 6u, UITYPE_CLOAK, "Cloak", "Cloak", 2, 18, 0, 0, 3, 7, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 40, 70 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 137, 6u, UITYPE_ROBE, "Robe", "Robe", 3, 24, 0, 0, 4, 7, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 75, 125 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 129, 6u, UITYPE_NONE, "Quilted Armor", "Armor", 4, 30, 0, 0, 7, 10, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 200, 300 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 135, 6u, UITYPE_LEATHARMOR, "Leather Armor", "Armor", 6, 35, 0, 0, 10, 13, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 300, 400 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 127, 6u, UITYPE_NONE, "Hard Leather Armor", "Armor", 7, 40, 0, 0, 11, 14, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 450, 550 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 107, 6u, UITYPE_STUDARMOR, "Studded Leather Armor", "Armor", 9, 45, 0, 0, 15, 17, 20u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 700, 800 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 154, 8u, UITYPE_NONE, "Ring Mail", "Mail", 11, 50, 0, 0, 17, 20, 25u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 900, 1100 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 111, 8u, UITYPE_CHAINMAIL, "Chain Mail", "Mail", 13, 55, 0, 0, 18, 22, 30u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 1250, 1750 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 114, 8u, UITYPE_NONE, "Scale Mail", "Mail", 15, 60, 0, 0, 23, 28, 35u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 2300, 2800 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 153, 9u, UITYPE_BREASTPLATE, "Breast Plate", "Plate", 16, 80, 0, 0, 20, 24, 40u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 2800, 3200 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 136, 8u, UITYPE_NONE, "Splint Mail", "Mail", 17, 65, 0, 0, 30, 35, 40u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 3250, 3750 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 103, 9u, UITYPE_PLATEMAIL, "Plate Mail", "Plate", 19, 75, 0, 0, 42, 50, 60u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 4600, 5400 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 103, 9u, UITYPE_NONE, "Field Plate", "Plate", 21, 80, 0, 0, 40, 45, 65u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 5800, 6200 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 152, 9u, UITYPE_NONE, "Gothic Plate", "Plate", 23, 100, 0, 0, 50, 60, 80u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 8000, 10000 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, 151, 9u, UITYPE_FULLPLATE, "Full Plate Mail", "Plate", 25, 90, 0, 0, 60, 75, 90u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 6500, 8000 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, 83, 5u, UITYPE_BUCKLER, "Buckler", "Shield", 1, 16, 0, 0, 1, 5, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 30, 70 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, 105, 5u, UITYPE_SMALLSHIELD, "Small Shield", "Shield", 5, 24, 0, 0, 3, 8, 25u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 90, 130 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, 147, 5u, UITYPE_LARGESHIELD, "Large Shield", "Shield", 9, 32, 0, 0, 5, 10, 40u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 200, 300 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, 113, 5u, UITYPE_KITESHIELD, "Kite Shield", "Shield", 14, 40, 0, 0, 8, 15, 50u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 400, 700 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, 132, 5u, UITYPE_GOTHSHIELD, "Tower Shield", "Shield", 20, 50, 0, 0, 12, 20, 60u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 850, 1200 }, + { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, 148, 5u, UITYPE_GOTHSHIELD, "Gothic Shield", "Shield", 23, 60, 0, 0, 14, 18, 80u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 2300, 2700 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 32, 0u, UITYPE_NONE, "Potion of Healing", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_HEAL, SPL_NULL, 1, 50, 50 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 35, 0u, UITYPE_NONE, "Potion of Full Healing", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_FULLHEAL, SPL_NULL, 1, 150, 150 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 39, 0u, UITYPE_NONE, "Potion of Mana", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_MANA, SPL_NULL, 1, 50, 50 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 0, 0u, UITYPE_NONE, "Potion of Full Mana", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_FULLMANA, SPL_NULL, 1, 150, 150 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 37, 0u, UITYPE_NONE, "Potion of Rejuvenation", NULL, 3, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_REJUV, SPL_NULL, 1, 120, 120 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 33, 0u, UITYPE_NONE, "Potion of Full Rejuvenation", NULL, 7, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_FULLREJUV, SPL_NULL, 1, 600, 600 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 38, 0u, UITYPE_NONE, "Elixir of Strength", NULL, 15, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_ELIXSTR, SPL_NULL, 1, 5000, 5000 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 34, 0u, UITYPE_NONE, "Elixir of Magic", NULL, 15, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_ELIXMAG, SPL_NULL, 1, 5000, 5000 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 36, 0u, UITYPE_NONE, "Elixir of Dexterity", NULL, 15, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_ELIXDEX, SPL_NULL, 1, 5000, 5000 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 31, 0u, UITYPE_NONE, "Elixir of Vitality", NULL, 20, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_ELIXVIT, SPL_NULL, 1, 5000, 5000 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Healing", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_HEAL, 1, 50, 50 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Lightning", NULL, 4, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_LIGHTNING, 1, 150, 150 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Identify", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_IDENTIFY, 1, 100, 100 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Resurrect", NULL, 1, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_RESURRECT, 1, 250, 250 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Fire Wall", NULL, 4, 0, 0, 0, 0, 0, 0u, 17u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_FIREWALL, 1, 400, 400 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Inferno", NULL, 1, 0, 0, 0, 0, 0, 0u, 19u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_FLAME, 1, 100, 100 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Town Portal", NULL, 4, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_TOWN, 1, 200, 200 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Flash", NULL, 6, 0, 0, 0, 0, 0, 0u, 21u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_FLASH, 1, 500, 500 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Infravision", NULL, 8, 0, 0, 0, 0, 0, 0u, 23u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_INFRA, 1, 600, 600 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Phasing", NULL, 6, 0, 0, 0, 0, 0, 0u, 25u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_RNDTELEPORT, 1, 200, 200 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Mana Shield", NULL, 8, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_MANASHIELD, 1, 1200, 1200 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Flame Wave", NULL, 10, 0, 0, 0, 0, 0, 0u, 29u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_WAVE, 1, 650, 650 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Fireball", NULL, 8, 0, 0, 0, 0, 0, 0u, 31u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_FIREBALL, 1, 300, 300 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Stone Curse", NULL, 6, 0, 0, 0, 0, 0, 0u, 33u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_STONE, 1, 800, 800 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Chain Lightning", NULL, 10, 0, 0, 0, 0, 0, 0u, 35u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_CHAIN, 1, 750, 750 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Guardian", NULL, 12, 0, 0, 0, 0, 0, 0u, 47u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_GUARDIAN, 1, 950, 950 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Non Item", NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Nova", NULL, 14, 0, 0, 0, 0, 0, 0u, 57u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_NOVA, 1, 1300, 1300 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Golem", NULL, 10, 0, 0, 0, 0, 0, 0u, 51u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_GOLEM, 1, 1100, 1100 }, + { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of None", NULL, 99, 0, 0, 0, 0, 0, 0u, 61u, 0u, ISPL_NONE, IMISC_SCROLLT, SPL_NULL, 1, 1000, 1000 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Teleport", NULL, 14, 0, 0, 0, 0, 0, 0u, 81u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_TELEPORT, 1, 3000, 3000 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 1, 0u, UITYPE_NONE, "Scroll of Apocalypse", NULL, 22, 0, 0, 0, 0, 0, 0u, 117u, 0u, ISPL_NONE, IMISC_SCROLL, SPL_APOCA, 1, 2000, 2000 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 88, 0u, UITYPE_NONE, "Book of ", NULL, 2, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_BOOK, SPL_NULL, 1, 0, 0 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 88, 0u, UITYPE_NONE, "Book of ", NULL, 8, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_BOOK, SPL_NULL, 1, 0, 0 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 88, 0u, UITYPE_NONE, "Book of ", NULL, 14, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_BOOK, SPL_NULL, 1, 0, 0 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, 88, 0u, UITYPE_NONE, "Book of ", NULL, 20, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_BOOK, SPL_NULL, 1, 0, 0 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 51, 1u, UITYPE_DAGGER, "Dagger", "Dagger", 1, 16, 1, 4, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 60, 60 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 64, 1u, UITYPE_NONE, "Short Sword", "Sword", 1, 24, 2, 6, 0, 0, 18u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 120, 120 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 62, 1u, UITYPE_FALCHION, "Falchion", "Sword", 2, 20, 4, 8, 0, 0, 30u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 250, 250 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 72, 1u, UITYPE_SCIMITAR, "Scimitar", "Sword", 4, 28, 3, 7, 0, 0, 23u, 0u, 23u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 200, 200 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 65, 1u, UITYPE_CLAYMORE, "Claymore", "Sword", 5, 36, 1, 12, 0, 0, 35u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 450, 450 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 56, 1u, UITYPE_NONE, "Blade", "Blade", 4, 30, 3, 8, 0, 0, 25u, 0u, 30u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 280, 280 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 67, 1u, UITYPE_SABRE, "Sabre", "Sabre", 1, 45, 1, 8, 0, 0, 17u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 170, 170 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 60, 1u, UITYPE_LONGSWR, "Long Sword", "Sword", 6, 40, 2, 10, 0, 0, 30u, 0u, 30u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 350, 350 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 61, 1u, UITYPE_BROADSWR, "Broad Sword", "Sword", 8, 50, 4, 12, 0, 0, 40u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 750, 750 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 57, 1u, UITYPE_BASTARDSWR, "Bastard Sword", "Sword", 10, 60, 6, 15, 0, 0, 50u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 1000, 1000 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 110, 1u, UITYPE_TWOHANDSWR, "Two-Handed Sword", "Sword", 14, 75, 8, 16, 0, 0, 65u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 1800, 1800 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 134, 1u, UITYPE_GREATSWR, "Great Sword", "Sword", 17, 100, 10, 20, 0, 0, 75u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 3000, 3000 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 112, 2u, UITYPE_SMALLAXE, "Small Axe", "Axe", 2, 24, 2, 10, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 150, 150 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 144, 2u, UITYPE_NONE, "Axe", "Axe", 4, 32, 4, 12, 0, 0, 22u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 450, 450 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 142, 2u, UITYPE_LARGEAXE, "Large Axe", "Axe", 6, 40, 6, 16, 0, 0, 30u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 750, 750 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 141, 2u, UITYPE_BROADAXE, "Broad Axe", "Axe", 8, 50, 8, 20, 0, 0, 50u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 1000, 1000 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 101, 2u, UITYPE_BATTLEAXE, "Battle Axe", "Axe", 10, 60, 10, 25, 0, 0, 65u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 1500, 1500 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 143, 2u, UITYPE_GREATAXE, "Great Axe", "Axe", 12, 75, 12, 30, 0, 0, 80u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 2500, 2500 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 59, 4u, UITYPE_MACE, "Mace", "Mace", 2, 32, 1, 8, 0, 0, 16u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 200, 200 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 63, 4u, UITYPE_MORNSTAR, "Morning Star", "Mace", 3, 40, 1, 10, 0, 0, 26u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 300, 300 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 121, 4u, UITYPE_WARHAMMER, "War Hammer", "Hammer", 5, 50, 5, 9, 0, 0, 40u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 600, 600 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 70, 4u, UITYPE_SPIKCLUB, "Spiked Club", "Club", 4, 20, 3, 6, 0, 0, 18u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 225, 225 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 66, 4u, UITYPE_SPIKCLUB, "Club", "Club", 1, 20, 1, 6, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 20, 20 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, 131, 4u, UITYPE_FLAIL, "Flail", "Flail", 7, 36, 2, 12, 0, 0, 30u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 500, 500 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 122, 4u, UITYPE_MAUL, "Maul", "Maul", 10, 50, 6, 20, 0, 0, 55u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 900, 900 }, + { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, 118, 3u, UITYPE_SHORTBOW, "Short Bow", "Bow", 1, 30, 1, 4, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 100, 100 }, + { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, 102, 3u, UITYPE_HUNTBOW, "Hunter's Bow", "Bow", 3, 40, 2, 5, 0, 0, 20u, 0u, 35u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 350, 350 }, + { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, 102, 3u, UITYPE_LONGBOW, "Long Bow", "Bow", 5, 35, 1, 6, 0, 0, 25u, 0u, 30u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 250, 250 }, + { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, 133, 3u, UITYPE_COMPBOW, "Composite Bow", "Bow", 7, 45, 3, 6, 0, 0, 25u, 0u, 40u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 600, 600 }, + { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, 167, 3u, UITYPE_NONE, "Short Battle Bow", "Bow", 9, 45, 3, 7, 0, 0, 30u, 0u, 50u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 750, 750 }, + { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, 119, 3u, UITYPE_BATTLEBOW, "Long Battle Bow", "Bow", 11, 50, 1, 10, 0, 0, 30u, 0u, 60u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 1000, 1000 }, + { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, 165, 3u, UITYPE_NONE, "Short War Bow", "Bow", 15, 55, 4, 8, 0, 0, 35u, 0u, 70u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 1500, 1500 }, + { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, 119, 3u, UITYPE_WARBOW, "Long War Bow", "Bow", 19, 60, 1, 14, 0, 0, 45u, 0u, 80u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 2000, 2000 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 109, 10u, UITYPE_SHORTSTAFF, "Short Staff", "Staff", 1, 25, 2, 4, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_STAFF, SPL_NULL, 0, 30, 30 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 123, 10u, UITYPE_LONGSTAFF, "Long Staff", "Staff", 4, 35, 4, 8, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_STAFF, SPL_NULL, 0, 100, 100 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 166, 10u, UITYPE_COMPSTAFF, "Composite Staff", "Staff", 6, 45, 5, 10, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_STAFF, SPL_NULL, 0, 500, 500 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 109, 10u, UITYPE_QUARSTAFF, "Quarter Staff", "Staff", 9, 55, 6, 12, 0, 0, 20u, 0u, 0u, ISPL_NONE, IMISC_STAFF, SPL_NULL, 0, 1000, 1000 }, + { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, 124, 10u, UITYPE_WARSTAFF, "War Staff", "Staff", 12, 75, 8, 16, 0, 0, 30u, 0u, 0u, ISPL_NONE, IMISC_STAFF, SPL_NULL, 0, 1500, 1500 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_RING, 12, 12u, UITYPE_RING, "Ring", "Ring", 5, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_RING, SPL_NULL, 0, 1000, 1000 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_RING, 12, 12u, UITYPE_RING, "Ring", "Ring", 10, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_RING, SPL_NULL, 0, 1000, 1000 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_RING, 12, 12u, UITYPE_RING, "Ring", "Ring", 15, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_RING, SPL_NULL, 0, 1000, 1000 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_AMULET, 45, 13u, UITYPE_AMULET, "Amulet", "Amulet", 8, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_AMULET, SPL_NULL, 0, 1200, 1200 }, + { IDROP_REGULAR, ICLASS_MISC, ILOC_AMULET, 45, 13u, UITYPE_AMULET, "Amulet", "Amulet", 16, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_AMULET, SPL_NULL, 0, 1200, 1200 }, + { IDROP_NEVER, ICLASS_NONE, ILOC_INVALID, 0, 0u, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0u, 0u, 0u, ISPL_NONE, IMISC_NONE, SPL_NULL, 0, 0, 0 } +}; +unsigned char ItemCAnimTbl[169] = +{ + 20, 16, 16, 16, 4, 4, 4, 12, 12, 12, + 12, 12, 12, 12, 12, 21, 21, 25, 12, 28, + 28, 28, 0, 0, 0, 32, 0, 0, 0, 24, + 24, 26, 2, 25, 22, 23, 24, 25, 27, 27, + 29, 0, 0, 0, 12, 12, 12, 12, 12, 0, + 8, 8, 0, 8, 8, 8, 8, 8, 8, 6, + 8, 8, 8, 6, 8, 8, 6, 8, 8, 6, + 6, 6, 8, 8, 8, 5, 9, 13, 13, 13, + 5, 5, 5, 15, 5, 5, 18, 18, 18, 30, + 5, 5, 14, 5, 14, 13, 16, 18, 5, 5, + 7, 1, 3, 17, 1, 15, 10, 14, 3, 11, + 8, 0, 1, 7, 0, 7, 15, 7, 3, 3, + 3, 6, 6, 11, 11, 11, 31, 14, 14, 14, + 6, 6, 7, 3, 8, 14, 0, 14, 14, 0, + 33, 1, 1, 1, 1, 1, 7, 7, 7, 14, + 14, 17, 17, 17, 0, 34, 1, 0, 3, 17, + 8, 8, 6, 1, 3, 3, 11, 3, 4 +}; +char *ItemDropStrs[35] = +{ + "Armor2", + "Axe", + "FBttle", + "Bow", + "GoldFlip", + "Helmut", + "Mace", + "Shield", + "SwrdFlip", + "Rock", + "Cleaver", + "Staff", + "Ring", + "CrownF", + "LArmor", + "WShield", + "Scroll", + "FPlateAr", + "FBook", + "Food", + "FBttleBB", + "FBttleDY", + "FBttleOR", + "FBttleBR", + "FBttleBL", + "FBttleBY", + "FBttleWH", + "FBttleDB", + "FEar", + "FBrain", + "FMush", + "Innsign", + "Bldstn", + "Fanvil", + "FLazStaf" +}; +unsigned char ItemAnimLs[35] = +{ + 15u, + 13u, + 16u, + 13u, + 10u, + 13u, + 13u, + 13u, + 13u, + 10u, + 13u, + 13u, + 13u, + 13u, + 13u, + 13u, + 13u, + 13u, + 13u, + 1u, + 16u, + 16u, + 16u, + 16u, + 16u, + 16u, + 16u, + 16u, + 13u, + 12u, + 12u, + 13u, + 13u, + 13u, + 8u +}; +int ItemDropSnds[35] = +{ + IS_FHARM, + IS_FAXE, + IS_FPOT, + IS_FBOW, + IS_GOLD, + IS_FCAP, + IS_FSWOR, + IS_FSHLD, + IS_FSWOR, + IS_FROCK, + IS_FAXE, + IS_FSTAF, + IS_FRING, + IS_FCAP, + IS_FLARM, + IS_FSHLD, + IS_FSCRL, + IS_FHARM, + IS_FBOOK, + IS_FLARM, + IS_FPOT, + IS_FPOT, + IS_FPOT, + IS_FPOT, + IS_FPOT, + IS_FPOT, + IS_FPOT, + IS_FPOT, + IS_FBODY, + IS_FBODY, + IS_FMUSH, + IS_ISIGN, + IS_FBLST, + IS_FANVL, + IS_FSTAF +}; +int ItemInvSnds[35] = +{ + IS_IHARM, + IS_IAXE, + IS_IPOT, + IS_IBOW, + IS_GOLD, + IS_ICAP, + IS_ISWORD, + IS_ISHIEL, + IS_ISWORD, + IS_IROCK, + IS_IAXE, + IS_ISTAF, + IS_IRING, + IS_ICAP, + IS_ILARM, + IS_ISHIEL, + IS_ISCROL, + IS_IHARM, + IS_IBOOK, + IS_IHARM, + IS_IPOT, + IS_IPOT, + IS_IPOT, + IS_IPOT, + IS_IPOT, + IS_IPOT, + IS_IPOT, + IS_IPOT, + IS_IBODY, + IS_IBODY, + IS_IMUSH, + IS_ISIGN, + IS_IBLST, + IS_IANVL, + IS_ISTAF +}; +int idoppely = 16; // weak +int premiumlvladd[6] = { -1, -1, 0, 0, 1, 2 }; + +void __cdecl InitItemGFX() +{ + signed int v0; // esi + char arglist[64]; // [esp+4h] [ebp-40h] + + v0 = 0; + do + { + sprintf(arglist, "Items\\%s.CEL", ItemDropStrs[v0]); + Item2Frm[v0] = LoadFileInMem(arglist, 0); + ++v0; + } + while ( v0 < 35 ); + memset(UniqueItemFlag, 0, 0x200u); +} + +bool __fastcall ItemPlace(int xp, int yp) +{ + int v2; // ecx + int v3; // eax + bool result; // al + + v2 = xp; + v3 = v2 * 112 + yp; + if ( dMonster[0][v3] || dPlayer[v2][yp] || dItem[v2][yp] || dObject[v2][yp] || dFlags[v2][yp] & 8 ) + result = 0; + else + result = nSolidTable[dPiece[0][v3]] == 0; + return result; +} + +void __cdecl AddInitItems() +{ + int i; // eax + int ii; // ebx + int xx; // esi + int yy; // eax + int j; // eax + + i = random(11, 3) + 3; + if ( i > 0 ) + { + do + { + ii = itemavail[0]; + itemactive[numitems] = itemavail[0]; + itemavail[0] = itemavail[-numitems + 126]; + do + { + xx = random(12, 80) + 16; + yy = random(12, 80) + 16; + } + while ( !ItemPlace(xx, yy) ); + item[ii]._ix = xx; + item[ii]._iy = yy; + dItem[xx][yy] = ii + 1; + j = GetRndSeed(); + item[ii]._iSeed = j; + SetRndSeed(j); + if ( random(12, 2) ) + GetItemAttrs(ii, IDI_HEAL, currlevel); + else + GetItemAttrs(ii, IDI_MANA, currlevel); + item[ii]._iCreateInfo = currlevel + -32768; + SetupItem(ii); + item[ii]._iAnimFlag = 0; + item[ii]._iAnimFrame = item[ii]._iAnimLen; + item[ii]._iSelFlag = 1; + DeltaAddItem(ii); + ++numitems; + --i; + } + while ( i ); + } +} + +void __cdecl InitItems() +{ + int *v0; // eax + int v1; // edx + + GetItemAttrs(0, IDI_GOLD, 1); + numitems = 0; + qmemcpy(&golditem, item, sizeof(golditem)); + golditem._iStatFlag = 1; + v0 = &item[0]._ix; + do + { + *(v0 - 1) = 0; + *v0 = 0; + v0[1] = 0; + v0[2] = 0; + *((_BYTE *)v0 + 36) = 0; + v0[11] = 0; + v0[10] = 0; + v0 += 92; + } + while ( (signed int)v0 < (signed int)&item[MAXITEMS+1]._ix ); + v1 = 0; + memset(itemactive, 0, sizeof(itemactive)); + do + { + itemavail[v1] = v1; + ++v1; + } + while ( v1 < MAXITEMS ); + if ( !setlevel ) + { + GetRndSeed(); + if ( QuestStatus(0) ) + SpawnRock(); + if ( QuestStatus(10) ) + SpawnQuestItem(16, 2 * setpc_x + 27, 2 * setpc_y + 27, 0, 1); + if ( currlevel > 0u && currlevel < 0x10u ) + AddInitItems(); + } + uitemflag = 0; +} +// 5CF31D: using guessed type char setlevel; + +void __fastcall CalcPlrItemVals(int p, BOOL Loadgfx) +{ + int mind = 0; // min damage + int maxd = 0; // max damage + int tac = 0; // accuracy + + int g; + int i; + int mi; + + int bdam = 0; // bonus damage + int btohit = 0; // bonus chance to hit + int bac = 0; // bonus accuracy + + int iflgs = 0; // item_special_effect flags + + int sadd = 0; // added stregth + int madd = 0; // added magic + int dadd = 0; // added dexterity + int vadd = 0; // added vitality + + UINT64 spl = 0; // bitarray for all enabled/active spells + + signed int fr = 0; // fire resistance + signed int lr = 0; // lightning resistance + signed int mr = 0; // magic resistance + + int dmod = 0; // bonus damage mod? + int ghit = 0; // (reduced) chance to get hit + + signed int lrad = 10; // light radius + + int ihp = 0; // increased HP + int imana = 0; // increased mana + + int spllvladd = 0; // increased spell level + int enac = 0; // enhanced accuracy + + int fmin = 0; // minimum fire damage + int fmax = 0; // maximum fire damage + int lmin = 0; // minimum lightning damage + int lmax = 0; // maximum lightning damage + + // didn't find a use for t for now + // int t; + + for ( i = 0; i < NUM_INVLOC; i++ ) + { + ItemStruct *itm = &plr[p].InvBody[i]; + if ( itm->_itype != ITYPE_NONE && itm->_iStatFlag ) + { + + mind += itm->_iMinDam; + tac += itm->_iAC; + maxd += itm->_iMaxDam; + + if ( itm->_iSpell != SPL_NULL ) + { + spl |= (unsigned __int64)1 << (itm->_iSpell - 1); + } + + if ( !itm->_iMagical || itm->_iIdentified ) + { + bdam += itm->_iPLDam; + btohit += itm->_iPLToHit; + if ( itm->_iPLAC ) + { + int tmpac = itm->_iPLAC * itm->_iAC / 100; + if ( tmpac == 0 ) + tmpac = 1; + bac += tmpac; + } + dmod += itm->_iPLDamMod; + iflgs |= itm->_iFlags; + sadd += itm->_iPLStr; + madd += itm->_iPLMag; + dadd += itm->_iPLDex; + vadd += itm->_iPLVit; + fr += itm->_iPLFR; + lr += itm->_iPLLR; + mr += itm->_iPLMR; + ghit += itm->_iPLGetHit; + lrad += itm->_iPLLight; + ihp += itm->_iPLHP; + imana += itm->_iPLMana; + spllvladd += itm->_iSplLvlAdd; + enac += itm->_iPLEnAc; + fmin += itm->_iFMinDam; + fmax += itm->_iFMaxDam; + lmin += itm->_iLMinDam; + lmax += itm->_iLMaxDam; + } + } + } + + if ( mind == 0 && maxd == 0 ) + { + mind = 1; + maxd = 1; + + if ( plr[p].InvBody[4]._itype == ITYPE_SHIELD && plr[p].InvBody[4]._iStatFlag ) + { + maxd = 3; + } + + if ( plr[p].InvBody[5]._itype == ITYPE_SHIELD && plr[p].InvBody[5]._iStatFlag ) + { + maxd = 3; + } + } + + plr[p]._pIMaxDam = maxd; + plr[p]._pIAC = tac; + plr[p]._pIBonusDam = bdam; + plr[p]._pIBonusToHit = btohit; + plr[p]._pIBonusAC = bac; + plr[p]._pIFlags = iflgs; + plr[p]._pIGetHit = ghit; + plr[p]._pIMinDam = mind; + plr[p]._pIBonusDamMod = dmod; + + if ( lrad < 2 ) + { + lrad = 2; + } + if ( lrad > 15 ) + { + lrad = 15; + } + + if ( plr[p]._pLightRad != lrad && p == myplr ) + { + ChangeLightRadius(plr[p]._plid, lrad); + + int pvid = plr[p]._pvid; + if ( lrad >= 10 ) + { + ChangeVisionRadius(pvid, lrad); + } + else + { + ChangeVisionRadius(pvid, 10); + } + + plr[p]._pLightRad = lrad; + } + + plr[p]._pStrength = sadd + plr[p]._pBaseStr; + if ( plr[myplr]._pStrength <= 0 ) + { + plr[myplr]._pStrength = 0; + } + + plr[p]._pMagic = madd + plr[p]._pBaseMag; + if ( plr[myplr]._pMagic <= 0 ) + { + plr[myplr]._pMagic = 0; + } + + plr[p]._pDexterity = dadd + plr[p]._pBaseDex; + if ( plr[myplr]._pDexterity <= 0 ) + { + plr[myplr]._pDexterity = 0; + } + + plr[p]._pVitality = vadd + plr[p]._pBaseVit; + if ( plr[myplr]._pVitality <= 0 ) + { + plr[myplr]._pVitality = 0; + } + + if ( plr[p]._pClass == PC_ROGUE ) + { + plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 200; + } + else + { + plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 100; + } + + plr[p]._pISpells64 = spl; + + // check if the current RSplType is a valid/allowed spell + if ( plr[p]._pRSplType == RSPLTYPE_CHARGES + && !(spl & ((UINT64)1 << (plr[p]._pRSpell - 1))) ) + { + plr[p]._pRSpell = SPL_INVALID; + plr[p]._pRSplType = RSPLTYPE_INVALID; + drawpanflag = 255; + } + + plr[p]._pISplLvlAdd = spllvladd; + plr[p]._pIEnAc = enac; + + if ( iflgs & ISPL_ALLRESZERO ) + { + // reset resistances to zero if the respective special effect is active + mr = 0; + fr = 0; + lr = 0; + } + + if ( mr > 75 ) + { + mr = 75; + } + plr[p]._pMagResist = mr; + + if ( fr > 75 ) + { + fr = 75; + } + plr[p]._pFireResist = fr; + + if ( lr > 75 ) + { + lr = 75; + } + plr[p]._pLghtResist = lr; + + if ( plr[p]._pClass == PC_WARRIOR ) + { + vadd *= 2; + } + if ( plr[p]._pClass == PC_ROGUE ) + { + vadd += vadd >> 1; + } + ihp += (vadd << 6); + + if ( plr[p]._pClass == PC_SORCERER ) + { + madd *= 2; + } + if ( plr[p]._pClass == PC_ROGUE ) + { + madd += madd >> 1; + } + imana += (madd << 6); + + plr[p]._pHitPoints = ihp + plr[p]._pHPBase; + plr[p]._pMaxHP = ihp + plr[p]._pMaxHPBase; + + if ( p == myplr && (plr[p]._pHitPoints >> 6) <= 0 ) + { + SetPlayerHitPoints(p, 0); + } + + plr[p]._pMana = imana + plr[p]._pManaBase; + plr[p]._pMaxMana = imana + plr[p]._pMaxManaBase; + + plr[p]._pIFMinDam = fmin; + plr[p]._pIFMaxDam = fmax; + plr[p]._pILMinDam = lmin; + plr[p]._pILMaxDam = lmax; + + if ( iflgs & ISPL_INFRAVISION ) + { + plr[p]._pInfraFlag = 1; + } + else + { + plr[p]._pInfraFlag = 0; + } + + plr[p]._pBlockFlag = 0; + plr[p]._pwtype = 0; + + g = 0; + + if ( plr[p].InvBody[4]._itype != ITYPE_NONE + && plr[p].InvBody[4]._iClass == ICLASS_WEAPON + && plr[p].InvBody[4]._iStatFlag ) + { + g = plr[p].InvBody[4]._itype; + } + + if ( plr[p].InvBody[5]._itype != ITYPE_NONE + && plr[p].InvBody[5]._iClass == ICLASS_WEAPON + && plr[p].InvBody[5]._iStatFlag ) + { + g = plr[p].InvBody[5]._itype; + } + + switch ( g ) + { + case ITYPE_SWORD: + g = 2; + break; + case ITYPE_AXE: + g = 5; + break; + case ITYPE_BOW: + plr[p]._pwtype = 1; + g = 4; + break; + case ITYPE_MACE: + g = 6; + break; + case ITYPE_STAFF: + g = 8; + break; + } + + if ( plr[p].InvBody[4]._itype == ITYPE_SHIELD && plr[p].InvBody[4]._iStatFlag ) + { + plr[p]._pBlockFlag = 1; + g++; + } + if ( plr[p].InvBody[5]._itype == ITYPE_SHIELD && plr[p].InvBody[5]._iStatFlag ) + { + plr[p]._pBlockFlag = 1; + g++; + } + + if ( plr[p].InvBody[6]._itype == ITYPE_MARMOR && plr[p].InvBody[6]._iStatFlag ) + { + // probably a flag set + g += 16; + } + if ( plr[p].InvBody[6]._itype == ITYPE_HARMOR && plr[p].InvBody[6]._iStatFlag ) + { + // probably a flag set + g += 32; + } + + if ( plr[p]._pgfxnum != g && Loadgfx ) + { + plr[p]._pgfxnum = g; + plr[p]._pGFXLoad = 0; + LoadPlrGFX(p, PFILE_STAND); + SetPlrAnims(p); + + + int d = plr[p]._pdir; + + // TODO: Add debug assert here ( plr[p]._pNAnim[d] != NULL ) + plr[p]._pAnimData = plr[p]._pNAnim[d]; + + plr[p]._pAnimLen = plr[p]._pNFrames; + plr[p]._pAnimFrame = 1; + plr[p]._pAnimCnt = 0; + plr[p]._pAnimDelay = 3; + plr[p]._pAnimWidth = plr[p]._pNWidth; + plr[p]._pAnimWidth2 = (plr[p]._pNWidth - 64) >> 1; + } + else + { + plr[p]._pgfxnum = g; + } + + for ( i = 0; i < nummissiles; i++ ) + { + mi = missileactive[i]; + if ( missile[mi]._mitype == 13 && missile[mi]._misource == p ) + { + missile[mi]._miVar1 = plr[p]._pHitPoints; + missile[mi]._miVar2 = plr[p]._pHPBase; + } + } + + drawmanaflag = 1; + drawhpflag = 1; +} + +void __fastcall CalcPlrScrolls(int p) +{ + int v1; // esi + int v2; // eax + int *v3; // edi + int v4; // ebx + signed __int64 v5; // rax + int *v6; // edi + signed int v7; // ebx + signed __int64 v8; // rax + __int64 v9; // rax + + v1 = p; + v2 = plr[p]._pNumInv; + plr[v1]._pScrlSpells[0] = 0; + plr[v1]._pScrlSpells[1] = 0; + if ( v2 > 0 ) + { + v3 = &plr[v1].InvList[0]._iMiscId; + v4 = v2; + do + { + if ( *(v3 - 53) != -1 && (*v3 == IMISC_SCROLL || *v3 == IMISC_SCROLLT) && v3[34] ) + { + v5 = (__int64)1 << (*((_BYTE *)v3 + 4) - 1); + plr[v1]._pScrlSpells[0] |= v5; + plr[v1]._pScrlSpells[1] |= HIDWORD(v5); + } + v3 += 92; + --v4; + } + while ( v4 ); + } + v6 = &plr[v1].SpdList[0]._iMiscId; + v7 = 8; + do + { + if ( *(v6 - 53) != -1 && (*v6 == IMISC_SCROLL || *v6 == IMISC_SCROLLT) && v6[34] ) + { + v8 = (__int64)1 << (*((_BYTE *)v6 + 4) - 1); + plr[v1]._pScrlSpells[0] |= v8; + plr[v1]._pScrlSpells[1] |= HIDWORD(v8); + } + v6 += 92; + --v7; + } + while ( v7 ); + if ( _LOBYTE(plr[v1]._pRSplType) == 2 ) + { + v9 = 1 << (_LOBYTE(plr[v1]._pRSpell) - 1); + if ( !(plr[v1]._pScrlSpells[1] & HIDWORD(v9) | plr[v1]._pScrlSpells[0] & (unsigned int)v9) ) + { + plr[v1]._pRSpell = -1; + _LOBYTE(plr[v1]._pRSplType) = 4; + drawpanflag = 255; + } + } +} +// 52571C: using guessed type int drawpanflag; + +void __fastcall CalcPlrStaff(int pnum) +{ + int v1; // esi + bool v2; // zf + signed __int64 v3; // rax + + v1 = pnum; + v2 = plr[pnum].InvBody[4]._itype == ITYPE_NONE; + plr[v1]._pISpells[0] = 0; + plr[v1]._pISpells[1] = 0; + if ( !v2 && plr[v1].InvBody[4]._iStatFlag && plr[v1].InvBody[4]._iCharges > 0 ) + { + v3 = (__int64)1 << (_LOBYTE(plr[v1].InvBody[4]._iSpell) - 1); + plr[v1]._pISpells[0] = v3; + plr[v1]._pISpells[1] = HIDWORD(v3); + } +} + +void __fastcall CalcSelfItems(int pnum) +{ + PlayerStruct *v1; // ecx + int v2; // edx + int v3; // esi + int v4; // edi + int *v5; // eax + signed int v6; // ebx + bool v7; // zf + char *v8; // eax + signed int v9; // [esp+Ch] [ebp-10h] + signed int v10; // [esp+10h] [ebp-Ch] + int v11; // [esp+14h] [ebp-8h] + signed int v12; // [esp+18h] [ebp-4h] + + v1 = &plr[pnum]; + v2 = 0; + v3 = 0; + v4 = 0; + v5 = &v1->InvBody[0]._iStatFlag; + v6 = 7; + do + { + if ( *(v5 - 87) != -1 ) + { + v7 = *(v5 - 75) == 0; + *v5 = 1; + if ( !v7 ) + { + v2 += *(v5 - 25); + v3 += *(v5 - 24); + v4 += *(v5 - 23); + } + } + v5 += 92; + --v6; + } + while ( v6 ); + v11 = v4; + do + { + v9 = 0; + v8 = &v1->InvBody[0]._iMinStr; + v10 = 7; + do + { + if ( *((_DWORD *)v8 - 86) != -1 && *((_DWORD *)v8 + 1) ) + { + v12 = 1; + if ( v2 + v1->_pBaseStr < *v8 ) + v12 = 0; + if ( v3 + v1->_pBaseMag < (unsigned char)v8[1] ) + v12 = 0; + if ( v11 + v1->_pBaseDex < v8[2] ) + v12 = 0; + if ( !v12 ) + { + v7 = *((_DWORD *)v8 - 74) == 0; + v9 = 1; + *((_DWORD *)v8 + 1) = 0; + if ( !v7 ) + { + v2 -= *((_DWORD *)v8 - 24); + v3 -= *((_DWORD *)v8 - 23); + v11 -= *((_DWORD *)v8 - 22); + } + } + } + v8 += 368; + --v10; + } + while ( v10 ); + } + while ( v9 ); +} + +void __fastcall CalcPlrItemMin(int pnum) +{ + PlayerStruct *v1; // ecx + PlayerStruct *v2; // esi + ItemStruct *v3; // edi + int v4; // ebp + ItemStruct *v6; // edi + signed int v7; // ebp + + v1 = &plr[pnum]; + v2 = v1; + v3 = v1->InvList; + if ( v1->_pNumInv ) + { + v4 = v1->_pNumInv; + do + { + v3->_iStatFlag = ItemMinStats(v2, v3); + ++v3; + --v4; + } + while ( v4 ); + } + v6 = v2->SpdList; + v7 = 8; + do + { + if ( v6->_itype != -1 ) + { + v6->_iStatFlag = ItemMinStats(v2, v6); + } + ++v6; + --v7; + } + while ( v7 ); +} + +bool __fastcall ItemMinStats(PlayerStruct *p, ItemStruct *x) +{ + if ( p->_pStrength < x->_iMinStr || p->_pMagic < x->_iMinMag || p->_pDexterity < x->_iMinDex ) + return 0; + else + return 1; +} + +void __fastcall CalcPlrBookVals(int p) +{ + int v1; // esi + int v2; // ebx + int *v3; // edi + int v5; // esi + int *v6; // edi + int v7; // eax + unsigned char v8; // cl + unsigned char v9; // cl + int v10; // eax + int v12; // [esp+Ch] [ebp-Ch] + int v13; // [esp+10h] [ebp-8h] + unsigned char v14; // [esp+17h] [ebp-1h] + + v1 = p; + if ( !currlevel ) + { + v2 = 1; + if ( witchitem[1]._itype != -1 ) + { + v3 = &witchitem[1]._iStatFlag; + do + { + WitchBookLevel(v2); + *v3 = StoreStatOk((ItemStruct *)(v3 - 89)); + v3 += 92; + ++v2; + } + while ( *(v3 - 87) != -1 ); + } + } + v5 = v1; + v12 = 0; + if ( plr[v5]._pNumInv > 0 ) + { + v6 = &plr[v5].InvList[0]._iSpell; + do + { + if ( !*(v6 - 54) && *(v6 - 1) == 24 ) + { + v7 = *v6; + v8 = spelldata[*v6].sMinInt; + *((_BYTE *)v6 + 129) = v8; + v13 = plr[0]._pSplLvl[v7 + v5 * 21720]; + if ( plr[0]._pSplLvl[v7 + v5 * 21720] ) + { + do + { + v9 = 20 * v8 / 100 + v8; + --v13; + v14 = v9; + v10 = v9 + 20 * v9 / 100; + v8 = -1; + if ( v10 <= 255 ) + v8 = v14; + else + v13 = 0; + } + while ( v13 ); + *((_BYTE *)v6 + 129) = v8; + } + v6[33] = ItemMinStats(&plr[v5], (ItemStruct *)(v6 - 56)); + } + ++v12; + v6 += 92; + } + while ( v12 < plr[v5]._pNumInv ); + } +} + +void __fastcall CalcPlrInv(int p, BOOL Loadgfx) +{ + CalcPlrItemMin(p); + CalcSelfItems(p); + CalcPlrItemVals(p, Loadgfx); + CalcPlrItemMin(p); + if ( p == myplr ) + { + CalcPlrBookVals(p); + CalcPlrScrolls(p); + CalcPlrStaff(p); + if ( p == myplr && !currlevel ) + RecalcStoreStats(); + } +} + +void __fastcall SetPlrHandItem(ItemStruct *h, int idata) +{ + ItemDataStruct *pAllItem; + + pAllItem = &AllItemsList[idata]; + + // zero-initialize struct + memset(h, 0, sizeof(*h)); + + h->_itype = pAllItem->itype; + h->_iCurs = pAllItem->iCurs; + strcpy(h->_iName, pAllItem->iName); + strcpy(h->_iIName, pAllItem->iName); + h->_iLoc = pAllItem->iLoc; + h->_iClass = pAllItem->iClass; + h->_iMinDam = pAllItem->iMinDam; + h->_iMaxDam = pAllItem->iMaxDam; + h->_iAC = pAllItem->iMinAC; + h->_iMiscId = pAllItem->iMiscId; + h->_iSpell = pAllItem->iSpell; + + if ( pAllItem->iMiscId == IMISC_STAFF ) + { + h->_iCharges = 40; + } + + h->_iMaxCharges = h->_iCharges; + h->_iDurability = pAllItem->iDurability; + h->_iMaxDur = pAllItem->iDurability; + h->_iMinStr = pAllItem->iMinStr; + h->_iMinMag = pAllItem->iMinMag; + h->_iMinDex = pAllItem->iMinDex; + h->_ivalue = pAllItem->iValue; + h->_iIvalue = pAllItem->iValue; + h->_iPrePower = -1; + h->_iSufPower = -1; + h->_iMagical = 0; + h->IDidx = idata; +} + +void __fastcall GetPlrHandSeed(ItemStruct *h) +{ + h->_iSeed = GetRndSeed(); +} + +void __fastcall GetGoldSeed(int pnum, ItemStruct *h) +{ + int v3; // edi + signed int v4; // esi + int v5; // eax + int i; // ecx + int v7; // edx + ItemStruct *v8; // ecx + + v3 = pnum; + do + { + v4 = 1; + v5 = GetRndSeed(); + for ( i = 0; i < numitems; ++i ) + { + if ( item[itemactive[i]]._iSeed == v5 ) + v4 = 0; + } + if ( v3 == myplr ) + { + v7 = plr[v3]._pNumInv; + if ( v7 > 0 ) + { + v8 = plr[v3].InvList; + do + { + if ( v8->_iSeed == v5 ) + v4 = 0; + ++v8; + --v7; + } + while ( v7 ); + } + } + } + while ( !v4 ); + h->_iSeed = v5; +} + +void __fastcall SetPlrHandSeed(ItemStruct *h, int iseed) +{ + h->_iSeed = iseed; +} + +void __fastcall SetPlrHandGoldCurs(ItemStruct *h) +{ + int v1; // eax + + v1 = h->_ivalue; + if ( v1 < 2500 ) + { + if ( v1 > 1000 ) + h->_iCurs = 5; + else + h->_iCurs = 4; + } + else + { + h->_iCurs = 6; + } +} + +void __fastcall CreatePlrItems(int p) +{ + int i; + ItemStruct *pi = plr[p].InvBody; + + for ( i = 0; i < NUM_INVLOC; i++ ) + { + pi[i]._itype = ITYPE_NONE; + } + + // converting this to a for loop creates a `rep stosd` instruction, + // so this probably actually was a memset + memset(&plr[p].InvGrid, 0, sizeof(plr[p].InvGrid)); + + pi = plr[p].InvList; + for ( i = 0; i < NUM_INV_GRID_ELEM; i++ ) + { + pi[i]._itype = ITYPE_NONE; + } + + plr[p]._pNumInv = 0; + + pi = plr[p].SpdList; + // TODO: define/const for that 8 + for ( i = 0; i < 8; i++ ) + { + pi[i]._itype = ITYPE_NONE; + } + + switch ( plr[p]._pClass ) + { + case PC_WARRIOR: + SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_WARRIOR); + GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]); + + SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_RIGHT], IDI_WARRSHLD); + GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_RIGHT]); + + // TODO: Add debug logic from 1.00 here + + SetPlrHandItem(&plr[p].HoldItem, IDI_WARRCLUB); + GetPlrHandSeed(&plr[p].HoldItem); + AutoPlace(p, 0, 1, 3, 1); + + SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL); + GetPlrHandSeed(&plr[p].SpdList[0]); + + SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL); + GetPlrHandSeed(&plr[p].SpdList[1]); + break; + case PC_ROGUE: + SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_ROGUE); + GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]); + + SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL); + GetPlrHandSeed(&plr[p].SpdList[0]); + + SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL); + GetPlrHandSeed(&plr[p].SpdList[1]); + break; + case PC_SORCERER: + SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_SORCEROR); + GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]); + + SetPlrHandItem(&plr[p].SpdList[0], IDI_MANA); + GetPlrHandSeed(&plr[p].SpdList[0]); + + SetPlrHandItem(&plr[p].SpdList[1], IDI_MANA); + GetPlrHandSeed(&plr[p].SpdList[1]); + break; + } + + SetPlrHandItem(&plr[p].HoldItem, IDI_GOLD); + GetPlrHandSeed(&plr[p].HoldItem); + + // TODO: Add debug logic from 1.00 here + + plr[p].HoldItem._iCurs = CURSOR_RECHARGE; + plr[p].HoldItem._ivalue = 100; + plr[p]._pGold = 100; + + plr[p].InvList[plr[p]._pNumInv++] = plr[p].HoldItem; + plr[p].InvGrid[30] = plr[p]._pNumInv; + + CalcPlrItemVals(p, FALSE); +} + +BOOL __fastcall ItemSpaceOk(int i, int j) +{ + int v2; // eax + int v3; // esi + char v4; // cl + int v5; // ecx + char v6; // cl + bool v7; // sf + char v8; // cl + char v9; // al + + if ( i < 0 ) + return 0; + if ( i >= 112 ) + return 0; + if ( j < 0 ) + return 0; + if ( j >= 112 ) + return 0; + v2 = i; + v3 = 112 * i + j; + if ( dMonster[0][v3] || dPlayer[v2][j] || dItem[v2][j] ) + return 0; + v4 = dObject[v2][j]; + if ( v4 ) + { + v5 = v4 <= 0 ? -1 - v4 : v4 - 1; + if ( object[v5]._oSolidFlag ) + return 0; + } + v6 = dObject[v2 + 1][j + 1]; + v7 = v6 < 0; + if ( v6 > 0 ) + { + if ( object[v6-1]._oSelFlag ) /* check */ + return 0; + v7 = v6 < 0; + } + if ( !v7 || !object[-(v6 + 1)]._oSelFlag ) + { + v8 = dObject[v2 + 1][j]; + if ( v8 <= 0 ) + return nSolidTable[dPiece[0][v3]] == 0; + v9 = dObject[v2][j + 1]; + if ( v9 <= 0 || !object[v8-1]._oSelFlag || !object[v9-1]._oSelFlag ) + return nSolidTable[dPiece[0][v3]] == 0; + } + return 0; +} + +bool __fastcall GetItemSpace(int x, int y, char inum) +{ + int v3; // eax + int v4; // edx + BOOL *v5; // edi + int v6; // ebx + BOOL *v7; // esi + signed int v9; // esi + BOOL *v10; // eax + int v11; // ecx + int v12; // eax + int v14; // ecx + int v15; // edx + int v16; // eax + int v17; // esi + int v18; // ecx + int v19; // [esp+8h] [ebp-Ch] + int v20; // [esp+Ch] [ebp-8h] + BOOL *v21; // [esp+10h] [ebp-4h] + + v3 = y; + v19 = y; + v4 = y - 1; + v20 = x; + v5 = itemhold[0]; + if ( v4 <= v19 + 1 ) + { + v21 = itemhold[0]; + do + { + v6 = x - 1; + if ( (unsigned char)(__OFSUB__(x - 1, x + 1) ^ 1) | (x - 1 == x + 1) ) + { + v7 = v21; + do + { + *v7 = ItemSpaceOk(v6, v4); + v7 += 3; + ++v6; + } + while ( v6 <= v20 + 1 ); + v3 = v19; + x = v20; + } + ++v21; + ++v4; + } + while ( v4 <= v3 + 1 ); + } + v9 = 0; + do + { + v10 = v5; + v11 = 3; + do + { + if ( *v10 ) + v9 = 1; + v10 += 3; + --v11; + } + while ( v11 ); + ++v5; + } + while ( v5 < itemhold[1] ); + v12 = random(13, 15) + 1; + if ( !v9 ) + return 0; + v14 = 0; + v15 = 0; + if ( v12 > 0 ) + { + while ( 1 ) + { + if (itemhold[v14][v15]) + --v12; + if ( v12 <= 0 ) + break; + if ( ++v14 == 3 ) + { + v14 = 0; + if ( ++v15 == 3 ) + v15 = 0; + } + } + } + v16 = v14 + v20 - 1; + v17 = v15 + v19 - 1; + v18 = inum; + item[v18]._ix = v16; + dItem[v16][v17] = inum + 1; + item[v18]._iy = v17; + return 1; +} + +void __fastcall GetSuperItemSpace(int x, int y, char inum) +{ + signed int v4; // edi + signed int v5; // ebx + int v6; // edx + int v7; // esi + int v9; // eax + int v10; // [esp+Ch] [ebp-10h] + int v11; // [esp+10h] [ebp-Ch] + signed int v12; // [esp+14h] [ebp-8h] + signed int v13; // [esp+18h] [ebp-4h] + + v11 = y; + v10 = x; + if ( !GetItemSpace(x, y, inum) ) + { + v13 = 2; + v4 = -2; + do + { + v5 = v4; + if ( v4 <= v13 ) + { + while ( 2 ) + { + v12 = v4; + v6 = v5 + v11; + v7 = v4 + v10; + do + { + if ( ItemSpaceOk(v7, v6) ) + { + v9 = inum; + item[v9]._ix = v7; + item[v9]._iy = v6; + dItem[v7][v6] = inum + 1; + return; + } + ++v12; + ++v7; + } + while ( v12 <= v13 ); + if ( ++v5 <= v13 ) + continue; + break; + } + } + ++v13; + --v4; + } + while ( v4 > -50 ); + } +} + +void __fastcall GetSuperItemLoc(int x, int y, int *xx, int *yy) +{ + signed int v4; // edi + signed int v5; // ebx + int v6; // esi + int v8; // [esp+Ch] [ebp-10h] + int v9; // [esp+10h] [ebp-Ch] + signed int v10; // [esp+14h] [ebp-8h] + signed int v11; // [esp+18h] [ebp-4h] + + v9 = y; + v8 = x; + v11 = 1; + v4 = -1; + while ( 1 ) + { + v5 = v4; + if ( v4 <= v11 ) + break; +LABEL_7: + ++v11; + if ( --v4 <= -50 ) + return; + } +LABEL_3: + v10 = v4; + *yy = v5 + v9; + v6 = v4 + v8; + while ( 1 ) + { + *xx = v6; + if ( ItemSpaceOk(v6, *yy) ) + break; + ++v10; + ++v6; + if ( v10 > v11 ) + { + if ( ++v5 <= v11 ) + goto LABEL_3; + goto LABEL_7; + } + } +} + +void __fastcall CalcItemValue(int i) +{ + int v1; // ecx + int v2; // esi + bool v3; // sf + int v4; // esi + + v1 = i; + v2 = item[v1]._iVMult1 + item[v1]._iVMult2; + v3 = v2 < 0; + if ( v2 > 0 ) + { + v2 *= item[v1]._ivalue; + v3 = v2 < 0; + } + if ( v3 ) + v2 = item[v1]._ivalue / v2; + v4 = item[v1]._iVAdd1 + item[v1]._iVAdd2 + v2; + if ( v4 <= 0 ) + v4 = 1; + item[v1]._iIvalue = v4; +} + +void __fastcall GetBookSpell(int i, int lvl) +{ + int v2; // edi + int v3; // esi + int v4; // eax + int v5; // edx + signed int v6; // ecx + int v7; // esi + const char **v8; // ebx + int v9; // eax + char v10; // al + int v11; // [esp+8h] [ebp-4h] + + v2 = lvl; + v3 = i; + if ( !lvl ) + v2 = lvl + 1; + v4 = random(14, 37) + 1; +LABEL_13: + v6 = 1; + while ( v4 > 0 ) + { + v5 = spelldata[v6].sBookLvl; + if ( v5 != -1 && v2 >= v5 ) + { + --v4; + v11 = v6; + } + ++v6; + if ( gbMaxPlayers == 1 ) + { + if ( v6 == SPL_RESURRECT ) + v6 = SPL_TELEKINESIS; + if ( v6 == SPL_HEALOTHER ) + v6 = SPL_FLARE; + } + if ( v6 == 37 ) + goto LABEL_13; + } + v7 = v3; + v8 = (const char **)&spelldata[v11].sNameText; + strcat(item[v7]._iName, *v8); + strcat(item[v7]._iIName, *v8); + item[v7]._iSpell = v11; + item[v7]._iMinMag = spelldata[v11].sMinInt; + v9 = spelldata[v11].sBookCost; + item[v7]._ivalue += v9; + item[v7]._iIvalue += v9; + v10 = spelldata[v11].sType; + if ( v10 == STYPE_FIRE ) + item[v7]._iCurs = 87; // Red Book + if ( v10 == STYPE_LIGHTNING ) + item[v7]._iCurs = 88; // Blue Book + if ( v10 == STYPE_MAGIC ) + item[v7]._iCurs = 86; // Black Book +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall GetStaffPower(int i, int lvl, int bs, unsigned char onlygood) +{ + int v4; // esi + int v5; // ebx + int v6; // edx + int v7; // ecx + int v9; // edi + int v10; // ecx + int v11; // ST14_4 + int v12; // esi + char *v13; // edi + int l[256]; // [esp+Ch] [ebp-484h] + char istr[128]; // [esp+40Ch] [ebp-84h] + int ia; // [esp+48Ch] [ebp-4h] + char *v17; // [esp+49Ch] [ebp+Ch] + + v4 = lvl; + ia = i; + v5 = -1; + if ( !random(15, 10) || onlygood ) + { + v6 = 0; + v7 = 0; + if ( PL_Prefix[0].PLPower != -1 ) + { + do + { + if ( PL_Prefix[v7].PLIType & 0x100 && PL_Prefix[v7].PLMinLvl <= v4 && (!onlygood || PL_Prefix[v7].PLOk) ) + { + l[v6++] = v7; + if ( PL_Prefix[v7].PLDouble ) + l[v6++] = v7; + } + ++v7; + } + while ( PL_Prefix[v7].PLPower != -1 ); + if ( v6 ) + { + v5 = l[random(16, v6)]; + v9 = ia; + v17 = item[ia]._iIName; + sprintf(istr, "%s %s", PL_Prefix[v5].PLName, item[ia]._iIName); + strcpy(v17, istr); + v10 = ia; + v11 = PL_Prefix[v5].PLMultVal; + item[v9]._iMagical = 1; + SaveItemPower( + v10, + PL_Prefix[v5].PLPower, + PL_Prefix[v5].PLParam1, + PL_Prefix[v5].PLParam2, + PL_Prefix[v5].PLMinVal, + PL_Prefix[v5].PLMaxVal, + v11); + item[v9]._iPrePower = PL_Prefix[v5].PLPower; + } + } + } + v12 = ia; + v13 = item[ia]._iIName; + if ( !control_WriteStringToBuffer(item[ia]._iIName) ) + { + strcpy(v13, AllItemsList[item[v12].IDidx].iSName); + if ( v5 != -1 ) + { + sprintf(istr, "%s %s", PL_Prefix[v5].PLName, v13); + strcpy(v13, istr); + } + sprintf(istr, "%s of %s", v13, spelldata[bs].sNameText); + strcpy(v13, istr); + if ( !item[v12]._iMagical ) + strcpy(item[v12]._iName, v13); + } + CalcItemValue(ia); +} +// 420514: using guessed type int var_484[256]; + +void __fastcall GetStaffSpell(int i, int lvl, unsigned char onlygood) +{ + int l; // esi + int rv; // eax + int s; // ecx + int minc; // ebx + int maxc; // edx + int v; // eax + char istr[64]; // [esp+4h] [ebp-4Ch] + int bs; // [esp+4Ch] [ebp-4h] + + if ( random(17, 4) ) + { + l = lvl >> 1; + if ( !l ) + l = 1; + rv = random(18, 37) + 1; +LABEL_15: + s = 1; + while ( rv > 0 ) + { + if ( spelldata[s].sStaffLvl != -1 && l >= spelldata[s].sStaffLvl ) + { + --rv; + bs = s; + } + ++s; + if ( gbMaxPlayers == 1 ) + { + if ( s == SPL_RESURRECT ) + s = SPL_TELEKINESIS; + if ( s == SPL_HEALOTHER ) + s = SPL_FLARE; + } + if ( s == 37 ) + goto LABEL_15; + } + sprintf(istr, "%s of %s", item[i]._iName, spelldata[bs].sNameText); + if ( !control_WriteStringToBuffer(istr) ) + sprintf(istr, "Staff of %s", spelldata[bs].sNameText); + strcpy(item[i]._iName, istr); + strcpy(item[i]._iIName, istr); + minc = spelldata[bs].sStaffMin; + maxc = spelldata[bs].sStaffMax - minc + 1; + item[i]._iSpell = bs; + v = random(19, maxc) + minc; + item[i]._iMinMag = spelldata[bs].sMinInt; + item[i]._iCharges = v; + item[i]._iMaxCharges = v; + v = (v * spelldata[bs].sStaffCost) / 5; + item[i]._ivalue += v; + item[i]._iIvalue += v; + GetStaffPower(i, lvl, bs, onlygood); + } + else + { + GetItemPower(i, lvl >> 1, lvl, 256, onlygood); + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall GetItemAttrs(int i, int idata, int lvl) +{ + int rndv; // eax + + item[i]._itype = AllItemsList[idata].itype; + item[i]._iCurs = AllItemsList[idata].iCurs; + strcpy(item[i]._iName, AllItemsList[idata].iName); + strcpy(item[i]._iIName, AllItemsList[idata].iName); + item[i]._iLoc = AllItemsList[idata].iLoc; + item[i]._iClass = AllItemsList[idata].iClass; + item[i]._iMinDam = AllItemsList[idata].iMinDam; + item[i]._iMaxDam = AllItemsList[idata].iMaxDam; + item[i]._iMiscId = AllItemsList[idata].iMiscId; + item[i]._iAC = AllItemsList[idata].iMinAC + random(20, AllItemsList[idata].iMaxAC - AllItemsList[idata].iMinAC + 1); + item[i]._iFlags = AllItemsList[idata].iFlags; + item[i]._iSpell = AllItemsList[idata].iSpell; + item[i]._ivalue = AllItemsList[idata].iValue; + item[i]._iIvalue = AllItemsList[idata].iValue; + item[i]._iMagical = 0; + item[i]._iDurability = AllItemsList[idata].iDurability; + item[i]._iMaxDur = AllItemsList[idata].iDurability; + item[i]._iVAdd1 = 0; + item[i]._iMinStr = AllItemsList[idata].iMinStr; + item[i]._iMinMag = AllItemsList[idata].iMinMag; + item[i]._iMinDex = AllItemsList[idata].iMinDex; + item[i]._iVMult1 = 0; + item[i]._iVAdd2 = 0; + item[i]._iVMult2 = 0; + item[i]._iPLDam = 0; + item[i]._iPLToHit = 0; + item[i]._iPLAC = 0; + item[i]._iPLStr = 0; + item[i]._iPLMag = 0; + item[i]._iPLDex = 0; + item[i]._iPLVit = 0; + item[i]._iCharges = 0; + item[i]._iMaxCharges = 0; + item[i]._iPLFR = 0; + item[i]._iPLLR = 0; + item[i]._iPLMR = 0; + item[i].IDidx = idata; + item[i]._iPLDamMod = 0; + item[i]._iPLGetHit = 0; + item[i]._iPLLight = 0; + item[i]._iSplLvlAdd = 0; + item[i]._iPrePower = -1; + item[i]._iSufPower = -1; + item[i]._iRequest = 0; + item[i]._iFMinDam = 0; + item[i]._iFMaxDam = 0; + item[i]._iLMinDam = 0; + item[i]._iLMaxDam = 0; + item[i]._iPLEnAc = 0; + item[i]._iPLMana = 0; + item[i]._iPLHP = 0; + + if ( AllItemsList[idata].iMiscId == IMISC_BOOK ) + GetBookSpell(i, lvl); + + if ( item[i]._itype == ITYPE_GOLD ) + { + if ( gnDifficulty ) /* clean this up, NORMAL */ + rndv = lvl; + else + rndv = 5 * currlevel + random(21, 10 * currlevel); + + if ( gnDifficulty == DIFF_NIGHTMARE ) + rndv = 5 * (currlevel + 16) + random(21, 10 * (currlevel + 16)); + if ( gnDifficulty == DIFF_HELL ) + rndv = 5 * (currlevel + 32) + random(21, 10 * (currlevel + 32)); + + if ( leveltype == DTYPE_HELL ) + rndv += rndv >> 3; + if ( rndv > 5000 ) + rndv = 5000; + + item[i]._ivalue = rndv; + + if ( rndv < 2500 ) + item[i]._iCurs = (rndv > 1000) + 4; + else + item[i]._iCurs = 6; + } +} +// 5BB1ED: using guessed type char leveltype; + +int __fastcall RndPL(int param1, int param2) +{ + return param1 + random(22, param2 - param1 + 1); +} + +int __fastcall PLVal(int pv, int p1, int p2, int minv, int maxv) +{ + if ( p1 == p2 ) + return minv; + if ( minv == maxv ) + return minv; + return minv + (maxv - minv) * (100 * (pv - p1) / (p2 - p1)) / 100; +} + +void __fastcall SaveItemPower(int i, int power, int param1, int param2, int minval, int maxval, int multval) +{ + int v7; // edi + int v8; // esi + int v9; // eax + int v10; // ebx + int *v11; // eax + int *v12; // eax + int v13; // edi + int v14; // eax + int v15; // edi + int v16; // eax + int v17; // eax + int v18; // ecx + int v19; // edx + int v20; // edi + int *v21; // edx + int v22; // eax + int v23; // eax + int v24; // eax + int v25; // eax + int v26; // eax + int v27; // eax + int v28; // ecx + int *v29; // eax + int v30; // ecx + int *v31; // eax + int v32; // ecx + int v33; // eax + int v34; // ST18_4 + int v35; // eax + int v36; // ecx + int v37; // edx + signed int v38; // ecx + int v39; // eax + int v40; // eax + int v41; // ecx + int *v42; // eax + int v43; // esi + + v7 = power; + v8 = i; + v9 = RndPL(param1, param2); + v10 = v9; + switch ( v7 ) + { + case IPL_TOHIT: + v11 = &item[v8]._iPLToHit; + goto LABEL_115; + case IPL_TOHIT_CURSE: + v12 = &item[v8]._iPLToHit; + goto LABEL_62; + case IPL_DAMP: + v11 = &item[v8]._iPLDam; + goto LABEL_115; + case IPL_DAMP_CURSE: + v12 = &item[v8]._iPLDam; + goto LABEL_62; + case IPL_TOHIT_DAMP: + v10 = RndPL(param1, param2); + v13 = v8; + item[v13]._iPLDam += v10; + if ( param1 == 20 ) + v14 = RndPL(1, 5); + else + v14 = param1; + if ( param1 == 36 ) + v14 = RndPL(6, 10); + if ( param1 == 51 ) + v14 = RndPL(11, 15); + if ( param1 == 66 ) + v14 = RndPL(16, 20); + if ( param1 == 81 ) + v14 = RndPL(21, 30); + if ( param1 == 96 ) + v14 = RndPL(31, 40); + if ( param1 == 111 ) + v14 = RndPL(41, 50); + if ( param1 == 126 ) + v14 = RndPL(51, 75); + if ( param1 == 151 ) + v14 = RndPL(76, 100); + item[v13]._iPLToHit += v14; + break; + case IPL_TOHIT_DAMP_CURSE: + v15 = v8; + item[v15]._iPLDam -= v9; + if ( param1 == 25 ) + v16 = RndPL(1, 5); + else + v16 = param1; + if ( param1 == 50 ) + v16 = RndPL(6, 10); + item[v15]._iPLToHit -= v16; + break; + case IPL_ACP: + v11 = &item[v8]._iPLAC; + goto LABEL_115; + case IPL_ACP_CURSE: + v12 = &item[v8]._iPLAC; + goto LABEL_62; + case IPL_FIRERES: + v11 = &item[v8]._iPLFR; + goto LABEL_115; + case IPL_LIGHTRES: + v11 = &item[v8]._iPLLR; + goto LABEL_115; + case IPL_MAGICRES: + v11 = &item[v8]._iPLMR; + goto LABEL_115; + case IPL_ALLRES: + v17 = v8; + item[v17]._iPLFR += v10; + v18 = item[v8]._iPLFR; + item[v17]._iPLLR += v10; + item[v17]._iPLMR += v10; + v19 = item[v8]._iPLLR; + v20 = item[v8]._iPLMR; + if ( v18 < 0 ) + item[v17]._iPLFR = 0; + if ( v19 < 0 ) + item[v17]._iPLLR = 0; + if ( v20 < 0 ) + item[v17]._iPLMR = 0; + break; + case IPL_SPLLVLADD: + item[v8]._iSplLvlAdd = v9; + break; + case IPL_CHARGES: + v21 = &item[v8]._iCharges; + v22 = param1 * *v21; + *v21 = v22; + item[v8]._iMaxCharges = v22; + break; + case IPL_FIREDAM: + v24 = v8; + item[v24]._iFlags |= 0x10u; + goto LABEL_77; + case IPL_LIGHTDAM: + v25 = v8; + item[v25]._iFlags |= 0x20u; + goto LABEL_79; + case IPL_STR: + v11 = &item[v8]._iPLStr; + goto LABEL_115; + case IPL_STR_CURSE: + v12 = &item[v8]._iPLStr; + goto LABEL_62; + case IPL_MAG: + v11 = &item[v8]._iPLMag; + goto LABEL_115; + case IPL_MAG_CURSE: + v12 = &item[v8]._iPLMag; + goto LABEL_62; + case IPL_DEX: + v11 = &item[v8]._iPLDex; + goto LABEL_115; + case IPL_DEX_CURSE: + v12 = &item[v8]._iPLDex; + goto LABEL_62; + case IPL_VIT: + v11 = &item[v8]._iPLVit; + goto LABEL_115; + case IPL_VIT_CURSE: + v12 = &item[v8]._iPLVit; + goto LABEL_62; + case IPL_ATTRIBS: + v26 = v8; + item[v26]._iPLStr += v10; + item[v26]._iPLMag += v10; + item[v26]._iPLDex += v10; + item[v26]._iPLVit += v10; + break; + case IPL_ATTRIBS_CURSE: + v27 = v8; + item[v27]._iPLStr -= v10; + item[v27]._iPLMag -= v10; + item[v27]._iPLDex -= v10; + item[v27]._iPLVit -= v10; + break; + case IPL_GETHIT_CURSE: + v11 = &item[v8]._iPLGetHit; + goto LABEL_115; + case IPL_GETHIT: + v12 = &item[v8]._iPLGetHit; + goto LABEL_62; + case IPL_LIFE: + v28 = v9 << 6; + v29 = &item[v8]._iPLHP; + goto LABEL_73; + case IPL_LIFE_CURSE: + v30 = v9 << 6; + v31 = &item[v8]._iPLHP; + goto LABEL_75; + case IPL_MANA: + item[v8]._iPLMana += v9 << 6; + goto LABEL_92; + case IPL_MANA_CURSE: + item[v8]._iPLMana -= v9 << 6; + goto LABEL_92; + case IPL_DUR: + v32 = v8; + v33 = item[v8]._iMaxDur; + v34 = v33; + v35 = v10 * v33 / 100; + item[v32]._iDurability += v35; + item[v32]._iMaxDur = v35 + v34; + break; + case IPL_DUR_CURSE: + v36 = v8; + v37 = item[v8]._iMaxDur - v9 * item[v8]._iMaxDur / 100; + item[v8]._iMaxDur = v37; + if ( v37 < 1 ) + item[v36]._iMaxDur = 1; + item[v36]._iDurability = item[v36]._iMaxDur; + break; + case IPL_INDESTRUCTIBLE: + v38 = 255; + goto LABEL_119; + case IPL_LIGHT: + v28 = param1; + v29 = &item[v8]._iPLLight; +LABEL_73: + *v29 += v28; + break; + case IPL_LIGHT_CURSE: + v30 = param1; + v31 = &item[v8]._iPLLight; +LABEL_75: + *v31 -= v30; + break; + case IPL_FIRE_ARROWS: + v24 = v8; + item[v24]._iFlags |= 8u; +LABEL_77: + item[v24]._iFMinDam = param1; + item[v24]._iFMaxDam = param2; + break; + case IPL_LIGHT_ARROWS: + v25 = v8; + _HIBYTE(item[v8]._iFlags) |= 2u; +LABEL_79: + item[v25]._iLMinDam = param1; + item[v25]._iLMaxDam = param2; + break; + case IPL_INVCURS: + item[v8]._iCurs = param1; + break; + case IPL_THORNS: + _HIBYTE(item[v8]._iFlags) |= 4u; + break; + case IPL_NOMANA: + _HIBYTE(item[v8]._iFlags) |= 8u; + goto LABEL_92; + case IPL_NOHEALPLR: + BYTE1(item[v8]._iFlags) |= 1u; + break; + case IPL_ABSHALFTRAP: + _HIBYTE(item[v8]._iFlags) |= 0x10u; + break; + case IPL_KNOCKBACK: + BYTE1(item[v8]._iFlags) |= 8u; + break; + case IPL_NOHEALMON: + BYTE1(item[v8]._iFlags) |= 0x10u; + break; + case IPL_STEALMANA: + if ( param1 == 3 ) + BYTE1(item[v8]._iFlags) |= 0x20u; + if ( param1 == 5 ) + BYTE1(item[v8]._iFlags) |= 0x40u; +LABEL_92: + drawmanaflag = 1; + break; + case IPL_STEALLIFE: + if ( param1 == 3 ) + BYTE1(item[v8]._iFlags) |= 0x80u; + if ( param1 == 5 ) + BYTE2(item[v8]._iFlags) |= 1u; + drawhpflag = 1; + break; + case IPL_TARGAC: + v11 = &item[v8]._iPLEnAc; + goto LABEL_115; + case IPL_FASTATTACK: + if ( param1 == 1 ) + BYTE2(item[v8]._iFlags) |= 2u; + if ( param1 == 2 ) + BYTE2(item[v8]._iFlags) |= 4u; + if ( param1 == 3 ) + BYTE2(item[v8]._iFlags) |= 8u; + if ( param1 == 4 ) + BYTE2(item[v8]._iFlags) |= 0x10u; + break; + case IPL_FASTRECOVER: + if ( param1 == 1 ) + BYTE2(item[v8]._iFlags) |= 0x20u; + if ( param1 == 2 ) + BYTE2(item[v8]._iFlags) |= 0x40u; + if ( param1 == 3 ) + BYTE2(item[v8]._iFlags) |= 0x80u; + break; + case IPL_FASTBLOCK: + _HIBYTE(item[v8]._iFlags) |= 1u; + break; + case IPL_DAMMOD: + v11 = &item[v8]._iPLDamMod; +LABEL_115: + *v11 += v10; + break; + case IPL_RNDARROWVEL: + item[v8]._iFlags |= 4u; + break; + case IPL_SETDAM: + v39 = v8; + item[v39]._iMinDam = param1; + item[v39]._iMaxDam = param2; + break; + case IPL_SETDUR: + v38 = param1; +LABEL_119: + v40 = v8; + item[v40]._iDurability = v38; + item[v40]._iMaxDur = v38; + break; + case IPL_NOMINSTR: + item[v8]._iMinStr = 0; + break; + case IPL_SPELL: + v23 = v8; + item[v23]._iSpell = param1; + item[v23]._iCharges = param1; + item[v23]._iMaxCharges = param2; + break; + case IPL_FASTSWING: + BYTE2(item[v8]._iFlags) |= 8u; + break; + case IPL_ONEHAND: + item[v8]._iLoc = ILOC_ONEHAND; + break; + case IPL_3XDAMVDEM: + _HIBYTE(item[v8]._iFlags) |= 0x40u; + break; + case IPL_ALLRESZERO: + _HIBYTE(item[v8]._iFlags) |= 0x80u; + break; + case IPL_DRAINLIFE: + item[v8]._iFlags |= 0x40u; + break; + case IPL_RNDSTEALLIFE: + item[v8]._iFlags |= 2u; + break; + case IPL_INFRAVISION: + item[v8]._iFlags |= 1u; + break; + case IPL_SETAC: + item[v8]._iAC = v9; + break; + case IPL_ADDACLIFE: + item[v8]._iPLHP = (plr[myplr]._pIBonusAC + plr[myplr]._pIAC + plr[myplr]._pDexterity / 5) << 6; + break; + case IPL_ADDMANAAC: + item[v8]._iAC += (plr[myplr]._pMaxManaBase >> 6) / 10; + break; + case IPL_FIRERESCLVL: + v41 = 30 - plr[myplr]._pLevel; + v42 = &item[v8]._iPLFR; + *v42 = v41; + if ( v41 < 0 ) + *v42 = 0; + break; + case IPL_AC_CURSE: + v12 = &item[v8]._iAC; +LABEL_62: + *v12 -= v10; + break; + default: + break; + } + v43 = v8; + if ( item[v43]._iVAdd1 || item[v43]._iVMult1 ) + { + item[v43]._iVAdd2 = PLVal(v10, param1, param2, minval, maxval); + item[v43]._iVMult2 = multval; + } + else + { + item[v43]._iVAdd1 = PLVal(v10, param1, param2, minval, maxval); + item[v43]._iVMult1 = multval; + } +} + +void __fastcall GetItemPower(int i, int minlvl, int maxlvl, int flgs, int onlygood) +{ + //int v6; // ecx + int pre; // esi + //int v9; // ecx + unsigned char goe; // bl + int v11; // edx + int v14; // ecx + int l[256]; // [esp+4h] [ebp-494h] + char istr[128]; // [esp+404h] [ebp-94h] + int post; // [esp+488h] [ebp-10h] + int sufidx; // [esp+48Ch] [ebp-Ch] + int preidx; // [esp+490h] [ebp-8h] + + pre = random(23, 4); + post = random(23, 3); + if ( pre && !post ) + { + if ( random(23, 2) ) + post = 1; + else + pre = 0; + } + preidx = -1; + sufidx = -1; + goe = 0; + if ( !onlygood ) + { + if ( random(0, 3) ) + onlygood = 1; + } + if ( !pre ) + { + v11 = 0; + if ( PL_Prefix[0].PLPower != -1 ) + { + v14 = 0; + do + { + if ( flgs & PL_Prefix[v14].PLIType ) + { + if ( PL_Prefix[v14].PLMinLvl >= minlvl && PL_Prefix[v14].PLMinLvl <= maxlvl && (!onlygood || PL_Prefix[v14].PLOk) && (flgs != 256 || PL_Prefix[v14].PLPower != 15) ) + { + l[v11++] = v14; + if ( PL_Prefix[v14].PLDouble ) + l[v11++] = v14; + } + } + v14++; + } + while ( PL_Prefix[v14].PLPower != -1 ); + if ( v11 ) + { + preidx = l[random(23, v11)]; + sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, item[i]._iIName); + strcpy(item[i]._iIName, istr); + item[i]._iMagical = 1; + SaveItemPower( + i, + PL_Prefix[preidx].PLPower, + PL_Prefix[preidx].PLParam1, + PL_Prefix[preidx].PLParam2, + PL_Prefix[preidx].PLMinVal, + PL_Prefix[preidx].PLMaxVal, + PL_Prefix[preidx].PLMultVal); + goe = PL_Prefix[preidx].PLGOE; + item[i]._iPrePower = PL_Prefix[preidx].PLPower; + } + } + } + if ( post ) + { + v11 = 0; + if ( PL_Suffix[0].PLPower != -1 ) + { + v14 = 0; + do + { + if ( flgs & PL_Suffix[v14].PLIType ) + { + if ( PL_Suffix[v14].PLMinLvl >= minlvl && PL_Suffix[v14].PLMinLvl <= maxlvl && (goe | PL_Suffix[v14].PLGOE) != 0x11 && (!onlygood || PL_Suffix[v14].PLOk) ) + l[v11++] = v14; + } + v14++; + } + while ( PL_Suffix[v14].PLPower != -1 ); + if ( v11 ) + { + sufidx = l[random(23, v11)]; + sprintf(istr, "%s of %s", item[i]._iIName, PL_Suffix[sufidx].PLName); + strcpy(item[i]._iIName, istr); + item[i]._iMagical = 1; + SaveItemPower( + i, + PL_Suffix[sufidx].PLPower, + PL_Suffix[sufidx].PLParam1, + PL_Suffix[sufidx].PLParam2, + PL_Suffix[sufidx].PLMinVal, + PL_Suffix[sufidx].PLMaxVal, + PL_Suffix[sufidx].PLMultVal); + item[i]._iSufPower = PL_Suffix[sufidx].PLPower; + } + } + } + if ( !control_WriteStringToBuffer(item[i]._iIName) ) + { + strcpy(item[i]._iIName, AllItemsList[item[i].IDidx].iSName); + if ( preidx != -1 ) + { + sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, item[i]._iIName); + strcpy(item[i]._iIName, istr); + } + if ( sufidx != -1 ) + { + sprintf(istr, "%s of %s", item[i]._iIName, PL_Suffix[sufidx].PLName); + strcpy(item[i]._iIName, istr); + } + } + if ( preidx != -1 || sufidx != -1 ) + CalcItemValue(i); +} +// 4215EF: using guessed type int var_494[256]; + +void __fastcall GetItemBonus(int i, int idata, int minlvl, int maxlvl, int onlygood) +{ + if ( item[i]._iClass != ICLASS_GOLD ) + { + if ( minlvl > 25 ) + minlvl = 25; + + switch ( item[i]._itype ) + { + case ITYPE_SWORD: + case ITYPE_AXE: + case ITYPE_MACE: + GetItemPower(i, minlvl, maxlvl, 0x1000, onlygood); + break; + case ITYPE_BOW: + GetItemPower(i, minlvl, maxlvl, 0x10, onlygood); + break; + case ITYPE_SHIELD: + GetItemPower(i, minlvl, maxlvl, 0x10000, onlygood); + break; + case ITYPE_LARMOR: + case ITYPE_HELM: + case ITYPE_MARMOR: + case ITYPE_HARMOR: + GetItemPower(i, minlvl, maxlvl, 0x100000, onlygood); + break; + case ITYPE_STAFF: + GetStaffSpell(i, maxlvl, onlygood); + break; + case ITYPE_RING: + case ITYPE_AMULET: + GetItemPower(i, minlvl, maxlvl, 1, onlygood); + break; + default: + return; + } + } +} + +void __fastcall SetupItem(int i) +{ + int it; // eax + int il; // eax + + it = ItemCAnimTbl[item[i]._iCurs]; + item[i]._iAnimWidth = 96; + item[i]._iAnimWidth2 = 16; + il = ItemAnimLs[it]; + item[i]._iAnimData = Item2Frm[it]; + item[i]._iAnimLen = il; + item[i]._iIdentified = 0; + item[i]._iPostDraw = 0; + + if ( !plr[myplr].pLvlLoad ) + { + item[i]._iSelFlag = 0; + il = 1; + item[i]._iAnimFlag = 1; + } + else + { + item[i]._iAnimFlag = 0; + item[i]._iSelFlag = 1; + } + + item[i]._iAnimFrame = il; +} + +int __fastcall RndItem(int m) +{ + int ri; // esi + int i; // edx + int ril[512]; // [esp+4h] [ebp-800h] + + if ( (monster[m].MData->mTreasure & 0x8000) != 0 ) + return -1 - (monster[m].MData->mTreasure & 0xFFF); + if ( monster[m].MData->mTreasure & 0x4000 ) + return 0; + + if ( random(24, 100) > 40 ) + return 0; + if ( random(24, 100) > 25 ) + return 1; + + ri = 0; + i = 0; + if ( AllItemsList[0].iLoc != -1 ) + { + do + { + if ( AllItemsList[i].iRnd == 2 && monster[m].mLevel >= AllItemsList[i].iMinMLvl ) + ril[ri++] = i; + if ( AllItemsList[i].iRnd && monster[m].mLevel >= AllItemsList[i].iMinMLvl ) + ril[ri++] = i; + if ( AllItemsList[i].iSpell == SPL_RESURRECT && gbMaxPlayers == 1 ) + --ri; + if ( AllItemsList[i].iSpell == SPL_HEALOTHER && gbMaxPlayers == 1 ) + --ri; + ++i; + } + while ( AllItemsList[i].iLoc != -1 ); + } + + return ril[random(24, ri)] + 1; +} +// 679660: using guessed type char gbMaxPlayers; +// 421A4B: using guessed type int var_800[512]; + +int __fastcall RndUItem(int m) +{ + int ri; // edx + int i; // ebp + bool okflag; // edi + int ril[512]; // [esp+0h] [ebp-800h] + + if ( m != -1 ) + { + if ( (monster[m].MData->mTreasure & 0x8000) != 0 && gbMaxPlayers == 1 ) + return -1 - (monster[m].MData->mTreasure & 0xFFF); + } + ri = 0; + i = 0; + if ( AllItemsList[0].iLoc != -1 ) + { + do + { + okflag = 1; + if ( !AllItemsList[i].iRnd ) + okflag = 0; + if ( m == -1 ) + { + if ( 2 * currlevel - AllItemsList[i].iMinMLvl < 0 ) + okflag = 0; + } + else + { + if ( monster[m].mLevel - AllItemsList[i].iMinMLvl < 0 ) + okflag = 0; + } + if ( !AllItemsList[i].itype ) + okflag = 0; + if ( AllItemsList[i].itype == ITYPE_GOLD ) + okflag = 0; + if ( AllItemsList[i].itype == ITYPE_0E ) + okflag = 0; + if ( AllItemsList[i].iMiscId == IMISC_BOOK ) + okflag = 1; + if ( AllItemsList[i].iSpell == SPL_RESURRECT && gbMaxPlayers == 1 ) + okflag = 0; + if ( AllItemsList[i].iSpell == SPL_HEALOTHER && gbMaxPlayers == 1 ) + okflag = 0; + if ( okflag ) + ril[ri++] = i; + ++i; + } + while ( AllItemsList[i].iLoc != -1 ); + } + + return ril[random(25, ri)]; +} +// 679660: using guessed type char gbMaxPlayers; +// 421B32: using guessed type int var_800[512]; + +int __cdecl RndAllItems() +{ + int ri; // esi + int i; // edi + int ril[512]; // [esp+0h] [ebp-800h] + + if ( random(26, 100) > 25 ) + return 0; + + ri = 0; + i = 0; + if ( AllItemsList[0].iLoc != -1 ) + { + do + { + if ( AllItemsList[i].iRnd && 2 * currlevel >= AllItemsList[i].iMinMLvl ) + ril[ri++] = i; + if ( AllItemsList[i].iSpell == SPL_RESURRECT && gbMaxPlayers == 1 ) + --ri; + if ( AllItemsList[i].iSpell == SPL_HEALOTHER && gbMaxPlayers == 1 ) + --ri; + ++i; + } + while ( AllItemsList[i].iLoc != -1 ); + } + return ril[random(26, ri)]; +} +// 679660: using guessed type char gbMaxPlayers; +// 421C2A: using guessed type int var_800[512]; + +int __fastcall RndTypeItems(int itype, int imid) +{ + int i; // edi + bool okflag; // esi + int ril[512]; // [esp+4h] [ebp-80Ch] + int ri; // [esp+80Ch] [ebp-4h] + + ri = 0; + i = 0; + + if ( AllItemsList[0].iLoc != -1 ) + { + do + { + okflag = 1; + if ( !AllItemsList[i].iRnd ) + okflag = 0; + if ( 2 * currlevel < AllItemsList[i].iMinMLvl ) + okflag = 0; + if ( AllItemsList[i].itype != itype ) + okflag = 0; + if ( imid != -1 && AllItemsList[i].iMiscId != imid ) + okflag = 0; + if ( okflag ) + ril[ri++] = i; + ++i; + } + while ( AllItemsList[i].iLoc != -1 ); + } + + return ril[random(27, ri)]; +} +// 421CB7: using guessed type int var_80C[512]; + +int __fastcall CheckUnique(int i, int lvl, int uper, bool recreate) +{ + int numu; // ebx + int j; // esi + int idata; // eax + char uok[128]; // [esp+8h] [ebp-84h] + + if ( random(28, 100) > uper ) + return -1; + numu = 0; + memset(uok, 0, 0x80u); + + if ( UniqueItemList[0].UIItemId == -1 ) + return -1; + j = 0; + do + { + if ( UniqueItemList[j].UIItemId == AllItemsList[item[i].IDidx].iItemId + && lvl >= UniqueItemList[j].UIMinLvl + && (recreate || !UniqueItemFlag[j] || gbMaxPlayers != 1) ) + { + uok[j] = 1; + ++numu; + } + j++; + } + while ( UniqueItemList[j].UIItemId != -1 ); + if ( !numu ) + return -1; + + random(29, 10); + idata = 0; + if ( numu > 0 ) + { + while ( 1 ) + { + if ( uok[idata] ) + --numu; + if ( numu <= 0 ) + break; + if ( ++idata == 128 ) + idata = 0; + } + } + return idata; +} +// 679660: using guessed type char gbMaxPlayers; +// 421D41: using guessed type char var_84[128]; + +void __fastcall GetUniqueItem(int i, int uid) +{ + UniqueItemFlag[uid] = 1; + SaveItemPower(i, UniqueItemList[uid].UIPower1, UniqueItemList[uid].UIParam1, UniqueItemList[uid].UIParam2, 0, 0, 1); + + if ( UniqueItemList[uid].UINumPL > 1 ) + SaveItemPower(i, UniqueItemList[uid].UIPower2, UniqueItemList[uid].UIParam3, UniqueItemList[uid].UIParam4, 0, 0, 1); + if ( UniqueItemList[uid].UINumPL > 2 ) + SaveItemPower(i, UniqueItemList[uid].UIPower3, UniqueItemList[uid].UIParam5, UniqueItemList[uid].UIParam6, 0, 0, 1); + if ( UniqueItemList[uid].UINumPL > 3 ) + SaveItemPower(i, UniqueItemList[uid].UIPower4, UniqueItemList[uid].UIParam7, UniqueItemList[uid].UIParam8, 0, 0, 1); + if ( UniqueItemList[uid].UINumPL > 4 ) + SaveItemPower(i, UniqueItemList[uid].UIPower5, UniqueItemList[uid].UIParam9, UniqueItemList[uid].UIParam10, 0, 0, 1); + if ( UniqueItemList[uid].UINumPL > 5 ) + SaveItemPower(i, UniqueItemList[uid].UIPower6, UniqueItemList[uid].UIParam11, UniqueItemList[uid].UIParam12, 0, 0, 1); + + strcpy(item[i]._iIName, UniqueItemList[uid].UIName); + item[i]._iIvalue = UniqueItemList[uid].UIValue; + + if ( item[i]._iMiscId == IMISC_UNIQUE ) + item[i]._iSeed = uid; + + item[i]._iCreateInfo |= 0x0200; + item[i]._iUid = uid; + item[i]._iMagical = 2; +} + +void __fastcall SpawnUnique(int uid, int x, int y) +{ + int ii; // esi + int itype; // edx + + if ( numitems < MAXITEMS ) + { + ii = itemavail[0]; + GetSuperItemSpace(x, y, itemavail[0]); + itype = 0; + itemactive[numitems] = ii; + itemavail[0] = itemavail[-numitems + 126]; /* MAXITEMS */ + + if ( AllItemsList[0].iItemId != UniqueItemList[uid].UIItemId ) + { + while ( AllItemsList[itype].iItemId != UniqueItemList[uid].UIItemId ) + { + itype++; + } + } + + GetItemAttrs(ii, itype, currlevel); + GetUniqueItem(ii, uid); + SetupItem(ii); + ++numitems; + } +} +// 421F5C: could not find valid save-restore pair for esi + +void __fastcall ItemRndDur(int ii) +{ + if ( item[ii]._iDurability && item[ii]._iDurability != 255 ) + item[ii]._iDurability = random(0, item[ii]._iMaxDur >> 1) + (item[ii]._iMaxDur >> 2) + 1; +} + +void __fastcall SetupAllItems(int ii, int idx, int iseed, int lvl, int uper, int onlygood, int recreate, int pregen) +{ + int iblvl; // edi + int uid; // eax + + item[ii]._iSeed = iseed; + SetRndSeed(iseed); + GetItemAttrs(ii, idx, lvl >> 1); + item[ii]._iCreateInfo = lvl; + + if ( pregen ) + item[ii]._iCreateInfo = lvl | 0x8000; + if ( onlygood ) + item[ii]._iCreateInfo |= 0x40; + + if ( uper == 15 ) + item[ii]._iCreateInfo |= 0x80; + else if ( uper == 1 ) + item[ii]._iCreateInfo |= 0x0100; + + if ( item[ii]._iMiscId == IMISC_UNIQUE ) + { + if ( item[ii]._iLoc != ILOC_UNEQUIPABLE ) + GetUniqueItem(ii, iseed); + } + else + { + iblvl = -1; + if ( random(32, 100) > 10 && random(33, 100) > lvl || (iblvl = lvl, lvl == -1) ) + { + + if ( item[ii]._iMiscId != IMISC_STAFF || (iblvl = lvl, lvl == -1) ) + { + if ( item[ii]._iMiscId != IMISC_RING || (iblvl = lvl, lvl == -1) ) + { + if ( item[ii]._iMiscId == IMISC_AMULET ) + iblvl = lvl; + } + } + } + if ( onlygood ) + iblvl = lvl; + if ( uper == 15 ) + iblvl = lvl + 4; + if ( iblvl != -1 ) + { + uid = CheckUnique(ii, iblvl, uper, recreate); + if ( uid == -1 ) + { + GetItemBonus(ii, idx, iblvl >> 1, iblvl, onlygood); + } + else + { + GetUniqueItem(ii, uid); + item[ii]._iCreateInfo |= 0x0200; + } + } + if ( item[ii]._iMagical != 2 ) + ItemRndDur(ii); + } + SetupItem(ii); +} + +void __fastcall SpawnItem(int m, int x, int y, unsigned char sendmsg) +{ + int ii; // edi + int onlygood; // [esp+Ch] [ebp-Ch] + int idx; // [esp+14h] [ebp-4h] + + if ( !monster[m]._uniqtype && ((monster[m].MData->mTreasure & 0x8000) == 0 || gbMaxPlayers == 1) ) + { + if ( quests[1]._qactive == 2 && quests[1]._qvar1 == 5 ) + { + idx = 18; // Brain + quests[1]._qvar1 = 6; + goto LABEL_13; + } + idx = RndItem(m); + if ( !idx ) + return; + if ( idx > 0 ) + { + onlygood = 0; + idx--; + goto LABEL_13; + } +LABEL_10: + SpawnUnique(-1 - idx, x, y); + return; + } + idx = RndUItem(m); + if ( idx < 0 ) + goto LABEL_10; + onlygood = 1; +LABEL_13: + if ( numitems < MAXITEMS ) + { + ii = itemavail[0]; + GetSuperItemSpace(x, y, itemavail[0]); + itemactive[numitems] = ii; + itemavail[0] = itemavail[-numitems + 126]; /* MAXITEMS */ + + if ( !monster[m]._uniqtype ) + SetupAllItems(ii, idx, GetRndSeed(), monster[m].MData->mLevel, 1, onlygood, 0, 0); + else + SetupAllItems(ii, idx, GetRndSeed(), monster[m].MData->mLevel, 15, onlygood, 0, 0); + + ++numitems; + if ( sendmsg ) + NetSendCmdDItem(0, ii); + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall CreateItem(int uid, int x, int y) +{ + int ii; // esi + int idx; // edx + + if ( numitems < MAXITEMS ) + { + ii = itemavail[0]; + GetSuperItemSpace(x, y, itemavail[0]); + idx = 0; + itemactive[numitems] = ii; + itemavail[0] = itemavail[-numitems + 126]; /* MAXITEMS */ + + if ( AllItemsList[0].iItemId != UniqueItemList[uid].UIItemId ) + { + while ( AllItemsList[idx].iItemId != UniqueItemList[uid].UIItemId ) + { + idx++; + } + } + + GetItemAttrs(ii, idx, currlevel); + GetUniqueItem(ii, uid); + SetupItem(ii); + ++numitems; + item[ii]._iMagical = 2; + } +} +// 422290: could not find valid save-restore pair for esi + +void __fastcall CreateRndItem(int x, int y, unsigned char onlygood, unsigned char sendmsg, int delta) +{ + int idx; // edi + int ii; // esi + + if ( onlygood ) + idx = RndUItem(-1); + else + idx = RndAllItems(); + + if ( numitems < MAXITEMS ) + { + ii = itemavail[0]; + GetSuperItemSpace(x, y, itemavail[0]); + itemactive[numitems] = ii; + itemavail[0] = itemavail[-numitems + 126]; /* MAXITEMS */ + SetupAllItems(ii, idx, GetRndSeed(), 2 * currlevel, 1, onlygood, 0, delta); + + if ( sendmsg ) + NetSendCmdDItem(0, ii); + if ( delta ) + DeltaAddItem(ii); + + ++numitems; + } +} + +void __fastcall SetupAllUseful(int ii, int iseed, int lvl) +{ + int idx; // esi + + item[ii]._iSeed = iseed; + SetRndSeed(iseed); + idx = 25 - (random(34, 2) != 0); + + if ( lvl > 1 ) + { + if ( !random(34, 3) ) + idx = 27; // unique? + } + + GetItemAttrs(ii, idx, lvl); + item[ii]._iCreateInfo = lvl + 0x180; + SetupItem(ii); +} + +void __fastcall CreateRndUseful(int pnum, int x, int y, unsigned char sendmsg) +{ + int ii; // esi + + if ( numitems < MAXITEMS ) + { + ii = itemavail[0]; + GetSuperItemSpace(x, y, itemavail[0]); + itemactive[numitems] = ii; + itemavail[0] = itemavail[-numitems + 126]; /* MAXITEMS */ + SetupAllUseful(ii, GetRndSeed(), currlevel); + + if ( sendmsg ) + NetSendCmdDItem(0, ii); + + ++numitems; + } +} + +void __fastcall CreateTypeItem(int x, int y, unsigned char onlygood, int itype, int imisc, int sendmsg, int delta) +{ + int idx; // edi + int ii; // esi + + if ( itype == ITYPE_GOLD ) + idx = 0; + else + idx = RndTypeItems(itype, imisc); + + if ( numitems < MAXITEMS ) + { + ii = itemavail[0]; + GetSuperItemSpace(x, y, itemavail[0]); + itemactive[numitems] = ii; + itemavail[0] = itemavail[-numitems + 126]; /* MAXITEMS */ + SetupAllItems(ii, idx, GetRndSeed(), 2 * currlevel, 1, onlygood, 0, delta); + + if ( sendmsg ) + NetSendCmdDItem(0, ii); + if ( delta ) + DeltaAddItem(ii); + + ++numitems; + } +} + +void __fastcall RecreateItem(int ii, int idx, unsigned short ic, int iseed, int ivalue) +{ + int uper; // esi + int onlygood; // edx + int recreate; // ebx + int pregen; // edi + + if ( idx ) + { + if ( ic ) + { + if ( ic & 0x7C00 ) + { + RecreateTownItem(ii, idx, ic, iseed, ivalue); + } + else if ( (ic & 0x0180) == 0x0180 ) + { + SetupAllUseful(ii, iseed, ic & 0x3F); + } + else + { + uper = 0; + onlygood = 0; + recreate = 0; + pregen = 0; + if ( ic & 0x0100 ) + uper = 1; + if ( ic & 0x80 ) + uper = 15; + if ( ic & 0x40 ) + onlygood = 1; + if ( ic & 0x0200 ) + recreate = 1; + if ( ic & 0x8000 ) + pregen = 1; + SetupAllItems(ii, idx, iseed, ic & 0x3F, uper, onlygood, recreate, pregen); + } + } + else + { + SetPlrHandItem(&item[ii], idx); + SetPlrHandSeed(&item[ii], iseed); + } + } + else + { + SetPlrHandItem(&item[ii], IDI_GOLD); + item[ii]._iSeed = iseed; + item[ii]._iCreateInfo = ic; + item[ii]._ivalue = ivalue; + if ( ivalue < 2500 ) + { + if ( ivalue > 1000 ) + item[ii]._iCurs = 5; + else + item[ii]._iCurs = 4; + } + else + { + item[ii]._iCurs = 6; + } + } +} + +void __fastcall RecreateEar(int ii, unsigned short ic, int iseed, unsigned char Id, int dur, int mdur, int ch, int mch, int ivalue, int ibuff) +{ + SetPlrHandItem(&item[ii], IDI_EAR); + tempstr[0] = (ic >> 8) & 0x7F; + tempstr[1] = ic & 0x7F; + tempstr[2] = (iseed >> 24) & 0x7F; + tempstr[3] = (iseed >> 16) & 0x7F; + tempstr[4] = (iseed >> 8) & 0x7F; + tempstr[5] = iseed & 0x7F; + tempstr[6] = Id & 0x7F; + tempstr[7] = dur & 0x7F; + tempstr[8] = mdur & 0x7F; + tempstr[9] = ch & 0x7F; + tempstr[10] = mch & 0x7F; + tempstr[11] = (ivalue >> 8) & 0x7F; + tempstr[12] = (ibuff >> 24) & 0x7F; + tempstr[13] = (ibuff >> 16) & 0x7F; + tempstr[14] = (ibuff >> 8) & 0x7F; + tempstr[15] = ibuff & 0x7F; + tempstr[16] = '\0'; + sprintf(item[ii]._iName, "Ear of %s", tempstr); + item[ii]._iCurs = ((ivalue >> 6) & 3) + 19; + item[ii]._iCreateInfo = ic; + item[ii]._ivalue = ivalue & 0x3F; + item[ii]._iSeed = iseed; +} + +void __fastcall SpawnQuestItem(int itemid, int x, int y, int randarea, int selflag) +{ + int i; // ebx + BOOL failed; // eax + int j; // esi + int v12; // ebx + int v13; // esi + int tries; // [esp+10h] [ebp-4h] + + if ( randarea ) + { + tries = 0; + while ( 1 ) + { +LABEL_3: + if ( ++tries > 1000 && randarea > 1 ) + --randarea; + + x = random(0, 112); + y = random(0, 112); + i = 0; + failed = 0; + if ( randarea <= 0 ) + break; + while ( !failed ) + { + for(j = 0; j < randarea; j++) + { + if ( failed ) + break; + + failed = ItemSpaceOk(i + x, j + y) == 0; + } + + if ( ++i >= randarea ) + { + if ( failed ) + goto LABEL_3; + goto LABEL_13; + } + } + } + } +LABEL_13: + if ( numitems < MAXITEMS ) + { + v12 = itemavail[0]; + v13 = itemavail[0]; + item[v13]._ix = x; + itemactive[numitems] = v12; + item[v13]._iy = y; + itemavail[0] = itemavail[-numitems + 126]; /* double check, MAXITEMS */ + dItem[x][y] = v12 + 1; + GetItemAttrs(v12, itemid, currlevel); + SetupItem(v12); + item[v13]._iPostDraw = 1; + if ( selflag ) + { + item[v13]._iAnimFlag = 0; + item[v13]._iSelFlag = selflag; + item[v13]._iAnimFrame = item[v13]._iAnimLen; + } + ++numitems; + } +} + +void __cdecl SpawnRock() +{ + BOOL v0; // edx + int v1; // eax + int v2; // ecx + BOOL v3; // ebx + int v4; // ebx + int v5; // ecx + int v6; // esi + int *v7; // edx + int v8; // eax + int v9; // edi + int v10; // ST04_4 + //int v11; // [esp+8h] [ebp-4h] + + v0 = 0; + v1 = 0; + if ( nobjects > 0 ) + { + v2 = 0; //v11; /* chceck */ + while ( !v0 ) + { + v2 = objectactive[v1]; + v3 = object[objectactive[v1++]]._otype == OBJ_STAND; + v0 = v3; + if ( v1 >= nobjects ) + { + if ( !v3 ) + return; + break; + } + } + v4 = itemavail[0]; + v5 = v2; + v6 = itemavail[0]; + v7 = &itemavail[-numitems + 126]; + itemactive[numitems] = itemavail[0]; + v8 = object[v5]._ox; + item[v6]._ix = v8; + v9 = object[v5]._oy; + itemavail[0] = *v7; + dItem[v8][v9] = v4 + 1; + v10 = currlevel; + item[v6]._iy = v9; + GetItemAttrs(v4, IDI_ROCK, v10); + SetupItem(v4); + ++numitems; + item[v6]._iSelFlag = 2; + item[v6]._iPostDraw = 1; + item[v6]._iAnimFrame = 11; + } +} + +void __fastcall RespawnItem(int i, bool FlipFlag) +{ + int it; // ecx + int il; // eax + + item[i]._iAnimWidth = 96; + item[i]._iAnimWidth2 = 16; + it = ItemCAnimTbl[item[i]._iCurs]; + il = ItemAnimLs[it]; + item[i]._iAnimLen = il; + item[i]._iAnimData = Item2Frm[it]; + item[i]._iPostDraw = 0; + item[i]._iRequest = 0; + + if ( FlipFlag ) + { + item[i]._iSelFlag = 0; + il = 1; + item[i]._iAnimFlag = 1; + } + else + { + item[i]._iAnimFlag = 0; + item[i]._iSelFlag = 1; + } + + item[i]._iAnimFrame = il; + + if ( item[i]._iCurs == 76 ) // Magic Rock + { + item[i]._iSelFlag = 1; + PlaySfxLoc(ItemDropSnds[it], item[i]._ix, item[i]._iy); + } + if ( item[i]._iCurs == 126 ) // Tavern Sign + item[i]._iSelFlag = 1; + if ( item[i]._iCurs == 140 ) // Anvil of Fury + item[i]._iSelFlag = 1; +} + +void __fastcall DeleteItem(int ii, int i) +{ + int v2; // eax + bool v3; // zf + bool v4; // sf + + v2 = numitems - 1; + v3 = numitems == 1; + v4 = numitems - 1 < 0; + itemavail[-numitems + MAXITEMS] = ii; + numitems = v2; + if ( !v4 && !v3 && i != v2 ) + itemactive[i] = itemactive[v2]; +} + +void __cdecl ItemDoppel() +{ + int idoppelx; // esi + ItemStruct *i; // edx + + if ( gbMaxPlayers != 1 ) + { + for(idoppelx = 16; idoppelx < 96; idoppelx++) + { + if ( dItem[idoppelx][idoppely] ) + { + i = &item[dItem[idoppelx][idoppely]-1]; + if ( i->_ix != idoppelx || i->_iy != idoppely ) + dItem[idoppelx][idoppely] = 0; + } + } + + if ( idoppely++ == 95 ) + idoppely = 16; + } +} +// 492EAC: using guessed type int idoppely; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl ProcessItems() +{ + int i; // edi + int ii; // esi + + for ( i = 0; i < numitems; i++ ) + { + ii = itemactive[i]; + if ( item[ii]._iAnimFlag ) + { + item[ii]._iAnimFrame++; + if ( item[ii]._iCurs == 76 ) // Magic Rock + { + if ( item[ii]._iSelFlag == 1 && item[ii]._iAnimFrame == 11 ) + item[ii]._iAnimFrame = 1; + if ( item[ii]._iSelFlag == 2 && item[ii]._iAnimFrame == 21 ) + item[ii]._iAnimFrame = 11; + } + else + { + if ( item[ii]._iAnimFrame == item[ii]._iAnimLen >> 1 ) + PlaySfxLoc(ItemDropSnds[ItemCAnimTbl[item[ii]._iCurs]], item[ii]._ix, item[ii]._iy); + + if ( item[ii]._iAnimFrame >= item[ii]._iAnimLen ) + { + item[ii]._iAnimFlag = 0; + item[ii]._iAnimFrame = item[ii]._iAnimLen; + item[ii]._iSelFlag = 1; + } + } + } + } + ItemDoppel(); +} + +void __cdecl FreeItemGFX() +{ + int i; // esi + void *v1; // ecx + + for(i = 0; i < 35; i++) + { + v1 = (void *)Item2Frm[i]; + Item2Frm[i] = 0; + mem_free_dbg(v1); + } +} + +void __fastcall GetItemFrm(int i) +{ + item[i]._iAnimData = Item2Frm[ItemCAnimTbl[item[i]._iCurs]]; +} + +void __fastcall GetItemStr(int i) +{ + int nGold; // esi + + if ( item[i]._itype == ITYPE_GOLD ) + { + nGold = item[i]._ivalue; + sprintf(infostr, "%i gold %s", nGold, get_pieces_str(nGold)); + } + else + { + if ( !item[i]._iIdentified ) + strcpy(infostr, item[i]._iName); + else + strcpy(infostr, item[i]._iIName); + + if ( item[i]._iMagical == 1 ) + infoclr = COL_BLUE; + if ( item[i]._iMagical == 2 ) + infoclr = COL_GOLD; + } +} +// 4B883C: using guessed type int infoclr; + +void __fastcall CheckIdentify(int pnum, int cii) +{ + ItemStruct *pi; // esi + + pi = &plr[pnum].InvBody[cii]; + pi->_iIdentified = 1; + + CalcPlrInv(pnum, 1); + + if ( pnum == myplr ) + SetCursor(CURSOR_HAND); +} + +void __fastcall DoRepair(int pnum, int cii) +{ + PlayerStruct *p; // eax + ItemStruct *pi; // esi + + p = &plr[pnum]; + pi = &p->InvBody[cii]; + + PlaySfxLoc(IS_REPAIR, p->WorldX, p->WorldY); + RepairItem(pi, p->_pLevel); + CalcPlrInv(pnum, 1); + + if ( pnum == myplr ) + SetCursor(CURSOR_HAND); +} + +void __fastcall RepairItem(ItemStruct *i, int lvl) +{ + int rep; // edi + int d; // eax + + if ( i->_iDurability != i->_iMaxDur ) + { + if ( i->_iMaxDur > 0 ) + { + rep = 0; + while ( 1 ) + { + rep += lvl + random(37, lvl); + d = i->_iMaxDur / (lvl + 9); + + if ( d < 1 ) + d = 1; + if ( i->_iMaxDur == d ) + break; + + i->_iMaxDur -= d; + + if ( rep + i->_iDurability >= i->_iMaxDur ) + { + i->_iDurability += rep; + if ( i->_iDurability > i->_iMaxDur ) + i->_iDurability = i->_iMaxDur; + return; + } + } + } + i->_itype = -1; + } +} + +void __fastcall DoRecharge(int pnum, int cii) +{ + PlayerStruct *p; // eax + ItemStruct *pi; // esi + + p = &plr[pnum]; + pi = &p->InvBody[cii]; + + if ( pi->_itype == ITYPE_STAFF && pi->_iSpell ) + { + RechargeItem(pi, random(38, p->_pLevel / spelldata[pi->_iSpell].sBookLvl) + 1); + CalcPlrInv(pnum, 1); + } + + if ( pnum == myplr ) + SetCursor(CURSOR_HAND); +} + +void __fastcall RechargeItem(ItemStruct *i, int r) +{ + if ( i->_iCharges != i->_iMaxCharges ) + { + while ( 1 ) + { + if ( i->_iMaxCharges-- == 1 ) + break; + + i->_iCharges += r; + + if ( i->_iCharges >= i->_iMaxCharges ) + { + if ( i->_iCharges > i->_iMaxCharges ) + i->_iCharges = i->_iMaxCharges; + return; + } + } + } +} + +void __fastcall PrintItemOil(char IDidx) +{ + switch ( IDidx ) + { + case IMISC_FULLHEAL: + strcpy(tempstr, "fully recover life"); + break; + case IMISC_HEAL: + strcpy(tempstr, "recover partial life"); + break; + case IMISC_OLDHEAL: + strcpy(tempstr, "recover life"); + break; + case IMISC_DEADHEAL: + strcpy(tempstr, "deadly heal"); + break; + case IMISC_MANA: + strcpy(tempstr, "recover mana"); + break; + case IMISC_FULLMANA: + strcpy(tempstr, "fully recover mana"); + break; + case IMISC_ELIXSTR: + strcpy(tempstr, "increase strength"); + break; + case IMISC_ELIXMAG: + strcpy(tempstr, "increase magic"); + break; + case IMISC_ELIXDEX: + strcpy(tempstr, "increase dexterity"); + break; + case IMISC_ELIXVIT: + strcpy(tempstr, "increase vitality"); + break; + case IMISC_ELIXWEAK: + case IMISC_ELIXDIS: + strcpy(tempstr, "decrease strength"); + break; + case IMISC_ELIXCLUM: + strcpy(tempstr, "decrease dexterity"); + break; + case IMISC_ELIXSICK: + strcpy(tempstr, "decrease vitality"); + break; + case IMISC_REJUV: + strcpy(tempstr, "recover life and mana"); + break; + case IMISC_FULLREJUV: + strcpy(tempstr, "fully recover life and mana"); + break; + default: + return; + } + + AddPanelString(tempstr, 1); +} + +void __fastcall PrintItemPower(char plidx, ItemStruct *x) +{ + ItemStruct *v2; // esi + int *v3; // esi + int *v4; // esi + int v5; // esi + const char *v6; // [esp-4h] [ebp-Ch] + const char *v7; // [esp-4h] [ebp-Ch] + const char *v8; // [esp-4h] [ebp-Ch] + const char *v9; // [esp-4h] [ebp-Ch] + + v2 = x; + switch ( plidx ) + { + case IPL_TOHIT: + case IPL_TOHIT_CURSE: + sprintf(tempstr, "chance to hit : %+i%%", x->_iPLToHit); + return; + case IPL_DAMP: + case IPL_DAMP_CURSE: + sprintf(tempstr, "%+i%% damage", x->_iPLDam); + return; + case IPL_TOHIT_DAMP: + case IPL_TOHIT_DAMP_CURSE: + sprintf(tempstr, "to hit: %+i%%, %+i%% damage", x->_iPLToHit, x->_iPLDam); + return; + case IPL_ACP: + case IPL_ACP_CURSE: + sprintf(tempstr, "%+i%% armor", x->_iPLAC); + return; + case IPL_FIRERES: + if ( x->_iPLFR < 75 ) + sprintf(tempstr, "Resist Fire : %+i%%", x->_iPLFR); + if ( v2->_iPLFR >= 75 ) + { + v6 = "Resist Fire : 75%% MAX"; + goto LABEL_11; + } + return; + case IPL_LIGHTRES: + if ( x->_iPLLR < 75 ) + sprintf(tempstr, "Resist Lightning : %+i%%", x->_iPLLR); + if ( v2->_iPLLR >= 75 ) + { + v6 = "Resist Lightning : 75%% MAX"; + goto LABEL_11; + } + return; + case IPL_MAGICRES: + if ( x->_iPLMR < 75 ) + sprintf(tempstr, "Resist Magic : %+i%%", x->_iPLMR); + if ( v2->_iPLMR >= 75 ) + { + v6 = "Resist Magic : 75%% MAX"; + goto LABEL_11; + } + return; + case IPL_ALLRES: + if ( x->_iPLFR < 75 ) + sprintf(tempstr, "Resist All : %+i%%", x->_iPLFR); + if ( v2->_iPLFR >= 75 ) + { + v6 = "Resist All : 75%% MAX"; +LABEL_11: + sprintf(tempstr, v6); + } + return; + case IPL_SPLLVLADD: + if ( x->_iSplLvlAdd == 1 ) + strcpy(tempstr, "spells are increased 1 level"); + if ( v2->_iSplLvlAdd == 2 ) + strcpy(tempstr, "spells are increased 2 levels"); + if ( v2->_iSplLvlAdd < 1 ) + { + v7 = "spells are decreased 1 level"; + goto LABEL_81; + } + return; + case IPL_CHARGES: + v8 = "Extra charges"; + goto LABEL_104; + case IPL_FIREDAM: + sprintf(tempstr, "Fire hit damage: %i-%i", x->_iFMinDam, x->_iFMaxDam); + return; + case IPL_LIGHTDAM: + sprintf(tempstr, "Lightning hit damage: %i-%i", x->_iLMinDam, x->_iLMaxDam); + return; + case IPL_STR: + case IPL_STR_CURSE: + sprintf(tempstr, "%+i to strength", x->_iPLStr); + return; + case IPL_MAG: + case IPL_MAG_CURSE: + sprintf(tempstr, "%+i to magic", x->_iPLMag); + return; + case IPL_DEX: + case IPL_DEX_CURSE: + sprintf(tempstr, "%+i to dexterity", x->_iPLDex); + return; + case IPL_VIT: + case IPL_VIT_CURSE: + sprintf(tempstr, "%+i to vitality", x->_iPLVit); + return; + case IPL_ATTRIBS: + case IPL_ATTRIBS_CURSE: + sprintf(tempstr, "%+i to all attributes", x->_iPLStr); + return; + case IPL_GETHIT_CURSE: + case IPL_GETHIT: + sprintf(tempstr, "%+i damage from enemies", x->_iPLGetHit); + return; + case IPL_LIFE: + case IPL_LIFE_CURSE: + sprintf(tempstr, "Hit Points : %+i", x->_iPLHP >> 6); + return; + case IPL_MANA: + case IPL_MANA_CURSE: + sprintf(tempstr, "Mana : %+i", x->_iPLMana >> 6); + return; + case IPL_DUR: + v8 = "high durability"; + goto LABEL_104; + case IPL_DUR_CURSE: + v8 = "decreased durability"; + goto LABEL_104; + case IPL_INDESTRUCTIBLE: + v8 = "indestructible"; + goto LABEL_104; + case IPL_LIGHT: + sprintf(tempstr, "+%i%% light radius", 10 * x->_iPLLight); + return; + case IPL_LIGHT_CURSE: + sprintf(tempstr, "-%i%% light radius", -10 * x->_iPLLight); + return; + case IPL_FIRE_ARROWS: + sprintf(tempstr, "fire arrows damage: %i-%i", x->_iFMinDam, x->_iFMaxDam); + return; + case IPL_LIGHT_ARROWS: + sprintf(tempstr, "lightning arrows damage %i-%i", x->_iLMinDam, x->_iLMaxDam); + return; + case IPL_INVCURS: + v8 = " "; + goto LABEL_104; + case IPL_THORNS: + v8 = "attacker takes 1-3 damage"; + goto LABEL_104; + case IPL_NOMANA: + v8 = "user loses all mana"; + goto LABEL_104; + case IPL_NOHEALPLR: + v8 = "you can't heal"; + goto LABEL_104; + case IPL_ABSHALFTRAP: + v8 = "absorbs half of trap damage"; + goto LABEL_104; + case IPL_KNOCKBACK: + v8 = "knocks target back"; + goto LABEL_104; + case IPL_NOHEALMON: + v8 = "hit monster doesn't heal"; + goto LABEL_104; + case IPL_STEALMANA: + v3 = &x->_iFlags; + if ( x->_iFlags & 0x2000 ) + strcpy(tempstr, "hit steals 3% mana"); + if ( !(*((_BYTE *)v3 + 1) & 0x40) ) + return; + v7 = "hit steals 5% mana"; + goto LABEL_81; + case IPL_STEALLIFE: + v4 = &x->_iFlags; + if ( (x->_iFlags & 0x8000) != 0 ) + strcpy(tempstr, "hit steals 3% life"); + if ( !(*((_BYTE *)v4 + 2) & 1) ) + return; + v7 = "hit steals 5% life"; + goto LABEL_81; + case IPL_TARGAC: + v8 = "damages target's armor"; + goto LABEL_104; + case IPL_FASTATTACK: + if ( x->_iFlags & 0x20000 ) + strcpy(tempstr, "quick attack"); + if ( v2->_iFlags & 0x40000 ) + strcpy(tempstr, "fast attack"); + if ( v2->_iFlags & 0x80000 ) + strcpy(tempstr, "faster attack"); + if ( !(v2->_iFlags & 0x100000) ) + return; + v7 = "fastest attack"; + goto LABEL_81; + case IPL_FASTRECOVER: + if ( x->_iFlags & 0x200000 ) + strcpy(tempstr, "fast hit recovery"); + if ( v2->_iFlags & 0x400000 ) + strcpy(tempstr, "faster hit recovery"); + if ( (v2->_iFlags & 0x800000) != 0 ) + { + v7 = "fastest hit recovery"; +LABEL_81: + strcpy(tempstr, v7); + } + return; + case IPL_FASTBLOCK: + v8 = "fast block"; + goto LABEL_104; + case IPL_DAMMOD: + sprintf(tempstr, "adds %i points to damage", x->_iPLDamMod); + return; + case IPL_RNDARROWVEL: + v8 = "fires random speed arrows"; + goto LABEL_104; + case IPL_SETDAM: + v9 = "unusual item damage"; + goto LABEL_98; + case IPL_SETDUR: + v8 = "altered durability"; + goto LABEL_104; + case IPL_NOMINSTR: + v8 = "no strength requirement"; + goto LABEL_104; + case IPL_SPELL: + sprintf(tempstr, "%i %s charges", x->_iMaxCharges, spelldata[x->_iSpell].sNameText); + return; + case IPL_FASTSWING: + v8 = "Faster attack swing"; + goto LABEL_104; + case IPL_ONEHAND: + v8 = "one handed sword"; + goto LABEL_104; + case IPL_3XDAMVDEM: + v8 = "+200% damage vs. demons"; + goto LABEL_104; + case IPL_ALLRESZERO: + v8 = "All Resistance equals 0"; + goto LABEL_104; + case IPL_DRAINLIFE: + v8 = "constantly lose hit points"; + goto LABEL_104; + case IPL_RNDSTEALLIFE: + v8 = "life stealing"; + goto LABEL_104; + case IPL_INFRAVISION: + v8 = "see with infravision"; + goto LABEL_104; + case IPL_SETAC: + case IPL_AC_CURSE: + sprintf(tempstr, "armor class: %i", x->_iAC); + return; + case IPL_ADDACLIFE: + v8 = "Armor class added to life"; + goto LABEL_104; + case IPL_ADDMANAAC: + v8 = "10% of mana added to armor"; + goto LABEL_104; + case IPL_FIRERESCLVL: + v5 = x->_iPLFR; + if ( v5 > 0 ) + { + if ( v5 >= 1 ) + sprintf(tempstr, "Resist Fire : %+i%%", v5); + } + else + { + v9 = " "; +LABEL_98: + sprintf(tempstr, v9); + } + break; + default: + v8 = "Another ability (NW)"; +LABEL_104: + strcpy(tempstr, v8); + break; + } +} + +void __cdecl DrawUBack() +{ + char *v0; // edi + signed int v1; // edx + signed int v2; // ecx + int v3; // edi + signed int v4; // ecx + _BYTE *v5; // edi + signed int v6; // ecx + + CelDecodeOnly(88, 487, pSTextBoxCels, 1, 271); + v0 = &gpBuffer->row[324].pixels[27]; + v1 = 148; + do + { + v2 = 132; + do + { + *v0 = 0; + v0 += 2; + --v2; + } + while ( v2 ); + *v0 = 0; + v3 = (int)(v0 - 1032); + v4 = 132; + do + { + v5 = (_BYTE *)(v3 + 1); + *v5 = 0; + v3 = (int)(v5 + 1); + --v4; + } + while ( v4 ); + v0 = (char *)(v3 - 1032); + --v1; + } + while ( v1 ); + v6 = 132; + do + { + *v0 = 0; + v0 += 2; + --v6; + } + while ( v6 ); + *v0 = 0; +} + +void __fastcall PrintUString(int x, int y, int cjustflag, char *str, int col) +{ + char *v5; // edi + int v6; // ebx + size_t v7; // eax + int v8; // esi + int v9; // ecx + signed int v10; // eax + int v11; // edx + int v12; // eax + unsigned char v13; // al + int v14; // edi + int v15; // [esp+Ch] [ebp-4h] + int a3; // [esp+18h] [ebp+8h] + + v5 = str; + v6 = screen_y_times_768[SStringY[y] + 204] + x + 96; + v7 = strlen(str); + v8 = 0; + v9 = 0; + v15 = v7; + if ( cjustflag ) + { + v10 = 0; + if ( v15 <= 0 ) + goto LABEL_16; + do + { + v11 = (unsigned char)str[v9++]; + v10 += fontkern[fontframe[fontidx[v11]]] + 1; + } + while ( v9 < v15 ); + if ( v10 < 257 ) +LABEL_16: + v8 = (257 - v10) >> 1; + v6 += v8; + } + v12 = 0; + a3 = 0; + if ( v15 > 0 ) + { + while ( 1 ) + { + v13 = fontframe[fontidx[(unsigned char)v5[v12]]]; + v14 = v13; + v8 += fontkern[v13] + 1; + if ( v13 ) + { + if ( v8 <= 257 ) + CPrintString(v6, v13, col); + } + v6 += fontkern[v14] + 1; + v12 = a3++ + 1; + if ( a3 >= v15 ) + break; + v5 = str; + } + } +} + +void __fastcall DrawULine(int y) +{ + char *v1; // esi + char *v2; // edi + signed int v3; // edx + + v1 = &gpBuffer->row[25].pixels[26]; + v2 = &gpBuffer->row_unused_1[0].pixels[screen_y_times_768[SStringY[y] + 198] + 26]; + v3 = 3; + do + { + qmemcpy(v2, v1, 0x10A); /* find real fix */ + v1 += 264; + v2 += 264; + *v2 = *v1; + v1 += 504; + v2 += 504; + --v3; + } + while ( v3 ); +} + +void __cdecl DrawUniqueInfo() +{ + int v0; // esi + int v1; // esi + int v2; // edi + + if ( !chrflag && !questlog ) + { + v0 = curruitem._iUid; + DrawUBack(); + v1 = v0; + PrintUString(0, 2, 1, UniqueItemList[v1].UIName, 3); + DrawULine(5); + PrintItemPower(UniqueItemList[v1].UIPower1, &curruitem); + v2 = 14 - (char)UniqueItemList[v1].UINumPL; + PrintUString(0, v2, 1, tempstr, 0); + if ( UniqueItemList[v1].UINumPL > 1 ) + { + PrintItemPower(UniqueItemList[v1].UIPower2, &curruitem); + PrintUString(0, v2 + 2, 1, tempstr, 0); + } + if ( UniqueItemList[v1].UINumPL > 2 ) + { + PrintItemPower(UniqueItemList[v1].UIPower3, &curruitem); + PrintUString(0, v2 + 4, 1, tempstr, 0); + } + if ( UniqueItemList[v1].UINumPL > 3 ) + { + PrintItemPower(UniqueItemList[v1].UIPower4, &curruitem); + PrintUString(0, v2 + 6, 1, tempstr, 0); + } + if ( UniqueItemList[v1].UINumPL > 4 ) + { + PrintItemPower(UniqueItemList[v1].UIPower5, &curruitem); + PrintUString(0, v2 + 8, 1, tempstr, 0); + } + if ( UniqueItemList[v1].UINumPL > 5 ) + { + PrintItemPower(UniqueItemList[v1].UIPower6, &curruitem); + PrintUString(0, v2 + 10, 1, tempstr, 0); + } + } +} +// 69BD04: using guessed type int questlog; + +void __fastcall PrintItemMisc(ItemStruct *x) +{ + if ( x->_iMiscId == IMISC_SCROLL ) + { + strcpy(tempstr, "Right-click to read"); + AddPanelString(tempstr, 1); + } + if ( x->_iMiscId == IMISC_SCROLLT ) + { + strcpy(tempstr, "Right-click to read, then"); + AddPanelString(tempstr, 1); + strcpy(tempstr, "left-click to target"); + AddPanelString(tempstr, 1); + } + if ( x->_iMiscId >= IMISC_USEFIRST && x->_iMiscId <= IMISC_USELAST ) + { + PrintItemOil(x->_iMiscId); + strcpy(tempstr, "Right click to use"); + AddPanelString(tempstr, 1); + } + if ( x->_iMiscId == IMISC_BOOK ) + { + strcpy(tempstr, "Right click to read"); + AddPanelString(tempstr, 1); + } + if ( x->_iMiscId == IMISC_MAPOFDOOM ) + { + strcpy(tempstr, "Right click to view"); + AddPanelString(tempstr, 1); + } + if ( x->_iMiscId == IMISC_EAR ) + { + sprintf(tempstr, "Level : %i", x->_ivalue); + AddPanelString(tempstr, 1); + } +} + +void __fastcall PrintItemDetails(ItemStruct *x) +{ + ItemStruct *v1; // ebp + char v2; // cl + char v3; // cl + char v4; // al + unsigned char v5; // al + char v6; // al + + v1 = x; + if ( x->_iClass == 1 ) + { + if ( x->_iMaxDur == 255 ) + sprintf(tempstr, "damage: %i-%i Indestructible", x->_iMinDam, x->_iMaxDam); + else + sprintf(tempstr, "damage: %i-%i Dur: %i/%i", x->_iMinDam, x->_iMaxDam, x->_iDurability, x->_iMaxDur); + AddPanelString(tempstr, 1); + } + if ( v1->_iClass == 2 ) + { + if ( v1->_iMaxDur == 255 ) + sprintf(tempstr, "armor: %i Indestructible", v1->_iAC); + else + sprintf(tempstr, "armor: %i Dur: %i/%i", v1->_iAC, v1->_iDurability, v1->_iMaxDur); + AddPanelString(tempstr, 1); + } + if ( v1->_iMiscId == IMISC_STAFF && v1->_iMaxCharges ) + { + sprintf(tempstr, "dam: %i-%i Dur: %i/%i", v1->_iMinDam, v1->_iMaxDam, v1->_iDurability, v1->_iMaxDur); + sprintf(tempstr, "Charges: %i/%i", v1->_iCharges, v1->_iMaxCharges); + AddPanelString(tempstr, 1); + } + v2 = v1->_iPrePower; + if ( v2 != -1 ) + { + PrintItemPower(v2, v1); + AddPanelString(tempstr, 1); + } + v3 = v1->_iSufPower; + if ( v3 != -1 ) + { + PrintItemPower(v3, v1); + AddPanelString(tempstr, 1); + } + if ( v1->_iMagical == 2 ) + { + AddPanelString("unique item", 1); + uitemflag = 1; + qmemcpy(&curruitem, v1, sizeof(curruitem)); + } + PrintItemMisc(v1); + if ( (unsigned char)v1->_iMinMag + v1->_iMinDex + v1->_iMinStr ) + { + strcpy(tempstr, "Required:"); + v4 = v1->_iMinStr; + if ( v4 ) + sprintf(tempstr, "%s %i Str", tempstr, v4); + v5 = v1->_iMinMag; + if ( v5 ) + sprintf(tempstr, "%s %i Mag", tempstr, v5); + v6 = v1->_iMinDex; + if ( v6 ) + sprintf(tempstr, "%s %i Dex", tempstr, v6); + AddPanelString(tempstr, 1); + } + pinfoflag = 1; +} +// 4B8824: using guessed type int pinfoflag; + +void __fastcall PrintItemDur(ItemStruct *x) +{ + ItemStruct *v1; // esi + int v2; // eax + char v3; // al + unsigned char v4; // al + char v5; // al + + v1 = x; + if ( x->_iClass == 1 ) + { + if ( x->_iMaxDur == 255 ) + sprintf(tempstr, "damage: %i-%i Indestructible", x->_iMinDam, x->_iMaxDam); + else + sprintf(tempstr, "damage: %i-%i Dur: %i/%i", x->_iMinDam, x->_iMaxDam, x->_iDurability, x->_iMaxDur); + AddPanelString(tempstr, 1); + if ( v1->_iMiscId == IMISC_STAFF && v1->_iMaxCharges ) + { + sprintf(tempstr, "Charges: %i/%i", v1->_iCharges, v1->_iMaxCharges); + AddPanelString(tempstr, 1); + } + if ( v1->_iMagical ) + AddPanelString("Not Identified", 1); + } + if ( v1->_iClass == 2 ) + { + if ( v1->_iMaxDur == 255 ) + sprintf(tempstr, "armor: %i Indestructible", v1->_iAC); + else + sprintf(tempstr, "armor: %i Dur: %i/%i", v1->_iAC, v1->_iDurability, v1->_iMaxDur); + AddPanelString(tempstr, 1); + if ( v1->_iMagical ) + AddPanelString("Not Identified", 1); + if ( v1->_iMiscId == IMISC_STAFF && v1->_iMaxCharges ) + { + sprintf(tempstr, "Charges: %i/%i", v1->_iCharges, v1->_iMaxCharges); + AddPanelString(tempstr, 1); + } + } + v2 = v1->_itype; + if ( v2 == ITYPE_RING || v2 == ITYPE_AMULET ) + AddPanelString("Not Identified", 1); + PrintItemMisc(v1); + if ( (unsigned char)v1->_iMinMag + v1->_iMinDex + v1->_iMinStr ) + { + strcpy(tempstr, "Required:"); + v3 = v1->_iMinStr; + if ( v3 ) + sprintf(tempstr, "%s %i Str", tempstr, v3); + v4 = v1->_iMinMag; + if ( v4 ) + sprintf(tempstr, "%s %i Mag", tempstr, v4); + v5 = v1->_iMinDex; + if ( v5 ) + sprintf(tempstr, "%s %i Dex", tempstr, v5); + AddPanelString(tempstr, 1); + } + pinfoflag = 1; +} +// 4B8824: using guessed type int pinfoflag; + +void __fastcall UseItem(int p, int Mid, int spl) +{ + int v3; // esi + int v5; // edx + int v6; // edx + int v7; // edx + int v8; // edx + int v9; // esi + int v10; // esi + int v11; // edi + unsigned int v12; // edi + char v13; // al + int v14; // edi + int v15; // ecx + int *v16; // eax + int *v17; // eax + int v18; // esi + int v21; // edx + int v22; // edx + int v23; // edx + int v24; // edx + int v25; // edi + char *v26; // eax + int v27; // edx + int *v28; // ecx + int v29; // eax + int *v30; // ecx + int v31; // edi + int v32; // edi + int v33; // eax + int v34; // ecx + int v35; // eax + bool v36; // zf + int v37; // ecx + int v38; // eax + int v39; // edx + int v40; // eax + int v41; // edx + int v42; // esi + int v43; // edi + unsigned int v44; // edi + char v45; // al + int v46; // edi + int v47; // ecx + int *v48; // eax + int v49; // ecx + int *v50; // eax + int v51; // edi + int v52; // edx + unsigned int v53; // edi + char v54; // al + int v55; // edi + int v56; // ecx + int *v57; // eax + int *v58; // eax + int v59; // esi + int v61; // esi + int v62; // edi + unsigned int v63; // edi + char v64; // al + int v65; // edi + int v66; // ecx + int *v67; // eax + int *v68; // eax + int v69; // esi + int pa; // [esp+Ch] [ebp-4h] + + v3 = p; + pa = p; + if ( Mid > 28 ) + { + if ( Mid == IMISC_MAPOFDOOM ) + { + doom_init(); + } else if ( Mid == IMISC_SPECELIX ) { + ModifyPlrStr(p, 3); + ModifyPlrMag(v3, 3); + ModifyPlrDex(v3, 3); + ModifyPlrVit(v3, 3); + } + return; + } + if ( Mid == IMISC_HEAL_1C ) + goto LABEL_71; + if ( Mid <= 12 ) + { + if ( Mid == IMISC_ELIXDEX ) + { + ModifyPlrDex(p, 1); + return; + } + if ( Mid == IMISC_FULLHEAL ) + { + plr[p]._pHitPoints = plr[p]._pMaxHP; + plr[p]._pHPBase = plr[p]._pMaxHPBase; + drawhpflag = 1; + return; + } + v5 = Mid - 3; + if ( v5 ) + { + v6 = v5 - 3; + if ( v6 ) + { + v7 = v6 - 1; + if ( v7 ) + { + v8 = v7 - 3; + if ( v8 ) + { + if ( v8 == 1 ) + ModifyPlrMag(p, 1); + } + else + { + ModifyPlrStr(p, 1); + } + return; + } + v9 = p; + if ( plr[p]._pIFlags & 0x8000000 ) + return; + plr[v9]._pMana = plr[v9]._pMaxMana; + plr[v9]._pManaBase = plr[v9]._pMaxManaBase; +LABEL_41: + drawmanaflag = 1; + return; + } + v10 = p; + v11 = plr[v10]._pMaxMana >> 8; + v12 = (v11 & 0xFFFFFFFE) + 2 * random(40, v11); + v13 = plr[v10]._pClass; + v14 = 32 * v12; + if ( v13 == 2 ) + v14 *= 2; + if ( v13 == 1 ) + v14 += v14 >> 1; + if ( !(plr[v10]._pIFlags & 0x8000000) ) + { + v15 = plr[v10]._pMaxMana; + v16 = &plr[v10]._pMana; + *v16 += v14; + if ( plr[v10]._pMana > v15 ) + *v16 = v15; + v17 = &plr[v10]._pManaBase; + v18 = plr[v10]._pMaxManaBase; + *v17 += v14; + if ( *v17 > v18 ) + *v17 = v18; + goto LABEL_41; + } + return; + } +LABEL_71: + v61 = p; + v62 = plr[v61]._pMaxHP >> 8; + v63 = (v62 & 0xFFFFFFFE) + 2 * random(39, v62); + v64 = plr[v61]._pClass; + v65 = 32 * v63; + if ( !v64 ) + v65 *= 2; + if ( v64 == 1 ) + v65 += v65 >> 1; + v66 = plr[v61]._pMaxHP; + v67 = &plr[v61]._pHitPoints; + *v67 += v65; + if ( plr[v61]._pHitPoints > v66 ) + *v67 = v66; + v68 = &plr[v61]._pHPBase; + v69 = plr[v61]._pMaxHPBase; + *v68 += v65; + if ( *v68 > v69 ) + *v68 = v69; + drawhpflag = 1; + return; + } + if ( Mid == IMISC_ELIXVIT ) + { + ModifyPlrVit(v3, 1); + return; + } + v21 = Mid - 18; + if ( v21 ) + { + v22 = v21 - 1; + if ( v22 ) + { + v23 = v22 - 2; + if ( v23 ) + { + v24 = v23 - 1; + if ( v24 ) + { + if ( v24 != 2 ) + return; + v25 = p; + *(_QWORD *)plr[p]._pMemSpells |= (__int64)1 << ((unsigned char)spl - 1); + v26 = &plr[p]._pSplLvl[spl]; + if ( *v26 < 15 ) + ++*v26; + v27 = plr[v25]._pMaxMana; + v28 = &plr[v25]._pMana; + v29 = spelldata[spl].sManaCost << 6; + *v28 += v29; + if ( plr[v25]._pMana > v27 ) + *v28 = v27; + v30 = &plr[v25]._pManaBase; + v31 = plr[v25]._pMaxManaBase; + *v30 += v29; + if ( *v30 > v31 ) + *v30 = v31; + if ( pa == myplr ) + CalcPlrBookVals(pa); + goto LABEL_41; + } + v32 = spl; + if ( !spelldata[spl].sTargeted ) + { + ClrPlrPath(p); + v33 = v3; + plr[v33].destParam1 = cursmx; + v34 = cursmy; + plr[v33]._pSpell = spl; + plr[v33]._pSplType = 4; + plr[v33]._pSplFrom = 3; + plr[v33].destAction = 12; + plr[v33].destParam2 = v34; + return; + } + } + else + { + v32 = spl; + if ( !spelldata[spl].sTargeted ) + { + ClrPlrPath(p); + v37 = cursmx; + v38 = v3; + v39 = cursmy; + v36 = v3 == myplr; + plr[v38]._pSpell = spl; + plr[v38]._pSplType = 4; + plr[v38]._pSplFrom = 3; + plr[v38].destAction = 12; + plr[v38].destParam1 = v37; + plr[v38].destParam2 = v39; + if ( v36 && spl == SPL_NOVA ) + NetSendCmdLoc(1u, CMD_NOVA, v37, v39); + return; + } + } + v35 = p; + v36 = p == myplr; + plr[v35]._pTSpell = v32; + _LOBYTE(plr[v35]._pTSplType) = 4; + if ( v36 ) + SetCursor(CURSOR_TELEPORT); + return; + } + v40 = p; + plr[v40]._pHitPoints = plr[p]._pMaxHP; + plr[v40]._pHPBase = plr[p]._pMaxHPBase; + v36 = (plr[p]._pIFlags & 0x8000000) == 0; + drawhpflag = 1; + if ( v36 ) + { + v41 = plr[v40]._pMaxMana; + drawmanaflag = 1; + plr[v40]._pMana = v41; + plr[v40]._pManaBase = plr[v40]._pMaxManaBase; + } + } + else + { + v42 = p; + v43 = plr[v42]._pMaxHP >> 8; + v44 = (v43 & 0xFFFFFFFE) + 2 * random(39, v43); + v45 = plr[v42]._pClass; + v46 = 32 * v44; + if ( !v45 ) + v46 *= 2; + if ( v45 == 1 ) + v46 += v46 >> 1; + v47 = plr[v42]._pMaxHP; + v48 = &plr[v42]._pHitPoints; + *v48 += v46; + if ( plr[v42]._pHitPoints > v47 ) + *v48 = v47; + v49 = plr[v42]._pMaxHPBase; + v50 = &plr[v42]._pHPBase; + *v50 += v46; + if ( plr[v42]._pHPBase > v49 ) + *v50 = v49; + v51 = plr[v42]._pMaxMana >> 8; + v52 = plr[v42]._pMaxMana >> 8; + drawhpflag = 1; + v53 = (v51 & 0xFFFFFFFE) + 2 * random(40, v52); + v54 = plr[v42]._pClass; + v55 = 32 * v53; + if ( v54 == 2 ) + v55 *= 2; + if ( v54 == 1 ) + v55 += v55 >> 1; + if ( !(plr[v42]._pIFlags & 0x8000000) ) + { + v56 = plr[v42]._pMaxMana; + v57 = &plr[v42]._pMana; + *v57 += v55; + if ( plr[v42]._pMana > v56 ) + *v57 = v56; + v58 = &plr[v42]._pManaBase; + v59 = plr[v42]._pMaxManaBase; + *v58 += v55; + if ( *v58 > v59 ) + *v58 = v59; + drawmanaflag = 1; + } + } +} + +bool __fastcall StoreStatOk(ItemStruct *h) +{ + bool sf; // al + + sf = 1; + if ( plr[myplr]._pStrength < h->_iMinStr + || plr[myplr]._pMagic < h->_iMinMag + || plr[myplr]._pDexterity < h->_iMinDex ) + sf = 0; + return sf; +} + +bool __fastcall SmithItemOk(int i) +{ + unsigned char v1; // cl + bool rv; // eax + + v1 = AllItemsList[i].itype; + rv = 1; + if ( !v1 || v1 == ITYPE_GOLD || v1 == ITYPE_0E || v1 == ITYPE_STAFF || v1 == ITYPE_RING || v1 == ITYPE_AMULET ) + rv = 0; + return rv; +} + +int __fastcall RndSmithItem(int lvl) +{ + int ri; // edx + int i; // edi + int ril[512]; // [esp+4h] [ebp-804h] + + ri = 0; + i = 1; + if ( AllItemsList[1].iLoc != -1 ) + { + do + { + if ( AllItemsList[i].iRnd && SmithItemOk(i) && lvl >= AllItemsList[i].iMinMLvl ) + { + ril[ri++] = i; + if ( AllItemsList[i].iRnd == 2 ) + ril[ri++] = i; + } + ++i; + } + while ( AllItemsList[i].iLoc != -1 ); + } + return ril[random(50, ri)] + 1; +} +// 424252: using guessed type int var_804[512]; + +void __fastcall BubbleSwapItem(ItemStruct *a, ItemStruct *b) +{ + ItemStruct h; // [esp+8h] [ebp-170h] + + qmemcpy(&h, a, sizeof(h)); + qmemcpy(a, b, sizeof(ItemStruct)); + qmemcpy(b, &h, sizeof(ItemStruct)); +} + +void __cdecl SortSmith() +{ + int v0; // esi + int *v1; // eax + signed int v2; // ecx + int *v3; // eax + int v4; // ebx + int v5; // edi + + v0 = 0; + if ( smithitem[1]._itype != -1 ) + { + v1 = &smithitem[1]._itype; + do + { + v1 += 92; + ++v0; + } + while ( *v1 != -1 ); + } + v2 = 0; + while ( v0 > 0 && !v2 ) + { + v2 = 1; + if ( v0 > 0 ) + { + v3 = &smithitem[0].IDidx; + v4 = v0; + do + { + v5 = (int)(v3 + 92); + if ( *v3 > v3[92] ) + { + BubbleSwapItem((ItemStruct *)(v3 - 90), (ItemStruct *)(v3 + 2)); + v2 = 0; + } + --v4; + v3 = (int *)v5; + } + while ( v4 ); + } + --v0; + } +} + +void __fastcall SpawnSmith(int lvl) +{ + int v3; // ebp + ItemStruct *v4; // ebx + int v9; // [esp+Ch] [ebp-8h] + + v3 = random(50, 10) + 10; + if ( v3 > 0 ) + { + v4 = smithitem; + v9 = v3; + while ( 1 ) + { + do + { + item[0]._iSeed = GetRndSeed(); + SetRndSeed(item[0]._iSeed); + GetItemAttrs(0, RndSmithItem(lvl) - 1, lvl); + } + while ( item[0]._iIvalue > 140000 ); + qmemcpy(v4, item, sizeof(ItemStruct)); + v4->_iCreateInfo = lvl | 0x400; + v4->_iIdentified = 1; + v4->_iStatFlag = StoreStatOk(v4); + ++v4; + if ( !--v9 ) + break; + } + } + if ( v3 < 20 ) + { + do + { + smithitem[v3]._itype = -1; + v3++; + } + while ( v3 < 20 ); + } + SortSmith(); +} + +bool __fastcall PremiumItemOk(int i) +{ + unsigned char v1; // cl + bool rv; // eax + + v1 = AllItemsList[i].itype; + rv = 1; + if ( !v1 || v1 == ITYPE_GOLD || v1 == ITYPE_0E || v1 == ITYPE_STAFF ) + rv = 0; + if ( gbMaxPlayers != 1 && ( v1 == ITYPE_RING || v1 == ITYPE_AMULET ) ) + { + rv = 0; + } + return rv; +} +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall RndPremiumItem(int minlvl, int maxlvl) +{ + int ri; // edx + int i; // edi + int ril[512]; // [esp+8h] [ebp-804h] + + ri = 0; + i = 1; + if ( AllItemsList[1].iLoc != -1 ) + { + do + { + if ( AllItemsList[i].iRnd ) + { + if ( PremiumItemOk(i) ) + { + if ( AllItemsList[i].iMinMLvl >= minlvl && AllItemsList[i].iMinMLvl <= maxlvl ) + ril[ri++] = i; + } + } + ++i; + } + while ( AllItemsList[i].iLoc != -1 ); + } + return ril[random(50, ri)] + 1; +} +// 42445F: using guessed type int ril[512]; + +void __fastcall SpawnOnePremium(int i, int plvl) +{ + int itype; // esi + ItemStruct holditem; // [esp+Ch] [ebp-178h] + + qmemcpy(&holditem, item, sizeof(ItemStruct)); + if ( plvl > 30 ) + plvl = 30; + if ( plvl < 1 ) + plvl = 1; + do + { + item[0]._iSeed = GetRndSeed(); + SetRndSeed(item[0]._iSeed); + itype = RndPremiumItem(plvl >> 2, plvl) - 1; + GetItemAttrs(0, itype, plvl); + GetItemBonus(0, itype, plvl >> 1, plvl, 1); + } + while ( item[0]._iIvalue > 140000 ); + qmemcpy(&premiumitem[i], item, sizeof(ItemStruct)); + premiumitem[i]._iCreateInfo = plvl | 0x800; + premiumitem[i]._iIdentified = 1; + premiumitem[i]._iStatFlag = StoreStatOk(&premiumitem[i]); + qmemcpy(item, &holditem, sizeof(ItemStruct)); +} + +void __fastcall SpawnPremium(int lvl) +{ + int i; // eax + + if ( numpremium < 6 ) + { + for(i = 0; i < 6; i++) + { + if ( premiumitem[i]._itype == -1 ) + SpawnOnePremium(i, premiumlevel + premiumlvladd[i]); + } + numpremium = 6; + } + for ( i = premiumlevel; premiumlevel < lvl; i = premiumlevel ) + { + qmemcpy(premiumitem, &premiumitem[2], sizeof(ItemStruct)); + qmemcpy(&premiumitem[1], &premiumitem[3], sizeof(ItemStruct)); + qmemcpy(&premiumitem[2], &premiumitem[4], sizeof(ItemStruct)); + premiumlevel = i + 1; + SpawnOnePremium(3, premiumlvladd[3] + i + 1); + qmemcpy(&premiumitem[4], &premiumitem[5], sizeof(ItemStruct)); + SpawnOnePremium(5, premiumlvladd[5] + premiumlevel); + } +} +// 69FB38: using guessed type int talker; + +bool __fastcall WitchItemOk(int i) +{ + bool rv; // eax + unsigned char v3; // dl + int v4; // edx + int v5; // ecx + + rv = 0; + v3 = AllItemsList[i].itype; + if ( !v3 ) + rv = 1; + if ( v3 == ITYPE_STAFF ) + rv = 1; + v4 = AllItemsList[i].iMiscId; + if ( v4 == IMISC_MANA ) + rv = 0; + if ( v4 == IMISC_FULLMANA ) + rv = 0; + if ( v4 == IMISC_FULLHEAL ) + rv = 0; + if ( v4 == IMISC_HEAL ) + rv = 0; + v5 = AllItemsList[i].iSpell; + if ( v5 == SPL_TOWN ) + rv = 0; + if ( v5 == SPL_RESURRECT && gbMaxPlayers == 1 ) + rv = 0; + if ( v5 == SPL_HEALOTHER && gbMaxPlayers == 1 ) + rv = 0; + return rv; +} +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall RndWitchItem(int lvl) +{ + int ri; // ebx + int i; // edi + int ril[512]; // [esp+8h] [ebp-804h] + + ri = 0; + i = 1; + if ( AllItemsList[1].iLoc != -1 ) + { + do + { + if ( AllItemsList[i].iRnd && WitchItemOk(i) && lvl >= AllItemsList[i].iMinMLvl ) + ril[ri++] = i; + ++i; + } + while ( AllItemsList[i].iLoc != -1 ); + } + return ril[random(51, ri)] + 1; +} +// 4246D2: using guessed type int var_804[512]; + +void __cdecl SortWitch() +{ + signed int v0; // esi + int *v1; // eax + signed int v2; // ecx + int *v3; // eax + int v4; // ebx + int v5; // edi + + v0 = 3; + if ( witchitem[4]._itype != -1 ) + { + v1 = &witchitem[4]._itype; + do + { + v1 += 92; + ++v0; + } + while ( *v1 != -1 ); + } + v2 = 0; + while ( v0 > 3 && !v2 ) + { + v2 = 1; + if ( v0 > 3 ) + { + v3 = &witchitem[3].IDidx; + v4 = v0 - 3; + do + { + v5 = (int)(v3 + 92); + if ( *v3 > v3[92] ) + { + BubbleSwapItem((ItemStruct *)(v3 - 90), (ItemStruct *)(v3 + 2)); + v2 = 0; + } + --v4; + v3 = (int *)v5; + } + while ( v4 ); + } + --v0; + } +} + +void __fastcall WitchBookLevel(int ii) +{ + int slvl; // edi + + if ( witchitem[ii]._iMiscId == IMISC_BOOK ) + { + witchitem[ii]._iMinMag = spelldata[witchitem[ii]._iSpell].sMinInt; + slvl = plr[myplr]._pSplLvl[witchitem[ii]._iSpell]; + if ( slvl ) + { + do + { + witchitem[ii]._iMinMag += 20 * witchitem[ii]._iMinMag / 100; + --slvl; + if ( witchitem[ii]._iMinMag > 255 ) + { + witchitem[ii]._iMinMag = -1; + slvl = 0; + } + } + while ( slvl ); + } + } +} + +void __fastcall SpawnWitch(int lvl) +{ + int v2; // ebp + int itype; // esi + int iblvl; // eax + signed int ii; // [esp+10h] [ebp-8h] + ItemStruct *itm; // [esp+14h] [ebp-4h] + + GetItemAttrs(0, IDI_MANA, 1); + qmemcpy(witchitem, item, sizeof(ItemStruct)); + witchitem[0]._iCreateInfo = lvl; + witchitem[0]._iStatFlag = 1; + GetItemAttrs(0, IDI_FULLMANA, 1); + qmemcpy(&witchitem[1], item, sizeof(ItemStruct)); + witchitem[1]._iCreateInfo = lvl; + witchitem[1]._iStatFlag = 1; + GetItemAttrs(0, IDI_PORTAL, 1); + qmemcpy(&witchitem[2], item, sizeof(ItemStruct)); + witchitem[2]._iCreateInfo = lvl; + witchitem[2]._iStatFlag = 1; + v2 = random(51, 8) + 10; + ii = 3; + if ( v2 > 3 ) + { + itm = &witchitem[3]; + while ( 1 ) + { + item[0]._iSeed = GetRndSeed(); + SetRndSeed(item[0]._iSeed); + itype = RndWitchItem(lvl) - 1; + GetItemAttrs(0, itype, lvl); + if ( random(51, 100) > 5 || (iblvl = 2 * lvl, iblvl == -1) ) + { + if ( item[0]._iMiscId != IMISC_STAFF ) + continue; + iblvl = 2 * lvl; + if ( iblvl == -1 ) + continue; + } + GetItemBonus(0, itype, iblvl >> 1, iblvl, 1); + if ( item[0]._iIvalue <= 140000 ) + { + qmemcpy(itm, item, sizeof(ItemStruct)); + itm->_iIdentified = 1; + itm->_iCreateInfo = lvl | 0x2000; + WitchBookLevel(ii); + ++ii; + itm->_iStatFlag = StoreStatOk(itm); + ++itm; + if ( ii >= v2 ) + break; + } + } + } + if ( v2 < 20 ) + { + do + { + witchitem[v2]._itype = -1; + v2++; + } + while ( v2 < 20 ); + } + SortWitch(); +} + +int __fastcall RndBoyItem(int lvl) +{ + int ri; // edx + int i; // edi + int ril[512]; // [esp+8h] [ebp-800h] + + ri = 0; + i = 1; + if ( AllItemsList[1].iLoc != -1 ) + { + do + { + if ( AllItemsList[i].iRnd && PremiumItemOk(i) && lvl >= AllItemsList[i].iMinMLvl ) + ril[ri++] = i; + ++i; + } + while ( AllItemsList[i].iLoc != -1 ); + } + return ril[random(49, ri)] + 1; +} +// 4249A4: using guessed type int var_800[512]; + +void __fastcall SpawnBoy(int lvl) +{ + int itype; // esi + + if ( boylevel < lvl >> 1 || boyitem._itype == -1 ) + { + do + { + item[0]._iSeed = GetRndSeed(); + SetRndSeed(item[0]._iSeed); + itype = RndBoyItem(lvl) - 1; + GetItemAttrs(0, itype, lvl); + GetItemBonus(0, itype, lvl, 2 * lvl, 1); + } + while ( item[0]._iIvalue > 90000 ); + qmemcpy(&boyitem, item, sizeof(boyitem)); + boyitem._iCreateInfo = lvl | 0x10; + boyitem._iIdentified = 1; + boyitem._iStatFlag = StoreStatOk(&boyitem); + boylevel = lvl >> 1; + } +} +// 6A8A3C: using guessed type int boylevel; + +bool __fastcall HealerItemOk(int i) +{ + int v1; // ecx + bool result; // eax + int v3; // esi + + v1 = i; + result = 0; + if ( AllItemsList[v1].itype ) + return 0; + v3 = AllItemsList[v1].iMiscId; + if ( v3 == IMISC_SCROLL && AllItemsList[v1].iSpell == SPL_HEAL ) + result = 1; + if ( v3 != IMISC_SCROLLT ) + goto LABEL_12; + if ( AllItemsList[v1].iSpell == SPL_RESURRECT && gbMaxPlayers != 1 ) + result = 0; + if ( AllItemsList[v1].iSpell != SPL_HEALOTHER ) + { +LABEL_12: + if ( gbMaxPlayers != 1 ) + goto LABEL_21; + goto LABEL_13; + } + if ( gbMaxPlayers != 1 ) + { + result = 1; + goto LABEL_12; + } +LABEL_13: + if ( v3 == IMISC_ELIXSTR ) + result = 1; + if ( v3 == IMISC_ELIXMAG ) + result = 1; + if ( v3 == IMISC_ELIXDEX ) + result = 1; + if ( v3 == IMISC_ELIXVIT ) + result = 1; +LABEL_21: + if ( v3 == IMISC_FULLHEAL ) + result = 1; + if ( v3 == IMISC_REJUV ) + result = 1; + if ( v3 == IMISC_FULLREJUV ) + result = 1; + if ( v3 == IMISC_HEAL ) + result = 0; + if ( v3 == IMISC_FULLHEAL ) + result = 0; + if ( v3 == IMISC_MANA ) + result = 0; + if ( v3 == IMISC_FULLMANA ) + return 0; + return result; +} +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall RndHealerItem(int lvl) +{ + int ri; // ebx + int i; // edi + int ril[512]; // [esp+8h] [ebp-804h] + + ri = 0; + i = 1; + if ( AllItemsList[1].iLoc != -1 ) + { + do + { + if ( AllItemsList[i].iRnd && HealerItemOk(i) && lvl >= AllItemsList[i].iMinMLvl ) + ril[ri++] = i; + ++i; + } + while ( AllItemsList[i].iLoc != -1 ); + } + return ril[random(50, ri)] + 1; +} +// 424B49: using guessed type int var_804[512]; + +void __cdecl SortHealer() +{ + signed int v0; // esi + int *v1; // eax + signed int v2; // ecx + int *v3; // eax + int v4; // ebx + int v5; // edi + + v0 = 2; + if ( healitem[3]._itype != -1 ) + { + v1 = &healitem[3]._itype; + do + { + v1 += 92; + ++v0; + } + while ( *v1 != -1 ); + } + v2 = 0; + while ( v0 > 2 && !v2 ) + { + v2 = 1; + if ( v0 > 2 ) + { + v3 = &healitem[2].IDidx; + v4 = v0 - 2; + do + { + v5 = (int)(v3 + 92); + if ( *v3 > v3[92] ) + { + BubbleSwapItem((ItemStruct *)(v3 - 90), (ItemStruct *)(v3 + 2)); + v2 = 0; + } + --v4; + v3 = (int *)v5; + } + while ( v4 ); + } + --v0; + } +} + +void __fastcall SpawnHealer(int lvl) +{ + int v3; // eax + ItemStruct *v4; // ebp + signed int v8; // [esp-4h] [ebp-20h] + int v10; // [esp+14h] [ebp-8h] + + GetItemAttrs(0, IDI_HEAL, 1); + qmemcpy(healitem, item, sizeof(ItemStruct)); + healitem[0]._iCreateInfo = lvl; + healitem[0]._iStatFlag = 1; + GetItemAttrs(0, IDI_FULLHEAL, 1); + qmemcpy(&healitem[1], item, sizeof(ItemStruct)); + healitem[1]._iCreateInfo = lvl; + healitem[1]._iStatFlag = 1; + if ( gbMaxPlayers == 1 ) + { + v8 = 2; + } + else + { + GetItemAttrs(0, IDI_RESURRECT, 1); + qmemcpy(&healitem[2], item, sizeof(ItemStruct)); + healitem[2]._iCreateInfo = lvl; + healitem[2]._iStatFlag = 1; + v8 = 3; + } + v3 = random(50, 8) + 10; + if ( v8 < v3 ) + { + v4 = &healitem[v8]; + v10 = v3 - v8; + do + { + item[0]._iSeed = GetRndSeed(); + SetRndSeed(item[0]._iSeed); + GetItemAttrs(0, RndHealerItem(lvl) - 1, lvl); + qmemcpy(v4, item, sizeof(ItemStruct)); + v4->_iCreateInfo = lvl | 0x4000; + v4->_iIdentified = 1; + v4->_iStatFlag = StoreStatOk(v4); + ++v4; + --v10; + } + while ( v10 ); + } + if ( v3 < 20 ) + { + do + { + healitem[v3]._itype = -1; + v3++; + } + while ( v3 < 20 ); + } + SortHealer(); +} +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl SpawnStoreGold() +{ + GetItemAttrs(0, IDI_GOLD, 1); + qmemcpy(&golditem, item, sizeof(golditem)); + golditem._iStatFlag = 1; +} + +void __fastcall RecreateSmithItem(int ii, int idx, int plvl, int iseed) +{ + SetRndSeed(iseed); + GetItemAttrs(ii, RndSmithItem(plvl) - 1, plvl); + item[ii]._iSeed = iseed; + item[ii]._iCreateInfo = plvl | 0x400; + item[ii]._iIdentified = 1; +} + +void __fastcall RecreatePremiumItem(int ii, int idx, int lvl, int iseed) +{ + int itype; // edi + + SetRndSeed(iseed); + itype = RndPremiumItem(lvl >> 2, lvl) - 1; + GetItemAttrs(ii, itype, lvl); + GetItemBonus(ii, itype, lvl >> 1, lvl, 1); + item[ii]._iCreateInfo = lvl | 0x800; + item[ii]._iSeed = iseed; + item[ii]._iIdentified = 1; +} + +void __fastcall RecreateBoyItem(int ii, int idx, int lvl, int iseed) +{ + int itype; // edi + + SetRndSeed(iseed); + itype = RndBoyItem(lvl) - 1; + GetItemAttrs(ii, itype, lvl); + GetItemBonus(ii, itype, lvl, 2 * lvl, 1); + item[ii]._iCreateInfo = lvl | 0x1000; + item[ii]._iSeed = iseed; + item[ii]._iIdentified = 1; +} + +void __fastcall RecreateWitchItem(int ii, int idx, int lvl, int iseed) +{ + int itype; // edi + int iblvl; // eax + + if ( idx == IDI_MANA || idx == IDI_FULLMANA || idx == IDI_PORTAL ) + { + GetItemAttrs(ii, idx, lvl); + } + else + { + SetRndSeed(iseed); + itype = RndWitchItem(lvl) - 1; + GetItemAttrs(ii, itype, lvl); + iblvl = 2 * lvl; + if ( iblvl != -1 && (random(51, 100) <= 5 || item[ii]._iMiscId == IMISC_STAFF) ) + { + GetItemBonus(ii, itype, iblvl >> 1, iblvl, 1); + } + } + item[ii]._iCreateInfo = lvl | 0x2000; + item[ii]._iSeed = iseed; + item[ii]._iIdentified = 1; +} + +void __fastcall RecreateHealerItem(int ii, int idx, int lvl, int iseed) +{ + if ( idx != IDI_HEAL && idx != IDI_FULLHEAL && idx != IDI_RESURRECT ) + { + SetRndSeed(iseed); + idx = RndHealerItem(lvl) - 1; + } + GetItemAttrs(ii, idx, lvl); + item[ii]._iCreateInfo = lvl | 0x4000; + item[ii]._iSeed = iseed; + item[ii]._iIdentified = 1; +} + +void __fastcall RecreateTownItem(int ii, int idx, unsigned short icreateinfo, int iseed, int ivalue) +{ + if ( icreateinfo & 0x400 ) + RecreateSmithItem(ii, idx, icreateinfo & 0x3F, iseed); + else if ( icreateinfo & 0x800 ) + RecreatePremiumItem(ii, idx, icreateinfo & 0x3F, iseed); + else if ( icreateinfo & 0x1000 ) + RecreateBoyItem(ii, idx, icreateinfo & 0x3F, iseed); + else if ( icreateinfo & 0x2000 ) + RecreateWitchItem(ii, idx, icreateinfo & 0x3F, iseed); + else if ( icreateinfo & 0x4000 ) + RecreateHealerItem(ii, idx, icreateinfo & 0x3F, iseed); +} + +void __cdecl RecalcStoreStats() +{ + int i; + + for(i = 0; i < 20; i++) + { + if ( smithitem[i]._itype != -1 ) + smithitem[i]._iStatFlag = StoreStatOk(&smithitem[i]); + if ( witchitem[i]._itype != -1 ) + witchitem[i]._iStatFlag = StoreStatOk(&witchitem[i]); + if ( healitem[i]._itype != -1 ) + healitem[i]._iStatFlag = StoreStatOk(&healitem[i]); + } + + for(i = 0; i < 6; i++) + { + if ( premiumitem[i]._itype != -1 ) + premiumitem[i]._iStatFlag = StoreStatOk(&premiumitem[i]); + } + + boyitem._iStatFlag = StoreStatOk(&boyitem); +} +// 6A6BB8: using guessed type int stextscrl; +// 6AA700: using guessed type int stextdown; + +int __cdecl ItemNoFlippy() +{ + int r; // ecx + + r = itemactive[numitems-1]; + item[r]._iAnimFlag = 0; + item[r]._iAnimFrame = item[r]._iAnimLen; + item[r]._iSelFlag = 1; + + return r; +} + +void __fastcall CreateSpellBook(int x, int y, int ispell, bool sendmsg, int delta) +{ + int ii; // edi + int idx; // [esp+8h] [ebp-8h] + bool done; // [esp+Ch] [ebp-4h] + + done = 0; + idx = RndTypeItems(0, 24); + if ( numitems < MAXITEMS ) + { + ii = itemavail[0]; + GetSuperItemSpace(x, y, itemavail[0]); + itemactive[numitems] = ii; + itemavail[0] = itemavail[-numitems + 126]; /* MAXITEMS */ + do + { + SetupAllItems(ii, idx, GetRndSeed(), 2 * currlevel, 1, 1, 0, delta); + if ( item[ii]._iMiscId == IMISC_BOOK && item[ii]._iSpell == ispell ) + done = 1; + } + while ( !done ); + if ( sendmsg ) + NetSendCmdDItem(0, ii); + if ( delta ) + DeltaAddItem(ii); + ++numitems; + } +} + +void __fastcall CreateMagicItem(int x, int y, int imisc, int icurs, int sendmsg, int delta) +{ + int ii; // esi + int idx; // ebx + bool done; // [esp+Ch] [ebp-4h] + + done = 0; + if ( numitems < MAXITEMS ) + { + ii = itemavail[0]; + GetSuperItemSpace(x, y, itemavail[0]); + itemactive[numitems] = ii; + itemavail[0] = itemavail[-numitems + 126]; /* MAXITEMS */ + idx = RndTypeItems(imisc, 0); + do + { + SetupAllItems(ii, idx, GetRndSeed(), 2 * currlevel, 1, 1, 0, delta); + if ( item[ii]._iCurs == icurs ) + done = 1; + else + idx = RndTypeItems(imisc, 0); + } + while ( !done ); + if ( sendmsg ) + NetSendCmdDItem(0, ii); + if ( delta ) + DeltaAddItem(ii); + ++numitems; + } +} + +bool __fastcall GetItemRecord(int dwSeed, int CI, int indx) +{ + int v3; // edi + int *v4; // ebx + int v6; // [esp+Ch] [ebp-18h] + DWORD v7; // [esp+10h] [ebp-14h] + int *v8; // [esp+14h] [ebp-10h] + unsigned short *v9; // [esp+18h] [ebp-Ch] + ItemGetRecordStruct *v10; // [esp+1Ch] [ebp-8h] + short v11; // [esp+20h] [ebp-4h] + + v11 = CI; + v6 = dwSeed; + v3 = 0; + v7 = GetTickCount(); + if ( gnNumGetRecords <= 0 ) + return 1; + v8 = &itemrecord[0].nIndex; + v9 = &itemrecord[0].wCI; + v10 = itemrecord; + v4 = &itemrecord[0].dwTimestamp; + while ( v7 - *v4 > 6000 ) + { + NextItemRecord(v3); + --v10; + v9 -= 8; + --v3; + v4 -= 4; + v8 -= 4; +LABEL_8: + ++v10; + v9 += 8; + v8 += 4; + ++v3; + v4 += 4; + if ( v3 >= gnNumGetRecords ) + return 1; + } + if ( v6 != v10->nSeed || v11 != *v9 || indx != *v8 ) + goto LABEL_8; + return 0; +} + +void __fastcall NextItemRecord(int i) +{ + int v1; // eax + + v1 = gnNumGetRecords-- - 1; + if ( gnNumGetRecords ) + { + itemrecord[i].nIndex = itemrecord[v1].nIndex; + itemrecord[i].nSeed = itemrecord[v1].nSeed; + itemrecord[i].wCI = itemrecord[v1].wCI; + itemrecord[i].dwTimestamp = itemrecord[v1].dwTimestamp; + } +} + +void __fastcall SetItemRecord(int dwSeed, int CI, int indx) +{ + int i; // ecx + + if ( gnNumGetRecords != MAXITEMS ) + { + i = gnNumGetRecords++; + itemrecord[i].dwTimestamp = GetTickCount(); + itemrecord[i].nSeed = dwSeed; + itemrecord[i].wCI = CI; + itemrecord[i].nIndex = indx; + } +} + +void __fastcall PutItemRecord(int seed, int ci, int index) +{ + int v3; // edi + int *v4; // ebx + int v5; // [esp+Ch] [ebp-18h] + DWORD v6; // [esp+10h] [ebp-14h] + int *v7; // [esp+14h] [ebp-10h] + unsigned short *v8; // [esp+18h] [ebp-Ch] + ItemGetRecordStruct *v9; // [esp+1Ch] [ebp-8h] + short v10; // [esp+20h] [ebp-4h] + + v10 = ci; + v5 = seed; + v3 = 0; + v6 = GetTickCount(); + if ( gnNumGetRecords > 0 ) + { + v7 = &itemrecord[0].nIndex; + v8 = &itemrecord[0].wCI; + v9 = itemrecord; + v4 = &itemrecord[0].dwTimestamp; + do + { + if ( v6 - *v4 <= 6000 ) + { + if ( v5 == v9->nSeed && v10 == *v8 && index == *v7 ) + { + NextItemRecord(v3); + return; + } + } + else + { + NextItemRecord(v3); + --v9; + v8 -= 8; + --v3; + v4 -= 4; + v7 -= 4; + } + ++v9; + v8 += 8; + v7 += 4; + ++v3; + v4 += 4; + } + while ( v3 < gnNumGetRecords ); + } +} diff --git a/Source/items.h b/Source/items.h new file mode 100644 index 000000000..6a2c7a1d1 --- /dev/null +++ b/Source/items.h @@ -0,0 +1,146 @@ +//HEADER_GOES_HERE +#ifndef __ITEMS_H__ +#define __ITEMS_H__ + +extern int itemactive[MAXITEMS]; +extern int uitemflag; +extern int itemavail[MAXITEMS]; +extern ItemStruct curruitem; +extern ItemGetRecordStruct itemrecord[MAXITEMS]; +extern ItemStruct item[MAXITEMS+1]; +extern BOOL itemhold[3][3]; +extern unsigned char *Item2Frm[35]; +extern int UniqueItemFlag[128]; +extern int numitems; +extern int gnNumGetRecords; + +void __cdecl InitItemGFX(); +bool __fastcall ItemPlace(int xp, int yp); +void __cdecl AddInitItems(); +void __cdecl InitItems(); +void __fastcall CalcPlrItemVals(int p, BOOL Loadgfx); +void __fastcall CalcPlrScrolls(int p); +void __fastcall CalcPlrStaff(int pnum); +void __fastcall CalcSelfItems(int pnum); +void __fastcall CalcPlrItemMin(int pnum); +bool __fastcall ItemMinStats(PlayerStruct *p, ItemStruct *x); +void __fastcall CalcPlrBookVals(int p); +void __fastcall CalcPlrInv(int p, BOOL Loadgfx); +void __fastcall SetPlrHandItem(ItemStruct *h, int idata); +void __fastcall GetPlrHandSeed(ItemStruct *h); +void __fastcall GetGoldSeed(int pnum, ItemStruct *h); +void __fastcall SetPlrHandSeed(ItemStruct *h, int iseed); +void __fastcall SetPlrHandGoldCurs(ItemStruct *h); +void __fastcall CreatePlrItems(int p); +BOOL __fastcall ItemSpaceOk(int i, int j); +bool __fastcall GetItemSpace(int x, int y, char inum); +void __fastcall GetSuperItemSpace(int x, int y, char inum); +void __fastcall GetSuperItemLoc(int x, int y, int *xx, int *yy); +void __fastcall CalcItemValue(int i); +void __fastcall GetBookSpell(int i, int lvl); +void __fastcall GetStaffPower(int i, int lvl, int bs, unsigned char onlygood); +void __fastcall GetStaffSpell(int i, int lvl, unsigned char onlygood); +void __fastcall GetItemAttrs(int i, int idata, int lvl); +int __fastcall RndPL(int param1, int param2); +int __fastcall PLVal(int pv, int p1, int p2, int minv, int maxv); +void __fastcall SaveItemPower(int i, int power, int param1, int param2, int minval, int maxval, int multval); +void __fastcall GetItemPower(int i, int minlvl, int maxlvl, int flgs, int onlygood); +void __fastcall GetItemBonus(int i, int idata, int minlvl, int maxlvl, int onlygood); +void __fastcall SetupItem(int i); +int __fastcall RndItem(int m); +int __fastcall RndUItem(int m); +int __cdecl RndAllItems(); +int __fastcall RndTypeItems(int itype, int imid); +int __fastcall CheckUnique(int i, int lvl, int uper, bool recreate); +void __fastcall GetUniqueItem(int i, int uid); +void __fastcall SpawnUnique(int uid, int x, int y); +void __fastcall ItemRndDur(int ii); +void __fastcall SetupAllItems(int ii, int idx, int iseed, int lvl, int uper, int onlygood, int recreate, int pregen); +void __fastcall SpawnItem(int m, int x, int y, unsigned char sendmsg); +void __fastcall CreateItem(int uid, int x, int y); +void __fastcall CreateRndItem(int x, int y, unsigned char onlygood, unsigned char sendmsg, int delta); +void __fastcall SetupAllUseful(int ii, int iseed, int lvl); +void __fastcall CreateRndUseful(int pnum, int x, int y, unsigned char sendmsg); +void __fastcall CreateTypeItem(int x, int y, unsigned char onlygood, int itype, int imisc, int sendmsg, int delta); +void __fastcall RecreateItem(int ii, int idx, unsigned short ic, int iseed, int ivalue); +void __fastcall RecreateEar(int ii, unsigned short ic, int iseed, unsigned char Id, int dur, int mdur, int ch, int mch, int ivalue, int ibuff); +void __fastcall SpawnQuestItem(int itemid, int x, int y, int randarea, int selflag); +void __cdecl SpawnRock(); +void __fastcall RespawnItem(int i, bool FlipFlag); +void __fastcall DeleteItem(int ii, int i); +void __cdecl ItemDoppel(); +void __cdecl ProcessItems(); +void __cdecl FreeItemGFX(); +void __fastcall GetItemFrm(int i); +void __fastcall GetItemStr(int i); +void __fastcall CheckIdentify(int pnum, int cii); +void __fastcall DoRepair(int pnum, int cii); +void __fastcall RepairItem(ItemStruct *i, int lvl); +void __fastcall DoRecharge(int pnum, int cii); +void __fastcall RechargeItem(ItemStruct *i, int r); +void __fastcall PrintItemOil(char IDidx); +void __fastcall PrintItemPower(char plidx, ItemStruct *x); +void __cdecl DrawUBack(); +void __fastcall PrintUString(int x, int y, int cjustflag, char *str, int col); +void __fastcall DrawULine(int y); +void __cdecl DrawUniqueInfo(); +void __fastcall PrintItemMisc(ItemStruct *x); +void __fastcall PrintItemDetails(ItemStruct *x); +void __fastcall PrintItemDur(ItemStruct *x); +void __fastcall UseItem(int p, int Mid, int spl); +bool __fastcall StoreStatOk(ItemStruct *h); +bool __fastcall SmithItemOk(int i); +int __fastcall RndSmithItem(int lvl); +void __fastcall BubbleSwapItem(ItemStruct *a, ItemStruct *b); +void __cdecl SortSmith(); +void __fastcall SpawnSmith(int lvl); +bool __fastcall PremiumItemOk(int i); +int __fastcall RndPremiumItem(int minlvl, int maxlvl); +void __fastcall SpawnOnePremium(int i, int plvl); +void __fastcall SpawnPremium(int lvl); +bool __fastcall WitchItemOk(int i); +int __fastcall RndWitchItem(int lvl); +void __cdecl SortWitch(); +void __fastcall WitchBookLevel(int ii); +void __fastcall SpawnWitch(int lvl); +int __fastcall RndBoyItem(int lvl); +void __fastcall SpawnBoy(int lvl); +bool __fastcall HealerItemOk(int i); +int __fastcall RndHealerItem(int lvl); +void __cdecl SortHealer(); +void __fastcall SpawnHealer(int lvl); +void __cdecl SpawnStoreGold(); +void __fastcall RecreateSmithItem(int ii, int idx, int plvl, int iseed); +void __fastcall RecreatePremiumItem(int ii, int idx, int lvl, int iseed); +void __fastcall RecreateBoyItem(int ii, int idx, int lvl, int iseed); +void __fastcall RecreateWitchItem(int ii, int idx, int lvl, int iseed); +void __fastcall RecreateHealerItem(int ii, int idx, int lvl, int iseed); +void __fastcall RecreateTownItem(int ii, int idx, unsigned short icreateinfo, int iseed, int ivalue); +void __cdecl RecalcStoreStats(); +int __cdecl ItemNoFlippy(); +void __fastcall CreateSpellBook(int x, int y, int ispell, bool sendmsg, int delta); +void __fastcall CreateMagicItem(int x, int y, int imisc, int icurs, int sendmsg, int delta); +bool __fastcall GetItemRecord(int dwSeed, int CI, int indx); +void __fastcall NextItemRecord(int i); +void __fastcall SetItemRecord(int dwSeed, int CI, int indx); +void __fastcall PutItemRecord(int seed, int ci, int index); + +/* rdata */ + +extern const PLStruct PL_Prefix[84]; +extern const PLStruct PL_Suffix[96]; +extern const UItemStruct UniqueItemList[91]; + +/* data */ + + +extern ItemDataStruct AllItemsList[157]; +extern unsigned char ItemCAnimTbl[169]; +extern char *ItemDropStrs[35]; +extern unsigned char ItemAnimLs[35]; +extern int ItemDropSnds[35]; +extern int ItemInvSnds[35]; +extern int idoppely; // weak +extern int premiumlvladd[6]; + +#endif /* __ITEMS_H__ */ diff --git a/Source/lighting.cpp b/Source/lighting.cpp new file mode 100644 index 000000000..38f3c7960 --- /dev/null +++ b/Source/lighting.cpp @@ -0,0 +1,1755 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +LightListStruct VisionList[32]; +char lightactive[32]; +LightListStruct LightList[32]; +int numlights; +char dung_map_radius[2048]; /* char [16][128] */ +int dovision; // weak +int numvision; +char lightmax; // weak +int dolighting; // weak +char dung_map_rgba[16384]; /* int [64][64] short [64][128] char [64][256] */ +int visionid; +char *pLightTbl; /* todo: struct? */ +int lightflag; // weak +#endif + +char CrawlTable[2749] = +{ + 1, + 0, 0, + 4, + 0, 1, 0, -1, -1, 0, 1, 0, + 16, + 0, 2, 0, -2, -1, 2, 1, 2, + -1, -2, 1, -2, -1, 1, 1, 1, + -1, -1, 1, -1, -2, 1, 2, 1, + -2, -1, 2, -1, -2, 0, 2, 0, + 24, + 0, 3, 0, -3, -1, 3, 1, 3, + -1, -3, 1, -3, -2, 3, 2, 3, + -2, -3, 2, -3, -2, 2, 2, 2, + -2, -2, 2, -2, -3, 2, 3, 2, + -3, -2, 3, -2, -3, 1, 3, 1, + -3, -1, 3, -1, -3, 0, 3, 0, + 32, + 0, 4, 0, -4, -1, 4, 1, 4, + -1, -4, 1, -4, -2, 4, 2, 4, + -2, -4, 2, -4, -3, 4, 3, 4, + -3, -4, 3, -4, -3, 3, 3, 3, + -3, -3, 3, -3, -4, 3, 4, 3, + -4, -3, 4, -3, -4, 2, 4, 2, + -4, -2, 4, -2, -4, 1, 4, 1, + -4, -1, 4, -1, -4, 0, 4, 0, + 40, + 0, 5, 0, -5, -1, 5, 1, 5, + -1, -5, 1, -5, -2, 5, 2, 5, + -2, -5, 2, -5, -3, 5, 3, 5, + -3, -5, 3, -5, -4, 5, 4, 5, + -4, -5, 4, -5, -4, 4, 4, 4, + -4, -4, 4, -4, -5, 4, 5, 4, + -5, -4, 5, -4, -5, 3, 5, 3, + -5, -3, 5, -3, -5, 2, 5, 2, + -5, -2, 5, -2, -5, 1, 5, 1, + -5, -1, 5, -1, -5, 0, 5, 0, + 48, + 0, 6, 0, -6, -1, 6, 1, 6, + -1, -6, 1, -6, -2, 6, 2, 6, + -2, -6, 2, -6, -3, 6, 3, 6, + -3, -6, 3, -6, -4, 6, 4, 6, + -4, -6, 4, -6, -5, 6, 5, 6, + -5, -6, 5, -6, -5, 5, 5, 5, + -5, -5, 5, -5, -6, 5, 6, 5, + -6, -5, 6, -5, -6, 4, 6, 4, + -6, -4, 6, -4, -6, 3, 6, 3, + -6, -3, 6, -3, -6, 2, 6, 2, + -6, -2, 6, -2, -6, 1, 6, 1, + -6, -1, 6, -1, -6, 0, 6, 0, + 56, + 0, 7, 0, -7, -1, 7, 1, 7, + -1, -7, 1, -7, -2, 7, 2, 7, + -2, -7, 2, -7, -3, 7, 3, 7, + -3, -7, 3, -7, -4, 7, 4, 7, + -4, -7, 4, -7, -5, 7, 5, 7, + -5, -7, 5, -7, -6, 7, 6, 7, + -6, -7, 6, -7, -6, 6, 6, 6, + -6, -6, 6, -6, -7, 6, 7, 6, + -7, -6, 7, -6, -7, 5, 7, 5, + -7, -5, 7, -5, -7, 4, 7, 4, + -7, -4, 7, -4, -7, 3, 7, 3, + -7, -3, 7, -3, -7, 2, 7, 2, + -7, -2, 7, -2, -7, 1, 7, 1, + -7, -1, 7, -1, -7, 0, 7, 0, + 64, + 0, 8, 0, -8, -1, 8, 1, 8, + -1, -8, 1, -8, -2, 8, 2, 8, + -2, -8, 2, -8, -3, 8, 3, 8, + -3, -8, 3, -8, -4, 8, 4, 8, + -4, -8, 4, -8, -5, 8, 5, 8, + -5, -8, 5, -8, -6, 8, 6, 8, + -6, -8, 6, -8, -7, 8, 7, 8, + -7, -8, 7, -8, -7, 7, 7, 7, + -7, -7, 7, -7, -8, 7, 8, 7, + -8, -7, 8, -7, -8, 6, 8, 6, + -8, -6, 8, -6, -8, 5, 8, 5, + -8, -5, 8, -5, -8, 4, 8, 4, + -8, -4, 8, -4, -8, 3, 8, 3, + -8, -3, 8, -3, -8, 2, 8, 2, + -8, -2, 8, -2, -8, 1, 8, 1, + -8, -1, 8, -1, -8, 0, 8, 0, + 72, + 0, 9, 0, -9, -1, 9, 1, 9, + -1, -9, 1, -9, -2, 9, 2, 9, + -2, -9, 2, -9, -3, 9, 3, 9, + -3, -9, 3, -9, -4, 9, 4, 9, + -4, -9, 4, -9, -5, 9, 5, 9, + -5, -9, 5, -9, -6, 9, 6, 9, + -6, -9, 6, -9, -7, 9, 7, 9, + -7, -9, 7, -9, -8, 9, 8, 9, + -8, -9, 8, -9, -8, 8, 8, 8, + -8, -8, 8, -8, -9, 8, 9, 8, + -9, -8, 9, -8, -9, 7, 9, 7, + -9, -7, 9, -7, -9, 6, 9, 6, + -9, -6, 9, -6, -9, 5, 9, 5, + -9, -5, 9, -5, -9, 4, 9, 4, + -9, -4, 9, -4, -9, 3, 9, 3, + -9, -3, 9, -3, -9, 2, 9, 2, + -9, -2, 9, -2, -9, 1, 9, 1, + -9, -1, 9, -1, -9, 0, 9, 0, + 80, + 0, 10, 0, -10, -1, 10, 1, 10, + -1, -10, 1, -10, -2, 10, 2, 10, + -2, -10, 2, -10, -3, 10, 3, 10, + -3, -10, 3, -10, -4, 10, 4, 10, + -4, -10, 4, -10, -5, 10, 5, 10, + -5, -10, 5, -10, -6, 10, 6, 10, + -6, -10, 6, -10, -7, 10, 7, 10, + -7, -10, 7, -10, -8, 10, 8, 10, + -8, -10, 8, -10, -9, 10, 9, 10, + -9, -10, 9, -10, -9, 9, 9, 9, + -9, -9, 9, -9, -10, 9, 10, 9, + -10, -9, 10, -9, -10, 8, 10, 8, + -10, -8, 10, -8, -10, 7, 10, 7, + -10, -7, 10, -7, -10, 6, 10, 6, + -10, -6, 10, -6, -10, 5, 10, 5, + -10, -5, 10, -5, -10, 4, 10, 4, + -10, -4, 10, -4, -10, 3, 10, 3, + -10, -3, 10, -3, -10, 2, 10, 2, + -10, -2, 10, -2, -10, 1, 10, 1, + -10, -1, 10, -1, -10, 0, 10, 0, + 88, + 0, 11, 0, -11, -1, 11, 1, 11, + -1, -11, 1, -11, -2, 11, 2, 11, + -2, -11, 2, -11, -3, 11, 3, 11, + -3, -11, 3, -11, -4, 11, 4, 11, + -4, -11, 4, -11, -5, 11, 5, 11, + -5, -11, 5, -11, -6, 11, 6, 11, + -6, -11, 6, -11, -7, 11, 7, 11, + -7, -11, 7, -11, -8, 11, 8, 11, + -8, -11, 8, -11, -9, 11, 9, 11, + -9, -11, 9, -11, -10, 11, 10, 11, + -10, -11, 10, -11, -10, 10, 10, 10, + -10, -10, 10, -10, -11, 10, 11, 10, + -11, -10, 11, -10, -11, 9, 11, 9, + -11, -9, 11, -9, -11, 8, 11, 8, + -11, -8, 11, -8, -11, 7, 11, 7, + -11, -7, 11, -7, -11, 6, 11, 6, + -11, -6, 11, -6, -11, 5, 11, 5, + -11, -5, 11, -5, -11, 4, 11, 4, + -11, -4, 11, -4, -11, 3, 11, 3, + -11, -3, 11, -3, -11, 2, 11, 2, + -11, -2, 11, -2, -11, 1, 11, 1, + -11, -1, 11, -1, -11, 0, 11, 0, + 96, + 0, 12, 0, -12, -1, 12, 1, 12, + -1, -12, 1, -12, -2, 12, 2, 12, + -2, -12, 2, -12, -3, 12, 3, 12, + -3, -12, 3, -12, -4, 12, 4, 12, + -4, -12, 4, -12, -5, 12, 5, 12, + -5, -12, 5, -12, -6, 12, 6, 12, + -6, -12, 6, -12, -7, 12, 7, 12, + -7, -12, 7, -12, -8, 12, 8, 12, + -8, -12, 8, -12, -9, 12, 9, 12, + -9, -12, 9, -12, -10, 12, 10, 12, + -10, -12, 10, -12, -11, 12, 11, 12, + -11, -12, 11, -12, -11, 11, 11, 11, + -11, -11, 11, -11, -12, 11, 12, 11, + -12, -11, 12, -11, -12, 10, 12, 10, + -12, -10, 12, -10, -12, 9, 12, 9, + -12, -9, 12, -9, -12, 8, 12, 8, + -12, -8, 12, -8, -12, 7, 12, 7, + -12, -7, 12, -7, -12, 6, 12, 6, + -12, -6, 12, -6, -12, 5, 12, 5, + -12, -5, 12, -5, -12, 4, 12, 4, + -12, -4, 12, -4, -12, 3, 12, 3, + -12, -3, 12, -3, -12, 2, 12, 2, + -12, -2, 12, -2, -12, 1, 12, 1, + -12, -1, 12, -1, -12, 0, 12, 0, + 104, + 0, 13, 0, -13, -1, 13, 1, 13, + -1, -13, 1, -13, -2, 13, 2, 13, + -2, -13, 2, -13, -3, 13, 3, 13, + -3, -13, 3, -13, -4, 13, 4, 13, + -4, -13, 4, -13, -5, 13, 5, 13, + -5, -13, 5, -13, -6, 13, 6, 13, + -6, -13, 6, -13, -7, 13, 7, 13, + -7, -13, 7, -13, -8, 13, 8, 13, + -8, -13, 8, -13, -9, 13, 9, 13, + -9, -13, 9, -13, -10, 13, 10, 13, + -10, -13, 10, -13, -11, 13, 11, 13, + -11, -13, 11, -13, -12, 13, 12, 13, + -12, -13, 12, -13, -12, 12, 12, 12, + -12, -12, 12, -12, -13, 12, 13, 12, + -13, -12, 13, -12, -13, 11, 13, 11, + -13, -11, 13, -11, -13, 10, 13, 10, + -13, -10, 13, -10, -13, 9, 13, 9, + -13, -9, 13, -9, -13, 8, 13, 8, + -13, -8, 13, -8, -13, 7, 13, 7, + -13, -7, 13, -7, -13, 6, 13, 6, + -13, -6, 13, -6, -13, 5, 13, 5, + -13, -5, 13, -5, -13, 4, 13, 4, + -13, -4, 13, -4, -13, 3, 13, 3, + -13, -3, 13, -3, -13, 2, 13, 2, + -13, -2, 13, -2, -13, 1, 13, 1, + -13, -1, 13, -1, -13, 0, 13, 0, + 112, + 0, 14, 0, -14, -1, 14, 1, 14, + -1, -14, 1, -14, -2, 14, 2, 14, + -2, -14, 2, -14, -3, 14, 3, 14, + -3, -14, 3, -14, -4, 14, 4, 14, + -4, -14, 4, -14, -5, 14, 5, 14, + -5, -14, 5, -14, -6, 14, 6, 14, + -6, -14, 6, -14, -7, 14, 7, 14, + -7, -14, 7, -14, -8, 14, 8, 14, + -8, -14, 8, -14, -9, 14, 9, 14, + -9, -14, 9, -14, -10, 14, 10, 14, + -10, -14, 10, -14, -11, 14, 11, 14, + -11, -14, 11, -14, -12, 14, 12, 14, + -12, -14, 12, -14, -13, 14, 13, 14, + -13, -14, 13, -14, -13, 13, 13, 13, + -13, -13, 13, -13, -14, 13, 14, 13, + -14, -13, 14, -13, -14, 12, 14, 12, + -14, -12, 14, -12, -14, 11, 14, 11, + -14, -11, 14, -11, -14, 10, 14, 10, + -14, -10, 14, -10, -14, 9, 14, 9, + -14, -9, 14, -9, -14, 8, 14, 8, + -14, -8, 14, -8, -14, 7, 14, 7, + -14, -7, 14, -7, -14, 6, 14, 6, + -14, -6, 14, -6, -14, 5, 14, 5, + -14, -5, 14, -5, -14, 4, 14, 4, + -14, -4, 14, -4, -14, 3, 14, 3, + -14, -3, 14, -3, -14, 2, 14, 2, + -14, -2, 14, -2, -14, 1, 14, 1, + -14, -1, 14, -1, -14, 0, 14, 0, + 120, + 0, 15, 0, -15, -1, 15, 1, 15, + -1, -15, 1, -15, -2, 15, 2, 15, + -2, -15, 2, -15, -3, 15, 3, 15, + -3, -15, 3, -15, -4, 15, 4, 15, + -4, -15, 4, -15, -5, 15, 5, 15, + -5, -15, 5, -15, -6, 15, 6, 15, + -6, -15, 6, -15, -7, 15, 7, 15, + -7, -15, 7, -15, -8, 15, 8, 15, + -8, -15, 8, -15, -9, 15, 9, 15, + -9, -15, 9, -15, -10, 15, 10, 15, + -10, -15, 10, -15, -11, 15, 11, 15, + -11, -15, 11, -15, -12, 15, 12, 15, + -12, -15, 12, -15, -13, 15, 13, 15, + -13, -15, 13, -15, -14, 15, 14, 15, + -14, -15, 14, -15, -14, 14, 14, 14, + -14, -14, 14, -14, -15, 14, 15, 14, + -15, -14, 15, -14, -15, 13, 15, 13, + -15, -13, 15, -13, -15, 12, 15, 12, + -15, -12, 15, -12, -15, 11, 15, 11, + -15, -11, 15, -11, -15, 10, 15, 10, + -15, -10, 15, -10, -15, 9, 15, 9, + -15, -9, 15, -9, -15, 8, 15, 8, + -15, -8, 15, -8, -15, 7, 15, 7, + -15, -7, 15, -7, -15, 6, 15, 6, + -15, -6, 15, -6, -15, 5, 15, 5, + -15, -5, 15, -5, -15, 4, 15, 4, + -15, -4, 15, -4, -15, 3, 15, 3, + -15, -3, 15, -3, -15, 2, 15, 2, + -15, -2, 15, -2, -15, 1, 15, 1, + -15, -1, 15, -1, -15, 0, 15, 0, + (char)128, + 0, 16, 0, -16, -1, 16, 1, 16, + -1, -16, 1, -16, -2, 16, 2, 16, + -2, -16, 2, -16, -3, 16, 3, 16, + -3, -16, 3, -16, -4, 16, 4, 16, + -4, -16, 4, -16, -5, 16, 5, 16, + -5, -16, 5, -16, -6, 16, 6, 16, + -6, -16, 6, -16, -7, 16, 7, 16, + -7, -16, 7, -16, -8, 16, 8, 16, + -8, -16, 8, -16, -9, 16, 9, 16, + -9, -16, 9, -16, -10, 16, 10, 16, + -10, -16, 10, -16, -11, 16, 11, 16, + -11, -16, 11, -16, -12, 16, 12, 16, + -12, -16, 12, -16, -13, 16, 13, 16, + -13, -16, 13, -16, -14, 16, 14, 16, + -14, -16, 14, -16, -15, 16, 15, 16, + -15, -16, 15, -16, -15, 15, 15, 15, + -15, -15, 15, -15, -16, 15, 16, 15, + -16, -15, 16, -15, -16, 14, 16, 14, + -16, -14, 16, -14, -16, 13, 16, 13, + -16, -13, 16, -13, -16, 12, 16, 12, + -16, -12, 16, -12, -16, 11, 16, 11, + -16, -11, 16, -11, -16, 10, 16, 10, + -16, -10, 16, -10, -16, 9, 16, 9, + -16, -9, 16, -9, -16, 8, 16, 8, + -16, -8, 16, -8, -16, 7, 16, 7, + -16, -7, 16, -7, -16, 6, 16, 6, + -16, -6, 16, -6, -16, 5, 16, 5, + -16, -5, 16, -5, -16, 4, 16, 4, + -16, -4, 16, -4, -16, 3, 16, 3, + -16, -3, 16, -3, -16, 2, 16, 2, + -16, -2, 16, -2, -16, 1, 16, 1, + -16, -1, 16, -1, -16, 0, 16, 0, + (char)136, + 0, 17, 0, -17, -1, 17, 1, 17, + -1, -17, 1, -17, -2, 17, 2, 17, + -2, -17, 2, -17, -3, 17, 3, 17, + -3, -17, 3, -17, -4, 17, 4, 17, + -4, -17, 4, -17, -5, 17, 5, 17, + -5, -17, 5, -17, -6, 17, 6, 17, + -6, -17, 6, -17, -7, 17, 7, 17, + -7, -17, 7, -17, -8, 17, 8, 17, + -8, -17, 8, -17, -9, 17, 9, 17, + -9, -17, 9, -17, -10, 17, 10, 17, + -10, -17, 10, -17, -11, 17, 11, 17, + -11, -17, 11, -17, -12, 17, 12, 17, + -12, -17, 12, -17, -13, 17, 13, 17, + -13, -17, 13, -17, -14, 17, 14, 17, + -14, -17, 14, -17, -15, 17, 15, 17, + -15, -17, 15, -17, -16, 17, 16, 17, + -16, -17, 16, -17, -16, 16, 16, 16, + -16, -16, 16, -16, -17, 16, 17, 16, + -17, -16, 17, -16, -17, 15, 17, 15, + -17, -15, 17, -15, -17, 14, 17, 14, + -17, -14, 17, -14, -17, 13, 17, 13, + -17, -13, 17, -13, -17, 12, 17, 12, + -17, -12, 17, -12, -17, 11, 17, 11, + -17, -11, 17, -11, -17, 10, 17, 10, + -17, -10, 17, -10, -17, 9, 17, 9, + -17, -9, 17, -9, -17, 8, 17, 8, + -17, -8, 17, -8, -17, 7, 17, 7, + -17, -7, 17, -7, -17, 6, 17, 6, + -17, -6, 17, -6, -17, 5, 17, 5, + -17, -5, 17, -5, -17, 4, 17, 4, + -17, -4, 17, -4, -17, 3, 17, 3, + -17, -3, 17, -3, -17, 2, 17, 2, + -17, -2, 17, -2, -17, 1, 17, 1, + -17, -1, 17, -1, -17, 0, 17, 0, + (char)144, + 0, 18, 0, -18, -1, 18, 1, 18, + -1, -18, 1, -18, -2, 18, 2, 18, + -2, -18, 2, -18, -3, 18, 3, 18, + -3, -18, 3, -18, -4, 18, 4, 18, + -4, -18, 4, -18, -5, 18, 5, 18, + -5, -18, 5, -18, -6, 18, 6, 18, + -6, -18, 6, -18, -7, 18, 7, 18, + -7, -18, 7, -18, -8, 18, 8, 18, + -8, -18, 8, -18, -9, 18, 9, 18, + -9, -18, 9, -18, -10, 18, 10, 18, + -10, -18, 10, -18, -11, 18, 11, 18, + -11, -18, 11, -18, -12, 18, 12, 18, + -12, -18, 12, -18, -13, 18, 13, 18, + -13, -18, 13, -18, -14, 18, 14, 18, + -14, -18, 14, -18, -15, 18, 15, 18, + -15, -18, 15, -18, -16, 18, 16, 18, + -16, -18, 16, -18, -17, 18, 17, 18, + -17, -18, 17, -18, -17, 17, 17, 17, + -17, -17, 17, -17, -18, 17, 18, 17, + -18, -17, 18, -17, -18, 16, 18, 16, + -18, -16, 18, -16, -18, 15, 18, 15, + -18, -15, 18, -15, -18, 14, 18, 14, + -18, -14, 18, -14, -18, 13, 18, 13, + -18, -13, 18, -13, -18, 12, 18, 12, + -18, -12, 18, -12, -18, 11, 18, 11, + -18, -11, 18, -11, -18, 10, 18, 10, + -18, -10, 18, -10, -18, 9, 18, 9, + -18, -9, 18, -9, -18, 8, 18, 8, + -18, -8, 18, -8, -18, 7, 18, 7, + -18, -7, 18, -7, -18, 6, 18, 6, + -18, -6, 18, -6, -18, 5, 18, 5, + -18, -5, 18, -5, -18, 4, 18, 4, + -18, -4, 18, -4, -18, 3, 18, 3, + -18, -3, 18, -3, -18, 2, 18, 2, + -18, -2, 18, -2, -18, 1, 18, 1, + -18, -1, 18, -1, -18, 0, 18, 0 +}; + +char *pCrawlTable[19] = /* figure out what this is for */ +{ + CrawlTable, + CrawlTable+3, + CrawlTable+12, + CrawlTable+45, + CrawlTable+94, + CrawlTable+159, + CrawlTable+240, + CrawlTable+337, + CrawlTable+450, + CrawlTable+579, + CrawlTable+724, + CrawlTable+885, + CrawlTable+1062, + CrawlTable+1255, + CrawlTable+1464, + CrawlTable+1689, + CrawlTable+1930, + CrawlTable+2187, + CrawlTable+2460 +}; +unsigned char vCrawlTable[23][30] = +{ + { 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0 }, + { 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1 }, + { 1, 0, 2, 0, 3, 0, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 2, 13, 2, 14, 2, 15, 2 }, + { 1, 0, 2, 0, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 13, 3, 14, 3, 15, 3 }, + { 1, 0, 2, 1, 3, 1, 4, 1, 5, 1, 6, 2, 7, 2, 8, 2, 9, 3, 10, 3, 11, 3, 12, 3, 13, 4, 14, 4, 0, 0 }, + { 1, 0, 2, 1, 3, 1, 4, 1, 5, 2, 6, 2, 7, 3, 8, 3, 9, 3, 10, 4, 11, 4, 12, 4, 13, 5, 14, 5, 0, 0 }, + { 1, 0, 2, 1, 3, 1, 4, 2, 5, 2, 6, 3, 7, 3, 8, 3, 9, 4, 10, 4, 11, 5, 12, 5, 13, 6, 14, 6, 0, 0 }, + { 1, 1, 2, 1, 3, 2, 4, 2, 5, 3, 6, 3, 7, 4, 8, 4, 9, 5, 10, 5, 11, 6, 12, 6, 13, 7, 0, 0, 0, 0 }, + { 1, 1, 2, 1, 3, 2, 4, 2, 5, 3, 6, 4, 7, 4, 8, 5, 9, 6, 10, 6, 11, 7, 12, 7, 12, 8, 13, 8, 0, 0 }, + { 1, 1, 2, 2, 3, 2, 4, 3, 5, 4, 6, 5, 7, 5, 8, 6, 9, 7, 10, 7, 10, 8, 11, 8, 12, 9, 0, 0, 0, 0 }, + { 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 5, 7, 6, 8, 7, 9, 8, 10, 9, 11, 9, 11, 10, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 9, 11, 10, 11, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 5, 7, 6, 8, 7, 9, 7, 10, 8, 10, 8, 11, 9, 12, 0, 0, 0, 0 }, + { 1, 1, 1, 2, 2, 3, 2, 4, 3, 5, 4, 6, 4, 7, 5, 8, 6, 9, 6, 10, 7, 11, 7, 12, 8, 12, 8, 13, 0, 0 }, + { 1, 1, 1, 2, 2, 3, 2, 4, 3, 5, 3, 6, 4, 7, 4, 8, 5, 9, 5, 10, 6, 11, 6, 12, 7, 13, 0, 0, 0, 0 }, + { 0, 1, 1, 2, 1, 3, 2, 4, 2, 5, 3, 6, 3, 7, 3, 8, 4, 9, 4, 10, 5, 11, 5, 12, 6, 13, 6, 14, 0, 0 }, + { 0, 1, 1, 2, 1, 3, 1, 4, 2, 5, 2, 6, 3, 7, 3, 8, 3, 9, 4, 10, 4, 11, 4, 12, 5, 13, 5, 14, 0, 0 }, + { 0, 1, 1, 2, 1, 3, 1, 4, 1, 5, 2, 6, 2, 7, 2, 8, 3, 9, 3, 10, 3, 11, 3, 12, 4, 13, 4, 14, 0, 0 }, + { 0, 1, 0, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 12, 3, 13, 3, 14, 3, 15 }, + { 0, 1, 0, 2, 0, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 2, 12, 2, 13, 2, 14, 2, 15 }, + { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15 }, + { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15 } +}; +unsigned char byte_49463C[18][18] = /* unused */ +{ + { 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3 }, + { 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3 }, + { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3 }, + { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3 }, + { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2 } +}; + +unsigned char RadiusAdj[23] = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 4, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0 }; + +void __fastcall SetLightFX(int *x, int *y, short *s_r, short *s_g, int *s_b, int *d_r, int *d_g, int *d_b) +{ + short *v8; // eax + int v9; // edx + int *v10; // [esp+Ch] [ebp-4h] + short *s_ra; // [esp+18h] [ebp+8h] + + *d_g = 0; + *d_b = 0; + v8 = s_r; + v10 = y; + v9 = *(_DWORD *)s_r; + *(_DWORD *)s_r = 7 - *(_DWORD *)s_g; + *(_DWORD *)s_g = v9; + s_ra = (short *)*s_b; + *s_b = 7 - *d_r; + *d_r = (int)s_ra; + *x = *(_DWORD *)v8 - *s_b; + *v10 = *(_DWORD *)s_g - *d_r; + if ( *x < 0 ) + { + *x += 8; + *d_g = 1; + } + if ( *v10 < 0 ) + { + *v10 += 8; + *d_b = 1; + } +} + +void __fastcall DoLighting(int nXPos, int nYPos, int nRadius, int Lnum) +{ + int v4; // edi + int v5; // ebx + int v6; // ecx + int v7; // eax + int v8; // edx + int v9; // esi + int v10; // eax + char *v11; // edi + signed int v12; // ecx + int v13; // edx + _BYTE *v14; // ecx + int v15; // ebx + bool v16; // sf + unsigned char v17; // of + int v18; // esi + int v19; // ecx + char *v20; // edi + signed int v21; // eax + int v22; // edx + _BYTE *v23; // eax + int v24; // ebx + int v25; // eax + int v26; // esi + char *v27; // edi + signed int v28; // ecx + int v29; // edx + _BYTE *v30; // ecx + int v31; // ebx + signed int v32; // ebx + int v33; // ecx + char *v34; // esi + signed int v35; // eax + int v36; // edx + _BYTE *v37; // eax + int v38; // edi + short s_r[2]; // [esp+Ch] [ebp-44h] + short s_g[2]; // [esp+10h] [ebp-40h] + int s_b; // [esp+14h] [ebp-3Ch] + int d_r; // [esp+18h] [ebp-38h] + int v43; // [esp+1Ch] [ebp-34h] + int v44; // [esp+20h] [ebp-30h] + int v45; // [esp+24h] [ebp-2Ch] + int v46; // [esp+28h] [ebp-28h] + int v47; // [esp+2Ch] [ebp-24h] + int v48; // [esp+30h] [ebp-20h] + int d_g; // [esp+34h] [ebp-1Ch] + int d_b; // [esp+38h] [ebp-18h] + int v51; // [esp+3Ch] [ebp-14h] + int v52; // [esp+40h] [ebp-10h] + int y; // [esp+44h] [ebp-Ch] + int x; // [esp+48h] [ebp-8h] + int v55; // [esp+4Ch] [ebp-4h] + int Lnuma; // [esp+5Ch] [ebp+Ch] + int Lnumb; // [esp+5Ch] [ebp+Ch] + int Lnumc; // [esp+5Ch] [ebp+Ch] + int Lnumd; // [esp+5Ch] [ebp+Ch] + + v4 = nYPos; + v5 = nXPos; + v6 = 0; + v7 = 0; + v48 = nYPos; + v52 = v5; + x = 0; + y = 0; + s_b = 0; + d_r = 0; + d_g = 0; + d_b = 0; + if ( Lnum >= 0 ) + { + v7 = LightList[Lnum]._yoff; + x = LightList[Lnum]._xoff; + v6 = x; + y = v7; + if ( x < 0 ) + { + v6 = x + 8; + --v5; + x += 8; + v52 = v5; + } + if ( v7 < 0 ) + { + v7 += 8; + v4 = nYPos - 1; + y = v7; + v48 = nYPos - 1; + } + } + *(_DWORD *)s_r = v6; + *(_DWORD *)s_g = v7; + v8 = 15; + if ( v5 - 15 >= 0 ) + v44 = 15; + else + v44 = v5 + 1; + if ( v5 + 15 <= 112 ) + v46 = 15; + else + v46 = 112 - v5; + if ( v4 - 15 >= 0 ) + v43 = 15; + else + v43 = v4 + 1; + if ( v4 + 15 > 112 ) + v8 = 112 - v4; + v45 = v8; + if ( v5 >= 0 && v5 < 112 && v4 >= 0 && v4 < 112 ) + dTransVal[v5][v4] = 0; + v55 = 0; + v51 = v6 + 8 * v7; + if ( v43 > 0 ) + { + v47 = v4; + do + { + Lnuma = 1; + if ( v46 > 1 ) + { + v9 = v5 + 1; + v10 = 112 * (v5 + 1); + v11 = &dung_map_rgba[16 * (v55 + 16 * v51)]; + do + { + v12 = (unsigned char)v11[Lnuma]; + if ( v12 < 128 ) + { + v13 = (unsigned char)dung_map_radius[128 * nRadius + v12]; + if ( v9 >= 0 && v9 < 112 && v47 >= 0 && v47 < 112 ) + { + v14 = (unsigned char *)dTransVal + v47 + v10; + v15 = (char)*v14; + v17 = __OFSUB__(v13, v15); + v16 = v13 - v15 < 0; + v5 = v52; + if ( v16 ^ v17 ) + *v14 = v13; + } + } + ++Lnuma; + v10 += 112; + ++v9; + } + while ( Lnuma < v46 ); + v4 = v48; + } + ++v55; + ++v47; + } + while ( v55 < v43 ); + } + SetLightFX(&x, &y, s_r, s_g, &s_b, &d_r, &d_g, &d_b); + v18 = 0; + v51 = x + 8 * y; + if ( v45 > 0 ) + { + v47 = 112 * v5; + do + { + Lnumb = 1; + if ( v46 > 1 ) + { + v19 = v4 - 1; + v20 = &dung_map_rgba[16 * (d_b + v18 + 16 * v51) + d_g]; + do + { + v21 = (unsigned char)v20[Lnumb]; + if ( v21 < 128 ) + { + v22 = (unsigned char)dung_map_radius[128 * nRadius + v21]; + if ( v18 + v5 >= 0 && v18 + v5 < 112 && v19 >= 0 && v19 < 112 ) + { + v23 = (unsigned char *)dTransVal + v47 + v19; + v24 = (char)*v23; + v17 = __OFSUB__(v22, v24); + v16 = v22 - v24 < 0; + v5 = v52; + if ( v16 ^ v17 ) + *v23 = v22; + } + } + ++Lnumb; + --v19; + } + while ( Lnumb < v46 ); + v4 = v48; + } + v47 += 112; + ++v18; + } + while ( v18 < v45 ); + } + SetLightFX(&x, &y, s_r, s_g, &s_b, &d_r, &d_g, &d_b); + v55 = 0; + v51 = x + 8 * y; + if ( v45 > 0 ) + { + v46 = v4; + do + { + Lnumc = 1; + if ( v44 > 1 ) + { + v25 = 112 * v5 - 112; + v26 = v5 - 1; + v27 = &dung_map_rgba[16 * (d_b + v55 + 16 * v51) + d_g]; + do + { + v28 = (unsigned char)v27[Lnumc]; + if ( v28 < 128 ) + { + v29 = (unsigned char)dung_map_radius[128 * nRadius + v28]; + if ( v26 >= 0 && v26 < 112 && v46 >= 0 && v46 < 112 ) + { + v30 = (unsigned char *)dTransVal + v46 + v25; + v31 = (char)*v30; + v17 = __OFSUB__(v29, v31); + v16 = v29 - v31 < 0; + v5 = v52; + if ( v16 ^ v17 ) + *v30 = v29; + } + } + ++Lnumc; + v25 -= 112; + --v26; + } + while ( Lnumc < v44 ); + v4 = v48; + } + ++v55; + --v46; + } + while ( v55 < v45 ); + } + SetLightFX(&x, &y, s_r, s_g, &s_b, &d_r, &d_g, &d_b); + v55 = 0; + v51 = x + 8 * y; + if ( v43 > 0 ) + { + Lnumd = v5; + *(_DWORD *)s_r = 112 * v5; + do + { + v32 = 1; + if ( v44 > 1 ) + { + v33 = v4 + 1; + v34 = &dung_map_rgba[16 * (d_b + v55 + 16 * v51) + d_g]; + do + { + v35 = (unsigned char)v34[v32]; + if ( v35 < 128 ) + { + v36 = (unsigned char)dung_map_radius[128 * nRadius + v35]; + if ( Lnumd >= 0 && Lnumd < 112 && v33 >= 0 && v33 < 112 ) + { + v37 = (unsigned char *)dTransVal + v33 + *(_DWORD *)s_r; + v38 = (char)*v37; + v17 = __OFSUB__(v36, v38); + v16 = v36 - v38 < 0; + v4 = v48; + if ( v16 ^ v17 ) + *v37 = v36; + } + } + ++v32; + ++v33; + } + while ( v32 < v44 ); + } + ++v55; + --Lnumd; + *(_DWORD *)s_r -= 112; + } + while ( v55 < v43 ); + } +} + +void __fastcall DoUnLight(int nXPos, int nYPos, int nRadius) +{ + int max_y; // ebx + int y; // esi + int x; // edx + int max_x; // edi + signed int v7; // esi + int v8; // eax + int radius_block; // [esp+14h] [ebp+8h] + + max_y = nYPos + nRadius + 1; + y = nYPos - (nRadius + 1); + x = nXPos - (nRadius + 1); + max_x = nXPos + nRadius + 1; + if ( y < 0 ) + y = 0; + if ( max_y > 112 ) + max_y = 112; + if ( x < 0 ) + x = 0; + if ( max_x > 112 ) + max_x = 112; + for ( radius_block = y; radius_block < max_y; ++radius_block ) + { + v7 = x; + if ( x < max_x ) + { + v8 = radius_block + 112 * x; + do + { + if ( v7 >= 0 && v7 < 112 && radius_block >= 0 && radius_block < 112 ) + dTransVal[0][v8] = dTransVal2[0][v8]; + ++v7; + v8 += 112; + } + while ( v7 < max_x ); + } + } +} + +void __fastcall DoUnVision(int nXPos, int nYPos, int nRadius) +{ + int y2; // edi + int y1; // esi + int x1; // edx + int x2; // ecx + char *v7; // eax + int i; // ecx + int j; // edx + + y2 = nYPos + nRadius + 1; + y1 = nYPos - (nRadius + 1); + x1 = nXPos - (nRadius + 1); + x2 = nRadius + 1 + nXPos; + if ( y1 < 0 ) + y1 = 0; + if ( y2 > 112 ) + y2 = 112; + if ( x1 < 0 ) + x1 = 0; + if ( x2 > 112 ) + x2 = 112; + if ( x1 < x2 ) + { + v7 = dFlags[x1]; + i = x2 - x1; + do + { + for ( j = y1; j < y2; ++j ) + v7[j] &= 0xBDu; + v7 += 112; + --i; + } + while ( i ); + } +} + +void __fastcall DoVision(int nXPos, int nYPos, int nRadius, unsigned char doautomap, int visible) +{ + char *v5; // esi + int v6; // esi + int v7; // edi + unsigned char *v8; // eax + int v9; // ebx + int v10; // ecx + unsigned char v11; // dl + int v12; // ecx + int v13; // ecx + unsigned char v14; // cl + unsigned char v15; // dl + int v16; // ecx + int v17; // ecx + int i; // [esp+Ch] [ebp-34h] + unsigned char *v19; // [esp+10h] [ebp-30h] + int v20; // [esp+14h] [ebp-2Ch] + int v21; // [esp+18h] [ebp-28h] + int v22; // [esp+1Ch] [ebp-24h] + signed int v23; // [esp+20h] [ebp-20h] + signed int v24; // [esp+24h] [ebp-1Ch] + signed int v25; // [esp+28h] [ebp-18h] + signed int v26; // [esp+2Ch] [ebp-14h] + signed int v27; // [esp+30h] [ebp-10h] + int v28; // [esp+34h] [ebp-Ch] + int v29; // [esp+38h] [ebp-8h] + unsigned char v30; // [esp+3Fh] [ebp-1h] + unsigned char v31; // [esp+3Fh] [ebp-1h] + + v28 = nYPos; + v29 = nXPos; + if ( nXPos >= 0 && nXPos <= 112 && nYPos >= 0 && nYPos <= 112 ) + { + if ( doautomap ) + { + v5 = &dFlags[nXPos][nYPos]; + if ( *v5 >= 0 ) + { + SetAutomapView(nXPos, nXPos); + nYPos = v28; + nXPos = v29; + } + *v5 |= 0x80u; + } + if ( visible ) + dFlags[nXPos][nYPos] |= 0x40u; + dFlags[nXPos][nYPos] |= 2u; + } + v27 = 0; + v6 = doautomap; + v7 = doautomap; + do + { + v20 = 0; + v8 = &vCrawlTable[0][1]; + v19 = &vCrawlTable[0][1]; + do + { + v9 = 0; + v21 = 0; + for ( i = 2 * (nRadius - RadiusAdj[v20]); v9 < i; v9 += 2 ) + { + if ( v21 ) + break; + v26 = 0; + v24 = 0; + v25 = 0; + v23 = 0; + if ( v27 ) + { + switch ( v27 ) + { + case 1: + v13 = v8[v9 - 1]; + v6 = v29 - (unsigned char)v13; + v31 = v8[v9]; + v7 = v28 - v31; + if ( (_BYTE)v13 && v31 ) + { + v25 = 1; + v24 = 1; + } + break; + case 2: + v12 = v8[v9 - 1]; + v30 = v8[v9]; + v6 = v29 + (unsigned char)v12; + v7 = v28 - v30; + if ( (_BYTE)v12 && v30 ) + { + v26 = -1; + v23 = 1; + } + break; + case 3: + v10 = v8[v9 - 1]; + v6 = v29 - (unsigned char)v10; + v11 = v8[v9]; + v7 = v28 + v11; + if ( (_BYTE)v10 ) + { + if ( v11 ) + { + v25 = -1; + v24 = 1; + } + } + break; + } + } + else + { + v14 = v8[v9 - 1]; + v15 = v8[v9]; + v6 = v29 + v14; + v7 = v28 + v15; + if ( v14 && v15 ) + { + v26 = -1; + v23 = -1; + } + } + if ( v6 >= 0 && v6 <= 112 && v7 >= 0 && v7 <= 112 ) + { + v22 = v7 + 112 * v6; + v21 = (unsigned char)nBlockTable[dPiece[0][v22]]; + if ( !nBlockTable[dPiece[0][v25 + v7 + 112 * (v6 + v26)]] + || !nBlockTable[dPiece[0][v23 + v7 + 112 * (v6 + v24)]] ) + { + v16 = v7 + 112 * v6; + if ( doautomap ) + { + if ( dFlags[0][v22] >= 0 ) + { + SetAutomapView(v6, v7); + v16 = v7 + 112 * v6; + v8 = v19; + } + dFlags[0][v16] |= 0x80u; + } + if ( visible ) + dFlags[0][v16] |= 0x40u; + dFlags[0][v16] |= 2u; + if ( !v21 ) + { + v17 = dung_map[0][v16]; + if ( v17 ) + TransList[v17] = 1; + } + } + } + } + ++v20; + v8 += 30; + v19 = v8; + } + while ( (signed int)v8 < (signed int)&vCrawlTable[23][1] ); + ++v27; + } + while ( v27 < 4 ); +} + +void __cdecl FreeLightTable() +{ + char *v0; // ecx + + v0 = pLightTbl; + pLightTbl = 0; + mem_free_dbg(v0); +} + +void __cdecl InitLightTable() +{ + pLightTbl = (char *)DiabloAllocPtr(LIGHTSIZE); +} + +void __cdecl MakeLightTable() +{ + char *v0; // ebx + signed int v1; // esi + unsigned char v2; // al + unsigned char v3; // cl + signed int v4; // edi + int v5; // edx + signed int v6; // edi + unsigned char v7; // cl + unsigned char v8; // al + signed int v9; // edx + unsigned char v10; // cl + unsigned char v11; // al + char *v12; // ebx + char *v13; // ebx + int v14; // ecx + signed int v15; // esi + char v16; // al + int v17; // edx + int v18; // ebx + signed int v19; // esi + _BYTE *v20; // ebx + char *v21; // ebx + int v22; // edi + unsigned char *v23; // esi + signed int v24; // edx + unsigned char *v25; // esi + signed int v26; // edx + signed int v27; // ecx + char v28; // al + _BYTE *v29; // ebx + signed int v30; // edx + char v31; // al + signed int v32; // ecx + signed int v33; // ecx + char v34; // al + int v35; // eax + signed int v36; // esi + char *v37; // eax + signed int v38; // ebx + int v39; // esi + double v40; // st7 + double v41; // st6 + int v42; // ecx + char *v43; // ecx + bool v44; // zf + char v45[16]; // [esp+14h] [ebp-2Ch] /* check */ + int v46; // [esp+24h] [ebp-1Ch] + int v47; // [esp+28h] [ebp-18h] + char *v48; // [esp+2Ch] [ebp-14h] + int v49; // [esp+30h] [ebp-10h] + int v50; // [esp+34h] [ebp-Ch] + int v51; // [esp+38h] [ebp-8h] + int v52; // [esp+3Ch] [ebp-4h] + + v51 = 0; + v0 = pLightTbl; + v1 = light4flag != 0 ? 3 : 15; + v50 = light4flag != 0 ? 3 : 15; + if ( v1 > 0 ) + { + v49 = light4flag != 0 ? 3 : 15; + do + { + *v0++ = 0; + v52 = 0; + do + { + v2 = 16 * v52 + 15; + v3 = v51 + 16 * v52; + v4 = 0; + do + { + if ( v4 || v52 ) + *v0++ = v3; + if ( v3 >= v2 ) + { + v2 = 0; + v3 = 0; + } + else + { + ++v3; + } + ++v4; + } + while ( v4 < 16 ); + ++v52; + } + while ( v52 < 8 ); + v52 = 16; + v5 = v51 >> 1; + do + { + v6 = 8; + v7 = v5 + 8 * v52; + v8 = 8 * v52 + 7; + do + { + *v0++ = v7; + if ( v7 >= v8 ) + { + v8 = 0; + v7 = 0; + } + else + { + ++v7; + } + --v6; + } + while ( v6 ); + ++v52; + } + while ( v52 < 20 ); + v52 = 10; + do + { + v9 = 16; + v10 = v51 + 16 * v52; + v11 = 16 * v52 + 15; + do + { + *v0++ = v10; + if ( v10 >= v11 ) + { + v11 = 0; + v10 = 0; + } + else + { + ++v10; + } + if ( v10 == LOBYTE(-1) ) + { + v11 = 0; + v10 = 0; + } + --v9; + } + while ( v9 ); + ++v52; + } + while ( v52 < 16 ); + if ( light4flag ) + v51 += 5; + else + ++v51; + --v49; + } + while ( v49 ); + } + memset(v0, 0, 0x100u); + v12 = v0 + 256; + if ( leveltype == DTYPE_HELL ) + { + v13 = pLightTbl; + if ( v1 > 0 ) + { + v14 = v50; + v49 = v50; + do + { + v52 = 0; + v45[0] = 0; + v51 = v14; + v15 = 1; + v48 = (char *)(v50 / v14); + v47 = v50 % v14; + v16 = 1; + do + { + v17 = v51; + v45[v15] = v16; + v51 = v47 + v17; + if ( v47 + v17 > v14 && v15 < 15 ) + { + ++v15; + v51 -= v14; + v45[v15] = v16; + } + if ( (char *)++v52 == v48 ) + { + ++v16; + v52 = 0; + } + ++v15; + } + while ( v15 < 16 ); + *v13 = 0; + v18 = (int)(v13 + 1); + *(_DWORD *)v18 = *(_DWORD *)&v45[1]; + *(_DWORD *)(v18 + 4) = *(_DWORD *)&v45[5]; + *(_DWORD *)(v18 + 8) = *(_DWORD *)&v45[9]; + *(_WORD *)(v18 + 12) = *(_WORD *)&v45[13]; + *(_BYTE *)(v18 + 14) = v45[15]; + v19 = 15; + v20 = (_BYTE *)(v18 + 15); + do + *v20++ = v45[v19--]; + while ( v19 > 0 ); + *v20 = 1; + v13 = (char *)v20 + 225; + --v14; + --v49; + } + while ( v49 ); + } + *v13 = 0; + v21 = v13 + 1; + memset(v21, 1u, 0x1Cu); + v22 = (int)(v21 + 28); + *(_WORD *)v22 = 257; + *(_BYTE *)(v22 + 2) = 1; + v12 = v21 + 255; + } + v23 = LoadFileInMem("PlrGFX\\Infra.TRN", 0); + v24 = 0; + do + *v12++ = v23[v24++]; + while ( v24 < 256 ); + mem_free_dbg(v23); + v25 = LoadFileInMem("PlrGFX\\Stone.TRN", 0); + v26 = 0; + do + *v12++ = v25[v26++]; + while ( v26 < 256 ); + mem_free_dbg(v25); + v27 = 0; + do + { + v28 = -30; + do + { + if ( v27 || v28 != -30 ) + *v12 = v28; + else + *v12 = 0; + ++v12; + ++v28; + } + while ( (unsigned char)v28 < 0xEFu ); + *v12 = 0; + v29 = (unsigned char *)v12 + 1; + *v29++ = 0; + *v29 = 0; + v12 = (char *)v29 + 1; + ++v27; + } + while ( v27 < 8 ); + v30 = 4; + do + { + v31 = -32; + v32 = 8; + do + { + *v12++ = v31; + v31 += 2; + --v32; + } + while ( v32 ); + --v30; + } + while ( v30 ); + v33 = 6; + do + { + v34 = -32; + do + *v12++ = v34++; + while ( (unsigned char)v34 < 0xEFu ); + *v12++ = 0; + --v33; + } + while ( v33 ); + v35 = 0; + v51 = (int)dung_map_radius; + v52 = 8; + do + { + v36 = 0; + v49 = 0; + v50 = v35 + 1; + do + { + if ( v36 <= v52 ) + *(_BYTE *)(v51 + v36) = (signed __int64)((double)v49 * 15.0 / ((double)v50 * 8.0) + 0.5); + else + *(_BYTE *)(v51 + v36) = 15; + v49 = ++v36; + } + while ( v36 < 128 ); + v52 += 8; + v51 += 128; + v35 = v50; + } + while ( v52 < 136 ); + v49 = 0; + v37 = dung_map_rgba; + do + { + v52 = 0; + do + { + v48 = v37; + v50 = v49; + v47 = 16; + do + { + v38 = 0; + v39 = v50 * v50; + v51 = v52; + do + { + v46 = v39 + v51 * v51; + v46 = (unsigned char)(signed __int64)sqrt((double)v46); + v40 = (double)v46; + if ( v40 >= 0.0 ) + v41 = 0.5; + else + v41 = -0.5; + v42 = (int)v48; + v51 += 8; + v48[v38++] = (signed __int64)(v41 + v40); + } + while ( v38 < 16 ); + v50 += 8; + v43 = (char *)(v42 + 16); + v44 = v47-- == 1; + v48 = v43; + } + while ( !v44 ); + --v52; + v37 = v43; + } + while ( v52 > -8 ); + --v49; + } + while ( (signed int)v43 < (signed int)&dung_map_rgba[16384] ); +} +// 525728: using guessed type int light4flag; +// 5BB1ED: using guessed type char leveltype; + +#ifdef _DEBUG +void __cdecl ToggleLighting() +{ + int i; + + lightflag ^= 1; + if ( lightflag ) + { + memset(dTransVal, 0, 0x3100u); + } + else + { + memcpy(dTransVal, dTransVal2, 0x3100u); + for(i = 0; i < 4; i++) + { + if ( plr[i].plractive ) + { + if ( currlevel == plr[i].plrlevel ) + DoLighting(plr[i].WorldX, plr[i].WorldY, plr[i]._pLightRad, -1); + } + } + } +} +#endif + +void __cdecl InitLightMax() +{ + lightmax = light4flag == 0 ? 15 : 3; +} +// 525728: using guessed type int light4flag; +// 642A14: using guessed type char lightmax; + +void __cdecl InitLighting() +{ + signed int v0; // eax + + v0 = 0; + numlights = 0; + dolighting = 0; + lightflag = 0; + do + { + lightactive[v0] = v0; + ++v0; + } + while ( v0 < 32 ); +} +// 642A18: using guessed type int dolighting; +// 646A28: using guessed type int lightflag; + +int __fastcall AddLight(int x, int y, int r) +{ + int lid; // eax + + lid = -1; + if ( !lightflag && numlights < 32 ) + { + lid = lightactive[numlights++]; + dolighting = 1; + LightList[lid]._lx = x; + LightList[lid]._ly = y; + LightList[lid]._lradius = r; + LightList[lid]._xoff = 0; + LightList[lid]._yoff = 0; + LightList[lid]._ldel = 0; + LightList[lid]._lunflag = 0; + } + return lid; +} +// 642A18: using guessed type int dolighting; +// 646A28: using guessed type int lightflag; + +void __fastcall AddUnLight(int i) +{ + if ( !lightflag && i != -1 ) + { + LightList[i]._ldel = 1; + dolighting = 1; + } +} +// 642A18: using guessed type int dolighting; +// 646A28: using guessed type int lightflag; + +void __fastcall ChangeLightRadius(int i, int r) +{ + if ( !lightflag && i != -1 ) + { + LightList[i]._lunx = LightList[i]._lx; + LightList[i]._luny = LightList[i]._ly; + LightList[i]._lunflag = 1; + LightList[i]._lunr = LightList[i]._lradius; + dolighting = 1; + LightList[i]._lradius = r; + } +} +// 642A18: using guessed type int dolighting; +// 646A28: using guessed type int lightflag; + +void __fastcall ChangeLightXY(int i, int x, int y) +{ + if ( !lightflag && i != -1 ) + { + LightList[i]._lunx = LightList[i]._lx; + LightList[i]._lunflag = 1; + dolighting = 1; + LightList[i]._luny = LightList[i]._ly; + LightList[i]._lunr = LightList[i]._lradius; + LightList[i]._ly = y; + LightList[i]._lx = x; + } +} +// 642A18: using guessed type int dolighting; +// 646A28: using guessed type int lightflag; + +void __fastcall ChangeLightOff(int i, int x, int y) +{ + if ( !lightflag && i != -1 ) + { + LightList[i]._xoff = x; + LightList[i]._lunx = LightList[i]._lx; + LightList[i]._luny = LightList[i]._ly; + LightList[i]._lunr = LightList[i]._lradius; + LightList[i]._lunflag = 1; + LightList[i]._yoff = y; + dolighting = 1; + } +} +// 642A18: using guessed type int dolighting; +// 646A28: using guessed type int lightflag; + +void __fastcall ChangeLight(int i, int x, int y, int r) +{ + if ( !lightflag && i != -1 ) + { + LightList[i]._lunx = LightList[i]._lx; + LightList[i]._luny = LightList[i]._ly; + LightList[i]._lunr = LightList[i]._lradius; + LightList[i]._lunflag = 1; + LightList[i]._lx = x; + LightList[i]._ly = y; + LightList[i]._lradius = r; + dolighting = 1; + } +} +// 642A18: using guessed type int dolighting; +// 646A28: using guessed type int lightflag; + +void __cdecl ProcessLightList() +{ + int v0; // ebp + int v1; // edi + int v2; // esi + int i; // esi + int v4; // eax + int v5; // ecx + unsigned char v6; // bl + char v7; // dl + + v0 = 0; + if ( !lightflag ) + { + if ( dolighting ) + { + v1 = numlights; + if ( numlights > 0 ) + { + do + { + v2 = (unsigned char)lightactive[v0]; + if ( LightList[v2]._ldel ) + DoUnLight(LightList[v2]._lx, LightList[v2]._ly, LightList[v2]._lradius); + if ( LightList[v2]._lunflag ) + { + DoUnLight(LightList[v2]._lunx, LightList[v2]._luny, LightList[v2]._lunr); + LightList[v2]._lunflag = 0; + } + ++v0; + } + while ( v0 < v1 ); + } + for ( i = 0; i < v1; ++i ) + { + v4 = (unsigned char)lightactive[i]; + if ( !LightList[v4]._ldel ) + DoLighting( + LightList[v4]._lx, + LightList[v4]._ly, + LightList[v4]._lradius, + (unsigned char)lightactive[i]); + } + v5 = 0; + if ( v1 > 0 ) + { + do + { + v6 = lightactive[v5]; + if ( LightList[v6]._ldel ) + { + v7 = lightactive[--v1]; + lightactive[v1] = v6; + lightactive[v5] = v7; + } + else + { + ++v5; + } + } + while ( v5 < v1 ); + numlights = v1; + } + } + dolighting = 0; + } +} +// 642A18: using guessed type int dolighting; +// 646A28: using guessed type int lightflag; + +void __cdecl SavePreLighting() +{ + memcpy(dTransVal2, dTransVal, 0x3100u); +} + +void __cdecl InitVision() +{ + numvision = 0; + dovision = 0; + visionid = 1; + if ( TransVal > 0 ) + memset(TransList, 0, TransVal); +} +// 5A5590: using guessed type char TransVal; +// 642A0C: using guessed type int dovision; + +int __fastcall AddVision(int x, int y, int r, BOOL mine) +{ + int vid; // eax + int v5; // esi + + vid = r; + if ( numvision < 32 ) + { + v5 = numvision; + dovision = 1; + VisionList[v5]._lx = x; + VisionList[v5]._ly = y; + VisionList[v5]._lradius = r; + vid = visionid++; + VisionList[v5]._lid = vid; + VisionList[v5]._ldel = 0; + ++numvision; + VisionList[v5]._lunflag = 0; + VisionList[v5]._lflags = mine != 0; + } + return vid; +} +// 642A0C: using guessed type int dovision; + +void __fastcall ChangeVisionRadius(int id, int r) +{ + int i; // esi + + if ( numvision > 0 ) + { + for(i = 0; i < numvision; i++) + { + if ( VisionList[i]._lid == id ) + { + VisionList[i]._lunflag = 1; + VisionList[i]._lunx = VisionList[i]._lx; + VisionList[i]._luny = VisionList[i]._ly; + VisionList[i]._lunr = VisionList[i]._lradius; + VisionList[i]._lradius = r; + dovision = 1; + } + } + } +} +// 642A0C: using guessed type int dovision; + +void __fastcall ChangeVisionXY(int id, int x, int y) +{ + int i; // esi + + if ( numvision > 0 ) + { + for(i = 0; i < numvision; i++) + { + if ( VisionList[i]._lid == id ) + { + VisionList[i]._lunflag = 1; + VisionList[i]._lunx = VisionList[i]._lx; + VisionList[i]._luny = VisionList[i]._ly; + VisionList[i]._lunr = VisionList[i]._lradius; + VisionList[i]._lx = x; + VisionList[i]._ly = y; + dovision = 1; + } + } + } +} +// 642A0C: using guessed type int dovision; + +void __cdecl ProcessVisionList() +{ + bool delflag; // ecx + int i; + + if ( dovision ) + { + for(i = 0; i < numvision; i++) + { + if ( VisionList[i]._ldel ) + DoUnVision(VisionList[i]._lx, VisionList[i]._ly, VisionList[i]._lradius); + if ( VisionList[i]._lunflag ) + { + DoUnVision(VisionList[i]._lunx, VisionList[i]._luny, VisionList[i]._lunr); + VisionList[i]._lunflag = 0; + } + } + + if ( TransVal > 0 ) + memset(TransList, 0, TransVal); + + for(i = 0; i < numvision; i++) + { + if ( !VisionList[i]._ldel ) + DoVision(VisionList[i]._lx, VisionList[i]._ly, VisionList[i]._lradius, VisionList[i]._lflags & 1, VisionList[i]._lflags & 1); + } + + do + { + delflag = 0; + if ( numvision <= 0 ) + break; + for(i = 0; i < numvision; i++) + { + if ( VisionList[i]._ldel ) + { + --numvision; + if ( numvision > 0 && i != numvision ) + qmemcpy(&VisionList[i], &VisionList[numvision], sizeof(LightListStruct)); + delflag = 1; + } + } + } + while ( delflag ); + } + + dovision = 0; +} +// 5A5590: using guessed type char TransVal; +// 642A0C: using guessed type int dovision; + +void __cdecl lighting_color_cycling() +{ + char *v0; // eax + signed int v1; // ebx + char *v2; // eax + char *v3; // edi + char v4; // dl + const void *v5; // esi + + if ( leveltype == DTYPE_HELL ) + { + v0 = pLightTbl; + if ( (light4flag != 0 ? 4 : 16) > 0 ) + { + v1 = light4flag != 0 ? 4 : 16; + do + { + v2 = v0 + 1; + v3 = v2; + v4 = *v2; + v5 = v2 + 1; + v2 += 30; + qmemcpy(v3, v5, 0x1Eu); + *v2 = v4; + v0 = v2 + 225; + --v1; + } + while ( v1 ); + } + } +} +// 525728: using guessed type int light4flag; +// 5BB1ED: using guessed type char leveltype; diff --git a/Source/lighting.h b/Source/lighting.h new file mode 100644 index 000000000..c1dfd3f2b --- /dev/null +++ b/Source/lighting.h @@ -0,0 +1,55 @@ +//HEADER_GOES_HERE +#ifndef __LIGHTING_H__ +#define __LIGHTING_H__ + +extern LightListStruct VisionList[32]; +extern char lightactive[32]; +extern LightListStruct LightList[32]; +extern int numlights; +extern char dung_map_radius[2048]; /* char [16][128] */ +extern int dovision; // weak +extern int numvision; +extern char lightmax; // weak +extern int dolighting; // weak +extern char dung_map_rgba[16384]; /* int [64][64] short [64][128] char [64][256] */ +extern int visionid; +extern char *pLightTbl; /* todo: struct? */ +extern int lightflag; // weak + +void __fastcall SetLightFX(int *x, int *y, short *s_r, short *s_g, int *s_b, int *d_r, int *d_g, int *d_b); +void __fastcall DoLighting(int nXPos, int nYPos, int nRadius, int Lnum); +void __fastcall DoUnLight(int nXPos, int nYPos, int nRadius); +void __fastcall DoUnVision(int nXPos, int nYPos, int nRadius); +void __fastcall DoVision(int nXPos, int nYPos, int nRadius, unsigned char doautomap, int visible); +void __cdecl FreeLightTable(); +void __cdecl InitLightTable(); +void __cdecl MakeLightTable(); +#ifdef _DEBUG +void __cdecl ToggleLighting(); +#endif +void __cdecl InitLightMax(); +void __cdecl InitLighting(); +int __fastcall AddLight(int x, int y, int r); +void __fastcall AddUnLight(int i); +void __fastcall ChangeLightRadius(int i, int r); +void __fastcall ChangeLightXY(int i, int x, int y); +void __fastcall ChangeLightOff(int i, int x, int y); +void __fastcall ChangeLight(int i, int x, int y, int r); +void __cdecl ProcessLightList(); +void __cdecl SavePreLighting(); +void __cdecl InitVision(); +int __fastcall AddVision(int x, int y, int r, BOOL mine); +void __fastcall ChangeVisionRadius(int id, int r); +void __fastcall ChangeVisionXY(int id, int x, int y); +void __cdecl ProcessVisionList(); +void __cdecl lighting_color_cycling(); + +/* rdata */ + +extern char CrawlTable[2749]; +extern char *pCrawlTable[19]; +extern unsigned char vCrawlTable[23][30]; +extern unsigned char byte_49463C[18][18]; +extern unsigned char RadiusAdj[23]; + +#endif /* __LIGHTING_H__ */ diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp new file mode 100644 index 000000000..ef8572cb9 --- /dev/null +++ b/Source/loadsave.cpp @@ -0,0 +1,1267 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +void *tbuff; +#endif + +void __fastcall LoadGame(BOOL firstflag) +{ + int v1; // esi + int v2; // edi + int v5; // ebx + int v6; // eax + int v7; // eax + int v8; // ecx + bool v9; // sf + unsigned char v10; // of + int *v11; // esi + int *v12; // esi + int i; // esi + int *v14; // esi + int *v15; // esi + int j; // esi + int *v17; // esi + int *v18; // esi + int k; // esi + int l; // esi + signed int v21; // esi + int m; // esi + int v23; // esi + int *v24; // esi + int *v25; // esi + int n; // esi + int *v27; // esi + char *v29; // edi + char *v30; // edi + char *v31; // edi + char *v32; // edi + int (*v33)[112]; // ebx + _DWORD *v34; // edi + char *v35; // edi + char *v36; // edi + char *v37; // edi + char *v38; // edi + signed int v39; // ebx + bool *v40; // edi + char *v41; // edi + int v42; // esi + char dst[260]; // [esp+0h] [ebp-120h] + int len; // [esp+104h] [ebp-1Ch] + int v46; // [esp+108h] [ebp-18h] + int v47; // [esp+10Ch] [ebp-14h] + void *ptr; // [esp+110h] [ebp-10h] + int v49; // [esp+114h] [ebp-Ch] + int from_save; // [esp+118h] [ebp-8h] + int quest_num; // [esp+11Ch] [ebp-4h] + + FreeGameMem(); + pfile_remove_temp_files(); + pfile_get_game_name(dst); + ptr = pfile_read(dst, &len); + tbuff = ptr; + if ( ILoad_2() != 'RETL' ) + TermMsg("Invalid save file"); + setlevel = OLoad(); + setlvlnum = ILoad(); + currlevel = ILoad(); + leveltype = ILoad(); + v1 = ILoad(); + v2 = ILoad(); + invflag = OLoad(); + chrflag = OLoad(); + v5 = ILoad(); + v47 = ILoad(); + v49 = ILoad(); + v6 = ILoad(); + quest_num = 0; + v46 = v6; + do + { + *(int *)((char *)glSeedTbl + quest_num) = ILoad_2(); + v7 = ILoad(); + v8 = quest_num; + quest_num += 4; + v10 = __OFSUB__(quest_num, 68); + v9 = quest_num - 68 < 0; + *(int *)((char *)gnLevelTypeTbl + v8) = v7; + } + while ( v9 ^ v10 ); + LoadPlayer(myplr); + quest_num = 0; + do + LoadQuest(quest_num++); + while ( quest_num < MAXQUESTS ); + quest_num = 0; + do + LoadPortal(quest_num++); + while ( quest_num < MAXPORTAL ); + LoadGameLevel(firstflag, 4); + SyncInitPlr(myplr); + SyncPlrAnim(myplr); + ViewX = v1; + numitems = v47; + nummissiles = v49; + ViewY = v2; + nummonsters = v5; + nobjects = v46; + v11 = monstkills; + do + { + *v11 = ILoad_2(); + ++v11; + } + while ( (signed int)v11 < (signed int)&monstkills[MAXMONSTERS] ); + if ( leveltype ) + { + v12 = monstactive; + do + { + *v12 = ILoad(); + ++v12; + } + while ( (signed int)v12 < (signed int)&monstactive[MAXMONSTERS] ); + for ( i = 0; i < nummonsters; ++i ) + LoadMonster(monstactive[i]); + v14 = missileactive; + do + { + *v14 = BLoad(); + ++v14; + } + while ( (signed int)v14 < (signed int)&missileactive[MAXMISSILES] ); + v15 = missileavail; + do + { + *v15 = BLoad(); + ++v15; + } + while ( (signed int)v15 < (signed int)&missileavail[MAXMISSILES] ); + for ( j = 0; j < nummissiles; ++j ) + LoadMissile(missileactive[j]); + v17 = objectactive; + do + { + *v17 = BLoad(); + ++v17; + } + while ( (signed int)v17 < (signed int)&objectactive[MAXOBJECTS] ); + v18 = objectavail; + do + { + *v18 = BLoad(); + ++v18; + } + while ( (signed int)v18 < (signed int)&objectavail[MAXOBJECTS] ); + for ( k = 0; k < nobjects; ++k ) + LoadObject(objectactive[k]); + for ( l = 0; l < nobjects; ++l ) + SyncObjectAnim(objectactive[l]); + numlights = ILoad(); + v21 = 0; + do + lightactive[v21++] = BLoad(); + while ( v21 < 32 ); + for ( m = 0; m < numlights; ++m ) + LoadLighting((unsigned char)lightactive[m]); + visionid = ILoad(); + v23 = 0; + numvision = ILoad(); + if ( numvision > 0 ) + { + do + LoadVision(v23++); + while ( v23 < numvision ); + } + } + v24 = itemactive; + do + { + *v24 = BLoad(); + ++v24; + } + while ( (signed int)v24 < (signed int)&itemactive[MAXITEMS] ); + v25 = itemavail; + do + { + *v25 = BLoad(); + ++v25; + } + while ( (signed int)v25 < (signed int)&itemavail[MAXITEMS] ); + for ( n = 0; n < numitems; ++n ) + LoadItem(itemactive[n]); + v27 = UniqueItemFlag; + do + { + *v27 = OLoad(); + ++v27; + } + while ( (signed int)v27 < (signed int)&UniqueItemFlag[128] ); + quest_num = 0; + do + { + from_save = 112; + v29 = (char *)dTransVal + quest_num; + do + { + *v29 = BLoad(); + v29 += 112; + --from_save; + } + while ( from_save ); + ++quest_num; + } + while ( quest_num < 112 ); + quest_num = 0; + do + { + from_save = 112; + v30 = (char *)dFlags + quest_num; + do + { + *v30 = BLoad(); + v30 += 112; + --from_save; + } + while ( from_save ); + ++quest_num; + } + while ( quest_num < 112 ); + quest_num = 0; + do + { + from_save = 112; + v31 = (char *)dPlayer + quest_num; + do + { + *v31 = BLoad(); + v31 += 112; + --from_save; + } + while ( from_save ); + ++quest_num; + } + while ( quest_num < 112 ); + quest_num = 0; + do + { + from_save = 112; + v32 = (char *)dItem + quest_num; + do + { + *v32 = BLoad(); + v32 += 112; + --from_save; + } + while ( from_save ); + ++quest_num; + } + while ( quest_num < 112 ); + if ( leveltype ) + { + v33 = dMonster; + do + { + v34 = (unsigned int *)v33; + from_save = 112; + do + { + *v34 = ILoad(); + v34 += 112; + --from_save; + } + while ( from_save ); + v33 = (int (*)[112])((char *)v33 + 4); + } + while ( (signed int)v33 < (signed int)dMonster[1] ); + quest_num = 0; + do + { + from_save = 112; + v35 = (char *)dDead + quest_num; + do + { + *v35 = BLoad(); + v35 += 112; + --from_save; + } + while ( from_save ); + ++quest_num; + } + while ( quest_num < 112 ); + quest_num = 0; + do + { + from_save = 112; + v36 = (char *)dObject + quest_num; + do + { + *v36 = BLoad(); + v36 += 112; + --from_save; + } + while ( from_save ); + ++quest_num; + } + while ( quest_num < 112 ); + quest_num = 0; + do + { + from_save = 112; + v37 = (char *)dTransVal + quest_num; + do + { + *v37 = BLoad(); + v37 += 112; + --from_save; + } + while ( from_save ); + ++quest_num; + } + while ( quest_num < 112 ); + quest_num = 0; + do + { + from_save = 112; + v38 = (char *)dTransVal2 + quest_num; + do + { + *v38 = BLoad(); + v38 += 112; + --from_save; + } + while ( from_save ); + ++quest_num; + } + while ( quest_num < 112 ); + v39 = 0; + do + { + v40 = (bool *)automapview + v39; + from_save = 40; + do + { + *v40 = OLoad(); + v40 += 40; + --from_save; + } + while ( from_save ); + ++v39; + } + while ( v39 < 40 ); + quest_num = 0; + do + { + from_save = 112; + v41 = (char *)dMissile + quest_num; + do + { + *v41 = BLoad(); + v41 += 112; + --from_save; + } + while ( from_save ); + ++quest_num; + } + while ( quest_num < 112 ); + } + numpremium = ILoad(); + premiumlevel = ILoad(); + v42 = 0; + do + LoadPremium(v42++); + while ( v42 < 6 ); + automapflag = OLoad(); + AutoMapScale = ILoad(); + mem_free_dbg(ptr); + AutomapZoomReset(); + ResyncQuests(); + if ( leveltype ) + ProcessLightList(); + RedoPlayerVision(); + ProcessVisionList(); + missiles_process_charge(); + ResetPal(); + SetCursor(CURSOR_HAND); + gbProcessPlayers = 1; +} +// 5256A0: using guessed type int gbProcessPlayers; +// 5BB1ED: using guessed type char leveltype; +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +char __cdecl BLoad() +{ + char result; // al + + result = *(_BYTE *)tbuff; + tbuff = (char *)tbuff + 1; + return result; +} + +int __cdecl ILoad() +{ + int v0; // eax + int v1; // eax + unsigned short v2; // dx + int result; // eax + + v0 = *(unsigned char *)tbuff << 24; + tbuff = (char *)tbuff + 1; + v1 = (*(unsigned char *)tbuff << 16) | v0; + _LOBYTE(v2) = 0; + tbuff = (char *)tbuff + 1; + _HIBYTE(v2) = *(_BYTE *)tbuff; + tbuff = (char *)tbuff + 1; + result = *(unsigned char *)tbuff | v2 | v1; + tbuff = (char *)tbuff + 1; + return result; +} + +int __cdecl ILoad_2() +{ + int v0; // eax + int v1; // eax + unsigned short v2; // dx + int result; // eax + + v0 = *(unsigned char *)tbuff << 24; + tbuff = (char *)tbuff + 1; + v1 = (*(unsigned char *)tbuff << 16) | v0; + _LOBYTE(v2) = 0; + tbuff = (char *)tbuff + 1; + _HIBYTE(v2) = *(_BYTE *)tbuff; + tbuff = (char *)tbuff + 1; + result = *(unsigned char *)tbuff | v2 | v1; + tbuff = (char *)tbuff + 1; + return result; +} + +bool __cdecl OLoad() +{ + char v0; // cl + bool result; // al + + v0 = *(_BYTE *)tbuff; + tbuff = (char *)tbuff + 1; + result = 1; + if ( v0 != 1 ) + result = 0; + return result; +} + +void __fastcall LoadPlayer(int i) +{ + memcpy(&plr[i], tbuff, 0x54B0u); + tbuff = (char *)tbuff + 21680; +} + +void __fastcall LoadMonster(int i) +{ + int v1; // edi + + v1 = i; + memcpy(&monster[i], tbuff, 0xD8u); + tbuff = (char *)tbuff + 216; + SyncMonsterAnim(v1); +} + +void __fastcall LoadMissile(int i) +{ + memcpy(&missile[i], tbuff, 0xB0u); + tbuff = (char *)tbuff + 176; +} + +void __fastcall LoadObject(int i) +{ + memcpy(&object[i], tbuff, 0x78u); + tbuff = (char *)tbuff + 120; +} + +void __fastcall LoadItem(int i) +{ + int v1; // edi + + v1 = i; + memcpy(&item[i], tbuff, 0x170u); + tbuff = (char *)tbuff + 368; + GetItemFrm(v1); +} + +void __fastcall LoadPremium(int i) +{ + memcpy(&premiumitem[i], tbuff, 0x170u); + tbuff = (char *)tbuff + 368; +} + +void __fastcall LoadQuest(int i) +{ + memcpy(&quests[i], tbuff, 0x18u); + tbuff = (char *)tbuff + 24; + ReturnLvlX = ILoad(); + ReturnLvlY = ILoad(); + ReturnLvl = ILoad(); + ReturnLvlT = ILoad(); + DoomQuestState = ILoad(); +} + +void __fastcall LoadLighting(int i) +{ + memcpy(&LightList[i], tbuff, 0x34u); + tbuff = (char *)tbuff + 52; +} + +void __fastcall LoadVision(int i) +{ + memcpy(&VisionList[i], tbuff, 0x34u); + tbuff = (char *)tbuff + 52; +} + +void __fastcall LoadPortal(int i) +{ + memcpy(&portal[i], tbuff, 0x18u); + tbuff = (char *)tbuff + 24; +} + +void __cdecl SaveGame() +{ + int v0; // eax + signed int v1; // ebx + signed int v2; // esi + int v3; // esi + int v4; // esi + int *v5; // esi + int *v6; // esi + int i; // esi + int *v8; // esi + int *v9; // esi + int j; // esi + int *v11; // esi + int *v12; // esi + int k; // esi + signed int v14; // esi + int l; // esi + int m; // esi + int *v17; // esi + int *v18; // esi + int n; // esi + int *v20; // esi + char *v21; // edi + signed int v22; // ebx + _BYTE *v23; // edi + signed int v24; // ebx + char *v25; // edi + signed int v26; // ebx + char *v27; // edi + int (*v28)[112]; // ebx + int *v29; // edi + signed int v30; // ebx + char *v31; // edi + signed int v32; // ebx + char *v33; // edi + signed int v34; // ebx + char *v35; // edi + signed int v36; // ebx + char *v37; // edi + signed int v38; // ebx + unsigned char *v39; // edi + signed int v40; // ebx + char *v41; // edi + int v42; // esi + void *v43; // esi + int v44; // eax + char v45[260]; // [esp+Ch] [ebp-10Ch] + void *ptr; // [esp+110h] [ebp-8h] + int v47; // [esp+114h] [ebp-4h] + + v0 = codec_get_encoded_len(262147); /* FILEBUFF */ + ptr = DiabloAllocPtr(v0); + tbuff = ptr; + ISave_2('RETL'); + OSave(setlevel); + ISave((unsigned char)setlvlnum); + ISave(currlevel); + ISave((unsigned char)leveltype); + ISave(ViewX); + ISave(ViewY); + OSave(invflag); + OSave(chrflag); + ISave(nummonsters); + ISave(numitems); + ISave(nummissiles); + ISave(nobjects); + v1 = 0; + v2 = 0; + do + { + ISave_2(glSeedTbl[v2]); + ISave(gnLevelTypeTbl[v2]); + ++v2; + } + while ( v2 < NUMLEVELS ); + SavePlayer(myplr); + v3 = 0; + do + SaveQuest(v3++); + while ( v3 < MAXQUESTS ); + v4 = 0; + do + SavePortal(v4++); + while ( v4 < MAXPORTAL ); + v5 = monstkills; + do + { + ISave_2(*v5); + ++v5; + } + while ( (signed int)v5 < (signed int)&monstkills[MAXMONSTERS] ); + if ( leveltype ) + { + v6 = monstactive; + do + { + ISave(*v6); + ++v6; + } + while ( (signed int)v6 < (signed int)&monstactive[MAXMONSTERS] ); + for ( i = 0; i < nummonsters; ++i ) + SaveMonster(monstactive[i]); + v8 = missileactive; + do + { + BSave(*(_BYTE *)v8); + ++v8; + } + while ( (signed int)v8 < (signed int)&missileactive[MAXMISSILES] ); + v9 = missileavail; + do + { + BSave(*(_BYTE *)v9); + ++v9; + } + while ( (signed int)v9 < (signed int)&missileavail[MAXMISSILES] ); + for ( j = 0; j < nummissiles; ++j ) + SaveMissile(missileactive[j]); + v11 = objectactive; + do + { + BSave(*(_BYTE *)v11); + ++v11; + } + while ( (signed int)v11 < (signed int)&objectactive[MAXOBJECTS] ); + v12 = objectavail; + do + { + BSave(*(_BYTE *)v12); + ++v12; + } + while ( (signed int)v12 < (signed int)&objectavail[MAXOBJECTS] ); + for ( k = 0; k < nobjects; ++k ) + SaveObject(objectactive[k]); + ISave(numlights); + v14 = 0; + do + BSave(lightactive[v14++]); + while ( v14 < 32 ); + for ( l = 0; l < numlights; ++l ) + SaveLighting((unsigned char)lightactive[l]); + ISave(visionid); + ISave(numvision); + for ( m = 0; m < numvision; ++m ) + SaveVision(m); + } + v17 = itemactive; + do + { + BSave(*(_BYTE *)v17); + ++v17; + } + while ( (signed int)v17 < (signed int)&itemactive[MAXITEMS] ); + v18 = itemavail; + do + { + BSave(*(_BYTE *)v18); + ++v18; + } + while ( (signed int)v18 < (signed int)&itemavail[MAXITEMS] ); + for ( n = 0; n < numitems; ++n ) + SaveItem(itemactive[n]); + v20 = UniqueItemFlag; + do + { + OSave(*v20); + ++v20; + } + while ( (signed int)v20 < (signed int)&UniqueItemFlag[128] ); + do + { + v21 = (char *)dTransVal + v1; + v47 = 112; + do + { + BSave(*v21); + v21 += 112; + --v47; + } + while ( v47 ); + ++v1; + } + while ( v1 < 112 ); + v22 = 0; + do + { + v23 = (unsigned char *)dFlags + v22; + v47 = 112; + do + { + BSave(*v23 & 0xF8); + v23 += 112; + --v47; + } + while ( v47 ); + ++v22; + } + while ( v22 < 112 ); + v24 = 0; + do + { + v25 = (char *)dPlayer + v24; + v47 = 112; + do + { + BSave(*v25); + v25 += 112; + --v47; + } + while ( v47 ); + ++v24; + } + while ( v24 < 112 ); + v26 = 0; + do + { + v27 = (char *)dItem + v26; + v47 = 112; + do + { + BSave(*v27); + v27 += 112; + --v47; + } + while ( v47 ); + ++v26; + } + while ( v26 < 112 ); + if ( leveltype ) + { + v28 = dMonster; + do + { + v29 = (int *)v28; + v47 = 112; + do + { + ISave(*v29); + v29 += 112; + --v47; + } + while ( v47 ); + v28 = (int (*)[112])((char *)v28 + 4); + } + while ( (signed int)v28 < (signed int)dMonster[1] ); + v30 = 0; + do + { + v31 = (char *)dDead + v30; + v47 = 112; + do + { + BSave(*v31); + v31 += 112; + --v47; + } + while ( v47 ); + ++v30; + } + while ( v30 < 112 ); + v32 = 0; + do + { + v33 = (char *)dObject + v32; + v47 = 112; + do + { + BSave(*v33); + v33 += 112; + --v47; + } + while ( v47 ); + ++v32; + } + while ( v32 < 112 ); + v34 = 0; + do + { + v35 = (char *)dTransVal + v34; + v47 = 112; + do + { + BSave(*v35); + v35 += 112; + --v47; + } + while ( v47 ); + ++v34; + } + while ( v34 < 112 ); + v36 = 0; + do + { + v37 = (char *)dTransVal2 + v36; + v47 = 112; + do + { + BSave(*v37); + v37 += 112; + --v47; + } + while ( v47 ); + ++v36; + } + while ( v36 < 112 ); + v38 = 0; + do + { + v39 = (unsigned char *)automapview + v38; + v47 = 40; + do + { + OSave(*v39); + v39 += 40; + --v47; + } + while ( v47 ); + ++v38; + } + while ( v38 < 40 ); + v40 = 0; + do + { + v41 = (char *)dMissile + v40; + v47 = 112; + do + { + BSave(*v41); + v41 += 112; + --v47; + } + while ( v47 ); + ++v40; + } + while ( v40 < 112 ); + } + ISave(numpremium); + ISave(premiumlevel); + v42 = 0; + do + SavePremium(v42++); + while ( v42 < 6 ); + OSave(automapflag); + ISave(AutoMapScale); + pfile_get_game_name(v45); + v43 = ptr; + v44 = codec_get_encoded_len((_BYTE *)tbuff - (_BYTE *)ptr); + pfile_write_save_file(v45, v43, (_BYTE *)tbuff - (_BYTE *)v43, v44); + mem_free_dbg(v43); + *(_DWORD *)&gbValidSaveFile = 1; + pfile_rename_temp_to_perm(); + pfile_write_hero(); +} +// 5BB1ED: using guessed type char leveltype; +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +void __fastcall BSave(char v) +{ + *(_BYTE *)tbuff = v; + tbuff = (char *)tbuff + 1; +} + +void __fastcall ISave(int v) +{ + *(_BYTE *)tbuff = _HIBYTE(v); + tbuff = (char *)tbuff + 1; + *(_BYTE *)tbuff = BYTE2(v); + tbuff = (char *)tbuff + 1; + *(_BYTE *)tbuff = BYTE1(v); + tbuff = (char *)tbuff + 1; + *(_BYTE *)tbuff = v; + tbuff = (char *)tbuff + 1; +} + +void __fastcall ISave_2(int v) +{ + *(_BYTE *)tbuff = _HIBYTE(v); + tbuff = (char *)tbuff + 1; + *(_BYTE *)tbuff = BYTE2(v); + tbuff = (char *)tbuff + 1; + *(_BYTE *)tbuff = BYTE1(v); + tbuff = (char *)tbuff + 1; + *(_BYTE *)tbuff = v; + tbuff = (char *)tbuff + 1; +} + +void __fastcall OSave(unsigned char v) +{ + if ( v ) + *(_BYTE *)tbuff = 1; + else + *(_BYTE *)tbuff = 0; + tbuff = (char *)tbuff + 1; +} + +void __fastcall SavePlayer(int i) +{ + memcpy(tbuff, &plr[i], 0x54B0u); + tbuff = (char *)tbuff + 21680; +} + +void __fastcall SaveMonster(int i) +{ + memcpy(tbuff, &monster[i], 0xD8u); + tbuff = (char *)tbuff + 216; +} + +void __fastcall SaveMissile(int i) +{ + memcpy(tbuff, &missile[i], 0xB0u); + tbuff = (char *)tbuff + 176; +} + +void __fastcall SaveObject(int i) +{ + memcpy(tbuff, &object[i], 0x78u); + tbuff = (char *)tbuff + 120; +} + +void __fastcall SaveItem(int i) +{ + memcpy(tbuff, &item[i], 0x170u); + tbuff = (char *)tbuff + 368; +} + +void __fastcall SavePremium(int i) +{ + memcpy(tbuff, &premiumitem[i], 0x170u); + tbuff = (char *)tbuff + 368; +} + +void __fastcall SaveQuest(int i) +{ + memcpy(tbuff, &quests[i], 0x18u); + tbuff = (char *)tbuff + 24; + ISave(ReturnLvlX); + ISave(ReturnLvlY); + ISave(ReturnLvl); + ISave(ReturnLvlT); + ISave(DoomQuestState); +} + +void __fastcall SaveLighting(int i) +{ + memcpy(tbuff, &LightList[i], 0x34u); + tbuff = (char *)tbuff + 52; +} + +void __fastcall SaveVision(int i) +{ + memcpy(tbuff, &VisionList[i], 0x34u); + tbuff = (char *)tbuff + 52; +} + +void __fastcall SavePortal(int i) +{ + memcpy(tbuff, &portal[i], 0x18u); + tbuff = (char *)tbuff + 24; +} + +void __cdecl SaveLevel() +{ + int v0; // eax + int i; // esi + int j; // esi + void *v47; // esi + int v48; // eax + int v49; // eax + char v50[260]; // [esp+0h] [ebp-10Ch] + void *SaveBuff; // [esp+104h] [ebp-8h] + + if ( !currlevel ) + glSeedTbl[0] = GetRndSeed(); + v0 = codec_get_encoded_len(262147); /* FILEBUFF */ + SaveBuff = DiabloAllocPtr(v0); + tbuff = SaveBuff; + if ( leveltype ) + { + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + BSave(dDead[j][i]); /* check */ + } + } + } + ISave(nummonsters); + ISave(numitems); + ISave(nobjects); + + if ( leveltype ) + { + for(i = 0; i < MAXMONSTERS; i++) + ISave(monstactive[i]); + + for(i = 0; i < nummonsters; i++) + SaveMonster(monstactive[i]); + + for(i = 0; i < MAXOBJECTS; i++) + BSave(objectactive[i]); + + for(i = 0; i < MAXOBJECTS; i++) + BSave(objectavail[i]); + + for(i = 0; i < nobjects; i++) + SaveObject(objectactive[i]); + } + + for(i = 0; i < MAXITEMS; i++) + BSave(itemactive[i]); + + for(i = 0; i < MAXITEMS; i++) + BSave(itemavail[i]); + + for(i = 0; i < numitems; i++) + SaveItem(itemactive[i]); + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + BSave(dFlags[j][i] & 0xF8); + } + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + BSave(dItem[j][i]); + } + } + + if ( leveltype ) + { + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + ISave(dMonster[j][i]); + } + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + BSave(dObject[j][i]); + } + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + BSave(dTransVal[j][i]); + } + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + BSave(dTransVal2[j][i]); + } + } + + for(i = 0; i < 40; i++) + { + for(j = 0; j < 40; j++) + { + OSave(automapview[j][i]); + } + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + BSave(dMissile[j][i]); + } + } + } + GetTempLevelNames(v50); + v47 = SaveBuff; + v48 = codec_get_encoded_len((_BYTE *)tbuff - (_BYTE *)SaveBuff); + pfile_write_save_file(v50, v47, (_BYTE *)tbuff - (_BYTE *)v47, v48); + mem_free_dbg(v47); + v49 = myplr; + if ( setlevel ) + plr[v49]._pSLvlVisited[(unsigned char)setlvlnum] = 1; + else + plr[v49]._pLvlVisited[currlevel] = 1; +} +// 5BB1ED: using guessed type char leveltype; +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +void __cdecl LoadLevel() +{ + int i; // esi + int j; // esi + char dst[260]; // [esp+Ch] [ebp-10Ch] + int len; // [esp+110h] [ebp-8h] + void *LoadBuff; // [esp+114h] [ebp-4h] + + GetPermLevelNames(dst); + LoadBuff = pfile_read(dst, &len); + tbuff = LoadBuff; + + if ( leveltype ) + { + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + dDead[j][i] = BLoad(); /* check */ + } + } + + SetDead(); + } + + nummonsters = ILoad(); + numitems = ILoad(); + nobjects = ILoad(); + + if ( leveltype ) + { + for(i = 0; i < MAXMONSTERS; i++) + monstactive[i] = ILoad(); + + for(i = 0; i < nummonsters; i++) + LoadMonster(monstactive[i]); + + for(i = 0; i < MAXOBJECTS; i++) + objectactive[i] = BLoad(); + + for(i = 0; i < MAXOBJECTS; i++) + objectavail[i] = BLoad(); + + for(i = 0; i < nobjects; i++) + LoadObject(objectactive[i]); + + for(i = 0; i < nobjects; i++) + SyncObjectAnim(objectactive[i]); + } + + for(i = 0; i < MAXITEMS; i++) + itemactive[i] = BLoad(); + + for(i = 0; i < MAXITEMS; i++) + itemavail[i] = BLoad(); + + for(i = 0; i < numitems; i++) + LoadItem(itemactive[i]); + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + dFlags[j][i] = BLoad(); + } + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + dItem[j][i] = BLoad(); + } + } + + if ( leveltype ) + { + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + dMonster[j][i] = ILoad(); + } + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + dObject[j][i] = BLoad(); + } + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + dTransVal[j][i] = BLoad(); + } + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + dTransVal2[j][i] = BLoad(); + } + } + + for(i = 0; i < 40; i++) + { + for(j = 0; j < 40; j++) + { + automapview[j][i] = OLoad(); + } + } + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + dMissile[j][i] = 0; + } + } + } + + AutomapZoomReset(); + ResyncQuests(); + SyncPortals(); + dolighting = 1; + + for(i = 0; i < 4; i++) + { + if ( plr[i].plractive && currlevel == plr[i].plrlevel ) + LightList[plr[i]._plid]._lunflag = 1; + } + + mem_free_dbg(LoadBuff); +} +// 5BB1ED: using guessed type char leveltype; +// 642A18: using guessed type int dolighting; diff --git a/Source/loadsave.h b/Source/loadsave.h new file mode 100644 index 000000000..8782c1dff --- /dev/null +++ b/Source/loadsave.h @@ -0,0 +1,40 @@ +//HEADER_GOES_HERE +#ifndef __LOADSAVE_H__ +#define __LOADSAVE_H__ + +extern void *tbuff; + +void __fastcall LoadGame(BOOL firstflag); +char __cdecl BLoad(); +int __cdecl ILoad(); +int __cdecl ILoad_2(); +bool __cdecl OLoad(); +void __fastcall LoadPlayer(int i); +void __fastcall LoadMonster(int i); +void __fastcall LoadMissile(int i); +void __fastcall LoadObject(int i); +void __fastcall LoadItem(int i); +void __fastcall LoadPremium(int i); +void __fastcall LoadQuest(int i); +void __fastcall LoadLighting(int i); +void __fastcall LoadVision(int i); +void __fastcall LoadPortal(int i); +void __cdecl SaveGame(); +void __fastcall BSave(char v); +void __fastcall ISave(int v); +void __fastcall ISave_2(int v); +void __fastcall OSave(unsigned char v); +void __fastcall SavePlayer(int i); +void __fastcall SaveMonster(int i); +void __fastcall SaveMissile(int i); +void __fastcall SaveObject(int i); +void __fastcall SaveItem(int i); +void __fastcall SavePremium(int i); +void __fastcall SaveQuest(int i); +void __fastcall SaveLighting(int i); +void __fastcall SaveVision(int i); +void __fastcall SavePortal(int i); +void __cdecl SaveLevel(); +void __cdecl LoadLevel(); + +#endif /* __LOADSAVE_H__ */ diff --git a/Source/logging.cpp b/Source/logging.cpp new file mode 100644 index 000000000..885c51cb5 --- /dev/null +++ b/Source/logging.cpp @@ -0,0 +1,229 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int log_cpp_init_value; // weak +static CRITICAL_SECTION sgMemCrit; +CHAR FileName[260]; // idb +char log_buffer[388]; +LPCVOID lpAddress; // idb +DWORD nNumberOfBytesToWrite; // idb + +const int log_inf = 0x7F800000; // weak + +/* data */ + +int log_not_created = 1; // weak +HANDLE log_file = (HANDLE)0xFFFFFFFF; // idb + +struct log_cpp_init_1 +{ + log_cpp_init_1() + { + log_cpp_init_value = log_inf; + } +} _log_cpp_init_1; +// 47F070: using guessed type int log_inf; +// 646A30: using guessed type int log_cpp_init_value; + +struct log_cpp_init_2 +{ + log_cpp_init_2() + { + log_init_mutex(); + j_log_cleanup_mutex(); + } +} _log_cpp_init_2; + +void __cdecl log_init_mutex() +{ + InitializeCriticalSection(&sgMemCrit); +} + +void __cdecl j_log_cleanup_mutex() +{ + atexit(log_cleanup_mutex); +} + +void __cdecl log_cleanup_mutex() +{ + DeleteCriticalSection(&sgMemCrit); +} + +void __cdecl log_flush(bool force_close) +{ + void *v1; // eax + DWORD NumberOfBytesWritten; // [esp+8h] [ebp-4h] + + EnterCriticalSection(&sgMemCrit); + if ( nNumberOfBytesToWrite ) + { + if ( log_file == (HANDLE)-1 ) + { + v1 = log_create(); + log_file = v1; + if ( v1 == (void *)-1 ) + { + nNumberOfBytesToWrite = 0; + return; + } + SetFilePointer(v1, 0, NULL, FILE_END); + } + WriteFile(log_file, lpAddress, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0); + nNumberOfBytesToWrite = 0; + } + if ( force_close && log_file != (HANDLE)-1 ) + { + CloseHandle(log_file); + log_file = (HANDLE)-1; + } + LeaveCriticalSection(&sgMemCrit); +} + +void *__cdecl log_create() +{ + char *v0; // eax + void *v1; // ebx + HANDLE v2; // eax + char *v3; // edx + char Filename[260]; // [esp+Ch] [ebp-15Ch] + VS_FIXEDFILEINFO file_info; // [esp+110h] [ebp-58h] + char Buffer[32]; // [esp+144h] [ebp-24h] + DWORD pcbBuffer; // [esp+164h] [ebp-4h] + + if ( log_not_created ) + { + if ( GetModuleFileName(0, Filename, 0x104u) && (v0 = strrchr(Filename, '\\')) != 0 ) + v0[1] = 0; + else + Filename[0] = 0; + pcbBuffer = 32; + if ( !GetUserName(Buffer, &pcbBuffer) ) + Buffer[0] = 0; + log_get_version(&file_info); + _snprintf( + FileName, + 0x104u, + "%s%s%02u%02u%02u.ERR", + Filename, + Buffer, + _LOWORD(file_info.dwProductVersionMS), + file_info.dwProductVersionLS >> 16, + _LOWORD(file_info.dwProductVersionLS)); + } + v1 = (void *)-1; + for ( pcbBuffer = log_not_created == 0; (signed int)pcbBuffer < 2; ++pcbBuffer ) + { + v2 = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + v1 = v2; + if ( v2 != (HANDLE)-1 ) + { + if ( GetFileSize(v2, 0) > 0x10000 ) + SetEndOfFile(v1); + break; + } + v3 = strrchr(FileName, '\\'); + if ( !v3 ) + v3 = FileName; + strcpy(Filename, "c:\\"); + memset(&Filename[4], 0, 0x100u); + strcat(Filename, v3); + strcpy(FileName, Filename); + } + log_not_created = 0; + return v1; +} +// 4947D4: using guessed type int log_not_created; + +void __fastcall log_get_version(VS_FIXEDFILEINFO *file_info) +{ + DWORD v1; // eax + DWORD v2; // esi + void *v3; // ebx + unsigned int v4; // eax + char Filename[260]; // [esp+8h] [ebp-114h] + DWORD dwHandle; // [esp+10Ch] [ebp-10h] + LPVOID lpBuffer; // [esp+110h] [ebp-Ch] + unsigned int puLen; // [esp+114h] [ebp-8h] + void *v9; // [esp+118h] [ebp-4h] + + v9 = file_info; + memset(file_info, 0, 0x34u); + if ( GetModuleFileName(0, Filename, 0x104u) ) + { + v1 = GetFileVersionInfoSize(Filename, &dwHandle); + v2 = v1; + if ( v1 ) + { + v3 = VirtualAlloc(0, v1, 0x1000u, 4u); + if ( GetFileVersionInfo(Filename, 0, v2, v3) && VerQueryValue(v3, "\\", &lpBuffer, &puLen) ) + { + v4 = puLen; + if ( puLen >= 0x34 ) + v4 = 52; + memcpy(v9, lpBuffer, v4); + } + VirtualFree(v3, 0, 0x8000u); + } + } +} + +void log_printf(const char *pszFmt, ...) +{ + size_t v1; // edi + char *v2; // eax + char v3[512]; // [esp+Ch] [ebp-200h] + va_list va; // [esp+218h] [ebp+Ch] + + va_start(va, pszFmt); + EnterCriticalSection(&sgMemCrit); + _vsnprintf(v3, 0x200u, pszFmt, va); + v3[511] = 0; + v1 = strlen(v3); + if ( v1 + nNumberOfBytesToWrite > 0x1000 ) + log_flush(0); + v2 = (char *)lpAddress; + if ( lpAddress + || (v2 = (char *)VirtualAlloc((LPVOID)lpAddress, 0x1000u, 0x1000u, 4u), + nNumberOfBytesToWrite = 0, + (lpAddress = v2) != 0) ) + { + memcpy(&v2[nNumberOfBytesToWrite], v3, v1); + nNumberOfBytesToWrite += v1; + } + LeaveCriticalSection(&sgMemCrit); +} + +void __cdecl log_dump_computer_info() +{ + char Buffer[64]; // [esp+0h] [ebp-88h] + VS_FIXEDFILEINFO file_info; // [esp+40h] [ebp-48h] + struct _SYSTEMTIME SystemTime; // [esp+74h] [ebp-14h] + DWORD pcbBuffer; // [esp+84h] [ebp-4h] + + GetLocalTime(&SystemTime); + pcbBuffer = 64; + if ( !GetUserName(Buffer, &pcbBuffer) ) + Buffer[0] = 0; + log_get_version(&file_info); + log_printf( + "\r\n" + "------------------------------------------------------\r\n" + "PROGRAM VERSION: %d.%d.%d.%d\r\n" + "COMPUTER NAME: %s\r\n" + "TIME: %02u/%02u/%02u %02u:%02u:%02u\r\n" + "INFO: %s\r\n" + "\r\n", + file_info.dwProductVersionMS >> 16, + _LOWORD(file_info.dwProductVersionMS), + file_info.dwProductVersionLS >> 16, + _LOWORD(file_info.dwProductVersionLS), + Buffer, + SystemTime.wMonth, + SystemTime.wDay, + SystemTime.wYear % 100, + SystemTime.wHour, + SystemTime.wMinute, + SystemTime.wSecond, + log_buffer); +} diff --git a/Source/logging.h b/Source/logging.h new file mode 100644 index 000000000..b910555d1 --- /dev/null +++ b/Source/logging.h @@ -0,0 +1,31 @@ +//HEADER_GOES_HERE +#ifndef __LOGGING_H__ +#define __LOGGING_H__ + +extern int log_cpp_init_value; // weak +extern CHAR FileName[260]; // idb +extern char log_buffer[388]; +extern LPCVOID lpAddress; // idb +extern DWORD nNumberOfBytesToWrite; // idb + +void __cdecl log_cpp_init_1(); +void __cdecl log_cpp_init_2(); +void __cdecl log_init_mutex(); +void __cdecl j_log_cleanup_mutex(); +void __cdecl log_cleanup_mutex(); +void __cdecl log_flush(bool force_close); +void *__cdecl log_create(); // should be HANDLE +void __fastcall log_get_version(VS_FIXEDFILEINFO *file_info); +void log_printf(const char *pszFmt, ...); // LogMessage +void __cdecl log_dump_computer_info(); + +/* rdata */ + +extern const int log_inf; // weak + +/* data */ + +extern int log_not_created; // weak +extern HANDLE log_file; // idb + +#endif /* __LOGGING_H__ */ diff --git a/Source/mainmenu.cpp b/Source/mainmenu.cpp new file mode 100644 index 000000000..6826f850a --- /dev/null +++ b/Source/mainmenu.cpp @@ -0,0 +1,191 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int mainmenu_cpp_init_value; // weak + +#ifndef NO_GLOBALS +char chr_name_str[16]; +#endif + +const int mainmenu_inf = 0x7F800000; // weak + +/* data */ + +int menu_music_track_id = 5; // idb + +struct mainmenu_cpp_init +{ + mainmenu_cpp_init() + { + mainmenu_cpp_init_value = mainmenu_inf; + } +} _mainmenu_cpp_init; +// 47F074: using guessed type int mainmenu_inf; +// 646CE0: using guessed type int mainmenu_cpp_init_value; + +void __cdecl mainmenu_refresh_music() +{ + int v0; // eax + + music_start(menu_music_track_id); + v0 = menu_music_track_id; + do + { + if ( ++v0 == 6 ) + v0 = 0; + } + while ( !v0 || v0 == 1 ); + menu_music_track_id = v0; +} + +void __stdcall mainmenu_create_hero(char *a1, char *a2) +{ + // char *v2; // [esp-14h] [ebp-14h] + + if ( UiValidPlayerName(a1) ) /* v2 */ + pfile_create_save_file(a1, a2); +} + +int __stdcall mainmenu_select_hero_dialog(int u1, int u2, int u3, int u4, int mode, char *cname, int clen, char *cdesc, int cdlen, int *multi) /* fix args */ +{ + int v10; // eax + int a6; // [esp+8h] [ebp-8h] + int a5; // [esp+Ch] [ebp-4h] + + a6 = 1; + a5 = 0; + if ( gbMaxPlayers == 1 ) + { + if ( !UiSelHeroSingDialog( + pfile_ui_set_hero_infos, + pfile_ui_save_create, + pfile_delete_save, + pfile_ui_set_class_stats, + &a5, + chr_name_str, + &gnDifficulty) ) + TermMsg("Unable to display SelHeroSing"); + if ( a5 == 2 ) + { + dword_5256E8 = 1; + goto LABEL_6; + } + dword_5256E8 = 0; + } + else if ( !UiSelHeroMultDialog( + pfile_ui_set_hero_infos, + pfile_ui_save_create, + pfile_delete_save, + pfile_ui_set_class_stats, + &a5, + &a6, + chr_name_str) ) + { + TermMsg("Can't load multiplayer dialog"); + } + if ( a5 == 4 ) + { + SErrSetLastError(1223); + return 0; + } +LABEL_6: + pfile_create_player_description(cdesc, cdlen); + if ( multi ) + { + if ( mode == 'BNET' ) + v10 = a6 || !plr[myplr].pBattleNet; + else + v10 = a6; + *multi = v10; + } + if ( cname ) + { + if ( clen ) + SStrCopy(cname, chr_name_str, clen); + } + return 1; +} +// 5256E8: using guessed type int dword_5256E8; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall mainmenu_action(int option) +{ + int v1; // eax + int a2; // [esp+0h] [ebp-4h] + + a2 = option; + mainmenu_refresh_music(); + do + { + while ( 1 ) + { + a2 = 0; + if ( !UiMainMenuDialog("Diablo v1.09", &a2, effects_play_sound, 30) ) + TermMsg("Unable to display mainmenu"); + if ( a2 == 1 ) + break; + switch ( a2 ) + { + case MAINMENU_MULTIPLAYER: + v1 = mainmenu_multi_player(); + goto LABEL_15; + case MAINMENU_REPLAY_INTRO: + goto LABEL_10; + case MAINMENU_SHOW_CREDITS: + UiCreditsDialog(16); + break; + case MAINMENU_EXIT_DIABLO: + goto LABEL_16; + case MAINMENU_ATTRACT_MODE: +LABEL_10: + if ( gbActive ) + mainmenu_play_intro(); + break; + } + } + v1 = mainmenu_single_player(); +LABEL_15: + ; + } + while ( v1 ); +LABEL_16: + music_stop(); +} +// 634980: using guessed type int gbActive; + +int __cdecl mainmenu_single_player() +{ + gbMaxPlayers = 1; + return mainmenu_init_menu(1); +} +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall mainmenu_init_menu(int a1) +{ + int v1; // esi + int v3; // esi + + v1 = a1; + if ( a1 == 4 ) + return 1; + music_stop(); + v3 = diablo_init_menu(v1 != 2, v1 != 3); + if ( v3 ) + mainmenu_refresh_music(); + return v3; +} + +int __cdecl mainmenu_multi_player() +{ + gbMaxPlayers = MAX_PLRS; + return mainmenu_init_menu(3); +} +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl mainmenu_play_intro() +{ + music_stop(); + play_movie("gendata\\diablo1.smk", 1); + mainmenu_refresh_music(); +} diff --git a/Source/mainmenu.h b/Source/mainmenu.h new file mode 100644 index 000000000..336b98400 --- /dev/null +++ b/Source/mainmenu.h @@ -0,0 +1,26 @@ +//HEADER_GOES_HERE +#ifndef __MAINMENU_H__ +#define __MAINMENU_H__ + +extern int mainmenu_cpp_init_value; // weak +extern char chr_name_str[16]; + +void __cdecl mainmenu_cpp_init(); +void __cdecl mainmenu_refresh_music(); +void __stdcall mainmenu_create_hero(char *, char *); +int __stdcall mainmenu_select_hero_dialog(int u1, int u2, int u3, int u4, int mode, char *cname, int clen, char *cdesc, int cdlen, int *multi); +void __fastcall mainmenu_action(int option); +int __cdecl mainmenu_single_player(); +int __fastcall mainmenu_init_menu(int a1); +int __cdecl mainmenu_multi_player(); +void __cdecl mainmenu_play_intro(); + +/* rdata */ + +extern const int mainmenu_inf; // weak + +/* data */ + +extern int menu_music_track_id; // idb + +#endif /* __MAINMENU_H__ */ diff --git a/Source/minitext.cpp b/Source/minitext.cpp new file mode 100644 index 000000000..742e3eaae --- /dev/null +++ b/Source/minitext.cpp @@ -0,0 +1,326 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int qtexty; // weak +char *qtextptr; +int qtextSpd; // weak +char qtextflag; // weak +int scrolltexty; // weak +int sgLastScroll; // weak +void *pMedTextCels; +void *pTextBoxCels; +#endif + +const unsigned char mfontframe[127] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 49, 38, 0, 39, 40, 47, + 42, 43, 41, 45, 52, 44, 53, 55, 36, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 51, 50, + 48, 46, 49, 54, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 42, 0, 43, 0, 0, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 48, 0, 49, 0 +}; +const unsigned char mfontkern[56] = +{ + 5, 15, 10, 13, 14, 10, 9, 13, 11, 5, + 5, 11, 10, 16, 13, 16, 10, 15, 12, 10, + 14, 17, 17, 22, 17, 16, 11, 5, 11, 11, + 11, 10, 11, 11, 11, 11, 15, 5, 10, 18, + 15, 8, 6, 6, 7, 10, 9, 6, 10, 10, + 5, 5, 5, 5, 11, 12 +}; + +/* data */ + +int qscroll_spd_tbl[9] = { 2, 4, 6, 8, 0, -1, -2, -3, -4 }; + +void __cdecl FreeQuestText() +{ + void *v0; // ecx + void *v1; // ecx + + v0 = pMedTextCels; + pMedTextCels = 0; + mem_free_dbg(v0); + v1 = pTextBoxCels; + pTextBoxCels = 0; + mem_free_dbg(v1); +} + +void __cdecl InitQuestText() +{ + unsigned char *v0; // eax + + pMedTextCels = LoadFileInMem("Data\\MedTextS.CEL", 0); + v0 = LoadFileInMem("Data\\TextBox.CEL", 0); + qtextflag = 0; + pTextBoxCels = v0; +} +// 646D00: using guessed type char qtextflag; + +void __fastcall InitQTextMsg(int m) +{ + if ( alltext[m].scrlltxt ) + { + questlog = 0; + qtextptr = alltext[m].txtstr; + qtextflag = 1; + qtexty = 500; + sgLastScroll = qscroll_spd_tbl[alltext[m].txtspd - 1]; /* double check offset */ + scrolltexty = sgLastScroll; + qtextSpd = GetTickCount(); + } + PlaySFX(alltext[m].sfxnr); +} +// 646CF4: using guessed type int qtexty; +// 646CFC: using guessed type int qtextSpd; +// 646D00: using guessed type char qtextflag; +// 646D04: using guessed type int scrolltexty; +// 646D08: using guessed type int sgLastScroll; +// 69BD04: using guessed type int questlog; + +void __cdecl DrawQTextBack() +{ + char *v0; // edi + signed int v1; // edx + signed int v2; // ecx + int v3; // edi + signed int v4; // ecx + _BYTE *v5; // edi + signed int v6; // ecx + + CelDecodeOnly(88, 487, pTextBoxCels, 1, 591); + v0 = &gpBuffer->row[324].pixels[27]; + v1 = 148; + do + { + v2 = 292; + do + { + *v0 = 0; + v0 += 2; + --v2; + } + while ( v2 ); + *v0 = 0; + v3 = (int)(v0 - 1352); + v4 = 292; + do + { + v5 = (_BYTE *)(v3 + 1); + *v5 = 0; + v3 = (int)(v5 + 1); + --v4; + } + while ( v4 ); + v0 = (char *)(v3 - 1352); + --v1; + } + while ( v1 ); + v6 = 292; + do + { + *v0 = 0; + v0 += 2; + --v6; + } + while ( v6 ); + *v0 = 0; +} + +void __fastcall PrintQTextChr(int screen_x, int screen_y, char *cel_buf, int frame) +{ + char *v4; // ebx + char *v5; // esi + char *v6; // edi + int v7; // ebx + signed int v8; // edx + unsigned int v9; // eax + unsigned int v10; // ecx + char v11; // cf + unsigned int v12; // ecx + char *v13; // [esp+14h] [ebp-8h] + char *v14; // [esp+18h] [ebp-4h] + + v13 = (char *)gpBuffer + screen_y_times_768[209]; + v14 = (char *)gpBuffer + screen_y_times_768[469]; + v4 = &cel_buf[4 * frame]; + v5 = &cel_buf[*(_DWORD *)v4]; + v6 = (char *)gpBuffer + screen_y_times_768[screen_y] + screen_x; + v7 = (int)&v5[*((_DWORD *)v4 + 1) - *(_DWORD *)v4]; + do + { + v8 = 22; + do + { + while ( 1 ) + { + v9 = (unsigned char)*v5++; + if ( (v9 & 0x80u) == 0 ) + break; + _LOBYTE(v9) = -(char)v9; + v6 += v9; + v8 -= v9; + if ( !v8 ) + goto LABEL_15; + } + v8 -= v9; + if ( v6 < v13 || v6 > v14 ) + { + v5 += v9; + v6 += v9; + } + else + { + v10 = v9 >> 1; + if ( !(v9 & 1) || (*v6 = *v5, ++v5, ++v6, v10) ) + { + v11 = v10 & 1; + v12 = v9 >> 2; + if ( !v11 || (*(_WORD *)v6 = *(_WORD *)v5, v5 += 2, v6 += 2, v12) ) + { + qmemcpy(v6, v5, 4 * v12); + v5 += 4 * v12; + v6 += 4 * v12; + } + } + } + } + while ( v8 ); +LABEL_15: + v6 -= 790; + } + while ( (char *)v7 != v5 ); +} + +void __cdecl DrawQText() +{ + char *v0; // edi + signed int v1; // edx + int v2; // ecx + char *i; // esi + unsigned char v4; // al + unsigned char v5; // al + char v6; // dl + char *v7; // eax + unsigned char v8; // al + char *v9; // esi + unsigned char v10; // bl + DWORD v11; // eax + char qstr[128]; // [esp+8h] [ebp-90h] + char *v13; // [esp+88h] [ebp-10h] + int v14; // [esp+8Ch] [ebp-Ch] + int screen_y; // [esp+90h] [ebp-8h] + int screen_x; // [esp+94h] [ebp-4h] + + DrawQTextBack(); + v0 = qtextptr; + screen_x = 112; + v13 = 0; + screen_y = qtexty; + v14 = 0; + do + { + v1 = 0; + v2 = 0; + for ( i = v0; *i != 10; ++v2 ) + { + if ( *i == 124 || v1 >= 543 ) + break; + v4 = *i++; + v5 = fontidx[v4]; + if ( v5 ) + { + qstr[v2] = v5; + v1 += mfontkern[mfontframe[v5]] + 2; + } + else + { + --v2; + } + } + v6 = *i; + v7 = &qstr[v2]; + qstr[v2] = 0; + if ( v6 == 124 ) + { + *v7 = 0; + v14 = 1; + } + else if ( v6 != 10 ) + { + while ( *v7 != 32 && v2 > 0 ) + { + *v7 = 0; + v7 = &qstr[--v2]; + } + } + v8 = qstr[0]; + if ( qstr[0] ) + { + v9 = qstr; + do + { + ++v0; + v10 = mfontframe[fontidx[v8]]; + if ( *v0 == 10 ) + ++v0; + if ( v10 ) + PrintQTextChr(screen_x, screen_y, (char *)pMedTextCels, v10); + ++v9; + screen_x += mfontkern[v10] + 2; + v8 = *v9; + } + while ( *v9 ); + } + if ( !v13 ) + v13 = v0; + screen_y += 38; + screen_x = 112; + if ( screen_y > 501 ) + v14 = 1; + } + while ( !v14 ); + v11 = GetTickCount(); + while ( 1 ) + { + if ( sgLastScroll <= 0 ) + { + qtexty = qtexty + sgLastScroll - 1; + goto LABEL_33; + } + if ( --scrolltexty ) + { + --qtexty; +LABEL_33: + if ( scrolltexty ) + goto LABEL_35; + } + scrolltexty = sgLastScroll; +LABEL_35: + if ( qtexty <= 209 ) + break; + qtextSpd += 50; + if ( v11 - qtextSpd >= 0x7FFFFFFF ) + return; + } + qtexty += 38; + qtextptr = v13; + if ( *v13 == 124 ) + qtextflag = 0; +} +// 646CF4: using guessed type int qtexty; +// 646CFC: using guessed type int qtextSpd; +// 646D00: using guessed type char qtextflag; +// 646D04: using guessed type int scrolltexty; +// 646D08: using guessed type int sgLastScroll; +// 428202: using guessed type char qstr[128]; diff --git a/Source/minitext.h b/Source/minitext.h new file mode 100644 index 000000000..39d9181e1 --- /dev/null +++ b/Source/minitext.h @@ -0,0 +1,30 @@ +//HEADER_GOES_HERE +#ifndef __MINITEXT_H__ +#define __MINITEXT_H__ + +extern int qtexty; // weak +extern char *qtextptr; +extern int qtextSpd; // weak +extern char qtextflag; // weak +extern int scrolltexty; // weak +extern int sgLastScroll; // weak +extern void *pMedTextCels; +extern void *pTextBoxCels; + +void __cdecl FreeQuestText(); +void __cdecl InitQuestText(); +void __fastcall InitQTextMsg(int m); +void __cdecl DrawQTextBack(); +void __fastcall PrintQTextChr(int screen_x, int screen_y, char *cel_buf, int frame); +void __cdecl DrawQText(); + +/* rdata */ + +extern const unsigned char mfontframe[127]; +extern const unsigned char mfontkern[56]; + +/* data */ + +extern int qscroll_spd_tbl[9]; + +#endif /* __MINITEXT_H__ */ diff --git a/Source/missiles.cpp b/Source/missiles.cpp new file mode 100644 index 000000000..10588fe62 --- /dev/null +++ b/Source/missiles.cpp @@ -0,0 +1,7497 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int missileactive[MAXMISSILES]; +int missileavail[MAXMISSILES]; +MissileStruct missile[MAXMISSILES]; +int nummissiles; // idb +int ManashieldFlag; +ChainStruct chain[MAXMISSILES]; +int MissilePreFlag; // weak +int numchains; // weak +#endif + +MissileData missiledata[68] = +{ + { MIS_ARROW, &AddArrow, &MI_Arrow, 1, 0u, 0u, MFILE_ARROWS, -1, -1 }, + { MIS_FIREBOLT, &AddFirebolt, &MI_Firebolt, 1, 1u, 1u, MFILE_FIREBA, LS_FBOLT1, LS_FIRIMP2 }, + { MIS_GUARDIAN, &AddGuardian, &MI_Guardian, 1, 1u, 0u, MFILE_GUARD, LS_GUARD, LS_GUARDLAN }, + { MIS_RNDTELEPORT, &AddRndTeleport, &MI_Teleport, 0, 1u, 0u, MFILE_NONE, LS_TELEPORT, -1 }, + { MIS_LIGHTBALL, &AddLightball, &MI_Lightball, 1, 1u, 2u, MFILE_LGHNING, -1, -1 }, + { MIS_FIREWALL, &AddFirewall, &MI_Firewall, 1, 1u, 1u, MFILE_FIREWAL, LS_WALLLOOP, LS_FIRIMP2 }, + { MIS_FIREBALL, &AddFireball, &MI_Fireball, 1, 1u, 1u, MFILE_FIREBA, LS_FBOLT1, LS_FIRIMP2 }, + { MIS_LIGHTCTRL, &AddLightctrl, &MI_Lightctrl, 0, 1u, 2u, MFILE_LGHNING, -1, -1 }, + { MIS_LIGHTNING, &AddLightning, &MI_Lightning, 1, 1u, 2u, MFILE_LGHNING, LS_LNING1, LS_ELECIMP1 }, + { MIS_MISEXP, &AddMisexp, &MI_Misexp, 1, 2u, 0u, MFILE_MAGBLOS, -1, -1 }, + { MIS_TOWN, &AddTown, &MI_Town, 1, 1u, 3u, MFILE_PORTAL, LS_SENTINEL, LS_ELEMENTL }, + { MIS_FLASH, &AddFlash, &MI_Flash, 1, 1u, 3u, MFILE_BLUEXFR, LS_NOVA, LS_ELECIMP1 }, + { MIS_FLASH2, &AddFlash2, &MI_Flash2, 1, 1u, 3u, MFILE_BLUEXBK, -1, -1 }, + { MIS_MANASHIELD, &AddManashield, &MI_SetManashield, 0, 1u, 3u, MFILE_MANASHLD, LS_MSHIELD, -1 }, + { MIS_FIREMOVE, &AddFiremove, &MI_Firemove, 1, 1u, 1u, MFILE_FIREWAL, -1, -1 }, + { MIS_CHAIN, &AddChain, &MI_Chain, 1, 1u, 2u, MFILE_LGHNING, LS_LNING1, LS_ELECIMP1 }, + { MIS_NULL_10, NULL, NULL, 1, 1u, 2u, MFILE_LGHNING, -1, -1 }, + { MIS_NULL_11, &miss_null_11, &mi_null_11, 1, 2u, 0u, MFILE_BLOOD, LS_BLODSTAR, LS_BLSIMPT }, + { MIS_NULL_12, &miss_null_12, &mi_null_11, 1, 2u, 0u, MFILE_BONE, -1, -1 }, + { MIS_NULL_13, &miss_null_13, &mi_null_11, 1, 2u, 0u, MFILE_METLHIT, -1, -1 }, + { MIS_RHINO, &AddRhino, &MI_Rhino, 1, 2u, 0u, MFILE_NONE, -1, -1 }, + { MIS_MAGMABALL, &AddMagmaball, &MI_Firebolt, 1, 1u, 1u, MFILE_MAGBALL, -1, -1 }, + { MIS_LIGHTCTRL2, &AddLightctrl, &MI_Lightctrl, 0, 1u, 2u, MFILE_THINLGHT, -1, -1 }, + { MIS_LIGHTNING2, &AddLightning, &MI_Lightning, 1, 1u, 2u, MFILE_THINLGHT, -1, -1 }, + { MIS_FLARE, &AddFlare, &MI_Firebolt, 1, 1u, 3u, MFILE_FLARE, -1, -1 }, + { MIS_MISEXP2, &AddMisexp, &MI_Misexp, 1, 2u, 3u, MFILE_FLAREEXP, -1, -1 }, + { MIS_TELEPORT, &AddTeleport, &MI_Teleport, 0, 1u, 0u, MFILE_NONE, LS_ELEMENTL, -1 }, + { MIS_FARROW, &AddLArrow, &MI_LArrow, 1, 0u, 1u, MFILE_FARROW, -1, -1 }, + { MIS_DOOMSERP, NULL, NULL, 0, 1u, 3u, MFILE_DOOM, LS_DSERP, -1 }, + { MIS_NULL_1D, &miss_null_1D, &MI_Firewall, 1, 2u, 1u, MFILE_FIREWAL, -1, -1 }, + { MIS_STONE, &AddStone, &MI_Stone, 0, 1u, 3u, MFILE_NONE, LS_SCURIMP, -1 }, + { MIS_NULL_1F, &miss_null_1F, &MI_Dummy, 1, 1u, 0u, MFILE_NONE, -1, -1 }, + { MIS_INVISIBL, NULL, NULL, 0, 1u, 0u, MFILE_NONE, LS_INVISIBL, -1 }, + { MIS_GOLEM, &AddGolem, &MI_Golem, 0, 1u, 0u, MFILE_NONE, LS_GOLUM, -1 }, + { MIS_ETHEREALIZE, &AddEtherealize, &MI_Etherealize, 1, 1u, 0u, MFILE_ETHRSHLD, LS_ETHEREAL, -1 }, + { MIS_NULL_23, &miss_null_23, &mi_null_11, 1, 2u, 0u, MFILE_BLODBUR, -1, -1 }, + { MIS_BOOM, &AddBoom, &MI_Boom, 1, 2u, 0u, MFILE_NEWEXP, -1, -1 }, + { MIS_HEAL, &AddHeal, &MI_Dummy, 0, 1u, 0u, MFILE_NONE, -1, -1 }, + { MIS_FIREWALLC, &AddFirewallC, &MI_FirewallC, 0, 1u, 1u, MFILE_FIREWAL, -1, -1 }, + { MIS_INFRA, &AddInfra, &MI_Infra, 0, 1u, 0u, MFILE_NONE, LS_INFRAVIS, -1 }, + { MIS_IDENTIFY, &AddIdentify, &MI_Dummy, 0, 1u, 0u, MFILE_NONE, -1, -1 }, + { MIS_WAVE, &AddWave, &MI_Wave, 1, 1u, 1u, MFILE_FIREWAL, LS_FLAMWAVE, -1 }, + { MIS_NOVA, &AddNova, &MI_Nova, 1, 1u, 2u, MFILE_LGHNING, LS_NOVA, -1 }, + { MIS_BLODBOIL, &miss_null_1F, &MI_Blodboil, 1, 1u, 0u, MFILE_NONE, -1, LS_BLODBOIL }, + { MIS_APOCA, &AddApoca, &MI_Apoca, 1, 1u, 3u, MFILE_NEWEXP, LS_APOC, -1 }, + { MIS_REPAIR, &AddRepair, &MI_Dummy, 0, 2u, 0u, MFILE_NONE, -1, -1 }, + { MIS_RECHARGE, &AddRecharge, &MI_Dummy, 0, 2u, 0u, MFILE_NONE, -1, -1 }, + { MIS_DISARM, &AddDisarm, &MI_Dummy, 0, 2u, 0u, MFILE_NONE, LS_TRAPDIS, -1 }, + { MIS_FLAME, &AddFlame, &MI_Flame, 1, 1u, 1u, MFILE_INFERNO, LS_SPOUTSTR, -1 }, + { MIS_FLAMEC, &AddFlamec, &MI_Flamec, 0, 1u, 1u, MFILE_NONE, -1, -1 }, + { MIS_NULL_32, &miss_null_32, &mi_null_32, 1, 2u, 0u, MFILE_NONE, -1, -1 }, + { MIS_NULL_33, &miss_null_33, &mi_null_33, 1, 0u, 1u, MFILE_KRULL, -1, -1 }, + { MIS_CBOLT, &AddCbolt, &MI_Cbolt, 1, 1u, 2u, MFILE_MINILTNG, LS_CBOLT, -1 }, + { MIS_HBOLT, &AddHbolt, &MI_Hbolt, 1, 1u, 0u, MFILE_HOLY, LS_HOLYBOLT, LS_ELECIMP1 }, + { MIS_RESURRECT, &AddResurrect, &MI_Dummy, 0, 1u, 3u, MFILE_NONE, -1, LS_RESUR }, + { MIS_TELEKINESIS, &AddTelekinesis, &MI_Dummy, 0, 1u, 0u, MFILE_NONE, LS_ETHEREAL, -1 }, + { MIS_LARROW, &AddLArrow, &MI_LArrow, 1, 0u, 2u, MFILE_LARROW, -1, -1 }, + { MIS_ACID, &AddAcid, &MI_Firebolt, 1, 1u, 4u, MFILE_ACIDBF, LS_ACID, -1 }, + { MIS_MISEXP3, &AddMisexp, &MI_Acidsplat, 1, 2u, 4u, MFILE_ACIDSPLA, -1, -1 }, + { MIS_ACIDPUD, &AddAcidpud, &MI_Acidpud, 1, 2u, 4u, MFILE_ACIDPUD, LS_PUDDLE, -1 }, + { MIS_HEALOTHER, &AddHealOther, &MI_Dummy, 0, 1u, 0u, MFILE_NONE, -1, -1 }, + { MIS_ELEMENT, &AddElement, &MI_Element, 1, 1u, 1u, MFILE_FIRERUN, LS_ELEMENTL, -1 }, + { MIS_RESURRECTBEAM, &AddResurrectBeam, &MI_ResurrectBeam, 1, 1u, 0u, MFILE_RESSUR1, -1, -1 }, + { MIS_BONESPIRIT, &AddBoneSpirit, &MI_Bonespirit, 1, 1u, 3u, MFILE_SKLBALL, LS_BONESP, LS_BSIMPCT }, + { MIS_WEAPEXP, &AddWeapexp, &MI_Weapexp, 1, 2u, 0u, MFILE_NONE, -1, -1 }, + { MIS_RPORTAL, &AddRportal, &MI_Rportal, 1, 2u, 0u, MFILE_RPORTAL, LS_SENTINEL, LS_ELEMENTL }, + { MIS_BOOM2, &AddBoom, &MI_Boom, 1, 2u, 0u, MFILE_FIREPLAR, -1, -1 }, + { MIS_DIABAPOCA, &AddDiabApoca, &MI_Dummy, 0, 2u, 0u, MFILE_NONE, -1, -1 } +}; +MisFileData misfiledata[47] = +{ + { + MFILE_ARROWS, 1, "Arrows", 2, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_FIREBA, 16, "Fireba", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14 }, + { 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 } + }, + { + MFILE_GUARD, 3, "Guard", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 15, 14, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_LGHNING, 1, "Lghning", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_FIREWAL, 2, "Firewal", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 13, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_MAGBLOS, 1, "MagBlos", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_PORTAL, 2, "Portal", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_BLUEXFR, 1, "Bluexfr", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_BLUEXBK, 1, "Bluexbk", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_MANASHLD, 1, "Manashld", 2, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_BLOOD, 4, "Blood", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 15, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_BONE, 3, "Bone", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_METLHIT, 3, "Metlhit", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_FARROW, 16, "Farrow", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, + { 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 } + }, + { + MFILE_DOOM, 9, "Doom", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, + { 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_0F, 1, " ", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_BLODBUR, 2, "Blodbur", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_NEWEXP, 1, "Newexp", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_SHATTER1, 1, "Shatter1", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_BIGEXP, 1, "Bigexp", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_INFERNO, 1, "Inferno", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_THINLGHT, 1, "Thinlght", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_FLARE, 1, "Flare", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_FLAREEXP, 1, "Flareexp", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_MAGBALL, 8, "Magball", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_KRULL, 1, "Krull", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_MINILTNG, 1, "Miniltng", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_HOLY, 16, "Holy", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14 }, + { 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 } + }, + { + MFILE_HOLYEXPL, 1, "Holyexpl", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_LARROW, 16, "Larrow", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, + { 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 } + }, + { + MFILE_FIRARWEX, 1, "Firarwex", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_ACIDBF, 16, "Acidbf", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, + { 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 } + }, + { + MFILE_ACIDSPLA, 1, "Acidspla", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_ACIDPUD, 2, "Acidpud", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 9, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_ETHRSHLD, 1, "Ethrshld", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_FIRERUN, 8, "Firerun", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_RESSUR1, 1, "Ressur1", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_SKLBALL, 9, "Sklball", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 8, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_RPORTAL, 2, "Rportal", 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_FIREPLAR, 1, "Fireplar", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_SCUBMISB, 1, "Scubmisb", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_SCBSEXPB, 1, "Scbsexpb", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_SCUBMISC, 1, "Scubmisc", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_SCBSEXPC, 1, "Scbsexpc", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_SCUBMISD, 1, "Scubmisd", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_SCBSEXPD, 1, "Scbsexpd", 1, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + MFILE_NONE, 0, &empty_string, 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + } +}; +int XDirAdd[8] = { 1, 0, -1, -1, -1, 0, 1, 1 }; +int YDirAdd[8] = { 1, 1, 1, 0, -1, -1, -1, 0 }; + +void __fastcall GetDamageAmt(int i, int *mind, int *maxd) +{ + int v3; // eax + int v4; // esi + int v5; // eax + int v6; // ecx + int v7; // eax + int *v8; // eax + signed int v9; // ecx + int v10; // eax + int v11; // ecx + int v12; // eax + int v13; // eax + int v14; // eax + int v15; // ecx + int *v16; // ecx + int v17; // eax + int v18; // ecx + int v19; // eax + int v20; // ecx + int v21; // eax + signed int v22; // eax + signed int v23; // ecx + int v24; // eax + int v25; // ecx + int v26; // ecx + int v27; // eax + signed int v28; // ecx + + v3 = myplr; + v4 = plr[myplr]._pISplLvlAdd + plr[myplr]._pSplLvl[i]; + switch ( i ) + { + case SPL_FIREBOLT: + *mind = (plr[v3]._pMagic >> 3) + v4 + 1; + v5 = (plr[myplr]._pMagic >> 3) + v4 + 10; + goto LABEL_73; + case SPL_HEAL: + v6 = plr[v3]._pLevel + v4 + 1; + *mind = v6; + v7 = myplr; + if ( !_LOBYTE(plr[myplr]._pClass) ) + { + *mind = 2 * v6; + v7 = myplr; + } + if ( _LOBYTE(plr[v7]._pClass) == 1 ) + *mind += *mind >> 1; + v8 = maxd; + v9 = 0; + *maxd = 10; + if ( plr[myplr]._pLevel > 0 ) + { + do + { + *maxd += 4; + ++v9; + } + while ( v9 < plr[myplr]._pLevel ); + } + goto LABEL_65; + case SPL_LIGHTNING: + v10 = 2; + *mind = 2; + v11 = plr[myplr]._pLevel; + goto LABEL_43; + case SPL_FLASH: + v12 = plr[v3]._pLevel; + *mind = v12; + if ( v4 > 0 ) + { + do + { + v12 += v12 >> 3; + --v4; + } + while ( v4 ); + *mind = v12; + } + v13 = (*mind >> 1) + *mind; + *mind = v13; + goto LABEL_33; + case SPL_IDENTIFY: + case SPL_TOWN: + case SPL_STONE: + case SPL_INFRA: + case SPL_RNDTELEPORT: + case SPL_MANASHIELD: + case SPL_DOOMSERP: + case SPL_BLODRIT: + case SPL_INVISIBIL: + case SPL_BLODBOIL: + case SPL_TELEPORT: + case SPL_ETHEREALIZE: + case SPL_REPAIR: + case SPL_RECHARGE: + case SPL_DISARM: + case SPL_RESURRECT: + case SPL_TELEKINESIS: + case SPL_BONESPIRIT: + v8 = maxd; + goto LABEL_71; + case SPL_FIREWALL: + *mind = (4 * plr[v3]._pLevel + 8) >> 1; + v5 = (4 * plr[myplr]._pLevel + 80) >> 1; + goto LABEL_73; + case SPL_FIREBALL: + v14 = 2 * plr[v3]._pLevel + 4; + *mind = v14; + if ( v4 > 0 ) + { + v15 = v4; + do + { + v14 += v14 >> 3; + --v15; + } + while ( v15 ); + *mind = v14; + } + v16 = maxd; + v5 = 2 * plr[myplr]._pLevel + 40; /// BUGFIX: set to `2 * (plr[myplr]._pLevel + 20) + 4` + *maxd = v5; + if ( v4 <= 0 ) + return; + do + { + v5 += v5 >> 3; + --v4; + } + while ( v4 ); + goto LABEL_74; + case SPL_GUARDIAN: + v17 = (plr[v3]._pLevel >> 1) + 1; + *mind = v17; + if ( v4 > 0 ) + { + v18 = v4; + do + { + v17 += v17 >> 3; + --v18; + } + while ( v18 ); + *mind = v17; + } + v16 = maxd; + v5 = (plr[myplr]._pLevel >> 1) + 10; + *maxd = v5; + if ( v4 <= 0 ) + return; + do + { + v5 += v5 >> 3; + --v4; + } + while ( v4 ); + goto LABEL_74; + case SPL_CHAIN: + *mind = 4; + v5 = 2 * plr[myplr]._pLevel + 4; + goto LABEL_73; + case SPL_WAVE: + *mind = 6 * (plr[v3]._pLevel + 1); + v13 = 3 * (plr[myplr]._pLevel + 10); +LABEL_33: + v5 = 2 * v13; + goto LABEL_73; + case SPL_NOVA: + v19 = (plr[v3]._pLevel + 5) >> 1; + *mind = v19; + if ( v4 > 0 ) + { + v20 = v4; + do + { + v19 += v19 >> 3; + --v20; + } + while ( v20 ); + *mind = v19; + } + v16 = maxd; + *mind *= 5; + v21 = (plr[myplr]._pLevel + 30) >> 1; + *maxd = v21; + if ( v4 > 0 ) + { + do + { + v21 += v21 >> 3; + --v4; + } + while ( v4 ); + *maxd = v21; + } + v5 = 5 * *maxd; + goto LABEL_74; + case SPL_FLAME: + *mind = 3; + v10 = plr[myplr]._pLevel + 4; + v11 = v10 >> 1; +LABEL_43: + *maxd = v10 + v11; + return; + case SPL_GOLEM: + *mind = 11; + *maxd = 17; + return; + case SPL_APOCA: + *mind = 0; + v22 = 0; + if ( plr[myplr]._pLevel > 0 ) + { + do + { + ++*mind; + ++v22; + } + while ( v22 < plr[myplr]._pLevel ); + } + v23 = 0; + *maxd = 0; + if ( plr[myplr]._pLevel > 0 ) + { + do + { + *maxd += 6; + ++v23; + } + while ( v23 < plr[myplr]._pLevel ); + } + return; + case SPL_ELEMENT: + v24 = 2 * plr[v3]._pLevel + 4; + *mind = v24; + if ( v4 > 0 ) + { + v25 = v4; + do + { + v24 += v24 >> 3; + --v25; + } + while ( v25 ); + *mind = v24; + } + v16 = maxd; + v5 = 2 * plr[myplr]._pLevel + 40; /// BUGFIX: set to `2 * (plr[myplr]._pLevel + 20) + 4` + *maxd = v5; + if ( v4 <= 0 ) + return; + do + { + v5 += v5 >> 3; + --v4; + } + while ( v4 ); + goto LABEL_74; + case SPL_CBOLT: + *mind = 1; + v5 = (plr[myplr]._pMagic >> 2) + 1; + goto LABEL_73; + case SPL_HBOLT: + *mind = plr[v3]._pLevel + 9; + v5 = plr[myplr]._pLevel + 18; + goto LABEL_73; + case SPL_HEALOTHER: + v26 = plr[v3]._pLevel + v4 + 1; + *mind = v26; + v27 = myplr; + if ( !_LOBYTE(plr[myplr]._pClass) ) + { + *mind = 2 * v26; + v27 = myplr; + } + if ( _LOBYTE(plr[v27]._pClass) == 1 ) + *mind += *mind >> 1; + v8 = maxd; + v28 = 0; + *maxd = 10; + if ( plr[myplr]._pLevel > 0 ) + { + do + { + *maxd += 4; + ++v28; + } + while ( v28 < plr[myplr]._pLevel ); + } +LABEL_65: + if ( v4 > 0 ) + *v8 += 6 * v4; + if ( !_LOBYTE(plr[myplr]._pClass) ) + *v8 *= 2; + if ( _LOBYTE(plr[myplr]._pClass) == 1 ) + *v8 += *v8 >> 1; +LABEL_71: + *mind = -1; + *v8 = -1; + break; + case SPL_FLARE: + v5 = 3 * v4 + (plr[v3]._pMagic >> 1) - (plr[v3]._pMagic >> 3); + *mind = v5; +LABEL_73: + v16 = maxd; +LABEL_74: + *v16 = v5; + break; + default: + return; + } +} + +int __fastcall CheckBlock(int fx, int fy, int tx, int ty) +{ + int v4; // edi + int v5; // esi + int v6; // ebx + int v7; // eax + + v4 = fy; + v5 = fx; + v6 = 0; + while ( v5 != tx || v4 != ty ) + { + v7 = GetDirection(v5, v4, tx, ty); + v5 += XDirAdd[v7]; + v4 += YDirAdd[v7]; + if ( nSolidTable[dPiece[0][v4 + 112 * v5]] ) + v6 = 1; + } + return v6; +} + +int __fastcall FindClosest(int sx, int sy, int rad) +{ + int v3; // eax + int v4; // eax + int v5; // ebx + char *v6; // esi + int v7; // eax + int v8; // ecx + int v9; // edi + int CrawlNum[19]; // [esp+0h] [ebp-58h] + int fy; // [esp+4Ch] [ebp-Ch] + int v13; // [esp+50h] [ebp-8h] + int fx; // [esp+54h] [ebp-4h] + + CrawlNum[0] = 0; + fy = sy; + fx = sx; + CrawlNum[1] = 3; + CrawlNum[2] = 12; + CrawlNum[3] = 45; + CrawlNum[4] = 94; + CrawlNum[5] = 159; + CrawlNum[6] = 240; + CrawlNum[7] = 337; + CrawlNum[8] = 450; + CrawlNum[9] = 579; + CrawlNum[10] = 724; + CrawlNum[11] = 885; + CrawlNum[12] = 1062; + CrawlNum[13] = 1255; + CrawlNum[14] = 1464; + CrawlNum[15] = 1689; + CrawlNum[16] = 1930; + CrawlNum[17] = 2187; + CrawlNum[18] = 2460; + if ( rad > 19 ) + rad = 19; + v3 = 1; + v13 = 1; + if ( rad <= 1 ) + return -1; + while ( 1 ) + { + v4 = CrawlNum[v3]; + v5 = (unsigned char)CrawlTable[v4]; + if ( v5 > 0 ) + break; +LABEL_13: + v3 = v13++ + 1; + if ( v13 >= rad ) + return -1; + } + v6 = &CrawlTable[v4 + 2]; + while ( 1 ) + { + v7 = fx + (char)*(v6 - 1); + v8 = fy + (char)*v6; + if ( v7 > 0 && v7 < 112 && v8 > 0 && v8 < 112 ) + { + v9 = dMonster[0][v8 + 112 * v7]; + if ( v9 > 0 && !CheckBlock(fx, fy, v7, fy + (char)*v6) ) + return v9 - 1; + } + v6 += 2; + if ( --v5 <= 0 ) + goto LABEL_13; + } +} + +int __fastcall GetSpellLevel(int id, int sn) +{ + int result; // eax + + if ( id == myplr ) + result = plr[id]._pISplLvlAdd + plr[id]._pSplLvl[sn]; + else + result = 1; + if ( result < 0 ) + result = 0; + return result; +} + +int __fastcall GetDirection8(int x1, int y1, int x2, int y2) +{ + int v4; // edi + int v5; // esi + int v6; // eax + int v7; // eax + int result; // eax + int v9; // [esp+8h] [ebp-110h] + char Dirs[16][16]; // [esp+Ch] [ebp-10Ch] + char lrtoul[3]; // [esp+10Ch] [ebp-Ch] + char urtoll[3]; // [esp+10Fh] [ebp-9h] + char lltour[3]; // [esp+112h] [ebp-6h] + char ultolr[3]; // [esp+115h] [ebp-3h] + + v9 = y1; + v4 = x1; + strcpy((char *)Dirs, "c"); + *(_QWORD *)&Dirs[0][2] = (__int64)0; + *(_DWORD *)&Dirs[0][10] = 0; + *(_WORD *)&Dirs[0][14] = 0; + *(_QWORD *)&Dirs[1][0] = (__int64)0x1010102; + *(_QWORD *)&Dirs[1][8] = (__int64)0; + *(_QWORD *)&Dirs[2][0] = (__int64)0x1010101010102; + *(_QWORD *)&Dirs[2][8] = (__int64)0; + *(_QWORD *)&Dirs[3][0] = (__int64)0x101010101010102; + *(_QWORD *)&Dirs[3][8] = (__int64)1; + *(_QWORD *)&Dirs[4][0] = (__int64)0x101010101010202; + *(_QWORD *)&Dirs[4][8] = (__int64)0x1010101; + *(_QWORD *)&Dirs[5][0] = (__int64)0x101010101010202; + *(_QWORD *)&Dirs[5][8] = (__int64)0x10101010101; + *(_QWORD *)&Dirs[6][0] = (__int64)0x101010101010202; + *(_QWORD *)&Dirs[6][8] = (__int64)0x101010101010101; + *(_QWORD *)&Dirs[7][0] = (__int64)0x101010101020202; + *(_QWORD *)&Dirs[7][8] = (__int64)0x101010101010101; + *(_QWORD *)&Dirs[8][0] = (__int64)0x101010101020202; + *(_QWORD *)&Dirs[8][8] = (__int64)0x101010101010101; + *(_QWORD *)&Dirs[9][0] = (__int64)0x101010102020202; + *(_QWORD *)&Dirs[9][8] = (__int64)0x101010101010101; + *(_QWORD *)&Dirs[10][0] = (__int64)0x101010102020202; + *(_QWORD *)&Dirs[10][8] = (__int64)0x101010101010101; + *(_QWORD *)&Dirs[11][0] = (__int64)0x101010102020202; + *(_QWORD *)&Dirs[11][8] = (__int64)0x101010101010101; + *(_QWORD *)&Dirs[12][0] = (__int64)0x101010202020202; + *(_QWORD *)&Dirs[12][8] = (__int64)0x101010101010101; + *(_QWORD *)&Dirs[13][0] = (__int64)0x101010202020202; + *(_QWORD *)&Dirs[13][8] = (__int64)0x101010101010101; + *(_QWORD *)&Dirs[14][0] = (__int64)0x101020202020202; + *(_QWORD *)&Dirs[14][8] = (__int64)0x101010101010101; + lltour[1] = 0; + *(_QWORD *)&Dirs[15][0] = (__int64)0x101020202020202; + *(_QWORD *)&Dirs[15][8] = (__int64)0x101010101010101; + lrtoul[0] = 3; + lrtoul[1] = 4; + lrtoul[2] = 5; + urtoll[0] = 3; + urtoll[1] = 2; + urtoll[2] = 1; + ultolr[0] = 7; + ultolr[1] = 6; + ultolr[2] = 5; + lltour[0] = 7; + lltour[2] = 1; + v5 = abs(x2 - x1); + if ( v5 > 15 ) + v5 = 15; + v6 = abs(y2 - v9); + if ( v6 > 15 ) + v6 = 15; + v7 = (unsigned char)Dirs[v6][v5]; + if ( v4 <= x2 ) + { + if ( v9 <= y2 ) + result = (unsigned char)lltour[v7]; + else + result = (unsigned char)ultolr[v7]; + } + else if ( v9 <= y2 ) + { + result = (unsigned char)urtoll[v7]; + } + else + { + result = (unsigned char)lrtoul[v7]; + } + return result; +} + +int __fastcall GetDirection16(int x1, int y1, int x2, int y2) +{ + int v4; // edi + int v5; // esi + int v6; // eax + int v7; // eax + int result; // eax + int v9; // [esp+8h] [ebp-124h] + char Dirs[16][16]; // [esp+Ch] [ebp-120h] + char lrtoul[5]; // [esp+10Ch] [ebp-20h] + char urtoll[5]; // [esp+114h] [ebp-18h] + char lltour[5]; // [esp+11Ch] [ebp-10h] + char ultolr[5]; // [esp+124h] [ebp-8h] + + v9 = y1; + v4 = x1; + strcpy((char *)Dirs, "c"); + *(_QWORD *)&Dirs[0][2] = (__int64)0; + *(_DWORD *)&Dirs[0][10] = 0; + *(_WORD *)&Dirs[0][14] = 0; + *(_QWORD *)&Dirs[1][0] = (__int64)0x1010204; + *(_QWORD *)&Dirs[1][8] = (__int64)0; + *(_QWORD *)&Dirs[2][0] = (__int64)0x101010101020304; + *(_QWORD *)&Dirs[2][8] = (__int64)0; + *(_QWORD *)&Dirs[3][0] = (__int64)0x101010202030304; + *(_QWORD *)&Dirs[3][8] = (__int64)0x1010101; + *(_QWORD *)&Dirs[4][0] = (__int64)0x101010202030404; + *(_QWORD *)&Dirs[4][8] = (__int64)0x101010101010101; + *(_QWORD *)&Dirs[5][0] = (__int64)0x102020203030404; + *(_QWORD *)&Dirs[5][8] = (__int64)0x101010101010101; + *(_QWORD *)&Dirs[6][0] = (__int64)0x202020203030404; + *(_QWORD *)&Dirs[6][8] = (__int64)0x101010101010102; + *(_QWORD *)&Dirs[7][0] = (__int64)0x202030303030404; + *(_QWORD *)&Dirs[7][8] = (__int64)0x101010101010202; + *(_QWORD *)&Dirs[8][0] = (__int64)0x202030303040404; + *(_QWORD *)&Dirs[8][8] = (__int64)0x101010101020202; + *(_QWORD *)&Dirs[9][0] = (__int64)0x203030303040404; + *(_QWORD *)&Dirs[9][8] = (__int64)0x101010102020202; + *(_QWORD *)&Dirs[10][0] = (__int64)0x303030303040404; + *(_QWORD *)&Dirs[10][8] = (__int64)0x101020202020202; + *(_QWORD *)&Dirs[11][0] = (__int64)0x303030303040404; + *(_QWORD *)&Dirs[11][8] = (__int64)0x102020202020203; + *(_QWORD *)&Dirs[12][0] = (__int64)0x303030304040404; + *(_QWORD *)&Dirs[12][8] = (__int64)0x202020202020303; + *(_QWORD *)&Dirs[13][0] = (__int64)0x303030304040404; + *(_QWORD *)&Dirs[13][8] = (__int64)0x202020202020303; + *(_QWORD *)&Dirs[14][0] = (__int64)0x303030304040404; + *(_QWORD *)&Dirs[14][8] = (__int64)0x202020202030303; + lrtoul[2] = 0; + *(_QWORD *)&Dirs[15][0] = (__int64)0x303030304040404; + *(_QWORD *)&Dirs[15][8] = (__int64)0x202020203030303; + urtoll[0] = 6; + urtoll[1] = 7; + urtoll[2] = 8; + urtoll[3] = 9; + urtoll[4] = 10; + ultolr[0] = 6; + ultolr[1] = 5; + ultolr[2] = 4; + ultolr[3] = 3; + ultolr[4] = 2; + lltour[0] = 14; + lltour[1] = 13; + lltour[2] = 12; + lltour[3] = 11; + lltour[4] = 10; + lrtoul[0] = 14; + lrtoul[1] = 15; + lrtoul[3] = 1; + lrtoul[4] = 2; + v5 = abs(x2 - x1); + if ( v5 > 15 ) + v5 = 15; + v6 = abs(y2 - v9); + if ( v6 > 15 ) + v6 = 15; + v7 = (unsigned char)Dirs[v6][v5]; + if ( v4 <= x2 ) + { + if ( v9 <= y2 ) + result = (unsigned char)lrtoul[v7]; + else + result = (unsigned char)lltour[v7]; + } + else if ( v9 <= y2 ) + { + result = (unsigned char)ultolr[v7]; + } + else + { + result = (unsigned char)urtoll[v7]; + } + return result; +} + +void __fastcall DeleteMissile(int mi, int i) +{ + int v2; // edi + int v3; // ebx + int v4; // esi + int v5; // eax + bool v6; // zf + bool v7; // sf + + v2 = mi; + v3 = i; + if ( missile[mi]._mitype == MIS_MANASHIELD ) + { + v4 = missile[mi]._misource; + if ( v4 == myplr ) + NetSendCmd(1u, CMD_REMSHIELD); + plr[v4].pManaShield = 0; + } + v5 = nummissiles - 1; + v6 = nummissiles == 1; + v7 = nummissiles - 1 < 0; + missileavail[-nummissiles + MAXMISSILES] = v2; /* *(&missile[0]._mitype - nummissiles) = v2; */ + nummissiles = v5; + if ( !v7 && !v6 && v3 != v5 ) + missileactive[v3] = missileactive[v5]; +} + +void __fastcall GetMissileVel(int i, int sx, int sy, int dx, int dy, int v) +{ + int v6; // eax + double v7; // ST18_8 + double v8; // ST10_8 + int v9; // esi + double v10; // st7 + + if ( dx != sx || dy != sy ) + { + v7 = (double)((dx + sy - sx - dy) << 21); + v8 = (double)((dy + dx - sx - sy) << 21); + v9 = i; + v10 = 1.0 / sqrt(v8 * v8 + v7 * v7); + missile[v9]._mixvel = (signed __int64)((double)(v << 16) * v7 * v10); + missile[v9]._miyvel = (signed __int64)((double)(v << 15) * v8 * v10); + } + else + { + v6 = i; + missile[v6]._mixvel = 0; + missile[v6]._miyvel = 0; + } +} + +void __fastcall PutMissile(int i) +{ + int v1; // eax + int v2; // edx + int v3; // esi + int v4; // edx + _BYTE *v5; // edx + + v1 = i; + v2 = missile[i]._mix; + v3 = missile[i]._miy; + if ( v2 <= 0 || v3 <= 0 || v2 >= 112 || v3 >= 112 ) + missile[v1]._miDelFlag = 1; + if ( !missile[v1]._miDelFlag ) + { + v4 = v3 + 112 * v2; + dFlags[0][v4] |= 1u; + v5 = (unsigned char *)dMissile + v4; + if ( *v5 ) + *v5 = -1; + else + *v5 = i + 1; + if ( missile[v1]._miPreFlag ) + MissilePreFlag = 1; + } +} +// 64CCD4: using guessed type int MissilePreFlag; + +void __fastcall GetMissilePos(int i) +{ + int v1; // ecx + int v2; // eax + int v3; // esi + int v4; // edi + int v5; // edx + int v6; // edi + int v7; // esi + int v8; // edi + int v9; // edx + int v10; // esi + int v11; // edx + int v12; // [esp+Ch] [ebp-8h] + + v1 = i; + v2 = SHIWORD(missile[v1]._mityoff); + v3 = SHIWORD(missile[v1]._mitxoff); + v4 = 2 * v2 + v3; + v5 = 2 * v2 - v3; + if ( v4 >= 0 ) + { + v7 = v4 >> 3; + v8 = v4 >> 6; + } + else + { + v6 = -v4; + v7 = -(v6 >> 3); + v8 = -(v6 >> 6); + } + v12 = v7; + if ( v5 >= 0 ) + { + v10 = v5 >> 3; + v11 = v5 >> 6; + } + else + { + v9 = -v5; + v10 = -(v9 >> 3); + v11 = -(v9 >> 6); + } + missile[v1]._mix = v8 + missile[v1]._misx; + missile[v1]._miy = v11 + missile[v1]._misy; + missile[v1]._mixoff = SHIWORD(missile[v1]._mitxoff) + 32 * v11 - 32 * v8; + missile[v1]._miyoff = v2 - 16 * v11 - 16 * v8; + ChangeLightOff(missile[v1]._mlid, v12 - 8 * v8, v10 - 8 * v11); +} + +void __fastcall MoveMissilePos(int i) +{ + int v1; // esi + signed int v2; // ebx + signed int v3; // edi + //signed int v4; // [esp+Ch] [ebp-4h] + + v1 = i; + switch ( missile[i]._mimfnum ) + { + case 0: + case 1: + case 7: + v2 = 1; + goto LABEL_3; + case 2: + v2 = 0; +LABEL_3: + v3 = 1; + break; + case 3: + case 4: + case 5: + v2 = 0; + goto LABEL_7; + case 6: + v2 = 1; +LABEL_7: + v3 = 0; + break; + default: + v2 = 0; // v4; /* check */ + v3 = 0; // v4; + break; + } + if ( PosOkMonst(missile[v1]._misource, v2 + missile[v1]._mix, v3 + missile[v1]._miy) ) + { + missile[v1]._mix += v2; + missile[v1]._miy += v3; + missile[v1]._mixoff += 32 * v3 - 32 * v2; + missile[v1]._miyoff -= 16 * v2 + 16 * v3; + } +} + +BOOL __fastcall MonsterTrapHit(int m, int mindam, int maxdam, int dist, int t, int shift) +{ + int v6; // esi + int v8; // ecx + int v9; // eax + int v10; // edi + //int v11; // eax + int v13; // eax + int v14; // [esp+Ch] [ebp-10h] + int v15; // [esp+10h] [ebp-Ch] + signed int v16; // [esp+14h] [ebp-8h] + signed int arglist; // [esp+18h] [ebp-4h] + + v16 = 0; + arglist = m; + v6 = m; + v15 = mindam; + if ( monster[m].mtalkmsg + || (signed int)(monster[v6]._mhitpoints & 0xFFFFFFC0) <= 0 + || monster[v6].MType->mtype == MT_ILLWEAV && _LOBYTE(monster[v6]._mgoal) == 2 ) + { + return 0; + } + if ( monster[v6]._mmode == MM_CHARGE ) + return 0; + v8 = _LOWORD(monster[v6].mMagicRes); + v9 = missiledata[t].mResist; + if ( v8 & 8 ) + { + if ( v9 == 3 ) + return 0; + } + if ( v8 & 0x10 && v9 == 1 || v8 & 0x20 && v9 == 2 ) + return 0; + if ( v8 & 1 && v9 == 3 || v8 & 2 && v9 == 1 || v8 & 4 && v9 == 2 ) + v16 = 1; + v14 = random(68, 100); + v10 = 90 - (unsigned char)monster[v6].mArmorClass - dist; + if ( v10 < 5 ) + v10 = 5; + if ( v10 > 95 ) + v10 = 95; + //_LOBYTE(v11) = CheckMonsterHit(arglist, (unsigned char *)&t); + BOOL ret; + if ( CheckMonsterHit(arglist, &ret) ) + return ret; +#ifdef _DEBUG + if ( v14 >= v10 && !debug_mode_dollar_sign && !debug_mode_key_inverted_v && monster[v6]._mmode != MM_STONE ) + return 0; +#else + if ( v14 >= v10 && monster[v6]._mmode != MM_STONE ) + return 0; +#endif + v13 = v15 + random(68, maxdam - v15 + 1); + if ( !(_BYTE)shift ) + v13 <<= 6; + if ( v16 ) + monster[v6]._mhitpoints -= v13 >> 2; + else + monster[v6]._mhitpoints -= v13; +#ifdef _DEBUG + if ( debug_mode_dollar_sign || debug_mode_key_inverted_v ) + monster[v6]._mhitpoints = 0; +#endif + if ( (signed int)(monster[v6]._mhitpoints & 0xFFFFFFC0) > 0 ) + { + if ( v16 ) + { + PlayEffect(arglist, 1); + return 1; + } + if ( monster[v6]._mmode != MM_STONE ) + { + if ( arglist > 3 ) + M_StartHit(arglist, -1, v13); + return 1; + } + if ( arglist > 3 ) + M_StartHit(arglist, -1, v13); + } + else + { + if ( monster[v6]._mmode != MM_STONE ) + { + M_StartKill(arglist, -1); + return 1; + } + M_StartKill(arglist, -1); + } + monster[v6]._mmode = MM_STONE; + return 1; +} + +bool __fastcall MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, int shift) +{ + int v7; // edi + bool v8; // zf + short v9; // ax + int v10; // ecx + int v11; // eax + int v12; // esi + int v13; // ebx + char v14; // al + int v15; // eax + //int v16; // eax + int v19; // ebx + int v20; // ebx + int v21; // edx + int v22; // eax + int v23; // [esp+Ch] [ebp-18h] + BOOL ret; // [esp+10h] [ebp-14h] + int v25; // [esp+14h] [ebp-10h] + int v26; // [esp+18h] [ebp-Ch] + int pnuma; // [esp+1Ch] [ebp-8h] + int arglist; // [esp+20h] [ebp-4h] + unsigned char dist_3; // [esp+37h] [ebp+13h] + + arglist = m; + v7 = m; + v26 = 0; + v8 = monster[m].mtalkmsg == 0; + pnuma = pnum; + if ( !v8 + || (signed int)(monster[v7]._mhitpoints & 0xFFFFFFC0) <= 0 + || t == 53 && monster[v7].MType->mtype != MT_DIABLO && monster[v7].MData->mMonstClass ) + { + return 0; + } + if ( monster[v7].MType->mtype == MT_ILLWEAV && _LOBYTE(monster[v7]._mgoal) == 2 ) + return 0; + if ( monster[v7]._mmode == MM_CHARGE ) + return 0; + v9 = monster[v7].mMagicRes; + v10 = missiledata[t].mResist; + v23 = t; + if ( v9 & 8 ) + { + if ( v10 == 3 ) + return 0; + } + if ( v9 & 0x10 && v10 == 1 || v9 & 0x20 && v10 == 2 || (v9 & 0x80u) != 0 && v10 == 4 ) + return 0; + if ( v9 & 1 && v10 == 3 || v9 & 2 && v10 == 1 || v9 & 4 && v10 == 2 ) + v26 = 1; + v11 = random(69, 100); + v8 = missiledata[t].mType == 0; + v25 = v11; + if ( v8 ) + { + v12 = pnuma; + v13 = plr[v12]._pDexterity + + plr[v12]._pIBonusToHit + + plr[v12]._pLevel + - (unsigned char)monster[v7].mArmorClass + - (dist * dist >> 1) + + plr[pnuma]._pIEnAc + + 50; + v14 = plr[pnuma]._pClass; + if ( v14 == 1 ) + v13 = plr[v12]._pDexterity + + plr[v12]._pIBonusToHit + + plr[v12]._pLevel + - (unsigned char)monster[v7].mArmorClass + - (dist * dist >> 1) + + plr[pnuma]._pIEnAc + + 70; + if ( !v14 ) + v13 += 10; + } + else + { + v12 = pnuma; + v15 = 2 * SLOBYTE(monster[v7].mLevel); + v13 = plr[pnuma]._pMagic - v15 - dist + 50; + if ( _LOBYTE(plr[pnuma]._pClass) == 2 ) + v13 = plr[v12]._pMagic - v15 - dist + 70; + } + if ( v13 < 5 ) + v13 = 5; + if ( v13 > 95 ) + v13 = 95; + if ( monster[v7]._mmode == MM_STONE ) + v25 = 0; + if ( CheckMonsterHit(arglist, &ret) ) + return ret; +#ifdef _DEBUG + if ( v25 >= v13 && !debug_mode_key_inverted_v && !debug_mode_dollar_sign ) + return 0; +#else + if ( v25 >= v13 ) + return 0; +#endif + if ( t == 63 ) + { + v19 = monster[v7]._mhitpoints / 3 >> 6; + } + else + { + v19 = mindam + random(70, maxdam - mindam + 1); + } + dist_3 = missiledata[v23].mType; + if ( !missiledata[v23].mType ) + { + v20 = plr[v12]._pIBonusDamMod + v19 * plr[v12]._pIBonusDam / 100 + v19; + if ( _LOBYTE(plr[v12]._pClass) == 1 ) + v19 = plr[v12]._pDamageMod + v20; + else + v19 = (plr[v12]._pDamageMod >> 1) + v20; + } + if ( !(_BYTE)shift ) + v19 <<= 6; + if ( v26 ) + v19 >>= 2; + v21 = pnuma; + if ( pnuma == myplr ) + monster[v7]._mhitpoints -= v19; + v22 = plr[v12]._pIFlags; + if ( v22 & 8 ) + monster[v7]._mFlags |= 8u; + if ( (signed int)(monster[v7]._mhitpoints & 0xFFFFFFC0) > 0 ) + { + if ( v26 ) + { + PlayEffect(arglist, 1); + } + else if ( monster[v7]._mmode == MM_STONE ) + { + if ( arglist > 3 ) + M_StartHit(arglist, v21, v19); + monster[v7]._mmode = MM_STONE; + } + else + { + if ( !dist_3 && v22 & 0x800 ) + { + M_GetKnockback(arglist); + v21 = pnuma; + } + if ( arglist > 3 ) + M_StartHit(arglist, v21, v19); + } + } + else if ( monster[v7]._mmode == MM_STONE ) + { + M_StartKill(arglist, v21); + monster[v7]._mmode = MM_STONE; + } + else + { + M_StartKill(arglist, v21); + } + if ( !monster[v7]._msquelch ) + { + monster[v7]._msquelch = -1; + monster[v7]._lastx = plr[v12].WorldX; + monster[v7]._lasty = plr[v12].WorldY; + } + return 1; +} + +bool __fastcall PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, int shift, int earflag) +{ + int v8; // ebx + int v9; // esi + int v10; // edi + int v11; // ecx + int v12; // eax + int v13; // edi + int v14; // edi + int v15; // eax + int v16; // eax + int v17; // ebx + int v18; // ebx + unsigned char v19; // al + int v20; // eax + int v21; // ecx + int v22; // ecx + int v23; // ecx + int v24; // edi + int v25; // ecx + int v26; // eax + char v27; // al + int v28; // ecx + int v29; // eax + int v30; // eax + int v32; // [esp+Ch] [ebp-14h] + int arglist; // [esp+14h] [ebp-Ch] + int v34; // [esp+18h] [ebp-8h] + int v35; // [esp+1Ch] [ebp-4h] + int dista; // [esp+28h] [ebp+8h] + + v8 = m; + arglist = pnum; + v9 = pnum; + v34 = m; + if ( (signed int)(plr[pnum]._pHitPoints & 0xFFFFFFC0) <= 0 + || plr[v9]._pInvincible + || plr[v9]._pSpellFlags & 1 && !missiledata[mtype].mType ) + { + return 0; + } + v10 = 100; + v32 = random(72, 100); +#ifdef _DEBUG + if ( debug_mode_dollar_sign || debug_mode_key_inverted_v ) + v32 = 1000; +#endif + if ( !missiledata[mtype].mType ) + { + v11 = 5; + v12 = plr[v9]._pIAC + plr[v9]._pIBonusAC + plr[v9]._pDexterity / 5; + if ( v8 != -1 ) + { + v11 = 2 * dist; + v13 = (unsigned char)monster[v8].mHit + + 2 * (SLOBYTE(monster[v8].mLevel) - plr[v9]._pLevel) + + 30 + - 2 * dist; +LABEL_8: + v14 = v13 - v12; + goto LABEL_14; + } + v15 = v12 >> 1; +LABEL_12: + v13 = v10 - v15; + v12 = 2 * dist; + goto LABEL_8; + } + if ( v8 != -1 ) + { + v10 = 2 * SLOBYTE(monster[v8].mLevel) + 40; + v15 = 2 * plr[v9]._pLevel; + goto LABEL_12; + } + v14 = 40; +LABEL_14: + if ( v14 < 10 ) + v14 = 10; + if ( currlevel == 14 ) + { + if ( v14 >= 20 ) + goto LABEL_25; + v14 = 20; + } + if ( currlevel == 15 ) + { + if ( v14 >= 25 ) + goto LABEL_25; + v14 = 25; + } + if ( currlevel == 16 && v14 < 30 ) + v14 = 30; +LABEL_25: + v16 = plr[v9]._pmode; + if ( v16 && v16 != 4 || !plr[v9]._pBlockFlag ) + { + v35 = 100; + } + else + { + v35 = random(73, 100); + } + if ( (_BYTE)shift == 1 ) + v35 = 100; + if ( mtype == 59 ) + v35 = 100; + if ( v8 == -1 ) + v17 = plr[v9]._pBaseToBlk; + else + v17 = plr[v9]._pBaseToBlk + 2 * plr[v9]._pLevel - 2 * SLOBYTE(monster[v8].mLevel); + v18 = plr[v9]._pDexterity + v17; + if ( v18 < 0 ) + v18 = 0; + if ( v18 > 100 ) + v18 = 100; + v19 = missiledata[mtype].mResist; + if ( v19 == 1 ) + { + v20 = plr[v9]._pFireResist; + } + else if ( v19 == 2 ) + { + v20 = plr[v9]._pLghtResist; + } + else + { + if ( v19 <= 2u || v19 > 4u ) + { + dista = 0; + goto LABEL_50; + } + v20 = plr[v9]._pMagResist; + } + dista = v20; +LABEL_50: + if ( v32 < v14 ) + { + if ( mtype == 63 ) + { + v21 = plr[v9]._pHitPoints / 3; + } + else + { + if ( (_BYTE)shift ) + { + v23 = mind + random(75, maxd - mind + 1); + if ( v34 == -1 && plr[v9]._pIFlags & 0x10000000 ) + v23 >>= 1; + v21 = plr[v9]._pIGetHit + v23; + } + else + { + v22 = (mind << 6) + random(75, (maxd - mind + 1) << 6); + if ( v34 == -1 && plr[v9]._pIFlags & 0x10000000 ) + v22 >>= 1; + v21 = (plr[v9]._pIGetHit << 6) + v22; + } + if ( v21 < 64 ) + v21 = 64; + } + if ( dista <= 0 ) + { + if ( v35 < v18 ) + { + if ( v34 == -1 ) + v29 = plr[v9]._pdir; + else + v29 = GetDirection(plr[v9].WorldX, plr[v9].WorldY, monster[v34]._mx, monster[v34]._my); + StartPlrBlock(arglist, v29); + return 1; + } + v24 = arglist; + if ( arglist == myplr ) + { + plr[v9]._pHitPoints -= v21; + plr[v9]._pHPBase -= v21; + } + v30 = plr[v9]._pMaxHP; + if ( plr[v9]._pHitPoints > v30 ) + { + plr[v9]._pHitPoints = v30; + plr[v9]._pHPBase = plr[v9]._pMaxHPBase; + } + if ( (signed int)(plr[v9]._pHitPoints & 0xFFFFFFC0) > 0 ) + { + StartPlrHit(arglist, v21, 0); + return 1; + } + goto LABEL_70; + } + v24 = arglist; + v25 = dista * v21 / -100 + v21; + if ( arglist == myplr ) + { + plr[v9]._pHitPoints -= v25; + plr[v9]._pHPBase -= v25; + } + v26 = plr[v9]._pMaxHP; + if ( plr[v9]._pHitPoints > v26 ) + { + plr[v9]._pHitPoints = v26; + plr[v9]._pHPBase = plr[v9]._pMaxHPBase; + } + if ( (signed int)(plr[v9]._pHitPoints & 0xFFFFFFC0) <= 0 ) + { +LABEL_70: + SyncPlrKill(v24, earflag); + return 1; + } + v27 = plr[v9]._pClass; + if ( v27 ) + { + if ( v27 == 1 ) + { + v28 = PS_ROGUE69; + } + else + { + if ( v27 != 2 ) + { +LABEL_78: + drawhpflag = 1; + return 1; + } + v28 = PS_MAGE69; + } + } + else + { + v28 = PS_WARR69; + } + PlaySfxLoc(v28, plr[v9].WorldX, plr[v9].WorldY); + goto LABEL_78; + } + return 0; +} + +bool __fastcall Plr2PlrMHit(int pnum, int p, int mindam, int maxdam, int dist, int mtype, int shift) +{ + int v7; // edi + unsigned char v8; // al + int v9; // eax + int v10; // esi + int v11; // eax + int v12; // ecx + int v13; // eax + int v14; // ecx + bool v15; // sf + int v16; // ecx + int v17; // ebx + char v18; // al + int v19; // ecx + int v20; // eax + int v22; // [esp+Ch] [ebp-14h] + int v23; // [esp+10h] [ebp-10h] + int v24; // [esp+10h] [ebp-10h] + int arglist; // [esp+14h] [ebp-Ch] + int v26; // [esp+18h] [ebp-8h] + int v27; // [esp+1Ch] [ebp-4h] + int dista; // [esp+30h] [ebp+10h] + + arglist = p; + v7 = p; + v26 = pnum; + if ( plr[p]._pInvincible || mtype == 53 || plr[v7]._pSpellFlags & 1 && !missiledata[mtype].mType ) + return 0; + v22 = mtype; + v8 = missiledata[mtype].mResist; + if ( v8 == 1 ) + { + v9 = plr[v7]._pFireResist; + } + else if ( v8 == 2 ) + { + v9 = plr[v7]._pLghtResist; + } + else + { + if ( v8 <= 2u || v8 > 4u ) + { + v27 = 0; + goto LABEL_14; + } + v9 = plr[v7]._pMagResist; + } + v27 = v9; +LABEL_14: + v23 = random(69, 100); + if ( missiledata[mtype].mType ) + { + v10 = v26; + v12 = 2 * plr[v7]._pLevel; + v11 = plr[v26]._pMagic - v12 - dist + 50; + if ( _LOBYTE(plr[v26]._pClass) == 2 ) + v11 = plr[v10]._pMagic - v12 - dist + 70; + } + else + { + v10 = v26; + v12 = plr[v10]._pIBonusToHit + + plr[v10]._pLevel + - (dist * dist >> 1) + - plr[v7]._pDexterity / 5 + - plr[v7]._pIBonusAC + - plr[v7]._pIAC; + v11 = v12 + plr[v26]._pDexterity + 50; + _LOBYTE(v12) = plr[v26]._pClass; + if ( (_BYTE)v12 == 1 ) + v11 += 20; + if ( !(_BYTE)v12 ) + v11 += 10; + } + if ( v11 < 5 ) + v11 = 5; + if ( v11 > 95 ) + v11 = 95; + if ( v23 < v11 ) + { + v13 = plr[v7]._pmode; + if ( v13 && v13 != 4 || !plr[v7]._pBlockFlag ) + { + v24 = 100; + } + else + { + v24 = random(73, 100); + } + if ( (_BYTE)shift == 1 ) + v24 = 100; + v14 = plr[v7]._pBaseToBlk + 2 * plr[v7]._pLevel - 2 * plr[v10]._pLevel; + v15 = plr[v7]._pDexterity + v14 < 0; + v16 = plr[v7]._pDexterity + v14; + dista = v16; + if ( v15 ) + { + dista = 0; + v16 = 0; + } + if ( v16 > 100 ) + { + dista = 100; + v16 = 100; + } + if ( mtype == 63 ) + { + v17 = plr[v7]._pHitPoints / 3; + } + else + { + v17 = mindam + random(70, maxdam - mindam + 1); + if ( !missiledata[v22].mType ) + v17 += plr[v10]._pIBonusDamMod + plr[v10]._pDamageMod + v17 * plr[v10]._pIBonusDam / 100; + v16 = dista; + if ( !(_BYTE)shift ) + v17 <<= 6; + } + if ( missiledata[v22].mType ) + v17 >>= 1; + if ( v27 <= 0 ) + { + if ( v24 >= v16 ) + { + if ( v26 == myplr ) + NetSendCmdDamage(1u, arglist, v17); + StartPlrHit(arglist, v17, 0); + } + else + { + v20 = GetDirection(plr[v7].WorldX, plr[v7].WorldY, plr[v10].WorldX, plr[v10].WorldY); + StartPlrBlock(arglist, v20); + } + return 1; + } + if ( v26 == myplr ) + NetSendCmdDamage(1u, arglist, v17 - v27 * v17 / 100); + v18 = plr[v10]._pClass; + if ( v18 ) + { + if ( v18 == 1 ) + { + v19 = PS_ROGUE69; + } + else + { + if ( v18 != 2 ) + return 1; + v19 = PS_MAGE69; + } + } + else + { + v19 = PS_WARR69; + } + PlaySfxLoc(v19, plr[v10].WorldX, plr[v10].WorldY); + return 1; + } + return 0; +} + +void __fastcall CheckMissileCol(int i, int mindam, int maxdam, bool shift, int mx, int my, int nodel) +{ + int v7; // ebx + int v8; // esi + char v9; // dl + int v10; // ecx + int v11; // edi + int v12; // eax + bool v13; // eax + char v14; // al + int v15; // ecx + int v16; // edx + bool v17; // eax + int v18; // eax + bool v19; // eax + char v20; // al + int v21; // eax + int v22; // eax + char v23; // al + char v24; // al + int v25; // edx + int v26; // ecx + int v27; // [esp-Ch] [ebp-1Ch] + int v28; // [esp-8h] [ebp-18h] + int mindama; // [esp+Ch] [ebp-4h] + + v7 = mindam; + v8 = i; + mindama = mindam; + v9 = missile[i]._miAnimType; + if ( v9 == 4 || (v10 = missile[v8]._misource, v10 == -1) ) + { + v11 = 112 * mx + my; + v21 = dMonster[0][v11]; + if ( v21 > 0 ) + { + v28 = missile[v8]._mitype; + v27 = missile[v8]._midist; + v22 = v9 == 4 ? MonsterMHit(missile[v8]._misource, v21 - 1, v7, maxdam, v27, v28, shift) : MonsterTrapHit(v21 - 1, v7, maxdam, v27, v28, shift); + if ( v22 ) + { + if ( !(_BYTE)nodel ) + missile[v8]._mirange = 0; + missile[v8]._miHitFlag = 1; + } + } + v23 = dPlayer[0][v11]; + if ( v23 > 0 ) + { + v17 = PlayerMHit( + v23 - 1, + -1, + missile[v8]._midist, + v7, + maxdam, + missile[v8]._mitype, + shift, + _LOBYTE(missile[v8]._miAnimType) == 4); +LABEL_35: + if ( v17 ) + { + if ( !(_BYTE)nodel ) + missile[v8]._mirange = 0; + missile[v8]._miHitFlag = 1; + } + goto LABEL_39; + } + } + else + { + if ( !missile[v8]._micaster ) + { + v11 = 112 * mx + my; + v12 = dMonster[0][v11]; + if ( v12 <= 0 ) + { + if ( v12 >= 0 || monster[-(v12 + 1)]._mmode != MM_STONE ) + { +LABEL_13: + v14 = dPlayer[0][v11]; + if ( v14 <= 0 ) + goto LABEL_39; + v15 = missile[v8]._misource; + v16 = v14 - 1; + if ( v16 == v15 ) + goto LABEL_39; + v17 = Plr2PlrMHit( + v15, + v16, + mindama, + maxdam, + missile[v8]._midist, + missile[v8]._mitype, + shift); + goto LABEL_35; + } + v13 = MonsterMHit( + v10, + -1 - v12, + mindama, + maxdam, + missile[v8]._midist, + missile[v8]._mitype, + shift); + } + else + { + v13 = MonsterMHit(v10, v12 - 1, v7, maxdam, missile[v8]._midist, missile[v8]._mitype, shift); + } + if ( v13 ) + { + if ( !(_BYTE)nodel ) + missile[v8]._mirange = 0; + missile[v8]._miHitFlag = 1; + } + goto LABEL_13; + } + if ( monster[v10]._mFlags & 0x10 ) + { + v18 = dMonster[0][my + 112 * mx]; + if ( v18 > 0 ) + { + if ( monster[v18-1]._mFlags & 0x20 ) /* fix */ + { + v19 = MonsterTrapHit( + v18 - 1, + mindama, + maxdam, + missile[v8]._midist, + missile[v8]._mitype, + shift); + if ( v19 ) + { + if ( !(_BYTE)nodel ) + missile[v8]._mirange = 0; + missile[v8]._miHitFlag = 1; + } + } + } + } + v11 = my + 112 * mx; + v20 = dPlayer[0][v11]; + if ( v20 > 0 ) + { + v17 = PlayerMHit( + v20 - 1, + missile[v8]._misource, + missile[v8]._midist, + mindama, + maxdam, + missile[v8]._mitype, + shift, + 0); + goto LABEL_35; + } + } +LABEL_39: + v24 = dObject[0][v11]; + if ( v24 ) + { + v25 = v24 <= 0 ? -1 - v24 : v24 - 1; + if ( !object[v25]._oMissFlag ) + { + if ( object[v25]._oBreak == 1 ) + BreakObject(-1, v25); + if ( !(_BYTE)nodel ) + missile[v8]._mirange = 0; + missile[v8]._miHitFlag = 0; + } + } + if ( nMissileTable[dPiece[0][v11]] ) + { + if ( !(_BYTE)nodel ) + missile[v8]._mirange = 0; + missile[v8]._miHitFlag = 0; + } + if ( !missile[v8]._mirange ) + { + v26 = missiledata[missile[v8]._mitype].miSFX; + if ( v26 != -1 ) + PlaySfxLoc(v26, missile[v8]._mix, missile[v8]._miy); + } +} + +void __fastcall SetMissAnim(int mi, int animtype) +{ + int v2; // ecx + int v3; // esi + int v4; // edi + int v5; // eax + int v6; // edx + int v7; // esi + int v8; // eax + int v9; // eax + unsigned char *v10; // edi + int v11; // eax + + v2 = mi; + v3 = missile[v2]._mimfnum; + _LOBYTE(missile[v2]._miAnimType) = animtype; + v4 = misfiledata[animtype].mFlags; + v5 = v3 + 236 * animtype; + v6 = v3 + 59 * animtype; + v7 = misfiledata[0].mAnimDelay[v5]; + v8 = misfiledata[0].mAnimLen[v5]; + missile[v2]._miAnimCnt = 0; + missile[v2]._miAnimLen = v8; + v9 = misfiledata[0].mAnimWidth[v6]; + missile[v2]._miAnimFlags = v4; + v10 = misfiledata[0].mAnimData[v6]; + missile[v2]._miAnimWidth = v9; + v11 = misfiledata[0].mAnimWidth2[v6]; + missile[v2]._miAnimData = v10; + missile[v2]._miAnimDelay = v7; + missile[v2]._miAnimWidth2 = v11; + missile[v2]._miAnimFrame = 1; +} + +void __fastcall SetMissDir(int mi, int dir) +{ + missile[mi]._mimfnum = dir; + SetMissAnim(mi, _LOBYTE(missile[mi]._miAnimType)); +} + +// TODO: replace `int mi` parameter with `missile_graphic_id mi` +// to enable the compiler to optimize int to char properly +// check for example the calls in `InitMonsterGFX` +void __fastcall LoadMissileGFX(BYTE mi) +{ + MisFileData *v1; // esi + unsigned char *v2; // eax + signed int v3; // ecx + int *v4; // edx + int v5; // edi + unsigned char v6; // cl + int v7; // eax + _DWORD *v8; // edi + int v9; // ebx + char arglist[256]; // [esp+8h] [ebp-100h] + + v1 = &misfiledata[(unsigned char)mi]; + if ( v1->mFlags & 4 ) + { + sprintf(arglist, "Missiles\\%s.CL2", v1->mName); + v2 = LoadFileInMem(arglist, 0); + v3 = 0; + if ( v1->mAnimFAmt ) + { + v4 = (int *)v1->mAnimData; + do + { + v5 = (int)&v2[*(_DWORD *)&v2[4 * v3++]]; + *v4 = v5; + ++v4; + } + while ( v3 < v1->mAnimFAmt ); + } + } + else + { + v6 = v1->mAnimFAmt; + if ( v6 == 1 ) + { + sprintf(arglist, "Missiles\\%s.CL2", v1->mName); + if ( !v1->mAnimData[0] ) + v1->mAnimData[0] = LoadFileInMem(arglist, 0); + } + else + { + v7 = 0; + if ( v6 ) + { + v8 = (unsigned int *)v1->mAnimData; + do + { + v9 = v7 + 1; + sprintf(arglist, "Missiles\\%s%i.CL2", v1->mName, v7 + 1); + if ( !*v8 ) + *v8 = (unsigned int)LoadFileInMem(arglist, 0); + v7 = v9; + ++v8; + } + while ( v9 < v1->mAnimFAmt ); + } + } + } +} + +void __cdecl InitMissileGFX() +{ + char v0; // bl + unsigned char *v1; // esi + + v0 = 0; + if ( misfiledata[0].mAnimFAmt ) + { + v1 = &misfiledata[0].mAnimFAmt; + do + { + if ( !(v1[7] & 1) ) + LoadMissileGFX(v0); + v1 += 236; + ++v0; + } + while ( *v1 ); + } +} + +void __fastcall FreeMissileGFX(int mi) +{ + int v1; // esi + unsigned char *v2; // ecx + signed int v3; // ebx + void **v4; // edi + void *v5; // ecx + + v1 = mi; + if ( misfiledata[mi].mFlags & 4 ) + { + v2 = misfiledata[v1].mAnimData[0]; + if ( v2 ) + { + mem_free_dbg(&v2[-4 * misfiledata[v1].mAnimFAmt]); + misfiledata[v1].mAnimData[0] = 0; + } + } + else + { + v3 = 0; + if ( misfiledata[v1].mAnimFAmt ) + { + v4 = (void **)misfiledata[v1].mAnimData; + do + { + v5 = *v4; + if ( *v4 ) + { + *v4 = 0; + mem_free_dbg(v5); + } + ++v3; + ++v4; + } + while ( v3 < misfiledata[v1].mAnimFAmt ); + } + } +} + +void __cdecl FreeMissiles() +{ + int v0; // edi + unsigned char *v1; // esi + + v0 = 0; + if ( misfiledata[0].mAnimFAmt ) + { + v1 = &misfiledata[0].mAnimFAmt; + do + { + if ( !(v1[7] & 1) ) + FreeMissileGFX(v0); + v1 += 236; + ++v0; + } + while ( *v1 ); + } +} + +void __cdecl FreeMissiles2() +{ + int v0; // edi + unsigned char *v1; // esi + + v0 = 0; + if ( misfiledata[0].mAnimFAmt ) + { + v1 = &misfiledata[0].mAnimFAmt; + do + { + if ( v1[7] & 1 ) + FreeMissileGFX(v0); + v1 += 236; + ++v0; + } + while ( *v1 ); + } +} + +void __cdecl InitMissiles() +{ + int v0; // eax + int i; // esi + int v2; // eax + int v3; // eax + int v4; // edx + int *v5; // eax + signed int v6; // ecx + _BYTE *v7; // eax + signed int v8; // edx + + v0 = myplr; + _LOBYTE(plr[v0]._pSpellFlags) &= 0xFEu; + if ( plr[v0]._pInfraFlag == 1 ) + { + for ( i = 0; i < nummissiles; ++i ) + { + v2 = missileactive[i]; + if ( missile[v2]._mitype == MIS_INFRA ) + { + v3 = missile[v2]._misource; + if ( v3 == myplr ) + CalcPlrItemVals(v3, 1); + } + } + } + v4 = 0; + memset(missileactive, 0, sizeof(missileactive)); + nummissiles = 0; + do + { + missileavail[v4] = v4; + ++v4; + } + while ( v4 < MAXMISSILES ); + numchains = 0; + v5 = &chain[0]._mitype; + do + { + *(v5 - 1) = -1; + *v5 = 0; + v5[1] = 0; + v5 += 3; + } + while ( (signed int)v5 < (signed int)&chain[MAXMISSILES]._mitype ); + v6 = 0; + do + { + v7 = (unsigned char *)dFlags + v6; + v8 = 112; + do + { + *v7 &= 0xFEu; + v7 += 112; + --v8; + } + while ( v8 ); + ++v6; + } + while ( v6 < 112 ); +} +// 64CCD8: using guessed type int numchains; + +void __fastcall AddLArrow(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // ebx + int v11; // edi + int v12; // eax + char v13; // dl + int v14; // eax + int v15; // esi + int v16; // [esp-4h] [ebp-14h] + int mia; // [esp+Ch] [ebp-4h] + + v9 = dx; + v10 = sx; + v11 = dy; + mia = mi; + if ( sx == dx && sy == dy ) + { + v9 = XDirAdd[midir] + dx; + v11 = YDirAdd[midir] + dy; + } + if ( (_BYTE)mienemy ) + { + v16 = 32; + goto LABEL_11; + } + v12 = id; + v13 = plr[id]._pClass; + if ( v13 == 1 ) + { + v16 = (plr[v12]._pLevel >> 2) + 31; +LABEL_11: + GetMissileVel(mi, v10, sy, v9, v11, v16); + goto LABEL_12; + } + if ( v13 ) + GetMissileVel(mi, v10, sy, v9, v11, 32); + else + GetMissileVel(mi, v10, sy, v9, v11, (plr[v12]._pLevel >> 3) + 31); +LABEL_12: + v14 = GetDirection16(v10, sy, v9, v11); + SetMissDir(mia, v14); + v15 = mia; + missile[v15]._mirange = 256; + missile[v15]._miVar1 = v10; + missile[v15]._miVar2 = sy; + missile[v15]._mlid = AddLight(v10, sy, 5); +} + +void __fastcall AddArrow(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ebx + int v10; // esi + int v11; // edi + int v12; // eax + char v13; // cl + int v14; // esi + int v15; // eax + int x1; // [esp+8h] [ebp-8h] + int i; // [esp+Ch] [ebp-4h] + + v9 = dy; + v10 = dx; + x1 = sx; + i = mi; + if ( sx == dx && sy == dy ) + { + v10 = XDirAdd[midir] + dx; + v9 = YDirAdd[midir] + dy; + dx += XDirAdd[midir]; + } + if ( (_BYTE)mienemy ) + { + GetMissileVel(mi, sx, sy, v10, v9, 32); + } + else + { + v11 = id; + v12 = 32; + if ( plr[id]._pIFlags & 4 ) + { + v12 = random(64, 32) + 16; + } + v13 = plr[v11]._pClass; + if ( v13 == 1 ) + v12 += (plr[v11]._pLevel - 1) >> 2; + if ( !v13 ) + v12 += (plr[v11]._pLevel - 1) >> 3; + GetMissileVel(i, x1, sy, v10, v9, v12); + } + v14 = i; + v15 = GetDirection16(x1, sy, dx, v9); + missile[v14]._mirange = 256; + missile[v14]._miAnimFrame = v15 + 1; +} + +void __fastcall GetVileMissPos(int mi, int dx, int dy) +{ + signed int v3; // edi + int v4; // ebx + int v5; // esi + int v6; // eax + int v7; // eax + int v8; // [esp+Ch] [ebp-14h] + int v9; // [esp+10h] [ebp-10h] + signed int v10; // [esp+14h] [ebp-Ch] + signed int v11; // [esp+18h] [ebp-8h] + signed int v12; // [esp+1Ch] [ebp-4h] + + v8 = dx; + v9 = mi; + v12 = 1; + v3 = -1; + do + { + v11 = v3; + if ( v3 <= v12 ) + { + while ( 2 ) + { + v10 = v3; + v4 = v11 + dy; + v5 = v3 + v8; + do + { + if ( PosOkPlayer(myplr, v5, v4) ) + { + v7 = v9; + missile[v7]._mix = v5; + missile[v7]._miy = v4; + return; + } + ++v10; + ++v5; + } + while ( v10 <= v12 ); + if ( ++v11 <= v12 ) + continue; + break; + } + } + ++v12; + --v3; + } + while ( v3 > -50 ); + v6 = v9; + missile[v6]._mix = v8; + missile[v6]._miy = dy; +} + +void __fastcall AddRndTeleport(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // eax + int v11; // esi + int v12; // eax + int v14; // edi + int v16; // eax + bool v17; // zf + int v18; // ecx + int v19; // ecx + int v20; // [esp+Ch] [ebp-Ch] + int mia; // [esp+10h] [ebp-8h] + int v22; // [esp+14h] [ebp-4h] + + v22 = 0; + v20 = sx; + mia = mi; + while ( ++v22 <= 500 ) + { + v9 = random(58, 3); + v11 = v9 + 4; + v12 = random(58, 3); + v14 = v12 + 4; + if ( random(58, 2) == 1 ) + v11 = -v11; + if ( random(58, 2) == 1 ) + v14 = -v14; + mi = 4 * (sy + v14 + 112 * (v11 + v20)); + if ( !nSolidTable[dPiece[0][mi / 4u]] && !dObject[v11 + v20][sy + v14] && !dMonster[0][mi / 4u] ) + goto LABEL_12; + } + v11 = 0; + v14 = 0; +LABEL_12: + v16 = mia; + missile[v16]._miVar1 = 0; + v17 = setlevel == 0; + missile[v16]._mirange = 2; + if ( v17 || setlvlnum != SL_VILEBETRAYER ) + { + missile[v16]._mix = v20 + v11; + missile[v16]._miy = sy + v14; + if ( !(_BYTE)mienemy ) + UseMana(id, 10); + } + else + { + v18 = object[dObject[dx][dy] - 1]._otype; + if ( v18 == OBJ_MCIRCLE1 || v18 == OBJ_MCIRCLE2 ) + { + v19 = myplr; + missile[v16]._mix = dx; + missile[v16]._miy = dy; + if ( !PosOkPlayer(v19, dx, dy) ) + GetVileMissPos(mia, dx, dy); + } + } +} +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +void __fastcall AddFirebolt(int mi, int sx, int sy, int dx, int dy, int midir, int micaster, int id, int dam) +{ + int v9; // ebx + int v10; // esi + int v11; // edi + int v12; // eax + int v13; // eax + int v14; // eax + int v15; // esi + signed int v16; // [esp-4h] [ebp-14h] + int i; // [esp+Ch] [ebp-4h] + int micastera; // [esp+28h] [ebp+18h] + + v9 = dx; + v10 = dy; + v11 = sx; + i = mi; + if ( sx == dx && sy == dy ) + { + v9 = XDirAdd[midir] + dx; + v10 = YDirAdd[midir] + dy; + } + if ( (_BYTE)micaster ) + { + v16 = 26; + goto LABEL_17; + } + for ( micastera = 0; micastera < nummissiles; ++micastera ) + { + v12 = missileactive[micastera]; + if ( missile[v12]._mitype == 2 && missile[v12]._misource == id && missile[v12]._miVar3 == mi ) + break; + } + if ( micastera == nummissiles ) + UseMana(id, 1); + if ( id == -1 ) + { + v16 = 16; + goto LABEL_17; + } + v13 = 2 * missile[i]._mispllvl + 16; + if ( v13 >= 63 ) + { + v16 = 63; +LABEL_17: + v13 = v16; + } + GetMissileVel(i, v11, sy, v9, v10, v13); + v14 = GetDirection16(v11, sy, v9, v10); + SetMissDir(i, v14); + v15 = i; + missile[v15]._mirange = 256; + missile[v15]._miVar1 = v11; + missile[v15]._miVar2 = sy; + missile[v15]._mlid = AddLight(v11, sy, 8); +} + +void __fastcall AddMagmaball(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // edi + int i; // ST1C_4 + + v9 = mi; + v10 = sx; + i = mi; + GetMissileVel(mi, sx, sy, dx, dy, 16); + v9 *= 176; + *(int *)((char *)&missile[0]._mitxoff + v9) += 3 * *(int *)((char *)&missile[0]._mixvel + v9); + *(int *)((char *)&missile[0]._mityoff + v9) += 3 * *(int *)((char *)&missile[0]._miyvel + v9); + GetMissilePos(i); + *(int *)((char *)&missile[0]._mirange + v9) = 256; + *(int *)((char *)&missile[0]._miVar1 + v9) = v10; + *(int *)((char *)&missile[0]._miVar2 + v9) = sy; + *(int *)((char *)&missile[0]._mlid + v9) = AddLight(v10, sy, 8); +} + +void __fastcall miss_null_33(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // edi + int v11; // eax + + v9 = sx; + v10 = mi; + GetMissileVel(mi, sx, sy, dx, dy, 16); + v11 = v10; + missile[v11]._mirange = 256; + missile[v11]._miVar1 = v9; + missile[v11]._miVar2 = sy; + PutMissile(v10); +} + +void __fastcall AddTeleport(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // eax + int v11; // ecx + char *v12; // edx + int v13; // ecx + int v14; // eax + int v15; // edx + int v16; // ebx + int v17; // edi + int v18; // edx + int CrawlNum[6]; // [esp+Ch] [ebp-28h] + int v20; // [esp+24h] [ebp-10h] + char *v21; // [esp+28h] [ebp-Ch] + int v22; // [esp+2Ch] [ebp-8h] + int v23; // [esp+30h] [ebp-4h] + + CrawlNum[0] = 0; + v9 = mi; + v23 = 0; + CrawlNum[1] = 3; + CrawlNum[2] = 12; + CrawlNum[3] = 45; + CrawlNum[4] = 94; + CrawlNum[5] = 159; + missile[mi]._miDelFlag = 1; + do + { + v10 = CrawlNum[v23]; + v11 = (unsigned char)CrawlTable[v10]; + v22 = (unsigned char)CrawlTable[v10]; + if ( v11 <= 0 ) + goto LABEL_13; + v12 = &CrawlTable[v10 + 2]; + v21 = &CrawlTable[v10 + 2]; + while ( 1 ) + { + v13 = dx + (char)*(v12 - 1); + v14 = dy + (char)*v12; + if ( v13 <= 0 || v13 >= 112 || v14 <= 0 || v14 >= 112 ) + goto LABEL_10; + v15 = v14 + 112 * v13; + v16 = dPlayer[0][v15]; + v17 = v15; + v18 = dObject[0][v15]; + v20 = v17 * 4; + if ( !(dMonster[0][v17] | v18 | v16 | nSolidTable[dPiece[0][v17]]) ) + break; + v12 = v21; +LABEL_10: + v12 += 2; + --v22; + v21 = v12; + if ( v22 <= 0 ) + goto LABEL_13; + } + missile[v9]._miDelFlag = 0; + missile[v9]._mix = v13; + missile[v9]._miy = v14; + missile[v9]._misx = v13; + missile[v9]._misy = v14; + v23 = 6; +LABEL_13: + ++v23; + } + while ( v23 < 6 ); + if ( !missile[v9]._miDelFlag ) + { + UseMana(id, 23); + missile[v9]._mirange = 2; + } +} + +void __fastcall AddLightball(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // edi + int v10; // esi + int v11; // esi + int v13; // eax + int v14; // eax + + v9 = sx; + v10 = mi; + GetMissileVel(mi, sx, sy, dx, dy, 16); + v11 = v10; + missile[v11]._midam = dam; + v13 = random(63, 8); + missile[v11]._mirange = 255; + missile[v11]._miAnimFrame = v13 + 1; + if ( id >= 0 ) + { + v14 = plr[id].WorldY; + missile[v11]._miVar1 = plr[id].WorldX; + missile[v11]._miVar2 = v14; + } + else + { + missile[v11]._miVar1 = v9; + missile[v11]._miVar2 = sy; + } +} + +void __fastcall AddFirewall(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ST20_4 + int i; // ST1C_4 + int v11; // esi + int v12; // eax + int v14; // eax + int v15; // eax + int v16; // eax + + v9 = sx; + i = mi; + v11 = i; + v12 = random(53, 10); + missile[v11]._midam = 16 * (random(53, 10) + v12 + plr[id]._pLevel + 2) >> 1; + GetMissileVel(i, v9, sy, dx, dy, 16); + v14 = missile[i]._mispllvl; + missile[v11]._mirange = 10; + if ( v14 > 0 ) + missile[v11]._mirange = 2 * (5 * v14 + 5); + v15 = ((missile[v11]._mirange * plr[id]._pISplDur >> 3) & 0xFFFFFFF0) + 16 * missile[v11]._mirange; + missile[v11]._mirange = v15; + v16 = v15 - missile[v11]._miAnimLen; + missile[v11]._miVar2 = 0; + missile[v11]._miVar1 = v16; +} + +void __fastcall AddFireball(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // edi + int v10; // eax + int v12; // ecx + int v13; // edx + int v14; // esi + int v15; // eax + int v16; // esi + int i; // [esp+Ch] [ebp-4h] + int mienemya; // [esp+28h] [ebp+18h] + + v9 = sx; + i = mi; + if ( sx == dx ) + { + mi = dy; + if ( sy == dy ) + { + mi = YDirAdd[midir] + dy; + dx += XDirAdd[midir]; + dy += YDirAdd[midir]; + } + } + if ( (_BYTE)mienemy ) + { + v14 = 16; + } + else + { + v10 = random(60, 10); + v12 = 2 * (plr[id]._pLevel + random(60, 10) + v10) + 4; + v13 = missile[i]._mispllvl; + missile[i]._midam = v12; + if ( v13 > 0 ) + { + mienemya = v13; + do + { + v12 += v12 >> 3; + --mienemya; + } + while ( mienemya ); + missile[i]._midam = v12; + } + v14 = 2 * v13 + 16; + if ( v14 > 50 ) + v14 = 50; + UseMana(id, 12); + } + GetMissileVel(i, v9, sy, dx, dy, v14); + v15 = GetDirection16(v9, sy, dx, dy); + SetMissDir(i, v15); + v16 = i; + missile[v16]._miVar3 = 0; + missile[v16]._mirange = 256; + missile[v16]._miVar1 = v9; + missile[v16]._miVar2 = sy; + missile[v16]._miVar4 = v9; + missile[v16]._miVar5 = sy; + missile[v16]._mlid = AddLight(v9, sy, 8); +} + +void __fastcall AddLightctrl(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // edi + int v10; // ebx + int v11; // esi + int v13; // eax + + v9 = sx; + v10 = mi; + if ( !dam && !(_BYTE)mienemy ) + UseMana(id, 3); + v11 = v10; + missile[v11]._miVar1 = v9; + missile[v11]._miVar2 = sy; + GetMissileVel(v10, v9, sy, dx, dy, 32); + v13 = random(52, 8); + missile[v11]._mirange = 256; + missile[v11]._miAnimFrame = v13 + 1; +} + +void __fastcall AddLightning(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + + v9 = mi; + missile[v9]._misx = dx; + missile[v9]._misy = dy; + if ( midir >= 0 ) + { + missile[v9]._mixoff = missile[midir]._mixoff; + missile[v9]._miyoff = missile[midir]._miyoff; + mi = missile[midir]._mitxoff; + missile[v9]._mitxoff = mi; + missile[v9]._mityoff = missile[midir]._mityoff; + } + missile[v9]._miAnimFrame = random(52, 8) + 1; + if ( midir < 0 ) + goto LABEL_9; + if ( (_BYTE)mienemy == 1 ) + { + if ( id != -1 ) + { + missile[v9]._mirange = 10; + goto LABEL_10; + } +LABEL_9: + missile[v9]._mirange = 8; + goto LABEL_10; + } + if ( id == -1 ) + goto LABEL_9; + missile[v9]._mirange = (missile[v9]._mispllvl >> 1) + 6; +LABEL_10: + missile[v9]._mlid = AddLight(missile[v9]._mix, missile[v9]._miy, 4); +} + +void __fastcall AddMisexp(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // edi + CMonster *v10; // esi + int v11; // eax + int v12; // ecx + + v9 = mi; + if ( (_BYTE)mienemy && id > 0 ) + { + v10 = monster[id].MType; + if ( v10->mtype == MT_SUCCUBUS ) + SetMissAnim(mi, MFILE_FLAREEXP); + if ( v10->mtype == MT_SNOWWICH ) + SetMissAnim(v9, MFILE_SCBSEXPB); + if ( v10->mtype == MT_HLSPWN ) + SetMissAnim(v9, MFILE_SCBSEXPD); + if ( v10->mtype == MT_SOLBRNR ) + SetMissAnim(v9, MFILE_SCBSEXPC); + } + v11 = v9; + missile[v11]._mix = missile[dx]._mix; + missile[v11]._miy = missile[dx]._miy; + missile[v11]._misx = missile[dx]._misx; + missile[v11]._misy = missile[dx]._misy; + missile[v11]._mixoff = missile[dx]._mixoff; + missile[v11]._miyoff = missile[dx]._miyoff; + missile[v11]._mitxoff = missile[dx]._mitxoff; + v12 = missile[dx]._mityoff; + missile[v11]._mixvel = 0; + missile[v11]._miyvel = 0; + missile[v11]._miVar1 = 0; + missile[v11]._mityoff = v12; + missile[v11]._mirange = missile[v9]._miAnimLen; +} + +void __fastcall AddWeapexp(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + + v9 = mi; + missile[v9]._miy = sy; + missile[v9]._misy = sy; + missile[v9]._mix = sx; + missile[v9]._misx = sx; + missile[v9]._mixvel = 0; + missile[v9]._miyvel = 0; + missile[v9]._miVar1 = 0; + missile[v9]._miVar2 = dx; + missile[v9]._mimfnum = 0; + if ( dx == 1 ) + SetMissAnim(mi, 5); + else + SetMissAnim(mi, MFILE_MINILTNG); + missile[v9]._mirange = missile[v9]._miAnimLen - 1; +} + +bool __fastcall CheckIfTrig(int x, int y) +{ + int v2; // edi + int v3; // ebx + int *v4; // esi + int v5; // eax + int v7; // [esp+Ch] [ebp-4h] + + v7 = 0; + v2 = y; + v3 = x; + if ( trigflag[4] <= 0 ) + return 0; + v4 = &trigs[0]._ty; + while ( 1 ) + { + v5 = *(v4 - 1); + if ( v3 == v5 && v2 == *v4 ) + break; + if ( abs(v5 - v3) < 2 && abs(*v4 - v2) < 2 ) + break; + ++v7; + v4 += 4; + if ( v7 >= trigflag[4] ) + return 0; + } + return 1; +} + +void __fastcall AddTown(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ebx + int v10; // esi + int v11; // edi + int v12; // eax + int v13; // ecx + char *v14; // eax + int v15; // eax + //int v16; // eax + int v17; // ecx + int v18; // eax + int v19; // eax + int v20; // ecx + int v21; // eax + int v22; // ST0C_4 + int CrawlNum[6]; // [esp+Ch] [ebp-28h] + int i; // [esp+24h] [ebp-10h] + char *v25; // [esp+28h] [ebp-Ch] + int v26; // [esp+2Ch] [ebp-8h] + int v27; // [esp+30h] [ebp-4h] + int x; // [esp+40h] [ebp+Ch] + + _LOBYTE(v9) = dx; + i = mi; + v10 = mi; + CrawlNum[0] = 0; + CrawlNum[1] = 3; + CrawlNum[2] = 12; + CrawlNum[3] = 45; + CrawlNum[4] = 94; + CrawlNum[5] = 159; + if ( currlevel ) + { + _LOBYTE(v11) = dx; + missile[v10]._miDelFlag = 1; + v26 = 0; + do + { + v12 = CrawlNum[v26]; + v13 = (unsigned char)CrawlTable[v12]; + v27 = (unsigned char)CrawlTable[v12]; + if ( v13 > 0 ) + { + v14 = &CrawlTable[v12 + 2]; + v25 = v14; + while ( 1 ) + { + v9 = dx + (char)*(v14 - 1); + v11 = dy + (char)*v14; + if ( v9 > 0 && v9 < 112 && v11 > 0 && v11 < 112 ) + { + v15 = v11 + 112 * v9; + if ( !(dObject[0][v15] | dPlayer[0][v15] | dMissile[0][v15] | nSolidTable[dPiece[0][v15]] | (unsigned char)nMissileTable[dPiece[0][v15]]) ) + { + //_LOBYTE(v16) = CheckIfTrig(v9, v11); + if ( !CheckIfTrig(v9, v11) ) + break; + } + } + v14 = v25 + 2; + --v27; + v25 += 2; + if ( v27 <= 0 ) + goto LABEL_14; + } + missile[v10]._miDelFlag = 0; + missile[v10]._mix = v9; + missile[v10]._miy = v11; + missile[v10]._misx = v9; + missile[v10]._misy = v11; + v26 = 6; + } +LABEL_14: + ++v26; + } + while ( v26 < 6 ); + } + else + { + _LOBYTE(v11) = dy; + missile[v10]._mix = dx; + missile[v10]._miy = dy; + missile[v10]._misx = dx; + missile[v10]._misy = dy; + missile[v10]._miDelFlag = 0; + } + v17 = nummissiles; + missile[v10]._miVar2 = 0; + v27 = 0; + missile[v10]._mirange = 100; + for ( missile[v10]._miVar1 = 100 - missile[v10]._miAnimLen; v27 < v17; ++v27 ) + { + v18 = missileactive[v27]; + x = v18; + v19 = v18; + if ( missile[v19]._mitype == 10 && x != i && missile[v19]._misource == id ) + missile[v19]._mirange = 0; + } + PutMissile(i); + _HIWORD(v21) = _HIWORD(id); + if ( id == myplr && !missile[v10]._miDelFlag && currlevel ) + { + if ( setlevel ) + { + _LOWORD(v21) = (unsigned char)leveltype; + v22 = v21; + _LOWORD(v21) = (unsigned char)setlvlnum; + NetSendCmdLocParam3(1u, CMD_ACTIVATEPORTAL, v9, v11, v21, v22, 1); + } + else + { + _LOWORD(v20) = (unsigned char)leveltype; + _LOWORD(v21) = currlevel; + NetSendCmdLocParam3(1u, CMD_ACTIVATEPORTAL, v9, v11, v21, v20, 0); + } + } +} +// 5BB1ED: using guessed type char leveltype; +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +void __fastcall AddFlash(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + signed int v10; // ebx + char *v11; // edi + int v12; // ecx + int v13; // eax + int v14; // eax + + v9 = mi; + if ( (_BYTE)mienemy ) + { + v14 = 2 * SLOBYTE(monster[id].mLevel); + goto LABEL_12; + } + if ( id == -1 ) + { + v14 = (unsigned int)currlevel >> 1; +LABEL_12: + missile[v9]._midam = v14; + goto LABEL_13; + } + v10 = 0; + v11 = &plr[id]._pLevel; + missile[v9]._midam = 0; + if ( *v11 >= 0 ) + { + do + { + missile[v9]._midam += random(55, 20) + 1; + ++v10; + } + while ( v10 <= *v11 ); + } + v12 = missile[v9]._mispllvl; + if ( v12 > 0 ) + { + v13 = missile[v9]._midam; + do + { + v13 += v13 >> 3; + --v12; + } + while ( v12 ); + missile[v9]._midam = v13; + } + missile[v9]._midam += missile[v9]._midam >> 1; + UseMana(id, 4); +LABEL_13: + missile[v9]._mirange = 19; +} + +void __fastcall AddFlash2(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + char *v10; // edi + signed int v11; // ebx + int v12; // ecx + int v13; // eax + int v14; // eax + int v15; // [esp+4h] [ebp-4h] + + v15 = mi; + if ( !(_BYTE)mienemy ) + { + if ( id == -1 ) + { + missile[mi]._midam = (unsigned int)currlevel >> 1; + } + else + { + v9 = mi; + v10 = &plr[id]._pLevel; + v11 = 0; + for ( missile[mi]._midam = 0; v11 <= *v10; ++v11 ) + { + missile[v9]._midam += random(56, 2) + 1; + } + v12 = missile[v9]._mispllvl; + if ( v12 > 0 ) + { + v13 = missile[v9]._midam; + do + { + v13 += v13 >> 3; + --v12; + } + while ( v12 ); + missile[v9]._midam = v13; + } + missile[v9]._midam += missile[v9]._midam >> 1; + } + } + v14 = v15; + missile[v14]._miPreFlag = 1; + missile[v14]._mirange = 19; +} + +void __fastcall AddManashield(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // eax + + v9 = mi; + missile[v9]._miVar8 = -1; + missile[v9]._mirange = 48 * plr[id]._pLevel; + missile[v9]._miVar1 = plr[id]._pHitPoints; + missile[v9]._miVar2 = plr[id]._pHPBase; + if ( !(_BYTE)mienemy ) + UseMana(id, 11); + if ( id == myplr ) + NetSendCmd(1u, CMD_SETSHIELD); + plr[id].pManaShield = 1; +} + +void __fastcall AddFiremove(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // edi + int v10; // ebx + int v11; // esi + + v9 = mi; + v10 = sx; + v11 = mi; + v11 *= 176; + *(int *)((char *)&missile[0]._midam + v11) = random(59, 10) + plr[id]._pLevel + 1; + GetMissileVel(v9, v10, sy, dx, dy, 16); + *(int *)((char *)&missile[0]._miVar1 + v11) = 0; + *(int *)((char *)&missile[0]._miVar2 + v11) = 0; + ++*(int *)((char *)&missile[0]._mix + v11); + ++*(int *)((char *)&missile[0]._miy + v11); + *(int *)((char *)&missile[0]._miyoff + v11) -= 32; + *(int *)((char *)&missile[0]._mirange + v11) = 255; +} + +void __fastcall AddGuardian(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // edi + int v10; // esi + int v11; // esi + int v12; // eax + int v13; // ecx + int v14; // eax + int v15; // ecx + char *v16; // eax + int v17; // ebx + int v18; // edi + //int v19; // eax + int v20; // edx + int v21; // ecx + int v22; // eax + int v23; // ecx + int v24; // eax + int v25; // eax + int v26; // eax + int v27; // eax + int CrawlNum[6]; // [esp+8h] [ebp-38h] + unsigned int v29; // [esp+20h] [ebp-20h] + int v30; // [esp+24h] [ebp-1Ch] + int v31; // [esp+28h] [ebp-18h] + int x1; // [esp+2Ch] [ebp-14h] + int v33; // [esp+30h] [ebp-10h] + char *v34; // [esp+34h] [ebp-Ch] + int v35; // [esp+38h] [ebp-8h] + int v36; // [esp+3Ch] [ebp-4h] + + CrawlNum[0] = 0; + v9 = 21720 * id; + x1 = sx; + v10 = mi; + CrawlNum[1] = 3; + CrawlNum[2] = 12; + CrawlNum[3] = 45; + CrawlNum[4] = 94; + CrawlNum[5] = 159; + v33 = 21720 * id; + v11 = v10; + v12 = random(62, 10) + (plr[id]._pLevel >> 1) + 1; + v13 = missile[v11]._mispllvl; + missile[v11]._midam = v12; + if ( v13 > 0 ) + { + do + { + v12 += v12 >> 3; + --v13; + } + while ( v13 ); + missile[v11]._midam = v12; + } + v36 = 0; + missile[v11]._miDelFlag = 1; + do + { + v14 = CrawlNum[v36]; + v15 = (unsigned char)CrawlTable[v14]; + v35 = (unsigned char)CrawlTable[v14]; + if ( v15 <= 0 ) + goto LABEL_18; + v16 = &CrawlTable[v14 + 2]; + v34 = v16; + while ( 1 ) + { + v17 = dx + (char)*(v16 - 1); + v18 = dy + (char)*v16; + v30 = v18 + 112 * (dx + (char)*(v16 - 1)); + v29 = 4 * v30; + v31 = dPiece[0][v30]; + if ( v17 <= 0 || v17 >= 112 || v18 <= 0 || v18 >= 112 ) + goto LABEL_14; + //_LOBYTE(v19) = LineClear(x1, sy, v17, v18); + if ( LineClear(x1, sy, v17, v18) ) + { + if ( !(dMonster[0][v29 / 4] | dObject[0][v30] | dMissile[0][v30] | nSolidTable[v31] | (unsigned char)nMissileTable[v31]) ) + break; + } + v16 = v34; +LABEL_14: + v16 += 2; + --v35; + v34 = v16; + if ( v35 <= 0 ) + goto LABEL_17; + } + missile[v11]._miDelFlag = 0; + missile[v11]._mix = v17; + missile[v11]._miy = v18; + missile[v11]._misx = v17; + missile[v11]._misy = v18; + UseMana(id, 13); + v36 = 6; +LABEL_17: + v9 = v33; +LABEL_18: + ++v36; + } + while ( v36 < 6 ); + if ( missile[v11]._miDelFlag != 1 ) + { + v20 = missile[v11]._miy; + v21 = missile[v11]._mix; + missile[v11]._misource = id; + v22 = AddLight(v21, v20, 1); + v23 = missile[v11]._mispllvl; + missile[v11]._mlid = v22; + v24 = v23 + (*(&plr[0]._pLevel + v9) >> 1); + v25 = (v24 * *(int *)((char *)&plr[0]._pISplDur + v9) >> 7) + v24; + missile[v11]._mirange = v25; + if ( v25 > 30 ) + missile[v11]._mirange = 30; + missile[v11]._mirange *= 16; + if ( missile[v11]._mirange < 30 ) + missile[v11]._mirange = 30; + v26 = missile[v11]._mirange; + missile[v11]._miVar3 = 1; + v27 = v26 - missile[v11]._miAnimLen; + missile[v11]._miVar2 = 0; + missile[v11]._miVar1 = v27; + } +} + +void __fastcall AddChain(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ecx + + v9 = mi; + missile[v9]._miVar1 = dx; + missile[v9]._miVar2 = dy; + missile[v9]._mirange = 1; + UseMana(id, 14); +} + +void __fastcall miss_null_11(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // eax + + v9 = mi; + SetMissDir(mi, dx); + v10 = v9; + missile[v10]._midam = 0; + missile[v10]._miLightFlag = 1; + missile[v10]._mirange = 250; +} + +void __fastcall miss_null_12(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + signed int v9; // edx + int v10; // esi + int v11; // eax + + v9 = dx; + v10 = mi; + if ( dx > 3 ) + v9 = 2; + SetMissDir(mi, v9); + v11 = v10; + missile[v11]._midam = 0; + missile[v11]._miLightFlag = 1; + missile[v11]._mirange = 250; +} + +void __fastcall miss_null_13(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + signed int v9; // edx + int v10; // esi + int v11; // eax + int v12; // ecx + + v9 = dx; + v10 = mi; + if ( dx > 3 ) + v9 = 2; + SetMissDir(mi, v9); + v11 = v10; + v12 = missile[v10]._miAnimLen; + missile[v11]._midam = 0; + missile[v11]._miLightFlag = 1; + missile[v11]._mirange = v12; +} + +void __fastcall AddRhino(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + CMonster *v10; // eax + char v11; // cl + AnimStruct *v12; // edi + int v13; // eax + CMonster *v14; // ecx + char v15; // cl + bool v16; // zf + int i; // [esp+8h] [ebp-4h] + + v9 = id; + i = mi; + v10 = monster[id].MType; + v11 = v10->mtype; + if ( v10->mtype < MT_HORNED || v11 > MT_OBLORD ) + { + if ( v11 < MT_NSNAKE || (v12 = &v10->Anims[2], v11 > MT_GSNAKE) ) + v12 = &v10->Anims[1]; + } + else + { + v12 = &v10->Anims[5]; + } + GetMissileVel(i, sx, sy, dx, dy, 18); + v13 = i; + missile[v13]._miAnimFlags = 0; + missile[v13]._mimfnum = midir; + missile[v13]._miAnimData = v12->Frames[midir]; + missile[v13]._miAnimDelay = v12->Delay; + missile[v13]._miAnimLen = v12->Rate; + v14 = monster[v9].MType; + missile[v13]._miAnimWidth = v14->flags_1; + missile[v13]._miAnimWidth2 = v14->flags_2; + missile[v13]._miAnimAdd = 1; + v15 = v14->mtype; + if ( v15 >= MT_NSNAKE && v15 <= MT_GSNAKE ) + missile[v13]._miAnimFrame = 7; + missile[v13]._miVar1 = 0; + missile[v13]._miVar2 = 0; + v16 = monster[v9]._uniqtype == 0; + missile[v13]._miLightFlag = 1; + if ( !v16 ) + { + missile[v13]._miUniqTrans = (unsigned char)monster[v9]._uniqtrans + 1; + missile[v13]._mlid = (unsigned char)monster[v9].mlid; + } + missile[v13]._mirange = 256; + PutMissile(i); +} + +void __fastcall miss_null_32(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // ebx + AnimStruct *v11; // edi + int v12; // eax + CMonster *v13; // ecx + bool v14; // zf + int v15; // ecx + + v9 = id; + v10 = mi; + v11 = &monster[id].MType->Anims[1]; + GetMissileVel(mi, sx, sy, dx, dy, 16); + v12 = v10; + missile[v12]._mimfnum = midir; + missile[v12]._miAnimFlags = 0; + missile[v12]._miAnimData = v11->Frames[midir]; + missile[v12]._miAnimDelay = v11->Delay; + missile[v12]._miAnimLen = v11->Rate; + v13 = monster[id].MType; + missile[v12]._miAnimWidth = v13->flags_1; + missile[v12]._miAnimWidth2 = v13->flags_2; + v14 = monster[id]._uniqtype == 0; + missile[v12]._miAnimAdd = 1; + missile[v12]._miVar1 = 0; + missile[v12]._miVar2 = 0; + missile[v12]._miLightFlag = 1; + if ( !v14 ) + missile[v12]._miUniqTrans = (unsigned char)monster[v9]._uniqtrans + 1; + v15 = monster[v9]._mx; + missile[v12]._mirange = 256; + dMonster[0][monster[v9]._my + 112 * v15] = 0; + PutMissile(v10); +} + +void __fastcall AddFlare(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // edi + int v10; // edx + int v11; // esi + int v12; // ecx + int v13; // esi + int v14; // eax + CMonster *v15; // esi + int code; // [esp+Ch] [ebp-4h] + + v9 = sx; + v10 = dx; + v11 = mi; + v12 = dy; + code = v11; + if ( v9 == dx && sy == dy ) + { + v10 = XDirAdd[midir] + dx; + v12 = YDirAdd[midir] + dy; + } + GetMissileVel(v11, v9, sy, v10, v12, 16); + v13 = v11; + missile[v13]._mirange = 256; + missile[v13]._miVar1 = v9; + missile[v13]._miVar2 = sy; + missile[v13]._mlid = AddLight(v9, sy, 8); + if ( (_BYTE)mienemy ) + { + if ( id > 0 ) + { + v15 = monster[id].MType; + if ( v15->mtype == MT_SUCCUBUS ) + SetMissAnim(code, MFILE_FLARE); + if ( v15->mtype == MT_SNOWWICH ) + SetMissAnim(code, MFILE_SCUBMISB); + if ( v15->mtype == MT_HLSPWN ) + SetMissAnim(code, MFILE_SCUBMISD); + if ( v15->mtype == MT_SOLBRNR ) + SetMissAnim(code, MFILE_SCUBMISC); + } + } + else + { + UseMana(id, 35); + v14 = id; + drawhpflag = 1; + plr[v14]._pHPBase -= 320; + plr[v14]._pHitPoints -= 320; + if ( plr[id]._pHitPoints <= 0 ) + SyncPlrKill(id, 0); + } +} + +void __fastcall AddAcid(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // edi + int v11; // eax + int v12; // eax + int v13; // ecx + + v9 = sx; + v10 = mi; + GetMissileVel(mi, sx, sy, dx, dy, 16); + v11 = GetDirection16(v9, sy, dx, dy); + SetMissDir(v10, v11); + v12 = v10; + v13 = (unsigned char)monster[id]._mint; + missile[v12]._mlid = -1; + missile[v12]._miVar1 = v9; + missile[v12]._miVar2 = sy; + missile[v12]._mirange = 5 * (v13 + 4); + PutMissile(v10); +} + +void __fastcall miss_null_1D(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ecx + int v10; // eax + + v9 = mi; + missile[v9]._midam = dam; + missile[v9]._mirange = 50; + v10 = 50 - missile[v9]._miAnimLen; + missile[v9]._mixvel = 0; + missile[v9]._miyvel = 0; + missile[v9]._miVar1 = v10; + missile[v9]._miVar2 = 0; +} + +void __fastcall AddAcidpud(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // edi + int v11; // eax + + v9 = mi; + v10 = missile[mi]._misource; + missile[v9]._mixvel = 0; + missile[v9]._miyvel = 0; + missile[v9]._mixoff = 0; + missile[v9]._miyoff = 0; + missile[v9]._miLightFlag = 1; + v11 = random(50, 15); + missile[v9]._miPreFlag = 1; + missile[v9]._mirange = v11 + 40 * ((unsigned char)monster[v10]._mint + 1); +} + +void __fastcall AddStone(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // eax + int v10; // edx + int v11; // esi + int v12; // edi + int v13; // ecx + char *v14; // ecx + int v15; // ebx + int v16; // ebx + int v17; // edi + int *v18; // edi + int v19; // ecx + int v20; // edx + int v21; // ecx + int v22; // edx + int *v23; // eax + int CrawlNum[6]; // [esp+Ch] [ebp-20h] + int v25; // [esp+24h] [ebp-8h] + int v26; // [esp+28h] [ebp-4h] + + v9 = mi; + CrawlNum[0] = 0; + v26 = 0; + v10 = id; + v11 = id; + CrawlNum[1] = 3; + CrawlNum[2] = 12; + CrawlNum[3] = 45; + CrawlNum[4] = 94; + CrawlNum[5] = 159; + missile[mi]._misource = id; + do + { + v12 = CrawlNum[v26]; + v13 = (unsigned char)CrawlTable[v12]; + v25 = (unsigned char)CrawlTable[v12]; + if ( v13 > 0 ) + { + v14 = &CrawlTable[v12 + 2]; + while ( 1 ) + { + v10 = dx + (char)*(v14 - 1); + v11 = dy + (char)*v14; + if ( v10 > 0 && v10 < 112 && v11 > 0 && v11 < 112 ) + { + v15 = dMonster[0][v11 + 112 * v10]; + v16 = v15 <= 0 ? -1 - v15 : v15 - 1; + if ( v16 > 3 && monster[v16]._mAi != AI_DIABLO ) + { + v17 = monster[v16]._mmode; + if ( v17 != MM_FADEIN && v17 != MM_FADEOUT && v17 != MM_CHARGE ) + break; + } + } + v14 += 2; + if ( --v25 <= 0 ) + goto LABEL_19; + } + v25 = -99; + v26 = 6; + missile[v9]._miVar2 = v16; + v18 = (int *)&monster[v16]._mmode; + v19 = *v18; + *v18 = MM_STONE; + missile[v9]._miVar1 = v19; + } +LABEL_19: + ++v26; + } + while ( v26 < 6 ); + if ( v25 == -99 ) + { + missile[v9]._mix = v10; + missile[v9]._misx = v10; + v20 = missile[v9]._mispllvl + 6; + v21 = v20 * plr[id]._pISplDur >> 7; + missile[v9]._miy = v11; + missile[v9]._misy = v11; + v22 = v21 + v20; + v23 = &missile[v9]._mirange; + *v23 = v22; + if ( v22 > 15 ) + *v23 = 15; + *v23 *= 16; + UseMana(id, 8); + } + else + { + missile[v9]._miDelFlag = 1; + } +} + +void __fastcall AddGolem(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // eax + int v10; // ebx + int v11; // edi + int v12; // ecx + bool v13; // zf + bool v14; // sf + int v15; // esi + int v16; // esi + int v17; // [esp+Ch] [ebp-8h] + int v18; // [esp+10h] [ebp-4h] + + v18 = mi; + v9 = mi; + v10 = id; + v11 = nummissiles; + v12 = 0; + v13 = nummissiles == 0; + v14 = nummissiles < 0; + missile[v9]._miDelFlag = 0; + if ( v14 || v13 ) + { +LABEL_6: + missile[v9]._miVar1 = sx; + missile[v9]._miVar2 = sy; + missile[v9]._miVar4 = dx; + missile[v9]._miVar5 = dy; + if ( (monster[v10]._mx != 1 || monster[v10]._my) && v10 == myplr ) + M_StartKill(v10, v10); + UseMana(id, 21); + } + else + { + while ( 1 ) + { + v15 = missileactive[v12]; + v17 = v15; + v16 = v15; + if ( missile[v16]._mitype == 33 ) + { + v10 = id; + if ( v17 != v18 && missile[v16]._misource == id ) + break; + } + if ( ++v12 >= v11 ) + goto LABEL_6; + } + missile[v9]._miDelFlag = 1; + } +} + +void __fastcall AddEtherealize(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // edx + int v10; // eax + int v11; // ecx + int v12; // esi + int v13; // esi + int v14; // ecx + + v9 = id; + v10 = mi; + v11 = missile[mi]._mispllvl; + v12 = 16 * plr[id]._pLevel >> 1; + missile[v10]._mirange = v12; + if ( v11 > 0 ) + { + do + { + v12 += v12 >> 3; + --v11; + } + while ( v11 ); + missile[v10]._mirange = v12; + } + v13 = missile[v10]._mirange + (missile[v10]._mirange * plr[v9]._pISplDur >> 7); + missile[v10]._miVar1 = plr[v9]._pHitPoints; + v14 = plr[v9]._pHPBase; + missile[v10]._mirange = v13; + missile[v10]._miVar2 = v14; + if ( !(_BYTE)mienemy ) + UseMana(id, 25); +} + +void __fastcall miss_null_1F(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + missile[mi]._miDelFlag = 1; +} + +void __fastcall miss_null_23(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // edx + int v11; // eax + + v9 = mi; + missile[v9]._mix = sx; + missile[v9]._miy = sy; + missile[v9]._misx = sx; + missile[v9]._misy = sy; + v10 = 0; + missile[v9]._midam = dam; + missile[v9]._misource = id; + if ( dam != 1 ) + v10 = 1; + SetMissDir(mi, v10); + v11 = missile[v9]._miAnimLen; + missile[v9]._miLightFlag = 1; + missile[v9]._mirange = v11; +} + +void __fastcall AddBoom(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ecx + int v10; // edx + + v9 = mi; + missile[v9]._miy = dy; + missile[v9]._misy = dy; + missile[v9]._mix = dx; + missile[v9]._misx = dx; + missile[v9]._midam = dam; + v10 = missile[v9]._miAnimLen; + missile[v9]._mixvel = 0; + missile[v9]._miyvel = 0; + missile[v9]._mirange = v10; + missile[v9]._miVar1 = 0; +} + +void __fastcall AddHeal(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + signed int v10; // ebx + int v12; // edi + int i; // ebx + char v14; // al + int v15; // ecx + int *v16; // eax + int *v17; // eax + int v18; // esi + int v19; // [esp+Ch] [ebp-8h] + int v20; // [esp+10h] [ebp-4h] + + v19 = mi; + v9 = id; + v10 = 0; + v12 = (random(57, 10) + 1) << 6; + if ( plr[id]._pLevel > 0 ) + { + do + { + v12 += (random(57, 4) + 1) << 6; + ++v10; + } + while ( v10 < plr[v9]._pLevel ); + } + v20 = 0; + for ( i = v19; v20 < missile[i]._mispllvl; ++v20 ) + { + v12 += (random(57, 6) + 1) << 6; + } + v14 = plr[v9]._pClass; + if ( !v14 ) + v12 *= 2; + if ( v14 == 1 ) + v12 += v12 >> 1; + v15 = plr[v9]._pMaxHP; + v16 = &plr[v9]._pHitPoints; + *v16 += v12; + if ( plr[v9]._pHitPoints > v15 ) + *v16 = v15; + v17 = &plr[v9]._pHPBase; + v18 = plr[v9]._pMaxHPBase; + *v17 += v12; + if ( *v17 > v18 ) + *v17 = v18; + UseMana(id, 2); + missile[i]._miDelFlag = 1; + drawhpflag = 1; +} + +void __fastcall AddHealOther(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + missile[mi]._miDelFlag = 1; + UseMana(id, 34); + if ( id == myplr ) + SetCursor(CURSOR_HEALOTHER); +} + +void __fastcall AddElement(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ebx + int v10; // edi + int v11; // eax + int v13; // eax + int v14; // esi + int v15; // ecx + int v16; // eax + int x; // [esp+Ch] [ebp-8h] + int i; // [esp+10h] [ebp-4h] + + v9 = dx; + v10 = dy; + x = sx; + i = mi; + if ( sx == dx && sy == dy ) + { + v9 = XDirAdd[midir] + dx; + v10 = YDirAdd[midir] + dy; + } + v11 = random(60, 10); + v13 = 2 * (plr[id]._pLevel + random(60, 10) + v11) + 4; + v14 = i; + v15 = missile[i]._mispllvl; + missile[i]._midam = v13; + if ( v15 > 0 ) + { + do + { + v13 += v13 >> 3; + --v15; + } + while ( v15 ); + missile[v14]._midam = v13; + } + missile[v14]._midam >>= 1; + GetMissileVel(i, x, sy, v9, v10, 16); + v16 = GetDirection8(x, sy, v9, v10); + SetMissDir(i, v16); + missile[v14]._miVar3 = 0; + missile[v14]._mirange = 256; + missile[v14]._miVar1 = x; + missile[v14]._miVar2 = sy; + missile[v14]._miVar4 = v9; + missile[v14]._miVar5 = v10; + missile[v14]._mlid = AddLight(x, sy, 8); + UseMana(id, 29); +} + +void __fastcall AddIdentify(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + missile[mi]._miDelFlag = 1; + UseMana(id, 5); + if ( id == myplr ) + { + if ( sbookflag ) + sbookflag = 0; + if ( !invflag ) + invflag = 1; + SetCursor(CURSOR_IDENTIFY); + } +} +// 4B8968: using guessed type int sbookflag; + +void __fastcall AddFirewallC(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // eax + int v11; // ecx + char *v12; // eax + int v13; // ebx + int v14; // edi + //int v15; // eax + int CrawlNum[6]; // [esp+Ch] [ebp-30h] + int v17; // [esp+24h] [ebp-18h] + int v18; // [esp+28h] [ebp-14h] + char *v19; // [esp+2Ch] [ebp-10h] + int x1; // [esp+30h] [ebp-Ch] + int v21; // [esp+34h] [ebp-8h] + int v22; // [esp+38h] [ebp-4h] + + CrawlNum[0] = 0; + v9 = mi; + v22 = 0; + x1 = sx; + CrawlNum[1] = 3; + CrawlNum[2] = 12; + CrawlNum[3] = 45; + CrawlNum[4] = 94; + CrawlNum[5] = 159; + missile[mi]._miDelFlag = 1; + do + { + v10 = CrawlNum[v22]; + v11 = (unsigned char)CrawlTable[v10]; + v21 = (unsigned char)CrawlTable[v10]; + if ( v11 <= 0 ) + goto LABEL_16; + v12 = &CrawlTable[v10 + 2]; + v19 = v12; + while ( 1 ) + { + v13 = dx + (char)*(v12 - 1); + v14 = dy + (char)*v12; + if ( v13 <= 0 || v13 >= 112 || v14 <= 0 || v14 >= 112 ) + goto LABEL_13; + v18 = v14 + 112 * v13; + v17 = dPiece[0][v18]; + //_LOBYTE(v15) = LineClear(x1, sy, v13, v14); + if ( LineClear(x1, sy, v13, v14) ) + { + if ( (x1 != v13 || sy != v14) && !(nSolidTable[v17] | dObject[0][v18]) ) + break; + } + v12 = v19; +LABEL_13: + v12 += 2; + --v21; + v19 = v12; + if ( v21 <= 0 ) + goto LABEL_16; + } + missile[v9]._miDelFlag = 0; + missile[v9]._miVar1 = v13; + missile[v9]._miVar2 = v14; + missile[v9]._miVar5 = v13; + missile[v9]._miVar6 = v14; + v22 = 6; +LABEL_16: + ++v22; + } + while ( v22 < 6 ); + if ( missile[v9]._miDelFlag != 1 ) + { + missile[v9]._miVar7 = 0; + missile[v9]._miVar8 = 0; + missile[v9]._miVar3 = (midir - 2) & 7; + missile[v9]._mirange = 7; + missile[v9]._miVar4 = (midir + 2) & 7; + UseMana(id, 6); + } +} + +void __fastcall AddInfra(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ecx + int v10; // eax + int v11; // edx + + v9 = mi; + v10 = 1584; + v11 = missile[v9]._mispllvl; + missile[v9]._mirange = 1584; + if ( v11 > 0 ) + { + do + { + v10 += v10 >> 3; + --v11; + } + while ( v11 ); + missile[v9]._mirange = v10; + } + missile[v9]._mirange += missile[v9]._mirange * plr[id]._pISplDur >> 7; + if ( !(_BYTE)mienemy ) + UseMana(id, 9); +} + +void __fastcall AddWave(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ecx + + v9 = mi; + missile[v9]._miVar3 = 0; + missile[v9]._miVar4 = 0; + missile[v9]._miVar1 = dx; + missile[v9]._miVar2 = dy; + missile[v9]._mirange = 1; + missile[v9]._miAnimFrame = 4; + UseMana(id, 15); +} + +void __fastcall AddNova(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // eax + int v12; // ebx + int v13; // eax + int v15; // ebx + int v16; // eax + int v18; // ebx + int v19; // eax + int v21; // ebx + int v22; // eax + int v23; // ecx + int v24; // eax + int v25; // eax + int v27; // edi + int v28; // eax + + v9 = mi; + missile[v9]._miVar1 = dx; + missile[v9]._miVar2 = dy; + if ( id == -1 ) + { + v25 = random(66, 3); + v27 = v25; + v28 = random(66, 3); + missile[v9]._midam = ((unsigned int)currlevel >> 1) + random(66, 3) + v28 + v27; + } + else + { + v10 = random(66, 6); + v12 = v10; + v13 = random(66, 6); + v15 = v13 + v12; + v16 = random(66, 6); + v18 = v16 + v15; + v19 = random(66, 6); + v21 = v19 + v18; + v22 = random(66, 6); + v23 = missile[v9]._mispllvl; + v24 = (v22 + v21 + plr[id]._pLevel + 5) >> 1; + missile[v9]._midam = v24; + if ( v23 > 0 ) + { + do + { + v24 += v24 >> 3; + --v23; + } + while ( v23 ); + missile[v9]._midam = v24; + } + if ( !(_BYTE)mienemy ) + UseMana(id, 18); + } + missile[v9]._mirange = 1; +} + +void __fastcall AddRepair(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + missile[mi]._miDelFlag = 1; + UseMana(id, 26); + if ( id == myplr ) + { + if ( sbookflag ) + sbookflag = 0; + if ( !invflag ) + invflag = 1; + SetCursor(CURSOR_REPAIR); + } +} +// 4B8968: using guessed type int sbookflag; + +void __fastcall AddRecharge(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + missile[mi]._miDelFlag = 1; + UseMana(id, 27); + if ( id == myplr ) + { + if ( sbookflag ) + sbookflag = 0; + if ( !invflag ) + invflag = 1; + SetCursor(CURSOR_RECHARGE); + } +} +// 4B8968: using guessed type int sbookflag; + +void __fastcall AddDisarm(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + missile[mi]._miDelFlag = 1; + UseMana(id, 28); + if ( id == myplr ) + SetCursor(CURSOR_DISARM); +} + +void __fastcall AddApoca(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // eax + int v11; // edx + int v12; // ecx + signed int v13; // ebx + char *v14; // edi + + v9 = mi; + v10 = sx - 8; + v11 = sx + 8; + missile[v9]._miVar1 = 8; + missile[v9]._miVar2 = sy - 8; + missile[v9]._miVar3 = sy + 8; + missile[v9]._miVar4 = v10; + missile[v9]._miVar5 = v11; + missile[v9]._miVar6 = v10; + if ( sy - 8 <= 0 ) + missile[v9]._miVar2 = 1; + v12 = 111; + if ( sy + 8 >= 112 ) + missile[v9]._miVar3 = 111; + if ( v10 <= 0 ) + missile[v9]._miVar4 = 1; + if ( v11 >= 112 ) + missile[v9]._miVar5 = 111; + v13 = 0; + v14 = &plr[id]._pLevel; + if ( *v14 > 0 ) + { + do + { + missile[v9]._midam += random(67, 6) + 1; + ++v13; + } + while ( v13 < *v14 ); + } + missile[v9]._miDelFlag = 0; + missile[v9]._mirange = 255; + UseMana(id, 24); +} + +void __fastcall AddFlame(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v11; // eax + int v13; // edi + int v14; // eax + + v9 = mi; + missile[mi]._miVar2 = 0; + if ( dam > 0 ) + missile[v9]._miVar2 = 5 * dam; + missile[v9]._misx = dx; + missile[v9]._misy = dy; + missile[v9]._mixoff = missile[midir]._mixoff; + missile[v9]._miyoff = missile[midir]._miyoff; + missile[v9]._mitxoff = missile[midir]._mitxoff; + missile[v9]._mityoff = missile[midir]._mityoff; + missile[v9]._mirange = missile[v9]._miVar2 + 20; + missile[v9]._mlid = AddLight(sx, sy, 1); + if ( (_BYTE)mienemy ) + { + missile[v9]._midam = (unsigned char)monster[id].mMinDamage + + random( + 77, + (unsigned char)monster[id].mMaxDamage - (unsigned char)monster[id].mMinDamage + 1); + } + else + { + v11 = random(79, plr[id]._pLevel); + v13 = v11; + v14 = random(79, 2); + missile[v9]._midam = 8 * (v14 + v13) + 16 + ((8 * (v14 + v13) + 16) >> 1); + } +} + +void __fastcall AddFlamec(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + int v10; // edx + int v11; // ebx + int v12; // ecx + int v13; // eax + + v9 = sx; + v10 = dx; + v11 = mi; + v12 = dy; + if ( v9 == dx && sy == dy ) + { + v10 = XDirAdd[midir] + dx; + v12 = YDirAdd[midir] + dy; + } + GetMissileVel(v11, v9, sy, v10, v12, 32); + if ( !(_BYTE)mienemy ) + UseMana(id, 20); + v13 = v11; + missile[v13]._miVar3 = 0; + missile[v13]._miVar2 = sy; + missile[v13]._miVar1 = v9; + missile[v13]._mirange = 256; +} + +void __fastcall AddCbolt(int mi, int sx, int sy, int dx, int dy, int midir, int micaster, int id, int dam) +{ + int v9; // esi + int v10; // eax + int v12; // edx + int v13; // eax + int v14; // ecx + int i; // [esp+Ch] [ebp-8h] + int x; // [esp+10h] [ebp-4h] + + i = mi; + v9 = mi; + x = sx; + if ( (_BYTE)micaster ) + { + v13 = random(63, 15); + missile[v9]._midam = 15; + missile[v9]._mirnd = v13 + 1; + } + else + { + v10 = random(63, 15); + v12 = plr[id]._pMagic; + missile[v9]._mirnd = v10 + 1; + missile[v9]._midam = random(68, v12 >> 2) + 1; + } + v14 = dx; + if ( x == dx && sy == dy ) + { + v14 = XDirAdd[midir] + dx; + dx += XDirAdd[midir]; + dy += YDirAdd[midir]; + } + missile[v9]._miAnimFrame = random(63, 8) + 1; + missile[v9]._mlid = AddLight(x, sy, 5); + GetMissileVel(i, x, sy, dx, dy, 8); + missile[v9]._miVar3 = 0; + missile[v9]._miVar1 = 5; + missile[v9]._miVar2 = midir; + missile[v9]._mirange = 256; +} + +void __fastcall AddHbolt(int mi, int sx, int sy, int dx, int dy, int midir, int micaster, int id, int dam) +{ + int v9; // esi + int v10; // ecx + int v11; // edi + int v12; // eax + int v13; // eax + int v14; // esi + int v15; // eax + signed int v17; // [esp-4h] [ebp-14h] + int i; // [esp+Ch] [ebp-4h] + + v9 = dy; + i = mi; + v10 = dx; + v11 = sx; + if ( sx == dx && sy == dy ) + { + v10 = XDirAdd[midir] + dx; + v9 = YDirAdd[midir] + dy; + dx += XDirAdd[midir]; + } + if ( id == -1 ) + { + v17 = 16; + goto LABEL_8; + } + v12 = 2 * missile[i]._mispllvl + 16; + if ( v12 >= 63 ) + { + v17 = 63; +LABEL_8: + v12 = v17; + } + GetMissileVel(i, sx, sy, v10, v9, v12); + v13 = GetDirection16(v11, sy, dx, v9); + SetMissDir(i, v13); + v14 = i; + missile[v14]._mirange = 256; + missile[v14]._miVar1 = v11; + missile[v14]._miVar2 = sy; + v15 = AddLight(v11, sy, 8); + missile[v14]._mlid = v15; + missile[v14]._midam = random(69, 10) + plr[id]._pLevel + 9; + UseMana(id, 31); +} + +void __fastcall AddResurrect(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // esi + + v9 = mi; + UseMana(id, 32); + if ( id == myplr ) + SetCursor(CURSOR_RESURRECT); + missile[v9]._miDelFlag = 1; +} + +void __fastcall AddResurrectBeam(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ecx + int v10; // eax + + v9 = mi; + missile[v9]._mixvel = 0; + missile[v9]._miyvel = 0; + missile[v9]._mix = dx; + missile[v9]._misx = dx; + v10 = misfiledata[36].mAnimLen[0]; + missile[v9]._miy = dy; + missile[v9]._misy = dy; + missile[v9]._mirange = v10; +} + +void __fastcall AddTelekinesis(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + missile[mi]._miDelFlag = 1; + UseMana(id, 33); + if ( id == myplr ) + SetCursor(CURSOR_TELEKINESIS); +} + +void __fastcall AddBoneSpirit(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // ebx + int v10; // edi + int v11; // esi + int v12; // eax + int v13; // eax + int mia; // [esp+Ch] [ebp-8h] + int x; // [esp+10h] [ebp-4h] + + v9 = dx; + v10 = dy; + x = sx; + mia = mi; + if ( sx == dx && sy == dy ) + { + v9 = XDirAdd[midir] + dx; + v10 = YDirAdd[midir] + dy; + } + v11 = mi; + missile[mi]._midam = 0; + GetMissileVel(mi, sx, sy, v9, v10, 16); + v12 = GetDirection8(x, sy, v9, v10); + SetMissDir(mia, v12); + missile[v11]._miVar3 = 0; + missile[v11]._mirange = 256; + missile[v11]._miVar1 = x; + missile[v11]._miVar2 = sy; + missile[v11]._miVar4 = v9; + missile[v11]._miVar5 = v10; + missile[v11]._mlid = AddLight(x, sy, 8); + if ( !(_BYTE)mienemy ) + { + UseMana(id, 36); + v13 = id; + drawhpflag = 1; + plr[v13]._pHPBase -= 384; + plr[v13]._pHitPoints -= 384; + if ( plr[id]._pHitPoints <= 0 ) + SyncPlrKill(id, 0); + } +} + +void __fastcall AddRportal(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + int v9; // eax + int v10; // edx + + v9 = mi; + missile[v9]._miVar2 = 0; + missile[v9]._mix = sx; + missile[v9]._misx = sx; + missile[v9]._mirange = 100; + v10 = 100 - missile[mi]._miAnimLen; + missile[v9]._miy = sy; + missile[v9]._misy = sy; + missile[v9]._miVar1 = v10; + PutMissile(mi); +} + +void __fastcall AddDiabApoca(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam) +{ + signed int v9; // edi + int *v10; // esi + //int v11; // eax + int x1; // [esp+4h] [ebp-8h] + int v13; // [esp+8h] [ebp-4h] + + v9 = 0; + x1 = sx; + v13 = mi; + if ( gbMaxPlayers ) + { + v10 = &plr[0]._py; + do + { + if ( *((_BYTE *)v10 - 39) ) + { + //_LOBYTE(v11) = LineClear(x1, sy, *(v10 - 1), *v10); + if ( LineClear(x1, sy, *(v10 - 1), *v10) ) + AddMissile(0, 0, *(v10 - 1), *v10, 0, 66, mienemy, id, dam, 0); + mi = v13; + } + ++v9; + v10 += 5430; + } + while ( v9 < (unsigned char)gbMaxPlayers ); + } + missile[mi]._miDelFlag = 1; +} +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall AddMissile(int sx, int sy, int v1, int v2, int midir, int mitype, int micaster, int id, int v3, int spllvl) +{ + int v10; // esi + int v11; // ecx + int v12; // ecx + int v13; // ebx + int v14; // esi + int v15; // esi + int v16; // edi + int v17; // ecx + char v18; // al + int v19; // edx + int v20; // ecx + int v21; // eax + int sya; // [esp+8h] [ebp-8h] + int sxa; // [esp+Ch] [ebp-4h] + + sya = sy; + sxa = sx; + if ( nummissiles >= MAXMISSILES ) + return -1; + if ( mitype != 13 || plr[id].pManaShield != 1 ) + goto LABEL_9; + if ( currlevel != plr[id].plrlevel ) + return -1; + v10 = 0; + if ( nummissiles > 0 ) + { + do + { + v11 = missileactive[v10]; + if ( missile[v11]._mitype == 13 && missile[v11]._misource == id ) + return -1; + } + while ( ++v10 < nummissiles ); + } +LABEL_9: + v12 = nummissiles; + v13 = missileavail[0]; + v14 = missileavail[-nummissiles++ + 124]; /* MAXMISSILES */ + missileavail[0] = v14; + v15 = v13; + missile[v15]._mitype = mitype; + v16 = mitype; + missileactive[v12] = v13; + v17 = missiledata[mitype].mDraw; + missile[v15]._micaster = (char)micaster; + v18 = missiledata[mitype].mFileNum; + missile[v15]._misource = id; + v19 = midir; + missile[v15]._miDrawFlag = v17; + _LOBYTE(missile[v15]._miAnimType) = v18; + missile[v15]._mispllvl = spllvl; + missile[v15]._mimfnum = midir; + if ( v18 == -1 || misfiledata[(unsigned char)v18].mAnimFAmt < 8u ) + v19 = 0; + SetMissDir(v13, v19); + v20 = sya; + missile[v15]._mlid = -1; + missile[v15]._mixoff = 0; + missile[v15]._miyoff = 0; + missile[v15]._mitxoff = 0; + missile[v15]._mityoff = 0; + missile[v15]._miDelFlag = 0; + missile[v15]._miLightFlag = 0; + missile[v15]._miPreFlag = 0; + missile[v15]._miUniqTrans = 0; + missile[v15]._miHitFlag = 0; + missile[v15]._midist = 0; + missile[v15]._mirnd = 0; + v21 = missiledata[v16].mlSFX; + missile[v15]._mix = sxa; + missile[v15]._misx = sxa; + missile[v15]._miy = sya; + missile[v15]._misy = sya; + missile[v15]._miAnimAdd = 1; + missile[v15]._midam = v3; + if ( v21 != -1 ) + { + PlaySfxLoc(v21, sxa, sya); + v20 = sya; + } + missiledata[v16].mAddProc(v13, sxa, v20, v1, v2, midir, micaster, id, v3); + return v13; +} + +int __fastcall Sentfire(int i, int sx, int sy) +{ + int v3; // esi + int v4; // ebx + int v5; // edi + //int v6; // eax + int v7; // eax + int v8; // eax + int v9; // edi + int midir; // ST30_4 + int v11; // ecx + int v12; // eax + //int v13; // edx + int mi; // [esp+Ch] [ebp-8h] + + mi = i; + v3 = i; + v4 = sx; + v5 = 0; + //_LOBYTE(v6) = LineClear(missile[i]._mix, missile[i]._miy, sx, sy); + if ( LineClear(missile[i]._mix, missile[i]._miy, sx, sy) ) + { + v7 = dMonster[0][sy + 112 * v4]; + if ( v7 > 0 && (signed int)(monster[v7-1]._mhitpoints & 0xFFFFFFC0) > 0 && v7 - 1 > 3 ) /* fix monstactive */ + { + v8 = GetDirection(missile[v3]._mix, missile[v3]._miy, v4, sy); + v9 = missile[v3]._misource; + midir = v8; + v11 = missile[v3]._misource; + missile[v3]._miVar3 = missileavail[0]; + v12 = GetSpellLevel(v11, 1); + AddMissile(missile[v3]._mix, missile[v3]._miy, v4, sy, midir, MIS_FIREBOLT, 0, v9, missile[v3]._midam, v12); /* check mtype v13 */ + v5 = -1; + SetMissDir(mi, 2); + missile[v3]._miVar2 = 3; + } + } + return v5; +} + +void __fastcall MI_Dummy(int i) +{ + return; +} + +void __fastcall MI_Golem(int i) +{ + int v1; // esi + int v2; // eax + int v3; // eax + bool v4; // zf + int v5; // eax + int v6; // ecx + char *v7; // eax + int v8; // ebx + int v9; // edi + int v10; // edx + int v11; // ecx + int CrawlNum[6]; // [esp+4h] [ebp-38h] + int arglist; // [esp+1Ch] [ebp-20h] + int mi; // [esp+20h] [ebp-1Ch] + unsigned int v16; // [esp+24h] [ebp-18h] + int v17; // [esp+28h] [ebp-14h] + int v18; // [esp+2Ch] [ebp-10h] + char *v19; // [esp+30h] [ebp-Ch] + int v20; // [esp+34h] [ebp-8h] + int v21; // [esp+38h] [ebp-4h] + + mi = i; + v1 = i; + v2 = missile[i]._misource; + arglist = v2; + v3 = v2; + v4 = monster[v3]._mx == 1; + CrawlNum[0] = 0; + CrawlNum[1] = 3; + CrawlNum[2] = 12; + CrawlNum[3] = 45; + CrawlNum[4] = 94; + CrawlNum[5] = 159; + if ( !v4 || monster[v3]._my ) + goto LABEL_17; + v21 = 0; + do + { + v5 = CrawlNum[v21]; + v6 = (unsigned char)CrawlTable[v5]; + v20 = (unsigned char)CrawlTable[v5]; + if ( v6 <= 0 ) + goto LABEL_16; + v7 = &CrawlTable[v5 + 2]; + v19 = v7; + while ( 1 ) + { + v8 = missile[v1]._miVar4 + (char)*(v7 - 1); + v9 = missile[v1]._miVar5 + (char)*v7; + if ( v8 <= 0 || v8 >= 112 || v9 <= 0 || v9 >= 112 ) + goto LABEL_13; + v10 = missile[v1]._miVar2; + v11 = missile[v1]._miVar1; + v18 = v9 + 112 * v8; + v16 = 4 * v18; + v17 = dPiece[0][v18]; + if ( LineClear(v11, v10, v8, v9) ) + { + if ( !(dMonster[0][v16 / 4] | nSolidTable[v17] | dObject[0][v18]) ) + break; + } + v7 = v19; +LABEL_13: + v7 += 2; + --v20; + v19 = v7; + if ( v20 <= 0 ) + goto LABEL_16; + } + v21 = 6; + SpawnGolum(arglist, v8, v9, mi); +LABEL_16: + ++v21; + } + while ( v21 < 6 ); +LABEL_17: + missile[v1]._miDelFlag = 1; +} + +void __fastcall MI_SetManashield(int i) +{ + ManashieldFlag = 1; +} + +void __fastcall MI_LArrow(int i) +{ + int v1; // esi + char v2; // al + int v3; // ebx + int v4; // eax + int v6; // edi + int v7; // ecx + int v8; // eax + int v9; // ecx + int v10; // edx + int v11; // ST0C_4 + unsigned char *v12; // eax + unsigned char v13; // bl + int v14; // eax + int v15; // edx + int v16; // ecx + int v17; // ST10_4 + int v18; // ecx + int v19; // edi + int v20; // eax + int v21; // eax + int v22; // ecx + int v23; // ST0C_4 + int v24; // edi + int v25; // eax + int v26; // eax + int v27; // ecx + int v28; // ST10_4 + int v29; // ecx + unsigned char v32; // [esp+Ch] [ebp-8h] + int ia; // [esp+10h] [ebp-4h] + + v1 = i; + ia = i; + v2 = missile[i]._miAnimType; + --missile[v1]._mirange; + v3 = missile[i]._misource; + if ( v2 == 26 || v2 == 5 ) + { + ChangeLight(missile[v1]._mlid, missile[v1]._mix, missile[v1]._miy, missile[v1]._miAnimFrame + 5); + v18 = missiledata[missile[v1]._mitype].mResist; + v32 = missiledata[missile[v1]._mitype].mResist; + if ( missile[v1]._mitype == 56 ) + { + if ( v3 == -1 ) + { + v21 = random(68, 10); + v22 = currlevel; + v19 = v21 + currlevel + 1; + v20 = random(68, 10) + 2 * currlevel + 1; + } + else + { + v19 = plr[v3]._pILMinDam; + v20 = plr[v3]._pILMaxDam; + } + v23 = missile[v1]._miy; + missiledata[56].mResist = 2; + CheckMissileCol(ia, v19, v20, 0, missile[v1]._mix, v23, 1); + } + if ( missile[v1]._mitype == 27 ) + { + if ( v3 == -1 ) + { + v26 = random(68, 10); + v27 = currlevel; + v24 = v26 + currlevel + 1; + v25 = random(68, 10) + 2 * currlevel + 1; + } + else + { + v24 = plr[v3]._pIFMinDam; + v25 = plr[v3]._pIFMaxDam; + } + v28 = missile[v1]._miy; + missiledata[27].mResist = 1; + CheckMissileCol(ia, v24, v25, 0, missile[v1]._mix, v28, 1); + } + missiledata[missile[v1]._mitype].mResist = v32; + } + else + { + v4 = missile[v1]._mixvel; + ++missile[v1]._midist; + missile[v1]._mitxoff += v4; + missile[v1]._mityoff += missile[v1]._miyvel; + GetMissilePos(i); + if ( v3 == -1 ) + { + v8 = random(68, 10); + v9 = currlevel; + v6 = v8 + currlevel + 1; + v7 = random(68, 10) + 2 * currlevel + 1; + } + else if ( missile[v1]._micaster ) + { + v6 = (unsigned char)monster[v3].mMinDamage; + v7 = (unsigned char)monster[v3].mMaxDamage; + } + else + { + v6 = plr[v3]._pIMinDam; + v7 = plr[v3]._pIMaxDam; + } + v10 = missile[v1]._mix; + if ( v10 != missile[v1]._misx || missile[v1]._miy != missile[v1]._misy ) + { + v11 = missile[v1]._miy; + v12 = &missiledata[missile[v1]._mitype].mResist; + v13 = *v12; + *v12 = 0; + CheckMissileCol(ia, v6, v7, 0, v10, v11, 0); + missiledata[missile[v1]._mitype].mResist = v13; + } + if ( missile[v1]._mirange ) + { + v15 = missile[v1]._mix; + if ( v15 != missile[v1]._miVar1 || missile[v1]._miy != missile[v1]._miVar2 ) + { + v16 = missile[v1]._mlid; + missile[v1]._miVar1 = v15; + v17 = missile[v1]._miy; + missile[v1]._miVar2 = v17; + ChangeLight(v16, v15, v17, 5); + } + } + else + { + missile[v1]._mitxoff -= missile[v1]._mixvel; + v14 = missile[v1]._miyvel; + missile[v1]._mimfnum = 0; + missile[v1]._mityoff -= v14; + GetMissilePos(ia); + if ( missile[v1]._mitype == 56 ) + SetMissAnim(ia, 26); + else + SetMissAnim(ia, MFILE_MAGBLOS); + missile[v1]._mirange = missile[v1]._miAnimLen - 1; + } + } + if ( !missile[v1]._mirange ) + { + v29 = missile[v1]._mlid; + missile[v1]._miDelFlag = 1; + AddUnLight(v29); + } + PutMissile(ia); +} + +void __fastcall MI_Arrow(int i) +{ + int v1; // esi + int v2; // eax + int v3; // eax + int v4; // eax + int v5; // eax + int v6; // edx + int v7; // eax + int v8; // eax + int v9; // ecx + int ia; // [esp+4h] [ebp-4h] + + v1 = i; + ia = i; + v2 = missile[i]._mixvel; + --missile[v1]._mirange; + missile[v1]._mitxoff += v2; + v3 = missile[i]._miyvel; + ++missile[v1]._midist; + missile[v1]._mityoff += v3; + GetMissilePos(i); + v4 = missile[v1]._misource; + if ( v4 == -1 ) + { + v6 = currlevel; + v7 = 2 * currlevel; + } + else if ( missile[v1]._micaster ) + { + v8 = v4; + v6 = (unsigned char)monster[v8].mMinDamage; + v7 = (unsigned char)monster[v8].mMaxDamage; + } + else + { + v5 = v4; + v6 = plr[v5]._pIMinDam; + v7 = plr[v5]._pIMaxDam; + } + v9 = missile[v1]._mix; + if ( v9 != missile[v1]._misx || missile[v1]._miy != missile[v1]._misy ) + CheckMissileCol(ia, v6, v7, 0, v9, missile[v1]._miy, 0); + if ( !missile[v1]._mirange ) + missile[v1]._miDelFlag = 1; + PutMissile(ia); +} + +void __fastcall MI_Firebolt(int i) +{ + int v1; // edi + int v2; // esi + int v3; // ecx + int v4; // ST1C_4 + int v5; // edx + int v6; // ecx + int v7; // eax + int v9; // edi + int v10; // eax + int v11; // edi + int v12; // eax + int v13; // ecx + int v14; // ecx + int v15; // eax + int v16; // esi + int v17; // edx + int v18; // eax + int v19; // esi + int v21; // [esp+Ch] [ebp-Ch] + int v22; // [esp+10h] [ebp-8h] + int ia; // [esp+14h] [ebp-4h] + + v1 = i; + ia = i; + v2 = i; + --missile[v2]._mirange; + if ( missile[i]._mitype == 63 && missile[v2]._mimfnum == 8 ) + { + if ( !missile[i]._mirange ) + { + v3 = missile[v2]._mlid; + if ( v3 >= 0 ) + AddUnLight(v3); + v4 = missile[v2]._miy; + v5 = missile[v2]._mix; + missile[v2]._miDelFlag = 1; + PlaySfxLoc(LS_BSIMPCT, v5, v4); + } + goto LABEL_39; + } + v6 = missile[v2]._mityoff; + v22 = missile[v2]._mitxoff; + v21 = v6; + v7 = v6 + missile[v2]._miyvel; + missile[v2]._mitxoff = v22 + missile[v2]._mixvel; + missile[v2]._mityoff = v7; + GetMissilePos(v1); + v9 = missile[v2]._misource; + if ( v9 == -1 ) + { + v12 = random(78, 2 * currlevel); + v13 = currlevel; + goto LABEL_17; + } + if ( missile[v2]._micaster ) + { + v11 = v9; + v12 = random(77, (unsigned char)monster[v11].mMaxDamage - (unsigned char)monster[v11].mMinDamage + 1); + v13 = (unsigned char)monster[v11].mMinDamage; +LABEL_17: + v10 = v13 + v12; + goto LABEL_19; + } + switch ( missile[v2]._mitype ) + { + case 1: + v10 = (plr[v9]._pMagic >> 3) + random(75, 10) + missile[v2]._mispllvl + 1; + break; + case 0x18: + v10 = (plr[v9]._pMagic >> 1) + 3 * missile[v2]._mispllvl - (plr[v9]._pMagic >> 3); + break; + case 0x3F: + v10 = 0; + break; + default: + v10 = v21; + break; + } +LABEL_19: + v14 = missile[v2]._mix; + if ( v14 == missile[v2]._misx && missile[v2]._miy == missile[v2]._misy ) + { + v1 = ia; + } + else + { + v1 = ia; + CheckMissileCol(ia, v10, v10, 0, v14, missile[v2]._miy, 0); + } + if ( missile[v2]._mirange ) + { + v17 = missile[v2]._mix; + if ( v17 != missile[v2]._miVar1 || missile[v2]._miy != missile[v2]._miVar2 ) + { + missile[v2]._miVar1 = v17; + v18 = missile[v2]._miy; + missile[v2]._miVar2 = v18; + v19 = missile[v2]._mlid; + if ( v19 >= 0 ) + ChangeLight(v19, v17, v18, 8); + } + } + else + { + missile[v2]._mitxoff = v22; + missile[v2]._miDelFlag = 1; + missile[v2]._mityoff = v21; + GetMissilePos(v1); + v15 = missile[v2]._mitype - 1; + if ( missile[v2]._mitype == 1 || (v15 = missile[v2]._mitype - 21, missile[v2]._mitype == 21) ) + { + _LOBYTE(v15) = missile[v2]._micaster; + AddMissile( + missile[v2]._mix, + missile[v2]._miy, + v1, + 0, + missile[v2]._mimfnum, + 9, + v15, + missile[v2]._misource, + 0, + 0); + } + else + { + switch ( missile[v2]._mitype ) + { + case 0x18: + AddMissile( + missile[v2]._mix, + missile[v2]._miy, + v1, + 0, + missile[v2]._mimfnum, + 25, + _LOBYTE(missile[v2]._micaster), + missile[v2]._misource, + 0, + 0); + break; + case 0x39: + AddMissile( + missile[v2]._mix, + missile[v2]._miy, + v1, + 0, + missile[v2]._mimfnum, + 58, + _LOBYTE(missile[v2]._micaster), + missile[v2]._misource, + 0, + 0); + break; + case 0x3F: + SetMissDir(v1, 8); + missile[v2]._mirange = 7; + missile[v2]._miDelFlag = 0; + goto LABEL_39; + } + } + v16 = missile[v2]._mlid; + if ( v16 >= 0 ) + AddUnLight(v16); + } +LABEL_39: + PutMissile(v1); +} + +void __fastcall MI_Lightball(int i) +{ + int v1; // esi + int v2; // ebx + int v3; // eax + int v4; // edi + char v5; // al + int v6; // eax + int v7; // eax + int ia; // [esp+Ch] [ebp-8h] + int v10; // [esp+10h] [ebp-4h] + + v1 = i; + ia = i; + v2 = missile[i]._miVar1; + missile[v1]._mitxoff += missile[i]._mixvel; + v3 = missile[i]._miyvel; + v4 = missile[i]._miVar2; + --missile[v1]._mirange; + missile[v1]._mityoff += v3; + GetMissilePos(i); + v10 = missile[v1]._mirange; + CheckMissileCol(ia, missile[v1]._midam, missile[v1]._midam, 0, missile[v1]._mix, missile[v1]._miy, 0); + if ( missile[v1]._miHitFlag == 1 ) + missile[v1]._mirange = v10; + v5 = dObject[v2][v4]; + if ( v5 && v2 == missile[v1]._mix && v4 == missile[v1]._miy ) + { + v6 = v5 <= 0 ? -1 - v5 : v5 - 1; + v7 = object[v6]._otype; + if ( v7 == OBJ_SHRINEL || v7 == OBJ_SHRINER ) + missile[v1]._mirange = v10; + } + if ( !missile[v1]._mirange ) + missile[v1]._miDelFlag = 1; + PutMissile(ia); +} + +void __fastcall mi_null_33(int i) +{ + int v1; // edi + int v2; // esi + int v3; // eax + + v1 = i; + v2 = i; + v3 = missile[i]._mixvel; + --missile[v2]._mirange; + missile[v2]._mitxoff += v3; + missile[v2]._mityoff += missile[i]._miyvel; + GetMissilePos(i); + CheckMissileCol(v1, missile[v2]._midam, missile[v2]._midam, 0, missile[v2]._mix, missile[v2]._miy, 0); + if ( !missile[v2]._mirange ) + missile[v2]._miDelFlag = 1; + PutMissile(v1); +} + +void __fastcall MI_Acidpud(int i) +{ + int v1; // ebx + int v2; // esi + int v3; // ST0C_4 + int v4; // edx + int v5; // edi + + v1 = i; + v2 = i; + v3 = missile[i]._miy; + v4 = missile[i]._midam; + --missile[v2]._mirange; + v5 = missile[i]._mirange; + CheckMissileCol(i, v4, v4, 1, missile[i]._mix, v3, 0); + missile[v2]._mirange = v5; + if ( !v5 ) + { + if ( missile[v2]._mimfnum ) + { + missile[v2]._miDelFlag = 1; + } + else + { + SetMissDir(v1, 1); + missile[v2]._mirange = missile[v2]._miAnimLen; + } + } + PutMissile(v1); +} + +void __fastcall MI_Firewall(int i) +{ + int v1; // esi + int v3; // ecx + int v4; // eax + int ExpLight[14]; // [esp+8h] [ebp-3Ch] + int ia; // [esp+40h] [ebp-4h] + + v1 = i; + ExpLight[3] = 5; + ExpLight[4] = 5; + ExpLight[11] = 12; + ExpLight[12] = 12; + --missile[v1]._mirange; + ExpLight[0] = 2; + ExpLight[1] = 3; + ExpLight[2] = 4; + ExpLight[5] = 6; + ExpLight[6] = 7; + ExpLight[7] = 8; + ExpLight[8] = 9; + ExpLight[9] = 10; + ExpLight[10] = 11; + ia = i; + ExpLight[13] = 0; + if ( missile[i]._mirange == missile[i]._miVar1 ) + { + SetMissDir(i, 1); + missile[v1]._miAnimFrame = random(83, 11) + 1; + } + if ( missile[v1]._mirange == missile[v1]._miAnimLen - 1 ) + { + SetMissDir(ia, 0); + missile[v1]._miAnimAdd = -1; + missile[v1]._miAnimFrame = 13; + } + CheckMissileCol(ia, missile[v1]._midam, missile[v1]._midam, 1, missile[v1]._mix, missile[v1]._miy, 1); + if ( !missile[v1]._mirange ) + { + v3 = missile[v1]._mlid; + missile[v1]._miDelFlag = 1; + AddUnLight(v3); + } + if ( missile[v1]._mimfnum ) + { + if ( missile[v1]._mirange ) + { + if ( missile[v1]._miAnimAdd != -1 ) + { + v4 = missile[v1]._miVar2; + if ( v4 < 12 ) + { + if ( !v4 ) + missile[v1]._mlid = AddLight(missile[v1]._mix, missile[v1]._miy, ExpLight[0]); + ChangeLight(missile[v1]._mlid, missile[v1]._mix, missile[v1]._miy, ExpLight[missile[v1]._miVar2]); + ++missile[v1]._miVar2; + } + } + } + } + PutMissile(ia); +} + +void __fastcall MI_Fireball(int i) +{ + int v1; // esi + bool v2; // zf + int v3; // eax + int v4; // ecx + int v5; // edi + int v6; // eax + int v7; // edx + int v8; // eax + int v9; // eax + int v10; // ecx + int v11; // eax + int v12; // edx + int v13; // eax + int v14; // ecx + int v15; // ST10_4 + int fx; // [esp+Ch] [ebp-14h] + //int fxa; // [esp+Ch] [ebp-14h] + //int fxb; // [esp+Ch] [ebp-14h] + int fy; // [esp+10h] [ebp-10h] + //int fya; // [esp+10h] [ebp-10h] + //int fyb; // [esp+10h] [ebp-10h] + int ia; // [esp+14h] [ebp-Ch] + //int ib; // [esp+14h] [ebp-Ch] + int ty; // [esp+18h] [ebp-8h] + //int tya; // [esp+18h] [ebp-8h] + //int tyb; // [esp+18h] [ebp-8h] + int tx; // [esp+1Ch] [ebp-4h] + //int txa; // [esp+1Ch] [ebp-4h] + + ia = i; + v1 = i; + --missile[v1]._mirange; + v2 = missile[i]._micaster == 0; + v3 = missile[i]._misource; + v4 = missile[i]._mirange; + v5 = missile[v1]._midam; + if ( v2 ) + { + v6 = v3; + v7 = plr[v6].WorldX; + v8 = plr[v6].WorldY; + } + else + { + v9 = v3; + v7 = monster[v9]._mx; + v8 = monster[v9]._my; + } + fx = v7; + fy = v8; + if ( _LOBYTE(missile[v1]._miAnimType) == 19 ) + { + if ( !v4 ) + { + v10 = missile[v1]._mlid; + missile[v1]._miDelFlag = 1; + AddUnLight(v10); + } + } + else + { + missile[v1]._mitxoff += missile[v1]._mixvel; + missile[v1]._mityoff += missile[v1]._miyvel; + GetMissilePos(ia); + v11 = missile[v1]._mix; + if ( v11 != missile[v1]._misx || missile[v1]._miy != missile[v1]._misy ) + CheckMissileCol(ia, v5, v5, 0, v11, missile[v1]._miy, 0); + v12 = missile[v1]._mix; + if ( missile[v1]._mirange ) + { + if ( v12 != missile[v1]._miVar1 || missile[v1]._miy != missile[v1]._miVar2 ) + { + v14 = missile[v1]._mlid; + missile[v1]._miVar1 = v12; + v15 = missile[v1]._miy; + missile[v1]._miVar2 = v15; + ChangeLight(v14, v12, v15, 8); + } + } + else + { + tx = missile[v1]._mix; + ty = missile[v1]._miy; + ChangeLight(missile[v1]._mlid, v12, ty, missile[v1]._miAnimFrame); + if ( !CheckBlock(fx, fy, tx, ty) ) + CheckMissileCol(ia, v5, v5, 0, tx, ty, 1); + if ( !CheckBlock(fx, fy, tx, ty + 1) ) + CheckMissileCol(ia, v5, v5, 0, tx, ty + 1, 1); + if ( !CheckBlock(fx, fy, tx, ty - 1) ) + CheckMissileCol(ia, v5, v5, 0, tx, ty - 1, 1); + if ( !CheckBlock(fx, fy, tx + 1, ty) ) + CheckMissileCol(ia, v5, v5, 0, tx + 1, ty, 1); + if ( !CheckBlock(fx, fy, tx + 1, ty - 1) ) + CheckMissileCol(ia, v5, v5, 0, tx + 1, ty - 1, 1); /* check x/y */ + if ( !CheckBlock(fx, fy, tx + 1, ty + 1) ) + CheckMissileCol(ia, v5, v5, 0, tx + 1, ty + 1, 1); + if ( !CheckBlock(fx, fy, tx - 1, ty) ) + CheckMissileCol(ia, v5, v5, 0, tx - 1, ty, 1); + if ( !CheckBlock(fx, fy, tx - 1, ty + 1) ) + CheckMissileCol(ia, v5, v5, 0, tx - 1, ty + 1, 1); + if ( !CheckBlock(fx, fy, ty - 2, ty - 1) ) + CheckMissileCol(ia, v5, v5, 0, 0, ty - 1, 1); + v13 = 112 * tx + ty; + if ( !TransList[dung_map[0][v13]] /* check */ + || missile[v1]._mixvel < 0 + && (TransList[dung_map[0][v13 + 1]] && nSolidTable[dPiece[0][v13 + 1]] + || TransList[dung_map[0][v13 - 1]] && nSolidTable[dPiece[0][v13 - 1]]) ) // TransList[*(&byte_5B78EB + v13)] && nSolidTable[*(_DWORD *)&dflags[39][4 * v13 + 36]]) ) + { + ++missile[v1]._mix; + ++missile[v1]._miy; + missile[v1]._miyoff -= 32; + } + if ( missile[v1]._miyvel > 0 + && (TransList[dung_map[tx + 1][ty]] && nSolidTable[dPiece[1][v13]] + || TransList[dung_map[tx - 1][ty]] && nSolidTable[dPiece[-1][v13]]) ) // TransList[block_lvid[v13 + 1940]] && nSolidTable[*(_DWORD *)&dflags[28][4 * v13 + 32]]) ) + { + missile[v1]._miyoff -= 32; + } + if ( missile[v1]._mixvel > 0 + && (TransList[dung_map[0][v13 + 1]] && nSolidTable[dPiece[0][v13 + 1]] + || TransList[dung_map[0][v13 - 1]] && nSolidTable[dPiece[0][v13 - 1]]) ) // TransList[*(&byte_5B78EB + v13)] && nSolidTable[*(_DWORD *)&dflags[39][4 * v13 + 36]]) ) + { + missile[v1]._mixoff -= 32; + } + missile[v1]._mimfnum = 0; + SetMissAnim(ia, MFILE_BIGEXP); + missile[v1]._mirange = missile[v1]._miAnimLen - 1; + } + } + PutMissile(ia); +} + +void __fastcall MI_Lightctrl(int i) +{ + int v1; // esi + int v2; // eax + int v3; // eax + int v5; // edi + signed int v6; // ebx + signed int v7; // edx + int v8; // ecx + int v9; // eax + int v10; // [esp-10h] [ebp-24h] + int v11; // [esp-Ch] [ebp-20h] + int v12; // [esp-8h] [ebp-1Ch] + int v13; // [esp+Ch] [ebp-8h] + int ia; // [esp+10h] [ebp-4h] + + ia = i; + v1 = i; + v2 = missile[i]._misource; + --missile[v1]._mirange; + if ( v2 == -1 ) + { + v5 = random(81, currlevel) + 2 * currlevel; + } + else if ( missile[v1]._micaster ) + { + v5 = 2 + * ((unsigned char)monster[v2].mMinDamage + + random(80, (unsigned char)monster[v2].mMaxDamage - (unsigned char)monster[v2].mMinDamage + 1)); + } + else + { + v3 = random(79, plr[v2]._pLevel); + v5 = (v3 + random(79, 2) + 2) << 6; + } + missile[v1]._mitxoff += missile[v1]._mixvel; + missile[v1]._mityoff += missile[v1]._miyvel; + GetMissilePos(ia); + v6 = missile[v1]._mix; + v7 = missile[v1]._miy; + v8 = missile[v1]._misource; + v13 = missile[v1]._miy; + v9 = dPiece[0][v7 + 112 * missile[v1]._mix]; + if ( v8 != -1 || v6 != missile[v1]._misx || v7 != missile[v1]._misy ) + { + if ( !nMissileTable[v9] ) + goto LABEL_12; + missile[v1]._mirange = 0; + } + if ( !nMissileTable[v9] ) + { +LABEL_12: + if ( v6 == missile[v1]._miVar1 && v7 == missile[v1]._miVar2 || v6 <= 0 || v7 <= 0 || v6 >= 112 || v7 >= 112 ) + goto LABEL_27; + if ( v8 == -1 ) + { + v12 = missile[v1]._mispllvl; + v11 = v5; + v10 = -1; + } + else + { + if ( missile[v1]._micaster == 1 ) + { + v9 = (int)monster[v8].MType; + _LOBYTE(v9) = *(_BYTE *)v9; + if ( (unsigned char)v9 >= MT_STORM && (unsigned char)v9 <= MT_MAEL ) + { + _LOBYTE(v9) = missile[v1]._micaster; + AddMissile(v6, v7, missile[v1]._misx, missile[v1]._misy, ia, 23, v9, v8, v5, missile[v1]._mispllvl); +LABEL_26: + v7 = v13; + missile[v1]._miVar1 = missile[v1]._mix; + missile[v1]._miVar2 = missile[v1]._miy; + goto LABEL_27; + } + } + v12 = missile[v1]._mispllvl; + v11 = v5; + v10 = v8; + } + _LOBYTE(v9) = missile[v1]._micaster; + AddMissile(v6, v7, missile[v1]._misx, missile[v1]._misy, ia, 8, v9, v10, v11, v12); + goto LABEL_26; + } +LABEL_27: + if ( !missile[v1]._mirange || v6 <= 0 || v7 <= 0 || v6 >= 112 || v7 > 112 ) + missile[v1]._miDelFlag = 1; +} + +void __fastcall MI_Lightning(int i) +{ + int v1; // edi + int v2; // esi + int v3; // eax + int v4; // ebx + int v5; // ecx + + v1 = i; + v2 = i; + v3 = missile[i]._mix; + --missile[v2]._mirange; + v4 = missile[i]._mirange; + if ( v3 != missile[i]._misx || missile[v2]._miy != missile[v2]._misy ) + CheckMissileCol(i, missile[v2]._midam, missile[v2]._midam, 1, v3, missile[v2]._miy, 0); + if ( missile[v2]._miHitFlag == 1 ) + missile[v2]._mirange = v4; + if ( !missile[v2]._mirange ) + { + v5 = missile[v2]._mlid; + missile[v2]._miDelFlag = 1; + AddUnLight(v5); + } + PutMissile(v1); +} + +void __fastcall MI_Town(int i) +{ + int v1; // esi + int v2; // eax + int *v3; // edi + int v4; // ecx + int ExpLight[17]; // [esp+8h] [ebp-4Ch] + int ia; // [esp+4Ch] [ebp-8h] + int arglist; // [esp+50h] [ebp-4h] + + v1 = i; + ExpLight[14] = 15; + ExpLight[15] = 15; + ExpLight[16] = 15; + v2 = missile[i]._mirange; + ia = i; + ExpLight[0] = 1; + ExpLight[1] = 2; + ExpLight[2] = 3; + ExpLight[3] = 4; + ExpLight[4] = 5; + ExpLight[5] = 6; + ExpLight[6] = 7; + ExpLight[7] = 8; + ExpLight[8] = 9; + ExpLight[9] = 10; + ExpLight[10] = 11; + ExpLight[11] = 12; + ExpLight[12] = 13; + ExpLight[13] = 14; + if ( v2 > 1 ) + missile[v1]._mirange = v2 - 1; + if ( missile[v1]._mirange == missile[v1]._miVar1 ) + SetMissDir(i, 1); + if ( currlevel && missile[v1]._mimfnum != 1 && missile[v1]._mirange ) + { + if ( !missile[v1]._miVar2 ) + missile[v1]._mlid = AddLight(missile[v1]._mix, missile[v1]._miy, 1); + ChangeLight(missile[v1]._mlid, missile[v1]._mix, missile[v1]._miy, ExpLight[missile[v1]._miVar2]); + ++missile[v1]._miVar2; + } + arglist = 0; + v3 = &plr[0].plrlevel; + do + { + if ( *((_BYTE *)v3 - 23) ) + { + if ( currlevel == *v3 + && !*((_BYTE *)v3 + 267) + && !*(v3 - 13) + && v3[1] == missile[v1]._mix + && v3[2] == missile[v1]._miy ) + { + ClrPlrPath(arglist); + if ( arglist == myplr ) + { + NetSendCmdParam1(1u, CMD_WARP, missile[v1]._misource); + *(v3 - 13) = 10; + } + } + } + ++arglist; + v3 += 5430; + } + while ( (signed int)v3 < (signed int)&plr[4].plrlevel ); + if ( !missile[v1]._mirange ) + { + v4 = missile[v1]._mlid; + missile[v1]._miDelFlag = 1; + AddUnLight(v4); + } + PutMissile(ia); +} + +void __fastcall MI_Flash(int i) +{ + int v1; // edi + int v2; // esi + int v3; // eax + int v4; // eax + bool v5; // zf + int v6; // esi + + v1 = i; + v2 = i; + if ( !missile[i]._micaster ) + { + v3 = missile[v2]._misource; + if ( v3 != -1 ) + plr[v3]._pInvincible = 1; + } + v4 = missile[v2]._mix; + --missile[v2]._mirange; + CheckMissileCol(i, missile[v2]._midam, missile[v2]._midam, 1, v4 - 1, missile[v2]._miy, 1); + CheckMissileCol(v1, missile[v2]._midam, missile[v2]._midam, 1, missile[v2]._mix, missile[v2]._miy, 1); + CheckMissileCol(v1, missile[v2]._midam, missile[v2]._midam, 1, missile[v2]._mix + 1, missile[v2]._miy, 1); + CheckMissileCol(v1, missile[v2]._midam, missile[v2]._midam, 1, missile[v2]._mix - 1, missile[v2]._miy + 1, 1); + CheckMissileCol(v1, missile[v2]._midam, missile[v2]._midam, 1, missile[v2]._mix, missile[v2]._miy + 1, 1); + CheckMissileCol(v1, missile[v2]._midam, missile[v2]._midam, 1, missile[v2]._mix + 1, missile[v2]._miy + 1, 1); + if ( !missile[v2]._mirange ) + { + v5 = missile[v2]._micaster == 0; + missile[v2]._miDelFlag = 1; + if ( v5 ) + { + v6 = missile[v2]._misource; + if ( v6 != -1 ) + plr[v6]._pInvincible = 0; + } + } + PutMissile(v1); +} + +void __fastcall MI_Flash2(int i) +{ + int v1; // edi + int v2; // esi + int v3; // eax + int v4; // eax + bool v5; // zf + int v6; // esi + + v1 = i; + v2 = i; + if ( !missile[i]._micaster ) + { + v3 = missile[v2]._misource; + if ( v3 != -1 ) + plr[v3]._pInvincible = 1; + } + v4 = missile[v2]._miy; + --missile[v2]._mirange; + CheckMissileCol(i, missile[v2]._midam, missile[v2]._midam, 1, missile[v2]._mix - 1, v4 - 1, 1); + CheckMissileCol(v1, missile[v2]._midam, missile[v2]._midam, 1, missile[v2]._mix, missile[v2]._miy - 1, 1); + CheckMissileCol(v1, missile[v2]._midam, missile[v2]._midam, 1, missile[v2]._mix + 1, missile[v2]._miy - 1, 1); + if ( !missile[v2]._mirange ) + { + v5 = missile[v2]._micaster == 0; + missile[v2]._miDelFlag = 1; + if ( v5 ) + { + v6 = missile[v2]._misource; + if ( v6 != -1 ) + plr[v6]._pInvincible = 0; + } + } + PutMissile(v1); +} + +void __fastcall MI_Manashield(int i) +{ + int v1; // edi + int v2; // esi + int v3; // edx + int v4; // eax + int v5; // ecx + int v6; // edx + bool v7; // zf + int v8; // eax + int v9; // ecx + int v10; // edx + int v11; // ecx + int v12; // ecx + bool v13; // sf + int v14; // [esp+Ch] [ebp-10h] + int ia; // [esp+14h] [ebp-8h] + int arglist; // [esp+18h] [ebp-4h] + + ia = i; + v1 = i; + arglist = missile[i]._misource; + v2 = arglist; + v3 = plr[arglist]._pxoff; + v4 = plr[arglist].WorldX; + v5 = plr[arglist].WorldY; + missile[v1]._mix = v4; + missile[v1]._mitxoff = v3 << 16; + v6 = plr[arglist]._pyoff << 16; + v7 = plr[arglist]._pmode == PM_WALK3; + missile[v1]._miy = v5; + missile[v1]._mityoff = v6; + if ( v7 ) + { + missile[v1]._misx = plr[v2]._px; + missile[v1]._misy = plr[v2]._py; + } + else + { + missile[v1]._misx = v4; + missile[v1]._misy = v5; + } + GetMissilePos(ia); + if ( plr[v2]._pmode == PM_WALK3 ) + { + if ( plr[v2]._pdir == 2 ) + ++missile[v1]._mix; + else + ++missile[v1]._miy; + } + if ( arglist != myplr ) + { + if ( currlevel != plr[v2].plrlevel ) + missile[v1]._miDelFlag = 1; + goto LABEL_33; + } + v8 = plr[v2]._pMana; + v14 = plr[v2]._pMana; + if ( v8 <= 0 || !plr[v2].plractive ) + missile[v1]._mirange = 0; + v9 = missile[v1]._miVar1; + if ( plr[v2]._pHitPoints >= v9 ) + goto LABEL_26; + v10 = v9 - plr[v2]._pHitPoints; + if ( missile[v1]._mispllvl > 0 ) + { + v10 = v10 / -3 + v9 - plr[v2]._pHitPoints; + v8 = v14; + } + if ( v10 < 0 ) + v10 = 0; + drawmanaflag = 1; + drawhpflag = 1; + if ( v8 >= v10 ) + { + plr[v2]._pHitPoints = v9; + v11 = missile[v1]._miVar2; + plr[v2]._pManaBase -= v10; + plr[v2]._pHPBase = v11; + plr[v2]._pMana = v8 - v10; +LABEL_26: + if ( arglist == myplr && !plr[v2]._pHitPoints && !missile[v1]._miVar1 && plr[v2]._pmode != PM_DEATH ) + { + missile[v1]._mirange = 0; + missile[v1]._miDelFlag = 1; + SyncPlrKill(arglist, -1); + } + goto LABEL_31; + } + missile[v1]._miDelFlag = 1; + plr[v2]._pHitPoints = v8 + v9 - v10; + plr[v2]._pHPBase = v8 + missile[v1]._miVar2 - v10; + v12 = plr[v2]._pMaxManaBase - plr[v2]._pMaxMana; + v13 = plr[v2]._pHitPoints < 0; + plr[v2]._pMana = 0; + missile[v1]._mirange = 0; + plr[v2]._pManaBase = v12; + if ( v13 ) + SetPlayerHitPoints(arglist, 0); + if ( plr[v2]._pHitPoints & 0xFFFFFFC0 ) + goto LABEL_26; + if ( arglist == myplr ) + { + SyncPlrKill(arglist, missile[v1]._miVar8); + goto LABEL_26; + } +LABEL_31: + v7 = missile[v1]._mirange == 0; + missile[v1]._miVar1 = plr[v2]._pHitPoints; + missile[v1]._miVar2 = plr[v2]._pHPBase; + if ( v7 ) + { + missile[v1]._miDelFlag = 1; + NetSendCmd(1u, CMD_ENDSHIELD); + } +LABEL_33: + PutMissile(ia); +} + +void __fastcall MI_Etherealize(int i) +{ + int v1; // ebx + int v2; // esi + int v3; // edi + int v4; // edi + int v5; // edx + int v6; // eax + int v7; // ecx + int v8; // edx + bool v9; // zf + char v10; // al + + v1 = i; + v2 = i; + v3 = missile[i]._misource; + --missile[v2]._mirange; + v4 = v3; + v5 = plr[v4]._pxoff; + v6 = plr[v4].WorldX; + v7 = plr[v4].WorldY; + missile[v2]._mix = v6; + missile[v2]._mitxoff = v5 << 16; + v8 = plr[v4]._pyoff << 16; + v9 = plr[v4]._pmode == PM_WALK3; + missile[v2]._miy = v7; + missile[v2]._mityoff = v8; + if ( v9 ) + { + missile[v2]._misx = plr[v4]._px; + missile[v2]._misy = plr[v4]._py; + } + else + { + missile[v2]._misx = v6; + missile[v2]._misy = v7; + } + GetMissilePos(v1); + if ( plr[v4]._pmode == PM_WALK3 ) + { + if ( plr[v4]._pdir == 2 ) + ++missile[v2]._mix; + else + ++missile[v2]._miy; + } + _LOBYTE(plr[v4]._pSpellFlags) |= 1u; + v10 = plr[v4]._pSpellFlags; + if ( !missile[v2]._mirange || plr[v4]._pHitPoints <= 0 ) + { + missile[v2]._miDelFlag = 1; + _LOBYTE(plr[v4]._pSpellFlags) = v10 & 0xFE; + } + PutMissile(v1); +} + +void __fastcall MI_Firemove(int i) +{ + int v1; // esi + int *v2; // eax + int v4; // ecx + int v5; // ebx + int v6; // ecx + int v7; // edx + int v8; // ecx + int v9; // ST10_4 + int v10; // ecx + int ExpLight[14]; // [esp+Ch] [ebp-3Ch] + int ia; // [esp+44h] [ebp-4h] + + v1 = i; + ExpLight[3] = 5; + ExpLight[4] = 5; + missile[v1]._miyoff += 32; + ExpLight[11] = 12; + ExpLight[12] = 12; + --missile[v1]._mix; + --missile[v1]._miy; + ExpLight[0] = 2; + ExpLight[1] = 3; + ExpLight[2] = 4; + ExpLight[5] = 6; + ExpLight[6] = 7; + ExpLight[7] = 8; + ExpLight[8] = 9; + ExpLight[9] = 10; + ExpLight[10] = 11; + ia = i; + ExpLight[13] = 0; + v2 = &missile[i]._miVar1; + if ( ++*v2 == missile[i]._miAnimLen ) + { + SetMissDir(i, 1); + missile[v1]._miAnimFrame = random(82, 11) + 1; + } + v4 = ia; + missile[v1]._mitxoff += missile[v1]._mixvel; + missile[v1]._mityoff += missile[v1]._miyvel; + GetMissilePos(v4); + v5 = missile[v1]._mirange; + CheckMissileCol(ia, missile[v1]._midam, missile[v1]._midam, 0, missile[v1]._mix, missile[v1]._miy, 0); + if ( missile[v1]._miHitFlag == 1 ) + missile[v1]._mirange = v5; + if ( !missile[v1]._mirange ) + { + v6 = missile[v1]._mlid; + missile[v1]._miDelFlag = 1; + AddUnLight(v6); + } + if ( missile[v1]._mimfnum || !missile[v1]._mirange ) + { + v7 = missile[v1]._mix; + if ( v7 != missile[v1]._miVar3 || missile[v1]._miy != missile[v1]._miVar4 ) + { + v8 = missile[v1]._mlid; + missile[v1]._miVar3 = v7; + v9 = missile[v1]._miy; + missile[v1]._miVar4 = v9; + ChangeLight(v8, v7, v9, 8); + } + } + else + { + if ( !missile[v1]._miVar2 ) + missile[v1]._mlid = AddLight(missile[v1]._mix, missile[v1]._miy, ExpLight[0]); + ChangeLight(missile[v1]._mlid, missile[v1]._mix, missile[v1]._miy, ExpLight[missile[v1]._miVar2]); + ++missile[v1]._miVar2; + } + ++missile[v1]._mix; + v10 = ia; + ++missile[v1]._miy; + missile[v1]._miyoff -= 32; + PutMissile(v10); +} + +void __fastcall MI_Guardian(int i) +{ + int v1; // esi + int v2; // eax + int v3; // ecx + unsigned char *v4; // edi + int v5; // eax + signed int v6; // ecx + unsigned char *v7; // ebx + unsigned char v8; // dl + unsigned char *v9; // edi + int v10; // ecx + int *v11; // eax + int v12; // ecx + int v13; // ecx + signed int v14; // [esp+Ch] [ebp-14h] + int v15; // [esp+10h] [ebp-10h] + int v16; // [esp+14h] [ebp-Ch] + unsigned char *v17; // [esp+18h] [ebp-8h] + int ia; // [esp+1Ch] [ebp-4h] + + ia = i; + v1 = i; + v2 = missile[i]._miVar2; + --missile[v1]._mirange; + v3 = missile[i]._mirange; + v16 = 0; + v15 = 0; + if ( v2 > 0 ) + missile[v1]._miVar2 = v2 - 1; + if ( v3 == missile[v1]._miVar1 || missile[v1]._mimfnum == 2 && !missile[v1]._miVar2 ) + SetMissDir(ia, 1); + if ( !(missile[v1]._mirange % 16) ) + { + v4 = &vCrawlTable[0][1]; + v5 = 0; + v17 = &vCrawlTable[0][1]; + do + { + if ( v5 == -1 ) + break; + v6 = 10; + v14 = 10; + do + { + v7 = &v4[v6 - 1]; + v8 = *v7; + if ( !*v7 && !v4[v6] ) + break; + if ( v16 != v8 || v15 != v4[v6] ) + { + v9 = &v4[v6]; + v5 = Sentfire(ia, v8 + missile[v1]._mix, missile[v1]._miy + *v9); + if ( v5 == -1 + || (v5 = Sentfire(ia, missile[v1]._mix - *v7, missile[v1]._miy - *v9), v5 == -1) + || (v5 = Sentfire(ia, missile[v1]._mix + *v7, missile[v1]._miy - *v9), v5 == -1) + || (v5 = Sentfire(ia, missile[v1]._mix - *v7, missile[v1]._miy + *v9), v5 == -1) ) + { + v4 = v17; + break; + } + v16 = *v7; + v10 = *v9; + v4 = v17; + v15 = v10; + v6 = v14; + } + v6 -= 2; + v14 = v6; + } + while ( v6 >= 0 ); + v4 += 30; + v17 = v4; + } + while ( (signed int)v4 < (signed int)&vCrawlTable[23][1] ); + } + if ( missile[v1]._mirange == 14 ) + { + SetMissDir(ia, 0); + missile[v1]._miAnimAdd = -1; + missile[v1]._miAnimFrame = 15; + } + v11 = &missile[v1]._miVar3; + *v11 += missile[v1]._miAnimAdd; + v12 = missile[v1]._miVar3; + if ( v12 <= 15 ) + { + if ( v12 > 0 ) + ChangeLight(missile[v1]._mlid, missile[v1]._mix, missile[v1]._miy, missile[v1]._miVar3); + } + else + { + *v11 = 15; + } + if ( !missile[v1]._mirange ) + { + v13 = missile[v1]._mlid; + missile[v1]._miDelFlag = 1; + AddUnLight(v13); + } + PutMissile(ia); +} + +void __fastcall MI_Chain(int i) +{ + int v1; // esi + int ST1C_4_1; // ST1C_4 + int v3; // edi + int v4; // ebx + int v5; // eax + int v6; // ST18_4 + int v7; // eax + int v8; // edi + int v9; // ecx + int v10; // eax + char *v11; // ecx + int v12; // ebx + int v13; // eax + int v14; // eax + bool v15; // zf + int CrawlNum[19]; // [esp+Ch] [ebp-68h] + int v2; // [esp+58h] [ebp-1Ch] + int v18; // [esp+5Ch] [ebp-18h] + char *v19; // [esp+60h] [ebp-14h] + int id; // [esp+64h] [ebp-10h] + int sx; // [esp+68h] [ebp-Ch] + int sy; // [esp+6Ch] [ebp-8h] + int j; // [esp+70h] [ebp-4h] + + CrawlNum[0] = 0; + v1 = i; + CrawlNum[1] = 3; + ST1C_4_1 = missile[i]._miVar2; + v3 = missile[i]._mix; + v4 = missile[i]._miy; + v5 = missile[i]._misource; + v6 = missile[i]._miVar1; + CrawlNum[2] = 12; + CrawlNum[3] = 45; + CrawlNum[4] = 94; + CrawlNum[5] = 159; + CrawlNum[6] = 240; + CrawlNum[7] = 337; + CrawlNum[8] = 450; + CrawlNum[9] = 579; + CrawlNum[10] = 724; + CrawlNum[11] = 885; + CrawlNum[12] = 1062; + CrawlNum[13] = 1255; + CrawlNum[14] = 1464; + CrawlNum[15] = 1689; + CrawlNum[16] = 1930; + CrawlNum[17] = 2187; + CrawlNum[18] = 2460; + id = v5; + sx = v3; + sy = v4; + v7 = GetDirection(v3, v4, v6, ST1C_4_1); + AddMissile(v3, v4, missile[v1]._miVar1, missile[v1]._miVar2, v7, 7, 0, id, 1, missile[v1]._mispllvl); + v8 = missile[v1]._mispllvl + 3; + if ( v8 > 19 ) + v8 = 19; + for ( j = 1; j < v8; ++j ) + { + v9 = CrawlNum[j]; + v10 = (unsigned char)CrawlTable[v9]; + if ( v10 > 0 ) + { + v11 = &CrawlTable[v9 + 2]; + v18 = v10; + v19 = v11; + do + { + v12 = sx + (char)*(v11 - 1); + v13 = sy + (char)*v11; + v2 = sy + (char)*v11; + if ( v12 > 0 && v12 < 112 && v13 > 0 && v13 < 112 && dMonster[0][v13 + 112 * v12] > 0 ) + { + v14 = GetDirection(sx, sy, v12, v13); + AddMissile(sx, sy, v12, v2, v14, 7, 0, id, 1, missile[v1]._mispllvl); + v11 = v19; + } + v11 += 2; + v15 = v18-- == 1; + v19 = v11; + } + while ( !v15 ); + } + } + v15 = missile[v1]._mirange-- == 1; + if ( v15 ) + missile[v1]._miDelFlag = 1; +} + +void __fastcall mi_null_11(int i) +{ + int v1; // eax + bool v2; // zf + + v1 = i; + v2 = missile[i]._mirange == 1; + --missile[v1]._mirange; + if ( v2 ) + missile[v1]._miDelFlag = 1; + if ( missile[v1]._miAnimFrame == missile[v1]._miAnimLen ) + missile[v1]._miPreFlag = 1; + PutMissile(i); +} + +void __fastcall MI_Weapexp(int i) +{ + int v1; // esi + int v2; // ecx + int v3; // eax + int v4; // ecx + bool v5; // zf + int v6; // edx + int v7; // eax + int v8; // eax + int v9; // ecx + int ExpLight[10]; // [esp+4h] [ebp-2Ch] + int ia; // [esp+2Ch] [ebp-4h] + + ia = i; + v1 = i; + --missile[v1]._mirange; + ExpLight[0] = 9; + ExpLight[1] = 10; + ExpLight[5] = 10; + v2 = missile[i]._mitype; + ExpLight[2] = 11; + ExpLight[4] = 11; + v3 = missile[v1]._misource; + v4 = v2; + v5 = missile[v1]._miVar2 == 1; + ExpLight[3] = 12; + ExpLight[6] = 8; + ExpLight[7] = 6; + ExpLight[8] = 4; + ExpLight[9] = 2; + if ( v5 ) + { + v6 = plr[v3]._pIFMinDam; + v7 = plr[v3]._pIFMaxDam; + missiledata[v4].mResist = 1; + } + else + { + v6 = plr[v3]._pILMinDam; + v7 = plr[v3]._pILMaxDam; + missiledata[v4].mResist = 2; + } + CheckMissileCol(ia, v6, v7, 0, missile[v1]._mix, missile[v1]._miy, 0); + v8 = missile[v1]._miVar1; + if ( v8 ) + { + if ( missile[v1]._mirange ) + ChangeLight(missile[v1]._mlid, missile[v1]._mix, missile[v1]._miy, ExpLight[v8]); + } + else + { + missile[v1]._mlid = AddLight(missile[v1]._mix, missile[v1]._miy, 9); + } + ++missile[v1]._miVar1; + if ( missile[v1]._mirange ) + { + PutMissile(ia); + } + else + { + v9 = missile[v1]._mlid; + missile[v1]._miDelFlag = 1; + AddUnLight(v9); + } +} + +void __fastcall MI_Misexp(int i) +{ + int v1; // edi + int v2; // esi + bool v3; // zf + int v4; // ecx + int v5; // eax + int ExpLight[10]; // [esp+8h] [ebp-28h] + + v1 = i; + v2 = i; + ExpLight[0] = 9; + v3 = missile[i]._mirange == 1; + --missile[v2]._mirange; + ExpLight[1] = 10; + ExpLight[3] = 12; + ExpLight[2] = 11; + ExpLight[4] = 11; + ExpLight[5] = 10; + ExpLight[6] = 8; + ExpLight[7] = 6; + ExpLight[8] = 4; + ExpLight[9] = 2; + if ( v3 ) + { + v4 = missile[v2]._mlid; + missile[v2]._miDelFlag = 1; + AddUnLight(v4); + } + else + { + v5 = missile[v2]._miVar1; + if ( v5 ) + ChangeLight(missile[v2]._mlid, missile[v2]._mix, missile[v2]._miy, ExpLight[v5]); + else + missile[v2]._mlid = AddLight(missile[v2]._mix, missile[v2]._miy, 9); + ++missile[v2]._miVar1; + PutMissile(v1); + } +} + +void __fastcall MI_Acidsplat(int i) +{ + int v1; // eax + int v2; // edx + int v3; // edx + int v4; // edx + int v5; // ST1C_4 + + v1 = i; + v2 = missile[i]._mirange; + if ( v2 == missile[i]._miAnimLen ) + { + ++missile[v1]._mix; + ++missile[v1]._miy; + missile[v1]._miyoff -= 32; + } + v3 = v2 - 1; + missile[v1]._mirange = v3; + if ( v3 ) + { + PutMissile(i); + } + else + { + v4 = missile[v1]._misource; + v5 = missile[v1]._mispllvl; + missile[v1]._miDelFlag = 1; + AddMissile( + missile[v1]._mix, + missile[v1]._miy, + i, + 0, + missile[v1]._mimfnum, + 59, + 1, + v4, + (monster[v4].MData->mLevel >= 2) + 1, + v5); + } +} + +void __fastcall MI_Teleport(int i) +{ + int v1; // edi + int v2; // ebx + int *v3; // eax + int v4; // esi + int v5; // ecx + int v6; // edx + int v7; // ecx + int v8; // edx + int v9; // edx + int v10; // eax + bool v11; // zf + + v1 = i; + v2 = missile[i]._misource; + v3 = &missile[i]._mirange; + if ( --*v3 > 0 ) + { + v4 = v2; + v5 = plr[v2].WorldX; + v6 = plr[v2].WorldY; + dPlayer[plr[v2].WorldX][v6] = 0; + PlrClrTrans(v5, v6); + v7 = missile[v1]._mix; + v8 = missile[v1]._miy; + plr[v4].WorldX = v7; + plr[v4].WorldY = v8; + plr[v4]._px = v7; + plr[v4]._py = v8; + plr[v4]._poldx = v7; + plr[v4]._poldy = v8; + PlrDoTrans(v7, v8); + v9 = plr[v2].WorldX; + missile[v1]._miVar1 = 1; + v10 = plr[v2].WorldY; + v11 = leveltype == DTYPE_TOWN; + dPlayer[v9][v10] = v2 + 1; + if ( !v11 ) + { + ChangeLightXY(plr[v4]._plid, v9, v10); + ChangeVisionXY(plr[v4]._pvid, plr[v4].WorldX, plr[v4].WorldY); + } + if ( v2 == myplr ) + { + ViewX = plr[v4].WorldX - ScrollInfo._sdx; + ViewY = plr[v4].WorldY - ScrollInfo._sdy; + } + } + else + { + missile[v1]._miDelFlag = 1; + } +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall MI_Stone(int i) +{ + int v1; // esi + int v2; // edi + int v3; // edi + bool v4; // zf + bool v5; // sf + int ia; // [esp+Ch] [ebp-4h] + + v1 = i; + ia = i; + v2 = missile[i]._miVar2; + --missile[v1]._mirange; + v3 = v2; + if ( !monster[v3]._mhitpoints && _LOBYTE(missile[v1]._miAnimType) != 18 ) + { + missile[v1]._mimfnum = 0; + missile[v1]._miDrawFlag = 1; + SetMissAnim(i, MFILE_SHATTER1); + missile[v1]._mirange = 11; + } + if ( monster[v3]._mmode == MM_STONE ) + { + if ( !missile[v1]._mirange ) + { + v4 = monster[v3]._mhitpoints == 0; + v5 = monster[v3]._mhitpoints < 0; + missile[v1]._miDelFlag = 1; + if ( v5 || v4 ) + AddDead(monster[v3]._mx, monster[v3]._my, stonendx, (direction)monster[v3]._mdir); + else + monster[v3]._mmode = missile[v1]._miVar1; + } + if ( _LOBYTE(missile[v1]._miAnimType) == 18 ) + PutMissile(ia); + } + else + { + missile[v1]._miDelFlag = 1; + } +} + +void __fastcall MI_Boom(int i) +{ + int v1; // edi + int v2; // esi + + v1 = i; + v2 = i; + --missile[v2]._mirange; + if ( !missile[i]._miVar1 ) + CheckMissileCol(i, missile[v2]._midam, missile[v2]._midam, 0, missile[v2]._mix, missile[v2]._miy, 1); + if ( missile[v2]._miHitFlag == 1 ) + missile[v2]._miVar1 = 1; + if ( !missile[v2]._mirange ) + missile[v2]._miDelFlag = 1; + PutMissile(v1); +} + +void __fastcall MI_Rhino(int i) +{ + int v1; // ebx + int v2; // esi + int v3; // edi + int v4; // edi + int v5; // eax + int v6; // eax + int v7; // ebx + bool v8; // zf + int x; // [esp+Ch] [ebp-1Ch] + int v10; // [esp+10h] [ebp-18h] + int y; // [esp+14h] [ebp-14h] + int a2; // [esp+18h] [ebp-10h] + int a3; // [esp+1Ch] [ebp-Ch] + int arglist; // [esp+20h] [ebp-8h] + int a1; // [esp+24h] [ebp-4h] + + v1 = i; + v2 = i; + arglist = i; + v3 = missile[i]._misource; + a1 = v3; + v4 = v3; + if ( monster[v4]._mmode != MM_CHARGE ) + goto LABEL_12; + GetMissilePos(i); + v5 = missile[v2]._mix; + x = v5; + v10 = missile[v2]._miy; + dMonster[0][v10 + 112 * v5] = 0; + v6 = missile[v2]._mixvel; + if ( monster[v4]._mAi == AI_SNAKE ) + { + missile[v2]._mitxoff += 2 * v6; + missile[v2]._mityoff += 2 * missile[v2]._miyvel; + GetMissilePos(v1); + a2 = missile[v2]._mix; + a3 = missile[v2]._miy; + missile[v2]._mitxoff -= missile[v2]._mixvel; + missile[v2]._mityoff -= missile[v2]._miyvel; + } + else + { + missile[v2]._mitxoff += v6; + missile[v2]._mityoff += missile[v2]._miyvel; + } + GetMissilePos(v1); + v7 = missile[v2]._mix; + y = missile[v2]._miy; + if ( !PosOkMonst(a1, missile[v2]._mix, missile[v2]._miy) || monster[v4]._mAi == AI_SNAKE && !PosOkMonst(a1, a2, a3) ) + { + MissToMonst(arglist, x, v10); +LABEL_12: + missile[v2]._miDelFlag = 1; + return; + } + v8 = monster[v4]._uniqtype == 0; + monster[v4]._mfutx = v7; + monster[v4]._moldx = v7; + dMonster[0][y + 112 * v7] = -1 - a1; + monster[v4]._mx = v7; + monster[v4]._mfuty = y; + monster[v4]._moldy = y; + monster[v4]._my = y; + if ( !v8 ) + ChangeLightXY(missile[v2]._mlid, v7, y); + MoveMissilePos(arglist); + PutMissile(arglist); +} + +void __fastcall mi_null_32(int i) +{ + int v1; // edi + int v2; // esi + int v3; // ebx + int v4; // edi + int v5; // eax + int v6; // eax + int v7; // ecx + int v8; // eax + int v9; // eax + int v10; // ebx + int v11; // eax + //int v12; // eax + int v13; // ecx + int v14; // ecx + unsigned char *v15; // eax + int v16; // [esp+Ch] [ebp-14h] + int arglist; // [esp+10h] [ebp-10h] + int x; // [esp+14h] [ebp-Ch] + int y; // [esp+18h] [ebp-8h] + int a3; // [esp+1Ch] [ebp-4h] + + v1 = i; + arglist = i; + GetMissilePos(i); + v2 = v1; + v3 = missile[v1]._mix; + a3 = missile[v1]._miy; + missile[v2]._mitxoff += missile[v1]._mixvel; + missile[v2]._mityoff += missile[v1]._miyvel; + GetMissilePos(v1); + v4 = missile[v1]._misource; + y = missile[v2]._miy; + v5 = monster[v4]._menemy; + x = missile[v2]._mix; + if ( monster[v4]._mFlags & 0x10 ) + { + v9 = v5; + v7 = monster[v9]._mx; + v8 = monster[v9]._my; + } + else + { + v6 = v5; + v7 = plr[v6].WorldX; + v8 = plr[v6].WorldY; + } + v16 = v8; + if ( (missile[v2]._mix != v3 || y != a3) + && (missile[v2]._miVar1 & 1 && (abs(v3 - v7) >= 4 || abs(a3 - v16) >= 4) || missile[v2]._miVar2 > 1) + && PosOkMonst(missile[v2]._misource, v3, a3) ) + { + MissToMonst(arglist, v3, a3); + v10 = v16; + missile[v2]._miDelFlag = 1; + } + else + { + v11 = x; + if ( monster[v4]._mFlags & 0x10 ) + v10 = dMonster[0][y + v11 * 112]; + else + v10 = dPlayer[v11][y]; + } + //_LOBYTE(v12) = PosOkMissile(x, y); + if ( !PosOkMissile(x, y) || v10 > 0 && !(missile[v2]._miVar1 & 1) ) + { + missile[v2]._mixvel = -missile[v2]._mixvel; + v13 = missile[v2]._mimfnum; + missile[v2]._miyvel = -missile[v2]._miyvel; + v14 = opposite[v13]; + missile[v2]._mimfnum = v14; + v15 = monster[v4].MType->Anims[1].Frames[v14]; + ++missile[v2]._miVar2; + missile[v2]._miAnimData = v15; + if ( v10 > 0 ) + missile[v2]._miVar1 |= 1u; + } + MoveMissilePos(arglist); + PutMissile(arglist); +} + +void __fastcall MI_FirewallC(int i) +{ + int v1; // esi + int v2; // edx + bool v3; // zf + int v4; // eax + int v5; // edi + int v6; // ecx + int v7; // ebx + int v8; // eax + int v9; // edi + int v10; // ecx + int v11; // ebx + int id; // [esp+Ch] [ebp-4h] + + v1 = i; + v2 = missile[i]._misource; + v3 = missile[i]._mirange == 1; + --missile[v1]._mirange; + id = v2; + if ( v3 ) + { + missile[v1]._miDelFlag = 1; + } + else + { + v4 = missile[v1]._miVar3; + v5 = missile[v1]._miVar1 + XDirAdd[v4]; + v6 = missile[v1]._miVar2; + v7 = v6 + YDirAdd[v4]; + if ( nMissileTable[dPiece[0][v6 + 112 * missile[v1]._miVar1]] + || missile[v1]._miVar8 + || v5 <= 0 + || v5 >= 112 + || v7 <= 0 + || v7 >= 112 ) + { + missile[v1]._miVar8 = 1; + } + else + { + AddMissile( + missile[v1]._miVar1, + v6, + missile[v1]._miVar1, + v6, + plr[v2]._pdir, + 5, + 0, + v2, + 0, + missile[v1]._mispllvl); + v2 = id; + missile[v1]._miVar1 = v5; + missile[v1]._miVar2 = v7; + } + v8 = missile[v1]._miVar4; + v9 = missile[v1]._miVar5 + XDirAdd[v8]; + v10 = missile[v1]._miVar6; + v11 = v10 + YDirAdd[v8]; + if ( nMissileTable[dPiece[0][v10 + 112 * missile[v1]._miVar5]] + || missile[v1]._miVar7 + || v9 <= 0 + || v9 >= 112 + || v11 <= 0 + || v11 >= 112 ) + { + missile[v1]._miVar7 = 1; + } + else + { + AddMissile( + missile[v1]._miVar5, + v10, + missile[v1]._miVar5, + v10, + plr[v2]._pdir, + 5, + 0, + v2, + 0, + missile[v1]._mispllvl); + missile[v1]._miVar5 = v9; + missile[v1]._miVar6 = v11; + } + } +} + +void __fastcall MI_Infra(int i) +{ + int v1; // eax + int *v2; // ecx + int v3; // esi + int v4; // ecx + + v1 = i; + v2 = &missile[i]._mirange; + v3 = --*v2; + v4 = missile[v1]._misource; + plr[missile[v1]._misource]._pInfraFlag = 1; + if ( !v3 ) + { + missile[v1]._miDelFlag = 1; + CalcPlrItemVals(v4, 1); + } +} + +void __fastcall MI_Apoca(int i) +{ + int v1; // esi + int v2; // edi + signed int v3; // eax + int v4; // ecx + int v5; // ebx + int id; // [esp+8h] [ebp-8h] + int v7; // [esp+Ch] [ebp-4h] + + v1 = i; + v2 = missile[i]._miVar2; + id = missile[i]._misource; + v3 = 0; + if ( v2 >= missile[i]._miVar3 ) + goto LABEL_18; + do + { + if ( v3 ) + break; + v4 = missile[v1]._miVar4; + v7 = missile[v1]._miVar4; + if ( v4 >= missile[v1]._miVar5 ) + { +LABEL_11: + missile[v1]._miVar4 = missile[v1]._miVar6; + } + else + { + v5 = v2 + 112 * v4; + while ( !v3 ) + { + if ( dMonster[0][v5] > 3 && !nSolidTable[dPiece[0][v5]] ) + { + AddMissile(v4, v2, v4, v2, plr[id]._pdir, 36, 0, id, missile[v1]._midam, 0); + v4 = v7; + v3 = 1; + } + ++v4; + v5 += 112; + v7 = v4; + if ( v4 >= missile[v1]._miVar5 ) + { + if ( v3 ) + break; + goto LABEL_11; + } + } + } + ++v2; + } + while ( v2 < missile[v1]._miVar3 ); + if ( v3 != 1 ) + { +LABEL_18: + missile[v1]._miDelFlag = 1; + } + else + { + missile[v1]._miVar2 = v2 - 1; + missile[v1]._miVar4 = v7; + } +} + +void __fastcall MI_Wave(int i) +{ + int v1; // esi + int v2; // ebx + int v3; // eax + int v4; // edi + int v5; // ecx + int v6; // eax + int v7; // ebx + int v8; // eax + int v9; // ebx + int v10; // eax + int v11; // ebx + bool v12; // zf + int v13; // [esp+Ch] [ebp-2Ch] + int v14; // [esp+10h] [ebp-28h] + int v15; // [esp+14h] [ebp-24h] + int v16; // [esp+14h] [ebp-24h] + signed int v17; // [esp+18h] [ebp-20h] + int *v18; // [esp+1Ch] [ebp-1Ch] + signed int v19; // [esp+20h] [ebp-18h] + int v20; // [esp+24h] [ebp-14h] + int v21; // [esp+24h] [ebp-14h] + int v22; // [esp+28h] [ebp-10h] + int j; // [esp+28h] [ebp-10h] + int id; // [esp+2Ch] [ebp-Ch] + int sx; // [esp+30h] [ebp-8h] + int sy; // [esp+34h] [ebp-4h] + int sya; // [esp+34h] [ebp-4h] + + v19 = 0; + v1 = i; + v17 = 0; + v2 = missile[i]._mix; + id = missile[i]._misource; + v14 = v2; + v20 = missile[i]._miy; + v3 = GetDirection(v2, v20, missile[i]._miVar1, missile[i]._miVar2); + v22 = ((_BYTE)v3 - 2) & 7; + v4 = v3; + v15 = ((_BYTE)v3 + 2) & 7; + v5 = YDirAdd[v3]; + v6 = XDirAdd[v3]; + v7 = v6 + v2; + sy = v5 + v20; + if ( !nMissileTable[dPiece[0][v5 + v20 + 112 * v7]] ) + { + v18 = &plr[id]._pdir; + AddMissile(v7, sy, v7 + v6, sy + v5, *v18, 14, 0, id, 0, missile[v1]._mispllvl); + v13 = v22; + sya = YDirAdd[v22] + sy; + v8 = v15; + sx = XDirAdd[v22] + v7; + v16 = v8 * 4; + v9 = XDirAdd[v8]; + v10 = v20 + YDirAdd[v4] + YDirAdd[v8]; + v11 = v14 + XDirAdd[v4] + v9; + v21 = 0; + for ( j = v10; v21 < (missile[v1]._mispllvl >> 1) + 2; ++v21 ) + { + if ( nMissileTable[dPiece[0][sya + 112 * sx]] || v19 || sx <= 0 || sx >= 112 || sya <= 0 || sya >= 112 ) + { + v19 = 1; + } + else + { + AddMissile(sx, sya, sx + XDirAdd[v4], sya + YDirAdd[v4], *v18, 14, 0, id, 0, missile[v1]._mispllvl); + sx += XDirAdd[v13]; + sya += YDirAdd[v13]; + v10 = j; + } + if ( nMissileTable[dPiece[0][v10 + 112 * v11]] || v17 || v11 <= 0 || v11 >= 112 || v10 <= 0 || v10 >= 112 ) + { + v17 = 1; + } + else + { + AddMissile(v11, v10, v11 + XDirAdd[v4], v10 + YDirAdd[v4], *v18, 14, 0, id, 0, missile[v1]._mispllvl); + v11 += *(int *)((char *)XDirAdd + v16); + j += *(int *)((char *)YDirAdd + v16); + v10 = j; + } + } + } + v12 = missile[v1]._mirange-- == 1; + if ( v12 ) + missile[v1]._miDelFlag = 1; +} + +void __fastcall MI_Nova(int i) +{ + int v1; // edi + int v2; // edx + int eax1; // eax + int v4; // ebx + unsigned char *v5; // esi + int v6; // eax + bool v7; // zf + int v8; // [esp+Ch] [ebp-18h] + int sy; // [esp+10h] [ebp-14h] + int id; // [esp+14h] [ebp-10h] + int v3; // [esp+18h] [ebp-Ch] + int midir; // [esp+1Ch] [ebp-8h] + signed int micaster; // [esp+20h] [ebp-4h] + + v1 = i; + v2 = 0; + eax1 = missile[i]._misource; + v4 = missile[i]._mix; + v3 = missile[i]._midam; + v8 = 0; + id = missile[i]._misource; + sy = missile[i]._miy; + if ( eax1 == -1 ) + { + midir = 0; + micaster = 1; + } + else + { + micaster = 0; + midir = plr[eax1]._pdir; + } + v5 = &vCrawlTable[0][7]; + do + { + v6 = *(v5 - 1); + if ( v2 != v6 || v8 != *v5 ) + { + AddMissile(v4, sy, v4 + v6, sy + *v5, midir, 4, micaster, id, v3, missile[v1]._mispllvl); + AddMissile(v4, sy, v4 - *(v5 - 1), sy - *v5, midir, 4, micaster, id, v3, missile[v1]._mispllvl); + AddMissile(v4, sy, v4 - *(v5 - 1), sy + *v5, midir, 4, micaster, id, v3, missile[v1]._mispllvl); + AddMissile(v4, sy, v4 + *(v5 - 1), sy - *v5, midir, 4, micaster, id, v3, missile[v1]._mispllvl); + v2 = *(v5 - 1); + v8 = *v5; + } + v5 += 30; + } + while ( (signed int)v5 < (signed int)&vCrawlTable[23][7] ); + v7 = missile[v1]._mirange-- == 1; + if ( v7 ) + missile[v1]._miDelFlag = 1; +} + +void __fastcall MI_Blodboil(int i) +{ + missile[i]._miDelFlag = 1; +} + +void __fastcall MI_Flame(int i) +{ + int v1; // ebx + int v2; // esi + int v3; // ST0C_4 + int v4; // edx + int v5; // edi + int v6; // ST08_4 + int v7; // eax + int v8; // eax + int v9; // ecx + + v1 = i; + v2 = i; + v3 = missile[i]._miy; + v4 = missile[i]._midam; + --missile[v2]._mirange; + v5 = missile[i]._mirange; + v6 = missile[i]._mix; + --missile[v2]._miVar2; + CheckMissileCol(i, v4, v4, 1, v6, v3, 0); + if ( !missile[v2]._mirange && missile[v2]._miHitFlag == 1 ) + missile[v2]._mirange = v5; + v7 = missile[v2]._miVar2; + if ( !v7 ) + missile[v2]._miAnimFrame = 20; + if ( v7 <= 0 ) + { + v8 = missile[v2]._miAnimFrame; + if ( v8 > 11 ) + v8 = 24 - v8; + ChangeLight(missile[v2]._mlid, missile[v2]._mix, missile[v2]._miy, v8); + } + if ( !missile[v2]._mirange ) + { + v9 = missile[v2]._mlid; + missile[v2]._miDelFlag = 1; + AddUnLight(v9); + } + if ( missile[v2]._miVar2 <= 0 ) + PutMissile(v1); +} + +void __fastcall MI_Flamec(int i) +{ + int v1; // edi + int v2; // esi + int v3; // eax + int v4; // ebx + int v5; // ecx + int v6; // edx + int v7; // eax + int v8; // eax + + v1 = i; + v2 = i; + v3 = missile[i]._mixvel; + --missile[v2]._mirange; + missile[v2]._mitxoff += v3; + v4 = missile[i]._misource; + missile[v2]._mityoff += missile[i]._miyvel; + GetMissilePos(i); + v5 = missile[v2]._mix; + if ( v5 != missile[v2]._miVar1 || missile[v2]._miy != missile[v2]._miVar2 ) + { + v6 = missile[v2]._miy; + v7 = dPiece[0][v6 + 112 * v5]; + if ( nMissileTable[v7] ) + { + missile[v2]._mirange = 0; + } + else + { + _LOBYTE(v7) = missile[v2]._micaster; + AddMissile( + v5, + v6, + missile[v2]._misx, + missile[v2]._misy, + v1, + 48, + v7, + v4, + missile[v2]._miVar3, + missile[v2]._mispllvl); + } + v8 = missile[v2]._mix; + ++missile[v2]._miVar3; + missile[v2]._miVar1 = v8; + missile[v2]._miVar2 = missile[v2]._miy; + } + if ( !missile[v2]._mirange || missile[v2]._miVar3 == 3 ) + missile[v2]._miDelFlag = 1; +} + +void __fastcall MI_Cbolt(int i) +{ + int v1; // esi + bool v2; // zf + int v3; // eax + int v4; // edx + int v5; // eax + int v6; // ecx + int v7; // ecx + int v8; // ecx + int v9; // ecx + int bpath[16]; // [esp+Ch] [ebp-44h] + int ia; // [esp+4Ch] [ebp-4h] + + ia = i; + v1 = i; + --missile[v1]._mirange; + v2 = _LOBYTE(missile[i]._miAnimType) == 3; + bpath[0] = -1; + bpath[1] = 0; + bpath[2] = 1; + bpath[3] = -1; + bpath[4] = 0; + bpath[5] = 1; + bpath[6] = -1; + bpath[7] = -1; + bpath[8] = 0; + bpath[9] = 0; + bpath[10] = 1; + bpath[11] = 1; + bpath[12] = 0; + bpath[13] = 1; + bpath[14] = -1; + bpath[15] = 0; + if ( !v2 ) + { + v3 = missile[v1]._miVar3; + if ( v3 ) + { + missile[v1]._miVar3 = v3 - 1; + } + else + { + v4 = missile[v1]._mirnd; + v5 = (missile[v1]._miVar2 + bpath[v4]) & 7; + missile[v1]._mirnd = ((_BYTE)v4 + 1) & 0xF; + GetMissileVel( + ia, + missile[v1]._mix, + missile[v1]._miy, + missile[v1]._mix + XDirAdd[v5], + missile[v1]._miy + YDirAdd[v5], + 8); + missile[v1]._miVar3 = 16; + } + v6 = ia; + missile[v1]._mitxoff += missile[v1]._mixvel; + missile[v1]._mityoff += missile[v1]._miyvel; + GetMissilePos(v6); + CheckMissileCol(ia, missile[v1]._midam, missile[v1]._midam, 0, missile[v1]._mix, missile[v1]._miy, 0); + if ( missile[v1]._miHitFlag == 1 ) + { + v7 = ia; + missile[v1]._miVar1 = 8; + missile[v1]._mimfnum = 0; + missile[v1]._mixoff = 0; + missile[v1]._miyoff = 0; + SetMissAnim(v7, MFILE_LGHNING); + v8 = ia; + missile[v1]._mirange = missile[v1]._miAnimLen; + GetMissilePos(v8); + } + ChangeLight(missile[v1]._mlid, missile[v1]._mix, missile[v1]._miy, missile[v1]._miVar1); + } + if ( !missile[v1]._mirange ) + { + v9 = missile[v1]._mlid; + missile[v1]._miDelFlag = 1; + AddUnLight(v9); + } + PutMissile(ia); +} + +void __fastcall MI_Hbolt(int i) +{ + int v1; // edi + int v2; // esi + int v3; // eax + int v4; // edx + int v5; // ecx + int v6; // ST10_4 + int v7; // ecx + + v1 = i; + v2 = i; + --missile[v2]._mirange; + if ( _LOBYTE(missile[i]._miAnimType) == 28 ) + { + ChangeLight(missile[v2]._mlid, missile[v2]._mix, missile[v2]._miy, missile[v2]._miAnimFrame + 7); + if ( !missile[v2]._mirange ) + { + v7 = missile[v2]._mlid; + missile[v2]._miDelFlag = 1; + AddUnLight(v7); + } + } + else + { + missile[v2]._mitxoff += missile[v2]._mixvel; + missile[v2]._mityoff += missile[v2]._miyvel; + GetMissilePos(i); + v3 = missile[v2]._mix; + if ( v3 != missile[v2]._misx || missile[v2]._miy != missile[v2]._misy ) + CheckMissileCol(v1, missile[v2]._midam, missile[v2]._midam, 0, v3, missile[v2]._miy, 0); + if ( missile[v2]._mirange ) + { + v4 = missile[v2]._mix; + if ( v4 != missile[v2]._miVar1 || missile[v2]._miy != missile[v2]._miVar2 ) + { + v5 = missile[v2]._mlid; + missile[v2]._miVar1 = v4; + v6 = missile[v2]._miy; + missile[v2]._miVar2 = v6; + ChangeLight(v5, v4, v6, 8); + } + } + else + { + missile[v2]._mitxoff -= missile[v2]._mixvel; + missile[v2]._mityoff -= missile[v2]._miyvel; + GetMissilePos(v1); + missile[v2]._mimfnum = 0; + SetMissAnim(v1, MFILE_HOLYEXPL); + missile[v2]._mirange = missile[v2]._miAnimLen - 1; + } + } + PutMissile(v1); +} + +void __fastcall MI_Element(int i) +{ + int v1; // esi + int v2; // edi + int v3; // eax + int v4; // ebx + int v5; // ebx + int v6; // ecx + int v7; // ebx + int v8; // eax + int v9; // edi + int v10; // eax + int v11; // edi + int v12; // ecx + int ty; // [esp+Ch] [ebp-18h] + int tya; // [esp+Ch] [ebp-18h] + //int tyb; // [esp+Ch] [ebp-18h] + int my; // [esp+10h] [ebp-14h] + //int mya; // [esp+10h] [ebp-14h] + //int myb; // [esp+10h] [ebp-14h] + int fx; // [esp+14h] [ebp-10h] + //int fxa; // [esp+14h] [ebp-10h] + int fy; // [esp+18h] [ebp-Ch] + int ia; // [esp+1Ch] [ebp-8h] + int y; // [esp+20h] [ebp-4h] + int ya; // [esp+20h] [ebp-4h] + + v1 = i; + ia = i; + --missile[v1]._mirange; + v2 = missile[i]._midam; + ty = missile[i]._misource; + if ( _LOBYTE(missile[i]._miAnimType) == 19 ) + { + v3 = missile[i]._misource; + v4 = missile[v1]._mix; + y = missile[v1]._miy; + fx = plr[v3].WorldX; + fy = plr[v3].WorldY; + ChangeLight(missile[v1]._mlid, v4, y, missile[v1]._miAnimFrame); + if ( !CheckBlock(fx, fy, v4, y) ) + CheckMissileCol(ia, v2, v2, 1, v4, y, 1); + my = y + 1; + if ( !CheckBlock(fx, fy, v4, y + 1) ) + CheckMissileCol(ia, v2, v2, 1, v4, my, 1); + tya = y - 1; + if ( !CheckBlock(fx, fy, v4, y - 1) ) + CheckMissileCol(ia, v2, v2, 1, v4, tya, 1); + if ( !CheckBlock(fx, fy, v4 + 1, y) ) + CheckMissileCol(ia, v2, v2, 1, v4 + 1, y, 1); /* check x/y */ + if ( !CheckBlock(fx, fy, v4 + 1, tya) ) + CheckMissileCol(ia, v2, v2, 1, v4 + 1, tya, 1); + if ( !CheckBlock(fx, fy, v4 + 1, my) ) + CheckMissileCol(ia, v2, v2, 1, v4 + 1, my, 1); + v5 = v4 - 1; + if ( !CheckBlock(fx, fy, v5, y) ) + CheckMissileCol(ia, v2, v2, 1, v5, y, 1); + if ( !CheckBlock(fx, fy, v5, my) ) + CheckMissileCol(ia, v2, v2, 1, v5, my, 1); + if ( !CheckBlock(fx, fy, v5, tya) ) + CheckMissileCol(ia, v2, v2, 1, v5, tya, 1); + if ( !missile[v1]._mirange ) + { + v6 = missile[v1]._mlid; + missile[v1]._miDelFlag = 1; + AddUnLight(v6); + } + } + else + { + missile[v1]._mitxoff += missile[v1]._mixvel; + missile[v1]._mityoff += missile[v1]._miyvel; + GetMissilePos(i); + v7 = missile[v1]._mix; + ya = missile[v1]._miy; + CheckMissileCol(ia, v2, v2, 0, missile[v1]._mix, ya, 0); + if ( !missile[v1]._miVar3 && v7 == missile[v1]._miVar4 && ya == missile[v1]._miVar5 ) + missile[v1]._miVar3 = 1; + if ( missile[v1]._miVar3 == 1 ) + { + missile[v1]._miVar3 = 2; + missile[v1]._mirange = 255; + v8 = FindClosest(v7, ya, 19); + if ( v8 <= 0 ) + { + v11 = plr[ty]._pdir; + SetMissDir(ia, plr[ty]._pdir); + GetMissileVel(ia, v7, ya, v7 + XDirAdd[v11], ya + YDirAdd[v11], 16); + } + else + { + v9 = v8; + v10 = GetDirection8(v7, ya, monster[v8]._mx, monster[v8]._my); + SetMissDir(ia, v10); + GetMissileVel(ia, v7, ya, monster[v9]._mx, monster[v9]._my, 16); + } + } + if ( v7 != missile[v1]._miVar1 || ya != missile[v1]._miVar2 ) + { + missile[v1]._miVar2 = ya; + v12 = missile[v1]._mlid; + missile[v1]._miVar1 = v7; + ChangeLight(v12, v7, ya, 8); + } + if ( !missile[v1]._mirange ) + { + missile[v1]._mimfnum = 0; + SetMissAnim(ia, MFILE_BIGEXP); + missile[v1]._mirange = missile[v1]._miAnimLen - 1; + } + } + PutMissile(ia); +} + +void __fastcall MI_Bonespirit(int i) +{ + int v1; // ebx + int v2; // esi + int v3; // eax + int v4; // ecx + int v5; // ecx + int v6; // edi + int v7; // ebx + int v8; // eax + int v9; // edi + int v10; // ST14_4 + int v11; // ST10_4 + int v12; // eax + int v13; // ST24_4 + int v14; // ecx + int v16; // [esp+Ch] [ebp-10h] + int maxdam; // [esp+10h] [ebp-Ch] + int y1; // [esp+14h] [ebp-8h] + int ia; // [esp+18h] [ebp-4h] + + v1 = i; + v2 = i; + ia = i; + v3 = missile[i]._midam; + --missile[v2]._mirange; + maxdam = v3; + v16 = missile[i]._misource; + if ( missile[i]._mimfnum == 8 ) + { + ChangeLight(missile[v2]._mlid, missile[v2]._mix, missile[v2]._miy, missile[v2]._miAnimFrame); + if ( !missile[v2]._mirange ) + { + v4 = missile[v2]._mlid; + missile[v2]._miDelFlag = 1; + AddUnLight(v4); + } + v5 = v1; + } + else + { + missile[v2]._mitxoff += missile[v2]._mixvel; + missile[v2]._mityoff += missile[v2]._miyvel; + GetMissilePos(i); + v6 = missile[v2]._miy; + v7 = missile[v2]._mix; + y1 = missile[v2]._miy; + CheckMissileCol(ia, maxdam, maxdam, 0, missile[v2]._mix, v6, 0); + if ( !missile[v2]._miVar3 && v7 == missile[v2]._miVar4 && v6 == missile[v2]._miVar5 ) + missile[v2]._miVar3 = 1; + if ( missile[v2]._miVar3 == 1 ) + { + missile[v2]._miVar3 = 2; + missile[v2]._mirange = 255; + v8 = FindClosest(v7, v6, 19); + if ( v8 <= 0 ) + { + v13 = plr[v16]._pdir; + SetMissDir(ia, v13); + GetMissileVel(ia, v7, v6, v7 + XDirAdd[v13], v6 + YDirAdd[v13], 16); + } + else + { + v9 = v8; + v10 = monster[v8]._my; + v11 = monster[v8]._mx; + missile[v2]._midam = monster[v8]._mhitpoints >> 7; + v12 = GetDirection8(v7, y1, v11, v10); + SetMissDir(ia, v12); + GetMissileVel(ia, v7, y1, monster[v9]._mx, monster[v9]._my, 16); + v6 = y1; + } + } + if ( v7 != missile[v2]._miVar1 || v6 != missile[v2]._miVar2 ) + { + v14 = missile[v2]._mlid; + missile[v2]._miVar1 = v7; + missile[v2]._miVar2 = v6; + ChangeLight(v14, v7, v6, 8); + } + if ( !missile[v2]._mirange ) + { + SetMissDir(ia, 8); + missile[v2]._mirange = 7; + } + v5 = ia; + } + PutMissile(v5); +} + +void __fastcall MI_ResurrectBeam(int i) +{ + int v1; // eax + bool v2; // zf + + v1 = i; + v2 = missile[i]._mirange == 1; + --missile[v1]._mirange; + if ( v2 ) + missile[v1]._miDelFlag = 1; + PutMissile(i); +} + +void __fastcall MI_Rportal(int i) +{ + int v1; // esi + int v2; // eax + int v3; // ecx + int ExpLight[17]; // [esp+8h] [ebp-48h] + int ia; // [esp+4Ch] [ebp-4h] + + v1 = i; + ExpLight[14] = 15; + ExpLight[15] = 15; + ExpLight[16] = 15; + v2 = missile[i]._mirange; + ia = i; + ExpLight[0] = 1; + ExpLight[1] = 2; + ExpLight[2] = 3; + ExpLight[3] = 4; + ExpLight[4] = 5; + ExpLight[5] = 6; + ExpLight[6] = 7; + ExpLight[7] = 8; + ExpLight[8] = 9; + ExpLight[9] = 10; + ExpLight[10] = 11; + ExpLight[11] = 12; + ExpLight[12] = 13; + ExpLight[13] = 14; + if ( v2 > 1 ) + missile[v1]._mirange = v2 - 1; + if ( missile[v1]._mirange == missile[v1]._miVar1 ) + SetMissDir(i, 1); + if ( currlevel && missile[v1]._mimfnum != 1 ) + { + if ( !missile[v1]._mirange ) + { +LABEL_12: + v3 = missile[v1]._mlid; + missile[v1]._miDelFlag = 1; + AddUnLight(v3); + goto LABEL_13; + } + if ( !missile[v1]._miVar2 ) + missile[v1]._mlid = AddLight(missile[v1]._mix, missile[v1]._miy, 1); + ChangeLight(missile[v1]._mlid, missile[v1]._mix, missile[v1]._miy, ExpLight[missile[v1]._miVar2]); + ++missile[v1]._miVar2; + } + if ( !missile[v1]._mirange ) + goto LABEL_12; +LABEL_13: + PutMissile(ia); +} + +void __cdecl ProcessMissiles() +{ + int v0; // eax + int i; // edx + int v2; // ecx + int v3; // edx + int v4; // edi + int v5; // esi + int *v6; // eax + int v7; // ecx + int *v8; // eax + int v9; // esi + int v10; // esi + int v11; // edx + + v0 = nummissiles; + for ( i = 0; i < v0; dMissile[0][v2] = 0 ) + { + v2 = 112 * missile[missileactive[i]]._mix + missile[missileactive[i]]._miy; + dFlags[0][v2] &= 0xFEu; + ++i; + } + v3 = 0; + while ( v3 < v0 ) + { + if ( missile[missileactive[v3]]._miDelFlag ) + { + DeleteMissile(missileactive[v3], v3); + v0 = nummissiles; + v3 = 0; + } + else + { + ++v3; + } + } + v4 = 0; + MissilePreFlag = 0; + ManashieldFlag = 0; + if ( v0 > 0 ) + { + do + { + v5 = missileactive[v4]; + missiledata[missile[v5]._mitype].mProc(missileactive[v4]); + if ( !(missile[v5]._miAnimFlags & 2) ) + { + v6 = &missile[v5]._miAnimCnt; + ++*v6; + if ( missile[v5]._miAnimCnt >= missile[v5]._miAnimDelay ) + { + v7 = missile[v5]._miAnimAdd; + *v6 = 0; + v8 = &missile[v5]._miAnimFrame; + v9 = missile[v5]._miAnimLen; + *v8 += v7; + if ( *v8 > v9 ) + *v8 = 1; + if ( *v8 < 1 ) + *v8 = v9; + } + } + v0 = nummissiles; + ++v4; + } + while ( v4 < nummissiles ); + if ( ManashieldFlag ) + { + v10 = 0; + if ( nummissiles > 0 ) + { + do + { + if ( missile[missileactive[v10]]._mitype == MIS_MANASHIELD ) + { + MI_Manashield(missileactive[v10]); + v0 = nummissiles; + } + ++v10; + } + while ( v10 < v0 ); + } + } + } + v11 = 0; + while ( v11 < v0 ) + { + if ( missile[missileactive[v11]]._miDelFlag ) + { + DeleteMissile(missileactive[v11], v11); + v0 = nummissiles; + v11 = 0; + } + else + { + ++v11; + } + } +} +// 64CCD4: using guessed type int MissilePreFlag; + +void __cdecl missiles_process_charge() +{ + int v0; // ebx + int i; // edi + int v2; // ecx + int v3; // esi + bool v4; // zf + CMonster *v5; // eax + char v6; // dl + AnimStruct *v7; // eax + + v0 = nummissiles; + for ( i = 0; i < v0; ++i ) + { + v2 = missileactive[i]; + v3 = missile[v2]._mimfnum; + v4 = missile[v2]._mitype == MIS_RHINO; + missile[v2]._miAnimData = misfiledata[0].mAnimData[v3 + 59 * _LOBYTE(missile[v2]._miAnimType)]; + if ( v4 ) + { + v5 = monster[missile[v2]._misource].MType; + v6 = v5->mtype; + if ( v5->mtype < MT_HORNED || v6 > MT_OBLORD ) + { + if ( v6 < MT_NSNAKE || v6 > MT_GSNAKE ) + v7 = &v5->Anims[1]; + else + v7 = &v5->Anims[2]; + } + else + { + v7 = &v5->Anims[5]; + } + missile[v2]._miAnimData = v7->Frames[v3]; + } + } +} + +void __fastcall ClearMissileSpot(int mi) +{ + dFlags[missile[mi]._mix][missile[mi]._miy] &= 0xFE; + dMissile[missile[mi]._mix][missile[mi]._miy] = 0; +} diff --git a/Source/missiles.h b/Source/missiles.h new file mode 100644 index 000000000..3cde16641 --- /dev/null +++ b/Source/missiles.h @@ -0,0 +1,155 @@ +//HEADER_GOES_HERE +#ifndef __MISSILES_H__ +#define __MISSILES_H__ + +extern int missileactive[MAXMISSILES]; +extern int missileavail[MAXMISSILES]; +extern MissileStruct missile[MAXMISSILES]; +extern int nummissiles; // idb +extern int ManashieldFlag; +extern ChainStruct chain[MAXMISSILES]; +extern int MissilePreFlag; // weak +extern int numchains; // weak + +void __fastcall GetDamageAmt(int i, int *mind, int *maxd); +int __fastcall CheckBlock(int fx, int fy, int tx, int ty); +int __fastcall FindClosest(int sx, int sy, int rad); +int __fastcall GetSpellLevel(int id, int sn); +int __fastcall GetDirection8(int x1, int y1, int x2, int y2); +int __fastcall GetDirection16(int x1, int y1, int x2, int y2); +void __fastcall DeleteMissile(int mi, int i); +void __fastcall GetMissileVel(int i, int sx, int sy, int dx, int dy, int v); +void __fastcall PutMissile(int i); +void __fastcall GetMissilePos(int i); +void __fastcall MoveMissilePos(int i); +BOOL __fastcall MonsterTrapHit(int m, int mindam, int maxdam, int dist, int t, int shift); +bool __fastcall MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, int shift); +bool __fastcall PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, int shift, int earflag); +bool __fastcall Plr2PlrMHit(int pnum, int p, int mindam, int maxdam, int dist, int mtype, int shift); +void __fastcall CheckMissileCol(int i, int mindam, int maxdam, bool shift, int mx, int my, int nodel); +void __fastcall SetMissAnim(int mi, int animtype); +void __fastcall SetMissDir(int mi, int dir); +void __fastcall LoadMissileGFX(BYTE mi); +void __cdecl InitMissileGFX(); +void __fastcall FreeMissileGFX(int mi); +void __cdecl FreeMissiles(); +void __cdecl FreeMissiles2(); +void __cdecl InitMissiles(); +void __fastcall AddLArrow(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddArrow(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall GetVileMissPos(int mi, int dx, int dy); +void __fastcall AddRndTeleport(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddFirebolt(int mi, int sx, int sy, int dx, int dy, int midir, int micaster, int id, int dam); +void __fastcall AddMagmaball(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall miss_null_33(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddTeleport(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddLightball(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddFirewall(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddFireball(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddLightctrl(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddLightning(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddMisexp(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddWeapexp(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +bool __fastcall CheckIfTrig(int x, int y); +void __fastcall AddTown(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddFlash(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddFlash2(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddManashield(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddFiremove(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddGuardian(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddChain(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall miss_null_11(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall miss_null_12(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall miss_null_13(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddRhino(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall miss_null_32(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddFlare(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddAcid(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall miss_null_1D(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddAcidpud(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddStone(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddGolem(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddEtherealize(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall miss_null_1F(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall miss_null_23(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddBoom(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddHeal(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddHealOther(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddElement(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddIdentify(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddFirewallC(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddInfra(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddWave(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddNova(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddRepair(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddRecharge(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddDisarm(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddApoca(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddFlame(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddFlamec(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddCbolt(int mi, int sx, int sy, int dx, int dy, int midir, int micaster, int id, int dam); +void __fastcall AddHbolt(int mi, int sx, int sy, int dx, int dy, int midir, int micaster, int id, int dam); +void __fastcall AddResurrect(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddResurrectBeam(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddTelekinesis(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddBoneSpirit(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddRportal(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +void __fastcall AddDiabApoca(int mi, int sx, int sy, int dx, int dy, int midir, int mienemy, int id, int dam); +int __fastcall AddMissile(int sx, int sy, int v1, int v2, int midir, int mitype, int micaster, int id, int v3, int spllvl); +int __fastcall Sentfire(int i, int sx, int sy); +void __fastcall MI_Dummy(int i); +void __fastcall MI_Golem(int i); +void __fastcall MI_SetManashield(int i); +void __fastcall MI_LArrow(int i); +void __fastcall MI_Arrow(int i); +void __fastcall MI_Firebolt(int i); +void __fastcall MI_Lightball(int i); +void __fastcall mi_null_33(int i); +void __fastcall MI_Acidpud(int i); +void __fastcall MI_Firewall(int i); +void __fastcall MI_Fireball(int i); +void __fastcall MI_Lightctrl(int i); +void __fastcall MI_Lightning(int i); +void __fastcall MI_Town(int i); +void __fastcall MI_Flash(int i); +void __fastcall MI_Flash2(int i); +void __fastcall MI_Manashield(int i); +void __fastcall MI_Etherealize(int i); +void __fastcall MI_Firemove(int i); +void __fastcall MI_Guardian(int i); +void __fastcall MI_Chain(int i); +void __fastcall mi_null_11(int i); +void __fastcall MI_Weapexp(int i); +void __fastcall MI_Misexp(int i); +void __fastcall MI_Acidsplat(int i); +void __fastcall MI_Teleport(int i); +void __fastcall MI_Stone(int i); +void __fastcall MI_Boom(int i); +void __fastcall MI_Rhino(int i); +void __fastcall mi_null_32(int i); +void __fastcall MI_FirewallC(int i); +void __fastcall MI_Infra(int i); +void __fastcall MI_Apoca(int i); +void __fastcall MI_Wave(int i); +void __fastcall MI_Nova(int i); +void __fastcall MI_Blodboil(int i); +void __fastcall MI_Flame(int i); +void __fastcall MI_Flamec(int i); +void __fastcall MI_Cbolt(int i); +void __fastcall MI_Hbolt(int i); +void __fastcall MI_Element(int i); +void __fastcall MI_Bonespirit(int i); +void __fastcall MI_ResurrectBeam(int i); +void __fastcall MI_Rportal(int i); +void __cdecl ProcessMissiles(); +void __cdecl missiles_process_charge(); +void __fastcall ClearMissileSpot(int mi); + +/* rdata */ + +extern MissileData missiledata[68]; +extern MisFileData misfiledata[47]; +extern int XDirAdd[8]; +extern int YDirAdd[8]; + +#endif /* __MISSILES_H__ */ diff --git a/Source/monster.cpp b/Source/monster.cpp new file mode 100644 index 000000000..286c2a923 --- /dev/null +++ b/Source/monster.cpp @@ -0,0 +1,8865 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +// Tracks which missile files are already loaded +int MissileFileFlag; + +int monster_cpp_init_value; // weak +int monstkills[MAXMONSTERS]; +int monstactive[MAXMONSTERS]; +int nummonsters; +int sgbSaveSoundOn; // weak +MonsterStruct monster[MAXMONSTERS]; +int totalmonsters; // weak +CMonster Monsters[16]; +// int END_Monsters_17; // weak +int monstimgtot; // weak +int uniquetrans; +int nummtypes; +#endif + +const int monster_inf = 0x7F800000; // weak +const char plr2monst[9] = { 0, 5, 3, 7, 1, 4, 6, 0, 2 }; +const unsigned char counsmiss[4] = { MIS_FIREBOLT, MIS_CBOLT, MIS_LIGHTCTRL, MIS_FIREBALL }; + +/* data */ + +MonsterData monsterdata[112] = +{ + { 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", 0, "Monsters\\Zombie\\Zombie%c%i.WAV", 0, 0, NULL, { 11, 24, 12, 6, 16, 0 }, { 4, 0, 0, 0, 0, 0 }, "Zombie", 1, 3, 1, 4, 7, AI_ZOMBIE, 0, 0, 10, 8, 2, 5, 0, 0, 0, 0, 5, MC_UNDEAD, 72, 72, 0, 3, 54 }, + { 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", 0, "Monsters\\Zombie\\Zombie%c%i.WAV", 0, 1, "Monsters\\Zombie\\Bluered.TRN", { 11, 24, 12, 6, 16, 0 }, { 4, 0, 0, 0, 0, 0 }, "Ghoul", 2, 4, 2, 7, 11, AI_ZOMBIE, 0, 1, 10, 8, 3, 10, 0, 0, 0, 0, 10, MC_UNDEAD, 72, 72, 0, 3, 58 }, + { 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", 0, "Monsters\\Zombie\\Zombie%c%i.WAV", 0, 1, "Monsters\\Zombie\\Grey.TRN", { 11, 24, 12, 6, 16, 0 }, { 4, 0, 0, 0, 0, 0 }, "Rotting Carcass", 2, 6, 4, 15, 25, AI_ZOMBIE, 0, 2, 25, 8, 5, 15, 0, 0, 0, 0, 15, MC_UNDEAD, 72, 74, 0, 3, 136 }, + { 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", 0, "Monsters\\Zombie\\Zombie%c%i.WAV", 0, 1, "Monsters\\Zombie\\Yellow.TRN", { 11, 24, 12, 6, 16, 0 }, { 4, 0, 0, 0, 0, 0 }, "Black Death", 4, 8, 6, 25, 40, AI_ZOMBIE, 0, 3, 30, 8, 6, 22, 0, 0, 0, 0, 20, MC_UNDEAD, 72, 76, 0, 3, 240 }, + { 128, 543, "Monsters\\FalSpear\\Phall%c.CL2", 1, "Monsters\\FalSpear\\Phall%c%i.WAV", 1, 1, "Monsters\\FalSpear\\FallenT.TRN", { 11, 11, 13, 11, 18, 13 }, { 3, 0, 0, 0, 0, 0 }, "Fallen One", 1, 3, 1, 1, 4, AI_FALLEN, 0, 0, 15, 7, 1, 3, 0, 5, 0, 0, 0, MC_ANIMAL, 0, 0, 0, 3, 46 }, + { 128, 543, "Monsters\\FalSpear\\Phall%c.CL2", 1, "Monsters\\FalSpear\\Phall%c%i.WAV", 1, 1, "Monsters\\FalSpear\\Dark.TRN", { 11, 11, 13, 11, 18, 13 }, { 3, 0, 0, 0, 0, 0 }, "Carver", 2, 5, 3, 4, 8, AI_FALLEN, 0, 2, 20, 7, 2, 5, 0, 5, 0, 0, 5, MC_ANIMAL, 0, 0, 0, 3, 80 }, + { 128, 543, "Monsters\\FalSpear\\Phall%c.CL2", 1, "Monsters\\FalSpear\\Phall%c%i.WAV", 1, 0, NULL, { 11, 11, 13, 11, 18, 13 }, { 3, 0, 0, 0, 0, 0 }, "Devil Kin", 3, 7, 5, 12, 24, AI_FALLEN, 0, 2, 25, 7, 3, 7, 0, 5, 0, 0, 10, MC_ANIMAL, 0, 2, 0, 3, 155 }, + { 128, 543, "Monsters\\FalSpear\\Phall%c.CL2", 1, "Monsters\\FalSpear\\Phall%c%i.WAV", 1, 1, "Monsters\\FalSpear\\Blue.TRN", { 11, 11, 13, 11, 18, 13 }, { 3, 0, 0, 0, 0, 0 }, "Dark One", 5, 9, 7, 20, 36, AI_FALLEN, 0, 3, 30, 7, 4, 8, 0, 5, 0, 0, 15, MC_ANIMAL, 64, 68, 0, 3, 255 }, + { 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", 1, "Monsters\\SkelAxe\\SklAx%c%i.WAV", 0, 1, "Monsters\\SkelAxe\\White.TRN", { 12, 8, 13, 6, 17, 16 }, { 5, 0, 0, 0, 0, 0 }, "Skeleton", 1, 3, 1, 2, 4, AI_SKELSD, 0, 0, 20, 8, 1, 4, 0, 0, 0, 0, 0, MC_UNDEAD, 72, 72, 0, 3, 64 }, + { 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", 1, "Monsters\\SkelAxe\\SklAx%c%i.WAV", 0, 1, "Monsters\\SkelAxe\\Skelt.TRN", { 12, 8, 13, 6, 17, 16 }, { 4, 0, 0, 0, 0, 0 }, "Corpse Axe", 2, 5, 2, 4, 7, AI_SKELSD, 0, 1, 25, 8, 3, 5, 0, 0, 0, 0, 0, MC_UNDEAD, 72, 72, 0, 3, 68 }, + { 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", 1, "Monsters\\SkelAxe\\SklAx%c%i.WAV", 0, 0, NULL, { 12, 8, 13, 6, 17, 16 }, { 2, 0, 0, 0, 0, 0 }, "Burning Dead", 2, 6, 4, 8, 12, AI_SKELSD, 0, 2, 30, 8, 3, 7, 0, 0, 0, 0, 5, MC_UNDEAD, 74, 88, 0, 3, 154 }, + { 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", 1, "Monsters\\SkelAxe\\SklAx%c%i.WAV", 0, 1, "Monsters\\SkelAxe\\Black.TRN", { 12, 8, 13, 6, 17, 16 }, { 3, 0, 0, 0, 0, 0 }, "Horror", 4, 8, 6, 12, 20, AI_SKELSD, 0, 3, 35, 8, 4, 9, 0, 0, 0, 0, 15, MC_UNDEAD, 76, 76, 0, 3, 264 }, + { 128, 623, "Monsters\\FalSword\\Fall%c.CL2", 1, "Monsters\\FalSword\\Fall%c%i.WAV", 1, 1, "Monsters\\FalSword\\FallenT.TRN", { 12, 12, 13, 11, 14, 15 }, { 3, 0, 0, 0, 0, 0 }, "Fallen One", 1, 3, 1, 2, 5, AI_FALLEN, 0, 0, 15, 8, 1, 4, 0, 5, 0, 0, 10, MC_ANIMAL, 0, 0, 0, 3, 52 }, + { 128, 623, "Monsters\\FalSword\\Fall%c.CL2", 1, "Monsters\\FalSword\\Fall%c%i.WAV", 1, 1, "Monsters\\FalSword\\Dark.TRN", { 12, 12, 13, 11, 14, 15 }, { 3, 0, 0, 0, 0, 0 }, "Carver", 2, 5, 3, 5, 9, AI_FALLEN, 0, 1, 20, 8, 2, 7, 0, 5, 0, 0, 15, MC_ANIMAL, 0, 0, 0, 3, 90 }, + { 128, 623, "Monsters\\FalSword\\Fall%c.CL2", 1, "Monsters\\FalSword\\Fall%c%i.WAV", 1, 0, NULL, { 12, 12, 13, 11, 14, 15 }, { 3, 0, 0, 0, 0, 0 }, "Devil Kin", 3, 7, 5, 16, 24, AI_FALLEN, 0, 2, 25, 8, 4, 10, 0, 5, 0, 0, 20, MC_ANIMAL, 0, 2, 0, 3, 180 }, + { 128, 623, "Monsters\\FalSword\\Fall%c.CL2", 1, "Monsters\\FalSword\\Fall%c%i.WAV", 1, 1, "Monsters\\FalSword\\Blue.TRN", { 12, 12, 13, 11, 14, 15 }, { 3, 0, 0, 0, 0, 0 }, "Dark One", 5, 9, 7, 24, 36, AI_FALLEN, 0, 3, 30, 8, 4, 12, 0, 5, 0, 0, 25, MC_ANIMAL, 64, 68, 0, 3, 280 }, + { 128, 410, "Monsters\\Scav\\Scav%c.CL2", 1, "Monsters\\Scav\\Scav%c%i.WAV", 0, 0, NULL, { 12, 8, 12, 6, 20, 11 }, { 2, 0, 0, 0, 0, 0 }, "Scavenger", 1, 4, 2, 3, 6, AI_SCAV, 0, 0, 20, 7, 1, 5, 0, 0, 0, 0, 10, MC_ANIMAL, 0, 2, 0, 3, 80 }, + { 128, 410, "Monsters\\Scav\\Scav%c.CL2", 1, "Monsters\\Scav\\Scav%c%i.WAV", 0, 1, "Monsters\\Scav\\ScavBr.TRN", { 12, 8, 12, 6, 20, 11 }, { 2, 0, 0, 0, 0, 0 }, "Plague Eater", 3, 6, 4, 12, 24, AI_SCAV, 0, 1, 30, 7, 1, 8, 0, 0, 0, 0, 20, MC_ANIMAL, 0, 4, 0, 3, 188 }, + { 128, 410, "Monsters\\Scav\\Scav%c.CL2", 1, "Monsters\\Scav\\Scav%c%i.WAV", 0, 1, "Monsters\\Scav\\ScavBe.TRN", { 12, 8, 12, 6, 20, 11 }, { 2, 0, 0, 0, 0, 0 }, "Shadow Beast", 4, 8, 6, 24, 36, AI_SCAV, 0, 2, 35, 7, 3, 12, 0, 0, 0, 0, 25, MC_ANIMAL, 64, 66, 0, 3, 375 }, + { 128, 410, "Monsters\\Scav\\Scav%c.CL2", 1, "Monsters\\Scav\\Scav%c%i.WAV", 0, 1, "Monsters\\Scav\\ScavW.TRN", { 12, 8, 12, 6, 20, 11 }, { 2, 0, 0, 0, 0, 0 }, "Bone Gasher", 6, 10, 8, 28, 40, AI_SCAV, 0, 3, 35, 7, 5, 15, 0, 0, 0, 0, 30, MC_ANIMAL, 65, 68, 0, 3, 552 }, + { 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", 1, "Monsters\\SkelBow\\SklBw%c%i.WAV", 0, 1, "Monsters\\SkelBow\\White.TRN", { 9, 8, 16, 5, 16, 16 }, { 4, 0, 0, 0, 0, 0 }, "Skeleton", 2, 5, 3, 2, 4, AI_SKELBOW, 0, 0, 15, 12, 1, 2, 0, 0, 0, 0, 0, MC_UNDEAD, 72, 72, 0, 3, 110 }, + { 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", 1, "Monsters\\SkelBow\\SklBw%c%i.WAV", 0, 1, "Monsters\\SkelBow\\Skelt.TRN", { 9, 8, 16, 5, 16, 16 }, { 4, 0, 0, 0, 0, 0 }, "Corpse Bow", 3, 7, 5, 8, 16, AI_SKELBOW, 0, 1, 25, 12, 1, 4, 0, 0, 0, 0, 0, MC_UNDEAD, 72, 72, 0, 3, 210 }, + { 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", 1, "Monsters\\SkelBow\\SklBw%c%i.WAV", 0, 0, NULL, { 9, 8, 16, 5, 16, 16 }, { 2, 0, 0, 0, 0, 0 }, "Burning Dead", 5, 9, 7, 10, 24, AI_SKELBOW, 0, 2, 30, 12, 1, 6, 0, 0, 0, 0, 5, MC_UNDEAD, 74, 88, 0, 3, 364 }, + { 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", 1, "Monsters\\SkelBow\\SklBw%c%i.WAV", 0, 1, "Monsters\\SkelBow\\Black.TRN", { 9, 8, 16, 5, 16, 16 }, { 3, 0, 0, 0, 0, 0 }, "Horror", 7, 11, 9, 15, 45, AI_SKELBOW, 0, 3, 35, 12, 2, 9, 0, 0, 0, 0, 15, MC_UNDEAD, 76, 76, 0, 3, 594 }, + { 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", 1, "Monsters\\SkelSd\\SklSr%c%i.WAV", 1, 1, "Monsters\\SkelSd\\White.TRN", { 13, 8, 12, 7, 15, 16 }, { 4, 0, 0, 0, 0, 0 }, "Skeleton Captain", 1, 4, 2, 3, 6, AI_SKELSD, 0, 0, 20, 8, 2, 7, 0, 0, 0, 0, 10, MC_UNDEAD, 72, 72, 0, 3, 90 }, + { 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", 1, "Monsters\\SkelSd\\SklSr%c%i.WAV", 0, 1, "Monsters\\SkelSd\\Skelt.TRN", { 13, 8, 12, 7, 15, 16 }, { 4, 0, 0, 0, 0, 0 }, "Corpse Captain", 2, 6, 4, 12, 20, AI_SKELSD, 0, 1, 30, 8, 3, 9, 0, 0, 0, 0, 5, MC_UNDEAD, 72, 72, 0, 3, 200 }, + { 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", 1, "Monsters\\SkelSd\\SklSr%c%i.WAV", 0, 0, NULL, { 13, 8, 12, 7, 15, 16 }, { 4, 0, 0, 0, 0, 0 }, "Burning Dead Captain", 4, 8, 6, 16, 30, AI_SKELSD, 0, 2, 35, 8, 4, 10, 0, 0, 0, 0, 15, MC_UNDEAD, 74, 88, 0, 3, 393 }, + { 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", 1, "Monsters\\SkelSd\\SklSr%c%i.WAV", 0, 1, "Monsters\\SkelSd\\Black.TRN", { 13, 8, 12, 7, 15, 16 }, { 4, 0, 0, 0, 0, 0 }, "Horror Captain", 6, 10, 8, 35, 50, AI_SKELSD, 256, 3, 40, 8, 5, 14, 0, 0, 0, 0, 30, MC_UNDEAD, 76, 76, 0, 3, 604 }, + { 128, 2000, "Monsters\\TSneak\\TSneak%c.CL2", 0, "Monsters\\TSneak\\Sneakl%c%i.WAV", 0, 0, NULL, { 13, 13, 15, 11, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Invisible Lord", 14, 14, 14, 278, 278, AI_SKELSD, 256, 3, 65, 8, 16, 30, 0, 0, 0, 0, 60, MC_DEMON, 71, 71, 0, 3, 2000 }, + { 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", 1, "Monsters\\Sneak\\Sneak%c%i.WAV", 0, 0, NULL, { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Hidden", 3, 8, 5, 8, 24, AI_SNEAK, 1, 0, 35, 8, 3, 6, 0, 0, 0, 0, 25, MC_DEMON, 0, 64, 0, 3, 278 }, + { 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", 1, "Monsters\\Sneak\\Sneak%c%i.WAV", 0, 1, "Monsters\\Sneak\\Sneakv2.TRN", { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Stalker", 8, 12, 9, 30, 45, AI_SNEAK, 257, 1, 40, 8, 8, 16, 0, 0, 0, 0, 30, MC_DEMON, 0, 64, 0, 3, 630 }, + { 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", 1, "Monsters\\Sneak\\Sneak%c%i.WAV", 0, 1, "Monsters\\Sneak\\Sneakv3.TRN", { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Unseen", 10, 14, 11, 35, 50, AI_SNEAK, 257, 2, 45, 8, 12, 20, 0, 0, 0, 0, 30, MC_DEMON, 65, 72, 0, 3, 935 }, + { 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", 1, "Monsters\\Sneak\\Sneak%c%i.WAV", 0, 1, "Monsters\\Sneak\\Sneakv1.TRN", { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Illusion Weaver", 14, 18, 13, 40, 60, AI_SNEAK, 257, 3, 60, 8, 16, 24, 0, 0, 0, 0, 30, MC_DEMON, 3, 74, 0, 3, 1500 }, + { 160, 2000, "Monsters\\GoatLord\\GoatL%c.CL2", 0, "Monsters\\GoatLord\\Goatl%c%i.WAV", 0, 0, NULL, { 13, 13, 14, 9, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Lord Sayter", 13, 13, 12, 351, 351, AI_SKELSD, 256, 3, 80, 8, 14, 24, 0, 0, 0, 0, 60, MC_DEMON, 67, 67, 0, 3, 1500 }, + { 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", 1, "Monsters\\GoatMace\\Goat%c%i.WAV", 0, 0, NULL, { 12, 8, 12, 6, 20, 12 }, { 2, 0, 0, 0, 1, 0 }, "Flesh Clan", 6, 10, 8, 30, 45, AI_GOATMC, 768, 0, 50, 8, 4, 10, 0, 0, 0, 0, 40, MC_DEMON, 0, 0, 0, 3, 460 }, + { 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", 1, "Monsters\\GoatMace\\Goat%c%i.WAV", 0, 1, "Monsters\\GoatMace\\Beige.TRN", { 12, 8, 12, 6, 20, 12 }, { 2, 0, 0, 0, 1, 0 }, "Stone Clan", 8, 12, 10, 40, 55, AI_GOATMC, 768, 1, 60, 8, 6, 12, 0, 0, 0, 0, 40, MC_DEMON, 65, 72, 0, 3, 685 }, + { 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", 1, "Monsters\\GoatMace\\Goat%c%i.WAV", 0, 1, "Monsters\\GoatMace\\Red.TRN", { 12, 8, 12, 6, 20, 12 }, { 2, 0, 0, 0, 1, 0 }, "Fire Clan", 10, 14, 12, 50, 65, AI_GOATMC, 768, 2, 70, 8, 8, 16, 0, 0, 0, 0, 45, MC_DEMON, 2, 16, 0, 3, 906 }, + { 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", 1, "Monsters\\GoatMace\\Goat%c%i.WAV", 0, 1, "Monsters\\GoatMace\\Gray.TRN", { 12, 8, 12, 6, 20, 12 }, { 2, 0, 0, 0, 1, 0 }, "Night Clan", 12, 16, 14, 55, 70, AI_GOATMC, 768, 3, 80, 8, 10, 20, 15, 0, 30, 30, 50, MC_DEMON, 65, 72, 0, 3, 1190 }, + { 96, 364, "Monsters\\Bat\\Bat%c.CL2", 0, "Monsters\\Bat\\Bat%c%i.WAV", 0, 1, "Monsters\\Bat\\red.trn", { 9, 13, 10, 9, 13, 0 }, { 0, 0, 0, 0, 0, 0 }, "Fiend", 2, 5, 3, 3, 6, AI_BAT, 0, 0, 35, 5, 1, 6, 0, 0, 0, 0, 0, MC_ANIMAL, 0, 0, 16384, 6, 102 }, + { 96, 364, "Monsters\\Bat\\Bat%c.CL2", 0, "Monsters\\Bat\\Bat%c%i.WAV", 0, 0, NULL, { 9, 13, 10, 9, 13, 0 }, { 0, 0, 0, 0, 0, 0 }, "Blink", 5, 9, 7, 12, 28, AI_BAT, 0, 1, 45, 5, 1, 8, 0, 0, 0, 0, 15, MC_ANIMAL, 0, 0, 16384, 6, 340 }, + { 96, 364, "Monsters\\Bat\\Bat%c.CL2", 0, "Monsters\\Bat\\Bat%c%i.WAV", 0, 1, "Monsters\\Bat\\grey.trn", { 9, 13, 10, 9, 13, 0 }, { 0, 0, 0, 0, 0, 0 }, "Gloom", 7, 11, 9, 28, 36, AI_BAT, 256, 2, 70, 5, 4, 12, 0, 0, 0, 0, 35, MC_ANIMAL, 1, 65, 16384, 6, 509 }, + { 96, 364, "Monsters\\Bat\\Bat%c.CL2", 0, "Monsters\\Bat\\Bat%c%i.WAV", 0, 1, "Monsters\\Bat\\orange.trn", { 9, 13, 10, 9, 13, 0 }, { 0, 0, 0, 0, 0, 0 }, "Familiar", 11, 15, 13, 20, 35, AI_BAT, 256, 3, 50, 5, 4, 16, 0, 0, 0, 0, 35, MC_DEMON, 33, 97, 16384, 6, 448 }, + { 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", 0, "Monsters\\GoatBow\\GoatB%c%i.WAV", 0, 0, NULL, { 12, 8, 16, 6, 20, 0 }, { 3, 0, 0, 0, 0, 0 }, "Flesh Clan", 6, 10, 8, 20, 35, AI_GOATBOW, 512, 0, 35, 13, 1, 7, 0, 0, 0, 0, 35, MC_DEMON, 0, 0, 0, 3, 448 }, + { 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", 0, "Monsters\\GoatBow\\GoatB%c%i.WAV", 0, 1, "Monsters\\GoatBow\\Beige.TRN", { 12, 8, 16, 6, 20, 0 }, { 3, 0, 0, 0, 0, 0 }, "Stone Clan", 8, 12, 10, 30, 40, AI_GOATBOW, 512, 1, 40, 13, 2, 9, 0, 0, 0, 0, 35, MC_DEMON, 65, 72, 0, 3, 645 }, + { 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", 0, "Monsters\\GoatBow\\GoatB%c%i.WAV", 0, 1, "Monsters\\GoatBow\\Red.TRN", { 12, 8, 16, 6, 20, 0 }, { 3, 0, 0, 0, 0, 0 }, "Fire Clan", 10, 14, 12, 40, 50, AI_GOATBOW, 768, 2, 45, 13, 3, 11, 0, 0, 0, 0, 35, MC_DEMON, 2, 16, 0, 3, 822 }, + { 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", 0, "Monsters\\GoatBow\\GoatB%c%i.WAV", 0, 1, "Monsters\\GoatBow\\Gray.TRN", { 12, 8, 16, 6, 20, 0 }, { 3, 0, 0, 0, 0, 0 }, "Night Clan", 12, 16, 14, 50, 65, AI_GOATBOW, 768, 3, 50, 13, 4, 13, 15, 0, 0, 0, 40, MC_DEMON, 65, 72, 0, 3, 1092 }, + { 128, 716, "Monsters\\Acid\\Acid%c.CL2", 1, "Monsters\\Acid\\Acid%c%i.WAV", 1, 0, NULL, { 13, 8, 12, 8, 16, 12 }, { 0, 0, 0, 0, 0, 0 }, "Acid Beast", 10, 14, 11, 40, 66, AI_ACID, 0, 0, 40, 8, 4, 12, 25, 8, 0, 0, 30, MC_ANIMAL, 128, 136, 0, 3, 846 }, + { 128, 716, "Monsters\\Acid\\Acid%c.CL2", 1, "Monsters\\Acid\\Acid%c%i.WAV", 1, 1, "Monsters\\Acid\\AcidBlk.TRN", { 13, 8, 12, 8, 16, 12 }, { 0, 0, 0, 0, 0, 0 }, "Poison Spitter", 14, 18, 15, 60, 85, AI_ACID, 0, 1, 45, 8, 4, 16, 25, 8, 0, 0, 30, MC_ANIMAL, 128, 136, 0, 3, 1248 }, + { 128, 716, "Monsters\\Acid\\Acid%c.CL2", 1, "Monsters\\Acid\\Acid%c%i.WAV", 1, 1, "Monsters\\Acid\\AcidB.TRN", { 13, 8, 12, 8, 16, 12 }, { 0, 0, 0, 0, 0, 0 }, "Pit Beast", 18, 22, 21, 80, 110, AI_ACID, 0, 2, 55, 8, 8, 18, 35, 8, 0, 0, 35, MC_ANIMAL, 129, 140, 0, 3, 2060 }, + { 128, 716, "Monsters\\Acid\\Acid%c.CL2", 1, "Monsters\\Acid\\Acid%c%i.WAV", 1, 1, "Monsters\\Acid\\AcidR.TRN", { 13, 8, 12, 8, 16, 12 }, { 0, 0, 0, 0, 0, 0 }, "Lava Maw", 22, 27, 25, 100, 150, AI_ACID, 0, 3, 65, 8, 10, 20, 40, 8, 0, 0, 35, MC_ANIMAL, 145, 152, 0, 3, 2940 }, + { 160, 1010, "Monsters\\SKing\\SKing%c.CL2", 1, "Monsters\\SKing\\SKing%c%i.WAV", 1, 1, "Monsters\\SkelAxe\\White.TRN", { 8, 6, 16, 6, 16, 6 }, { 2, 0, 0, 0, 0, 2 }, "Skeleton King", 6, 6, 9, 140, 140, AI_SKELKING, 768, 3, 60, 8, 6, 16, 0, 0, 0, 0, 70, MC_UNDEAD, 78, 120, 32769, 7, 570 }, + { 128, 980, "Monsters\\FatC\\FatC%c.CL2", 0, "Monsters\\FatC\\FatC%c%i.WAV", 0, 0, NULL, { 10, 8, 12, 6, 16, 0 }, { 1, 0, 0, 0, 0, 0 }, "The Butcher", 0, 0, 1, 320, 320, AI_CLEAVER, 0, 3, 50, 8, 6, 12, 0, 0, 0, 0, 50, MC_DEMON, 6, 49, 32768, 3, 710 }, + { 128, 1130, "Monsters\\Fat\\Fat%c.CL2", 1, "Monsters\\Fat\\Fat%c%i.WAV", 0, 0, NULL, { 8, 10, 15, 6, 16, 10 }, { 4, 0, 0, 0, 0, 0 }, "Overlord", 8, 12, 10, 60, 80, AI_FAT, 0, 0, 55, 8, 6, 12, 0, 0, 0, 0, 55, MC_DEMON, 0, 2, 0, 3, 635 }, + { 128, 1130, "Monsters\\Fat\\Fat%c.CL2", 1, "Monsters\\Fat\\Fat%c%i.WAV", 0, 1, "Monsters\\Fat\\Blue.TRN", { 8, 10, 15, 6, 16, 10 }, { 4, 0, 0, 0, 0, 0 }, "Mud Man", 13, 17, 14, 100, 125, AI_FAT, 256, 1, 60, 8, 8, 16, 0, 0, 0, 0, 60, MC_DEMON, 0, 32, 0, 3, 1165 }, + { 128, 1130, "Monsters\\Fat\\Fat%c.CL2", 1, "Monsters\\Fat\\Fat%c%i.WAV", 0, 1, "Monsters\\Fat\\FatB.TRN", { 8, 10, 15, 6, 16, 10 }, { 4, 0, 0, 0, 0, 0 }, "Toad Demon", 15, 19, 16, 135, 160, AI_FAT, 256, 2, 70, 8, 8, 16, 40, 0, 8, 20, 65, MC_DEMON, 8, 12, 0, 3, 1380 }, + { 128, 1130, "Monsters\\Fat\\Fat%c.CL2", 1, "Monsters\\Fat\\Fat%c%i.WAV", 0, 1, "Monsters\\Fat\\FatF.TRN", { 8, 10, 15, 6, 16, 10 }, { 4, 0, 0, 0, 0, 0 }, "Flayed One", 19, 23, 20, 160, 200, AI_FAT, 256, 3, 85, 8, 10, 20, 0, 0, 0, 0, 70, MC_DEMON, 17, 24, 0, 3, 2058 }, + { 160, 2420, "Monsters\\Worm\\Worm%c.CL2", 0, "Monsters\\Fat\\Fat%c%i.WAV", 0, 0, NULL, { 13, 13, 13, 11, 19, 0 }, { 0, 0, 0, 0, 0, 0 }, "Wyrm", 9, 13, 11, 60, 90, AI_SKELSD, 0, 0, 40, 8, 4, 10, 0, 0, 0, 0, 25, MC_ANIMAL, 1, 1, 0, 3, 660 }, + { 160, 2420, "Monsters\\Worm\\Worm%c.CL2", 0, "Monsters\\Fat\\Fat%c%i.WAV", 0, 0, NULL, { 13, 13, 13, 11, 19, 0 }, { 0, 0, 0, 0, 0, 0 }, "Cave Slug", 11, 15, 13, 75, 110, AI_SKELSD, 0, 1, 50, 8, 6, 13, 0, 0, 0, 0, 30, MC_ANIMAL, 1, 1, 0, 3, 994 }, + { 160, 2420, "Monsters\\Worm\\Worm%c.CL2", 0, "Monsters\\Fat\\Fat%c%i.WAV", 0, 0, NULL, { 13, 13, 13, 11, 19, 0 }, { 0, 0, 0, 0, 0, 0 }, "Devil Wyrm", 13, 17, 15, 100, 140, AI_SKELSD, 0, 2, 55, 8, 8, 16, 0, 0, 0, 0, 30, MC_ANIMAL, 3, 3, 0, 3, 1320 }, + { 160, 2420, "Monsters\\Worm\\Worm%c.CL2", 0, "Monsters\\Fat\\Fat%c%i.WAV", 0, 0, NULL, { 13, 13, 13, 11, 19, 0 }, { 0, 0, 0, 0, 0, 0 }, "Devourer", 15, 19, 17, 125, 200, AI_SKELSD, 0, 3, 60, 8, 10, 20, 0, 0, 0, 0, 35, MC_ANIMAL, 67, 67, 0, 3, 1827 }, + { 128, 1680, "Monsters\\Magma\\Magma%c.CL2", 1, "Monsters\\Magma\\Magma%c%i.WAV", 1, 0, NULL, { 8, 10, 14, 7, 18, 18 }, { 2, 0, 0, 0, 1, 0 }, "Magma Demon", 14, 17, 13, 50, 70, AI_MAGMA, 768, 0, 45, 4, 2, 10, 50, 13, 0, 0, 45, MC_DEMON, 10, 24, 0, 7, 1076 }, + { 128, 1680, "Monsters\\Magma\\Magma%c.CL2", 1, "Monsters\\Magma\\Magma%c%i.WAV", 1, 1, "Monsters\\Magma\\Yellow.TRN", { 8, 10, 14, 7, 18, 18 }, { 2, 0, 0, 0, 1, 0 }, "Blood Stone", 15, 19, 14, 55, 75, AI_MAGMA, 768, 1, 50, 4, 2, 12, 50, 14, 0, 0, 45, MC_DEMON, 24, 24, 0, 7, 1309 }, + { 128, 1680, "Monsters\\Magma\\Magma%c.CL2", 1, "Monsters\\Magma\\Magma%c%i.WAV", 1, 1, "Monsters\\Magma\\Blue.TRN", { 8, 10, 14, 7, 18, 18 }, { 2, 0, 0, 0, 1, 0 }, "Hell Stone", 16, 20, 16, 60, 80, AI_MAGMA, 768, 2, 60, 4, 2, 20, 60, 14, 0, 0, 50, MC_DEMON, 24, 24, 0, 7, 1680 }, + { 128, 1680, "Monsters\\Magma\\Magma%c.CL2", 1, "Monsters\\Magma\\Magma%c%i.WAV", 1, 1, "Monsters\\Magma\\Wierd.TRN", { 8, 10, 14, 7, 18, 18 }, { 2, 0, 0, 0, 1, 0 }, "Lava Lord", 17, 21, 18, 70, 85, AI_MAGMA, 768, 3, 75, 4, 4, 24, 60, 14, 0, 0, 60, MC_DEMON, 24, 24, 0, 7, 2124 }, + { 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", 1, "Monsters\\Rhino\\Rhino%c%i.WAV", 1, 0, NULL, { 8, 8, 14, 6, 16, 6 }, { 2, 0, 0, 0, 0, 0 }, "Horned Demon", 12, 16, 13, 40, 80, AI_RHINO, 768, 0, 60, 7, 2, 16, 100, 0, 5, 32, 40, MC_ANIMAL, 0, 2, 0, 7, 1172 }, + { 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", 1, "Monsters\\Rhino\\Rhino%c%i.WAV", 1, 1, "Monsters\\Rhino\\Orange.TRN", { 8, 8, 14, 6, 16, 6 }, { 2, 0, 0, 0, 0, 0 }, "Mud Runner", 14, 18, 15, 50, 90, AI_RHINO, 768, 1, 70, 7, 6, 18, 100, 0, 12, 36, 45, MC_ANIMAL, 0, 2, 0, 7, 1404 }, + { 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", 1, "Monsters\\Rhino\\Rhino%c%i.WAV", 1, 1, "Monsters\\Rhino\\Blue.TRN", { 8, 8, 14, 6, 16, 6 }, { 2, 0, 0, 0, 0, 0 }, "Frost Charger", 16, 20, 17, 60, 100, AI_RHINO, 768, 2, 80, 7, 8, 20, 100, 0, 20, 40, 50, MC_ANIMAL, 12, 12, 0, 7, 1720 }, + { 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", 1, "Monsters\\Rhino\\Rhino%c%i.WAV", 1, 1, "Monsters\\Rhino\\RhinoB.TRN", { 8, 8, 14, 6, 16, 6 }, { 2, 0, 0, 0, 0, 0 }, "Obsidian Lord", 18, 22, 19, 70, 110, AI_RHINO, 768, 3, 90, 7, 10, 22, 100, 0, 20, 50, 55, MC_ANIMAL, 12, 56, 0, 7, 1809 }, + { 128, 1740, "Monsters\\Demskel\\Demskl%c.CL2", 1, "Monsters\\Thin\\Thin%c%i.WAV", 1, 0, "Monsters\\Thin\\Thinv3.TRN", { 10, 8, 20, 6, 24, 16 }, { 3, 0, 0, 0, 0, 0 }, "Bone Demon", 10, 14, 12, 70, 70, AI_STORM, 0, 0, 60, 8, 6, 14, 12, 0, 0, 0, 50, MC_DEMON, 72, 72, 0, 7, 1344 }, + { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", 1, "Monsters\\Thin\\Thin%c%i.WAV", 1, 1, "Monsters\\Thin\\Thinv3.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Red Death", 14, 18, 16, 96, 96, AI_STORM, 0, 1, 75, 5, 10, 20, 0, 0, 0, 0, 60, MC_DEMON, 24, 24, 0, 7, 2168 }, + { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", 1, "Monsters\\Thin\\Thin%c%i.WAV", 1, 1, "Monsters\\Thin\\Thinv3.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Litch Demon", 16, 20, 18, 110, 110, AI_STORM, 0, 2, 80, 5, 10, 24, 0, 0, 0, 0, 45, MC_DEMON, 104, 104, 0, 7, 2736 }, + { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", 1, "Monsters\\Thin\\Thin%c%i.WAV", 1, 1, "Monsters\\Thin\\Thinv3.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Undead Balrog", 20, 24, 22, 130, 130, AI_STORM, 0, 3, 85, 5, 12, 30, 0, 0, 0, 0, 65, MC_DEMON, 78, 78, 0, 7, 3575 }, + { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", 1, "Monsters\\Acid\\Acid%c%i.WAV", 0, 0, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Incinerator", 14, 18, 16, 30, 45, AI_FIREMAN, 0, 0, 75, 8, 8, 16, 0, 0, 0, 0, 25, MC_DEMON, 24, 24, 0, 3, 1888 }, + { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", 1, "Monsters\\Acid\\Acid%c%i.WAV", 0, 0, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Flame Lord", 16, 20, 18, 40, 55, AI_FIREMAN, 0, 1, 75, 8, 10, 20, 0, 0, 0, 0, 25, MC_DEMON, 24, 24, 0, 3, 2250 }, + { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", 1, "Monsters\\Acid\\Acid%c%i.WAV", 0, 0, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Doom Fire", 18, 22, 20, 50, 65, AI_FIREMAN, 0, 2, 80, 8, 12, 24, 0, 0, 0, 0, 30, MC_DEMON, 28, 28, 0, 3, 2740 }, + { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", 1, "Monsters\\Acid\\Acid%c%i.WAV", 0, 0, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Hell Burner", 20, 24, 22, 60, 80, AI_FIREMAN, 0, 3, 85, 8, 15, 30, 0, 0, 0, 0, 30, MC_DEMON, 28, 28, 0, 3, 3355 }, + { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", 1, "Monsters\\Thin\\Thin%c%i.WAV", 1, 1, "Monsters\\Thin\\Thinv3.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Red Storm", 17, 21, 18, 55, 110, AI_STORM, 768, 0, 80, 5, 8, 18, 75, 8, 4, 16, 30, MC_DEMON, 12, 40, 0, 7, 2160 }, + { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", 1, "Monsters\\Thin\\Thin%c%i.WAV", 1, 0, NULL, { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Storm Rider", 19, 23, 20, 60, 120, AI_STORM, 768, 1, 80, 5, 8, 18, 80, 8, 4, 16, 30, MC_DEMON, 33, 40, 0, 7, 2391 }, + { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", 1, "Monsters\\Thin\\Thin%c%i.WAV", 1, 1, "Monsters\\Thin\\Thinv2.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Storm Lord", 21, 25, 22, 75, 135, AI_STORM, 768, 2, 85, 5, 12, 24, 75, 8, 4, 16, 35, MC_DEMON, 33, 40, 0, 7, 2775 }, + { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", 1, "Monsters\\Thin\\Thin%c%i.WAV", 1, 1, "Monsters\\Thin\\Thinv1.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Maelstorm", 23, 27, 24, 90, 150, AI_STORM, 768, 3, 90, 5, 12, 28, 75, 8, 4, 16, 40, MC_DEMON, 97, 104, 0, 7, 3177 }, + { 128, 1650, "Monsters\\BigFall\\Fallg%c.CL2", 1, "Monsters\\BigFall\\Bfal%c%i.WAV", 0, 0, NULL, { 10, 8, 11, 8, 17, 0 }, { 0, 0, 0, 0, 2, 2 }, "Devil Kin Brute", 20, 20, 24, 160, 220, AI_SKELSD, 768, 3, 100, 6, 18, 24, 0, 0, 0, 0, 75, MC_ANIMAL, 0, 0, 0, 6, 2000 }, + { 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", 1, "Monsters\\Gargoyle\\Gargo%c%i.WAV", 0, 0, NULL, { 14, 14, 14, 10, 18, 14 }, { 0, 0, 0, 0, 0, 2 }, "Winged-Demon", 8, 12, 9, 45, 60, AI_GARG, 512, 0, 50, 7, 10, 16, 0, 0, 0, 0, 45, MC_DEMON, 74, 88, 0, 6, 662 }, + { 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", 1, "Monsters\\Gargoyle\\Gargo%c%i.WAV", 0, 1, "Monsters\\Gargoyle\\GarE.TRN", { 14, 14, 14, 10, 18, 14 }, { 0, 0, 0, 0, 0, 2 }, "Gargoyle", 12, 16, 13, 60, 90, AI_GARG, 512, 1, 65, 7, 10, 16, 0, 0, 0, 0, 45, MC_DEMON, 76, 104, 0, 6, 1205 }, + { 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", 1, "Monsters\\Gargoyle\\Gargo%c%i.WAV", 0, 1, "Monsters\\Gargoyle\\GargBr.TRN", { 14, 14, 14, 10, 18, 14 }, { 0, 0, 0, 0, 0, 0 }, "Blood Claw", 16, 20, 19, 75, 125, AI_GARG, 512, 2, 80, 7, 14, 22, 0, 0, 0, 0, 50, MC_DEMON, 88, 92, 0, 6, 1873 }, + { 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", 1, "Monsters\\Gargoyle\\Gargo%c%i.WAV", 0, 1, "Monsters\\Gargoyle\\GargB.TRN", { 14, 14, 14, 10, 18, 14 }, { 0, 0, 0, 0, 0, 0 }, "Death Wing", 18, 22, 23, 90, 150, AI_GARG, 512, 3, 95, 7, 16, 28, 0, 0, 0, 0, 60, MC_DEMON, 104, 106, 0, 6, 2278 }, + { 160, 2220, "Monsters\\Mega\\Mega%c.CL2", 1, "Monsters\\Mega\\Mega%c%i.WAV", 1, 0, NULL, { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Slayer", 19, 23, 20, 120, 140, AI_MEGA, 768, 0, 100, 8, 12, 20, 0, 3, 0, 0, 60, MC_DEMON, 17, 17, 0, 7, 2300 }, + { 160, 2220, "Monsters\\Mega\\Mega%c.CL2", 1, "Monsters\\Mega\\Mega%c%i.WAV", 1, 1, "Monsters\\Mega\\Guard.TRN", { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Guardian", 21, 25, 22, 140, 160, AI_MEGA, 768, 1, 110, 8, 14, 22, 0, 3, 0, 0, 65, MC_DEMON, 17, 17, 0, 7, 2714 }, + { 160, 2220, "Monsters\\Mega\\Mega%c.CL2", 1, "Monsters\\Mega\\Mega%c%i.WAV", 1, 1, "Monsters\\Mega\\Vtexl.TRN", { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Vortex Lord", 23, 26, 24, 160, 180, AI_MEGA, 768, 2, 120, 8, 18, 24, 0, 3, 0, 0, 70, MC_DEMON, 81, 85, 0, 7, 3252 }, + { 160, 2220, "Monsters\\Mega\\Mega%c.CL2", 1, "Monsters\\Mega\\Mega%c%i.WAV", 1, 1, "Monsters\\Mega\\Balr.TRN", { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Balrog", 25, 29, 26, 180, 200, AI_MEGA, 768, 3, 130, 8, 22, 30, 0, 3, 0, 0, 75, MC_DEMON, 81, 85, 0, 7, 3643 }, + { 160, 1270, "Monsters\\Snake\\Snake%c.CL2", 0, "Monsters\\Snake\\Snake%c%i.WAV", 0, 0, NULL, { 12, 11, 13, 5, 18, 0 }, { 2, 0, 0, 0, 1, 0 }, "Cave Viper", 20, 24, 21, 100, 150, AI_SNAKE, 256, 0, 90, 8, 8, 20, 0, 0, 0, 0, 60, MC_DEMON, 8, 8, 0, 7, 2725 }, + { 160, 1270, "Monsters\\Snake\\Snake%c.CL2", 0, "Monsters\\Snake\\Snake%c%i.WAV", 0, 1, "Monsters\\Snake\\SnakR.TRN", { 12, 11, 13, 5, 18, 0 }, { 2, 0, 0, 0, 1, 0 }, "Fire Drake", 22, 26, 23, 120, 170, AI_SNAKE, 256, 1, 105, 8, 12, 24, 0, 0, 0, 0, 65, MC_DEMON, 10, 24, 0, 7, 3139 }, + { 160, 1270, "Monsters\\Snake\\Snake%c.CL2", 0, "Monsters\\Snake\\Snake%c%i.WAV", 0, 1, "Monsters\\Snake\\Snakg.TRN", { 12, 11, 13, 5, 18, 0 }, { 2, 0, 0, 0, 1, 0 }, "Gold Viper", 24, 27, 25, 140, 180, AI_SNAKE, 256, 2, 120, 8, 15, 26, 0, 0, 0, 0, 70, MC_DEMON, 12, 12, 0, 7, 3540 }, + { 160, 1270, "Monsters\\Snake\\Snake%c.CL2", 0, "Monsters\\Snake\\Snake%c%i.WAV", 0, 1, "Monsters\\Snake\\Snakb.TRN", { 12, 11, 13, 5, 18, 0 }, { 2, 0, 0, 0, 1, 0 }, "Azure Drake", 28, 30, 27, 160, 200, AI_SNAKE, 256, 3, 130, 8, 18, 30, 0, 0, 0, 0, 75, MC_DEMON, 6, 42, 0, 7, 3791 }, + { 160, 2120, "Monsters\\Black\\Black%c.CL2", 0, "Monsters\\Black\\Black%c%i.WAV", 0, 0, NULL, { 8, 8, 16, 4, 24, 0 }, { 2, 0, 0, 0, 0, 0 }, "Black Knight", 23, 27, 24, 150, 150, AI_SKELSD, 256, 0, 110, 8, 15, 20, 0, 0, 0, 0, 75, MC_DEMON, 69, 97, 0, 7, 3360 }, + { 160, 2120, "Monsters\\Black\\Black%c.CL2", 0, "Monsters\\Black\\Black%c%i.WAV", 0, 1, "Monsters\\Black\\BlkKntRT.TRN", { 8, 8, 16, 4, 24, 0 }, { 2, 0, 0, 0, 0, 0 }, "Doom Guard", 25, 29, 26, 165, 165, AI_SKELSD, 256, 0, 130, 8, 18, 25, 0, 0, 0, 0, 75, MC_DEMON, 67, 81, 0, 7, 3650 }, + { 160, 2120, "Monsters\\Black\\Black%c.CL2", 0, "Monsters\\Black\\Black%c%i.WAV", 0, 1, "Monsters\\Black\\BlkKntBT.TRN", { 8, 8, 16, 4, 24, 0 }, { 2, 0, 0, 0, 0, 0 }, "Steel Lord", 27, 30, 28, 180, 180, AI_SKELSD, 256, 1, 120, 8, 20, 30, 0, 0, 0, 0, 80, MC_DEMON, 85, 92, 0, 7, 4252 }, + { 160, 2120, "Monsters\\Black\\Black%c.CL2", 0, "Monsters\\Black\\Black%c%i.WAV", 0, 1, "Monsters\\Black\\BlkKntBe.TRN", { 8, 8, 16, 4, 24, 0 }, { 2, 0, 0, 0, 0, 0 }, "Blood Knight", 24, 26, 30, 200, 200, AI_SKELSD, 256, 1, 130, 8, 25, 35, 0, 0, 0, 0, 85, MC_DEMON, 106, 106, 0, 7, 5130 }, + { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", 0, "Monsters\\Acid\\Acid%c%i.WAV", 0, 0, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Unraveler", 26, 28, 25, 70, 150, AI_SKELSD, 0, 0, 75, 7, 10, 20, 0, 0, 0, 0, 70, MC_UNDEAD, 106, 106, 0, 3, 3812 }, + { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", 0, "Monsters\\Acid\\Acid%c%i.WAV", 0, 0, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Hollow One", 28, 30, 27, 135, 240, AI_SKELSD, 0, 1, 75, 7, 12, 24, 0, 0, 0, 0, 75, MC_UNDEAD, 92, 92, 0, 3, 4374 }, + { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", 0, "Monsters\\Acid\\Acid%c%i.WAV", 0, 0, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Pain Master", 27, 30, 29, 110, 200, AI_SKELSD, 0, 2, 80, 7, 16, 30, 0, 0, 0, 0, 80, MC_UNDEAD, 92, 92, 0, 3, 5147 }, + { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", 0, "Monsters\\Acid\\Acid%c%i.WAV", 0, 0, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Reality Weaver", 28, 30, 30, 135, 240, AI_SKELSD, 0, 3, 85, 7, 20, 35, 0, 0, 0, 0, 85, MC_UNDEAD, 113, 113, 0, 3, 5925 }, + { 128, 980, "Monsters\\Succ\\Scbs%c.CL2", 0, "Monsters\\Succ\\Scbs%c%i.WAV", 0, 0, NULL, { 14, 8, 16, 7, 24, 0 }, { 0, 0, 0, 0, 0, 0 }, "Succubus", 22, 26, 24, 120, 150, AI_SUCC, 512, 0, 100, 10, 1, 20, 0, 0, 0, 0, 60, MC_DEMON, 1, 10, 0, 3, 3696 }, + { 128, 980, "Monsters\\Succ\\Scbs%c.CL2", 0, "Monsters\\Succ\\Scbs%c%i.WAV", 0, 1, "Monsters\\Succ\\Succb.TRN", { 14, 8, 16, 7, 24, 0 }, { 0, 0, 0, 0, 0, 0 }, "Snow Witch", 25, 28, 26, 135, 175, AI_SUCC, 512, 1, 110, 10, 1, 24, 0, 0, 0, 0, 65, MC_DEMON, 68, 76, 0, 3, 4084 }, + { 128, 980, "Monsters\\Succ\\Scbs%c.CL2", 0, "Monsters\\Succ\\Scbs%c%i.WAV", 0, 1, "Monsters\\Succ\\Succrw.TRN", { 14, 8, 16, 7, 24, 0 }, { 0, 0, 0, 0, 0, 0 }, "Hell Spawn", 27, 30, 28, 150, 200, AI_SUCC, 768, 2, 115, 10, 1, 30, 0, 0, 0, 0, 75, MC_DEMON, 33, 28, 0, 3, 4480 }, + { 128, 980, "Monsters\\Succ\\Scbs%c.CL2", 0, "Monsters\\Succ\\Scbs%c%i.WAV", 0, 1, "Monsters\\Succ\\Succbw.TRN", { 14, 8, 16, 7, 24, 0 }, { 0, 0, 0, 0, 0, 0 }, "Soul Burner", 28, 30, 30, 140, 225, AI_SUCC, 768, 3, 120, 10, 1, 35, 0, 0, 0, 0, 85, MC_DEMON, 21, 56, 0, 3, 4644 }, + { 128, 2000, "Monsters\\Mage\\Mage%c.CL2", 1, "Monsters\\Mage\\Mage%c%i.WAV", 0, 0, NULL, { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Counselor", 24, 26, 25, 70, 70, AI_COUNSLR, 512, 0, 90, 8, 8, 20, 0, 0, 0, 0, 0, MC_DEMON, 7, 7, 0, 7, 4070 }, + { 128, 2000, "Monsters\\Mage\\Mage%c.CL2", 1, "Monsters\\Mage\\Mage%c%i.WAV", 0, 1, "Monsters\\Mage\\Cnselg.TRN", { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Magistrate", 26, 28, 27, 85, 85, AI_COUNSLR, 512, 1, 100, 8, 10, 24, 0, 0, 0, 0, 0, MC_DEMON, 85, 92, 0, 7, 4478 }, + { 128, 2000, "Monsters\\Mage\\Mage%c.CL2", 1, "Monsters\\Mage\\Mage%c%i.WAV", 0, 1, "Monsters\\Mage\\Cnselgd.TRN", { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Cabalist", 28, 30, 29, 120, 120, AI_COUNSLR, 512, 2, 110, 8, 14, 30, 0, 0, 0, 0, 0, MC_DEMON, 99, 106, 0, 7, 4929 }, + { 128, 2000, "Monsters\\Mage\\Mage%c.CL2", 1, "Monsters\\Mage\\Mage%c%i.WAV", 0, 1, "Monsters\\Mage\\Cnselbk.TRN", { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Advocate", 30, 30, 30, 145, 145, AI_COUNSLR, 512, 3, 120, 8, 15, 25, 0, 0, 0, 0, 0, MC_DEMON, 106, 120, 0, 7, 4968 }, + { 96, 386, "Monsters\\Golem\\Golem%c.CL2", 1, "Monsters\\Golem\\Golm%c%i.WAV", 0, 0, NULL, { 0, 16, 12, 0, 12, 20 }, { 0, 0, 0, 0, 0, 0 }, "Golem", 0, 0, 12, 1, 1, AI_GOLUM, 512, 0, 0, 7, 1, 1, 0, 0, 0, 0, 1, MC_DEMON, 0, 0, 0, 0, 0 }, + { 160, 2000, "Monsters\\Diablo\\Diablo%c.CL2", 1, "Monsters\\Diablo\\Diablo%c%i.WAV", 1, 0, NULL, { 16, 6, 16, 6, 16, 16 }, { 0, 0, 0, 0, 0, 0 }, "The Dark Lord", 50, 50, 30, 1666, 1666, AI_DIABLO, 896, 3, 220, 4, 30, 60, 0, 11, 0, 0, 70, MC_DEMON, 78, 78, 0, 7, 31666 }, + { 128, 1060, "Monsters\\DarkMage\\Dmage%c.CL2", 1, "Monsters\\DarkMage\\Dmag%c%i.WAV", 0, 0, NULL, { 6, 1, 21, 6, 23, 18 }, { 0, 0, 0, 0, 0, 0 }, "The Arch-Litch Malignus", 30, 30, 30, 160, 160, AI_COUNSLR, 512, 3, 120, 8, 20, 40, 0, 0, 0, 0, 70, MC_DEMON, 71, 120, 0, 7, 4968 } +}; +char MonstConvTbl[128] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, + 31, 32, 34, 35, 36, 37, 38, 40, 39, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, + 53, 54, 55, 56, 57, 59, 58, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 0, + 0, 0, 0, 72, 73, 74, 75, 0, 0, 0, + 0, 77, 76, 78, 79, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 92, 91, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 0, 110, 0, 109, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 80, 111 +}; + +unsigned char MonstAvailTbl[112] = +{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, + 2, 2, 2, 0, 2, 2, 2, 2, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0 +}; +UniqMonstStruct UniqMonst[98] = +{ + { MT_NGOATMC, "Gharbad the Weak", "BSDB", 4, 120, AI_GARBUD, 3, 8, 16, 96, 0, 0, 0, QUEST_GARBUD1 }, + { MT_SKING, "Skeleton King", "GENRL", 0, 240, AI_SKELKING, 3, 6, 16, 78, 1, 0, 0, 0 }, + { MT_COUNSLR, "Zhar the Mad", "GENERAL", 8, 360, AI_ZHAR, 3, 16, 40, 14, 0, 0, 0, QUEST_ZHAR1 }, + { MT_BFALLSP, "Snotspill", "BNG", 4, 220, AI_SNOTSPIL, 3, 10, 18, 4, 0, 0, 0, QUEST_BANNER10 }, + { MT_ADVOCATE, "Arch-Bishop Lazarus", "GENERAL", 0, 600, AI_LAZURUS, 3, 30, 50, 78, 0, 0, 0, QUEST_VILE13 }, + { MT_HLSPWN, "Red Vex", "REDV", 0, 400, AI_LAZHELP, 3, 30, 50, 74, 0, 0, 0, QUEST_VILE13 }, + { MT_HLSPWN, "BlackJade", "BLKJD", 0, 400, AI_LAZHELP, 3, 30, 50, 76, 0, 0, 0, QUEST_VILE13 }, + { MT_RBLACK, "Lachdanan", "BHKA", 14, 500, AI_LACHDAN, 3, 0, 0, 0, 0, 0, 0, QUEST_VEIL9 }, + { MT_BTBLACK, "Warlord of Blood", "GENERAL", 13, 850, AI_WARLORD, 3, 35, 50, 120, 0, 0, 0, QUEST_WARLRD9 }, + { MT_CLEAVER, "The Butcher", "GENRL", 0, 220, AI_CLEAVER, 3, 6, 12, 70, 0, 0, 0, 0 }, + { MT_TSKELAX, "Bonehead Keenaxe", "BHKA", 2, 91, AI_SKELSD, 2, 4, 10, 72, 7, 100, 0, 0 }, + { MT_RFALLSD, "Bladeskin the Slasher", "BSTS", 2, 51, AI_FALLEN, 0, 6, 18, 2, 11, 45, 0, 0 }, + { MT_NZOMBIE, "Soulpus", "GENERAL", 2, 133, AI_ZOMBIE, 0, 4, 8, 6, 0, 0, 0, 0 }, + { MT_RFALLSP, "Pukerat the Unclean", "PTU", 2, 77, AI_FALLEN, 3, 1, 5, 2, 0, 0, 0, 0 }, + { MT_WSKELAX, "Boneripper", "BR", 2, 54, AI_BAT, 0, 6, 15, 88, 3, 0, 0, 0 }, + { MT_NZOMBIE, "Rotfeast the Hungry", "ETH", 2, 85, AI_SKELSD, 3, 4, 12, 72, 3, 0, 0, 0 }, + { MT_DFALLSD, "Gutshank the Quick", "GTQ", 3, 66, AI_BAT, 2, 6, 16, 2, 3, 0, 0, 0 }, + { MT_TSKELSD, "Brokenhead Bangshield", "BHBS", 3, 108, AI_SKELSD, 3, 12, 20, 76, 3, 0, 0, 0 }, + { MT_YFALLSP, "Bongo", "BNG", 3, 178, AI_FALLEN, 3, 9, 21, 0, 3, 0, 0, 0 }, + { MT_BZOMBIE, "Rotcarnage", "RCRN", 3, 102, AI_ZOMBIE, 3, 9, 24, 76, 11, 45, 0, 0 }, + { MT_NSCAV, "Shadowbite", "SHBT", 2, 60, AI_SKELSD, 3, 3, 20, 16, 3, 0, 0, 0 }, + { MT_WSKELBW, "Deadeye", "DE", 2, 49, AI_GOATBOW, 0, 6, 9, 74, 0, 0, 0, 0 }, + { MT_RSKELAX, "Madeye the Dead", "MTD", 4, 75, AI_BAT, 0, 9, 21, 24, 11, 30, 0, 0 }, + { MT_BSCAV, "El Chupacabras", "GENERAL", 3, 120, AI_GOATMC, 0, 10, 18, 2, 3, 30, 0, 0 }, + { MT_TSKELBW, "Skullfire", "SKFR", 3, 125, AI_GOATBOW, 1, 6, 10, 16, 0, 100, 0, 0 }, + { MT_SNEAK, "Warpskull", "TSPO", 3, 117, AI_SNEAK, 2, 6, 18, 6, 3, 0, 0, 0 }, + { MT_GZOMBIE, "Goretongue", "PMR", 3, 156, AI_SKELSD, 1, 15, 30, 72, 0, 0, 0, 0 }, + { MT_WSCAV, "Pulsecrawler", "BHKA", 4, 150, AI_SCAV, 0, 16, 20, 20, 11, 45, 0, 0 }, + { MT_BLINK, "Moonbender", "GENERAL", 4, 135, AI_BAT, 0, 9, 27, 16, 3, 0, 0, 0 }, + { MT_BLINK, "Wrathraven", "GENERAL", 5, 135, AI_BAT, 2, 9, 22, 16, 3, 0, 0, 0 }, + { MT_YSCAV, "Spineeater", "GENERAL", 4, 180, AI_SCAV, 1, 18, 25, 96, 3, 0, 0, 0 }, + { MT_RSKELBW, "Blackash the Burning", "BASHTB", 4, 120, AI_GOATBOW, 0, 6, 16, 24, 3, 0, 0, 0 }, + { MT_BFALLSD, "Shadowcrow", "GENERAL", 5, 270, AI_SNEAK, 2, 12, 25, 0, 3, 0, 0, 0 }, + { MT_LRDSAYTR, "Blightstone the Weak", "BHKA", 4, 360, AI_SKELSD, 0, 4, 12, 12, 7, 70, 0, 0 }, + { MT_FAT, "Bilefroth the Pit Master", "BFTP", 6, 210, AI_BAT, 1, 16, 23, 28, 3, 0, 0, 0 }, + { MT_NGOATBW, "Bloodskin Darkbow", "BSDB", 5, 207, AI_GOATBOW, 0, 3, 16, 6, 11, 55, 0, 0 }, + { MT_GLOOM, "Foulwing", "DB", 5, 246, AI_RHINO, 3, 12, 28, 2, 3, 0, 0, 0 }, + { MT_XSKELSD, "Shadowdrinker", "SHDR", 5, 300, AI_SNEAK, 1, 18, 26, 78, 8, 45, 0, 0 }, + { MT_UNSEEN, "Hazeshifter", "BHKA", 5, 285, AI_SNEAK, 3, 18, 30, 96, 3, 0, 0, 0 }, + { MT_NACID, "Deathspit", "BFDS", 6, 303, AI_ACIDUNIQ, 0, 12, 32, 6, 3, 0, 0, 0 }, + { MT_RGOATMC, "Bloodgutter", "BGBL", 6, 315, AI_BAT, 1, 24, 34, 16, 3, 0, 0, 0 }, + { MT_BGOATMC, "Deathshade Fleshmaul", "DSFM", 6, 276, AI_RHINO, 0, 12, 24, 10, 8, 65, 0, 0 }, + { MT_WYRM, "Warmaggot the Mad", "GENERAL", 6, 246, AI_BAT, 3, 15, 30, 4, 3, 0, 0, 0 }, + { MT_STORM, "Glasskull the Jagged", "BHKA", 7, 354, AI_STORM, 0, 18, 30, 88, 3, 0, 0, 0 }, + { MT_RGOATBW, "Blightfire", "BLF", 7, 321, AI_SUCC, 2, 13, 21, 16, 3, 0, 0, 0 }, + { MT_GARGOYLE, "Nightwing the Cold", "GENERAL", 7, 342, AI_BAT, 1, 18, 26, 76, 3, 0, 0, 0 }, + { MT_GGOATBW, "Gorestone", "GENERAL", 7, 303, AI_GOATBOW, 1, 15, 28, 68, 7, 70, 0, 0 }, + { MT_BMAGMA, "Bronzefist Firestone", "GENERAL", 8, 360, AI_MAGMA, 0, 30, 36, 10, 3, 0, 0, 0 }, + { MT_INCIN, "Wrathfire the Doomed", "WFTD", 8, 270, AI_SKELSD, 2, 20, 30, 14, 3, 0, 0, 0 }, + { MT_NMAGMA, "Firewound the Grim", "BHKA", 8, 303, AI_MAGMA, 0, 18, 22, 10, 3, 0, 0, 0 }, + { MT_MUDMAN, "Baron Sludge", "BSM", 8, 315, AI_SNEAK, 3, 25, 34, 78, 11, 75, 0, 0 }, + { MT_GGOATMC, "Blighthorn Steelmace", "BHSM", 7, 250, AI_RHINO, 0, 20, 28, 4, 11, 45, 0, 0 }, + { MT_RACID, "Chaoshowler", "GENERAL", 8, 240, AI_ACIDUNIQ, 0, 12, 20, 0, 3, 0, 0, 0 }, + { MT_REDDTH, "Doomgrin the Rotting", "GENERAL", 8, 405, AI_STORM, 3, 25, 50, 78, 3, 0, 0, 0 }, + { MT_FLAMLRD, "Madburner", "GENERAL", 9, 270, AI_STORM, 0, 20, 40, 56, 3, 0, 0, 0 }, + { MT_LTCHDMN, "Bonesaw the Litch", "GENERAL", 9, 495, AI_STORM, 2, 30, 55, 78, 3, 0, 0, 0 }, + { MT_MUDRUN, "Breakspine", "GENERAL", 9, 351, AI_RHINO, 0, 25, 34, 2, 3, 0, 0, 0 }, + { MT_REDDTH, "Devilskull Sharpbone", "GENERAL", 9, 444, AI_STORM, 1, 25, 40, 16, 3, 0, 0, 0 }, + { MT_STORM, "Brokenstorm", "GENERAL", 9, 411, AI_STORM, 2, 25, 36, 32, 3, 0, 0, 0 }, + { MT_RSTORM, "Stormbane", "GENERAL", 9, 555, AI_STORM, 3, 30, 30, 32, 3, 0, 0, 0 }, + { MT_TOAD, "Oozedrool", "GENERAL", 9, 483, AI_FAT, 3, 25, 30, 4, 3, 0, 0, 0 }, + { MT_BLOODCLW, "Goldblight of the Flame", "GENERAL", 10, 405, AI_GARG, 0, 15, 35, 24, 11, 80, 0, 0 }, + { MT_OBLORD, "Blackstorm", "GENERAL", 10, 525, AI_RHINO, 3, 20, 40, 40, 11, 90, 0, 0 }, + { MT_RACID, "Plaguewrath", "GENERAL", 10, 450, AI_ACIDUNIQ, 2, 20, 30, 74, 3, 0, 0, 0 }, + { MT_RSTORM, "The Flayer", "GENERAL", 10, 501, AI_STORM, 1, 20, 35, 99, 3, 0, 0, 0 }, + { MT_FROSTC, "Bluehorn", "GENERAL", 11, 477, AI_RHINO, 1, 25, 30, 10, 11, 90, 0, 0 }, + { MT_HELLBURN, "Warpfire Hellspawn", "GENERAL", 11, 525, AI_FIREMAN, 3, 10, 40, 17, 3, 0, 0, 0 }, + { MT_NSNAKE, "Fangspeir", "GENERAL", 11, 444, AI_SKELSD, 1, 15, 32, 80, 3, 0, 0, 0 }, + { MT_UDEDBLRG, "Festerskull", "GENERAL", 11, 600, AI_STORM, 2, 15, 30, 72, 3, 0, 0, 0 }, + { MT_NBLACK, "Lionskull the Bent", "GENERAL", 12, 525, AI_SKELSD, 2, 25, 25, 120, 3, 0, 0, 0 }, + { MT_COUNSLR, "Blacktongue", "GENERAL", 12, 360, AI_COUNSLR, 3, 15, 30, 66, 3, 0, 0, 0 }, + { MT_DEATHW, "Viletouch", "GENERAL", 12, 525, AI_GARG, 3, 20, 40, 96, 3, 0, 0, 0 }, + { MT_RSNAKE, "Viperflame", "GENERAL", 12, 570, AI_SKELSD, 1, 25, 35, 20, 3, 0, 0, 0 }, + { MT_BSNAKE, "Fangskin", "BHKA", 14, 681, AI_SKELSD, 2, 15, 50, 12, 3, 0, 0, 0 }, + { MT_SUCCUBUS, "Witchfire the Unholy", "GENERAL", 12, 444, AI_SUCC, 3, 10, 20, 28, 3, 0, 0, 0 }, + { MT_BALROG, "Blackskull", "BHKA", 13, 750, AI_SKELSD, 3, 25, 40, 12, 3, 0, 0, 0 }, + { MT_UNRAV, "Soulslash", "GENERAL", 12, 450, AI_SKELSD, 0, 25, 25, 72, 3, 0, 0, 0 }, + { MT_VTEXLRD, "Windspawn", "GENERAL", 12, 711, AI_SKELSD, 1, 35, 40, 24, 3, 0, 0, 0 }, + { MT_GSNAKE, "Lord of the Pit", "GENERAL", 13, 762, AI_SKELSD, 2, 25, 42, 66, 3, 0, 0, 0 }, + { MT_RTBLACK, "Rustweaver", "GENERAL", 13, 400, AI_SKELSD, 3, 1, 60, 120, 0, 0, 0, 0 }, + { MT_HOLOWONE, "Howlingire the Shade", "GENERAL", 13, 450, AI_SKELSD, 2, 40, 75, 6, 3, 0, 0, 0 }, + { MT_MAEL, "Doomcloud", "GENERAL", 13, 612, AI_STORM, 1, 1, 60, 34, 0, 0, 0, 0 }, + { MT_PAINMSTR, "Bloodmoon Soulfire", "GENERAL", 13, 684, AI_SKELSD, 1, 15, 40, 14, 3, 0, 0, 0 }, + { MT_SNOWWICH, "Witchmoon", "GENERAL", 13, 310, AI_SUCC, 3, 30, 40, 4, 0, 0, 0, 0 }, + { MT_VTEXLRD, "Gorefeast", "GENERAL", 13, 771, AI_SKELSD, 3, 20, 55, 66, 0, 0, 0, 0 }, + { MT_RTBLACK, "Graywar the Slayer", "GENERAL", 14, 672, AI_SKELSD, 1, 30, 50, 68, 0, 0, 0, 0 }, + { MT_MAGISTR, "Dreadjudge", "GENERAL", 14, 540, AI_COUNSLR, 1, 30, 40, 14, 3, 0, 0, 0 }, + { MT_HLSPWN, "Stareye the Witch", "GENERAL", 14, 726, AI_SUCC, 2, 30, 50, 16, 0, 0, 0, 0 }, + { MT_BTBLACK, "Steelskull the Hunter", "GENERAL", 14, 831, AI_SKELSD, 3, 40, 50, 68, 0, 0, 0, 0 }, + { MT_RBLACK, "Sir Gorash", "GENERAL", 16, 1050, AI_SKELSD, 1, 20, 60, 64, 0, 0, 0, 0 }, + { MT_CABALIST, "The Vizier", "GENERAL", 15, 850, AI_COUNSLR, 2, 25, 40, 16, 3, 0, 0, 0 }, + { MT_REALWEAV, "Zamphir", "GENERAL", 15, 891, AI_SKELSD, 2, 30, 50, 78, 3, 0, 0, 0 }, + { MT_HLSPWN, "Bloodlust", "GENERAL", 15, 825, AI_SUCC, 1, 20, 55, 104, 0, 0, 0, 0 }, + { MT_HLSPWN, "Webwidow", "GENERAL", 16, 774, AI_SUCC, 1, 20, 50, 88, 0, 0, 0, 0 }, + { MT_SOLBRNR, "Fleshdancer", "GENERAL", 16, 999, AI_SUCC, 3, 30, 50, 74, 0, 0, 0, 0 }, + { MT_OBLORD, "Grimspike", "GENERAL", 19, 534, AI_SNEAK, 1, 25, 40, 74, 3, 0, 0, 0 }, + { MT_STORML, "Doomlock", "GENERAL", 28, 534, AI_SNEAK, 1, 35, 55, 78, 3, 0, 0, 0 }, + { -1, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; +int MWVel[24][3] = +{ + { 256, 512, 1024 }, + { 128, 256, 512 }, + { 85, 170, 341 }, + { 64, 128, 256 }, + { 51, 102, 204 }, + { 42, 85, 170 }, + { 36, 73, 146 }, + { 32, 64, 128 }, + { 28, 56, 113 }, + { 26, 51, 102 }, + { 23, 46, 93 }, + { 21, 42, 85 }, + { 19, 39, 78 }, + { 18, 36, 73 }, + { 17, 34, 68 }, + { 16, 32, 64 }, + { 15, 30, 60 }, + { 14, 28, 57 }, + { 13, 26, 54 }, + { 12, 25, 51 }, + { 12, 24, 48 }, + { 11, 23, 46 }, + { 11, 22, 44 }, + { 10, 21, 42 } +}; +char animletter[7] = "nwahds"; +int left[8] = { 7, 0, 1, 2, 3, 4, 5, 6 }; +int right[8] = { 1, 2, 3, 4, 5, 6, 7, 0 }; +int opposite[8] = { 4, 5, 6, 7, 0, 1, 2, 3 }; +int offset_x[8] = { 1, 0, -1, -1, -1, 0, 1, 1 }; +int offset_y[8] = { 1, 1, 1, 0, -1, -1, -1, 0 }; + +/* unused */ +int rnd5[4] = { 5, 10, 15, 20 }; +int rnd10[4] = { 10, 15, 20, 30 }; +int rnd20[4] = { 20, 30, 40, 50 }; +int rnd60[4] = { 60, 70, 80, 90 }; +// + +void(__fastcall *AiProc[])(int i) = +{ + &MAI_Zombie, + &MAI_Fat, + &MAI_SkelSd, + &MAI_SkelBow, + &MAI_Scav, + &MAI_Rhino, + &MAI_GoatMc, + &MAI_GoatBow, + &MAI_Fallen, + &MAI_Magma, + &MAI_SkelKing, + &MAI_Bat, + &MAI_Garg, + &MAI_Cleaver, + &MAI_Succ, + &MAI_Sneak, + &MAI_Storm, + &MAI_Fireman, + &MAI_Garbud, + &MAI_Acid, + &MAI_AcidUniq, + &MAI_Golum, + &MAI_Zhar, + &MAI_SnotSpil, + &MAI_Snake, + &MAI_Counselor, + &MAI_Mega, + &MAI_Diablo, + &MAI_Lazurus, + &MAI_Lazhelp, + &MAI_Lachdanan, + &MAI_Warlord +}; + +struct monster_cpp_init +{ + monster_cpp_init() + { + monster_cpp_init_value = monster_inf; + } +} _monster_cpp_init; +// 47F130: using guessed type int monster_inf; +// 64CCE4: using guessed type int monster_cpp_init_value; + +void __fastcall InitMonsterTRN(int monst, BOOL special) +{ + BYTE *f = Monsters[monst].trans_file; + for ( int i = 0; i < 256; i++ ) + { + if ( *f == 255 ) + { + *f = 0; + } + f++; + } + + int n = special ? 6 : 5; + for ( int j = 0; j < n; ++j ) + { + if ( j != 1 || Monsters[monst].mtype < MT_COUNSLR || Monsters[monst].mtype > MT_ADVOCATE ) + { + for ( int k = 0; k < 8; k++ ) + { + Cl2ApplyTrans( + Monsters[monst].Anims[j].Frames[k], + Monsters[monst].trans_file, + Monsters[monst].Anims[j].Rate); + } + } + } +} + +void __cdecl InitLevelMonsters() +{ + int i; + + nummtypes = 0; + monstimgtot = 0; + MissileFileFlag = 0; + + for ( i = 0; i < MAX_LVLMTYPES; i++ ) + { + Monsters[i].mPlaceFlags = 0; + } + + ClrAllMonsters(); + nummonsters = 0; + totalmonsters = MAXMONSTERS; + + for ( i = 0; i < MAXMONSTERS; i++ ) + { + monstactive[i] = i; + } + + uniquetrans = 0; +} + +int __fastcall AddMonsterType(int type, int placeflag) +{ + BOOL done = FALSE; + int i; + + for ( i = 0; i < nummtypes && !done; i++ ) + { + done = Monsters[i].mtype == type; + } + + i--; + + if ( !done ) + { + i = nummtypes; + nummtypes++; + Monsters[i].mtype = type; + monstimgtot += monsterdata[type].mType; + InitMonsterGFX(i); + InitMonsterSND(i); + } + + Monsters[i].mPlaceFlags |= placeflag; + return i; +} + +void __cdecl GetLevelMTypes() +{ + int i; + + // this array is merged with skeltypes down below. + int typelist[MAXMONSTERS]; + int skeltypes[NUM_MTYPES]; + + int minl; // min level + int maxl; // max level + char mamask = 3; // monster availability mask + + int nt; // number of types + + AddMonsterType(MT_GOLEM, 2); + if ( currlevel == 16 ) + { + AddMonsterType(MT_ADVOCATE, 1); + AddMonsterType(MT_RBLACK, 1); + AddMonsterType(MT_DIABLO, 2); + return; + } + + if ( !setlevel ) + { + if ( QuestStatus(QTYPE_BUTCH) ) + AddMonsterType(MT_CLEAVER, 2); + if ( QuestStatus(QTYPE_GARB) ) + AddMonsterType(UniqMonst[0].mtype, 4); + if ( QuestStatus(QTYPE_ZHAR) ) + AddMonsterType(UniqMonst[2].mtype, 4); + if ( QuestStatus(QTYPE_BOL) ) + AddMonsterType(UniqMonst[3].mtype, 4); + if ( QuestStatus(QTYPE_VEIL) ) + AddMonsterType(UniqMonst[7].mtype, 4); + if ( QuestStatus(QTYPE_WARLRD) ) + AddMonsterType(UniqMonst[8].mtype, 4); + + if ( gbMaxPlayers != 1 && currlevel == quests[QTYPE_KING]._qlevel ) + { + + AddMonsterType(MT_SKING, 4); + const int numskeltypes = 19; + + nt = 0; + for ( i = MT_WSKELAX; i <= MT_WSKELAX + numskeltypes; i++ ) + { + if ( IsSkel(i) ) + { + minl = 15 * monsterdata[i].mMinDLvl / 30 + 1; + maxl = 15 * monsterdata[i].mMaxDLvl / 30 + 1; + + if ( currlevel >= minl && currlevel <= maxl ) + { + if ( MonstAvailTbl[i] & mamask ) + { + skeltypes[nt++] = i; + } + } + } + } + AddMonsterType(skeltypes[random(88, nt)], 1); + } + + nt = 0; + for ( i = 0; i < 111; i++ ) + { + minl = 15 * monsterdata[i].mMinDLvl / 30 + 1; + maxl = 15 * monsterdata[i].mMaxDLvl / 30 + 1; + + if ( currlevel >= minl && currlevel <= maxl ) + { + if ( MonstAvailTbl[i] & mamask ) + { + typelist[nt++] = i; + } + } + } + + if ( monstdebug ) + { + for ( i = 0; i < debugmonsttypes; i++ ) + AddMonsterType(DebugMonsters[i], 1); + } + else + { + + while ( nt > 0 && nummtypes < MAX_LVLMTYPES && monstimgtot < 4000 ) + { + for ( i = 0; i < nt; ) + { + if ( monsterdata[typelist[i]].mType > 4000 - monstimgtot ) + { + typelist[i] = typelist[--nt]; + continue; + } + + i++; + } + + if ( nt != 0 ) + { + i = random(88, nt); + AddMonsterType(typelist[i], 1); + typelist[i] = typelist[--nt]; + } + } + } + + } + else + { + if ( setlvlnum == SL_SKELKING ) + { + AddMonsterType(MT_SKING, 4); + } + } + +} + +void __fastcall InitMonsterGFX(int monst) +{ + int mtype = (unsigned char)Monsters[monst].mtype; + char strBuff[256]; + + for ( int anim = 0; anim < 6; anim++ ) + { + if ( (animletter[anim] != 's' || monsterdata[mtype].has_special) && monsterdata[mtype].Frames[anim] > 0 ) + { + sprintf(strBuff, monsterdata[mtype].GraphicType, animletter[anim]); + + unsigned char* celBuf = LoadFileInMem(strBuff, NULL); + Monsters[monst].Anims[anim].CMem = celBuf; + + if ( Monsters[monst].mtype != MT_GOLEM || (animletter[anim] != 's' && animletter[anim] != 'd') ) + { + + for ( int i = 0; i < 8; i++ ) + { + Monsters[monst].Anims[anim].Frames[i] = + &celBuf[((int *)celBuf)[i]]; + } + } + else + { + for ( int i = 0; i < 8; i++ ) + { + Monsters[monst].Anims[anim].Frames[i] = celBuf; + } + } + } + + // TODO: either the AnimStruct members have wrong naming or the MonsterData ones it seems + Monsters[monst].Anims[anim].Rate = monsterdata[mtype].Frames[anim]; + Monsters[monst].Anims[anim].Delay = monsterdata[mtype].Rate[anim]; + } + + Monsters[monst].flags_1 = monsterdata[mtype].flags; + Monsters[monst].flags_2 = (monsterdata[mtype].flags - 64) >> 1; + Monsters[monst].mMinHP = monsterdata[mtype].mMinHP; + Monsters[monst].mMaxHP = monsterdata[mtype].mMaxHP; + Monsters[monst].has_special = monsterdata[mtype].has_special; + Monsters[monst].mAFNum = monsterdata[mtype].mAFNum; + Monsters[monst].MData = &monsterdata[mtype]; + + if ( monsterdata[mtype].has_trans ) + { + Monsters[monst].trans_file = LoadFileInMem(monsterdata[mtype].TransFile, NULL); + InitMonsterTRN(monst, monsterdata[mtype].has_special); + + void *trans_file = Monsters[monst].trans_file; + Monsters[monst].trans_file = NULL; + + mem_free_dbg(trans_file); + } + + if ( mtype >= MT_NMAGMA && mtype <= MT_WMAGMA && !(MissileFileFlag & 1) ) + { + MissileFileFlag |= 1; + LoadMissileGFX(MFILE_MAGBALL); + } + if ( mtype >= MT_STORM && mtype <= MT_MAEL && !(MissileFileFlag & 2) ) + { + MissileFileFlag |= 2; + LoadMissileGFX(MFILE_THINLGHT); + } + if ( mtype == MT_SUCCUBUS ) + { + if ( MissileFileFlag & 4 ) return; + + MissileFileFlag |= 4; + LoadMissileGFX(MFILE_FLARE); + LoadMissileGFX(MFILE_FLAREEXP); + } + if ( mtype == MT_SNOWWICH ) + { + if ( MissileFileFlag & 0x20 ) return; + + MissileFileFlag |= 0x20; + LoadMissileGFX(MFILE_SCUBMISB); + LoadMissileGFX(MFILE_SCBSEXPB); + } + if ( mtype == MT_HLSPWN ) + { + if ( MissileFileFlag & 0x40 ) return; + + MissileFileFlag |= 0x40; + LoadMissileGFX(MFILE_SCUBMISD); + LoadMissileGFX(MFILE_SCBSEXPD); + } + if ( mtype == MT_SOLBRNR ) + { + if ( MissileFileFlag & 0x80 ) return; + + MissileFileFlag |= 0x80; + LoadMissileGFX(MFILE_SCUBMISC); + LoadMissileGFX(MFILE_SCBSEXPC); + } + if ( mtype >= MT_INCIN && mtype <= MT_HELLBURN && !(MissileFileFlag & 8) ) + { + MissileFileFlag |= 8; + LoadMissileGFX(MFILE_KRULL); + } + if ( mtype >= MT_NACID && mtype <= MT_XACID && !(MissileFileFlag & 0x10) ) + { + MissileFileFlag |= 0x10; + LoadMissileGFX(MFILE_ACIDBF); + LoadMissileGFX(MFILE_ACIDSPLA); + LoadMissileGFX(MFILE_ACIDPUD); + } + if ( mtype == MT_DIABLO ) + { + LoadMissileGFX(MFILE_FIREPLAR); + } +} + +void __fastcall ClearMVars(int i) +{ + monster[i]._mVar1 = 0; + monster[i]._mVar2 = 0; + monster[i]._mVar3 = 0; + monster[i]._mVar4 = 0; + monster[i]._mVar5 = 0; + monster[i]._mVar6 = 0; + monster[i]._mVar7 = 0; + monster[i]._mVar8 = 0; +} + +void __fastcall InitMonster(int i, int rd, int mtype, int x, int y) +{ + CMonster *monst = &Monsters[mtype]; + + monster[i]._mdir = rd; + monster[i]._mx = x; + monster[i]._my = y; + monster[i]._mfutx = x; + monster[i]._mfuty = y; + monster[i]._moldx = x; + monster[i]._moldy = y; + monster[i]._mmode = MM_STAND; + monster[i]._mMTidx = mtype; + monster[i].mName = monst->MData->mName; + monster[i].MType = monst; + monster[i].MData = monst->MData; + monster[i]._mAnimData = monst->Anims[0].Frames[rd]; + monster[i]._mAnimDelay = monst->Anims[0].Delay; + monster[i]._mAnimCnt = random(88, monst->Anims[0].Delay - 1); + monster[i]._mAnimLen = monst->Anims[0].Rate; + monster[i]._mAnimFrame = random(88, monst->Anims[0].Rate - 1) + 1; + + if ( monst->mtype == MT_DIABLO ) + { + monster[i]._mmaxhp = (random(88, 1) + 1666) << 6; + } + else + { + monster[i]._mmaxhp = (monst->mMinHP + random(88, monst->mMaxHP - monst->mMinHP + 1)) << 6; + } + + if ( gbMaxPlayers == 1 ) + { + monster[i]._mmaxhp >>= 1; + if ( monster[i]._mmaxhp < 64 ) + { + monster[i]._mmaxhp = 64; + } + } + + monster[i]._mhitpoints = monster[i]._mmaxhp; + monster[i]._mAi = monst->MData->mAi; + monster[i]._mint = monst->MData->mInt; + monster[i]._mgoal = 1; + monster[i]._mgoalvar1 = 0; + monster[i]._mgoalvar2 = 0; + monster[i]._mgoalvar3 = 0; + monster[i]._pathcount = 0; + monster[i]._uniqtype = 0; + monster[i]._msquelch = 0; + monster[i].field_18 = 0; + monster[i]._mDelFlag = 0; + monster[i]._mRndSeed = GetRndSeed(); + monster[i]._mAISeed = GetRndSeed(); + monster[i].mWhoHit = 0; + monster[i].mLevel = monst->MData->mLevel; + monster[i].mExp = monst->MData->mExp; + monster[i].mHit = monst->MData->mHit; + monster[i].mMinDamage = monst->MData->mMinDamage; + monster[i].mMaxDamage = monst->MData->mMaxDamage; + monster[i].mHit2 = monst->MData->mHit2; + monster[i].mMinDamage2 = monst->MData->mMinDamage2; + monster[i].mMaxDamage2 = monst->MData->mMaxDamage2; + monster[i].mArmorClass = monst->MData->mArmorClass; + monster[i].mMagicRes = monst->MData->mMagicRes; + monster[i].leader = 0; + monster[i].leaderflag = 0; + monster[i]._mFlags = monst->MData->mFlags; + monster[i].mtalkmsg = 0; + + if ( monster[i]._mAi == AI_GARG ) + { + monster[i]._mAnimData = monst->Anims[5].Frames[rd]; + monster[i]._mAnimFrame = 1; + monster[i]._mFlags |= 4u; + monster[i]._mmode = MM_SATTACK; + } + + if ( gnDifficulty == DIFF_NIGHTMARE ) + { + monster[i].mLevel += 15; + monster[i].mHit += 85; + monster[i].mHit2 += 85; + monster[i]._mmaxhp = 3 * monster[i]._mmaxhp + 64; + monster[i]._mhitpoints = monster[i]._mmaxhp; + monster[i].mExp = 2 * (monster[i].mExp + 1000); + monster[i].mMinDamage = 2 * (monster[i].mMinDamage + 2); + monster[i].mMaxDamage = 2 * (monster[i].mMaxDamage + 2); + monster[i].mMinDamage2 = 2 * (monster[i].mMinDamage2 + 2); + monster[i].mMaxDamage2 = 2 * (monster[i].mMaxDamage2 + 2); + monster[i].mArmorClass += 50; + } + + if ( gnDifficulty == DIFF_HELL ) + { + monster[i].mLevel += 30; + monster[i]._mmaxhp = 4 * monster[i]._mmaxhp + 192; + monster[i]._mhitpoints = monster[i]._mmaxhp; + monster[i].mHit += 120; + monster[i].mHit2 += 120; + monster[i].mExp = 4 * (monster[i].mExp + 1000); + monster[i].mMinDamage = 4 * monster[i].mMinDamage + 6; + monster[i].mMaxDamage = 4 * monster[i].mMaxDamage + 6; + monster[i].mMinDamage2 = 4 * monster[i].mMinDamage2 + 6; + monster[i].mMaxDamage2 = 4 * monster[i].mMaxDamage2 + 6; + monster[i].mArmorClass += 80; + monster[i].mMagicRes = monst->MData->mMagicRes2; + } +} + +void __cdecl ClrAllMonsters() +{ + MonsterStruct *Monst; + + for ( int i = 0; i < 200; i++ ) + { + Monst = &monster[i]; + ClearMVars(i); + Monst->mName = "Invalid Monster"; + Monst->_mgoal = 0; + Monst->_mmode = MM_STAND; + Monst->_mVar1 = 0; + Monst->_mVar2 = 0; + Monst->_mx = 0; + Monst->_my = 0; + Monst->_mfutx = 0; + Monst->_mfuty = 0; + Monst->_moldx = 0; + Monst->_moldy = 0; + Monst->_mdir = random(89, 8); + Monst->_mxvel = 0; + Monst->_myvel = 0; + Monst->_mAnimData = NULL; + Monst->_mAnimDelay = 0; + Monst->_mAnimCnt = 0; + Monst->_mAnimLen = 0; + Monst->_mAnimFrame = 0; + Monst->_mFlags = 0; + Monst->_mDelFlag = 0; + Monst->_menemy = random(89, gbActivePlayers); + Monst->_menemyx = plr[Monst->_menemy]._px; + Monst->_menemyy = plr[Monst->_menemy]._py; + } +} + +BOOL __fastcall MonstPlace(int xp, int yp) +{ + if ( xp < 0 || xp >= 112 + || yp < 0 || yp >= 112 + || dMonster[xp][yp] + || dPlayer[xp][yp] ) + { + return FALSE; + } + + char f = dFlags[xp][yp]; + + // TODO: Add enum values here + if ( f & 2 ) + { + return FALSE; + } + + if ( f & 8 ) + { + return FALSE; + } + + return !SolidLoc(xp, yp); +} + +void __fastcall PlaceMonster(int i, int mtype, int x, int y) +{ + dMonster[x][y] = i + 1; + + int rd = random(90, 8); + InitMonster(i, rd, mtype, x, y); +} + +void __fastcall PlaceUniqueMonst(int uniqindex, int miniontype, int unpackfilesize) +{ + int xp; + int yp; + char filestr[64]; + + UniqMonstStruct *Uniq = &UniqMonst[uniqindex]; + MonsterStruct *Monst = &monster[nummonsters]; + int count = 0; + + if ( (uniquetrans + 19) << 8 >= LIGHTSIZE ) + { + return; + } + + int uniqtype; + for ( uniqtype = 0; uniqtype < nummtypes; uniqtype++ ) + { + if ( Monsters[uniqtype].mtype == Uniq->mtype ) + { + break; + } + } + + while (true) + { + + xp = random(91, 80) + 16; + yp = random(91, 80) + 16; + int count2 = 0; + for ( int x = xp - 3; x < xp + 3; x++ ) + { + for ( int y = yp - 3; y < yp + 3; y++ ) + { + if ( y >= 0 && y < 112 && x >= 0 && x < 112 && MonstPlace(x, y) ) + { + count2++; + } + } + } + + if ( count2 < 9 ) { + count++; + if ( count < 1000 ) + { + continue; + } + } + + + if ( MonstPlace(xp, yp) ) + { + break; + } + } + + if ( uniqindex == 3 ) + { + xp = 2 * setpc_x + 24; + yp = 2 * setpc_y + 28; + } + if ( uniqindex == 8 ) + { + xp = 2 * setpc_x + 22; + yp = 2 * setpc_y + 23; + } + if ( uniqindex == 2 ) + { + BOOL zharflag = TRUE; + for ( int i = 0; i < themeCount; i++ ) + { + if ( i == zharlib && zharflag == TRUE ) + { + zharflag = FALSE; + xp = 2 * themeLoc[i].x + 20; + yp = 2 * themeLoc[i].y + 20; + } + } + } + if ( gbMaxPlayers == 1 ) + { + if ( uniqindex == 4 ) + { + xp = 32; + yp = 46; + } + if ( uniqindex == 5 ) + { + xp = 40; + yp = 45; + } + if ( uniqindex == 6 ) + { + xp = 38; + yp = 49; + } + if ( uniqindex == 1 ) + { + xp = 35; + yp = 47; + } + } + else + { + if ( uniqindex == 4 ) + { + xp = 2 * setpc_x + 19; + yp = 2 * setpc_y + 22; + } + if ( uniqindex == 5 ) + { + xp = 2 * setpc_x + 21; + yp = 2 * setpc_y + 19; + } + if ( uniqindex == 6 ) + { + xp = 2 * setpc_x + 21; + yp = 2 * setpc_y + 25; + } + } + if ( uniqindex == 9 ) + { + BOOL done = FALSE; + for ( yp = 0; yp < 112 && !done; yp++ ) + { + for ( xp = 0; xp < 112 && !done; xp++ ) + { + done = dPiece[xp][yp] == 367; + } + } + } + + PlaceMonster(nummonsters, uniqtype, xp, yp); + Monst->_uniqtype = uniqindex + 1; + + if ( Uniq->mlevel ) + { + Monst->mLevel = 2 * Uniq->mlevel; + } + else + { + Monst->mLevel += 5; + } + + Monst->mExp *= 2; + Monst->mName = Uniq->mName; + Monst->_mmaxhp = Uniq->mmaxhp << 6; + + if ( gbMaxPlayers == 1 ) + { + Monst->_mmaxhp = Monst->_mmaxhp >> 1; + if ( Monst->_mmaxhp < 64 ) + { + Monst->_mmaxhp = 64; + } + } + + Monst->_mhitpoints = Monst->_mmaxhp; + Monst->_mAi = Uniq->mAi; + Monst->_mint = Uniq->mint; + Monst->mMinDamage = Uniq->mMinDamage; + Monst->mMaxDamage = Uniq->mMaxDamage; + Monst->mMinDamage2 = Uniq->mMinDamage; + Monst->mMaxDamage2 = Uniq->mMaxDamage; + Monst->mMagicRes = Uniq->mMagicRes; + Monst->mtalkmsg = Uniq->mtalkmsg; + Monst->mlid = AddLight(Monst->_mx, Monst->_my, 3); + + if ( gbMaxPlayers == 1 ) + { + if ( Monst->mtalkmsg ) + { + Monst->_mgoal = 6; + } + } + else + { + if ( Monst->_mAi == AI_LAZHELP ) + { + Monst->mtalkmsg = 0; + } + + if ( Monst->_mAi != AI_LAZURUS || quests[15]._qvar1 <= 3 ) + { + if ( Monst->mtalkmsg ) + { + Monst->_mgoal = 6; + } + } + else + { + Monst->_mgoal = 1; + } + } + + if ( gnDifficulty == DIFF_NIGHTMARE ) + { + Monst->mLevel += 15; + Monst->_mmaxhp = 3 * Monst->_mmaxhp + 64; + Monst->_mhitpoints = Monst->_mmaxhp; + Monst->mExp = 2 * (Monst->mExp + 1000); + Monst->mMinDamage = 2 * (Monst->mMinDamage + 2); + Monst->mMaxDamage = 2 * (Monst->mMaxDamage + 2); + Monst->mMinDamage2 = 2 * (Monst->mMinDamage2 + 2); + Monst->mMaxDamage2 = 2 * (Monst->mMaxDamage2 + 2); + } + + if ( gnDifficulty == DIFF_HELL ) + { + Monst->mLevel += 30; + Monst->_mmaxhp = 4 * Monst->_mmaxhp + 192; + Monst->_mhitpoints = Monst->_mmaxhp; + Monst->mExp = 4 * (Monst->mExp + 1000); + Monst->mMinDamage = 4 * Monst->mMinDamage + 6; + Monst->mMaxDamage = 4 * Monst->mMaxDamage + 6; + Monst->mMinDamage2 = 4 * Monst->mMinDamage2 + 6; + Monst->mMaxDamage2 = 4 * Monst->mMaxDamage2 + 6; + } + + sprintf(filestr, "Monsters\\Monsters\\%s.TRN", Uniq->mMode); + LoadFileWithMem(filestr, &pLightTbl[256 * (uniquetrans + 19)]); + + Monst->_uniqtrans = uniquetrans++; + + if ( Uniq->mUnqAttr & 4 ) + { + Monst->mHit = Uniq->mUnqVar1; + Monst->mHit2 = Uniq->mUnqVar1; + } + if ( Uniq->mUnqAttr & 8 ) + { + Monst->mArmorClass = Uniq->mUnqVar1; + } + + nummonsters++; + + if ( Uniq->mUnqAttr & 1 ) + { + PlaceGroup(miniontype, unpackfilesize, Uniq->mUnqAttr, nummonsters - 1); + } + + if ( Monst->_mAi != AI_GARG ) + { + Monst->_mAnimData = Monst->MType->Anims[0].Frames[Monst->_mdir]; + Monst->_mAnimFrame = random(88, Monst->_mAnimLen - 1) + 1; + Monst->_mFlags &= 0xFFFFFFFB; + Monst->_mmode = MM_STAND; + } +} + +void __cdecl PlaceQuestMonsters() +{ + int skeltype; + unsigned char *setp; + + if ( !setlevel ) + { + if ( QuestStatus(QTYPE_BUTCH) ) + { + PlaceUniqueMonst(9, 0, 0); + } + + if ( currlevel == quests[12]._qlevel && gbMaxPlayers != 1 ) + { + skeltype = 0; + + for ( skeltype = 0; skeltype < nummtypes; skeltype++ ) + { + if ( IsSkel(Monsters[skeltype].mtype) ) + { + break; + } + } + + PlaceUniqueMonst(1, skeltype, 30); + } + + if ( QuestStatus(QTYPE_BOL) ) + { + setp = LoadFileInMem("Levels\\L1Data\\Banner1.DUN", 0); + SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y); + mem_free_dbg(setp); + } + if ( QuestStatus(QTYPE_BLOOD) ) + { + setp = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", 0); + SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y); + mem_free_dbg(setp); + } + if ( QuestStatus(QTYPE_BLIND) ) + { + setp = LoadFileInMem("Levels\\L2Data\\Blind2.DUN", 0); + SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y); + mem_free_dbg(setp); + } + if ( QuestStatus(QTYPE_ANVIL) ) + { + setp = LoadFileInMem("Levels\\L3Data\\Anvil.DUN", 0); + SetMapMonsters(setp, 2 * setpc_x + 2, 2 * setpc_y + 2); + mem_free_dbg(setp); + } + if ( QuestStatus(QTYPE_WARLRD) ) + { + setp = LoadFileInMem("Levels\\L4Data\\Warlord.DUN", 0); + SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y); + mem_free_dbg(setp); + AddMonsterType(UniqMonst[8].mtype, 1); + } + if ( QuestStatus(QTYPE_VEIL) ) + { + AddMonsterType(UniqMonst[7].mtype, 1); + } + if ( QuestStatus(QTYPE_ZHAR) && zharlib == -1 ) + { + quests[3]._qactive = 0; + } + + if ( currlevel == quests[15]._qlevel && gbMaxPlayers != 1 ) + { + AddMonsterType(UniqMonst[4].mtype, 4); + AddMonsterType(UniqMonst[5].mtype, 4); + PlaceUniqueMonst(4, 0, 0); + PlaceUniqueMonst(5, 0, 0); + PlaceUniqueMonst(6, 0, 0); + setp = LoadFileInMem("Levels\\L4Data\\Vile1.DUN", 0); + SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y); + mem_free_dbg(setp); + } + } + else + { + if ( setlvlnum == SL_SKELKING ) + { + PlaceUniqueMonst(1, 0, 0); + } + } +} + +void __fastcall PlaceGroup(int mtype, int num, int leaderf, int leader) +{ + int placed = 0; + int xp; + int yp; + int x1; + int y1; + + for ( int try1 = 0; try1 < 10; try1++ ) + { + while ( placed ) + { + nummonsters--; + placed--; + dMonster[monster[nummonsters]._mx][monster[nummonsters]._my] = 0; + } + + if ( leaderf & 1 ) + { + int offset = random(92, 8); + xp = monster[leader]._mx + offset_x[offset]; + yp = monster[leader]._my + offset_y[offset]; + x1 = xp; + y1 = yp; + } + else + { + do + { + xp = random(93, 80) + 16; + x1 = xp; + yp = random(93, 80) + 16; + y1 = yp; + } + while ( !MonstPlace(xp, yp) ); + } + + if ( num + nummonsters > totalmonsters ) + { + num = totalmonsters - nummonsters; + } + + int j = 0; + for ( int try2 = 0; j < num && try2 < 100; xp += offset_x[random(94, 8)], yp += offset_x[random(94, 8)] ) + { + if ( !MonstPlace(xp, yp) + || (dung_map[x1][y1] != dung_map[xp][yp]) + || (leaderf & 2) && ((abs(xp - x1) >= 4) || (abs(yp - y1) >= 4)) ) + { + try2++; + continue; + } + + PlaceMonster(nummonsters, mtype, xp, yp); + if ( leaderf & 1 ) + { + monster[nummonsters]._mmaxhp *= 2; + monster[nummonsters]._mhitpoints = monster[nummonsters]._mmaxhp; + monster[nummonsters]._mint = monster[leader]._mint; + + if ( leaderf & 2 ) + { + monster[nummonsters].leader = leader; + monster[nummonsters].leaderflag = 1; + monster[nummonsters]._mAi = monster[leader]._mAi; + } + + if ( monster[nummonsters]._mAi != AI_GARG ) + { + monster[nummonsters]._mAnimData = monster[nummonsters].MType->Anims[0].Frames[monster[nummonsters]._mdir]; + monster[nummonsters]._mAnimFrame = random(88, monster[nummonsters]._mAnimLen - 1) + 1; + monster[nummonsters]._mFlags &= 0xFFFFFFFB; + monster[nummonsters]._mmode = MM_STAND; + } + + } + nummonsters++; + placed++; + j++; + } + + if ( placed >= num ) + { + break; + } + } + + if ( leaderf & 2 ) + { + monster[leader].unpackfilesize = placed; + } +} + +void __cdecl LoadDiabMonsts() +{ + unsigned char *lpSetPiece; // esi + + lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab1.DUN", 0); + SetMapMonsters(lpSetPiece, 2 * diabquad1x, 2 * diabquad1y); + mem_free_dbg(lpSetPiece); + lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab2a.DUN", 0); + SetMapMonsters(lpSetPiece, 2 * diabquad2x, 2 * diabquad2y); + mem_free_dbg(lpSetPiece); + lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab3a.DUN", 0); + SetMapMonsters(lpSetPiece, 2 * diabquad3x, 2 * diabquad3y); + mem_free_dbg(lpSetPiece); + lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab4a.DUN", 0); + SetMapMonsters(lpSetPiece, 2 * diabquad4x, 2 * diabquad4y); + mem_free_dbg(lpSetPiece); +} +// 5289C4: using guessed type int diabquad1x; +// 5289C8: using guessed type int diabquad1y; + +void __cdecl InitMonsters() +{ + int v0; // ebp + int v1; // ebx + TriggerStruct *v2; // esi + signed int v3; // ebp + signed int v4; // edi + int v5; // edi + int v6; // esi + int v7; // eax + int v8; // ecx + int v9; // edx + int v10; // eax + int v11; // esi + unsigned char *v12; // edi + int v13; // ebx + int v15; // esi + int v17; // eax + int v18; // eax + int v19; // ebx + TriggerStruct *v20; // esi + signed int v21; // ebp + signed int v22; // edi + int max; // [esp+10h] [ebp-1C4h] + int v24; // [esp+14h] [ebp-1C0h] + int scattertypes[111]; // [esp+18h] [ebp-1BCh] + + v0 = 0; + max = 0; + if ( gbMaxPlayers != 1 ) + CheckDungeonClear(); + if ( !setlevel ) + { + AddMonster(1, 0, 0, 0, 0); + AddMonster(1, 0, 0, 0, 0); + AddMonster(1, 0, 0, 0, 0); + AddMonster(1, 0, 0, 0, 0); + if ( !setlevel && currlevel == 16 ) + LoadDiabMonsts(); + } + v24 = trigflag[4]; + if ( currlevel == 15 ) + v24 = 1; + v1 = v24; + if ( v24 > 0 ) + { + v2 = trigs; + do + { + v3 = -2; + do + { + v4 = -2; + do + DoVision(v3 + v2->_tx, v4++ + v2->_ty, 15, 0, 0); + while ( v4 < 2 ); + ++v3; + } + while ( v3 < 2 ); + ++v2; + --v1; + } + while ( v1 ); + v0 = 0; + } + PlaceQuestMonsters(); + if ( !setlevel ) + { + PlaceUniques(); + v5 = 16; + do + { + v6 = 16; + do + { + if ( !SolidLoc(v5, v6) ) + ++v0; + ++v6; + } + while ( v6 < 96 ); + ++v5; + } + while ( v5 < 96 ); + v7 = v0 / 30; + if ( gbMaxPlayers != 1 ) + v7 += v7 >> 1; + v8 = nummonsters; + if ( nummonsters + v7 > 190 ) + v7 = 190 - nummonsters; + v9 = nummtypes; + v10 = nummonsters + v7; + v11 = 0; + totalmonsters = v10; + if ( nummtypes > 0 ) + { + v12 = &Monsters[0].mPlaceFlags; + do + { + if ( *v12 & 1 ) + { + v13 = max++; + scattertypes[v13] = v11; + } + ++v11; + v12 += 328; + } + while ( v11 < v9 ); + } + if ( v8 < v10 ) + { + while ( 1 ) + { + v15 = scattertypes[random(95, max)]; + if ( currlevel == 1 ) + break; + if ( !random(95, 2) ) + break; + if ( currlevel == 2 ) + { + v17 = random(95, 2) + 1; + LABEL_40: + v18 = v17 + 1; + goto LABEL_41; + } + v18 = random(95, 3) + 3; + LABEL_41: + PlaceGroup(v15, v18, 0, 0); + if ( nummonsters >= totalmonsters ) + goto LABEL_42; + } + v17 = 0; + goto LABEL_40; + } + } +LABEL_42: + v19 = v24; + if ( v24 > 0 ) + { + v20 = trigs; + do + { + v21 = -2; + do + { + v22 = -2; + do + DoUnVision(v21 + v20->_tx, v22++ + v20->_ty, 15); + while ( v22 < 2 ); + ++v21; + } + while ( v21 < 2 ); + ++v20; + --v19; + } + while ( v19 ); + } +} +// 5CF31D: using guessed type char setlevel; +// 658550: using guessed type int totalmonsters; +// 679660: using guessed type char gbMaxPlayers; +// 432637: using guessed type int var_1BC[111]; + +void __cdecl PlaceUniques() +{ + int v0; // edi + int v1; // eax + UniqMonstStruct *v2; // ecx + int v3; // eax + int v4; // edx + CMonster *v5; // esi + int v6; // eax + int v7; // edx + + v0 = 0; + if ( UniqMonst[0].mtype != -1 ) + { + v1 = 0; + v2 = UniqMonst; + while ( UniqMonst[v1].mlevel != currlevel ) + { + LABEL_25: + v1 = ++v0; + v2 = &UniqMonst[v0]; + if ( v2->mtype == -1 ) + return; + } + v3 = 0; + v4 = 0; + if ( nummtypes > 0 ) + { + v5 = Monsters; + do + { + if ( v3 ) + break; + v6 = -((char)v2->mtype != (unsigned char)v5->mtype); + ++v5; + v3 = v6 + 1; + ++v4; + } + while ( v4 < nummtypes ); + } + v7 = v4 - 1; + if ( !v0 ) + { + if ( quests[2]._qactive ) + goto LABEL_23; + v3 = 0; + } + if ( v0 == 2 ) + { + if ( quests[3]._qactive ) + goto LABEL_23; + v3 = 0; + } + if ( v0 == 3 ) + { + if ( quests[7]._qactive ) + goto LABEL_23; + v3 = 0; + } + if ( v0 != 7 ) + { + LABEL_20: + if ( v0 == 8 && !quests[11]._qactive ) + v3 = 0; + goto LABEL_23; + } + if ( !quests[4]._qactive ) + { + v3 = 0; + goto LABEL_20; + } + LABEL_23: + if ( v3 ) + PlaceUniqueMonst(v0, v7, 8); + goto LABEL_25; + } +} + +void __fastcall SetMapMonsters(unsigned char *pMap, int startx, int starty) +{ + unsigned char *v3; // esi + unsigned short v4; // cx + int v5; // edx + int v6; // edi + int v7; // ecx + unsigned char *v8; // edx + int i; // esi + int v10; // eax + int v11; // ecx + int v12; // [esp+Ch] [ebp-Ch] + int v13; // [esp+10h] [ebp-8h] + unsigned char *v14; // [esp+14h] [ebp-4h] + int startya; // [esp+20h] [ebp+8h] + + v12 = startx; + v3 = pMap; + AddMonsterType(MT_GOLEM, 2); + AddMonster(1, 0, 0, 0, 0); + AddMonster(1, 0, 0, 0, 0); + AddMonster(1, 0, 0, 0, 0); + AddMonster(1, 0, 0, 0, 0); + if ( setlevel && setlvlnum == SL_VILEBETRAYER ) + { + AddMonsterType((char)UniqMonst[4].mtype, 4); + AddMonsterType((char)UniqMonst[5].mtype, 4); + AddMonsterType((char)UniqMonst[6].mtype, 4); + PlaceUniqueMonst(4, 0, 0); + PlaceUniqueMonst(5, 0, 0); + PlaceUniqueMonst(6, 0, 0); + } + v4 = *((_WORD *)v3 + 1); + v5 = *(unsigned short *)v3 * v4; + v6 = (unsigned short)(2 * *(_WORD *)v3); + v7 = (unsigned short)(2 * v4); + v8 = &v3[2 * v5 + 4 + 2 * v7 * v6]; + v14 = v8; + if ( v7 > 0 ) + { + v13 = v7; + startya = starty + 16; + do + { + for ( i = 0; i < v6; v14 += 2 ) + { + if ( *(_WORD *)v8 ) + { + v10 = AddMonsterType(MonstConvTbl[*(unsigned short *)v8 - 1], 2); /* fix */ + v11 = nummonsters++; + PlaceMonster(v11, v10, i + v12 + 16, startya); + } + v8 = v14 + 2; + ++i; + } + ++startya; + --v13; + } + while ( v13 ); + } +} +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +void __fastcall DeleteMonster(int i) +{ + int *v1; // ecx + int *v2; // eax + int v3; // edx + + --nummonsters; + v1 = &monstactive[i]; + v2 = &monstactive[nummonsters]; + v3 = *v2; + *v2 = *v1; + *v1 = v3; +} + +int __fastcall AddMonster(int x, int y, int dir, int mtype, int InMap) +{ + int i; // esi + + if ( nummonsters >= MAXMONSTERS ) + return -1; + i = monstactive[nummonsters++]; + if ( InMap ) + dMonster[x][y] = i + 1; + InitMonster(i, dir, mtype, x, y); + return i; +} + +void __fastcall NewMonsterAnim(int i, AnimStruct *anim, int md) +{ + MonsterStruct *v3; // eax + int v4; // esi + int v5; // edx + + v3 = &monster[i]; + v3->_mAnimData = anim->Frames[md]; + v4 = anim->Rate; + v3->_mAnimCnt = 0; + v3->_mAnimLen = v4; + v3->_mAnimFrame = 1; + v5 = anim->Delay; + v3->_mFlags &= 0xFFFFFFF9; + v3->_mAnimDelay = v5; + v3->_mdir = md; +} + +bool __fastcall M_Ranged(int i) +{ + char v1; // cl + + v1 = monster[i]._mAi; + return v1 == AI_SKELBOW || v1 == AI_GOATBOW || v1 == AI_SUCC || v1 == AI_LAZHELP; +} + +bool __fastcall M_Talker(int i) +{ + char v1; // cl + + v1 = monster[i]._mAi; + return v1 == AI_LAZURUS + || v1 == AI_WARLORD + || v1 == AI_GARBUD + || v1 == AI_ZHAR + || v1 == AI_SNOTSPIL + || v1 == AI_LACHDAN + || v1 == AI_LAZHELP; +} + +void __fastcall M_Enemy(int i) +{ + MonsterStruct *v1; // esi + int *v2; // edi + int v3; // eax + int v4; // ecx + int v5; // ebx + int v6; // eax + int v7; // eax + int v8; // eax + int v9; // ecx + int v10; // edi + //int v11; // edx + int v12; // eax + int v13; // ecx + int v14; // ebx + int v15; // eax + int v16; // eax + int v17; // [esp+Ch] [ebp-20h] + int v18; // [esp+10h] [ebp-1Ch] + BOOL v19; // [esp+14h] [ebp-18h] + BOOL v20; // [esp+14h] [ebp-18h] + signed int v21; // [esp+18h] [ebp-14h] + int j; // [esp+18h] [ebp-14h] + signed int v23; // [esp+1Ch] [ebp-10h] + signed int v24; // [esp+20h] [ebp-Ch] + BOOL v25; // [esp+24h] [ebp-8h] + char v26; // [esp+2Ah] [ebp-2h] + char v27; // [esp+2Bh] [ebp-1h] + + v24 = -1; + v18 = i; + v23 = -1; + v1 = &monster[i]; + v25 = 0; + if ( !(v1->_mFlags & 0x20) ) + { + v21 = 0; + v2 = &plr[0].plrlevel; + do + { + if ( !*((_BYTE *)v2 - 23) || currlevel != *v2 || *((_BYTE *)v2 + 267) || !v2[89] && gbMaxPlayers != 1 ) + goto LABEL_18; + v3 = v1->_my; + v4 = v2[2]; + v19 = dung_map[v2[1]][v4] == dung_map[v1->_mx][v3]; + v5 = abs(v3 - v4); + if ( abs(v1->_mx - v2[1]) <= v5 ) + v6 = v1->_my - v2[2]; + else + v6 = v1->_mx - v2[1]; + v7 = abs(v6); + if ( v19 ) + { + if ( !v25 ) + goto LABEL_17; + } + else if ( v25 ) + { + goto LABEL_16; + } + if ( v7 < v23 ) + goto LABEL_17; + LABEL_16: + if ( v24 == -1 ) + { + LABEL_17: + v1->_mFlags &= 0xFFFFFFEF; + v24 = v21; + v27 = *((_BYTE *)v2 + 12); + v26 = *((_BYTE *)v2 + 16); + v23 = v7; + v25 = v19; + } + LABEL_18: + ++v21; + v2 += 5430; + } + while ( (signed int)v2 < (signed int)&plr[4].plrlevel ); + } + v8 = 0; + for ( j = 0; j < nummonsters; v8 = j++ + 1 ) + { + v9 = monstactive[v8]; + v17 = monstactive[v8]; + if ( v9 == v18 ) + continue; + v10 = v9; + if ( monster[v9]._mx == 1 && !monster[v10]._my ) + continue; + if ( M_Talker(v9) && monster[v10].mtalkmsg ) + continue; + if ( !(v1->_mFlags & 0x20) + && ((abs(monster[v10]._mx - v1->_mx) >= 2 || abs(monster[v10]._my - v1->_my) >= 2) && !M_Ranged(v18) /* v11 */ + || !(v1->_mFlags & 0x20) && !(monster[v10]._mFlags & 0x20)) ) + { + continue; + } + v12 = v1->_my; + v13 = monster[v10]._my; + v20 = dung_map[monster[v10]._mx][v13] == dung_map[v1->_mx][v12]; + v14 = abs(v12 - v13); + if ( abs(v1->_mx - monster[v10]._mx) <= v14 ) + v15 = v1->_my - monster[v10]._my; + else + v15 = v1->_mx - monster[v10]._mx; + v16 = abs(v15); + if ( v20 ) + { + if ( !v25 ) + goto LABEL_40; + } + else if ( v25 ) + { + goto LABEL_39; + } + if ( v16 < v23 ) + goto LABEL_40; + LABEL_39: + if ( v24 == -1 ) + { + LABEL_40: + v1->_mFlags |= 0x10u; + v24 = v17; + v27 = monster[v10]._mfutx; + v26 = monster[v10]._mfuty; + v23 = v16; + v25 = v20; + } + } + if ( v24 == -1 ) + { + BYTE1(v1->_mFlags) |= 4u; + } + else + { + BYTE1(v1->_mFlags) &= 0xFBu; + v1->_menemy = v24; + v1->_menemyx = v27; + v1->_menemyy = v26; + } +} +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall M_GetDir(int i) +{ + return GetDirection( + monster[i]._mx, + monster[i]._my, + (unsigned char)monster[i]._menemyx, + (unsigned char)monster[i]._menemyy); +} + +void __fastcall M_CheckEFlag(int i) +{ + int v1; // ecx + int v2; // edi + char *v3; // eax + signed int v4; // edx + + v1 = i; + v2 = 0; + v3 = (char *)dpiece_defs_map_2 + 32 * (112 * (monster[v1]._mx - 1) + monster[v1]._my + 1); + if ( v3 < (char *)dpiece_defs_map_2 ) + goto LABEL_9; + v4 = 2; + do + v2 |= *(unsigned short *)&v3[2 * v4++]; + while ( v4 < 10 ); + if ( v2 | dArch[monster[v1]._mx - 1][monster[v1]._my + 1] ) + monster[v1]._meflag = 1; + else + LABEL_9: + monster[v1]._meflag = 0; +} + +void __fastcall M_StartStand(int i, int md) +{ + int v2; // ebx + int v3; // edi + int v4; // esi + CMonster *v5; // eax + AnimStruct *v6; // edx + int v7; // eax + int v8; // ecx + + v2 = md; + v3 = i; + ClearMVars(i); + v4 = v3; + v5 = monster[v3].MType; + v6 = &v5->Anims[1]; + if ( v5->mtype != MT_GOLEM ) + v6 = v5->Anims; + NewMonsterAnim(v3, v6, v2); + monster[v4]._mdir = v2; + monster[v4]._mVar1 = monster[v4]._mmode; + monster[v4]._mVar2 = 0; + monster[v4]._mmode = MM_STAND; + v7 = monster[v4]._mx; + monster[v4]._mxoff = 0; + monster[v4]._myoff = 0; + v8 = monster[v4]._my; + monster[v4]._mfuty = v8; + monster[v4]._moldy = v8; + monster[v4]._mfutx = v7; + monster[v4]._moldx = v7; + M_CheckEFlag(v3); + M_Enemy(v3); +} + +void __fastcall M_StartDelay(int i, int len) +{ + int v2; // eax + + if ( len > 0 ) + { + v2 = i; + if ( monster[i]._mAi != AI_LAZURUS ) + { + monster[v2]._mVar2 = len; + monster[v2]._mmode = MM_DELAY; + } + } +} + +void __fastcall M_StartSpStand(int i, int md) +{ + int v2; // ebx + int v3; // esi + int v4; // edi + int v5; // eax + int v6; // ecx + + v2 = i; + v3 = i; + v4 = md; + NewMonsterAnim(i, &monster[i].MType->Anims[5], md); + v5 = monster[v3]._mx; + v6 = monster[v3]._my; + monster[v3]._mxoff = 0; + monster[v3]._myoff = 0; + monster[v3]._mdir = v4; + monster[v3]._mmode = MM_SPSTAND; + monster[v3]._mfutx = v5; + monster[v3]._mfuty = v6; + monster[v3]._moldx = v5; + monster[v3]._moldy = v6; + M_CheckEFlag(v2); +} + +void __fastcall M_StartWalk(int i, int xvel, int yvel, int xadd, int yadd, int EndDir) +{ + int v6; // ST18_4 + int v7; // esi + int v8; // eax + int v9; // ecx + CMonster *v10; // edx + + v6 = i; + v7 = i; + v8 = monster[i]._mx; + monster[v7]._moldx = v8; + v9 = monster[i]._my; + monster[v7]._mfuty = v9 + yadd; + monster[v7]._mxvel = xvel; + monster[v7]._myvel = yvel; + monster[v7]._mVar1 = xadd; + monster[v7]._mVar2 = yadd; + dMonster[0][v9 + yadd + 112 * (v8 + xadd)] = -1 - v6; + v10 = monster[v7].MType; + monster[v7]._moldy = v9; + monster[v7]._mmode = MM_WALK; + monster[v7]._mfutx = v8 + xadd; + monster[v7]._mVar3 = EndDir; + monster[v7]._mdir = EndDir; + NewMonsterAnim(v6, &v10->Anims[1], EndDir); + monster[v7]._mVar6 = 0; + monster[v7]._mVar7 = 0; + monster[v7]._mVar8 = 0; + M_CheckEFlag(v6); +} + +void __fastcall M_StartWalk2(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int EndDir) +{ + int v8; // esi + int v9; // edx + int v10; // ecx + int v11; // eax + int v12; // eax + bool v13; // zf + CMonster *v14; // edx + int v15; // [esp+Ch] [ebp-8h] + int ia; // [esp+10h] [ebp-4h] + int EndDira; // [esp+28h] [ebp+14h] + + v15 = xvel; + ia = i; + v8 = i; + v9 = xadd + monster[i]._mx; + EndDira = monster[i]._mx; + v10 = monster[i]._my; + v11 = monster[v8]._my; + monster[v8]._mVar2 = v10; + dMonster[0][v10 + 112 * EndDira] = -1 - ia; + monster[v8]._mVar1 = EndDira; + monster[v8]._moldx = EndDira; + v12 = yadd + v11; + monster[v8]._moldy = v10; + v13 = monster[v8]._uniqtype == 0; + monster[v8]._mx = v9; + monster[v8]._my = v12; + monster[v8]._mfutx = v9; + monster[v8]._mfuty = v12; + dMonster[0][v12 + 112 * v9] = ia + 1; + if ( !v13 ) + ChangeLightXY((unsigned char)monster[v8].mlid, v9, v12); + v14 = monster[v8].MType; + monster[v8]._mxvel = v15; + monster[v8]._myvel = yvel; + monster[v8]._mxoff = xoff; + monster[v8]._myoff = yoff; + monster[v8]._mmode = MM_WALK2; + monster[v8]._mVar3 = EndDir; + monster[v8]._mdir = EndDir; + NewMonsterAnim(ia, &v14->Anims[1], EndDir); + monster[v8]._mVar8 = 0; + monster[v8]._mVar6 = 16 * xoff; + monster[v8]._mVar7 = 16 * yoff; + M_CheckEFlag(ia); +} + +void __fastcall M_StartWalk3(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int mapx, int mapy, int EndDir) +{ + int v10; // esi + int v11; // ebx + int v12; // edi + int v13; // edi + int v14; // ebx + int v15; // ecx + CMonster *v16; // edx + int v17; // [esp+Ch] [ebp-8h] + int ia; // [esp+10h] [ebp-4h] + int a6a; // [esp+28h] [ebp+14h] + int a7a; // [esp+2Ch] [ebp+18h] + + ia = i; + v10 = i; + v11 = monster[i]._my; + v12 = monster[i]._mx; + v17 = xvel; + a6a = v12 + xadd; + a7a = v11 + yadd; + v13 = mapx + v12; + v14 = mapy + v11; + if ( monster[i]._uniqtype ) + ChangeLightXY((unsigned char)monster[v10].mlid, v13, v14); + v15 = monster[v10]._my + 112 * monster[v10]._mx; + monster[v10]._mVar4 = v13; + dMonster[0][v15] = -1 - ia; + monster[v10]._mVar5 = v14; + dMonster[0][a7a + 112 * a6a] = -1 - ia; + monster[v10]._moldx = monster[v10]._mx; + monster[v10]._moldy = monster[v10]._my; + monster[v10]._mfutx = a6a; + monster[v10]._mxvel = v17; + dFlags[v13][v14] |= 0x10u; + v16 = monster[v10].MType; + monster[v10]._myvel = yvel; + monster[v10]._mfuty = a7a; + monster[v10]._mVar1 = a6a; + monster[v10]._mVar2 = a7a; + monster[v10]._mxoff = xoff; + monster[v10]._myoff = yoff; + monster[v10]._mmode = MM_WALK3; + monster[v10]._mVar3 = EndDir; + monster[v10]._mdir = EndDir; + NewMonsterAnim(ia, &v16->Anims[1], EndDir); + monster[v10]._mVar8 = 0; + monster[v10]._mVar6 = 16 * xoff; + monster[v10]._mVar7 = 16 * yoff; + M_CheckEFlag(ia); +} + +void __fastcall M_StartAttack(int i) +{ + int v1; // edi + int v2; // ebx + int v3; // esi + int v4; // ecx + int v5; // eax + + v1 = i; + v2 = M_GetDir(i); + v3 = v1; + NewMonsterAnim(v1, &monster[v1].MType->Anims[2], v2); + v4 = monster[v1]._my; + v5 = monster[v1]._mx; + monster[v3]._mxoff = 0; + monster[v3]._myoff = 0; + monster[v3]._mfuty = v4; + monster[v3]._moldy = v4; + monster[v3]._mmode = MM_ATTACK; + monster[v3]._mfutx = v5; + monster[v3]._moldx = v5; + monster[v3]._mdir = v2; + M_CheckEFlag(v1); +} + +void __fastcall M_StartRAttack(int i, int missile_type, int dam) +{ + int v3; // ebp + int v4; // edi + int v5; // ebx + int v6; // esi + int v7; // ecx + int v8; // eax + + v3 = missile_type; + v4 = i; + v5 = M_GetDir(i); + v6 = v4; + NewMonsterAnim(v4, &monster[v4].MType->Anims[2], v5); + v7 = monster[v4]._my; + monster[v6]._mxoff = 0; + monster[v6]._myoff = 0; + monster[v6]._mVar2 = dam; + v8 = monster[v4]._mx; + monster[v6]._mfuty = v7; + monster[v6]._moldy = v7; + monster[v6]._mmode = MM_RATTACK; + monster[v6]._mVar1 = v3; + monster[v6]._mfutx = v8; + monster[v6]._moldx = v8; + monster[v6]._mdir = v5; + M_CheckEFlag(v4); +} + +void __fastcall M_StartRSpAttack(int i, int missile_type, int dam) +{ + int v3; // ebp + int v4; // edi + int v5; // ebx + int v6; // esi + int v7; // ecx + int v8; // eax + + v3 = missile_type; + v4 = i; + v5 = M_GetDir(i); + v6 = v4; + NewMonsterAnim(v4, &monster[v4].MType->Anims[5], v5); + monster[v6]._mmode = MM_RSPATTACK; + monster[v6]._mVar2 = 0; + monster[v6]._mVar3 = dam; + v7 = monster[v4]._my; + monster[v6]._mxoff = 0; + monster[v6]._myoff = 0; + v8 = monster[v4]._mx; + monster[v6]._mfuty = v7; + monster[v6]._moldy = v7; + monster[v6]._mVar1 = v3; + monster[v6]._mfutx = v8; + monster[v6]._moldx = v8; + monster[v6]._mdir = v5; + M_CheckEFlag(v4); +} + +void __fastcall M_StartSpAttack(int i) +{ + int v1; // edi + int v2; // ebx + int v3; // esi + int v4; // ecx + int v5; // eax + + v1 = i; + v2 = M_GetDir(i); + v3 = v1; + NewMonsterAnim(v1, &monster[v1].MType->Anims[5], v2); + v4 = monster[v1]._my; + v5 = monster[v1]._mx; + monster[v3]._mxoff = 0; + monster[v3]._myoff = 0; + monster[v3]._mfuty = v4; + monster[v3]._moldy = v4; + monster[v3]._mmode = MM_SATTACK; + monster[v3]._mfutx = v5; + monster[v3]._moldx = v5; + monster[v3]._mdir = v2; + M_CheckEFlag(v1); +} + +void __fastcall M_StartEat(int i) +{ + int v1; // edi + int v2; // esi + int v3; // ecx + int v4; // eax + + v1 = i; + v2 = i; + NewMonsterAnim(i, &monster[i].MType->Anims[5], monster[i]._mdir); + v3 = monster[v2]._my; + v4 = monster[v2]._mx; + monster[v2]._mxoff = 0; + monster[v2]._myoff = 0; + monster[v2]._mfuty = v3; + monster[v2]._moldy = v3; + monster[v2]._mmode = MM_SATTACK; + monster[v2]._mfutx = v4; + monster[v2]._moldx = v4; + M_CheckEFlag(v1); +} + +void __fastcall M_ClearSquares(int i) +{ + int v1; // edx + int v2; // eax + int v3; // esi + int v4; // ecx + int v5; // edi + int v6; // [esp+8h] [ebp-Ch] + _DWORD *v7; // [esp+Ch] [ebp-8h] + int v8; // [esp+10h] [ebp-4h] + + v1 = monster[i]._moldx; + v2 = monster[i]._moldy; + v3 = -1 - i; + v6 = i + 1; + v4 = v2 - 1; + v5 = v2 + 1; + if ( (unsigned char)(__OFSUB__(v2 - 1, v2 + 1) ^ 1) | (v2 - 1 == v2 + 1) ) + { + do + { + if ( v4 >= 0 && v4 < 112 ) + { + v8 = v1 - 1; + if ( (unsigned char)(__OFSUB__(v1 - 1, v1 + 1) ^ 1) | (v1 - 1 == v1 + 1) ) + { + v7 = (_DWORD *)((char *)dMonster + 4 * (v4 + 112 * (v1 - 1))); + do + { + if ( v8 >= 0 && v8 < 112 && (*v7 == v3 || *v7 == v6) ) + *v7 = 0; + ++v8; + v7 += 112; + } + while ( v8 <= v1 + 1 ); + } + } + ++v4; + v5 = v2 + 1; + } + while ( v4 <= v2 + 1 ); + } + if ( v1 + 1 < 112 ) + dFlags[v1 + 1][v2] &= 0xEFu; + if ( v5 < 112 ) + dFlags[v1][v2 + 1] &= 0xEFu; +} + +void __fastcall M_GetKnockback(int i) +{ + int v1; // edi + int v2; // esi + int v3; // ebx + //int v4; // eax + int v5; // ST00_4 + AnimStruct *v6; // edx + int v7; // eax + int v8; // ecx + int v9; // eax + + v1 = i; + v2 = i; + v3 = ((unsigned char)monster[i]._mdir - 4) & 7; + //_LOBYTE(v4) = DirOK(i, v3); + if ( DirOK(i, v3) ) + { + M_ClearSquares(v1); + v5 = monster[v2]._mdir; + v6 = &monster[v2].MType->Anims[3]; + v7 = offset_y[v3]; + monster[v2]._moldx += offset_x[v3]; + monster[v2]._moldy += v7; + NewMonsterAnim(v1, v6, v5); + v8 = monster[v2]._moldy; + v9 = monster[v2]._moldx; + monster[v2]._mxoff = 0; + monster[v2]._myoff = 0; + monster[v2]._my = v8; + monster[v2]._mfuty = v8; + monster[v2]._mmode = MM_GOTHIT; + monster[v2]._mx = v9; + monster[v2]._mfutx = v9; + M_CheckEFlag(v1); + M_ClearSquares(v1); + dMonster[0][monster[v2]._my + 112 * monster[v2]._mx] = v1 + 1; + } +} + +void __fastcall M_StartHit(int i, int pnum, int dam) +{ + int v3; // ebx + int v4; // edi + int v5; // esi + unsigned char v6; // al + char v7; // al + unsigned char v8; // al + int v9; // ecx + int v10; // eax + + v3 = pnum; + v4 = i; + if ( pnum >= 0 ) + monster[i].mWhoHit |= 1 << pnum; + if ( pnum == myplr ) + { + delta_monster_hp(i, monster[i]._mhitpoints, currlevel); + NetSendCmdParam2(0, CMD_MONSTDAMAGE, v4, dam); + } + PlayEffect(v4, 1); + v5 = v4; + v6 = monster[v4].MType->mtype; + if ( v6 >= MT_SNEAK && v6 <= MT_ILLWEAV || dam >> 6 >= SLOBYTE(monster[v5].mLevel) + 3 ) + { + if ( v3 >= 0 ) + { + monster[v5]._mFlags &= 0xFFFFFFEF; + monster[v5]._menemy = v3; + v7 = plr[v3]._py; + monster[v5]._menemyx = plr[v3]._px; + monster[v5]._menemyy = v7; + monster[v5]._mdir = M_GetDir(v4); + } + v8 = monster[v5].MType->mtype; + if ( v8 == MT_BLINK ) + { + M_Teleport(v4); + } + else if ( v8 >= MT_NSCAV && v8 <= MT_YSCAV ) + { + _LOBYTE(monster[v5]._mgoal) = 1; + } + if ( monster[v5]._mmode != MM_STONE ) + { + NewMonsterAnim(v4, &monster[v5].MType->Anims[3], monster[v5]._mdir); + v9 = monster[v5]._moldy; + v10 = monster[v5]._moldx; + monster[v5]._mxoff = 0; + monster[v5]._myoff = 0; + monster[v5]._my = v9; + monster[v5]._mfuty = v9; + monster[v5]._mmode = MM_GOTHIT; + monster[v5]._mx = v10; + monster[v5]._mfutx = v10; + M_CheckEFlag(v4); + M_ClearSquares(v4); + dMonster[0][monster[v5]._my + 112 * monster[v5]._mx] = v4 + 1; + } + } +} + +void __fastcall M_DiabloDeath(int i, unsigned char sendmsg) +{ + int v2; // esi + int v3; // edi + int v4; // eax + int v5; // ebx + int v6; // esi + int v7; // ecx + int v8; // eax + int v9; // esi + int v10; // eax + double v11; // st7 + int v12; // eax + int v13; // ecx + int v14; // esi + int v15; // [esp+8h] [ebp-8h] + int j; // [esp+Ch] [ebp-4h] + int v17; // [esp+Ch] [ebp-4h] + + v15 = i; + v2 = sendmsg; + v3 = i; + PlaySFX(USFX_DIABLOD); + quests[5]._qactive = 3; + if ( v2 ) + NetSendCmdQuest(1u, 5u); + gbProcessPlayers = 0; + _LOBYTE(sgbSaveSoundOn) = gbSoundOn; + v4 = 0; + for ( j = 0; j < nummonsters; ++j ) + { + v5 = monstactive[v4]; + if ( v5 != v15 && monster[v3]._msquelch ) + { + v6 = v5; + NewMonsterAnim(monstactive[v4], &monster[v5].MType->Anims[4], monster[v5]._mdir); + v7 = monster[v5]._moldy; + monster[v6]._mxoff = 0; + monster[v6]._myoff = 0; + monster[v6]._mVar1 = 0; + v8 = monster[v5]._moldx; + monster[v6]._my = v7; + monster[v6]._mfuty = v7; + monster[v6]._mmode = MM_DEATH; + monster[v6]._mx = v8; + monster[v6]._mfutx = v8; + M_CheckEFlag(v5); + M_ClearSquares(v5); + dMonster[0][monster[v6]._my + 112 * monster[v6]._mx] = v5 + 1; + } + v4 = j + 1; + } + AddLight(monster[v3]._mx, monster[v3]._my, 8); + DoVision(monster[v3]._mx, monster[v3]._my, 8, 0, 1); + v9 = abs(ViewY - monster[v3]._my); + if ( abs(ViewX - monster[v3]._mx) <= v9 ) + v10 = ViewY - monster[v3]._my; + else + v10 = ViewX - monster[v3]._mx; + v17 = abs(v10); + if ( v17 > 20 ) + v17 = 20; + v11 = (double)v17; + v12 = ViewX << 16; + v13 = monster[v3]._mx << 16; + monster[v3]._mVar3 = ViewX << 16; + v14 = ViewY << 16; + monster[v3]._mVar4 = ViewY << 16; + monster[v3]._mVar5 = (signed __int64)((double)(v12 - v13) / v11); + monster[v3]._mVar6 = (signed __int64)((double)(v14 - (monster[v3]._my << 16)) / v11); +} +// 4A22D5: using guessed type char gbSoundOn; +// 5256A0: using guessed type int gbProcessPlayers; +// 64D32C: using guessed type int sgbSaveSoundOn; + +void __fastcall M2MStartHit(int mid, int i, int dam) +{ + int v3; // edi + int v4; // ebx + int v5; // esi + CMonster *v6; // eax + char v7; // al + CMonster *v8; // eax + int v9; // ecx + int v10; // eax + int v11; // [esp+Ch] [ebp-4h] + + v3 = mid; + v4 = i; + v11 = i; + if ( (unsigned int)mid >= MAXMONSTERS ) + TermMsg("Invalid monster %d getting hit by monster", mid); + v5 = v3; + if ( !monster[v3].MType ) + TermMsg("Monster %d \"%s\" getting hit by monster: MType NULL", v3, monster[v5].mName); + if ( v4 >= 0 ) + monster[v4].mWhoHit |= 1 << v4; + delta_monster_hp(v3, monster[v5]._mhitpoints, currlevel); + NetSendCmdParam2(0, CMD_MONSTDAMAGE, v3, dam); + PlayEffect(v3, 1); + v6 = monster[v5].MType; + if ( v6->mtype >= MT_SNEAK && v6->mtype <= MT_ILLWEAV || dam >> 6 >= SLOBYTE(monster[v5].mLevel) + 3 ) + { + if ( v11 >= 0 ) + monster[v5]._mdir = ((unsigned char)monster[v11]._mdir - 4) & 7; + v7 = v6->mtype; + if ( v7 == 39 ) + { + M_Teleport(v3); + } + else if ( v7 >= MT_NSCAV && v7 <= MT_YSCAV ) + { + _LOBYTE(monster[v5]._mgoal) = 1; + } + if ( monster[v5]._mmode != MM_STONE ) + { + v8 = monster[v5].MType; + if ( v8->mtype != MT_GOLEM ) + { + NewMonsterAnim(v3, &v8->Anims[3], monster[v5]._mdir); + monster[v5]._mmode = MM_GOTHIT; + } + v9 = monster[v5]._moldy; + v10 = monster[v5]._moldx; + monster[v5]._mxoff = 0; + monster[v5]._myoff = 0; + monster[v5]._my = v9; + monster[v5]._mfuty = v9; + monster[v5]._mx = v10; + monster[v5]._mfutx = v10; + M_CheckEFlag(v3); + M_ClearSquares(v3); + dMonster[0][monster[v5]._my + 112 * monster[v5]._mx] = v3 + 1; + } + } +} + +void __fastcall MonstStartKill(int i, int pnum, unsigned char sendmsg) +{ + signed int v3; // edi + int v4; // ebx + signed int v5; // esi + int v6; // ecx + int v7; // eax + //int v8; // eax + int v9; // eax + AnimStruct *v10; // edx + int v11; // ecx + int v12; // eax + unsigned char v13; // al + + v3 = i; + v4 = pnum; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MonstStartKill: Invalid monster %d", i); + v5 = v3; + if ( !monster[v3].MType ) + TermMsg("MonstStartKill: Monster %d \"%s\" MType NULL", v3, monster[v5].mName); + if ( v4 >= 0 ) + monster[v5].mWhoHit |= 1 << v4; + if ( v4 < 4 && v3 > 4 ) + AddPlrMonstExper(SLOBYTE(monster[v5].mLevel), (unsigned short)monster[v5].mExp, monster[v5].mWhoHit); + v6 = monster[v5]._mRndSeed; + v7 = monster[v5].MType->mtype; + monster[v5]._mhitpoints = 0; + ++monstkills[v7]; + SetRndSeed(v6); + //_LOBYTE(v8) = QuestStatus(2); + if ( QuestStatus(2) && monster[v5].mName == UniqMonst[0].mName ) + { + CreateTypeItem(monster[v5]._mx + 1, monster[v5]._my + 1, 1u, 4, 0, 1, 0); + } + else if ( v3 > 3 ) + { + SpawnItem(v3, monster[v5]._mx, monster[v5]._my, sendmsg); + } + if ( monster[v5].MType->mtype == MT_DIABLO ) + M_DiabloDeath(v3, 1u); + else + PlayEffect(v3, 2); + if ( v4 < 0 ) + v9 = monster[v5]._mdir; + else + v9 = M_GetDir(v3); + v10 = &monster[v5].MType->Anims[4]; + monster[v5]._mdir = v9; + NewMonsterAnim(v3, v10, v9); + v11 = monster[v5]._moldy; + v12 = monster[v5]._moldx; + monster[v5]._my = v11; + monster[v5]._mfuty = v11; + monster[v5]._mmode = MM_DEATH; + monster[v5]._mxoff = 0; + monster[v5]._myoff = 0; + monster[v5]._mVar1 = 0; + monster[v5]._mx = v12; + monster[v5]._mfutx = v12; + M_CheckEFlag(v3); + M_ClearSquares(v3); + dMonster[0][monster[v5]._my + 112 * monster[v5]._mx] = v3 + 1; + CheckQuestKill(v3, sendmsg); + M_FallenFear(monster[v5]._mx, monster[v5]._my); + v13 = monster[v5].MType->mtype; + if ( v13 >= MT_NACID && v13 <= MT_XACID ) + AddMissile(monster[v5]._mx, monster[v5]._my, 0, 0, 0, 59, 1, v3, (unsigned char)monster[v5]._mint + 1, 0); +} + +void __fastcall M2MStartKill(int i, int mid) +{ + signed int v2; // ebx + signed int v3; // edi + signed int v4; // esi + int v5; // ecx + int v6; // eax + CMonster *v7; // ecx + int v8; // eax + int v9; // ecx + int v10; // eax + unsigned char v11; // al + + v2 = i; + v3 = mid; + if ( (unsigned int)i >= MAXMONSTERS ) + { + TermMsg("M2MStartKill: Invalid monster (attacker) %d", i); + TermMsg("M2MStartKill: Invalid monster (killed) %d", v3); + } + if ( !monster[v2].MType ) + TermMsg("M2MStartKill: Monster %d \"%s\" MType NULL", v3, monster[v3].mName); + v4 = v3; + delta_kill_monster(v3, monster[v3]._mx, monster[v3]._my, currlevel); + NetSendCmdLocParam1(0, CMD_MONSTDEATH, monster[v4]._mx, monster[v4]._my, v3); + monster[v4].mWhoHit |= 1 << v2; + if ( v2 < 4 ) + AddPlrMonstExper(SLOBYTE(monster[v4].mLevel), (unsigned short)monster[v4].mExp, monster[v3].mWhoHit); + v5 = monster[v4]._mRndSeed; + v6 = monster[v4].MType->mtype; + monster[v4]._mhitpoints = 0; + ++monstkills[v6]; + SetRndSeed(v5); + if ( v3 >= 4 ) + SpawnItem(v3, monster[v4]._mx, monster[v4]._my, 1u); + if ( monster[v4].MType->mtype == MT_DIABLO ) + M_DiabloDeath(v3, 1u); + else + PlayEffect(v2, 2); + PlayEffect(v3, 2); + v7 = monster[v4].MType; + v8 = ((unsigned char)monster[v2]._mdir - 4) & 7; + if ( v7->mtype == MT_GOLEM ) + v8 = 0; + monster[v4]._mdir = v8; + NewMonsterAnim(v3, &v7->Anims[4], v8); + v9 = monster[v4]._moldy; + v10 = monster[v4]._moldx; + monster[v4]._my = v9; + monster[v4]._mfuty = v9; + monster[v4]._mmode = MM_DEATH; + monster[v4]._mxoff = 0; + monster[v4]._myoff = 0; + monster[v4]._mx = v10; + monster[v4]._mfutx = v10; + M_CheckEFlag(v3); + M_ClearSquares(v3); + dMonster[0][monster[v4]._my + 112 * monster[v4]._mx] = v3 + 1; + CheckQuestKill(v3, 1u); + M_FallenFear(monster[v4]._mx, monster[v4]._my); + v11 = monster[v4].MType->mtype; + if ( v11 >= MT_NACID && v11 <= MT_XACID ) + AddMissile(monster[v4]._mx, monster[v4]._my, 0, 0, 0, 59, 1, v3, (unsigned char)monster[v4]._mint + 1, 0); +} + +void __fastcall M_StartKill(int i, int pnum) +{ + int v2; // edi + int v3; // ebx + int v4; // esi + int v5; // eax + + v2 = i; + v3 = pnum; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_StartKill: Invalid monster %d", i); + if ( myplr == v3 ) + { + v4 = v2; + delta_kill_monster(v2, monster[v2]._mx, monster[v2]._my, currlevel); + if ( v2 == v3 ) + { + _LOWORD(v5) = currlevel; + NetSendCmdLocParam1(0, CMD_KILLGOLEM, monster[v4]._mx, monster[v4]._my, v5); + } + else + { + NetSendCmdLocParam1(0, CMD_MONSTDEATH, monster[v4]._mx, monster[v4]._my, v2); + } + } + MonstStartKill(v2, v3, 1u); +} + +void __fastcall M_SyncStartKill(int i, int x, int y, int pnum) +{ + int v4; // esi + int v5; // ebx + int v6; // esi + int arglist; // [esp+Ch] [ebp-4h] + + v4 = i; + v5 = x; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_SyncStartKill: Invalid monster %d", i); + v6 = v4; + if ( monster[v6]._mhitpoints && monster[v6]._mmode != MM_DEATH ) + { + if ( !dMonster[0][y + 112 * v5] ) + { + M_ClearSquares(arglist); + monster[v6]._mx = v5; + monster[v6]._my = y; + monster[v6]._moldx = v5; + monster[v6]._moldy = y; + } + if ( monster[v6]._mmode == MM_STONE ) + { + MonstStartKill(arglist, pnum, 0); + monster[v6]._mmode = MM_STONE; + } + else + { + MonstStartKill(arglist, pnum, 0); + } + } +} + +void __fastcall M_StartFadein(int i, int md, unsigned char backwards) +{ + int v3; // esi + int v4; // ebx + int v5; // esi + int v6; // ecx + int v7; // eax + int *v8; // eax + int arglist; // [esp+Ch] [ebp-4h] + + v3 = i; + v4 = md; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_StartFadein: Invalid monster %d", i); + v5 = v3; + if ( !monster[v5].MType ) + TermMsg("M_StartFadein: Monster %d \"%s\" MType NULL", arglist, monster[v5].mName); + NewMonsterAnim(arglist, &monster[v5].MType->Anims[5], v4); + v6 = monster[v5]._my; + v7 = monster[v5]._mx; + monster[v5]._mfuty = v6; + monster[v5]._moldy = v6; + monster[v5]._mmode = MM_FADEIN; + monster[v5]._mxoff = 0; + monster[v5]._myoff = 0; + monster[v5]._mfutx = v7; + monster[v5]._moldx = v7; + M_CheckEFlag(arglist); + v8 = &monster[v5]._mFlags; + monster[v5]._mdir = v4; + *v8 &= 0xFFFFFFFE; + if ( backwards ) + { + *v8 = monster[v5]._mFlags | 2; + monster[v5]._mAnimFrame = monster[v5]._mAnimLen; + } +} + +void __fastcall M_StartFadeout(int i, int md, unsigned char backwards) +{ + int v3; // ebx + int v4; // esi + CMonster **v5; // edi + int v6; // ecx + int v7; // eax + int v8; // eax + int mda; // [esp+Ch] [ebp-4h] + + v3 = i; + mda = md; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_StartFadeout: Invalid monster %d", i); + v4 = v3; + v5 = &monster[v3].MType; + if ( !*v5 ) + TermMsg("M_StartFadeout: Monster %d \"%s\" MType NULL", v3, monster[v4].mName); + NewMonsterAnim(v3, &(*v5)->Anims[5], mda); + v6 = monster[v4]._my; + v7 = monster[v4]._mx; + monster[v4]._mfuty = v6; + monster[v4]._moldy = v6; + monster[v4]._mmode = MM_FADEOUT; + monster[v4]._mxoff = 0; + monster[v4]._myoff = 0; + monster[v4]._mfutx = v7; + monster[v4]._moldx = v7; + M_CheckEFlag(v3); + monster[v4]._mdir = mda; + if ( backwards ) + { + v8 = monster[v4]._mAnimLen; + monster[v4]._mFlags |= 2u; + monster[v4]._mAnimFrame = v8; + } +} + +void __fastcall M_StartHeal(int i) +{ + int v1; // edi + int v2; // esi + CMonster *v3; // eax + unsigned char *v4; // ecx + int v5; // eax + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_StartHeal: Invalid monster %d", i); + v2 = v1; + if ( !monster[v1].MType ) + TermMsg("M_StartHeal: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + v3 = monster[v2].MType; + v4 = v3->Anims[5].Frames[monster[v2]._mdir]; + monster[v2]._mAnimData = v4; + v5 = v3->Anims[5].Rate; + monster[v2]._mFlags |= 2u; + monster[v2]._mAnimFrame = v5; + monster[v2]._mmode = MM_HEAL; + monster[v2]._mVar1 = monster[v2]._mmaxhp / (16 * (random(97, 5) + 4)); +} + +void __fastcall M_ChangeLightOffset(int monst) +{ + int v1; // esi + int v2; // ecx + int v3; // eax + int v4; // esi + int v5; // edx + int v6; // eax + signed int v7; // esi + int v8; // edx + signed int v9; // esi + + v1 = monst; + if ( (unsigned int)monst >= MAXMONSTERS ) + TermMsg("M_ChangeLightOffset: Invalid monster %d", monst); + v2 = v1; + v3 = monster[v1]._myoff; + v4 = monster[v1]._mxoff; + v3 *= 2; + v5 = v4 + v3; + v6 = v3 - v4; + if ( v5 >= 0 ) + { + v7 = 1; + } + else + { + v7 = -1; + v5 = -v5; + } + v8 = v7 * (v5 >> 3); + if ( v6 >= 0 ) + { + v9 = 1; + } + else + { + v9 = -1; + v6 = -v6; + } + ChangeLightOff((unsigned char)monster[v2].mlid, v8, v9 * (v6 >> 3)); +} + +int __fastcall M_DoStand(int i) +{ + int v1; // edi + int v2; // esi + CMonster *v3; // eax + int v4; // ecx + unsigned char *v5; // eax + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoStand: Invalid monster %d", i); + v2 = v1; + if ( !monster[v1].MType ) + TermMsg("M_DoStand: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + v3 = monster[v2].MType; + v4 = monster[v2]._mdir; + if ( v3->mtype == MT_GOLEM ) + v5 = v3->Anims[1].Frames[v4]; + else + v5 = v3->Anims[0].Frames[v4]; + monster[v2]._mAnimData = v5; + if ( monster[v2]._mAnimFrame == monster[v2]._mAnimLen ) + M_Enemy(v1); + ++monster[v2]._mVar2; + return 0; +} + +int __fastcall M_DoWalk(int i) +{ + int v1; // ebx + int v2; // esi + int v3; // edi + int v4; // eax + int v5; // edi + int v6; // ecx + int v7; // edx + int v8; // eax + bool v9; // zf + int v10; // ecx + int v11; // edx + int v12; // eax + int v13; // ecx + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoWalk: Invalid monster %d", i); + v2 = v1; + v3 = 0; + if ( !monster[v1].MType ) + TermMsg("M_DoWalk: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + v4 = monster[v2]._mVar8; + if ( v4 == monster[v2].MType->Anims[1].Rate ) + { + v5 = monster[v2]._my; + v6 = monster[v2]._mx; + dMonster[0][v5 + 112 * monster[v2]._mx] = 0; + v7 = v6 + monster[v2]._mVar1; + monster[v2]._mx = v7; + v8 = v5 + monster[v2]._mVar2; + v9 = monster[v2]._uniqtype == 0; + monster[v2]._my = v8; + dMonster[0][v8 + 112 * v7] = v1 + 1; + if ( !v9 ) + ChangeLightXY((unsigned char)monster[v2].mlid, v7, v8); + M_StartStand(v1, monster[v2]._mdir); + v3 = 1; + } + else if ( !monster[v2]._mAnimCnt ) + { + v10 = monster[v2]._mxvel; + v11 = monster[v2]._myvel; + monster[v2]._mVar8 = v4 + 1; + monster[v2]._mVar6 += v10; + v12 = monster[v2]._mVar6 >> 4; + monster[v2]._mVar7 += v11; + v13 = monster[v2]._mVar7 >> 4; + monster[v2]._mxoff = v12; + monster[v2]._myoff = v13; + } + if ( monster[v2]._uniqtype ) + M_ChangeLightOffset(v1); + return v3; +} + +int __fastcall M_DoWalk2(int i) +{ + int v1; // ebp + int v2; // esi + int v3; // eax + bool v4; // zf + int v5; // edi + int v6; // ecx + int v7; // edx + int v8; // eax + int v9; // ecx + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoWalk2: Invalid monster %d", i); + v2 = v1; + if ( !monster[v1].MType ) + TermMsg("M_DoWalk2: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + v3 = monster[v2]._mVar8; + if ( v3 == monster[v2].MType->Anims[1].Rate ) + { + v4 = monster[v2]._uniqtype == 0; + dMonster[0][monster[v2]._mVar2 + 112 * monster[v2]._mVar1] = 0; + if ( !v4 ) + ChangeLightXY((unsigned char)monster[v2].mlid, monster[v2]._mx, monster[v2]._my); + M_StartStand(v1, monster[v2]._mdir); + v5 = 1; + } + else + { + if ( !monster[v2]._mAnimCnt ) + { + v6 = monster[v2]._mxvel; + v7 = monster[v2]._myvel; + monster[v2]._mVar8 = v3 + 1; + monster[v2]._mVar6 += v6; + v8 = monster[v2]._mVar6 >> 4; + monster[v2]._mVar7 += v7; + v9 = monster[v2]._mVar7 >> 4; + monster[v2]._mxoff = v8; + monster[v2]._myoff = v9; + } + v5 = 0; + } + if ( monster[v2]._uniqtype ) + M_ChangeLightOffset(v1); + return v5; +} + +int __fastcall M_DoWalk3(int i) +{ + int v1; // ebp + int v2; // esi + int v3; // eax + int v4; // edi + int v5; // edx + int v6; // ecx + int v7; // edx + char *v8; // eax + bool v9; // zf + int v10; // edi + int v11; // ecx + int v12; // edx + int v13; // eax + int v14; // ecx + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoWalk3: Invalid monster %d", i); + v2 = v1; + if ( !monster[v1].MType ) + TermMsg("M_DoWalk3: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + v3 = monster[v2]._mVar8; + if ( v3 == monster[v2].MType->Anims[1].Rate ) + { + v4 = monster[v2]._mVar2; + v5 = monster[v2]._my + 112 * monster[v2]._mx; + monster[v2]._my = v4; + v6 = monster[v2]._mVar5; + dMonster[0][v5] = 0; + v7 = monster[v2]._mVar1; + monster[v2]._mx = v7; + v8 = &dFlags[monster[v2]._mVar4][v6]; + *v8 &= 0xEFu; + v9 = monster[v2]._uniqtype == 0; + dMonster[0][v4 + 112 * v7] = v1 + 1; + if ( !v9 ) + ChangeLightXY((unsigned char)monster[v2].mlid, v7, v4); + M_StartStand(v1, monster[v2]._mdir); + v10 = 1; + } + else + { + if ( !monster[v2]._mAnimCnt ) + { + v11 = monster[v2]._mxvel; + v12 = monster[v2]._myvel; + monster[v2]._mVar8 = v3 + 1; + monster[v2]._mVar6 += v11; + v13 = monster[v2]._mVar6 >> 4; + monster[v2]._mVar7 += v12; + v14 = monster[v2]._mVar7 >> 4; + monster[v2]._mxoff = v13; + monster[v2]._myoff = v14; + } + v10 = 0; + } + if ( monster[v2]._uniqtype ) + M_ChangeLightOffset(v1); + return v10; +} + +void __fastcall M_TryM2MHit(int i, int mid, int hper, int mind, int maxd) +{ + int v5; // edi + //int v6; // ST08_4 + int v7; // esi + int v8; // ebx + //int v9; // eax + int v11; // eax + BOOL ret; // [esp+Ch] [ebp-Ch] + char v13[4]; // [esp+10h] [ebp-8h] + char arglist[4]; // [esp+14h] [ebp-4h] + + v5 = mid; + *(_DWORD *)arglist = mid; + *(_DWORD *)v13 = i; + if ( (unsigned int)mid >= MAXMONSTERS ) + { + TermMsg("M_TryM2MHit: Invalid monster %d", mid); + //i = v6; + } + v7 = v5; + if ( !monster[v5].MType ) + TermMsg("M_TryM2MHit: Monster %d \"%s\" MType NULL", v5, monster[v7].mName); + if ( (signed int)(monster[v7]._mhitpoints & 0xFFFFFFC0) > 0 + && (monster[v7].MType->mtype != MT_ILLWEAV || _LOBYTE(monster[v7]._mgoal) != 2) ) + { + v8 = random(4, 100); + if ( monster[v7]._mmode == MM_STONE ) + v8 = 0; + //_LOBYTE(v9) = CheckMonsterHit(*(int *)arglist, &ret); + if ( !CheckMonsterHit(*(int *)arglist, &ret) && v8 < hper ) + { + v11 = (mind + random(5, maxd - mind + 1)) << 6; + monster[v7]._mhitpoints -= v11; + if ( (signed int)(monster[v7]._mhitpoints & 0xFFFFFFC0) > 0 ) + { + if ( monster[v7]._mmode == MM_STONE ) + { + M2MStartHit(*(int *)arglist, *(int *)v13, v11); + goto LABEL_15; + } + M2MStartHit(*(int *)arglist, *(int *)v13, v11); + } + else + { + if ( monster[v7]._mmode == MM_STONE ) + { + M2MStartKill(*(int *)v13, *(int *)arglist); + LABEL_15: + monster[v7]._mmode = MM_STONE; + return; + } + M2MStartKill(*(int *)v13, *(int *)arglist); + } + } + } +} + +void __fastcall M_TryH2HHit(int i, int pnum, int Hit, int MinDam, int MaxDam) +{ + int v5; // esi + int v6; // ebx + int v7; // esi + int v8; // edi + int v9; // eax + //int v10; // ST08_4 + int v12; // ecx + int v13; // edi + int v14; // eax + int v15; // eax + int *v16; // ecx + int v17; // eax + int v18; // edi + int v19; // edx + int v20; // eax + int v21; // eax + int v22; // edx + int v23; // eax + bool v24; // zf + bool v25; // sf + unsigned char v26; // of + int v27; // eax + int v29; // edi + int v30; // eax + int v31; // eax + int v32; // eax + int v33; // edi + int v34; // ebx + int v35; // edx + int v36; // [esp+Ch] [ebp-Ch] + int arglist; // [esp+10h] [ebp-8h] + int plr_num; // [esp+14h] [ebp-4h] + int hper; // [esp+20h] [ebp+8h] + + v5 = i; + plr_num = pnum; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_TryH2HHit: Invalid monster %d", i); + v6 = v5; + if ( !monster[v5].MType ) + TermMsg("M_TryH2HHit: Monster %d \"%s\" MType NULL", v5, monster[v6].mName); + if ( monster[v6]._mFlags & 0x10 ) + { + M_TryM2MHit(v5, plr_num, Hit, MinDam, MaxDam); + return; + } + v7 = plr_num; + if ( (signed int)(plr[plr_num]._pHitPoints & 0xFFFFFFC0) > 0 && !plr[v7]._pInvincible && !(plr[v7]._pSpellFlags & 1) ) + { + v8 = abs(monster[v6]._mx - plr[v7].WorldX); + v9 = abs(monster[v6]._my - plr[v7].WorldY); + //v11 = v10; + if ( v8 < 2 && v9 < 2 ) + { + v36 = random(98, 100); +#ifdef _DEBUG + if ( debug_mode_dollar_sign || debug_mode_key_inverted_v ) + v36 = 1000; +#endif + v12 = 5; + v13 = Hit + + 2 * (SLOBYTE(monster[v6].mLevel) - plr[v7]._pLevel) + + 30 + - plr[v7]._pIBonusAC + - plr[v7]._pIAC + - plr[v7]._pDexterity / 5; + if ( v13 < 15 ) + v13 = 15; + if ( currlevel == 14 ) + { + if ( v13 >= 20 ) + goto LABEL_23; + v13 = 20; + } + if ( currlevel != 15 ) + { + LABEL_20: + if ( currlevel == 16 && v13 < 30 ) + v13 = 30; + goto LABEL_23; + } + if ( v13 < 25 ) + { + v13 = 25; + goto LABEL_20; + } + LABEL_23: + v14 = plr[v7]._pmode; + if ( v14 && v14 != 4 || !plr[v7]._pBlockFlag ) + { + v15 = 100; + } + else + { + v15 = random(98, 100); + } + v16 = (int *)(plr[v7]._pDexterity + + plr[v7]._pBaseToBlk + - 2 * SLOBYTE(monster[v6].mLevel) + + 2 * plr[v7]._pLevel); + if ( (signed int)v16 < 0 ) + v16 = 0; + if ( (signed int)v16 > 100 ) + v16 = (int *)100; + if ( v36 < v13 ) + { + if ( v15 >= (signed int)v16 ) + { + if ( monster[v6].MType->mtype == MT_YZOMBIE && plr_num == myplr ) + { + v18 = -1; + v19 = 0; + for ( hper = -1; v19 < nummissiles; ++v19 ) + { + v20 = missileactive[v19]; + if ( missile[v20]._mitype == 13 ) + { + if ( missile[v20]._misource == plr_num ) + { + v18 = missileactive[v19]; + hper = missileactive[v19]; + } + else + { + v18 = hper; + } + } + } + v16 = &plr[v7]._pMaxHP; + v21 = plr[v7]._pMaxHP; + if ( v21 > 64 ) + { + v22 = plr[v7]._pMaxHPBase; + if ( v22 > 64 ) + { + v23 = v21 - 64; + v26 = __OFSUB__(plr[v7]._pHitPoints, v23); + v24 = plr[v7]._pHitPoints == v23; + v25 = plr[v7]._pHitPoints - v23 < 0; + *v16 = v23; + if ( !((unsigned char)(v25 ^ v26) | v24) ) + { + plr[v7]._pHitPoints = v23; + if ( v18 >= 0 ) + missile[v18]._miVar1 = v23; + } + v16 = &plr[v7]._pHPBase; + v27 = v22 - 64; + plr[v7]._pMaxHPBase = v22 - 64; + if ( plr[v7]._pHPBase > v22 - 64 ) + { + *v16 = v27; + if ( v18 >= 0 ) + missile[v18]._miVar2 = v27; + } + } + } + } + v29 = (plr[v7]._pIGetHit << 6) + (MinDam << 6) + random(99, (MaxDam - MinDam + 1) << 6); + if ( v29 < 64 ) + v29 = 64; + if ( plr_num == myplr ) + { + plr[v7]._pHitPoints -= v29; + plr[v7]._pHPBase -= v29; + } + if ( plr[v7]._pIFlags & 0x4000000 ) + { + v30 = (random(99, 3) + 1) << 6; + monster[v6]._mhitpoints -= v30; + if ( (signed int)(monster[v6]._mhitpoints & 0xFFFFFFC0) > 0 ) + M_StartHit(arglist, plr_num, v30); + else + M_StartKill(arglist, plr_num); + } + if ( !(monster[v6]._mFlags & 0x1000) && monster[v6].MType->mtype == MT_SKING && gbMaxPlayers != 1 ) + monster[v6]._mhitpoints += v29; + v31 = plr[v7]._pMaxHP; + if ( plr[v7]._pHitPoints > v31 ) + { + plr[v7]._pHitPoints = v31; + plr[v7]._pHPBase = plr[v7]._pMaxHPBase; + } + if ( (signed int)(plr[v7]._pHitPoints & 0xFFFFFFC0) > 0 ) + { + StartPlrHit(plr_num, v29, 0); + if ( SLOBYTE(monster[v6]._mFlags) < 0 ) + { + if ( plr[v7]._pmode != PM_GOTHIT ) + StartPlrHit(plr_num, 0, 1u); + v32 = monster[v6]._mdir; + v33 = plr[v7].WorldX + offset_x[v32]; + v34 = plr[v7].WorldY + offset_y[v32]; + if ( PosOkPlayer(plr_num, v33, v34) ) + { + v35 = plr[v7]._pdir; + plr[v7].WorldX = v33; + plr[v7].WorldY = v34; + FixPlayerLocation(plr_num, v35); + FixPlrWalkTags(plr_num); + dPlayer[v33][v34] = plr_num + 1; + SetPlayerOld(plr_num); + } + } + } + else + { + SyncPlrKill(plr_num, 0); + } + } + else + { + v17 = GetDirection(plr[v7].WorldX, plr[v7].WorldY, monster[v6]._mx, monster[v6]._my); + StartPlrBlock(plr_num, v17); + } + } + return; + } + } +} +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall M_DoAttack(int i) +{ + int v1; // edi + int v2; // esi + CMonster **v3; // ebx + unsigned char v4; // al + unsigned char v5; // al + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoAttack: Invalid monster %d", i); + v2 = v1; + v3 = &monster[v1].MType; + if ( !*v3 ) + { + TermMsg("M_DoAttack: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + if ( !*v3 ) + TermMsg("M_DoAttack: Monster %d \"%s\" MData NULL", v1, monster[v2].mName); + } + if ( monster[v2]._mAnimFrame == monster[v2].MData->mAFNum ) + { + M_TryH2HHit( + v1, + monster[v2]._menemy, + (unsigned char)monster[v2].mHit, + (unsigned char)monster[v2].mMinDamage, + (unsigned char)monster[v2].mMaxDamage); + if ( monster[v2]._mAi != AI_SNAKE ) + PlayEffect(v1, 0); + } + v4 = monster[v2].MType->mtype; + if ( v4 >= MT_NMAGMA && v4 <= MT_WMAGMA && monster[v2]._mAnimFrame == 9 ) + { + M_TryH2HHit( + v1, + monster[v2]._menemy, + (unsigned char)monster[v2].mHit + 10, + (unsigned char)monster[v2].mMinDamage - 2, + (unsigned char)monster[v2].mMaxDamage - 2); + PlayEffect(v1, 0); + } + v5 = monster[v2].MType->mtype; + if ( v5 >= MT_STORM && v5 <= MT_MAEL && monster[v2]._mAnimFrame == 13 ) + { + M_TryH2HHit( + v1, + monster[v2]._menemy, + (unsigned char)monster[v2].mHit - 20, + (unsigned char)monster[v2].mMinDamage + 4, + (unsigned char)monster[v2].mMaxDamage + 4); + PlayEffect(v1, 0); + } + if ( monster[v2]._mAi == AI_SNAKE && monster[v2]._mAnimFrame == 1 ) + PlayEffect(v1, 0); + if ( monster[v2]._mAnimFrame != monster[v2]._mAnimLen ) + return 0; + M_StartStand(v1, monster[v2]._mdir); + return 1; +} + +int __fastcall M_DoRAttack(int i) +{ + int v1; // ebx + int v2; // esi + CMonster **v3; // edi + int v4; // eax + int v5; // eax + int v6; // edi + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoRAttack: Invalid monster %d", i); + v2 = v1; + v3 = &monster[v1].MType; + if ( !*v3 ) + { + TermMsg("M_DoRAttack: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + if ( !*v3 ) + TermMsg("M_DoRAttack: Monster %d \"%s\" MData NULL", v1, monster[v2].mName); + } + if ( monster[v2]._mAnimFrame == monster[v2].MData->mAFNum ) + { + v4 = monster[v2]._mVar1; + if ( v4 != -1 ) + { + v5 = 2 * (v4 == 52) + 1; + if ( v5 > 0 ) + { + v6 = v5; + do + { + AddMissile( + monster[v2]._mx, + monster[v2]._my, + (unsigned char)monster[v2]._menemyx, + (unsigned char)monster[v2]._menemyy, + monster[v2]._mdir, + monster[v2]._mVar1, + 1, + v1, + monster[v2]._mVar2, + 0); + --v6; + } + while ( v6 ); + } + } + PlayEffect(v1, 0); + } + if ( monster[v2]._mAnimFrame != monster[v2]._mAnimLen ) + return 0; + M_StartStand(v1, monster[v2]._mdir); + return 1; +} + +int __fastcall M_DoRSpAttack(int i) +{ + int v1; // ebx + int v2; // esi + CMonster **v3; // edi + bool v4; // zf + int v5; // ecx + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoRSpAttack: Invalid monster %d", i); + v2 = v1; + v3 = &monster[v1].MType; + v4 = *v3 == 0; + if ( !*v3 ) + { + TermMsg("M_DoRSpAttack: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + v4 = *v3 == 0; + } + if ( v4 ) + TermMsg("M_DoRSpAttack: Monster %d \"%s\" MData NULL", v1, monster[v2].mName); + if ( monster[v2]._mAnimFrame == monster[v2].MData->mAFNum2 && !monster[v2]._mAnimCnt ) + { + AddMissile( + monster[v2]._mx, + monster[v2]._my, + (unsigned char)monster[v2]._menemyx, + (unsigned char)monster[v2]._menemyy, + monster[v2]._mdir, + monster[v2]._mVar1, + 1, + v1, + monster[v2]._mVar3, + 0); + PlayEffect(v1, 3); + } + if ( monster[v2]._mAi == AI_MEGA && monster[v2]._mAnimFrame == 3 ) + { + v5 = monster[v2]._mVar2; + monster[v2]._mVar2 = v5 + 1; + if ( v5 ) + { + if ( v5 == 14 ) + monster[v2]._mFlags &= 0xFFFFFFFB; + } + else + { + monster[v2]._mFlags |= 4u; + } + } + if ( monster[v2]._mAnimFrame != monster[v2]._mAnimLen ) + return 0; + M_StartStand(v1, monster[v2]._mdir); + return 1; +} + +int __fastcall M_DoSAttack(int i) +{ + int v1; // ebx + int v2; // esi + CMonster **v3; // edi + bool v4; // zf + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoSAttack: Invalid monster %d", i); + v2 = v1; + v3 = &monster[v1].MType; + v4 = *v3 == 0; + if ( !*v3 ) + { + TermMsg("M_DoSAttack: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + v4 = *v3 == 0; + } + if ( v4 ) + TermMsg("M_DoSAttack: Monster %d \"%s\" MData NULL", v1, monster[v2].mName); + if ( monster[v2]._mAnimFrame == monster[v2].MData->mAFNum2 ) + M_TryH2HHit( + v1, + monster[v2]._menemy, + (unsigned char)monster[v2].mHit2, + (unsigned char)monster[v2].mMinDamage2, + (unsigned char)monster[v2].mMaxDamage2); + if ( monster[v2]._mAnimFrame != monster[v2]._mAnimLen ) + return 0; + M_StartStand(v1, monster[v2]._mdir); + return 1; +} + +int __fastcall M_DoFadein(int i) +{ + int v1; // edi + int v2; // esi + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoFadein: Invalid monster %d", i); + v2 = v1; + if ( (!(monster[v1]._mFlags & 2) || monster[v2]._mAnimFrame != 1) + && (monster[v1]._mFlags & 2 || monster[v2]._mAnimFrame != monster[v2]._mAnimLen) ) + { + return 0; + } + M_StartStand(v1, monster[v2]._mdir); + monster[v2]._mFlags &= 0xFFFFFFFD; + return 1; +} + +int __fastcall M_DoFadeout(int i) +{ + int v1; // esi + int v2; // eax + int v3; // ecx + signed int v4; // edx + int v5; // ecx + int v6; // edx + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoFadeout: Invalid monster %d", i); + v2 = v1; + v3 = monster[v1]._mFlags; + if ( (!(monster[v1]._mFlags & 2) || monster[v2]._mAnimFrame != 1) + && (monster[v1]._mFlags & 2 || monster[v2]._mAnimFrame != monster[v2]._mAnimLen) ) + { + return 0; + } + v4 = monster[v2].MType->mtype; + if ( v4 < MT_INCIN || v4 > MT_HELLBURN ) + v5 = v3 & 0xFFFFFFFD | 1; + else + v5 = v3 & 0xFFFFFFFD; + v6 = monster[v2]._mdir; + monster[v2]._mFlags = v5; + M_StartStand(v1, v6); + return 1; +} + +int __fastcall M_DoHeal(int i) +{ + int v1; // esi + int v2; // eax + int v3; // esi + int *v4; // edx + int v5; // ecx + int v6; // edi + int v7; // edi + int v8; // esi + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoHeal: Invalid monster %d", i); + v2 = v1; + if ( monster[v1]._mFlags & 8 ) + { + monster[v2]._mFlags &= 0xFFFFFFFB; + monster[v2]._mmode = MM_SATTACK; + } + else if ( monster[v2]._mAnimFrame == 1 ) + { + v3 = monster[v2]._mVar1; + v4 = &monster[v2]._mhitpoints; + v5 = monster[v2]._mFlags & 0xFFFFFFFD | 4; + v6 = monster[v2]._mhitpoints; + monster[v2]._mFlags = v5; + v7 = v3 + v6; + v8 = monster[v2]._mmaxhp; + if ( v7 >= v8 ) + { + *v4 = v8; + monster[v2]._mFlags = v5 & 0xFFFFFFFB; + monster[v2]._mmode = MM_SATTACK; + } + else + { + *v4 = v7; + } + } + return 0; +} + +int __fastcall M_DoTalk(int i) +{ + int v1; // edi + int v2; // esi + //int v3; // eax + int v4; // eax + int v5; // edx + int v6; // ecx + char v7; // bl + int v8; // eax + char *v9; // eax + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoTalk: Invalid monster %d", i); + v2 = v1; + M_StartStand(v1, monster[v1]._mdir); + _LOBYTE(monster[v1]._mgoal) = 7; + //_LOBYTE(v3) = effect_is_playing(alltext[monster[v1].mtalkmsg].sfxnr); + if ( !effect_is_playing(alltext[monster[v1].mtalkmsg].sfxnr) ) + { + InitQTextMsg(monster[v2].mtalkmsg); + if ( monster[v2].mName == UniqMonst[0].mName ) + { + v4 = monster[v2].mtalkmsg; + if ( v4 == QUEST_GARBUD1 ) + quests[2]._qactive = 2; + quests[2]._qlog = 1; + if ( v4 == QUEST_GARBUD2 && !(monster[v2]._mFlags & 0x40) ) + { + SpawnItem(v1, monster[v2]._mx + 1, monster[v2]._my + 1, 1u); + monster[v2]._mFlags |= 0x40u; + } + } + if ( monster[v2].mName == UniqMonst[2].mName + && monster[v2].mtalkmsg == QUEST_ZHAR1 + && !(monster[v2]._mFlags & 0x40) ) + { + v5 = monster[v2]._my + 1; + v6 = monster[v2]._mx + 1; + quests[3]._qactive = 2; + quests[3]._qlog = 1; + CreateTypeItem(v6, v5, 0, 0, 24, 1, 0); + monster[v2]._mFlags |= 0x40u; + } + if ( monster[v2].mName == UniqMonst[3].mName ) + { + if ( monster[v2].mtalkmsg == QUEST_BANNER10 && !(monster[v2]._mFlags & 0x40) ) + { + ObjChangeMap(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 2, (setpc_h >> 1) + setpc_y - 2); + v7 = TransVal; + TransVal = 9; + DRLG_MRectTrans(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 4, setpc_y + (setpc_h >> 1)); + TransVal = v7; + quests[7]._qvar1 = 2; + if ( quests[7]._qactive == 1 ) + quests[7]._qactive = 2; + monster[v2]._mFlags |= 0x40u; + } + if ( quests[7]._qvar1 < 2u ) + { + sprintf(tempstr, "SS Talk = %i, Flags = %i", monster[v2].mtalkmsg, monster[v2]._mFlags); + TermMsg(tempstr); + } + } + if ( monster[v2].mName == UniqMonst[7].mName ) + { + v8 = monster[v2].mtalkmsg; + if ( v8 == QUEST_VEIL9 ) + { + quests[4]._qactive = 2; + quests[4]._qlog = 1; + } + if ( v8 == QUEST_VEIL11 && !(monster[v2]._mFlags & 0x40) ) + { + SpawnUnique(UITEM_STEELVEIL, monster[v2]._mx + 1, monster[v2]._my + 1); + monster[v2]._mFlags |= 0x40u; + } + } + v9 = monster[v2].mName; + if ( v9 == UniqMonst[8].mName ) + quests[11]._qvar1 = 2; + if ( v9 == UniqMonst[4].mName && gbMaxPlayers != 1 ) + { + monster[v2]._msquelch = -1; + monster[v2].mtalkmsg = 0; + quests[15]._qvar1 = 6; + _LOBYTE(monster[v2]._mgoal) = 1; + } + } + return 0; +} +// 4351F5: could not find valid save-restore pair for ebp +// 5A5590: using guessed type char TransVal; +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall M_Teleport(int i) +{ + int v1; // ebx + //int v2; // ST04_4 + MonsterStruct *v3; // esi + int v4; // eax + int v6; // edi + int v7; // ebx + int v8; // eax + int v9; // [esp+Ch] [ebp-24h] + int v10; // [esp+10h] [ebp-20h] + int v11; // [esp+14h] [ebp-1Ch] + int v12; // [esp+18h] [ebp-18h] + int v13; // [esp+1Ch] [ebp-14h] + int a1; // [esp+20h] [ebp-10h] + signed int v15; // [esp+24h] [ebp-Ch] + signed int v16; // [esp+28h] [ebp-8h] + signed int v17; // [esp+2Ch] [ebp-4h] + + v1 = i; + a1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + { + TermMsg("M_Teleport: Invalid monster %d", i); + //i = v2; + } + v15 = 0; + v3 = &monster[v1]; + if ( v3->_mmode != MM_STONE ) + { + v10 = (unsigned char)v3->_menemyx; + v12 = (unsigned char)v3->_menemyy; + v4 = random(100, 2); + v11 = 2 * v4 - 1; + v17 = -1; + v6 = 0; /* v9 */ + v13 = 2 * random(100, 2) - 1; + while ( !v15 ) + { + v16 = -1; + v7 = v12 - v13; + do + { + if ( v15 ) + break; + if ( v17 || v16 ) + { + v9 = v7; + v6 = v10 + v11 * v17; + if ( v7 >= 0 && v7 < 112 && v6 >= 0 && v6 < 112 && v6 != v3->_mx && v7 != v3->_my ) + { + if ( PosOkMonst(a1, v10 + v11 * v17, v7) ) + v15 = 1; + } + } + ++v16; + v7 += v13; + } + while ( v16 < 1 ); + if ( ++v17 > 1 ) + { + if ( !v15 ) + return; + v1 = a1; + break; + } + v1 = a1; + } + M_ClearSquares(v1); + v8 = v3->_my + 112 * v3->_mx; + v3->_moldx = v6; + dMonster[0][v8] = 0; + v3->_moldy = v9; + dMonster[0][v9 + 112 * v6] = v1 + 1; + v3->_mdir = M_GetDir(v1); + M_CheckEFlag(v1); + } +} + +int __fastcall M_DoGotHit(int i) +{ + int v1; // edi + int v2; // esi + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoGotHit: Invalid monster %d", i); + v2 = v1; + if ( !monster[v1].MType ) + TermMsg("M_DoGotHit: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + if ( monster[v2]._mAnimFrame != monster[v2]._mAnimLen ) + return 0; + M_StartStand(v1, monster[v2]._mdir); + return 1; +} + +void __fastcall M_UpdateLeader(int i) +{ + int v1; // edi + int v2; // esi + int j; // edx + int v4; // eax + unsigned char *v5; // eax + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_UpdateLeader: Invalid monster %d", i); + v2 = nummonsters; + for ( j = 0; j < v2; ++j ) + { + v4 = monstactive[j]; + if ( monster[v4].leaderflag == 1 && (unsigned char)monster[v4].leader == v1 ) + monster[v4].leaderflag = 0; + } + if ( monster[v1].leaderflag == 1 ) + { + v5 = &monster[(unsigned char)monster[v1].leader].unpackfilesize; + --*v5; + } +} + +void __cdecl DoEnding() +{ + if ( gbMaxPlayers > 1 ) { + SNetLeaveGame(0x40000004); + } + + music_stop(); + + if ( gbMaxPlayers > 1 ) { + Sleep(1000); + } + + if ( plr[myplr]._pClass == PC_WARRIOR ) { + play_movie("gendata\\DiabVic2.smk", 0); + } else if ( plr[myplr]._pClass == PC_SORCERER ) { + play_movie("gendata\\DiabVic1.smk", 0); + } else { + play_movie("gendata\\DiabVic3.smk", 0); + } + play_movie("gendata\\Diabend.smk", 0); + + BOOL bMusicOn = gbMusicOn; + gbMusicOn = 1; + + int musicVolume = sound_get_or_set_music_volume(1); + sound_get_or_set_music_volume(0); + + music_start(2); + loop_movie = 1; + play_movie("gendata\\loopdend.smk", 1); + loop_movie = 0; + music_stop(); + + sound_get_or_set_music_volume(musicVolume); + gbMusicOn = bMusicOn; +} +// 4A22D4: using guessed type char gbMusicOn; +// 659AFC: using guessed type int loop_movie; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl PrepDoEnding() +{ + int *v0; // eax + int v1; // ecx + int *v2; // eax + bool v3; // cf + bool v4; // zf + + gbSoundOn = sgbSaveSoundOn; + gbRunGame = 0; + deathflag = 0; + v0 = &plr[myplr].pDiabloKillLevel; + v1 = gnDifficulty + 1; + cineflag = 1; + if ( *v0 > (unsigned int)(gnDifficulty + 1) ) + v1 = *v0; + *v0 = v1; + v2 = &plr[0]._pHitPoints; + do + { + v3 = (unsigned char)gbMaxPlayers < 1u; + v4 = gbMaxPlayers == 1; + *(v2 - 102) = 11; + *((_BYTE *)v2 - 91) = 1; + if ( !v3 && !v4 ) + { + if ( !(*v2 & 0xFFFFFFC0) ) + *v2 = 64; + if ( !(v2[5] & 0xFFFFFFC0) ) + v2[5] = 64; + } + v2 += 5430; + } + while ( (signed int)v2 < (signed int)&plr[4]._pHitPoints ); +} +// 4A22D5: using guessed type char gbSoundOn; +// 525650: using guessed type int gbRunGame; +// 525718: using guessed type char cineflag; +// 64D32C: using guessed type int sgbSaveSoundOn; +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall M_DoDeath(int i) +{ + int v1; // edi + int v2; // esi + CMonster *v3; // ecx + int v4; // eax + int v5; // ecx + signed int v6; // ecx + int v7; // esi + int v8; // esi + signed int v9; // ecx + char v10; // al + int v11; // eax + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoDeath: Invalid monster %d", i); + v2 = v1; + if ( !monster[v1].MType ) + TermMsg("M_DoDeath: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + v3 = monster[v2].MType; + v4 = ++monster[v2]._mVar1; + if ( v3->mtype == MT_DIABLO ) + { + v5 = monster[v2]._mx - ViewX; + if ( v5 >= 0 ) + v6 = v5 > 0; + else + v6 = -1; + v7 = monster[v2]._my; + ViewX += v6; + v8 = v7 - ViewY; + if ( v8 >= 0 ) + { + v9 = v8 < 0; + _LOBYTE(v9) = v8 > 0; + } + else + { + v9 = -1; + } + ViewY += v9; + if ( v4 == 140 ) + PrepDoEnding(); + } + else if ( monster[v2]._mAnimFrame == monster[v2]._mAnimLen ) + { + if ( monster[v2]._uniqtype ) + v10 = monster[v2]._udeadval; + else + v10 = v3->mdeadval; + AddDead(monster[v2]._mx, monster[v2]._my, v10, (direction)monster[v2]._mdir); + v11 = monster[v2]._my + 112 * monster[v2]._mx; + monster[v2]._mDelFlag = 1; + dMonster[0][v11] = 0; + M_UpdateLeader(v1); + } + return 0; +} + +int __fastcall M_DoSpStand(int i) +{ + int v1; // ebx + int v2; // esi + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoSpStand: Invalid monster %d", i); + v2 = v1; + if ( !monster[v1].MType ) + TermMsg("M_DoSpStand: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + if ( monster[v2]._mAnimFrame == monster[v2].MData->mAFNum2 ) + PlayEffect(v1, 3); + if ( monster[v2]._mAnimFrame != monster[v2]._mAnimLen ) + return 0; + M_StartStand(v1, monster[v2]._mdir); + return 1; +} + +int __fastcall M_DoDelay(int i) +{ + int v1; // ebp + int v2; // esi + int v3; // eax + bool v4; // zf + int v5; // ecx + int v6; // ecx + int v7; // ebx + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoDelay: Invalid monster %d", i); + v2 = v1; + if ( !monster[v1].MType ) + TermMsg("M_DoDelay: Monster %d \"%s\" MType NULL", v1, monster[v2].mName); + v3 = M_GetDir(v1); + v4 = monster[v2]._mAi == AI_LAZURUS; + monster[v2]._mAnimData = monster[v2].MType->Anims[0].Frames[v3]; + if ( v4 ) + { + v5 = monster[v2]._mVar2; + if ( v5 > 8 || v5 < 0 ) + monster[v2]._mVar2 = 8; + } + v6 = monster[v2]._mVar2; + monster[v2]._mVar2 = v6 - 1; + if ( v6 ) + return 0; + v7 = monster[v2]._mAnimFrame; + M_StartStand(v1, monster[v2]._mdir); + monster[v2]._mAnimFrame = v7; + return 1; +} + +int __fastcall M_DoStone(int i) +{ + int v1; // esi + int v2; // eax + int v3; // ecx + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_DoStone: Invalid monster %d", i); + v2 = v1; + if ( !monster[v1]._mhitpoints ) + { + v3 = monster[v2]._mx; + monster[v2]._mDelFlag = 1; + dMonster[0][monster[v2]._my + 112 * v3] = 0; + } + return 0; +} + +void __fastcall M_WalkDir(int i, int md) +{ + int v2; // esi + int v3; // edi + int v4; // eax + int v5; // eax + int v6; // edx + int v7; // ecx + int v8; // eax + int v9; // edx + int v10; // eax + int v11; // [esp-14h] [ebp-1Ch] + int v12; // [esp-Ch] [ebp-14h] + int v13; // [esp-Ch] [ebp-14h] + int v14; // [esp-8h] [ebp-10h] + int v15; // [esp-8h] [ebp-10h] + int v16; // [esp-4h] [ebp-Ch] + int v17; // [esp-4h] [ebp-Ch] + + v2 = i; + v3 = md; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_WalkDir: Invalid monster %d", i); + v4 = monster[v2].MType->Anims[1].Rate - 1; + switch ( v3 ) + { + case DIR_S: + M_StartWalk2(v2, 0, MWVel[v4][1], 0, -32, 1, 1, 0); + return; + case DIR_SW: + v17 = 1; + v8 = v4; + v15 = 1; + v13 = 0; + v11 = 32; + v9 = -MWVel[v8][1]; + goto LABEL_10; + case DIR_W: + M_StartWalk3(v2, -MWVel[v4][2], 0, 32, -16, -1, 1, 0, 1, 2); + return; + case DIR_NW: + v16 = 3; + v10 = v4; + v14 = 0; + v12 = -1; + v7 = -MWVel[v10][0]; + v6 = -MWVel[v10][1]; + goto LABEL_15; + case DIR_N: + M_StartWalk(v2, 0, -MWVel[v4][1], -1, -1, 4); + break; + case DIR_NE: + v16 = 5; + v5 = v4; + v14 = -1; + v12 = 0; + v6 = MWVel[v5][1]; + v7 = -MWVel[v5][0]; + LABEL_15: + M_StartWalk(v2, v6, v7, v12, v14, v16); + break; + case DIR_E: + M_StartWalk3(v2, MWVel[v4][2], 0, -32, -16, 1, -1, 1, 0, 6); + break; + case DIR_SE: + v17 = 7; + v8 = v4; + v15 = 0; + v13 = 1; + v9 = MWVel[v8][1]; + v11 = -32; + LABEL_10: + M_StartWalk2(v2, v9, MWVel[v8][0], v11, -16, v13, v15, v17); + break; + default: + return; + } +} + +void __fastcall GroupUnity(int i) +{ + int v1; // ebx + int v2; // esi + int v3; // ebp + int v4; // edi + bool v5; // eax + int v6; // eax + int v7; // ecx + unsigned char v8; // al + int v9; // ebp + int j; // edi + int v11; // eax + int v12; // ecx + //int v13; // [esp+10h] [ebp-4h] + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("GroupUnity: Invalid monster %d", i); + v2 = v1; + if ( monster[v1].leaderflag ) + { + v3 = (unsigned char)monster[v2].leader; + v4 = v3; + v5 = LineClearF( + CheckNoSolid, + monster[v2]._mx, + monster[v2]._my, + monster[v4]._mfutx, + monster[v4]._mfuty); + if ( v5 ) + { + if ( monster[v2].leaderflag == 2 + && abs(monster[v2]._mx - monster[v4]._mfutx) < 4 + && abs(monster[v2]._my - monster[v4]._mfuty) < 4 ) + { + ++monster[v4].unpackfilesize; + monster[v2].leaderflag = 1; + } + } + else + { + if ( monster[v2].leaderflag != 1 ) + goto LABEL_18; + --monster[v4].unpackfilesize; + monster[v2].leaderflag = 2; + } + } + else + { + v3 = 0; /* v13 */ + } + if ( monster[v2].leaderflag == 1 ) + { + v6 = v3; + if ( monster[v2]._msquelch > monster[v3]._msquelch ) + { + monster[v6]._lastx = monster[v2]._mx; + monster[v6]._lasty = monster[v2]._my; + monster[v6]._msquelch = monster[v2]._msquelch - 1; + } + if ( monster[v6]._mAi == AI_GARG ) + { + v7 = monster[v6]._mFlags; + if ( v7 & 4 ) + { + monster[v6]._mmode = MM_SATTACK; + monster[v6]._mFlags = v7 & 0xFFFFFFFB; + } + } + return; + } +LABEL_18: + v8 = monster[v2]._uniqtype; + if ( v8 ) + { + if ( UniqMonst[v8 - 1].mUnqAttr & 2 ) + { + v9 = nummonsters; + for ( j = 0; j < v9; ++j ) + { + v11 = monstactive[j]; + if ( monster[v11].leaderflag == 1 && (unsigned char)monster[v11].leader == v1 ) + { + if ( monster[v2]._msquelch > monster[v11]._msquelch ) + { + monster[v11]._lastx = monster[v2]._mx; + monster[v11]._lasty = monster[v2]._my; + monster[v11]._msquelch = monster[v2]._msquelch - 1; + } + if ( monster[v11]._mAi == AI_GARG ) + { + v12 = monster[v11]._mFlags; + if ( v12 & 4 ) + { + monster[v11]._mmode = MM_SATTACK; + monster[v11]._mFlags = v12 & 0xFFFFFFFB; + } + } + } + } + } + } +} + +bool __fastcall M_CallWalk(int i, int md) +{ + int v2; // esi + int v3; // edi + int v4; // ebp + //int v5; // eax + bool v7; // ebx + int v9; // ebx + //int v10; // eax + int v11; // ebx + //int v12; // eax + //int v13; // eax + signed int v14; // ebx + //int v15; // eax + //int v16; // eax + //int v17; // eax + unsigned char v18; // bl + + v2 = md; + v3 = i; + v4 = md; + //_LOBYTE(v5) = DirOK(i, md); + v7 = DirOK(i, md); + if ( random(101, 2) ) + { + if ( v7 ) + goto LABEL_10; + v9 = v2; + v2 = left[v2]; + //_LOBYTE(v10) = DirOK(v3, v2); + if ( DirOK(v3, v2) ) + goto LABEL_10; + v2 = right[v9]; + } + else + { + if ( v7 ) + goto LABEL_10; + v11 = v2; + v2 = right[v2]; + //_LOBYTE(v12) = DirOK(v3, v2); + if ( DirOK(v3, v2) ) + goto LABEL_10; + v2 = left[v11]; + } + //_LOBYTE(v13) = DirOK(v3, v2); + if ( !DirOK(v3, v2) ) + { + v14 = 0; + goto LABEL_11; + } +LABEL_10: + v14 = 1; +LABEL_11: + if ( random(102, 2) ) + { + if ( v14 ) + goto LABEL_20; + v2 = right[right[v4]]; + //_LOBYTE(v15) = DirOK(v3, v2); + if ( DirOK(v3, v2) ) + goto LABEL_20; + v2 = left[left[v4]]; + } + else + { + if ( v14 ) + goto LABEL_20; + v2 = left[left[v4]]; + //_LOBYTE(v16) = DirOK(v3, v2); + if ( DirOK(v3, v2) ) + goto LABEL_20; + v2 = right[right[v4]]; + } + //_LOBYTE(v17) = DirOK(v3, v2); + if ( DirOK(v3, v2) ) + { + LABEL_20: + v18 = 1; + M_WalkDir(v3, v2); + return v18; + } + return 0; +} + +bool __fastcall M_PathWalk(int i) +{ + int v1; // esi + BOOL(__fastcall *Check)(int, int, int); // ecx + char path[25]; // [esp+4h] [ebp-1Ch] + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("M_PathWalk: Invalid monster %d", i); + Check = PosOkMonst3; + if ( !(monster[v1]._mFlags & 0x200) ) + Check = PosOkMonst; + if ( !FindPath( + Check, + v1, + monster[v1]._mx, + monster[v1]._my, + (unsigned char)monster[v1]._menemyx, + (unsigned char)monster[v1]._menemyy, + path) ) + return 0; + M_CallWalk(v1, (char)plr2monst[path[0]]); /* plr2monst is local */ + return 1; +} + +bool __fastcall M_CallWalk2(int i, int md) +{ + int v2; // esi + int v3; // ebx + //int v4; // eax + bool v6; // edi + int v7; // edi + //int v8; // eax + int v9; // edi + //int v10; // eax + //int v11; // eax + bool v12; // di + + v2 = md; + v3 = i; + //_LOBYTE(v4) = DirOK(i, md); + v6 = DirOK(i, md); + if ( random(101, 2) ) + { + if ( v6 ) + goto LABEL_10; + v7 = v2; + v2 = left[v2]; + //_LOBYTE(v8) = DirOK(v3, v2); + if ( DirOK(v3, v2) ) + goto LABEL_10; + v2 = right[v7]; + } + else + { + if ( v6 ) + goto LABEL_10; + v9 = v2; + v2 = right[v2]; + //_LOBYTE(v10) = DirOK(v3, v2); + if ( DirOK(v3, v2) ) + goto LABEL_10; + v2 = left[v9]; + } + //_LOBYTE(v11) = DirOK(v3, v2); + if ( DirOK(v3, v2) ) + { + LABEL_10: + v12 = 1; + M_WalkDir(v3, v2); + return v12; + } + return 0; +} + +bool __fastcall M_DumbWalk(int i, int md) +{ + int v2; // esi + int v3; // edi + //int v4; // eax + bool v5; // bl + + v2 = md; + v3 = i; + //_LOBYTE(v4) = DirOK(i, md); + v5 = DirOK(i, md); + if ( v5 ) + M_WalkDir(v3, v2); + return v5; +} + +bool __fastcall M_RoundWalk(int i, int md, int *dir) +{ + int *v3; // ebp + int v4; // ebx + int v5; // esi + //int v6; // eax + bool v7; // di + int v8; // edi + //int v9; // eax + //int v10; // eax + int *v11; // ebp + //int v12; // eax + //int v13; // eax + + v3 = dir; + v4 = i; + if ( *dir ) + v5 = left[left[md]]; + else + v5 = right[right[md]]; + //_LOBYTE(v6) = DirOK(i, v5); + v7 = DirOK(i, v5); + if ( v7 ) + goto LABEL_12; + v8 = v5; + if ( !*dir ) + { + v11 = &left[v8]; + v5 = left[v8]; + //_LOBYTE(v12) = DirOK(v4, left[v8]); + if ( DirOK(v4, left[v8]) ) + goto LABEL_11; + v5 = left[*v11]; + //_LOBYTE(v13) = DirOK(v4, left[*v11]); + if ( DirOK(v4, left[*v11]) ) + goto LABEL_11; + v3 = dir; + LABEL_14: + *v3 = *v3 == 0; + return M_CallWalk(v4, opposite[v8]); + } + v5 = right[v8]; + //_LOBYTE(v9) = DirOK(v4, right[v8]); + if ( !DirOK(v4, right[v8]) ) + { + v5 = right[right[v8]]; + //_LOBYTE(v10) = DirOK(v4, v5); + if ( !DirOK(v4, v5) ) + goto LABEL_14; + } +LABEL_11: + v7 = 1; +LABEL_12: + M_WalkDir(v4, v5); + return v7; +} + +void __fastcall MAI_Zombie(int i) +{ + int v1; // esi + //int v2; // ST04_4 + MonsterStruct *v3; // esi + int v4; // edi + int v5; // ebx + int v6; // edi + int v7; // eax + int v8; // ecx + int v9; // eax + int v10; // eax + int v11; // eax + int v12; // ecx + int md; // [esp+Ch] [ebp-Ch] + int v14; // [esp+10h] [ebp-8h] + int arglist; // [esp+14h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + { + TermMsg("MAI_Zombie: Invalid monster %d", i); + //i = v2; + } + v3 = &monster[v1]; + if ( v3->_mmode == MM_STAND ) + { + v4 = v3->_my; + if ( dFlags[v3->_mx][v4] & 2 ) + { + v5 = v3->_mx - (unsigned char)v3->_menemyx; + v6 = v4 - (unsigned char)v3->_menemyy; + md = v3->_mdir; + v14 = random(103, 100); + if ( abs(v5) >= 2 || abs(v6) >= 2 ) + { + if ( v14 < 2 * (unsigned char)v3->_mint + 10 ) + { + v7 = abs(v5); + v8 = 2 * (unsigned char)v3->_mint + 4; + if ( v7 >= v8 || (v9 = abs(v6), v8 = 2 * (unsigned char)v3->_mint + 4, v9 >= v8) ) + { + v11 = random(104, 100); + v12 = 2 * (unsigned char)v3->_mint + 20; + if ( v11 < v12 ) + { + md = random(104, 8); + } + M_DumbWalk(arglist, md); + } + else + { + v10 = M_GetDir(arglist); + M_CallWalk(arglist, v10); + } + } + } + else if ( v14 < 2 * (unsigned char)v3->_mint + 10 ) + { + M_StartAttack(arglist); + } + if ( v3->_mmode == MM_STAND ) + v3->_mAnimData = v3->MType->Anims[0].Frames[v3->_mdir]; + } + } +} + +void __fastcall MAI_SkelSd(int i) +{ + int v1; // esi + MonsterStruct *v2; // esi + int v3; // ecx + int v4; // edx + int v5; // edi + int v6; // ebp + int v7; // ebx + int v8; // eax + //int v9; // ST04_4 + int v11; // eax + //int v12; // ST04_4 + int v13; // eax + int v14; // ecx + int v15; // edx + int v16; // eax + int v17; // ecx + int arglist; // [esp+8h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_SkelSd: Invalid monster %d", i); + v2 = &monster[v1]; + if ( v2->_mmode == MM_STAND && v2->_msquelch ) + { + v3 = v2->_mx; + v4 = v2->_my; + v5 = v3 - (unsigned char)v2->_menemyx; + v6 = v4 - (unsigned char)v2->_menemyy; + v7 = GetDirection(v3, v4, v2->_lastx, v2->_lasty); + v2->_mdir = v7; + v8 = abs(v5); + //v10 = v9; + if ( v8 >= 2 || (v11 = abs(v6), v11 >= 2) ) /* v10 = v12, */ + { + if ( v2->_mVar1 != 13 ) + { + v16 = random(106, 100); + v17 = 4 * (unsigned char)v2->_mint; + if ( v16 < 35 - v17 ) + { + v15 = 15 - 2 * (unsigned char)v2->_mint + random(106, 10); + goto LABEL_10; + } + } + M_CallWalk(arglist, v7); + } + else + { + if ( v2->_mVar1 != 13 ) + { + v13 = random(105, 100); + v14 = 2 * (unsigned char)v2->_mint + 20; + if ( v13 >= v14 ) + { + v15 = random(105, 10) + 2 * (5 - (unsigned char)v2->_mint); + LABEL_10: + M_StartDelay(arglist, v15); + goto LABEL_16; + } + } + M_StartAttack(arglist); + } + LABEL_16: + if ( v2->_mmode == MM_STAND ) + v2->_mAnimData = v2->MType->Anims[0].Frames[v7]; + } +} + +bool __fastcall MAI_Path(int i) +{ + int v1; // edi + MonsterStruct *v2; // esi + char v3; // al + bool v4; // eax + unsigned char v5; // al + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Path: Invalid monster %d", i); + v2 = &monster[v1]; + if ( v2->MType->mtype != MT_GOLEM ) + { + if ( !v2->_msquelch ) + return 0; + if ( v2->_mmode ) + return 0; + v3 = v2->_mgoal; + if ( v3 != 1 && v3 != 4 && v3 != 5 ) + return 0; + if ( v2->_mx == 1 && !v2->_my ) + return 0; + } + v4 = LineClearF1( + PosOkMonst2, + v1, + v2->_mx, + v2->_my, + (unsigned char)v2->_menemyx, + (unsigned char)v2->_menemyy); + if ( !v4 || (v5 = v2->_pathcount, v5 >= 5u) && v5 < 8u ) + { + if ( v2->_mFlags & 0x200 ) + MonstCheckDoors(v1); + if ( ++_LOBYTE(v2->_pathcount) < 5u ) + return 0; + if ( M_PathWalk(v1) ) + return 1; + } + if ( v2->MType->mtype != MT_GOLEM ) + _LOBYTE(v2->_pathcount) = 0; + return 0; +} + +void __fastcall MAI_Snake(int i) +{ + int esi1; // esi + MonsterStruct *esi3; // esi + bool v3; // zf + int v4; // ecx + int v5; // eax + int v6; // ST1C_4 + int v7; // edi + int v8; // edx + int v9; // ST18_4 + int v10; // ebx + int v11; // eax + //int v12; // ST1C_4 + int v14; // eax + int v15; // eax + int v16; // ecx + int v17; // edx + int v18; // ecx + int v19; // eax + //int v20; // ST1C_4 + int v22; // eax + //int v23; // ST1C_4 + int v24; // ebx + int v26; // ecx + int v27; // eax + int v28; // ecx + int v29; // ecx + int v30; // eax + int v31; // edx + int v32; // eax + int v33; // ecx + int v34; // ecx + int v35; // eax + char pattern[6]; // [esp+4h] [ebp-1Ch] + int micaster; // [esp+Ch] [ebp-14h] + int midir; // [esp+10h] [ebp-10h] + int v1; // [esp+14h] [ebp-Ch] + int v2; // [esp+18h] [ebp-8h] + int arglist; // [esp+1Ch] [ebp-4h] + + esi1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Snake: Invalid monster %d", i); + pattern[2] = 0; + pattern[3] = -1; + pattern[4] = -1; + pattern[5] = 0; + esi3 = &monster[esi1]; + pattern[0] = 1; + pattern[1] = 1; + v3 = esi3->_mmode == MM_STAND; + micaster = esi3->_menemy; + if ( v3 && esi3->_msquelch ) + { + v4 = esi3->_mx; + v5 = (unsigned char)esi3->_menemyy; + v6 = esi3->_lasty; + v1 = (unsigned char)esi3->_menemyx; + v7 = v4 - v1; + v8 = esi3->_my; + v9 = esi3->_lastx; + v2 = v5; + v10 = v8 - v5; + midir = GetDirection(v4, v8, v9, v6); + esi3->_mdir = midir; + if ( abs(v7) < 2 ) + { + v11 = abs(v10); + //v13 = v12; + if ( v11 < 2 ) + { + v14 = esi3->_mVar1; + if ( v14 == 13 + || v14 == 14 + || (v15 = random(105, 100), v16 = (unsigned char)esi3->_mint + 20, v15 < v16) ) + { + M_StartAttack(arglist); + LABEL_49: + if ( esi3->_mmode == MM_STAND ) + esi3->_mAnimData = esi3->MType->Anims[0].Frames[esi3->_mdir]; + return; + } + v17 = 10 - (unsigned char)esi3->_mint + random(105, 10); + v18 = arglist; + LABEL_11: + M_StartDelay(v18, v17); + goto LABEL_49; + } + } + v19 = abs(v7); + //v21 = v20; + if ( v19 >= 3 || (v22 = abs(v10), v22 >= 3) ) /* v21 = v23, */ + { + v24 = arglist; + } + else + { + v24 = arglist; + if ( LineClearF1(PosOkMonst, arglist, esi3->_mx, esi3->_my, v1, v2) && esi3->_mVar1 != 14 ) + { + if ( AddMissile(esi3->_mx, esi3->_my, v1, v2, midir, 20, micaster, arglist, 0, 0) != -1 ) + { + PlayEffect(arglist, 0); + v26 = esi3->_my + 112 * esi3->_mx; + esi3->_mmode = MM_CHARGE; + dMonster[0][v26] = -1 - v24; + } + goto LABEL_49; + } + } + if ( esi3->_mVar1 != 13 ) + { + v27 = random(106, 100); + v28 = 2 * (unsigned char)esi3->_mint; + if ( v27 < 35 - v28 ) + { + v17 = 15 - (unsigned char)esi3->_mint + random(106, 10); + v18 = v24; + goto LABEL_11; + } + } + v29 = esi3->_mgoalvar1; + v30 = midir + pattern[v29]; + if ( v30 >= 0 ) + { + v31 = v30 - 8; + if ( v30 < 8 ) + v31 = midir + pattern[v29]; + } + else + { + v31 = v30 + 8; + } + esi3->_mgoalvar1 = v29 + 1; + if ( v29 + 1 > 5 ) + esi3->_mgoalvar1 = 0; + v32 = esi3->_mgoalvar2; + v33 = v31 - v32; + if ( v31 - v32 >= 0 ) + { + if ( v33 >= 8 ) + v33 -= 8; + } + else + { + v33 += 8; + } + if ( v33 <= 0 ) + { + LABEL_47: + if ( !M_DumbWalk(v24, esi3->_mgoalvar2) ) + M_CallWalk2(v24, esi3->_mdir); + goto LABEL_49; + } + if ( v33 >= 4 ) + { + if ( v33 == 4 ) + { + esi3->_mgoalvar2 = v31; + goto LABEL_47; + } + v34 = v32 - 1; + if ( v32 - 1 < 0 ) + { + v35 = v32 + 7; + goto LABEL_46; + } + if ( v34 >= 8 ) + { + v35 = v32 - 9; + goto LABEL_46; + } + } + else + { + v34 = v32 + 1; + if ( v32 + 1 < 0 ) + { + v35 = v32 + 9; + LABEL_46: + esi3->_mgoalvar2 = v35; + goto LABEL_47; + } + if ( v34 >= 8 ) + { + v35 = v32 - 7; + goto LABEL_46; + } + } + v35 = v34; + goto LABEL_46; + } +} + +void __fastcall MAI_Bat(int i) +{ + int esi1; // esi + MonsterStruct *esi3; // esi + int v3; // ecx + int v4; // edx + int v5; // edi + int v6; // ebx + int v7; // eax + int v10; // edx + bool v11; // eax + int v12; // ecx + CMonster *v14; // eax + int v15; // edi + int v16; // eax + signed int v17; // ecx + int v18; // eax + int micaster; // [esp+Ch] [ebp-18h] + int v1; // [esp+10h] [ebp-14h] + int v2; // [esp+14h] [ebp-10h] + int v22; // [esp+18h] [ebp-Ch] + int midir; // [esp+1Ch] [ebp-8h] + int arglist; // [esp+20h] [ebp-4h] + + esi1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Bat: Invalid monster %d", i); + esi3 = &monster[esi1]; + micaster = esi3->_menemy; + if ( esi3->_mmode == MM_STAND && esi3->_msquelch ) + { + v3 = esi3->_mx; + v4 = esi3->_my; + v5 = v3 - (unsigned char)esi3->_menemyx; + v6 = v4 - (unsigned char)esi3->_menemyy; + v7 = GetDirection(v3, v4, esi3->_lastx, esi3->_lasty); + midir = v7; + esi3->_mdir = v7; + v22 = random(107, 100); + if ( _LOBYTE(esi3->_mgoal) == 2 ) + { + if ( esi3->_mgoalvar1 ) + { + if ( random(108, 2) ) + v10 = left[midir]; + else + v10 = right[midir]; + M_CallWalk(arglist, v10); + _LOBYTE(esi3->_mgoal) = 1; + } + else + { + M_CallWalk(arglist, opposite[midir]); + ++esi3->_mgoalvar1; + } + } + else + { + v1 = (unsigned char)esi3->_menemyx; + v2 = (unsigned char)esi3->_menemyy; + if ( esi3->MType->mtype == MT_GLOOM + && (abs(v5) >= 5 || abs(v6) >= 5) + && v22 < 4 * (unsigned char)esi3->_mint + 33 + && (v11 = LineClearF1( + PosOkMonst, + arglist, + esi3->_mx, + esi3->_my, + v1, + v2), + v11) ) + { + if ( AddMissile(esi3->_mx, esi3->_my, v1, v2, midir, 20, micaster, arglist, 0, 0) != -1 ) + { + v12 = esi3->_my + 112 * esi3->_mx; + esi3->_mmode = MM_CHARGE; + dMonster[0][v12] = -1 - arglist; + } + } + else if ( abs(v5) >= 2 || abs(v6) >= 2 ) + { + v17 = esi3->_mVar2; + if ( v17 > 20 && v22 < (unsigned char)esi3->_mint + 13 + || ((v18 = esi3->_mVar1, v18 == 1) || v18 == 2 || v18 == 3) + && !v17 + && v22 < (unsigned char)esi3->_mint + 63 ) + { + M_CallWalk(arglist, midir); + } + } + else if ( v22 < 4 * (unsigned char)esi3->_mint + 8 ) + { + M_StartAttack(arglist); + v14 = esi3->MType; + esi3->_mgoalvar1 = 0; + _LOBYTE(esi3->_mgoal) = 2; + if ( v14->mtype == 41 ) + { + v15 = (unsigned char)esi3->_menemyx; + v16 = random(109, 10); + AddMissile(v15, (unsigned char)esi3->_menemyy, v15 + 1, 0, -1, 8, 1, arglist, v16 + 1, 0); + } + } + if ( esi3->_mmode == MM_STAND ) + esi3->_mAnimData = esi3->MType->Anims[0].Frames[midir]; + } + } +} + +void __fastcall MAI_SkelBow(int i) +{ + int v1; // esi + MonsterStruct *v2; // esi + int v3; // edi + int v4; // ebx + int v5; // eax + int v7; // eax + //int v8; // ST04_4 + int v9; // ecx + int v10; // eax + //int v11; // ST04_4 + int v12; // eax + //int v13; // eax + int v14; // edi + int v15; // ebx + //int v16; // eax + int v17; // [esp+4h] [ebp-10h] + bool v18; // [esp+8h] [ebp-Ch] + int v19; // [esp+Ch] [ebp-8h] + int arglist; // [esp+10h] [ebp-4h] + + v18 = 0; + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_SkelBow: Invalid monster %d", i); + v2 = &monster[v1]; + if ( v2->_mmode == MM_STAND && v2->_msquelch ) + { + v3 = v2->_mx - (unsigned char)v2->_menemyx; + v4 = v2->_my - (unsigned char)v2->_menemyy; + v5 = M_GetDir(arglist); + v17 = v5; + v2->_mdir = v5; + v19 = random(110, 100); + v7 = abs(v3); + //v9 = v8; + if ( v7 < 4 ) + { + v10 = abs(v4); + //v9 = v11; + if ( v10 < 4 ) + { + if ( (v9 = v2->_mVar2, v9 > 20) && v19 < 2 * (unsigned char)v2->_mint + 13 + || ((v12 = v2->_mVar1, v12 == 1) || v12 == 2 || v12 == 3) + && !v9 + && v19 < 2 * (unsigned char)v2->_mint + 63 ) + { + //_LOBYTE(v13) = M_DumbWalk(arglist, opposite[v17]); + v18 = M_DumbWalk(arglist, opposite[v17]); + } + } + } + v14 = (unsigned char)v2->_menemyx; + v15 = (unsigned char)v2->_menemyy; + if ( !v18 ) + { + if ( random(110, 100) < 2 * (unsigned char)v2->_mint + 3 ) + { + //_LOBYTE(v16) = LineClear(v2->_mx, v2->_my, v14, v15); + if ( LineClear(v2->_mx, v2->_my, v14, v15) ) + M_StartRAttack(arglist, 0, 4); + } + } + if ( v2->_mmode == MM_STAND ) + v2->_mAnimData = v2->MType->Anims[0].Frames[v17]; + } +} + +void __fastcall MAI_Fat(int i) +{ + int v1; // esi + MonsterStruct *v2; // esi + int v3; // edi + int v4; // ebx + int v5; // eax + int v7; // eax + signed int v8; // ecx + int v9; // eax + int md; // [esp+4h] [ebp-Ch] + int arglist; // [esp+8h] [ebp-8h] + int v12; // [esp+Ch] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Fat: Invalid monster %d", i); + v2 = &monster[v1]; + if ( v2->_mmode == MM_STAND && v2->_msquelch ) + { + v3 = v2->_mx - (unsigned char)v2->_menemyx; + v4 = v2->_my - (unsigned char)v2->_menemyy; + v5 = M_GetDir(arglist); + md = v5; + v2->_mdir = v5; + v12 = random(111, 100); + if ( abs(v3) >= 2 || abs(v4) >= 2 ) + { + v8 = v2->_mVar2; + if ( v8 > 20 && v12 < 4 * (unsigned char)v2->_mint + 20 + || ((v9 = v2->_mVar1, v9 == 1) || v9 == 2 || v9 == 3) && !v8 && v12 < 4 * (unsigned char)v2->_mint + 70 ) + { + M_CallWalk(arglist, md); + } + } + else + { + v7 = (unsigned char)v2->_mint; + if ( v12 >= 4 * v7 + 15 ) + { + if ( v12 < 4 * v7 + 20 ) + M_StartSpAttack(arglist); + } + else + { + M_StartAttack(arglist); + } + } + if ( v2->_mmode == MM_STAND ) + v2->_mAnimData = v2->MType->Anims[0].Frames[md]; + } +} + +void __fastcall MAI_Sneak(int i) +{ + int v1; // edi + MonsterStruct *v2; // esi + int v3; // ebx + int v4; // ebx + int v6; // edi + int v7; // eax + //int v8; // ST04_4 + int v9; // eax + //int v10; // ST04_4 + int v11; // eax + int v12; // edi + signed int v13; // ecx + int v14; // eax + int v15; // [esp+Ch] [ebp-10h] + int arglist; // [esp+10h] [ebp-Ch] + int v17; // [esp+14h] [ebp-8h] + int md; // [esp+18h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Sneak: Invalid monster %d", i); + v2 = &monster[v1]; + if ( v2->_mmode == MM_STAND ) + { + v3 = v2->_my; + if ( dTransVal[v2->_mx][v3] != lightmax ) + { + v17 = v2->_mx - (unsigned char)v2->_menemyx; + v4 = v3 - (unsigned char)v2->_menemyy; + md = M_GetDir(v1); + v6 = 5 - (unsigned char)v2->_mint; + if ( v2->_mVar1 == 5 ) + { + v2->_mgoalvar1 = 0; + _LOBYTE(v2->_mgoal) = 2; + } + else + { + v7 = abs(v17); + //v5 = v8; + if ( v7 >= v6 + 3 || (v9 = abs(v4), v9 >= v6 + 3) || v2->_mgoalvar1 > 8 ) /* v5 = v10, */ + { + v2->_mgoalvar1 = 0; + _LOBYTE(v2->_mgoal) = 1; + } + } + if ( _LOBYTE(v2->_mgoal) == 2 ) + { + if ( v2->_mFlags & 0x10 ) + md = GetDirection(v2->_mx, v2->_my, plr[v2->_menemy]._pownerx, plr[v2->_menemy]._pownery); + md = opposite[md]; + if ( v2->MType->mtype == MT_UNSEEN ) + { + if ( random(112, 2) ) + v11 = left[md]; + else + v11 = right[md]; + md = v11; + } + } + v2->_mdir = md; + v15 = random(112, 100); + if ( abs(v17) < v6 && abs(v4) < v6 && v2->_mFlags & 1 ) + { + M_StartFadein(arglist, md, 0); + } + else + { + v12 = v6 + 1; + if ( abs(v17) < v12 && abs(v4) < v12 || v2->_mFlags & 1 ) + { + if ( _LOBYTE(v2->_mgoal) == 2 + || (abs(v17) >= 2 || abs(v4) >= 2) + && ((v13 = v2->_mVar2, v13 > 20) && v15 < 4 * (unsigned char)v2->_mint + 14 + || ((v14 = v2->_mVar1, v14 == 1) || v14 == 2 || v14 == 3) + && !v13 + && v15 < 4 * (unsigned char)v2->_mint + 64) ) + { + ++v2->_mgoalvar1; + M_CallWalk(arglist, md); + } + } + else + { + M_StartFadeout(arglist, md, 1u); + } + } + if ( v2->_mmode == MM_STAND ) + { + if ( abs(v17) >= 2 || abs(v4) >= 2 || v15 >= 4 * (unsigned char)v2->_mint + 10 ) + v2->_mAnimData = v2->MType->Anims[0].Frames[md]; + else + M_StartAttack(arglist); + } + } + } +} +// 642A14: using guessed type char lightmax; + +void __fastcall MAI_Fireman(int i) +{ + int esi1; // esi + int esi3; // esi + int v3; // ecx + int v4; // eax + int v5; // ebx + int v6; // edi + int v7; // edx + char v9; // al + //int v10; // eax + //int v11; // eax + int v13; // eax + //int v14; // eax + int v15; // edx + //int v16; // eax + int v17; // eax + int micaster; // [esp+Ch] [ebp-14h] + int v1; // [esp+10h] [ebp-10h] + int v2; // [esp+14h] [ebp-Ch] + int midir; // [esp+18h] [ebp-8h] + int arglist; // [esp+1Ch] [ebp-4h] + + esi1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Fireman: Invalid monster %d", i); + esi3 = esi1; + if ( monster[esi3]._mmode || !monster[esi3]._msquelch ) + return; + v3 = (unsigned char)monster[esi3]._menemyy; + micaster = monster[esi3]._menemy; + v4 = (unsigned char)monster[esi3]._menemyx; + v2 = v3; + v5 = monster[esi3]._my - v3; + v1 = v4; + v6 = monster[esi3]._mx - v4; + v7 = M_GetDir(arglist); + v9 = monster[esi3]._mgoal; + midir = v7; + switch ( v9 ) + { + case 1: + //_LOBYTE(v10) = LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2); + if ( !LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2) + || AddMissile(monster[esi3]._mx, monster[esi3]._my, v1, v2, midir, 50, micaster, arglist, 0, 0) == -1 ) + { + break; + } + monster[esi3]._mgoalvar1 = 0; + monster[esi3]._mmode = MM_CHARGE; + goto LABEL_18; + case 5: + if ( monster[esi3]._mgoalvar1 == 3 ) + { + _LOBYTE(monster[esi3]._mgoal) = 1; + M_StartFadeout(arglist, v7, 1u); + } + else + { + //_LOBYTE(v11) = LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2); + if ( LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2) ) + { + M_StartRAttack(arglist, 51, 4); + } + else + { + //_LOBYTE(v11) = LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2); + if ( LineClear(monster[esi3]._mx, monster[esi3]._my, v1, v2) ) + { + M_StartRAttack(arglist, 51, 4); + } + else + { + v13 = random(112, 10); + M_StartDelay(arglist, v13 + 5); + } + ++monster[esi3]._mgoalvar1; + } + ++monster[esi3]._mgoalvar1; + } + break; + case 2: + M_StartFadein(arglist, v7, 0); + LABEL_18: + _LOBYTE(monster[esi3]._mgoal) = 5; + break; + } + monster[esi3]._mdir = midir; + random(112, 100); + if ( monster[esi3]._mmode == MM_STAND ) + return; + if ( abs(v6) < 2 && abs(v5) < 2 && _LOBYTE(monster[esi3]._mgoal) == 1 ) + { + M_TryH2HHit( + arglist, + monster[esi3]._menemy, + (unsigned char)monster[esi3].mHit, + (unsigned char)monster[esi3].mMinDamage, + (unsigned char)monster[esi3].mMaxDamage); + _LOBYTE(monster[esi3]._mgoal) = 2; + //_LOBYTE(v14) = M_CallWalk(arglist, opposite[midir]); + if ( M_CallWalk(arglist, opposite[midir]) ) + return; + v15 = midir; + goto LABEL_29; + } + //_LOBYTE(v16) = M_CallWalk(arglist, midir); + if ( !M_CallWalk(arglist, midir) ) + { + v17 = _LOBYTE(monster[esi3]._mgoal); + if ( (_BYTE)v17 == 1 || (_BYTE)v17 == 2 ) + { + v15 = midir; + LABEL_29: + M_StartFadein(arglist, v15, 0); + _LOBYTE(monster[esi3]._mgoal) = 5; + return; + } + } +} + +void __fastcall MAI_Fallen(int i) +{ + int v1; // edi + //int v2; // ST04_4 + int v3; // esi + int v4; // eax + int v5; // ecx + int *v6; // eax + int v7; // edx + int v8; // edx + int j; // edi + int k; // ecx + int v11; // eax + int v12; // eax + char v13; // al + int v14; // edx + int v15; // eax + int v16; // esi + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + { + TermMsg("MAI_Fallen: Invalid monster %d", i); + //i = v2; + } + v3 = v1; + if ( _LOBYTE(monster[v1]._mgoal) == 5 ) + { + i = monster[v3]._mgoalvar1; + if ( i ) + monster[v3]._mgoalvar1 = --i; + else + _LOBYTE(monster[v3]._mgoal) = 1; + } + if ( monster[v3]._mmode == MM_STAND && monster[v3]._msquelch ) + { + if ( _LOBYTE(monster[v3]._mgoal) == 2 ) + { + i = monster[v3]._mgoalvar1; + monster[v3]._mgoalvar1 = i - 1; + if ( !i ) + { + v4 = monster[v3]._mdir; + _LOBYTE(monster[v3]._mgoal) = 1; + M_StartStand(v1, opposite[v4]); + } + } + if ( monster[v3]._mAnimFrame != monster[v3]._mAnimLen ) + { + v13 = monster[v3]._mgoal; + if ( v13 == 2 ) + { + v14 = monster[v3]._mdir; + } + else + { + if ( v13 != 5 ) + { + MAI_SkelSd(v1); + return; + } + v15 = monster[v3]._mx - (unsigned char)monster[v3]._menemyx; + v16 = monster[v3]._my - (unsigned char)monster[v3]._menemyy; + if ( abs(v15) < 2 && abs(v16) < 2 ) + { + M_StartAttack(v1); + return; + } + v14 = M_GetDir(v1); + } + M_CallWalk(v1, v14); + return; + } + if ( !random(113, 4) ) + { + if ( !(monster[v3]._mFlags & 8) ) + { + M_StartSpStand(v1, monster[v3]._mdir); + v5 = 2 * (unsigned char)monster[v3]._mint + 2; + v6 = &monster[v3]._mhitpoints; + v7 = monster[v3]._mhitpoints; + if ( monster[v3]._mmaxhp - v5 < v7 ) + *v6 = monster[v3]._mmaxhp; + else + *v6 = v5 + v7; + } + v8 = 2 * (unsigned char)monster[v3]._mint + 4; + for ( j = -v8; j <= v8; ++j ) + { + for ( k = -v8; k <= v8; ++k ) + { + if ( j >= 0 && j < 112 && k >= 0 && k < 112 ) + { + v11 = dMonster[0][j + monster[v3]._my + 112 * (k + monster[v3]._mx)]; + if ( v11 > 0 ) + { + v12 = v11 - 1; + if ( monster[v12]._mAi == AI_FALLEN ) + { + _LOBYTE(monster[v12]._mgoal) = 5; + monster[v12]._mgoalvar1 = 30 * (unsigned char)monster[v3]._mint + 105; + } + } + } + } + } + } + } +} + +void __fastcall MAI_Cleaver(int i) +{ + int v1; // esi + MonsterStruct *v2; // esi + int v3; // ecx + int v4; // edx + int v5; // edi + int v6; // ebp + int v7; // ebx + int arglist; // [esp+8h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Cleaver: Invalid monster %d", i); + v2 = &monster[v1]; + if ( v2->_mmode == MM_STAND && v2->_msquelch ) + { + v3 = v2->_mx; + v4 = v2->_my; + v5 = v3 - (unsigned char)v2->_menemyx; + v6 = v4 - (unsigned char)v2->_menemyy; + v7 = GetDirection(v3, v4, v2->_lastx, v2->_lasty); + v2->_mdir = v7; + if ( abs(v5) >= 2 || abs(v6) >= 2 ) + M_CallWalk(arglist, v7); + else + M_StartAttack(arglist); + if ( v2->_mmode == MM_STAND ) + v2->_mAnimData = v2->MType->Anims[0].Frames[v7]; + } +} + +void __fastcall MAI_Round(int i, unsigned char special) +{ + int v2; // esi + MonsterStruct *v3; // esi + int v4; // edx + int v5; // ecx + int v6; // edi + int v7; // ebx + int v9; // eax + //int v10; // ST04_4 + int v12; // eax + //int v13; // ST04_4 + int v15; // edi + int v16; // eax + int v17; // ecx + bool v18; // eax + //int v19; // eax + int v21; // eax + int v22; // eax + //int v23; // ST04_4 + signed int v25; // ecx + int v26; // eax + int v27; // [esp+4h] [ebp-18h] + int v28; // [esp+8h] [ebp-14h] + char *v29; // [esp+8h] [ebp-14h] + int v30; // [esp+Ch] [ebp-10h] + int md; // [esp+10h] [ebp-Ch] + int v32; // [esp+14h] [ebp-8h] + int arglist; // [esp+18h] [ebp-4h] + + v2 = i; + v27 = special; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Round: Invalid monster %d", i); + v3 = &monster[v2]; + if ( v3->_mmode == MM_STAND && v3->_msquelch ) + { + v4 = v3->_my; + v5 = v3->_mx; + v28 = (unsigned char)v3->_menemyy; + v6 = (unsigned char)v3->_menemyx; + v7 = v5 - v6; + v32 = v4 - v28; + md = GetDirection(v5, v4, v3->_lastx, v3->_lasty); + if ( v3->_msquelch < 0xFFu ) /* check sign */ + MonstCheckDoors(arglist); + v30 = random(114, 100); + if ( (abs(v7) >= 2 || abs(v32) >= 2) && v3->_msquelch == -1 ) + { + v29 = &dung_map[v6][v28]; + if ( dung_map[v3->_mx][v3->_my] == *v29 ) + { + if ( _LOBYTE(v3->_mgoal) != 4 ) + { + v9 = abs(v7); + //v11 = v10; + if ( v9 < 4 ) + { + v12 = abs(v32); + //v11 = v13; + if ( v12 < 4 ) + goto LABEL_26; + } + if ( random(115, 4) ) + goto LABEL_26; + if ( _LOBYTE(v3->_mgoal) != 4 ) + { + v3->_mgoalvar1 = 0; + v3->_mgoalvar2 = random(116, 2); + } + } + _LOBYTE(v3->_mgoal) = 4; + v15 = abs(v32); + if ( abs(v7) <= v15 ) + v16 = abs(v32); + else + v16 = abs(v7); + v17 = v3->_mgoalvar1; + v3->_mgoalvar1 = v17 + 1; + if ( v17 < 2 * v16 || (v18 = DirOK(arglist, md), !v18) ) + { + if ( dung_map[v3->_mx][v3->_my] == *v29 ) + { + //_LOBYTE(v19) = M_RoundWalk(arglist, md, &v3->_mgoalvar2); + if ( !M_RoundWalk(arglist, md, &v3->_mgoalvar2) ) + { + v21 = random(125, 10); + M_StartDelay(arglist, v21 + 10); + } + goto LABEL_26; + } + } + } + } + _LOBYTE(v3->_mgoal) = 1; + LABEL_26: + if ( _LOBYTE(v3->_mgoal) == 1 ) + { + if ( abs(v7) >= 2 || (v22 = abs(v32), v22 >= 2) ) /* v24 = v23, */ + { + v25 = v3->_mVar2; + if ( v25 > 20 && v30 < 2 * (unsigned char)v3->_mint + 28 + || ((v26 = v3->_mVar1, v26 == 1) || v26 == 2 || v26 == 3) + && !v25 + && v30 < 2 * (unsigned char)v3->_mint + 78 ) + { + M_CallWalk(arglist, md); + } + } + else if ( v30 < 2 * (unsigned char)v3->_mint + 23 ) + { + v3->_mdir = md; + if ( v27 && v3->_mhitpoints < v3->_mmaxhp >> 1 && random(117, 2) ) + M_StartSpAttack(arglist); + else + M_StartAttack(arglist); + } + } + if ( v3->_mmode == MM_STAND ) + v3->_mAnimData = v3->MType->Anims[0].Frames[md]; + } +} + +void __fastcall MAI_GoatMc(int i) +{ + MAI_Round(i, 1u); +} + +void __fastcall MAI_Ranged(int i, int missile_type, unsigned char special) +{ + int v3; // edi + int v4; // esi + char v5; // al + int v6; // eax + int v7; // ecx + int v8; // ebx + int v9; // edi + bool v11; // zf + int v12; // eax + int v13; // eax + //int v14; // ST00_4 + //int v16; // eax + int x2; // [esp+8h] [ebp-14h] + int y2; // [esp+Ch] [ebp-10h] + int missile_typea; // [esp+10h] [ebp-Ch] + int v20; // [esp+14h] [ebp-8h] + int arglist; // [esp+18h] [ebp-4h] + + v3 = i; + missile_typea = missile_type; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Ranged: Invalid monster %d", i); + v4 = v3; + if ( monster[v3]._mmode == MM_STAND ) + { + v5 = monster[v4]._msquelch; + if ( v5 == -1 || monster[v4]._mFlags & 0x10 ) + { + v7 = (unsigned char)monster[v4]._menemyy; + y2 = v7; + v8 = monster[v4]._my - v7; + x2 = (unsigned char)monster[v4]._menemyx; + v9 = monster[v4]._mx - x2; + v20 = M_GetDir(arglist); + if ( monster[v4]._msquelch < 0xFFu ) /* check sign */ + MonstCheckDoors(arglist); + v11 = monster[v4]._mVar1 == 10; + monster[v4]._mdir = v20; + if ( v11 ) + { + v12 = random(118, 20); + M_StartDelay(arglist, v12); + } + else if ( abs(v9) < 4 ) + { + v13 = abs(v8); + //v15 = v14; + if ( v13 < 4 ) + { + if ( random(119, 100) < 10 * ((unsigned char)monster[v4]._mint + 7) ) + M_CallWalk(arglist, opposite[v20]); + } + } + if ( monster[v4]._mmode == MM_STAND ) + { + //_LOBYTE(v16) = LineClear(monster[v4]._mx, monster[v4]._my, x2, y2); + if ( LineClear(monster[v4]._mx, monster[v4]._my, x2, y2) ) + { + if ( special ) + M_StartRSpAttack(arglist, missile_typea, 4); + else + M_StartRAttack(arglist, missile_typea, 4); + } + else + { + monster[v4]._mAnimData = monster[v4].MType->Anims[0].Frames[v20]; + } + } + } + else if ( v5 ) + { + v6 = GetDirection(monster[v4]._mx, monster[v4]._my, monster[v4]._lastx, monster[v4]._lasty); + M_CallWalk(v3, v6); + } + } +} + +void __fastcall MAI_GoatBow(int i) +{ + MAI_Ranged(i, 0, 0); +} + +void __fastcall MAI_Succ(int i) +{ + MAI_Ranged(i, 24, 0); +} + +void __fastcall MAI_AcidUniq(int i) +{ + MAI_Ranged(i, 57, 1u); +} + +void __fastcall MAI_Scav(int i) +{ + int v1; // edi + int v2; // esi + unsigned char *v3; // eax + int v4; // ecx + int v5; // ecx + signed int v6; // ebx + signed int v7; // edi + int v8; // edx + int v9; // eax + bool v10; // eax + int v11; // ebx + int v12; // edi + signed int v13; // edi + int v14; // edx + int v15; // eax + bool v16; // eax + int v17; // eax + int v18; // eax + int arglist; // [esp+Ch] [ebp-8h] + BOOL v20; // [esp+10h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Scav: Invalid monster %d", i); + v2 = v1; + v20 = 0; + if ( monster[v1]._mmode == MM_STAND ) + { + if ( monster[v2]._mhitpoints < monster[v2]._mmaxhp >> 1 ) + { + if ( _LOBYTE(monster[v2]._mgoal) == 3 ) + goto LABEL_10; + if ( monster[v2].leaderflag ) + { + v3 = &monster[(unsigned char)monster[v2].leader].unpackfilesize; + --*v3; + monster[v2].leaderflag = 0; + } + _LOBYTE(monster[v2]._mgoal) = 3; + monster[v2]._mgoalvar3 = 10; + } + if ( _LOBYTE(monster[v2]._mgoal) != 3 ) + { + LABEL_52: + if ( monster[v2]._mmode == MM_STAND ) + MAI_SkelSd(arglist); + return; + } + LABEL_10: + v4 = monster[v2]._mgoalvar3; + if ( v4 ) + { + monster[v2]._mgoalvar3 = v4 - 1; + v5 = monster[v2]._my; + if ( dDead[monster[v2]._mx][v5] ) + { + M_StartEat(v1); + if ( !(monster[v2]._mFlags & 8) ) + monster[v2]._mhitpoints += 64; + if ( monster[v2]._mhitpoints >= (monster[v2]._mmaxhp >> 1) + (monster[v2]._mmaxhp >> 2) ) + { + _LOBYTE(monster[v2]._mgoal) = 1; + monster[v2]._mgoalvar1 = 0; + monster[v2]._mgoalvar2 = 0; + } + } + else + { + if ( !monster[v2]._mgoalvar1 ) + { + v6 = arglist; + if ( random(120, 2) ) + { + v7 = -4; + do + { + if ( v20 ) + break; + v6 = -4; + do + { + if ( v20 ) + break; + if ( v7 >= 0 && v7 < 112 && v6 >= 0 && v6 < 112 ) + { + v8 = monster[v2]._mx; + v9 = monster[v2]._my; + v20 = dDead[v8 + v6][v9 + v7] + && (v10 = LineClearF( + CheckNoSolid, + v8, + v9, + v8 + v6, + v9 + v7), + v10); + } + ++v6; + } + while ( v6 <= 4 ); + ++v7; + } + while ( v7 <= 4 ); + v11 = v6 - 1; + v12 = v7 - 1; + } + else + { + v13 = 4; + do + { + if ( v20 ) + break; + v6 = 4; + do + { + if ( v20 ) + break; + if ( v13 >= 0 && v13 < 112 && v6 >= 0 && v6 < 112 ) + { + v14 = monster[v2]._mx; + v15 = monster[v2]._my; + v20 = dDead[v14 + v6][v15 + v13] + && (v16 = LineClearF( + CheckNoSolid, + v14, + v15, + v14 + v6, + v15 + v13), + v16); + } + --v6; + } + while ( v6 >= -4 ); + --v13; + } + while ( v13 >= -4 ); + v11 = v6 + 1; + v12 = v13 + 1; + } + if ( v20 ) + { + monster[v2]._mgoalvar1 = monster[v2]._mx + v11 + 1; + monster[v2]._mgoalvar2 = monster[v2]._my + v12 + 1; + } + } + v17 = monster[v2]._mgoalvar1; + if ( v17 ) + { + v18 = GetDirection(monster[v2]._mx, monster[v2]._my, v17 - 1, monster[v2]._mgoalvar2 - 1); + monster[v2]._mdir = v18; + M_CallWalk(arglist, v18); + } + } + } + goto LABEL_52; + } +} + +void __fastcall MAI_Garg(int i) +{ + int v1; // ebp + MonsterStruct *v2; // esi + int v3; // edi + int v4; // ebx + char v5; // al + int v6; // edi + //int v7; // eax + int v8; // [esp+10h] [ebp-4h] + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Garg: Invalid monster %d", i); + v2 = &monster[v1]; + v3 = v2->_mx - v2->_lastx; + v4 = v2->_my - v2->_lasty; + v8 = M_GetDir(v1); + v5 = v2->_msquelch; + if ( v5 && v2->_mFlags & 4 ) + { + M_Enemy(v1); + v6 = v2->_my - (unsigned char)v2->_menemyy; + if ( abs(v2->_mx - (unsigned char)v2->_menemyx) < (unsigned char)v2->_mint + 2 + && abs(v6) < (unsigned char)v2->_mint + 2 ) + { + v2->_mFlags &= 0xFFFFFFFB; + } + } + else if ( v2->_mmode == MM_STAND && v5 ) + { + if ( v2->_mhitpoints < v2->_mmaxhp >> 1 && !(v2->_mFlags & 8) ) + _LOBYTE(v2->_mgoal) = 2; + if ( _LOBYTE(v2->_mgoal) == 2 ) + { + if ( abs(v3) >= (unsigned char)v2->_mint + 2 || abs(v4) >= (unsigned char)v2->_mint + 2 ) + { + _LOBYTE(v2->_mgoal) = 1; + M_StartHeal(v1); + } + else + { + //_LOBYTE(v7) = M_CallWalk(v1, opposite[v8]); + if ( !M_CallWalk(v1, opposite[v8]) ) + _LOBYTE(v2->_mgoal) = 1; + } + } + MAI_Round(v1, 0); + } +} + +void __fastcall MAI_RoundRanged(int i, int missile_type, unsigned char checkdoors, int dam, int lessmissiles) +{ + int v5; // esi + MonsterStruct *v6; // esi + int v7; // edx + int v8; // ebx + int v9; // edi + int v11; // eax + //int v12; // ST04_4 + int v13; // ecx + int v14; // eax + //int v15; // ST04_4 + int v16; // eax + //int v17; // ST04_4 + int v18; // ecx + int v19; // ebx + int v20; // eax + int v21; // ecx + bool v22; // eax + bool v23; // eax + bool v24; // eax + int v25; // eax + //int v26; // ST04_4 + int v27; // eax + //int v28; // ST04_4 + int v29; // eax + int v30; // edx + int v31; // eax + int missile_typea; // [esp+4h] [ebp-18h] + int v33; // [esp+8h] [ebp-14h] + int x2; // [esp+Ch] [ebp-10h] + int md; // [esp+10h] [ebp-Ch] + int y2; // [esp+14h] [ebp-8h] + int arglist; // [esp+18h] [ebp-4h] + int checkdoorsa; // [esp+24h] [ebp+8h] + + v5 = i; + missile_typea = missile_type; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_RoundRanged: Invalid monster %d", i); + v6 = &monster[v5]; + if ( v6->_mmode == MM_STAND && v6->_msquelch ) + { + v7 = v6->_my; + y2 = (unsigned char)v6->_menemyy; + v8 = v7 - y2; + x2 = (unsigned char)v6->_menemyx; + v9 = v6->_mx - x2; + v33 = v7 - y2; + md = GetDirection(v6->_mx, v7, v6->_lastx, v6->_lasty); + if ( checkdoors && v6->_msquelch < 0xFFu ) /* check sign */ + MonstCheckDoors(arglist); + checkdoorsa = random(121, 10000); + v11 = abs(v9); + //v13 = v12; + if ( v11 < 2 ) + { + v14 = abs(v8); + //v13 = v15; + if ( v14 < 2 ) + goto LABEL_50; + } + if ( v6->_msquelch != -1 ) + goto LABEL_50; + //v13 = y2; + if ( dung_map[v6->_mx][v6->_my] != dung_map[x2][y2] ) + goto LABEL_50; + if ( _LOBYTE(v6->_mgoal) != 4 ) + { + if ( abs(v9) < 3 ) + { + v16 = abs(v8); + //v13 = v17; + if ( v16 < 3 ) + goto LABEL_28; + } + v18 = lessmissiles; + if ( random(122, 4 << lessmissiles) ) + goto LABEL_28; + if ( _LOBYTE(v6->_mgoal) != 4 ) + { + v6->_mgoalvar1 = 0; + v6->_mgoalvar2 = random(123, 2); + } + } + _LOBYTE(v6->_mgoal) = 4; + v19 = abs(v8); + if ( abs(v9) <= v19 ) + { + v8 = v33; + v20 = abs(v33); + } + else + { + v20 = abs(v9); + v8 = v33; + } + v21 = v6->_mgoalvar1; + v6->_mgoalvar1 = v21 + 1; + if ( v21 >= 2 * v20 && (v22 = DirOK(arglist, md), v22) ) + { + LABEL_50: + _LOBYTE(v6->_mgoal) = 1; + } + else if ( checkdoorsa < 500 * ((unsigned char)v6->_mint + 1) >> lessmissiles + && (v23 = LineClear(v6->_mx, v6->_my, x2, y2), v23) ) + { + M_StartRSpAttack(arglist, missile_typea, dam); + } + else + { + M_RoundWalk(arglist, md, &v6->_mgoalvar2); + } + LABEL_28: + if ( _LOBYTE(v6->_mgoal) == 1 ) + { + if ( ((abs(v9) >= 3 || abs(v8) >= 3) && checkdoorsa < 500 * ((unsigned char)v6->_mint + 2) >> lessmissiles + || checkdoorsa < 500 * ((unsigned char)v6->_mint + 1) >> lessmissiles) + && (v24 = LineClear(v6->_mx, v6->_my, x2, y2), v24) ) + { + M_StartRSpAttack(arglist, missile_typea, dam); + } + else + { + v25 = abs(v9); + //v13 = v26; + if ( v25 >= 2 || (v27 = abs(v8), v27 >= 2) ) /* v13 = v28, */ + { + v29 = random(124, 100); + v30 = (unsigned char)v6->_mint; + if ( v29 < 1000 * (v30 + 5) + || ((v13 = v6->_mVar1, v13 == 1) || v13 == 2 || v13 == 3) && !v6->_mVar2 && v29 < 1000 * (v30 + 8) ) + { + M_CallWalk(arglist, md); + } + } + else if ( checkdoorsa < 1000 * ((unsigned char)v6->_mint + 6) ) + { + v6->_mdir = md; + M_StartAttack(arglist); + } + } + } + if ( v6->_mmode == MM_STAND ) + { + v31 = random(125, 10); + M_StartDelay(arglist, v31 + 5); + } + } +} + +void __fastcall MAI_Magma(int i) +{ + MAI_RoundRanged(i, 21, 1u, 4, 0); +} + +void __fastcall MAI_Storm(int i) +{ + MAI_RoundRanged(i, 22, 1u, 4, 0); +} + +void __fastcall MAI_Acid(int i) +{ + MAI_RoundRanged(i, 57, 0, 4, 1); +} + +void __fastcall MAI_Diablo(int i) +{ + MAI_RoundRanged(i, 67, 0, 40, 0); +} + +void __fastcall MAI_RR2(int i, int mistype, int dam) +{ + int v3; // ebx + MonsterStruct *v4; // esi + int v5; // edi + int v6; // edx + int v7; // ebx + int v8; // edi + int v10; // eax + //int v11; // ST04_4 + int v12; // ecx + int v13; // eax + //int v14; // ST04_4 + int v15; // eax + //int v16; // ST04_4 + int v17; // eax + //int v18; // ST04_4 + int v19; // ebx + int v20; // eax + bool v21; // eax + bool v22; // eax + int v23; // ecx + int v24; // eax + //int v25; // ST04_4 + int v27; // eax + //int v28; // ST04_4 + int v29; // eax + int v30; // eax + int v31; // eax + int v32; // edx + int v33; // eax + int missile_type; // [esp+Ch] [ebp-1Ch] + int x2; // [esp+10h] [ebp-18h] + int v36; // [esp+14h] [ebp-14h] + int y2; // [esp+18h] [ebp-10h] + int v38; // [esp+1Ch] [ebp-Ch] + int md; // [esp+20h] [ebp-8h] + int arglist; // [esp+24h] [ebp-4h] + + v3 = i; + missile_type = mistype; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_RR2: Invalid monster %d", i); + v4 = &monster[v3]; + v5 = v4->_my - (unsigned char)v4->_menemyy; + if ( abs(v4->_mx - (unsigned char)v4->_menemyx) >= 5 || abs(v5) >= 5 ) + { + MAI_SkelSd(v3); + return; + } + if ( v4->_mmode == MM_STAND && v4->_msquelch ) + { + v6 = v4->_my; + y2 = (unsigned char)v4->_menemyy; + v7 = v6 - y2; + x2 = (unsigned char)v4->_menemyx; + v8 = v4->_mx - x2; + v36 = v6 - y2; + md = GetDirection(v4->_mx, v6, v4->_lastx, v4->_lasty); + if ( v4->_msquelch < 0xFFu ) /* check sign */ + MonstCheckDoors(arglist); + v38 = random(121, 100); + v10 = abs(v8); + //v12 = v11; + if ( v10 >= 2 || (v13 = abs(v7), v13 >= 2) ) /* v12 = v14, */ + { + if ( v4->_msquelch == -1 ) + { + //v12 = y2; + if ( dung_map[v4->_mx][v4->_my] == dung_map[x2][y2] ) + { + if ( _LOBYTE(v4->_mgoal) != 4 ) + { + v15 = abs(v8); + //v12 = v16; + if ( v15 < 3 ) + { + v17 = abs(v7); + //v12 = v18; + if ( v17 < 3 ) + goto LABEL_26; + } + if ( _LOBYTE(v4->_mgoal) != 4 ) + { + v4->_mgoalvar1 = 0; + v4->_mgoalvar2 = random(123, 2); + } + } + _LOBYTE(v4->_mgoal) = 4; + v4->_mgoalvar3 = 4; + v19 = abs(v7); + if ( abs(v8) <= v19 ) + { + v7 = v36; + v20 = abs(v36); + } + else + { + v20 = abs(v8); + v7 = v36; + } + v12 = v4->_mgoalvar1; + v4->_mgoalvar1 = v12 + 1; + if ( v12 < 2 * v20 || (v21 = DirOK(arglist, md), !v21) ) + { + if ( v38 < 5 * ((unsigned char)v4->_mint + 16) ) + M_RoundWalk(arglist, md, &v4->_mgoalvar2); + LABEL_26: + if ( _LOBYTE(v4->_mgoal) != 1 ) + goto LABEL_48; + if ( ((abs(v8) >= 3 || abs(v7) >= 3) && v38 < 5 * ((unsigned char)v4->_mint + 2) + || v38 < 5 * ((unsigned char)v4->_mint + 1) + || v4->_mgoalvar3 == 4) + && (v22 = LineClear(v4->_mx, v4->_my, x2, y2), v22) ) + { + v23 = arglist; + } + else + { + v24 = abs(v8); + //v26 = v25; + if ( v24 >= 2 || (v27 = abs(v7), v27 >= 2) ) /* v26 = v28, */ + { + v31 = random(124, 100); + v12 = (unsigned char)v4->_mint; + if ( v31 < 2 * (5 * v12 + 25) + || ((v32 = v4->_mVar1, v32 == 1) || v32 == 2 || v32 == 3) + && !v4->_mVar2 + && (v12 = 2 * (5 * v12 + 40), v31 < v12) ) + { + M_CallWalk(arglist, md); + } + goto LABEL_47; + } + v29 = random(124, 100); + v12 = 10 * ((unsigned char)v4->_mint + 4); + if ( v29 >= v12 ) + { + LABEL_47: + v4->_mgoalvar3 = 1; + LABEL_48: + if ( v4->_mmode == MM_STAND ) + { + v33 = random(125, 10); + M_StartDelay(arglist, v33 + 5); + } + return; + } + v4->_mdir = md; + v30 = random(124, 2); + v23 = arglist; + if ( v30 ) + { + M_StartAttack(arglist); + goto LABEL_47; + } + } + M_StartRSpAttack(v23, missile_type, dam); + goto LABEL_47; + } + } + } + } + _LOBYTE(v4->_mgoal) = 1; + goto LABEL_26; + } +} + +void __fastcall MAI_Mega(int i) +{ + MAI_RR2(i, 49, 0); +} + +void __fastcall MAI_Golum(int i) +{ + int v1; // edi + int v2; // esi + int v3; // eax + int v4; // eax + int v5; // edx + int v6; // edi + int v7; // ebx + int v8; // eax + char v9; // cl + //char v10; // eax + signed int v11; // edx + signed int v12; // ecx + int v13; // eax + bool v14; // eax + unsigned char *v15; // esi + bool v16; // eax + int v17; // esi + int v18; // edi + int v19; // [esp+Ch] [ebp-Ch] + unsigned int v20; // [esp+10h] [ebp-8h] + int arglist; // [esp+14h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Golum: Invalid monster %d", i); + v2 = v1; + if ( monster[v1]._mx != 1 || monster[v2]._my ) + { + v3 = monster[v2]._mmode; + if ( v3 != MM_DEATH && v3 != MM_SPSTAND && (v3 < MM_WALK || v3 > MM_WALK3) ) + { + if ( !(monster[v2]._mFlags & 0x10) ) + M_Enemy(v1); + v20 = ((unsigned int)~monster[v2]._mFlags >> 10) & 1; + if ( monster[v2]._mmode != MM_ATTACK ) + { + v4 = monster[v2]._menemy; + v5 = monster[v2]._my; + v6 = monster[v2]._mx - monster[v4]._mfutx; + v7 = v5 - monster[v4]._mfuty; + v19 = GetDirection(monster[v2]._mx, v5, monster[v4]._mx, monster[v4]._my); + monster[v2]._mdir = v19; + if ( abs(v6) >= 2 || abs(v7) >= 2 ) + { + if ( v20 ) + { + v14 = MAI_Path(arglist); + if ( v14 ) + return; + } + } + else if ( v20 ) + { + v8 = monster[v2]._menemy; + monster[v2]._menemyx = monster[v8]._mx; + v9 = monster[v8]._my; + monster[v2]._menemyy = v9; + if ( !monster[v8]._msquelch ) + { + monster[v8]._msquelch = -1; + monster[monster[v2]._menemy]._lastx = monster[v2]._mx; + v11 = 0; + monster[monster[v2]._menemy]._lasty = monster[v2]._my; + do + { + v12 = 0; + do + { + /* v13 = *(_DWORD *)&nTransTable[4 + * (monster[v2]._my + v11 + 112 * (v12 + monster[v2]._mx)) + + 1148]; check */ + v13 = dMonster[monster[v2]._mx + v12 - 2][monster[v2]._my + v11 - 2]; + if ( v13 > 0 ) + monster[v13]._msquelch = -1; + ++v12; + } + while ( v12 < 5 ); + ++v11; + } + while ( v11 < 5 ); + } + M_StartAttack(arglist); + return; + } + v15 = &monster[v2]._pathcount; + if ( ++*(_BYTE *)v15 > 8u ) + *(_BYTE *)v15 = 5; + v16 = M_CallWalk(arglist, plr[arglist]._pdir); + if ( !v16 ) + { + v17 = ((_BYTE)v19 - 1) & 7; + v18 = 0; + while ( !v16 ) + { + v17 = ((_BYTE)v17 + 1) & 7; + v16 = DirOK(arglist, v17); + if ( ++v18 >= 8 ) + { + if ( !v16 ) + return; + break; + } + } + M_WalkDir(arglist, v17); + } + } + } + } +} + +void __fastcall MAI_SkelKing(int i) +{ + int v1; // esi + MonsterStruct *v2; // esi + int v3; // edx + int v4; // ebx + int v5; // edi + int v7; // eax + //int v8; // ST04_4 + int v10; // eax + //int v11; // ST04_4 + int v13; // ebx + int v14; // eax + int v15; // ecx + bool v16; // eax + //int v17; // eax + int v19; // eax + bool v20; // eax + int v21; // edi + int v22; // ebx + int v23; // eax + //int v24; // ST04_4 + int v26; // eax + //int v27; // ST04_4 + int v28; // eax + int v29; // ecx + int v30; // edx + int v31; // eax + char *v32; // [esp+4h] [ebp-1Ch] + int x2; // [esp+8h] [ebp-18h] + int v34; // [esp+Ch] [ebp-14h] + int v35; // [esp+10h] [ebp-10h] + int y2; // [esp+14h] [ebp-Ch] + int md; // [esp+18h] [ebp-8h] + int arglist; // [esp+1Ch] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_SkelKing: Invalid monster %d", i); + v2 = &monster[v1]; + if ( v2->_mmode == MM_STAND && v2->_msquelch ) + { + v3 = v2->_my; + y2 = (unsigned char)v2->_menemyy; + v4 = v3 - y2; + x2 = (unsigned char)v2->_menemyx; + v5 = v2->_mx - x2; + v34 = v3 - y2; + md = GetDirection(v2->_mx, v3, v2->_lastx, v2->_lasty); + if ( v2->_msquelch < 0xFFu ) /* check sign */ + MonstCheckDoors(arglist); + v35 = random(126, 100); + if ( (abs(v5) >= 2 || abs(v4) >= 2) && v2->_msquelch == -1 ) + { + v32 = &dung_map[x2][y2]; + if ( dung_map[v2->_mx][v2->_my] == *v32 ) + { + if ( _LOBYTE(v2->_mgoal) != 4 ) + { + v7 = abs(v5); + //v9 = v8; + if ( v7 < 3 ) + { + v10 = abs(v4); + //v9 = v11; + if ( v10 < 3 ) + goto LABEL_26; + } + if ( random(127, 4) ) + goto LABEL_26; + if ( _LOBYTE(v2->_mgoal) != 4 ) + { + v2->_mgoalvar1 = 0; + v2->_mgoalvar2 = random(128, 2); + } + } + _LOBYTE(v2->_mgoal) = 4; + v13 = abs(v4); + if ( abs(v5) <= v13 ) + { + v4 = v34; + v14 = abs(v34); + } + else + { + v14 = abs(v5); + v4 = v34; + } + v15 = v2->_mgoalvar1; + v2->_mgoalvar1 = v15 + 1; + if ( v15 < 2 * v14 || (v16 = DirOK(arglist, md), !v16) ) + { + if ( dung_map[v2->_mx][v2->_my] == *v32 ) + { + //_LOBYTE(v17) = M_RoundWalk(arglist, md, &v2->_mgoalvar2); + if ( !M_RoundWalk(arglist, md, &v2->_mgoalvar2) ) + { + v19 = random(125, 10); + M_StartDelay(arglist, v19 + 10); + } + goto LABEL_26; + } + } + } + } + _LOBYTE(v2->_mgoal) = 1; + LABEL_26: + if ( _LOBYTE(v2->_mgoal) == 1 ) + { + if ( gbMaxPlayers == 1 + && ((abs(v5) >= 3 || abs(v4) >= 3) && v35 < 4 * (unsigned char)v2->_mint + 35 || v35 < 6) + && (v20 = LineClear(v2->_mx, v2->_my, x2, y2), v20) ) + { + v21 = v2->_mx + offset_x[md]; + v22 = v2->_my + offset_y[md]; + if ( PosOkMonst(arglist, v21, v22) && nummonsters < MAXMONSTERS ) + { + M_SpawnSkel(v21, v22, md); + M_StartSpStand(arglist, md); + } + } + else + { + v23 = abs(v5); + //v25 = v24; + if ( v23 >= 2 || (v26 = abs(v4), v26 >= 2) ) /* v25 = v27, */ + { + v28 = random(129, 100); + v29 = (unsigned char)v2->_mint; + if ( v28 >= v29 + 25 + && ((v30 = v2->_mVar1, v30 != 1) && v30 != 2 && v30 != 3 || v2->_mVar2 || (v29 += 75, v28 >= v29)) ) + { + v31 = random(130, 10); + M_StartDelay(arglist, v31 + 10); + } + else + { + M_CallWalk(arglist, md); + } + } + else if ( v35 < (unsigned char)v2->_mint + 20 ) + { + v2->_mdir = md; + M_StartAttack(arglist); + } + } + } + if ( v2->_mmode == MM_STAND ) + v2->_mAnimData = v2->MType->Anims[0].Frames[md]; + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall MAI_Rhino(int i) +{ + int esi1; // esi + MonsterStruct *esi3; // esi + int v3; // edx + int v4; // ebx + int v5; // edi + int v7; // eax + //int v8; // ST1C_4 + int v10; // eax + //int v11; // ST1C_4 + int v13; // ebx + int v14; // eax + int v15; // ecx + //int v16; // eax + int v18; // eax + bool v19; // eax + int v20; // ecx + int v21; // eax + //int v22; // ST1C_4 + int v24; // eax + //int v25; // ST1C_4 + int v26; // eax + int v27; // ecx + int v28; // edx + int v29; // eax + int v30; // [esp+4h] [ebp-18h] + int v31; // [esp+8h] [ebp-14h] + int v1; // [esp+Ch] [ebp-10h] + int midir; // [esp+10h] [ebp-Ch] + int v2; // [esp+14h] [ebp-8h] + int arglist; // [esp+18h] [ebp-4h] + + esi1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Rhino: Invalid monster %d", i); + esi3 = &monster[esi1]; + if ( esi3->_mmode == MM_STAND && esi3->_msquelch ) + { + v3 = esi3->_my; + v2 = (unsigned char)esi3->_menemyy; + v4 = v3 - v2; + v1 = (unsigned char)esi3->_menemyx; + v5 = esi3->_mx - v1; + v31 = v3 - v2; + midir = GetDirection(esi3->_mx, v3, esi3->_lastx, esi3->_lasty); + if ( esi3->_msquelch < 0xFFu ) /* check sign */ + MonstCheckDoors(arglist); + v30 = random(131, 100); + if ( abs(v5) >= 2 || abs(v4) >= 2 ) + { + if ( _LOBYTE(esi3->_mgoal) != 4 ) + { + v7 = abs(v5); + //v9 = v8; + if ( v7 < 5 ) + { + v10 = abs(v4); + //v9 = v11; + if ( v10 < 5 ) + goto LABEL_23; + } + if ( !random(132, 4) ) + goto LABEL_23; + if ( _LOBYTE(esi3->_mgoal) != 4 ) + { + esi3->_mgoalvar1 = 0; + esi3->_mgoalvar2 = random(133, 2); + } + } + _LOBYTE(esi3->_mgoal) = 4; + v13 = abs(v4); + if ( abs(v5) <= v13 ) + { + v4 = v31; + v14 = abs(v31); + } + else + { + v14 = abs(v5); + v4 = v31; + } + v15 = esi3->_mgoalvar1; + esi3->_mgoalvar1 = v15 + 1; + if ( v15 < 2 * v14 && dung_map[esi3->_mx][esi3->_my] == dung_map[v1][v2] ) + { + //_LOBYTE(v16) = M_RoundWalk(arglist, midir, &esi3->_mgoalvar2); + if ( !M_RoundWalk(arglist, midir, &esi3->_mgoalvar2) ) + { + v18 = random(125, 10); + M_StartDelay(arglist, v18 + 10); + } + goto LABEL_23; + } + } + _LOBYTE(esi3->_mgoal) = 1; + LABEL_23: + if ( _LOBYTE(esi3->_mgoal) == 1 ) + { + if ( (abs(v5) >= 5 || abs(v4) >= 5) + && v30 < 2 * (unsigned char)esi3->_mint + 43 + && (v19 = LineClearF1( + PosOkMonst, + arglist, + esi3->_mx, + esi3->_my, + v1, + v2), + v19) ) + { + if ( AddMissile(esi3->_mx, esi3->_my, v1, v2, midir, 20, esi3->_menemy, arglist, 0, 0) != -1 ) + { + if ( esi3->MData->snd_special ) + PlayEffect(arglist, 3); + v20 = esi3->_my + 112 * esi3->_mx; + esi3->_mmode = MM_CHARGE; + dMonster[0][v20] = -1 - arglist; + } + } + else + { + v21 = abs(v5); + //v23 = v22; + if ( v21 >= 2 || (v24 = abs(v4), v24 >= 2) ) /* v23 = v25, */ + { + v26 = random(134, 100); + v27 = 2 * (unsigned char)esi3->_mint; + if ( v26 >= v27 + 33 + && ((v28 = esi3->_mVar1, v28 != 1) && v28 != 2 && v28 != 3 + || esi3->_mVar2 + || (v27 += 83, v26 >= v27)) ) + { + v29 = random(135, 10); + M_StartDelay(arglist, v29 + 10); + } + else + { + M_CallWalk(arglist, midir); + } + } + else if ( v30 < 2 * (unsigned char)esi3->_mint + 28 ) + { + esi3->_mdir = midir; + M_StartAttack(arglist); + } + } + } + if ( esi3->_mmode == MM_STAND ) + esi3->_mAnimData = esi3->MType->Anims[0].Frames[esi3->_mdir]; + } +} + +void __fastcall MAI_Counselor(int i) +{ + int v1; // ebx + int v2; // esi + int v3; // ecx + int v4; // edi + int v5; // edx + int v6; // ebp + char v9; // al + int v10; // ecx + bool v11; // zf + bool v12; // sf + unsigned char v13; // of + int v14; // edx + int v15; // ecx + int v16; // ebx + int v17; // eax + int v18; // ebx + int v19; // edx + int v20; // ecx + //int v21; // eax + int v22; // eax + //int v23; // ST1C_4 + int v25; // eax + //int v26; // ST1C_4 + int v27; // edx + int v28; // eax + int v29; // eax + int v30; // ecx + //int v31; // eax + int v32; // eax + int v33; // eax + int v34; // eax + int md; // [esp+8h] [ebp-14h] + int arglist; // [esp+Ch] [ebp-10h] + int y2; // [esp+10h] [ebp-Ch] + int x2; // [esp+14h] [ebp-8h] + int v39; // [esp+18h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Counselor: Invalid monster %d", i); + v2 = v1; + if ( monster[v1]._mmode == MM_STAND && monster[v2]._msquelch ) + { + v3 = monster[v2]._mx; + x2 = (unsigned char)monster[v2]._menemyx; + v4 = v3 - x2; + v5 = monster[v2]._my; + y2 = (unsigned char)monster[v2]._menemyy; + v6 = v5 - y2; + md = GetDirection(v3, v5, monster[v2]._lastx, monster[v2]._lasty); + if ( monster[v2]._msquelch < 0xFFu ) /* check sign */ + MonstCheckDoors(v1); + v39 = random(121, 100); + v9 = monster[v2]._mgoal; + if ( v9 == 2 ) + { + v10 = monster[v2]._mgoalvar1; + v13 = __OFSUB__(v10, 3); + v11 = v10 == 3; + v12 = v10 - 3 < 0; + v14 = v10 + 1; + v15 = v1; + monster[v2]._mgoalvar1 = v14; + if ( (unsigned char)(v12 ^ v13) | v11 ) + { + M_CallWalk(v1, opposite[md]); + goto LABEL_39; + } + goto LABEL_21; + } + if ( v9 == 4 ) + { + v16 = abs(v6); + if ( abs(v4) <= v16 ) + v17 = abs(v6); + else + v17 = abs(v4); + v18 = v17; + if ( abs(v4) < 2 && abs(v6) < 2 + || monster[v2]._msquelch != -1 + || dung_map[monster[v2]._mx][monster[v2]._my] != dung_map[x2][y2] ) + { + v1 = arglist; + LABEL_20: + v15 = v1; + LABEL_21: + _LOBYTE(monster[v2]._mgoal) = 1; + M_StartFadein(v15, md, 1u); + goto LABEL_39; + } + v19 = 2 * v18; + v1 = arglist; + v20 = monster[v2]._mgoalvar1; + monster[v2]._mgoalvar1 = v20 + 1; + if ( v20 >= v19 ) + { + //_LOBYTE(v21) = DirOK(arglist, md); + if ( DirOK(arglist, md) ) + goto LABEL_20; + } + M_RoundWalk(arglist, md, &monster[v2]._mgoalvar2); + LABEL_39: + if ( monster[v2]._mmode == MM_STAND ) + { + v34 = random(125, 10); + M_StartDelay(v1, v34 + 5); + } + return; + } + if ( v9 != 1 ) + goto LABEL_39; + v22 = abs(v4); + //v24 = v23; + if ( v22 >= 2 || (v25 = abs(v6), v25 >= 2) ) /* v24 = v26, */ + { + if ( v39 < 5 * ((unsigned char)monster[v2]._mint + 10) ) + { + //_LOBYTE(v31) = LineClear(monster[v2]._mx, monster[v2]._my, x2, y2); + if ( LineClear(monster[v2]._mx, monster[v2]._my, x2, y2) ) + { + v32 = random( + 77, + (unsigned char)monster[v2].mMaxDamage - (unsigned char)monster[v2].mMinDamage + 1); + M_StartRAttack( + v1, + (unsigned char)counsmiss[(unsigned char)monster[v2]._mint], /* counsmiss is local */ + (unsigned char)monster[v2].mMinDamage + v32); + goto LABEL_39; + } + } + if ( random(124, 100) < 30 ) + { + v27 = md; + _LOBYTE(monster[v2]._mgoal) = 4; + goto LABEL_29; + } + } + else + { + v27 = md; + v28 = monster[v2]._mmaxhp >> 1; + v13 = __OFSUB__(monster[v2]._mhitpoints, v28); + v12 = monster[v2]._mhitpoints - v28 < 0; + monster[v2]._mdir = md; + if ( v12 ^ v13 ) + { + _LOBYTE(monster[v2]._mgoal) = 2; + LABEL_29: + monster[v2]._mgoalvar1 = 0; + M_StartFadeout(v1, v27, 0); + goto LABEL_39; + } + if ( monster[v2]._mVar1 == 13 + || (v29 = random(105, 100), + v30 = 2 * (unsigned char)monster[v2]._mint + 20, + v29 < v30) ) + { + M_StartRAttack(v1, -1, 0); + AddMissile(monster[v2]._mx, monster[v2]._my, 0, 0, monster[v2]._mdir, 11, 1, v1, 4, 0); + AddMissile(monster[v2]._mx, monster[v2]._my, 0, 0, monster[v2]._mdir, 12, 1, v1, 4, 0); + goto LABEL_39; + } + } + v33 = random(105, 10); + M_StartDelay(v1, v33 + 2 * (5 - (unsigned char)monster[v2]._mint)); + goto LABEL_39; + } +} + +void __fastcall MAI_Garbud(int i) +{ + int v1; // esi + int v2; // esi + int v3; // ebx + int v4; // edi + int v5; // eax + //int v6; // eax + char v7; // al + int v8; // [esp+4h] [ebp-8h] + int arglist; // [esp+8h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Garbud: Invalid monster %d", i); + v2 = v1; + if ( monster[v2]._mmode == MM_STAND ) + { + v3 = monster[v2]._my; + v4 = monster[v2]._mx; + v8 = M_GetDir(arglist); + v5 = monster[v2].mtalkmsg; + if ( v5 < (signed int)QUEST_GARBUD4 + && v5 >(signed int)QUEST_DOOM10 + && !(dFlags[v4][v3] & 2) + && _LOBYTE(monster[v2]._mgoal) == 7 ) + { + _LOBYTE(monster[v2]._mgoal) = 6; + monster[v2].mtalkmsg = v5 + 1; + } + if ( dFlags[v4][v3] & 2 ) + { + if ( monster[v2].mtalkmsg == QUEST_GARBUD4 ) + { + //_LOBYTE(v6) = effect_is_playing(USFX_GARBUD4); + if ( !effect_is_playing(USFX_GARBUD4) && _LOBYTE(monster[v2]._mgoal) == 7 ) + { + monster[v2]._msquelch = -1; + monster[v2].mtalkmsg = 0; + _LOBYTE(monster[v2]._mgoal) = 1; + } + } + } + v7 = monster[v2]._mgoal; + if ( v7 == 1 || v7 == 4 ) + MAI_Round(arglist, 1u); + monster[v2]._mdir = v8; + if ( monster[v2]._mmode == MM_STAND ) + monster[v2]._mAnimData = monster[v2].MType->Anims[0].Frames[v8]; + } +} + +void __fastcall MAI_Zhar(int i) +{ + int v1; // ebp + int v2; // esi + int v3; // ebx + int v4; // edi + int v5; // edi + int v6; // ebx + int v7; // ebp + //int v8; // eax + char v9; // al + int arglist; // [esp+8h] [ebp-8h] + int v11; // [esp+Ch] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Zhar: Invalid monster %d", i); + v2 = v1; + if ( monster[v1]._mmode == MM_STAND ) + { + v3 = monster[v2]._my; + v4 = monster[v2]._mx; + v11 = M_GetDir(v1); + if ( monster[v2].mtalkmsg == QUEST_ZHAR1 && !(dFlags[v4][v3] & 2) && _LOBYTE(monster[v2]._mgoal) == 7 ) + { + monster[v2].mtalkmsg = QUEST_ZHAR2; + _LOBYTE(monster[v2]._mgoal) = 6; + } + if ( dFlags[v4][v3] & 2 ) + { + v5 = monster[v2]._mx - (unsigned char)monster[v2]._menemyx; + v6 = monster[v2]._my - (unsigned char)monster[v2]._menemyy; + v7 = abs(v6); + if ( abs(v5) <= v7 ) + abs(v6); + else + abs(v5); + if ( monster[v2].mtalkmsg == QUEST_ZHAR2 ) + { + //_LOBYTE(v8) = effect_is_playing(USFX_ZHAR2); + if ( !effect_is_playing(USFX_ZHAR2) && _LOBYTE(monster[v2]._mgoal) == 7 ) + { + monster[v2]._msquelch = -1; + monster[v2].mtalkmsg = 0; + _LOBYTE(monster[v2]._mgoal) = 1; + } + } + } + v9 = monster[v2]._mgoal; + if ( v9 == 1 || v9 == 2 || v9 == 4 ) + MAI_Counselor(arglist); + monster[v2]._mdir = v11; + if ( monster[v2]._mmode == MM_STAND ) + monster[v2]._mAnimData = monster[v2].MType->Anims[0].Frames[v11]; + } +} + +void __fastcall MAI_SnotSpil(int i) +{ + int v1; // ebp + int v2; // esi + int v3; // ebx + int v4; // edi + int v5; // ebp + //int v6; // eax + char v7; // al + int arglist; // [esp+8h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_SnotSpil: Invalid monster %d", i); + v2 = v1; + if ( monster[v1]._mmode == MM_STAND ) + { + v3 = monster[v2]._my; + v4 = monster[v2]._mx; + v5 = M_GetDir(v1); + if ( monster[v2].mtalkmsg == QUEST_BANNER10 && !(dFlags[v4][v3] & 2) && _LOBYTE(monster[v2]._mgoal) == 7 ) + { + monster[v2].mtalkmsg = QUEST_BANNER11; + _LOBYTE(monster[v2]._mgoal) = 6; + } + if ( monster[v2].mtalkmsg == QUEST_BANNER11 && quests[7]._qvar1 == 3 ) + { + monster[v2].mtalkmsg = 0; + _LOBYTE(monster[v2]._mgoal) = 1; + } + if ( dFlags[v4][v3] & 2 ) + { + if ( monster[v2].mtalkmsg == QUEST_BANNER12 ) + { + //_LOBYTE(v6) = effect_is_playing(USFX_SNOT3); + if ( !effect_is_playing(USFX_SNOT3) && _LOBYTE(monster[v2]._mgoal) == 7 ) + { + ObjChangeMap(setpc_x, setpc_y, setpc_w + setpc_x + 1, setpc_h + setpc_y + 1); + quests[7]._qvar1 = 3; + RedoPlayerVision(); + monster[v2]._msquelch = -1; + monster[v2].mtalkmsg = 0; + _LOBYTE(monster[v2]._mgoal) = 1; + } + } + if ( quests[7]._qvar1 == 3 ) + { + v7 = monster[v2]._mgoal; + if ( v7 == 1 || v7 == 5 ) + MAI_Fallen(arglist); + } + } + monster[v2]._mdir = v5; + if ( monster[v2]._mmode == MM_STAND ) + monster[v2]._mAnimData = monster[v2].MType->Anims[0].Frames[v5]; + } +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __fastcall MAI_Lazurus(int i) +{ + int v1; // ebx + int v2; // esi + int v3; // ebp + int v4; // edi + int v5; // ebx + //int v6; // eax + char v7; // al + int v8; // eax + int arglist; // [esp+8h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Lazurus: Invalid monster %d", i); + v2 = v1; + if ( monster[v1]._mmode == MM_STAND ) + { + v3 = monster[v2]._my; + v4 = monster[v2]._mx; + v5 = M_GetDir(v1); + if ( dFlags[v4][v3] & 2 ) + { + if ( gbMaxPlayers != 1 ) + goto LABEL_29; + if ( monster[v2].mtalkmsg == QUEST_VILE13 ) + { + if ( _LOBYTE(monster[v2]._mgoal) == 6 && plr[myplr].WorldX == QUEST_VILE13 && plr[myplr].WorldY == 46 ) + { + PlayInGameMovie("gendata\\fprst3.smk"); + monster[v2]._mmode = MM_TALK; + quests[15]._qvar1 = 5; + } + if ( monster[v2].mtalkmsg == QUEST_VILE13 ) + { + //_LOBYTE(v6) = effect_is_playing(USFX_LAZ1); + if ( !effect_is_playing(USFX_LAZ1) && _LOBYTE(monster[v2]._mgoal) == 7 ) + { + ObjChangeMapResync(1, 18, 20, 24); + RedoPlayerVision(); + monster[v2]._msquelch = -1; + monster[v2].mtalkmsg = 0; + quests[15]._qvar1 = 6; + _LOBYTE(monster[v2]._mgoal) = 1; + } + } + } + if ( gbMaxPlayers != 1 ) + { + LABEL_29: + if ( monster[v2].mtalkmsg == QUEST_VILE13 && _LOBYTE(monster[v2]._mgoal) == 6 && quests[15]._qvar1 <= 3u ) + monster[v2]._mmode = MM_TALK; + } + } + v7 = monster[v2]._mgoal; + if ( v7 == 1 || v7 == 2 || v7 == 4 ) + { + monster[v2].mtalkmsg = 0; + MAI_Counselor(arglist); + } + monster[v2]._mdir = v5; + v8 = monster[v2]._mmode; + if ( v8 == MM_STAND || v8 == MM_TALK ) + monster[v2]._mAnimData = monster[v2].MType->Anims[0].Frames[v5]; + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall MAI_Lazhelp(int i) +{ + int v1; // esi + int v2; // esi + int v3; // ebx + int v4; // edi + int v5; // [esp+4h] [ebp-8h] + int ia; // [esp+8h] [ebp-4h] + + v1 = i; + ia = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Lazhelp: Invalid monster %d", i); + v2 = v1; + if ( monster[v2]._mmode == MM_STAND ) + { + v3 = monster[v2]._my; + v4 = monster[v2]._mx; + v5 = M_GetDir(ia); + if ( dFlags[v4][v3] & 2 ) + { + if ( gbMaxPlayers == 1 ) + { + if ( quests[15]._qvar1 <= 5u ) + { + _LOBYTE(monster[v2]._mgoal) = 6; + goto LABEL_10; + } + monster[v2].mtalkmsg = 0; + } + _LOBYTE(monster[v2]._mgoal) = 1; + } + LABEL_10: + if ( _LOBYTE(monster[v2]._mgoal) == 1 ) + MAI_Succ(ia); + monster[v2]._mdir = v5; + if ( monster[v2]._mmode == MM_STAND ) + monster[v2]._mAnimData = monster[v2].MType->Anims[0].Frames[v5]; + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall MAI_Lachdanan(int i) +{ + int v1; // ebp + int v2; // esi + int v3; // ebx + int v4; // edi + //int v5; // eax + int v6; // [esp+8h] [ebp-4h] + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Lachdanan: Invalid monster %d", i); + v2 = v1; + if ( monster[v1]._mmode == MM_STAND ) + { + v3 = monster[v2]._my; + v4 = monster[v2]._mx; + v6 = M_GetDir(v1); + if ( monster[v2].mtalkmsg == QUEST_VEIL9 && !(dFlags[v4][v3] & 2) && _LOBYTE(monster[v2]._mgoal) == 7 ) + { + monster[v2].mtalkmsg = QUEST_VEIL10; + _LOBYTE(monster[v2]._mgoal) = 6; + } + if ( dFlags[v4][v3] & 2 ) + { + if ( monster[v2].mtalkmsg == QUEST_VEIL11 ) + { + //_LOBYTE(v5) = effect_is_playing(USFX_LACH3); + if ( !effect_is_playing(USFX_LACH3) && _LOBYTE(monster[v2]._mgoal) == 7 ) + { + monster[v2].mtalkmsg = 0; + quests[4]._qactive = 3; + M_StartKill(v1, -1); + } + } + } + monster[v2]._mdir = v6; + if ( monster[v2]._mmode == MM_STAND ) + monster[v2]._mAnimData = monster[v2].MType->Anims[0].Frames[v6]; + } +} + +void __fastcall MAI_Warlord(int i) +{ + int v1; // ebp + int v2; // esi + int v3; // ebx + int v4; // edi + int v5; // ebp + //int v6; // eax + int v7; // eax + int arglist; // [esp+8h] [ebp-4h] + + v1 = i; + arglist = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("MAI_Warlord: Invalid monster %d", i); + v2 = v1; + if ( monster[v1]._mmode == MM_STAND ) + { + v3 = monster[v2]._my; + v4 = monster[v2]._mx; + v5 = M_GetDir(v1); + if ( dFlags[v4][v3] & 2 && monster[v2].mtalkmsg == QUEST_WARLRD9 ) + { + if ( _LOBYTE(monster[v2]._mgoal) == 6 ) + monster[v2]._mmode = MM_TALK; + //_LOBYTE(v6) = effect_is_playing(USFX_WARLRD1); + if ( !effect_is_playing(USFX_WARLRD1) && _LOBYTE(monster[v2]._mgoal) == 7 ) + { + monster[v2]._msquelch = -1; + monster[v2].mtalkmsg = 0; + _LOBYTE(monster[v2]._mgoal) = 1; + } + } + if ( _LOBYTE(monster[v2]._mgoal) == 1 ) + MAI_SkelSd(arglist); + monster[v2]._mdir = v5; + v7 = monster[v2]._mmode; + if ( v7 == MM_STAND || v7 == MM_TALK ) + monster[v2]._mAnimData = monster[v2].MType->Anims[0].Frames[v5]; + } +} + +void __cdecl DeleteMonsterList() +{ + int *v0; // eax + signed int v1; // ecx + + v0 = &monster[0]._my; + do + { + if ( v0[18] ) + { + *(v0 - 1) = 1; + *v0 = 0; + v0[1] = 0; + v0[2] = 0; + v0[3] = 0; + v0[4] = 0; + v0[18] = 0; + } + v0 += 57; + } + while ( (signed int)v0 < (signed int)&monster[4]._my ); + v1 = 4; + while ( v1 < nummonsters ) + { + if ( monster[monstactive[v1]]._mDelFlag ) + { + DeleteMonster(v1); + v1 = 0; + } + else + { + ++v1; + } + } +} + +void __cdecl ProcessMonsters() +{ + int v0; // edi + int v1; // esi + int v2; // ecx + int v3; // eax + char *v4; // ebx + unsigned int v5; // eax + int v6; // eax + int v7; // edx + int v8; // eax + unsigned int v9; // eax + int v10; // eax + bool v11; // zf + char *v12; // ecx + char *v13; // eax + int v14; // ecx + int v15; // eax + char v16; // al + int v17; // ecx + bool v18; // eax + int v19; // eax + int v20; // ecx + int *v21; // eax + int *v22; // eax + int v23; // [esp+0h] [ebp-Ch] + int v24; // [esp+4h] [ebp-8h] + int v25; // [esp+8h] [ebp-4h] + + DeleteMonsterList(); + v24 = 0; + if ( nummonsters <= 0 ) + goto LABEL_60; + do + { + v25 = 0; + v23 = monstactive[v24]; + v0 = v23; + v1 = v23; + if ( (unsigned char)gbMaxPlayers > 1u ) + { + SetRndSeed(monster[v1]._mAISeed); + monster[v1]._mAISeed = GetRndSeed(); + } + if ( !(monster[v1]._mFlags & 8) ) + { + v2 = monster[v1]._mhitpoints; + if ( v2 < monster[v1]._mmaxhp && (signed int)(v2 & 0xFFFFFFC0) > 0 ) + { + v3 = SLOBYTE(monster[v1].mLevel); + if ( (char)v3 > 1 ) + v3 = (char)v3 >> 1; + monster[v1]._mhitpoints = v2 + v3; + } + } + v4 = &dFlags[monster[v1]._mx][monster[v1]._my]; + if ( *v4 & 2 && !monster[v1]._msquelch && monster[v1].MType->mtype == MT_CLEAVER ) + PlaySFX(USFX_CLEAVER); + if ( monster[v1]._mFlags & 0x10 ) + { + v5 = monster[v1]._menemy; + if ( v5 >= MAXMONSTERS ) + TermMsg("Illegal enemy monster %d for monster \"%s\"", v5, monster[v1].mName); + v6 = monster[v1]._menemy; + v7 = monster[v6]._mfutx; + monster[v1]._lastx = v7; + monster[v1]._menemyx = v7; + v8 = monster[v6]._mfuty; + monster[v1]._menemyy = v8; + monster[v1]._lasty = v8; + } + else + { + v9 = monster[v1]._menemy; + if ( v9 >= MAX_PLRS ) + TermMsg("Illegal enemy player %d for monster \"%s\"", v9, monster[v1].mName); + v10 = monster[v1]._menemy; + v11 = (*v4 & 2) == 0; + v12 = (char *)&plr[v10]._px; + v13 = (char *)&plr[v10]._py; + monster[v1]._menemyx = *v12; + monster[v1]._menemyy = *v13; + if ( v11 ) + { + v16 = monster[v1]._msquelch; + if ( v16 && monster[v1]._mAi != MT_DIABLO ) /// BUGFIX: test `MT_DIABLO` with 'MType->mtype' instead of '_mAi' + monster[v1]._msquelch = v16 - 1; + } + else + { + v14 = *(_DWORD *)v12; + v15 = *(_DWORD *)v13; + monster[v1]._msquelch = -1; + monster[v1]._lastx = v14; + monster[v1]._lasty = v15; + } + v0 = v23; + } + while ( 1 ) + { + v17 = v0; + if ( monster[v1]._mFlags & 0x100 ) + { + v18 = MAI_Path(v0); + if ( v18 ) + goto LABEL_30; + v17 = v0; + } + AiProc[(unsigned char)monster[v1]._mAi](v17); + LABEL_30: + switch ( monster[v1]._mmode ) + { + case MM_STAND: + v19 = M_DoStand(v0); + goto LABEL_48; + case MM_WALK: + v19 = M_DoWalk(v0); + goto LABEL_48; + case MM_WALK2: + v19 = M_DoWalk2(v0); + goto LABEL_48; + case MM_WALK3: + v19 = M_DoWalk3(v0); + goto LABEL_48; + case MM_ATTACK: + v19 = M_DoAttack(v0); + goto LABEL_48; + case MM_GOTHIT: + v19 = M_DoGotHit(v0); + goto LABEL_48; + case MM_DEATH: + v19 = M_DoDeath(v0); + goto LABEL_48; + case MM_SATTACK: + v19 = M_DoSAttack(v0); + goto LABEL_48; + case MM_FADEIN: + v19 = M_DoFadein(v0); + goto LABEL_48; + case MM_FADEOUT: + v19 = M_DoFadeout(v0); + goto LABEL_48; + case MM_RATTACK: + v19 = M_DoRAttack(v0); + goto LABEL_48; + case MM_SPSTAND: + v19 = M_DoSpStand(v0); + goto LABEL_48; + case MM_RSPATTACK: + v19 = M_DoRSpAttack(v0); + goto LABEL_48; + case MM_DELAY: + v19 = M_DoDelay(v0); + goto LABEL_48; + case MM_CHARGE: + goto LABEL_51; + case MM_STONE: + v19 = M_DoStone(v0); + goto LABEL_48; + case MM_HEAL: + v19 = M_DoHeal(v0); + goto LABEL_48; + case MM_TALK: + v19 = M_DoTalk(v0); + LABEL_48: + v25 = v19; + break; + default: + break; + } + if ( !v25 ) + break; + GroupUnity(v0); + } + LABEL_51: + if ( monster[v1]._mmode != MM_STONE ) + { + v20 = monster[v1]._mFlags; + v21 = &monster[v1]._mAnimCnt; + ++*v21; + if ( !(v20 & 4) && monster[v1]._mAnimCnt >= monster[v1]._mAnimDelay ) + { + *v21 = 0; + v22 = &monster[v1]._mAnimFrame; + if ( v20 & 2 ) + { + v11 = (*v22)-- == 1; + if ( v11 ) + *v22 = monster[v1]._mAnimLen; + } + else if ( ++*v22 > monster[v1]._mAnimLen ) + { + *v22 = 1; + } + } + } + ++v24; + } + while ( v24 < nummonsters ); +LABEL_60: + DeleteMonsterList(); +} +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl FreeMonsters() +{ + void **v0; // edi + int v1; // ebx + signed int v2; // ebp + void **v3; // esi + void *v4; // ecx + int v5; // [esp+0h] [ebp-4h] + + v5 = 0; + if ( nummtypes > 0 ) + { + v0 = (void **)Monsters[0].Anims; + do + { + v1 = *((unsigned char *)v0 - 4); + v2 = 0; + v3 = v0; + do + { + if ( animletter[v2] != 's' || monsterdata[v1].has_special ) + { + v4 = *v3; + *v3 = 0; + mem_free_dbg(v4); + } + ++v2; + v3 += 11; + } + while ( v2 < 6 ); + ++v5; + v0 += 82; + } + while ( v5 < nummtypes ); + } + FreeMissiles2(); +} + +bool __fastcall DirOK(int i, int mdir) +{ + int v2; // ebx + int v3; // esi + int v4; // ebx + int v5; // edi + int v6; // esi + int v7; // edi + bool v8; // zf + int v9; // edx + unsigned char *v11; // ebx + unsigned char v12; // al + int v13; // edx + int v14; // eax + int v15; // edi + int v16; // ecx + signed int j; // esi + int v18; // eax + bool v19; // zf + int v20; // eax + int v21; // [esp+Ch] [ebp-14h] + int v22; // [esp+10h] [ebp-10h] + int v23; // [esp+14h] [ebp-Ch] + int a1; // [esp+18h] [ebp-8h] + int v25; // [esp+1Ch] [ebp-4h] + int v26; // [esp+1Ch] [ebp-4h] + + v2 = i; + v3 = mdir; + v25 = mdir; + a1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("DirOK: Invalid monster %d", i); + v4 = v2; + v5 = offset_y[v3]; + v6 = monster[v4]._mx + offset_x[v3]; + v7 = monster[v4]._my + v5; + if ( v7 < 0 || v7 >= 112 || v6 < 0 || v6 >= 112 || !PosOkMonst(a1, v6, v7) ) + return 0; + if ( v25 == DIR_E ) + { + if ( !SolidLoc(v6, v7 + 1) ) + { + v8 = (dFlags[v6][v7 + 1] & 0x10) == 0; + goto LABEL_18; + } + return 0; + } + if ( v25 == DIR_W ) + { + if ( SolidLoc(v6 + 1, v7) ) + return 0; + v8 = (dFlags[v6 + 1][v7] & 0x10) == 0; + } + else + { + if ( v25 == DIR_N ) + { + if ( SolidLoc(v6 + 1, v7) ) + return 0; + v9 = v7 + 1; + } + else + { + if ( v25 ) + goto LABEL_24; + if ( SolidLoc(v6 - 1, v7) ) + return 0; + v9 = v7 - 1; + } + v8 = SolidLoc(v6, v9) == 0; + } +LABEL_18: + if ( !v8 ) + return 0; +LABEL_24: + if ( monster[v4].leaderflag == 1 ) + { + v11 = &monster[v4].leader; + if ( abs(v6 - monster[(unsigned char)*v11]._mfutx) >= 4 + || abs(v7 - monster[(unsigned char)*v11]._mfuty) >= 4 ) + { + return 0; + } + return 1; + } + v12 = monster[v4]._uniqtype; + if ( !v12 || !(UniqMonst[v12 - 1].mUnqAttr & 2) ) + return 1; + v26 = 0; + v13 = v6 - 3; + v21 = v6 + 3; + if ( v6 - 3 <= v6 + 3 ) + { + v14 = v7 - 3; + v15 = v7 + 3; + v23 = v14; + v22 = v15; + v16 = 112 * v13; + do + { + for ( j = v23; j <= v15; ++j ) + { + if ( j >= 0 && j < 112 && v16 >= 0 && v16 < 12544 ) + { + v18 = dMonster[0][v16 + j]; + v19 = v18 == 0; + if ( v18 < 0 ) + { + v18 = -v18; + v19 = v18 == 0; + } + if ( !v19 ) + --v18; + v20 = v18; + if ( monster[v20].leaderflag == 1 + && (unsigned char)monster[v20].leader == a1 + && monster[v20]._mfutx == v13 + && monster[v20]._mfuty == j ) + { + ++v26; + } + } + v15 = v22; + } + ++v13; + v16 += 112; + } + while ( v13 <= v21 ); + } + return v26 == (unsigned char)monster[v4].unpackfilesize; +} + +BOOL __fastcall PosOkMissile(int x, int y) +{ + return !nMissileTable[dPiece[x][y]] && !(dFlags[x][y] & 0x10); +} + +BOOL __fastcall CheckNoSolid(int x, int y) +{ + return nSolidTable[dPiece[x][y]] == 0; +} + +BOOL __fastcall LineClearF(BOOL(__fastcall *Clear)(int, int), int x1, int y1, int x2, int y2) +{ + int v5; // esi + int v6; // edi + int v7; // ebx + int v8; // eax + int v9; // eax + int v10; // eax + int v11; // ebx + int v12; // esi + signed int v13; // edi + int v14; // edx + int v15; // ecx + int v16; // eax + int v17; // eax + int v18; // eax + int v19; // ebx + int v20; // edi + signed int v21; // esi + int v22; // ecx + int v25; // [esp+10h] [ebp-10h] + int v26; // [esp+14h] [ebp-Ch] + int v27; // [esp+18h] [ebp-8h] + int v28; // [esp+18h] [ebp-8h] + int v29; // [esp+1Ch] [ebp-4h] + + v5 = y2 - y1; + v29 = x1; + v25 = x1; + v26 = y1; + v6 = x2 - x1; + v7 = abs(y2 - y1); + if ( abs(v6) <= v7 ) + { + if ( v5 < 0 ) + { + v16 = y1; + y1 = y2; + y2 = v16; + v17 = v29; + v5 = -v5; + v29 = x2; + x2 = v17; + v6 = -v6; + } + v18 = 2 * v6; + v28 = 2 * v6; + if ( v6 <= 0 ) + { + v19 = v18 + v5; + v20 = 2 * (v5 + v6); + v21 = -1; + } + else + { + v19 = v18 - v5; + v20 = 2 * (v6 - v5); + v21 = 1; + } + while ( 1 ) + { + v22 = v29; + if ( y1 == y2 && v29 == x2 ) + break; + if ( v19 <= 0 == v21 < 0 ) + { + v19 += v20; + v22 = v21 + v29; + v29 += v21; + } + else + { + v19 += v28; + } + if ( (++y1 != v26 || v22 != v25) && !Clear(v22, y1) ) /* check args */ + goto LABEL_29; + } + } + else + { + if ( v6 < 0 ) + { + v8 = v29; + v29 = x2; + x2 = v8; + v9 = y1; + v6 = -v6; + y1 = y2; + y2 = v9; + v5 = -v5; + } + v10 = 2 * v5; + v27 = 2 * v5; + if ( v5 <= 0 ) + { + v11 = v10 + v6; + v12 = 2 * (v6 + v5); + v13 = -1; + } + else + { + v11 = v10 - v6; + v12 = 2 * (v5 - v6); + v13 = 1; + } + do + { + v14 = y1; + if ( v29 == x2 && y1 == y2 ) + break; + if ( v11 <= 0 == v13 < 0 ) + { + v11 += v12; + v14 = v13 + y1; + y1 += v13; + } + else + { + v11 += v27; + } + v15 = v29 + 1; + } + while ( ++v29 == v25 && v14 == v26 || Clear(v15, v14) ); + LABEL_29: + if ( v29 != x2 ) + return 0; + } + if ( y1 == y2 ) + return 1; + return 0; +} + +BOOL __fastcall LineClear(int x1, int y1, int x2, int y2) +{ + return LineClearF(PosOkMissile, x1, y1, x2, y2); +} + +BOOL __fastcall LineClearF1(BOOL(__fastcall *Clear)(int, int, int), int monst, int x1, int y1, int x2, int y2) +{ + int v6; // esi + int v7; // edi + int v8; // ebx + int v9; // eax + int v10; // eax + int v11; // eax + int v12; // ebx + int v13; // esi + signed int v14; // edi + int v15; // eax + int v16; // eax + int v17; // eax + int v18; // eax + int v19; // ebx + int v20; // edi + signed int v21; // esi + int v22; // edx + int v25; // [esp+10h] [ebp-10h] + int v26; // [esp+14h] [ebp-Ch] + int v27; // [esp+18h] [ebp-8h] + int v28; // [esp+1Ch] [ebp-4h] + int v29; // [esp+1Ch] [ebp-4h] + + v6 = y2 - y1; + v25 = monst; + v26 = x1; + v27 = y1; + v7 = x2 - x1; + v8 = abs(y2 - y1); + if ( abs(x2 - x1) <= v8 ) + { + if ( v6 < 0 ) + { + v16 = y1; + y1 = y2; + y2 = v16; + v17 = x1; + v6 = -v6; + x1 = x2; + x2 = v17; + v7 = -v7; + } + v18 = 2 * v7; + v29 = 2 * v7; + if ( v7 <= 0 ) + { + v19 = v18 + v6; + v20 = 2 * (v6 + v7); + v21 = -1; + } + else + { + v19 = v18 - v6; + v20 = 2 * (v7 - v6); + v21 = 1; + } + while ( 1 ) + { + v22 = x1; + if ( y1 == y2 && x1 == x2 ) + break; + if ( v19 <= 0 == v21 < 0 ) + { + v19 += v20; + v22 = v21 + x1; + x1 += v21; + } + else + { + v19 += v29; + } + if ( (++y1 != v27 || v22 != v26) && !Clear(v25, v22, y1) ) + goto LABEL_29; + } + } + else + { + if ( v7 < 0 ) + { + v9 = x1; + x1 = x2; + x2 = v9; + v10 = y1; + v7 = -v7; + y1 = y2; + y2 = v10; + v6 = -v6; + } + v11 = 2 * v6; + v28 = 2 * v6; + if ( v6 <= 0 ) + { + v12 = v11 + v7; + v13 = 2 * (v7 + v6); + v14 = -1; + } + else + { + v12 = v11 - v7; + v13 = 2 * (v6 - v7); + v14 = 1; + } + do + { + v15 = y1; + if ( x1 == x2 && y1 == y2 ) + break; + if ( v12 <= 0 == v14 < 0 ) + { + v12 += v13; + v15 = v14 + y1; + y1 += v14; + } + else + { + v12 += v28; + } + } + while ( ++x1 == v26 && v15 == v27 || Clear(v25, x1, v15) ); /* check args */ + LABEL_29: + if ( x1 != x2 ) + return 0; + } + if ( y1 == y2 ) + return 1; + return 0; +} + +void __fastcall SyncMonsterAnim(int i) +{ + int v1; // esi + int v2; // eax + int v3; // edx + MonsterData *v4; // esi + CMonster *v5; // ecx + unsigned char v6; // dl + char *v7; // edx + int v8; // esi + int v9; // edx + unsigned char *v10; // ecx + unsigned char *v11; // edx + int v12; // ecx + unsigned char *v13; // edx + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("SyncMonsterAnim: Invalid monster %d", i); + v2 = v1; + v3 = monster[v1]._mMTidx; + v4 = Monsters[v3].MData; + v5 = &Monsters[v3]; + v6 = monster[v2]._uniqtype; + monster[v2].MType = v5; + monster[v2].MData = v4; + if ( v6 ) + v7 = UniqMonst[v6 - 1].mName; + else + v7 = v4->mName; + v8 = monster[v2]._mmode; + monster[v2].mName = v7; + v9 = monster[v2]._mdir; + switch ( v8 ) + { + case MM_STAND: + case MM_DELAY: + case MM_TALK: + v10 = v5->Anims[0].Frames[v9]; + goto LABEL_13; + case MM_WALK: + case MM_WALK2: + case MM_WALK3: + v10 = v5->Anims[1].Frames[v9]; + goto LABEL_13; + case MM_ATTACK: + case MM_RATTACK: + v10 = v5->Anims[2].Frames[v9]; + goto LABEL_13; + case MM_GOTHIT: + v10 = v5->Anims[3].Frames[v9]; + goto LABEL_13; + case MM_DEATH: + v10 = v5->Anims[4].Frames[v9]; + goto LABEL_13; + case MM_SATTACK: + case MM_FADEIN: + case MM_FADEOUT: + case MM_SPSTAND: + case MM_RSPATTACK: + case MM_HEAL: + v10 = v5->Anims[5].Frames[v9]; +LABEL_13: + monster[v2]._mAnimData = v10; + return; + case MM_CHARGE: + v11 = v5->Anims[2].Frames[v9]; + monster[v2]._mAnimFrame = 1; + monster[v2]._mAnimData = v11; + v12 = v5->Anims[2].Rate; + break; + default: + v13 = v5->Anims[0].Frames[v9]; + monster[v2]._mAnimFrame = 1; + monster[v2]._mAnimData = v13; + v12 = v5->Anims[0].Rate; + break; + } + monster[v2]._mAnimLen = v12; +} + +void __fastcall M_FallenFear(int x, int y) +{ + int v2; // eax + int *v3; // ebx + int v4; // edi + int v5; // esi + signed int v6; // eax + int v7; // eax + bool v8; // zf + int v9; // eax + int v10; // eax + signed int v11; // [esp-10h] [ebp-1Ch] + int v12; // [esp+0h] [ebp-Ch] + int x1; // [esp+4h] [ebp-8h] + int y1; // [esp+8h] [ebp-4h] + + v2 = 0; + y1 = y; + x1 = x; + v12 = 0; + if ( nummonsters > 0 ) + { + v3 = &monster[0]._mx; + do + { + v4 = 0; + v5 = monstactive[v2]; + v6 = monster[v5].MType->mtype; + if ( v6 > MT_RFALLSD ) + { + v9 = v6 - 13; + v8 = v9 == 0; + } + else + { + if ( v6 == MT_RFALLSD || (v7 = v6 - 4) == 0 ) + { + v11 = 7; + goto LABEL_15; + } + v9 = v7 - 1; + v8 = v9 == 0; + } + if ( v8 ) + { + v11 = 5; + } + else + { + v10 = v9 - 1; + if ( v10 ) + { + if ( v10 != 1 ) + goto LABEL_16; + v11 = 2; + } + else + { + v11 = 3; + } + } + LABEL_15: + v4 = v11; + LABEL_16: + if ( monster[v5]._mAi == AI_FALLEN + && v4 + && abs(x1 - monster[v5]._mx) < 5 + && abs(y1 - monster[v5]._my) < 5 + && (signed int)(monster[v5]._mhitpoints & 0xFFFFFFC0) > 0 ) + { + _LOBYTE(monster[v5]._mgoal) = 2; + monster[v5]._mgoalvar1 = v4; + monster[v5]._mdir = GetDirection(x1, y1, *v3, v3[1]); + } + v3 += 57; + v2 = v12++ + 1; + } + while ( v12 < nummonsters ); + } +} + +void __fastcall PrintMonstHistory(int mt) +{ + int v1; // edi + int *v2; // ebx + int v3; // ecx + int v4; // eax + int v5; // edi + short v6; // bx + int v7; // ebx + + v1 = mt; + v2 = &monstkills[mt]; + sprintf(tempstr, "Total kills : %i", *v2); + AddPanelString(tempstr, 1); + if ( *v2 >= 30 ) + { + v3 = monsterdata[v1].mMinHP; + v4 = monsterdata[v1].mMaxHP; + if ( gbMaxPlayers == 1 ) + { + v3 = monsterdata[v1].mMinHP >> 1; + v4 = monsterdata[v1].mMaxHP >> 1; + } + if ( v3 < 1 ) + v3 = 1; + if ( v4 < 1 ) + v4 = 1; + if ( gnDifficulty == DIFF_NIGHTMARE ) + { + v3 = 3 * v3 + 1; + v4 = 3 * v4 + 1; + } + if ( gnDifficulty == DIFF_HELL ) + { + v3 = 4 * v3 + 3; + v4 = 4 * v4 + 3; + } + sprintf(tempstr, "Hit Points : %i-%i", v3, v4); + AddPanelString(tempstr, 1); + } + if ( *v2 >= 15 ) + { + v5 = v1 << 7; + if ( gnDifficulty == DIFF_HELL ) + v6 = *(short *)((char *)&monsterdata[0].mMagicRes2 + v5); + else + v6 = *(short *)((char *)&monsterdata[0].mMagicRes + v5); + v7 = v6 & 0x3F; + if ( v7 ) + { + if ( v7 & 7 ) + { + strcpy(tempstr, "Resists : "); + if ( v7 & 1 ) + strcat(tempstr, "Magic "); + if ( v7 & 2 ) + strcat(tempstr, "Fire "); + if ( v7 & 4 ) + strcat(tempstr, "Lightning "); + tempstr[strlen(tempstr) - 1] = '\0'; + AddPanelString(tempstr, 1); + } + if ( v7 & 0x38 ) + { + strcpy(tempstr, "Immune : "); + if ( v7 & 8 ) + strcat(tempstr, "Magic "); + if ( v7 & 0x10 ) + strcat(tempstr, "Fire "); + if ( v7 & 0x20 ) + strcat(tempstr, "Lightning "); + tempstr[strlen(tempstr) - 1] = '\0'; + AddPanelString(tempstr, 1); + } + } + else + { + strcpy(tempstr, "No magic resistance"); + AddPanelString(tempstr, 1); + } + } + pinfoflag = 1; +} +// 4B8824: using guessed type int pinfoflag; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl PrintUniqueHistory() +{ + char v0; // bl + + v0 = monster[pcursmonst].mMagicRes & 0x3F; + if ( v0 ) + { + if ( monster[pcursmonst].mMagicRes & 7 ) + strcpy(tempstr, "Some Magic Resistances"); + else + strcpy(tempstr, "No resistances"); + AddPanelString(tempstr, 1); + if ( v0 & 0x38 ) + { + strcpy(tempstr, "Some Magic Immunities"); + goto LABEL_4; + } + } + else + { + strcpy(tempstr, "No resistances"); + AddPanelString(tempstr, 1); + } + strcpy(tempstr, "No Immunities"); +LABEL_4: + AddPanelString(tempstr, 1); + pinfoflag = 1; +} +// 4B8824: using guessed type int pinfoflag; + +void __fastcall MissToMonst(int i, int x, int y) +{ + int v3; // edi + MissileStruct *v4; // edi + unsigned int v5; // ebx + MonsterStruct *v6; // esi + int v7; // edx + char v8; // al + int v9; // eax + char *v10; // edi + int v11; // eax + int v12; // edx + char v13; // al + char v14; // al + int v15; // ebx + int v16; // eax + int v17; // esi + int v18; // edi + int v19; // esi + int v20; // edx + int *v21; // ebx + char v22; // cl + char v23; // al + int v24; // esi + int v25; // edi + int v26; // esi + int v27; // eax + int v28; // eax + int ia; // [esp+Ch] [ebp-10h] + int v30; // [esp+10h] [ebp-Ch] + int v31; // [esp+14h] [ebp-8h] + int v32; // [esp+18h] [ebp-4h] + int arglist; // [esp+24h] [ebp+8h] + + v3 = i; + v30 = x; + if ( (unsigned int)i >= MAXMISSILES ) + TermMsg("MissToMonst: Invalid missile %d", i); + v4 = &missile[v3]; + v5 = v4->_misource; + ia = v4->_misource; + if ( v5 >= MAXMONSTERS ) + TermMsg("MissToMonst: Invalid monster %d", v5); + v32 = v4->_mix; + v31 = v4->_miy; + v6 = &monster[v5]; + v6->_mx = v30; + dMonster[0][y + 112 * v30] = v5 + 1; + v7 = v4->_mimfnum; + v6->_mdir = v7; + v6->_my = y; + M_StartStand(v5, v7); + v8 = v6->MType->mtype; + if ( v8 < MT_INCIN || v8 > MT_HELLBURN ) + { + if ( v6->_mFlags & 0x10 ) + M2MStartHit(v5, -1, 0); + else + M_StartHit(v5, -1, 0); + } + else + { + M_StartFadein(v5, v6->_mdir, 0); + } + v9 = v32; + if ( v6->_mFlags & 0x10 ) + { + v21 = (int *)((char *)dMonster + 4 * (v31 + v9 * 112)); + if ( *v21 > 0 ) + { + v22 = v6->MType->mtype; + if ( v22 != MT_GLOOM && (v22 < MT_INCIN || v22 > MT_HELLBURN) ) + { + M_TryM2MHit(ia, *v21 - 1, 500, (unsigned char)v6->mMinDamage2, (unsigned char)v6->mMaxDamage2); + v23 = v6->MType->mtype; + if ( v23 < MT_NSNAKE || v23 > MT_GSNAKE ) + { + v24 = v6->_mdir; + v25 = v32 + offset_x[v24]; + v26 = v31 + offset_y[v24]; + if ( PosOkMonst(*v21 - 1, v25, v26) ) + { + v27 = *v21; + dMonster[0][v26 + 112 * v25] = *v21; + *v21 = 0; + v28 = v27 - 1; + monster[v28]._mx = v25; + monster[v28]._mfutx = v25; + monster[v28]._my = v26; + monster[v28]._mfuty = v26; + } + } + } + } + } + else + { + v10 = &dPlayer[v9][v31]; + v11 = *v10; + v12 = v11 - 1; + arglist = v11 - 1; + if ( *v10 > 0 ) + { + v13 = v6->MType->mtype; + if ( v13 != MT_GLOOM && (v13 < MT_INCIN || v13 > MT_HELLBURN) ) + { + M_TryH2HHit(v5, v12, 500, (unsigned char)v6->mMinDamage2, (unsigned char)v6->mMaxDamage2); + if ( arglist == *v10 - 1 ) + { + v14 = v6->MType->mtype; + if ( v14 < MT_NSNAKE || v14 > MT_GSNAKE ) + { + v15 = arglist; + v16 = plr[arglist]._pmode; + if ( v16 != 7 && v16 != 8 ) + StartPlrHit(arglist, 0, 1u); + v17 = v6->_mdir; + v18 = v32 + offset_x[v17]; + v19 = v31 + offset_y[v17]; + if ( PosOkPlayer(arglist, v18, v19) ) + { + v20 = plr[v15]._pdir; + plr[v15].WorldX = v18; + plr[v15].WorldY = v19; + FixPlayerLocation(arglist, v20); + FixPlrWalkTags(arglist); + dPlayer[v18][v19] = arglist + 1; + SetPlayerOld(arglist); + } + } + } + } + } + } +} + +BOOL __fastcall PosOkMonst(int i, int x, int y) +{ + int v3; // edi + signed int v4; // ebx + int v5; // ecx + char v6; // dl + bool result; // eax + int v8; // edx + int v9; // ecx + int v10; // [esp+Ch] [ebp-4h] + + v3 = x; + v10 = i; + v4 = 0; + if ( SolidLoc(x, y) ) + return 0; + v5 = 112 * v3; + if ( dPlayer[v3][y] || dMonster[0][v5 + y] ) + return 0; + v6 = dObject[0][v5 + y]; + result = 1; + if ( v6 ) + { + v8 = v6 <= 0 ? -1 - v6 : v6 - 1; + if ( object[v8]._oSolidFlag ) + return 0; + } + _LOBYTE(v5) = dMissile[0][v5 + y]; + if ( (_BYTE)v5 ) + { + if ( v10 >= 0 ) + { + v5 = (char)v5; + if ( (char)v5 > 0 ) + { + if ( missile[v5]._mitype == 5 ) + goto LABEL_24; + v9 = 0; + if ( nummissiles > 0 ) + { + do + { + if ( missile[missileactive[v9]]._mitype == 5 ) + v4 = 1; + ++v9; + } + while ( v9 < nummissiles ); + if ( v4 ) + { + LABEL_24: + if ( !(monster[v10].mMagicRes & 0x10) || monster[v10].MType->mtype == MT_DIABLO ) + return 0; + } + } + } + } + } + return result; +} + +BOOL __fastcall PosOkMonst2(int i, int x, int y) +{ + int v3; // edi + int v4; // ebx + signed int v5; // ebp + bool result; // eax + char v7; // dl + int v8; // edx + int v9; // ecx + int v10; // ecx + + v3 = x; + v4 = i; + v5 = 0; + result = SolidLoc(x, y) == 0; + if ( result ) + { + v7 = dObject[v3][y]; + if ( v7 ) + { + v8 = v7 <= 0 ? -1 - v7 : v7 - 1; + if ( object[v8]._oSolidFlag ) + result = 0; + } + if ( result ) + { + _LOBYTE(v9) = dMissile[v3][y]; + if ( (_BYTE)v9 ) + { + if ( v4 >= 0 ) + { + v9 = (char)v9; + if ( (char)v9 > 0 ) + { + if ( missile[v9]._mitype == 5 ) + goto LABEL_23; + v10 = 0; + if ( nummissiles > 0 ) + { + do + { + if ( missile[missileactive[v10]]._mitype == 5 ) + v5 = 1; + ++v10; + } + while ( v10 < nummissiles ); + if ( v5 ) + { + LABEL_23: + if ( !(monster[v4].mMagicRes & 0x10) || monster[v4].MType->mtype == MT_DIABLO ) + result = 0; + } + } + } + } + } + } + } + return result; +} + +BOOL __fastcall PosOkMonst3(int i, int x, int y) +{ + int v3; // esi + signed int v4; // ebp + char v5; // al + int v6; // eax + int v7; // eax + int v8; // ecx + int v9; // ecx + bool result; // eax + int v11; // ecx + signed int v12; // [esp+10h] [ebp-8h] + int v13; // [esp+14h] [ebp-4h] + + v12 = 0; + v3 = x; + v4 = 0; + v13 = i; + v5 = dObject[x][y]; + if ( v5 ) + { + if ( v5 <= 0 ) + v6 = -1 - v5; + else + v6 = v5 - 1; + v7 = v6; + v8 = object[v7]._otype; + v4 = 1; + if ( v8 != 1 + && v8 != OBJ_L1RDOOR + && v8 != OBJ_L2LDOOR + && v8 != OBJ_L2RDOOR + && v8 != OBJ_L3LDOOR + && v8 != OBJ_L3RDOOR ) + { + v4 = 0; + } + if ( object[v7]._oSolidFlag && !v4 ) + return 0; + } + if ( SolidLoc(x, y) && !v4 || dPlayer[v3][y] || dMonster[0][v3 * 112 + y] ) + return 0; + _LOBYTE(v9) = dMissile[v3][y]; + result = 1; + if ( (_BYTE)v9 ) + { + if ( v13 >= 0 ) + { + v9 = (char)v9; + if ( (char)v9 > 0 ) + { + if ( missile[v9]._mitype == 5 ) + goto LABEL_33; + v11 = 0; + if ( nummissiles > 0 ) + { + do + { + if ( missile[missileactive[v11]]._mitype == 5 ) + v12 = 1; + ++v11; + } + while ( v11 < nummissiles ); + if ( v12 ) + { + LABEL_33: + if ( !(monster[v13].mMagicRes & 0x10) || monster[v13].MType->mtype == MT_DIABLO ) + return 0; + } + } + } + } + } + return result; +} + +BOOL __fastcall IsSkel(int mt) +{ + return mt >= MT_WSKELAX && mt <= MT_XSKELAX + || mt >= MT_WSKELBW && mt <= MT_XSKELBW + || mt >= MT_WSKELSD && mt <= MT_XSKELSD; +} + +bool __fastcall IsGoat(int mt) +{ + return mt >= MT_NGOATMC && mt <= MT_GGOATMC || mt >= MT_NGOATBW && mt <= MT_GGOATBW; +} + +int __fastcall M_SpawnSkel(int x, int y, int dir) +{ + CMonster *v3; // ebx + CMonster *v4; // esi + int v5; // edx + int v7; // esi + //int v8; // edx + int v9; // eax + int v10; // esi + int xa; // [esp+Ch] [ebp-10h] + int ya; // [esp+10h] [ebp-Ch] + int v14; // [esp+14h] [ebp-8h] + int v15; // [esp+18h] [ebp-4h] + int v16; // [esp+18h] [ebp-4h] + + ya = y; + xa = x; + v5 = 0; + if ( nummtypes <= 0 ) + return -1; + v3 = Monsters; + v15 = nummtypes; + v4 = Monsters; + do + { + if ( IsSkel((unsigned char)v4->mtype) ) + ++v5; + ++v4; + --v15; + } + while ( v15 ); + if ( !v5 ) + return -1; + v7 = 0; + v14 = random(136, v5); + v16 = 0; + if ( nummtypes > 0 ) + { + do + { + if ( v16 > v14 ) + break; + if ( IsSkel((unsigned char)v3->mtype) ) + ++v16; + ++v7; + ++v3; + } + while ( v7 < nummtypes ); /* v8 */ + } + v9 = AddMonster(xa, ya, dir, v7 - 1, 1); + v10 = v9; + if ( v9 != -1 ) + M_StartSpStand(v9, dir); + return v10; +} + +void __fastcall ActivateSpawn(int i, int x, int y, int dir) +{ + int v4; // eax + + dMonster[0][y + 112 * x] = i + 1; + v4 = i; + monster[v4]._mx = x; + monster[v4]._mfutx = x; + monster[v4]._moldx = x; + monster[v4]._my = y; + monster[v4]._mfuty = y; + monster[v4]._moldy = y; + M_StartSpStand(i, dir); +} + +bool __fastcall SpawnSkeleton(int ii, int x, int y) +{ + int v3; // esi + int v4; // ebx + int v5; // ST04_4 + int v6; // ecx + int v7; // edi + int *v8; // esi + bool v9; // eax + int v11; // eax + int v12; // ecx + int v13; // edx + int v14; // esi + int v15; // edi + int v16; // ST04_4 + int monstok[9]; // [esp+Ch] [ebp-34h] + int i; // [esp+30h] [ebp-10h] + int x2; // [esp+34h] [ebp-Ch] + int v20; // [esp+38h] [ebp-8h] + int *v21; // [esp+3Ch] [ebp-4h] + int a3; // [esp+48h] [ebp+8h] + int a3a; // [esp+48h] [ebp+8h] + + i = ii; + v3 = x; + x2 = x; + if ( ii == -1 ) + return 0; + v4 = y; + if ( !PosOkMonst(-1, x, y) ) + { + v20 = 0; + v6 = y - 1; + a3 = y - 1; + if ( (unsigned char)(__OFSUB__(v4 - 1, v4 + 1) ^ 1) | (v4 - 1 == v4 + 1) ) + { + v21 = monstok; + do + { + v7 = v3 - 1; + if ( (unsigned char)(__OFSUB__(v3 - 1, v3 + 1) ^ 1) | (v3 - 1 == v3 + 1) ) + { + v8 = v21; + do + { + v9 = PosOkMonst(-1, v7, a3); + v20 |= v9; + *v8 = v9; + v8 += 3; + ++v7; + } + while ( v7 <= x2 + 1 ); + v3 = x2; + } + ++v21; + ++a3; + } + while ( a3 <= v4 + 1 ); + if ( v20 ) + { + v11 = random(137, 15); + v12 = 0; + v13 = 0; + a3a = v11 + 1; + if ( v11 + 1 > 0 ) + { + while ( 1 ) + { + if ( monstok[v13 + 2 * v12 + v12] ) + --a3a; + if ( a3a <= 0 ) + break; + if ( ++v12 == 3 ) + { + v12 = 0; + if ( ++v13 == 3 ) + v13 = 0; + } + } + } + v14 = v12 + v3 - 1; + v15 = v13 + v4 - 1; + v16 = GetDirection(v14, v15, x2, v4); + ActivateSpawn(i, v14, v15, v16); + return 1; + } + } + return 0; + } + v5 = GetDirection(v3, y, v3, y); + ActivateSpawn(i, v3, y, v5); + return 1; +} +// 43A879: using guessed type int var_34[9]; + +int __cdecl PreSpawnSkeleton() +{ + int skeltypes; // edx // should be i/j + int j; // edx // remove + int skel; // eax + int i; // [esp+10h] [ebp-4h] // should be skeltypes + + skeltypes = 0; + + if ( nummtypes <= 0 ) + return -1; + + for ( i = 0; i < nummtypes; i++ ) + { + if ( IsSkel(Monsters[i].mtype) ) + ++skeltypes; + } + + if ( !skeltypes ) + return -1; + + j = random(136, skeltypes); /* check this code -i integer is messed up*/ + skeltypes = 0; + + for ( i = 0; i < nummtypes; ++i ) + { + if ( skeltypes > j ) + break; + if ( IsSkel(Monsters[i].mtype) ) + ++skeltypes; + } + skel = AddMonster(0, 0, 0, i - 1, 0); + if ( skel != -1 ) + M_StartStand(skel, 0); + return skel; +} + +void __fastcall TalktoMonster(int i) +{ + int v1; // esi + MonsterStruct *v2; // esi + char v3; // al + int v4; // edi + //int v5; // eax + //int v6; // eax + int inv_item_num; // [esp+8h] [ebp-4h] + + v1 = i; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("TalktoMonster: Invalid monster %d", i); + v2 = &monster[v1]; + v3 = v2->_mAi; + v4 = v2->_menemy; + v2->_mmode = MM_TALK; + if ( v3 == AI_SNOTSPIL || v3 == AI_LACHDAN ) + { + //_LOBYTE(v5) = QuestStatus(7); + if ( QuestStatus(7) && quests[7]._qvar1 == 2 && PlrHasItem(v4, IDI_BANNER, &inv_item_num) ) + { + RemoveInvItem(v4, inv_item_num); + quests[7]._qactive = 3; + v2->mtalkmsg = QUEST_BANNER12; + _LOBYTE(v2->_mgoal) = 6; + } + //_LOBYTE(v6) = QuestStatus(4); + if ( QuestStatus(4) && v2->mtalkmsg >= (signed int)QUEST_VEIL9 ) + { + if ( PlrHasItem(v4, IDI_GLDNELIX, &inv_item_num) ) + { + RemoveInvItem(v4, inv_item_num); + v2->mtalkmsg = QUEST_VEIL11; + _LOBYTE(v2->_mgoal) = 6; + } + } + } +} + +void __fastcall SpawnGolum(int i, int x, int y, int mi) +{ + int v4; // edi + int v5; // ebx + int v6; // esi + int v7; // eax + int *v8; // edx + int v9; // eax + char v10; // cl + int v11; // eax + + v4 = i; + v5 = x; + if ( (unsigned int)i >= MAXMONSTERS ) + TermMsg("SpawnGolum: Invalid monster %d", i); + v6 = v4; + monster[v6]._mx = v5; + monster[v6]._my = y; + monster[v6]._mfuty = y; + monster[v6]._moldy = y; + monster[v6]._mfutx = v5; + monster[v6]._moldx = v5; + v7 = plr[v4]._pMaxMana; + dMonster[0][y + 112 * v5] = v4 + 1; + _LOBYTE(monster[v6]._pathcount) = 0; + monster[v6]._mFlags |= 0x20u; + v8 = &missile[mi]._mispllvl; + monster[v6].mArmorClass = 25; + v9 = 320 * *v8 + v7 / 3; + v10 = *(_BYTE *)v8; + _LOBYTE(v8) = plr[v4]._pLevel; + v9 *= 2; + monster[v6]._mmaxhp = v9; + monster[v6]._mhitpoints = v9; + monster[v6].mHit = 5 * (v10 + 8) + 2 * (_BYTE)v8; + monster[v6].mMinDamage = 2 * (v10 + 4); + monster[v6].mMaxDamage = 2 * (v10 + 8); + M_StartSpStand(v4, 0); + M_Enemy(v4); + if ( v4 == myplr ) + { + _LOBYTE(v11) = currlevel; + NetSendCmdGolem( + monster[v6]._mx, + monster[v6]._my, + monster[v6]._mdir, + monster[v6]._menemy, + monster[v6]._mhitpoints, + v11); + } +} + +bool __fastcall CanTalkToMonst(int m) +{ + int v1; // esi + char v2; // al + bool result; // al + + v1 = m; + if ( (unsigned int)m >= MAXMONSTERS ) + TermMsg("CanTalkToMonst: Invalid monster %d", m); + v2 = monster[v1]._mgoal; + if ( v2 == 6 ) + result = 1; + else + result = v2 == 7; + return result; +} + +BOOL __fastcall CheckMonsterHit(int m, BOOL *ret) +{ + if ( (DWORD)m >= MAXMONSTERS ) { + TermMsg("CheckMonsterHit: Invalid monster %d", m); + } + + if ( monster[m]._mAi == AI_GARG && monster[m]._mFlags & 4) { + monster[m]._mmode = MM_SATTACK; + monster[m]._mFlags &= 0xFFFFFFFB; + *ret = TRUE; + return TRUE; + } + + if ( monster[m].MType->mtype < MT_COUNSLR || monster[m].MType->mtype > MT_ADVOCATE || monster[m]._mgoal == 1 ) { + return FALSE; + } else { + *ret = FALSE; + } + + return TRUE; +} + +int __fastcall encode_enemy(int m) +{ + int v1; // ecx + int result; // eax + + v1 = m; + result = monster[v1]._menemy; + if ( monster[v1]._mFlags & 0x10 ) + result += 4; + return result; +} + +void __fastcall decode_enemy(int m, int enemy) +{ + int v2; // eax + int v3; // edx + char v4; // cl + int v5; // edx + + v2 = m; + if ( enemy >= 4 ) + { + monster[v2]._mFlags |= 0x10u; + v5 = enemy - 4; + monster[v2]._menemy = v5; + monster[v2]._menemyx = monster[v5]._mfutx; + v4 = monster[v5]._mfuty; + } + else + { + monster[v2]._mFlags &= 0xFFFFFFEF; + monster[v2]._menemy = enemy; + v3 = enemy; + monster[v2]._menemyx = plr[v3]._px; + v4 = plr[v3]._py; + } + monster[v2]._menemyy = v4; +} diff --git a/Source/monster.h b/Source/monster.h new file mode 100644 index 000000000..783a0ae8f --- /dev/null +++ b/Source/monster.h @@ -0,0 +1,195 @@ +//HEADER_GOES_HERE +#ifndef __MONSTER_H__ +#define __MONSTER_H__ + +extern int MissileFileFlag; // weak +extern int monster_cpp_init_value; // weak +extern int monstkills[MAXMONSTERS]; +extern int monstactive[MAXMONSTERS]; +extern int nummonsters; +extern int sgbSaveSoundOn; // weak +extern MonsterStruct monster[MAXMONSTERS]; +extern int totalmonsters; // weak +extern CMonster Monsters[16]; +// int END_Monsters_17; // weak +extern int monstimgtot; // weak +extern int uniquetrans; +extern int nummtypes; + +void __cdecl monster_cpp_init(); +void __fastcall InitMonsterTRN(int monst, BOOL special); +void __cdecl InitLevelMonsters(); +int __fastcall AddMonsterType(int type, int placeflag); +void __cdecl GetLevelMTypes(); +void __fastcall InitMonsterGFX(int monst); +void __fastcall ClearMVars(int i); +void __fastcall InitMonster(int i, int rd, int mtype, int x, int y); +void __cdecl ClrAllMonsters(); +BOOL __fastcall MonstPlace(int xp, int yp); +void __fastcall PlaceMonster(int i, int mtype, int x, int y); +void __fastcall PlaceUniqueMonst(int uniqindex, int miniontype, int unpackfilesize); +void __cdecl PlaceQuestMonsters(); +void __fastcall PlaceGroup(int mtype, int num, int leaderf, int leader); +void __cdecl LoadDiabMonsts(); +void __cdecl InitMonsters(); +void __cdecl PlaceUniques(); +void __fastcall SetMapMonsters(unsigned char *pMap, int startx, int starty); +void __fastcall DeleteMonster(int i); +int __fastcall AddMonster(int x, int y, int dir, int mtype, int InMap); +void __fastcall NewMonsterAnim(int i, AnimStruct *anim, int md); +bool __fastcall M_Ranged(int i); +bool __fastcall M_Talker(int i); +void __fastcall M_Enemy(int i); +int __fastcall M_GetDir(int i); +void __fastcall M_CheckEFlag(int i); +void __fastcall M_StartStand(int i, int md); +void __fastcall M_StartDelay(int i, int len); +void __fastcall M_StartSpStand(int i, int md); +void __fastcall M_StartWalk(int i, int xvel, int yvel, int xadd, int yadd, int EndDir); +void __fastcall M_StartWalk2(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int EndDir); +void __fastcall M_StartWalk3(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int mapx, int mapy, int EndDir); +void __fastcall M_StartAttack(int i); +void __fastcall M_StartRAttack(int i, int missile_type, int dam); +void __fastcall M_StartRSpAttack(int i, int missile_type, int dam); +void __fastcall M_StartSpAttack(int i); +void __fastcall M_StartEat(int i); +void __fastcall M_ClearSquares(int i); +void __fastcall M_GetKnockback(int i); +void __fastcall M_StartHit(int i, int pnum, int dam); +void __fastcall M_DiabloDeath(int i, unsigned char sendmsg); +void __fastcall M2MStartHit(int mid, int i, int dam); +void __fastcall MonstStartKill(int i, int pnum, unsigned char sendmsg); +void __fastcall M2MStartKill(int i, int mid); +void __fastcall M_StartKill(int i, int pnum); +void __fastcall M_SyncStartKill(int i, int x, int y, int pnum); +void __fastcall M_StartFadein(int i, int md, unsigned char backwards); +void __fastcall M_StartFadeout(int i, int md, unsigned char backwards); +void __fastcall M_StartHeal(int i); +void __fastcall M_ChangeLightOffset(int monst); +int __fastcall M_DoStand(int i); +int __fastcall M_DoWalk(int i); +int __fastcall M_DoWalk2(int i); +int __fastcall M_DoWalk3(int i); +void __fastcall M_TryM2MHit(int i, int mid, int hper, int mind, int maxd); +void __fastcall M_TryH2HHit(int i, int pnum, int Hit, int MinDam, int MaxDam); +int __fastcall M_DoAttack(int i); +int __fastcall M_DoRAttack(int i); +int __fastcall M_DoRSpAttack(int i); +int __fastcall M_DoSAttack(int i); +int __fastcall M_DoFadein(int i); +int __fastcall M_DoFadeout(int i); +int __fastcall M_DoHeal(int i); +int __fastcall M_DoTalk(int i); +void __fastcall M_Teleport(int i); +int __fastcall M_DoGotHit(int i); +void __fastcall M_UpdateLeader(int i); +void __cdecl DoEnding(); +void __cdecl PrepDoEnding(); +int __fastcall M_DoDeath(int i); +int __fastcall M_DoSpStand(int i); +int __fastcall M_DoDelay(int i); +int __fastcall M_DoStone(int i); +void __fastcall M_WalkDir(int i, int md); +void __fastcall GroupUnity(int i); +bool __fastcall M_CallWalk(int i, int md); +bool __fastcall M_PathWalk(int i); +bool __fastcall M_CallWalk2(int i, int md); +bool __fastcall M_DumbWalk(int i, int md); +bool __fastcall M_RoundWalk(int i, int md, int *dir); +void __fastcall MAI_Zombie(int i); +void __fastcall MAI_SkelSd(int i); +bool __fastcall MAI_Path(int i); +void __fastcall MAI_Snake(int i); +void __fastcall MAI_Bat(int i); +void __fastcall MAI_SkelBow(int i); +void __fastcall MAI_Fat(int i); +void __fastcall MAI_Sneak(int i); +void __fastcall MAI_Fireman(int i); +void __fastcall MAI_Fallen(int i); +void __fastcall MAI_Cleaver(int i); +void __fastcall MAI_Round(int i, unsigned char special); +void __fastcall MAI_GoatMc(int i); +void __fastcall MAI_Ranged(int i, int missile_type, unsigned char special); +void __fastcall MAI_GoatBow(int i); +void __fastcall MAI_Succ(int i); +void __fastcall MAI_AcidUniq(int i); +void __fastcall MAI_Scav(int i); +void __fastcall MAI_Garg(int i); +void __fastcall MAI_RoundRanged(int i, int missile_type, unsigned char checkdoors, int dam, int lessmissiles); +void __fastcall MAI_Magma(int i); +void __fastcall MAI_Storm(int i); +void __fastcall MAI_Acid(int i); +void __fastcall MAI_Diablo(int i); +void __fastcall MAI_RR2(int i, int mistype, int dam); +void __fastcall MAI_Mega(int i); +void __fastcall MAI_Golum(int i); +void __fastcall MAI_SkelKing(int i); +void __fastcall MAI_Rhino(int i); +void __fastcall MAI_Counselor(int i); +void __fastcall MAI_Garbud(int i); +void __fastcall MAI_Zhar(int i); +void __fastcall MAI_SnotSpil(int i); +void __fastcall MAI_Lazurus(int i); +void __fastcall MAI_Lazhelp(int i); +void __fastcall MAI_Lachdanan(int i); +void __fastcall MAI_Warlord(int i); +void __cdecl DeleteMonsterList(); +void __cdecl ProcessMonsters(); +void __cdecl FreeMonsters(); +bool __fastcall DirOK(int i, int mdir); +BOOL __fastcall PosOkMissile(int x, int y); +BOOL __fastcall CheckNoSolid(int x, int y); +BOOL __fastcall LineClearF(BOOL (__fastcall *Clear)(int, int), int x1, int y1, int x2, int y2); +BOOL __fastcall LineClear(int x1, int y1, int x2, int y2); +BOOL __fastcall LineClearF1(BOOL (__fastcall *Clear)(int, int, int), int monst, int x1, int y1, int x2, int y2); +void __fastcall SyncMonsterAnim(int i); +void __fastcall M_FallenFear(int x, int y); +void __fastcall PrintMonstHistory(int mt); +void __cdecl PrintUniqueHistory(); +void __fastcall MissToMonst(int i, int x, int y); +BOOL __fastcall PosOkMonst(int i, int x, int y); +BOOL __fastcall PosOkMonst2(int i, int x, int y); +BOOL __fastcall PosOkMonst3(int i, int x, int y); +BOOL __fastcall IsSkel(int mt); +bool __fastcall IsGoat(int mt); +int __fastcall M_SpawnSkel(int x, int y, int dir); +void __fastcall ActivateSpawn(int i, int x, int y, int dir); +bool __fastcall SpawnSkeleton(int ii, int x, int y); +int __cdecl PreSpawnSkeleton(); +void __fastcall TalktoMonster(int i); +void __fastcall SpawnGolum(int i, int x, int y, int mi); +bool __fastcall CanTalkToMonst(int m); +BOOL __fastcall CheckMonsterHit(int m, BOOL *ret); +int __fastcall encode_enemy(int m); +void __fastcall decode_enemy(int m, int enemy); + +/* rdata */ + +extern const int monster_inf; // weak +extern const char plr2monst[9]; +extern const unsigned char counsmiss[4]; + +/* data */ + +extern MonsterData monsterdata[112]; +extern char MonstConvTbl[128]; +extern unsigned char MonstAvailTbl[112]; +extern UniqMonstStruct UniqMonst[98]; +extern int MWVel[24][3]; +extern char animletter[7]; +extern int left[8]; +extern int right[8]; +extern int opposite[8]; +extern int offset_x[8]; +extern int offset_y[8]; + +/* unused */ +extern int rnd5[4]; +extern int rnd10[4]; +extern int rnd20[4]; +extern int rnd60[4]; +// + +extern void (__fastcall *AiProc[])(int i); + +#endif /* __MONSTER_H__ */ diff --git a/Source/movie.cpp b/Source/movie.cpp new file mode 100644 index 000000000..cbe2b5db4 --- /dev/null +++ b/Source/movie.cpp @@ -0,0 +1,91 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int movie_cpp_init_value; // weak +char movie_playing; // weak +BOOL loop_movie; // weak + +const int movie_inf = 0x7F800000; // weak + +struct movie_cpp_init +{ + movie_cpp_init() + { + movie_cpp_init_value = movie_inf; + } +} _movie_cpp_init; +// 47F144: using guessed type int movie_inf; +// 659AF4: using guessed type int movie_cpp_init_value; + +void __fastcall play_movie(char *pszMovie, BOOL user_can_close) +{ + char *v2; // esi + WNDPROC saveProc; // edi + //int v4; // eax + MSG Msg; // [esp+8h] [ebp-24h] + BOOL v6; // [esp+24h] [ebp-8h] + void *video_stream; // [esp+28h] [ebp-4h] + + v6 = user_can_close; + v2 = pszMovie; + if ( gbActive ) + { + saveProc = SetWindowProc(MovieWndProc); + InvalidateRect(ghMainWnd, 0, 0); + UpdateWindow(ghMainWnd); + movie_playing = 1; + sound_disable_music(1); + sfx_stop(); + effects_play_sound("Sfx\\Misc\\blank.wav"); + SVidPlayBegin(v2, 0, 0, 0, 0, loop_movie != 0 ? 0x100C0808 : 0x10280808, &video_stream); + if ( video_stream ) + { + do + { + if ( !gbActive || v6 && !movie_playing ) + break; + while ( PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) ) + { + if ( Msg.message != WM_QUIT ) + { + TranslateMessage(&Msg); + DispatchMessage(&Msg); + } + } + //_LOBYTE(v4) = SVidPlayContinue(); + if ( !SVidPlayContinue() ) + break; + } + while ( video_stream ); + if ( video_stream ) + SVidPlayEnd(video_stream); + } + SetWindowProc(saveProc); + sound_disable_music(0); + } +} +// 634980: using guessed type int gbActive; +// 659AF8: using guessed type int movie_playing; +// 659AFC: using guessed type int loop_movie; + +LRESULT __stdcall MovieWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + if ( Msg == WM_KEYFIRST || Msg == WM_CHAR ) + { +LABEL_6: + movie_playing = 0; + return MainWndProc(hWnd, Msg, wParam, lParam); + } + if ( Msg != WM_SYSCOMMAND ) + { + if ( Msg != WM_LBUTTONDOWN && Msg != WM_RBUTTONDOWN ) + return MainWndProc(hWnd, Msg, wParam, lParam); + goto LABEL_6; + } + if ( wParam != SC_CLOSE ) + return MainWndProc(hWnd, Msg, wParam, lParam); + movie_playing = 0; + return 0; +} +// 659AF8: using guessed type int movie_playing; diff --git a/Source/movie.h b/Source/movie.h new file mode 100644 index 000000000..04295d87e --- /dev/null +++ b/Source/movie.h @@ -0,0 +1,17 @@ +//HEADER_GOES_HERE +#ifndef __MOVIE_H__ +#define __MOVIE_H__ + +extern int movie_cpp_init_value; // weak +extern char movie_playing; // weak +extern BOOL loop_movie; // weak + +void __cdecl movie_cpp_init(); +void __fastcall play_movie(char *pszMovie, BOOL user_can_close); +LRESULT __stdcall MovieWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); + +/* rdata */ + +extern const int movie_inf; // weak + +#endif /* __MOVIE_H__ */ diff --git a/Source/mpqapi.cpp b/Source/mpqapi.cpp new file mode 100644 index 000000000..9e0b68119 --- /dev/null +++ b/Source/mpqapi.cpp @@ -0,0 +1,809 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int mpqapi_cpp_init_value; // weak + +#ifndef NO_GLOBALS +int sgdwMpqOffset; // idb +char mpq_buf[4096]; +_HASHENTRY *sgpHashTbl; +bool save_archive_modified; // weak +_BLOCKENTRY *sgpBlockTbl; +bool save_archive_open; // weak +#endif + +const int mpqapi_inf = 0x7F800000; // weak + +//note: 32872 = 32768 + 104 (sizeof(_FILEHEADER)) + +/* data */ + +#ifndef NO_GLOBALS +HANDLE sghArchive = (HANDLE)0xFFFFFFFF; // idb +#endif + +struct mpqapi_cpp_init +{ + mpqapi_cpp_init() + { + mpqapi_cpp_init_value = mpqapi_inf; + } +} _mpqapi_cpp_init; +// 47F148: using guessed type int mpqapi_inf; +// 659B00: using guessed type int mpqapi_cpp_init_value; + +bool __fastcall mpqapi_set_hidden(char *pszArchive, bool hidden) +{ + char *v2; // edi + BOOL v3; // esi + DWORD v4; // eax + bool result; // al + DWORD v6; // esi + + v2 = pszArchive; + v3 = hidden; + v4 = GetFileAttributes(pszArchive); + if ( v4 == -1 ) + return GetLastError() == ERROR_FILE_NOT_FOUND; + v6 = v3 != 0 ? FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN : 0; + if ( v4 == v6 ) + result = 1; + else + result = SetFileAttributes(v2, v6); + return result; +} + +void __fastcall mpqapi_store_creation_time(char *pszArchive, int dwChar) +{ + int v2; // esi + char *v3; // ebx + HANDLE v4; // eax + int v5; // esi + struct _WIN32_FIND_DATAA FindFileData; // [esp+8h] [ebp-1E0h] + char dst[160]; // [esp+148h] [ebp-A0h] + + v2 = dwChar; + v3 = pszArchive; + if ( gbMaxPlayers != 1 ) + { + mpqapi_reg_load_modification_time(dst, 160); + v4 = FindFirstFile(v3, &FindFileData); + if ( v4 != (HANDLE)-1 ) + { + FindClose(v4); + v5 = 16 * v2; + *(_DWORD *)&dst[v5] = FindFileData.ftCreationTime.dwLowDateTime; + *(_DWORD *)&dst[v5 + 4] = FindFileData.ftCreationTime.dwHighDateTime; + mpqapi_reg_store_modification_time(dst, 160); + } + } +} +// 679660: using guessed type char gbMaxPlayers; + +bool __fastcall mpqapi_reg_load_modification_time(char *dst, int size) +{ + unsigned int v2; // esi + char *v3; // edi + unsigned int v6; // esi + char *v7; // ecx + int nbytes_read; // [esp+8h] [ebp-4h] + + v2 = size; + v3 = dst; + memset(dst, 0, size); + if ( !SRegLoadData("Diablo", "Video Player ", 0, (unsigned char *)v3, v2, (unsigned long *)&nbytes_read) || nbytes_read != v2 ) + return 0; + if ( v2 >= 8 ) + { + v6 = v2 >> 3; + do + { + v7 = v3; + v3 += 8; + mpqapi_xor_buf(v7); + --v6; + } + while ( v6 ); + } + return 1; +} + +void __fastcall mpqapi_xor_buf(char *pbData) +{ + signed int v1; // eax + char *v2; // esi + signed int v3; // edi + + v1 = 0xF0761AB; + v2 = pbData; + v3 = 8; + do + { + *v2 ^= v1; + ++v2; + v1 = _rotl(v1, 1); + --v3; + } + while ( v3 ); +} + +bool __fastcall mpqapi_reg_store_modification_time(char *pbData, int dwLen) +{ + int v2; // ebx + char *v3; // ebp + char *v4; // edi + unsigned int v5; // esi + char *v6; // ecx + + v2 = dwLen; + v3 = pbData; + v4 = pbData; + if ( (unsigned int)dwLen >= 8 ) + { + v5 = (unsigned int)dwLen >> 3; + do + { + v6 = v4; + v4 += 8; + mpqapi_xor_buf(v6); + --v5; + } + while ( v5 ); + } + return SRegSaveData("Diablo", "Video Player ", 0, (unsigned char *)v3, v2); +} + +void __fastcall mpqapi_remove_hash_entry(char *pszName) +{ + int v1; // eax + _HASHENTRY *v2; // ecx + _BLOCKENTRY *v3; // eax + int v4; // esi + int v5; // edi + + v1 = mpqapi_get_hash_index_of_path(pszName); + if ( v1 != -1 ) + { + v2 = &sgpHashTbl[v1]; + v3 = &sgpBlockTbl[v2->block]; + v2->block = -2; + v4 = v3->offset; + v5 = v3->sizealloc; + memset(v3, 0, 0x10u); + mpqapi_free_block(v4, v5); + save_archive_modified = 1; + } +} +// 65AB0C: using guessed type int save_archive_modified; + +void __fastcall mpqapi_free_block(int block_offset, int block_size) +{ + int v2; // esi + int v3; // edi + _BLOCKENTRY *v4; // eax + signed int v5; // edx + signed int v6; // ecx + int v7; // ecx + bool v8; // zf + _BLOCKENTRY *v9; // eax + + v2 = block_size; + v3 = block_offset; +LABEL_2: + v4 = sgpBlockTbl; + v5 = 2048; + while ( 1 ) + { + v6 = v5--; + if ( !v6 ) + break; + v7 = v4->offset; + if ( v4->offset && !v4->flags && !v4->sizefile ) + { + if ( v7 + v4->sizealloc == v3 ) + { + v3 = v4->offset; +LABEL_11: + v2 += v4->sizealloc; + memset(v4, 0, 0x10u); + goto LABEL_2; + } + if ( v3 + v2 == v7 ) + goto LABEL_11; + } + ++v4; + } + v8 = v3 + v2 == sgdwMpqOffset; + if ( v3 + v2 > sgdwMpqOffset ) + { + TermMsg("MPQ free list error"); + v8 = v3 + v2 == sgdwMpqOffset; + } + if ( v8 ) + { + sgdwMpqOffset = v3; + } + else + { + v9 = mpqapi_new_block(0); + v9->offset = v3; + v9->sizealloc = v2; + v9->sizefile = 0; + v9->flags = 0; + } +} + +_BLOCKENTRY *__fastcall mpqapi_new_block(int *block_index) +{ + _BLOCKENTRY *result; // eax + unsigned int v2; // edx + + result = sgpBlockTbl; + v2 = 0; + while ( result->offset || result->sizealloc || result->flags || result->sizefile ) + { + ++v2; + ++result; + if ( v2 >= 0x800 ) + { + TermMsg("Out of free block entries"); + return 0; + } + } + if ( block_index ) + *block_index = v2; + return result; +} + +int __fastcall mpqapi_get_hash_index_of_path(char *pszName) // FetchHandle +{ + char *v1; // esi + int v2; // ST00_4 + int v3; // edi + short v4; // ax + + v1 = pszName; + v2 = encrypt_hash(pszName, 2); // MPQ_HASH_NAME_B + v3 = encrypt_hash(v1, 1); // MPQ_HASH_NAME_A + v4 = encrypt_hash(v1, 0); // MPQ_HASH_TABLE_INDEX + return mpqapi_get_hash_index(v4, v3, v2, 0); +} + +int __fastcall mpqapi_get_hash_index(short index, int hash_a, int hash_b, int locale) +{ + int v4; // ecx + signed int v5; // eax + signed int v6; // edx + _HASHENTRY *v7; // ecx + int v8; // edi + int v10; // [esp+Ch] [ebp-8h] + int i; // [esp+10h] [ebp-4h] + + v4 = index & 0x7FF; + v10 = hash_a; + v5 = 2048; + for ( i = v4; ; i = (i + 1) & 0x7FF ) + { + v7 = &sgpHashTbl[v4]; + v8 = v7->block; + if ( v8 == -1 ) + return -1; + v6 = v5--; + if ( !v6 ) + return -1; + if ( v7->hashcheck[0] == v10 && v7->hashcheck[1] == hash_b && v7->lcid == locale && v8 != -2 ) + break; + v4 = (i + 1) & 0x7FF; + } + return i; +} + +void __fastcall mpqapi_remove_hash_entries(bool (__stdcall *fnGetName)(int, char *)) +{ + bool (__stdcall *v1)(int, char *); // edi + signed int v2; // esi + int i; // eax + int v4; // eax + char v5[260]; // [esp+8h] [ebp-104h] + + v1 = fnGetName; + v2 = 1; + for ( i = fnGetName(0, v5); i; i = v1(v4, v5) ) + { + mpqapi_remove_hash_entry(v5); + v4 = v2++; + } +} + +bool __fastcall mpqapi_write_file(char *pszName, char *pbData, int dwLen) +{ + char *v3; // edi + char *v4; // esi + _BLOCKENTRY *v5; // eax + + v3 = pbData; + v4 = pszName; + save_archive_modified = 1; + mpqapi_remove_hash_entry(pszName); + v5 = mpqapi_add_file(v4, 0, 0); + if ( mpqapi_write_file_contents(v4, v3, dwLen, v5) ) + return 1; + mpqapi_remove_hash_entry(v4); + return 0; +} +// 65AB0C: using guessed type int save_archive_modified; + +_BLOCKENTRY *__fastcall mpqapi_add_file(char *pszName, _BLOCKENTRY *pBlk, int block_index) +{ + char *v3; // edi + short v4; // si + int v5; // ebx + signed int v6; // edx + int v7; // esi + int v8; // ecx + int v9; // esi + int v11; // [esp+Ch] [ebp-8h] + _BLOCKENTRY *v12; // [esp+10h] [ebp-4h] + + v12 = pBlk; + v3 = pszName; + v4 = encrypt_hash(pszName, 0); + v5 = encrypt_hash(v3, 1); + v11 = encrypt_hash(v3, 2); + if ( mpqapi_get_hash_index(v4, v5, v11, 0) != -1 ) + TermMsg("Hash collision between \"%s\" and existing file\n", v3); + v6 = 2048; + v7 = v4 & 0x7FF; + while ( 1 ) + { + --v6; + v8 = sgpHashTbl[v7].block; + if ( v8 == -1 || v8 == -2 ) + break; + v7 = (v7 + 1) & 0x7FF; + if ( !v6 ) + { + v6 = -1; + break; + } + } + if ( v6 < 0 ) + TermMsg("Out of hash space"); + if ( !v12 ) + v12 = mpqapi_new_block(&block_index); + v9 = v7; + sgpHashTbl[v9].hashcheck[0] = v5; + sgpHashTbl[v9].hashcheck[1] = v11; + sgpHashTbl[v9].lcid = 0; + sgpHashTbl[v9].block = block_index; + return v12; +} + +bool __fastcall mpqapi_write_file_contents(char *pszName, char *pbData, int dwLen, _BLOCKENTRY *pBlk) +{ + char *v4; // esi + char *v5; // eax + unsigned int destsize; // ebx + char *v7; // eax + unsigned int v8; // esi + _BLOCKENTRY *v9; // edi + int v10; // eax + signed int v11; // eax + unsigned int v13; // eax + unsigned int v14; // eax + int v15; // ecx + int size; // [esp+Ch] [ebp-10h] + char *v17; // [esp+10h] [ebp-Ch] + int v18; // [esp+14h] [ebp-8h] + DWORD nNumberOfBytesToWrite; // [esp+18h] [ebp-4h] + + v4 = pszName; + v17 = pbData; + v5 = strchr(pszName, ':'); + destsize = 0; + while ( v5 ) + { + v4 = v5 + 1; + v5 = strchr(v5 + 1, ':'); + } + while ( 1 ) + { + v7 = strchr(v4, '\\'); + if ( !v7 ) + break; + v4 = v7 + 1; + } + encrypt_hash(v4, 3); + v8 = dwLen; + v9 = pBlk; + size = 4 * ((unsigned int)(dwLen + 4095) >> 12) + 4; + nNumberOfBytesToWrite = 4 * ((unsigned int)(dwLen + 4095) >> 12) + 4; + v10 = mpqapi_find_free_block(size + dwLen, &pBlk->sizealloc); + v9->offset = v10; + v9->sizefile = v8; + v9->flags = 0x80000100; + if ( SetFilePointer(sghArchive, v10, NULL, FILE_BEGIN) == -1 ) + return 0; + pBlk = 0; + v18 = 0; + while ( v8 ) + { + v11 = 0; + do + mpq_buf[v11++] -= 86; + while ( v11 < 4096 ); + dwLen = v8; + if ( v8 >= 0x1000 ) + dwLen = 4096; + memcpy(mpq_buf, v17, dwLen); + v17 += dwLen; + dwLen = encrypt_compress(mpq_buf, dwLen); + if ( !v18 ) + { + nNumberOfBytesToWrite = size; + pBlk = (_BLOCKENTRY *)DiabloAllocPtr(size); + memset(pBlk, 0, nNumberOfBytesToWrite); + if ( !WriteFile(sghArchive, pBlk, nNumberOfBytesToWrite, &nNumberOfBytesToWrite, 0) ) + goto LABEL_25; + destsize += nNumberOfBytesToWrite; + } + *(&pBlk->offset + v18) = destsize; + if ( !WriteFile(sghArchive, mpq_buf, dwLen, (LPDWORD)&dwLen, 0) ) + goto LABEL_25; + ++v18; + if ( v8 <= 0x1000 ) + v8 = 0; + else + v8 -= 4096; + destsize += dwLen; + } + *(&pBlk->offset + v18) = destsize; + if ( SetFilePointer(sghArchive, -destsize, NULL, FILE_CURRENT) == -1 + || !WriteFile(sghArchive, pBlk, nNumberOfBytesToWrite, &nNumberOfBytesToWrite, 0) + || SetFilePointer(sghArchive, destsize - nNumberOfBytesToWrite, NULL, FILE_CURRENT) == -1 ) + { +LABEL_25: + if ( pBlk ) + mem_free_dbg(pBlk); + return 0; + } + mem_free_dbg(pBlk); + v13 = v9->sizealloc; + if ( destsize < v13 ) + { + v14 = v13 - destsize; + if ( v14 >= 0x400 ) + { + v15 = destsize + v9->offset; + v9->sizealloc = destsize; + mpqapi_free_block(v15, v14); + } + } + return 1; +} + +int __fastcall mpqapi_find_free_block(int size, int *block_size) +{ + _BLOCKENTRY *v2; // eax + signed int v3; // esi + int result; // eax + int v5; // esi + bool v6; // zf + + v2 = sgpBlockTbl; + v3 = 2048; + while ( 1 ) + { + --v3; + if ( v2->offset ) + { + if ( !v2->flags && !v2->sizefile && v2->sizealloc >= (unsigned int)size ) + break; + } + ++v2; + if ( !v3 ) + { + *block_size = size; + result = sgdwMpqOffset; + sgdwMpqOffset += size; + return result; + } + } + v5 = v2->offset; + *block_size = size; + v2->offset += size; + v6 = v2->sizealloc == size; + v2->sizealloc -= size; + if ( v6 ) + memset(v2, 0, 0x10u); + return v5; +} + +void __fastcall mpqapi_rename(char *pszOld, char *pszNew) +{ + char *v2; // esi + int v3; // eax + _HASHENTRY *v4; // eax + int v5; // ST00_4 + _BLOCKENTRY *v6; // edx + + v2 = pszNew; + v3 = mpqapi_get_hash_index_of_path(pszOld); + if ( v3 != -1 ) + { + v4 = &sgpHashTbl[v3]; + v5 = v4->block; + v6 = &sgpBlockTbl[v5]; + v4->block = -2; + mpqapi_add_file(v2, v6, v5); + save_archive_modified = 1; + } +} +// 65AB0C: using guessed type int save_archive_modified; + +bool __fastcall mpqapi_has_file(char *pszName) +{ + return mpqapi_get_hash_index_of_path(pszName) != -1; +} + +bool __fastcall mpqapi_open_archive(char *pszArchive, bool hidden, int dwChar) // OpenMPQ +{ + char *v3; // ebp + BOOL v4; // esi + DWORD v6; // edi + int v8; // eax + int v10; // eax + char *lpFileName; // [esp+10h] [ebp-70h] + DWORD dwTemp; // [esp+14h] [ebp-6Ch] + _FILEHEADER fhdr; // [esp+18h] [ebp-68h] + + v3 = pszArchive; + v4 = hidden; + lpFileName = pszArchive; + encrypt_init_lookup_table(); + if ( !mpqapi_set_hidden(v3, v4) ) + return 0; + v6 = (unsigned char)gbMaxPlayers > 1u ? FILE_FLAG_WRITE_THROUGH : 0; + save_archive_open = 0; + sghArchive = CreateFile(v3, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, v6, NULL); + if ( sghArchive == (HANDLE)-1 ) + { + sghArchive = CreateFile(lpFileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, v6 | (v4 != 0 ? FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN : 0), NULL); + if ( sghArchive == (HANDLE)-1 ) + return 0; + save_archive_open = 1; + save_archive_modified = 1; + } + if ( !sgpBlockTbl || !sgpHashTbl ) + { + memset(&fhdr, 0, 0x68u); + if ( !mpqapi_parse_archive_header(&fhdr, &sgdwMpqOffset) ) + { +LABEL_15: + mpqapi_close_archive(lpFileName, 1, dwChar); + return 0; + } + sgpBlockTbl = (_BLOCKENTRY *)DiabloAllocPtr(0x8000); + memset(sgpBlockTbl, 0, 0x8000u); + if ( fhdr.blockcount ) + { + if ( SetFilePointer(sghArchive, 104, NULL, FILE_BEGIN) == -1 + || !ReadFile(sghArchive, sgpBlockTbl, 0x8000u, &dwTemp, NULL) ) + { + goto LABEL_15; + } + v8 = encrypt_hash("(block table)", 3); + encrypt_decrypt_block(sgpBlockTbl, 0x8000, v8); + } + sgpHashTbl = (_HASHENTRY *)DiabloAllocPtr(0x8000); + memset(sgpHashTbl, 255, 0x8000u); + if ( fhdr.hashcount ) + { + if ( SetFilePointer(sghArchive, 32872, NULL, FILE_BEGIN) == -1 + || !ReadFile(sghArchive, sgpHashTbl, 0x8000u, &dwTemp, NULL) ) + { + goto LABEL_15; + } + v10 = encrypt_hash("(hash table)", 3); + encrypt_decrypt_block(sgpHashTbl, 0x8000, v10); + } + } + return 1; +} +// 65AB0C: using guessed type int save_archive_modified; +// 65AB14: using guessed type char save_archive_open; +// 679660: using guessed type char gbMaxPlayers; + +bool __fastcall mpqapi_parse_archive_header(_FILEHEADER *pHdr, int *pdwNextFileStart) // ParseMPQHeader +{ + int *v2; // ebp + _FILEHEADER *v3; // esi + DWORD v4; // eax + DWORD v5; // edi + DWORD NumberOfBytesRead; // [esp+10h] [ebp-4h] + + v2 = pdwNextFileStart; + v3 = pHdr; + v4 = GetFileSize(sghArchive, 0); + v5 = v4; + *v2 = v4; + if ( v4 == -1 + || v4 < 0x68 + || !ReadFile(sghArchive, v3, 0x68u, &NumberOfBytesRead, NULL) + || NumberOfBytesRead != 104 + || v3->signature != '\x1AQPM' + || v3->headersize != 32 + || v3->version > 0u + || v3->sectorsizeid != 3 + || v3->filesize != v5 + || v3->hashoffset != 32872 + || v3->blockoffset != 104 + || v3->hashcount != 2048 + || v3->blockcount != 2048 ) + { + if ( SetFilePointer(sghArchive, 0, NULL, FILE_BEGIN) == -1 || !SetEndOfFile(sghArchive) ) + return 0; + memset(v3, 0, 0x68u); + v3->signature = '\x1AQPM'; + v3->headersize = 32; + v3->sectorsizeid = 3; + v3->version = 0; + *v2 = 0x10068; + save_archive_modified = 1; + save_archive_open = 1; + } + return 1; +} +// 65AB0C: using guessed type int save_archive_modified; +// 65AB14: using guessed type char save_archive_open; + +void __fastcall mpqapi_close_archive(char *pszArchive, bool bFree, int dwChar) // CloseMPQ +{ + char *v3; // esi + _BLOCKENTRY *v4; // ecx + _HASHENTRY *v5; // ecx + + v3 = pszArchive; + if ( bFree ) + { + v4 = sgpBlockTbl; + sgpBlockTbl = 0; + mem_free_dbg(v4); + v5 = sgpHashTbl; + sgpHashTbl = 0; + mem_free_dbg(v5); + } + if ( sghArchive != (HANDLE)-1 ) + { + CloseHandle(sghArchive); + sghArchive = (HANDLE)-1; + } + if ( save_archive_modified ) + { + save_archive_modified = 0; + mpqapi_store_modified_time(v3, dwChar); + } + if ( save_archive_open ) + { + save_archive_open = 0; + mpqapi_store_creation_time(v3, dwChar); + } +} +// 65AB0C: using guessed type int save_archive_modified; +// 65AB14: using guessed type char save_archive_open; + +void __fastcall mpqapi_store_modified_time(char *pszArchive, int dwChar) +{ + int v2; // esi + char *v3; // ebx + HANDLE v4; // eax + int v5; // esi + struct _WIN32_FIND_DATAA FindFileData; // [esp+8h] [ebp-1E0h] + char dst[160]; // [esp+148h] [ebp-A0h] + + v2 = dwChar; + v3 = pszArchive; + if ( gbMaxPlayers != 1 ) + { + mpqapi_reg_load_modification_time(dst, 160); + v4 = FindFirstFile(v3, &FindFileData); + if ( v4 != (HANDLE)-1 ) + { + FindClose(v4); + v5 = 16 * v2; + *(_DWORD *)&dst[v5 + 8] = FindFileData.ftLastWriteTime.dwLowDateTime; + *(_DWORD *)&dst[v5 + 12] = FindFileData.ftLastWriteTime.dwHighDateTime; + mpqapi_reg_store_modification_time(dst, 160); + } + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall mpqapi_flush_and_close(char *pszArchive, bool bFree, int dwChar) +{ + if ( sghArchive != (HANDLE)-1 ) + { + if ( save_archive_modified ) + { + if ( mpqapi_can_seek() ) + { + if ( mpqapi_write_header() ) + { + if ( mpqapi_write_block_table() ) + mpqapi_write_hash_table(); + } + } + } + } + mpqapi_close_archive(pszArchive, bFree, dwChar); +} +// 65AB0C: using guessed type int save_archive_modified; + +bool __cdecl mpqapi_write_header() // WriteMPQHeader +{ + bool result; // al + _FILEHEADER fhdr; // [esp+8h] [ebp-6Ch] + DWORD NumberOfBytesWritten; // [esp+70h] [ebp-4h] + + memset(&fhdr, 0, 0x68u); + fhdr.signature = '\x1AQPM'; + fhdr.headersize = 32; + fhdr.filesize = GetFileSize(sghArchive, 0); + fhdr.version = 0; + fhdr.sectorsizeid = 3; + fhdr.hashoffset = 32872; + fhdr.blockoffset = 104; + fhdr.hashcount = 2048; + fhdr.blockcount = 2048; + if ( SetFilePointer(sghArchive, 0, NULL, FILE_BEGIN) != -1 && WriteFile(sghArchive, &fhdr, 0x68u, &NumberOfBytesWritten, 0) ) + result = NumberOfBytesWritten == 104; + else + result = 0; + return result; +} + +bool __cdecl mpqapi_write_block_table() +{ + int v1; // eax + BOOL v2; // ebx + int v3; // eax + DWORD NumberOfBytesWritten; // [esp+4h] [ebp-4h] + + if ( SetFilePointer(sghArchive, 104, NULL, FILE_BEGIN) == -1 ) + return 0; + v1 = encrypt_hash("(block table)", 3); + encrypt_encrypt_block(sgpBlockTbl, 0x8000, v1); + v2 = WriteFile(sghArchive, sgpBlockTbl, 0x8000u, &NumberOfBytesWritten, 0); + v3 = encrypt_hash("(block table)", 3); + encrypt_decrypt_block(sgpBlockTbl, 0x8000, v3); + return v2 && NumberOfBytesWritten == 0x8000; +} + +bool __cdecl mpqapi_write_hash_table() +{ + int v1; // eax + BOOL v2; // ebx + int v3; // eax + DWORD NumberOfBytesWritten; // [esp+4h] [ebp-4h] + + if ( SetFilePointer(sghArchive, 32872, NULL, FILE_BEGIN) == -1 ) + return 0; + v1 = encrypt_hash("(hash table)", 3); + encrypt_encrypt_block(sgpHashTbl, 0x8000, v1); + v2 = WriteFile(sghArchive, sgpHashTbl, 0x8000u, &NumberOfBytesWritten, 0); + v3 = encrypt_hash("(hash table)", 3); + encrypt_decrypt_block(sgpHashTbl, 0x8000, v3); + return v2 && NumberOfBytesWritten == 0x8000; +} + +bool __cdecl mpqapi_can_seek() +{ + bool result; // al + + if ( SetFilePointer(sghArchive, sgdwMpqOffset, NULL, FILE_BEGIN) == -1 ) + result = 0; + else + result = SetEndOfFile(sghArchive); + return result; +} diff --git a/Source/mpqapi.h b/Source/mpqapi.h new file mode 100644 index 000000000..b0dea1486 --- /dev/null +++ b/Source/mpqapi.h @@ -0,0 +1,50 @@ +//HEADER_GOES_HERE +#ifndef __MPQAPI_H__ +#define __MPQAPI_H__ + +extern int mpqapi_cpp_init_value; // weak +extern int sgdwMpqOffset; // idb +extern char mpq_buf[4096]; +extern _HASHENTRY *sgpHashTbl; +extern bool save_archive_modified; // weak +extern _BLOCKENTRY *sgpBlockTbl; +extern bool save_archive_open; // weak + +void __cdecl mpqapi_cpp_init(); +bool __fastcall mpqapi_set_hidden(char *pszArchive, bool hidden); +void __fastcall mpqapi_store_creation_time(char *pszArchive, int dwChar); +bool __fastcall mpqapi_reg_load_modification_time(char *dst, int size); +void __fastcall mpqapi_xor_buf(char *pbData); +bool __fastcall mpqapi_reg_store_modification_time(char *pbData, int dwLen); +_BLOCKENTRY *__fastcall j_mpqapi_remove_hash_entry(char *pszName); +void __fastcall mpqapi_remove_hash_entry(char *pszName); +void __fastcall mpqapi_free_block(int block_offset, int block_size); +_BLOCKENTRY *__fastcall mpqapi_new_block(int *block_index); +int __fastcall mpqapi_get_hash_index_of_path(char *pszName); +int __fastcall mpqapi_get_hash_index(short index, int hash_a, int hash_b, int locale); +void __fastcall mpqapi_remove_hash_entries(bool (__stdcall *fnGetName)(int, char *)); +bool __fastcall mpqapi_write_file(char *pszName, char *pbData, int dwLen); +_BLOCKENTRY *__fastcall mpqapi_add_file(char *pszName, _BLOCKENTRY *pBlk, int block_index); +bool __fastcall mpqapi_write_file_contents(char *pszName, char *pbData, int dwLen, _BLOCKENTRY *pBlk); +int __fastcall mpqapi_find_free_block(int size, int *block_size); +void __fastcall mpqapi_rename(char *pszOld, char *pszNew); +bool __fastcall mpqapi_has_file(char *pszName); +bool __fastcall mpqapi_open_archive(char *pszArchive, bool hidden, int dwChar); +bool __fastcall mpqapi_parse_archive_header(_FILEHEADER *pHdr, int *pdwNextFileStart); +void __fastcall mpqapi_close_archive(char *pszArchive, bool bFree, int dwChar); +void __fastcall mpqapi_store_modified_time(char *pszArchive, int dwChar); +void __fastcall mpqapi_flush_and_close(char *pszArchive, bool bFree, int dwChar); +bool __cdecl mpqapi_write_header(); +bool __cdecl mpqapi_write_block_table(); +bool __cdecl mpqapi_write_hash_table(); +bool __cdecl mpqapi_can_seek(); + +/* rdata */ + +extern const int mpqapi_inf; // weak + +/* data */ + +extern HANDLE sghArchive; // idb + +#endif /* __MPQAPI_H__ */ diff --git a/Source/msg.cpp b/Source/msg.cpp new file mode 100644 index 000000000..08baa03e4 --- /dev/null +++ b/Source/msg.cpp @@ -0,0 +1,3842 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int sgdwOwnerWait; // weak +int msg_cpp_init_value; // weak +int sgdwRecvOffset; // idb +int sgnCurrMegaPlayer; // weak +DLevel sgLevels[NUMLEVELS]; +char sbLastCmd; // weak +TMegaPkt *sgpCurrPkt; +char sgRecvBuf[4722]; +unsigned char sgbRecvCmd; // idb +LocalLevel sgLocals[NUMLEVELS]; +DJunk sgJunk; +TMegaPkt *sgpMegaPkt; +char sgbDeltaChanged; // weak +char sgbDeltaChunks; // weak +int deltaload; // weak +char gbBufferMsgs; // weak +int dword_676198; // weak +int msg_err_timer; // weak +#endif + +const int msg_inf = 0x7F800000; // weak + +struct msg_cpp_init +{ + msg_cpp_init() + { + msg_cpp_init_value = msg_inf; + } +} _msg_cpp_init; +// 47F14C: using guessed type int msg_inf; +// 65AB1C: using guessed type int msg_cpp_init_value; + +void __fastcall msg_send_drop_pkt(int pnum, int reason) +{ + TFakeDropPlr cmd; // [esp+0h] [ebp-8h] + + cmd.dwReason = reason; + cmd.bCmd = FAKE_CMD_DROPID; + cmd.bPlr = pnum; + msg_send_packet(pnum, &cmd, 6); +} + +void __fastcall msg_send_packet(int pnum, void *packet, int dwSize) +{ + void *v3; // edi + TMegaPkt *v4; // eax + TFakeCmdPlr cmd; // [esp+Ah] [ebp-2h] + + v3 = packet; + if ( pnum != sgnCurrMegaPlayer ) + { + sgnCurrMegaPlayer = pnum; + cmd.bCmd = FAKE_CMD_SETID; + cmd.bPlr = pnum; + msg_send_packet(pnum, &cmd, 2); + } + v4 = sgpCurrPkt; + if ( sgpCurrPkt->dwSpaceLeft < (unsigned int)dwSize ) + { + msg_get_next_packet(); + v4 = sgpCurrPkt; + } + memcpy((char *)&v4[1] - v4->dwSpaceLeft, v3, dwSize); + sgpCurrPkt->dwSpaceLeft -= dwSize; +} +// 65AB24: using guessed type int sgnCurrMegaPlayer; + +TMegaPkt *__cdecl msg_get_next_packet() +{ + TMegaPkt *v0; // eax + TMegaPkt *v1; // ecx + TMegaPkt *result; // eax + + v0 = (TMegaPkt *)DiabloAllocPtr(32008); + sgpCurrPkt = v0; + v0->pNext = 0; + sgpCurrPkt->dwSpaceLeft = 32000; + v1 = sgpMegaPkt; + result = (TMegaPkt *)&sgpMegaPkt; + while ( v1 ) + { + result = v1; + v1 = v1->pNext; + } + result->pNext = sgpCurrPkt; + return result; +} + +int __cdecl msg_wait_resync() +{ + int v0; // eax + + msg_get_next_packet(); + sgbDeltaChunks = 0; + sgnCurrMegaPlayer = -1; + sgbRecvCmd = CMD_DLEVEL_END; + gbBufferMsgs = 1; + sgdwOwnerWait = GetTickCount(); + v0 = UiProgressDialog(ghMainWnd, "Waiting for game data...", 1, msg_wait_for_turns, 20); + gbBufferMsgs = 0; + if ( !v0 ) + goto LABEL_6; + if ( gbGameDestroyed ) + { + DrawDlg("The game ended"); +LABEL_6: + msg_free_packets(); + return 0; + } + if ( sgbDeltaChunks != 21 ) + { + DrawDlg("Unable to get level data"); + goto LABEL_6; + } + return 1; +} +// 65AB18: using guessed type int sgdwOwnerWait; +// 65AB24: using guessed type int sgnCurrMegaPlayer; +// 67618D: using guessed type char sgbDeltaChunks; +// 676194: using guessed type char gbBufferMsgs; +// 67862D: using guessed type char gbGameDestroyed; + +void __cdecl msg_free_packets() +{ + TMegaPkt *v0; // eax + TMegaPkt *v1; // ecx + + v0 = sgpMegaPkt; + while ( v0 ) + { + v1 = v0->pNext; + sgpMegaPkt = 0; + sgpCurrPkt = v1; + mem_free_dbg(v0); + v0 = sgpCurrPkt; + sgpMegaPkt = sgpCurrPkt; + } +} + +int __cdecl msg_wait_for_turns() +{ + //int v0; // eax + //int v2; // eax + int recieved; // [esp+0h] [ebp-8h] + int turns; // [esp+4h] [ebp-4h] + + if ( !sgbDeltaChunks ) + { + nthread_send_and_recv_turn(0, 0); + //_LOBYTE(v0) = SNetGetOwnerTurnsWaiting(&turns); + if ( !SNetGetOwnerTurnsWaiting(&turns) && SErrGetLastError() == STORM_ERROR_NOT_IN_GAME ) + return 100; + if ( GetTickCount() - sgdwOwnerWait <= 2000 && turns < (unsigned int)gdwTurnsInTransit ) + return 0; + ++sgbDeltaChunks; + } + multi_process_network_packets(); + nthread_send_and_recv_turn(0, 0); + //_LOBYTE(v2) = nthread_has_500ms_passed(); + if ( nthread_has_500ms_passed() ) + nthread_recv_turns(&recieved); + if ( gbGameDestroyed ) + return 100; + if ( (unsigned char)gbDeltaSender >= 4u ) + { + sgbDeltaChunks = 0; + sgbRecvCmd = CMD_DLEVEL_END; + gbDeltaSender = myplr; + nthread_set_turn_upper_bit(); + } + if ( sgbDeltaChunks == 20 ) + { + sgbDeltaChunks = 21; + return 99; + } + return 100 * (unsigned char)sgbDeltaChunks / 21; +} +// 65AB18: using guessed type int sgdwOwnerWait; +// 67618D: using guessed type char sgbDeltaChunks; +// 67862D: using guessed type char gbGameDestroyed; +// 6796E4: using guessed type char gbDeltaSender; +// 679738: using guessed type int gdwTurnsInTransit; + +void __cdecl msg_process_net_packets() +{ + if ( gbMaxPlayers != 1 ) + { + gbBufferMsgs = 2; + msg_pre_packet(); + gbBufferMsgs = 0; + msg_free_packets(); + } +} +// 676194: using guessed type char gbBufferMsgs; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl msg_pre_packet() +{ + TMegaPkt *v0; // edi + int i; // ebp + signed int v2; // ebx + TFakeCmdPlr *v3; // esi + TFakeCmdPlr *v4; // eax + TFakeDropPlr *v5; // eax + int v6; // eax + + v0 = sgpMegaPkt; + for ( i = -1; v0; v0 = v0->pNext ) + { + v2 = 32000; + v3 = (TFakeCmdPlr *)v0->data; + while ( v2 != v0->dwSpaceLeft ) + { + if ( v3->bCmd == FAKE_CMD_SETID ) + { + v4 = v3; + ++v3; + i = (unsigned char)v4->bPlr; + v2 -= 2; + } + else if ( v3->bCmd == FAKE_CMD_DROPID ) + { + v5 = (TFakeDropPlr *)v3; + v3 += 3; + v2 -= 6; + multi_player_left((unsigned char)v5->bPlr, v5->dwReason); + } + else + { + v6 = ParseCmd(i, (TCmd *)v3); + v3 = (TFakeCmdPlr *)((char *)v3 + v6); + v2 -= v6; + } + } + } +} + +void __fastcall DeltaExportData(int pnum) +{ + char *v1; // edi + DObjectStr *v2; // esi + void *v3; // ebx + void *v4; // eax + void *v5; // eax + void *v6; // eax + int v7; // eax + char *v8; // eax + int v9; // eax + int player_num; // [esp+0h] [ebp-Ch] + int v11; // [esp+4h] [ebp-8h] + char src; // [esp+Bh] [ebp-1h] + + player_num = pnum; + if ( sgbDeltaChanged ) + { + v11 = 0; + v1 = (char *)DiabloAllocPtr(4722); + v2 = sgLevels[0].object; + v3 = v1 + 1; + do + { + v4 = DeltaExportItem(v3, &v2[-2794]); + v5 = DeltaExportObject(v4, v2); + v6 = DeltaExportMonster(v5, &v2[127]); + v7 = msg_comp_level(v1, (int)v6); + dthread_send_delta(player_num, (_BYTE)v11++ + CMD_DLEVEL_0, v1, v7); + v2 += 4721; + } + while ( (signed int)v2 < (signed int)&sgLevels[NUMLEVELS].object ); + v8 = DeltaExportJunk((char *)v3); + v9 = msg_comp_level(v1, (int)v8); + dthread_send_delta(player_num, CMD_DLEVEL_JUNK, v1, v9); + mem_free_dbg(v1); + } + src = 0; + dthread_send_delta(player_num, CMD_DLEVEL_END, &src, 1); +} +// 67618C: using guessed type char sgbDeltaChanged; + +void *__fastcall DeltaExportItem(void *dst, void *src) +{ + _BYTE *v2; // edi + _BYTE *v3; // esi + signed int v4; // ebx + + v2 = (unsigned char *)src; + v3 = (unsigned char *)dst; + v4 = 127; + do + { + if ( *v2 == -1 ) + { + *v3++ = -1; + } + else + { + memcpy(v3, v2, 0x16u); + v3 += 22; + } + v2 += 22; + --v4; + } + while ( v4 ); + return v3; +} + +void *__fastcall DeltaExportObject(void *dst, void *src) +{ + char *v2; // esi + + v2 = (char *)dst; + memcpy(dst, src, 0x7Fu); + return v2 + 127; +} + +void *__fastcall DeltaExportMonster(void *dst, void *src) +{ + _BYTE *v2; // edi + _BYTE *v3; // esi + signed int v4; // ebx + + v2 = (unsigned char *)src; + v3 = (unsigned char *)dst; + v4 = MAXMONSTERS; + do + { + if ( *v2 == -1 ) + { + *v3++ = -1; + } + else + { + memcpy(v3, v2, 9u); + v3 += 9; + } + v2 += 9; + --v4; + } + while ( v4 ); + return v3; +} + +char *__fastcall DeltaExportJunk(char *a1) +{ + char *v1; // ebx + DJunk *v2; // edi + MultiQuests *v3; // esi + unsigned char *v4; // edi + int *v5; // ebp + + v1 = a1; + v2 = &sgJunk; + v3 = sgJunk.quests; + do + { + if ( v2->portal[0].x == LOBYTE(-1) ) + { + *v1++ = -1; + } + else + { + memcpy(v1, v2, 5u); + v1 += 5; + } + v2 = (DJunk *)((char *)v2 + 5); + } + while ( (signed int)v2 < (signed int)sgJunk.quests ); + v4 = &quests[0]._qactive; + v5 = &questlist[0]._qflags; + do + { + if ( *(_BYTE *)v5 & 1 ) + { + v3->qlog = v4[18]; + v3->qstate = *v4; + v3->qvar1 = v4[13]; + memcpy(v1, v3, 3u); + v1 += 3; + ++v3; + } + v5 += 5; + v4 += 24; + } + while ( (signed int)v5 < (signed int)&questlist[16]._qflags ); + return v1; +} + +int __fastcall msg_comp_level(char *buffer, int size) +{ + char *v2; // esi + int v3; // edi + int v4; // eax + + v2 = buffer; + v3 = size - (_DWORD)buffer - 1; + v4 = encrypt_compress(buffer + 1, v3); + *v2 = v3 != v4; + return v4 + 1; +} + +void __cdecl delta_init() +{ + sgbDeltaChanged = 0; + memset(&sgJunk, 255, 0x20u); + memset(sgLevels, 255, 0x13981u); + memset(sgLocals, 0, 0x6A40u); + deltaload = 0; +} +// 67618C: using guessed type char sgbDeltaChanged; +// 676190: using guessed type int deltaload; + +void __fastcall delta_kill_monster(int mi, unsigned char x, unsigned char y, unsigned char bLevel) +{ + DMonsterStr *v4; // eax + char v5; // cl + + if ( gbMaxPlayers != 1 ) + { + v4 = &sgLevels[bLevel].monster[mi]; + sgbDeltaChanged = 1; + v5 = monster[mi]._mdir; + v4->_mhitpoints = 0; + v4->_mx = x; + v4->_mdir = v5; + v4->_my = y; + } +} +// 67618C: using guessed type char sgbDeltaChanged; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall delta_monster_hp(int mi, int hp, unsigned char bLevel) +{ + DMonsterStr *v3; // eax + + if ( gbMaxPlayers != 1 ) + { + sgbDeltaChanged = 1; + v3 = &sgLevels[bLevel].monster[mi]; + if ( v3->_mhitpoints > hp ) + v3->_mhitpoints = hp; + } +} +// 67618C: using guessed type char sgbDeltaChanged; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall delta_sync_monster(TCmdLocParam1 *packet, char level) +{ + DMonsterStr *v2; // eax + char v3; // dl + + if ( gbMaxPlayers != 1 ) + { + sgbDeltaChanged = 1; + v2 = &sgLevels[(unsigned char)level].monster[(unsigned char)packet->bCmd]; + if ( v2->_mhitpoints ) + { + v2->_mx = packet->x; + v3 = packet->y; + v2->_mactive = -1; + v2->_my = v3; + v2->_menemy = packet->wParam1; + } + } +} +// 67618C: using guessed type char sgbDeltaChanged; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall delta_sync_golem(TCmdGolem *pG, int pnum, int bLevel) +{ + DMonsterStr *v3; // eax + char v4; // dl + + if ( gbMaxPlayers != 1 ) + { + sgbDeltaChanged = 1; + v3 = &sgLevels[(unsigned char)bLevel].monster[pnum]; + v3->_mx = pG->_mx; + v4 = pG->_my; + v3->_mactive = -1; + v3->_my = v4; + v3->_menemy = pG->_menemy; + v3->_mdir = pG->_mdir; + v3->_mhitpoints = pG->_mhitpoints; + } +} +// 67618C: using guessed type char sgbDeltaChanged; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall delta_leave_sync(unsigned char bLevel) +{ + unsigned char v1; // bl + bool v2; // zf + int v3; // eax + int i; // ebp + int v5; // ecx + int v6; // esi + DMonsterStr *v7; // edi + + v1 = bLevel; + if ( gbMaxPlayers != 1 ) + { + v2 = currlevel == 0; + if ( !currlevel ) + { + v3 = GetRndSeed(); + v2 = currlevel == 0; + glSeedTbl[0] = v3; + } + if ( !v2 ) + { + for ( i = 0; i < nummonsters; ++i ) + { + v5 = monstactive[i]; + v6 = monstactive[i]; + if ( monster[v6]._mhitpoints ) + { + sgbDeltaChanged = 1; + v7 = &sgLevels[v1].monster[v5]; + v7->_mx = monster[v6]._mx; + v7->_my = monster[v6]._my; + v7->_mdir = monster[v6]._mdir; + v7->_menemy = encode_enemy(v5); + v7->_mhitpoints = monster[v6]._mhitpoints; + v7->_mactive = monster[v6]._msquelch; + } + } + memcpy(&sgLocals[v1], automapview, 0x640u); + } + } +} +// 43C17D: could not find valid save-restore pair for edi +// 67618C: using guessed type char sgbDeltaChanged; +// 679660: using guessed type char gbMaxPlayers; + +bool __fastcall delta_portal_inited(int i) +{ + return sgJunk.portal[i].x == LOBYTE(-1); +} + +bool __fastcall delta_quest_inited(int i) +{ + return sgJunk.quests[i].qstate != LOBYTE(-1); +} + +void __fastcall DeltaAddItem(int ii) +{ + int v1; // eax + int v2; // ecx + signed int v3; // ebp + DLevel *v4; // edx + DLevel *v5; // edi + char v6; // bl + int v7; // esi + signed int v8; // esi + int v9; // eax + char v10; // cl + char v11; // cl + + v1 = ii; + if ( gbMaxPlayers != 1 ) + { + v2 = currlevel; + v3 = 0; + v4 = &sgLevels[v2]; + v5 = &sgLevels[v2]; + while ( 1 ) + { + v6 = v5->item[0].bCmd; + if ( v5->item[0].bCmd != -1 ) + { + v7 = v1; + if ( (unsigned short)v5->item[0].wIndx == item[v1].IDidx + && v5->item[0].wCI == item[v7]._iCreateInfo + && v5->item[0].dwSeed == item[v7]._iSeed + && (v6 == 1 || !v6) ) + { + break; + } + } + ++v3; + v5 = (DLevel *)((char *)v5 + 22); + if ( v3 >= 127 ) + { + v8 = 0; + while ( v4->item[0].bCmd != -1 ) + { + ++v8; + v4 = (DLevel *)((char *)v4 + 22); + if ( v8 >= 127 ) + return; + } + v4->item[0].bCmd = 0; + v9 = 368 * v1; + v10 = *((_BYTE *)&item[0]._ix + v9); + sgbDeltaChanged = 1; + v4->item[0].x = v10; + v4->item[0].y = *((_BYTE *)&item[0]._iy + v9); + v4->item[0].wIndx = *(_WORD *)((char *)&item[0].IDidx + v9); + v4->item[0].wCI = *(short *)((char *)&item[0]._iCreateInfo + v9); + v4->item[0].dwSeed = *(int *)((char *)&item[0]._iSeed + v9); + v4->item[0].bId = *((_BYTE *)&item[0]._iIdentified + v9); + v4->item[0].bDur = *((_BYTE *)&item[0]._iDurability + v9); + v4->item[0].bMDur = *((_BYTE *)&item[0]._iMaxDur + v9); + v4->item[0].bCh = *((_BYTE *)&item[0]._iCharges + v9); + v11 = *((_BYTE *)&item[0]._iMaxCharges + v9); + _LOWORD(v9) = *(_WORD *)((char *)&item[0]._ivalue + v9); + v4->item[0].bMCh = v11; + v4->item[0].wValue = v9; + return; + } + } + } +} +// 67618C: using guessed type char sgbDeltaChanged; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl DeltaSaveLevel() +{ + int v0; // eax + int v1; // edx + int *v2; // ecx + unsigned char v3; // cl + + if ( gbMaxPlayers != 1 ) + { + v0 = myplr; + v1 = 0; + v2 = &plr[0]._pGFXLoad; + do + { + if ( v1 != v0 ) + *v2 = 0; + v2 += 5430; + ++v1; + } + while ( (signed int)v2 < (signed int)&plr[4]._pGFXLoad ); + v3 = currlevel; + plr[v0]._pLvlVisited[currlevel] = 1; + delta_leave_sync(v3); + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl DeltaLoadLevel() +{ + int v0; // ebx + int *v1; // esi + int v2; // eax + int v3; // ecx + int v4; // edx + int v5; // edi + char v6; // al + int v7; // eax + signed int v8; // esi + int v9; // eax + char v10; // cl + int v11; // eax + char *v12; // edx + int v13; // eax + int v14; // ebx + int *v15; // edx + unsigned short v16; // cx + int v17; // ST1C_4 + int v18; // ST18_4 + int v19; // eax + int v20; // ecx + int v21; // edx + int v22; // eax + int v23; // eax + int v24; // esi + int v25; // edi + int v26; // eax + int v27; // eax + int v28; // esi + unsigned char v29; // al + int j; // esi + int v31; // eax + signed int v32; // [esp+0h] [ebp-24h] + int v33; // [esp+4h] [ebp-20h] + int o2; // [esp+8h] [ebp-1Ch] + int i; // [esp+Ch] [ebp-18h] + signed int v36; // [esp+10h] [ebp-14h] + int v37; // [esp+14h] [ebp-10h] + signed int v38; // [esp+18h] [ebp-Ch] + signed int v39; // [esp+1Ch] [ebp-8h] + int v40; // [esp+20h] [ebp-4h] + signed int v41; // [esp+20h] [ebp-4h] + + if ( gbMaxPlayers != 1 ) + { + deltaload = 1; + if ( currlevel ) + { + v0 = 0; + if ( nummonsters > 0 ) + { + v40 = 0; + v1 = &monster[0]._mfuty; + do + { + if ( sgLevels[currlevel].monster[v40]._mx != -1 ) + { + M_ClearSquares(v0); + v2 = v40 * 9 + 4721 * currlevel; + v3 = *((unsigned char *)&sgLevels[0].monster[0]._mx + v2); + v4 = *((unsigned char *)&sgLevels[0].monster[0]._my + v2); + v5 = *(int *)((char *)&sgLevels[0].monster[0]._mhitpoints + v2); + *(v1 - 3) = v3; + *(v1 - 2) = v4; + v1[1] = v3; + v1[2] = v4; + *(v1 - 1) = v3; + *v1 = v4; + if ( v5 != -1 ) + v1[26] = v5; + if ( v5 ) + { + decode_enemy(v0, *((unsigned char *)&sgLevels[0].monster[0]._menemy + v2)); + v7 = *(v1 - 3); + if ( v7 && v7 != 1 || *(v1 - 2) ) + dMonster[0][*(v1 - 2) + 112 * v7] = v0 + 1; + if ( (signed int)v1 >= (signed int)&monster[4]._mfuty ) + { + M_StartStand(v0, v1[7]); + } + else + { + MAI_Golum(v0); + v1[28] |= 0x30u; + } + *((_BYTE *)v1 + 116) = sgLevels[currlevel].monster[v40]._mactive; + } + else + { + v1[1] = v3; + v1[2] = v4; + M_ClearSquares(v0); + if ( *((_BYTE *)v1 + 108) != 27 ) + { + if ( *((_BYTE *)v1 + 144) ) + v6 = *((_BYTE *)v1 + 146); + else + v6 = *(_BYTE *)(v1[44] + 317); + AddDead(*(v1 - 3), *(v1 - 2), v6, (direction)v1[7]); + } + v1[16] = 1; + M_UpdateLeader(v0); + } + } + ++v40; + ++v0; + v1 += 57; + } + while ( v0 < nummonsters ); + } + memcpy(automapview, &sgLocals[currlevel], 0x640u); + } + v8 = 0; + i = 0; + v32 = 0; + do + { + v9 = v8 + 4721 * currlevel; + v10 = *(&sgLevels[0].item[0].bCmd + v9); + if ( v10 != -1 ) + { + if ( v10 == 1 ) + { + v11 = FindGetItem( + *(unsigned short *)((char *)&sgLevels[0].item[0].wIndx + v9), + *(short *)((char *)&sgLevels[0].item[0].wCI + v9), + *(int *)((char *)&sgLevels[0].item[0].dwSeed + v9)); + if ( v11 != -1 ) + { + v12 = &dItem[item[v11]._ix][item[v11]._iy]; + if ( *v12 == v11 + 1 ) + *v12 = 0; + DeleteItem(v11, i); + } + } + v13 = v8 + 4721 * currlevel; + if ( *(&sgLevels[0].item[0].bCmd + v13) == 2 ) + { + v14 = itemavail[0]; + v33 = itemavail[0]; + v15 = &itemavail[-numitems + 126]; + itemactive[numitems] = itemavail[0]; + v16 = *(short *)((char *)&sgLevels[0].item[0].wIndx + v13); + itemavail[0] = *v15; + if ( v16 == IDI_EAR ) + { + RecreateEar( + v14, + *(short *)((char *)&sgLevels[0].item[0].wCI + v13), + *(int *)((char *)&sgLevels[0].item[0].dwSeed + v13), + *(&sgLevels[0].item[0].bId + v13), + *((unsigned char *)&sgLevels[0].item[0].bDur + v13), + *((unsigned char *)&sgLevels[0].item[0].bMDur + v13), + *((unsigned char *)&sgLevels[0].item[0].bCh + v13), + *((unsigned char *)&sgLevels[0].item[0].bMCh + v13), + *(unsigned short *)((char *)&sgLevels[0].item[0].wValue + v13), + *(int *)((char *)&sgLevels[0].item[0].dwBuff + v13)); + } + else + { + v17 = *(unsigned short *)((char *)&sgLevels[0].item[0].wValue + v13); + v18 = *(int *)((char *)&sgLevels[0].item[0].dwSeed + v13); + _LOWORD(v13) = *(short *)((char *)&sgLevels[0].item[0].wCI + v13); + RecreateItem(v14, v16, v13, v18, v17); + v19 = v8 + 4721 * currlevel; + if ( *(&sgLevels[0].item[0].bId + v19) ) + item[v14]._iIdentified = 1; + v20 = v14; + item[v20]._iDurability = *((unsigned char *)&sgLevels[0].item[0].bDur + v19); + item[v20]._iMaxDur = *((unsigned char *)&sgLevels[0].item[0].bMDur + v19); + v21 = *((unsigned char *)&sgLevels[0].item[0].bCh + v19); + v22 = *((unsigned char *)&sgLevels[0].item[0].bMCh + v19); + item[v20]._iCharges = v21; + item[v20]._iMaxCharges = v22; + } + v23 = v8 + 4721 * currlevel; + v24 = *((unsigned char *)&sgLevels[0].item[0].x + v23); + v25 = *((unsigned char *)&sgLevels[0].item[0].y + v23); + if ( !CanPut(v24, v25) ) + { + v39 = 0; + v26 = -1; + v41 = 1; + v36 = -1; + do + { + if ( v39 ) + break; + v37 = v26; + while ( v26 <= v41 && !v39 ) + { + o2 = v25 + v37; + v38 = v36; + do + { + if ( v39 ) + break; + if ( CanPut(v38 + v24, o2) ) + { + v25 = o2; + v39 = 1; + v24 += v38; + } + ++v38; + v14 = v33; + } + while ( v38 <= v41 ); + v26 = ++v37; + } + ++v41; + v26 = v36-- - 1; + } + while ( v36 > -50 ); + } + v27 = v14; + item[v27]._ix = v24; + item[v27]._iy = v25; + dItem[v24][v25] = v14 + 1; + RespawnItem(v14, 0); + ++numitems; + v8 = v32; + } + } + ++i; + v8 += 22; + v32 = v8; + } + while ( v8 < 2794 ); + if ( currlevel ) + { + v28 = 0; + do + { + v29 = sgLevels[currlevel].object[v28].bCmd; + if ( v29 >= CMD_OPENDOOR ) + { + if ( v29 <= CMD_PLROPOBJ ) + { + SyncOpObject(-1, v29, v28); + } + else if ( v29 == CMD_BREAKOBJ ) + { + SyncBreakObj(-1, v28); + } + } + ++v28; + } + while ( v28 < 127 ); + for ( j = 0; j < nobjects; ++j ) + { + v31 = object[objectactive[j]]._otype; + if ( v31 == OBJ_TRAPL || v31 == OBJ_TRAPR ) + Obj_Trap(objectactive[j]); + } + } + deltaload = 0; + } +} +// 676190: using guessed type int deltaload; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall NetSendCmd(unsigned char bHiPri, unsigned char bCmd) +{ + TCmd cmd; // [esp+3h] [ebp-1h] + + cmd.bCmd = bCmd; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 1u); + else + NetSendLoPri((unsigned char *)&cmd, 1u); +} + +void __fastcall NetSendCmdGolem(unsigned char mx, unsigned char my, unsigned char dir, unsigned char menemy, int hp, int cl) +{ + TCmdGolem cmd; // [esp+0h] [ebp-Ch] + + cmd._mx = mx; + cmd._mdir = dir; + cmd._menemy = menemy; + cmd._mhitpoints = hp; + cmd._my = my; + cmd.bCmd = CMD_AWAKEGOLEM; + cmd._currlevel = cl; + NetSendLoPri((unsigned char *)&cmd, 0xAu); +} + +void __fastcall NetSendCmdLoc(unsigned char bHiPri, unsigned char bCmd, unsigned char x, unsigned char y) +{ + TCmdLoc cmd; // [esp+1h] [ebp-3h] + + cmd.bCmd = bCmd; + cmd.x = x; + cmd.y = y; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 3u); + else + NetSendLoPri((unsigned char *)&cmd, 3u); +} + +void __fastcall NetSendCmdLocParam1(unsigned char bHiPri, unsigned char bCmd, unsigned char x, unsigned char y, int wParam1) +{ + TCmdLocParam1 cmd; // [esp+0h] [ebp-8h] + + cmd.bCmd = bCmd; + cmd.x = x; + cmd.y = y; + cmd.wParam1 = wParam1; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 5u); + else + NetSendLoPri((unsigned char *)&cmd, 5u); +} + +void __fastcall NetSendCmdLocParam2(unsigned char bHiPri, unsigned char bCmd, unsigned char x, unsigned char y, int wParam1, int wParam2) +{ + TCmdLocParam2 cmd; // [esp+0h] [ebp-8h] + + cmd.bCmd = bCmd; + cmd.x = x; + cmd.y = y; + cmd.wParam1 = wParam1; + cmd.wParam2 = wParam2; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 7u); + else + NetSendLoPri((unsigned char *)&cmd, 7u); +} + +void __fastcall NetSendCmdLocParam3(unsigned char bHiPri, unsigned char bCmd, unsigned char x, unsigned char y, int wParam1, int wParam2, int wParam3) +{ + TCmdLocParam3 cmd; // [esp+0h] [ebp-Ch] + + cmd.bCmd = bCmd; + cmd.x = x; + cmd.y = y; + cmd.wParam1 = wParam1; + cmd.wParam2 = wParam2; + cmd.wParam3 = wParam3; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 9u); + else + NetSendLoPri((unsigned char *)&cmd, 9u); +} + +void __fastcall NetSendCmdParam1(BOOL bHiPri, unsigned char bCmd, unsigned short wParam1) +{ + TCmdParam1 cmd; // [esp+1h] [ebp-3h] + + cmd.bCmd = bCmd; + cmd.wParam1 = wParam1; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 3u); + else + NetSendLoPri((unsigned char *)&cmd, 3u); +} + +void __fastcall NetSendCmdParam2(BOOL bHiPri, unsigned char bCmd, unsigned short wParam1, unsigned short wParam2) +{ + TCmdParam2 cmd; // [esp+0h] [ebp-8h] + + cmd.bCmd = bCmd; + cmd.wParam1 = wParam1; + cmd.wParam2 = wParam2; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 5u); + else + NetSendLoPri((unsigned char *)&cmd, 5u); +} + +void __fastcall NetSendCmdParam3(unsigned char bHiPri, unsigned char bCmd, unsigned short wParam1, unsigned short wParam2, int wParam3) +{ + TCmdParam3 cmd; // [esp+0h] [ebp-8h] + + cmd.bCmd = bCmd; + cmd.wParam1 = wParam1; + cmd.wParam2 = wParam2; + cmd.wParam3 = wParam3; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 7u); + else + NetSendLoPri((unsigned char *)&cmd, 7u); +} + +void __fastcall NetSendCmdQuest(unsigned char bHiPri, unsigned char q) +{ + int v2; // eax + char v3; // dl + TCmdQuest cmd; // [esp+0h] [ebp-8h] + + cmd.q = q; + cmd.bCmd = CMD_SYNCQUEST; + v2 = 24 * q; + cmd.qstate = *(&quests[0]._qactive + v2); + v3 = *((_BYTE *)&quests[0]._qlog + v2); + _LOBYTE(v2) = *(&quests[0]._qvar1 + v2); + cmd.qlog = v3; + cmd.qvar1 = v2; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 5u); + else + NetSendLoPri((unsigned char *)&cmd, 5u); +} + +void __fastcall NetSendCmdGItem(unsigned char bHiPri, unsigned char bCmd, unsigned char mast, unsigned char pnum, int ii) +{ + int v5; // eax + bool v6; // zf + short v7; // dx + short v8; // bx + int v9; // esi + int v10; // esi + char v11; // dl + short v12; // ax + TCmdGItem cmd; // [esp+4h] [ebp-20h] + + cmd.bCmd = bCmd; + cmd.bPnum = pnum; + cmd.bMaster = mast; + cmd.bLevel = currlevel; + cmd.bCursitem = ii; + cmd.dwTime = 0; + v5 = (unsigned char)ii; + cmd.x = item[v5]._ix; + cmd.y = item[v5]._iy; + v6 = item[v5].IDidx == IDI_EAR; + cmd.wIndx = item[v5].IDidx; + if ( v6 ) + { + _LOBYTE(v7) = 0; + _HIBYTE(v7) = item[v5]._iName[7]; + _LOBYTE(v8) = 0; + _HIBYTE(v8) = item[v5]._iName[18]; + v9 = item[v5]._iName[10]; + cmd.wCI = item[v5]._iName[8] | v7; + cmd.dwSeed = item[v5]._iName[12] | ((item[v5]._iName[11] | ((v9 | (item[v5]._iName[9] << 8)) << 8)) << 8); + cmd.bId = item[v5]._iName[13]; + cmd.bDur = item[v5]._iName[14]; + cmd.bMDur = item[v5]._iName[15]; + cmd.bCh = item[v5]._iName[16]; + cmd.bMCh = item[v5]._iName[17]; + v10 = item[v5]._iName[20]; + cmd.wValue = _LOWORD(item[v5]._ivalue) | v8 | ((_LOWORD(item[v5]._iCurs) - 19) << 6); + cmd.dwBuff = item[v5]._iName[22] | ((item[v5]._iName[21] | ((v10 | (item[v5]._iName[19] << 8)) << 8)) << 8); + } + else + { + cmd.wCI = item[v5]._iCreateInfo; + cmd.dwSeed = item[v5]._iSeed; + cmd.bId = item[v5]._iIdentified; + cmd.bDur = item[v5]._iDurability; + cmd.bMDur = item[v5]._iMaxDur; + cmd.bCh = item[v5]._iCharges; + v11 = item[v5]._iMaxCharges; + v12 = item[v5]._ivalue; + cmd.bMCh = v11; + cmd.wValue = v12; + } + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 0x1Eu); + else + NetSendLoPri((unsigned char *)&cmd, 0x1Eu); +} + +void __fastcall NetSendCmdGItem2(unsigned char usonly, unsigned char bCmd, unsigned char mast, unsigned char pnum, struct TCmdGItem *p) +{ + unsigned char v5; // bl + int v6; // esi + int v7; // eax + TCmdGItem cmd; // [esp+8h] [ebp-20h] + + v5 = bCmd; + v6 = usonly; + memcpy(&cmd, p, 0x1Eu); + cmd.bPnum = pnum; + cmd.bCmd = v5; + cmd.bMaster = mast; + if ( !v6 ) + { + cmd.dwTime = 0; + NetSendHiPri((unsigned char *)&cmd, 0x1Eu); + return; + } + v7 = GetTickCount(); + if ( cmd.dwTime ) + { + if ( v7 - cmd.dwTime > 5000 ) + return; + } + else + { + cmd.dwTime = v7; + } + multi_msg_add(&cmd.bCmd, 0x1Eu); +} + +bool __fastcall NetSendCmdReq2(unsigned char bCmd, unsigned char mast, unsigned char pnum, struct TCmdGItem *p) +{ + unsigned char v4; // bl + int v5; // eax + TCmdGItem cmd; // [esp+4h] [ebp-24h] + unsigned char v8; // [esp+24h] [ebp-4h] + + v4 = mast; + v8 = bCmd; + memcpy(&cmd, p, 0x1Eu); + cmd.bCmd = v8; + cmd.bPnum = pnum; + cmd.bMaster = v4; + v5 = GetTickCount(); + if ( !cmd.dwTime ) + { + cmd.dwTime = v5; +LABEL_3: + multi_msg_add(&cmd.bCmd, 0x1Eu); + return 1; + } + if ( v5 - cmd.dwTime <= 5000 ) + goto LABEL_3; + return 0; +} + +void __fastcall NetSendCmdExtra(struct TCmdGItem *p) +{ + TCmdGItem cmd; // [esp+0h] [ebp-20h] + + memcpy(&cmd, p, 0x1Eu); + cmd.dwTime = 0; + cmd.bCmd = CMD_ITEMEXTRA; + NetSendHiPri((unsigned char *)&cmd, 0x1Eu); +} + +void __fastcall NetSendCmdPItem(unsigned char bHiPri, unsigned char bCmd, unsigned char x, unsigned char y) +{ + int v4; // eax + short *v5; // edx + bool v6; // zf + short v7; // dx + short v8; // bx + int v9; // esi + int v10; // esi + char v11; // dl + short v12; // ax + TCmdPItem cmd; // [esp+4h] [ebp-18h] + + cmd.bCmd = bCmd; + cmd.x = x; + cmd.y = y; + v4 = myplr; + v5 = (short *)&plr[myplr].HoldItem.IDidx; + v6 = *(_DWORD *)v5 == IDI_EAR; + cmd.wIndx = *v5; + if ( v6 ) + { + _LOBYTE(v7) = 0; + _HIBYTE(v7) = plr[v4].HoldItem._iName[7]; + _LOBYTE(v8) = 0; + _HIBYTE(v8) = plr[v4].HoldItem._iName[18]; + v9 = plr[v4].HoldItem._iName[10]; + cmd.wCI = plr[v4].HoldItem._iName[8] | v7; + cmd.dwSeed = plr[v4].HoldItem._iName[12] | ((plr[v4].HoldItem._iName[11] | ((v9 | (plr[v4].HoldItem._iName[9] << 8)) << 8)) << 8); + cmd.bId = plr[v4].HoldItem._iName[13]; + cmd.bDur = plr[v4].HoldItem._iName[14]; + cmd.bMDur = plr[v4].HoldItem._iName[15]; + cmd.bCh = plr[v4].HoldItem._iName[16]; + cmd.bMCh = plr[v4].HoldItem._iName[17]; + v10 = plr[v4].HoldItem._iName[20]; + cmd.wValue = _LOWORD(plr[v4].HoldItem._ivalue) | v8 | ((_LOWORD(plr[v4].HoldItem._iCurs) - 19) << 6); + cmd.dwBuff = plr[v4].HoldItem._iName[22] | ((plr[v4].HoldItem._iName[21] | ((v10 | (plr[v4].HoldItem._iName[19] << 8)) << 8)) << 8); + } + else + { + cmd.wCI = plr[v4].HoldItem._iCreateInfo; + cmd.dwSeed = plr[v4].HoldItem._iSeed; + cmd.bId = plr[v4].HoldItem._iIdentified; + cmd.bDur = plr[v4].HoldItem._iDurability; + cmd.bMDur = plr[v4].HoldItem._iMaxDur; + cmd.bCh = plr[v4].HoldItem._iCharges; + v11 = plr[v4].HoldItem._iMaxCharges; + v12 = plr[v4].HoldItem._ivalue; + cmd.bMCh = v11; + cmd.wValue = v12; + } + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 0x16u); + else + NetSendLoPri((unsigned char *)&cmd, 0x16u); +} + +void __fastcall NetSendCmdChItem(unsigned char bHiPri, unsigned char bLoc) +{ + short v2; // dx + char v3; // al + TCmdChItem cmd; // [esp+0h] [ebp-Ch] + + cmd.bLoc = bLoc; + v2 = plr[myplr].HoldItem.IDidx; + cmd.bCmd = CMD_CHANGEPLRITEMS; + cmd.wIndx = v2; + cmd.wCI = plr[myplr].HoldItem._iCreateInfo; + v3 = plr[myplr].HoldItem._iIdentified; + cmd.dwSeed = plr[myplr].HoldItem._iSeed; + cmd.bId = v3; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 0xBu); + else + NetSendLoPri((unsigned char *)&cmd, 0xBu); +} + +void __fastcall NetSendCmdDelItem(BOOL bHiPri, unsigned char bLoc) +{ + TCmdDelItem cmd; // [esp+2h] [ebp-2h] + + cmd.bLoc = bLoc; + cmd.bCmd = CMD_DELPLRITEMS; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 2u); + else + NetSendLoPri((unsigned char *)&cmd, 2u); +} + +void __fastcall NetSendCmdDItem(unsigned char bHiPri, int ii) +{ + int v2; // eax + short *v3; // edx + bool v4; // zf + short v5; // dx + short v6; // bx + int v7; // esi + int v8; // esi + char v9; // dl + short v10; // ax + TCmdPItem cmd; // [esp+4h] [ebp-18h] + + v2 = ii; + cmd.bCmd = CMD_DROPITEM; + cmd.x = item[ii]._ix; + cmd.y = item[ii]._iy; + v3 = (short *)&item[ii].IDidx; + v4 = *(_DWORD *)v3 == IDI_EAR; + cmd.wIndx = *v3; + if ( v4 ) + { + _LOBYTE(v5) = 0; + _HIBYTE(v5) = item[v2]._iName[7]; + _LOBYTE(v6) = 0; + _HIBYTE(v6) = item[v2]._iName[18]; + v7 = item[v2]._iName[10]; + cmd.wCI = item[v2]._iName[8] | v5; + cmd.dwSeed = item[v2]._iName[12] | ((item[v2]._iName[11] | ((v7 | (item[v2]._iName[9] << 8)) << 8)) << 8); + cmd.bId = item[v2]._iName[13]; + cmd.bDur = item[v2]._iName[14]; + cmd.bMDur = item[v2]._iName[15]; + cmd.bCh = item[v2]._iName[16]; + cmd.bMCh = item[v2]._iName[17]; + v8 = item[v2]._iName[20]; + cmd.wValue = _LOWORD(item[v2]._ivalue) | v6 | ((_LOWORD(item[v2]._iCurs) - 19) << 6); + cmd.dwBuff = item[v2]._iName[22] | ((item[v2]._iName[21] | ((v8 | (item[v2]._iName[19] << 8)) << 8)) << 8); + } + else + { + cmd.wCI = item[v2]._iCreateInfo; + cmd.dwSeed = item[v2]._iSeed; + cmd.bId = item[v2]._iIdentified; + cmd.bDur = item[v2]._iDurability; + cmd.bMDur = item[v2]._iMaxDur; + cmd.bCh = item[v2]._iCharges; + v9 = item[v2]._iMaxCharges; + v10 = item[v2]._ivalue; + cmd.bMCh = v9; + cmd.wValue = v10; + } + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 0x16u); + else + NetSendLoPri((unsigned char *)&cmd, 0x16u); +} + +void __fastcall NetSendCmdDamage(unsigned char bHiPri, unsigned char bPlr, unsigned int dwDam) +{ + TCmdDamage cmd; // [esp+0h] [ebp-8h] + + cmd.bPlr = bPlr; + cmd.bCmd = CMD_PLRDAMAGE; + cmd.dwDam = dwDam; + if ( bHiPri ) + NetSendHiPri((unsigned char *)&cmd, 6u); + else + NetSendLoPri((unsigned char *)&cmd, 6u); +} + +void __fastcall NetSendCmdString(int a1, const char *pszStr) +{ + const char *v2; // esi + int v3; // edi + char dwStrLen; // bl + TCmdString cmd; // [esp+Ch] [ebp-54h] + + v2 = pszStr; + v3 = a1; + dwStrLen = strlen(pszStr); + cmd.bCmd = CMD_STRING; + strcpy(cmd.str, v2); + multi_send_msg_packet(v3, &cmd.bCmd, dwStrLen + 2); +} + +void __fastcall RemovePlrPortal(int pnum) +{ + memset(&sgJunk.portal[pnum], 255, 5u); + sgbDeltaChanged = 1; +} +// 67618C: using guessed type char sgbDeltaChanged; + +int __fastcall ParseCmd(int pnum, TCmd *pCmd) +{ + bool v2; // zf + TCmd *v3; // eax + char v4; // dl + unsigned char v5; // bl + int result; // eax + TCmd *v7; // esi + + v2 = sgwPackPlrOffsetTbl[pnum] == 0; + v3 = pCmd; + v4 = pCmd->bCmd; + sbLastCmd = v4; + if ( !v2 && v4 != CMD_ACK_PLRINFO && v4 != CMD_SEND_PLRINFO ) + return 0; + v5 = v3->bCmd; + switch ( v3->bCmd ) + { + case CMD_WALKXY: + return On_WALKXY((struct TCmdLoc *)v3, pnum); + case CMD_ACK_PLRINFO: + return On_ACK_PLRINFO((struct TCmdPlrInfoHdr *)v3, pnum); + case CMD_ADDSTR: + return On_ADDSTR((struct TCmdParam1 *)v3, pnum); + case CMD_ADDMAG: + return On_ADDMAG((struct TCmdParam1 *)v3, pnum); + case CMD_ADDDEX: + return On_ADDDEX((struct TCmdParam1 *)v3, pnum); + case CMD_ADDVIT: + return On_ADDVIT((struct TCmdParam1 *)v3, pnum); + case CMD_SBSPELL: + return On_SBSPELL((struct TCmdParam1 *)v3, pnum); + case CMD_GETITEM: + return On_GETITEM((struct TCmdGItem *)v3, pnum); + case CMD_AGETITEM: + return On_AGETITEM((struct TCmdGItem *)v3, pnum); + case CMD_PUTITEM: + return On_PUTITEM((struct TCmdPItem *)v3, pnum); + case CMD_RESPAWNITEM: + return On_RESPAWNITEM((struct TCmdPItem *)v3, pnum); + case CMD_ATTACKXY: + return On_ATTACKXY((struct TCmdLoc *)v3, pnum); + case CMD_RATTACKXY: + return On_RATTACKXY((struct TCmdLoc *)v3, pnum); + case CMD_SPELLXY: + return On_SPELLXY((struct TCmdLocParam2 *)v3, pnum); + case CMD_TSPELLXY: + return On_TSPELLXY((struct TCmdLocParam2 *)v3, pnum); + case CMD_OPOBJXY: + return On_OPOBJXY((struct TCmdLocParam1 *)v3, pnum); + case CMD_DISARMXY: + return On_DISARMXY((struct TCmdLocParam1 *)v3, pnum); + case CMD_ATTACKID: + return On_ATTACKID((struct TCmdParam1 *)v3, pnum); + case CMD_ATTACKPID: + return On_ATTACKPID((struct TCmdParam1 *)v3, pnum); + case CMD_RATTACKID: + return On_RATTACKID((struct TCmdParam1 *)v3, pnum); + case CMD_RATTACKPID: + return On_RATTACKPID((struct TCmdParam1 *)v3, pnum); + case CMD_SPELLID: + return On_SPELLID((struct TCmdLocParam2 *)v3, pnum); + case CMD_SPELLPID: + return On_SPELLPID((struct TCmdLocParam2 *)v3, pnum); + case CMD_TSPELLID: + return On_TSPELLID((struct TCmdLocParam2 *)v3, pnum); + case CMD_TSPELLPID: + return On_TSPELLPID((struct TCmdLocParam2 *)v3, pnum); + case CMD_RESURRECT: + return On_RESURRECT((struct TCmdParam1 *)v3, pnum); + case CMD_OPOBJT: + return On_OPOBJT((struct TCmdParam1 *)v3, pnum); + case CMD_KNOCKBACK: + return On_KNOCKBACK((struct TCmdParam1 *)v3, pnum); + case CMD_TALKXY: + return On_TALKXY((struct TCmdLocParam1 *)v3, pnum); + case CMD_NEWLVL: + return On_NEWLVL((struct TCmdParam2 *)v3, pnum); + case CMD_WARP: + return On_WARP((struct TCmdParam1 *)v3, pnum); +#ifdef _DEBUG + case CMD_CHEAT_EXPERIENCE: + return On_CHEAT_EXPERIENCE(v3, pnum); + case CMD_CHEAT_SPELL_LEVEL: + return On_CHEAT_SPELL_LEVEL(v3, pnum); +#else + case CMD_CHEAT_EXPERIENCE: + return On_DEBUG(); + case CMD_CHEAT_SPELL_LEVEL: + return On_DEBUG(); +#endif + case CMD_DEBUG: + return On_DEBUG(); + case CMD_SYNCDATA: + return On_SYNCDATA(v3, pnum); + case CMD_MONSTDEATH: + return On_MONSTDEATH((struct TCmdLocParam1 *)v3, pnum); + case CMD_MONSTDAMAGE: + return On_MONSTDAMAGE((struct TCmdLocParam1 *)v3, pnum); + case CMD_PLRDEAD: + return On_PLRDEAD((struct TCmdParam1 *)v3, pnum); + case CMD_REQUESTGITEM: + return On_REQUESTGITEM((struct TCmdGItem *)v3, pnum); + case CMD_REQUESTAGITEM: + return On_REQUESTAGITEM((struct TCmdGItem *)v3, pnum); + case CMD_GOTOGETITEM: + return On_GOTOGETITEM((struct TCmdLocParam1 *)v3, pnum); + case CMD_GOTOAGETITEM: + return On_GOTOAGETITEM((struct TCmdLocParam1 *)v3, pnum); + case CMD_OPENDOOR: + return On_OPENDOOR((struct TCmdParam1 *)v3, pnum); + case CMD_CLOSEDOOR: + return On_CLOSEDOOR((struct TCmdParam1 *)v3, pnum); + case CMD_OPERATEOBJ: + return On_OPERATEOBJ((struct TCmdParam1 *)v3, pnum); + case CMD_PLROPOBJ: + return On_PLROPOBJ((struct TCmdParam2 *)v3, pnum); + case CMD_BREAKOBJ: + return On_BREAKOBJ((struct TCmdParam2 *)v3, pnum); + case CMD_CHANGEPLRITEMS: + return On_CHANGEPLRITEMS((struct TCmdChItem *)v3, pnum); + case CMD_DELPLRITEMS: + return On_DELPLRITEMS((struct TCmdDelItem *)v3, pnum); + case CMD_PLRDAMAGE: + return On_PLRDAMAGE((struct TCmdDamage *)v3, pnum); + case CMD_PLRLEVEL: + return On_PLRLEVEL((struct TCmdParam1 *)v3, pnum); + case CMD_DROPITEM: + return On_DROPITEM((struct TCmdPItem *)v3, pnum); + case CMD_PLAYER_JOINLEVEL: + return On_PLAYER_JOINLEVEL((struct TCmdLocParam1 *)v3, pnum); + case CMD_SEND_PLRINFO: + return On_SEND_PLRINFO((struct TCmdPlrInfoHdr *)v3, pnum); + case CMD_SATTACKXY: + return On_SATTACKXY((struct TCmdLoc *)v3, pnum); + case CMD_ACTIVATEPORTAL: + return On_ACTIVATEPORTAL((DJunk *)v3, pnum); + case CMD_DEACTIVATEPORTAL: + return On_DEACTIVATEPORTAL(v3, pnum); + case CMD_HEALOTHER: + return On_HEALOTHER((struct TCmdParam1 *)v3, pnum); + case CMD_STRING: + return On_STRING((struct TCmdString *)v3, pnum); + case CMD_SETSTR: + return On_SETSTR((struct TCmdParam1 *)v3, pnum); + case CMD_SETMAG: + return On_SETMAG((struct TCmdParam1 *)v3, pnum); + case CMD_SETDEX: + return On_SETDEX((struct TCmdParam1 *)v3, pnum); + case CMD_SETVIT: + return On_SETVIT((struct TCmdParam1 *)v3, pnum); + case CMD_RETOWN: + return On_RETOWN(v3, pnum); + case CMD_SPELLXYD: + return On_SPELLXYD((struct TCmdLocParam3 *)v3, pnum); + case CMD_ITEMEXTRA: + return On_ITEMEXTRA((struct TCmdGItem *)v3, pnum); + case CMD_SYNCPUTITEM: + return On_SYNCPUTITEM((struct TCmdPItem *)v3, pnum); + case CMD_KILLGOLEM: + return On_KILLGOLEM((struct TCmdLocParam1 *)v3, pnum); + case CMD_SYNCQUEST: + return On_SYNCQUEST((struct TCmdQuest *)v3, pnum); + case CMD_ENDSHIELD: + return On_ENDSHIELD((int)v3, pnum); + case CMD_AWAKEGOLEM: + return On_AWAKEGOLEM((struct TCmdGolem *)v3, pnum); + case CMD_NOVA: + return On_NOVA((struct TCmdLoc *)v3, pnum); + case CMD_SETSHIELD: + return On_SETSHIELD((int)v3, pnum); + case CMD_REMSHIELD: + return On_REMSHIELD((int)v3, pnum); + default: + if ( v5 < CMD_DLEVEL_0 || v5 > CMD_DLEVEL_END ) + { + SNetDropPlayer(pnum, 0x40000006); + return 0; + } + v7 = v3; + if ( (unsigned char)gbDeltaSender == pnum ) + { + if ( sgbRecvCmd != CMD_DLEVEL_END ) + { + if ( sgbRecvCmd == v3->bCmd ) + { +LABEL_99: + memcpy(&sgRecvBuf[*(unsigned short *)&v7[1].bCmd], &v7[5], *(unsigned short *)&v7[3].bCmd); + sgdwRecvOffset += *(unsigned short *)&v7[3].bCmd; + goto LABEL_100; + } + DeltaImportData(sgbRecvCmd, sgdwRecvOffset); + if ( v7->bCmd == CMD_DLEVEL_END ) + { + sgbDeltaChunks = 20; + sgbRecvCmd = CMD_DLEVEL_END; + goto LABEL_100; + } + sgdwRecvOffset = 0; +LABEL_98: + sgbRecvCmd = v7->bCmd; + goto LABEL_99; + } + } + else + { + if ( v3->bCmd != CMD_DLEVEL_END && (v3->bCmd != CMD_DLEVEL_0 || *(_WORD *)&v3[1].bCmd) ) + goto LABEL_100; + gbDeltaSender = pnum; + sgbRecvCmd = CMD_DLEVEL_END; + } + if ( v3->bCmd == CMD_DLEVEL_END ) + { + sgbDeltaChunks = 20; + goto LABEL_100; + } + if ( v3->bCmd == CMD_DLEVEL_0 && !*(_WORD *)&v3[1].bCmd ) + { + sgdwRecvOffset = 0; + goto LABEL_98; + } +LABEL_100: + result = *(unsigned short *)&v7[3].bCmd + 5; + break; + } + return result; +} +// 66E4A9: using guessed type char sbLastCmd; +// 67618D: using guessed type char sgbDeltaChunks; +// 6796E4: using guessed type char gbDeltaSender; + +void __fastcall DeltaImportData(unsigned char cmd, int recv_offset) +{ + unsigned char v2; // bl + int v3; // esi + void *v4; // eax + void *v5; // eax + + v2 = cmd; + if ( sgRecvBuf[0] ) + encrypt_decompress(&sgRecvBuf[1], recv_offset, 4721); + if ( v2 == CMD_DLEVEL_JUNK ) + { + DeltaImportJunk((int)&sgRecvBuf[1]); + } + else if ( v2 < CMD_DLEVEL_0 || v2 > CMD_DLEVEL_16 ) + { + TermMsg("msg:1"); + } + else + { + v3 = (unsigned char)(v2 - CMD_DLEVEL_0); + v4 = DeltaImportItem(&sgRecvBuf[1], &sgLevels[v3]); + v5 = DeltaImportObject(v4, sgLevels[v3].object); + DeltaImportMonster(v5, sgLevels[v3].monster); + } + ++sgbDeltaChunks; + sgbDeltaChanged = 1; +} +// 67618C: using guessed type char sgbDeltaChanged; +// 67618D: using guessed type char sgbDeltaChunks; + +void *__fastcall DeltaImportItem(void *src, void *dst) +{ + char *v2; // edi + _BYTE *v3; // esi + signed int v4; // ebx + + v2 = (char *)dst; + v3 = (unsigned char *)src; + v4 = 127; + do + { + if ( *v3 == -1 ) + { + memset(v2, 255, 0x16u); + ++v3; + } + else + { + memcpy(v2, v3, 0x16u); + v3 += 22; + } + v2 += 22; + --v4; + } + while ( v4 ); + return v3; +} + +void *__fastcall DeltaImportObject(void *src, void *dst) +{ + char *v2; // esi + + v2 = (char *)src; + memcpy(dst, src, 0x7Fu); + return v2 + 127; +} + +void *__fastcall DeltaImportMonster(void *src, void *dst) +{ + char *v2; // edi + _BYTE *v3; // esi + signed int v4; // ebx + + v2 = (char *)dst; + v3 = (unsigned char *)src; + v4 = MAXMONSTERS; + do + { + if ( *v3 == -1 ) + { + memset(v2, 255, 9u); + ++v3; + } + else + { + memcpy(v2, v3, 9u); + v3 += 9; + } + v2 += 9; + --v4; + } + while ( v4 ); + return v3; +} + +char __fastcall DeltaImportJunk(int a1) +{ + _BYTE *v1; // ebx + int v2; // edi + DJunk *v3; // esi + char result; // al + MultiQuests *v5; // esi + unsigned char *v6; // edi + int *v7; // ebp + + v1 = (_BYTE *)a1; + v2 = 0; + v3 = &sgJunk; + do + { + if ( *v1 == -1 ) + { + memset(v3, 255, 5u); + ++v1; + SetPortalStats(v2, 0, 0, 0, 0, 0); + } + else + { + memcpy(v3, v1, 5u); + v1 += 5; + SetPortalStats( + v2, + 1, + (unsigned char)v3->portal[0].x, + (unsigned char)v3->portal[0].y, + (unsigned char)v3->portal[0].level, + (unsigned char)v3->portal[0].ltype); + } + v3 = (DJunk *)((char *)v3 + 5); + ++v2; + } + while ( (signed int)v3 < (signed int)sgJunk.quests ); + v5 = sgJunk.quests; + v6 = &quests[0]._qactive; + v7 = &questlist[0]._qflags; + do + { + if ( *(_BYTE *)v7 & 1 ) + { + memcpy(v5, v1, 3u); + *(_DWORD *)(v6 + 18) = (unsigned char)v5->qlog; + *v6 = v5->qstate; + result = v5->qvar1; + v1 += 3; + v6[13] = result; + ++v5; + } + v7 += 5; + v6 += 24; + } + while ( (signed int)v7 < (signed int)&questlist[16]._qflags ); + return result; +} + +int __fastcall On_SYNCDATA(void *packet, int pnum) +{ + return SyncData(pnum, (TSyncHeader *)packet); +} + +int __fastcall On_WALKXY(struct TCmdLoc *pCmd, int pnum) +{ + int v2; // ebx + struct TCmdLoc *v3; // edi + int v4; // esi + + v2 = pnum; + v3 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v4 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + ClrPlrPath(pnum); + MakePlrPath(v2, (unsigned char)v3->x, (unsigned char)v3->y, 1u); + plr[v4].destAction = -1; + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_ADDSTR(struct TCmdParam1 *pCmd, int pnum) +{ + unsigned short v2; // cx + + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v2 = pCmd->wParam1; + if ( v2 <= 0x100u ) + ModifyPlrStr(pnum, v2); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_ADDMAG(struct TCmdParam1 *pCmd, int pnum) +{ + unsigned short v2; // cx + + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v2 = pCmd->wParam1; + if ( v2 <= 0x100u ) + ModifyPlrMag(pnum, v2); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_ADDDEX(struct TCmdParam1 *pCmd, int pnum) +{ + unsigned short v2; // cx + + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v2 = pCmd->wParam1; + if ( v2 <= 0x100u ) + ModifyPlrDex(pnum, v2); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_ADDVIT(struct TCmdParam1 *pCmd, int pnum) +{ + unsigned short v2; // cx + + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v2 = pCmd->wParam1; + if ( v2 <= 0x100u ) + ModifyPlrVit(pnum, v2); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SBSPELL(struct TCmdParam1 *pCmd, int pnum) +{ + int v2; // eax + + if ( gbBufferMsgs != 1 ) + { + if ( currlevel || *(_DWORD *)&spelldata[(unsigned short)pCmd->wParam1].sTownSpell ) + { + v2 = pnum; + plr[v2]._pSpell = (unsigned short)pCmd->wParam1; + plr[v2]._pSplType = plr[v2]._pSBkSplType; + plr[v2]._pSplFrom = 1; + plr[v2].destAction = 12; + } + else + { + msg_errorf("%s has cast an illegal spell.", plr[pnum]._pName); + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +void msg_errorf(char *pszFmt, ...) +{ + DWORD v1; // eax + char v2[256]; // [esp+0h] [ebp-100h] + va_list va; // [esp+10Ch] [ebp+Ch] + + va_start(va, pszFmt); + v1 = GetTickCount(); + if ( v1 - msg_err_timer >= 5000 ) + { + msg_err_timer = v1; + vsprintf(v2, pszFmt, va); + ErrorPlrMsg(v2); + } +} +// 67619C: using guessed type int msg_err_timer; + +int __fastcall On_GOTOGETITEM(struct TCmdLocParam1 *pCmd, int pnum) +{ + struct TCmdLocParam1 *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + MakePlrPath(pnum, (unsigned char)pCmd->x, (unsigned char)pCmd->y, 0); + plr[v3].destAction = 15; + plr[v3].destParam1 = (unsigned short)v2->wParam1; + } + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_REQUESTGITEM(struct TCmdGItem *pCmd, int pnum) +{ + struct TCmdGItem *v2; // esi + int v4; // edx + int v5; // edx + int v7; // edi + unsigned char v8; // al + int v9; // edx + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + if ( i_own_level(plr[pnum].plrlevel) ) + { + _LOWORD(v4) = v2->wCI; + if ( GetItemRecord(v2->dwSeed, v4, (unsigned short)v2->wIndx) ) + { + _LOWORD(v5) = v2->wCI; + v7 = FindGetItem((unsigned short)v2->wIndx, v5, v2->dwSeed); + v8 = v2->bPnum; + if ( v7 == -1 ) + { + if ( !NetSendCmdReq2(CMD_REQUESTGITEM, myplr, v8, v2) ) + NetSendCmdExtra(v2); + } + else + { + NetSendCmdGItem2(0, CMD_GETITEM, myplr, v8, v2); + if ( (unsigned char)v2->bPnum == myplr ) + InvGetItem(myplr, v7); + else + SyncGetItem( + (unsigned char)v2->x, + (unsigned char)v2->y, + (unsigned short)v2->wIndx, + v2->wCI, + v2->dwSeed); + _LOWORD(v9) = v2->wCI; + SetItemRecord(v2->dwSeed, v9, (unsigned short)v2->wIndx); + } + } + } + } + return 30; +} +// 676194: using guessed type char gbBufferMsgs; + +bool __fastcall i_own_level(int nReqLevel) +{ + int v1; // edx + unsigned char *v2; // eax + + v1 = 0; + v2 = &plr[0]._pLvlChanging; + do + { + if ( *(v2 - 290) && !*v2 && *(_DWORD *)(v2 - 267) == nReqLevel && (v1 != myplr || !gbBufferMsgs) ) + break; + v2 += 21720; + ++v1; + } + while ( (signed int)v2 < (signed int)&plr[4]._pLvlChanging ); + return v1 == myplr; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_GETITEM(struct TCmdGItem *pCmd, int pnum) +{ + struct TCmdGItem *v2; // esi + int v4; // edi + char v6; // al + int v7; // ecx + int v8; // edx + int v9; // eax + int v10; // edx + + v2 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet((unsigned short)pnum, pCmd, 30); + } + else + { + v4 = FindGetItem((unsigned short)pCmd->wIndx, pCmd->wCI, pCmd->dwSeed); + if ( !delta_get_item(v2, v2->bLevel) ) + { + NetSendCmdGItem2(1u, CMD_GETITEM, v2->bMaster, v2->bPnum, v2); + return 30; + } + v6 = v2->bLevel; + v7 = myplr; + if ( (currlevel == v6 || (unsigned char)v2->bPnum == myplr) && (unsigned char)v2->bMaster != myplr ) + { + if ( (unsigned char)v2->bPnum != myplr ) + { + SyncGetItem( + (unsigned char)v2->x, + (unsigned char)v2->y, + (unsigned short)v2->wIndx, + v2->wCI, + v2->dwSeed); + return 30; + } + if ( currlevel == v6 ) + { + v10 = v4; + } + else + { + v8 = (unsigned char)v2->bId; + _LOWORD(v8) = v2->wCI; + v9 = SyncPutItem( + myplr, + plr[myplr].WorldX, + plr[myplr].WorldY, + (unsigned short)v2->wIndx, + v8, + v2->dwSeed, + (unsigned char)v2->bId, + (unsigned char)v2->bDur, + (unsigned char)v2->bMDur, + (unsigned char)v2->bCh, + (unsigned char)v2->bMCh, + (unsigned short)v2->wValue, + v2->dwBuff); + if ( v9 == -1 ) + return 30; + v7 = myplr; + v10 = v9; + } + InvGetItem(v7, v10); + return 30; + } + } + return 30; +} +// 676194: using guessed type char gbBufferMsgs; + +bool __fastcall delta_get_item(struct TCmdGItem *pI, unsigned char bLevel) +{ + struct TCmdGItem *v2; // esi + signed int v3; // ecx + DLevel *v4; // edi + DLevel *v5; // eax + char v6; // cl + DLevel *v8; // eax + signed int v9; // ecx + + v2 = pI; + if ( gbMaxPlayers != 1 ) + { + v3 = 0; + v4 = &sgLevels[bLevel]; + v5 = &sgLevels[bLevel]; + while ( v5->item[0].bCmd == -1 + || v5->item[0].wIndx != v2->wIndx + || v5->item[0].wCI != v2->wCI + || v5->item[0].dwSeed != v2->dwSeed ) + { + ++v3; + v5 = (DLevel *)((char *)v5 + 22); + if ( v3 >= 127 ) + goto LABEL_15; + } + v6 = v5->item[0].bCmd; + if ( v5->item[0].bCmd == 1 ) + return 1; + if ( !v6 ) + { + sgbDeltaChanged = 1; + v5->item[0].bCmd = 1; + return 1; + } + if ( v6 == 2 ) + { + v5->item[0].bCmd = -1; + sgbDeltaChanged = 1; + return 1; + } + TermMsg("delta:1"); +LABEL_15: + if ( v2->wCI >= 0 ) + return 0; + v8 = v4; + v9 = 0; + while ( v8->item[0].bCmd != -1 ) + { + ++v9; + v8 = (DLevel *)((char *)v8 + 22); + if ( v9 >= 127 ) + return 1; + } + sgbDeltaChanged = 1; + v8->item[0].bCmd = 1; + v8->item[0].x = v2->x; + v8->item[0].y = v2->y; + v8->item[0].wIndx = v2->wIndx; + v8->item[0].wCI = v2->wCI; + v8->item[0].dwSeed = v2->dwSeed; + v8->item[0].bId = v2->bId; + v8->item[0].bDur = v2->bDur; + v8->item[0].bMDur = v2->bMDur; + v8->item[0].bCh = v2->bCh; + v8->item[0].bMCh = v2->bMCh; + v8->item[0].wValue = v2->wValue; + v8->item[0].dwBuff = v2->dwBuff; + } + return 1; +} +// 67618C: using guessed type char sgbDeltaChanged; +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall On_GOTOAGETITEM(struct TCmdLocParam1 *pCmd, int pnum) +{ + struct TCmdLocParam1 *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + MakePlrPath(pnum, (unsigned char)pCmd->x, (unsigned char)pCmd->y, 0); + plr[v3].destAction = 16; + plr[v3].destParam1 = (unsigned short)v2->wParam1; + } + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_REQUESTAGITEM(struct TCmdGItem *pCmd, int pnum) +{ + struct TCmdGItem *v2; // esi + int v4; // edx + int v5; // edx + int v7; // zf + unsigned char v8; // al + int v9; // edx + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + if ( i_own_level(plr[pnum].plrlevel) ) + { + _LOWORD(v4) = v2->wCI; + if ( GetItemRecord(v2->dwSeed, v4, (unsigned short)v2->wIndx) ) + { + _LOWORD(v5) = v2->wCI; + v7 = FindGetItem((unsigned short)v2->wIndx, v5, v2->dwSeed); + v8 = v2->bPnum; + if ( v7 == -1 ) + { + if ( !NetSendCmdReq2(CMD_REQUESTAGITEM, myplr, v8, v2) ) + NetSendCmdExtra(v2); + } + else + { + NetSendCmdGItem2(0, CMD_AGETITEM, myplr, v8, v2); + if ( (unsigned char)v2->bPnum == myplr ) + AutoGetItem(myplr, (unsigned char)v2->bCursitem); + else + SyncGetItem( + (unsigned char)v2->x, + (unsigned char)v2->y, + (unsigned short)v2->wIndx, + v2->wCI, + v2->dwSeed); + _LOWORD(v9) = v2->wCI; + SetItemRecord(v2->dwSeed, v9, (unsigned short)v2->wIndx); + } + } + } + } + return 30; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_AGETITEM(struct TCmdGItem *pCmd, int pnum) +{ + struct TCmdGItem *v2; // esi + char v4; // al + int v5; // ecx + int v6; // edx + int v7; // eax + int v8; // edx + + v2 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet((unsigned short)pnum, pCmd, 30); + } + else + { + FindGetItem((unsigned short)pCmd->wIndx, pCmd->wCI, pCmd->dwSeed); + if ( !delta_get_item(v2, v2->bLevel) ) + { + NetSendCmdGItem2(1u, CMD_AGETITEM, v2->bMaster, v2->bPnum, v2); + return 30; + } + v4 = v2->bLevel; + v5 = myplr; + if ( (currlevel == v4 || (unsigned char)v2->bPnum == myplr) && (unsigned char)v2->bMaster != myplr ) + { + if ( (unsigned char)v2->bPnum != myplr ) + { + SyncGetItem( + (unsigned char)v2->x, + (unsigned char)v2->y, + (unsigned short)v2->wIndx, + v2->wCI, + v2->dwSeed); + return 30; + } + if ( currlevel == v4 ) + { + v8 = (unsigned char)v2->bCursitem; + } + else + { + v6 = (unsigned char)v2->bId; + _LOWORD(v6) = v2->wCI; + v7 = SyncPutItem( + myplr, + plr[myplr].WorldX, + plr[myplr].WorldY, + (unsigned short)v2->wIndx, + v6, + v2->dwSeed, + (unsigned char)v2->bId, + (unsigned char)v2->bDur, + (unsigned char)v2->bMDur, + (unsigned char)v2->bCh, + (unsigned char)v2->bMCh, + (unsigned short)v2->wValue, + v2->dwBuff); + if ( v7 == -1 ) + return 30; + v5 = myplr; + v8 = v7; + } + AutoGetItem(v5, v8); + return 30; + } + } + return 30; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_ITEMEXTRA(struct TCmdGItem *pCmd, int pnum) +{ + int v2; // edi + struct TCmdGItem *v3; // esi + + v2 = pnum; + v3 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 30); + } + else + { + delta_get_item(pCmd, pCmd->bLevel); + if ( currlevel == plr[v2].plrlevel ) + SyncGetItem( + (unsigned char)v3->x, + (unsigned char)v3->y, + (unsigned short)v3->wIndx, + v3->wCI, + v3->dwSeed); + } + return 30; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_PUTITEM(struct TCmdPItem *pCmd, int pnum) +{ + int v2; // edi + struct TCmdPItem *v3; // esi + unsigned char *v4; // ebx + int v5; // edx + int v6; // eax + int v7; // edx + int v8; // ebp + + v2 = pnum; + v3 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 22); + return 22; + } + v4 = (unsigned char *)&plr[pnum].plrlevel; + if ( currlevel != *(_DWORD *)v4 ) + { + _LOWORD(pnum) = pCmd->wCI; + PutItemRecord(pCmd->dwSeed, pnum, (unsigned short)pCmd->wIndx); + delta_put_item(v3, (unsigned char)v3->x, (unsigned char)v3->y, *v4); + check_update_plr(v2); + return 22; + } + v5 = (unsigned char)pCmd->x; + if ( v2 == myplr ) + v6 = InvPutItem(v2, v5, (unsigned char)pCmd->y); + else + v6 = SyncPutItem( + v2, + v5, + (unsigned char)pCmd->y, + (unsigned short)pCmd->wIndx, + (unsigned short)pCmd->wCI, + pCmd->dwSeed, + (unsigned char)pCmd->bId, + (unsigned char)pCmd->bDur, + (unsigned char)pCmd->bMDur, + (unsigned char)pCmd->bCh, + (unsigned char)pCmd->bMCh, + (unsigned short)pCmd->wValue, + pCmd->dwBuff); + v8 = v6; + if ( v6 != -1 ) + { + _LOWORD(v7) = v3->wCI; + PutItemRecord(v3->dwSeed, v7, (unsigned short)v3->wIndx); + delta_put_item(v3, item[v8]._ix, item[v8]._iy, *v4); + check_update_plr(v2); + } + return 22; +} +// 676194: using guessed type char gbBufferMsgs; + +void __fastcall delta_put_item(struct TCmdPItem *pI, int x, int y, unsigned char bLevel) +{ + struct TCmdPItem *v4; // ebx + int v5; // eax + DLevel *v6; // esi + DLevel *v7; // edi + char v8; // al + signed int v9; // eax + char v10; // [esp+Ch] [ebp-4h] + signed int bLevela; // [esp+1Ch] [ebp+Ch] + + v10 = x; + v4 = pI; + if ( gbMaxPlayers != 1 ) + { + v5 = bLevel; + bLevela = 0; + v6 = &sgLevels[v5]; + v7 = &sgLevels[v5]; + do + { + v8 = v7->item[0].bCmd; + if ( v7->item[0].bCmd != 1 + && v8 != -1 + && v7->item[0].wIndx == v4->wIndx + && v7->item[0].wCI == v4->wCI + && v7->item[0].dwSeed == v4->dwSeed ) + { + if ( v8 == 2 ) + return; + TermMsg("Trying to drop a floor item?"); + } + ++bLevela; + v7 = (DLevel *)((char *)v7 + 22); + } + while ( bLevela < 127 ); + v9 = 0; + while ( v6->item[0].bCmd != -1 ) + { + ++v9; + v6 = (DLevel *)((char *)v6 + 22); + if ( v9 >= 127 ) + return; + } + sgbDeltaChanged = 1; + memcpy(v6, v4, 0x16u); + v6->item[0].x = v10; + v6->item[0].bCmd = 2; + v6->item[0].y = y; + } +} +// 67618C: using guessed type char sgbDeltaChanged; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall check_update_plr(int pnum) +{ + if ( gbMaxPlayers != 1 && pnum == myplr ) + pfile_update(1); +} +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall On_SYNCPUTITEM(struct TCmdPItem *pCmd, int pnum) +{ + int v2; // ebx + struct TCmdPItem *v3; // esi + unsigned char *v4; // edi + int v5; // edx + int v6; // ebp + + v2 = pnum; + v3 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 22); + return 22; + } + v4 = (unsigned char *)&plr[pnum].plrlevel; + if ( currlevel != *(_DWORD *)v4 ) + { + _LOWORD(pnum) = pCmd->wCI; + PutItemRecord(pCmd->dwSeed, pnum, (unsigned short)pCmd->wIndx); + delta_put_item(v3, (unsigned char)v3->x, (unsigned char)v3->y, *v4); + check_update_plr(v2); + return 22; + } + v6 = SyncPutItem( + pnum, + (unsigned char)pCmd->x, + (unsigned char)pCmd->y, + (unsigned short)pCmd->wIndx, + (unsigned short)pCmd->wCI, + pCmd->dwSeed, + (unsigned char)pCmd->bId, + (unsigned char)pCmd->bDur, + (unsigned char)pCmd->bMDur, + (unsigned char)pCmd->bCh, + (unsigned char)pCmd->bMCh, + (unsigned short)pCmd->wValue, + pCmd->dwBuff); + if ( v6 != -1 ) + { + _LOWORD(v5) = v3->wCI; + PutItemRecord(v3->dwSeed, v5, (unsigned short)v3->wIndx); + delta_put_item(v3, item[v6]._ix, item[v6]._iy, *v4); + check_update_plr(v2); + } + return 22; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_RESPAWNITEM(struct TCmdPItem *pCmd, int pnum) +{ + struct TCmdPItem *v2; // esi + unsigned char *v3; // edi + + v2 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 22); + } + else + { + v3 = (unsigned char *)&plr[pnum].plrlevel; + if ( currlevel == *(_DWORD *)v3 && pnum != myplr ) + SyncPutItem( + pnum, + (unsigned char)pCmd->x, + (unsigned char)pCmd->y, + (unsigned short)pCmd->wIndx, + (unsigned short)pCmd->wCI, + pCmd->dwSeed, + (unsigned char)pCmd->bId, + (unsigned char)pCmd->bDur, + (unsigned char)pCmd->bMDur, + (unsigned char)pCmd->bCh, + (unsigned char)pCmd->bMCh, + (unsigned short)pCmd->wValue, + pCmd->dwBuff); + _LOWORD(pnum) = v2->wCI; + PutItemRecord(v2->dwSeed, pnum, (unsigned short)v2->wIndx); + delta_put_item(v2, (unsigned char)v2->x, (unsigned char)v2->y, *v3); + } + return 22; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_ATTACKXY(struct TCmdLoc *pCmd, int pnum) +{ + struct TCmdLoc *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + MakePlrPath(pnum, (unsigned char)pCmd->x, (unsigned char)pCmd->y, 0); + plr[v3].destAction = 9; + plr[v3].destParam1 = (unsigned char)v2->x; + plr[v3].destParam2 = (unsigned char)v2->y; + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SATTACKXY(struct TCmdLoc *pCmd, int pnum) +{ + struct TCmdLoc *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 9; + plr[v3].destParam1 = (unsigned char)v2->x; + plr[v3].destParam2 = (unsigned char)v2->y; + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_RATTACKXY(struct TCmdLoc *pCmd, int pnum) +{ + struct TCmdLoc *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 10; + plr[v3].destParam1 = (unsigned char)v2->x; + plr[v3].destParam2 = (unsigned char)v2->y; + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SPELLXYD(struct TCmdLocParam3 *pCmd, int pnum) +{ + struct TCmdLocParam3 *v2; // edi + int v3; // esi + int v4; // eax + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + if ( currlevel || *(_DWORD *)&spelldata[(unsigned short)pCmd->wParam1].sTownSpell ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 26; + plr[v3].destParam1 = (unsigned char)v2->x; + plr[v3].destParam2 = (unsigned char)v2->y; + plr[v3].destParam3 = (unsigned short)v2->wParam2; + plr[v3].destParam4 = (unsigned short)v2->wParam3; + v4 = (unsigned short)v2->wParam1; + plr[v3]._pSplFrom = 0; + plr[v3]._pSpell = v4; + plr[v3]._pSplType = plr[v3]._pRSplType; + } + else + { + msg_errorf("%s has cast an illegal spell.", plr[v3]._pName); + } + } + } + return 9; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SPELLXY(struct TCmdLocParam2 *pCmd, int pnum) +{ + struct TCmdLocParam2 *v2; // edi + int v3; // esi + int v4; // eax + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + if ( currlevel || *(_DWORD *)&spelldata[(unsigned short)pCmd->wParam1].sTownSpell ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 12; + plr[v3].destParam1 = (unsigned char)v2->x; + plr[v3].destParam2 = (unsigned char)v2->y; + plr[v3].destParam3 = (unsigned short)v2->wParam2; + v4 = (unsigned short)v2->wParam1; + plr[v3]._pSplFrom = 0; + plr[v3]._pSpell = v4; + plr[v3]._pSplType = plr[v3]._pRSplType; + } + else + { + msg_errorf("%s has cast an illegal spell.", plr[v3]._pName); + } + } + } + return 7; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_TSPELLXY(struct TCmdLocParam2 *pCmd, int pnum) +{ + struct TCmdLocParam2 *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + if ( currlevel || *(_DWORD *)&spelldata[(unsigned short)pCmd->wParam1].sTownSpell ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 12; + plr[v3].destParam1 = (unsigned char)v2->x; + plr[v3].destParam2 = (unsigned char)v2->y; + plr[v3].destParam3 = (unsigned short)v2->wParam2; + plr[v3]._pSpell = (unsigned short)v2->wParam1; + plr[v3]._pSplType = plr[v3]._pTSplType; + plr[v3]._pSplFrom = 2; + } + else + { + msg_errorf("%s has cast an illegal spell.", plr[v3]._pName); + } + } + } + return 7; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_OPOBJXY(struct TCmdLocParam1 *pCmd, int pnum) +{ + struct TCmdLocParam1 *v2; // esi + int v3; // edi + int v4; // eax + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + v4 = (unsigned short)pCmd->wParam1; + if ( object[v4]._oSolidFlag || object[v4]._oDoorFlag ) + MakePlrPath(pnum, (unsigned char)pCmd->x, (unsigned char)pCmd->y, 0); + else + MakePlrPath(pnum, (unsigned char)pCmd->x, (unsigned char)pCmd->y, 1u); + plr[v3].destAction = 13; + plr[v3].destParam1 = (unsigned short)v2->wParam1; + } + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_DISARMXY(struct TCmdLocParam1 *pCmd, int pnum) +{ + struct TCmdLocParam1 *v2; // esi + int v3; // edi + int v4; // eax + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + v4 = (unsigned short)pCmd->wParam1; + if ( object[v4]._oSolidFlag || object[v4]._oDoorFlag ) + MakePlrPath(pnum, (unsigned char)pCmd->x, (unsigned char)pCmd->y, 0); + else + MakePlrPath(pnum, (unsigned char)pCmd->x, (unsigned char)pCmd->y, 1u); + plr[v3].destAction = 14; + plr[v3].destParam1 = (unsigned short)v2->wParam1; + } + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_OPOBJT(struct TCmdParam1 *pCmd, int pnum) +{ + int v2; // eax + + if ( gbBufferMsgs != 1 ) + { + v2 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + plr[v2].destAction = 18; + plr[v2].destParam1 = (unsigned short)pCmd->wParam1; + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_ATTACKID(struct TCmdParam1 *pCmd, int pnum) +{ + int v2; // ebp + struct TCmdParam1 *v3; // edi + int v4; // esi + int v5; // ebx + int v6; // eax + + v2 = pnum; + v3 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v4 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + v5 = abs(plr[v4].WorldX - monster[(unsigned short)pCmd->wParam1]._mfutx); + v6 = abs(plr[v4].WorldY - monster[(unsigned short)v3->wParam1]._mfuty); + if ( v5 > 1 || v6 > 1 ) + MakePlrPath( + v2, + monster[(unsigned short)v3->wParam1]._mfutx, + monster[(unsigned short)v3->wParam1]._mfuty, + 0); + plr[v4].destAction = 20; + plr[v4].destParam1 = (unsigned short)v3->wParam1; + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_ATTACKPID(struct TCmdParam1 *pCmd, int pnum) +{ + struct TCmdParam1 *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + MakePlrPath(pnum, plr[(unsigned short)pCmd->wParam1]._px, plr[(unsigned short)pCmd->wParam1]._py, 0); + plr[v3].destAction = 21; + plr[v3].destParam1 = (unsigned short)v2->wParam1; + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_RATTACKID(struct TCmdParam1 *pCmd, int pnum) +{ + struct TCmdParam1 *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 22; + plr[v3].destParam1 = (unsigned short)v2->wParam1; + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_RATTACKPID(struct TCmdParam1 *pCmd, int pnum) +{ + struct TCmdParam1 *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 23; + plr[v3].destParam1 = (unsigned short)v2->wParam1; + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SPELLID(struct TCmdLocParam2 *pCmd, int pnum) +{ + struct TCmdLocParam2 *v2; // edi + int v3; // esi + int v4; // eax + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + if ( currlevel || *(_DWORD *)&spelldata[(unsigned short)pCmd->wParam1].sTownSpell ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 24; + plr[v3].destParam1 = *(unsigned short *)&v2->x; + plr[v3].destParam2 = (unsigned short)v2->wParam2; + v4 = (unsigned short)v2->wParam1; + plr[v3]._pSplFrom = 0; + plr[v3]._pSpell = v4; + plr[v3]._pSplType = plr[v3]._pRSplType; + } + else + { + msg_errorf("%s has cast an illegal spell.", plr[v3]._pName); + } + } + } + return 7; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SPELLPID(struct TCmdLocParam2 *pCmd, int pnum) +{ + struct TCmdLocParam2 *v2; // edi + int v3; // esi + int v4; // eax + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + if ( currlevel || *(_DWORD *)&spelldata[(unsigned short)pCmd->wParam1].sTownSpell ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 25; + plr[v3].destParam1 = *(unsigned short *)&v2->x; + plr[v3].destParam2 = (unsigned short)v2->wParam2; + v4 = (unsigned short)v2->wParam1; + plr[v3]._pSplFrom = 0; + plr[v3]._pSpell = v4; + plr[v3]._pSplType = plr[v3]._pRSplType; + } + else + { + msg_errorf("%s has cast an illegal spell.", plr[v3]._pName); + } + } + } + return 7; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_TSPELLID(struct TCmdLocParam2 *pCmd, int pnum) +{ + struct TCmdLocParam2 *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + if ( currlevel || *(_DWORD *)&spelldata[(unsigned short)pCmd->wParam1].sTownSpell ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 24; + plr[v3].destParam1 = *(unsigned short *)&v2->x; + plr[v3].destParam2 = (unsigned short)v2->wParam2; + plr[v3]._pSpell = (unsigned short)v2->wParam1; + plr[v3]._pSplType = plr[v3]._pTSplType; + plr[v3]._pSplFrom = 2; + } + else + { + msg_errorf("%s has cast an illegal spell.", plr[v3]._pName); + } + } + } + return 7; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_TSPELLPID(struct TCmdLocParam2 *pCmd, int pnum) +{ + struct TCmdLocParam2 *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + if ( currlevel || *(_DWORD *)&spelldata[(unsigned short)pCmd->wParam1].sTownSpell ) + { + ClrPlrPath(pnum); + plr[v3].destAction = 25; + plr[v3].destParam1 = *(unsigned short *)&v2->x; + plr[v3].destParam2 = (unsigned short)v2->wParam2; + plr[v3]._pSpell = (unsigned short)v2->wParam1; + plr[v3]._pSplType = plr[v3]._pTSplType; + plr[v3]._pSplFrom = 2; + } + else + { + msg_errorf("%s has cast an illegal spell.", plr[v3]._pName); + } + } + } + return 7; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_KNOCKBACK(struct TCmdParam1 *pCmd, int pnum) +{ + int v2; // edi + struct TCmdParam1 *v3; // esi + + v2 = pnum; + v3 = pCmd; + if ( gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel ) + { + M_GetKnockback((unsigned short)pCmd->wParam1); + M_StartHit((unsigned short)v3->wParam1, v2, 0); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_RESURRECT(struct TCmdParam1 *pCmd, int pnum) +{ + int v2; // esi + + v2 = pnum; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + DoResurrect(pnum, (unsigned short)pCmd->wParam1); + check_update_plr(v2); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_HEALOTHER(struct TCmdParam1 *pCmd, int pnum) +{ + if ( gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel ) + DoHealOther(pnum, (unsigned short)pCmd->wParam1); + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_TALKXY(struct TCmdLocParam1 *pCmd, int pnum) +{ + struct TCmdLocParam1 *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + MakePlrPath(pnum, (unsigned char)pCmd->x, (unsigned char)pCmd->y, 0); + plr[v3].destAction = 17; + plr[v3].destParam1 = (unsigned short)v2->wParam1; + } + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_NEWLVL(struct TCmdParam2 *pCmd, int pnum) +{ + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 5); + } + else if ( pnum != myplr ) + { + StartNewLvl(pnum, (unsigned short)pCmd->wParam1, (unsigned short)pCmd->wParam2); + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_WARP(struct TCmdParam1 *pCmd, int pnum) +{ + int v2; // esi + + v2 = pnum; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + StartWarpLvl(pnum, (unsigned short)pCmd->wParam1); + if ( v2 == myplr && pcurs >= CURSOR_FIRSTITEM ) + { + qmemcpy(&item[127], &plr[myplr].HoldItem, sizeof(ItemStruct)); + AutoGetItem(myplr, 127); + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_MONSTDEATH(struct TCmdLocParam1 *pCmd, int pnum) +{ + struct TCmdLocParam1 *v2; // esi + unsigned char *v3; // edi + + v2 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 5); + } + else if ( pnum != myplr ) + { + v3 = (unsigned char *)&plr[pnum].plrlevel; + if ( currlevel == *(_DWORD *)v3 ) + M_SyncStartKill((unsigned short)pCmd->wParam1, (unsigned char)pCmd->x, (unsigned char)pCmd->y, pnum); + delta_kill_monster((unsigned short)v2->wParam1, v2->x, v2->y, *v3); + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_KILLGOLEM(struct TCmdLocParam1 *pCmd, int pnum) +{ + int v2; // edi + struct TCmdLocParam1 *v3; // esi + + v2 = pnum; + v3 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 5); + } + else if ( pnum != myplr ) + { + if ( currlevel == pCmd->wParam1 ) + M_SyncStartKill(pnum, (unsigned char)pCmd->x, (unsigned char)pCmd->y, pnum); + delta_kill_monster(v2, v3->x, v3->y, plr[v2].plrlevel); + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_AWAKEGOLEM(struct TCmdGolem *pCmd, int pnum) +{ + int v2; // esi + int v3; // eax + signed int v4; // ebp + int v5; // edi + int v6; // edx + + v2 = pnum; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 10); + } + else + { + v3 = 21720 * pnum; + if ( currlevel == plr[pnum].plrlevel ) + { + if ( pnum != myplr ) + { + v4 = 1; + v5 = 0; + if ( nummissiles <= 0 ) + goto LABEL_16; + do + { + v6 = missileactive[v5]; + if ( missile[v6]._mitype == MIS_GOLEM && missile[v6]._misource == v2 ) + v4 = 0; + ++v5; + } + while ( v5 < nummissiles ); + if ( v4 ) +LABEL_16: + AddMissile( + *(int *)((char *)&plr[0].WorldX + v3), + *(int *)((char *)&plr[0].WorldY + v3), + (unsigned char)pCmd->_mx, + (unsigned char)pCmd->_my, + (unsigned char)pCmd->_mdir, + MIS_GOLEM, + 0, + v2, + 0, + 1); + } + } + else + { + _LOBYTE(v3) = pCmd->_currlevel; + delta_sync_golem(pCmd, pnum, v3); + } + } + return 10; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_MONSTDAMAGE(struct TCmdLocParam1 *pCmd, int pnum) +{ + int v2; // edi + struct TCmdLocParam1 *v3; // edx + unsigned char *v4; // ebx + char *v5; // esi + int *v6; // ecx + int *v7; // eax + + v2 = pnum; + v3 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(v2, pCmd, 5); + } + else if ( v2 != myplr ) + { + v4 = (unsigned char *)&plr[v2].plrlevel; + if ( currlevel == *(_DWORD *)v4 ) + { + v5 = &monster[*(unsigned short *)&pCmd->x].mWhoHit; + *v5 |= 1 << v2; + v6 = &monster[*(unsigned short *)&pCmd->x]._mhitpoints; + if ( *v6 ) + { + *v6 -= (unsigned short)v3->wParam1; + v7 = &monster[*(unsigned short *)&v3->x]._mhitpoints; + if ( (signed int)(*v7 & 0xFFFFFFC0) < 64 ) + *v7 = 64; + delta_monster_hp(*(unsigned short *)&v3->x, monster[*(unsigned short *)&v3->x]._mhitpoints, *v4); + } + } + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_PLRDEAD(struct TCmdParam1 *pCmd, int pnum) +{ + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else if ( pnum == myplr ) + { + check_update_plr(pnum); + } + else + { + StartPlayerKill(pnum, (unsigned short)pCmd->wParam1); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_PLRDAMAGE(struct TCmdDamage *pCmd, int pnum) +{ + int v2; // edi + int v3; // eax + int v4; // esi + int *v5; // esi + int v6; // ecx + + v2 = myplr; + if ( (unsigned char)pCmd->bPlr == myplr ) + { + if ( currlevel ) + { + if ( gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel && pCmd->dwDam <= 0x2EE00u ) + { + v3 = myplr; + v4 = plr[myplr]._pHitPoints; + if ( (signed int)(v4 & 0xFFFFFFC0) > 0 ) + { + drawhpflag = 1; + plr[v3]._pHitPoints = v4 - pCmd->dwDam; + v5 = &plr[v3]._pHPBase; + *v5 -= pCmd->dwDam; + v6 = plr[v3]._pMaxHP; + if ( plr[v3]._pHitPoints > v6 ) + { + plr[v3]._pHitPoints = v6; + *v5 = plr[v3]._pMaxHPBase; + } + if ( (signed int)(plr[v3]._pHitPoints & 0xFFFFFFC0) <= 0 ) + SyncPlrKill(v2, 1); + } + } + } + } + return 6; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_OPENDOOR(struct TCmdParam1 *pCmd, int pnum) +{ + struct TCmdParam1 *v2; // edi + unsigned char *v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v3 = (unsigned char *)&plr[pnum].plrlevel; + if ( currlevel == *(_DWORD *)v3 ) + SyncOpObject(pnum, CMD_OPENDOOR, (unsigned short)pCmd->wParam1); + delta_sync_object((unsigned short)v2->wParam1, 0x2Bu, *v3); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +void __fastcall delta_sync_object(int oi, unsigned char bCmd, unsigned char bLevel) +{ + if ( gbMaxPlayers != 1 ) + { + sgbDeltaChanged = 1; + sgLevels[bLevel].object[oi].bCmd = bCmd; + } +} +// 67618C: using guessed type char sgbDeltaChanged; +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall On_CLOSEDOOR(struct TCmdParam1 *pCmd, int pnum) +{ + struct TCmdParam1 *v2; // edi + unsigned char *v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v3 = (unsigned char *)&plr[pnum].plrlevel; + if ( currlevel == *(_DWORD *)v3 ) + SyncOpObject(pnum, CMD_CLOSEDOOR, (unsigned short)pCmd->wParam1); + delta_sync_object((unsigned short)v2->wParam1, 0x2Cu, *v3); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_OPERATEOBJ(struct TCmdParam1 *pCmd, int pnum) +{ + struct TCmdParam1 *v2; // edi + unsigned char *v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v3 = (unsigned char *)&plr[pnum].plrlevel; + if ( currlevel == *(_DWORD *)v3 ) + SyncOpObject(pnum, CMD_OPERATEOBJ, (unsigned short)pCmd->wParam1); + delta_sync_object((unsigned short)v2->wParam1, 0x2Du, *v3); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_PLROPOBJ(struct TCmdParam2 *pCmd, int pnum) +{ + struct TCmdParam2 *v2; // esi + unsigned char *v3; // edi + + v2 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 5); + } + else + { + v3 = (unsigned char *)&plr[pnum].plrlevel; + if ( currlevel == *(_DWORD *)v3 ) + SyncOpObject((unsigned short)pCmd->wParam1, CMD_PLROPOBJ, (unsigned short)pCmd->wParam2); + delta_sync_object((unsigned short)v2->wParam2, 0x2Eu, *v3); + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_BREAKOBJ(struct TCmdParam2 *pCmd, int pnum) +{ + struct TCmdParam2 *v2; // esi + unsigned char *v3; // edi + + v2 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 5); + } + else + { + v3 = (unsigned char *)&plr[pnum].plrlevel; + if ( currlevel == *(_DWORD *)v3 ) + SyncBreakObj((unsigned short)pCmd->wParam1, (unsigned short)pCmd->wParam2); + delta_sync_object((unsigned short)v2->wParam2, 0x2Fu, *v3); + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_CHANGEPLRITEMS(struct TCmdChItem *pCmd, int pnum) +{ + int v2; // eax + int v3; // edx + int v4; // ST04_4 + int v5; // edx + + v2 = pnum; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 11); + } + else if ( pnum != myplr ) + { + v3 = (unsigned char)pCmd->bId; + _LOWORD(v3) = pCmd->wCI; + v4 = v3; + v5 = (unsigned short)pCmd->wIndx; + _LOBYTE(v5) = pCmd->bLoc; + CheckInvSwap(v2, v5, (unsigned short)pCmd->wIndx, v4, pCmd->dwSeed, (unsigned char)pCmd->bId); + } + return 11; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_DELPLRITEMS(struct TCmdDelItem *pCmd, int pnum) +{ + int v2; // eax + + v2 = pnum; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 2); + } + else if ( pnum != myplr ) + { + _LOBYTE(pnum) = pCmd->bLoc; + inv_update_rem_item(v2, pnum); + } + return 2; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_PLRLEVEL(struct TCmdParam1 *pCmd, int pnum) +{ + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else if ( pCmd->wParam1 <= 0x33u && pnum != myplr ) + { + plr[pnum]._pLevel = pCmd->wParam1; + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_DROPITEM(struct TCmdPItem *pCmd, int pnum) +{ + if ( gbBufferMsgs == 1 ) + msg_send_packet(pnum, pCmd, 22); + else + delta_put_item(pCmd, (unsigned char)pCmd->x, (unsigned char)pCmd->y, plr[pnum].plrlevel); + return 22; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SEND_PLRINFO(struct TCmdPlrInfoHdr *pCmd, int pnum) +{ + struct TCmdPlrInfoHdr *v2; // esi + + v2 = pCmd; + if ( gbBufferMsgs == 1 ) + msg_send_packet(pnum, pCmd, (unsigned short)pCmd->wBytes + 5); + else + multi_player_joins(pnum, pCmd, pCmd->bCmd == 2); + return (unsigned short)v2->wBytes + 5; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_ACK_PLRINFO(struct TCmdPlrInfoHdr *pCmd, int pnum) +{ + return On_SEND_PLRINFO(pCmd, pnum); +} + +int __fastcall On_PLAYER_JOINLEVEL(struct TCmdLocParam1 *pCmd, int pnum) +{ + int v2; // ebx + struct TCmdLocParam1 *v3; // edi + int v4; // esi + int v5; // ecx + int v6; // ST08_4 + unsigned char *v7; // edx + int v8; // eax + int v9; // ecx + int v10; // eax + int v11; // eax + + v2 = pnum; + v3 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 5); + } + else + { + v4 = pnum; + plr[pnum]._pLvlChanging = 0; + if ( plr[pnum]._pName[0] && !plr[v4].plractive ) + { + plr[v4].plractive = 1; + ++gbActivePlayers; + EventPlrMsg("Player '%s' (level %d) just joined the game", plr[pnum]._pName, plr[v4]._pLevel); + } + if ( plr[v4].plractive ) + { + if ( myplr != v2 ) + { + plr[v4].WorldX = (unsigned char)v3->x; + plr[v4].WorldY = (unsigned char)v3->y; + v5 = (unsigned short)v3->wParam1; + plr[v4]._pGFXLoad = 0; + plr[v4].plrlevel = v5; + if ( currlevel == plr[v4].plrlevel ) + { + LoadPlrGFX(v2, PFILE_STAND); + SyncInitPlr(v2); + if ( (signed int)(plr[v4]._pHitPoints & 0xFFFFFFC0) <= 0 ) + { + plr[v4]._pgfxnum = 0; + LoadPlrGFX(v2, PFILE_DEATH); + v6 = plr[v4]._pDWidth; + v7 = plr[v4]._pDAnim[0]; + plr[v4]._pmode = PM_DEATH; + NewPlrAnim(v2, v7, plr[v4]._pDFrames, 1, v6); + v8 = plr[v4]._pAnimLen; + v9 = v8 - 1; + plr[v4]._pVar8 = 2 * v8; + v10 = plr[v4].WorldX; + plr[v4]._pAnimFrame = v9; + dFlags[v10][plr[v4].WorldY] |= 4u; + } + else + { + StartStand(v2, 0); + } + v11 = AddVision(plr[v4].WorldX, plr[v4].WorldY, plr[v4]._pLightRad, v2 == myplr); + plr[v4]._plid = -1; + plr[v4]._pvid = v11; + } + } + } + } + return 5; +} +// 676194: using guessed type char gbBufferMsgs; +// 67862C: using guessed type char gbActivePlayers; + +int __fastcall On_ACTIVATEPORTAL(DJunk *pCmd, int pnum) +{ + signed int v2; // ebx + int v3; // edi + DJunk *v4; // esi + int v5; // eax + int v6; // edx + int v7; // ecx + int v8; // ST0C_4 + int v9; // ST08_4 + int v10; // ST04_4 + + v2 = 1; + v3 = pnum; + v4 = pCmd; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 9); + } + else + { + ActivatePortal( + pnum, + (unsigned char)pCmd->portal[0].y, + (unsigned char)pCmd->portal[0].level, + *(unsigned short *)&pCmd->portal[0].ltype, + *(unsigned short *)&pCmd->portal[1].x, + *(unsigned short *)&pCmd->portal[1].level); + if ( v3 != myplr ) + { + if ( currlevel ) + { + if ( currlevel == plr[v3].plrlevel ) + { + v6 = nummissiles; + v7 = 0; + if ( nummissiles <= 0 ) + goto LABEL_19; + do + { + v5 = 176 * missileactive[v7]; + if ( *(int *)((char *)&missile[0]._mitype + v5) == MIS_TOWN + && *(int *)((char *)&missile[0]._misource + v5) == v3 ) + { + v2 = 0; + } + ++v7; + } + while ( v7 < nummissiles ); + if ( v2 ) +LABEL_19: + AddWarpMissile(v3, (unsigned char)v4->portal[0].y, (unsigned char)v4->portal[0].level); + } + else + { + RemovePortalMissile(v3); + } + } + else + { + AddInTownPortal(v3); + } + } + _LOBYTE(v5) = v4->portal[1].level; + _LOBYTE(v6) = v4->portal[0].y; + v8 = v5; + _LOBYTE(v5) = v4->portal[1].x; + v9 = v5; + _LOBYTE(v5) = v4->portal[0].ltype; + v10 = v5; + _LOBYTE(v5) = v4->portal[0].level; + delta_open_portal(v3, v6, v5, v10, v9, v8); + } + return 9; +} +// 676194: using guessed type char gbBufferMsgs; + +void __fastcall delta_open_portal(int pnum, int x, int y, int bLevel, int bLType, int bSetLvl) +{ + int v6; // eax + + v6 = pnum; + sgbDeltaChanged = 1; + sgJunk.portal[v6].y = y; + sgJunk.portal[v6].level = bLevel; + sgJunk.portal[v6].ltype = bLType; + sgJunk.portal[v6].x = x; + sgJunk.portal[v6].setlvl = bSetLvl; +} +// 67618C: using guessed type char sgbDeltaChanged; + +int __fastcall On_DEACTIVATEPORTAL(struct TCmd *pCmd, int pnum) +{ + int v2; // esi + + v2 = pnum; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 1); + } + else + { + if ( PortalOnLevel(pnum) ) + RemovePortalMissile(v2); + DeactivatePortal(v2); + RemovePlrPortal(v2); + } + return 1; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_RETOWN(struct TCmd *pCmd, int pnum) +{ + int v2; // esi + + v2 = pnum; + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 1); + } + else + { + if ( pnum == myplr ) + { + deathflag = 0; + gamemenu_off(); + } + RestartTownLvl(v2); + } + return 1; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SETSTR(struct TCmdParam1 *pCmd, int pnum) +{ + unsigned short v2; // cx + + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v2 = pCmd->wParam1; + if ( v2 <= 0x2EEu && pnum != myplr ) + SetPlrStr(pnum, v2); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SETDEX(struct TCmdParam1 *pCmd, int pnum) +{ + unsigned short v2; // cx + + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v2 = pCmd->wParam1; + if ( v2 <= 0x2EEu && pnum != myplr ) + SetPlrDex(pnum, v2); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SETMAG(struct TCmdParam1 *pCmd, int pnum) +{ + unsigned short v2; // cx + + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v2 = pCmd->wParam1; + if ( v2 <= 0x2EEu && pnum != myplr ) + SetPlrMag(pnum, v2); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SETVIT(struct TCmdParam1 *pCmd, int pnum) +{ + unsigned short v2; // cx + + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 3); + } + else + { + v2 = pCmd->wParam1; + if ( v2 <= 0x2EEu && pnum != myplr ) + SetPlrVit(pnum, v2); + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_STRING(struct TCmdString *pCmd, int pnum) +{ + const char *v2; // esi + int v3; // edi + size_t v4; // ebx + + v2 = pCmd->str; + v3 = pnum; + v4 = strlen(pCmd->str); + if ( !gbBufferMsgs ) + SendPlrMsg(v3, v2); + return v4 + 2; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SYNCQUEST(struct TCmdQuest *pCmd, int pnum) +{ + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 5); + } + else + { + if ( pnum != myplr ) + SetMultiQuest( + (unsigned char)pCmd->q, + (unsigned char)pCmd->qstate, + pCmd->qlog, + (unsigned char)pCmd->qvar1); + sgbDeltaChanged = 1; + } + return 5; +} +// 67618C: using guessed type char sgbDeltaChanged; +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_ENDSHIELD(int a1, int pnum) +{ + int v2; // ebx + int i; // esi + int v4; // edi + int v5; // eax + + v2 = pnum; + if ( gbBufferMsgs != 1 && pnum != myplr && currlevel == plr[pnum].plrlevel ) + { + for ( i = 0; i < nummissiles; ++i ) + { + v4 = missileactive[i]; + v5 = missileactive[i]; + if ( missile[v5]._mitype == MIS_MANASHIELD && missile[v5]._misource == v2 ) + { + ClearMissileSpot(missileactive[i]); + DeleteMissile(v4, i); + } + } + } + return 1; +} +// 676194: using guessed type char gbBufferMsgs; + +#ifdef _DEBUG +int __fastcall On_CHEAT_EXPERIENCE(struct TCmd *pCmd, int pnum) +{ + if ( gbBufferMsgs == 1 ) + { + msg_send_packet(pnum, pCmd, 1); + } + else if ( plr[pnum]._pLevel < 50 ) + { + plr[pnum]._pExperience = plr[pnum]._pNextExper; + NextPlrLevel(pnum); + } + return 1; +} + +int __fastcall On_CHEAT_SPELL_LEVEL(struct TCmd *pCmd, int pnum) +{ + if ( gbBufferMsgs == 1 ) + msg_send_packet(pnum, pCmd, 1); + else + plr[pnum]._pSplLvl[plr[pnum]._pRSpell]++; + + return 1; +} +#endif + +int __cdecl On_DEBUG() +{ + return 1; +} + +int __fastcall On_NOVA(struct TCmdLoc *pCmd, int pnum) +{ + struct TCmdLoc *v2; // edi + int v3; // esi + + v2 = pCmd; + if ( gbBufferMsgs != 1 ) + { + v3 = pnum; + if ( currlevel == plr[pnum].plrlevel && pnum != myplr ) + { + ClrPlrPath(pnum); + plr[v3]._pSpell = SPL_NOVA; + plr[v3]._pSplType = 4; + plr[v3]._pSplFrom = 3; + plr[v3].destAction = 12; + plr[v3].destParam1 = (unsigned char)v2->x; + plr[v3].destParam2 = (unsigned char)v2->y; + } + } + return 3; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_SETSHIELD(int unused, int pnum) +{ + int result; // eax + + result = 1; + if ( gbBufferMsgs != 1 ) + plr[pnum].pManaShield = 1; + return result; +} +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall On_REMSHIELD(int unused, int pnum) +{ + int result; // eax + + result = 1; + if ( gbBufferMsgs != 1 ) + plr[pnum].pManaShield = 0; + return result; +} +// 676194: using guessed type char gbBufferMsgs; diff --git a/Source/msg.h b/Source/msg.h new file mode 100644 index 000000000..1223d7ad0 --- /dev/null +++ b/Source/msg.h @@ -0,0 +1,165 @@ +//HEADER_GOES_HERE +#ifndef __MSG_H__ +#define __MSG_H__ + +extern int sgdwOwnerWait; // weak +extern int msg_cpp_init_value; // weak +extern int sgdwRecvOffset; // idb +extern int sgnCurrMegaPlayer; // weak +extern DLevel sgLevels[NUMLEVELS]; +extern char sbLastCmd; // weak +extern TMegaPkt *sgpCurrPkt; +extern char sgRecvBuf[4722]; +extern unsigned char sgbRecvCmd; // idb +extern LocalLevel sgLocals[NUMLEVELS]; +extern DJunk sgJunk; +extern TMegaPkt *sgpMegaPkt; +extern char sgbDeltaChanged; // weak +extern char sgbDeltaChunks; // weak +extern int deltaload; // weak +extern char gbBufferMsgs; // weak +extern int dword_676198; // weak +extern int msg_err_timer; // weak + +void __cdecl msg_cpp_init(); +void __fastcall msg_send_drop_pkt(int pnum, int reason); +void __fastcall msg_send_packet(int pnum, void *packet, int dwSize); +TMegaPkt *__cdecl msg_get_next_packet(); +int __cdecl msg_wait_resync(); +void __cdecl msg_free_packets(); +int __cdecl msg_wait_for_turns(); +void __cdecl msg_process_net_packets(); +void __cdecl msg_pre_packet(); +void __fastcall DeltaExportData(int pnum); +void *__fastcall DeltaExportItem(void *dst, void *src); +void *__fastcall DeltaExportObject(void *dst, void *src); +void *__fastcall DeltaExportMonster(void *dst, void *src); +char *__fastcall DeltaExportJunk(char *a1); +int __fastcall msg_comp_level(char *buffer, int size); +void __cdecl delta_init(); +void __fastcall delta_kill_monster(int mi, unsigned char x, unsigned char y, unsigned char bLevel); +void __fastcall delta_monster_hp(int mi, int hp, unsigned char bLevel); +void __fastcall delta_sync_monster(TCmdLocParam1 *packet, char level); +void __fastcall delta_sync_golem(TCmdGolem *pG, int pnum, int bLevel); +void __fastcall delta_leave_sync(unsigned char bLevel); +bool __fastcall delta_portal_inited(int i); +bool __fastcall delta_quest_inited(int i); +void __fastcall DeltaAddItem(int ii); +void __cdecl DeltaSaveLevel(); +void __cdecl DeltaLoadLevel(); +void __fastcall NetSendCmd(unsigned char bHiPri, unsigned char bCmd); +void __fastcall NetSendCmdGolem(unsigned char mx, unsigned char my, unsigned char dir, unsigned char menemy, int hp, int cl); +void __fastcall NetSendCmdLoc(unsigned char bHiPri, unsigned char bCmd, unsigned char x, unsigned char y); +void __fastcall NetSendCmdLocParam1(unsigned char bHiPri, unsigned char bCmd, unsigned char x, unsigned char y, int wParam1); +void __fastcall NetSendCmdLocParam2(unsigned char bHiPri, unsigned char bCmd, unsigned char x, unsigned char y, int wParam1, int wParam2); +void __fastcall NetSendCmdLocParam3(unsigned char bHiPri, unsigned char bCmd, unsigned char x, unsigned char y, int wParam1, int wParam2, int wParam3); +void __fastcall NetSendCmdParam1(BOOL bHiPri, unsigned char bCmd, unsigned short wParam1); +void __fastcall NetSendCmdParam2(BOOL bHiPri, unsigned char bCmd, unsigned short wParam1, unsigned short wParam2); +void __fastcall NetSendCmdParam3(unsigned char bHiPri, unsigned char bCmd, unsigned short wParam1, unsigned short wParam2, int wParam3); +void __fastcall NetSendCmdQuest(unsigned char bHiPri, unsigned char q); +void __fastcall NetSendCmdGItem(unsigned char bHiPri, unsigned char bCmd, unsigned char mast, unsigned char pnum, int ii); +void __fastcall NetSendCmdGItem2(unsigned char usonly, unsigned char bCmd, unsigned char mast, unsigned char pnum, struct TCmdGItem *p); +bool __fastcall NetSendCmdReq2(unsigned char bCmd, unsigned char mast, unsigned char pnum, struct TCmdGItem *p); +void __fastcall NetSendCmdExtra(struct TCmdGItem *p); +void __fastcall NetSendCmdPItem(unsigned char bHiPri, unsigned char bCmd, unsigned char x, unsigned char y); +void __fastcall NetSendCmdChItem(unsigned char bHiPri, unsigned char bLoc); +void __fastcall NetSendCmdDelItem(BOOL bHiPri, unsigned char bLoc); +void __fastcall NetSendCmdDItem(unsigned char bHiPri, int ii); +void __fastcall NetSendCmdDamage(unsigned char bHiPri, unsigned char bPlr, unsigned int dwDam); +void __fastcall NetSendCmdString(int a1, const char *pszStr); +void __fastcall RemovePlrPortal(int pnum); +int __fastcall ParseCmd(int pnum, TCmd *pCmd); +void __fastcall DeltaImportData(unsigned char cmd, int recv_offset); +void *__fastcall DeltaImportItem(void *src, void *dst); +void *__fastcall DeltaImportObject(void *src, void *dst); +void *__fastcall DeltaImportMonster(void *src, void *dst); +char __fastcall DeltaImportJunk(int a1); +int __fastcall On_SYNCDATA(void *packet, int pnum); +int __fastcall On_WALKXY(struct TCmdLoc *pCmd, int pnum); +int __fastcall On_ADDSTR(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_ADDMAG(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_ADDDEX(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_ADDVIT(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_SBSPELL(struct TCmdParam1 *pCmd, int pnum); +void msg_errorf(char *pszFmt, ...); +int __fastcall On_GOTOGETITEM(struct TCmdLocParam1 *pCmd, int pnum); +int __fastcall On_REQUESTGITEM(struct TCmdGItem *pCmd, int pnum); +bool __fastcall i_own_level(int nReqLevel); +int __fastcall On_GETITEM(struct TCmdGItem *pCmd, int pnum); +bool __fastcall delta_get_item(struct TCmdGItem *pI, unsigned char bLevel); +int __fastcall On_GOTOAGETITEM(struct TCmdLocParam1 *pCmd, int pnum); +int __fastcall On_REQUESTAGITEM(struct TCmdGItem *pCmd, int pnum); +int __fastcall On_AGETITEM(struct TCmdGItem *pCmd, int pnum); +int __fastcall On_ITEMEXTRA(struct TCmdGItem *pCmd, int pnum); +int __fastcall On_PUTITEM(struct TCmdPItem *pCmd, int pnum); +void __fastcall delta_put_item(struct TCmdPItem *pI, int x, int y, unsigned char bLevel); +void __fastcall check_update_plr(int pnum); +int __fastcall On_SYNCPUTITEM(struct TCmdPItem *pCmd, int pnum); +int __fastcall On_RESPAWNITEM(struct TCmdPItem *pCmd, int pnum); +int __fastcall On_ATTACKXY(struct TCmdLoc *pCmd, int pnum); +int __fastcall On_SATTACKXY(struct TCmdLoc *pCmd, int pnum); +int __fastcall On_RATTACKXY(struct TCmdLoc *pCmd, int pnum); +int __fastcall On_SPELLXYD(struct TCmdLocParam3 *pCmd, int pnum); +int __fastcall On_SPELLXY(struct TCmdLocParam2 *pCmd, int pnum); +int __fastcall On_TSPELLXY(struct TCmdLocParam2 *pCmd, int pnum); +int __fastcall On_OPOBJXY(struct TCmdLocParam1 *pCmd, int pnum); +int __fastcall On_DISARMXY(struct TCmdLocParam1 *pCmd, int pnum); +int __fastcall On_OPOBJT(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_ATTACKID(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_ATTACKPID(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_RATTACKID(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_RATTACKPID(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_SPELLID(struct TCmdLocParam2 *pCmd, int pnum); +int __fastcall On_SPELLPID(struct TCmdLocParam2 *pCmd, int pnum); +int __fastcall On_TSPELLID(struct TCmdLocParam2 *pCmd, int pnum); +int __fastcall On_TSPELLPID(struct TCmdLocParam2 *pCmd, int pnum); +int __fastcall On_KNOCKBACK(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_RESURRECT(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_HEALOTHER(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_TALKXY(struct TCmdLocParam1 *pCmd, int pnum); +int __fastcall On_NEWLVL(struct TCmdParam2 *pCmd, int pnum); +int __fastcall On_WARP(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_MONSTDEATH(struct TCmdLocParam1 *pCmd, int pnum); +int __fastcall On_KILLGOLEM(struct TCmdLocParam1 *pCmd, int pnum); +int __fastcall On_AWAKEGOLEM(struct TCmdGolem *pCmd, int pnum); +int __fastcall On_MONSTDAMAGE(struct TCmdLocParam1 *pCmd, int pnum); +int __fastcall On_PLRDEAD(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_PLRDAMAGE(struct TCmdDamage *pCmd, int pnum); +int __fastcall On_OPENDOOR(struct TCmdParam1 *pCmd, int pnum); +void __fastcall delta_sync_object(int oi, unsigned char bCmd, unsigned char bLevel); +int __fastcall On_CLOSEDOOR(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_OPERATEOBJ(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_PLROPOBJ(struct TCmdParam2 *pCmd, int pnum); +int __fastcall On_BREAKOBJ(struct TCmdParam2 *pCmd, int pnum); +int __fastcall On_CHANGEPLRITEMS(struct TCmdChItem *pCmd, int pnum); +int __fastcall On_DELPLRITEMS(struct TCmdDelItem *pCmd, int pnum); +int __fastcall On_PLRLEVEL(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_DROPITEM(struct TCmdPItem *pCmd, int pnum); +int __fastcall On_SEND_PLRINFO(struct TCmdPlrInfoHdr *pCmd, int pnum); +int __fastcall On_ACK_PLRINFO(struct TCmdPlrInfoHdr *pCmd, int pnum); +int __fastcall On_PLAYER_JOINLEVEL(struct TCmdLocParam1 *pCmd, int pnum); +int __fastcall On_ACTIVATEPORTAL(DJunk *pCmd, int pnum); +void __fastcall delta_open_portal(int pnum, int x, int y, int bLevel, int bLType, int bSetLvl); +int __fastcall On_DEACTIVATEPORTAL(struct TCmd *pCmd, int pnum); +int __fastcall On_RETOWN(struct TCmd *pCmd, int pnum); +int __fastcall On_SETSTR(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_SETDEX(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_SETMAG(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_SETVIT(struct TCmdParam1 *pCmd, int pnum); +int __fastcall On_STRING(struct TCmdString *pCmd, int pnum); +int __fastcall On_SYNCQUEST(struct TCmdQuest *pCmd, int pnum); +int __fastcall On_ENDSHIELD(int a1, int pnum); +#ifdef _DEBUG +int __fastcall On_CHEAT_EXPERIENCE(struct TCmd *pCmd, int pnum); +int __fastcall On_CHEAT_SPELL_LEVEL(struct TCmd *pCmd, int pnum); +#endif +int __cdecl On_DEBUG(); +int __fastcall On_NOVA(struct TCmdLoc *pCmd, int pnum); +int __fastcall On_SETSHIELD(int unused, int pnum); +int __fastcall On_REMSHIELD(int unused, int pnum); + +/* rdata */ + +extern const int msg_inf; // weak + +#endif /* __MSG_H__ */ diff --git a/Source/msgcmd.cpp b/Source/msgcmd.cpp new file mode 100644 index 000000000..5c9a212d1 --- /dev/null +++ b/Source/msgcmd.cpp @@ -0,0 +1,274 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +/* TODO: decompile and fix, commands are NOT deleted properly */ + +int msgcmd_cpp_init_value; // weak +#ifndef NO_GLOBALS +ChatCmd sgChat_Cmd; +int sgdwMsgCmdTimer; +#endif + +const int msgcmd_inf = 0x7F800000; // weak + +struct msgcmd_cpp_init_1 +{ + msgcmd_cpp_init_1() + { + msgcmd_cpp_init_value = msgcmd_inf; + } +} _msgcmd_cpp_init_1; +// 47F150: using guessed type int msgcmd_inf; +// 6761A0: using guessed type int msgcmd_cpp_init_value; + +struct msgcmd_cpp_init_2 +{ + msgcmd_cpp_init_2() + { + msgcmd_init_event(); + msgcmd_cleanup_chatcmd_atexit(); + } +} _msgcmd_cpp_init_2; + +void __cdecl msgcmd_init_event() +{ + msgcmd_init_chatcmd(&sgChat_Cmd); +} + +void __cdecl msgcmd_cleanup_chatcmd_atexit() +{ + atexit(msgcmd_cleanup_chatcmd); +} + +void __cdecl msgcmd_cleanup_chatcmd() +{ + msgcmd_cleanup_chatcmd_1(&sgChat_Cmd); + msgcmd_cleanup_extern_msg(sgChat_Cmd.extern_msgs); +} + +void __cdecl msgcmd_cmd_cleanup() +{ + msgcmd_free_event(&sgChat_Cmd); +} + +void __cdecl msgcmd_send_chat() +{ + ServerCommand *v0; // esi + int v1; // eax + + if ( (signed int)sgChat_Cmd.extern_msgs[1] > 0 ) + { + v0 = sgChat_Cmd.extern_msgs[1]; + v1 = GetTickCount(); + if ( (unsigned int)(v1 - sgdwMsgCmdTimer) >= 2000 ) + { + sgdwMsgCmdTimer = v1; + SNetSendServerChatCommand(v0->command); + msgcmd_delete_server_cmd_W(&sgChat_Cmd, v0); + } + } +} + +bool __fastcall msgcmd_add_server_cmd_W(char *chat_message) +{ + if ( *chat_message != '/' ) + return 0; + msgcmd_add_server_cmd(chat_message); + return 1; +} + +void __fastcall msgcmd_add_server_cmd(char *command) +{ + char *v1; // edi + size_t v2; // eax + int v3; // edx + size_t v4; // esi + ChatCmd *v5; // eax + + v1 = command; + v2 = strlen(command); + if ( v2 ) + { + v4 = v2 + 1; + if ( v2 + 1 <= 0x80 ) + { + v5 = msgcmd_alloc_event(&sgChat_Cmd, v3, 2, 0, 0); + memcpy(&v5->extern_msgs[1], v1, v4); + } + } +} + +void __fastcall msgcmd_init_chatcmd(ChatCmd *chat_cmd) +{ + ServerCommand **v1; // edx + + v1 = chat_cmd->extern_msgs; + *v1 = 0; + v1[1] = 0; + *v1 = (ServerCommand *)v1; + chat_cmd->next = 0; + chat_cmd->extern_msgs[1] = (ServerCommand *)~(unsigned int)chat_cmd->extern_msgs; +} + +void __fastcall msgcmd_free_event(ChatCmd *a1) +{ + int v1; // edx + ChatCmd *v2; // edi + ChatCmd *v3; // esi + + v2 = a1; + while ( 1 ) + { + v3 = (ChatCmd *)v2->extern_msgs[1]; + if ( (signed int)v3 <= 0 ) + break; + msgcmd_remove_event(v3, v1); + SMemFree(v3, ".?AUEXTERNMESSAGE@@", -2, 0); + } +} + +bool __fastcall msgcmd_delete_server_cmd_W(ChatCmd *cmd, ServerCommand *extern_msg) +{ + char *v2; // eax + ServerCommand *v3; // eax + bool v4; // si + ChatCmd *ptr; // [esp+Ch] [ebp+4h] + + v2 = (char *)ptr; + if ( !ptr ) + v2 = (char *)cmd->extern_msgs; + v3 = (ServerCommand *)*((_DWORD *)v2 + 1); + if ( (signed int)v3 > 0 ) + v4 = (char)v3; + else + v4 = 0; + msgcmd_remove_event(ptr, (int)extern_msg); + SMemFree(ptr, ".?AUEXTERNMESSAGE@@", -2, 0); + return v4; +} + +ChatCmd *__fastcall msgcmd_alloc_event(ChatCmd *a1, int a2, int a3, int a4, int a5) +{ + int v5; // eax + ChatCmd *v6; // edi + ChatCmd *v7; // eax + int v8; // edx + ChatCmd *v9; // esi + + v5 = a5; + _LOBYTE(v5) = a5 | 8; + v6 = a1; + v7 = (ChatCmd *)SMemAlloc(a4 + 136, ".?AUEXTERNMESSAGE@@", -2, v5); + if ( v7 ) + { + v7->next = 0; + v7->extern_msgs[0] = 0; + v9 = v7; + } + else + { + v9 = 0; + } + if ( a3 ) + msgcmd_event_type(v6, v8, (int *)v9, a3, 0); + return v9; +} + +void __fastcall msgcmd_remove_event(ChatCmd *a1, int a2) +{ + ServerCommand **v2; // esi + + v2 = (ServerCommand **)a1; + msgcmd_cleanup_extern_msg((ServerCommand **)a1); + msgcmd_cleanup_extern_msg(v2); + if ( a2 & 1 ) + { + if ( v2 ) + SMemFree(v2, "delete", -1, 0); + } +} + +void __fastcall msgcmd_event_type(ChatCmd *a1, int a2, int *a3, int a4, int a5) +{ + ChatCmd *v5; // edi + int *v6; // esi + int *v7; // eax + int v8; // ecx + int v9; // edx + int v10; // ecx + int v11; // edx + + v5 = a1; + v6 = a3; + if ( !a3 ) + v6 = (int *)a1->extern_msgs; + if ( *v6 ) + msgcmd_cleanup_extern_msg((ServerCommand **)v6); + v7 = (int *)a5; + if ( !a5 ) + v7 = (int *)v5->extern_msgs; + if ( a4 == 1 ) + { + *v6 = (int)v7; + v6[1] = v7[1]; + v9 = v7[1]; + v10 = (int)v5->next; + if ( v9 > 0 ) + { + if ( v10 < 0 ) + v10 = (int)v7 - *(_DWORD *)(*v7 + 4); + v11 = v10 + v9; + } + else + { + v11 = ~v9; + } + *(_DWORD *)v11 = (unsigned int)v6; + v7[1] = (int)a3; + } + else if ( a4 == 2 ) + { + v8 = *v7; + *v6 = *v7; + v6[1] = *(_DWORD *)(v8 + 4); + *(_DWORD *)(v8 + 4) = (unsigned int)a3; + *v7 = (int)v6; + } +} + +void __fastcall msgcmd_cleanup_chatcmd_1(ChatCmd *a1) +{ + ChatCmd *v1; // esi + ServerCommand **v2; // ecx + + v1 = a1; + while ( 1 ) + { + v2 = (ServerCommand **)v1->extern_msgs[1]; + if ( (signed int)v2 <= 0 ) + break; + msgcmd_cleanup_extern_msg(v2); + } +} + +void __fastcall msgcmd_cleanup_extern_msg(ServerCommand **extern_msgs) +{ + ServerCommand *v1; // esi + signed int v2; // edx + int v3; // edx + + v1 = *extern_msgs; + if ( *extern_msgs ) + { + v2 = (signed int)extern_msgs[1]; + if ( v2 > 0 ) + v3 = (int)extern_msgs + v2 - v1->field_4; + else + v3 = ~v2; + *(_DWORD *)v3 = (unsigned int)v1; + (*extern_msgs)->field_4 = (int)extern_msgs[1]; + *extern_msgs = 0; + extern_msgs[1] = 0; + } +} diff --git a/Source/msgcmd.h b/Source/msgcmd.h new file mode 100644 index 000000000..2384e667a --- /dev/null +++ b/Source/msgcmd.h @@ -0,0 +1,31 @@ +//HEADER_GOES_HERE +#ifndef __MSGCMD_H__ +#define __MSGCMD_H__ + +extern int msgcmd_cpp_init_value; // weak +extern ChatCmd sgChat_Cmd; +extern int sgdwMsgCmdTimer; + +void __cdecl msgcmd_cpp_init_1(); +void __cdecl msgcmd_cpp_init_2(); +void __cdecl msgcmd_init_event(); +void __cdecl msgcmd_cleanup_chatcmd_atexit(); +void __cdecl msgcmd_cleanup_chatcmd(); +void __cdecl msgcmd_cmd_cleanup(); +void __cdecl msgcmd_send_chat(); +bool __fastcall msgcmd_add_server_cmd_W(char *chat_message); +void __fastcall msgcmd_add_server_cmd(char *command); +void __fastcall msgcmd_init_chatcmd(ChatCmd *chat_cmd); +void __fastcall msgcmd_free_event(ChatCmd *a1); +bool __fastcall msgcmd_delete_server_cmd_W(ChatCmd *cmd, ServerCommand *extern_msg); +ChatCmd *__fastcall msgcmd_alloc_event(ChatCmd *a1, int a2, int a3, int a4, int a5); +void __fastcall msgcmd_remove_event(ChatCmd *a1, int a2); +void __fastcall msgcmd_event_type(ChatCmd *a1, int a2, int *a3, int a4, int a5); +void __fastcall msgcmd_cleanup_chatcmd_1(ChatCmd *a1); +void __fastcall msgcmd_cleanup_extern_msg(ServerCommand **extern_msgs); + +/* rdata */ + +extern const int msgcmd_inf; // weak + +#endif /* __MSGCMD_H__ */ diff --git a/Source/multi.cpp b/Source/multi.cpp new file mode 100644 index 000000000..16833af33 --- /dev/null +++ b/Source/multi.cpp @@ -0,0 +1,1159 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +char gbSomebodyWonGameKludge; // weak +char pkdata_6761C0[4100]; +char szPlayerDescript[128]; +short sgwPackPlrOffsetTbl[MAX_PLRS]; +PkPlayerStruct netplr[MAX_PLRS]; +char sgbPlayerTurnBitTbl[MAX_PLRS]; +char sgbPlayerLeftGameTbl[MAX_PLRS]; +int multi_cpp_init_value; // weak +int sgbSentThisCycle; // idb +int dword_678628; // weak +char gbActivePlayers; // weak +char gbGameDestroyed; // weak +char sgbSendDeltaTbl[MAX_PLRS]; +_gamedata sgGameInitInfo; +char byte_678640; // weak +int sglTimeoutStart; // weak +int sgdwPlayerLeftReasonTbl[MAX_PLRS]; +char pkdata_678658[4100]; +unsigned int sgdwGameLoops; // idb +UCHAR gbMaxPlayers; // weak +char sgbTimeout; // weak +char szPlayerName[128]; +char gbDeltaSender; // weak +int sgbNetInited; // weak +int player_state[MAX_PLRS]; +#endif + +const int multi_inf = 0x7F800000; // weak +const int event_types[3] = +{ + EVENT_TYPE_PLAYER_LEAVE_GAME, + EVENT_TYPE_PLAYER_CREATE_GAME, + EVENT_TYPE_PLAYER_MESSAGE +}; + +struct multi_cpp_init +{ + multi_cpp_init() + { + multi_cpp_init_value = multi_inf; + } +} _multi_cpp_init; +// 47F154: using guessed type int multi_inf; +// 678620: using guessed type int multi_cpp_init_value; + +void __fastcall multi_msg_add(unsigned char *a1, unsigned char a2) +{ + if ( a1 ) + { + if ( a2 ) + tmsg_add(a1, a2); + } +} + +void __fastcall NetSendLoPri(unsigned char *pbMsg, unsigned char bLen) +{ + unsigned char *v2; // esi + unsigned char v3; // bl + int v4; // edx + + v2 = pbMsg; + v3 = bLen; + if ( pbMsg ) + { + if ( bLen ) + { + multi_copy_packet(pkdata_678658, pbMsg, bLen); + _LOBYTE(v4) = v3; + multi_send_packet(v2, v4); + } + } +} + +void __fastcall multi_copy_packet(void *a1, void *packet, int size) +{ + int v3; // eax + int v4; // ebx + char *v5; // esi + + v3 = *(_DWORD *)a1; + v4 = *(_DWORD *)a1 + (unsigned char)size; + if ( (unsigned int)(v4 + 2) <= 0x1000 ) + { + *(_DWORD *)a1 = v4 + 1; + *((_BYTE *)a1 + v3 + 4) = size; + v5 = (char *)a1 + v3 + 5; + memcpy(v5, packet, (unsigned char)size); + v5[(unsigned char)size] = 0; + } +} + +void __fastcall multi_send_packet(void *packet, int dwSize) +{ + void *v2; // esi + unsigned char v3; // bl + TPkt pkt; // [esp+8h] [ebp-200h] + + v2 = packet; + v3 = dwSize; + NetRecvPlrData(&pkt); + pkt.hdr.wLen = v3 + 19; + memcpy(pkt.body, v2, v3); + if ( !SNetSendMessage(myplr, &pkt.hdr, (unsigned short)pkt.hdr.wLen) ) + nthread_terminate_game("SNetSendMessage0"); +} + +void __fastcall NetRecvPlrData(TPkt *pkt) +{ + pkt->hdr.wCheck = 'ip'; + pkt->hdr.px = plr[myplr].WorldX; + pkt->hdr.py = plr[myplr].WorldY; + pkt->hdr.targx = plr[myplr]._ptargx; + pkt->hdr.targy = plr[myplr]._ptargy; + pkt->hdr.php = plr[myplr]._pHitPoints; + pkt->hdr.pmhp = plr[myplr]._pMaxHP; + pkt->hdr.bstr = plr[myplr]._pBaseStr; + pkt->hdr.bmag = plr[myplr]._pBaseMag; + pkt->hdr.bdex = plr[myplr]._pBaseDex; +} + +void __fastcall NetSendHiPri(unsigned char *pbMsg, unsigned char bLen) +{ + unsigned char *v2; // edi + unsigned char v3; // bl + int v4; // edx + unsigned char *v5; // eax + TSyncHeader *v6; // eax + int v7; // eax + int v8; // eax + TPkt pkt; // [esp+Ch] [ebp-204h] + int size; // [esp+20Ch] [ebp-4h] + + v2 = pbMsg; + v3 = bLen; + if ( pbMsg && bLen ) + { + multi_copy_packet(pkdata_6761C0, pbMsg, bLen); + _LOBYTE(v4) = v3; + multi_send_packet(v2, v4); + } + if ( !dword_678628 ) + { + dword_678628 = 1; + NetRecvPlrData(&pkt); + size = gdwNormalMsgSize - 19; + v5 = multi_recv_packet(pkdata_6761C0, pkt.body, &size); + v6 = (TSyncHeader *)multi_recv_packet(pkdata_678658, v5, &size); + v7 = sync_all_monsters(v6, size); + size = v7; + v8 = gdwNormalMsgSize - v7; + pkt.hdr.wLen = v8; + if ( !SNetSendMessage(-2, &pkt.hdr, v8) ) + nthread_terminate_game("SNetSendMessage"); + } +} +// 678628: using guessed type int dword_678628; +// 679760: using guessed type int gdwNormalMsgSize; + +unsigned char *__fastcall multi_recv_packet(void *packet, unsigned char *a2, int *a3) +{ + char *v3; // esi + unsigned char *result; // eax + char *v5; // ebx + size_t v6; // edi + char *v7; // ebx + unsigned char *v8; // [esp+4h] [ebp-4h] + + v3 = (char *)packet; + result = a2; + v8 = a2; + if ( *(_DWORD *)packet ) + { + v5 = (char *)packet + 4; + while ( *v5 ) + { + v6 = (unsigned char)*v5; + if ( v6 > *a3 ) + break; + v7 = v5 + 1; + memcpy(v8, v7, v6); + v8 += v6; + v5 = &v7[v6]; + *a3 -= v6; + } + memcpy(v3 + 4, v5, (size_t)&v3[*(_DWORD *)v3 - (_DWORD)v5 + 5]); + *(_DWORD *)v3 += v3 - v5 + 4; + result = v8; + } + return result; +} + +void __fastcall multi_send_msg_packet(int a1, unsigned char *a2, unsigned char len) +{ + //const void *v3; // edx + signed int v4; // ebx + unsigned int v5; // edi + TPkt pkt; // [esp+Ch] [ebp-204h] + int v8; // [esp+20Ch] [ebp-4h] + + v8 = a1; + NetRecvPlrData(&pkt); + pkt.hdr.wLen = len + 19; + memcpy(pkt.body, a2, len); + v4 = 1; + v5 = 0; + while ( 1 ) + { + if ( v4 & v8 ) + { + if ( !SNetSendMessage(v5, &pkt.hdr, len + 19) && SErrGetLastError() != STORM_ERROR_INVALID_PLAYER ) + break; + } + ++v5; + v4 *= 2; + if ( v5 >= 4 ) + return; + } + nthread_terminate_game("SNetSendMessage"); +} + +void __cdecl multi_msg_countdown() +{ + int v0; // esi + + v0 = 0; + do + { + if ( player_state[v0] & 0x20000 ) + { + if ( gdwMsgLenTbl[v0] == 4 ) + multi_parse_turn(v0, *(_DWORD *)glpMsgTbl[v0]); + } + ++v0; + } + while ( v0 < MAX_PLRS ); +} + +void __fastcall multi_parse_turn(int pnum, int turn) +{ + int v2; // esi + unsigned int v3; // esi + + v2 = turn; + if ( turn < 0 ) + multi_handle_turn_upper_bit(pnum); + v3 = v2 & 0x7FFFFFFF; + if ( sgbSentThisCycle < gdwTurnsInTransit + v3 ) + { + if ( v3 >= 0x7FFFFFFF ) + v3 = (unsigned short)v3; + sgbSentThisCycle = v3 + gdwTurnsInTransit; + sgdwGameLoops = 4 * v3 * (unsigned char)byte_679704; + } +} +// 679704: using guessed type char byte_679704; +// 679738: using guessed type int gdwTurnsInTransit; + +void __fastcall multi_handle_turn_upper_bit(int pnum) +{ + signed int v1; // eax + + v1 = 0; + do + { + if ( player_state[v1] & 0x10000 && v1 != pnum ) + break; + ++v1; + } + while ( v1 < MAX_PLRS ); + if ( myplr == v1 ) + { + sgbSendDeltaTbl[pnum] = 1; + } + else if ( myplr == pnum ) + { + gbDeltaSender = v1; + } +} +// 6796E4: using guessed type char gbDeltaSender; + +void __fastcall multi_player_left(int pnum, int reason) +{ + sgbPlayerLeftGameTbl[pnum] = 1; + sgdwPlayerLeftReasonTbl[pnum] = reason; + multi_clear_left_tbl(); +} + +void __cdecl multi_clear_left_tbl() +{ + int v0; // esi + + v0 = 0; + do + { + if ( sgbPlayerLeftGameTbl[v0] ) + { + if ( gbBufferMsgs == 1 ) + msg_send_drop_pkt(v0, sgdwPlayerLeftReasonTbl[v0]); + else + multi_player_left_msg(v0, 1); + sgbPlayerLeftGameTbl[v0] = 0; + sgdwPlayerLeftReasonTbl[v0] = 0; + } + ++v0; + } + while ( v0 < MAX_PLRS ); +} +// 676194: using guessed type char gbBufferMsgs; + +void __fastcall multi_player_left_msg(int pnum, int left) +{ + int v2; // edi + int v3; // ebx + int v4; // esi + char *v5; // eax + int v6; // edi + + v2 = pnum; + v3 = left; + v4 = pnum; + if ( plr[pnum].plractive ) + { + RemovePlrFromMap(pnum); + RemovePortalMissile(v2); + DeactivatePortal(v2); + RemovePlrPortal(v2); + RemovePlrMissiles(v2); + if ( v3 ) + { + v5 = "Player '%s' just left the game"; + v6 = sgdwPlayerLeftReasonTbl[v2] - 0x40000004; + if ( v6 ) + { + if ( v6 == 2 ) + v5 = "Player '%s' dropped due to timeout"; + } + else + { + v5 = "Player '%s' killed Diablo and left the game!"; + gbSomebodyWonGameKludge = 1; + } + EventPlrMsg(v5, plr[v4]._pName); + } + plr[v4].plractive = 0; + plr[v4]._pName[0] = 0; + --gbActivePlayers; + } +} +// 6761B8: using guessed type char gbSomebodyWonGameKludge; +// 67862C: using guessed type char gbActivePlayers; + +void __cdecl multi_net_ping() +{ + sgbTimeout = 1; + sglTimeoutStart = GetTickCount(); +} +// 678644: using guessed type int sglTimeoutStart; +// 679661: using guessed type char sgbTimeout; + +int __cdecl multi_handle_delta() +{ + int v0; // esi + int recieved; // [esp+4h] [ebp-4h] + + if ( gbGameDestroyed ) + { + gbRunGame = 0; + return 0; + } + v0 = 0; + do + { + if ( sgbSendDeltaTbl[v0] ) + { + sgbSendDeltaTbl[v0] = 0; + DeltaExportData(v0); + } + ++v0; + } + while ( v0 < MAX_PLRS ); + sgbSentThisCycle = nthread_send_and_recv_turn(sgbSentThisCycle, 1); + if ( !nthread_recv_turns(&recieved) ) + { + multi_begin_timeout(); + return 0; + } + sgbTimeout = 0; + if ( recieved ) + { + if ( dword_678628 ) + { + dword_678628 = 0; + if ( !multi_check_pkt_valid(pkdata_6761C0) ) + NetSendHiPri(0, 0); + } + else + { + NetSendHiPri(0, 0); + dword_678628 = 0; + } + } + multi_mon_seeds(); + return 1; +} +// 525650: using guessed type int gbRunGame; +// 678628: using guessed type int dword_678628; +// 67862D: using guessed type char gbGameDestroyed; +// 679661: using guessed type char sgbTimeout; + +// Microsoft VisualC 2-11/net runtime +int __fastcall multi_check_pkt_valid(char *a1) +{ + return *(_DWORD *)a1 == 0; +} + +void __cdecl multi_mon_seeds() +{ + unsigned int v0; // eax + int v1; // edx + int *v2; // ecx + int v3; // esi + + v0 = _rotr(++sgdwGameLoops, 8); + v1 = 0; + v2 = &monster[0]._mAISeed; + do + { + v3 = v1++ + v0; + *v2 = v3; + v2 += 57; + } + while ( (signed int)v2 < (signed int)&monster[MAXMONSTERS]._mAISeed ); +} + +void __cdecl multi_begin_timeout() +{ + unsigned char bGroupPlayers; // bl + signed int v1; // eax + signed int nLowestActive; // esi + signed int nLowestPlayer; // edi + signed int v4; // eax + int v5; // edx + unsigned char v6; // [esp+Fh] [ebp-1h] + + bGroupPlayers = 0; +#ifdef _DEBUG + if ( sgbTimeout && !debug_mode_key_i ) +#else + if ( sgbTimeout ) +#endif + { + v1 = GetTickCount() - sglTimeoutStart; + if ( v1 <= 20000 ) + { + if ( v1 >= 10000 ) + { + v6 = 0; + nLowestActive = -1; + nLowestPlayer = -1; + v4 = 0; + do + { + v5 = player_state[v4]; + if ( v5 & 0x10000 ) + { + if ( nLowestPlayer == -1 ) + nLowestPlayer = v4; + if ( v5 & 0x40000 ) + { + ++bGroupPlayers; + if ( nLowestActive == -1 ) + nLowestActive = v4; + } + else + { + ++v6; + } + } + ++v4; + } + while ( v4 < MAX_PLRS ); + if ( bGroupPlayers >= v6 && (bGroupPlayers != v6 || nLowestPlayer == nLowestActive) ) + { + if ( nLowestActive == myplr ) + multi_check_drop_player(); + } + else + { + gbGameDestroyed = 1; + } + } + } + else + { + gbRunGame = 0; + } + } +} +// 525650: using guessed type int gbRunGame; +// 67862D: using guessed type char gbGameDestroyed; +// 678644: using guessed type int sglTimeoutStart; +// 679661: using guessed type char sgbTimeout; + +void __cdecl multi_check_drop_player() +{ + int v0; // esi + int v1; // eax + + v0 = 0; + do + { + v1 = player_state[v0]; + if ( !(v1 & 0x40000) ) + { + if ( v1 & 0x10000 ) + SNetDropPlayer(v0, 0x40000006); + } + ++v0; + } + while ( v0 < MAX_PLRS ); +} + +void __cdecl multi_process_network_packets() +{ + //int v0; // eax + TPktHdr *v1; // ecx + TPktHdr *v2; // edi + int v3; // eax + bool v4; // zf + unsigned char *v5; // esi + int v6; // ebx + int v7; // eax + int v8; // ecx + int v9; // eax + int v10; // eax + int v11; // esi + int v12; // eax + int v13; // ecx + int v14; // eax + //int v15; // eax + TPktHdr *pkt; // [esp+0h] [ebp-Ch] + int len; // [esp+4h] [ebp-8h] + char arglist[4]; // [esp+8h] [ebp-4h] /* fix, int */ + + multi_clear_left_tbl(); + multi_process_tmsgs(); + //_LOBYTE(v0) = SNetReceiveMessage((int *)arglist, (char **)&pkt, &len); + if ( SNetReceiveMessage((int *)arglist, (char **)&pkt, &len) ) + { + do + { + ++dword_676198; + multi_clear_left_tbl(); + v1 = pkt; + v2 = pkt; + if ( (unsigned int)len >= 0x13 + && *(_DWORD *)arglist < 4u + && pkt->wCheck == 'ip' + && (unsigned short)pkt->wLen == len ) + { + v3 = *(_DWORD *)arglist; + v4 = *(_DWORD *)arglist == myplr; + plr[v3]._pownerx = (unsigned char)pkt->px; + v5 = &v1->py; + plr[v3]._pownery = (unsigned char)v1->py; + if ( !v4 ) + { + v4 = gbBufferMsgs == 1; + plr[v3]._pHitPoints = v1->php; + plr[v3]._pMaxHP = v1->pmhp; + plr[v3]._pBaseStr = (unsigned char)v1->bstr; + plr[v3]._pBaseMag = (unsigned char)v1->bmag; + plr[v3]._pBaseDex = (unsigned char)v1->bdex; + if ( !v4 && plr[v3].plractive && plr[v3]._pHitPoints ) + { + if ( currlevel != plr[v3].plrlevel || plr[v3]._pLvlChanging ) + { + plr[v3].WorldX = (unsigned char)v1->px; + plr[v3].WorldY = (unsigned char)*v5; + plr[v3]._px = (unsigned char)v1->px; + plr[v3]._py = (unsigned char)*v5; + plr[v3]._ptargx = (unsigned char)v1->targx; + plr[v3]._ptargy = (unsigned char)v1->targy; + } + else + { + v6 = abs(plr[v3].WorldX - (unsigned char)v1->px); + v7 = abs(plr[*(_DWORD *)arglist].WorldY - (unsigned char)*v5); + if ( (v6 > 3 || v7 > 3) && !dPlayer[(unsigned char)v2->px][(unsigned char)*v5] ) + { + FixPlrWalkTags(*(int *)arglist); + v8 = *(_DWORD *)arglist; + v9 = *(_DWORD *)arglist; + plr[v9]._poldx = plr[*(_DWORD *)arglist].WorldX; + plr[v9]._poldy = plr[v9].WorldY; + FixPlrWalkTags(v8); + v10 = *(_DWORD *)arglist; + plr[v10].WorldX = (unsigned char)v2->px; + plr[v10].WorldY = (unsigned char)*v5; + plr[v10]._px = (unsigned char)v2->px; + plr[v10]._py = (unsigned char)*v5; + dPlayer[plr[v10].WorldX][plr[v10].WorldY] = arglist[0] + 1; + } + v11 = abs(plr[*(_DWORD *)arglist]._px - plr[*(_DWORD *)arglist].WorldX); + v12 = abs(plr[*(_DWORD *)arglist]._py - plr[*(_DWORD *)arglist].WorldY); + v13 = *(_DWORD *)arglist; + if ( v11 > 1 || v12 > 1 ) + { + v14 = *(_DWORD *)arglist; + plr[v14]._px = plr[*(_DWORD *)arglist].WorldX; + plr[v14]._py = plr[v13].WorldY; + } + MakePlrPath(v13, (unsigned char)v2->targx, (unsigned char)v2->targy, 1u); + } + } + } + multi_handle_all_packets(*(int *)arglist, (TPkt *)&v2[1], len - 19); + } + //_LOBYTE(v15) = SNetReceiveMessage((int *)arglist, (char **)&pkt, &len); + } + while ( SNetReceiveMessage((int *)arglist, (char **)&pkt, &len) ); + } + if ( SErrGetLastError() != STORM_ERROR_NO_MESSAGES_WAITING ) + nthread_terminate_game("SNetReceiveMsg"); +} +// 676194: using guessed type char gbBufferMsgs; +// 676198: using guessed type int dword_676198; + +void __fastcall multi_handle_all_packets(int players, TPkt *packet, int a3) +{ + TCmd *v3; // esi + int i; // edi + int v5; // eax + + v3 = (TCmd *)packet; + for ( i = players; a3; a3 -= v5 ) + { + v5 = ParseCmd(i, v3); + if ( !v5 ) + break; + v3 += v5; + } +} + +void __cdecl multi_process_tmsgs() +{ + int v0; // eax + TPkt pkt; // [esp+0h] [ebp-200h] + + while ( 1 ) + { + v0 = tmsg_get((unsigned char *)&pkt, 512); + if ( !v0 ) + break; + multi_handle_all_packets(myplr, &pkt, v0); + } +} + +void __fastcall multi_send_zero_packet(int pnum, char a2, void *pbSrc, int dwLen) +{ + unsigned int v4; // edi + short v5; // si + unsigned short dwBody; // ax + TPkt pkt; // [esp+Ch] [ebp-208h] + int pnuma; // [esp+20Ch] [ebp-8h] + int v10; // [esp+210h] [ebp-4h] + + v4 = dwLen; + _LOBYTE(v10) = a2; + pnuma = pnum; + v5 = 0; + while ( v4 ) + { + pkt.hdr.wCheck = 'ip'; + pkt.body[0] = v10; + dwBody = gdwLargestMsgSize - 24; + pkt.hdr.px = 0; + pkt.hdr.py = 0; + pkt.hdr.targx = 0; + pkt.hdr.targy = 0; + pkt.hdr.php = 0; + pkt.hdr.pmhp = 0; + pkt.hdr.bstr = 0; + pkt.hdr.bmag = 0; + pkt.hdr.bdex = 0; + *(_WORD *)&pkt.body[1] = v5; + if ( v4 < gdwLargestMsgSize - 24 ) + dwBody = v4; + *(_WORD *)&pkt.body[3] = dwBody; + memcpy(&pkt.body[5], pbSrc, dwBody); + pkt.hdr.wLen = *(_WORD *)&pkt.body[3] + 24; + if ( !SNetSendMessage(pnuma, &pkt.hdr, *(unsigned short *)&pkt.body[3] + 24) ) + { + nthread_terminate_game("SNetSendMessage2"); + return; + } + pbSrc = (char *)pbSrc + *(unsigned short *)&pkt.body[3]; + v4 -= *(unsigned short *)&pkt.body[3]; + v5 += *(_WORD *)&pkt.body[3]; + } +} +// 67975C: using guessed type int gdwLargestMsgSize; + +void __cdecl NetClose() +{ + if ( sgbNetInited ) + { + sgbNetInited = 0; + nthread_cleanup(); + dthread_cleanup(); + tmsg_cleanup(); + multi_event_handler(0); + SNetLeaveGame(3); + msgcmd_cmd_cleanup(); + if ( (unsigned char)gbMaxPlayers > 1u ) + Sleep(2000); + } +} +// 679660: using guessed type char gbMaxPlayers; +// 6796E8: using guessed type int sgbNetInited; + +char __fastcall multi_event_handler(int a1) +{ + int v1; // edi + void *(__stdcall *v2)(int, void (__stdcall *)(_SNETEVENT *)); // ebx + unsigned int v3; // esi + int v4; // eax + char *v5; // eax + + v1 = a1; + v2 = SNetRegisterEventHandler; + if ( !a1 ) + v2 = SNetUnregisterEventHandler; + v3 = 0; + do + { + v4 = (int)v2(event_types[v3], multi_handle_events); + if ( !v4 && v1 ) + { + v5 = TraceLastError(); + TermMsg("SNetRegisterEventHandler:\n%s", v5); + } + ++v3; + } + while ( v3 < 3 ); + return v4; +} + +void __stdcall multi_handle_events(_SNETEVENT *pEvt) +{ + int v1; // ecx + int *v2; // eax + int *v3; // eax + + switch ( pEvt->eventid ) + { + case EVENT_TYPE_PLAYER_CREATE_GAME: + v3 = (int *)pEvt->data; + sgGameInitInfo.dwSeed = *v3; + _LOBYTE(sgGameInitInfo.bDiff) = *((_BYTE *)v3 + 4); + sgbPlayerTurnBitTbl[pEvt->playerid] = 1; + break; + case EVENT_TYPE_PLAYER_LEAVE_GAME: + v1 = 0; + sgbPlayerLeftGameTbl[pEvt->playerid] = 1; + sgbPlayerTurnBitTbl[pEvt->playerid] = 0; + v2 = (int *)pEvt->data; + if ( v2 && pEvt->databytes >= 4u ) + v1 = *v2; + sgdwPlayerLeftReasonTbl[pEvt->playerid] = v1; + if ( v1 == 0x40000004 ) + gbSomebodyWonGameKludge = 1; + sgbSendDeltaTbl[pEvt->playerid] = 0; + dthread_remove_player(pEvt->playerid); + if ( (unsigned char)gbDeltaSender == pEvt->playerid ) + gbDeltaSender = 4; + break; + case EVENT_TYPE_PLAYER_MESSAGE: + ErrorPlrMsg((char *)pEvt->data); + break; + } +} +// 6761B8: using guessed type char gbSomebodyWonGameKludge; +// 6796E4: using guessed type char gbDeltaSender; + +int __fastcall NetInit(int bSinglePlayer, int *pfExitProgram) +{ + int v2; // ebx + int v4; // eax + //int v5; // ecx + bool v7; // zf + //int v9; // eax + //int v10; // eax + _SNETPROGRAMDATA ProgramData; // [esp+8h] [ebp-A8h] + _SNETUIDATA UiData; // [esp+44h] [ebp-6Ch] + _SNETPLAYERDATA a2; // [esp+94h] [ebp-1Ch] + int v14; // [esp+A4h] [ebp-Ch] + unsigned int len; // [esp+A8h] [ebp-8h] + int *a4; // [esp+ACh] [ebp-4h] + + a4 = pfExitProgram; + v14 = bSinglePlayer; + v2 = 0; + while ( 1 ) + { + *a4 = 0; + SetRndSeed(0); + sgGameInitInfo.dwSeed = time(NULL); + _LOBYTE(sgGameInitInfo.bDiff) = gnDifficulty; + memset(&ProgramData, 0, 0x3Cu); + ProgramData.size = 60; + ProgramData.programname = "Diablo Retail"; + ProgramData.programdescription = gszVersionNumber; + ProgramData.programid = 'DRTL'; + ProgramData.versionid = 42; + ProgramData.maxplayers = MAX_PLRS; + ProgramData.initdata = &sgGameInitInfo; + ProgramData.initdatabytes = 8; + ProgramData.optcategorybits = 15; + ProgramData.lcid = 1033; /* LANG_ENGLISH */ + memset(&a2, 0, 0x10u); + a2.size = 16; + memset(&UiData, 0, 0x50u); + UiData.size = 80; + UiData.parentwindow = SDrawGetFrameWindow(0); + UiData.artcallback = UiArtCallback; + UiData.createcallback = UiCreateGameCallback; + UiData.drawdesccallback = UiDrawDescCallback; + UiData.messageboxcallback = UiMessageBoxCallback; + UiData.soundcallback = UiSoundCallback; + UiData.authcallback = UiAuthCallback; + UiData.getdatacallback = UiGetDataCallback; + UiData.categorycallback = UiCategoryCallback; + UiData.selectnamecallback = (void (__cdecl *)())mainmenu_select_hero_dialog; + UiData.changenamecallback = (void (__cdecl *)())mainmenu_create_hero; + UiData.profilebitmapcallback = UiProfileDraw; + UiData.profilecallback = UiProfileCallback; + UiData.profilefields = UiProfileGetString(); + memset(sgbPlayerTurnBitTbl, 0, 4u); + gbGameDestroyed = 0; + memset(sgbPlayerLeftGameTbl, 0, 4u); + memset(sgdwPlayerLeftReasonTbl, 0, 0x10u); + memset(sgbSendDeltaTbl, 0, 4u); + memset(plr, 0, 0x15360u); + memset(sgwPackPlrOffsetTbl, 0, 8u); + SNetSetBasePlayer(0); + if ( v14 ) + v4 = multi_init_single(&ProgramData, &a2, &UiData); + else + v4 = multi_init_multi(&ProgramData, &a2, &UiData, a4); + if ( !v4 ) + return 0; + sgbNetInited = 1; + sgbTimeout = 0; + delta_init(); + InitPlrMsg(); + multi_clear_pkt(pkdata_6761C0); + multi_clear_pkt(pkdata_678658); + dword_678628 = 0; + sync_clear_pkt(); + nthread_start(sgbPlayerTurnBitTbl[myplr]); + dthread_start(); + MI_Dummy(0); /* v5 */ + sgdwGameLoops = 0; + sgbSentThisCycle = 0; + gbDeltaSender = myplr; + gbSomebodyWonGameKludge = 0; + nthread_send_and_recv_turn(0, 0); + SetupLocalCoords(); + multi_send_pinfo(-2, CMD_SEND_PLRINFO); + gbActivePlayers = 1; + v7 = sgbPlayerTurnBitTbl[myplr] == 0; + plr[myplr].plractive = 1; + if ( v7 || msg_wait_resync() ) + break; + NetClose(); + byte_678640 = 0; + } + gnDifficulty = _LOBYTE(sgGameInitInfo.bDiff); + SetRndSeed(sgGameInitInfo.dwSeed); + do + { + glSeedTbl[v2] = GetRndSeed(); + gnLevelTypeTbl[v2] = InitNewSeed(v2); + ++v2; + } + while ( v2 < 17 ); + //_LOBYTE(v9) = SNetGetGameInfo(GAMEINFO_NAME, szPlayerName, 128, len); + if ( !SNetGetGameInfo(GAMEINFO_NAME, szPlayerName, 128, &len) ) + nthread_terminate_game("SNetGetGameInfo1"); + //_LOBYTE(v10) = SNetGetGameInfo(GAMEINFO_PASSWORD, szPlayerDescript, 128, len); + if ( !SNetGetGameInfo(GAMEINFO_PASSWORD, szPlayerDescript, 128, &len) ) + nthread_terminate_game("SNetGetGameInfo2"); + return 1; +} +// 6761B8: using guessed type char gbSomebodyWonGameKludge; +// 678628: using guessed type int dword_678628; +// 67862C: using guessed type char gbActivePlayers; +// 67862D: using guessed type char gbGameDestroyed; +// 678640: using guessed type char byte_678640; +// 679661: using guessed type char sgbTimeout; +// 6796E4: using guessed type char gbDeltaSender; +// 6796E8: using guessed type int sgbNetInited; + +void __fastcall multi_clear_pkt(char *a1) +{ + *(_DWORD *)a1 = 0; + a1[4] = 0; +} + +void __fastcall multi_send_pinfo(int pnum, char cmd) +{ + char v2; // bl + int v3; // esi + PkPlayerStruct pkplr; // [esp+8h] [ebp-4F4h] + + v2 = cmd; + v3 = pnum; + PackPlayer(&pkplr, myplr, 1); + dthread_send_delta(v3, v2, &pkplr, 1266); +} + +int __fastcall InitNewSeed(int newseed) +{ + int result; // eax + + result = 0; + if ( newseed ) + { + result = 1; + if ( newseed < 1 || newseed > 4 ) + { + if ( newseed < 5 || newseed > 8 ) + { + if ( newseed < 9 || newseed > 12 ) + result = 4; + else + result = 3; + } + else + { + result = 2; + } + } + } + return result; +} + +void __cdecl SetupLocalCoords() +{ + int x; // ecx + int y; // edx + + if ( !leveldebug || (unsigned char)gbMaxPlayers > 1u ) + { + currlevel = 0; + leveltype = 0; + setlevel = 0; + } + x = 75; + y = 68; +#ifdef _DEBUG + if ( debug_mode_key_inverted_v || debug_mode_key_d ) + { + x = 49; + y = 23; + } +#endif + x += plrxoff[myplr]; + y += plryoff[myplr]; + plr[myplr].WorldX = x; + plr[myplr].WorldY = y; + plr[myplr]._px = x; + plr[myplr]._py = y; + plr[myplr]._ptargx = x; + plr[myplr]._ptargy = y; + plr[myplr].plrlevel = currlevel; + plr[myplr]._pLvlChanging = 1; + plr[myplr].pLvlLoad = 0; + plr[myplr]._pmode = PM_NEWLVL; + plr[myplr].destAction = -1; +} +// 52572C: using guessed type int leveldebug; +// 5BB1ED: using guessed type char leveltype; +// 5CF31D: using guessed type char setlevel; +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall multi_init_single(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info) +{ + //int v3; // eax + int result; // eax + //int v5; // eax + char *v6; // eax + + //_LOBYTE(v3) = SNetInitializeProvider(0, client_info, user_info, ui_info, &fileinfo); + if ( SNetInitializeProvider(0, client_info, user_info, ui_info, &fileinfo) ) + { + ui_info = 0; + //_LOBYTE(v5) = SNetCreateGame("local", "local", "local", 0, (char *)&sgGameInitInfo.dwSeed, 8, 1, "local", "local", (int *)&ui_info); + if ( !SNetCreateGame("local", "local", "local", 0, (char *)&sgGameInitInfo.dwSeed, 8, 1, "local", "local", (int *)&ui_info) ) + { + v6 = TraceLastError(); + TermMsg("SNetCreateGame1:\n%s", v6); + } + myplr = 0; + gbMaxPlayers = 1; + result = 1; + } + else + { + SErrGetLastError(); + result = 0; + } + return result; +} +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall multi_init_multi(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, int *a4) +{ + _SNETPLAYERDATA *v4; // ebx + signed int i; // edi + int a6; // [esp+Ch] [ebp-Ch] + int a2; // [esp+10h] [ebp-8h] + int type; // [esp+14h] [ebp-4h] + + v4 = user_info; + a2 = (int)client_info; + for ( i = 1; ; i = 0 ) + { + type = 0; + if ( byte_678640 ) + { + if ( !UiSelectProvider(0, (_SNETPROGRAMDATA *)a2, v4, ui_info, &fileinfo, &type) + && (!i || SErrGetLastError() != STORM_ERROR_REQUIRES_UPGRADE || !multi_upgrade(a4)) ) + { + return 0; + } + if ( type == 'BNET' ) + plr[0].pBattleNet = 1; + } + multi_event_handler(1); + if ( UiSelectGame(1, (_SNETPROGRAMDATA *)a2, v4, ui_info, &fileinfo, &a6) ) + break; + byte_678640 = 1; + } + if ( (unsigned int)a6 >= MAX_PLRS ) + return 0; + myplr = a6; + gbMaxPlayers = MAX_PLRS; + pfile_read_player_from_save(); + if ( type == 'BNET' ) + plr[myplr].pBattleNet = 1; + return 1; +} +// 678640: using guessed type char byte_678640; +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall multi_upgrade(int *a1) +{ + int *v1; // esi + int result; // eax + int status; // [esp+4h] [ebp-4h] + + v1 = a1; + SNetPerformUpgrade((unsigned long *)&status); + result = 1; + if ( status && status != 1 ) + { + if ( status == 2 ) + { + *v1 = 1; + } + else if ( status == -1 ) + { + DrawDlg("Network upgrade failed"); + } + result = 0; + } + return result; +} + +void __fastcall multi_player_joins(int pnum, TCmdPlrInfoHdr *cmd, int a3) +{ + int v3; // ebx + TCmdPlrInfoHdr *v4; // edi + short *v5; // esi + int v6; // esi + bool v7; // zf + char *v8; // eax + int v9; // ST08_4 + unsigned char *v10; // edx + int v11; // eax + int v12; // ecx + int v13; // eax + + v3 = pnum; + v4 = cmd; + if ( myplr != pnum ) + { + v5 = &sgwPackPlrOffsetTbl[pnum]; + if ( *v5 == cmd->wOffset || (*v5 = 0, !cmd->wOffset) ) + { + if ( !a3 && !*v5 ) + { + multi_send_pinfo(pnum, CMD_ACK_PLRINFO); + } + memcpy((char *)&netplr[v3] + (unsigned short)v4->wOffset, &v4[1], (unsigned short)v4->wBytes); + *v5 += v4->wBytes; + if ( *v5 == 1266 ) + { + *v5 = 0; + multi_player_left_msg(v3, 0); + v6 = v3; + plr[v3]._pGFXLoad = 0; + UnPackPlayer(&netplr[v3], v3, 1); + if ( a3 ) + { + ++gbActivePlayers; + v7 = sgbPlayerTurnBitTbl[v3] == 0; + plr[v6].plractive = 1; + v8 = "Player '%s' (level %d) just joined the game"; + if ( v7 ) + v8 = "Player '%s' (level %d) is already in the game"; + EventPlrMsg(v8, plr[v6]._pName, plr[v6]._pLevel); + LoadPlrGFX(v3, PFILE_STAND); + SyncInitPlr(v3); + if ( plr[v6].plrlevel == currlevel ) + { + if ( (signed int)(plr[v6]._pHitPoints & 0xFFFFFFC0) <= 0 ) + { + plr[v6]._pgfxnum = 0; + LoadPlrGFX(v3, PFILE_DEATH); + v9 = plr[v6]._pDWidth; + v10 = plr[v6]._pDAnim[0]; + plr[v6]._pmode = 8; + NewPlrAnim(v3, v10, plr[v6]._pDFrames, 1, v9); + v11 = plr[v6]._pAnimLen; + v12 = v11 - 1; + plr[v6]._pVar8 = 2 * v11; + v13 = plr[v6].WorldX; + plr[v6]._pAnimFrame = v12; + dFlags[v13][plr[v6].WorldY] |= 4u; + } + else + { + StartStand(v3, 0); + } + } + } + } + } + } +} +// 67862C: using guessed type char gbActivePlayers; diff --git a/Source/multi.h b/Source/multi.h new file mode 100644 index 000000000..4f95bbcbf --- /dev/null +++ b/Source/multi.h @@ -0,0 +1,74 @@ +//HEADER_GOES_HERE +#ifndef __MULTI_H__ +#define __MULTI_H__ + +extern char gbSomebodyWonGameKludge; // weak +extern char pkdata_6761C0[4100]; +extern char szPlayerDescript[128]; +extern short sgwPackPlrOffsetTbl[MAX_PLRS]; +extern PkPlayerStruct netplr[MAX_PLRS]; +extern char sgbPlayerTurnBitTbl[MAX_PLRS]; +extern char sgbPlayerLeftGameTbl[MAX_PLRS]; +extern int multi_cpp_init_value; // weak +extern int sgbSentThisCycle; // idb +extern int dword_678628; // weak +extern char gbActivePlayers; // weak +extern char gbGameDestroyed; // weak +extern char sgbSendDeltaTbl[MAX_PLRS]; +extern _gamedata sgGameInitInfo; +extern char byte_678640; // weak +extern int sglTimeoutStart; // weak +extern int sgdwPlayerLeftReasonTbl[MAX_PLRS]; +extern char pkdata_678658[4100]; +extern unsigned int sgdwGameLoops; // idb +extern UCHAR gbMaxPlayers; +extern char sgbTimeout; // weak +extern char szPlayerName[128]; +extern char gbDeltaSender; // weak +extern int sgbNetInited; // weak +extern int player_state[MAX_PLRS]; + +void __cdecl multi_cpp_init(); +void __fastcall multi_msg_add(unsigned char *a1, unsigned char a2); +void __fastcall NetSendLoPri(unsigned char *pbMsg, unsigned char bLen); +void __fastcall multi_copy_packet(void *a1, void *packet, int size); +void __fastcall multi_send_packet(void *packet, int dwSize); +void __fastcall NetRecvPlrData(TPkt *pkt); +void __fastcall NetSendHiPri(unsigned char *pbMsg, unsigned char bLen); +unsigned char *__fastcall multi_recv_packet(void *packet, unsigned char *a2, int *a3); +void __fastcall multi_send_msg_packet(int a1, unsigned char *a2, unsigned char len); +void __cdecl multi_msg_countdown(); +void __fastcall multi_parse_turn(int pnum, int turn); +void __fastcall multi_handle_turn_upper_bit(int pnum); +void __fastcall multi_player_left(int pnum, int reason); +void __cdecl multi_clear_left_tbl(); +void __fastcall multi_player_left_msg(int pnum, int left); +void __cdecl multi_net_ping(); +int __cdecl multi_handle_delta(); +int __fastcall multi_check_pkt_valid(char *a1); +void __cdecl multi_mon_seeds(); +void __cdecl multi_begin_timeout(); +void __cdecl multi_check_drop_player(); +void __cdecl multi_process_network_packets(); +void __fastcall multi_handle_all_packets(int players, TPkt *packet, int a3); +void __cdecl multi_process_tmsgs(); +void __fastcall multi_send_zero_packet(int pnum, char a2, void *pbSrc, int dwLen); +void __cdecl NetClose(); +char __fastcall multi_event_handler(int a1); +void __stdcall multi_handle_events(_SNETEVENT *pEvt); +int __fastcall NetInit(int bSinglePlayer, int *pfExitProgram); +void __fastcall multi_clear_pkt(char *a1); +void __fastcall multi_send_pinfo(int pnum, char cmd); +int __fastcall InitNewSeed(int newseed); +void __cdecl SetupLocalCoords(); +int __fastcall multi_init_single(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info); +int __fastcall multi_init_multi(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, int *a4); +int __fastcall multi_upgrade(int *a1); +void __fastcall multi_player_joins(int pnum, TCmdPlrInfoHdr *cmd, int a3); + +/* rdata */ + +extern const int multi_inf; // weak +extern const int event_types[3]; + +#endif /* __MULTI_H__ */ diff --git a/Source/nthread.cpp b/Source/nthread.cpp new file mode 100644 index 000000000..50772aecb --- /dev/null +++ b/Source/nthread.cpp @@ -0,0 +1,345 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int nthread_cpp_init_value; // weak +char byte_679704; // weak +int gdwMsgLenTbl[4]; +static CRITICAL_SECTION sgMemCrit; +int gdwDeltaBytesSec; // weak +char byte_679734; // weak +int gdwTurnsInTransit; // weak +int glpMsgTbl[4]; +unsigned int glpNThreadId; +char sgbSyncCountdown; // weak +int dword_679754; // weak +char byte_679758; // weak +char sgbPacketCountdown; // weak +char sgbThreadIsRunning; // weak +int gdwLargestMsgSize; // weak +int gdwNormalMsgSize; // weak +int dword_679764; // weak + +const int nthread_inf = 0x7F800000; // weak + +/* data */ +static HANDLE sghThread = (HANDLE)0xFFFFFFFF; // idb + +struct nthread_cpp_init_1 +{ + nthread_cpp_init_1() + { + nthread_cpp_init_value = nthread_inf; + } +} _nthread_cpp_init_1; +// 47F164: using guessed type int nthread_inf; +// 679700: using guessed type int nthread_cpp_init_value; + +#ifndef MINIWIN +struct nthread_cpp_init_2 +{ + nthread_cpp_init_2() + { + nthread_init_mutex(); + nthread_cleanup_mutex_atexit(); + } +} _nthread_cpp_init_2; +#endif + +void __cdecl nthread_init_mutex() +{ + InitializeCriticalSection(&sgMemCrit); +} + +void __cdecl nthread_cleanup_mutex_atexit() +{ + atexit(nthread_cleanup_mutex); +} + +void __cdecl nthread_cleanup_mutex() +{ + DeleteCriticalSection(&sgMemCrit); +} + +void __fastcall nthread_terminate_game(char *pszFcn) +{ + char *v1; // esi + int v2; // eax + char *v3; // eax + + v1 = pszFcn; + v2 = SErrGetLastError(); + if ( v2 != STORM_ERROR_INVALID_PLAYER ) + { + if ( v2 == STORM_ERROR_GAME_TERMINATED || v2 == STORM_ERROR_NOT_IN_GAME ) + { + gbGameDestroyed = 1; + } + else + { + v3 = TraceLastError(); + TermMsg("%s:\n%s", v1, v3); + } + } +} +// 67862D: using guessed type char gbGameDestroyed; + +int __fastcall nthread_send_and_recv_turn(int cur_turn, int turn_delta) +{ + int v2; // ebx + unsigned int v3; // edi + char *v5; // ecx + int v6; // eax + int turn; // [esp+Ch] [ebp-8h] + int turns; // [esp+10h] [ebp-4h] + + v2 = turn_delta; + v3 = cur_turn; + if ( SNetGetTurnsInTransit(&turns) ) + { + if ( turns >= (unsigned int)gdwTurnsInTransit ) + return v3; + while ( 1 ) + { + ++turns; + v6 = dword_679754 | v3 & 0x7FFFFFFF; + dword_679754 = 0; + turn = v6; + if ( !SNetSendTurn((char *)&turn, 4) ) + break; + v3 += v2; + if ( v3 >= 0x7FFFFFFF ) + v3 = (unsigned short)v3; + if ( turns >= (unsigned int)gdwTurnsInTransit ) + return v3; + } + v5 = "SNetSendTurn"; + } + else + { + v5 = "SNetGetTurnsInTransit"; + } + nthread_terminate_game(v5); + return 0; +} +// 679738: using guessed type int gdwTurnsInTransit; +// 679754: using guessed type int dword_679754; + +int __fastcall nthread_recv_turns(int *pfSendAsync) +{ + int *v1; // esi + bool v2; // zf + + v1 = pfSendAsync; + *pfSendAsync = 0; + if ( --sgbPacketCountdown ) + { + dword_679764 += 50; + return 1; + } + v2 = sgbSyncCountdown-- == 1; + sgbPacketCountdown = byte_679704; + if ( !v2 ) + goto LABEL_11; + if ( SNetReceiveTurns(0, 4, (char **)glpMsgTbl, (unsigned int *)gdwMsgLenTbl, (unsigned long *)player_state) ) + { + if ( !byte_679758 ) + { + byte_679758 = 1; + dword_679764 = GetTickCount(); + } + sgbSyncCountdown = 4; + multi_msg_countdown(); +LABEL_11: + *v1 = 1; + dword_679764 += 50; + return 1; + } + if ( SErrGetLastError() != STORM_ERROR_NO_MESSAGES_WAITING ) + nthread_terminate_game("SNetReceiveTurns"); + byte_679758 = 0; + sgbSyncCountdown = 1; + sgbPacketCountdown = 1; + return 0; +} +// 679704: using guessed type char byte_679704; +// 679750: using guessed type char sgbSyncCountdown; +// 679758: using guessed type char byte_679758; +// 679759: using guessed type char sgbPacketCountdown; +// 679764: using guessed type int dword_679764; + +void __cdecl nthread_set_turn_upper_bit() +{ + dword_679754 = 0x80000000; +} +// 679754: using guessed type int dword_679754; + +void __fastcall nthread_start(bool set_turn_upper_bit) +{ + BOOL v1; // esi + char *v3; // eax + unsigned int v4; // esi + unsigned int v5; // eax + char *v6; // eax + _SNETCAPS caps; // [esp+8h] [ebp-24h] + + v1 = set_turn_upper_bit; + dword_679764 = GetTickCount(); + sgbPacketCountdown = 1; + sgbSyncCountdown = 1; + byte_679758 = 1; + if ( v1 ) + nthread_set_turn_upper_bit(); + else + dword_679754 = 0; + caps.size = 36; + if ( !SNetGetProviderCaps(&caps) ) + { + v3 = TraceLastError(); + TermMsg("SNetGetProviderCaps:\n%s", v3); + } + gdwTurnsInTransit = caps.defaultturnsintransit; + if ( !caps.defaultturnsintransit ) + gdwTurnsInTransit = 1; + if ( caps.defaultturnssec <= 0x14u && caps.defaultturnssec ) + byte_679704 = 0x14u / caps.defaultturnssec; + else + byte_679704 = 1; + v4 = 512; + if ( caps.maxmessagesize < 0x200u ) + v4 = caps.maxmessagesize; + gdwDeltaBytesSec = (unsigned int)caps.bytessec >> 2; + gdwLargestMsgSize = v4; + if ( caps.maxplayers > 4u ) + caps.maxplayers = 4; + v5 = (3 * (caps.bytessec * (unsigned int)(unsigned char)byte_679704 / 0x14) >> 2) / caps.maxplayers; + gdwNormalMsgSize = v5; + if ( v5 < 0x80 ) + { + do + { + byte_679704 *= 2; + v5 *= 2; + } + while ( v5 < 0x80 ); + gdwNormalMsgSize = v5; + } + if ( v5 > v4 ) + gdwNormalMsgSize = v4; + if ( (unsigned char)gbMaxPlayers > 1u ) + { + sgbThreadIsRunning = 0; + EnterCriticalSection(&sgMemCrit); + byte_679734 = 1; + sghThread = (HANDLE)_beginthreadex(NULL, 0, nthread_handler, NULL, 0, &glpNThreadId); + if ( sghThread == (HANDLE)-1 ) + { + v6 = TraceLastError(); + TermMsg("nthread2:\n%s", v6); + } + SetThreadPriority(sghThread, THREAD_PRIORITY_HIGHEST); + } +} +// 679660: using guessed type char gbMaxPlayers; +// 679704: using guessed type char byte_679704; +// 679730: using guessed type int gdwDeltaBytesSec; +// 679734: using guessed type char byte_679734; +// 679738: using guessed type int gdwTurnsInTransit; +// 679750: using guessed type char sgbSyncCountdown; +// 679754: using guessed type int dword_679754; +// 679758: using guessed type char byte_679758; +// 679759: using guessed type char sgbPacketCountdown; +// 67975A: using guessed type char sgbThreadIsRunning; +// 67975C: using guessed type int gdwLargestMsgSize; +// 679760: using guessed type int gdwNormalMsgSize; +// 679764: using guessed type int dword_679764; + +unsigned int __stdcall nthread_handler(void *a1) +{ + signed int v1; // esi + int recieved; // [esp+Ch] [ebp-4h] + + if ( byte_679734 ) + { + while ( 1 ) + { + EnterCriticalSection(&sgMemCrit); + if ( !byte_679734 ) + break; + nthread_send_and_recv_turn(0, 0); + if ( nthread_recv_turns(&recieved) ) + v1 = dword_679764 - GetTickCount(); + else + v1 = 50; + LeaveCriticalSection(&sgMemCrit); + if ( v1 > 0 ) + Sleep(v1); + if ( !byte_679734 ) + return 0; + } + LeaveCriticalSection(&sgMemCrit); + } + return 0; +} +// 679734: using guessed type char byte_679734; +// 679764: using guessed type int dword_679764; + +void __cdecl nthread_cleanup() +{ + char *v0; // eax + + byte_679734 = 0; + gdwTurnsInTransit = 0; + gdwNormalMsgSize = 0; + gdwLargestMsgSize = 0; + if ( sghThread != (HANDLE)-1 && glpNThreadId != GetCurrentThreadId() ) + { + if ( !sgbThreadIsRunning ) + LeaveCriticalSection(&sgMemCrit); + if ( WaitForSingleObject(sghThread, 0xFFFFFFFF) == -1 ) + { + v0 = TraceLastError(); + TermMsg("nthread3:\n(%s)", v0); + } + CloseHandle(sghThread); + sghThread = (HANDLE)-1; + } +} +// 679734: using guessed type char byte_679734; +// 679738: using guessed type int gdwTurnsInTransit; +// 67975A: using guessed type char sgbThreadIsRunning; +// 67975C: using guessed type int gdwLargestMsgSize; +// 679760: using guessed type int gdwNormalMsgSize; + +void __fastcall nthread_ignore_mutex(bool bStart) +{ + bool v1; // bl + + v1 = bStart; + if ( sghThread != (HANDLE)-1 ) + { + if ( bStart ) + LeaveCriticalSection(&sgMemCrit); + else + EnterCriticalSection(&sgMemCrit); + sgbThreadIsRunning = v1; + } +} +// 67975A: using guessed type char sgbThreadIsRunning; + +bool __cdecl nthread_has_500ms_passed() +{ + DWORD v0; // eax + int v1; // ecx + + v0 = GetTickCount(); + v1 = v0 - dword_679764; + if ( gbMaxPlayers == 1 && v1 > 500 ) + { + dword_679764 = v0; + v1 = 0; + } + return v1 >= 0; +} +// 679660: using guessed type char gbMaxPlayers; +// 679764: using guessed type int dword_679764; diff --git a/Source/nthread.h b/Source/nthread.h new file mode 100644 index 000000000..4c2b75748 --- /dev/null +++ b/Source/nthread.h @@ -0,0 +1,41 @@ +//HEADER_GOES_HERE +#ifndef __NTHREAD_H__ +#define __NTHREAD_H__ + +extern int nthread_cpp_init_value; // weak +extern char byte_679704; // weak +extern int gdwMsgLenTbl[4]; +extern int gdwDeltaBytesSec; // weak +extern char byte_679734; // weak +extern int gdwTurnsInTransit; // weak +extern int glpMsgTbl[4]; +extern unsigned int glpNThreadId; +extern char sgbSyncCountdown; // weak +extern int dword_679754; // weak +extern char byte_679758; // weak +extern char sgbPacketCountdown; // weak +extern char sgbThreadIsRunning; // weak +extern int gdwLargestMsgSize; // weak +extern int gdwNormalMsgSize; // weak +extern int dword_679764; // weak + +void __cdecl nthread_cpp_init_1(); +void __cdecl nthread_cpp_init_2(); +void __cdecl nthread_init_mutex(); +void __cdecl nthread_cleanup_mutex_atexit(); +void __cdecl nthread_cleanup_mutex(); +void __fastcall nthread_terminate_game(char *pszFcn); +int __fastcall nthread_send_and_recv_turn(int cur_turn, int turn_delta); +int __fastcall nthread_recv_turns(int *pfSendAsync); +void __cdecl nthread_set_turn_upper_bit(); +void __fastcall nthread_start(bool set_turn_upper_bit); +unsigned int __stdcall nthread_handler(void *a1); +void __cdecl nthread_cleanup(); +void __fastcall nthread_ignore_mutex(bool bStart); +bool __cdecl nthread_has_500ms_passed(); + +/* rdata */ + +extern const int nthread_inf; // weak + +#endif /* __NTHREAD_H__ */ diff --git a/Source/objects.cpp b/Source/objects.cpp new file mode 100644 index 000000000..f648f5a85 --- /dev/null +++ b/Source/objects.cpp @@ -0,0 +1,7286 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int trapid; // weak +int trapdir; // weak +unsigned char *pObjCels[40]; +char ObjFileList[40]; +int objectactive[MAXOBJECTS]; +int nobjects; // idb +int leverid; // idb +int objectavail[MAXOBJECTS]; +ObjectStruct object[MAXOBJECTS]; +int InitObjFlag; // weak +int numobjfiles; // weak +#endif + +int ObjTypeConv[113] = +{ + 0, + 4, + 20, + 21, + 22, + 24, + 11, + 12, + 13, + 0, + 0, + 0, + 0, + 0, + 25, + 41, + 26, + 0, + 8, + 9, + 10, + 80, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 49, + 0, + 0, + 0, + 0, + 0, + 84, + 85, + 3, + 14, + 15, + 16, + 17, + 18, + 19, + 0, + 0, + 0, + 0, + 0, + 0, + 28, + 0, + 53, + 54, + 36, + 37, + 38, + 39, + 40, + 0, + 0, + 0, + 0, + 0, + 27, + 0, + 0, + 0, + 0, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 5, + 5, + 5, + 6, + 6, + 6, + 7, + 7, + 7, + 0, + 0, + 0, + 0, + 0, + 73, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 83, + 0, + 0, + 89, + 90, + 47, + 46, + 94 +}; +ObjDataStruct AllObjects[99] = +{ + { 1, OFILE_L1BRAZ, 1, 4, 1, -1, -1, 1, 1, 26, 64, 1, 1, 0, 0, 0, 0 }, + { 1, OFILE_L1DOORS, 1, 4, 1, -1, -1, 0, 1, 0, 64, 0, 0, 1, 0, 3, 1 }, + { 1, OFILE_L1DOORS, 1, 4, 1, -1, -1, 0, 2, 0, 64, 0, 0, 1, 0, 3, 1 }, + { 3, OFILE_SKULFIRE, 0, 0, 0, 3, -1, 1, 2, 11, 96, 1, 1, 0, 0, 0, 0 }, + { 1, OFILE_LEVER, 1, 4, 1, -1, -1, 0, 1, 1, 96, 1, 1, 1, 0, 1, 1 }, + { 1, OFILE_CHEST1, 1, 16, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 1, 1 }, + { 1, OFILE_CHEST2, 1, 16, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 1, 1 }, + { 1, OFILE_CHEST3, 1, 16, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 1, 1 }, + { 2, OFILE_L1BRAZ, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 3, OFILE_CANDLE2, 0, 0, 0, 1, -1, 1, 2, 4, 96, 1, 1, 1, 0, 0, 0 }, + { 2, OFILE_L1BRAZ, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 3, OFILE_BANNER, 0, 0, 0, 3, -1, 0, 2, 0, 96, 1, 1, 1, 0, 0, 0 }, + { 3, OFILE_BANNER, 0, 0, 0, 3, -1, 0, 1, 0, 96, 1, 1, 1, 0, 0, 0 }, + { 3, OFILE_BANNER, 0, 0, 0, 3, -1, 0, 3, 0, 96, 1, 1, 1, 0, 0, 0 }, + { 2, OFILE_SKULPILE, 1, 4, 0, -1, -1, 0, 0, 1, 96, 1, 1, 1, 0, 0, 0 }, + { 2, OFILE_L1BRAZ, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 2, OFILE_L1BRAZ, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 2, OFILE_L1BRAZ, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 2, OFILE_L1BRAZ, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 2, OFILE_L1BRAZ, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 2, OFILE_CRUXSK1, 0, 0, 0, -1, -1, 0, 1, 15, 96, 1, 0, 1, 1, 3, 0 }, + { 2, OFILE_CRUXSK2, 0, 0, 0, -1, -1, 0, 1, 15, 96, 1, 0, 1, 1, 3, 0 }, + { 2, OFILE_CRUXSK3, 0, 0, 0, -1, -1, 0, 1, 15, 96, 1, 0, 1, 1, 3, 0 }, + { 1, OFILE_ROCKSTAN, 5, 5, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 0, 0 }, + { 2, OFILE_ANGEL, 0, 0, 0, -1, -1, 0, 1, 0, 96, 1, 0, 1, 0, 0, 0 }, + { 2, OFILE_BOOK2, 0, 0, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 3, 0 }, + { 2, OFILE_BURNCROS, 0, 0, 0, -1, -1, 1, 0, 10, 160, 1, 0, 0, 0, 0, 0 }, + { 2, OFILE_NUDE2, 0, 0, 0, -1, -1, 1, 3, 6, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_SWITCH4, 16, 16, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 1, 1 }, + { 1, OFILE_TNUDEM, 13, 16, 0, -1, 6, 0, 1, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TNUDEM, 13, 16, 0, 6, 6, 0, 2, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TNUDEM, 13, 16, 0, 6, 6, 0, 3, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TNUDEM, 13, 16, 0, 6, 6, 0, 4, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TNUDEW, 13, 16, 0, 6, 6, 0, 1, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TNUDEW, 13, 16, 0, 6, 6, 0, 2, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TNUDEW, 13, 16, 0, 6, 6, 0, 3, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TSOUL, 13, 16, 0, -1, 6, 0, 1, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TSOUL, 13, 16, 0, -1, 6, 0, 2, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TSOUL, 13, 16, 0, -1, 6, 0, 3, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TSOUL, 13, 16, 0, -1, 6, 0, 4, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_TSOUL, 13, 16, 0, -1, 6, 0, 5, 0, 128, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_BOOK2, 6, 6, 0, -1, -1, 0, 4, 0, 96, 1, 1, 1, 0, 3, 0 }, + { 1, OFILE_L2DOORS, 5, 8, 2, -1, -1, 0, 1, 0, 64, 0, 0, 1, 0, 3, 1 }, + { 1, OFILE_L2DOORS, 5, 8, 2, -1, -1, 0, 2, 0, 64, 0, 0, 1, 0, 3, 1 }, + { 1, OFILE_WTORCH4, 5, 8, 2, -1, -1, 1, 1, 9, 96, 0, 1, 0, 0, 0, 0 }, + { 1, OFILE_WTORCH3, 5, 8, 2, -1, -1, 1, 1, 9, 96, 0, 1, 0, 0, 0, 0 }, + { 1, OFILE_WTORCH1, 5, 8, 2, -1, -1, 1, 1, 9, 96, 0, 1, 0, 0, 0, 0 }, + { 1, OFILE_WTORCH2, 5, 8, 2, -1, -1, 1, 1, 9, 96, 0, 1, 0, 0, 0, 0 }, + { 1, OFILE_SARC, 1, 4, 1, -1, -1, 0, 1, 5, 128, 1, 1, 1, 0, 3, 1 }, + { 2, OFILE_FLAME1, 1, 4, 1, -1, -1, 0, 1, 20, 96, 0, 1, 1, 0, 0, 0 }, + { 2, OFILE_LEVER, 1, 4, 1, -1, -1, 0, 1, 2, 96, 1, 1, 1, 0, 1, 1 }, + { 2, OFILE_MINIWATR, 1, 4, 1, -1, -1, 1, 1, 10, 64, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_BOOK1, 3, 4, 1, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 3, 0 }, + { 1, OFILE_TRAPHOLE, 1, 16, 0, -1, -1, 0, 1, 0, 64, 0, 1, 1, 0, 0, 0 }, + { 1, OFILE_TRAPHOLE, 1, 16, 0, -1, -1, 0, 2, 0, 64, 0, 1, 1, 0, 0, 0 }, + { 2, OFILE_BCASE, 0, 0, 0, -1, -1, 0, 1, 0, 96, 1, 0, 1, 0, 0, 0 }, + { 2, OFILE_WEAPSTND, 0, 0, 0, -1, -1, 0, 1, 0, 96, 1, 0, 1, 0, 0, 0 }, + { 1, OFILE_BARREL, 1, 16, 0, -1, -1, 0, 1, 9, 96, 1, 1, 1, 1, 3, 0 }, + { 1, OFILE_BARRELEX, 1, 16, 0, -1, -1, 0, 1, 10, 96, 1, 1, 1, 1, 3, 0 }, + { 3, OFILE_LSHRINEG, 0, 0, 0, 1, -1, 0, 1, 11, 128, 0, 0, 1, 0, 3, 0 }, + { 3, OFILE_RSHRINEG, 0, 0, 0, 1, -1, 0, 1, 11, 128, 0, 0, 1, 0, 3, 0 }, + { 3, OFILE_BOOK2, 0, 0, 0, 3, -1, 0, 4, 0, 96, 1, 1, 1, 0, 3, 0 }, + { 3, OFILE_BCASE, 0, 0, 0, 5, -1, 0, 3, 0, 96, 0, 0, 1, 0, 3, 0 }, + { 3, OFILE_BCASE, 0, 0, 0, 5, -1, 0, 4, 0, 96, 0, 0, 1, 0, 3, 0 }, + { 3, OFILE_BOOK2, 0, 0, 0, 5, -1, 0, 1, 0, 96, 1, 1, 1, 0, 3, 0 }, + { 3, OFILE_CANDLE2, 0, 0, 0, 5, -1, 1, 2, 4, 96, 1, 1, 1, 0, 0, 0 }, + { 3, OFILE_BLOODFNT, 0, 0, 0, 7, -1, 1, 2, 10, 96, 1, 1, 1, 0, 3, 0 }, + { 1, OFILE_DECAP, 13, 16, 0, 8, -1, 0, 1, 0, 96, 1, 1, 1, 0, 1, 0 }, + { 1, OFILE_CHEST1, 1, 16, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 1, 1 }, + { 1, OFILE_CHEST2, 1, 16, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 1, 1 }, + { 1, OFILE_CHEST3, 1, 16, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 1, 1 }, + { 1, OFILE_BOOK1, 7, 7, 2, -1, 8, 0, 1, 0, 96, 1, 1, 1, 0, 3, 0 }, + { 1, OFILE_BOOK1, 5, 5, 2, -1, 9, 0, 4, 0, 96, 1, 1, 1, 0, 3, 0 }, + { 1, OFILE_PEDISTL, 5, 5, 2, -1, 9, 0, 1, 0, 96, 1, 1, 1, 0, 3, 0 }, + { 1, OFILE_L3DOORS, 9, 12, 3, -1, -1, 0, 1, 0, 64, 0, 0, 1, 0, 3, 1 }, + { 1, OFILE_L3DOORS, 9, 12, 3, -1, -1, 0, 2, 0, 64, 0, 0, 1, 0, 3, 1 }, + { 3, OFILE_PFOUNTN, 0, 0, 0, 9, -1, 1, 2, 10, 128, 1, 1, 1, 0, 3, 0 }, + { 3, OFILE_ARMSTAND, 0, 0, 0, 10, -1, 0, 1, 0, 96, 1, 0, 1, 0, 3, 0 }, + { 3, OFILE_ARMSTAND, 0, 0, 0, 10, -1, 0, 2, 0, 96, 1, 0, 1, 0, 0, 0 }, + { 3, OFILE_GOATSHRN, 0, 0, 0, 11, -1, 1, 2, 10, 96, 1, 1, 1, 0, 3, 0 }, + { 1, OFILE_CAULDREN, 13, 16, 0, -1, -1, 0, 1, 0, 96, 1, 0, 1, 0, 3, 0 }, + { 3, OFILE_MFOUNTN, 0, 0, 0, 13, -1, 1, 2, 10, 128, 1, 1, 1, 0, 3, 0 }, + { 3, OFILE_TFOUNTN, 0, 0, 0, 14, -1, 1, 2, 4, 128, 1, 1, 1, 0, 3, 0 }, + { 1, OFILE_ALTBOY, 0, 0, 1, -1, 15, 0, 1, 0, 128, 1, 1, 1, 0, 0, 0 }, + { 1, OFILE_MCIRL, 0, 0, 1, -1, 15, 0, 1, 0, 96, 0, 1, 1, 0, 0, 0 }, + { 1, OFILE_MCIRL, 0, 0, 1, -1, 15, 0, 1, 0, 96, 0, 1, 1, 0, 0, 0 }, + { 1, OFILE_BKSLBRNT, 4, 12, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 3, 0 }, + { 1, OFILE_CANDLE2, 2, 12, 0, -1, 15, 1, 2, 4, 96, 1, 1, 1, 0, 0, 0 }, + { 1, OFILE_BOOK1, 13, 13, 4, -1, 11, 0, 4, 0, 96, 1, 1, 1, 0, 3, 0 }, + { 1, OFILE_ARMSTAND, 13, 13, 0, -1, 11, 0, 1, 0, 96, 1, 0, 1, 0, 3, 0 }, + { 2, OFILE_WEAPSTND, 13, 13, 0, -1, 11, 0, 1, 0, 96, 1, 0, 1, 0, 3, 0 }, + { 2, OFILE_BURNCROS, 0, 0, 0, 15, -1, 1, 0, 10, 160, 1, 0, 0, 0, 0, 0 }, + { 2, OFILE_WEAPSTND, 0, 0, 0, 16, -1, 0, 1, 0, 96, 1, 0, 1, 0, 3, 0 }, + { 2, OFILE_WEAPSTND, 0, 0, 0, 16, -1, 0, 2, 0, 96, 1, 0, 1, 0, 0, 0 }, + { 2, OFILE_MUSHPTCH, 0, 0, 0, -1, 1, 0, 1, 0, 96, 1, 1, 1, 0, 3, 1 }, + { 2, OFILE_LZSTAND, 0, 0, 0, -1, 15, 0, 1, 0, 128, 1, 0, 1, 0, 3, 0 }, + { 1, OFILE_DECAP, 9, 9, 3, -1, -1, 0, 2, 0, 96, 1, 1, 1, 0, 1, 0 }, + { 2, OFILE_CHEST3, 0, 0, 0, -1, -1, 0, 1, 0, 96, 1, 1, 1, 0, 1, 1 }, + { -1, 0, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; +char *ObjMasterLoadList[56] = +{ + "L1Braz", + "L1Doors", + "Lever", + "Chest1", + "Chest2", + "Banner", + "SkulPile", + "SkulFire", + "SkulStik", + "CruxSk1", + "CruxSk2", + "CruxSk3", + "Book1", + "Book2", + "Rockstan", + "Angel", + "Chest3", + "Burncros", + "Candle2", + "Nude2", + "Switch4", + "TNudeM", + "TNudeW", + "TSoul", + "L2Doors", + "WTorch4", + "WTorch3", + "Sarc", + "Flame1", + "Prsrplt1", + "Traphole", + "MiniWatr", + "WTorch2", + "WTorch1", + "BCase", + "BShelf", + "WeapStnd", + "Barrel", + "Barrelex", + "LShrineG", + "RShrineG", + "Bloodfnt", + "Decap", + "Pedistl", + "L3Doors", + "PFountn", + "Armstand", + "Goatshrn", + "Cauldren", + "MFountn", + "TFountn", + "Altboy", + "Mcirl", + "Bkslbrnt", + "Mushptch", + "LzStand" +}; +int bxadd[8] = { -1, 0, 1, -1, 1, -1, 0, 1 }; +int byadd[8] = { -1, -1, -1, 0, 0, 1, 1, 1 }; +char *shrinestrs[NUM_SHRINETYPE] = +{ + "Mysterious", + "Hidden", + "Gloomy", + "Weird", + "Magical", + "Stone", + "Religious", + "Enchanted", + "Thaumaturgic", + "Fascinating", + "Cryptic", + "Magical", + "Eldritch", + "Eerie", + "Divine", + "Holy", + "Sacred", + "Spiritual", + "Spooky", + "Abandoned", + "Creepy", + "Quiet", + "Secluded", + "Ornate", + "Glimmering", + "Tainted" +}; +unsigned char shrinemin[NUM_SHRINETYPE] = +{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1 +}; +unsigned char shrinemax[NUM_SHRINETYPE] = +{ + 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16 +}; +// 0 - sp+mp, 1 - sp only, 2 - mp only +unsigned char shrineavail[NUM_SHRINETYPE] = +{ + 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 2 +}; +char *StoryBookName[9] = +{ + "The Great Conflict", + "The Wages of Sin are War", + "The Tale of the Horadrim", + "The Dark Exile", + "The Sin War", + "The Binding of the Three", + "The Realms Beyond", + "Tale of the Three", + "The Black King" +}; +int StoryText[3][3] = +{ + { QUEST_BOOK11, QUEST_BOOK12, QUEST_BOOK13 }, + { QUEST_BOOK21, QUEST_BOOK22, QUEST_BOOK23 }, + { QUEST_BOOK31, QUEST_BOOK32, QUEST_BOOK33 } +}; + +void __cdecl InitObjectGFX() +{ + ObjDataStruct *v0; // eax + char *v1; // esi + unsigned char v2; // cl + int v3; // edx + int i; // eax + char v5; // al + signed int v7; // ebx + char *v8; // ST08_4 + unsigned char *v9; // eax + int v10; // ecx + unsigned char fileload[56]; // [esp+4h] [ebp-58h] + char filestr[32]; // [esp+3Ch] [ebp-20h] + + memset(fileload, 0, 0x38u); + if ( AllObjects[0].oload != -1 ) + { + v0 = AllObjects; + v1 = &AllObjects[0].otheme; + do + { + if ( v0->oload == 1 && currlevel >= (signed int)(char)*(v1 - 3) && currlevel <= (signed int)(char)*(v1 - 2) ) + fileload[(char)*(v1 - 4)] = 1; + v2 = *v1; + if ( *v1 != -1 ) + { + v3 = numthemes; + for ( i = 0; i < v3; ++i ) + { + if ( themes[i].ttype == v2 ) + fileload[(char)*(v1 - 4)] = 1; + } + } + v5 = v1[1]; + if ( v5 != -1 ) + { + if ( QuestStatus(v5) ) + fileload[(char)*(v1 - 4)] = 1; + } + v1 += 44; + v0 = (ObjDataStruct *)(v1 - 5); + } + while ( *(v1 - 5) != -1 ); + } + v7 = 0; + do + { + if ( fileload[v7] ) + { + v8 = ObjMasterLoadList[v7]; + ObjFileList[numobjfiles] = v7; + sprintf(filestr, "Objects\\%s.CEL", v8); + v9 = LoadFileInMem(filestr, 0); + v10 = numobjfiles++; + pObjCels[v10] = v9; + } + ++v7; + } + while ( v7 < 56 ); +} +// 67D7C4: using guessed type int numobjfiles; +// 44121D: using guessed type char fileload[56]; + +void __cdecl FreeObjectGFX() +{ + int i; // esi + void *v1; // ecx + + for ( i = 0; i < numobjfiles; ++i ) + { + v1 = (void *)pObjCels[i]; + pObjCels[i] = 0; + mem_free_dbg(v1); + } + numobjfiles = 0; +} +// 67D7C4: using guessed type int numobjfiles; + +bool __fastcall RndLocOk(int xp, int yp) +{ + int v2; // ecx + int v3; // eax + int v4; // eax + bool result; // eax + + v2 = xp; + v3 = v2 * 112 + yp; + result = 0; + if ( !dMonster[0][v3] && !dPlayer[v2][yp] && !dObject[v2][yp] && !(dFlags[v2][yp] & 8) ) + { + v4 = dPiece[0][v3]; + if ( !nSolidTable[v4] && (leveltype != 1 || v4 <= 126 || v4 >= 144) ) + result = 1; + } + return result; +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall InitRndLocObj(int min, int max, int objtype) +{ + int numobjs; // ebx + int xp; // esi + int yp; // edi + int i; // [esp+8h] [ebp-4h] + + i = 0; + numobjs = min + random(139, max - min); + if ( numobjs > 0 ) + { + while ( 1 ) + { + do + { + xp = random(139, 80) + 16; + yp = random(139, 80) + 16; + } + while ( !RndLocOk(xp - 1, yp - 1) ); + if ( RndLocOk(xp, yp - 1) ) + { + if ( RndLocOk(xp + 1, yp - 1) ) /* check */ + { + if ( RndLocOk(xp - 1, yp) ) + { + if ( RndLocOk(xp, yp) ) + { + if ( RndLocOk(xp + 1, yp) ) + { + if ( RndLocOk(xp - 1, yp + 1) ) + { + if ( RndLocOk(xp, yp + 1) ) + { + if ( RndLocOk(xp + 1, yp + 1) ) + { + AddObject(objtype, xp, yp); + if ( ++i >= numobjs ) + break; + } + } + } + } + } + } + } + } + } + } +} + +void __fastcall InitRndLocBigObj(int min, int max, int objtype) +{ + int xp; // edi + int yp; // esi + int numobjs; // [esp+4h] [ebp-8h] + int i; // [esp+8h] [ebp-4h] + + i = 0; + numobjs = min + random(140, max - min); + if ( numobjs > 0 ) + { + while ( 1 ) + { + do + { + xp = random(140, 80) + 16; + yp = random(140, 80) + 16; + } + while ( !RndLocOk(xp - 1, yp - 2) ); + if ( RndLocOk(xp, yp - 2) ) + { + if ( RndLocOk(xp + 1, yp - 2) ) /* check */ + { + if ( RndLocOk(xp - 1, yp - 1) ) + { + if ( RndLocOk(xp, yp - 1) ) + { + if ( RndLocOk(xp + 1, yp - 1) ) + { + if ( RndLocOk(xp - 1, yp) ) + { + if ( RndLocOk(xp, yp) ) + { + if ( RndLocOk(xp + 1, yp) ) + { + if ( RndLocOk(xp - 1, yp + 1) ) + { + if ( RndLocOk(xp, yp + 1) ) + { + if ( RndLocOk(xp + 1, yp + 1) ) + { + AddObject(objtype, xp, yp); + if ( ++i >= numobjs ) + break; + } + } + } + } + } + } + } + } + } + } + } + } + } +} + +void __fastcall InitRndLocObj5x5(int min, int max, int objtype) +{ + int v3; // esi + int v4; // edx + int v6; // ebx + int v7; // eax + int v9; // edi + int v10; // esi + int v11; // edx + signed int v12; // [esp+Ch] [ebp-14h] + int v13; // [esp+10h] [ebp-10h] + int v14; // [esp+14h] [ebp-Ch] + signed int v15; // [esp+18h] [ebp-8h] + signed int v16; // [esp+1Ch] [ebp-4h] + + v3 = min; + v4 = max - min; + v13 = 0; + v6 = v3 + random(139, v4); + if ( v6 > 0 ) + { + do + { + v14 = 0; + while ( 1 ) + { + v12 = 1; + v7 = random(139, 80); + v9 = v7 + 16; + v15 = -2; + v10 = random(139, 80) + 16; + do + { + v16 = -2; + v11 = v15 + v10; + do + { + if ( !RndLocOk(v16 + v9, v11) ) + v12 = 0; + ++v16; + } + while ( v16 <= 2 ); + ++v15; + } + while ( v15 <= 2 ); + if ( v12 ) + break; + if ( ++v14 > 20000 ) + return; + } + AddObject(objtype, v9, v10); + ++v13; + } + while ( v13 < v6 ); + } +} + +void __cdecl ClrAllObjects() +{ + int *v0; // eax + int v1; // edx + + v0 = &object[0]._oy; + do + { + *(v0 - 1) = 0; + *v0 = 0; + v0[3] = 0; + v0[4] = 0; + v0[5] = 0; + v0[6] = 0; + v0[7] = 0; + v0[10] = 0; + v0[20] = 0; + v0[21] = 0; + v0[22] = 0; + v0[23] = 0; + v0 += 30; + } + while ( (signed int)v0 < (signed int)&object[MAXOBJECTS]._oy ); + v1 = 0; + memset(objectactive, 0, sizeof(objectactive)); + nobjects = 0; + do + { + objectavail[v1] = v1; + ++v1; + } + while ( v1 < MAXOBJECTS ); + trapdir = 0; + trapid = 1; + leverid = 1; +} +// 679768: using guessed type int trapid; +// 67976C: using guessed type int trapdir; +// 67D7C8: using guessed type int hero_cpp_init_value; + +void __cdecl AddTortures() +{ + int v0; // esi + int v1; // edi + _DWORD *v2; // [esp+Ch] [ebp-4h] + + v0 = 0; + do + { + v1 = 2; + v2 = (_DWORD *)((char *)dPiece + 4 * v0); + do + { + if ( *v2 == 367 ) + { + AddObject(OBJ_TORTURE1, v1 - 2, v0 + 1); + AddObject(OBJ_TORTURE3, v1, v0 - 1); + AddObject(OBJ_TORTURE2, v1 - 2, v0 + 3); + AddObject(OBJ_TORTURE4, v1 + 2, v0 - 1); + AddObject(OBJ_TORTURE5, v1 - 2, v0 + 5); + AddObject(OBJ_TNUDEM1, v1 - 1, v0 + 3); + AddObject(OBJ_TNUDEM2, v1 + 2, v0 + 5); + AddObject(OBJ_TNUDEM3, v1, v0); + AddObject(OBJ_TNUDEM4, v1 + 1, v0 + 2); + AddObject(OBJ_TNUDEW1, v1, v0 + 4); + AddObject(OBJ_TNUDEW2, v1, v0 + 1); + AddObject(OBJ_TNUDEW3, v1 + 2, v0 + 2); + } + v2 += 112; + ++v1; + } + while ( v1 - 2 < 112 ); + ++v0; + } + while ( v0 < 112 ); +} + +void __cdecl AddCandles() +{ + int v0; // esi + int v1; // edi + int v2; // ebx + + v0 = quests[13]._qtx; + v1 = quests[13]._qty; + v2 = quests[13]._qty + 1; + AddObject(OBJ_STORYCANDLE, quests[13]._qtx - 2, quests[13]._qty + 1); + AddObject(OBJ_STORYCANDLE, v0 + 3, v2); + v1 += 2; + AddObject(OBJ_STORYCANDLE, v0 - 1, v1); + AddObject(OBJ_STORYCANDLE, v0 + 2, v1); +} + +void __fastcall AddBookLever(int lx1, int ly1, int lx2, int ly2, int x1, int y1, int x2, int y2, int msg) +{ + int v9; // esi + int v10; // edi + signed int v11; // ebx + int v12; // edx + //int v13; // eax + //int v14; // eax + //int v15; // eax + int v16; // esi + signed int v17; // [esp+Ch] [ebp-Ch] + int v18; // [esp+10h] [ebp-8h] + signed int v19; // [esp+14h] [ebp-4h] + + v18 = 0; + while ( 1 ) + { + v17 = 1; + v9 = random(139, 80) + 16; + v10 = random(139, 80) + 16; + v11 = -2; + do + { + v19 = -2; + v12 = v11 + v10; + do + { + if ( !RndLocOk(v19 + v9, v12) ) + v17 = 0; + ++v19; + } + while ( v19 <= 2 ); + ++v11; + } + while ( v11 <= 2 ); + if ( v17 ) + break; + if ( ++v18 > 20000 ) + return; + } + //_LOBYTE(v13) = QuestStatus(8); + if ( QuestStatus(8) ) + AddObject(OBJ_BLINDBOOK, v9, v10); + //_LOBYTE(v14) = QuestStatus(11); + if ( QuestStatus(11) ) + AddObject(OBJ_STEELTOME, v9, v10); + //_LOBYTE(v15) = QuestStatus(9); + if ( QuestStatus(9) ) + { + v9 = 2 * setpc_x + 25; + v10 = 2 * setpc_y + 40; + AddObject(OBJ_BLOODBOOK, v9, v10); + } + v16 = dObject[v9][v10] - 1; + SetObjMapRange(v16, x1, y1, x2, y2, leverid); + SetBookMsg(v16, msg); + ++leverid; + object[v16]._oVar6 = object[v16]._oAnimFrame + 1; +} + +void __cdecl InitRndBarrels() +{ + int v0; // ebp + int v1; // esi + int v2; // edi + int v3; // eax + bool v4; // ebx + int v5; // edx + int v6; // eax + int v7; // eax + signed int v8; // [esp+4h] [ebp-Ch] + signed int v9; // [esp+8h] [ebp-8h] + int v10; // [esp+Ch] [ebp-4h] + + v10 = 0; + v0 = random(143, 5) + 3; + if ( v0 > 0 ) + { + do + { + do + { + v1 = random(143, 80) + 16; + v2 = random(143, 80) + 16; + } + while ( !RndLocOk(v1, v2) ); + v3 = random(143, 4); + AddObject(OBJ_BARRELEX - (v3 != 0), v1, v2); + v4 = 1; + v5 = 0; + v9 = 1; + while ( !random(143, v5) && v4 ) + { + v8 = 0; + v4 = 0; + do + { + if ( v8 >= 3 ) + break; + v6 = random(143, 8); + v1 += bxadd[v6]; + v2 += byadd[v6]; + ++v8; + v4 = RndLocOk(v1, v2); + } + while ( !v4 ); + if ( v4 ) + { + v7 = random(143, 5); + AddObject(OBJ_BARRELEX - (v7 != 0), v1, v2); + ++v9; + } + v5 = v9 >> 1; + } + ++v10; + } + while ( v10 < v0 ); + } +} + +void __fastcall AddL1Objs(int x1, int y1, int x2, int y2) +{ + int v4; // ebx + int *v5; // edi + int v6; // esi + int x; // [esp+0h] [ebp-8h] + int y; // [esp+4h] [ebp-4h] + + x = x1; + for ( y = y1; y < y2; ++y ) + { + v4 = x; + if ( x < x2 ) + { + v5 = (int *)((char *)dPiece + 4 * (y + 112 * x)); + do + { + v6 = *v5; + if ( *v5 == 270 ) + AddObject(OBJ_L1LIGHT, v4, y); + if ( v6 == 44 || v6 == 51 || v6 == 214 ) + AddObject(OBJ_L1LDOOR, v4, y); + if ( v6 == 46 || v6 == 56 ) + AddObject(OBJ_L1RDOOR, v4, y); + ++v4; + v5 += 112; + } + while ( v4 < x2 ); + } + } +} + +void __fastcall AddL2Objs(int x1, int y1, int x2, int y2) +{ + int v4; // ebx + int *v5; // esi + int v6; // edi + int x; // [esp+0h] [ebp-8h] + int y; // [esp+4h] [ebp-4h] + + x = x1; + for ( y = y1; y < y2; ++y ) + { + v4 = x; + if ( x < x2 ) + { + v5 = (int *)((char *)dPiece + 4 * (y + 112 * x)); + do + { + v6 = *v5; + if ( *v5 == 13 || v6 == 541 ) + AddObject(OBJ_L2LDOOR, v4, y); + if ( v6 == 17 || v6 == 542 ) + AddObject(OBJ_L2RDOOR, v4, y); + ++v4; + v5 += 112; + } + while ( v4 < x2 ); + } + } +} + +void __fastcall AddL3Objs(int x1, int y1, int x2, int y2) +{ + int v4; // edi + int *v5; // esi + int v6; // ebx + int x; // [esp+0h] [ebp-8h] + int y; // [esp+4h] [ebp-4h] + + x = x1; + for ( y = y1; y < y2; ++y ) + { + v4 = x; + if ( x < x2 ) + { + v5 = (int *)((char *)dPiece + 4 * (y + 112 * x)); + do + { + v6 = *v5; + if ( *v5 == 531 ) + AddObject(OBJ_L3LDOOR, v4, y); + if ( v6 == 534 ) + AddObject(OBJ_L3RDOOR, v4, y); + ++v4; + v5 += 112; + } + while ( v4 < x2 ); + } + } +} + +bool __fastcall WallTrapLocOk(int xp, int yp) +{ + return (~dFlags[xp][yp] & 8u) >> 3; +} + +void __cdecl AddL2Torches() +{ + int v0; // esi + int v1; // edi + char *v2; // ebx + //int v3; // eax + int (*v5)[112]; // [esp+Ch] [ebp-Ch] + int v6; // [esp+10h] [ebp-8h] + int (*v7)[112]; // [esp+14h] [ebp-4h] + + v0 = 0; + v7 = dPiece; + do + { + v1 = 0; + v2 = &dObject[0][v0 - 1]; /* &dungeon[39][v0 + 39]; */ + v5 = v7; + do + { + //_LOBYTE(v3) = WallTrapLocOk(v1, v0); + if ( !WallTrapLocOk(v1, v0) ) + goto LABEL_18; + v6 = (*v5)[0]; + if ( (*v5)[0] == 1 ) + { + if ( random(145, 3) ) + goto LABEL_18; + AddObject(OBJ_TORCHL2, v1, v0); + } + if ( v6 == 5 ) + { + if ( random(145, 3) ) + goto LABEL_18; + AddObject(OBJ_TORCHR2, v1, v0); + } + if ( v6 == 37 ) + { + if ( random(145, 10) || *(v2 - 111) ) + goto LABEL_18; + AddObject(OBJ_TORCHL, v1 - 1, v0); + } + if ( v6 == 41 ) + { + if ( !random(145, 10) && !*v2 ) + AddObject(OBJ_TORCHR, v1, v0 - 1); + } +LABEL_18: + ++v5; + ++v1; + v2 += 112; + } + while ( v1 < 112 ); + v7 = (int (*)[112])((char *)v7 + 4); + ++v0; + } + while ( (signed int)v7 < (signed int)dPiece[1] ); +} + +bool __fastcall TorchLocOK(int xp, int yp) +{ + int v2; // ecx + bool result; // al + + v2 = xp; + if ( dFlags[v2][yp] & 8 ) + result = 0; + else + result = nTrapTable[dPiece[0][yp + v2 * 112]] != 0; + return result; +} + +void __cdecl AddObjTraps() +{ + int v0; // esi + int *v1; // eax + char *v2; // edi + int v3; // ebx + int v4; // edi + int *j; // eax + //int v6; // eax + char v7; // al + int v8; // edi + int *i; // eax + //int v10; // eax + int v11; // eax + int *v12; // [esp+0h] [ebp-18h] + char *v13; // [esp+4h] [ebp-14h] + int *v14; // [esp+8h] [ebp-10h] + int v15; // [esp+Ch] [ebp-Ch] + signed int v16; // [esp+10h] [ebp-8h] + int x; // [esp+14h] [ebp-4h] + + if ( currlevel == 1 ) + v15 = 10; + if ( currlevel >= 2u ) + v15 = 15; + if ( currlevel >= 5u ) + v15 = 20; + if ( currlevel >= 7u ) + v15 = 25; + v0 = 0; + v1 = dPiece[-1]; + v12 = dPiece[-1]; + do + { + x = 0; + v16 = 0; + v2 = (char *)dObject + v0; + v14 = v1; + v13 = (char *)dObject + v0; + do + { + if ( *v2 > 0 && random(144, 100) < v15 ) + { + v3 = (char)(*v2 - 1); + if ( AllObjects[object[v3]._otype].oTrapFlag ) + { + if ( random(144, 2) ) + { + v8 = v0 - 1; + for ( i = &dPiece[v16][v0-1]; !nSolidTable[*i]; i-- ) /* check dpiece */ + --v8; + //_LOBYTE(v10) = TorchLocOK(x, v8); + if ( TorchLocOK(x, v8) && v0 - v8 > 1 ) + { + AddObject(OBJ_TRAPR, x, v8); + v7 = dObject[v16][v8]; + goto LABEL_27; + } + } + else + { + v4 = x - 1; + for ( j = v14; !nSolidTable[*j]; j -= 112 ) + --v4; + //_LOBYTE(v6) = TorchLocOK(v4, v0); + if ( TorchLocOK(v4, v0) && x - v4 > 1 ) + { + AddObject(OBJ_TRAPL, v4, v0); + v7 = dObject[v4][v0]; +LABEL_27: + v11 = (char)(v7 - 1); + object[v11]._oVar2 = v0; + object[v11]._oVar1 = x; + object[v3]._oTrapFlag = 1; + goto LABEL_28; + } + } + } + } +LABEL_28: + ++v16; + ++x; + v14 += 112; + v2 = (char *)v13 + 112; + v13 += 112; + } + while ( v16 < 112 ); + ++v0; + v1 = v12 + 1; + ++v12; + } + while ( (signed int)v12 < (signed int)dPiece ); +} + +void __cdecl AddChestTraps() +{ + signed int v0; // ebp + _BYTE *v1; // ebx + int v2; // esi + int v3; // eax + bool v4; // zf + int v5; // eax + signed int v6; // [esp+10h] [ebp-4h] + + v0 = 0; + do + { + v1 = (unsigned char *)dObject + v0; + v6 = 112; + do + { + if ( *v1 > 0 ) + { + v2 = (char)(*v1 - 1); + v3 = object[v2]._otype; + if ( v3 >= OBJ_CHEST1 && v3 <= OBJ_CHEST3 && !object[v2]._oTrapFlag && random(0, 100) < 10 ) + { + object[v2]._otype += OBJ_BOOKCASER; + v4 = leveltype == DTYPE_CATACOMBS; + object[v2]._oTrapFlag = 1; + if ( v4 ) + v5 = random(0, 2); + else + v5 = random(0, 3); + object[v2]._oVar4 = v5; + } + } + v1 += 112; + --v6; + } + while ( v6 ); + ++v0; + } + while ( v0 < 112 ); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall LoadMapObjects(unsigned char *pMap, int startx, int starty, int x1, int y1, int w, int h, int leveridx) +{ + unsigned char *v8; // ebx + int v9; // esi + int v10; // ecx + int v11; // eax + int v12; // ecx + int v13; // eax + int v14; // esi + unsigned char *v15; // ebx + int i; // edi + int v17; // eax + int v18; // [esp+8h] [ebp-10h] + int v19; // [esp+Ch] [ebp-Ch] + int v20; // [esp+10h] [ebp-8h] + int v21; // [esp+14h] [ebp-4h] + int y; // [esp+20h] [ebp+8h] + + v8 = pMap + 2; + InitObjFlag = 1; + v9 = *pMap; + v10 = pMap[2]; + v11 = v10; + v12 = 2 * v10; + v20 = startx; + v13 = v9 * v11; + v14 = 2 * v9; + v19 = v14; + v18 = v12; + v15 = &v8[4 * v14 * v12 + 2 + 2 * v13]; + if ( v12 > 0 ) + { + v21 = -16 - starty; + y = starty + 16; + do + { + for ( i = 0; i < v14; ++i ) + { + if ( *v15 ) + { + AddObject(ObjTypeConv[*v15], i + v20 + 16, y); + v17 = ObjIndex(i + v20 + 16, y); + SetObjMapRange(v17, x1, y1, x1 + w, y1 + h, leveridx); + v14 = v19; + v12 = v18; + } + v15 += 2; + } + ++y; + } + while ( y + v21 < v12 ); + } + InitObjFlag = 0; +} +// 67D7C0: using guessed type int InitObjFlag; + +void __fastcall LoadMapObjs(unsigned char *pMap, int startx, int starty) +{ + unsigned char *v3; // esi + int v4; // eax + int v5; // edi + int v6; // ecx + int v7; // eax + int v8; // ecx + int v9; // edi + unsigned char *v10; // esi + int i; // ebx + int v12; // [esp+8h] [ebp-8h] + int v13; // [esp+Ch] [ebp-4h] + int y; // [esp+18h] [ebp+8h] + + v3 = pMap + 2; + InitObjFlag = 1; + v4 = pMap[2]; + v5 = *pMap; + v6 = v4; + v7 = 2 * v4; + v12 = startx; + v8 = v5 * v6; + v9 = 2 * v5; + v10 = &v3[4 * v9 * v7 + 2 + 2 * v8]; + if ( v7 > 0 ) + { + v13 = v7; + y = starty + 16; + do + { + for ( i = 0; i < v9; ++i ) + { + if ( *v10 ) + AddObject(ObjTypeConv[*v10], i + v12 + 16, y); + v10 += 2; + } + ++y; + --v13; + } + while ( v13 ); + } + InitObjFlag = 0; +} +// 67D7C0: using guessed type int InitObjFlag; + +void __cdecl AddDiabObjs() +{ + unsigned char *v0; // esi + unsigned char *v1; // esi + unsigned char *v2; // esi + + v0 = LoadFileInMem("Levels\\L4Data\\diab1.DUN", 0); + LoadMapObjects(v0, 2 * diabquad1x, 2 * diabquad1y, diabquad2x, diabquad2y, 11, 12, 1); + mem_free_dbg(v0); + v1 = LoadFileInMem("Levels\\L4Data\\diab2a.DUN", 0); + LoadMapObjects(v1, 2 * diabquad2x, 2 * diabquad2y, diabquad3x, diabquad3y, 11, 11, 2); + mem_free_dbg(v1); + v2 = LoadFileInMem("Levels\\L4Data\\diab3a.DUN", 0); + LoadMapObjects(v2, 2 * diabquad3x, 2 * diabquad3y, diabquad4x, diabquad4y, 9, 9, 3); + mem_free_dbg(v2); +} +// 5289C4: using guessed type int diabquad1x; +// 5289C8: using guessed type int diabquad1y; + +void __cdecl AddStoryBooks() +{ + int v0; // esi + int v1; // edi + signed int v2; // ebx + int v3; // edx + int v4; // esi + int y; // [esp+Ch] [ebp-Ch] + int v6; // [esp+10h] [ebp-8h] + signed int v7; // [esp+14h] [ebp-4h] + + v6 = 0; + while ( 1 ) + { + y = 1; + v0 = random(139, 80) + 16; + v1 = random(139, 80) + 16; + v2 = -2; + do + { + v7 = -3; + v3 = v2 + v1; + do + { + if ( !RndLocOk(v7 + v0, v3) ) + y = 0; + ++v7; + } + while ( v7 <= 3 ); + ++v2; + } + while ( v2 <= 2 ); + if ( y ) + break; + if ( ++v6 > 20000 ) + return; + } + AddObject(OBJ_STORYBOOK, v0, v1); + AddObject(OBJ_STORYCANDLE, v0 - 2, v1 + 1); + AddObject(OBJ_STORYCANDLE, v0 - 2, v1); + AddObject(OBJ_STORYCANDLE, v0 - 1, v1 - 1); + AddObject(OBJ_STORYCANDLE, v0 + 1, v1 - 1); + v4 = v0 + 2; + AddObject(OBJ_STORYCANDLE, v4, v1); + AddObject(OBJ_STORYCANDLE, v4, v1 + 1); +} + +void __fastcall AddHookedBodies(int freq) +{ + int v1; // ebx + char *v2; // esi + int v3; // edi + //int v4; // eax + int v5; // eax + int v6; // eax + int v7; // eax + int v8; // [esp-8h] [ebp-20h] + int v9; // [esp-4h] [ebp-1Ch] + int max; // [esp+Ch] [ebp-Ch] + int x; // [esp+10h] [ebp-8h] + int y; // [esp+14h] [ebp-4h] + + y = 0; + max = freq; + v1 = 16; + do + { + x = 0; + v2 = (char *)dungeon + y; + v3 = 17; + do + { + if ( *v2 == 1 || *v2 == 2 ) + { + if ( !random(0, max) ) + { + //_LOBYTE(v4) = SkipThemeRoom(x, y); + if ( SkipThemeRoom(x, y) ) + { + if ( *v2 != 1 || v2[40] != 6 ) + { + if ( *v2 == 2 && v2[1] == 6 ) + { + v7 = random(0, 2); + if ( v7 ) + { + if ( v7 != 1 ) + goto LABEL_22; + v9 = v1; + v8 = 39; + } + else + { + v9 = v1; + v8 = 38; + } + AddObject(v8, v3 - 1, v9); + } + } + else + { + v5 = random(0, 3); + if ( v5 ) + { + v6 = v5 - 1; + if ( v6 ) + { + if ( v6 == 1 ) + AddObject(OBJ_TORTURE5, v3, v1); + } + else + { + AddObject(OBJ_TORTURE2, v3, v1); + } + } + else + { + AddObject(OBJ_TORTURE1, v3, v1); + } + } + } + } + } +LABEL_22: + ++x; + v3 += 2; + v2 += 40; + } + while ( v3 < 97 ); + ++y; + v1 += 2; + } + while ( v1 < 96 ); +} + +void __cdecl AddL4Goodies() +{ + AddHookedBodies(6); + InitRndLocObj(2, 6, OBJ_TNUDEM1); + InitRndLocObj(2, 6, OBJ_TNUDEM2); + InitRndLocObj(2, 6, OBJ_TNUDEM3); + InitRndLocObj(2, 6, OBJ_TNUDEM4); + InitRndLocObj(2, 6, OBJ_TNUDEW1); + InitRndLocObj(2, 6, OBJ_TNUDEW2); + InitRndLocObj(2, 6, OBJ_TNUDEW3); + InitRndLocObj(2, 6, OBJ_DECAP); + InitRndLocObj(1, 3, OBJ_CAULDRON); +} + +void __cdecl AddLazStand() +{ + int v0; // edi + int v1; // esi + signed int v2; // ebx + int v3; // edx + int v4; // edi + signed int v5; // [esp+Ch] [ebp-Ch] + int v6; // [esp+10h] [ebp-8h] + signed int v7; // [esp+14h] [ebp-4h] + + v6 = 0; + while ( 1 ) + { + v5 = 1; + v0 = random(139, 80) + 16; + v1 = random(139, 80) + 16; + v2 = -3; + do + { + v7 = -2; + v3 = v2 + v1; + do + { + if ( !RndLocOk(v7 + v0, v3) ) + v5 = 0; + ++v7; + } + while ( v7 <= 3 ); + ++v2; + } + while ( v2 <= 3 ); + if ( v5 ) + break; + if ( ++v6 > 10000 ) + { + InitRndLocObj(1, 1, OBJ_LAZSTAND); + return; + } + } + AddObject(OBJ_LAZSTAND, v0, v1); + AddObject(OBJ_TNUDEM2, v0, v1 + 2); + AddObject(OBJ_STORYCANDLE, v0 + 1, v1 + 2); + AddObject(OBJ_TNUDEM3, v0 + 2, v1 + 2); + AddObject(OBJ_TNUDEW1, v0, v1 - 2); + AddObject(OBJ_STORYCANDLE, v0 + 1, v1 - 2); + AddObject(OBJ_TNUDEW2, v0 + 2, v1 - 2); + v4 = v0 - 1; + AddObject(OBJ_STORYCANDLE, v4, v1 - 1); + AddObject(OBJ_TNUDEW3, v4, v1); + AddObject(OBJ_STORYCANDLE, v4, v1 + 1); +} + +void __cdecl InitObjects() +{ + //int v1; // eax + //int v2; // eax + //int v3; // eax + //int v4; // eax + //int v5; // eax + //int v6; // eax + char v7; // al + signed int v8; // ebx + unsigned char *v9; // esi + //int v10; // eax + char v11; // al + //int v12; // eax + char v13; // al + unsigned char *v14; // esi + //int v15; // eax + //int v16; // [esp+0h] [ebp-4h] + + ClrAllObjects(); + if ( currlevel == 16 ) + { + AddDiabObjs(); + } + else + { + InitObjFlag = 1; + GetRndSeed(); + if ( currlevel == 9 && gbMaxPlayers == 1 ) + AddSlainHero(); + if ( currlevel == quests[1]._qlevel && quests[1]._qactive == 1 ) + AddMushPatch(); + if ( currlevel == 4 ) + AddStoryBooks(); + if ( currlevel == 8 ) + AddStoryBooks(); + if ( currlevel == 12 ) + AddStoryBooks(); + if ( leveltype == DTYPE_CATHEDRAL ) + { + //_LOBYTE(v1) = QuestStatus(6); + if ( QuestStatus(6) ) + AddTortures(); + //_LOBYTE(v2) = QuestStatus(13); + if ( QuestStatus(13) ) + AddCandles(); + //_LOBYTE(v3) = QuestStatus(7); + if ( QuestStatus(7) ) + AddObject(OBJ_SIGNCHEST, 2 * setpc_x + 26, 2 * setpc_y + 19); + InitRndLocBigObj(10, 15, OBJ_SARC); + AddL1Objs(0, 0, 112, 112); + InitRndBarrels(); + } + if ( leveltype == DTYPE_CATACOMBS ) + { + //_LOBYTE(v4) = QuestStatus(0); + if ( QuestStatus(0) ) + InitRndLocObj5x5(1, 1, OBJ_STAND); + //_LOBYTE(v5) = QuestStatus(14); + if ( QuestStatus(14) ) + InitRndLocObj5x5(1, 1, OBJ_BOOK2R); + AddL2Objs(0, 0, 112, 112); + AddL2Torches(); + //_LOBYTE(v6) = QuestStatus(8); + if ( QuestStatus(8) ) + { + v7 = plr[myplr]._pClass; + if ( v7 ) + { + if ( v7 == 1 ) + { + v8 = QUEST_RBLINDING; + } + else + { + v8 = QUEST_MBLINDING; + } + } + else + { + v8 = QUEST_BLINDING; + } + quests[8]._qmsg = v8; + AddBookLever(0, 0, 112, 112, setpc_x, setpc_y, setpc_w + setpc_x + 1, setpc_h + setpc_y + 1, v8); + v9 = LoadFileInMem("Levels\\L2Data\\Blind2.DUN", 0); + LoadMapObjs(v9, 2 * setpc_x, 2 * setpc_y); + mem_free_dbg(v9); + } + //_LOBYTE(v10) = QuestStatus(9); + if ( QuestStatus(9) ) + { + v11 = plr[myplr]._pClass; + if ( v11 ) + { + if ( v11 == 1 ) + { + v8 = QUEST_RBLOODY; + } + else if ( v11 == 2 ) + { + v8 = QUEST_MBLOODY; + } + } + else + { + v8 = QUEST_BLOODY; + } + quests[9]._qmsg = v8; + AddBookLever(0, 0, 112, 112, setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7, v8); + AddObject(OBJ_PEDISTAL, 2 * setpc_x + 25, 2 * setpc_y + 32); + } + InitRndBarrels(); + } + if ( leveltype == DTYPE_CAVES ) + { + AddL3Objs(0, 0, 112, 112); + InitRndBarrels(); + } + if ( leveltype == DTYPE_HELL ) + { + //_LOBYTE(v12) = QuestStatus(11); + if ( QuestStatus(11) ) + { + v13 = plr[myplr]._pClass; + if ( v13 ) + { + if ( v13 == 1 ) + { + v8 = QUEST_RBLOODWAR; + } + else if ( v13 == 2 ) + { + v8 = QUEST_MBLOODWAR; + } + } + else + { + v8 = QUEST_BLOODWAR; + } + quests[11]._qmsg = v8; + AddBookLever(0, 0, 112, 112, setpc_x, setpc_y, setpc_x + setpc_w, setpc_y + setpc_h, v8); + v14 = LoadFileInMem("Levels\\L4Data\\Warlord.DUN", 0); + LoadMapObjs(v14, 2 * setpc_x, 2 * setpc_y); + mem_free_dbg(v14); + } + //_LOBYTE(v15) = QuestStatus(15); + if ( QuestStatus(15) && gbMaxPlayers == 1 ) + AddLazStand(); + InitRndBarrels(); + AddL4Goodies(); + } + InitRndLocObj(5, 10, 5); + InitRndLocObj(3, 6, 6); + InitRndLocObj(1, 5, 7); + if ( leveltype != 4 ) + AddObjTraps(); + if ( (unsigned char)leveltype > 1u ) + AddChestTraps(); + InitObjFlag = 0; + } +} +// 5BB1ED: using guessed type char leveltype; +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; +// 679660: using guessed type char gbMaxPlayers; +// 67D7C0: using guessed type int InitObjFlag; + +void __fastcall SetMapObjects(unsigned char *pMap, int startx, int starty) +{ + unsigned char *v3; // esi + int v6; // edi + int v7; // eax + int v8; // esi + int v9; // ecx + int v10; // esi + int v11; // ecx + int v12; // edi + _BYTE *v13; // eax + int v14; // ebx + signed int v15; // ebx + char *v16; // ST08_4 + unsigned char *v17; // eax + int v18; // ecx + int i; // ebx + int fileload[56]; // [esp+Ch] [ebp-10Ch] + char filestr[32]; // [esp+ECh] [ebp-2Ch] + _BYTE *v22; // [esp+10Ch] [ebp-Ch] + int v23; // [esp+110h] [ebp-8h] + _BYTE *v24; // [esp+114h] [ebp-4h] + int y; // [esp+120h] [ebp+8h] + + v23 = startx; + v3 = pMap; + ClrAllObjects(); + memset(fileload, 0, sizeof(fileload)); + InitObjFlag = 1; + if ( AllObjects[0].oload != -1 ) + { + i = 0; + do + { + if ( AllObjects[i].oload == 1 && leveltype == AllObjects[i].olvltype ) + fileload[AllObjects[i].ofindex] = 1; + i++; + } + while ( AllObjects[i].oload != -1 ); + } + v6 = (unsigned char)*v3; + v7 = (int)(v3 + 2); + v8 = (unsigned char)v3[2]; + v9 = v8; + v10 = 2 * v8; + v11 = v6 * v9; + v12 = 2 * v6; + v13 = (_BYTE *)(2 * v11 + 2 + 4 * v12 * v10 + v7); + v22 = v13; + if ( v10 > 0 ) + { + v24 = (_BYTE *)v10; + do + { + if ( v12 > 0 ) + { + v14 = v12; + do + { + if ( *v13 ) + fileload[(char)AllObjects[ObjTypeConv[(unsigned char)*v13]].ofindex] = 1; + v13 += 2; + --v14; + } + while ( v14 ); + } + --v24; + } + while ( v24 ); + } + v15 = 0; + do + { + if ( fileload[v15] ) + { + v16 = ObjMasterLoadList[v15]; + ObjFileList[numobjfiles] = v15; + sprintf(filestr, "Objects\\%s.CEL", v16); + v17 = LoadFileInMem(filestr, 0); + v18 = numobjfiles++; + pObjCels[v18] = v17; + } + ++v15; + } + while ( v15 < 56 ); + v24 = v22; + if ( v10 > 0 ) + { + y = starty + 16; + do + { + for ( i = 0; i < v12; ++i ) + { + if ( *v24 ) + AddObject(ObjTypeConv[(unsigned char)*v24], i + v23 + 16, y); + v24 += 2; + } + ++y; + --v10; + } + while ( v10 ); + } + InitObjFlag = 0; +} +// 5BB1ED: using guessed type char leveltype; +// 67D7C0: using guessed type int InitObjFlag; +// 67D7C4: using guessed type int numobjfiles; +// 4427C5: using guessed type int var_10C[56]; + +void __fastcall DeleteObject(int oi, int i) +{ + int v2; // eax + bool v3; // zf + bool v4; // sf + + dObject[object[oi]._ox][object[oi]._oy] = 0; + v2 = nobjects - 1; + v3 = nobjects == 1; + v4 = nobjects - 1 < 0; + objectavail[-nobjects + MAXOBJECTS] = oi; /* *(&object[0]._otype - nobjects) = oi; */ + nobjects = v2; + if ( !v4 && !v3 && i != v2 ) + objectactive[i] = objectactive[v2]; +} + +void __fastcall SetupObject(int i, int x, int y, int ot) +{ + int v4; // esi + int v5; // edi + int v6; // ecx + int v7; // edx + int v8; // eax + int v9; // eax + int v10; // edx + int v11; // eax + int v13; // eax + int v14; // eax + + v4 = i; + object[v4]._otype = ot; + v5 = ot; + v6 = AllObjects[ot].ofindex; + object[v4]._ox = x; + object[v4]._oy = y; + v7 = ObjFileList[0]; + v8 = 0; + while ( v7 != v6 ) + v7 = ObjFileList[v8++ + 1]; + object[v4]._oAnimData = pObjCels[v8]; + v9 = AllObjects[v5].oAnimFlag; + object[v4]._oAnimFlag = v9; + if ( v9 ) + { + v10 = AllObjects[v5].oAnimDelay; + object[v4]._oAnimDelay = v10; + object[v4]._oAnimCnt = random(146, v10); + v11 = AllObjects[v5].oAnimLen; + object[v4]._oAnimLen = v11; + v13 = random(146, v11 - 1) + 1; + } + else + { + v14 = AllObjects[v5].oAnimLen; + object[v4]._oAnimDelay = 1000; + object[v4]._oAnimLen = v14; + v13 = AllObjects[v5].oAnimDelay; + object[v4]._oAnimCnt = 0; + } + object[v4]._oAnimFrame = v13; + object[v4]._oAnimWidth = AllObjects[v5].oAnimWidth; + object[v4]._oSolidFlag = AllObjects[v5].oSolidFlag; + object[v4]._oMissFlag = AllObjects[v5].oMissFlag; + object[v4]._oLight = AllObjects[v5].oLightFlag; + object[v4]._oBreak = AllObjects[v5].oBreak; + object[v4]._oDelFlag = 0; + object[v4]._oSelFlag = AllObjects[v5].oSelFlag; + object[v4]._oPreFlag = 0; + object[v4]._oTrapFlag = 0; + object[v4]._oDoorFlag = 0; +} + +void __fastcall SetObjMapRange(int i, int x1, int y1, int x2, int y2, int v) +{ + object[i]._oVar1 = x1; + object[i]._oVar2 = y1; + object[i]._oVar3 = x2; + object[i]._oVar4 = y2; + object[i]._oVar8 = v; +} + +void __fastcall SetBookMsg(int i, int msg) +{ + object[i]._oVar7 = msg; +} + +void __fastcall AddL1Door(int i, int x, int y, int ot) +{ + int v4; // ecx + int v5; // edx + int *v6; // eax + int v7; // edx + int v8; // eax + int v9; // eax + + v4 = i; + v5 = 112 * x; + object[v4]._oDoorFlag = 1; + if ( ot == 1 ) + { + v6 = (int *)((char *)dPiece + 4 * (y + v5)); + v7 = *v6; + v8 = *(v6 - 1); + } + else + { + v9 = v5 + y; + v7 = dPiece[0][v5 + y]; + v8 = dPiece[-1][v5 + y]; // *(_DWORD *)&dflags[28][4 * v9 + 32]; /* check */ + } + object[v4]._oVar4 = 0; + object[v4]._oVar1 = v7; + object[v4]._oVar2 = v8; +} + +void __fastcall AddSCambBook(int i) +{ + object[i]._oVar1 = setpc_x; + object[i]._oVar2 = setpc_y; + object[i]._oVar3 = setpc_w + setpc_x + 1; + object[i]._oVar4 = setpc_h + setpc_y + 1; + object[i]._oVar6 = object[i]._oAnimFrame + 1; +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __fastcall AddChest(int i, int t) +{ + int v2; // edi + int v3; // esi + int v4; // esi + int v6; // [esp-4h] [ebp-Ch] + + v2 = t; + v3 = i; + if ( !random(147, 2) ) + object[v3]._oAnimFrame += 3; + v4 = v3; + object[v4]._oRndSeed = GetRndSeed(); + switch ( v2 ) + { + case OBJ_CHEST1: + goto LABEL_22; + case OBJ_CHEST2: +LABEL_12: + if ( setlevel ) + { + object[v4]._oVar1 = 2; + break; + } + v6 = 3; + goto LABEL_18; + case OBJ_CHEST3: +LABEL_9: + if ( setlevel ) + { + object[v4]._oVar1 = 3; + break; + } + v6 = 4; +LABEL_18: + object[v4]._oVar1 = random(147, v6); + break; + case OBJ_TCHEST1: +LABEL_22: + if ( setlevel ) + { + object[v4]._oVar1 = 1; + break; + } + v6 = 2; + goto LABEL_18; + case OBJ_TCHEST2: + goto LABEL_12; + case OBJ_TCHEST3: + goto LABEL_9; + } + object[v4]._oVar2 = random(147, 8); +} +// 5CF31D: using guessed type char setlevel; + +void __fastcall AddL2Door(int i, int x, int y, int ot) +{ + int v4; // esi + + v4 = i; + object[i]._oDoorFlag = 1; + if ( ot == OBJ_L2LDOOR ) + ObjSetMicro(x, y, 538); + else + ObjSetMicro(x, y, 540); + object[v4]._oVar4 = 0; +} + +void __fastcall AddL3Door(int i, int x, int y, int ot) +{ + int v4; // esi + + v4 = i; + object[i]._oDoorFlag = 1; + if ( ot == OBJ_L3LDOOR ) + ObjSetMicro(x, y, 531); + else + ObjSetMicro(x, y, 534); + object[v4]._oVar4 = 0; +} + +void __fastcall AddSarc(int i) +{ + int v1; // esi + char v2; // al + int v3; // ecx + int v4; // eax + bool v5; // sf + unsigned char v6; // of + + v1 = i; + v2 = -1 - i; + v3 = 112 * object[i]._ox; + dObject[0][v3 + object[v1]._oy - 1] = v2; /* dungeon[39][v3 + 39 + object[v1]._oy] = v2; */ + object[v1]._oVar1 = random(153, 10); + v4 = GetRndSeed(); + v6 = __OFSUB__(object[v1]._oVar1, 8); + v5 = object[v1]._oVar1 - 8 < 0; + object[v1]._oRndSeed = v4; + if ( !(v5 ^ v6) ) + object[v1]._oVar2 = PreSpawnSkeleton(); +} + +void __fastcall AddFlameTrap(int i) +{ + object[i]._oVar1 = trapid; + object[i]._oVar2 = 0; + object[i]._oVar3 = trapdir; + object[i]._oVar4 = 0; +} +// 679768: using guessed type int trapid; +// 67976C: using guessed type int trapdir; + +void __fastcall AddFlameLvr(int i) +{ + object[i]._oVar1 = trapid; + object[i]._oVar2 = 49; +} +// 679768: using guessed type int trapid; + +void __fastcall AddTrap(int i) +{ + int mt; // eax + + mt = random(148, currlevel / 3 + 1); + if ( !mt ) + object[i]._oVar3 = 0; + if ( mt == 1 ) + object[i]._oVar3 = 1; + if ( mt == 2 ) + object[i]._oVar3 = 7; + object[i]._oVar4 = 0; +} + +void __fastcall AddObjLight(int i, int r) +{ + if ( InitObjFlag ) + { + DoLighting(object[i]._ox, object[i]._oy, r, -1); + object[i]._oVar1 = -1; + } + else + { + object[i]._oVar1 = 0; + } +} +// 67D7C0: using guessed type int InitObjFlag; + +void __fastcall AddBarrel(int i) +{ + int v1; // esi + int v2; // eax + int v4; // eax + int v6; // eax + bool v7; // sf + unsigned char v8; // of + + v1 = i; + object[i]._oVar1 = 0; + v2 = GetRndSeed(); + object[v1]._oRndSeed = v2; + v4 = random(149, 10); + object[v1]._oVar2 = v4; + v6 = random(149, 3); + v8 = __OFSUB__(object[v1]._oVar2, 8); + v7 = object[v1]._oVar2 - 8 < 0; + object[v1]._oVar3 = v6; + if ( !(v7 ^ v8) ) + object[v1]._oVar4 = PreSpawnSkeleton(); +} + +void __fastcall AddShrine(int i) +{ + int v1; // esi + signed int v2; // edi + signed int v3; // eax + int *v4; // ecx + bool v5; // zf + int v6; // eax + int slist[26]; // [esp+8h] [ebp-68h] + + v1 = i; + v2 = currlevel; + v3 = 0; + object[i]._oPreFlag = 1; + do + { + if ( v2 < (char)shrinemin[v3] || v2 > (char)shrinemax[v3] ) + { + v4 = &slist[v3]; + *v4 = 0; + } + else + { + v4 = &slist[v3]; + *v4 = 1; + } + if ( gbMaxPlayers == 1 ) + v5 = shrineavail[v3] == 2; + else + v5 = shrineavail[v3] == 1; + if ( v5 ) + *v4 = 0; + ++v3; + } + while ( v3 < 26 ); + do + { + v6 = random(150, 26); + } + while ( !slist[v6] ); + object[v1]._oVar1 = v6; + if ( random(150, 2) ) + { + object[v1]._oAnimFrame = 12; + object[v1]._oAnimLen = 22; + } +} +// 679660: using guessed type char gbMaxPlayers; +// 442E0F: using guessed type int var_68[26]; + +void __fastcall AddBookcase(int i) +{ + int v1; // esi + + v1 = i; + object[v1]._oRndSeed = GetRndSeed(); + object[v1]._oPreFlag = 1; +} + +void __fastcall AddPurifyingFountain(int i) +{ + char *v1; // eax + + v1 = &dObject[object[i]._ox][object[i]._oy]; + *(v1 - 1) = -1 - i; + *(v1 - 112) = -1 - i; + *(v1 - 113) = -1 - i; + object[i]._oRndSeed = GetRndSeed(); +} + +void __fastcall AddArmorStand(int i) +{ + int v1; // eax + + if ( !armorFlag ) + { + v1 = i; + object[v1]._oSelFlag = 0; + object[v1]._oAnimFlag = 2; + } + object[i]._oRndSeed = GetRndSeed(); +} +// 6AAA3C: using guessed type int armorFlag; + +void __fastcall AddDecap(int i) +{ + int v1; // esi + int v2; // eax + int v4; // eax + + v1 = i; + v2 = GetRndSeed(); + object[v1]._oRndSeed = v2; + v4 = random(151, 8); + object[v1]._oPreFlag = 1; + object[v1]._oAnimFrame = v4 + 1; +} + +void __fastcall AddVilebook(int i) +{ + if ( setlevel ) + { + if ( setlvlnum == SL_VILEBETRAYER ) + object[i]._oAnimFrame = 4; + } +} +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +void __fastcall AddMagicCircle(int i) +{ + int v1; // esi + int v2; // eax + + v1 = i; + v2 = GetRndSeed(); + object[v1]._oVar6 = 0; + object[v1]._oRndSeed = v2; + object[v1]._oPreFlag = 1; + object[v1]._oVar5 = 1; +} + +void __fastcall AddBookstand(int i) +{ + object[i]._oRndSeed = GetRndSeed(); +} + +void __fastcall AddPedistal(int i) +{ + int v1; // ecx + int v2; // eax + int v3; // edx + int v4; // esi + int v5; // esi + int v6; // eax + + v1 = i; + v2 = setpc_x; + v3 = setpc_y; + v4 = setpc_w; + object[v1]._oVar1 = setpc_x; + v5 = v2 + v4; + v6 = setpc_h; + object[v1]._oVar3 = v5; + object[v1]._oVar2 = v3; + object[v1]._oVar4 = v3 + v6; +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __fastcall AddStoryBook(int i) +{ + int bookframe; // eax + int v7; // eax + + SetRndSeed(glSeedTbl[16]); + bookframe = random(0, 3); + + object[i]._oVar1 = bookframe; + if ( currlevel == 4 ) + object[i]._oVar2 = StoryText[bookframe][0]; + if ( currlevel == 8 ) + object[i]._oVar2 = StoryText[bookframe][1]; + if ( currlevel == 12 ) + object[i]._oVar2 = StoryText[bookframe][2]; + object[i]._oVar3 = ((unsigned int)currlevel >> 2) + 3 * bookframe - 1; + v7 = 5 - 2 * bookframe; + object[i]._oAnimFrame = v7; + object[i]._oVar4 = v7 + 1; +} + +void __fastcall AddWeaponRack(int i) +{ + if ( !weaponFlag ) + { + object[i]._oSelFlag = 0; + object[i]._oAnimFlag = 2; + } + object[i]._oRndSeed = GetRndSeed(); +} +// 6AAA50: using guessed type int weaponFlag; + +void __fastcall AddTorturedBody(int i) +{ + object[i]._oRndSeed = GetRndSeed(); + object[i]._oPreFlag = 1; + object[i]._oAnimFrame = random(0, 4) + 1; +} + +void __fastcall GetRndObjLoc(int randarea, int *xx, int *yy) +{ + int *v3; // ebx + int v4; // eax + int v6; // eax + int v7; // esi + bool v8; // eax + int v9; // edi + int v10; // [esp+Ch] [ebp-Ch] + int v11; // [esp+10h] [ebp-8h] + int v12; // [esp+14h] [ebp-4h] + + v3 = xx; + v12 = randarea; + if ( randarea ) + { + v10 = 0; + while ( 1 ) + { +LABEL_3: + if ( ++v10 > 1000 && v12 > 1 ) + --v12; + v4 = random(0, 112); + *v3 = v4; + v6 = random(0, 112); + v7 = v6; + *yy = v6; + v8 = 0; + v11 = 0; + if ( v12 <= 0 ) + break; + while ( !v8 ) + { + v9 = 0; + do + { + if ( v8 ) + break; + v8 = RndLocOk(v11 + *v3, v7 + v9++) == 0; + } + while ( v9 < v12 ); + randarea = ++v11; + if ( v11 >= v12 ) + { + if ( v8 ) + goto LABEL_3; + return; + } + } + } + } +} + +void __cdecl AddMushPatch() +{ + int i; // bl + int y; // [esp+0h] [ebp-8h] + int x; // [esp+4h] [ebp-4h] + + if ( nobjects < MAXOBJECTS ) + { + i = objectavail[0]; + GetRndObjLoc(5, &x, &y); + dObject[x + 1][y + 1] = -1 - i; + dObject[x + 2][y + 1] = -1 - i; + dObject[x + 1][y + 2] = -1 - i; + AddObject(OBJ_MUSHPATCH, x + 2, y + 2); + } +} + +void __cdecl AddSlainHero() +{ + int x; // [esp+0h] [ebp-8h] + int y; // [esp+4h] [ebp-4h] + + GetRndObjLoc(5, &x, &y); + AddObject(OBJ_SLAINHERO, x + 2, y + 2); +} + +void __fastcall AddObject(int ot, int ox, int oy) +{ + int v3; // ebp + int v4; // esi + //unsigned int v5; // eax + int v6; // ebx + int v7; // ebx + int v8; // eax + + v3 = ox; + v4 = ot; + if ( nobjects < MAXOBJECTS ) + { + //v5 = 4 * nobjects; + v6 = objectavail[0]; + objectactive[nobjects] = objectavail[0]; + objectavail[0] = objectavail[-nobjects + 126]; /* double check, MAXOBJECTS */ + dObject[ox][oy] = v6 + 1; + SetupObject(v6, ox, oy, ot); + switch ( v4 ) + { + case OBJ_L1LIGHT: + case OBJ_SKFIRE: + case OBJ_CANDLE1: + case OBJ_CANDLE2: + case OBJ_BOOKCANDLE: + goto LABEL_31; + case OBJ_L1LDOOR: + case OBJ_L1RDOOR: + AddL1Door(v6, v3, oy, v4); + break; + case OBJ_CHEST1: + case OBJ_CHEST2: + case OBJ_CHEST3: + case OBJ_TCHEST1: + case OBJ_TCHEST2: + case OBJ_TCHEST3: + AddChest(v6, v4); + break; + case OBJ_BOOK2L: + AddVilebook(v6); + break; + case OBJ_BCROSS: + case OBJ_TBCROSS: + AddBookstand(v6); +LABEL_31: + AddObjLight(v6, 5); + break; + case OBJ_TNUDEM2: + AddTorturedBody(v6); + break; + case OBJ_BOOK2R: + AddSCambBook(v6); + break; + case OBJ_L2LDOOR: + case OBJ_L2RDOOR: + AddL2Door(v6, v3, oy, v4); + break; + case OBJ_TORCHL: + case OBJ_TORCHR: + case OBJ_TORCHL2: + case OBJ_TORCHR2: + AddObjLight(v6, 8); + break; + case OBJ_SARC: + AddSarc(v6); + break; + case OBJ_FLAMEHOLE: + AddFlameTrap(v6); + break; + case OBJ_FLAMELVR: + AddFlameLvr(v6); + break; + case OBJ_WATER: + object[v6]._oAnimFrame = 1; + break; + case OBJ_TRAPL: + case OBJ_TRAPR: + AddTrap(v6); + break; + case OBJ_BARREL: + case OBJ_BARRELEX: + AddBarrel(v6); + break; + case OBJ_SHRINEL: + case OBJ_SHRINER: + AddShrine(v6); + break; + case OBJ_SKELBOOK: + case OBJ_BOOKSTAND: + AddBookstand(v6); + break; + case OBJ_BOOKCASEL: + case OBJ_BOOKCASER: + AddBookcase(v6); + break; + case OBJ_BLOODFTN: + AddBookstand(v6); + break; + case OBJ_DECAP: + AddDecap(v6); + break; + case OBJ_PEDISTAL: + AddPedistal(v6); + break; + case OBJ_L3LDOOR: + case OBJ_L3RDOOR: + AddL3Door(v6, v3, oy, v4); + break; + case OBJ_PURIFYINGFTN: + AddPurifyingFountain(v6); + break; + case OBJ_ARMORSTAND: + case OBJ_WARARMOR: + AddArmorStand(v6); + break; + case OBJ_GOATSHRINE: + AddBookstand(v6); + break; + case OBJ_CAULDRON: + AddBookstand(v6); + break; + case OBJ_MURKYFTN: + AddPurifyingFountain(v6); + break; + case OBJ_TEARFTN: + AddBookstand(v6); + break; + case OBJ_MCIRCLE1: + case OBJ_MCIRCLE2: + AddMagicCircle(v6); + break; + case OBJ_STORYBOOK: + AddStoryBook(v6); + break; + case OBJ_STORYCANDLE: + AddObjLight(v6, 3); + break; + case OBJ_WARWEAP: + case OBJ_WEAPONRACK: + AddWeaponRack(v6); + break; + default: + break; + } + v7 = v6; + v8 = object[v7]._oAnimWidth - 64; + ++nobjects; + object[v7]._oAnimWidth2 = v8 >> 1; + } +} + +void __fastcall Obj_Light(int i, int lr) +{ + int v2; // esi + int v3; // ebx + int *v4; // edi + int v5; // ST18_4 + int v6; // eax + int r; // [esp+Ch] [ebp-14h] + int x; // [esp+14h] [ebp-Ch] + int y; // [esp+18h] [ebp-8h] + signed int v10; // [esp+1Ch] [ebp-4h] + + v2 = i; + r = lr; + if ( object[i]._oVar1 != -1 ) + { + v10 = 0; + x = object[v2]._ox; + v3 = lr + 10; + y = object[v2]._oy; + if ( lightflag ) + { +LABEL_15: + if ( object[v2]._oVar1 == 1 ) + AddUnLight(object[v2]._olid); + object[v2]._oVar1 = 0; + } + else + { + v4 = &plr[0].plrlevel; + while ( !v10 ) + { + if ( *((_BYTE *)v4 - 23) ) + { + if ( currlevel == *v4 ) + { + v5 = abs(v4[1] - x); + v6 = abs(v4[2] - y); + if ( v5 < v3 && v6 < v3 ) + v10 = 1; + } + } + v4 += 5430; + if ( (signed int)v4 >= (signed int)&plr[4].plrlevel ) + { + if ( !v10 ) + goto LABEL_15; + break; + } + } + if ( !object[v2]._oVar1 ) + object[v2]._olid = AddLight(x, y, r); + object[v2]._oVar1 = 1; + } + } +} +// 646A28: using guessed type int lightflag; + +void __fastcall Obj_Circle(int i) +{ + int v1; // ecx + int v2; // edx + int v3; // esi + int v4; // eax + int v5; // ST1C_4 + int v6; // edx + int v7; // eax + + v1 = i; + v2 = object[v1]._ox; + v3 = object[v1]._oy; + if ( plr[myplr].WorldX != v2 || plr[myplr].WorldY != v3 ) + { + v7 = object[v1]._otype; + if ( v7 == OBJ_MCIRCLE1 ) + object[v1]._oAnimFrame = 1; + if ( v7 == OBJ_MCIRCLE2 ) + object[v1]._oAnimFrame = 3; + object[v1]._oVar6 = 0; + } + else + { + v4 = object[v1]._otype; + if ( v4 == OBJ_MCIRCLE1 ) + object[v1]._oAnimFrame = 2; + if ( v4 == OBJ_MCIRCLE2 ) + object[v1]._oAnimFrame = 4; + if ( v2 == 45 ) + { + if ( v3 == 47 ) + { + object[v1]._oVar6 = 2; + return; + } + } + else if ( v2 == 26 && v3 == 46 ) + { + object[v1]._oVar6 = 1; + return; + } + object[v1]._oVar6 = 0; + if ( v2 == 35 && v3 == 36 && object[v1]._oVar5 == 3 ) + { + v5 = object[v1]._oVar4; + v6 = object[v1]._oVar2; + object[v1]._oVar6 = 4; + ObjChangeMapResync(object[v1]._oVar1, v6, object[v1]._oVar3, v5); + if ( quests[15]._qactive == 2 ) + quests[15]._qvar1 = 4; + AddMissile(plr[myplr].WorldX, plr[myplr].WorldY, 35, 46, plr[myplr]._pdir, 3, 0, myplr, 0, 0); + track_repeat_walk(0); + sgbMouseDown = 0; + ReleaseCapture(); + ClrPlrPath(myplr); + StartStand(myplr, 0); + } + } +} +// 525748: using guessed type char sgbMouseDown; + +void __fastcall Obj_StopAnim(int i) +{ + if ( object[i]._oAnimFrame == object[i]._oAnimLen ) + { + object[i]._oAnimCnt = 0; + object[i]._oAnimDelay = 1000; + } +} + +void __fastcall Obj_Door(int i) +{ + int dy; // edx + int dx; // eax + + if ( object[i]._oVar4 ) + { + dy = object[i]._oy; + dx = object[i]._ox; + object[i]._oSelFlag = 2; + object[i]._oMissFlag = 1; + object[i]._oVar4 = ((dItem[dx][dy] == 0 + && dDead[dx][dy] == 0 + && dPlayer[dx][dy] == 0 + && dMonster[dx][dy] == 0) == 0) + + 1; + } + else + { + object[i]._oMissFlag = 0; + object[i]._oSelFlag = 3; + } +} + +void __fastcall Obj_Sarc(int i) +{ + if ( object[i]._oAnimFrame == object[i]._oAnimLen ) + object[i]._oAnimFlag = 0; +} + +void __fastcall ActivateTrapLine(int ttype, int tid) +{ + int v2; // edi + int i; // ebp + int v4; // esi + int v5; // edx + int v6; // ecx + int v7; // [esp+8h] [ebp-4h] + + v2 = 0; + v7 = tid; + for ( i = ttype; v2 < nobjects; ++v2 ) + { + v4 = objectactive[v2]; + if ( object[v4]._otype == i && object[v4]._oVar1 == v7 ) + { + v5 = object[v4]._oy; + v6 = object[v4]._ox; + object[v4]._oVar4 = 1; + object[v4]._oAnimFlag = 1; + object[v4]._oAnimDelay = 1; + object[v4]._olid = AddLight(v6, v5, 1); + } + } +} + +void __fastcall Obj_FlameTrap(int i) +{ + int v1; // ecx + int *v2; // esi + int v3; // eax + int v4; // ecx + bool v5; // zf + bool v6; // sf + unsigned char v7; // of + int v8; // edx + int v9; // eax + signed int v10; // esi + int v11; // eax + _BYTE *v12; // edx + _DWORD *v13; // eax + int v14; // eax + _BYTE *v15; // edx + _DWORD *v16; // eax + int *v17; // eax + + v1 = i; + if ( object[v1]._oVar2 ) + { + v2 = &object[v1]._oVar4; + if ( !object[v1]._oVar4 ) + return; + v3 = --object[v1]._oAnimFrame; + if ( v3 == 1 ) + { + v4 = object[v1]._olid; + *v2 = 0; + AddUnLight(v4); + return; + } + v7 = __OFSUB__(v3, 4); + v5 = v3 == 4; + v6 = v3 - 4 < 0; + goto LABEL_24; + } + if ( object[v1]._oVar4 ) + { + v17 = &object[v1]._oAnimFrame; + if ( object[v1]._oAnimFrame == object[v1]._oAnimLen ) + *v17 = 11; + v3 = *v17; + v7 = __OFSUB__(v3, 5); + v5 = v3 == 5; + v6 = v3 - 5 < 0; +LABEL_24: + if ( (unsigned char)(v6 ^ v7) | v5 ) + ChangeLightRadius(object[v1]._olid, v3); + return; + } + v8 = object[v1]._oy; + v9 = object[v1]._ox; + v10 = 5; + if ( object[v1]._oVar3 == 2 ) + { + v11 = v8 + 112 * (v9 - 2); + v12 = (unsigned char *)dPlayer + v11; + v13 = (_DWORD *)((char *)dMonster + 4 * v11); + do + { + if ( *v12 || *v13 ) + object[v1]._oVar4 = 1; + v13 += 112; + v12 += 112; + --v10; + } + while ( v10 ); + } + else + { + v14 = v8 - 2 + 112 * v9; + v15 = (unsigned char *)dPlayer + v14; + v16 = (_DWORD *)((char *)dMonster + 4 * v14); + do + { + if ( *v15 || *v16 ) + object[v1]._oVar4 = 1; + ++v16; + ++v15; + --v10; + } + while ( v10 ); + } + if ( object[v1]._oVar4 ) + ActivateTrapLine(object[v1]._otype, object[v1]._oVar1); +} + +void __fastcall Obj_Trap(int i) +{ + int edi1; // edi + int v2; // esi + int v3; // eax + int v4; // eax + int v5; // ebx + int v6; // ecx + int v7; // eax + int v8; // ecx + char *j; // edx + int v10; // eax + int v11; // [esp+8h] [ebp-1Ch] + int v12; // [esp+10h] [ebp-14h] + int sx; // [esp+14h] [ebp-10h] + int sy; // [esp+18h] [ebp-Ch] + int v15; // [esp+1Ch] [ebp-8h] + int v1; // [esp+20h] [ebp-4h] + + edi1 = i; + if ( object[i]._oVar4 ) + return; + v2 = dObject[object[edi1]._oVar1][object[edi1]._oVar2] - 1; + v3 = object[v2]._otype; + if ( v3 <= OBJ_L2RDOOR ) + { + if ( v3 < OBJ_L2LDOOR ) + { + if ( v3 <= 0 ) + return; + if ( v3 > OBJ_L1RDOOR ) + { + if ( v3 <= OBJ_SKFIRE || v3 > OBJ_CHEST3 && v3 != OBJ_SWITCHSKL ) + return; + goto LABEL_9; + } + } +LABEL_17: + if ( !object[v2]._oVar4 ) + return; + goto LABEL_10; + } + if ( v3 != OBJ_SARC ) + { + if ( v3 <= OBJ_PEDISTAL || v3 > OBJ_L3RDOOR ) + return; + goto LABEL_17; + } +LABEL_9: + if ( object[v2]._oSelFlag ) + return; +LABEL_10: + v4 = object[edi1]._ox; + object[edi1]._oVar4 = 1; + v5 = object[v2]._oy; + v6 = object[v2]._ox; + sx = v4; + sy = object[edi1]._oy; + v7 = v5 - 1; + v1 = object[v2]._ox; + v11 = v5 + 1; + if ( (unsigned char)(__OFSUB__(v5 - 1, v5 + 1) ^ 1) | (v5 - 1 == v5 + 1) ) + { + v12 = v6 - 1; + v15 = v6 + 1; + do + { + v8 = v12; + if ( v12 <= v15 ) + { + for ( j = &dPlayer[v12][v7]; ; j += 112 ) + { + if ( *j ) + { + v1 = v8; + v5 = v7; + } + if ( ++v8 > v15 ) + break; + } + } + ++v7; + } + while ( v7 <= v11 ); + v6 = v1; + } + if ( !deltaload ) + { + v10 = GetDirection(sx, sy, v6, v5); + AddMissile(sx, sy, v1, v5, v10, object[edi1]._oVar3, 1, -1, 0, 0); + PlaySfxLoc(IS_TRAP, object[v2]._ox, object[v2]._oy); + } + object[v2]._oTrapFlag = 0; +} +// 676190: using guessed type int deltaload; + +void __fastcall Obj_BCrossDamage(int i) +{ + int v1; // esi + bool v2; // zf + int v3; // ecx + int v4; // edx + char v5; // al + int v6; // ecx + int damage[4]; // [esp+4h] [ebp-18h] + int v8; // [esp+18h] [ebp-4h] + + v1 = myplr; + v8 = i; + v2 = plr[myplr]._pmode == PM_DEATH; + damage[0] = 6; + damage[1] = 8; + damage[2] = 10; + damage[3] = 12; + if ( !v2 ) + { + v3 = plr[v1]._pFireResist; + if ( v3 > 0 ) + damage[(unsigned char)leveltype-1] -= v3 * damage[(unsigned char)leveltype-1] / 100; + if ( plr[v1].WorldX == object[v8]._ox && plr[v1].WorldY == object[v8]._oy - 1 ) + { + v4 = damage[(unsigned char)leveltype-1]; + plr[v1]._pHitPoints -= v4; + plr[v1]._pHPBase -= v4; + if ( (signed int)(plr[v1]._pHitPoints & 0xFFFFFFC0) <= 0 ) + { + SyncPlrKill(myplr, 0); +LABEL_15: + drawhpflag = 1; + return; + } + v5 = plr[v1]._pClass; + if ( v5 ) + { + if ( v5 == 1 ) + { + v6 = PS_ROGUE68; + } + else + { + if ( v5 != 2 ) + goto LABEL_15; + v6 = PS_MAGE68; + } + } + else + { + v6 = PS_WARR68; + } + PlaySfxLoc(v6, plr[v1].WorldX, plr[v1].WorldY); + goto LABEL_15; + } + } +} +// 5BB1ED: using guessed type char leveltype; + +void __cdecl ProcessObjects() +{ + int v0; // ebx + int v1; // edi + int v2; // esi + int v3; // eax + int *v4; // eax + int *v5; // eax + int v6; // edx + + v0 = 0; + if ( nobjects > 0 ) + { + while ( 1 ) + { + v1 = objectactive[v0]; + v2 = objectactive[v0]; + v3 = object[v2]._otype; + if ( v3 <= OBJ_SARC ) + break; + if ( v3 <= OBJ_L3RDOOR ) + { + if ( v3 >= OBJ_L3LDOOR ) + goto LABEL_32; + if ( v3 == OBJ_FLAMEHOLE ) + { + Obj_FlameTrap(v1); + goto LABEL_40; + } + if ( v3 <= OBJ_BOOKLVR ) + goto LABEL_40; + if ( v3 <= OBJ_TRAPR ) + { + Obj_Trap(v1); + goto LABEL_40; + } + if ( v3 <= OBJ_WEAPRACK ) + goto LABEL_40; + if ( v3 <= OBJ_SHRINER ) + { +LABEL_29: + Obj_StopAnim(v1); + goto LABEL_40; + } + if ( v3 != OBJ_BOOKCANDLE ) + goto LABEL_40; +LABEL_28: + Obj_Light(v1, 5); + goto LABEL_40; + } + if ( v3 < OBJ_MCIRCLE1 ) + goto LABEL_40; + if ( v3 <= OBJ_MCIRCLE2 ) + { + Obj_Circle(v1); + } + else + { + if ( v3 != OBJ_STORYCANDLE ) + { + if ( v3 != OBJ_TBCROSS ) + goto LABEL_40; + goto LABEL_37; + } + Obj_Light(v1, 3); + } +LABEL_40: + if ( object[v2]._oAnimFlag ) + { + v4 = &object[v2]._oAnimCnt; + ++*v4; + if ( object[v2]._oAnimCnt >= object[v2]._oAnimDelay ) + { + *v4 = 0; + v5 = &object[v2]._oAnimFrame; + ++*v5; + if ( object[v2]._oAnimFrame > object[v2]._oAnimLen ) + *v5 = 1; + } + } + if ( ++v0 >= nobjects ) + goto LABEL_45; + } + if ( v3 == OBJ_SARC ) + { + Obj_Sarc(v1); + goto LABEL_40; + } + if ( v3 > OBJ_CRUX3 ) + { + if ( v3 != OBJ_BCROSS ) + { + if ( v3 <= OBJ_BOOK2R ) + goto LABEL_40; + if ( v3 > OBJ_L2RDOOR ) + { + if ( v3 <= OBJ_TORCHR2 ) + Obj_Light(v1, 8); + goto LABEL_40; + } +LABEL_32: + Obj_Door(v1); + goto LABEL_40; + } +LABEL_37: + Obj_Light(v1, 10); + Obj_BCrossDamage(v1); + goto LABEL_40; + } + if ( v3 >= OBJ_CRUX1 ) + goto LABEL_29; + if ( !v3 ) + { + Obj_Light(v1, 10); + goto LABEL_40; + } + if ( v3 <= 0 ) + goto LABEL_40; + if ( v3 <= OBJ_L1RDOOR ) + goto LABEL_32; + if ( v3 != OBJ_SKFIRE && v3 != OBJ_CANDLE2 ) + goto LABEL_40; + goto LABEL_28; + } +LABEL_45: + v6 = 0; + while ( v6 < nobjects ) + { + if ( object[objectactive[v6]]._oDelFlag ) + { + DeleteObject(objectactive[v6], v6); + v6 = 0; + } + else + { + ++v6; + } + } +} + +void __fastcall ObjSetMicro(int dx, int dy, int pn) +{ + int v3; // esi + char *v4; // eax + char *v5; // edx + signed int v6; // ecx + char *v7; // esi + signed int v8; // ecx + + dPiece[0][dy + 112 * dx] = pn; + v3 = pn - 1; + v4 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(dx, dy); + if ( leveltype == DTYPE_HELL ) + { + v7 = (char *)pLevelPieces + 32 * v3; + v8 = 0; + do + { + *(_WORD *)&v4[2 * v8] = *(_WORD *)&v7[2 * ((v8 & 1) - (v8 & 0xE)) + 28]; + ++v8; + } + while ( v8 < 16 ); + } + else + { + v5 = (char *)pLevelPieces + 20 * v3; + v6 = 0; + do + { + *(_WORD *)&v4[2 * v6] = *(_WORD *)&v5[2 * ((v6 & 1) - (v6 & 0xE)) + 16]; + ++v6; + } + while ( v6 < 10 ); + } +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall objects_set_door_piece(int x, int y) +{ + int v2; // edi + int v3; // ST10_4 + int v4; // ST18_4 + short v5; // ST14_2 + short v6; // ST0C_2 + + v2 = y; + v3 = x; + v4 = dPiece[0][y + 112 * x] - 1; + v5 = *((_WORD *)pLevelPieces + 10 * (unsigned short)v4 + 8); + v6 = *((_WORD *)pLevelPieces + 10 * (unsigned short)v4 + 9); + dpiece_defs_map_1[0][0][16 * gendung_get_dpiece_num_from_coord(x, y)] = v5; + dpiece_defs_map_1[0][0][16 * gendung_get_dpiece_num_from_coord(v3, v2) + 1] = v6; +} + +void __fastcall ObjSetMini(int x, int y, int v) +{ + unsigned short *v3; // esi + unsigned short v4; // ax + int v5; // eax + int pn; // ST1C_4 + int v7; // ST18_4 + int v8; // ST14_4 + int v9; // ST10_4 + int v10; // esi + int v11; // edi + + v3 = (unsigned short *)((char *)pMegaTiles + 8 * ((unsigned short)v - 1)); + v4 = *v3; + ++v3; + v5 = v4 + 1; + pn = v5; + _LOWORD(v5) = *v3; + ++v3; + v7 = ++v5; + _LOWORD(v5) = *v3; + v8 = ++v5; + _LOWORD(v5) = v3[1]; + v9 = v5 + 1; + v10 = 2 * x + 16; + v11 = 2 * y + 16; + ObjSetMicro(v10, v11, pn); + ObjSetMicro(v10 + 1, v11++, v7); + ObjSetMicro(v10, v11, v8); + ObjSetMicro(v10 + 1, v11, v9); +} + +void __fastcall ObjL1Special(int x1, int y1, int x2, int y2) +{ + int i; // ebx + int v5; // edx + _BYTE *v6; // eax + int *v7; // edi + int v8; // edx + int v9; // esi + + for ( i = y1; i <= y2; ++i ) + { + if ( x1 <= x2 ) + { + v5 = 112 * x1 + i; + v6 = (unsigned char *)dArch + v5; + v7 = (int *)((char *)dPiece + 4 * v5); + v8 = x2 - x1 + 1; + do + { + v9 = *v7; + *v6 = 0; + if ( v9 == 12 ) + *v6 = 1; + if ( v9 == 11 ) + *v6 = 2; + if ( v9 == 71 ) + *v6 = 1; + if ( v9 == 259 ) + *v6 = 5; + if ( v9 == 249 ) + *v6 = 2; + if ( v9 == 325 ) + *v6 = 2; + if ( v9 == 321 ) + *v6 = 1; + if ( v9 == 255 ) + *v6 = 4; + if ( v9 == 211 ) + *v6 = 1; + if ( v9 == 344 ) + *v6 = 2; + if ( v9 == 341 ) + *v6 = 1; + if ( v9 == 331 ) + *v6 = 2; + if ( v9 == 418 ) + *v6 = 1; + if ( v9 == 421 ) + *v6 = 2; + v7 += 112; + v6 += 112; + --v8; + } + while ( v8 ); + } + } +} + +void __fastcall ObjL2Special(int x1, int y1, int x2, int y2) +{ + int v4; // edi + int v5; // esi + _BYTE *v6; // eax + int *v7; // ebx + int v8; // esi + int v9; // edx + int i; // edi + int v11; // eax + char *v12; // edx + int *v13; // esi + int v14; // eax + int v15; // ebx + int v16; // [esp+Ch] [ebp-4h] + + v4 = y1; + v16 = y1; + if ( y1 <= y2 ) + { + do + { + if ( x1 <= x2 ) + { + v5 = 112 * x1 + v4; + v6 = (unsigned char *)dArch + v5; + v7 = (int *)((char *)dPiece + 4 * v5); + v8 = x2 - x1 + 1; + do + { + v9 = *v7; + *v6 = 0; + if ( v9 == 541 ) + *v6 = 5; + if ( v9 == 178 ) + *v6 = 5; + if ( v9 == 551 ) + *v6 = 5; + if ( v9 == 542 ) + *v6 = 6; + if ( v9 == 553 ) + *v6 = 6; + if ( v9 == 13 ) + *v6 = 5; + if ( v9 == 17 ) + *v6 = 6; + v7 += 112; + v6 += 112; + --v8; + } + while ( v8 ); + } + ++v4; + } + while ( v4 <= y2 ); + for ( i = v16; i <= y2; ++i ) + { + if ( x1 <= x2 ) + { + v11 = i + 112 * x1; + v12 = &dArch[0][v11 + 2]; + v13 = (int *)((char *)dPiece + 4 * v11); + v14 = x2 - x1 + 1; + do + { + v15 = *v13; + if ( *v13 == 132 ) + { + *(v12 - 1) = 2; + *v12 = 1; + } + if ( v15 == 135 || v15 == 139 ) + { + v12[110] = 3; + v12[222] = 4; + } + v13 += 112; + v12 += 112; + --v14; + } + while ( v14 ); + } + } + } +} + +void __fastcall DoorSet(int oi, int dx, int dy) +{ + int v3; // esi + int v4; // ebp + int v5; // ebx + ObjectStruct *v6; // ebp + + v3 = dx; + v4 = oi; + v5 = dPiece[0][dy + 112 * dx]; + if ( v5 == 43 ) + ObjSetMicro(dx, dy, 392); + if ( v5 == 45 ) + ObjSetMicro(v3, dy, 394); + if ( v5 != 50 ) + goto LABEL_10; + v6 = &object[v4]; + if ( v6->_otype == OBJ_L1LDOOR ) + ObjSetMicro(v3, dy, 411); + if ( v6->_otype == OBJ_L1RDOOR ) + { + ObjSetMicro(v3, dy, 412); +LABEL_10: + if ( v5 == 54 ) + ObjSetMicro(v3, dy, 397); + if ( v5 == 55 ) + ObjSetMicro(v3, dy, 398); + if ( v5 == 61 ) + ObjSetMicro(v3, dy, 399); + if ( v5 == 67 ) + ObjSetMicro(v3, dy, 400); + if ( v5 == 68 ) + ObjSetMicro(v3, dy, 401); + if ( v5 == 69 ) + ObjSetMicro(v3, dy, 403); + if ( v5 == 70 ) + ObjSetMicro(v3, dy, 404); + if ( v5 == 72 ) + ObjSetMicro(v3, dy, 406); + if ( v5 == 212 ) + ObjSetMicro(v3, dy, 407); + if ( v5 == 354 ) + ObjSetMicro(v3, dy, 409); + if ( v5 == 355 ) + ObjSetMicro(v3, dy, 410); + if ( v5 == 411 ) + ObjSetMicro(v3, dy, 396); + if ( v5 == 412 ) + ObjSetMicro(v3, dy, 396); + } +} + +void __cdecl RedoPlayerVision() +{ + int *v0; // esi + + v0 = &plr[0].plrlevel; + do + { + if ( *((_BYTE *)v0 - 23) ) + { + if ( currlevel == *v0 ) + ChangeVisionXY(v0[27], v0[1], v0[2]); + } + v0 += 5430; + } + while ( (signed int)v0 < (signed int)&plr[4].plrlevel ); +} + +void __fastcall OperateL1RDoor(int pnum, int oi, unsigned char sendflag) +{ + int v3; // esi + int v4; // eax + int v5; // ebx + int v6; // edi + int v7; // ST04_4 + int v8; // [esp+Ch] [ebp-Ch] + int v9; // [esp+10h] [ebp-8h] + int param1; // [esp+14h] [ebp-4h] + + v3 = oi; + param1 = oi; + v9 = pnum; + v4 = object[oi]._oVar4; + if ( v4 != 2 ) + { + v5 = object[v3]._ox; + v6 = object[v3]._oy; + if ( v4 ) + { + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, v5, object[v3]._oy); + v8 = v6 + 112 * v5; + if ( dDead[0][v8] != 0 || dMonster[0][v8] != 0 || dItem[0][v8] != 0 ) + { + object[v3]._oVar4 = 2; + return; + } + if ( v9 == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_CLOSEDOOR, param1); + v7 = object[v3]._oVar1; + object[v3]._oVar4 = 0; + object[v3]._oSelFlag = 3; + ObjSetMicro(v5, v6, v7); + if ( object[v3]._oVar2 == 50 ) + { + if ( dPiece[-1][v8] == 396 ) /* check *(_DWORD *)&dflags[28][4 * v8 + 32] == 396 ) */ + ObjSetMicro(v5 - 1, v6, 411); + else + ObjSetMicro(v5 - 1, v6, 50); + } + else + { + ObjSetMicro(v5 - 1, v6, object[v3]._oVar2); + } + object[v3]._oAnimFrame -= 2; + object[v3]._oPreFlag = 0; + } + else + { + if ( pnum == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_OPENDOOR, oi); + if ( !deltaload ) + PlaySfxLoc(IS_DOOROPEN, object[v3]._ox, object[v3]._oy); + ObjSetMicro(v5, v6, 395); + dArch[v5][v6] = 8; + objects_set_door_piece(v5, v6 - 1); + object[v3]._oAnimFrame += 2; + object[v3]._oPreFlag = 1; + DoorSet(param1, v5 - 1, v6); + object[v3]._oVar4 = 1; + object[v3]._oSelFlag = 2; + } + RedoPlayerVision(); + return; + } + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, object[v3]._ox, object[v3]._oy); +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateL1LDoor(int pnum, int oi, unsigned char sendflag) +{ + int v3; // esi + int v4; // eax + int v5; // ebx + int v6; // edi + int v7; // ST04_4 + int v8; // [esp+Ch] [ebp-Ch] + int v9; // [esp+10h] [ebp-8h] + int param1; // [esp+14h] [ebp-4h] + + v3 = oi; + param1 = oi; + v9 = pnum; + v4 = object[oi]._oVar4; + if ( v4 != 2 ) + { + v5 = object[v3]._ox; + v6 = object[v3]._oy; + if ( v4 ) + { + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, v5, object[v3]._oy); + v8 = v6 + 112 * v5; + if ( dDead[v5][v6] != 0 || dMonster[0][v8] != 0 || dItem[v5][v6] != 0 ) + { + object[v3]._oVar4 = 2; + return; + } + if ( v9 == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_CLOSEDOOR, param1); + v7 = object[v3]._oVar1; + object[v3]._oVar4 = 0; + object[v3]._oSelFlag = 3; + ObjSetMicro(v5, v6, v7); + if ( object[v3]._oVar2 == 50 ) + { + if ( dPiece[0][v8-1] == 396 ) /* check *(_DWORD *)&dflags[39][v8 * 4 + 36] == 396 ) */ + ObjSetMicro(v5, v6 - 1, 412); + else + ObjSetMicro(v5, v6 - 1, 50); + } + else + { + ObjSetMicro(v5, v6 - 1, object[v3]._oVar2); + } + object[v3]._oAnimFrame -= 2; + object[v3]._oPreFlag = 0; + } + else + { + if ( pnum == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_OPENDOOR, oi); + if ( !deltaload ) + PlaySfxLoc(IS_DOOROPEN, object[v3]._ox, object[v3]._oy); + if ( object[v3]._oVar1 == 214 ) + ObjSetMicro(v5, v6, 408); + else + ObjSetMicro(v5, v6, 393); + dArch[v5][v6] = 7; + objects_set_door_piece(v5 - 1, v6); + object[v3]._oAnimFrame += 2; + object[v3]._oPreFlag = 1; + DoorSet(param1, v5, v6 - 1); + object[v3]._oVar4 = 1; + object[v3]._oSelFlag = 2; + } + RedoPlayerVision(); + return; + } + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, object[v3]._ox, object[v3]._oy); +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateL2RDoor(int pnum, int oi, unsigned char sendflag) +{ + int v3; // esi + int v4; // eax + int v5; // ebx + short param1; // [esp+Ch] [ebp-Ch] + int v7; // [esp+10h] [ebp-8h] + int v8; // [esp+14h] [ebp-4h] + + v3 = oi; + param1 = oi; + v7 = pnum; + v4 = object[oi]._oVar4; + if ( v4 != 2 ) + { + v5 = object[v3]._oy; + v8 = object[v3]._ox; + if ( v4 ) + { + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, object[v3]._ox, v5); + if ( dDead[v8][v5] != 0 || dMonster[0][v5 + 112 * v8] != 0 || dItem[v8][v5] != 0 ) + { + object[v3]._oVar4 = 2; + return; + } + if ( v7 == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_CLOSEDOOR, param1); + object[v3]._oVar4 = 0; + object[v3]._oSelFlag = 3; + ObjSetMicro(v8, v5, 540); + object[v3]._oAnimFrame -= 2; + object[v3]._oPreFlag = 0; + } + else + { + if ( pnum == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_OPENDOOR, oi); + if ( !deltaload ) + PlaySfxLoc(IS_DOOROPEN, object[v3]._ox, object[v3]._oy); + ObjSetMicro(v8, v5, 17); + object[v3]._oAnimFrame += 2; + object[v3]._oPreFlag = 1; + object[v3]._oVar4 = 1; + object[v3]._oSelFlag = 2; + } + RedoPlayerVision(); + return; + } + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, object[v3]._ox, object[v3]._oy); +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateL2LDoor(int pnum, int oi, unsigned char sendflag) +{ + int v3; // esi + int v4; // eax + int v5; // ebx + short param1; // [esp+Ch] [ebp-Ch] + int v7; // [esp+10h] [ebp-8h] + int v8; // [esp+14h] [ebp-4h] + + v3 = oi; + param1 = oi; + v7 = pnum; + v4 = object[oi]._oVar4; + if ( v4 != 2 ) + { + v5 = object[v3]._oy; + v8 = object[v3]._ox; + if ( v4 ) + { + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, object[v3]._ox, v5); + if ( dDead[v8][v5] != 0 || dMonster[0][v5 + 112 * v8] != 0 || dItem[v8][v5] != 0 ) + { + object[v3]._oVar4 = 2; + return; + } + if ( v7 == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_CLOSEDOOR, param1); + object[v3]._oVar4 = 0; + object[v3]._oSelFlag = 3; + ObjSetMicro(v8, v5, 538); + object[v3]._oAnimFrame -= 2; + object[v3]._oPreFlag = 0; + } + else + { + if ( pnum == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_OPENDOOR, oi); + if ( !deltaload ) + PlaySfxLoc(IS_DOOROPEN, object[v3]._ox, object[v3]._oy); + ObjSetMicro(v8, v5, 13); + object[v3]._oAnimFrame += 2; + object[v3]._oPreFlag = 1; + object[v3]._oVar4 = 1; + object[v3]._oSelFlag = 2; + } + RedoPlayerVision(); + return; + } + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, object[v3]._ox, object[v3]._oy); +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateL3RDoor(int pnum, int oi, unsigned char sendflag) +{ + int v3; // esi + int v4; // eax + int v5; // ebx + short param1; // [esp+Ch] [ebp-Ch] + int v7; // [esp+10h] [ebp-8h] + int v8; // [esp+14h] [ebp-4h] + + v3 = oi; + param1 = oi; + v7 = pnum; + v4 = object[oi]._oVar4; + if ( v4 != 2 ) + { + v5 = object[v3]._oy; + v8 = object[v3]._ox; + if ( v4 ) + { + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, object[v3]._ox, v5); + if ( dDead[v8][v5] != 0 || dMonster[0][v5 + 112 * v8] != 0 || dItem[v8][v5] != 0 ) + { + object[v3]._oVar4 = 2; + return; + } + if ( v7 == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_CLOSEDOOR, param1); + object[v3]._oVar4 = 0; + object[v3]._oSelFlag = 3; + ObjSetMicro(v8, v5, 534); + object[v3]._oAnimFrame -= 2; + object[v3]._oPreFlag = 0; + } + else + { + if ( pnum == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_OPENDOOR, oi); + if ( !deltaload ) + PlaySfxLoc(IS_DOOROPEN, object[v3]._ox, object[v3]._oy); + ObjSetMicro(v8, v5, 541); + object[v3]._oAnimFrame += 2; + object[v3]._oPreFlag = 1; + object[v3]._oVar4 = 1; + object[v3]._oSelFlag = 2; + } + RedoPlayerVision(); + return; + } + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, object[v3]._ox, object[v3]._oy); +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateL3LDoor(int pnum, int oi, unsigned char sendflag) +{ + int v3; // esi + int v4; // eax + int v5; // ebx + short param1; // [esp+Ch] [ebp-Ch] + int v7; // [esp+10h] [ebp-8h] + int v8; // [esp+14h] [ebp-4h] + + v3 = oi; + param1 = oi; + v7 = pnum; + v4 = object[oi]._oVar4; + if ( v4 != 2 ) + { + v5 = object[v3]._oy; + v8 = object[v3]._ox; + if ( v4 ) + { + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, object[v3]._ox, v5); + if ( dDead[v8][v5] != 0 || dMonster[0][v5 + 112 * v8] != 0 || dItem[v8][v5] != 0 ) + { + object[v3]._oVar4 = 2; + return; + } + if ( v7 == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_CLOSEDOOR, param1); + object[v3]._oVar4 = 0; + object[v3]._oSelFlag = 3; + ObjSetMicro(v8, v5, 531); + object[v3]._oAnimFrame -= 2; + object[v3]._oPreFlag = 0; + } + else + { + if ( pnum == myplr && sendflag ) + NetSendCmdParam1(1u, CMD_OPENDOOR, oi); + if ( !deltaload ) + PlaySfxLoc(IS_DOOROPEN, object[v3]._ox, object[v3]._oy); + ObjSetMicro(v8, v5, 538); + object[v3]._oAnimFrame += 2; + object[v3]._oPreFlag = 1; + object[v3]._oVar4 = 1; + object[v3]._oSelFlag = 2; + } + RedoPlayerVision(); + return; + } + if ( !deltaload ) + PlaySfxLoc(IS_DOORCLOS, object[v3]._ox, object[v3]._oy); +} +// 676190: using guessed type int deltaload; + +void __fastcall MonstCheckDoors(int m) +{ + int v1; // ecx + int v2; // eax + int v3; // ecx + int v4; // eax + char *v5; // ecx + int v6; // eax + int v7; // esi + int v8; // esi + int v9; // eax + int v10; // ebx + int v11; // eax + bool v12; // zf + bool v13; // sf + unsigned char v14; // of + int v15; // eax + int v16; // ebx + int v17; // eax + bool v18; // zf + bool v19; // sf + unsigned char v20; // of + int v21; // eax + int v22; // ebx + int v23; // eax + bool v24; // zf + bool v25; // sf + unsigned char v26; // of + int v27; // [esp+0h] [ebp-14h] + int v28; // [esp+4h] [ebp-10h] + int v29; // [esp+8h] [ebp-Ch] + int v30; // [esp+Ch] [ebp-8h] + int v31; // [esp+Ch] [ebp-8h] + int v32; // [esp+Ch] [ebp-8h] + int oi; // [esp+10h] [ebp-4h] + + v1 = m; + v2 = monster[v1]._mx; + v3 = monster[v1]._my; + v29 = v2; + v4 = v3 + 112 * v2; + v28 = v3; + v5 = (char *)dObject + v4; + if ( dObject[-1][v4 - 1] + || *(v5 - 1) + || dObject[0][v4 + 111] + || *(v5 - 112) + || dObject[1][v4] + || dObject[-1][v4 + 1] + || dObject[0][v4 + 1] + || dObject[1][v4 + 1] ) + { + v6 = 0; + v27 = 0; + if ( nobjects > 0 ) + { + while ( 1 ) + { + v7 = objectactive[v6]; + oi = v7; + v8 = v7; + v9 = object[v8]._otype; + if ( v9 != 1 && v9 != OBJ_L1RDOOR || object[v8]._oVar4 ) + goto LABEL_21; + v10 = abs(object[v8]._ox - v29); + v11 = abs(object[v8]._oy - v28); + v14 = __OFSUB__(v10, 1); + v12 = v10 == 1; + v13 = v10 - 1 < 0; + v30 = v11; + if ( v10 != 1 ) + goto LABEL_17; + if ( v11 <= 1 && object[v8]._otype == 1 ) + break; +LABEL_18: + if ( v30 == 1 && object[v8]._otype == OBJ_L1RDOOR ) + OperateL1RDoor(myplr, oi, 1u); +LABEL_21: + v15 = object[v8]._otype; + if ( v15 != OBJ_L2LDOOR && v15 != OBJ_L2RDOOR || object[v8]._oVar4 ) + goto LABEL_32; + v16 = abs(object[v8]._ox - v29); + v17 = abs(object[v8]._oy - v28); + v20 = __OFSUB__(v16, 1); + v18 = v16 == 1; + v19 = v16 - 1 < 0; + v31 = v17; + if ( v16 != 1 ) + goto LABEL_28; + if ( v17 <= 1 && object[v8]._otype == OBJ_L2LDOOR ) + { + OperateL2LDoor(myplr, oi, 1u); + v20 = 0; + v18 = 1; + v19 = 0; +LABEL_28: + if ( !((unsigned char)(v19 ^ v20) | v18) ) + goto LABEL_32; + } + if ( v31 == 1 && object[v8]._otype == OBJ_L2RDOOR ) + OperateL2RDoor(myplr, oi, 1u); +LABEL_32: + v21 = object[v8]._otype; + if ( v21 != OBJ_L3LDOOR && v21 != OBJ_L3RDOOR || object[v8]._oVar4 ) + goto LABEL_43; + v22 = abs(object[v8]._ox - v29); + v23 = abs(object[v8]._oy - v28); + v26 = __OFSUB__(v22, 1); + v24 = v22 == 1; + v25 = v22 - 1 < 0; + v32 = v23; + if ( v22 == 1 ) + { + if ( v23 > 1 || object[v8]._otype != OBJ_L3RDOOR ) + { +LABEL_40: + if ( v32 == 1 && object[v8]._otype == OBJ_L3LDOOR ) + OperateL3LDoor(myplr, oi, 1u); + goto LABEL_43; + } + OperateL3RDoor(myplr, oi, 1u); + v26 = 0; + v24 = 1; + v25 = 0; + } + if ( (unsigned char)(v25 ^ v26) | v24 ) + goto LABEL_40; +LABEL_43: + v6 = v27++ + 1; + if ( v27 >= nobjects ) + return; + } + OperateL1LDoor(myplr, oi, 1u); + v14 = 0; + v12 = 1; + v13 = 0; +LABEL_17: + if ( !((unsigned char)(v13 ^ v14) | v12) ) + goto LABEL_21; + goto LABEL_18; + } + } +} + +void __fastcall ObjChangeMap(int x1, int y1, int x2, int y2) +{ + int v4; // ebx + int v5; // edi + int v6; // esi + //int v7; // ecx + int v8; // edi + int v9; // ebx + //int v10; // ecx + int v11; // [esp+Ch] [ebp-8h] + int a2; // [esp+10h] [ebp-4h] + int i; // [esp+1Ch] [ebp+8h] + int y_end; // [esp+20h] [ebp+Ch] + + v4 = y1; + v5 = x2; + v6 = x1; + for ( a2 = y1; a2 <= y2; ++a2 ) + { + i = v6; + if ( v6 <= v5 ) + { + v11 = a2 + 40 * v6; + do + { + ObjSetMini(i++, a2, (unsigned char)pdungeon[0][v11]); + dungeon[0][v11] = pdungeon[0][v11]; + v11 += 40; + } + while ( i <= v5 ); + } + } + if ( leveltype == DTYPE_CATHEDRAL ) + { + ObjL1Special(2 * v6 + 16, 2 * v4 + 16, 2 * v5 + 17, 2 * y2 + 17); + AddL1Objs(2 * v6 + 16, 2 * v4 + 16, 2 * v5 + 17, 2 * y2 + 17); /* v7 */ + } + if ( leveltype == DTYPE_CATACOMBS ) + { + v8 = 2 * v5 + 17; + v9 = 2 * v4 + 16; + y_end = 2 * y2 + 17; + ObjL2Special(2 * v6 + 16, v9, v8, y_end); + AddL2Objs(2 * v6 + 16, v9, v8, y_end); /* v10 */ + } +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall ObjChangeMapResync(int x1, int y1, int x2, int y2) +{ + int v4; // edi + int v5; // esi + int v6; // ebx + int v7; // edi + int v8; // [esp+Ch] [ebp-Ch] + int i; // [esp+10h] [ebp-8h] + int a2; // [esp+14h] [ebp-4h] + + v4 = y2; + v5 = y1; + v6 = x1; + v8 = y1; + for ( a2 = y1; a2 <= v4; ++a2 ) + { + i = v6; + if ( v6 <= x2 ) + { + v7 = a2 + 40 * v6; + do + { + ObjSetMini(i++, a2, (unsigned char)pdungeon[0][v7]); + dungeon[0][v7] = pdungeon[0][v7]; + v7 += 40; + } + while ( i <= x2 ); + v4 = y2; + v5 = v8; + } + } + if ( leveltype == DTYPE_CATHEDRAL ) + ObjL1Special(2 * v6 + 16, 2 * v5 + 16, 2 * x2 + 17, 2 * v4 + 17); + if ( leveltype == DTYPE_CATACOMBS ) + ObjL2Special(2 * v6 + 16, 2 * v5 + 16, 2 * x2 + 17, 2 * v4 + 17); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall OperateL1Door(int pnum, int i, unsigned char sendflag) +{ + int v3; // ebx + int v4; // edi + int v5; // esi + int v6; // ST1C_4 + int v7; // eax + bool v8; // zf + bool v9; // sf + unsigned char v10; // of + int v11; // [esp+Ch] [ebp-Ch] + int pnuma; // [esp+10h] [ebp-8h] + + v3 = i; + v4 = i; + pnuma = pnum; + v5 = pnum; + v6 = abs(object[i]._ox - plr[pnum].WorldX); + v7 = abs(object[v4]._oy - plr[v5].WorldY); + v10 = __OFSUB__(v6, 1); + v8 = v6 == 1; + v9 = v6 - 1 < 0; + v11 = v7; + if ( v6 != 1 ) + { +LABEL_5: + if ( !((unsigned char)(v9 ^ v10) | v8) ) + return; + goto LABEL_6; + } + if ( v7 <= 1 && object[v4]._otype == 1 ) + { + OperateL1LDoor(pnuma, v3, sendflag); + v10 = 0; + v8 = 1; + v9 = 0; + goto LABEL_5; + } +LABEL_6: + if ( v11 == 1 && object[v4]._otype == OBJ_L1RDOOR ) + OperateL1RDoor(pnuma, v3, sendflag); +} + +void __fastcall OperateLever(int pnum, int i) +{ + int v2; // esi + int *v3; // edi + signed int v4; // edi + int v5; // ecx + int v6; // eax + short param1; // [esp+8h] [ebp-8h] + int v8; // [esp+Ch] [ebp-4h] + + param1 = i; + v2 = i; + v3 = (int*)&object[i]._oSelFlag; + v8 = pnum; + if ( *(_BYTE *)v3 ) + { + if ( !deltaload ) + PlaySfxLoc(IS_LEVER, object[v2]._ox, object[v2]._oy); + *(_BYTE *)v3 = 0; + ++object[v2]._oAnimFrame; + v4 = 1; + if ( currlevel != 16 ) + goto LABEL_17; + v5 = 0; + if ( nobjects <= 0 ) + goto LABEL_17; + do + { + v6 = objectactive[v5]; + if ( object[v6]._otype == OBJ_SWITCHSKL + && object[v2]._oVar8 == object[v6]._oVar8 + && object[v6]._oSelFlag ) + { + v4 = 0; + } + ++v5; + } + while ( v5 < nobjects ); + if ( v4 ) +LABEL_17: + ObjChangeMap(object[v2]._oVar1, object[v2]._oVar2, object[v2]._oVar3, object[v2]._oVar4); + if ( v8 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, param1); + } +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateBook(int pnum, int i) +{ + int esi1; // esi + int v3; // edx + signed int v4; // ecx + int v5; // eax + bool v6; // zf + int v7; // ecx + int *v8; // eax + int j; // esi + int v10; // [esp+Ch] [ebp-14h] + signed int v11; // [esp+10h] [ebp-10h] + signed int v1; // [esp+14h] [ebp-Ch] + signed int v2; // [esp+18h] [ebp-8h] + int v14; // [esp+1Ch] [ebp-4h] + + esi1 = i; + v3 = pnum; + v10 = pnum; + if ( !object[esi1]._oSelFlag ) + return; + if ( !setlevel || setlvlnum != SL_VILEBETRAYER ) + goto LABEL_17; + v4 = 0; + v11 = 0; + v14 = 0; + if ( nobjects > 0 ) + { + while ( 1 ) + { + v5 = objectactive[v14]; + if ( object[v5]._otype == OBJ_MCIRCLE2 ) + { + if ( object[v5]._oVar6 == 1 ) + { + v1 = 27; + v2 = 29; + object[v5]._oVar6 = 4; + v4 = 1; + } + if ( object[v5]._oVar6 == 2 ) + { + v1 = 43; + v2 = 29; + object[v5]._oVar6 = 4; + v4 = 1; + } + } + if ( v4 ) + { + ++object[dObject[35][36]-1]._oVar5; // ++objectavail[30 * dObject[35][36] + 123]; /* fix */ + AddMissile(plr[v3].WorldX, plr[v3].WorldY, v1, v2, plr[v3]._pdir, MIS_RNDTELEPORT, 0, v3, 0, 0); + v11 = 1; + v4 = 0; + } + if ( ++v14 >= nobjects ) + break; + v3 = v10; + } + if ( v11 ) + { + v3 = v10; +LABEL_17: + ++object[esi1]._oAnimFrame; + v6 = setlevel == 0; + object[esi1]._oSelFlag = 0; + if ( !v6 ) + { + if ( setlvlnum == SL_BONECHAMB ) + { + v7 = 21720 * myplr; + v8 = plr[myplr]._pMemSpells; + *((_BYTE *)v8 + 1) |= 0x10u; + v8[1] = v8[1]; + if ( plr[v3]._pSplLvl[SPL_GUARDIAN] < 15 ) + ++plr[0]._pSplLvl[v7 + SPL_GUARDIAN]; + quests[14]._qactive = 3; + if ( !deltaload ) + PlaySfxLoc(IS_QUESTDN, object[esi1]._ox, object[esi1]._oy); + _LOBYTE(v7) = 43; + InitDiabloMsg(v7); + AddMissile( + plr[myplr].WorldX, + plr[myplr].WorldY, + object[esi1]._ox - 2, + object[esi1]._oy - 4, + plr[myplr]._pdir, + MIS_GUARDIAN, + 0, + myplr, + 0, + 0); + } + if ( setlevel ) + { + if ( setlvlnum == SL_VILEBETRAYER ) + { + ObjChangeMapResync( + object[esi1]._oVar1, + object[esi1]._oVar2, + object[esi1]._oVar3, + object[esi1]._oVar4); + for ( j = 0; j < nobjects; ++j ) + SyncObjectAnim(objectactive[j]); + } + } + } + return; + } + } +} +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; +// 676190: using guessed type int deltaload; + +void __fastcall OperateBookLever(int pnum, int i) +{ + int v2; // esi + int v3; // edi + int v4; // ebp + int v5; // edx + int v6; // eax + int v7; // ST0C_4 + int v8; // edx + char v9; // bl + int v10; // ST08_4 + int v11; // ecx + int v12; // ecx + int v13; // [esp+Ch] [ebp-8h] + short param1; // [esp+10h] [ebp-4h] + + param1 = i; + v2 = i; + v13 = pnum; + v3 = 2 * setpc_x + 16; + v4 = 2 * setpc_y + 16; + if ( object[i]._oSelFlag && !qtextflag ) + { + v5 = object[v2]._otype; + if ( v5 == OBJ_BLINDBOOK && !quests[8]._qvar1 ) + { + quests[8]._qactive = 2; + quests[8]._qlog = 1; + quests[8]._qvar1 = 1; + } + if ( v5 == OBJ_BLOODBOOK && !quests[9]._qvar1 ) + { + quests[9]._qactive = 2; + quests[9]._qlog = 1; + quests[9]._qvar1 = 1; + SpawnQuestItem(21, 2 * setpc_x + 19, 2 * setpc_y + 26, 0, 1); + SpawnQuestItem(21, 2 * setpc_x + 31, 2 * setpc_y + 26, 0, 1); + SpawnQuestItem(21, 2 * setpc_x + 25, 2 * setpc_y + 33, 0, 1); + } + v6 = object[v2]._otype; + if ( v6 == OBJ_STEELTOME && !quests[11]._qvar1 ) + { + quests[11]._qactive = 2; + quests[11]._qlog = 1; + quests[11]._qvar1 = 1; + } + if ( object[v2]._oAnimFrame != object[v2]._oVar6 ) + { + if ( v6 != OBJ_BLOODBOOK ) + ObjChangeMap(object[v2]._oVar1, object[v2]._oVar2, object[v2]._oVar3, object[v2]._oVar4); + if ( object[v2]._otype == OBJ_BLINDBOOK ) + { + CreateItem(3, v3 + 5, v4 + 5); + v7 = object[v2]._oVar4; + v8 = object[v2]._oVar2; + v9 = TransVal; + v10 = object[v2]._oVar3; + v11 = object[v2]._oVar1; + TransVal = 9; + DRLG_MRectTrans(v11, v8, v10, v7); + TransVal = v9; + } + } + v12 = object[v2]._oVar7; + object[v2]._oAnimFrame = object[v2]._oVar6; + InitQTextMsg(v12); + if ( v13 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, param1); + } +} +// 5A5590: using guessed type char TransVal; +// 646D00: using guessed type char qtextflag; + +void __fastcall OperateSChambBk(int pnum, int i) +{ + int v2; // esi + int j; // edi + char v4; // al + signed int v5; // ecx + //int speech_id; // [esp+4h] [ebp-4h] + + v2 = i; + if ( object[i]._oSelFlag && !qtextflag ) + { + if ( object[v2]._oAnimFrame != object[v2]._oVar6 ) + { + ObjChangeMapResync(object[v2]._oVar1, object[v2]._oVar2, object[v2]._oVar3, object[v2]._oVar4); + for ( j = 0; j < nobjects; ++j ) + SyncObjectAnim(objectactive[j]); + } + object[v2]._oAnimFrame = object[v2]._oVar6; + if ( quests[14]._qactive == 1 ) + { + quests[14]._qactive = 2; + quests[14]._qlog = 1; + } + v4 = plr[myplr]._pClass; + if ( v4 ) + { + if ( v4 == 1 ) + { + v5 = QUEST_RBONER; + } + else + { + v5 = QUEST_MBONER; + //if ( v4 != 2 ) + //v5 = speech_id; + } + } + else + { + v5 = QUEST_BONER; + } + quests[14]._qmsg = v5; + InitQTextMsg(v5); + } +} +// 646D00: using guessed type char qtextflag; + +void __fastcall OperateChest(int pnum, int i, unsigned char sendmsg) +{ + int v3; // esi + bool v4; // zf + int v5; // edi + int v6; // eax + int v7; // eax + int v8; // ecx + int v9; // ecx + int v10; // ecx + signed int v11; // [esp-8h] [ebp-18h] + short param2; // [esp+8h] [ebp-8h] + int param1; // [esp+Ch] [ebp-4h] + + param2 = i; + v3 = i; + param1 = pnum; + if ( object[i]._oSelFlag ) + { + if ( !deltaload ) + PlaySfxLoc(IS_CHEST, object[v3]._ox, object[v3]._oy); + object[v3]._oAnimFrame += 2; + v4 = deltaload == 0; + object[v3]._oSelFlag = 0; + if ( v4 ) + { + SetRndSeed(object[v3]._oRndSeed); + v5 = 0; + if ( setlevel ) + { + if ( object[v3]._oVar1 > 0 ) + { + do + { + CreateRndItem(object[v3]._ox, object[v3]._oy, 1u, sendmsg, 0); + ++v5; + } + while ( v5 < object[v3]._oVar1 ); + } + } + else if ( object[v3]._oVar1 > 0 ) + { + do + { + if ( object[v3]._oVar2 ) + CreateRndItem(object[v3]._ox, object[v3]._oy, 0, sendmsg, 0); + else + CreateRndUseful(param1, object[v3]._ox, object[v3]._oy, sendmsg); + ++v5; + } + while ( v5 < object[v3]._oVar1 ); + } + if ( !object[v3]._oTrapFlag ) + goto LABEL_26; + v6 = object[v3]._otype; + if ( v6 < OBJ_TCHEST1 || v6 > OBJ_TCHEST3 ) + goto LABEL_26; + v7 = GetDirection(object[v3]._ox, object[v3]._oy, plr[param1].WorldX, plr[param1].WorldY); + v8 = object[v3]._oVar4; + if ( v8 ) + { + v9 = v8 - 1; + if ( v9 ) + { + if ( v9 != 1 ) + { + v10 = sendmsg; + goto LABEL_25; + } + v11 = 42; + } + else + { + v11 = 27; + } + v10 = v11; + } + else + { + v10 = 0; + } +LABEL_25: + AddMissile(object[v3]._ox, object[v3]._oy, plr[param1].WorldX, plr[param1].WorldY, v7, v10, 1, -1, 0, 0); + object[v3]._oTrapFlag = 0; +LABEL_26: + if ( param1 == myplr ) + NetSendCmdParam2(0, CMD_PLROPOBJ, param1, param2); + return; + } + } +} +// 5CF31D: using guessed type char setlevel; +// 676190: using guessed type int deltaload; + +void __fastcall OperateMushPatch(int pnum, int i) +{ + int v2; // esi + bool v3; // zf + char v4; // al + int v5; // ecx + int xx; // [esp+8h] [ebp-8h] + int yy; // [esp+Ch] [ebp-4h] + + if ( quests[1]._qactive != 2 || quests[1]._qvar1 < 2u ) + { + if ( !deltaload && pnum == myplr ) + { + v4 = plr[myplr]._pClass; + if ( v4 ) + { + if ( v4 == 1 ) + { + v5 = PS_ROGUE13; + } + else + { + if ( v4 != 2 ) + return; + v5 = PS_MAGE13; + } + } + else + { + v5 = PS_WARR13; + } + PlaySFX(v5); + } + } + else + { + v2 = i; + if ( object[i]._oSelFlag ) + { + if ( !deltaload ) + PlaySfxLoc(IS_CHEST, object[v2]._ox, object[v2]._oy); + ++object[v2]._oAnimFrame; + v3 = deltaload == 0; + object[v2]._oSelFlag = 0; + if ( v3 ) + { + GetSuperItemLoc(object[v2]._ox, object[v2]._oy, &xx, &yy); + SpawnQuestItem(17, xx, yy, 0, 0); + quests[1]._qvar1 = 3; + } + } + } +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateInnSignChest(int pnum, int i) +{ + char v2; // al + int v3; // ecx + int v4; // esi + bool v5; // zf + int xx; // [esp+8h] [ebp-8h] + int yy; // [esp+Ch] [ebp-4h] + + if ( quests[7]._qvar1 == 2 ) + { + v4 = i; + if ( object[i]._oSelFlag ) + { + if ( !deltaload ) + PlaySfxLoc(IS_CHEST, object[v4]._ox, object[v4]._oy); + object[v4]._oAnimFrame += 2; + v5 = deltaload == 0; + object[v4]._oSelFlag = 0; + if ( v5 ) + { + GetSuperItemLoc(object[v4]._ox, object[v4]._oy, &xx, &yy); + SpawnQuestItem(IDI_BANNER, xx, yy, 0, 0); + } + } + } + else if ( !deltaload && pnum == myplr ) + { + v2 = plr[myplr]._pClass; + switch ( v2 ) + { + case UI_WARRIOR: + v3 = PS_WARR24; +LABEL_8: + PlaySFX(v3); + return; + case UI_ROGUE: + v3 = PS_ROGUE24; + goto LABEL_8; + case UI_SORCERER: + v3 = PS_MAGE24; + goto LABEL_8; + } + } +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateSlainHero(int pnum, int i, unsigned char sendmsg) +{ + unsigned short v3; // di + int v4; // esi + int v5; // eax + bool v6; // zf + char v7; // cl + int v8; // ecx + + v3 = i; + v4 = pnum; + v5 = i; + if ( object[i]._oSelFlag ) + { + v6 = deltaload == 0; + object[v5]._oSelFlag = 0; + if ( v6 ) + { + v7 = plr[pnum]._pClass; + if ( v7 ) + { + if ( v7 == 1 ) + { + CreateMagicItem(object[v5]._ox, object[v5]._oy, 3, 119, 0, 1); + v8 = PS_ROGUE9; + } + else + { + if ( v7 != 2 ) + goto LABEL_10; + CreateSpellBook(object[v5]._ox, object[v5]._oy, 3, 0, 1); + v8 = PS_MAGE9; + } + } + else + { + CreateMagicItem(object[v5]._ox, object[v5]._oy, 9, 153, 0, 1); + v8 = PS_WARR9; + } + PlaySfxLoc(v8, plr[myplr].WorldX, plr[myplr].WorldY); +LABEL_10: + if ( v4 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, v3); + return; + } + } +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateTrapLvr(int i) +{ + int v1; // ecx + int v2; // eax + int v3; // esi + int v4; // edx + int v5; // eax + int v6; // eax + + v1 = i; + v2 = object[v1]._oAnimFrame; + v3 = nobjects; + v4 = 0; + if ( v2 == 1 ) + { + object[v1]._oAnimFrame = 2; + if ( v3 > 0 ) + { + do + { + v5 = objectactive[v4]; + if ( object[v5]._otype == object[v1]._oVar2 && object[v5]._oVar1 == object[v1]._oVar1 ) + { + object[v5]._oAnimFlag = 0; + object[v5]._oVar2 = 1; + } + ++v4; + } + while ( v4 < v3 ); + } + } + else + { + object[v1]._oAnimFrame = v2 - 1; + if ( v3 > 0 ) + { + do + { + v6 = objectactive[v4]; + if ( object[v6]._otype == object[v1]._oVar2 && object[v6]._oVar1 == object[v1]._oVar1 ) + { + object[v6]._oVar2 = 0; + if ( object[v6]._oVar4 ) + object[v6]._oAnimFlag = 1; + } + ++v4; + } + while ( v4 < v3 ); + } + } +} + +void __fastcall OperateSarc(int pnum, int i, unsigned char sendmsg) +{ + unsigned short v3; // bp + int v4; // esi + bool v5; // zf + int v6; // ecx + int v7; // [esp+Ch] [ebp-4h] + + v3 = i; + v4 = i; + v7 = pnum; + if ( object[i]._oSelFlag ) + { + if ( !deltaload ) + PlaySfxLoc(IS_SARC, object[v4]._ox, object[v4]._oy); + v5 = deltaload == 0; + object[v4]._oSelFlag = 0; + if ( v5 ) + { + v6 = object[v4]._oRndSeed; + object[v4]._oAnimFlag = 1; + object[v4]._oAnimDelay = 3; + SetRndSeed(v6); + if ( object[v4]._oVar1 <= 2 ) + CreateRndItem(object[v4]._ox, object[v4]._oy, 0, sendmsg, 0); + if ( object[v4]._oVar1 >= 8 ) + SpawnSkeleton(object[v4]._oVar2, object[v4]._ox, object[v4]._oy); + if ( v7 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, v3); + } + else + { + object[v4]._oAnimFrame = object[v4]._oAnimLen; + } + } +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateL2Door(int pnum, int i, unsigned char sendflag) +{ + int v3; // ebx + int v4; // edi + int v5; // esi + int v6; // ST1C_4 + int v7; // eax + bool v8; // zf + bool v9; // sf + unsigned char v10; // of + int v11; // [esp+Ch] [ebp-Ch] + int pnuma; // [esp+10h] [ebp-8h] + + v3 = i; + v4 = i; + pnuma = pnum; + v5 = pnum; + v6 = abs(object[i]._ox - plr[pnum].WorldX); + v7 = abs(object[v4]._oy - plr[v5].WorldY); + v10 = __OFSUB__(v6, 1); + v8 = v6 == 1; + v9 = v6 - 1 < 0; + v11 = v7; + if ( v6 != 1 ) + { +LABEL_5: + if ( !((unsigned char)(v9 ^ v10) | v8) ) + return; + goto LABEL_6; + } + if ( v7 <= 1 && object[v4]._otype == OBJ_L2LDOOR ) + { + OperateL2LDoor(pnuma, v3, sendflag); + v10 = 0; + v8 = 1; + v9 = 0; + goto LABEL_5; + } +LABEL_6: + if ( v11 == 1 && object[v4]._otype == OBJ_L2RDOOR ) + OperateL2RDoor(pnuma, v3, sendflag); +} + +void __fastcall OperateL3Door(int pnum, int i, unsigned char sendflag) +{ + int v3; // ebx + int v4; // edi + int v5; // esi + int v6; // ST1C_4 + int v7; // eax + bool v8; // zf + bool v9; // sf + unsigned char v10; // of + int v11; // [esp+Ch] [ebp-Ch] + int pnuma; // [esp+10h] [ebp-8h] + + v3 = i; + v4 = i; + pnuma = pnum; + v5 = pnum; + v6 = abs(object[i]._ox - plr[pnum].WorldX); + v7 = abs(object[v4]._oy - plr[v5].WorldY); + v10 = __OFSUB__(v6, 1); + v8 = v6 == 1; + v9 = v6 - 1 < 0; + v11 = v7; + if ( v6 != 1 ) + { +LABEL_5: + if ( !((unsigned char)(v9 ^ v10) | v8) ) + return; + goto LABEL_6; + } + if ( v7 <= 1 && object[v4]._otype == OBJ_L3RDOOR ) + { + OperateL3RDoor(pnuma, v3, sendflag); + v10 = 0; + v8 = 1; + v9 = 0; + goto LABEL_5; + } +LABEL_6: + if ( v11 == 1 && object[v4]._otype == OBJ_L3LDOOR ) + OperateL3LDoor(pnuma, v3, sendflag); +} + +void __fastcall OperatePedistal(int pnum, int i) +{ + int v2; // esi + int v3; // edi + unsigned char *v4; // edi + int inv_item_num; // [esp+8h] [ebp-4h] + + v2 = i; + v3 = pnum; + if ( object[i]._oVar6 != 3 ) + { + if ( PlrHasItem(pnum, 21, &inv_item_num) ) + { + RemoveInvItem(v3, inv_item_num); + ++object[v2]._oAnimFrame; + ++object[v2]._oVar6; + } + if ( object[v2]._oVar6 == 1 ) + { + if ( !deltaload ) + PlaySfxLoc(LS_PUDDLE, object[v2]._ox, object[v2]._oy); + ObjChangeMap(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7); + } + if ( object[v2]._oVar6 == 2 ) + { + if ( !deltaload ) + PlaySfxLoc(LS_PUDDLE, object[v2]._ox, object[v2]._oy); + ObjChangeMap(setpc_x + 6, setpc_y + 3, setpc_x + setpc_w, setpc_y + 7); + } + if ( object[v2]._oVar6 == 3 ) + { + if ( !deltaload ) + PlaySfxLoc(LS_BLODSTAR, object[v2]._ox, object[v2]._oy); + ObjChangeMap(object[v2]._oVar1, object[v2]._oVar2, object[v2]._oVar3, object[v2]._oVar4); + v4 = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", 0); + LoadMapObjs(v4, 2 * setpc_x, 2 * setpc_y); + mem_free_dbg(v4); + CreateItem(7, 2 * setpc_x + 25, 2 * setpc_y + 19); + object[v2]._oSelFlag = 0; + } + } +} +// 5CF334: using guessed type int setpc_w; +// 676190: using guessed type int deltaload; + +void __fastcall TryDisarm(int pnum, int i) +{ + int v2; // edi + int v3; // esi + int v4; // esi + int v5; // edi + int v6; // ebx + int j; // edx + signed int v8; // edi + int v9; // eax + int v10; // ecx + int v11; // eax + int v12; // [esp+Ch] [ebp-4h] + + v2 = pnum; + v3 = i; + v12 = i; + if ( pnum == myplr ) + SetCursor(CURSOR_HAND); + v4 = v3; + if ( object[v4]._oTrapFlag ) + { + v5 = 2 * plr[v2]._pDexterity - 5 * currlevel; + if ( random(154, 100) <= v5 ) + { + v6 = nobjects; + for ( j = 0; j < v6; ++j ) + { + v8 = 0; + v9 = objectactive[j]; + v10 = object[v9]._otype; + if ( v10 == OBJ_TRAPL ) + v8 = 1; + if ( v10 == OBJ_TRAPR ) + v8 = 1; + if ( v8 && dObject[object[v9]._oVar1][object[v9]._oVar2] - 1 == v12 ) + { + object[v9]._oVar4 = 1; + object[v4]._oTrapFlag = 0; + } + } + v11 = object[v4]._otype; + if ( v11 >= OBJ_TCHEST1 && v11 <= OBJ_TCHEST3 ) + object[v4]._oTrapFlag = 0; + } + } +} + +int __fastcall ItemMiscIdIdx(int imiscid) +{ + int result; // eax + int *i; // edx + + result = 0; + for ( i = &AllItemsList[0].iMiscId; !*(i - 14) || *i != imiscid; i += 19 ) + ++result; + return result; +} + +void __fastcall OperateShrine(int pnum, int i, int sType) +{ + int v3; // esi + int *v4; // ebx + int v5; // eax + int v6; // ecx + int v7; // ecx + int v9; // eax + int v10; // eax + int v11; // eax + int v12; // edx + int v13; // esi + signed int v14; // ebx + int *v15; // eax + int *v16; // eax + int v17; // edx + int v18; // ebx + int *v19; // eax + signed int v20; // edx + int v21; // eax + int v22; // ecx + int *v23; // eax + int v24; // edx + int v25; // esi + int v26; // eax + int v27; // ecx + int v28; // edx + int *v29; // ecx + int v30; // edx + int v31; // ebx + signed int v32; // edx + int v33; // edx + int v34; // eax + int v35; // ecx + int v36; // esi + signed int v37; // edx + int v38; // eax + int *v39; // ecx + signed int v40; // esi + int v41; // esi + int *v42; // ecx + int *v43; // eax + signed int v44; // ecx + int v45; // eax + int *v46; // ecx + signed int v47; // edx + int v48; // ebx + int *v49; // ecx + int *v50; // eax + signed int v51; // ecx + signed int v52; // edi + int v53; // esi + int v54; // ebx + int v55; // eax + bool v56; // zf + signed int v57; // ebx + unsigned int v58; // edi + signed int v59; // edx + int v60; // ebx + char *v61; // esi + int j; // edi + int v63; // esi + int v64; // eax + int *v65; // eax + int v66; // edx + char v67; // al + char v68; // al + int v69; // esi + int v70; // edx + int v71; // ebx + int v72; // edi + int v73; // eax + int v74; // edx + int v75; // edx + int v76; // edx + int v77; // esi + int v78; // ebx + int *v79; // eax + int v80; // eax + int v81; // eax + int *v82; // eax + int v83; // eax + int v84; // eax + int v85; // ecx + int v86; // edx + int v87; // eax + int v88; // ebx + int v89; // eax + int v91; // esi + int v92; // eax + int v93; // edx + int *v94; // eax + int v95; // edx + char v96; // al + char v97; // al + int v98; // esi + int v99; // edx + int v100; // ebx + int v101; // edi + int v102; // eax + int v103; // edx + int v104; // edx + int v105; // edx + int v106; // ebx + int v107; // ST38_4 + int v108; // ST34_4 + int v109; // ST3C_4 + int v110; // eax + _BYTE *v111; // eax + signed int v112; // edx + int *v113; // eax + int v114; // edx + char v115; // al + char v116; // al + int v117; // esi + int v118; // edx + int v119; // ebx + int v120; // edi + int v121; // eax + int v122; // edx + int v123; // edx + int v124; // edx + int v125; // eax + int *v126; // ecx + signed int v127; // esi + int v128; // esi + int *v129; // ecx + int *v130; // eax + signed int v131; // ecx + int v133; // eax + int v134; // ebx + int v135; // edi + int v136; // esi + unsigned short param2; // [esp+Ch] [ebp-18h] + int v138; // [esp+14h] [ebp-10h] + signed int v139; // [esp+1Ch] [ebp-8h] + int *v140; // [esp+1Ch] [ebp-8h] + signed int v141; // [esp+1Ch] [ebp-8h] + int arglist; // [esp+20h] [ebp-4h] + int sfx_ida; // [esp+2Ch] [ebp+8h] + int sfx_ide; // [esp+2Ch] [ebp+8h] + int sfx_idb; // [esp+2Ch] [ebp+8h] + int *sfx_idc; // [esp+2Ch] [ebp+8h] + int sfx_idf; // [esp+2Ch] [ebp+8h] + int sfx_idd; // [esp+2Ch] [ebp+8h] + int sfx_idg; // [esp+2Ch] [ebp+8h] + + param2 = i; + arglist = pnum; + if ( dropGoldFlag ) + { + dropGoldFlag = 0; + dropGoldValue = 0; + } + v3 = i; + v4 = (int*)&object[i]._oSelFlag; + if ( object[i]._oSelFlag ) + { + SetRndSeed(object[v3]._oRndSeed); + v5 = deltaload; + *(_BYTE *)v4 = 0; + if ( v5 ) + { + v6 = object[v3]._oAnimLen; + object[v3]._oAnimFlag = 0; + object[v3]._oAnimFrame = v6; + } + else + { + PlaySfxLoc(sType, object[v3]._ox, object[v3]._oy); + object[v3]._oAnimFlag = 1; + object[v3]._oAnimDelay = 1; + v5 = deltaload; + } + v7 = object[v3]._oVar1; + switch ( v7 ) + { + case SHRINE_MYSTERIOUS: + if ( !v5 && arglist == myplr ) + { + ModifyPlrStr(arglist, -1); + ModifyPlrMag(arglist, -1); + ModifyPlrDex(arglist, -1); + ModifyPlrVit(arglist, -1); + v9 = random(0, 4); + if ( v9 ) + { + v10 = v9 - 1; + if ( v10 ) + { + v11 = v10 - 1; + if ( v11 ) + { + if ( v11 == 1 ) + ModifyPlrVit(arglist, 6); + } + else + { + ModifyPlrDex(arglist, 6); + } + } + else + { + ModifyPlrMag(arglist, 6); + } + } + else + { + ModifyPlrStr(arglist, 6); + } + CheckStats(arglist); + _LOBYTE(v7) = 12; + goto LABEL_221; + } + return; + case SHRINE_HIDDEN: + v12 = 0; + if ( v5 || arglist != myplr ) + return; + v13 = arglist; + v14 = 7; + v15 = &plr[arglist].InvBody[0]._itype; + v7 = 7; + do + { + if ( *v15 != -1 ) + ++v12; + v15 += 92; + --v7; + } + while ( v7 ); + if ( v12 <= 0 ) + goto LABEL_47; + v16 = &plr[v13].InvBody[0]._iMaxDur; + do + { + if ( *(v16 - 58) != -1 ) + { + v7 = *v16; + if ( *v16 != 255 ) + { + if ( v7 ) + { + *(v16 - 1) += 10; + v17 = *(v16 - 1); + v7 += 10; + *v16 = v7; + if ( v17 > v7 ) + *(v16 - 1) = v7; + } + } + } + v16 += 92; + --v14; + } + while ( v14 ); + while ( 1 ) + { + v18 = 0; + v19 = &plr[v13].InvBody[0]._iMaxDur; + v20 = 7; + do + { + if ( *(v19 - 58) != -1 ) + { + v7 = *v19; + if ( *v19 != 255 ) + { + if ( v7 ) + ++v18; + } + } + v19 += 92; + --v20; + } + while ( v20 ); + if ( !v18 ) + goto LABEL_47; + v21 = random(0, 7); + v7 = v13 * 21720 + 368 * v21; + if ( *(int *)((char *)&plr[0].InvBody[0]._itype + v7) != -1 ) + { + v7 = *(int *)((char *)&plr[0].InvBody[0]._iMaxDur + v7); + if ( v7 != 255 ) + { + if ( v7 ) + break; + } + } + } + v22 = 368 * v21 + v13 * 21720; + v23 = (int *)((char *)&plr[0].InvBody[0]._iDurability + v22); + v7 = (int)&plr[0].InvBody[0]._iMaxDur + v22; + *v23 -= 20; + v24 = *v23; + *(_DWORD *)v7 -= 20; + v25 = *(_DWORD *)v7; + if ( v24 <= 0 ) + *v23 = 1; + if ( v25 <= 0 ) + *(_DWORD *)v7 = 1; +LABEL_47: + _LOBYTE(v7) = 13; + goto LABEL_221; + case SHRINE_GLOOMY: + if ( v5 ) + return; + if ( arglist != myplr ) + goto LABEL_280; + v26 = arglist; + if ( plr[arglist].InvBody[0]._itype != ITYPE_NONE ) + plr[v26].InvBody[0]._iAC += 2; + if ( plr[v26].InvBody[6]._itype != ITYPE_NONE ) + plr[v26].InvBody[6]._iAC += 2; + v27 = plr[v26].InvBody[4]._itype; + if ( v27 != ITYPE_NONE ) + { + if ( v27 == ITYPE_SHIELD ) + { + plr[v26].InvBody[4]._iAC += 2; + } + else + { + v28 = plr[v26].InvBody[4]._iMinDam; + v29 = &plr[v26].InvBody[4]._iMaxDam; + --*v29; + if ( plr[v26].InvBody[4]._iMaxDam < v28 ) + *v29 = v28; + } + } + v7 = plr[v26].InvBody[5]._itype; + if ( v7 != ITYPE_NONE ) + { + if ( v7 == ITYPE_SHIELD ) + { + plr[v26].InvBody[5]._iAC += 2; + } + else + { + v30 = plr[v26].InvBody[5]._iMinDam; + v7 = (int)&plr[v26].InvBody[5]._iMaxDam; + --*(_DWORD *)v7; + if ( plr[v26].InvBody[5]._iMaxDam < v30 ) + *(_DWORD *)v7 = v30; + } + } + v31 = 0; + if ( plr[v26]._pNumInv <= 0 ) + goto LABEL_73; + v7 = (int)&plr[v26].InvList[0]._iAC; + break; + case SHRINE_WEIRD: + if ( v5 ) + return; + if ( arglist != myplr ) + goto LABEL_280; + v34 = arglist; + v35 = plr[arglist].InvBody[4]._itype; + if ( v35 != ITYPE_NONE && v35 != ITYPE_SHIELD ) + ++plr[v34].InvBody[4]._iMaxDam; + v7 = plr[v34].InvBody[5]._itype; + if ( v7 != ITYPE_NONE && v7 != ITYPE_SHIELD ) + ++plr[v34].InvBody[5]._iMaxDam; + v36 = 0; + if ( plr[v34]._pNumInv > 0 ) + { + v7 = (int)&plr[v34].InvList[0]._iMaxDam; + do + { + v37 = *(_DWORD *)(v7 - 200); + if ( v37 > 0 && (v37 <= 4 || v37 == 10) ) + ++*(_DWORD *)v7; + ++v36; + v7 += 368; + } + while ( v36 < plr[v34]._pNumInv ); + } + _LOBYTE(v7) = 15; + goto LABEL_221; + case SHRINE_MAGICAL: + case SHRINE_MAGICAL2: + if ( v5 ) + return; + AddMissile( + plr[arglist].WorldX, + plr[arglist].WorldY, + plr[arglist].WorldX, + plr[arglist].WorldY, + plr[arglist]._pdir, + 13, + -1, + arglist, + 0, + 2 * (unsigned char)leveltype); + if ( arglist != myplr ) + return; + _LOBYTE(v7) = 16; + goto LABEL_221; + case SHRINE_STONE: + if ( v5 ) + return; + if ( arglist != myplr ) + goto LABEL_280; + v38 = arglist; + v39 = &plr[arglist].InvBody[0]._iMaxCharges; + v40 = 7; + do + { + if ( *(v39 - 56) == 10 ) + *(v39 - 1) = *v39; + v39 += 92; + --v40; + } + while ( v40 ); + v41 = 0; + if ( plr[v38]._pNumInv > 0 ) + { + v42 = &plr[v38].InvList[0]._iMaxCharges; + do + { + if ( *(v42 - 56) == 10 ) + *(v42 - 1) = *v42; + ++v41; + v42 += 92; + } + while ( v41 < plr[v38]._pNumInv ); + } + v43 = &plr[v38].SpdList[0]._iMaxCharges; + v44 = 8; + do + { + if ( *(v43 - 56) == 10 ) + *(v43 - 1) = *v43; + v43 += 92; + --v44; + } + while ( v44 ); + v7 = 17; + goto LABEL_221; + case SHRINE_RELIGIOUS: + if ( v5 ) + return; + if ( arglist != myplr ) + goto LABEL_280; + v45 = arglist; + v46 = &plr[arglist].InvBody[0]._iDurability; + v47 = 7; + do + { + *v46 = v46[1]; + v46 += 92; + --v47; + } + while ( v47 ); + v48 = 0; + if ( plr[v45]._pNumInv > 0 ) + { + v49 = &plr[v45].InvList[0]._iDurability; + do + { + ++v48; + *v49 = v49[1]; + v49 += 92; + } + while ( v48 < plr[v45]._pNumInv ); + } + v50 = &plr[v45].SpdList[0]._iDurability; + v51 = 8; + do + { + *v50 = v50[1]; + v50 += 92; + --v51; + } + while ( v51 ); + v7 = 18; + goto LABEL_221; + case SHRINE_ENCHANTED: + if ( v5 || arglist != myplr ) + return; + sfx_ida = 0; + v138 = 0; + v52 = 1; + v53 = arglist; + v54 = plr[arglist]._pMemSpells[1]; + v139 = 37; + do + { + v7 = v138 & v54; + if ( v138 & v54 | v52 & plr[arglist]._pMemSpells[0] ) + ++sfx_ida; + v55 = __PAIR__((unsigned int)v138, v52) >> 31; + v52 *= 2; + v56 = v139-- == 1; + v138 = v55; + } + while ( !v56 ); + v57 = 1; + if ( sfx_ida > 1 ) + { + v58 = 0; + v59 = 1; + do + { + v7 = v58 & plr[v53]._pMemSpells[1]; + if ( v7 | v57 & plr[v53]._pMemSpells[0] ) + { + v7 = (int)&plr[v53]._pSplLvl[v59]; + if ( *(_BYTE *)v7 < 15 ) + ++*(_BYTE *)v7; + } + v58 = __PAIR__(v58, v57) >> 31; + v57 *= 2; + ++v59; + } + while ( v59 <= 37 ); + do + { + v60 = random(0, 37); + v7 = v60; + } + while ( !(plr[v53]._pMemSpells[1] & ((unsigned __int64)((__int64)1 << v60) >> 32) | plr[v53]._pMemSpells[0] & (unsigned int)((__int64)1 << v60)) ); + v61 = &plr[v53]._pSplLvl[v60 + 1]; + if ( *v61 < 2 ) + *v61 = 0; + else + *v61 -= 2; + } + _LOBYTE(v7) = 19; + goto LABEL_221; + case SHRINE_THAUMATURGIC: + for ( j = 0; j < nobjects; ++j ) + { + v63 = objectactive[j]; + v7 = object[v63]._otype; + if ( (v7 == OBJ_CHEST1 || v7 == OBJ_CHEST2 || v7 == OBJ_CHEST3) && !object[v63]._oSelFlag ) + { + v64 = GetRndSeed(); + object[v63]._oAnimFrame -= 2; + object[v63]._oRndSeed = v64; + v5 = deltaload; + object[v63]._oSelFlag = 1; + } + } + if ( v5 ) + return; + if ( arglist != myplr ) + goto LABEL_280; + _LOBYTE(v7) = 20; + goto LABEL_221; + case SHRINE_FASCINATING: + if ( v5 || arglist != myplr ) + return; + v7 = 21720 * arglist; + v65 = plr[arglist]._pMemSpells; + v66 = plr[arglist]._pMemSpells[1]; + *v65 |= 1u; + v65[1] = v66; + v67 = plr[arglist]._pSplLvl[1]; + if ( v67 < 15 ) + plr[0]._pSplLvl[v7 + 1] = v67 + 1; + v68 = plr[0]._pSplLvl[v7 + 1]; + if ( v68 < 15 ) + plr[0]._pSplLvl[v7 + 1] = v68 + 1; + v69 = *(int *)((char *)&plr[0]._pMaxManaBase + v7); + v70 = *(int *)((char *)&plr[0]._pManaBase + v7); + v71 = *(int *)((char *)&plr[0]._pMana + v7) - v70; + v72 = *(int *)((char *)&plr[0]._pMaxManaBase + v7) / 10; + v73 = *(int *)((char *)&plr[0]._pMaxMana + v7) - v69; + *(int *)((char *)&plr[0]._pManaBase + v7) = v70 - v72; + v74 = *(int *)((char *)&plr[0]._pMana + v7) - v72; + sfx_ide = v74; + *(int *)((char *)&plr[0]._pMana + v7) = v74; + v75 = *(int *)((char *)&plr[0]._pMaxMana + v7); + *(int *)((char *)&plr[0]._pMaxManaBase + v7) = v69 - v72; + v76 = v75 - v72; + *(int *)((char *)&plr[0]._pMaxMana + v7) = v76; + if ( (signed int)(sfx_ide & 0xFFFFFFC0) <= 0 ) + { + *(int *)((char *)&plr[0]._pManaBase + v7) = 0; + *(int *)((char *)&plr[0]._pMana + v7) = v71; + } + if ( (signed int)(v76 & 0xFFFFFFC0) <= 0 ) + { + *(int *)((char *)&plr[0]._pMaxManaBase + v7) = 0; + *(int *)((char *)&plr[0]._pMaxMana + v7) = v73; + } + _LOBYTE(v7) = 21; + goto LABEL_221; + case SHRINE_CRYPTIC: + if ( v5 ) + return; + v77 = arglist; + AddMissile( + plr[arglist].WorldX, + plr[arglist].WorldY, + plr[arglist].WorldX, + plr[arglist].WorldY, + plr[arglist]._pdir, + 42, + -1, + arglist, + 0, + 2 * (unsigned char)leveltype); + if ( arglist != myplr ) + return; + _LOBYTE(v7) = 22; + plr[v77]._pMana = plr[v77]._pMaxMana; + plr[v77]._pManaBase = plr[v77]._pMaxManaBase; + goto LABEL_221; + case SHRINE_ELDRITCH: + if ( v5 ) + return; + if ( arglist != myplr ) + goto LABEL_280; + sfx_idb = 0; + v78 = arglist; + if ( plr[arglist]._pNumInv > 0 ) + { + v79 = &plr[v78].InvList[0]._iMiscId; + v140 = &plr[v78].InvList[0]._iMiscId; + do + { + if ( !*(v79 - 53) ) + { + if ( *v79 == IMISC_HEAL || *v79 == IMISC_MANA ) + { + v80 = ItemMiscIdIdx(IMISC_REJUV); + SetPlrHandItem(&plr[v78].HoldItem, v80); + GetPlrHandSeed(&plr[v78].HoldItem); + v79 = v140; + plr[v78].HoldItem._iStatFlag = 1; + qmemcpy(v140 - 55, &plr[v78].HoldItem, 0x170u); + } + if ( *v79 == IMISC_FULLHEAL || *v79 == IMISC_FULLMANA ) + { + v81 = ItemMiscIdIdx(IMISC_FULLREJUV); + SetPlrHandItem(&plr[v78].HoldItem, v81); + GetPlrHandSeed(&plr[v78].HoldItem); + v79 = v140; + plr[v78].HoldItem._iStatFlag = 1; + qmemcpy(v140 - 55, &plr[v78].HoldItem, 0x170u); + } + } + ++sfx_idb; + v79 += 92; + v7 = sfx_idb; + v140 = v79; + } + while ( sfx_idb < plr[v78]._pNumInv ); + } + v82 = &plr[v78].SpdList[0]._iMiscId; + v141 = 8; + sfx_idc = &plr[v78].SpdList[0]._iMiscId; + do + { + if ( !*(v82 - 53) ) + { + if ( *v82 == IMISC_HEAL || *v82 == IMISC_MANA ) + { + v83 = ItemMiscIdIdx(IMISC_REJUV); + SetPlrHandItem(&plr[v78].HoldItem, v83); + GetPlrHandSeed(&plr[v78].HoldItem); + v82 = sfx_idc; + plr[v78].HoldItem._iStatFlag = 1; + qmemcpy(sfx_idc - 55, &plr[v78].HoldItem, 0x170u); + } + v7 = *v82; + if ( *v82 == IMISC_FULLHEAL || v7 == IMISC_FULLMANA ) + { + v84 = ItemMiscIdIdx(IMISC_FULLREJUV); + SetPlrHandItem(&plr[v78].HoldItem, v84); + GetPlrHandSeed(&plr[v78].HoldItem); + v82 = sfx_idc; + plr[v78].HoldItem._iStatFlag = 1; + qmemcpy(sfx_idc - 55, &plr[v78].HoldItem, 0x170u); + v7 = 0; + } + } + v82 += 92; + v56 = v141-- == 1; + sfx_idc = v82; + } + while ( !v56 ); + _LOBYTE(v7) = 24; + goto LABEL_221; + case SHRINE_EERIE: + if ( v5 || arglist != myplr ) + return; + ModifyPlrMag(arglist, 2); + CheckStats(arglist); + _LOBYTE(v7) = 25; + goto LABEL_221; + case SHRINE_DIVINE: + if ( v5 || arglist != myplr ) + return; + v85 = object[v3]._ox; + v86 = object[v3]._oy; + if ( 2 * currlevel >= 7 ) + { + CreateTypeItem(v85, v86, 0, ITYPE_MISC, 19, 0, 1); + CreateTypeItem(object[v3]._ox, object[v3]._oy, 0, ITYPE_MISC, 19, 0, 1); + } + else + { + CreateTypeItem(v85, v86, 0, ITYPE_MISC, 7, 0, 1); + CreateTypeItem(object[v3]._ox, object[v3]._oy, 0, ITYPE_MISC, 2, 0, 1); + } + v87 = arglist; + plr[v87]._pMana = plr[arglist]._pMaxMana; + plr[v87]._pManaBase = plr[arglist]._pMaxManaBase; + plr[v87]._pHitPoints = plr[arglist]._pMaxHP; + v7 = plr[arglist]._pMaxHPBase; + plr[v87]._pHPBase = v7; + _LOBYTE(v7) = 26; + goto LABEL_221; + case SHRINE_HOLY: + if ( v5 ) + return; + v88 = 0; + do + { + v89 = random(159, 112); + v91 = v89; + v92 = random(159, 112); + if ( ++v88 > 12544 ) + break; + v7 = v92 + 112 * v91; + v93 = v92 + 112 * v91; + } + while ( nSolidTable[dPiece[0][v93]] || dObject[0][v7] || dMonster[0][v93] ); + AddMissile( + plr[arglist].WorldX, + plr[arglist].WorldY, + v91, + v92, + plr[arglist]._pdir, + 3, + -1, + arglist, + 0, + 2 * (unsigned char)leveltype); + if ( arglist != myplr ) + return; + _LOBYTE(v7) = 27; + goto LABEL_221; + case SHRINE_SACRED: + if ( v5 || arglist != myplr ) + return; + v7 = 21720 * arglist; + v94 = plr[arglist]._pMemSpells; + v95 = plr[arglist]._pMemSpells[1]; + *((_BYTE *)v94 + 3) |= 0x20u; + v94[1] = v95; + v96 = plr[arglist]._pSplLvl[30]; + if ( v96 < 15 ) + plr[0]._pSplLvl[v7 + 30] = v96 + 1; + v97 = plr[0]._pSplLvl[v7 + 30]; + if ( v97 < 15 ) + plr[0]._pSplLvl[v7 + 30] = v97 + 1; + v98 = *(int *)((char *)&plr[0]._pMaxManaBase + v7); + v99 = *(int *)((char *)&plr[0]._pManaBase + v7); + v100 = *(int *)((char *)&plr[0]._pMana + v7) - v99; + v101 = *(int *)((char *)&plr[0]._pMaxManaBase + v7) / 10; + v102 = *(int *)((char *)&plr[0]._pMaxMana + v7) - v98; + *(int *)((char *)&plr[0]._pManaBase + v7) = v99 - v101; + v103 = *(int *)((char *)&plr[0]._pMana + v7) - v101; + sfx_idf = v103; + *(int *)((char *)&plr[0]._pMana + v7) = v103; + v104 = *(int *)((char *)&plr[0]._pMaxMana + v7); + *(int *)((char *)&plr[0]._pMaxManaBase + v7) = v98 - v101; + v105 = v104 - v101; + *(int *)((char *)&plr[0]._pMaxMana + v7) = v105; + if ( (signed int)(sfx_idf & 0xFFFFFFC0) <= 0 ) + { + *(int *)((char *)&plr[0]._pManaBase + v7) = 0; + *(int *)((char *)&plr[0]._pMana + v7) = v100; + } + if ( (signed int)(v105 & 0xFFFFFFC0) <= 0 ) + { + *(int *)((char *)&plr[0]._pMaxManaBase + v7) = 0; + *(int *)((char *)&plr[0]._pMaxMana + v7) = v102; + } + _LOBYTE(v7) = 28; + goto LABEL_221; + case SHRINE_SPIRITUAL: + if ( v5 || arglist != myplr ) + return; + sfx_idd = 0; + v106 = arglist; + do + { + if ( !plr[v106].InvGrid[sfx_idd] ) + { + v107 = 5 * (unsigned char)leveltype + random(160, 10 * (unsigned char)leveltype); + v108 = plr[v106]._pNumInv; + v109 = v106 * 21720 + 368 * v108; + qmemcpy((char *)plr[0].InvList + v109, &golditem, 0x170u); + *(int *)((char *)&plr[0].InvList[0]._iSeed + v109) = GetRndSeed(); + ++plr[v106]._pNumInv; + plr[v106].InvGrid[sfx_idd] = plr[v106]._pNumInv; + *(int *)((char *)&plr[0].InvList[0]._ivalue + v109) = v107; + plr[v106]._pGold += v107; + SetGoldCurs(arglist, v108); + } + ++sfx_idd; + } + while ( sfx_idd < 40 ); + _LOBYTE(v7) = 29; + goto LABEL_221; + case SHRINE_SPOOKY: + if ( v5 ) + return; + if ( arglist == myplr ) + { + _LOBYTE(v7) = 30; + goto LABEL_221; + } + _LOBYTE(v7) = 31; + InitDiabloMsg(v7); + v110 = myplr; + plr[v110]._pHitPoints = plr[myplr]._pMaxHP; + plr[v110]._pHPBase = plr[v110]._pMaxHPBase; + plr[v110]._pMana = plr[v110]._pMaxMana; + plr[v110]._pManaBase = plr[v110]._pMaxManaBase; + goto LABEL_280; + case SHRINE_ABANDONED: + if ( v5 || arglist != myplr ) + return; + ModifyPlrDex(arglist, 2); + CheckStats(arglist); + if ( arglist != myplr ) + goto LABEL_280; + _LOBYTE(v7) = 32; + goto LABEL_221; + case SHRINE_CREEPY: + if ( v5 || arglist != myplr ) + return; + ModifyPlrStr(arglist, 2); + CheckStats(arglist); + if ( arglist != myplr ) + goto LABEL_280; + _LOBYTE(v7) = 33; + goto LABEL_221; + case SHRINE_QUIET: + if ( v5 || arglist != myplr ) + return; + ModifyPlrVit(arglist, 2); + CheckStats(arglist); + if ( arglist != myplr ) + goto LABEL_280; + _LOBYTE(v7) = 34; + goto LABEL_221; + case SHRINE_SECLUDED: + if ( v5 ) + return; + if ( arglist != myplr ) + goto LABEL_280; + v7 = 0; + do + { + v111 = (unsigned char *)automapview + v7; + v112 = 40; + do + { + *v111 = 1; + v111 += 40; + --v112; + } + while ( v112 ); + ++v7; + } + while ( v7 < 40 ); + _LOBYTE(v7) = 35; + goto LABEL_221; + case SHRINE_ORNATE: + if ( v5 || arglist != myplr ) + return; + v7 = 21720 * arglist; + v113 = plr[arglist]._pMemSpells; + v114 = plr[arglist]._pMemSpells[1]; + *((_BYTE *)v113 + 3) |= 0x40u; + v113[1] = v114; + v115 = plr[arglist]._pSplLvl[31]; + if ( v115 < 15 ) + plr[0]._pSplLvl[v7 + 31] = v115 + 1; + v116 = plr[0]._pSplLvl[v7 + 31]; + if ( v116 < 15 ) + plr[0]._pSplLvl[v7 + 31] = v116 + 1; + v117 = *(int *)((char *)&plr[0]._pMaxManaBase + v7); + v118 = *(int *)((char *)&plr[0]._pManaBase + v7); + v119 = *(int *)((char *)&plr[0]._pMana + v7) - v118; + v120 = *(int *)((char *)&plr[0]._pMaxManaBase + v7) / 10; + v121 = *(int *)((char *)&plr[0]._pMaxMana + v7) - v117; + *(int *)((char *)&plr[0]._pManaBase + v7) = v118 - v120; + v122 = *(int *)((char *)&plr[0]._pMana + v7) - v120; + sfx_idg = v122; + *(int *)((char *)&plr[0]._pMana + v7) = v122; + v123 = *(int *)((char *)&plr[0]._pMaxMana + v7); + *(int *)((char *)&plr[0]._pMaxManaBase + v7) = v117 - v120; + v124 = v123 - v120; + *(int *)((char *)&plr[0]._pMaxMana + v7) = v124; + if ( (signed int)(sfx_idg & 0xFFFFFFC0) <= 0 ) + { + *(int *)((char *)&plr[0]._pManaBase + v7) = 0; + *(int *)((char *)&plr[0]._pMana + v7) = v119; + } + if ( (signed int)(v124 & 0xFFFFFFC0) <= 0 ) + { + *(int *)((char *)&plr[0]._pMaxManaBase + v7) = 0; + *(int *)((char *)&plr[0]._pMaxMana + v7) = v121; + } + _LOBYTE(v7) = 36; + goto LABEL_221; + case SHRINE_GLIMMERING: + if ( v5 || arglist != myplr ) + return; + v125 = arglist; + v126 = &plr[arglist].InvBody[0]._iIdentified; + v127 = 7; + do + { + if ( *((_BYTE *)v126 + 4) && !*v126 ) + *v126 = 1; + v126 += 92; + --v127; + } + while ( v127 ); + v128 = 0; + if ( plr[v125]._pNumInv > 0 ) + { + v129 = &plr[v125].InvList[0]._iIdentified; + do + { + if ( *((_BYTE *)v129 + 4) && !*v129 ) + *v129 = 1; + ++v128; + v129 += 92; + } + while ( v128 < plr[v125]._pNumInv ); + } + v130 = &plr[v125].SpdList[0]._iIdentified; + v131 = 8; + do + { + if ( *((_BYTE *)v130 + 4) && !*v130 ) + *v130 = 1; + v130 += 92; + --v131; + } + while ( v131 ); + v7 = 37; + goto LABEL_221; + case SHRINE_TAINTED: + if ( v5 ) + return; + if ( arglist == myplr ) + { + _LOBYTE(v7) = 38; + goto LABEL_221; + } + _LOBYTE(v7) = 39; + InitDiabloMsg(v7); + v133 = random(155, 4); + v134 = 1; + v135 = 2 * (v133 == 1) - 1; + if ( v133 == 2 || (v134 = -1, v133 != 3) ) + v136 = -1; + else + v136 = 1; + ModifyPlrStr(myplr, 2 * (v133 == 0) - 1); + ModifyPlrMag(myplr, v135); + ModifyPlrDex(myplr, v134); + ModifyPlrVit(myplr, v136); + CheckStats(myplr); + goto LABEL_280; + default: + goto LABEL_280; + } + while ( 1 ) + { + v32 = *(_DWORD *)(v7 - 204); + if ( v32 > 0 ) + { + if ( v32 <= 4 ) + goto LABEL_70; + if ( v32 <= 9 ) + { + *(_DWORD *)v7 += 2; + } + else if ( v32 == 10 ) + { +LABEL_70: + --*(_DWORD *)(v7 - 4); + v33 = *(_DWORD *)(v7 - 8); + if ( *(_DWORD *)(v7 - 4) < v33 ) + *(_DWORD *)(v7 - 4) = v33; + goto LABEL_72; + } + } +LABEL_72: + ++v31; + v7 += 368; + if ( v31 >= plr[v26]._pNumInv ) + { +LABEL_73: + _LOBYTE(v7) = 14; +LABEL_221: + InitDiabloMsg(v7); +LABEL_280: + CalcPlrInv(arglist, 1u); + drawpanflag = 255; + if ( arglist == myplr ) + NetSendCmdParam2(0, CMD_PLROPOBJ, arglist, param2); + return; + } + } + } +} +// 4B84DC: using guessed type int dropGoldFlag; +// 52571C: using guessed type int drawpanflag; +// 5BB1ED: using guessed type char leveltype; +// 676190: using guessed type int deltaload; + +void __fastcall OperateSkelBook(int pnum, int i, unsigned char sendmsg) +{ + unsigned short v3; // di + int v4; // esi + bool v5; // zf + int v7; // eax + int v8; // ecx + int v9; // edx + int v10; // [esp+Ch] [ebp-4h] + + v3 = i; + v4 = i; + v10 = pnum; + if ( object[i]._oSelFlag ) + { + if ( !deltaload ) + PlaySfxLoc(IS_ISCROL, object[v4]._ox, object[v4]._oy); + object[v4]._oAnimFrame += 2; + v5 = deltaload == 0; + object[v4]._oSelFlag = 0; + if ( v5 ) + { + SetRndSeed(object[v4]._oRndSeed); + v7 = random(161, 5); + v8 = object[v4]._ox; + v9 = object[v4]._oy; + if ( v7 ) + CreateTypeItem(v8, v9, 0, ITYPE_MISC, 21, sendmsg, 0); + else + CreateTypeItem(v8, v9, 0, ITYPE_MISC, 24, sendmsg, 0); + if ( v10 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, v3); + } + } +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateBookCase(int pnum, int i, unsigned char sendmsg) +{ + unsigned short v3; // di + int v4; // ebp + int v5; // esi + bool v6; // zf + //int v7; // eax + + v3 = i; + v4 = pnum; + v5 = i; + if ( object[i]._oSelFlag ) + { + if ( !deltaload ) + PlaySfxLoc(IS_ISCROL, object[v5]._ox, object[v5]._oy); + object[v5]._oAnimFrame -= 2; + v6 = deltaload == 0; + object[v5]._oSelFlag = 0; + if ( v6 ) + { + SetRndSeed(object[v5]._oRndSeed); + CreateTypeItem(object[v5]._ox, object[v5]._oy, 0, ITYPE_MISC, 24, sendmsg, 0); + //_LOBYTE(v7) = QuestStatus(3); + if ( QuestStatus(3) + && monster[4].mName == UniqMonst[2].mName + && monster[4]._msquelch == -1 + && monster[4]._mhitpoints ) + { + monster[4].mtalkmsg = QUEST_ZHAR2; + M_StartStand(0, monster[4]._mdir); + _LOBYTE(monster[4]._mgoal) = 5; + monster[4]._mmode = MM_TALK; + } + if ( v4 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, v3); + } + } +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateDecap(int pnum, int i, unsigned char sendmsg) +{ + unsigned short v3; // bp + int v4; // esi + int v5; // edi + int *v6; // eax + bool v7; // zf + + v3 = i; + v4 = i; + v5 = pnum; + v6 = (int*)&object[i]._oSelFlag; + if ( *(_BYTE *)v6 ) + { + v7 = deltaload == 0; + *(_BYTE *)v6 = 0; + if ( v7 ) + { + SetRndSeed(object[v4]._oRndSeed); + CreateRndItem(object[v4]._ox, object[v4]._oy, 0, sendmsg, 0); + if ( v5 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, v3); + } + } +} +// 676190: using guessed type int deltaload; + +void __fastcall OperateArmorStand(int pnum, int i, unsigned char sendmsg) +{ + unsigned short v3; // di + int v4; // esi + int *v5; // eax + bool v6; // zf + unsigned char v8; // al + int v9; // [esp-10h] [ebp-20h] + int v10; // [esp-8h] [ebp-18h] + int v11; // [esp+Ch] [ebp-4h] + + v3 = i; + v4 = i; + v11 = pnum; + v5 = (int*)&object[i]._oSelFlag; + if ( *(_BYTE *)v5 ) + { + ++object[v4]._oAnimFrame; + v6 = deltaload == 0; + *(_BYTE *)v5 = 0; + if ( v6 ) + { + SetRndSeed(object[v4]._oRndSeed); + v8 = random(0, 2); + if ( currlevel > 5u ) + { + if ( currlevel >= 6u && currlevel <= 9u ) + { + CreateTypeItem(object[v4]._ox, object[v4]._oy, v8, ITYPE_MARMOR, 0, sendmsg, 0); + goto LABEL_15; + } + if ( currlevel >= 0xAu && currlevel <= 0xCu ) + { + CreateTypeItem(object[v4]._ox, object[v4]._oy, 0, ITYPE_HARMOR, 0, sendmsg, 0); + goto LABEL_15; + } + if ( currlevel < 0xDu || currlevel > 0x10u ) + goto LABEL_15; + v10 = sendmsg; + v9 = ITYPE_HARMOR; + } + else + { + v10 = sendmsg; + v9 = ITYPE_LARMOR; + } + CreateTypeItem(object[v4]._ox, object[v4]._oy, 1u, v9, 0, v10, 0); +LABEL_15: + if ( v11 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, v3); + return; + } + } +} +// 676190: using guessed type int deltaload; + +int __fastcall FindValidShrine(int i) +{ + bool done; // esi + int rv; // eax + bool v3; // zf + + do + { + done = 0; + do + { + rv = random(0, 26); + if ( currlevel >= shrinemin[rv] && currlevel <= shrinemax[rv] && rv != 8 ) + done = 1; + } + while ( !done ); + if ( gbMaxPlayers == 1 ) + v3 = shrineavail[rv] == 2; + else + v3 = shrineavail[rv] == 1; + } + while ( v3 ); + return rv; +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall OperateGoatShrine(int pnum, int i, int sType) +{ + int v3; // edi + int v4; // ebx + int v5; // esi + + v3 = i; + v4 = pnum; + v5 = i; + SetRndSeed(object[i]._oRndSeed); + object[v5]._oVar1 = FindValidShrine(v3); + OperateShrine(v4, v3, sType); + object[v5]._oAnimDelay = 2; + drawpanflag = 255; +} +// 52571C: using guessed type int drawpanflag; + +void __fastcall OperateCauldron(int pnum, int i, int sType) +{ + int v3; // edi + int v4; // ebx + int v5; // esi + + v3 = i; + v4 = pnum; + v5 = i; + SetRndSeed(object[i]._oRndSeed); + object[v5]._oVar1 = FindValidShrine(v3); + OperateShrine(v4, v3, sType); + object[v5]._oAnimFlag = 0; + object[v5]._oAnimFrame = 3; + drawpanflag = 255; +} +// 52571C: using guessed type int drawpanflag; + +bool __fastcall OperateFountains(int pnum, int i) +{ + unsigned short v2; // bx + int v3; // esi + int v4; // edi + bool v5; // bp + signed int v7; // ebx + int v8; // ebp + int v10; // eax + int v11; // esi + int v12; // eax + int v13; // eax + int v14; // edi + int v15; // edx + int v16; // edx + int v17; // ecx + int *v18; // eax + int v19; // ecx + int v20; // edi + int v21; // edx + int v22; // ecx + int v23; // [esp-4h] [ebp-20h] + signed int v24; // [esp+10h] [ebp-Ch] + signed int v25; // [esp+14h] [ebp-8h] + short param1; // [esp+18h] [ebp-4h] + + v2 = i; + v3 = i; + v4 = pnum; + param1 = i; + v5 = 0; + SetRndSeed(object[i]._oRndSeed); + switch ( object[v3]._otype ) + { + case OBJ_BLOODFTN: + if ( !deltaload && v4 == myplr ) + { + v20 = v4; + v23 = object[v3]._oy; + v15 = object[v3]._ox; + if ( plr[v20]._pHitPoints < plr[v20]._pMaxHP ) + { + PlaySfxLoc(LS_FOUNTAIN, v15, v23); + plr[v20]._pHitPoints += 64; + v21 = plr[v20]._pHitPoints; + v22 = plr[v20]._pMaxHP; + v18 = &plr[v20]._pHPBase; + *v18 += 64; + if ( v21 <= v22 ) + goto LABEL_39; + plr[v20]._pHitPoints = v22; + v19 = plr[v20]._pMaxHPBase; + goto LABEL_38; + } +LABEL_45: + PlaySfxLoc(LS_FOUNTAIN, v15, v23); + break; + } + return 0; + case OBJ_PURIFYINGFTN: + if ( !deltaload && v4 == myplr ) + { + v14 = v4; + v23 = object[v3]._oy; + v15 = object[v3]._ox; + if ( plr[v14]._pMana < plr[v14]._pMaxMana ) + { + PlaySfxLoc(LS_FOUNTAIN, v15, v23); + plr[v14]._pMana += 64; + v16 = plr[v14]._pMana; + v17 = plr[v14]._pMaxMana; + v18 = &plr[v14]._pManaBase; + *v18 += 64; + if ( v16 <= v17 ) + { +LABEL_39: + v5 = 1; + break; + } + plr[v14]._pMana = v17; + v19 = plr[v14]._pMaxManaBase; +LABEL_38: + *v18 = v19; + goto LABEL_39; + } + goto LABEL_45; + } + return 0; + case OBJ_MURKYFTN: + if ( object[v3]._oSelFlag ) + { + if ( !deltaload ) + PlaySfxLoc(LS_FOUNTAIN, object[v3]._ox, object[v3]._oy); + object[v3]._oSelFlag = 0; + if ( deltaload ) + return 0; + AddMissile( + plr[v4].WorldX, + plr[v4].WorldY, + plr[v4].WorldX, + plr[v4].WorldY, + plr[v4]._pdir, + 39, + -1, + v4, + 0, + 2 * (unsigned char)leveltype); + v5 = 1; + if ( v4 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, v2); + } + break; + default: + if ( object[v3]._otype == OBJ_TEARFTN && object[v3]._oSelFlag ) + { + v7 = -1; + v8 = -1; + v25 = 0; + v24 = 0; + if ( !deltaload ) + PlaySfxLoc(LS_FOUNTAIN, object[v3]._ox, object[v3]._oy); + object[v3]._oSelFlag = 0; + if ( deltaload || v4 != myplr ) + return 0; + do + { + v10 = random(0, 4); + v11 = v10; + if ( v10 != v7 ) + { + if ( v10 ) + { + v12 = v10 - 1; + if ( v12 ) + { + v13 = v12 - 1; + if ( v13 ) + { + if ( v13 == 1 ) + ModifyPlrVit(v4, v8); + } + else + { + ModifyPlrDex(v4, v8); + } + } + else + { + ModifyPlrMag(v4, v8); + } + } + else + { + ModifyPlrStr(v4, v8); + } + v7 = v11; + v8 = 1; + ++v24; + } + if ( v24 > 1 ) + v25 = 1; + } + while ( !v25 ); + CheckStats(v4); + v5 = 1; + if ( v4 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, param1); + } + break; + } + drawpanflag = 255; + return v5; +} +// 52571C: using guessed type int drawpanflag; +// 5BB1ED: using guessed type char leveltype; +// 676190: using guessed type int deltaload; + +void __fastcall OperateWeaponRack(int pnum, int i, unsigned char sendmsg) +{ + unsigned short v3; // di + int v4; // esi + int v6; // eax + int v7; // eax + int v8; // eax + int v9; // eax + bool v10; // zf + int v11; // ecx + int v12; // edx + signed int v13; // [esp-4h] [ebp-14h] + int v14; // [esp+Ch] [ebp-4h] + + v3 = i; + v4 = i; + v14 = pnum; + if ( !object[i]._oSelFlag ) + return; + SetRndSeed(object[v4]._oRndSeed); + v6 = random(0, 4); + if ( v6 ) + { + v7 = v6 - 1; + if ( !v7 ) + { + v13 = ITYPE_AXE; + goto LABEL_7; + } + v8 = v7 - 1; + if ( !v8 ) + { + v13 = ITYPE_BOW; + goto LABEL_7; + } + if ( v8 == 1 ) + { + v13 = ITYPE_MACE; +LABEL_7: + v9 = v13; + goto LABEL_12; + } + v9 = sendmsg; + } + else + { + v9 = ITYPE_SWORD; + } +LABEL_12: + ++object[v4]._oAnimFrame; + v10 = deltaload == 0; + object[v4]._oSelFlag = 0; + if ( v10 ) + { + v11 = object[v4]._ox; + v12 = object[v4]._oy; + if ( (unsigned char)leveltype <= 1u ) + CreateTypeItem(v11, v12, 0, v9, 0, sendmsg, 0); + else + CreateTypeItem(v11, v12, 1u, v9, 0, sendmsg, 0); + if ( v14 == myplr ) + NetSendCmdParam1(0, CMD_OPERATEOBJ, v3); + } +} +// 5BB1ED: using guessed type char leveltype; +// 676190: using guessed type int deltaload; + +void __fastcall OperateStoryBook(int pnum, int i) +{ + unsigned short v2; // di + int v3; // esi + int v4; // ST04_4 + int v5; // edx + + v2 = i; + v3 = i; + if ( object[i]._oSelFlag && !deltaload && !qtextflag && pnum == myplr ) + { + v4 = object[v3]._oy; + v5 = object[v3]._ox; + object[v3]._oAnimFrame = object[v3]._oVar4; + PlaySfxLoc(IS_ISCROL, v5, v4); + InitQTextMsg(object[v3]._oVar2); + NetSendCmdParam1(0, CMD_OPERATEOBJ, v2); + } +} +// 646D00: using guessed type char qtextflag; +// 676190: using guessed type int deltaload; + +void __fastcall OperateLazStand(int pnum, int i) +{ + int v2; // eax + int v3; // edx + int xx; // [esp+4h] [ebp-8h] + int yy; // [esp+8h] [ebp-4h] + + v2 = i; + if ( object[i]._oSelFlag && !deltaload && !qtextflag && pnum == myplr ) + { + v3 = object[v2]._oy; + ++object[v2]._oAnimFrame; + object[v2]._oSelFlag = 0; + GetSuperItemLoc(object[v2]._ox, v3, &xx, &yy); + SpawnQuestItem(33, xx, yy, 0, 0); + } +} +// 646D00: using guessed type char qtextflag; +// 676190: using guessed type int deltaload; + +void __fastcall OperateObject(int pnum, int i, unsigned char TeleFlag) +{ + int v3; // esi + int v4; // edi + ObjectStruct *v5; // ebx + int v6; // ecx + bool sendmsg; // [esp+Ch] [ebp-4h] + + v3 = pnum; + v4 = i; + sendmsg = pnum == myplr; + v5 = &object[i]; + v6 = v5->_otype; + switch ( v5->_otype ) + { + case OBJ_L1LDOOR: + case OBJ_L1RDOOR: + if ( TeleFlag ) + { + if ( v6 == OBJ_L1LDOOR ) + OperateL1LDoor(v3, i, OBJ_L1LDOOR); + if ( v5->_otype == OBJ_L1RDOOR ) + OperateL1RDoor(v3, v4, 1u); + } + else if ( v3 == myplr ) + { + OperateL1Door(v3, i, 1u); + } + break; + case OBJ_LEVER: + case OBJ_SWITCHSKL: + OperateLever(v3, i); + break; + case OBJ_CHEST1: + case OBJ_CHEST2: + case OBJ_CHEST3: + case OBJ_TCHEST1: + case OBJ_TCHEST2: + case OBJ_TCHEST3: + OperateChest(v3, i, sendmsg); + break; + case OBJ_BOOK2L: + OperateBook(v3, i); + break; + case OBJ_BOOK2R: + OperateSChambBk(v3, i); + break; + case OBJ_L2LDOOR: + case OBJ_L2RDOOR: + if ( TeleFlag ) + { + if ( v6 == OBJ_L2LDOOR ) + OperateL2LDoor(v3, i, 1u); + if ( v5->_otype == OBJ_L2RDOOR ) + OperateL2RDoor(v3, v4, 1u); + } + else if ( v3 == myplr ) + { + OperateL2Door(v3, i, 1u); + } + break; + case OBJ_SARC: + OperateSarc(v3, i, sendmsg); + break; + case OBJ_FLAMELVR: + OperateTrapLvr(i); + break; + case OBJ_SHRINEL: + case OBJ_SHRINER: + OperateShrine(v3, i, IS_MAGIC); + break; + case OBJ_SKELBOOK: + case OBJ_BOOKSTAND: + OperateSkelBook(v3, i, sendmsg); + break; + case OBJ_BOOKCASEL: + case OBJ_BOOKCASER: + OperateBookCase(v3, i, sendmsg); + break; + case OBJ_BLOODFTN: + case OBJ_PURIFYINGFTN: + case OBJ_MURKYFTN: + case OBJ_TEARFTN: + OperateFountains(v3, i); + break; + case OBJ_DECAP: + OperateDecap(v3, i, sendmsg); + break; + case OBJ_BLINDBOOK: + case OBJ_BLOODBOOK: + case OBJ_STEELTOME: + OperateBookLever(v3, i); + break; + case OBJ_PEDISTAL: + OperatePedistal(v3, i); + break; + case OBJ_L3LDOOR: + case OBJ_L3RDOOR: + if ( TeleFlag ) + { + if ( v6 == OBJ_L3LDOOR ) + OperateL3LDoor(v3, i, 1u); + if ( v5->_otype == OBJ_L3RDOOR ) + OperateL3RDoor(v3, v4, 1u); + } + else if ( v3 == myplr ) + { + OperateL3Door(v3, i, 1u); + } + break; + case OBJ_ARMORSTAND: + case OBJ_WARARMOR: + OperateArmorStand(v3, i, sendmsg); + break; + case OBJ_GOATSHRINE: + OperateGoatShrine(v3, i, LS_GSHRINE); + break; + case OBJ_CAULDRON: + OperateCauldron(v3, i, LS_CALDRON); + break; + case OBJ_STORYBOOK: + OperateStoryBook(v3, i); + break; + case OBJ_WARWEAP: + case OBJ_WEAPONRACK: + OperateWeaponRack(v3, i, sendmsg); + break; + case OBJ_MUSHPATCH: + OperateMushPatch(v3, i); + break; + case OBJ_LAZSTAND: + OperateLazStand(v3, i); + break; + case OBJ_SLAINHERO: + OperateSlainHero(v3, i, sendmsg); + break; + case OBJ_SIGNCHEST: + OperateInnSignChest(v3, i); + break; + default: + return; + } +} + +void __fastcall SyncOpL1Door(int pnum, int cmd, int i) +{ + signed int v3; // eax + ObjectStruct *v4; // esi + + if ( pnum != myplr ) + { + v3 = 0; + if ( cmd == 43 ) + { + if ( object[i]._oVar4 ) + return; + v3 = 1; + } + if ( cmd == 44 && object[i]._oVar4 == 1 ) + v3 = 1; + if ( v3 ) + { + v4 = &object[i]; + if ( v4->_otype == 1 ) + OperateL1LDoor(-1, i, 0); + if ( v4->_otype == OBJ_L1RDOOR ) + OperateL1RDoor(-1, i, 0); + } + } +} + +void __fastcall SyncOpL2Door(int pnum, int cmd, int i) +{ + signed int v3; // eax + ObjectStruct *v4; // esi + + if ( pnum != myplr ) + { + v3 = 0; + if ( cmd == 43 ) + { + if ( object[i]._oVar4 ) + return; + v3 = 1; + } + if ( cmd == 44 && object[i]._oVar4 == 1 ) + v3 = 1; + if ( v3 ) + { + v4 = &object[i]; + if ( v4->_otype == OBJ_L2LDOOR ) + OperateL2LDoor(-1, i, 0); + if ( v4->_otype == OBJ_L2RDOOR ) + OperateL2RDoor(-1, i, 0); + } + } +} + +void __fastcall SyncOpL3Door(int pnum, int cmd, int i) +{ + signed int v3; // eax + ObjectStruct *v4; // esi + + if ( pnum != myplr ) + { + v3 = 0; + if ( cmd == 43 ) + { + if ( object[i]._oVar4 ) + return; + v3 = 1; + } + if ( cmd == 44 && object[i]._oVar4 == 1 ) + v3 = 1; + if ( v3 ) + { + v4 = &object[i]; + if ( v4->_otype == OBJ_L3LDOOR ) + OperateL3LDoor(-1, i, 0); + if ( v4->_otype == OBJ_L3RDOOR ) + OperateL3RDoor(-1, i, 0); + } + } +} + +void __fastcall SyncOpObject(int pnum, int cmd, int i) +{ + switch ( object[i]._otype ) + { + case OBJ_L1LDOOR: + case OBJ_L1RDOOR: + SyncOpL1Door(pnum, cmd, i); + break; + case OBJ_LEVER: + case OBJ_SWITCHSKL: + OperateLever(pnum, i); + break; + case OBJ_CHEST1: + case OBJ_CHEST2: + case OBJ_CHEST3: + case OBJ_TCHEST1: + case OBJ_TCHEST2: + case OBJ_TCHEST3: + OperateChest(pnum, i, 0); + break; + case OBJ_L2LDOOR: + case OBJ_L2RDOOR: + SyncOpL2Door(pnum, cmd, i); + break; + case OBJ_SARC: + OperateSarc(pnum, i, 0); + break; + case OBJ_SHRINEL: + case OBJ_SHRINER: + OperateShrine(pnum, i, IS_MAGIC); + break; + case OBJ_SKELBOOK: + case OBJ_BOOKSTAND: + OperateSkelBook(pnum, i, 0); + break; + case OBJ_BOOKCASEL: + case OBJ_BOOKCASER: + OperateBookCase(pnum, i, 0); + break; + case OBJ_DECAP: + OperateDecap(pnum, i, 0); + break; + case OBJ_BLINDBOOK: + case OBJ_BLOODBOOK: + case OBJ_STEELTOME: + OperateBookLever(pnum, i); + break; + case OBJ_PEDISTAL: + OperatePedistal(pnum, i); + break; + case OBJ_L3LDOOR: + case OBJ_L3RDOOR: + SyncOpL3Door(pnum, cmd, i); + break; + case OBJ_ARMORSTAND: + case OBJ_WARARMOR: + OperateArmorStand(pnum, i, 0); + break; + case OBJ_GOATSHRINE: + OperateGoatShrine(pnum, i, LS_GSHRINE); + break; + case OBJ_CAULDRON: + OperateCauldron(pnum, i, LS_CALDRON); + break; + case OBJ_MURKYFTN: + case OBJ_TEARFTN: + OperateFountains(pnum, i); + break; + case OBJ_STORYBOOK: + OperateStoryBook(pnum, i); + break; + case OBJ_WARWEAP: + case OBJ_WEAPONRACK: + OperateWeaponRack(pnum, i, 0); + break; + case OBJ_MUSHPATCH: + OperateMushPatch(pnum, i); + break; + case OBJ_SLAINHERO: + OperateSlainHero(pnum, i, 0); + break; + case OBJ_SIGNCHEST: + OperateInnSignChest(pnum, i); + break; + default: + return; + } +} + +void __fastcall BreakCrux(int i) +{ + int v1; // esi + int v2; // edi + int v3; // edx + signed int v4; // eax + int v5; // ecx + int v6; // ebx + + v1 = i; + v2 = nobjects; + object[v1]._oBreak = -1; + object[v1]._oSelFlag = 0; + v3 = 0; + v4 = 1; + object[v1]._oAnimFlag = 1; + object[v1]._oAnimFrame = 1; + object[v1]._oAnimDelay = 1; + object[v1]._oSolidFlag = 1; + object[v1]._oMissFlag = 1; + if ( v2 <= 0 ) + goto LABEL_15; + do + { + v5 = objectactive[v3]; + v6 = object[v5]._otype; + if ( (v6 == OBJ_CRUX1 || v6 == OBJ_CRUX2 || v6 == OBJ_CRUX3) + && object[v1]._oVar8 == object[v5]._oVar8 + && object[v5]._oBreak != -1 ) + { + v4 = 0; + } + ++v3; + } + while ( v3 < v2 ); + if ( v4 ) + { +LABEL_15: + if ( !deltaload ) + PlaySfxLoc(IS_LEVER, object[v1]._ox, object[v1]._oy); + ObjChangeMap(object[v1]._oVar1, object[v1]._oVar2, object[v1]._oVar3, object[v1]._oVar4); + } +} +// 676190: using guessed type int deltaload; + +void __fastcall BreakBarrel(int pnum, int i, int dam, unsigned char forcebreak, int sendmsg) +{ + int v5; // esi + bool v6; // zf + int v7; // eax + int v8; // edx + int v9; // eax + int v10; // eax + int v11; // eax + char v12; // al + char v13; // al + int v14; // edx + int v15; // [esp-4h] [ebp-24h] + short param2; // [esp+Ch] [ebp-14h] + int param1; // [esp+10h] [ebp-10h] + int v18; // [esp+14h] [ebp-Ch] + int *v19; // [esp+18h] [ebp-8h] + int v20; // [esp+1Ch] [ebp-4h] + int forcebreaka; // [esp+2Ch] [ebp+Ch] + + param2 = i; + v5 = i; + param1 = pnum; + if ( object[i]._oSelFlag ) + { + if ( forcebreak ) + { + object[v5]._oVar1 = 0; + } + else + { + object[v5]._oVar1 -= dam; + if ( pnum != myplr && object[v5]._oVar1 <= 0 ) + object[v5]._oVar1 = 1; + } + if ( object[v5]._oVar1 <= 0 ) + { + object[v5]._oBreak = -1; + v6 = deltaload == 0; + object[v5]._oVar1 = 0; + object[v5]._oAnimFlag = 1; + object[v5]._oAnimFrame = 1; + object[v5]._oAnimDelay = 1; + object[v5]._oSolidFlag = 0; + object[v5]._oMissFlag = 1; + object[v5]._oSelFlag = 0; + object[v5]._oPreFlag = 1; + if ( v6 ) + { + v8 = object[v5]._ox; + v15 = object[v5]._oy; + if ( object[v5]._otype == OBJ_BARRELEX ) + { + PlaySfxLoc(IS_BARLFIRE, v8, v15); + v9 = object[v5]._oy; + v20 = v9 - 1; + if ( v9 - 1 <= v9 + 1 ) + { + do + { + v10 = object[v5]._ox; + v18 = v10 - 1; + if ( v10 - 1 <= v10 + 1 ) + { + forcebreaka = 112 * (v10 - 1) + v20; + v19 = (int *)((char *)dMonster + 4 * forcebreaka); + do + { + v11 = *v19; + if ( *v19 > 0 ) + MonsterTrapHit(v11 - 1, 1, 4, 0, 1, 0); + v12 = dPlayer[0][forcebreaka]; + if ( v12 > 0 ) + PlayerMHit(v12 - 1, -1, 0, 8, 16, 1, 0, 0); + v13 = dObject[0][forcebreaka]; + if ( v13 > 0 ) + { + v14 = v13 - 1; + if ( object[v14]._otype == OBJ_BARRELEX && object[v14]._oBreak != -1 ) + BreakBarrel(param1, v14, dam, 1u, sendmsg); + } + ++v18; + v19 += 112; + forcebreaka += 112; + } + while ( v18 <= object[v5]._ox + 1 ); + } + ++v20; + } + while ( v20 <= object[v5]._oy + 1 ); + } + } + else + { + PlaySfxLoc(IS_BARREL, v8, v15); + SetRndSeed(object[v5]._oRndSeed); + if ( object[v5]._oVar2 <= 1 ) + { + if ( object[v5]._oVar3 ) + CreateRndItem(object[v5]._ox, object[v5]._oy, 0, sendmsg, 0); + else + CreateRndUseful(param1, object[v5]._ox, object[v5]._oy, sendmsg); + } + if ( object[v5]._oVar2 >= 8 ) + SpawnSkeleton(object[v5]._oVar4, object[v5]._ox, object[v5]._oy); + } + if ( param1 == myplr ) + NetSendCmdParam2(0, CMD_BREAKOBJ, param1, param2); + } + else + { + v7 = object[v5]._oAnimLen; + object[v5]._oAnimCnt = 0; + object[v5]._oAnimFrame = v7; + object[v5]._oAnimDelay = 1000; + } + } + else if ( !deltaload ) + { + PlaySfxLoc(IS_IBOW, object[v5]._ox, object[v5]._oy); + } + } +} +// 676190: using guessed type int deltaload; + +void __fastcall BreakObject(int pnum, int oi) +{ + int v2; // ebx + int v3; // ebp + int v4; // esi + int v5; // edi + int v6; // ecx + int v7; // ecx + int v8; // eax + + v2 = pnum; + v3 = oi; + if ( pnum == -1 ) + { + v7 = 10; + } + else + { + v4 = pnum; + v5 = plr[v2]._pIMinDam; + v6 = v5 + random(163, plr[v2]._pIMaxDam - v5 + 1); + v7 = plr[v4]._pIBonusDamMod + plr[v4]._pDamageMod + v6 * plr[v4]._pIBonusDam / 100 + v6; + } + v8 = object[v3]._otype; + if ( v8 >= OBJ_CRUX1 ) + { + if ( v8 <= OBJ_CRUX3 ) + { + BreakCrux(v3); + } + else if ( v8 > OBJ_WEAPRACK && v8 <= OBJ_BARRELEX ) + { + BreakBarrel(v2, v3, v7, 0, 1); + } + } +} + +void __fastcall SyncBreakObj(int pnum, int oi) +{ + int v2; // eax + + v2 = object[oi]._otype; + if ( v2 >= OBJ_BARREL && v2 <= OBJ_BARRELEX ) + BreakBarrel(pnum, oi, 0, 1u, 0); +} + +void __fastcall SyncL1Doors(int i) +{ + int v1; // ebx + int v2; // eax + int v3; // esi + int v4; // edi + bool v5; // zf + + v1 = i; + v2 = i; + if ( object[i]._oVar4 ) + { + v3 = object[v2]._oy; + v4 = object[v2]._ox; + v5 = object[v2]._otype == 1; + object[v2]._oMissFlag = 1; + object[v2]._oSelFlag = 2; + if ( v5 ) + { + if ( object[v2]._oVar1 == 214 ) + ObjSetMicro(v4, v3, 408); + else + ObjSetMicro(v4, v3, 393); + dArch[v4][v3] = 7; + objects_set_door_piece(v4 - 1, v3--); + } + else + { + ObjSetMicro(v4, v3, 395); + dArch[v4][v3] = 8; + objects_set_door_piece(v4--, v3 - 1); + } + DoorSet(v1, v4, v3); + } + else + { + object[v2]._oMissFlag = 0; + } +} + +void __fastcall SyncCrux(int i) +{ + signed int v1; // ebx + int v2; // edx + int v3; // eax + int v4; // esi + + v1 = 1; + v2 = 0; + if ( nobjects <= 0 ) + goto LABEL_13; + do + { + v3 = objectactive[v2]; + v4 = object[v3]._otype; + if ( (v4 == OBJ_CRUX1 || v4 == OBJ_CRUX2 || v4 == OBJ_CRUX3) + && object[i]._oVar8 == object[v3]._oVar8 + && object[v3]._oBreak != -1 ) + { + v1 = 0; + } + ++v2; + } + while ( v2 < nobjects ); + if ( v1 ) +LABEL_13: + ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); +} + +void __fastcall SyncLever(int i) +{ + int v1; // ecx + + v1 = i; + if ( !object[v1]._oSelFlag ) + ObjChangeMap(object[v1]._oVar1, object[v1]._oVar2, object[v1]._oVar3, object[v1]._oVar4); +} + +void __fastcall SyncQSTLever(int i) +{ + int v1; // esi + int v2; // edx + int v3; // ecx + int v4; // ST04_4 + char v5; // bl + int v6; // ST00_4 + + v1 = i; + if ( object[i]._oAnimFrame == object[i]._oVar6 ) + { + ObjChangeMapResync(object[v1]._oVar1, object[v1]._oVar2, object[v1]._oVar3, object[v1]._oVar4); + if ( object[v1]._otype == OBJ_BLINDBOOK ) + { + v2 = object[v1]._oVar2; + v3 = object[v1]._oVar1; + v4 = object[v1]._oVar4; + v5 = TransVal; + v6 = object[v1]._oVar3; + TransVal = 9; + DRLG_MRectTrans(v3, v2, v6, v4); + TransVal = v5; + } + } +} +// 5A5590: using guessed type char TransVal; + +void __fastcall SyncPedistal(int i) +{ + int v1; // esi + unsigned char *v2; // esi + + v1 = i; + if ( object[i]._oVar6 == 1 ) + ObjChangeMapResync(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7); + if ( object[v1]._oVar6 == 2 ) + { + ObjChangeMapResync(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7); + ObjChangeMapResync(setpc_x + 6, setpc_y + 3, setpc_x + setpc_w, setpc_y + 7); + } + if ( object[v1]._oVar6 == 3 ) + { + ObjChangeMapResync(object[v1]._oVar1, object[v1]._oVar2, object[v1]._oVar3, object[v1]._oVar4); + v2 = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", 0); + LoadMapObjs(v2, 2 * setpc_x, 2 * setpc_y); + mem_free_dbg(v2); + } +} +// 5CF334: using guessed type int setpc_w; + +void __fastcall SyncL2Doors(int i) +{ + int v1; // eax + int v2; // esi + int v3; // ecx + int v4; // edx + int v5; // eax + + v1 = i; + v2 = object[i]._oVar4; + if ( v2 ) + object[v1]._oMissFlag = 1; + else + object[v1]._oMissFlag = 0; + v3 = object[v1]._ox; + v4 = object[v1]._oy; + object[v1]._oSelFlag = 2; + v5 = object[v1]._otype; + if ( v5 != OBJ_L2LDOOR ) + goto LABEL_18; + if ( !v2 ) + { + ObjSetMicro(v3, v4, 538); + return; + } + if ( v2 != 1 && v2 != 2 ) + { +LABEL_18: + if ( v5 == OBJ_L2RDOOR ) + { + if ( v2 ) + { + if ( v2 == 1 || v2 == 2 ) + ObjSetMicro(v3, v4, 17); + } + else + { + ObjSetMicro(v3, v4, 540); + } + } + } + else + { + ObjSetMicro(v3, v4, 13); + } +} + +void __fastcall SyncL3Doors(int i) +{ + int v1; // eax + int v2; // esi + int v3; // ecx + int v4; // edx + int v5; // ebx + int v6; // eax + + v1 = i; + v2 = object[i]._otype; + v3 = object[i]._ox; + v4 = object[v1]._oy; + object[v1]._oMissFlag = 1; + object[v1]._oSelFlag = 2; + if ( v2 != OBJ_L3LDOOR ) + goto LABEL_15; + if ( !object[v1]._oVar4 ) + { + ObjSetMicro(v3, v4, 531); + return; + } + v5 = object[v1]._oVar4; + if ( v5 != 1 && v5 != 2 ) + { +LABEL_15: + if ( v2 == OBJ_L3RDOOR ) + { + if ( object[v1]._oVar4 ) + { + v6 = object[v1]._oVar4; + if ( v6 == 1 || v6 == 2 ) + ObjSetMicro(v3, v4, 541); + } + else + { + ObjSetMicro(v3, v4, 534); + } + } + } + else + { + ObjSetMicro(v3, v4, 538); + } +} + +void __fastcall SyncObjectAnim(int o) +{ + int v1; // edx + int v2; // ebx + int v3; // esi + + v1 = object[o]._otype; + v2 = ObjFileList[0]; + v3 = 0; + while ( v2 != (char)AllObjects[object[o]._otype].ofindex ) + v2 = ObjFileList[v3++ + 1]; + object[o]._oAnimData = pObjCels[v3]; + if ( v1 <= OBJ_BOOK2R ) + { + if ( v1 != OBJ_BOOK2R ) + { + if ( v1 > OBJ_L1LIGHT ) + { + if ( v1 <= OBJ_L1RDOOR ) + { + SyncL1Doors(o); + } + else + { + if ( v1 == OBJ_LEVER ) + goto LABEL_30; + if ( v1 > OBJ_SKSTICK5 ) + { + if ( v1 <= OBJ_CRUX3 ) + { + SyncCrux(o); + return; + } + if ( v1 == OBJ_BOOK2L || v1 == OBJ_SWITCHSKL ) +LABEL_30: + SyncLever(o); + } + } + } + return; + } +LABEL_24: + SyncQSTLever(o); + return; + } + if ( v1 >= OBJ_L2LDOOR ) + { + if ( v1 <= OBJ_L2RDOOR ) + { + SyncL2Doors(o); + return; + } + if ( v1 == OBJ_BLINDBOOK ) + goto LABEL_24; + if ( v1 == OBJ_PEDISTAL ) + { + SyncPedistal(o); + return; + } + if ( v1 > OBJ_PEDISTAL ) + { + if ( v1 <= OBJ_L3RDOOR ) + { + SyncL3Doors(o); + return; + } + if ( v1 == OBJ_STEELTOME ) + goto LABEL_24; + } + } +} + +void __fastcall GetObjectStr(int i) +{ + int v1; // edi + + v1 = i; + switch ( object[i]._otype ) + { + case OBJ_L1LDOOR: + case OBJ_L1RDOOR: + case OBJ_L2LDOOR: + case OBJ_L2RDOOR: + case OBJ_L3LDOOR: + case OBJ_L3RDOOR: + if ( object[v1]._oVar4 == 1 ) + strcpy(infostr, "Open Door"); + if ( !object[v1]._oVar4 ) + strcpy(infostr, "Closed Door"); + if ( object[v1]._oVar4 == 2 ) + strcpy(infostr, "Blocked Door"); + break; + case OBJ_LEVER: + case OBJ_FLAMELVR: + strcpy(infostr, "Lever"); + break; + case OBJ_CHEST1: + case OBJ_TCHEST1: + strcpy(infostr, "Small Chest"); + break; + case OBJ_CHEST2: + case OBJ_TCHEST2: + strcpy(infostr, "Chest"); + break; + case OBJ_CHEST3: + case OBJ_TCHEST3: + case OBJ_SIGNCHEST: + strcpy(infostr, "Large Chest"); + break; + case OBJ_CRUX1: + case OBJ_CRUX2: + case OBJ_CRUX3: + strcpy(infostr, "Crucified Skeleton"); + break; + case OBJ_BOOK2L: + if ( setlevel ) + { + if ( setlvlnum == SL_BONECHAMB ) + { + strcpy(infostr, "Ancient Tome"); + } + else if ( setlvlnum == SL_VILEBETRAYER ) + { + strcpy(infostr, "Book of Vileness"); + } + } + break; + case OBJ_SWITCHSKL: + strcpy(infostr, "Skull Lever"); + break; + case OBJ_BOOK2R: + strcpy(infostr, "Mythical Book"); + break; + case OBJ_SARC: + strcpy(infostr, "Sarcophagus"); + break; + case OBJ_BOOKSHELF: + strcpy(infostr, "Bookshelf"); + break; + case OBJ_BARREL: + case OBJ_BARRELEX: + strcpy(infostr, "Barrel"); + break; + case OBJ_SHRINEL: + case OBJ_SHRINER: + sprintf(tempstr, "%s Shrine", shrinestrs[object[v1]._oVar1]); + strcpy(infostr, tempstr); + break; + case OBJ_SKELBOOK: + strcpy(infostr, "Skeleton Tome"); + break; + case OBJ_BOOKCASEL: + case OBJ_BOOKCASER: + strcpy(infostr, "Bookcase"); + break; + case OBJ_BOOKSTAND: + strcpy(infostr, "Library Book"); + break; + case OBJ_BLOODFTN: + strcpy(infostr, "Blood Fountain"); + break; + case OBJ_DECAP: + strcpy(infostr, "Decapitated Body"); + break; + case OBJ_BLINDBOOK: + strcpy(infostr, "Book of the Blind"); + break; + case OBJ_BLOODBOOK: + strcpy(infostr, "Book of Blood"); + break; + case OBJ_PEDISTAL: + strcpy(infostr, "Pedestal of Blood"); + break; + case OBJ_PURIFYINGFTN: + strcpy(infostr, "Purifying Spring"); + break; + case OBJ_ARMORSTAND: + case OBJ_WARARMOR: + strcpy(infostr, "Armor"); + break; + case OBJ_GOATSHRINE: + strcpy(infostr, "Goat Shrine"); + break; + case OBJ_CAULDRON: + strcpy(infostr, "Cauldron"); + break; + case OBJ_MURKYFTN: + strcpy(infostr, "Murky Pool"); + break; + case OBJ_TEARFTN: + strcpy(infostr, "Fountain of Tears"); + break; + case OBJ_STORYBOOK: + strcpy(infostr, StoryBookName[object[v1]._oVar3]); + break; + case OBJ_STEELTOME: + strcpy(infostr, "Steel Tome"); + break; + case OBJ_WARWEAP: + case OBJ_WEAPONRACK: + strcpy(infostr, "Weapon Rack"); + break; + case OBJ_MUSHPATCH: + strcpy(infostr, "Mushroom Patch"); + break; + case OBJ_LAZSTAND: + strcpy(infostr, "Vile Stand"); + break; + case OBJ_SLAINHERO: + strcpy(infostr, "Slain Hero"); + break; + default: + break; + } + if ( _LOBYTE(plr[myplr]._pClass) == 1 ) + { + if ( object[v1]._oTrapFlag ) + { + sprintf(tempstr, "Trapped %s", infostr); + strcpy(infostr, tempstr); + _LOBYTE(infoclr) = 2; + } + } +} +// 4B883C: using guessed type int infoclr; +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; diff --git a/Source/objects.h b/Source/objects.h new file mode 100644 index 000000000..3fb9f29eb --- /dev/null +++ b/Source/objects.h @@ -0,0 +1,163 @@ +//HEADER_GOES_HERE +#ifndef __OBJECTS_H__ +#define __OBJECTS_H__ + +extern int trapid; // weak +extern int trapdir; // weak +extern unsigned char *pObjCels[40]; +extern char ObjFileList[40]; +extern int objectactive[MAXOBJECTS]; +extern int nobjects; // idb +extern int leverid; // idb +extern int objectavail[MAXOBJECTS]; +extern ObjectStruct object[MAXOBJECTS]; +extern int InitObjFlag; // weak +extern int numobjfiles; // weak + +void __cdecl InitObjectGFX(); +void __cdecl FreeObjectGFX(); +bool __fastcall RndLocOk(int xp, int yp); +void __fastcall InitRndLocObj(int min, int max, int objtype); +void __fastcall InitRndLocBigObj(int min, int max, int objtype); +void __fastcall InitRndLocObj5x5(int min, int max, int objtype); +void __cdecl ClrAllObjects(); +void __cdecl AddTortures(); +void __cdecl AddCandles(); +void __fastcall AddBookLever(int lx1, int ly1, int lx2, int ly2, int x1, int y1, int x2, int y2, int msg); +void __cdecl InitRndBarrels(); +void __fastcall AddL1Objs(int x1, int y1, int x2, int y2); +void __fastcall AddL2Objs(int x1, int y1, int x2, int y2); +void __fastcall AddL3Objs(int x1, int y1, int x2, int y2); +bool __fastcall WallTrapLocOk(int xp, int yp); +void __cdecl AddL2Torches(); +bool __fastcall TorchLocOK(int xp, int yp); +void __cdecl AddObjTraps(); +void __cdecl AddChestTraps(); +void __fastcall LoadMapObjects(unsigned char *pMap, int startx, int starty, int x1, int y1, int w, int h, int leveridx); +void __fastcall LoadMapObjs(unsigned char *pMap, int startx, int starty); +void __cdecl AddDiabObjs(); +void __cdecl AddStoryBooks(); +void __fastcall AddHookedBodies(int freq); +void __cdecl AddL4Goodies(); +void __cdecl AddLazStand(); +void __cdecl InitObjects(); +void __fastcall SetMapObjects(unsigned char *pMap, int startx, int starty); +void __fastcall DeleteObject(int oi, int i); +void __fastcall SetupObject(int i, int x, int y, int ot); +void __fastcall SetObjMapRange(int i, int x1, int y1, int x2, int y2, int v); +void __fastcall SetBookMsg(int i, int msg); +void __fastcall AddL1Door(int i, int x, int y, int ot); +void __fastcall AddSCambBook(int i); +void __fastcall AddChest(int i, int t); +void __fastcall AddL2Door(int i, int x, int y, int ot); +void __fastcall AddL3Door(int i, int x, int y, int ot); +void __fastcall AddSarc(int i); +void __fastcall AddFlameTrap(int i); +void __fastcall AddFlameLvr(int i); +void __fastcall AddTrap(int i); +void __fastcall AddObjLight(int i, int r); +void __fastcall AddBarrel(int i); +void __fastcall AddShrine(int i); +void __fastcall AddBookcase(int i); +void __fastcall AddPurifyingFountain(int i); +void __fastcall AddArmorStand(int i); +void __fastcall AddDecap(int i); +void __fastcall AddVilebook(int i); +void __fastcall AddMagicCircle(int i); +void __fastcall AddBookstand(int i); +void __fastcall AddPedistal(int i); +void __fastcall AddStoryBook(int i); +void __fastcall AddWeaponRack(int i); +void __fastcall AddTorturedBody(int i); +void __fastcall GetRndObjLoc(int randarea, int *xx, int *yy); +void __cdecl AddMushPatch(); +void __cdecl AddSlainHero(); +void __fastcall AddObject(int ot, int ox, int oy); +void __fastcall Obj_Light(int i, int lr); +void __fastcall Obj_Circle(int i); +void __fastcall Obj_StopAnim(int i); +void __fastcall Obj_Door(int i); +void __fastcall Obj_Sarc(int i); +void __fastcall ActivateTrapLine(int ttype, int tid); +void __fastcall Obj_FlameTrap(int i); +void __fastcall Obj_Trap(int i); +void __fastcall Obj_BCrossDamage(int i); +void __cdecl ProcessObjects(); +void __fastcall ObjSetMicro(int dx, int dy, int pn); +void __fastcall objects_set_door_piece(int x, int y); +void __fastcall ObjSetMini(int x, int y, int v); +void __fastcall ObjL1Special(int x1, int y1, int x2, int y2); +void __fastcall ObjL2Special(int x1, int y1, int x2, int y2); +void __fastcall DoorSet(int oi, int dx, int dy); +void __cdecl RedoPlayerVision(); +void __fastcall OperateL1RDoor(int pnum, int oi, unsigned char sendflag); +void __fastcall OperateL1LDoor(int pnum, int oi, unsigned char sendflag); +void __fastcall OperateL2RDoor(int pnum, int oi, unsigned char sendflag); +void __fastcall OperateL2LDoor(int pnum, int oi, unsigned char sendflag); +void __fastcall OperateL3RDoor(int pnum, int oi, unsigned char sendflag); +void __fastcall OperateL3LDoor(int pnum, int oi, unsigned char sendflag); +void __fastcall MonstCheckDoors(int m); +void __fastcall ObjChangeMap(int x1, int y1, int x2, int y2); +void __fastcall ObjChangeMapResync(int x1, int y1, int x2, int y2); +void __fastcall OperateL1Door(int pnum, int i, unsigned char sendflag); +void __fastcall OperateLever(int pnum, int i); +void __fastcall OperateBook(int pnum, int i); +void __fastcall OperateBookLever(int pnum, int i); +void __fastcall OperateSChambBk(int pnum, int i); +void __fastcall OperateChest(int pnum, int i, unsigned char sendmsg); +void __fastcall OperateMushPatch(int pnum, int i); +void __fastcall OperateInnSignChest(int pnum, int i); +void __fastcall OperateSlainHero(int pnum, int i, unsigned char sendmsg); +void __fastcall OperateTrapLvr(int i); +void __fastcall OperateSarc(int pnum, int i, unsigned char sendmsg); +void __fastcall OperateL2Door(int pnum, int i, unsigned char sendflag); +void __fastcall OperateL3Door(int pnum, int i, unsigned char sendflag); +void __fastcall OperatePedistal(int pnum, int i); +void __fastcall TryDisarm(int pnum, int i); +int __fastcall ItemMiscIdIdx(int imiscid); +void __fastcall OperateShrine(int pnum, int i, int sType); +void __fastcall OperateSkelBook(int pnum, int i, unsigned char sendmsg); +void __fastcall OperateBookCase(int pnum, int i, unsigned char sendmsg); +void __fastcall OperateDecap(int pnum, int i, unsigned char sendmsg); +void __fastcall OperateArmorStand(int pnum, int i, unsigned char sendmsg); +int __fastcall FindValidShrine(int i); +void __fastcall OperateGoatShrine(int pnum, int i, int sType); +void __fastcall OperateCauldron(int pnum, int i, int sType); +bool __fastcall OperateFountains(int pnum, int i); +void __fastcall OperateWeaponRack(int pnum, int i, unsigned char sendmsg); +void __fastcall OperateStoryBook(int pnum, int i); +void __fastcall OperateLazStand(int pnum, int i); +void __fastcall OperateObject(int pnum, int i, unsigned char TeleFlag); +void __fastcall SyncOpL1Door(int pnum, int cmd, int i); +void __fastcall SyncOpL2Door(int pnum, int cmd, int i); +void __fastcall SyncOpL3Door(int pnum, int cmd, int i); +void __fastcall SyncOpObject(int pnum, int cmd, int i); +void __fastcall BreakCrux(int i); +void __fastcall BreakBarrel(int pnum, int i, int dam, unsigned char forcebreak, int sendmsg); +void __fastcall BreakObject(int pnum, int oi); +void __fastcall SyncBreakObj(int pnum, int oi); +void __fastcall SyncL1Doors(int i); +void __fastcall SyncCrux(int i); +void __fastcall SyncLever(int i); +void __fastcall SyncQSTLever(int i); +void __fastcall SyncPedistal(int i); +void __fastcall SyncL2Doors(int i); +void __fastcall SyncL3Doors(int i); +void __fastcall SyncObjectAnim(int o); +void __fastcall GetObjectStr(int i); + +/* rdata */ + +extern int ObjTypeConv[113]; +extern ObjDataStruct AllObjects[99]; +extern char *ObjMasterLoadList[56]; +extern int bxadd[8]; +extern int byadd[8]; +extern char *shrinestrs[NUM_SHRINETYPE]; +extern unsigned char shrinemin[NUM_SHRINETYPE]; +extern unsigned char shrinemax[NUM_SHRINETYPE]; +extern unsigned char shrineavail[NUM_SHRINETYPE]; +extern char *StoryBookName[9]; +extern int StoryText[3][3]; + +#endif /* __OBJECTS_H__ */ diff --git a/Source/pack.cpp b/Source/pack.cpp new file mode 100644 index 000000000..a5c601941 --- /dev/null +++ b/Source/pack.cpp @@ -0,0 +1,289 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int pack_cpp_init_value; // weak + +const int pack_inf = 0x7F800000; // weak + +struct pack_cpp_init +{ + pack_cpp_init() + { + pack_cpp_init_value = pack_inf; + } +} _pack_cpp_init; +// 47F168: using guessed type int pack_inf; +// 67D7C8: using guessed type int pack_cpp_init_value; + +void __fastcall PackPlayer(PkPlayerStruct *pPack, int pnum, bool manashield) +{ + PlayerStruct *pPlayer; // edi + int i; // [esp+8h] [ebp-Ch] + ItemStruct *pi; // [esp+Ch] [ebp-8h] + PkItemStruct *pki; // [esp+10h] [ebp-4h] + + memset(pPack, 0, 0x4F2); + pPlayer = &plr[pnum]; + pPack->destAction = pPlayer->destAction; + pPack->destParam1 = pPlayer->destParam1; + pPack->destParam2 = pPlayer->destParam2; + pPack->plrlevel = pPlayer->plrlevel; + pPack->px = pPlayer->WorldX; + pPack->py = pPlayer->WorldY; + pPack->targx = pPlayer->_ptargx; + pPack->targy = pPlayer->_ptargy; + strcpy(pPack->pName, pPlayer->_pName); + pPack->pClass = pPlayer->_pClass; + pPack->pBaseStr = pPlayer->_pBaseStr; + pPack->pBaseMag = pPlayer->_pBaseMag; + pPack->pBaseDex = pPlayer->_pBaseDex; + pPack->pBaseVit = pPlayer->_pBaseVit; + pPack->pLevel = pPlayer->_pLevel; + pPack->pStatPts = pPlayer->_pStatPts; + pPack->pExperience = pPlayer->_pExperience; + pPack->pGold = pPlayer->_pGold; + pPack->pHPBase = pPlayer->_pHPBase; + pPack->pMaxHPBase = pPlayer->_pMaxHPBase; + pPack->pManaBase = pPlayer->_pManaBase; + pPack->pMaxManaBase = pPlayer->_pMaxManaBase; + pPack->pMemSpells = pPlayer->_pMemSpells[0]; + pPack->pMemSpells2 = pPlayer->_pMemSpells[1]; + + for(i = 0; i < 37; i++) + pPack->pSplLvl[i] = pPlayer->_pSplLvl[i]; + + pki = pPack->InvBody; + pi = pPlayer->InvBody; + + for(i = 0; i < 7; i++) + PackItem(pki++, pi++); + + pki = pPack->InvList; + pi = pPlayer->InvList; + + for(i = 0; i < 40; i++) + PackItem(pki++, pi++); + + for(i = 0; i < 40; i++) + pPack->InvGrid[i] = pPlayer->InvGrid[i]; + + pPack->_pNumInv = pPlayer->_pNumInv; + pki = pPack->SpdList; + pi = pPlayer->SpdList; + + for(i = 0; i < 8; i++) + PackItem(pki++, pi++); + + pPack->pDiabloKillLevel = pPlayer->pDiabloKillLevel; + + if ( gbMaxPlayers == 1 || manashield ) + pPack->pManaShield = pPlayer->pManaShield; + else + pPack->pManaShield = 0; +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall PackItem(PkItemStruct *id, ItemStruct *is) +{ + short v2; // ax + short v3; // bx + + if ( is->_itype == -1 ) + { + id->idx = -1; + } + else + { + id->idx = is->IDidx; + if ( is->IDidx == IDI_EAR ) + { + _LOBYTE(v2) = 0; + _LOBYTE(v3) = 0; + _HIBYTE(v2) = is->_iName[7]; + id->iCreateInfo = is->_iName[8] | v2; + id->iSeed = is->_iName[12] | ((is->_iName[11] | ((is->_iName[10] | (is->_iName[9] << 8)) << 8)) << 8); + id->bId = is->_iName[13]; + id->bDur = is->_iName[14]; + id->bMDur = is->_iName[15]; + id->bCh = is->_iName[16]; + id->bMCh = is->_iName[17]; + _HIBYTE(v3) = is->_iName[18]; + id->wValue = _LOWORD(is->_ivalue) | v3 | ((_LOWORD(is->_iCurs) - 19) << 6); + id->dwBuff = is->_iName[22] | ((is->_iName[21] | ((is->_iName[20] | (is->_iName[19] << 8)) << 8)) << 8); + } + else + { + id->iSeed = is->_iSeed; + id->iCreateInfo = is->_iCreateInfo; + id->bId = _LOBYTE(is->_iIdentified) + 2 * is->_iMagical; + id->bDur = is->_iDurability; + id->bMDur = is->_iMaxDur; + id->bCh = is->_iCharges; + id->bMCh = is->_iMaxCharges; + if ( !is->IDidx ) + id->wValue = is->_ivalue; + } + } +} + +void __fastcall VerifyGoldSeeds(PlayerStruct *pPlayer) +{ + int i; // ebp + int j; // ecx + + for(i = 0; i < pPlayer->_pNumInv; i++) + { + if ( pPlayer->InvList[i].IDidx == IDI_GOLD && pPlayer->_pNumInv > 0 ) + { + for(j = 0; j < pPlayer->_pNumInv; j++) + { + if ( i != j ) + { + if ( pPlayer->InvList[j].IDidx == IDI_GOLD && pPlayer->InvList[i]._iSeed == pPlayer->InvList[j]._iSeed ) + { + pPlayer->InvList[i]._iSeed = GetRndSeed(); + j = -1; + } + } + } + } + } +} + +void __fastcall UnPackPlayer(PkPlayerStruct *pPack, int pnum, bool killok) +{ + PlayerStruct *pPlayer; // esi + signed int v6; // eax + int i; // [esp+10h] [ebp-8h] + ItemStruct *pi; // [esp+14h] [ebp-4h] + PkItemStruct *pki; // [esp+20h] [ebp+8h] + + pPlayer = &plr[pnum]; + ClearPlrRVars(&plr[pnum]); + pPlayer->WorldX = (unsigned char)pPack->px; + pPlayer->WorldY = (unsigned char)pPack->py; + pPlayer->_px = (unsigned char)pPack->px; + pPlayer->_py = (unsigned char)pPack->py; + pPlayer->_ptargx = (unsigned char)pPack->targx; + pPlayer->_ptargy = (unsigned char)pPack->targy; + pPlayer->plrlevel = (unsigned char)pPack->plrlevel; + ClrPlrPath(pnum); + pPlayer->destAction = -1; + strcpy(pPlayer->_pName, pPack->pName); + _LOBYTE(pPlayer->_pClass) = pPack->pClass; + InitPlayer(pnum, TRUE); + pPlayer->_pBaseStr = (unsigned char)pPack->pBaseStr; + pPlayer->_pStrength = (unsigned char)pPack->pBaseStr; + pPlayer->_pBaseMag = (unsigned char)pPack->pBaseMag; + pPlayer->_pMagic = (unsigned char)pPack->pBaseMag; + pPlayer->_pBaseDex = (unsigned char)pPack->pBaseDex; + pPlayer->_pDexterity = (unsigned char)pPack->pBaseDex; + pPlayer->_pBaseVit = (unsigned char)pPack->pBaseVit; + pPlayer->_pVitality = (unsigned char)pPack->pBaseVit; + pPlayer->_pLevel = pPack->pLevel; + pPlayer->_pStatPts = (unsigned char)pPack->pStatPts; + pPlayer->_pExperience = pPack->pExperience; + pPlayer->_pGold = pPack->pGold; + pPlayer->_pMaxHPBase = pPack->pMaxHPBase; + v6 = pPack->pHPBase; + pPlayer->_pHPBase = v6; + if ( !killok ) + { + _LOBYTE(v6) = v6 & 0xC0; + if ( v6 < 64 ) + pPlayer->_pHPBase = 64; + } + pPlayer->_pMaxManaBase = pPack->pMaxManaBase; + pPlayer->_pManaBase = pPack->pManaBase; + pPlayer->_pMemSpells[0] = pPack->pMemSpells; + pPlayer->_pMemSpells[1] = pPack->pMemSpells2; + + for(i = 0; i < 37; i++) + pPlayer->_pSplLvl[i] = pPack->pSplLvl[i]; + + pki = pPack->InvBody; + pi = pPlayer->InvBody; + + for(i = 0; i < 7; i++) + UnPackItem(pki++, pi++); + + pki = pPack->InvList; + pi = pPlayer->InvList; + + for(i = 0; i < 40; i++) + UnPackItem(pki++, pi++); + + for(i = 0; i < 40; i++) + pPlayer->InvGrid[i] = pPack->InvGrid[i]; + + pPlayer->_pNumInv = (unsigned char)pPack->_pNumInv; + VerifyGoldSeeds(pPlayer); + + pki = pPack->SpdList; + pi = pPlayer->SpdList; + + for(i = 0; i < 8; i++) + UnPackItem(pki++, pi++); + + if ( pnum == myplr ) + { + for(i = 0; i < 20; i++) + witchitem[i]._itype = -1; + } + + CalcPlrInv(pnum, 0); + pPlayer->pTownWarps = 0; + pPlayer->pDungMsgs = 0; + pPlayer->pLvlLoad = 0; + pPlayer->pDiabloKillLevel = pPack->pDiabloKillLevel; + pPlayer->pBattleNet = pPack->pBattleNet; + pPlayer->pManaShield = pPack->pManaShield; +} + +// Note: last slot of item[MAXITEMS+1] used as temporary buffer +// find real name reference below, possibly [sizeof(item[])/sizeof(ItemStruct)] +void __fastcall UnPackItem(PkItemStruct *is, ItemStruct *id) +{ + PkItemStruct *v2; // esi + ItemStruct *v3; // edi + int v5; // ecx + + v2 = is; + v3 = id; + + if ( is->idx == -1 ) + { + id->_itype = -1; + } + else + { + if ( is->idx == IDI_EAR ) + { + RecreateEar( + MAXITEMS, + is->iCreateInfo, + is->iSeed, + is->bId, + (unsigned char)is->bDur, + (unsigned char)is->bMDur, + (unsigned char)is->bCh, + (unsigned char)is->bMCh, + (unsigned short)is->wValue, + is->dwBuff); + } + else + { + v5 = (unsigned short)is->wValue; + _LOWORD(v5) = v2->iCreateInfo; + RecreateItem(MAXITEMS, is->idx, v5, v2->iSeed, (unsigned short)v2->wValue); + item[MAXITEMS]._iMagical = (unsigned char)v2->bId >> 1; + item[MAXITEMS]._iIdentified = v2->bId & 1; + item[MAXITEMS]._iDurability = (unsigned char)v2->bDur; + item[MAXITEMS]._iMaxDur = (unsigned char)v2->bMDur; + item[MAXITEMS]._iCharges = (unsigned char)v2->bCh; + item[MAXITEMS]._iMaxCharges = (unsigned char)v2->bMCh; + } + qmemcpy(v3, &item[MAXITEMS], sizeof(ItemStruct)); + } +} diff --git a/Source/pack.h b/Source/pack.h new file mode 100644 index 000000000..7f9ec202f --- /dev/null +++ b/Source/pack.h @@ -0,0 +1,18 @@ +//HEADER_GOES_HERE +#ifndef __PACK_H__ +#define __PACK_H__ + +extern int pack_cpp_init_value; // weak + +void __cdecl pack_cpp_init(); +void __fastcall PackPlayer(PkPlayerStruct *pPack, int pnum, bool manashield); +void __fastcall PackItem(PkItemStruct *id, ItemStruct *is); +void __fastcall VerifyGoldSeeds(PlayerStruct *pPlayer); +void __fastcall UnPackPlayer(PkPlayerStruct *pPack, int pnum, bool killok); +void __fastcall UnPackItem(PkItemStruct *is, ItemStruct *id); + +/* rdata */ + +extern const int pack_inf; // weak + +#endif /* __PACK_H__ */ diff --git a/Source/palette.cpp b/Source/palette.cpp new file mode 100644 index 000000000..b1c08a983 --- /dev/null +++ b/Source/palette.cpp @@ -0,0 +1,331 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +PALETTEENTRY logical_palette[256]; +int palette_cpp_init_value; // weak +PALETTEENTRY system_palette[256]; +PALETTEENTRY orig_palette[256]; +UINT gdwPalEntries; +#endif + +const int palette_inf = 0x7F800000; // weak + +/* data */ + +int gamma_correction = 100; // idb +int color_cycling_enabled = 1; // idb +bool sgbFadedIn = 1; + +struct palette_cpp_init +{ + palette_cpp_init() + { + palette_cpp_init_value = palette_inf; + } +} _palette_cpp_init; +// 47F16C: using guessed type int palette_inf; +// 67DBCC: using guessed type int palette_cpp_init_value; + +void __cdecl SaveGamma() +{ + SRegSaveValue("Diablo", "Gamma Correction", 0, gamma_correction); + SRegSaveValue("Diablo", "Color Cycling", 0, color_cycling_enabled); +} + +void __cdecl palette_init() +{ + int v0; // eax + int v1; // eax + + LoadGamma(); + memcpy(system_palette, orig_palette, 0x400u); + LoadSysPal(); + v0 = lpDDInterface->CreatePalette(DDPCAPS_ALLOW256|DDPCAPS_8BIT, system_palette, &lpDDPalette, NULL); + if ( v0 ) + ErrDlg(IDD_DIALOG8, v0, "C:\\Src\\Diablo\\Source\\PALETTE.CPP", 143); + v1 = lpDDSPrimary->SetPalette(lpDDPalette); + if ( v1 ) + ErrDlg(IDD_DIALOG8, v1, "C:\\Src\\Diablo\\Source\\PALETTE.CPP", 146); +} + +void __cdecl LoadGamma() +{ + int v3; // eax + int value; // [esp+8h] [ebp-4h] + + value = gamma_correction; + if ( !SRegLoadValue("Diablo", "Gamma Correction", 0, &value) ) + value = 100; + if ( value >= 30 ) + { + if ( value > 100 ) + value = 100; + } + else + { + value = 30; + } + gamma_correction = value - value % 5; + if ( SRegLoadValue("Diablo", "Color Cycling", 0, &value) ) + v3 = value; + else + v3 = 1; + color_cycling_enabled = v3; +} + +void __cdecl LoadSysPal() +{ + HDC hDC; // ebx + int i; // ecx + int iStartIndex; // edi + + for(i = 0; i < 256; i++) + system_palette[i].peFlags = PC_NOCOLLAPSE|PC_RESERVED; + + if ( !fullscreen ) + { + hDC = GetDC(NULL); + gdwPalEntries = GetDeviceCaps(hDC, NUMRESERVED) / 2; + GetSystemPaletteEntries(hDC, 0, gdwPalEntries, system_palette); + for ( i = 0; i < gdwPalEntries; i++ ) + system_palette[i].peFlags = 0; + iStartIndex = 256 - gdwPalEntries; + GetSystemPaletteEntries(hDC, iStartIndex, gdwPalEntries, &system_palette[iStartIndex]); + if ( iStartIndex < 256 ) + { + for(i = iStartIndex; i < 256; i++) + system_palette[i].peFlags = 0; + } + ReleaseDC(NULL, hDC); + } +} +// 484364: using guessed type int fullscreen; + +void __fastcall LoadPalette(char *pszFileName) +{ + int i; // eax + char PalData[256][3]; // [esp+0h] [ebp-304h] + void *pBuf; // [esp+300h] [ebp-4h] + + WOpenFile(pszFileName, &pBuf, 0); + WReadFile(pBuf, (char *)PalData, 768); + WCloseFile(pBuf); + + for(i = 0; i < 256; i++) + { + orig_palette[i].peFlags = 0; + orig_palette[i].peRed = PalData[i][0]; + orig_palette[i].peGreen = PalData[i][1]; + orig_palette[i].peBlue = PalData[i][2]; + } +} + +void __fastcall LoadRndLvlPal(int l) +{ + char *pszPal; // ecx + char szTemp[260]; // [esp+4h] [ebp-104h] + + if ( l ) + { + sprintf(szTemp, "Levels\\L%iData\\L%i_%i.PAL", l, l, random(0, 4) + 1); + pszPal = szTemp; + } + else + { + pszPal = "Levels\\TownData\\Town.pal"; + } + LoadPalette(pszPal); +} + +void __cdecl ResetPal() +{ + if ( !lpDDSPrimary + || lpDDSPrimary->IsLost() != DDERR_SURFACELOST + || !lpDDSPrimary->Restore() ) + { + SDrawRealizePalette(); + } +} + +void __cdecl IncreaseGamma() +{ + if ( gamma_correction < 100 ) + { + gamma_correction += 5; + if ( gamma_correction > 100 ) + gamma_correction = 100; + ApplyGamma(system_palette, logical_palette, 256); + palette_update(); + } +} + +void __cdecl palette_update() +{ + int v0; // ecx + int v1; // eax + + if ( lpDDPalette ) + { + v0 = 0; + v1 = 256; + if ( !fullscreen ) + { + v0 = gdwPalEntries; + v1 = 2 * (128 - gdwPalEntries); + } + SDrawUpdatePalette(v0, v1, &system_palette[v0], 0); + } +} +// 484364: using guessed type int fullscreen; + +void __fastcall ApplyGamma(PALETTEENTRY *dst, PALETTEENTRY *src, int n) +{ + PALETTEENTRY *v3; // edi + PALETTEENTRY *v4; // esi + double v5; // [esp+18h] [ebp-Ch] + + v3 = src; + v4 = dst; + v5 = (double)gamma_correction * 0.01; + if ( n > 0 ) + { + do + { + v4->peRed = pow(v3->peRed * 0.00390625, v5) * 256.0; + v4->peGreen = pow(v3->peGreen * 0.00390625, v5) * 256.0; + v4->peBlue = pow(v3->peBlue * 0.00390625, v5) * 256.0; + ++v4; + ++v3; + --n; + } + while ( n ); + } +} + +void __cdecl DecreaseGamma() +{ + if ( gamma_correction > 30 ) + { + gamma_correction -= 5; + if ( gamma_correction < 30 ) + gamma_correction = 30; + ApplyGamma(system_palette, logical_palette, 256); + palette_update(); + } +} + +int __fastcall UpdateGamma(int gamma) +{ + if ( gamma ) + { + gamma_correction = 130 - gamma; + ApplyGamma(system_palette, logical_palette, 256); + palette_update(); + } + return 130 - gamma_correction; +} + +void __cdecl BlackPalette() +{ + SetFadeLevel(0); +} + +void __fastcall SetFadeLevel(int fadeval) +{ + int i; // eax + + if ( lpDDInterface ) + { + for(i = 0; i < 255; i++) + { + system_palette[i].peRed = (fadeval * logical_palette[i].peRed) >> 8; + system_palette[i].peGreen = (fadeval * logical_palette[i].peGreen) >> 8; + system_palette[i].peBlue = (fadeval * logical_palette[i].peBlue) >> 8; + } +#ifndef FASTER + Sleep(3); +#endif + lpDDInterface->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); + palette_update(); + } +} + +void __fastcall PaletteFadeIn(int fr) +{ + int i; // ebp + + ApplyGamma(logical_palette, orig_palette, 256); + +#ifndef FASTER + for(i = 0; i < 256; i += fr) + SetFadeLevel(i); +#endif + + SetFadeLevel(256); + memcpy(logical_palette, orig_palette, 0x400u); + sgbFadedIn = 1; +} + +void __fastcall PaletteFadeOut(int fr) +{ + int i; // esi + + if ( sgbFadedIn ) + { +#ifndef FASTER + for(i = 256; i > 0; i -= fr) + SetFadeLevel(i); +#endif + + SetFadeLevel(0); + sgbFadedIn = 0; + } +} + +void __cdecl palette_update_caves() +{ + BYTE v0; // cx + signed int v1; // esi + signed int v2; // eax + BYTE v4; // [esp+6h] [ebp-2h] + BYTE v5; + + v0 = system_palette[1].peRed; + v5 = system_palette[1].peGreen; + v4 = system_palette[1].peBlue; + v1 = 1; + do + { + v2 = v1++; + system_palette[v2].peRed = system_palette[v2 + 1].peRed; + system_palette[v2].peGreen = system_palette[v2 + 1].peGreen; + system_palette[v2].peBlue = system_palette[v2 + 1].peBlue; + } + while ( v1 < 31 ); + system_palette[v1].peRed = v0; + system_palette[v1].peGreen = v5; + system_palette[v1].peBlue = v4; + palette_update(); +} + +void __fastcall palette_update_quest_palette(int n) +{ + int i; // eax + + for ( i = 32 - n; i >= 0; --i ) + logical_palette[i] = orig_palette[i]; + ApplyGamma(system_palette, logical_palette, 32); + palette_update(); +} + +bool __cdecl palette_get_colour_cycling() +{ + return color_cycling_enabled; +} + +void __fastcall palette_set_color_cycling(bool enabled) +{ + color_cycling_enabled = enabled; +} diff --git a/Source/palette.h b/Source/palette.h new file mode 100644 index 000000000..81911ddac --- /dev/null +++ b/Source/palette.h @@ -0,0 +1,43 @@ +//HEADER_GOES_HERE +#ifndef __PALETTE_H__ +#define __PALETTE_H__ + +extern PALETTEENTRY logical_palette[256]; +extern int palette_cpp_init_value; // weak +extern PALETTEENTRY system_palette[256]; +extern PALETTEENTRY orig_palette[256]; +extern UINT gdwPalEntries; + +void __cdecl palette_cpp_init(); +void __cdecl SaveGamma(); +void __cdecl palette_init(); +void __cdecl LoadGamma(); +void __cdecl LoadSysPal(); +void __fastcall LoadPalette(char *pszFileName); +void __fastcall LoadRndLvlPal(int l); +void __cdecl ResetPal(); +void __cdecl IncreaseGamma(); +void __cdecl palette_update(); +void __fastcall ApplyGamma(PALETTEENTRY *dst, PALETTEENTRY *src, int n); +void __cdecl DecreaseGamma(); +int __fastcall UpdateGamma(int gamma); +void __cdecl BlackPalette(); +void __fastcall SetFadeLevel(int fadeval); +void __fastcall PaletteFadeIn(int fr); +void __fastcall PaletteFadeOut(int fr); +void __cdecl palette_update_caves(); +void __fastcall palette_update_quest_palette(int n); +bool __cdecl palette_get_colour_cycling(); +void __fastcall palette_set_color_cycling(bool enabled); + +/* rdata */ + +extern const int palette_inf; // weak + +/* data */ + +extern int gamma_correction; // idb +extern int color_cycling_enabled; // idb +extern bool sgbFadedIn; + +#endif /* __PALETTE_H__ */ diff --git a/Source/path.cpp b/Source/path.cpp new file mode 100644 index 000000000..abae6aeff --- /dev/null +++ b/Source/path.cpp @@ -0,0 +1,498 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +// preallocated nodes, search is terminated after 300 nodes are visited +PATHNODE path_nodes[300]; +// size of the pnode_tblptr stack +int gdwCurPathStep; +// the number of in-use nodes in path_nodes +int gdwCurNodes; +/* for reconstructing the path after the A* search is done. The longest + * possible path is actually 24 steps, even though we can fit 25 + */ +int pnode_vals[25]; +// a linked list of all visited nodes +PATHNODE *pnode_ptr; +// a stack for recursively searching nodes +PATHNODE *pnode_tblptr[300]; +// a linked list of the A* frontier, sorted by distance +PATHNODE *path_2_nodes; +#endif + +// for iterating over the 8 possible movement directions +const char pathxdir[8] = { -1, -1, 1, 1, -1, 0, 1, 0 }; +const char pathydir[8] = { -1, 1, -1, 1, 0, -1, 0, 1 }; + +/* data */ + +/* each step direction is assigned a number like this: + * dx + * -1 0 1 + * +----- + * -1|5 1 6 + * dy 0|2 0 3 + * 1|8 4 7 + */ +char path_directions[9] = { 5, 1, 6, 2, 0, 3, 8, 4, 7 }; + +/* find the shortest path from (sx,sy) to (dx,dy), using PosOk(PosOkArg,x,y) to + * check that each step is a valid position. Store the step directions (see + * path_directions) in path, which must have room for 24 steps + */ +int __fastcall FindPath(BOOL (__fastcall *PosOk)(int, int, int), int PosOkArg, int sx, int sy, int dx, int dy, char *path) +{ + PATHNODE *path_start; // esi + char initial_h; // al + PATHNODE *next_node; // eax + int result; // eax + PATHNODE *current; // edx + PATHNODE **previous; // eax + int path_length; // edi + bool path_is_full; // zf + int *step_ptr; // ecx + char step; // dl + + // clear all nodes, create root nodes for the visited/frontier linked lists + gdwCurNodes = 0; + path_2_nodes = path_new_step(); + gdwCurPathStep = 0; + pnode_ptr = path_new_step(); + path_start = path_new_step(); + path_start->g = 0; + initial_h = path_get_h_cost(sx, sy, dx, dy); + path_start->h = initial_h; + path_start->x = sx; + path_start->f = initial_h + path_start->g; + path_start->y = sy; + path_2_nodes->NextNode = path_start; + // A* search until we find (dx,dy) or fail + while ( 1 ) + { + next_node = GetNextPath(); + // frontier is empty, no path! + if ( !next_node ) + return 0; + // reached the end, success! + if ( next_node->x == dx && next_node->y == dy ) + break; + // ran out of nodes, abort! + if ( !path_get_path(PosOk, PosOkArg, next_node, dx, dy) ) + return 0; + } + current = next_node; + previous = &next_node->Parent; + path_length = 0; + if ( *previous ) + { + while ( 1 ) + { + path_is_full = path_length == 25; + if ( path_length >= 25 ) + break; + pnode_vals[++path_length-1] = path_directions[3 * (current->y - (*previous)->y) - (*previous)->x + 4 + current->x]; + current = *previous; + previous = &(*previous)->Parent; + if ( !*previous ) + { + path_is_full = path_length == 25; + break; + } + } + if ( path_is_full ) + return 0; + } + result = 0; + if ( path_length > 0 ) + { + step_ptr = &pnode_vals[path_length-1]; + do + { + step = *(_BYTE *)step_ptr; + --step_ptr; + path[result++] = step; + } + while ( result < path_length ); + } + return result; +} + +/* heuristic, estimated cost from (sx,sy) to (dx,dy) */ +int __fastcall path_get_h_cost(int sx, int sy, int dx, int dy) +{ + int y; // esi + int delta_x; // edi + int delta_y; // eax + int min_delta; // ecx + + y = sy; + delta_x = abs(sx - dx); + delta_y = abs(y - dy); + // this is a pointless swap, it's just 2(delta_x+delta_y) + min_delta = delta_x; + if ( delta_x >= delta_y ) + { + min_delta = delta_y; + if ( delta_x > delta_y ) + delta_y = delta_x; + } + // see path_check_equal for why this is times 2 + return 2 * (min_delta + delta_y); +} + +/* return 2 if pPath is horizontally/vertically aligned with (dx,dy), else 3 + * + * This approximates that diagonal movement on a square grid should have a cost + * of sqrt(2). That's approximately 1.5, so they multiply all step costs by 2, + * except diagonal steps which are times 3 + */ +int __fastcall path_check_equal(PATHNODE *pPath, int dx, int dy) +{ + int result; // [esp-4h] [ebp-4h] + + if ( pPath->x == dx || pPath->y == dy ) + result = 2; + else + result = 3; + return result; +} + +/* get the next node on the A* frontier to explore (estimated to be closest to + * the goal), mark it as visited, and return it + */ +PATHNODE *__cdecl GetNextPath() +{ + PATHNODE *result; // eax + + result = path_2_nodes->NextNode; + if ( result ) + { + path_2_nodes->NextNode = result->NextNode; + result->NextNode = pnode_ptr->NextNode; + pnode_ptr->NextNode = result; + } + return result; +} + +/* check if stepping from pPath to (dx,dy) cuts a corner. If you step from A to + * B, both Xs need to be clear: + * + * AX + * XB + * + * return true if step is allowed + */ +bool __fastcall path_solid_pieces(PATHNODE *pPath, int dx, int dy) +{ + bool result; // eax + int dir; // ecx + int tile1; // ecx + int tile2; // edx + + result = 1; + // this maps the four corner directions to 0,1,2,3 + dir = path_directions[3 * (dy - pPath->y) - pPath->x + 4 + dx] - 5; + // and this is basically a switch + if ( !dir ) // (-1,-1)->0 + { + result = 0; + if ( nSolidTable[dPiece[dx][dy + 1]] ) + return result; + tile1 = dPiece[dx + 1][dy]; + goto LABEL_13; + } + if ( !--dir ) // (1,-1)->1 + { + tile2 = dPiece[dx][dy + 1]; + goto LABEL_9; + } + if ( !--dir ) // (1,1)->2 + { + tile2 = dPiece[dx][dy-1]; /* check */ +LABEL_9: + result = 0; + if ( nSolidTable[tile2] ) + return result; + tile1 = dPiece[dx-1][dy]; /* check */ + goto LABEL_13; + } + if ( dir == 1 ) // (-1,1)->3 + { + result = 0; + if ( !nSolidTable[dPiece[dx + 1][dy]] ) + { + tile1 = dPiece[dx][dy-1]; /* check */ +LABEL_13: + if ( !nSolidTable[tile1] ) + result = 1; + return result; + } + } + return result; +} + +/* perform a single step of A* bread-first search by trying to step in every + * possible direction from pPath with goal (x,y). Check each step with PosOk + * + * return 0 if we ran out of preallocated nodes to use, else 1 + */ +int __fastcall path_get_path(BOOL (__fastcall *PosOk)(int, int, int), int PosOkArg, PATHNODE *pPath, int x, int y) +{ + int dir; // eax + int dx; // esi + int dy; // edi + int i; // [esp+14h] [ebp-4h] + + dir = 0; + for ( i = 0; ; dir = i ) + { + dx = pPath->x + pathxdir[dir]; + dy = pPath->y + pathydir[dir]; + if ( !PosOk(PosOkArg, dx, dy) ) + break; + if ( path_solid_pieces(pPath, dx, dy) ) + goto LABEL_8; +LABEL_9: + if ( ++i >= 8 ) + return 1; + } + if ( dx != x || dy != y ) + goto LABEL_9; +LABEL_8: + if ( path_parent_path(pPath, dx, dy, x, y) ) + goto LABEL_9; + return 0; +} + +/* add a step from pPath to (dx,dy), return 1 if successful, and update the + * frontier/visited nodes accordingly + * + * return 1 if step successfully added, 0 if we ran out of nodes to use + */ +int __fastcall path_parent_path(PATHNODE *pPath, int dx, int dy, int sx, int sy) +{ + PATHNODE *pPath2; // edi, pointless copy + int next_g; // ebx + + PATHNODE *dxdy_frontier; // esi + signed int empty_slot1; // eax + struct PATHNODE **pPath_child_ptr1; // ecx + char dxdy_h; // al + + PATHNODE *dxdy_visited; // esi + signed int empty_slot2; // eax + struct PATHNODE **pPath_child_ptr2; // ecx + char dxdy_f; // al + + PATHNODE *result; // eax + PATHNODE *dxdy_new; // esi + char h_new; // al + signed int empty_slot3; // ecx + struct PATHNODE **pPath_child_ptr3; // eax + + int dx2; // [esp+Ch] [ebp-4h], pointless copy + + dx2 = dx; + pPath2 = pPath; + next_g = pPath->g + path_check_equal(pPath, dx, dy); + + // 3 cases to consider + // case 1: (dx,dy) is already on the frontier + dxdy_frontier = path_get_node1(dx2, dy); + if ( dxdy_frontier ) + { + empty_slot1 = 0; + pPath_child_ptr1 = pPath2->Child; + do + { + if ( !*pPath_child_ptr1 ) + break; + ++empty_slot1; + ++pPath_child_ptr1; + } + while ( empty_slot1 < 8 ); + pPath2->Child[empty_slot1] = dxdy_frontier; + if ( next_g < dxdy_frontier->g ) + { + if ( path_solid_pieces(pPath2, dx2, dy) ) + { + // we'll explore it later, just update + dxdy_h = dxdy_frontier->h; + dxdy_frontier->Parent = pPath2; + dxdy_frontier->g = next_g; + dxdy_frontier->f = next_g + dxdy_h; + } + } + } + else + { + // case 2: (dx,dy) was already visited + dxdy_visited = path_get_node2(dx2, dy); + if ( dxdy_visited ) + { + empty_slot2 = 0; + pPath_child_ptr2 = pPath2->Child; + do + { + if ( !*pPath_child_ptr2 ) + break; + ++empty_slot2; + ++pPath_child_ptr2; + } + while ( empty_slot2 < 8 ); + pPath2->Child[empty_slot2] = dxdy_visited; + if ( next_g < dxdy_visited->g && path_solid_pieces(pPath2, dx2, dy) ) + { + // update the node + dxdy_f = next_g + dxdy_visited->h; + dxdy_visited->Parent = pPath2; + dxdy_visited->g = next_g; + dxdy_visited->f = dxdy_f; + // already explored, so re-update others starting from that node + path_set_coords(dxdy_visited); + } + } + else + { + // case 3: (dx,dy) is totally new + result = path_new_step(); + dxdy_new = result; + if ( !result ) + return 0; + result->Parent = pPath2; + result->g = next_g; + h_new = path_get_h_cost(dx2, dy, sx, sy); + dxdy_new->h = h_new; + dxdy_new->f = next_g + h_new; + dxdy_new->x = dx2; + dxdy_new->y = dy; + // add it to the frontier + path_next_node(dxdy_new); + empty_slot3 = 0; + pPath_child_ptr3 = pPath2->Child; + do + { + if ( !*pPath_child_ptr3 ) + break; + ++empty_slot3; + ++pPath_child_ptr3; + } + while ( empty_slot3 < 8 ); + pPath2->Child[empty_slot3] = dxdy_new; + } + } + return 1; +} + +/* return a node for (dx,dy) on the frontier, or NULL if not found */ +PATHNODE *__fastcall path_get_node1(int dx, int dy) +{ + PATHNODE *result; // eax + + result = path_2_nodes; + do + result = result->NextNode; + while ( result && (result->x != dx || result->y != dy) ); + return result; +} + +/* return a node for (dx,dy) if it was visited, or NULL if not found */ +PATHNODE *__fastcall path_get_node2(int dx, int dy) +{ + PATHNODE *result; // eax + + result = pnode_ptr; + do + result = result->NextNode; + while ( result && (result->x != dx || result->y != dy) ); + return result; +} + +/* insert pPath into the frontier (keeping the frontier sorted by total + * distance) */ +void __fastcall path_next_node(PATHNODE *pPath) +{ + PATHNODE *current; // edx + PATHNODE *next; // eax + + current = path_2_nodes; + next = path_2_nodes->NextNode; + if ( next ) + { + do + { + if ( next->f >= pPath->f ) + break; + current = next; + next = next->NextNode; + } + while ( next ); + pPath->NextNode = next; + } + current->NextNode = pPath; +} + +/* update all path costs using depth-first search starting at pPath */ +void __fastcall path_set_coords(PATHNODE *pPath) +{ + PATHNODE *PathOld; // edi + PATHNODE *PathAct; // esi + char next_g; // al + int i; // [esp+0h] [ebp-8h] + PATHNODE **child_ptr; // [esp+4h] [ebp-4h] + + path_push_active_step(pPath); + while ( gdwCurPathStep ) + { + PathOld = path_pop_active_step(); + child_ptr = PathOld->Child; + for(i = 0; i < 8; i++) + { + PathAct = *child_ptr; + if ( !*child_ptr ) + break; + + if ( PathOld->g + path_check_equal(PathOld, PathAct->x, PathAct->y) < PathAct->g ) + { + if ( path_solid_pieces(PathOld, PathAct->x, PathAct->y) ) + { + PathAct->Parent = PathOld; + next_g = PathOld->g + path_check_equal(PathOld, PathAct->x, PathAct->y); + PathAct->g = next_g; + PathAct->f = next_g + PathAct->h; + path_push_active_step(PathAct); + } + } + ++child_ptr; + } + } +} + +/* push pPath onto the pnode_tblptr stack */ +void __fastcall path_push_active_step(PATHNODE *pPath) +{ + int stack_index; // eax + + stack_index = gdwCurPathStep++; + pnode_tblptr[stack_index] = pPath; +} + +/* pop and return a node from the pnode_tblptr stack */ +PATHNODE *__cdecl path_pop_active_step() +{ + return pnode_tblptr[--gdwCurPathStep]; +} + +/* zero one of the preallocated nodes and return a pointer to it, or NULL if + * none are available */ +PATHNODE *__cdecl path_new_step() +{ + PATHNODE *new_node; // esi + + if ( gdwCurNodes == 300 ) + return 0; + new_node = &path_nodes[gdwCurNodes++]; + memset(new_node, 0, 0x34u); + return new_node; +} diff --git a/Source/path.h b/Source/path.h new file mode 100644 index 000000000..2f4c0ef81 --- /dev/null +++ b/Source/path.h @@ -0,0 +1,36 @@ +//HEADER_GOES_HERE +#ifndef __PATH_H__ +#define __PATH_H__ + +extern PATHNODE path_nodes[300]; +extern int gdwCurPathStep; +extern int gdwCurNodes; +extern int pnode_vals[25]; +extern PATHNODE *pnode_ptr; +extern PATHNODE *pnode_tblptr[300]; +extern PATHNODE *path_2_nodes; + +int __fastcall FindPath(BOOL (__fastcall *PosOk)(int, int, int), int PosOkArg, int sx, int sy, int dx, int dy, char *path); +int __fastcall path_get_h_cost(int sx, int sy, int dx, int dy); +int __fastcall path_check_equal(PATHNODE *pPath, int dx, int dy); +PATHNODE *__cdecl GetNextPath(); +bool __fastcall path_solid_pieces(PATHNODE *pPath, int dx, int dy); +int __fastcall path_get_path(BOOL (__fastcall *PosOk)(int, int, int), int PosOkArg, PATHNODE *pPath, int x, int y); +int __fastcall path_parent_path(PATHNODE *pPath, int dx, int dy, int sx, int sy); +PATHNODE *__fastcall path_get_node1(int dx, int dy); +PATHNODE *__fastcall path_get_node2(int dx, int dy); +void __fastcall path_next_node(PATHNODE *pPath); +void __fastcall path_set_coords(PATHNODE *pPath); +void __fastcall path_push_active_step(PATHNODE *pPath); +PATHNODE *__cdecl path_pop_active_step(); +PATHNODE *__cdecl path_new_step(); + +/* rdata */ + +extern const char pathxdir[8]; +extern const char pathydir[8]; + +/* data */ +extern char path_directions[9]; + +#endif /* __PATH_H__ */ diff --git a/Source/pfile.cpp b/Source/pfile.cpp new file mode 100644 index 000000000..b9bf86aaa --- /dev/null +++ b/Source/pfile.cpp @@ -0,0 +1,918 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int pfile_cpp_init_value; + +#ifndef NO_GLOBALS +char hero_names[MAX_CHARACTERS][PLR_NAME_LEN]; +bool gbValidSaveFile; // idb +int save_prev_tc; // weak +#endif + +const int pfile_inf = 0x7F800000; // weak + +struct pfile_cpp_init +{ + pfile_cpp_init() + { + pfile_cpp_init_value = pfile_inf; + } +} _pfile_cpp_init; +// 47F1C0: using guessed type int pfile_inf; + +void __cdecl pfile_init_save_directory() +{ + char Buffer[260]; // [esp+4h] [ebp-104h] + + if ( GetWindowsDirectory(Buffer, 0x104u) + && (pfile_check_available_space(Buffer), GetModuleFileName(ghInst, Buffer, 0x104u)) ) + { + pfile_check_available_space(Buffer); + } + else + { + TermMsg("Unable to initialize save directory"); + } +} + +void __fastcall pfile_check_available_space(char *pszDir) +{ + char *v1; // edi + char *v2; // eax + char v3; // cl + BOOL v4; // esi + DWORD TotalNumberOfClusters; // [esp+8h] [ebp-10h] + DWORD NumberOfFreeClusters; // [esp+Ch] [ebp-Ch] + DWORD BytesPerSector; // [esp+10h] [ebp-8h] + DWORD SectorsPerCluster; // [esp+14h] [ebp-4h] + + v1 = pszDir; + v2 = pszDir; + while ( 1 ) + { + v3 = *v2; + if ( !*v2 ) + break; + ++v2; + if ( v3 == '\\' ) + { + *v2 = '\0'; + break; + } + } + v4 = GetDiskFreeSpace(v1, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters); + if ( !v4 ) + goto LABEL_12; + if ( (signed __int64)(BytesPerSector * (unsigned __int64)SectorsPerCluster * NumberOfFreeClusters) < 0xA00000 ) + v4 = 0; + if ( !v4 ) +LABEL_12: + DiskFreeDlg(v1); +} + +void __cdecl pfile_write_hero() +{ + int v0; // eax + int v1; // esi + //int v2; // eax + PkPlayerStruct pkplr; // [esp+4h] [ebp-4F4h] + + v0 = pfile_get_save_num_from_name(plr[myplr]._pName); + v1 = v0; + //_LOBYTE(v2) = pfile_open_archive(1, v0); + if ( pfile_open_archive(1, v0) ) + { + PackPlayer(&pkplr, myplr, gbMaxPlayers == 1); + pfile_encode_hero(&pkplr); + pfile_flush(gbMaxPlayers == 1, v1); + } +} +// 679660: using guessed type char gbMaxPlayers; + +int __fastcall pfile_get_save_num_from_name(char *name) +{ + char *v1; // ebx + unsigned int v2; // esi + + v1 = name; + v2 = 0; + do + { + if ( !_strcmpi(hero_names[v2], v1) ) + break; + ++v2; + } + while ( v2 < MAX_CHARACTERS ); + return v2; +} + +void __fastcall pfile_encode_hero(PkPlayerStruct *pPack) +{ + int v1; // ebx + void *v2; // edi + char password[16]; // [esp+Ch] [ebp-14h] + void *v4; // [esp+1Ch] [ebp-4h] + + strcpy(password, "xrgyrkj1"); + *(_DWORD *)&password[9] = 0; + *(_WORD *)&password[13] = 0; + v4 = pPack; + password[15] = 0; + if ( (unsigned char)gbMaxPlayers > 1u ) + strcpy(password, "szqnlsk1"); + v1 = codec_get_encoded_len(1266); + v2 = DiabloAllocPtr(v1); + memcpy(v2, v4, 0x4F2u); + codec_encode(v2, 1266, v1, password); + mpqapi_write_file("hero", (char *)v2, v1); + mem_free_dbg(v2); +} +// 679660: using guessed type char gbMaxPlayers; + +bool __fastcall pfile_open_archive(bool a1, int save_num) +{ + int v2; // esi + BOOL v3; // edi + //int v4; // eax + char FileName[260]; // [esp+8h] [ebp-104h] + + v2 = save_num; + v3 = a1; + pfile_get_save_path(FileName, 260, save_num); + //_LOBYTE(v4) = mpqapi_open_archive(FileName, 0, v2); + if ( mpqapi_open_archive(FileName, 0, v2) ) + return 1; + if ( v3 ) + { + if ( (unsigned char)gbMaxPlayers > 1u ) + MI_Dummy(v2); + } + return 0; +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall pfile_get_save_path(char *pszBuf, int dwBufSize, int save_num) +{ + char *v3; // esi + const char *v4; // ebx + DWORD v5; // edi + char *v6; // eax + char v7[260]; // [esp+8h] [ebp-104h] + + v3 = pszBuf; + v4 = "\\multi_%d.sv"; + if ( (unsigned char)gbMaxPlayers <= 1u ) + v4 = "\\single_%d.sv"; + v5 = GetModuleFileName(ghInst, pszBuf, 0x104u); + v6 = strrchr(v3, '\\'); + if ( v6 ) + *v6 = 0; + if ( !v5 ) + TermMsg("Unable to get save directory"); + sprintf(v7, v4, save_num); + strcat(v3, v7); + _strlwr(v3); +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall pfile_flush(bool is_single_player, int save_num) +{ + int v2; // esi + bool v3; // di + char FileName[260]; // [esp+8h] [ebp-104h] + + v2 = save_num; + v3 = is_single_player; + pfile_get_save_path(FileName, 260, save_num); + mpqapi_flush_and_close(FileName, v3, v2); +} + +bool __fastcall pfile_create_player_description(char *dst, int len) +{ + int v2; // edi + char *v3; // ebx + int v4; // eax + char src[128]; // [esp+Ch] [ebp-ACh] + _uiheroinfo hero_info; // [esp+8Ch] [ebp-2Ch] + + myplr = 0; + v2 = len; + v3 = dst; + pfile_read_player_from_save(); + game_2_ui_player(plr, &hero_info, gbValidSaveFile); + UiSetupPlayerInfo(chr_name_str, &hero_info, 'DRTL'); + if ( !v3 || !v2 ) + goto LABEL_5; + v4 = UiCreatePlayerDescription(&hero_info, 'DRTL', src); + if ( v4 ) + { + SStrCopy(v3, src, v2); +LABEL_5: + v4 = 1; + } + return v4; +} + +int __fastcall pfile_create_save_file(char *name_1, char *name_2) +{ + char *v2; // edi + char *v3; // ebp + int v4; // esi + int v5; // eax + char *v7; // [esp+20h] [ebp-30h] + _uiheroinfo heroinfo; // [esp+24h] [ebp-2Ch] + + v2 = name_2; + v3 = name_1; + if ( pfile_get_save_num_from_name(name_2) != MAX_CHARACTERS ) + return 0; + v4 = 0; + v7 = plr[0]._pName; + while ( _strcmpi(v3, v7) ) + { + v7 += 21720; + ++v4; + if ( v7 == plr[4]._pName ) + return 0; + } + v5 = pfile_get_save_num_from_name(v3); + if ( v5 == MAX_CHARACTERS ) + return 0; + SStrCopy(hero_names[v5], v2, 32); + SStrCopy(plr[v4]._pName, v2, 32); + if ( !_strcmpi(chr_name_str, v3) ) + SStrCopy(chr_name_str, v2, 16); + game_2_ui_player(plr, &heroinfo, gbValidSaveFile); + UiSetupPlayerInfo(chr_name_str, &heroinfo, 'DRTL'); + pfile_write_hero(); + return 1; +} + +void __cdecl pfile_flush_W() +{ + int v0; // eax + + v0 = pfile_get_save_num_from_name(plr[myplr]._pName); + pfile_flush(1, v0); +} + +void __fastcall game_2_ui_player(PlayerStruct *p, _uiheroinfo *heroinfo, bool bHasSaveFile) +{ + _uiheroinfo *v3; // esi + PlayerStruct *v4; // edi + char v5; // al + + v3 = heroinfo; + v4 = p; + memset(heroinfo, 0, 0x2Cu); + strncpy(v3->name, v4->_pName, 0xFu); + v3->name[15] = 0; + v3->level = v4->_pLevel; + v3->heroclass = game_2_ui_class(v4); + v3->strength = v4->_pStrength; + v3->magic = v4->_pMagic; + v3->dexterity = v4->_pDexterity; + v3->vitality = v4->_pVitality; + v3->gold = v4->_pGold; + v3->hassaved = bHasSaveFile; + v5 = v4->pDiabloKillLevel; + v3->spawned = 0; + v3->herorank = v5; +} + +char __fastcall game_2_ui_class(PlayerStruct *p) +{ + char result; // al + + result = p->_pClass; + if ( result ) + result = (result != 1) + 1; + return result; +} + +bool __stdcall pfile_ui_set_hero_infos(void (__stdcall *ui_add_hero_info)(_uiheroinfo *)) +{ + char *v1; // esi + //int v2; // eax + int v3; // eax + DWORD v4; // eax + unsigned int v5; // esi + void *v7; // eax + void *v8; // edi + //int v9; // eax + bool v10; // al + PkPlayerStruct pkplr; // [esp+Ch] [ebp-7BCh] + struct _OFSTRUCT ReOpenBuff; // [esp+500h] [ebp-2C8h] + char FileName[260]; // [esp+588h] [ebp-240h] + char NewFileName[260]; // [esp+68Ch] [ebp-13Ch] + _uiheroinfo hero_info; // [esp+790h] [ebp-38h] + int unused; // [esp+7BCh] [ebp-Ch] + LPCSTR lpSrcStr; // [esp+7C0h] [ebp-8h] + int save_num; // [esp+7C4h] [ebp-4h] + + memset(hero_names, 0, 0x140u); + if ( (unsigned char)gbMaxPlayers > 1u ) + { + lpSrcStr = 0; + save_num = 0; + do + { + if ( (unsigned int)save_num >= MAX_CHARACTERS ) + break; + GetSaveDirectory(FileName, 260, (int)lpSrcStr); + v1 = strrchr(FileName, '\\') + 1; + if ( v1 != (char *)1 && OpenFile(FileName, &ReOpenBuff, 0x4000u) != -1 ) + { + if ( !SRegLoadString("Diablo\\Converted", (const char *)v1, 0, NewFileName, 260) ) + { + while ( 1 ) + { + v3 = save_num++; + pfile_get_save_path(NewFileName, 260, v3); + if ( OpenFile(NewFileName, &ReOpenBuff, 0x4000u) == -1 ) + break; + if ( (unsigned int)save_num >= MAX_CHARACTERS ) + goto LABEL_13; + } + if ( CopyFile(FileName, NewFileName, 1) ) + { + SRegSaveString("Diablo\\Converted", v1, 0, NewFileName); + v4 = GetFileAttributes(NewFileName); + if ( v4 != -1 ) + { + _LOBYTE(v4) = v4 & 0xF9; + SetFileAttributes(NewFileName, v4); + } + } + } + } +LABEL_13: + ++lpSrcStr; + } + while ( (unsigned int)lpSrcStr < MAX_CHARACTERS ); + } + unused = 1; + v5 = 0; + do + { + v7 = pfile_open_save_archive(&unused, v5); + v8 = v7; + if ( v7 ) + { + if ( pfile_read_hero(v7, &pkplr) ) + { + strcpy(hero_names[v5], pkplr.pName); + UnPackPlayer(&pkplr, 0, 0); + v10 = pfile_archive_contains_game(v8); + game_2_ui_player(plr, &hero_info, v10); + ui_add_hero_info(&hero_info); + } + pfile_SFileCloseArchive(v8); + } + ++v5; + } + while ( v5 < MAX_CHARACTERS ); + return 1; +} +// 679660: using guessed type char gbMaxPlayers; + +char *__fastcall GetSaveDirectory(char *dst, int dst_size, int save_num) +{ + char *v3; // esi + const char *v4; // ebx + DWORD v5; // edi + char *v6; // eax + char path_buf[260]; // [esp+Ch] [ebp-104h] + + v3 = dst; + if ( (unsigned char)gbMaxPlayers <= 1u ) + { + v4 = "\\single_%d.sv"; + v5 = GetModuleFileName(ghInst, dst, 0x104u); + v6 = strrchr(v3, '\\'); + if ( v6 ) + *v6 = '\0'; + } + else + { + v4 = "\\dlinfo_%d.drv"; + v5 = GetWindowsDirectory(dst, 0x104u); + } + if ( !v5 ) + TermMsg("Unable to get save directory"); + sprintf(path_buf, v4, save_num); + strcat(v3, path_buf); + return _strlwr(v3); +} +// 679660: using guessed type char gbMaxPlayers; + +bool __fastcall pfile_read_hero(void *archive, PkPlayerStruct *pPack) +{ + BOOL v2; // eax + int dwSize; // eax + int v4; // edi + char *v5; // eax + char *v6; // esi + //int v7; // eax + //int v8; // eax + char password[16]; // [esp+4h] [ebp-24h] + void *v11; // [esp+14h] [ebp-14h] + DWORD nSize; // [esp+18h] [ebp-10h] + int v13; // [esp+1Ch] [ebp-Ch] + int dwBytes; // [esp+20h] [ebp-8h] + void *file; // [esp+24h] [ebp-4h] + + v11 = pPack; + v2 = SFileOpenFileEx(archive, "hero", 0, &file); + if ( v2 ) + { + strcpy(password, "xrgyrkj1"); + v13 = 0; + *(_DWORD *)&password[9] = 0; + *(_WORD *)&password[13] = 0; + password[15] = 0; + nSize = 16; + if ( (unsigned char)gbMaxPlayers > 1u ) + strcpy(password, "szqnlsk1"); + dwSize = SFileGetFileSize((int *)file, 0); + v4 = dwSize; + if ( !dwSize ) + goto LABEL_15; + v5 = (char *)DiabloAllocPtr(dwSize); + v6 = v5; + //_LOBYTE(v7) = SFileReadFile(file, v5, v4, (unsigned long *)&dwBytes, 0); + if ( SFileReadFile(file, v5, v4, (unsigned long *)&dwBytes, 0) ) + { + dwBytes = codec_decode(v6, v4, password); + if ( dwBytes ) + goto LABEL_11; + if ( (unsigned char)gbMaxPlayers > 1u ) + { + GetComputerName(password, &nSize); + if ( !SFileSetFilePointer(file, 0, 0, 0) ) + { + //_LOBYTE(v8) = SFileReadFile(file, v6, v4, (unsigned long *)&dwBytes, 0); + if ( SFileReadFile(file, v6, v4, (unsigned long *)&dwBytes, 0) ) + { + dwBytes = codec_decode(v6, v4, password); +LABEL_11: + if ( dwBytes == 1266 ) + { + memcpy(v11, v6, 0x4F2u); + v13 = 1; + } + goto LABEL_13; + } + } + } + } +LABEL_13: + if ( v6 ) + mem_free_dbg(v6); +LABEL_15: + SFileCloseFile(file); + v2 = v13; + } + return v2; +} +// 679660: using guessed type char gbMaxPlayers; + +void *__fastcall pfile_open_save_archive(int *unused, int save_num) +{ + //int v2; // eax + char SrcStr[260]; // [esp+0h] [ebp-108h] + void *archive; // [esp+104h] [ebp-4h] + + pfile_get_save_path(SrcStr, 260, save_num); + //_LOBYTE(v2) = SFileOpenArchive(SrcStr, 0x7000, 0, &archive); + return SFileOpenArchive(SrcStr, 0x7000, 0, &archive) != 0 ? archive : NULL; +} + +void __fastcall pfile_SFileCloseArchive(void *hsArchive) +{ + SFileCloseArchive(hsArchive); +} + +bool __fastcall pfile_archive_contains_game(void *hsArchive) +{ + //int v1; // eax + void *file; // [esp+0h] [ebp-4h] + + file = hsArchive; + if ( gbMaxPlayers != 1 ) + return 0; + //_LOBYTE(v1) = SFileOpenFileEx(hsArchive, "game", 0, &file); + if ( !SFileOpenFileEx(hsArchive, "game", 0, &file) ) + return 0; + SFileCloseFile(file); + return 1; +} +// 679660: using guessed type char gbMaxPlayers; + +bool __stdcall pfile_ui_set_class_stats(int player_class_nr, _uidefaultstats *class_stats) +{ + int v2; // eax + + v2 = (char)pfile_get_player_class(player_class_nr); + class_stats->strength = StrengthTbl[v2]; + class_stats->magic = MagicTbl[v2]; + class_stats->dexterity = DexterityTbl[v2]; + class_stats->vitality = VitalityTbl[v2]; + return 1; +} + +int __fastcall pfile_get_player_class(int player_class_nr) +{ + int result; // eax + + if ( player_class_nr ) + _LOBYTE(result) = (player_class_nr != 1) + 1; + else + _LOBYTE(result) = 0; + return result; +} + +bool __stdcall pfile_ui_save_create(_uiheroinfo *heroinfo) +{ + unsigned int v1; // edi + //int v3; // eax + char v5; // al + PkPlayerStruct pkplr; // [esp+8h] [ebp-4F4h] + + v1 = pfile_get_save_num_from_name(heroinfo->name); + if ( v1 == MAX_CHARACTERS ) + { + v1 = 0; + do + { + if ( !*hero_names[v1] ) + break; + ++v1; + } + while ( v1 < MAX_CHARACTERS ); + if ( v1 == MAX_CHARACTERS ) + return 0; + } + //_LOBYTE(v3) = pfile_open_archive(0, v1); + if ( !pfile_open_archive(0, v1) ) + return 0; + mpqapi_remove_hash_entries(pfile_get_file_name); + strncpy(hero_names[v1], heroinfo->name, 0x20u); + hero_names[v1][31] = 0; + v5 = pfile_get_player_class((unsigned char)heroinfo->heroclass); + CreatePlayer(0, v5); + strncpy(plr[0]._pName, heroinfo->name, 0x20u); + plr[0]._pName[31] = 0; + PackPlayer(&pkplr, 0, 1); + pfile_encode_hero(&pkplr); + game_2_ui_player(plr, heroinfo, 0); + pfile_flush(1, v1); + return 1; +} + +bool __stdcall pfile_get_file_name(int lvl, char *dst) +{ + int v2; // ecx + bool v3; // zf + const char *v4; // eax + + v2 = lvl; + if ( (unsigned char)gbMaxPlayers > 1u ) + { + v3 = lvl == 0; + goto LABEL_10; + } + if ( (unsigned int)lvl < 0x11 ) + { + v4 = "perml%02d"; +LABEL_12: + sprintf(dst, v4, v2); + return 1; + } + if ( (unsigned int)lvl < 0x22 ) + { + v2 = lvl - 17; + v4 = "perms%02d"; + goto LABEL_12; + } + if ( lvl == 34 ) + { + v4 = "game"; + goto LABEL_12; + } + v3 = lvl == 35; +LABEL_10: + if ( v3 ) + { + v4 = "hero"; + goto LABEL_12; + } + return 0; +} +// 679660: using guessed type char gbMaxPlayers; + +bool __stdcall pfile_delete_save(_uiheroinfo *hero_info) +{ + unsigned int v1; // eax + char FileName[260]; // [esp+0h] [ebp-104h] + + v1 = pfile_get_save_num_from_name(hero_info->name); + if ( v1 < MAX_CHARACTERS ) + { + hero_names[v1][0] = 0; + pfile_get_save_path(FileName, 260, v1); + DeleteFile(FileName); + } + return 1; +} + +void __cdecl pfile_read_player_from_save() +{ + int dwChar; // edi + void *v1; // esi + //int v2; // eax + PkPlayerStruct pkplr; // [esp+8h] [ebp-4F4h] + + dwChar = pfile_get_save_num_from_name(chr_name_str); + v1 = pfile_open_save_archive(0, dwChar); + if ( !v1 ) + TermMsg("Unable to open archive"); + //_LOBYTE(v2) = pfile_read_hero(v1, &pkplr); + if ( !pfile_read_hero(v1, &pkplr) ) + TermMsg("Unable to load character"); + UnPackPlayer(&pkplr, myplr, 0); + *(_DWORD *)&gbValidSaveFile = pfile_archive_contains_game(v1); + pfile_SFileCloseArchive(v1); +} + +void __fastcall GetTempLevelNames(char *szTemp) +{ + char *v1; // esi + + v1 = szTemp; + pfile_get_save_num_from_name(plr[myplr]._pName); + if ( setlevel ) + sprintf(v1, "temps%02d", (unsigned char)setlvlnum); + else + sprintf(v1, "templ%02d", currlevel); +} +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +void __fastcall GetPermLevelNames(char *szPerm) +{ + char *v1; // esi + int v2; // ebx + //int v3; // eax + //int v4; // eax + int v5; // edi + + v1 = szPerm; + v2 = pfile_get_save_num_from_name(plr[myplr]._pName); + GetTempLevelNames(v1); + //_LOBYTE(v3) = pfile_open_archive(0, v2); + if ( !pfile_open_archive(0, v2) ) + TermMsg("Unable to read to save file archive"); + //_LOBYTE(v4) = mpqapi_has_file(v1); + v5 = mpqapi_has_file(v1); + pfile_flush(1, v2); + if ( !v5 ) + { + if ( setlevel ) + sprintf(v1, "perms%02d", (unsigned char)setlvlnum); + else + sprintf(v1, "perml%02d", currlevel); + } +} +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +void __fastcall pfile_get_game_name(char *dst) +{ + char *v1; // esi + + v1 = dst; + pfile_get_save_num_from_name(plr[myplr]._pName); + strcpy(v1, "game"); +} + +void __cdecl pfile_remove_temp_files() +{ + int v0; // eax + int v1; // esi + //int v2; // eax + + if ( (unsigned char)gbMaxPlayers <= 1u ) + { + v0 = pfile_get_save_num_from_name(plr[myplr]._pName); + v1 = v0; + //_LOBYTE(v2) = pfile_open_archive(0, v0); + if ( !pfile_open_archive(0, v0) ) + TermMsg("Unable to write to save file archive"); + mpqapi_remove_hash_entries(GetTempSaveNames); + pfile_flush(1, v1); + } +} +// 679660: using guessed type char gbMaxPlayers; + +bool __stdcall GetTempSaveNames(int dwIndex, char *szTemp) +{ + int v2; // eax + const char *v3; // ecx + + v2 = dwIndex; + if ( (unsigned int)dwIndex < 0x11 ) + { + v3 = "templ%02d"; +LABEL_5: + sprintf(szTemp, v3, v2); + return 1; + } + if ( (unsigned int)dwIndex < 0x22 ) + { + v2 = dwIndex - 17; + v3 = "temps%02d"; + goto LABEL_5; + } + return 0; +} + +void __cdecl pfile_rename_temp_to_perm() +{ + int v0; // eax + int v1; // edi + //int v2; // eax + int v3; // esi + //int v4; // eax + //int v5; // eax + //int v6; // eax + char v7[260]; // [esp+8h] [ebp-208h] + char v8[260]; // [esp+10Ch] [ebp-104h] + + v0 = pfile_get_save_num_from_name(plr[myplr]._pName); + v1 = v0; + //_LOBYTE(v2) = pfile_open_archive(0, v0); + if ( !pfile_open_archive(0, v0) ) + TermMsg("Unable to write to save file archive"); + v3 = 0; + while ( 1 ) + { + //_LOBYTE(v6) = GetTempSaveNames(v3, v7); + if ( !GetTempSaveNames(v3, v7) ) + break; + GetPermSaveNames(v3++, v8); + //_LOBYTE(v4) = mpqapi_has_file(v7); + if ( mpqapi_has_file(v7) ) + { + //_LOBYTE(v5) = mpqapi_has_file(v8); + if ( mpqapi_has_file(v8) ) + mpqapi_remove_hash_entry(v8); + mpqapi_rename(v7, v8); + } + } + GetPermSaveNames(v3, v8); + pfile_flush(1, v1); +} + +bool __stdcall GetPermSaveNames(int dwIndex, char *szPerm) +{ + int v2; // eax + const char *v3; // ecx + + v2 = dwIndex; + if ( (unsigned int)dwIndex < 0x11 ) + { + v3 = "perml%02d"; +LABEL_5: + sprintf(szPerm, v3, v2); + return 1; + } + if ( (unsigned int)dwIndex < 0x22 ) + { + v2 = dwIndex - 17; + v3 = "perms%02d"; + goto LABEL_5; + } + return 0; +} + +void __fastcall pfile_write_save_file(char *pszName, void *pbData, int dwLen, int qwLen) +{ + void *v4; // ebx + int v5; // eax + //int v6; // eax + char file_name[260]; // [esp+Ch] [ebp-118h] + char password[16]; // [esp+110h] [ebp-14h] + int v9; // [esp+120h] [ebp-4h] + + v4 = pbData; + pfile_strcpy(file_name, pszName); + v5 = pfile_get_save_num_from_name(plr[myplr]._pName); + strcpy(password, "xrgyrkj1"); + v9 = v5; + *(_DWORD *)&password[9] = 0; + *(_WORD *)&password[13] = 0; + password[15] = 0; + if ( (unsigned char)gbMaxPlayers > 1u ) + strcpy(password, "szqnlsk1"); + codec_encode(v4, dwLen, qwLen, password); + //_LOBYTE(v6) = pfile_open_archive(0, v9); + if ( !pfile_open_archive(0, v9) ) + TermMsg("Unable to write to save file archive"); + mpqapi_write_file(file_name, (char *)v4, qwLen); + pfile_flush(1, v9); +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall pfile_strcpy(char *dst, char *src) +{ + strcpy(dst, src); +} + +char *__fastcall pfile_read(char *pszName, int *pdwLen) +{ + int *v2; // ebx + int v3; // eax + void *v4; // edi + //int v5; // eax + int v6; // eax + void *v7; // eax + //int v8; // eax + char *v9; // esi + int v10; // eax + //int v11; // eax + char v13[260]; // [esp+Ch] [ebp-124h] + char password[16]; // [esp+110h] [ebp-20h] + void *src_dst; // [esp+120h] [ebp-10h] + int nread; // [esp+124h] [ebp-Ch] + DWORD nSize; // [esp+128h] [ebp-8h] + void *file; // [esp+12Ch] [ebp-4h] + + v2 = pdwLen; + pfile_strcpy(v13, pszName); + v3 = pfile_get_save_num_from_name(plr[myplr]._pName); + v4 = pfile_open_save_archive(0, v3); + if ( !v4 ) + TermMsg("Unable to open save file archive"); + //_LOBYTE(v5) = SFileOpenFileEx(v4, v13, 0, &file); + if ( !SFileOpenFileEx(v4, v13, 0, &file) ) + TermMsg("Unable to open save file"); + v6 = SFileGetFileSize((int *)file, 0); + *v2 = v6; + if ( !v6 ) + TermMsg("Invalid save file"); + v7 = DiabloAllocPtr(*v2); + src_dst = v7; + //_LOBYTE(v8) = SFileReadFile(file, (char *)v7, *v2, (unsigned long *)&nread, 0); + if ( !SFileReadFile(file, (char *)v7, *v2, (unsigned long *)&nread, 0) ) + TermMsg("Unable to read save file"); + SFileCloseFile(file); + pfile_SFileCloseArchive(v4); + strcpy(password, "xrgyrkj1"); + nSize = 16; + *(_DWORD *)&password[9] = 0; + *(_WORD *)&password[13] = 0; + password[15] = 0; + if ( (unsigned char)gbMaxPlayers > 1u ) + strcpy(password, "szqnlsk1"); + v9 = (char *)src_dst; + v10 = codec_decode(src_dst, *v2, password); + *v2 = v10; + if ( !v10 ) + { + if ( (unsigned char)gbMaxPlayers > 1u ) + { + GetComputerName(password, &nSize); + if ( SFileSetFilePointer(file, 0, 0, 0) ) + TermMsg("Unable to read save file"); + //_LOBYTE(v11) = SFileReadFile(file, v9, *v2, (unsigned long *)&nread, 0); + if ( !SFileReadFile(file, v9, *v2, (unsigned long *)&nread, 0) ) + TermMsg("Unable to read save file"); + *v2 = codec_decode(v9, *v2, password); + } + if ( !*v2 ) + TermMsg("Invalid save file"); + } + return v9; +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall pfile_update(bool force_save) +{ + BOOL v1; // esi + DWORD v2; // eax + + v1 = force_save; + if ( gbMaxPlayers != 1 ) + { + v2 = GetTickCount(); + if ( v1 || (signed int)(v2 - save_prev_tc) > 60000 ) + { + save_prev_tc = v2; + pfile_write_hero(); + } + } +} +// 679660: using guessed type char gbMaxPlayers; +// 686428: using guessed type int save_prev_tc; diff --git a/Source/pfile.h b/Source/pfile.h new file mode 100644 index 000000000..6b5553fc8 --- /dev/null +++ b/Source/pfile.h @@ -0,0 +1,52 @@ +//HEADER_GOES_HERE +#ifndef __PFILE_H__ +#define __PFILE_H__ + +extern int pfile_cpp_init_value; +extern char hero_names[MAX_CHARACTERS][PLR_NAME_LEN]; +extern bool gbValidSaveFile; // idb +extern int save_prev_tc; // weak + +void __cdecl pfile_cpp_init(); +void __cdecl pfile_init_save_directory(); +void __fastcall pfile_check_available_space(char *pszDir); +void __cdecl pfile_write_hero(); +int __fastcall pfile_get_save_num_from_name(char *name); +void __fastcall pfile_encode_hero(PkPlayerStruct *pPack); +bool __fastcall pfile_open_archive(bool a1, int save_num); +void __fastcall pfile_get_save_path(char *pszBuf, int dwBufSize, int save_num); +void __fastcall pfile_flush(bool is_single_player, int save_num); +bool __fastcall pfile_create_player_description(char *dst, int len); +int __fastcall pfile_create_save_file(char *name_1, char *name_2); +void __cdecl pfile_flush_W(); +void __fastcall game_2_ui_player(PlayerStruct *p, _uiheroinfo *heroinfo, bool bHasSaveFile); +char __fastcall game_2_ui_class(PlayerStruct *p); +bool __stdcall pfile_ui_set_hero_infos(void (__stdcall *ui_add_hero_info)(_uiheroinfo *)); +char *__fastcall GetSaveDirectory(char *dst, int dst_size, int save_num); +bool __fastcall pfile_read_hero(void *archive, PkPlayerStruct *pPack); +void *__fastcall pfile_open_save_archive(int *unused, int save_num); +void __fastcall pfile_SFileCloseArchive(void *hsArchive); +bool __fastcall pfile_archive_contains_game(void *hsArchive); +bool __stdcall pfile_ui_set_class_stats(int player_class_nr, _uidefaultstats *class_stats); +int __fastcall pfile_get_player_class(int player_class_nr); +bool __stdcall pfile_ui_save_create(_uiheroinfo *heroinfo); +bool __stdcall pfile_get_file_name(int lvl, char *dst); +bool __stdcall pfile_delete_save(_uiheroinfo *hero_info); +void __cdecl pfile_read_player_from_save(); +void __fastcall GetTempLevelNames(char *szTemp); +void __fastcall GetPermLevelNames(char *szPerm); +void __fastcall pfile_get_game_name(char *dst); +void __cdecl pfile_remove_temp_files(); +bool __stdcall GetTempSaveNames(int dwIndex, char *szTemp); +void __cdecl pfile_rename_temp_to_perm(); +bool __stdcall GetPermSaveNames(int dwIndex, char *szPerm); +void __fastcall pfile_write_save_file(char *pszName, void *pbData, int dwLen, int qwLen); +void __fastcall pfile_strcpy(char *dst, char *src); +char *__fastcall pfile_read(char *pszName, int *pdwLen); +void __fastcall pfile_update(bool force_save); + +/* rdata */ + +extern const int pfile_inf; // weak + +#endif /* __PFILE_H__ */ diff --git a/Source/player.cpp b/Source/player.cpp new file mode 100644 index 000000000..a57fd6569 --- /dev/null +++ b/Source/player.cpp @@ -0,0 +1,4996 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int plr_lframe_size; // idb +int plr_wframe_size; // idb +char plr_gfx_flag; // weak +int player_cpp_init_value; // weak +int plr_aframe_size; // idb +int myplr; +PlayerStruct plr[MAX_PLRS]; +int plr_fframe_size; // idb +int plr_qframe_size; // idb +int deathflag; // idb +int plr_hframe_size; // idb +int plr_bframe_size; // idb +char plr_gfx_bflag; // weak +int plr_sframe_size; // idb +int deathdelay; // weak +int plr_dframe_size; // idb +#endif + +const int player_inf = 0x7F800000; // weak +const char ArmourChar[4] = { 'L', 'M', 'H', 0 }; +const char WepChar[10] = { 'N', 'U', 'S', 'D', 'B', 'A', 'M', 'H', 'T', 0 }; +const char CharChar[4] = { 'W', 'R', 'S', 0 }; + +/* data */ + +int plrxoff[9] = { 0, 2, 0, 2, 1, 0, 1, 2, 1 }; +int plryoff[9] = { 0, 2, 2, 0, 1, 1, 0, 1, 2 }; +int plrxoff2[9] = { 0, 1, 0, 1, 2, 0, 1, 2, 2 }; +int plryoff2[9] = { 0, 0, 1, 1, 0, 2, 2, 1, 2 }; +char PlrGFXAnimLens[3][11] = +{ + { 10, 16, 8, 2, 20, 20, 6, 20, 8, 9, 14 }, + { 8, 18, 8, 4, 20, 16, 7, 20, 8, 10, 12 }, + { 8, 16, 8, 6, 20, 12, 8, 20, 8, 12, 8 } +}; +int PWVel[4][3] = { { 2048, 1024, 512 }, { 2048, 1024, 512 }, { 2048, 1024, 512 }, { 8, 8, 8 } }; +int StrengthTbl[3] = { 30, 20, 15 }; +int MagicTbl[3] = { 10, 15, 35 }; +int DexterityTbl[3] = { 20, 30, 15 }; +int VitalityTbl[3] = { 25, 20, 20 }; +int ToBlkTbl[3] = { 30, 20, 10 }; +char *ClassStrTblOld[3] = { "Warrior", "Rogue", "Sorceror" }; // unused +int MaxStats[3][4] = { { 250, 50, 60, 100 }, { 55, 70, 250, 80 }, { 45, 250, 85, 80 } }; +int ExpLvlsTbl[51] = +{ + 0, + 2000, + 4620, + 8040, + 12489, + 18258, + 25712, + 35309, + 47622, + 63364, + 83419, + 108879, + 141086, + 181683, + 231075, + 313656, + 424067, + 571190, + 766569, + 1025154, + 1366227, + 1814568, + 2401895, + 3168651, + 4166200, + 5459523, + 7130496, + 9281874, + 12042092, + 15571031, + 20066900, + 25774405, + 32994399, + 42095202, + 53525811, + 67831218, + 85670061, + 107834823, + 135274799, + 169122009, + 210720231, + 261657253, + 323800420, + 399335440, + 490808349, + 601170414, + 733825617, + 892680222, + 1082908612, + 1310707109, + 1583495809 +}; +char *ClassStrTbl[3] = { "Warrior", "Rogue", "Sorceror" }; +unsigned char fix[9] = { 0u, 0u, 3u, 3u, 3u, 6u, 6u, 6u, 8u }; /* PM_ChangeLightOff local type */ + +struct player_cpp_init +{ + player_cpp_init() + { + player_cpp_init_value = player_inf; + } +} _player_cpp_init; +// 47F204: using guessed type int player_inf; +// 68643C: using guessed type int player_cpp_init_value; + +void __fastcall SetPlayerGPtrs(UCHAR *pData, UCHAR **pAnim) +{ + for ( int i = 0; i < 8; i++ ) { + pAnim[i] = pData + ((DWORD *)pData)[i]; + } +} + +void __fastcall LoadPlrGFX(int pnum, player_graphic gfxflag) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("LoadPlrGFX: illegal player %d", pnum); + } + + char prefix[16]; + char pszName[256]; + char *szCel; + PlayerStruct *p = &plr[pnum]; + sprintf(prefix, "%c%c%c", CharChar[p->_pClass], ArmourChar[p->_pgfxnum >> 4], WepChar[p->_pgfxnum & 0xF]); + char *cs = ClassStrTbl[p->_pClass]; + UCHAR *pData; + UCHAR *pAnim; + + for (DWORD i = 1; i <= PFILE_NONDEATH; i <<= 1) { + if ( !(i & gfxflag) ) { + continue; + } + + switch ( i ) { + case PFILE_STAND: + szCel = "AS"; + if ( leveltype == DTYPE_TOWN ) { + szCel = "ST"; + } + pData = p->_pNData; + pAnim = (UCHAR *)p->_pNAnim; + break; + case PFILE_WALK: + szCel = "AW"; + if ( leveltype == DTYPE_TOWN ) { + szCel = "WL"; + } + pData = p->_pWData; + pAnim = (UCHAR *)p->_pWAnim; + break; + case PFILE_ATTACK: + if ( leveltype == DTYPE_TOWN ) { + continue; + } + szCel = "AT"; + pData = p->_pAData; + pAnim = (UCHAR *)p->_pAAnim; + break; + case PFILE_HIT: + if ( leveltype == DTYPE_TOWN ) { + continue; + } + szCel = "HT"; + pData = p->_pHData; + pAnim = (UCHAR *)p->_pHAnim; + break; + case PFILE_LIGHTNING: + if ( leveltype == DTYPE_TOWN ) { + continue; + } + szCel = "LM"; + pData = p->_pLData; + pAnim = (UCHAR *)p->_pLAnim; + break; + case PFILE_FIRE: + if ( leveltype == DTYPE_TOWN ) { + continue; + } + szCel = "FM"; + pData = p->_pFData; + pAnim = (UCHAR *)p->_pFAnim; + break; + case PFILE_MAGIC: + if ( leveltype == DTYPE_TOWN ) { + continue; + } + szCel = "QM"; + pData = p->_pTData; + pAnim = (UCHAR *)p->_pTAnim; + break; + case PFILE_DEATH: + if ( p->_pgfxnum & 0xF ) { + continue; + } + szCel = "DT"; + pData = p->_pDData; + pAnim = (UCHAR *)p->_pDAnim; + break; + case PFILE_BLOCK: + if ( leveltype == DTYPE_TOWN ) { + continue; + } + if ( !p->_pBlockFlag ) { + continue; + } + + szCel = "BL"; + pData = p->_pBData; + pAnim = (UCHAR *)p->_pBAnim; + break; + default: + TermMsg("PLR:2"); + break; + } + + sprintf(pszName, "PlrGFX\\%s\\%s\\%s%s.CL2", cs, prefix, prefix, szCel); + LoadFileWithMem(pszName, pData); + SetPlayerGPtrs((UCHAR *)pData, (UCHAR **)pAnim); + p->_pGFXLoad |= i; + } +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall InitPlayerGFX(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("InitPlayerGFX: illegal player %d", pnum); + } + + if ( plr[pnum]._pHitPoints >> 6 == 0 ) { + plr[pnum]._pgfxnum = 0; + LoadPlrGFX(pnum, PFILE_DEATH); + } else { + LoadPlrGFX(pnum, PFILE_NONDEATH); + } +} + +void __fastcall InitPlrGFXMem(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("InitPlrGFXMem: illegal player %d", pnum); + } + + if ( !(plr_gfx_flag & 1) ) { + plr_gfx_flag |= 1; + if ( GetPlrGFXSize("AS") <= GetPlrGFXSize("ST") ) { + plr_sframe_size = GetPlrGFXSize("ST"); + } else { + plr_sframe_size = GetPlrGFXSize("AS"); + } + } + plr[pnum]._pNData = DiabloAllocPtr(plr_sframe_size); + + if ( !(plr_gfx_flag & 2) ) { + plr_gfx_flag |= 2; + if ( GetPlrGFXSize("AW") <= GetPlrGFXSize("WL") ) { + plr_wframe_size = GetPlrGFXSize("WL"); + } else { + plr_wframe_size = GetPlrGFXSize("AW"); + } + } + plr[pnum]._pWData = DiabloAllocPtr(plr_wframe_size); + + if ( !(plr_gfx_flag & 4) ) { + plr_gfx_flag |= 4; + plr_aframe_size = GetPlrGFXSize("AT"); + } + plr[pnum]._pAData = DiabloAllocPtr(plr_aframe_size); + + if ( !(plr_gfx_flag & 8) ) { + plr_gfx_flag |= 8; + plr_hframe_size = GetPlrGFXSize("HT"); + } + plr[pnum]._pHData = DiabloAllocPtr(plr_hframe_size); + + if ( !(plr_gfx_flag & 0x10) ) { + plr_gfx_flag |= 0x10; + plr_lframe_size = GetPlrGFXSize("LM"); + } + plr[pnum]._pLData = DiabloAllocPtr(plr_lframe_size); + + if ( !(plr_gfx_flag & 0x20) ) { + plr_gfx_flag |= 0x20; + plr_fframe_size = GetPlrGFXSize("FM"); + } + plr[pnum]._pFData = DiabloAllocPtr(plr_fframe_size); + + if ( !(plr_gfx_flag & 0x40) ) { + plr_gfx_flag |= 0x40; + plr_qframe_size = GetPlrGFXSize("QM"); + } + plr[pnum]._pTData = DiabloAllocPtr(plr_qframe_size); + + if ( !(plr_gfx_flag & 0x80) ) { + plr_gfx_flag |= 0x80; + plr_dframe_size = GetPlrGFXSize("DT"); + } + plr[pnum]._pDData = DiabloAllocPtr(plr_dframe_size); + + if ( !(plr_gfx_bflag & 1) ) { + plr_gfx_bflag |= 1; + plr_bframe_size = GetPlrGFXSize("BL"); + } + plr[pnum]._pBData = DiabloAllocPtr(plr_bframe_size); + + plr[pnum]._pGFXLoad = 0; +} +// 686438: using guessed type char plr_gfx_flag; +// 69B7BC: using guessed type char plr_gfx_bflag; + +DWORD __fastcall GetPlrGFXSize(char *szCel) +{ + char prefix[16]; // [esp+10Ch] [ebp-24h] + char pszName[256]; // [esp+Ch] [ebp-124h] + void *file; // [esp+124h] [ebp-Ch] + DWORD size = 0; // [esp+11Ch] [ebp-14h] + DWORD result = 0; + int a = 0; + int w = 0; + + for (int c = 0; c < sizeof(ClassStrTbl) / sizeof(ClassStrTbl[0]); c++) { + for (a = 0; ArmourChar[a]; a++) { + for (w = 0; WepChar[w]; w++) { + sprintf(prefix, "%c%c%c", CharChar[c], ArmourChar[a], WepChar[w]); + sprintf(pszName, "PlrGFX\\%s\\%s\\%s%s.CL2", ClassStrTbl[c], prefix, prefix, szCel); + if ( WOpenFile(pszName, &file, TRUE) ) { + size = WGetFileSize(file, 0); + WCloseFile(file); + if ( result <= size ) { + result = size; + } + } + } + } + } + + return result; +} + +void __fastcall FreePlayerGFX(int pnum) +{ + void *ptr; + + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("FreePlayerGFX: illegal player %d", pnum); + } + + ptr = plr[pnum]._pNData; + plr[pnum]._pNData = NULL; + mem_free_dbg(ptr); + ptr = plr[pnum]._pWData; + plr[pnum]._pWData = NULL; + mem_free_dbg(ptr); + ptr = plr[pnum]._pAData; + plr[pnum]._pAData = NULL; + mem_free_dbg(ptr); + ptr = plr[pnum]._pHData; + plr[pnum]._pHData = NULL; + mem_free_dbg(ptr); + ptr = plr[pnum]._pLData; + plr[pnum]._pLData = NULL; + mem_free_dbg(ptr); + ptr = plr[pnum]._pFData; + plr[pnum]._pFData = NULL; + mem_free_dbg(ptr); + ptr = plr[pnum]._pTData; + plr[pnum]._pTData = NULL; + mem_free_dbg(ptr); + ptr = plr[pnum]._pDData; + plr[pnum]._pDData = NULL; + mem_free_dbg(ptr); + ptr = plr[pnum]._pBData; + plr[pnum]._pBData = NULL; + mem_free_dbg(ptr); + plr[pnum]._pGFXLoad = 0; +} + +void __fastcall NewPlrAnim(int pnum, unsigned char *Peq, int numFrames, int Delay, int width) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("NewPlrAnim: illegal player %d", pnum); + } + + plr[pnum]._pAnimData = Peq; + plr[pnum]._pAnimLen = numFrames; + plr[pnum]._pAnimFrame = 1; + plr[pnum]._pAnimCnt = 0; + plr[pnum]._pAnimDelay = Delay; + plr[pnum]._pAnimWidth = width; + plr[pnum]._pAnimWidth2 = (width - 64) >> 1; +} + +void __fastcall ClearPlrPVars(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("ClearPlrPVars: illegal player %d", pnum); + } + + plr[pnum]._pVar1 = 0; + plr[pnum]._pVar2 = 0; + plr[pnum]._pVar3 = 0; + plr[pnum]._pVar4 = 0; + plr[pnum]._pVar5 = 0; + plr[pnum]._pVar6 = 0; + plr[pnum]._pVar7 = 0; + plr[pnum]._pVar8 = 0; +} + +void __fastcall SetPlrAnims(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("SetPlrAnims: illegal player %d", pnum); + } + + int pc = plr[pnum]._pClass; + + plr[pnum]._pNWidth = 96; + plr[pnum]._pWWidth = 96; + plr[pnum]._pAWidth = 128; + plr[pnum]._pHWidth = 96; + plr[pnum]._pSWidth = 96; + plr[pnum]._pDWidth = 128; + plr[pnum]._pBWidth = 96; + + if ( leveltype == DTYPE_TOWN ) { + plr[pnum]._pNFrames = PlrGFXAnimLens[pc][7]; + plr[pnum]._pWFrames = PlrGFXAnimLens[pc][8]; + plr[pnum]._pDFrames = PlrGFXAnimLens[pc][4]; + plr[pnum]._pSFrames = PlrGFXAnimLens[pc][5]; + } else { + plr[pnum]._pNFrames = PlrGFXAnimLens[pc][0]; + plr[pnum]._pWFrames = PlrGFXAnimLens[pc][2]; + plr[pnum]._pAFrames = PlrGFXAnimLens[pc][1]; + plr[pnum]._pHFrames = PlrGFXAnimLens[pc][6]; + plr[pnum]._pSFrames = PlrGFXAnimLens[pc][5]; + plr[pnum]._pDFrames = PlrGFXAnimLens[pc][4]; + plr[pnum]._pBFrames = PlrGFXAnimLens[pc][3]; + plr[pnum]._pAFNum = PlrGFXAnimLens[pc][9]; + + } + plr[pnum]._pSFNum = PlrGFXAnimLens[pc][10]; + + int gn = plr[pnum]._pgfxnum & 0xF; + if ( pc == PC_WARRIOR ) { + if ( gn == 4 ) { + if ( leveltype != DTYPE_TOWN ) { + plr[pnum]._pNFrames = 8; + } + plr[pnum]._pAWidth = 96; + plr[pnum]._pAFNum = 11; + } else if ( gn == 5 ) { + plr[pnum]._pAFrames = 20; + plr[pnum]._pAFNum = 10; + } else if ( gn == 8 ) { + plr[pnum]._pAFrames = 16; + plr[pnum]._pAFNum = 11; + } + } else if ( pc == PC_ROGUE ) { + if ( gn == 5 ) { + plr[pnum]._pAFrames = 22; + plr[pnum]._pAFNum = 13; + } else if ( gn == 4 ) { + plr[pnum]._pAFrames = 12; + plr[pnum]._pAFNum = 7; + } else if ( gn == 8 ) { + plr[pnum]._pAFrames = 16; + plr[pnum]._pAFNum = 11; + } + } else if ( pc == PC_SORCERER ) { + plr[pnum]._pSWidth = 128; + if ( gn == 0 ) { + plr[pnum]._pAFrames = 20; + } else if ( gn == 1 ) { + plr[pnum]._pAFNum = 9; + } else if ( gn == 4 ) { + plr[pnum]._pAFrames = 20; + plr[pnum]._pAFNum = 16; + } else if ( gn == 5 ) { + plr[pnum]._pAFrames = 24; + plr[pnum]._pAFNum = 16; + } + } +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall ClearPlrRVars(PlayerStruct *p) +{ + // TODO: Missing debug assert p != NULL + p->bReserved[0] = 0; + p->bReserved[1] = 0; + p->bReserved[2] = 0; + p->wReserved[0] = 0; + p->wReserved[1] = 0; + p->wReserved[2] = 0; + p->wReserved[3] = 0; + p->wReserved[4] = 0; + p->wReserved[5] = 0; + p->wReserved[6] = 0; + p->wReserved[7] = 0; + p->dwReserved[0] = 0; + p->dwReserved[1] = 0; + p->dwReserved[2] = 0; + p->dwReserved[3] = 0; + p->dwReserved[4] = 0; + p->dwReserved[5] = 0; + p->dwReserved[6] = 0; +} + +// c: plr_classes value +void __fastcall CreatePlayer(int pnum, char c) +{ + ClearPlrRVars(&plr[pnum]); + SetRndSeed(GetTickCount()); + + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("CreatePlayer: illegal player %d", pnum); + } + plr[pnum]._pClass = c; + + char val = StrengthTbl[c]; + if ( val < 0 ) { + val = 0; + } + plr[pnum]._pStrength = val; + plr[pnum]._pBaseStr = val; + + val = MagicTbl[c]; + if ( val < 0 ) { + val = 0; + } + plr[pnum]._pMagic = val; + plr[pnum]._pBaseMag = val; + + val = DexterityTbl[c]; + if ( val < 0 ) { + val = 0; + } + plr[pnum]._pDexterity = val; + plr[pnum]._pBaseDex = val; + + val = VitalityTbl[c]; + if ( val < 0 ) { + val = 0; + } + plr[pnum]._pVitality = val; + plr[pnum]._pBaseVit = val; + + plr[pnum]._pStatPts = 0; + plr[pnum].pTownWarps = 0; + plr[pnum].pDungMsgs = 0; + plr[pnum].pLvlLoad = 0; + plr[pnum].pDiabloKillLevel = 0; + + if ( c == PC_ROGUE ) { + plr[pnum]._pDamageMod = plr[pnum]._pLevel * (plr[pnum]._pStrength + plr[pnum]._pDexterity) / 200; + } else { + plr[pnum]._pDamageMod = plr[pnum]._pStrength * plr[pnum]._pLevel / 100; + } + + plr[pnum]._pBaseToBlk = ToBlkTbl[c]; + + + plr[pnum]._pHitPoints = (val + 10) << 6; + if ( c == PC_WARRIOR ) { + plr[pnum]._pHitPoints *= 2; + } + if ( c == PC_ROGUE ) { + plr[pnum]._pHitPoints += plr[pnum]._pHitPoints >> 1; + } + + int hp = plr[pnum]._pHitPoints; + plr[pnum]._pMaxHP = hp; + plr[pnum]._pHPBase = hp; + plr[pnum]._pMaxHPBase = hp; + + plr[pnum]._pMana = plr[pnum]._pMagic << 6; + if ( c == PC_SORCERER ) { + plr[pnum]._pMana *= 2; + } + if ( c == PC_ROGUE ) { + plr[pnum]._pMana += plr[pnum]._pMana >> 1; + } + + int mana = plr[pnum]._pMana; + plr[pnum]._pMaxMana = mana; + plr[pnum]._pManaBase = mana; + plr[pnum]._pMaxManaBase = mana; + + plr[pnum]._pLevel = 1; + plr[pnum]._pMaxLvl = 1; + plr[pnum]._pExperience = 0; + plr[pnum]._pMaxExp = 0; + plr[pnum]._pNextExper = ExpLvlsTbl[1]; + plr[pnum]._pArmorClass = 0; + plr[pnum]._pMagResist = 0; + plr[pnum]._pFireResist = 0; + plr[pnum]._pLghtResist = 0; + plr[pnum]._pLightRad = 10; + plr[pnum]._pInfraFlag = 0; + + if ( c == PC_WARRIOR ) { + plr[pnum]._pAblSpells[0] = 0x2000000; + plr[pnum]._pAblSpells[1] = 0; + } else if ( c == PC_ROGUE ) { + plr[pnum]._pAblSpells[0] = 0x8000000; + plr[pnum]._pAblSpells[1] = 0; + } else if ( c == PC_SORCERER ) { + plr[pnum]._pAblSpells[0] = 0x4000000; + plr[pnum]._pAblSpells[1] = 0; + } + + if ( c == PC_SORCERER ) { + plr[pnum]._pMemSpells[0] = 1; + } else { + plr[pnum]._pMemSpells[0] = 0; + } + plr[pnum]._pMemSpells[1] = 0; + + int i; + for ( i = 0; i < sizeof(plr[pnum]._pSplLvl); i++ ) { + plr[pnum]._pSplLvl[i] = 0; + } + + plr[pnum]._pSpellFlags = 0; + + if ( plr[pnum]._pClass == PC_SORCERER ) { + plr[pnum]._pSplLvl[1] = 2; + } + + // interestingly, only the first three hotkeys are reset + // TODO: BUGFIX: clear all 4 hotkeys instead of 3 (demo leftover) + for ( i = 0; i < 3; i++ ) { + plr[pnum]._pSplHotKey[i] = -1; + } + + if ( c == PC_WARRIOR ) { + plr[pnum]._pgfxnum = 3; + } else if ( c == PC_ROGUE ) { + plr[pnum]._pgfxnum = 4; + } else if ( c == PC_SORCERER ) { + plr[pnum]._pgfxnum = 8; + } + + for ( i = 0; i < sizeof(plr[pnum]._pLvlVisited); i++ ) { + plr[pnum]._pLvlVisited[i] = 0; + } + + for ( i = 0; i < sizeof(plr[pnum]._pSLvlVisited); i++ ) { + plr[pnum]._pSLvlVisited[i] = 0; + } + + plr[pnum]._pLvlChanging = 0; + plr[pnum].pTownWarps = 0; + plr[pnum].pLvlLoad = 0; + plr[pnum].pBattleNet = 0; + plr[pnum].pManaShield = 0; + + InitDungMsgs(pnum); + CreatePlrItems(pnum); + SetRndSeed(0); +} + +int __fastcall CalcStatDiff(int pnum) +{ + int c = plr[pnum]._pClass; + return MaxStats[c][ATTRIB_STR] + - plr[pnum]._pBaseStr + + MaxStats[c][ATTRIB_MAG] + - plr[pnum]._pBaseMag + + MaxStats[c][ATTRIB_DEX] + - plr[pnum]._pBaseDex + + MaxStats[c][ATTRIB_VIT] + - plr[pnum]._pBaseVit; +} + +void __fastcall NextPlrLevel(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("NextPlrLevel: illegal player %d", pnum); + } + + plr[pnum]._pLevel++; + char l = plr[pnum]._pLevel; + + plr[pnum]._pMaxLvl++; + + if ( CalcStatDiff(pnum) < 5 ) { + plr[pnum]._pStatPts = CalcStatDiff(pnum); + } else { + plr[pnum]._pStatPts += 5; + } + + plr[pnum]._pNextExper = ExpLvlsTbl[l]; + + char c = plr[pnum]._pClass; + + int hp = c == PC_SORCERER ? 64 : 128; + if ( gbMaxPlayers == 1 ) { + hp++; + } + plr[pnum]._pMaxHP += hp; + plr[pnum]._pHitPoints = plr[pnum]._pMaxHP; + plr[pnum]._pMaxHPBase += hp; + plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase; + + if ( pnum == myplr ) { + drawhpflag = 1; + } + + int mana = c != PC_WARRIOR ? 128 : 64; + if ( gbMaxPlayers == 1 ) { + mana++; + } + plr[pnum]._pMaxMana += mana; + plr[pnum]._pMaxManaBase += mana; + + if ( !(plr[pnum]._pIFlags & ISPL_NOMANA) ) { + plr[pnum]._pMana = plr[pnum]._pMaxMana; + plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase; + } + + if ( pnum == myplr ) { + drawmanaflag = 1; + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall AddPlrExperience(int pnum, int lvl, int exp) +{ + if ( pnum != myplr ) { + return; + } + + if ( (DWORD)myplr >= MAX_PLRS ) { + TermMsg("AddPlrExperience: illegal player %d", myplr); + } + + if ( plr[myplr]._pHitPoints <= 0 ) { + return; + } + + // Adjust xp based on difference in level between player and monster + exp *= 1 + ((double)lvl - plr[pnum]._pLevel) / 10; + if ( exp < 0 ) { + exp = 0; + } + + // Prevent power leveling + if ( gbMaxPlayers > 1 ) { + int powerLvlCap = plr[pnum]._pLevel < 0 ? 0 : plr[pnum]._pLevel; + if ( powerLvlCap >= 50 ) { + powerLvlCap = 50; + } + // cap to 1/20 of current levels xp + if ( exp >= ExpLvlsTbl[powerLvlCap] / 20 ) { + exp = ExpLvlsTbl[powerLvlCap] / 20; + } + // cap to 200 * current level + int expCap = 200 * powerLvlCap; + if ( exp >= expCap ) { + exp = expCap; + } + } + + plr[pnum]._pExperience += exp; + if ( (DWORD)plr[pnum]._pExperience > MAXEXP ) { + plr[pnum]._pExperience = MAXEXP; + } + + if ( plr[pnum]._pExperience >= ExpLvlsTbl[49] ) { + plr[pnum]._pLevel = 50; + return; + } + + // Increase player level if applicable + int newLvl = 0; + while ( plr[pnum]._pExperience >= ExpLvlsTbl[newLvl] ) { + newLvl++; + } + if ( newLvl != plr[pnum]._pLevel ) { + for ( int i = newLvl - plr[pnum]._pLevel; i > 0; i--) { + NextPlrLevel(pnum); + } + } + + NetSendCmdParam1(FALSE, CMD_PLRLEVEL, plr[myplr]._pLevel); +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall AddPlrMonstExper(int lvl, int exp, char pmask) +{ + int totplrs = 0; + for (int i = 0; i < 4; i++ ) { + if ( (1 << i) & pmask ) { + totplrs++; + } + } + + if ( totplrs && (1 << myplr) & pmask ) { + AddPlrExperience(myplr, lvl, exp / totplrs); + } +} + +void __fastcall InitPlayer(int pnum, BOOL FirstTime) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("InitPlayer: illegal player %d", pnum); + } + + ClearPlrRVars(&plr[pnum]); + + if ( FirstTime ) { + plr[pnum]._pRSpell = SPL_INVALID; + plr[pnum]._pSBkSpell = SPL_INVALID; + plr[pnum]._pSpell = SPL_INVALID; + plr[pnum]._pRSplType = RSPLTYPE_INVALID; + plr[pnum]._pSplType = RSPLTYPE_INVALID; + if ((plr[pnum]._pgfxnum & 0xF) == 4) { + plr[pnum]._pwtype = TRUE; + } else { + plr[pnum]._pwtype = FALSE; + } + plr[pnum].pManaShield = 0; + } + + if ( plr[pnum].plrlevel == currlevel || leveldebug ) { + + SetPlrAnims(pnum); + + plr[pnum]._pxoff = 0; + plr[pnum]._pyoff = 0; + plr[pnum]._pxvel = 0; + plr[pnum]._pyvel = 0; + + ClearPlrPVars(pnum); + + if ( plr[pnum]._pHitPoints >> 6 > 0 ) { + plr[pnum]._pmode = PM_STAND; + NewPlrAnim(pnum, plr[pnum]._pNAnim[0], plr[pnum]._pNFrames, 3, plr[pnum]._pNWidth); + plr[pnum]._pAnimFrame = random(2, plr[pnum]._pNFrames - 1) + 1; + plr[pnum]._pAnimCnt = random(2, 3); + } else { + plr[pnum]._pmode = PM_DEATH; + NewPlrAnim(pnum, plr[pnum]._pDAnim[0], plr[pnum]._pDFrames, 1, plr[pnum]._pDWidth); + plr[pnum]._pAnimFrame = plr[pnum]._pAnimLen - 1; + plr[pnum]._pVar8 = 2 * plr[pnum]._pAnimLen; + } + + plr[pnum]._pdir = 0; + plr[pnum]._peflag = 0; + + if ( pnum == myplr ) { + if ( !FirstTime || currlevel ) { + plr[pnum].WorldX = ViewX; + plr[pnum].WorldY = ViewY; + } + plr[pnum]._ptargx = plr[pnum].WorldX; + plr[pnum]._ptargy = plr[pnum].WorldY; + } else { + plr[pnum]._ptargx = plr[pnum].WorldX; + plr[pnum]._ptargy = plr[pnum].WorldY; + DWORD i; + for ( i = 0; i < 8 && !PosOkPlayer(pnum, plrxoff2[i] + plr[pnum].WorldX, plryoff2[i] + plr[pnum].WorldY); ++i ); + plr[pnum].WorldX += plrxoff2[i]; + plr[pnum].WorldY += plryoff2[i]; + } + + plr[pnum]._px = plr[pnum].WorldX; + plr[pnum]._py = plr[pnum].WorldY; + plr[pnum].walkpath[0] = -1; + plr[pnum].destAction = -1; + + if ( pnum == myplr ) { + plr[pnum]._plid = AddLight(plr[pnum].WorldX, plr[pnum].WorldY, plr[pnum]._pLightRad); + } else { + plr[pnum]._plid = -1; + } + plr[pnum]._pvid = AddVision(plr[pnum].WorldX, plr[pnum].WorldY, plr[pnum]._pLightRad, pnum == myplr); + } + + if ( plr[pnum]._pClass == PC_WARRIOR ) { + plr[pnum]._pAblSpells64 = 1 << (SPL_REPAIR - 1); + } else if ( plr[pnum]._pClass == PC_ROGUE ) { + plr[pnum]._pAblSpells64 = 1 << (SPL_DISARM - 1); + } else if ( plr[pnum]._pClass == PC_SORCERER ) { + plr[pnum]._pAblSpells64 = 1 << (SPL_RECHARGE - 1); + } + +#ifdef _DEBUG + if ( debug_mode_dollar_sign && FirstTime ) { + plr[pnum]._pMemSpells64 |= 1 << (SPL_TELEPORT - 1); + if ( !plr[myplr]._pSplLvl[SPL_TELEPORT] ) { + plr[myplr]._pSplLvl[SPL_TELEPORT] = 1; + } + } + if ( debug_mode_key_inverted_v && FirstTime ) { + plr[pnum]._pMemSpells64 = SPL_INVALID; + } +#endif + + plr[pnum]._pNextExper = ExpLvlsTbl[plr[pnum]._pLevel]; + plr[pnum]._pInvincible = FALSE; + + if ( pnum == myplr ) { + deathdelay = 0; + deathflag = 0; + ScrollInfo._sxoff = 0; + ScrollInfo._syoff = 0; + ScrollInfo._sdir = 0; + } +} +// 44B83C: could not find valid save-restore pair for edi +// 52572C: using guessed type int leveldebug; +// 69B7C4: using guessed type int deathdelay; + +void __cdecl InitMultiView() +{ + if ( (DWORD)myplr >= MAX_PLRS ) { + TermMsg("InitPlayer: illegal player %d", myplr); + } + + ViewX = plr[myplr].WorldX; + ViewY = plr[myplr].WorldY; +} + +void __fastcall InitPlayerLoc(int pnum, BOOL flag) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("InitPlayer: illegal player %d", pnum); + } + + int x = plr[pnum].WorldX - 1; + int y = plr[pnum].WorldY + 1; + int bitflags = 0; + USHORT *pieces = (USHORT *)dpiece_defs_map_1 + 16 * gendung_get_dpiece_num_from_coord(x, y); + + int i; + for ( i = 2; i < 10; i++ ) { + bitflags |= pieces[i]; + } + + if ( bitflags | nSolidTable[dPiece[x][y]] | dArch[x][y] ) { + plr[pnum]._peflag = 1; + } + else { + plr[pnum]._peflag = 0; + } + + if ( flag != 1 || plr[pnum]._peflag != 1 ) { + return; + } + + x = plr[pnum].WorldX; + y = plr[pnum].WorldY + 2; + bitflags = 0; + pieces = (USHORT *)dpiece_defs_map_1 + 16 * gendung_get_dpiece_num_from_coord(x, y); + + for ( i = 2; i < 10; i++ ) { + bitflags |= pieces[i]; + } + + if ( bitflags | dArch[x][y] ) { + return; + } + + x = plr[pnum].WorldX - 2; + y = plr[pnum].WorldY + 1; + bitflags = 0; + pieces = (USHORT *)dpiece_defs_map_1 + 16 * gendung_get_dpiece_num_from_coord(x, y); + + for ( i = 2; i < 10; i++ ) { + bitflags |= pieces[i]; + } + + if ( bitflags | dArch[x][y] ) { + plr[pnum]._peflag = 2; + } +} + +BOOL __fastcall SolidLoc(int x, int y) +{ + if ( x < 0 || y < 0 || x >= MAXDUNX || y >= MAXDUNY ) { + return FALSE; + } + + return nSolidTable[dPiece[x][y]]; +} + +BOOL __fastcall PlrDirOK(int pnum, int dir) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("PlrDirOK: illegal player %d", pnum); + } + + int px = plr[pnum].WorldX + offset_x[dir]; + int py = plr[pnum].WorldY + offset_y[dir]; + + if ( px < 0 || !dPiece[px][py] || !PosOkPlayer(pnum, px, py) ) { + return FALSE; + } + + BOOL isOk = TRUE; + if ( dir == DIR_E ) { + isOk = !SolidLoc(px, py + 1) && !(dFlags[px][py + 1] & 32); + } + + if ( isOk && dir == DIR_W ) { + isOk = !SolidLoc(px + 1, py) && !(dFlags[px + 1][py] & 32); + } + + return isOk; +} + +void __fastcall PlrClrTrans(int x, int y) +{ + for ( int i = y - 1; i <= y + 1; i++ ) { + for ( int j = x - 1; j <= x + 1; j++ ) { + TransList[dung_map[j][i]] = 0; + } + } +} + +void __fastcall PlrDoTrans(int x, int y) +{ + if ( leveltype != DTYPE_CATHEDRAL && leveltype != DTYPE_CATACOMBS ) { + TransList[1] = 1; + } else { + for ( int i = y - 1; i <= y + 1; i++ ) { + for ( int j = x - 1; j <= x + 1; j++ ) { + if ( !nSolidTable[dPiece[j][i]] && dung_map[j][i] ) { + TransList[dung_map[j][i]] = 1; + } + } + } + } +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall SetPlayerOld(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("SetPlayerOld: illegal player %d", pnum); + } + + plr[pnum]._poldx = plr[pnum].WorldX; + plr[pnum]._poldy = plr[pnum].WorldY; +} + +void __fastcall FixPlayerLocation(int pnum, int dir) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("FixPlayerLocation: illegal player %d", pnum); + } + + plr[pnum]._px = plr[pnum].WorldX; + plr[pnum]._py = plr[pnum].WorldY; + plr[pnum]._ptargx = plr[pnum].WorldX; + plr[pnum]._ptargy = plr[pnum].WorldY; + plr[pnum]._pxoff = 0; + plr[pnum]._pyoff = 0; + InitPlayerLoc(pnum, FALSE); + plr[pnum]._pdir = dir; + if ( pnum == myplr ) { + ScrollInfo._sxoff = 0; + ScrollInfo._syoff = 0; + ScrollInfo._sdir = 0; + ViewX = plr[pnum].WorldX; + ViewY = plr[pnum].WorldY; + } +} + +void __fastcall StartStand(int pnum, int dir) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("StartStand: illegal player %d", pnum); + } + + if ( !plr[pnum]._pInvincible || plr[pnum]._pHitPoints || pnum != myplr ) { + if ( !(plr[pnum]._pGFXLoad & PFILE_STAND) ) { + LoadPlrGFX(pnum, PFILE_STAND); + } + + NewPlrAnim(pnum, plr[pnum]._pNAnim[dir], plr[pnum]._pNFrames, 3, plr[pnum]._pNWidth); + plr[pnum]._pmode = PM_STAND; + FixPlayerLocation(pnum, dir); + FixPlrWalkTags(pnum); + dPlayer[plr[pnum].WorldX][plr[pnum].WorldY] = pnum + 1; + SetPlayerOld(pnum); + } else { + SyncPlrKill(pnum, -1); + } +} + +void __fastcall StartWalkStand(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("StartWalkStand: illegal player %d", pnum); + } + + plr[pnum]._pmode = 0; + plr[pnum]._px = plr[pnum].WorldX; + plr[pnum]._py = plr[pnum].WorldY; + plr[pnum]._pxoff = 0; + plr[pnum]._pyoff = 0; + + InitPlayerLoc(pnum, 0); + + if ( pnum == myplr ) { + ScrollInfo._sxoff = 0; + ScrollInfo._syoff = 0; + ScrollInfo._sdir = 0; + ViewX = plr[pnum].WorldX; + ViewY = plr[pnum].WorldY; + } +} + +void __fastcall PM_ChangeLightOff(int pnum) +{ + int v1; // esi + int v2; // esi + signed int v3; // ebx + int v4; // edi + int v5; // edx + LightListStruct *v6; // eax + int v7; // ecx + int v8; // edx + signed int v9; // edi + int v10; // ebx + int v11; // edx + int v12; // ecx + int v13; // ebp + int ly; // [esp+10h] [ebp-Ch] + int lx; // [esp+18h] [ebp-4h] + + v1 = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("PM_ChangeLightOff: illegal player %d", pnum); + v2 = v1; + v3 = -1; + v4 = plr[v2]._pxoff; + v5 = 2 * plr[v2]._pyoff; + v6 = &LightList[plr[v2]._plid]; + v7 = v4 + v5; + v8 = v5 - v4; + if ( v7 >= 0 ) + { + v9 = 1; + } + else + { + v9 = -1; + v7 = -v7; + } + if ( v8 >= 0 ) + v3 = 1; + else + v8 = -v8; + v10 = v3 * (v8 >> 3); + v11 = 8 * v6->_ly; + ly = v11 + v10; + lx = v9 * (v7 >> 3); + v12 = 8 * v6->_lx; + v13 = v11 + v6->_yoff; + if ( abs(lx - v6->_xoff) >= 3 || abs(ly - v13) >= 3 ) + ChangeLightOff(plr[v2]._plid, lx, v10); +} + +void __fastcall PM_ChangeOffset(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("PM_ChangeOffset: illegal player %d", pnum); + } + + plr[pnum]._pVar8++; + int px = plr[pnum]._pVar6 >> 8; + int py = plr[pnum]._pVar7 >> 8; + + plr[pnum]._pVar6 += plr[pnum]._pxvel; + plr[pnum]._pVar7 += plr[pnum]._pyvel; + plr[pnum]._pxoff = plr[pnum]._pVar6 >> 8; + plr[pnum]._pyoff = plr[pnum]._pVar7 >> 8; + + if ( pnum == myplr && ScrollInfo._sdir ) { + ScrollInfo._sxoff += px - plr[pnum]._pxoff; + ScrollInfo._syoff += py - plr[pnum]._pyoff; + } + PM_ChangeLightOff(pnum); +} + +void __fastcall StartWalk(int pnum, int xvel, int yvel, int xadd, int yadd, int EndDir, int sdir) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("StartWalk: illegal player %d", pnum); + } + + if ( plr[pnum]._pInvincible && !plr[pnum]._pHitPoints && pnum == myplr ) { + SyncPlrKill(pnum, -1); + return; + } + + SetPlayerOld(pnum); + + int px = xadd + plr[pnum].WorldX; + int py = yadd + plr[pnum].WorldY; + + if ( !PlrDirOK(pnum, EndDir) ) { + return; + } + + plr[pnum]._px = px; + plr[pnum]._py = py; + + if ( pnum == myplr ) { + ScrollInfo._sdx = plr[pnum].WorldX - ViewX; + ScrollInfo._sdy = plr[pnum].WorldY - ViewY; + } + + dPlayer[px][py] = -(pnum + 1); + plr[pnum]._pmode = PM_WALK; + plr[pnum]._pxvel = xvel; + plr[pnum]._pyvel = yvel; + plr[pnum]._pxoff = 0; + plr[pnum]._pyoff = 0; + plr[pnum]._pVar1 = xadd; + plr[pnum]._pVar2 = yadd; + plr[pnum]._pVar3 = EndDir; + + if ( !(plr[pnum]._pGFXLoad & PFILE_WALK) ) { + LoadPlrGFX(pnum, PFILE_WALK); + } + NewPlrAnim(pnum, plr[pnum]._pWAnim[EndDir], plr[pnum]._pWFrames, 0, plr[pnum]._pWWidth); + + plr[pnum]._pdir = EndDir; + plr[pnum]._pVar6 = 0; + plr[pnum]._pVar7 = 0; + plr[pnum]._pVar8 = 0; + + InitPlayerLoc(pnum, FALSE); + + if ( pnum != myplr ) { + return; + } + + if ( zoomflag ) { + if ( abs(ScrollInfo._sdx) >= 3 || abs(ScrollInfo._sdy) >= 3 ) { + ScrollInfo._sdir = 0; + } else { + ScrollInfo._sdir = sdir; + } + } else if ( abs(ScrollInfo._sdx) >= 2 || abs(ScrollInfo._sdy) >= 2 ) { + ScrollInfo._sdir = 0; + } else { + ScrollInfo._sdir = sdir; + } +} +// 52569C: using guessed type int zoomflag; + +void __fastcall StartWalk2(int pnum, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int EndDir, int sdir) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("StartWalk2: illegal player %d", pnum); + } + + if ( plr[pnum]._pInvincible && !plr[pnum]._pHitPoints && pnum == myplr ) { + SyncPlrKill(pnum, -1); + return; + } + + SetPlayerOld(pnum); + int px = xadd + plr[pnum].WorldX; + int py = yadd + plr[pnum].WorldY; + + if ( !PlrDirOK(pnum, EndDir) ) { + return; + } + + plr[pnum]._px = px; + plr[pnum]._py = py; + + if ( pnum == myplr ) { + ScrollInfo._sdx = plr[pnum].WorldX - ViewX; + ScrollInfo._sdy = plr[pnum].WorldY - ViewY; + } + + dPlayer[plr[pnum].WorldX][plr[pnum].WorldY] = -1 - pnum; + plr[pnum]._pVar1 = plr[pnum].WorldX; + plr[pnum]._pVar2 = plr[pnum].WorldY; + plr[pnum].WorldX = px; + plr[pnum].WorldY = py; + dPlayer[plr[pnum].WorldX][plr[pnum].WorldY] = pnum + 1; + plr[pnum]._pxoff = xoff; + plr[pnum]._pyoff = yoff; + + ChangeLightXY(plr[pnum]._plid, plr[pnum].WorldX, plr[pnum].WorldY); + PM_ChangeLightOff(pnum); + + plr[pnum]._pmode = PM_WALK2; + plr[pnum]._pxvel = xvel; + plr[pnum]._pyvel = yvel; + plr[pnum]._pVar6 = xoff << 8; + plr[pnum]._pVar7 = yoff << 8; + plr[pnum]._pVar3 = EndDir; + + if ( !(plr[pnum]._pGFXLoad & PFILE_WALK) ) { + LoadPlrGFX(pnum, PFILE_WALK); + } + NewPlrAnim(pnum, plr[pnum]._pWAnim[EndDir], plr[pnum]._pWFrames, 0, plr[pnum]._pWWidth); + + plr[pnum]._pdir = EndDir; + plr[pnum]._pVar8 = 0; + + if ( EndDir == DIR_SE ) { + InitPlayerLoc(pnum, TRUE); + } else { + InitPlayerLoc(pnum, FALSE); + } + + if ( pnum != myplr ) { + return; + } + + if ( zoomflag ) { + if ( abs(ScrollInfo._sdx) >= 3 || abs(ScrollInfo._sdy) >= 3 ) { + ScrollInfo._sdir = 0; + } else { + ScrollInfo._sdir = sdir; + } + } else if ( abs(ScrollInfo._sdx) >= 2 || abs(ScrollInfo._sdy) >= 2 ) { + ScrollInfo._sdir = 0; + } else { + ScrollInfo._sdir = sdir; + } +} +// 52569C: using guessed type int zoomflag; + +void __fastcall StartWalk3(int pnum, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int mapx, int mapy, int EndDir, int sdir) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("StartWalk3: illegal player %d", pnum); + } + + if ( plr[pnum]._pInvincible && !plr[pnum]._pHitPoints && pnum == myplr ) { + SyncPlrKill(pnum, -1); + return; + } + + SetPlayerOld(pnum); + int px = xadd + plr[pnum].WorldX; + int py = yadd + plr[pnum].WorldY; + int x = mapx + plr[pnum].WorldX; + int y = mapy + plr[pnum].WorldY; + + if ( !PlrDirOK(pnum, EndDir) ) { + return; + } + + plr[pnum]._px = px; + plr[pnum]._py = py; + + if ( pnum == myplr ) { + ScrollInfo._sdx = plr[pnum].WorldX - ViewX; + ScrollInfo._sdy = plr[pnum].WorldY - ViewY; + } + + dPlayer[plr[pnum].WorldX][plr[pnum].WorldY] = -1 - pnum; + dPlayer[px][py] = -1 - pnum; + plr[pnum]._pVar4 = x; + plr[pnum]._pVar5 = y; + dFlags[x][y] |= 0x20; + plr[pnum]._pxoff = xoff; + plr[pnum]._pyoff = yoff; + + if ( leveltype ) { + ChangeLightXY(plr[pnum]._plid, x, y); + PM_ChangeLightOff(pnum); + } + + plr[pnum]._pmode = PM_WALK3; + plr[pnum]._pxvel = xvel; + plr[pnum]._pyvel = yvel; + plr[pnum]._pVar1 = px; + plr[pnum]._pVar2 = py; + plr[pnum]._pVar6 = xoff << 8; + plr[pnum]._pVar7 = yoff << 8; + plr[pnum]._pVar3 = EndDir; + + if ( !(plr[pnum]._pGFXLoad & PFILE_WALK) ) { + LoadPlrGFX(pnum, PFILE_WALK); + } + NewPlrAnim(pnum, plr[pnum]._pWAnim[EndDir], plr[pnum]._pWFrames, 0, plr[pnum]._pWWidth); + + plr[pnum]._pdir = EndDir; + plr[pnum]._pVar8 = 0; + + InitPlayerLoc(pnum, 0); + + if ( pnum != myplr ) { + return; + } + + if ( zoomflag ) { + if ( abs(ScrollInfo._sdx) >= 3 || abs(ScrollInfo._sdy) >= 3 ) { + ScrollInfo._sdir = 0; + } else { + ScrollInfo._sdir = sdir; + } + } else if ( abs(ScrollInfo._sdx) >= 2 || abs(ScrollInfo._sdy) >= 2 ) { + ScrollInfo._sdir = 0; + } else { + ScrollInfo._sdir = sdir; + } +} +// 52569C: using guessed type int zoomflag; +// 5BB1ED: using guessed type char leveltype; + +void __fastcall StartAttack(int pnum, int d) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("StartAttack: illegal player %d", pnum); + } + + if ( plr[pnum]._pInvincible && !plr[pnum]._pHitPoints && pnum == myplr ) { + SyncPlrKill(pnum, -1); + return; + } + + if ( !(plr[pnum]._pGFXLoad & PFILE_ATTACK) ) { + LoadPlrGFX(pnum, PFILE_ATTACK); + } + + NewPlrAnim(pnum, plr[pnum]._pAAnim[d], plr[pnum]._pAFrames, 0, plr[pnum]._pAWidth); + plr[pnum]._pmode = PM_ATTACK; + FixPlayerLocation(pnum, d); + SetPlayerOld(pnum); +} + +void __fastcall StartRangeAttack(int pnum, int d, int cx, int cy) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("StartRangeAttack: illegal player %d", pnum); + } + + if ( plr[pnum]._pInvincible && !plr[pnum]._pHitPoints && pnum == myplr ) { + SyncPlrKill(pnum, -1); + return; + } + + if ( !(plr[pnum]._pGFXLoad & PFILE_ATTACK) ) { + LoadPlrGFX(pnum, PFILE_ATTACK); + } + NewPlrAnim(pnum, plr[pnum]._pAAnim[d], plr[pnum]._pAFrames, 0, plr[pnum]._pAWidth); + + plr[pnum]._pmode = PM_RATTACK; + FixPlayerLocation(pnum, d); + SetPlayerOld(pnum); + plr[pnum]._pVar1 = cx; + plr[pnum]._pVar2 = cy; +} + +void __fastcall StartPlrBlock(int pnum, int dir) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("StartPlrBlock: illegal player %d", pnum); + } + + if ( plr[pnum]._pInvincible && !plr[pnum]._pHitPoints && pnum == myplr ) { + SyncPlrKill(pnum, -1); + return; + } + + PlaySfxLoc(IS_ISWORD, plr[pnum].WorldX, plr[pnum].WorldY); + + if ( !(plr[pnum]._pGFXLoad & PFILE_BLOCK) ) { + LoadPlrGFX(pnum, PFILE_BLOCK); + } + NewPlrAnim(pnum, plr[pnum]._pBAnim[dir], plr[pnum]._pBFrames, 2, plr[pnum]._pBWidth); + + plr[pnum]._pmode = PM_BLOCK; + FixPlayerLocation(pnum, dir); + SetPlayerOld(pnum); +} + +void __fastcall StartSpell(int pnum, int d, int cx, int cy) +{ + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("StartSpell: illegal player %d", pnum); + + if ( plr[pnum]._pInvincible && !plr[pnum]._pHitPoints && pnum == myplr ) { + SyncPlrKill(pnum, -1); + return; + } + + if ( leveltype != DTYPE_TOWN ) { + switch ( spelldata[plr[pnum]._pSpell].sType ) + { + case STYPE_FIRE: + if ( !(plr[pnum]._pGFXLoad & PFILE_FIRE) ) { + LoadPlrGFX(pnum, PFILE_FIRE); + } + NewPlrAnim(pnum, plr[pnum]._pFAnim[d], plr[pnum]._pSFrames, 0, plr[pnum]._pSWidth); + break; + case STYPE_LIGHTNING: + if ( !(plr[pnum]._pGFXLoad & PFILE_LIGHTNING) ) { + LoadPlrGFX(pnum, PFILE_LIGHTNING); + } + NewPlrAnim(pnum, plr[pnum]._pLAnim[d], plr[pnum]._pSFrames, 0, plr[pnum]._pSWidth); + break; + case STYPE_MAGIC: + if ( !(plr[pnum]._pGFXLoad & PFILE_MAGIC) ) { + LoadPlrGFX(pnum, PFILE_MAGIC); + } + NewPlrAnim(pnum, plr[pnum]._pTAnim[d], plr[pnum]._pSFrames, 0, plr[pnum]._pSWidth); + break; + } + } + + PlaySfxLoc(spelldata[plr[pnum]._pSpell].sSFX, plr[pnum].WorldX, plr[pnum].WorldY); + + plr[pnum]._pmode = PM_SPELL; + + FixPlayerLocation(pnum, d); + SetPlayerOld(pnum); + + plr[pnum]._pVar1 = cx; + plr[pnum]._pVar2 = cy; + plr[pnum]._pVar4 = GetSpellLevel(pnum, plr[pnum]._pSpell); + plr[pnum]._pVar8 = 1; +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall FixPlrWalkTags(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("FixPlrWalkTags: illegal player %d", pnum); + } + + int pNext = pnum + 1; + int pPrev = -(pnum + 1); + int dx = plr[pnum]._poldx; + int dy = plr[pnum]._poldy; + for ( int y = dy - 1; y <= dy + 1; y++ ) { + for ( int x = dx - 1; x <= dx + 1; x++ ) { + if ( x >= 0 && x < MAXDUNX && y >= 0 && y < MAXDUNY && (dPlayer[x][y] == pNext || dPlayer[x][y] == pPrev) ) { + dPlayer[x][y] = 0; + } + } + } + + if ( dx >= 0 && dx < MAXDUNX - 1 && dy >= 0 && dy < MAXDUNY -1 ) { + dFlags[dx + 1][dy] &= 0xDF; + dFlags[dx][dy + 1] &= 0xDF; + } +} + +void __fastcall RemovePlrFromMap(int pnum) +{ + int v1; // esi + signed int v2; // edi + signed int v3; // edx + signed int v4; // ebx + char v5; // al + signed int v6; // edx + _BYTE *v7; // eax + signed int v8; // edi + int v9; // ecx + int v10; // [esp+Ch] [ebp-4h] + + v1 = -1 - pnum; + v10 = pnum + 1; + v2 = 1; + do + { + v3 = v2; + v4 = 111; + do + { + if ( dPlayer[0][v3 + 111] == v1 || dPlayer[0][v3] == v1 ) + { + v5 = dFlags[1][v3]; + if ( v5 & 0x20 ) + dFlags[1][v3] = v5 & 0xDF; + } + v3 += 112; + --v4; + } + while ( v4 ); + ++v2; + } + while ( v2 < 112 ); + v6 = 0; + do + { + v7 = (unsigned char *)dPlayer + v6; + v8 = 112; + do + { + v9 = (char)*v7; + if ( v9 == v10 || v9 == v1 ) + *v7 = 0; + v7 += 112; + --v8; + } + while ( v8 ); + ++v6; + } + while ( v6 < 112 ); +} + +void __fastcall StartPlrHit(int pnum, int dam, BOOL forcehit) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("StartPlrHit: illegal player %d", pnum); + } + + if ( plr[pnum]._pInvincible && !plr[pnum]._pHitPoints && pnum == myplr ) { + SyncPlrKill(pnum, -1); + return; + } + + if ( plr[pnum]._pClass == PC_WARRIOR ) { + PlaySfxLoc(PS_WARR69, plr[pnum].WorldX, plr[pnum].WorldY); + } else if ( plr[pnum]._pClass == PC_ROGUE ) { + PlaySfxLoc(PS_ROGUE69, plr[pnum].WorldX, plr[pnum].WorldY); + } else if ( plr[pnum]._pClass == PC_SORCERER ) { + PlaySfxLoc(PS_MAGE69, plr[pnum].WorldX, plr[pnum].WorldY); + } + + drawhpflag = 1; + if ( dam >> 6 >= plr[pnum]._pLevel || forcehit ) { + int dir = plr[pnum]._pdir; + + if ( !(plr[pnum]._pGFXLoad & PFILE_HIT) ) { + LoadPlrGFX(pnum, PFILE_HIT); + } + NewPlrAnim(pnum, plr[pnum]._pHAnim[dir], plr[pnum]._pHFrames, 0, plr[pnum]._pHWidth); + + plr[pnum]._pmode = PM_GOTHIT; + FixPlayerLocation(pnum, dir); + plr[pnum]._pVar8 = 1; + FixPlrWalkTags(pnum); + dPlayer[plr[pnum].WorldX][plr[pnum].WorldY] = pnum + 1; + SetPlayerOld(pnum); + } +} + +void __fastcall RespawnDeadItem(ItemStruct *itm, int x, int y) +{ + ItemStruct *v3; // ebx + int v4; // eax + int i; // ST10_4 + //unsigned int v6; // ecx + + v3 = itm; + if ( numitems < MAXITEMS ) + { + if ( FindGetItem(itm->IDidx, itm->_iCreateInfo, itm->_iSeed) >= 0 ) + { + DrawInvMsg("A duplicate item has been detected. Destroying duplicate..."); + SyncGetItem(x, y, v3->IDidx, v3->_iCreateInfo, v3->_iSeed); + } + v4 = itemavail[0]; + i = itemavail[0]; + dItem[x][y] = _LOBYTE(itemavail[0]) + 1; + //v6 = 4 * numitems; + itemactive[numitems] = v4; + v4 *= 368; + itemavail[0] = itemavail[-numitems + 126]; /* double check, MAXITEMS */ + qmemcpy((char *)item + v4, v3, sizeof(ItemStruct)); + *(int *)((char *)&item[0]._ix + v4) = x; + *(int *)((char *)&item[0]._iy + v4) = y; + RespawnItem(i, 1); + ++numitems; + v3->_itype = -1; + } +} + +void __fastcall StartPlayerKill(int pnum, int earflag) +{ + unsigned int v2; // edi + unsigned int v3; // esi + char v4; // al + int v5; // ecx + int v6; // ST0C_4 + bool v7; // zf + int *v8; // eax + signed int v9; // ecx + char *v10; // eax + char v11; // al + short v12; // cx + short v13; // ax + int v14; // ecx + int v15; // eax + signed int v17; // ebx + int v18; // eax + ItemStruct ear; // [esp+Ch] [ebp-178h] + BOOL v20; // [esp+17Ch] [ebp-8h] + struct ItemStruct *itm; // [esp+180h] [ebp-4h] + + v2 = pnum; + v3 = 21720 * pnum; + itm = (struct ItemStruct *)earflag; + if ( plr[pnum]._pHitPoints <= 0 && plr[pnum]._pmode == PM_DEATH ) + return; + if ( myplr == pnum ) + NetSendCmdParam1(1u, CMD_PLRDEAD, earflag); + v20 = (unsigned char)gbMaxPlayers > 1u && plr[v3 / 0x54D8].plrlevel == 16; + if ( v2 >= 4 ) + TermMsg("StartPlayerKill: illegal player %d", v2); + v4 = plr[v3 / 0x54D8]._pClass; + if ( v4 ) + { + if ( v4 == 1 ) + { + v5 = PS_ROGUE71; + } + else + { + if ( v4 != 2 ) + goto LABEL_18; + v5 = PS_MAGE71; + } + PlaySfxLoc(v5, plr[v3 / 0x54D8].WorldX, plr[v3 / 0x54D8].WorldY); + goto LABEL_18; + } + PlaySfxLoc(PS_DEAD, plr[v3 / 0x54D8].WorldX, plr[v3 / 0x54D8].WorldY); /// BUGFIX: should use `PS_WARR71` like other classes +LABEL_18: + if ( plr[v3 / 0x54D8]._pgfxnum ) + { + plr[v3 / 0x54D8]._pgfxnum = 0; + plr[v3 / 0x54D8]._pGFXLoad = 0; + SetPlrAnims(v2); + } + if ( !(plr[pnum]._pGFXLoad & PFILE_DEATH) ) { + LoadPlrGFX(pnum, PFILE_DEATH); + } + v6 = plr[v3 / 0x54D8]._pDWidth; + NewPlrAnim(v2, plr[0]._pDAnim[plr[v3 / 0x54D8]._pdir + v3 / 4], plr[v3 / 0x54D8]._pDFrames, 1, v6); + plr[v3 / 0x54D8]._pBlockFlag = 0; + plr[v3 / 0x54D8]._pmode = PM_DEATH; + plr[v3 / 0x54D8]._pInvincible = 1; + SetPlayerHitPoints(v2, 0); + v7 = v2 == myplr; + plr[v3 / 0x54D8]._pVar8 = 1; + if ( !v7 && !itm && !v20 ) + { + v8 = &plr[v3 / 0x54D8].InvBody[0]._itype; + v9 = 7; + do + { + *v8 = -1; + v8 += 92; + --v9; + } + while ( v9 ); + CalcPlrInv(v2, 0); + } + if ( plr[v3 / 0x54D8].plrlevel == currlevel ) + { + FixPlayerLocation(v2, plr[v3 / 0x54D8]._pdir); + RemovePlrFromMap(v2); + v10 = &dFlags[plr[v3 / 0x54D8].WorldX][plr[v3 / 0x54D8].WorldY]; + *v10 |= 4u; + SetPlayerOld(v2); + if ( v2 == myplr ) + { + drawhpflag = 1; + deathdelay = 30; + if ( pcurs >= CURSOR_FIRSTITEM ) + { + PlrDeadItem(v2, &plr[v3 / 0x54D8].HoldItem, 0, 0); + SetCursor(CURSOR_HAND); + } + if ( !v20 ) + { + DropHalfPlayersGold(v2); + if ( itm != (struct ItemStruct *)-1 ) + { + if ( itm ) + { + SetPlrHandItem(&ear, IDI_EAR); + sprintf(ear._iName, "Ear of %s", plr[v3 / 0x54D8]._pName); + v11 = plr[v3 / 0x54D8]._pClass; + if ( v11 == 2 ) + { + ear._iCurs = 19; + } + else if ( v11 ) + { + if ( v11 == 1 ) + ear._iCurs = 21; + } + else + { + ear._iCurs = 20; + } + _LOBYTE(v12) = 0; + _HIBYTE(v12) = plr[v3 / 0x54D8]._pName[0]; + v13 = v12 | plr[v3 / 0x54D8]._pName[1]; + v14 = plr[v3 / 0x54D8]._pName[3]; + ear._iCreateInfo = v13; + v15 = plr[v3 / 0x54D8]._pName[5] | ((plr[v3 / 0x54D8]._pName[4] | ((v14 | (plr[v3 / 0x54D8]._pName[2] << 8)) << 8)) << 8); + ear._ivalue = plr[v3 / 0x54D8]._pLevel; + ear._iSeed = v15; + if ( FindGetItem(IDI_EAR, *(int *)&ear._iCreateInfo, v15) == -1 ) + PlrDeadItem(v2, &ear, 0, 0); + } + else + { + itm = plr[v3 / 0x54D8].InvBody; + v17 = 7; + do + { + v18 = ((_BYTE)--v17 + (unsigned char)plr[v3 / 0x54D8]._pdir) & 7; + PlrDeadItem(v2, itm, offset_x[v18], offset_y[v18]); + ++itm; + } + while ( v17 ); + CalcPlrInv(v2, 0); + } + } + } + } + } + SetPlayerHitPoints(v2, 0); +} +// 679660: using guessed type char gbMaxPlayers; +// 69B7C4: using guessed type int deathdelay; + +void __fastcall PlrDeadItem(int pnum, struct ItemStruct *itm, int xx, int yy) +{ + int v4; // edi + int v5; // edi + int v6; // esi + int v7; // ebx + int v8; // eax + int v9; // ST04_4 + ItemStruct *v10; // esi + int v11; // eax + int v12; // ebx + int v13; // esi + //int v14; // eax + int v15; // edx + unsigned char v16; // [esp-8h] [ebp-24h] + unsigned char v17; // [esp-4h] [ebp-20h] + int x; // [esp+Ch] [ebp-10h] + ItemStruct *pItem; // [esp+10h] [ebp-Ch] + int v20; // [esp+14h] [ebp-8h] + int v21; // [esp+14h] [ebp-8h] + int v22; // [esp+18h] [ebp-4h] + int xxa; // [esp+24h] [ebp+8h] + int yya; // [esp+28h] [ebp+Ch] + + pItem = itm; + v4 = pnum; + if ( itm->_itype != -1 ) + { + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("PlrDeadItem: illegal player %d", pnum); + v5 = v4; + v6 = yy + plr[v5].WorldY; + v7 = xx + plr[v5].WorldX; + v20 = yy + plr[v5].WorldY; + if ( (xx || yy) && (v8 = ItemSpaceOk(v7, v6), v8) ) + { + v9 = v6; + v10 = pItem; + RespawnDeadItem(pItem, v7, v9); + v17 = v20; + v16 = v7; + } + else + { + yya = -1; + xxa = 1; + while ( 1 ) + { + v11 = yya; + v21 = yya; +LABEL_14: + if ( v11 <= xxa ) + break; + ++xxa; + if ( --yya <= -50 ) + return; + } + v12 = v21 + plr[v5].WorldY; + v22 = yya; + while ( 1 ) + { + v13 = v22 + plr[v5].WorldX; + x = v22 + plr[v5].WorldX; + //_LOBYTE(v14) = ItemSpaceOk(v13, v12); + if ( ItemSpaceOk(v13, v12) ) + break; + if ( ++v22 > xxa ) + { + v11 = ++v21; + goto LABEL_14; + } + } + v15 = v13; + v10 = pItem; + RespawnDeadItem(pItem, v15, v12); + v17 = v12; + v16 = x; + } + qmemcpy(&plr[v5].HoldItem, v10, sizeof(plr[v5].HoldItem)); + NetSendCmdPItem(0, CMD_RESPAWNITEM, v16, v17); + } +} + +void __fastcall DropHalfPlayersGold(int pnum) +{ + int v1; // ebx + int v2; // esi + int v3; // edi + int v4; // ecx + int v5; // eax + int v6; // ecx + int v7; // eax + int v8; // edx + int v9; // ecx + int v10; // eax + int v11; // edx + int v12; // ecx + int v13; // eax + int v14; // [esp+Ch] [ebp-8h] + int v15; // [esp+Ch] [ebp-8h] + int v16; // [esp+Ch] [ebp-8h] + int v17; // [esp+Ch] [ebp-8h] + signed int i; // [esp+10h] [ebp-4h] + signed int ia; // [esp+10h] [ebp-4h] + signed int ib; // [esp+10h] [ebp-4h] + signed int ic; // [esp+10h] [ebp-4h] + + v1 = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("DropHalfPlayersGold: illegal player %d", pnum); + v2 = v1; + v3 = plr[v1]._pGold >> 1; + i = 0; + while ( v3 > 0 ) + { + v4 = 368 * i + v2 * 21720; + v14 = v4; + if ( *(int *)((char *)&plr[0].SpdList[0]._itype + v4) == ITYPE_GOLD ) + { + v5 = *(int *)((char *)&plr[0].SpdList[0]._ivalue + v4); + if ( v5 != 5000 ) + { + if ( v3 >= v5 ) + { + v3 -= v5; + RemoveSpdBarItem(v1, i); + SetPlrHandItem(&plr[v2].HoldItem, IDI_GOLD); + GetGoldSeed(v1, &plr[v2].HoldItem); + SetPlrHandGoldCurs(&plr[v2].HoldItem); + plr[v2].HoldItem._ivalue = *(int *)((char *)&plr[0].SpdList[0]._ivalue + v14); + PlrDeadItem(v1, &plr[v2].HoldItem, 0, 0); + i = -1; + } + else + { + *(int *)((char *)&plr[0].SpdList[0]._ivalue + v4) = v5 - v3; + SetSpdbarGoldCurs(v1, i); + SetPlrHandItem(&plr[v2].HoldItem, IDI_GOLD); + GetGoldSeed(v1, &plr[v2].HoldItem); + SetPlrHandGoldCurs(&plr[v2].HoldItem); + plr[v2].HoldItem._ivalue = v3; + v3 = 0; + PlrDeadItem(v1, &plr[v2].HoldItem, 0, 0); + } + } + } + if ( ++i >= 8 ) + { + if ( v3 > 0 ) + { + ia = 0; + do + { + if ( v3 <= 0 ) + break; + v6 = 368 * ia + v2 * 21720; + v15 = v6; + if ( *(int *)((char *)&plr[0].SpdList[0]._itype + v6) == ITYPE_GOLD ) + { + v7 = *(int *)((char *)&plr[0].SpdList[0]._ivalue + v6); + if ( v3 >= v7 ) + { + v3 -= v7; + RemoveSpdBarItem(v1, ia); + SetPlrHandItem(&plr[v2].HoldItem, IDI_GOLD); + GetGoldSeed(v1, &plr[v2].HoldItem); + SetPlrHandGoldCurs(&plr[v2].HoldItem); + plr[v2].HoldItem._ivalue = *(int *)((char *)&plr[0].SpdList[0]._ivalue + v15); + PlrDeadItem(v1, &plr[v2].HoldItem, 0, 0); + ia = -1; + } + else + { + *(int *)((char *)&plr[0].SpdList[0]._ivalue + v6) = v7 - v3; + SetSpdbarGoldCurs(v1, ia); + SetPlrHandItem(&plr[v2].HoldItem, IDI_GOLD); + GetGoldSeed(v1, &plr[v2].HoldItem); + SetPlrHandGoldCurs(&plr[v2].HoldItem); + plr[v2].HoldItem._ivalue = v3; + v3 = 0; + PlrDeadItem(v1, &plr[v2].HoldItem, 0, 0); + } + } + ++ia; + } + while ( ia < 8 ); + } + break; + } + } + v8 = 0; + drawpanflag = 255; + if ( v3 > 0 ) + { + ib = 0; + if ( plr[v2]._pNumInv <= 0 ) + { +LABEL_28: + if ( v3 > 0 ) + { + v11 = 0; + for ( ic = 0; ic < plr[v2]._pNumInv; v11 = ic++ + 1 ) + { + if ( v3 <= 0 ) + break; + v12 = 368 * v11 + v2 * 21720; + v17 = v12; + if ( *(int *)((char *)&plr[0].InvList[0]._itype + v12) == ITYPE_GOLD ) + { + v13 = *(int *)((char *)&plr[0].InvList[0]._ivalue + v12); + if ( v3 >= v13 ) + { + v3 -= v13; + RemoveInvItem(v1, v11); + SetPlrHandItem(&plr[v2].HoldItem, IDI_GOLD); + GetGoldSeed(v1, &plr[v2].HoldItem); + SetPlrHandGoldCurs(&plr[v2].HoldItem); + plr[v2].HoldItem._ivalue = *(int *)((char *)&plr[0].InvList[0]._ivalue + v17); + PlrDeadItem(v1, &plr[v2].HoldItem, 0, 0); + ic = -1; + } + else + { + *(int *)((char *)&plr[0].InvList[0]._ivalue + v12) = v13 - v3; + SetGoldCurs(v1, v11); + SetPlrHandItem(&plr[v2].HoldItem, IDI_GOLD); + GetGoldSeed(v1, &plr[v2].HoldItem); + SetPlrHandGoldCurs(&plr[v2].HoldItem); + plr[v2].HoldItem._ivalue = v3; + v3 = 0; + PlrDeadItem(v1, &plr[v2].HoldItem, 0, 0); + } + } + } + } + } + else + { + while ( v3 > 0 ) + { + v9 = 368 * v8 + v2 * 21720; + v16 = v9; + if ( *(int *)((char *)&plr[0].InvList[0]._itype + v9) == ITYPE_GOLD ) + { + v10 = *(int *)((char *)&plr[0].InvList[0]._ivalue + v9); + if ( v10 != 5000 ) + { + if ( v3 >= v10 ) + { + v3 -= v10; + RemoveInvItem(v1, v8); + SetPlrHandItem(&plr[v2].HoldItem, IDI_GOLD); + GetGoldSeed(v1, &plr[v2].HoldItem); + SetPlrHandGoldCurs(&plr[v2].HoldItem); + plr[v2].HoldItem._ivalue = *(int *)((char *)&plr[0].InvList[0]._ivalue + v16); + PlrDeadItem(v1, &plr[v2].HoldItem, 0, 0); + ib = -1; + } + else + { + *(int *)((char *)&plr[0].InvList[0]._ivalue + v9) = v10 - v3; + SetGoldCurs(v1, v8); + SetPlrHandItem(&plr[v2].HoldItem, IDI_GOLD); + GetGoldSeed(v1, &plr[v2].HoldItem); + SetPlrHandGoldCurs(&plr[v2].HoldItem); + plr[v2].HoldItem._ivalue = v3; + v3 = 0; + PlrDeadItem(v1, &plr[v2].HoldItem, 0, 0); + } + } + } + v8 = ib++ + 1; + if ( ib >= plr[v2]._pNumInv ) + goto LABEL_28; + } + } + } + plr[v2]._pGold = CalculateGold(v1); +} +// 52571C: using guessed type int drawpanflag; + +void __fastcall SyncPlrKill(int pnum, int earflag) +{ + if ( plr[pnum]._pHitPoints == 0 && currlevel == 0 ) { + SetPlayerHitPoints(pnum, 64); + return; + } + + for ( int i = 0; i < nummissiles; i++ ) { + int ma = missileactive[i]; + if ( missile[ma]._mitype == MIS_MANASHIELD && missile[ma]._misource == pnum && missile[ma]._miDelFlag == 0 ) { + if ( earflag != -1 ) { + missile[ma]._miVar8 = earflag; + } + + return; + } + } + + SetPlayerHitPoints(pnum, 0); + StartPlayerKill(pnum, earflag); +} + +void __fastcall RemovePlrMissiles(int pnum) +{ + if ( currlevel != 0 && pnum == myplr && (monster[myplr]._mx != 1 || monster[myplr]._my != 0 ) ) { + M_StartKill(myplr, myplr); + AddDead(monster[myplr]._mx, monster[myplr]._my, monster[myplr].MType->mdeadval, (direction)monster[myplr]._mdir); + dMonster[monster[myplr]._mx][monster[myplr]._my] = 0; + monster[myplr]._mDelFlag = 1; + DeleteMonsterList(); + } + + for ( int mi = 0; mi < nummissiles; mi++ ) { + int am = missileactive[mi]; + if ( missile[am]._mitype == MIS_STONE && missile[am]._misource == pnum ) { + monster[missile[am]._miVar2]._mmode = missile[am]._miVar1; + } + if ( missile[am]._mitype == MIS_MANASHIELD && missile[am]._misource == pnum ) { + ClearMissileSpot(am); + DeleteMissile(am, mi); + } + if ( missile[am]._mitype == MIS_ETHEREALIZE && missile[am]._misource == pnum ) { + ClearMissileSpot(am); + DeleteMissile(am, mi); + } + } +} + +void __fastcall InitLevelChange(int pnum) +{ + RemovePlrMissiles(pnum); + if ( pnum == myplr && qtextflag ) { + qtextflag = 0; + sfx_stop(); + } + + RemovePlrFromMap(pnum); + SetPlayerOld(pnum); + if ( pnum == myplr ) { + dPlayer[plr[myplr].WorldX][plr[myplr].WorldY] = myplr + 1; + } else { + plr[pnum]._pLvlVisited[plr[pnum].plrlevel] = 1; + } + + ClrPlrPath(pnum); + plr[pnum].destAction = -1; + plr[pnum]._pLvlChanging = 1; + + if ( pnum == myplr ) { + plr[pnum].pLvlLoad = 10; + } +} +// 646D00: using guessed type char qtextflag; + +void __fastcall StartNewLvl(int pnum, int fom, int lvl) +{ + InitLevelChange(pnum); + + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("StartNewLvl: illegal player %d", pnum); + } + + switch ( fom ) { + case WM_DIABNEXTLVL: + case WM_DIABPREVLVL: + plr[pnum].plrlevel = lvl; + break; + case WM_DIABRTNLVL: + case WM_DIABTOWNWARP: + plr[pnum].plrlevel = lvl; + break; + case WM_DIABSETLVL: + setlvlnum = lvl; + break; + case WM_DIABTWARPUP: + plr[myplr].pTownWarps |= 1 << (leveltype - 2); + plr[pnum].plrlevel = lvl; + break; + case WM_DIABRETOWN: + break; + default: + TermMsg("StartNewLvl"); + } + + if ( pnum == myplr ) { + plr[pnum]._pmode = PM_NEWLVL; + plr[pnum]._pInvincible = TRUE; + PostMessage(ghMainWnd, fom, 0, 0); + if ( gbMaxPlayers > 1 ) { + NetSendCmdParam2(TRUE, CMD_NEWLVL, fom, lvl); + } + } +} +// 5BB1ED: using guessed type char leveltype; +// 5CCB10: using guessed type char setlvlnum; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall RestartTownLvl(int pnum) +{ + unsigned int v1; // edi + unsigned int v2; // esi + int v3; // eax + HWND v4; // ST00_4 + + v1 = pnum; + InitLevelChange(pnum); + if ( v1 >= 4 ) + TermMsg("RestartTownLvl: illegal player %d", v1); + v2 = v1; + plr[v2].plrlevel = 0; + plr[v2]._pInvincible = 0; + SetPlayerHitPoints(v1, 64); + v3 = plr[v2]._pMaxManaBase - plr[v2]._pMaxMana; + plr[v2]._pMana = 0; + plr[v2]._pManaBase = v3; + CalcPlrInv(v1, 0); + if ( v1 == myplr ) + { + plr[v2]._pmode = PM_NEWLVL; + v4 = ghMainWnd; + plr[v2]._pInvincible = 1; + PostMessage(v4, WM_DIABRETOWN, 0, 0); + } +} + +void __fastcall StartWarpLvl(int pnum, int pidx) +{ + InitLevelChange(pnum); + + if ( gbMaxPlayers != 1 ) { + if ( plr[pnum].plrlevel != 0 ) { + plr[pnum].plrlevel = 0; + } else { + plr[pnum].plrlevel = portal[pidx].level; + } + } + + if ( pnum == myplr ) { + SetCurrentPortal(pidx); + plr[pnum]._pmode = PM_NEWLVL; + plr[pnum]._pInvincible = TRUE; + PostMessage(ghMainWnd, WM_DIABWARPLVL, 0, 0); + } +} +// 679660: using guessed type char gbMaxPlayers; + +BOOL __fastcall PM_DoStand(int pnum) +{ + return FALSE; +} + +BOOL __fastcall PM_DoWalk(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("PM_DoWalk: illegal player %d", pnum); + } + + if ( plr[pnum]._pAnimFrame == 3 + || (plr[pnum]._pWFrames == 8 && plr[pnum]._pAnimFrame == 7) + || (plr[pnum]._pWFrames != 8 && plr[pnum]._pAnimFrame == 4) + ) { + PlaySfxLoc(PS_WALK1, plr[pnum].WorldX, plr[pnum].WorldY); + } + + int vel = 8; + if ( currlevel ) { + vel = PWVel[3][plr[pnum]._pClass]; + } + + if ( plr[pnum]._pVar8 == vel ) { + dPlayer[plr[pnum].WorldX][plr[pnum].WorldY] = 0; + plr[pnum].WorldX += plr[pnum]._pVar1; + plr[pnum].WorldY += plr[pnum]._pVar2; + dPlayer[plr[pnum].WorldX][plr[pnum].WorldY] = pnum + 1; + + if ( leveltype != DTYPE_TOWN ) { + ChangeLightXY(plr[pnum]._plid, plr[pnum].WorldX, plr[pnum].WorldY); + ChangeVisionXY(plr[pnum]._pvid, plr[pnum].WorldX, plr[pnum].WorldY); + } + + if ( pnum == myplr && ScrollInfo._sdir ) { + ViewX = plr[pnum].WorldX - ScrollInfo._sdx; + ViewY = plr[pnum].WorldY - ScrollInfo._sdy; + } + + if ( plr[pnum].walkpath[0] != -1 ) { + StartWalkStand(pnum); + } else { + StartStand(pnum, plr[pnum]._pVar3); + } + + ClearPlrPVars(pnum); + if ( leveltype != DTYPE_TOWN ) { + ChangeLightOff(plr[pnum]._plid, 0, 0); + } + + return TRUE; + } + + PM_ChangeOffset(pnum); + return FALSE; + +} +// 5BB1ED: using guessed type char leveltype; + +BOOL __fastcall PM_DoWalk2(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("PM_DoWalk2: illegal player %d", pnum); + } + + if ( plr[pnum]._pAnimFrame == 3 + || (plr[pnum]._pWFrames == 8 && plr[pnum]._pAnimFrame == 7) + || (plr[pnum]._pWFrames != 8 && plr[pnum]._pAnimFrame == 4) + ) { + PlaySfxLoc(PS_WALK1, plr[pnum].WorldX, plr[pnum].WorldY); + } + + int vel = 8; + if ( currlevel ) { + vel = PWVel[3][plr[pnum]._pClass]; + } + + if ( plr[pnum]._pVar8 == vel ) { + dPlayer[plr[pnum]._pVar1][plr[pnum]._pVar2] = 0; + if ( leveltype != DTYPE_TOWN ) { + ChangeLightXY(plr[pnum]._plid, plr[pnum].WorldX, plr[pnum].WorldY); + ChangeVisionXY(plr[pnum]._pvid, plr[pnum].WorldX, plr[pnum].WorldY); + } + + if ( pnum == myplr && ScrollInfo._sdir ) { + ViewX = plr[pnum].WorldX - ScrollInfo._sdx; + ViewY = plr[pnum].WorldY - ScrollInfo._sdy; + } + + if ( plr[pnum].walkpath[0] != -1 ) { + StartWalkStand(pnum); + } else { + StartStand(pnum, plr[pnum]._pVar3); + } + + ClearPlrPVars(pnum); + + if ( leveltype != DTYPE_TOWN ) { + ChangeLightOff(plr[pnum]._plid, 0, 0); + } + + return TRUE; + } + + PM_ChangeOffset(pnum); + return FALSE; +} +// 5BB1ED: using guessed type char leveltype; + +BOOL __fastcall PM_DoWalk3(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("PM_DoWalk3: illegal player %d", pnum); + } + + if ( plr[pnum]._pAnimFrame == 3 + || (plr[pnum]._pWFrames == 8 && plr[pnum]._pAnimFrame == 7) + || (plr[pnum]._pWFrames != 8 && plr[pnum]._pAnimFrame == 4) + ) { + PlaySfxLoc(PS_WALK1, plr[pnum].WorldX, plr[pnum].WorldY); + } + + int vel = 8; + if ( currlevel ) { + vel = PWVel[3][plr[pnum]._pClass]; + } + + if ( plr[pnum]._pVar8 == vel ) { + dPlayer[plr[pnum].WorldX][plr[pnum].WorldY] = 0; + dFlags[plr[pnum]._pVar4][plr[pnum]._pVar5] &= 0xDFu; + plr[pnum].WorldX = plr[pnum]._pVar1; + plr[pnum].WorldY = plr[pnum]._pVar2; + dPlayer[plr[pnum]._pVar1][plr[pnum]._pVar2] = pnum + 1; + + if ( leveltype != DTYPE_TOWN ) { + ChangeLightXY(plr[pnum]._plid, plr[pnum]._pVar1, plr[pnum]._pVar2); + ChangeVisionXY(plr[pnum]._pvid, plr[pnum].WorldX, plr[pnum].WorldY); + } + + if ( pnum == myplr && ScrollInfo._sdir ) { + ViewX = plr[pnum].WorldX - ScrollInfo._sdx; + ViewY = plr[pnum].WorldY - ScrollInfo._sdy; + } + + if ( plr[pnum].walkpath[0] != -1 ) { + StartWalkStand(pnum); + } else { + StartStand(pnum, plr[pnum]._pVar3); + } + + ClearPlrPVars(pnum); + + if ( leveltype != DTYPE_TOWN ) { + ChangeLightOff(plr[pnum]._plid, 0, 0); + } + + return TRUE; + } + + PM_ChangeOffset(pnum); + return FALSE; +} +// 5BB1ED: using guessed type char leveltype; + +BOOL __fastcall WeaponDur(int pnum, int durrnd) +{ + if ( pnum != myplr ) { + return FALSE; + } + + if ( random(3, durrnd) != 0 ) { + return FALSE; + } + + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("WeaponDur: illegal player %d", pnum); + } + + if ( plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON ) { + if ( plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability == 255 ) { + return FALSE; + } + + plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability--; + if ( plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability != 0) { + NetSendCmdDelItem(TRUE, INVLOC_HAND_LEFT); + plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype = ITYPE_NONE; + CalcPlrInv(pnum, TRUE); + return TRUE; + } + } + + if ( plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON ) { + if ( plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iDurability == 255 ) { + return FALSE; + } + + plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iDurability--; + if ( plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iDurability != 0 ) { + NetSendCmdDelItem(TRUE, INVLOC_HAND_RIGHT); + plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype = ITYPE_NONE; + CalcPlrInv(pnum, TRUE); + return TRUE; + } + } + + if ( plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD ) { + if ( plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iDurability == 255 ) { + return FALSE; + } + + plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iDurability--; + if ( plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iDurability != 0 ) { + NetSendCmdDelItem(TRUE, INVLOC_HAND_RIGHT); + plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype = ITYPE_NONE; + CalcPlrInv(pnum, TRUE); + return TRUE; + } + } + + if ( plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD ) { + if ( plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability != 255 ) { + plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability--; + if ( plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability != 0 ) { + NetSendCmdDelItem(TRUE, INVLOC_HAND_LEFT); + plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype = ITYPE_NONE; + CalcPlrInv(pnum, TRUE); + return TRUE; + } + } + } + + return FALSE; +} + +bool __fastcall PlrHitMonst(int pnum, int m) +{ + int v2; // ebx + unsigned int v3; // esi + //int v4; // ST04_4 + int v5; // ebx + //int v7; // ST04_4 + int v8; // eax + unsigned int v9; // esi + int v10; // ecx + int v11; // eax + int v12; // edi + int v13; // edi + //int v14; // eax + int v16; // edx + int v17; // eax + int v18; // ecx + int v19; // edi + int v20; // eax + int v21; // eax + char v22; // dl + bool v23; // zf + int v24; // eax + int v25; // ecx + int v26; // edi + int v27; // eax + int v28; // edx + int *v29; // ecx + int v30; // edx + int *v31; // ecx + int v32; // ecx + int v33; // edx + int *v34; // ecx + int v35; // edx + int *v36; // ecx + int v37; // edx + int *v38; // ecx + int *v39; // ecx + int v40; // esi + BOOL ret; // [esp+Ch] [ebp-18h] + bool v42; // [esp+10h] [ebp-14h] + int v48; + int v43; // [esp+14h] [ebp-10h] + int pnuma; // [esp+18h] [ebp-Ch] + int arglist; // [esp+1Ch] [ebp-8h] + int v46; // [esp+20h] [ebp-4h] + + v2 = m; + v3 = pnum; + arglist = m; + pnuma = pnum; + if ( (unsigned int)m >= 0xC8 ) + { + TermMsg("PlrHitMonst: illegal monster %d", m); + //pnum = v4; + } + v5 = 228 * v2; + v43 = v5; + if ( (signed int)(*(int *)((_BYTE *)&monster[0]._mhitpoints + v5) & 0xFFFFFFC0) <= 0 + || **(_BYTE **)((char *)&monster[0].MType + v5) == MT_ILLWEAV && *((_BYTE *)&monster[0]._mgoal + v5) == 2 + || *(MON_MODE *)((char *)&monster[0]._mmode + v5) == MM_CHARGE ) + { + return 0; + } + if ( v3 >= 4 ) + { + TermMsg("PlrHitMonst: illegal player %d", v3); + //pnum = v7; + } + v42 = 0; + v8 = random(4, 100); + v23 = *(MON_MODE *)((char *)&monster[0]._mmode + v5) == MM_STONE; + v46 = v8; + if ( v23 ) + v46 = 0; + v9 = v3; + v10 = plr[v9]._pLevel; + v11 = plr[v9]._pIEnAc + (plr[v9]._pDexterity >> 1) - *((unsigned char *)&monster[0].mArmorClass + v5); + v12 = v11 + v10 + 50; + if ( !_LOBYTE(plr[v9]._pClass) ) + v12 = v11 + v10 + 70; + v13 = plr[v9]._pIBonusToHit + v12; + if ( v13 < 5 ) + v13 = 5; + if ( v13 > 95 ) + v13 = 95; + if ( CheckMonsterHit(arglist, &ret) ) + return ret; +#ifdef _DEBUG + if ( (signed int)v46 < v13 || debug_mode_key_inverted_v || debug_mode_dollar_sign ) +#else + if ( (signed int)v46 < v13 ) +#endif + { + v16 = plr[v9]._pIMaxDam - plr[v9]._pIMinDam + 1; + v48 = plr[v9]._pIMinDam; + v17 = random(5, v16); + v18 = 100; + v19 = plr[v9]._pIBonusDamMod + plr[v9]._pDamageMod + (v48 + v17) * plr[v9]._pIBonusDam / 100 + v48 + v17; + if ( !_LOBYTE(plr[v9]._pClass) ) + { + v48 = plr[v9]._pLevel; + v20 = random(6, 100); + if ( v20 < v48 ) + v19 *= 2; + } + v21 = plr[v9].InvBody[4]._itype; + v46 = -1; + if ( v21 == 1 || plr[v9].InvBody[5]._itype == 1 ) + v46 = 1; + if ( v21 == ITYPE_MACE || plr[v9].InvBody[5]._itype == ITYPE_MACE ) + v46 = ITYPE_MACE; + v22 = (*(MonsterData **)((char *)&monster[0].MData + v5))->mMonstClass; + if ( v22 ) + { + if ( v22 != 2 ) + goto LABEL_40; + if ( v46 == ITYPE_MACE ) + v19 -= v19 >> 1; + v23 = v46 == 1; + } + else + { + if ( v46 == 1 ) + v19 -= v19 >> 1; + v23 = v46 == ITYPE_MACE; + } + if ( v23 ) + v19 += v19 >> 1; +LABEL_40: + v24 = plr[v9]._pIFlags; + if ( v24 & 0x40000000 && v22 == 1 ) + v19 *= 3; + v25 = pnuma; + v26 = v19 << 6; + if ( pnuma == myplr ) + *(int *)((char *)&monster[0]._mhitpoints + v5) -= v26; + if ( v24 & 2 ) + { + v27 = random(7, v26 >> 3); + v28 = plr[v9]._pMaxHP; + v29 = &plr[v9]._pHitPoints; + *v29 += v27; + if ( plr[v9]._pHitPoints > v28 ) + *v29 = v28; + v30 = plr[v9]._pMaxHPBase; + v31 = &plr[v9]._pHPBase; + *v31 += v27; + if ( plr[v9]._pHPBase > v30 ) + *v31 = v30; + v5 = v43; + drawhpflag = 1; + } + else + { + v27 = ret; + } + v46 = plr[v9]._pIFlags; + v32 = v46; + if ( v32 & 0x6000 && !(v46 & 0x8000000) ) + { + if ( v32 & 0x2000 ) + v27 = 3 * v26 / 100; + if ( v32 & 0x4000 ) + v27 = 5 * v26 / 100; + v33 = plr[v9]._pMaxMana; + v34 = &plr[v9]._pMana; + *v34 += v27; + if ( plr[v9]._pMana > v33 ) + *v34 = v33; + v35 = plr[v9]._pMaxManaBase; + v36 = &plr[v9]._pManaBase; + *v36 += v27; + if ( plr[v9]._pManaBase > v35 ) + *v36 = v35; + v5 = v43; + v32 = v46; + drawmanaflag = 1; + } + if ( v32 & 0x18000 ) + { + if ( (v32 & 0x8000) != 0 ) + v27 = 3 * v26 / 100; + if ( v32 & 0x10000 ) + v27 = 5 * v26 / 100; + v37 = plr[v9]._pMaxHP; + v38 = &plr[v9]._pHitPoints; + *v38 += v27; + if ( plr[v9]._pHitPoints > v37 ) + *v38 = v37; + v39 = &plr[v9]._pHPBase; + v40 = plr[v9]._pMaxHPBase; + *v39 += v27; + if ( *v39 > v40 ) + *v39 = v40; + BYTE1(v32) = BYTE1(v46); + v5 = v43; + drawhpflag = 1; + } + if ( v32 & 0x100 ) + *(int *)((char *)&monster[0]._mFlags + v5) |= 8u; +#ifdef _DEBUG + if ( debug_mode_dollar_sign || debug_mode_key_inverted_v ) + monster[m]._mhitpoints = 0; /* double check */ +#endif + if ( (signed int)(*(int *)((_BYTE *)&monster[0]._mhitpoints + v5) & 0xFFFFFFC0) > 0 ) + { + if ( *(MON_MODE *)((char *)&monster[0]._mmode + v5) != MM_STONE ) + { + if ( v32 & 0x800 ) + M_GetKnockback(arglist); + M_StartHit(arglist, pnuma, v26); + goto LABEL_85; + } + M_StartHit(arglist, pnuma, v26); + } + else + { + if ( *(MON_MODE *)((char *)&monster[0]._mmode + v5) != MM_STONE ) + { + M_StartKill(arglist, pnuma); + goto LABEL_85; + } + M_StartKill(arglist, pnuma); + } + *(MON_MODE *)((char *)&monster[0]._mmode + v5) = MM_STONE; +LABEL_85: + v42 = 1; + } + return v42; +} + +bool __fastcall PlrHitPlr(int pnum, char p) +{ + char v2; // bl + unsigned int v3; // esi + //int v4; // ST04_4 + int v5; // edi + //int v7; // ST04_4 + unsigned int v8; // esi + int v9; // ecx + int v10; // eax + int v11; // ebx + int v12; // ebx + int v13; // eax + int v14; // eax + int v15; // ecx + int v16; // eax + int v17; // ebx + int v18; // eax + int v19; // ecx + int v20; // edi + int v21; // ebx + signed int v22; // edi + int v23; // eax + int v24; // edx + int *v25; // ecx + int *v26; // ecx + int v27; // esi + int v28; // [esp+Ch] [ebp-14h] + int v29; // [esp+10h] [ebp-10h] + bool v30; // [esp+14h] [ebp-Ch] + int arglist; // [esp+18h] [ebp-8h] + char bPlr; // [esp+1Ch] [ebp-4h] + + v2 = p; + v3 = pnum; + bPlr = p; + v28 = pnum; + if ( (unsigned char)p >= 4u ) + { + TermMsg("PlrHitPlr: illegal target player %d", p); + //pnum = v4; + } + arglist = v2; + v5 = v2; + v30 = 0; + if ( plr[v5]._pInvincible || plr[v5]._pSpellFlags & 1 ) + return 0; + if ( v3 >= 4 ) + { + TermMsg("PlrHitPlr: illegal attacking player %d", v3); + //pnum = v7; + } + v8 = v3; + v29 = random(4, 100); + v9 = (plr[v8]._pDexterity >> 1) - plr[v5]._pIBonusAC - plr[v5]._pIAC - plr[v5]._pDexterity / 5; + v10 = plr[v8]._pLevel; + v11 = v9 + v10 + 50; + if ( !_LOBYTE(plr[v8]._pClass) ) + v11 = v9 + v10 + 70; + v12 = plr[v8]._pIBonusToHit + v11; + if ( v12 < 5 ) + v12 = 5; + if ( v12 > 95 ) + v12 = 95; + v13 = plr[v5]._pmode; + if ( v13 && v13 != 4 || !plr[v5]._pBlockFlag ) + { + v14 = 100; + } + else + { + v14 = random(5, 100); + } + v15 = plr[v5]._pDexterity + plr[v5]._pBaseToBlk + 2 * plr[v5]._pLevel - 2 * plr[v8]._pLevel; + if ( v15 < 0 ) + v15 = 0; + if ( v15 > 100 ) + v15 = 100; + if ( v29 < v12 ) + { + if ( v14 >= v15 ) + { + v17 = plr[v8]._pIMinDam; + v18 = random(5, plr[v8]._pIMaxDam - v17 + 1); + v19 = 100; + v20 = plr[v8]._pIBonusDamMod + plr[v8]._pDamageMod + (v17 + v18) * plr[v8]._pIBonusDam / 100 + v17 + v18; + if ( !_LOBYTE(plr[v8]._pClass) ) + { + v21 = plr[v8]._pLevel; + if ( random(6, 100) < v21 ) + v20 *= 2; + } + v22 = v20 << 6; + if ( plr[v8]._pIFlags & 2 ) + { + v23 = random(7, v22 >> 3); + v24 = plr[v8]._pMaxHP; + v25 = &plr[v8]._pHitPoints; + *v25 += v23; + if ( plr[v8]._pHitPoints > v24 ) + *v25 = v24; + v26 = &plr[v8]._pHPBase; + v27 = plr[v8]._pMaxHPBase; + *v26 += v23; + if ( *v26 > v27 ) + *v26 = v27; + drawhpflag = 1; + } + if ( v28 == myplr ) + NetSendCmdDamage(1u, bPlr, v22); + StartPlrHit(arglist, v22, 0); + } + else + { + v16 = GetDirection(plr[v5].WorldX, plr[v5].WorldY, plr[v8].WorldX, plr[v8].WorldY); + StartPlrBlock(arglist, v16); + } + v30 = 1; + } + return v30; +} + +BOOL __fastcall PlrHitObj(int pnum, int mx, int my) +{ + int oi; + + if ( dObject[mx][my] > 0 ) { + oi = dObject[mx][my] - 1; + } else { + oi = -dObject[mx][my] - 1; + } + + if ( object[oi]._oBreak == 1 ) { + BreakObject(pnum, oi); + return TRUE; + } + + return FALSE; +} + +int __fastcall PM_DoAttack(int pnum) +{ + int v1; // esi + int v2; // esi + int v3; // ecx + int v4; // eax + int v5; // eax + int v6; // ebx + int v7; // edi + int v8; // eax + int v9; // edx + int v10; // ecx + //int v11; // eax + int v12; // edx + int v13; // eax + bool v14; // eax + int v15; // edx + char v16; // al + //int v17; // eax + int v19; // [esp+Ch] [ebp-8h] + int arglist; // [esp+10h] [ebp-4h] + + v1 = pnum; + arglist = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("PM_DoAttack: illegal player %d", pnum); + v2 = v1; + v3 = plr[v2]._pIFlags; + v4 = plr[v2]._pAnimFrame; + if ( v3 & 0x20000 && v4 == 1 ) // quick attack + plr[v2]._pAnimFrame = 2; + if ( v3 & 0x40000 && (v4 == 1 || v4 == 3) ) // fast attack + ++plr[v2]._pAnimFrame; + if ( v3 & 0x80000 && (v4 == 1 || v4 == 3 || v4 == 5) ) // faster attack + ++plr[v2]._pAnimFrame; + if ( v3 & 0x100000 && (v4 == 1 || v4 == 4) ) // fastest attack + plr[v2]._pAnimFrame += 2; + if ( plr[v2]._pAnimFrame == plr[v2]._pAFNum - 1 ) + PlaySfxLoc(PS_SWING, plr[v2].WorldX, plr[v2].WorldY); + if ( plr[v2]._pAnimFrame != plr[v2]._pAFNum ) + goto LABEL_49; + v5 = plr[v2]._pdir; + v6 = plr[v2].WorldX + offset_x[v5]; + v7 = plr[v2].WorldY + offset_y[v5]; + v8 = v7 + 112 * v6; + v19 = v8; + v9 = dMonster[0][v8]; + if ( !v9 ) + { +LABEL_29: + if ( plr[v2]._pIFlags & 0x10 ) + { + AddMissile(v6, v7, 1, 0, 0, MIS_WEAPEXP, 0, arglist, 0, 0); + v8 = v19; + } + if ( plr[v2]._pIFlags & 0x20 ) + { + AddMissile(v6, v7, 2, 0, 0, MIS_WEAPEXP, 0, arglist, 0, 0); + v8 = v19; + } + v12 = dMonster[0][v8]; + if ( v12 ) + { + if ( v12 <= 0 ) + v13 = -1 - v12; + else + v13 = v12 - 1; + v14 = PlrHitMonst(arglist, v13); + goto LABEL_46; + } + v15 = (unsigned char)dPlayer[0][v8]; + if ( (_BYTE)v15 && !FriendlyMode ) + { + if ( (char)v15 <= 0 ) + v16 = -1 - v15; + else + v16 = v15 - 1; + v14 = PlrHitPlr(arglist, v16); +LABEL_46: + if ( v14 ) + { + //_LOBYTE(v17) = WeaponDur(arglist, 30); + if ( WeaponDur(arglist, 30) ) + goto LABEL_48; + } + goto LABEL_49; + } + if ( dObject[0][v8] > 0 ) + { + v14 = PlrHitObj(arglist, v6, v7); + goto LABEL_46; + } +LABEL_49: + if ( plr[v2]._pAnimFrame != plr[v2]._pAFrames ) + return 0; +LABEL_48: + StartStand(arglist, plr[v2]._pdir); + ClearPlrPVars(arglist); + return 1; + } + if ( v9 <= 0 ) + v10 = -1 - v9; + else + v10 = v9 - 1; + //_LOBYTE(v11) = CanTalkToMonst(v10); + if ( !CanTalkToMonst(v10) ) + { + v8 = v19; + goto LABEL_29; + } + plr[v2]._pVar1 = 0; + return 0; +} +// 484368: using guessed type int FriendlyMode; + +BOOL __fastcall PM_DoRangeAttack(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("PM_DoRangeAttack: illegal player %d", pnum); + } + + int origFrame = plr[pnum]._pAnimFrame; + if ( plr[pnum]._pIFlags & ISPL_QUICKATTACK && origFrame == 1 ) { + plr[pnum]._pAnimFrame++; + } + if ( plr[pnum]._pIFlags & ISPL_FASTATTACK && (origFrame == 1 || origFrame == 3) ) { + plr[pnum]._pAnimFrame++; + } + + if ( plr[pnum]._pAnimFrame == plr[pnum]._pAFNum ) { + int mistype = MIS_ARROW; + if ( plr[pnum]._pIFlags & ISPL_FIRE_ARROWS ) { + mistype = MIS_FARROW; + } + if ( plr[pnum]._pIFlags & ISPL_LIGHT_ARROWS ) { + mistype = MIS_LARROW; + } + AddMissile( + plr[pnum].WorldX, + plr[pnum].WorldY, + plr[pnum]._pVar1, + plr[pnum]._pVar2, + plr[pnum]._pdir, + mistype, + 0, + pnum, + 4, + 0 + ); + + PlaySfxLoc(PS_BFIRE, plr[pnum].WorldX, plr[pnum].WorldY); + + if ( WeaponDur(pnum, 40) ) { + StartStand(pnum, plr[pnum]._pdir); + ClearPlrPVars(pnum); + return TRUE; + } + } + + if ( plr[pnum]._pAnimFrame >= plr[pnum]._pAFrames ) { + StartStand(pnum, plr[pnum]._pdir); + ClearPlrPVars(pnum); + return TRUE; + } else { + return FALSE; + } + +} + +void __fastcall ShieldDur(int pnum) +{ + if ( pnum != myplr ) { + return; + } + + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("ShieldDur: illegal player %d", pnum); + } + + if ( plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD ) { + if ( plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability == 255 ) { + return; + } + + plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability--; + if ( plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability == 0 ) { + NetSendCmdDelItem(TRUE, INVLOC_HAND_LEFT); + plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype = ITYPE_NONE; + CalcPlrInv(pnum, TRUE); + } + } + + if ( plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD ) { + if ( plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iDurability != 255 ) { + plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iDurability--; + if ( plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iDurability == 0 ) { + NetSendCmdDelItem(TRUE, INVLOC_HAND_RIGHT); + plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype = ITYPE_NONE; + CalcPlrInv(pnum, TRUE); + } + } + } +} + +BOOL __fastcall PM_DoBlock(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("PM_DoBlock: illegal player %d", pnum); + } + + if ( plr[pnum]._pIFlags & ISPL_FASTBLOCK && plr[pnum]._pAnimFrame != 1 ) { + plr[pnum]._pAnimFrame = plr[pnum]._pBFrames; + } + + if ( plr[pnum]._pAnimFrame >= plr[pnum]._pBFrames ) { + StartStand(pnum, plr[pnum]._pdir); + ClearPlrPVars(pnum); + + if ( !random(3, 10) ) { + ShieldDur(pnum); + } + return TRUE; + } + + return FALSE; +} + +BOOL __fastcall PM_DoSpell(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("PM_DoSpell: illegal player %d", pnum); + } + + if ( plr[pnum]._pVar8 == plr[pnum]._pSFNum ) + { + CastSpell( + pnum, + plr[pnum]._pSpell, + plr[pnum].WorldX, + plr[pnum].WorldY, + plr[pnum]._pVar1, + plr[pnum]._pVar2, + FALSE, + plr[pnum]._pVar4 + ); + + if ( !plr[pnum]._pSplFrom ) { + if ( plr[pnum]._pRSplType == RSPLTYPE_SCROLL) { + if ( !(plr[pnum]._pScrlSpells64 + & (UINT64)1 << (plr[pnum]._pRSpell - 1)) + ) { + plr[pnum]._pRSpell = SPL_INVALID; + plr[pnum]._pRSplType = RSPLTYPE_INVALID; + drawpanflag = 255; + } + } + + if ( plr[pnum]._pRSplType == RSPLTYPE_CHARGES) { + if ( !(plr[pnum]._pISpells64 + & (UINT64)1 << (plr[pnum]._pRSpell - 1)) + ) { + plr[pnum]._pRSpell = SPL_INVALID; + plr[pnum]._pRSplType = RSPLTYPE_INVALID; + drawpanflag = 255; + } + } + } + } + + plr[pnum]._pVar8++; + + if ( leveltype == DTYPE_TOWN ) { + if ( plr[pnum]._pVar8 > plr[pnum]._pSFrames ) { + StartWalkStand(pnum); + ClearPlrPVars(pnum); + return TRUE; + } + } else if ( plr[pnum]._pAnimFrame == plr[pnum]._pSFrames ) { + StartStand(pnum, plr[pnum]._pdir); + ClearPlrPVars(pnum); + return TRUE; + } + + return FALSE; +} +// 52571C: using guessed type int drawpanflag; +// 5BB1ED: using guessed type char leveltype; + +int __fastcall PM_DoGotHit(int pnum) +{ + int v1; // esi + int v2; // eax + int v3; // edx + int v4; // ecx + + v1 = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("PM_DoGotHit: illegal player %d", pnum); + v2 = v1; + v3 = plr[v1]._pIFlags; + v4 = plr[v1]._pAnimFrame; + if ( v3 & 0x200000 && v4 == 3 ) + plr[v2]._pAnimFrame = 4; + if ( v3 & 0x400000 && (v4 == 3 || v4 == 5) ) + ++plr[v2]._pAnimFrame; + if ( v3 & 0x800000 && (v4 == 1 || v4 == 3 || v4 == 5) ) + ++plr[v2]._pAnimFrame; + if ( plr[v2]._pAnimFrame < plr[v2]._pHFrames ) + return 0; + StartStand(v1, plr[v2]._pdir); + ClearPlrPVars(v1); + if ( random(3, 4) ) + ArmorDur(v1); + return 1; +} + +void __fastcall ArmorDur(int pnum) +{ + int v1; // ebp + //int v2; // ST04_4 + PlayerStruct *v3; // esi + int v4; // eax + int v5; // edi + int v6; // esi + int v7; // ecx + int v8; // ecx + unsigned char v9; // dl + + v1 = pnum; + if ( pnum == myplr ) + { + if ( (unsigned int)pnum >= MAX_PLRS ) + { + TermMsg("ArmorDur: illegal player %d", pnum); + //pnum = v2; + } + v3 = &plr[v1]; + if ( v3->InvBody[6]._itype != -1 || v3->InvBody[0]._itype != -1 ) + { + v4 = random(8, 3); + v5 = v3->InvBody[6]._itype; + if ( v5 == -1 ) + goto LABEL_23; + if ( v3->InvBody[0]._itype == -1 ) + v4 = 1; + if ( v5 == -1 ) + { +LABEL_23: + if ( v3->InvBody[0]._itype != -1 ) + v4 = 0; + } + if ( v4 ) + v6 = (int)&v3->InvBody[6]; + else + v6 = (int)v3->InvBody; + v7 = *(_DWORD *)(v6 + 236); + if ( v7 != 255 ) + { + v8 = v7 - 1; + *(_DWORD *)(v6 + 236) = v8; + if ( !v8 ) + { + if ( v4 ) + v9 = 6; + else + v9 = 0; + NetSendCmdDelItem(1u, v9); + *(_DWORD *)(v6 + 8) = -1; + CalcPlrInv(v1, 1u); + } + } + } + } +} + +int __fastcall PM_DoDeath(int pnum) +{ + int v1; // edi + int v2; // esi + int v3; // ecx + int v4; // eax + int v5; // eax + + v1 = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("PM_DoDeath: illegal player %d", pnum); + v2 = v1; + if ( plr[v1]._pVar8 >= 2 * plr[v1]._pDFrames ) + { + if ( deathdelay > 1 && v1 == myplr && --deathdelay == 1 ) + { + deathflag = 1; + if ( gbMaxPlayers == 1 ) + gamemenu_previous(); + } + v3 = plr[v2].WorldY; + plr[v2]._pAnimFrame = plr[v2]._pAnimLen; + v4 = plr[v2].WorldX; + plr[v2]._pAnimDelay = 10000; + dFlags[v4][v3] |= 4u; + } + v5 = plr[v2]._pVar8; + if ( v5 < 100 ) + plr[v2]._pVar8 = v5 + 1; + return 0; +} +// 679660: using guessed type char gbMaxPlayers; +// 69B7C4: using guessed type int deathdelay; + +void __fastcall CheckNewPath(int pnum) +{ + int v1; // edi + int v2; // ebx + int v3; // eax + int v4; // ecx + bool v5; // zf + int v6; // eax + int v7; // esi + int v8; // eax + int v9; // edx + int v10; // esi + int v11; // esi + int v12; // eax + int v13; // eax + int v14; // ecx + int v15; // edx + int v16; // eax + int v17; // eax + int v18; // eax + int v19; // ecx + int v20; // eax + int v21; // edi + int v22; // esi + int v23; // ST38_4 + int v24; // eax + int v25; // esi + int v26; // esi + int v27; // ST38_4 + int v28; // eax + int v29; // ecx + int v30; // edx + int v31; // ecx + int *v32; // esi + int *v33; // edi + int v34; // esi + int v35; // eax + int v36; // ecx + int v37; // eax + int v38; // eax + int v39; // eax + int v40; // eax + int v41; // eax + int *v42; // esi + int *v43; // edi + int v44; // eax + int v45; // eax + int v46; // esi + int v47; // esi + int v48; // eax + int v49; // ecx + int v50; // esi + int v51; // eax + int v52; // ecx + int v53; // edi + int v54; // esi + int v55; // ST38_4 + int v56; // eax + int v57; // edi + int v58; // esi + int v59; // ST38_4 + int v60; // eax + int v61; // eax + int v62; // ecx + int v63; // esi + int v64; // ST38_4 + int v65; // eax + int v66; // esi + int v67; // edi + int v68; // eax + int v69; // esi + int v70; // esi + int v71; // eax + int v72; // ecx + int v73; // eax + int v74; // eax + int *v75; // esi + int *v76; // edi + int v77; // eax + int v78; // eax + int v79; // eax + int v80; // eax + int *v81; // esi + int *v82; // edi + int v83; // eax + int v84; // eax + int v85; // eax + int v86; // [esp-18h] [ebp-34h] + int v87; // [esp-10h] [ebp-2Ch] + int v88; // [esp-10h] [ebp-2Ch] + int v89; // [esp-Ch] [ebp-28h] + int v90; // [esp-Ch] [ebp-28h] + int v91; // [esp-8h] [ebp-24h] + int v92; // [esp-8h] [ebp-24h] + int v93; // [esp-8h] [ebp-24h] + int v94; // [esp-4h] [ebp-20h] + int v95; // [esp-4h] [ebp-20h] + int v96; // [esp-4h] [ebp-20h] + signed int v97; // [esp+Ch] [ebp-10h] + int arglist; // [esp+10h] [ebp-Ch] + int arglista; // [esp+10h] [ebp-Ch] + int arglistb; // [esp+10h] [ebp-Ch] + int v101; // [esp+14h] [ebp-8h] + int v102; // [esp+14h] [ebp-8h] + int v103; // [esp+14h] [ebp-8h] + int v104; // [esp+14h] [ebp-8h] + int p; // [esp+18h] [ebp-4h] + + v1 = pnum; + p = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("CheckNewPath: illegal player %d", pnum); + v2 = v1; + if ( plr[v1].destAction == 20 ) + MakePlrPath(v1, monster[plr[v2].destParam1]._mfutx, monster[plr[v2].destParam1]._mfuty, 0); + if ( plr[v2].destAction == 21 ) + MakePlrPath(v1, plr[plr[v2].destParam1]._px, plr[plr[v2].destParam1]._py, 0); + if ( plr[v2].walkpath[0] == -1 ) + { + v18 = plr[v2].destAction; + if ( v18 == -1 ) + return; + v19 = plr[v2]._pmode; + if ( v19 == PM_STAND ) + { + switch ( v18 ) + { + case 9: + v20 = GetDirection(plr[v2].WorldX, plr[v2].WorldY, plr[v2].destParam1, plr[v2].destParam2); + goto LABEL_52; + case 10: + v30 = plr[v2].WorldY; + v31 = plr[v2].WorldX; + v32 = &plr[v2].destParam2; + v33 = &plr[v2].destParam1; + goto LABEL_59; + case 12: + v39 = GetDirection(plr[v2].WorldX, plr[v2].WorldY, plr[v2].destParam1, plr[v2].destParam2); + StartSpell(p, v39, plr[v2].destParam1, plr[v2].destParam2); + v40 = plr[v2].destParam3; + goto LABEL_66; + case 13: + v46 = plr[v2].destParam1; + arglista = v46; + v47 = v46; + v102 = abs(plr[v2].WorldX - object[v47]._ox); + v48 = abs(plr[v2].WorldY - object[v47]._oy); + if ( v48 > 1 ) + { + v49 = object[v47]._oy; + if ( dObject[object[v47]._ox][v49-1] == -1 - arglista ) /* dungeon[39][112 * object[v47]._ox + 39 + v49] check */ + v48 = abs(plr[v2].WorldY - v49 + 1); + } + if ( v102 > 1 || v48 > 1 ) + break; + if ( object[v47]._oBreak != 1 ) + goto LABEL_73; + goto LABEL_80; + case 14: + v50 = plr[v2].destParam1; + arglista = v50; + v47 = v50; + v103 = abs(plr[v2].WorldX - object[v47]._ox); + v51 = abs(plr[v2].WorldY - object[v47]._oy); + if ( v51 > 1 ) + { + v52 = object[v47]._oy; + if ( dObject[object[v47]._ox][v52-1] == -1 - arglista ) /* dungeon[39][112 * object[v47]._ox + 39 + v52] check */ + v51 = abs(plr[v2].WorldY - v52 + 1); + } + if ( v103 > 1 || v51 > 1 ) + break; + if ( object[v47]._oBreak == 1 ) + { +LABEL_80: + v20 = GetDirection(plr[v2].WorldX, plr[v2].WorldY, object[v47]._ox, object[v47]._oy); +LABEL_81: + v29 = p; +LABEL_82: + StartAttack(v29, v20); + } + else + { + TryDisarm(p, arglista); +LABEL_73: + OperateObject(p, arglista, 0); + } + break; + case 15: + if ( v1 == myplr ) + { + v53 = plr[v2].destParam1; + v54 = plr[v2].destParam1; + v55 = abs(plr[v2].WorldX - item[v54]._ix); + v56 = abs(plr[v2].WorldY - item[v54]._iy); + if ( v55 <= 1 && v56 <= 1 && pcurs == 1 && !item[v54]._iRequest ) + { + NetSendCmdGItem(1u, CMD_REQUESTGITEM, myplr, myplr, v53); + item[v54]._iRequest = 1; + } + } + break; + case 16: + if ( v1 == myplr ) + { + v57 = plr[v2].destParam1; + v58 = plr[v2].destParam1; + v59 = abs(plr[v2].WorldX - item[v58]._ix); + v60 = abs(plr[v2].WorldY - item[v58]._iy); + if ( v59 <= 1 && v60 <= 1 && pcurs == 1 ) + NetSendCmdGItem(1u, CMD_REQUESTAGITEM, myplr, myplr, v57); + } + break; + case 17: + if ( v1 == myplr ) + TalkToTowner(v1, plr[v2].destParam1); + break; + case 18: + if ( object[plr[v2].destParam1]._oBreak != 1 ) + OperateObject(v1, plr[v2].destParam1, 1u); + break; + case 20: + v21 = plr[v2].destParam1; + v22 = plr[v2].destParam1; + v23 = abs(plr[v2].WorldX - monster[v22]._mfutx); + v24 = abs(plr[v2].WorldY - monster[v22]._mfuty); + if ( v23 > 1 || v24 > 1 ) + break; + v20 = GetDirection(plr[v2]._px, plr[v2]._py, monster[v22]._mfutx, monster[v22]._mfuty); + v25 = monster[v22].mtalkmsg; + if ( v25 && v25 != QUEST_VILE14 ) + goto LABEL_56; + goto LABEL_81; + case 21: + v26 = plr[v2].destParam1; + v27 = abs(plr[v2].WorldX - plr[v26]._px); + v28 = abs(plr[v2].WorldY - plr[v26]._py); + if ( v27 > 1 || v28 > 1 ) + break; + v20 = GetDirection(plr[v2]._px, plr[v2]._py, plr[v26]._px, plr[v26]._py); +LABEL_52: + v29 = v1; + goto LABEL_82; + case 22: + v21 = plr[v2].destParam1; + v34 = plr[v2].destParam1; + v35 = GetDirection(plr[v2]._px, plr[v2]._py, monster[v34]._mfutx, monster[v34]._mfuty); + v36 = monster[v34].mtalkmsg; + if ( v36 && v36 != QUEST_VILE14 ) +LABEL_56: + TalktoMonster(v21); + else + StartRangeAttack(p, v35, monster[v34]._mfutx, monster[v34]._mfuty); + break; + case 23: + v30 = plr[v2]._py; + v37 = plr[v2].destParam1; + v31 = plr[v2]._px; + v32 = &plr[v37]._py; + v33 = &plr[v37]._px; +LABEL_59: + v38 = GetDirection(v31, v30, *v33, *v32); + StartRangeAttack(p, v38, *v33, *v32); + break; + case 24: + v41 = plr[v2].destParam1; + v42 = &monster[v41]._mfuty; + v43 = &monster[v41]._mfutx; + goto LABEL_65; + case 25: + v44 = plr[v2].destParam1; + v42 = &plr[v44]._py; + v43 = &plr[v44]._px; +LABEL_65: + v45 = GetDirection(plr[v2].WorldX, plr[v2].WorldY, *v43, *v42); + StartSpell(p, v45, *v43, *v42); + v40 = plr[v2].destParam2; + goto LABEL_66; + case 26: + StartSpell(v1, plr[v2].destParam3, plr[v2].destParam1, plr[v2].destParam2); + plr[v2]._pVar3 = plr[v2].destParam3; + v40 = plr[v2].destParam4; +LABEL_66: + plr[v2]._pVar4 = v40; + break; + default: + break; + } + FixPlayerLocation(p, plr[v2]._pdir); + goto LABEL_143; + } + if ( v19 == 4 && plr[v2]._pAnimFrame > plr[myplr]._pAFNum ) + { + switch ( v18 ) + { + case 9: + v61 = GetDirection(plr[v2]._px, plr[v2]._py, plr[v2].destParam1, plr[v2].destParam2); +LABEL_105: + v62 = v1; +LABEL_106: + StartAttack(v62, v61); +LABEL_107: + plr[v2].destAction = -1; + break; + case 20: + v63 = plr[v2].destParam1; + v64 = abs(plr[v2].WorldX - monster[v63]._mfutx); + v65 = abs(plr[v2].WorldY - monster[v63]._mfuty); + if ( v64 > 1 || v65 > 1 ) + goto LABEL_107; + v61 = GetDirection(plr[v2]._px, plr[v2]._py, monster[v63]._mfutx, monster[v63]._mfuty); + goto LABEL_105; + case 21: + v66 = plr[v2].destParam1; + v67 = abs(plr[v2].WorldX - plr[v66]._px); + v68 = abs(plr[v2].WorldY - plr[v66]._py); + if ( v67 > 1 || v68 > 1 ) + goto LABEL_107; + v61 = GetDirection(plr[v2]._px, plr[v2]._py, plr[v66]._px, plr[v66]._py); + v62 = p; + goto LABEL_106; + case 13: + v69 = plr[v2].destParam1; + arglistb = v69; + v70 = v69; + v104 = abs(plr[v2].WorldX - object[v70]._ox); + v71 = abs(plr[v2].WorldY - object[v70]._oy); + if ( v71 > 1 ) + { + v72 = object[v70]._oy; + if ( dObject[object[v70]._ox][v72-1] == -1 - arglistb ) /* dungeon[39][112 * object[v70]._ox + 39 + v72] check */ + v71 = abs(plr[v2].WorldY - v72 + 1); + } + if ( v104 <= 1 && v71 <= 1 ) + { + if ( object[v70]._oBreak == 1 ) + { + v73 = GetDirection(plr[v2].WorldX, plr[v2].WorldY, object[v70]._ox, object[v70]._oy); + StartAttack(p, v73); + } + else + { + OperateObject(p, arglistb, 0); + } + } + break; + } + } + if ( plr[v2]._pmode == PM_RATTACK && plr[v2]._pAnimFrame > plr[myplr]._pAFNum ) + { + v74 = plr[v2].destAction; + switch ( v74 ) + { + case 10: + v75 = &plr[v2].destParam2; + v76 = &plr[v2].destParam1; +LABEL_133: + v79 = GetDirection(plr[v2].WorldX, plr[v2].WorldY, *v76, *v75); + StartRangeAttack(p, v79, *v76, *v75); + plr[v2].destAction = -1; + break; + case 22: + v77 = plr[v2].destParam1; + v75 = &monster[v77]._mfuty; + v76 = &monster[v77]._mfutx; + goto LABEL_133; + case 23: + v78 = plr[v2].destParam1; + v75 = &plr[v78]._py; + v76 = &plr[v78]._px; + goto LABEL_133; + } + } + if ( plr[v2]._pmode == PM_SPELL && plr[v2]._pAnimFrame > plr[v2]._pSFNum ) + { + v80 = plr[v2].destAction; + switch ( v80 ) + { + case 12: + v81 = &plr[v2].destParam2; + v82 = &plr[v2].destParam1; + break; + case 24: + v83 = plr[v2].destParam1; + v81 = &monster[v83]._mfuty; + v82 = &monster[v83]._mfutx; + break; + case 25: + v84 = plr[v2].destParam1; + v81 = &plr[v84]._py; + v82 = &plr[v84]._px; + break; + default: + return; + } + v85 = GetDirection(plr[v2].WorldX, plr[v2].WorldY, *v82, *v81); + StartSpell(p, v85, *v82, *v81); + goto LABEL_143; + } + return; + } + if ( plr[v2]._pmode == PM_STAND ) + { + if ( v1 == myplr ) + { + v3 = plr[v2].destAction; + if ( v3 == 20 || v3 == 21 ) + { + v4 = plr[v2].destParam1; + v5 = v3 == 20; + v6 = plr[v2]._px; + arglist = plr[v2].destParam1; + if ( v5 ) + { + v7 = v4; + v101 = abs(v6 - monster[v4]._mfutx); + v8 = abs(plr[v2]._py - monster[v7]._mfuty); + v9 = plr[v2]._py; + v94 = monster[v7]._mfuty; + v91 = monster[v7]._mfutx; + } + else + { + v10 = v4; + v101 = abs(v6 - plr[v4]._px); + v8 = abs(plr[v2]._py - plr[v10]._py); + v9 = plr[v2]._py; + v94 = plr[v10]._py; + v91 = plr[v10]._px; + } + v97 = v8; + v11 = GetDirection(plr[v2]._px, v9, v91, v94); + if ( v101 < 2 && v97 < 2 ) + { + ClrPlrPath(p); + v12 = monster[arglist].mtalkmsg; + if ( v12 && v12 != QUEST_VILE14 ) + TalktoMonster(arglist); + else + StartAttack(p, v11); + plr[v2].destAction = -1; + } + } + } + if ( currlevel ) + { + v13 = SLOBYTE(plr[v2]._pClass); + v14 = PWVel[v13][0]; + v15 = PWVel[v13][1]; + v16 = PWVel[v13][2]; + } + else + { + v14 = 2048; + v15 = 1024; + v16 = 512; + } + switch ( plr[v2].walkpath[0] ) + { + case WALK_NE: + v95 = 2; + v92 = DIR_NE; + v89 = -1; + v87 = 0; + v17 = -v16; + goto LABEL_37; + case WALK_NW: + v95 = 8; + v92 = DIR_NW; + v89 = 0; + v87 = -1; + v17 = -v16; + v15 = -v15; +LABEL_37: + StartWalk(p, v15, v17, v87, v89, v92, v95); + break; + case WALK_SE: + v96 = 4; + v93 = DIR_SE; + v90 = 0; + v88 = 1; + v86 = -32; + goto LABEL_32; + case WALK_SW: + v96 = 6; + v93 = DIR_SW; + v90 = 1; + v88 = 0; + v86 = 32; + v15 = -v15; +LABEL_32: + StartWalk2(p, v15, v16, v86, -16, v88, v90, v93, v96); + break; + case WALK_N: + StartWalk(p, 0, -v15, -1, -1, DIR_N, 1); + break; + case WALK_E: + StartWalk3(p, v14, 0, -32, -16, 1, -1, 1, 0, DIR_E, 3); + break; + case WALK_S: + StartWalk2(p, 0, v15, 0, -32, 1, 1, DIR_S, 5); + break; + case WALK_W: + StartWalk3(p, -v14, 0, 32, -16, -1, 1, 0, 1, DIR_W, 7); + break; + default: + break; + } + qmemcpy(plr[v2].walkpath, &plr[v2].walkpath[1], 0x18u); + plr[v2].walkpath[24] = -1; + if ( plr[v2]._pmode == PM_STAND ) + { + StartStand(p, plr[v2]._pdir); +LABEL_143: + plr[v2].destAction = -1; + return; + } + } +} + +BOOL __fastcall PlrDeathModeOK(int pnum) +{ + if ( pnum != myplr ) { + return TRUE; + } + + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("PlrDeathModeOK: illegal player %d", pnum); + } + + if (plr[pnum]._pmode == PM_DEATH) { + return TRUE; + } else if (plr[pnum]._pmode == PM_QUIT) { + return TRUE; + } else if (plr[pnum]._pmode == PM_NEWLVL) { + return TRUE; + } + + return FALSE; +} + +void __cdecl ValidatePlayer() +{ + int v0; // edi + int v1; // esi + char *v2; // eax + int v3; // ecx + int v4; // ecx + int *v5; // eax + int v6; // eax + int v7; // edx + int v8; // edx + int v9; // edx + int v10; // eax + int *v11; // ebx + signed int v12; // edi + char *v13; // eax + __int64 v14; // [esp+Ch] [ebp-8h] + + v0 = 0; + v14 = (__int64)0; + if ( (unsigned int)myplr >= 4 ) + TermMsg("ValidatePlayer: illegal player %d", myplr); + v1 = myplr; + v2 = &plr[myplr]._pLevel; + if ( *v2 > 50 ) + *v2 = 50; + v3 = plr[v1]._pNextExper; + if ( plr[v1]._pExperience > v3 ) + plr[v1]._pExperience = v3; + v4 = 0; + if ( plr[v1]._pNumInv > 0 ) + { + v5 = &plr[v1].InvList[0]._ivalue; + do + { + if ( *(v5 - 47) == 11 ) + { + if ( *v5 > 5000 ) + *v5 = 5000; + v4 += *v5; + } + ++v0; + v5 += 92; + } + while ( v0 < plr[v1]._pNumInv ); + } + if ( v4 != plr[v1]._pGold ) + plr[v1]._pGold = v4; + v6 = SLOBYTE(plr[v1]._pClass); + v7 = MaxStats[v6][0]; + if ( plr[v1]._pBaseStr > v7 ) + plr[v1]._pBaseStr = v7; + v8 = MaxStats[v6][1]; + if ( plr[v1]._pBaseMag > v8 ) + plr[v1]._pBaseMag = v8; + v9 = MaxStats[v6][2]; + if ( plr[v1]._pBaseDex > v9 ) + plr[v1]._pBaseDex = v9; + v10 = MaxStats[v6][3]; + if ( plr[v1]._pBaseVit > v10 ) + plr[v1]._pBaseVit = v10; + v11 = &spelldata[1].sBookLvl; + v12 = 1; + do + { + if ( *v11 != -1 ) + { + v14 |= (__int64)1 << ((unsigned char)v12 - 1); + v13 = &plr[v1]._pSplLvl[v12]; + if ( *v13 > 15 ) + *v13 = 15; + } + v11 += 14; + ++v12; + } + while ( (signed int)v11 < (signed int)&spelldata[37].sBookLvl ); + *(_QWORD *)plr[v1]._pMemSpells &= v14; +} + +void __cdecl ProcessPlayers() +{ + int v0; // eax + int v1; // eax + unsigned char *v2; // ecx + char v3; // al + int v4; // ebp + int *v5; // esi + int v6; // eax + //int v7; // eax + int v8; // eax + int v9; // eax + int v10; // eax + int v11; // edi + int v12; // eax + char *v13; // eax + char *v14; // eax + + v0 = myplr; + if ( (unsigned int)myplr >= 4 ) + { + TermMsg("ProcessPlayers: illegal player %d", myplr); + v0 = myplr; + } + v1 = v0; + v2 = &plr[v1].pLvlLoad; + v3 = plr[v1].pLvlLoad; + if ( v3 ) + *v2 = v3 - 1; + v4 = 0; + if ( sfxdelay > 0 && !--sfxdelay ) + PlaySFX(sfxdnum); + ValidatePlayer(); + v5 = &plr[0]._pHitPoints; + do + { + v6 = (int)(v5 - 89); + if ( *((_BYTE *)v5 - 379) && currlevel == *(_DWORD *)v6 && (v4 == myplr || !*(_BYTE *)(v6 + 267)) ) + { + CheckCheatStats(v4); + //_LOBYTE(v7) = PlrDeathModeOK(v4); + if ( !PlrDeathModeOK(v4) && (signed int)(*v5 & 0xFFFFFFC0) <= 0 ) + SyncPlrKill(v4, -1); + if ( v4 == myplr ) + { + if ( v5[5294] & 0x40 && currlevel ) + { + *v5 -= 4; + v8 = *v5; + *(v5 - 2) -= 4; + if ( (signed int)(v8 & 0xFFFFFFC0) <= 0 ) + SyncPlrKill(v4, 0); + drawhpflag = 1; + } + if ( *((_BYTE *)v5 + 21179) & 8 ) + { + v9 = v5[3]; + if ( v9 > 0 ) + { + v10 = v9 - v5[5]; + v5[5] = 0; + drawmanaflag = 1; + v5[3] = v10; + } + } + } + v11 = 0; + do + { + switch ( *(v5 - 102) ) + { + case PM_STAND: + v12 = PM_DoStand(v4); + goto LABEL_38; + case PM_WALK: + v12 = PM_DoWalk(v4); + goto LABEL_38; + case PM_WALK2: + v12 = PM_DoWalk2(v4); + goto LABEL_38; + case PM_WALK3: + v12 = PM_DoWalk3(v4); + goto LABEL_38; + case PM_ATTACK: + v12 = PM_DoAttack(v4); + goto LABEL_38; + case PM_RATTACK: + v12 = PM_DoRangeAttack(v4); + goto LABEL_38; + case PM_BLOCK: + v12 = PM_DoBlock(v4); + goto LABEL_38; + case PM_GOTHIT: + v12 = PM_DoGotHit(v4); + goto LABEL_38; + case PM_DEATH: + v12 = PM_DoDeath(v4); + goto LABEL_38; + case PM_SPELL: + v12 = PM_DoSpell(v4); + goto LABEL_38; + case PM_NEWLVL: + v12 = PM_DoStand(v4); +LABEL_38: + v11 = v12; + break; + default: + break; + } + CheckNewPath(v4); + } + while ( v11 ); + v13 = (char *)(v5 - 69); + ++*(_DWORD *)v13; + if ( *(v5 - 69) > *(v5 - 70) ) + { + *(_DWORD *)v13 = 0; + v14 = (char *)(v5 - 67); + ++*(_DWORD *)v14; + if ( *(v5 - 67) > *(v5 - 68) ) + *(_DWORD *)v14 = 1; + } + } + v5 += 5430; + ++v4; + } + while ( (signed int)v5 < (signed int)&plr[MAX_PLRS]._pHitPoints ); +} +// 52A554: using guessed type int sfxdelay; + +void __fastcall CheckCheatStats(int pnum) +{ + if ( plr[pnum]._pStrength > 750 ) { + plr[pnum]._pStrength = 750; + } + + if ( plr[pnum]._pDexterity > 750 ) { + plr[pnum]._pDexterity = 750; + } + + if ( plr[pnum]._pMagic > 750 ) { + plr[pnum]._pMagic = 750; + } + + if ( plr[pnum]._pVitality > 750 ) { + plr[pnum]._pVitality = 750; + } + + if ( plr[pnum]._pHitPoints > 128000 ) { + plr[pnum]._pHitPoints = 128000; + } + + if ( plr[pnum]._pMana > 128000 ) { + plr[pnum]._pMana = 128000; + } +} + +void __fastcall ClrPlrPath(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("ClrPlrPath: illegal player %d", pnum); + } + + memset(plr[pnum].walkpath, -1, sizeof(plr[pnum].walkpath)); +} + +BOOL __fastcall PosOkPlayer(int pnum, int px, int py) +{ + char v8; // cl + unsigned int v9; // ecx + int v10; // esi + char v11; // al + char v12; // cl + bool result; // eax + + result = 0; + if ( px >= 0 && px < 112 && py >= 0 && py < 112 && !SolidLoc(px, py) ) + { + if ( dPiece[px][py] ) + { + v8 = dPlayer[px][py]; + if ( !v8 || (v8 <= 0 ? (v9 = -1 - v8) : (v9 = v8 - 1), v9 == pnum || v9 >= 4 || !plr[v9]._pHitPoints) ) + { + v10 = dMonster[px][py]; + if ( !v10 || currlevel && v10 > 0 && (signed int)(monster[v10-1]._mhitpoints & 0xFFFFFFC0) <= 0 ) /* fix */ + { + v11 = dObject[px][py]; + if ( !v11 || (v11 <= 0 ? (v12 = -1 - v11) : (v12 = v11 - 1), !object[v12]._oSolidFlag) ) + result = 1; + } + } + } + } + return result; +} + +void __fastcall MakePlrPath(int pnum, int xx, int yy, unsigned char endspace) +{ + int v4; // esi + int v5; // ebx + int v6; // esi + int v7; // edi + int v8; // eax + int v9; // eax + int v10; // ecx + int a2; // [esp+Ch] [ebp-4h] + + v4 = pnum; + v5 = xx; + a2 = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("MakePlrPath: illegal player %d", pnum); + v6 = v4; + v7 = yy; + v8 = plr[v6]._px; + plr[v6]._ptargx = v5; + plr[v6]._ptargy = yy; + if ( v8 != v5 || plr[v6]._py != yy ) + { + v9 = FindPath(PosOkPlayer, a2, v8, plr[v6]._py, v5, yy, plr[v6].walkpath); + if ( v9 ) + { + if ( !endspace ) + { + v10 = plr[v6].walkpath[--v9]; /* *((char *)&plr[v6]._pmode + v9-- + 3) */ + switch ( v10 ) + { + case 1: // N + goto LABEL_12; + case 2: // W + ++v5; + break; + case 3: // E + --v5; + break; + case 4: // S + goto LABEL_15; + case 5: // NW + ++v5; + goto LABEL_12; + case 6: // NE + --v5; +LABEL_12: + v7 = yy + 1; + break; + case 7: // SE + --v5; + goto LABEL_15; + case 8: // SW + ++v5; +LABEL_15: + v7 = yy - 1; + break; + default: // 0/Neutral + break; + } + plr[v6]._ptargx = v5; + plr[v6]._ptargy = v7; + } + plr[v6].walkpath[v9] = -1; + } + } +} + +void __fastcall CheckPlrSpell() +{ + int v0; // ecx + int v1; // eax + int v2; // edx + char v3; // al + int v4; // ecx + char v5; // al + int v6; // eax + int v7; // edx + int v8; // esi + int v9; // ST10_4 + int v10; // eax + int v11; // eax + int v12; // eax + int v13; // ST10_4 + int v14; // eax + char v15; // al + + v0 = myplr; + if ( (unsigned int)myplr >= 4 ) + { + TermMsg("CheckPlrSpell: illegal player %d", myplr); + v0 = myplr; + } + v1 = 21720 * v0; + v2 = plr[v0]._pRSpell; + if ( v2 != -1 ) + { + if ( leveltype == DTYPE_TOWN && !*(_DWORD *)&spelldata[v2].sTownSpell ) + { + v5 = *((_BYTE *)&plr[0]._pClass + v1); + switch ( v5 ) + { + case PC_WARRIOR: + v4 = PS_WARR27; + goto LABEL_53; + case PC_ROGUE: + v4 = PS_ROGUE27; + goto LABEL_53; + case PC_SORCERER: + v4 = PS_MAGE27; + goto LABEL_53; + } + return; + } + if ( pcurs != CURSOR_HAND + || MouseY >= 352 + || (chrflag && MouseX < 320 || invflag && MouseX > 320) + && v2 != 2 + && v2 != 5 + && v2 != 26 + && v2 != 9 + && v2 != 27 ) + { + return; + } + _LOBYTE(v1) = *((_BYTE *)&plr[0]._pRSplType + v1); + if ( (v1 & 0x80u) != 0 ) + goto LABEL_46; + if ( (char)v1 <= 1 ) + { + v6 = CheckSpell(v0, v2, v1, 0); + } + else + { + if ( (_BYTE)v1 != 2 ) + { + if ( (_BYTE)v1 == 3 ) + { + v6 = UseStaff(); + goto LABEL_36; + } +LABEL_46: + if ( _LOBYTE(plr[v0]._pRSplType) == 1 ) + { + v15 = plr[v0]._pClass; + switch ( v15 ) + { + case PC_WARRIOR: + v4 = PS_WARR35; + goto LABEL_53; + case PC_ROGUE: + v4 = PS_ROGUE35; + goto LABEL_53; + case PC_SORCERER: + v4 = PS_MAGE35; + goto LABEL_53; + } + } + return; + } + v6 = UseScroll(); + } +LABEL_36: + v0 = myplr; + if ( v6 ) + { + v7 = plr[myplr]._pRSpell; + if ( v7 == 6 ) + { + v8 = GetDirection(plr[myplr].WorldX, plr[myplr].WorldY, cursmx, cursmy); + v9 = GetSpellLevel(myplr, plr[myplr]._pRSpell); + v10 = 21720 * myplr; + _LOWORD(v10) = plr[myplr]._pRSpell; + NetSendCmdLocParam3(1u, CMD_SPELLXYD, cursmx, cursmy, v10, v8, v9); + } + else if ( pcursmonst == -1 ) + { + if ( pcursplr == -1 ) + { + v13 = GetSpellLevel(myplr, v7); + v14 = 21720 * myplr; + _LOWORD(v14) = plr[myplr]._pRSpell; + NetSendCmdLocParam2(1u, CMD_SPELLXY, cursmx, cursmy, v14, v13); + } + else + { + v12 = GetSpellLevel(myplr, v7); + NetSendCmdParam3(1u, CMD_SPELLPID, pcursplr, plr[myplr]._pRSpell, v12); + } + } + else + { + v11 = GetSpellLevel(myplr, v7); + NetSendCmdParam3(1u, CMD_SPELLID, pcursmonst, plr[myplr]._pRSpell, v11); + } + return; + } + goto LABEL_46; + } + v3 = *((_BYTE *)&plr[0]._pClass + v1); + switch ( v3 ) + { + case PC_WARRIOR: + v4 = PS_WARR34; +LABEL_53: + PlaySFX(v4); + return; + case PC_ROGUE: + v4 = PS_ROGUE34; + goto LABEL_53; + case PC_SORCERER: + v4 = PS_MAGE34; + goto LABEL_53; + } +} +// 4B8CC2: using guessed type char pcursplr; +// 5BB1ED: using guessed type char leveltype; + +void __fastcall SyncPlrAnim(int pnum) +{ + int v1; // esi + int v2; // eax + int v3; // ecx + unsigned char *v4; // ecx + int v5; // edx + + v1 = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("SyncPlrAnim: illegal player %d", pnum); + v2 = v1; + v3 = plr[v1]._pdir; + switch ( plr[v1]._pmode ) + { + case PM_STAND: + case PM_NEWLVL: + case PM_QUIT: + v4 = plr[0]._pNAnim[v3 + 5430 * v1]; + goto LABEL_19; + case PM_WALK: + case PM_WALK2: + case PM_WALK3: + v4 = plr[0]._pWAnim[v3 + 5430 * v1]; + goto LABEL_19; + case PM_ATTACK: + case PM_RATTACK: + v4 = plr[0]._pAAnim[v3 + 5430 * v1]; + goto LABEL_19; + case PM_BLOCK: + v4 = plr[0]._pBAnim[v3 + 5430 * v1]; + goto LABEL_19; + case PM_GOTHIT: + v4 = plr[0]._pHAnim[v3 + 5430 * v1]; + goto LABEL_19; + case PM_DEATH: + v4 = plr[0]._pDAnim[v3 + 5430 * v1]; + goto LABEL_19; + case PM_SPELL: + if ( v1 == myplr ) + v5 = (unsigned char)spelldata[plr[v2]._pSpell].sType; + else + v5 = 0; + if ( !v5 ) + plr[v2]._pAnimData = plr[0]._pFAnim[v3 + 5430 * v1]; + if ( v5 == STYPE_LIGHTNING ) + plr[v2]._pAnimData = plr[0]._pLAnim[v3 + 5430 * v1]; + if ( v5 == STYPE_MAGIC ) + { + v4 = plr[0]._pTAnim[v3 + 5430 * v1]; +LABEL_19: + plr[v2]._pAnimData = v4; + } + break; + default: + TermMsg("SyncPlrAnim"); + break; + } +} + +void __fastcall SyncInitPlrPos(int pnum) +{ + int v1; // esi + bool v2; // zf + unsigned int v3; // eax + int v4; // ebx + int v5; // edi + int v6; // eax + signed int v7; // [esp+Ch] [ebp-18h] + int p; // [esp+10h] [ebp-14h] + int v9; // [esp+14h] [ebp-10h] + signed int v10; // [esp+18h] [ebp-Ch] + signed int v11; // [esp+1Ch] [ebp-8h] + unsigned int i; // [esp+20h] [ebp-4h] + signed int v13; // [esp+20h] [ebp-4h] + + p = pnum; + v1 = pnum; + v2 = gbMaxPlayers == 1; + plr[v1]._ptargx = plr[pnum].WorldX; + plr[v1]._ptargy = plr[pnum].WorldY; + if ( !v2 && plr[v1].plrlevel == currlevel ) + { + v3 = 0; + for ( i = 0; ; v3 = i ) + { + v4 = plr[v1].WorldX + *(int *)((char *)plrxoff2 + v3); + v5 = plr[v1].WorldY + *(int *)((char *)plryoff2 + v3); + if ( PosOkPlayer(p, v4, v5) ) + break; + i += 4; + if ( i >= 0x20 ) + break; + } + if ( !PosOkPlayer(p, v4, v5) ) + { + v11 = 0; + v6 = -1; + v13 = 1; + v7 = -1; + do + { + if ( v11 ) + break; + v9 = v6; + while ( v6 <= v13 && !v11 ) + { + v5 = v9 + plr[v1].WorldY; + v10 = v7; + do + { + if ( v11 ) + break; + v4 = v10 + plr[v1].WorldX; + if ( PosOkPlayer(p, v10 + plr[v1].WorldX, v5) && !PosOkPortal(currlevel, v4, v5) ) + v11 = 1; + ++v10; + } + while ( v10 <= v13 ); + v6 = ++v9; + } + ++v13; + v6 = v7-- - 1; + } + while ( v7 > -50 ); + } + plr[v1].WorldX = v4; + v2 = p == myplr; + plr[v1].WorldY = v5; + dPlayer[v4][v5] = p + 1; + if ( v2 ) + { + plr[v1]._px = v4; + plr[v1]._py = v5; + plr[v1]._ptargx = v4; + plr[v1]._ptargy = v5; + ViewX = v4; + ViewY = v5; + } + } +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall SyncInitPlr(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("SyncInitPlr: illegal player %d", pnum); + } + + SetPlrAnims(pnum); + SyncInitPlrPos(pnum); +} + +void __fastcall CheckStats(int pnum) +{ + int v1; // esi + int v2; // eax + char v3; // cl + signed int v4; // esi + signed int v5; // edi + int v6; // edx + int v7; // ecx + int v8; // edx + int v9; // ecx + int v10; // edx + int v11; // ecx + int v12; // edx + int v13; // ecx + //signed int v14; // [esp+Ch] [ebp-4h] + + v1 = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("CheckStats: illegal player %d", pnum); + v2 = v1; + v3 = plr[v1]._pClass; + if ( v3 ) + { + if ( v3 == 1 ) + { + v4 = 1; + } + else if ( v3 == 2 ) + { + v4 = 2; + } + /*else + { + v4 = v14; + }*/ + } + else + { + v4 = 0; + } + v5 = 0; + do + { + if ( v5 ) + { + switch ( v5 ) + { + case ATTRIB_MAG: + v10 = plr[v2]._pBaseMag; + v11 = MaxStats[v4][1]; + if ( v10 <= v11 ) + { + if ( v10 < 0 ) + plr[v2]._pBaseMag = 0; + } + else + { + plr[v2]._pBaseMag = v11; + } + break; + case ATTRIB_DEX: + v8 = plr[v2]._pBaseDex; + v9 = MaxStats[v4][2]; + if ( v8 <= v9 ) + { + if ( v8 < 0 ) + plr[v2]._pBaseDex = 0; + } + else + { + plr[v2]._pBaseDex = v9; + } + break; + case ATTRIB_VIT: + v6 = plr[v2]._pBaseVit; + v7 = MaxStats[v4][3]; + if ( v6 <= v7 ) + { + if ( v6 < 0 ) + plr[v2]._pBaseVit = 0; + } + else + { + plr[v2]._pBaseVit = v7; + } + break; + } + } + else + { + v12 = plr[v2]._pBaseStr; + v13 = MaxStats[v4][0]; + if ( v12 <= v13 ) + { + if ( v12 < 0 ) + plr[v2]._pBaseStr = 0; + } + else + { + plr[v2]._pBaseStr = v13; + } + } + ++v5; + } + while ( v5 < 4 ); +} + +void __fastcall ModifyPlrStr(int pnum, int l) +{ + int v2; // esi + int v3; // edi + int v4; // esi + char v5; // dl + int v6; // ecx + int v7; // eax + int v8; // ebx + int v9; // eax + signed int v10; // ecx + int p; // [esp+8h] [ebp-4h] + + v2 = pnum; + v3 = l; + p = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("ModifyPlrStr: illegal player %d", pnum); + v4 = v2; + v5 = plr[v4]._pClass; + v6 = plr[v4]._pBaseStr; + v7 = MaxStats[v5][0]; + if ( v6 + v3 > v7 ) + v3 = v7 - v6; + plr[v4]._pBaseStr = v3 + v6; + plr[v4]._pStrength += v3; + v8 = plr[v4]._pStrength; + if ( v5 == 1 ) + { + v9 = plr[v4]._pLevel * (v8 + plr[v4]._pDexterity); + v10 = 200; + } + else + { + v9 = v8 * plr[v4]._pLevel; + v10 = 100; + } + plr[v4]._pDamageMod = v9 / v10; + CalcPlrInv(p, 1u); + if ( p == myplr ) + NetSendCmdParam1(0, CMD_SETSTR, plr[v4]._pBaseStr); +} + +void __fastcall ModifyPlrMag(int pnum, int l) +{ + int v2; // esi + int v3; // edi + int v4; // esi + char v5; // dl + int v6; // ecx + int v7; // eax + int v8; // eax + int v9; // edi + int p; // [esp+8h] [ebp-4h] + + v2 = pnum; + v3 = l; + p = pnum; + if ( (unsigned int)pnum >= MAX_PLRS ) + TermMsg("ModifyPlrMag: illegal player %d", pnum); + v4 = v2; + v5 = plr[v4]._pClass; + v6 = MaxStats[v5][1]; + v7 = plr[v4]._pBaseMag; + if ( v7 + v3 > v6 ) + v3 = v6 - v7; + plr[v4]._pMagic += v3; + v8 = v3 + v7; + v9 = v3 << 6; + plr[v4]._pBaseMag = v8; + if ( v5 == 2 ) + v9 *= 2; + plr[v4]._pMaxManaBase += v9; + plr[v4]._pMaxMana += v9; + if ( !(plr[v4]._pIFlags & 0x8000000) ) + { + plr[v4]._pManaBase += v9; + plr[v4]._pMana += v9; + } + CalcPlrInv(p, 1u); + if ( p == myplr ) + NetSendCmdParam1(0, CMD_SETMAG, plr[v4]._pBaseMag); +} + +void __fastcall ModifyPlrDex(int pnum, int l) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("ModifyPlrDex: illegal player %d", pnum); + } + + int max = MaxStats[plr[pnum]._pClass][ATTRIB_DEX]; + if ( plr[pnum]._pBaseDex + l > max ) + { + l = max - plr[pnum]._pBaseDex; + } + + plr[pnum]._pDexterity += l; + plr[pnum]._pBaseDex += l; + CalcPlrInv(pnum, 1); + + if ( plr[pnum]._pClass == PC_ROGUE ) { + plr[pnum]._pDamageMod = plr[pnum]._pLevel * (plr[pnum]._pDexterity + plr[pnum]._pStrength) / 200; + } + + if ( pnum == myplr ) { + NetSendCmdParam1(0, CMD_SETDEX, plr[pnum]._pBaseDex); + } +} + +void __fastcall ModifyPlrVit(int pnum, int l) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("ModifyPlrVit: illegal player %d", pnum); + } + + int max = MaxStats[plr[pnum]._pClass][ATTRIB_VIT]; + if ( plr[pnum]._pBaseVit + l > max ) + { + l = max - plr[pnum]._pBaseVit; + } + + plr[pnum]._pVitality += l; + plr[pnum]._pBaseVit += l; + + int ms = l << 6; + if ( plr[pnum]._pClass == PC_WARRIOR ) { + ms *= 2; + } + + plr[pnum]._pHPBase += ms; + plr[pnum]._pMaxHPBase += ms; + plr[pnum]._pHitPoints += ms; + plr[pnum]._pMaxHP += ms; + + CalcPlrInv(pnum, TRUE); + + if ( pnum == myplr ) { + NetSendCmdParam1(FALSE, CMD_SETVIT, plr[pnum]._pBaseVit); + } +} + +void __fastcall SetPlayerHitPoints(int pnum, int newhp) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("SetPlayerHitPoints: illegal player %d", pnum); + } + + plr[pnum]._pHitPoints = newhp; + plr[pnum]._pHPBase = newhp + plr[pnum]._pMaxHPBase - plr[pnum]._pMaxHP; + + if ( pnum == myplr ) { + drawhpflag = 1; + } +} + +void __fastcall SetPlrStr(int pnum, int v) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("SetPlrStr: illegal player %d", pnum); + } + + plr[pnum]._pBaseStr = v; + CalcPlrInv(pnum, TRUE); + + int dm; + if ( plr[pnum]._pClass == PC_ROGUE ) { + dm = plr[pnum]._pLevel * (plr[pnum]._pStrength + plr[pnum]._pDexterity) / 200; + } else { + dm = plr[pnum]._pLevel * plr[pnum]._pStrength / 100; + } + + plr[pnum]._pDamageMod = dm; +} + +void __fastcall SetPlrMag(int pnum, int v) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("SetPlrMag: illegal player %d", pnum); + } + + plr[pnum]._pBaseMag = v; + + int m = v << 6; + if ( plr[pnum]._pClass == PC_SORCERER ) { + m *= 2; + } + + plr[pnum]._pMaxManaBase = m; + plr[pnum]._pMaxMana = m; + CalcPlrInv(pnum, TRUE); +} + +void __fastcall SetPlrDex(int pnum, int v) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("SetPlrDex: illegal player %d", pnum); + } + + plr[pnum]._pBaseDex = v; + CalcPlrInv(pnum, TRUE); + + int dm; + if ( plr[pnum]._pClass == PC_ROGUE ) { + dm = plr[pnum]._pLevel * (plr[pnum]._pStrength + plr[pnum]._pDexterity) / 200; + } else { + dm = plr[pnum]._pStrength * plr[pnum]._pLevel / 100; + } + + plr[pnum]._pDamageMod = dm; +} + +void __fastcall SetPlrVit(int pnum, int v) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("SetPlrVit: illegal player %d", pnum); + } + + plr[pnum]._pBaseVit = v; + + int hp = v << 6; + if ( !_LOBYTE(plr[pnum]._pClass) ) { + hp *= 2; + } + + plr[pnum]._pHPBase = hp; + plr[pnum]._pMaxHPBase = hp; + CalcPlrInv(pnum, TRUE); +} + +void __fastcall InitDungMsgs(int pnum) +{ + if ( (DWORD)pnum >= MAX_PLRS ) { + TermMsg("InitDungMsgs: illegal player %d", pnum); + } + + plr[pnum].pDungMsgs = 0; +} + +void __cdecl PlayDungMsgs() +{ + int v0; // eax + int v1; // eax + char v2; // cl + char v3; // dl + char v4; // cl + char v5; // cl + char v6; // dl + char v7; // cl + char v8; // dl + char v9; // cl + char v10; // dl + char v11; // cl + char v12; // dl + + v0 = myplr; + if ( (unsigned int)myplr >= 4 ) + { + TermMsg("PlayDungMsgs: illegal player %d", myplr); + v0 = myplr; + } + switch ( currlevel ) + { + case 1u: + v1 = v0; + if ( !plr[v1]._pLvlVisited[1] && gbMaxPlayers == currlevel ) + { + v2 = plr[v1].pDungMsgs; + if ( !(v2 & 1) ) + { + v3 = plr[v1]._pClass; + sfxdelay = 40; + if ( v3 ) + { + if ( v3 == 1 ) + { + sfxdnum = PS_ROGUE97; + } + else if ( v3 == 2 ) + { + sfxdnum = PS_MAGE97; + } + } + else + { + sfxdnum = PS_WARR97; + } + v4 = v2 | 1; +LABEL_14: + plr[v1].pDungMsgs = v4; + return; + } + } + break; + case 5u: + v1 = v0; + if ( !plr[v1]._pLvlVisited[5] && gbMaxPlayers == 1 ) + { + v5 = plr[v1].pDungMsgs; + if ( !(v5 & 2) ) + { + v6 = plr[v1]._pClass; + sfxdelay = 40; + if ( v6 ) + { + if ( v6 == 1 ) + { + sfxdnum = PS_ROGUE96; + } + else if ( v6 == 2 ) + { + sfxdnum = PS_MAGE96; + } + } + else + { + sfxdnum = PS_WARR96B; + } + v4 = v5 | 2; + goto LABEL_14; + } + } + break; + case 9u: + v1 = v0; + if ( !plr[v1]._pLvlVisited[9] && gbMaxPlayers == 1 ) + { + v7 = plr[v1].pDungMsgs; + if ( !(v7 & 4) ) + { + v8 = plr[v1]._pClass; + sfxdelay = 40; + if ( v8 ) + { + if ( v8 == 1 ) + { + sfxdnum = PS_ROGUE98; + } + else if ( v8 == 2 ) + { + sfxdnum = PS_MAGE98; + } + } + else + { + sfxdnum = PS_WARR98; + } + v4 = v7 | 4; + goto LABEL_14; + } + } + break; + case 13u: + v1 = v0; + if ( !plr[v1]._pLvlVisited[13] && gbMaxPlayers == 1 ) + { + v9 = plr[v1].pDungMsgs; + if ( !(v9 & 8) ) + { + v10 = plr[v1]._pClass; + sfxdelay = 40; + if ( v10 ) + { + if ( v10 == 1 ) + { + sfxdnum = PS_ROGUE99; + } + else if ( v10 == 2 ) + { + sfxdnum = PS_MAGE99; + } + } + else + { + sfxdnum = PS_WARR99; + } + v4 = v9 | 8; + goto LABEL_14; + } + } + break; + case 16u: + v1 = v0; + if ( !plr[v1]._pLvlVisited[15] && gbMaxPlayers == 1 ) + { + v11 = plr[v1].pDungMsgs; + if ( !(v11 & 0x10) ) + { + v12 = plr[v1]._pClass; + sfxdelay = 40; + if ( !v12 || v12 == 1 || v12 == 2 ) + sfxdnum = PS_DIABLVLINT; + v4 = v11 | 0x10; + goto LABEL_14; + } + } + break; + } + sfxdelay = 0; +} +// 52A554: using guessed type int sfxdelay; +// 679660: using guessed type char gbMaxPlayers; diff --git a/Source/player.h b/Source/player.h new file mode 100644 index 000000000..22f81d1bc --- /dev/null +++ b/Source/player.h @@ -0,0 +1,139 @@ +//HEADER_GOES_HERE +#ifndef __PLAYER_H__ +#define __PLAYER_H__ + +extern int plr_lframe_size; // idb +extern int plr_wframe_size; // idb +extern char plr_gfx_flag; // weak +extern int player_cpp_init_value; // weak +extern int plr_aframe_size; // idb +extern int myplr; +extern PlayerStruct plr[MAX_PLRS]; +extern int plr_fframe_size; // idb +extern int plr_qframe_size; // idb +extern int deathflag; // idb +extern int plr_hframe_size; // idb +extern int plr_bframe_size; // idb +extern char plr_gfx_bflag; // weak +extern int plr_sframe_size; // idb +extern int deathdelay; // weak +extern int plr_dframe_size; // idb + +void __cdecl player_cpp_init(); +void __fastcall SetPlayerGPtrs(UCHAR *pData, UCHAR **pAnim); /* unsigned char *+** */ +void __fastcall LoadPlrGFX(int pnum, player_graphic gfxflag); +void __fastcall InitPlayerGFX(int pnum); +void __fastcall InitPlrGFXMem(int pnum); +DWORD __fastcall GetPlrGFXSize(char *szCel); +void __fastcall FreePlayerGFX(int pnum); +void __fastcall NewPlrAnim(int pnum, unsigned char *Peq, int numFrames, int Delay, int width); +void __fastcall ClearPlrPVars(int pnum); +void __fastcall SetPlrAnims(int pnum); +void __fastcall ClearPlrRVars(PlayerStruct *p); +void __fastcall CreatePlayer(int pnum, char c); +int __fastcall CalcStatDiff(int pnum); +void __fastcall NextPlrLevel(int pnum); +void __fastcall AddPlrExperience(int pnum, int lvl, int exp); +void __fastcall AddPlrMonstExper(int lvl, int exp, char pmask); +void __fastcall InitPlayer(int pnum, BOOL FirstTime); +void __cdecl InitMultiView(); +void __fastcall InitPlayerLoc(int pnum, BOOL flag); +BOOL __fastcall SolidLoc(int x, int y); +BOOL __fastcall PlrDirOK(int pnum, int dir); +void __fastcall PlrClrTrans(int x, int y); +void __fastcall PlrDoTrans(int x, int y); +void __fastcall SetPlayerOld(int pnum); +void __fastcall FixPlayerLocation(int pnum, int dir); +void __fastcall StartStand(int pnum, int dir); +void __fastcall StartWalkStand(int pnum); +void __fastcall PM_ChangeLightOff(int pnum); +void __fastcall PM_ChangeOffset(int pnum); +void __fastcall StartWalk(int pnum, int xvel, int yvel, int xadd, int yadd, int EndDir, int sdir); +void __fastcall StartWalk2(int pnum, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int EndDir, int sdir); +void __fastcall StartWalk3(int pnum, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int mapx, int mapy, int EndDir, int sdir); +void __fastcall StartAttack(int pnum, int d); +void __fastcall StartRangeAttack(int pnum, int d, int cx, int cy); +void __fastcall StartPlrBlock(int pnum, int dir); +void __fastcall StartSpell(int pnum, int d, int cx, int cy); +void __fastcall FixPlrWalkTags(int pnum); +void __fastcall RemovePlrFromMap(int pnum); +void __fastcall StartPlrHit(int pnum, int dam, BOOL forcehit); +void __fastcall RespawnDeadItem(ItemStruct *itm, int x, int y); +void __fastcall StartPlayerKill(int pnum, int earflag); +void __fastcall PlrDeadItem(int pnum, struct ItemStruct *itm, int xx, int yy); +void __fastcall DropHalfPlayersGold(int pnum); +void __fastcall SyncPlrKill(int pnum, int earflag); +void __fastcall j_StartPlayerKill(int pnum, int earflag); +void __fastcall RemovePlrMissiles(int pnum); +void __fastcall InitLevelChange(int pnum); +void __fastcall StartNewLvl(int pnum, int fom, int lvl); +void __fastcall RestartTownLvl(int pnum); +void __fastcall StartWarpLvl(int pnum, int pidx); +BOOL __fastcall PM_DoStand(int pnum); +BOOL __fastcall PM_DoWalk(int pnum); +BOOL __fastcall PM_DoWalk2(int pnum); +BOOL __fastcall PM_DoWalk3(int pnum); +BOOL __fastcall WeaponDur(int pnum, int durrnd); +bool __fastcall PlrHitMonst(int pnum, int m); +bool __fastcall PlrHitPlr(int pnum, char p); +BOOL __fastcall PlrHitObj(int pnum, int mx, int my); +int __fastcall PM_DoAttack(int pnum); +BOOL __fastcall PM_DoRangeAttack(int pnum); +void __fastcall ShieldDur(int pnum); +BOOL __fastcall PM_DoBlock(int pnum); +BOOL __fastcall PM_DoSpell(int pnum); +int __fastcall PM_DoGotHit(int pnum); +void __fastcall ArmorDur(int pnum); +int __fastcall PM_DoDeath(int pnum); +void __fastcall CheckNewPath(int pnum); +BOOL __fastcall PlrDeathModeOK(int pnum); +void __cdecl ValidatePlayer(); +void __cdecl ProcessPlayers(); +void __fastcall CheckCheatStats(int pnum); +void __fastcall ClrPlrPath(int pnum); +BOOL __fastcall PosOkPlayer(int pnum, int px, int py); +void __fastcall MakePlrPath(int pnum, int xx, int yy, unsigned char endspace); +void __fastcall CheckPlrSpell(); +void __fastcall SyncPlrAnim(int pnum); +void __fastcall SyncInitPlrPos(int pnum); +void __fastcall SyncInitPlr(int pnum); +void __fastcall CheckStats(int pnum); +void __fastcall ModifyPlrStr(int pnum, int l); +void __fastcall ModifyPlrMag(int pnum, int l); +void __fastcall ModifyPlrDex(int pnum, int l); +void __fastcall ModifyPlrVit(int pnum, int l); +void __fastcall SetPlayerHitPoints(int pnum, int newhp); +void __fastcall SetPlrStr(int pnum, int v); +void __fastcall SetPlrMag(int pnum, int v); +void __fastcall SetPlrDex(int pnum, int v); +void __fastcall SetPlrVit(int pnum, int v); +void __fastcall InitDungMsgs(int pnum); +void __cdecl PlayDungMsgs(); + +/* rdata */ + +extern const int player_inf; +extern const char ArmourChar[4]; +extern const char WepChar[10]; +extern const char CharChar[4]; + +/* data */ + +extern int plrxoff[9]; +extern int plryoff[9]; +extern int plrxoff2[9]; +extern int plryoff2[9]; +extern char PlrGFXAnimLens[3][11]; +extern int PWVel[4][3]; +extern int StrengthTbl[3]; +extern int MagicTbl[3]; +extern int DexterityTbl[3]; +extern int VitalityTbl[3]; +extern int ToBlkTbl[3]; +extern char *ClassStrTblOld[3]; +extern int MaxStats[3][4]; +extern int ExpLvlsTbl[51]; +extern char *ClassStrTbl[3]; +extern unsigned char fix[9]; + +#endif /* __PLAYER_H__ */ diff --git a/Source/plrmsg.cpp b/Source/plrmsg.cpp new file mode 100644 index 000000000..04903fdeb --- /dev/null +++ b/Source/plrmsg.cpp @@ -0,0 +1,220 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int plrmsg_ticks; // weak +char plr_msg_slot; // weak +_plrmsg plr_msgs[8]; +#endif + +const char text_color_from_player_num[5] = { COL_WHITE, COL_WHITE, COL_WHITE, COL_WHITE, COL_GOLD }; + +void __fastcall plrmsg_delay(int a1) +{ + _plrmsg *pMsg; // eax + signed int v2; // ecx + + if ( a1 ) + { + plrmsg_ticks = -GetTickCount(); + } + else + { + plrmsg_ticks += GetTickCount(); + pMsg = plr_msgs; + v2 = 8; + do + { + pMsg->time += plrmsg_ticks; + ++pMsg; + --v2; + } + while ( v2 ); + } +} +// 69B7D0: using guessed type int plrmsg_ticks; + +char *__fastcall ErrorPlrMsg(char *pszMsg) +{ + _plrmsg *pMsg; // esi + char *v2; // edi + char *result; // eax + + pMsg = &plr_msgs[(unsigned char)plr_msg_slot]; + v2 = pszMsg; + plr_msg_slot = (plr_msg_slot + 1) & 7; + pMsg->player = 4; + pMsg->time = GetTickCount(); + result = strncpy(pMsg->str, v2, 0x90u); + pMsg->str[143] = 0; + return result; +} +// 69B7D4: using guessed type char plr_msg_slot; + +size_t EventPlrMsg(char *pszFmt, ...) +{ + char *v1; // esi + va_list va; // [esp+Ch] [ebp+8h] + + va_start(va, pszFmt); + v1 = (char *)&plr_msgs[(unsigned char)plr_msg_slot]; + plr_msg_slot = (plr_msg_slot + 1) & 7; + v1[4] = 4; + *(_DWORD *)v1 = GetTickCount(); + v1 += 5; + vsprintf(v1, pszFmt, va); + return strlen(v1); +} +// 69B7D4: using guessed type char plr_msg_slot; + +void __fastcall SendPlrMsg(int pnum, const char *pszStr) +{ + _plrmsg *pMsg; // esi + int v3; // ebx + const char *v4; // ebp + int v5; // edi + const char *v6; // ebx + + pMsg = &plr_msgs[(unsigned char)plr_msg_slot]; + v3 = pnum; + v4 = pszStr; + plr_msg_slot = (plr_msg_slot + 1) & 7; + pMsg->player = pnum; + pMsg->time = GetTickCount(); + v5 = v3; + v6 = plr[v3]._pName; + strlen(v6); /* these are used in debug */ + strlen(v4); + sprintf(pMsg->str, "%s (lvl %d): %s", v6, plr[v5]._pLevel, v4); +} +// 69B7D4: using guessed type char plr_msg_slot; + +void __cdecl ClearPlrMsg() +{ + _plrmsg *pMsg; // esi + DWORD v1; // eax + signed int v2; // ecx + + pMsg = plr_msgs; + v1 = GetTickCount(); + v2 = 8; + do + { + if ( (signed int)(v1 - pMsg->time) > 10000 ) + pMsg->str[0] = 0; + ++pMsg; + --v2; + } + while ( v2 ); +} + +void __cdecl InitPlrMsg() +{ + memset(plr_msgs, 0, 0x4C0u); + plr_msg_slot = 0; +} +// 69B7D4: using guessed type char plr_msg_slot; + +void __cdecl DrawPlrMsg() +{ + int v0; // ebx + int v1; // ebp + int v2; // edi + char *v3; // esi + signed int v4; // [esp+Ch] [ebp-4h] + + v0 = 74; + v1 = 230; + v2 = 620; + if ( chrflag || questlog ) + { + if ( invflag || sbookflag ) + return; + v0 = 394; + goto LABEL_9; + } + if ( invflag || sbookflag ) +LABEL_9: + v2 = 300; + v3 = plr_msgs[0].str; + v4 = 8; + do + { + if ( *v3 ) + PrintPlrMsg(v0, v1, v2, v3, (unsigned char)text_color_from_player_num[(unsigned char)*(v3 - 1)]); + v3 += 152; + v1 += 35; + --v4; + } + while ( v4 ); +} +// 4B8968: using guessed type int sbookflag; +// 69BD04: using guessed type int questlog; + +void __fastcall PrintPlrMsg(int no, int x, int y, char *str, int just) +{ + char *v5; // edi + int *v6; // edx + int v7; // esi + char *v8; // edx + int v9; // esi + unsigned int v10; // eax + unsigned char v11; // cl + unsigned char v12; // cl + int v13; // eax + unsigned char v14; // bl + int v15; // [esp+Ch] [ebp-Ch] + int *v16; // [esp+10h] [ebp-8h] + int v17; // [esp+14h] [ebp-4h] + char *stra; // [esp+24h] [ebp+Ch] + + v17 = 0; + v5 = str; + v15 = no; + if ( *str ) + { + v6 = &screen_y_times_768[x]; + v16 = v6; + do + { + v7 = *v6; + v8 = v5; + v9 = v15 + v7; + v10 = 0; + stra = v5; + while ( 1 ) + { + v11 = *v8; + if ( !*v8 ) + break; + ++v8; + v12 = fontframe[fontidx[v11]]; + v10 += fontkern[v12] + 1; + if ( v12 ) + { + if ( v10 >= y ) + goto LABEL_13; + } + else + { + stra = v8; + } + } + stra = v8; +LABEL_13: + while ( v5 < stra ) + { + v13 = (unsigned char)*v5++; + v14 = fontframe[fontidx[v13]]; + if ( v14 ) + CPrintString(v9, v14, just); + v9 += fontkern[v14] + 1; + } + v6 = v16 + 10; + ++v17; + v16 += 10; + } + while ( v17 != 3 && *v5 ); + } +} diff --git a/Source/plrmsg.h b/Source/plrmsg.h new file mode 100644 index 000000000..785b629c8 --- /dev/null +++ b/Source/plrmsg.h @@ -0,0 +1,22 @@ +//HEADER_GOES_HERE +#ifndef __PLRMSG_H__ +#define __PLRMSG_H__ + +extern int plrmsg_ticks; // weak +extern char plr_msg_slot; // weak +extern _plrmsg plr_msgs[8]; + +void __fastcall plrmsg_delay(int a1); +char *__fastcall ErrorPlrMsg(char *pszMsg); +size_t EventPlrMsg(char *pszFmt, ...); +void __fastcall SendPlrMsg(int pnum, const char *pszStr); +void __cdecl ClearPlrMsg(); +void __cdecl InitPlrMsg(); +void __cdecl DrawPlrMsg(); +void __fastcall PrintPlrMsg(int no, int x, int y, char *str, int just); + +/* rdata */ + +extern const char text_color_from_player_num[5]; + +#endif /* __PLRMSG_H__ */ diff --git a/Source/portal.cpp b/Source/portal.cpp new file mode 100644 index 000000000..912b469bc --- /dev/null +++ b/Source/portal.cpp @@ -0,0 +1,214 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +PortalStruct portal[MAXPORTAL]; +int portalindex; +#endif + +int WarpDropX[MAXPORTAL] = { 57, 59, 61, 63 }; +int WarpDropY[MAXPORTAL] = { 40, 40, 40, 40 }; + +void __cdecl InitPortals() +{ + int i; // edi + + for(i = 0; i < MAXPORTAL; i++) + { + if(delta_portal_inited(i)) + portal[i].open = 0; + } +} + +void __fastcall SetPortalStats(int i, int o, int x, int y, int lvl, int lvltype) +{ + portal[i].x = x; + portal[i].setlvl = 0; + portal[i].y = y; + portal[i].open = o; + portal[i].level = lvl; + portal[i].ltype = lvltype; +} + +void __fastcall AddWarpMissile(int i, int x, int y) +{ + int mi; // eax + + missiledata[MIS_TOWN].mlSFX = -1; + dMissile[x][y] = 0; + mi = AddMissile(0, 0, x, y, 0, MIS_TOWN, 0, i, 0, 0); + + if ( mi != -1 ) + { + SetMissDir(mi, 1); + + if ( currlevel ) + missile[mi]._mlid = AddLight(missile[mi]._mix, missile[mi]._miy, 15); + + missiledata[MIS_TOWN].mlSFX = LS_SENTINEL; + } +} + +void __cdecl SyncPortals() +{ + int v0; // edi + int *v1; // esi + int v2; // eax + + v0 = 0; + v1 = &portal[0].level; + do + { + if ( *(v1 - 3) ) + { + if ( currlevel ) + { + v2 = currlevel; + if ( setlevel ) + v2 = (unsigned char)setlvlnum; + if ( *v1 == v2 ) + AddWarpMissile(v0, *(v1 - 2), *(v1 - 1)); + } + else + { + AddWarpMissile(v0, WarpDropX[v0], WarpDropY[v0]); + } + } + v1 += 6; + ++v0; + } + while ( (signed int)v1 < (signed int)&portal[MAXPORTAL].level ); +} +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; +// 69BD04: using guessed type int questlog; + +void __fastcall AddInTownPortal(int i) +{ + AddWarpMissile(i, WarpDropX[i], WarpDropY[i]); +} + +void __fastcall ActivatePortal(int i, int x, int y, int lvl, int lvltype, int sp) +{ + portal[i].open = 1; + + if ( lvl ) + { + portal[i].level = lvl; + portal[i].x = x; + portal[i].ltype = lvltype; + portal[i].y = y; + portal[i].setlvl = sp; + } +} + +void __fastcall DeactivatePortal(int i) +{ + portal[i].open = 0; +} + +bool __fastcall PortalOnLevel(int i) +{ + if ( portal[i].level == currlevel ) + return 1; + else + return currlevel == 0; +} + +void __fastcall RemovePortalMissile(int id) +{ + int i; // esi + int mi; // eax + + for ( i = 0; i < nummissiles; ++i ) + { + mi = missileactive[i]; + if ( missile[mi]._mitype == MIS_TOWN && missile[mi]._misource == id ) + { + dFlags[missile[mi]._mix][missile[mi]._miy] &= 0xFE; + dMissile[missile[mi]._mix][missile[mi]._miy] = 0; + + if ( portal[id].level ) + AddUnLight(missile[mi]._mlid); + + DeleteMissile(mi, i); + } + } +} + +void __fastcall SetCurrentPortal(int p) +{ + portalindex = p; +} + +void __cdecl GetPortalLevel() +{ + if ( currlevel ) + { + setlevel = 0; + currlevel = 0; + leveltype = 0; + plr[myplr].plrlevel = 0; + } + else + { + if ( portal[portalindex].setlvl ) + { + setlevel = 1; + setlvlnum = portal[portalindex].level; + } + else + { + setlevel = 0; + } + + currlevel = portal[portalindex].level; + leveltype = portal[portalindex].ltype; + plr[myplr].plrlevel = portal[portalindex].level; + + if ( portalindex == myplr ) + { + NetSendCmd(1, CMD_DEACTIVATEPORTAL); + DeactivatePortal(portalindex); + } + } +} +// 5BB1ED: using guessed type char leveltype; +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +void __cdecl GetPortalLvlPos() +{ + if ( currlevel ) + { + ViewX = portal[portalindex].x; + ViewY = portal[portalindex].y; + + if ( portalindex != myplr ) + { + ViewX++; + ViewY++; + } + } + else + { + ViewX = WarpDropX[portalindex] + 1; + ViewY = WarpDropY[portalindex] + 1; + } +} + +bool __fastcall PosOkPortal(int lvl, int x, int y) +{ + int *v3; // eax + + v3 = &portal[0].x; + while ( !*(v3 - 1) || v3[2] != lvl || (*v3 != x || v3[1] != y) && (*v3 != x - 1 || v3[1] != y - 1) ) + { + v3 += 6; + if ( (signed int)v3 >= (signed int)&portal[MAXPORTAL].x ) + return 0; + } + return 1; +} +// 69BCFC: using guessed type int END_portalstruct; diff --git a/Source/portal.h b/Source/portal.h new file mode 100644 index 000000000..f97623fdd --- /dev/null +++ b/Source/portal.h @@ -0,0 +1,27 @@ +//HEADER_GOES_HERE +#ifndef __PORTAL_H__ +#define __PORTAL_H__ + +extern PortalStruct portal[MAXPORTAL]; +extern int portalindex; +// int END_portalstruct; // weak + +void __cdecl InitPortals(); +void __fastcall SetPortalStats(int i, int o, int x, int y, int lvl, int lvltype); +void __fastcall AddWarpMissile(int i, int x, int y); +void __cdecl SyncPortals(); +void __fastcall AddInTownPortal(int i); +void __fastcall ActivatePortal(int i, int x, int y, int lvl, int lvltype, int sp); +void __fastcall DeactivatePortal(int i); +bool __fastcall PortalOnLevel(int i); +void __fastcall RemovePortalMissile(int id); +void __fastcall SetCurrentPortal(int p); +void __cdecl GetPortalLevel(); +void __cdecl GetPortalLvlPos(); +bool __fastcall PosOkPortal(int lvl, int x, int y); + +/* rdata */ +extern int WarpDropX[MAXPORTAL]; +extern int WarpDropY[MAXPORTAL]; + +#endif /* __PORTAL_H__ */ diff --git a/Source/quests.cpp b/Source/quests.cpp new file mode 100644 index 000000000..b43aaf49d --- /dev/null +++ b/Source/quests.cpp @@ -0,0 +1,1338 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int qtopline; // idb +int questlog; // weak +void *pQLogCel; +QuestStruct quests[MAXQUESTS]; +int qline; // weak +int qlist[MAXQUESTS]; +int numqlines; // weak +int WaterDone; // idb +int ReturnLvlY; // idb +int ReturnLvlX; // idb +int ReturnLvlT; // idb +int ALLQUESTS; // idb +int ReturnLvl; // idb +#endif + +QuestData questlist[MAXQUESTS] = +{ + { 5, -1, DTYPE_NONE, 0, 100, 0, 0, QUEST_INFRA5, "The Magic Rock" }, + { 9, -1, DTYPE_NONE, 1, 100, 0, 0, QUEST_MUSH8, "Black Mushroom" }, + { 4, -1, DTYPE_NONE, 2, 100, 0, 0, QUEST_GARBUD1, "Gharbad The Weak" }, + { 8, -1, DTYPE_NONE, 3, 100, 0, 0, QUEST_ZHAR1, "Zhar the Mad" }, + { 14, -1, DTYPE_NONE, 4, 100, 0, 0, QUEST_VEIL9, "Lachdanan" }, + { 15, -1, DTYPE_NONE, 5, 100, 0, 1, QUEST_VILE3, "Diablo" }, + { 2, 2, DTYPE_NONE, 6, 100, 0, 1, QUEST_BUTCH9, "The Butcher" }, + { 4, -1, DTYPE_NONE, 7, 100, 0, 0, QUEST_BANNER2, "Ogden's Sign" }, + { 7, -1, DTYPE_NONE, 8, 100, 0, 0, QUEST_BLINDING, "Halls of the Blind" }, + { 5, -1, DTYPE_NONE, 9, 100, 0, 0, QUEST_BLOODY, "Valor" }, + { 10, -1, DTYPE_NONE, 10, 100, 0, 0, QUEST_ANVIL5, "Anvil of Fury" }, + { 13, -1, DTYPE_NONE, 11, 100, 0, 0, QUEST_BLOODWAR, "Warlord of Blood" }, + { 3, 3, DTYPE_CATHEDRAL, 12, 100, 1, 1, QUEST_KING2, "The Curse of King Leoric" }, + { 2, -1, DTYPE_CAVES, 13, 100, 4, 0, QUEST_POISON3, "Poisoned Water Supply" }, + { 6, -1, DTYPE_CATACOMBS, 14, 100, 2, 0, QUEST_BONER, "The Chamber of Bone" }, + { 15, 15, DTYPE_CATHEDRAL, 15, 100, 5, 1, QUEST_VILE1, "Archbishop Lazarus" } +}; +char questxoff[7] = { 0, -1, 0, -1, -2, -1, -2 }; +char questyoff[7] = { 0, 0, -1, -1, -1, -2, -2 }; +char *questtrigstr[5] = +{ + "King Leoric's Tomb", + "The Chamber of Bone", + "Maze", + "A Dark Passage", + "Unholy Altar" +}; +int QuestGroup1[3] = { QTYPE_BUTCH, QTYPE_BOL, QTYPE_GARB }; +int QuestGroup2[3] = { QTYPE_BLIND, QTYPE_INFRA, QTYPE_BLOOD }; +int QuestGroup3[3] = { QTYPE_BLKM, QTYPE_ZHAR, QTYPE_ANVIL }; +int QuestGroup4[2] = { QTYPE_VEIL, QTYPE_WARLRD }; + +void __cdecl InitQuests() +{ + char v0; // dl + unsigned char *v1; // esi + unsigned char *v2; // eax + unsigned char *v3; // ecx + int *v4; // eax + int v5; // ebp + unsigned int v6; // edi + //int v7; // eax + unsigned char v8; // al + unsigned char v9; // al + char v10; // al + int v13; // eax + int v15; // eax + int v17; // eax + int v19; // eax + char v20; // [esp+8h] [ebp-4h] + + v0 = gbMaxPlayers; + v1 = &quests[0]._qactive; + if ( gbMaxPlayers == 1 ) + { + v2 = &quests[0]._qactive; + do + { + *v2 = 0; + v2 += 24; + } + while ( (signed int)v2 < (signed int)&quests[MAXQUESTS]._qactive ); + } + else + { + v3 = &quests[0]._qactive; + v4 = &questlist[0]._qflags; + do + { + if ( !(*(_BYTE *)v4 & 1) ) + *v3 = 0; + v4 += 5; + v3 += 24; + } + while ( (signed int)v4 < (signed int)&questlist[MAXQUESTS]._qflags ); + } + v5 = 0; + questlog = 0; + ALLQUESTS = 1; + WaterDone = 0; + v20 = 0; + v6 = 0; + do + { + if ( (unsigned char)v0 <= 1u || questlist[v6]._qflags & 1 ) + { + *(v1 - 1) = questlist[v6]._qdtype; + if ( (unsigned char)v0 <= 1u ) + { + v8 = questlist[v6]._qdlvl; + *v1 = 1; + *(v1 - 2) = v8; + v1[13] = 0; + *(_DWORD *)(v1 + 18) = 0; + } + else + { + *(v1 - 2) = questlist[v6]._qdmultlvl; + //_LOBYTE(v7) = delta_quest_inited(v5); + if ( !delta_quest_inited(v5) ) + { + *v1 = 1; + v1[13] = 0; + *(_DWORD *)(v1 + 18) = 0; + } + v0 = gbMaxPlayers; + ++v5; + } + v9 = questlist[v6]._qslvl; + *(_DWORD *)(v1 + 2) = 0; + v1[10] = v9; + v1[11] = v20; + v1[1] = questlist[v6]._qlvlt; + v10 = questlist[v6]._qdmsg; + *(_DWORD *)(v1 + 6) = 0; + v1[14] = 0; + v1[12] = v10; + } + ++v20; + ++v6; + v1 += 24; + } + while ( v6 < MAXQUESTS ); + if ( v0 == 1 ) + { + SetRndSeed(glSeedTbl[15]); + if ( random(0, 2) ) + quests[13]._qactive = 0; + else + quests[12]._qactive = 0; + v13 = random(0, 3); + quests[QuestGroup1[v13]]._qactive = 0; + v15 = random(0, 3); + quests[QuestGroup2[v15]]._qactive = 0; + v17 = random(0, 3); + quests[QuestGroup3[v17]]._qactive = 0; + v19 = random(0, 2); + v0 = gbMaxPlayers; + quests[QuestGroup4[v19]]._qactive = 0; + } +#ifdef _DEBUG + if ( questdebug != -1 ) + quests[questdebug]._qactive = 2; +#endif + if ( !quests[12]._qactive ) + quests[12]._qvar2 = 2; + if ( !quests[0]._qactive ) + quests[0]._qvar2 = 2; + quests[7]._qvar1 = 1; + if ( v0 != 1 ) + quests[15]._qvar1 = 2; +} +// 679660: using guessed type char gbMaxPlayers; +// 69BD04: using guessed type int questlog; +// 69BE90: using guessed type int qline; + +void __cdecl CheckQuests() +{ + //int v0; // eax + unsigned char *v1; // esi + unsigned char v2; // cl + + //_LOBYTE(v0) = QuestStatus(15); + if ( QuestStatus(15) ) + { + if ( gbMaxPlayers == 1 ) + goto LABEL_6; + if ( quests[15]._qvar1 == 2 ) + { + AddObject(OBJ_ALTBOY, 2 * setpc_x + 20, 2 * setpc_y + 22); + quests[15]._qvar1 = 3; + NetSendCmdQuest(1u, 0xFu); + } + } + if ( gbMaxPlayers != 1 ) + return; +LABEL_6: + if ( currlevel == quests[15]._qlevel && !setlevel && quests[15]._qvar1 >= 2u ) + { + if ( quests[15]._qactive != 2 && quests[15]._qactive != 3 ) + goto LABEL_29; + if ( !quests[15]._qvar2 || quests[15]._qvar2 == 2 ) + { + quests[15]._qtx = 2 * quests[15]._qtx + 16; + quests[15]._qty = 2 * quests[15]._qty + 16; + AddMissile(quests[15]._qtx, quests[15]._qty, quests[15]._qtx, quests[15]._qty, 0, 65, 0, myplr, 0, 0); + quests[15]._qvar2 = 1; + if ( quests[15]._qactive == 2 ) + quests[15]._qvar1 = 3; + } + } + if ( quests[15]._qactive == 3 ) + { + if ( !setlevel ) + goto LABEL_29; + if ( setlvlnum == SL_VILEBETRAYER && quests[15]._qvar2 == 4 ) + { + AddMissile(35, 32, 35, 32, 0, 65, 0, myplr, 0, 0); + quests[15]._qvar2 = 3; + } + } + if ( setlevel ) + { + if ( setlvlnum == quests[13]._qslvl + && quests[13]._qactive != 1 + && leveltype == quests[13]._qlvltype + && nummonsters == 4 + && quests[13]._qactive != 3 ) + { + quests[13]._qactive = 3; + PlaySfxLoc(IS_QUESTDN, plr[myplr].WorldX, plr[myplr].WorldY); + LoadPalette("Levels\\L3Data\\L3pwater.pal"); + WaterDone = 32; + } + if ( WaterDone > 0 ) + { + palette_update_quest_palette(WaterDone); + --WaterDone; + } + return; + } +LABEL_29: + if ( plr[myplr]._pmode == PM_STAND ) + { + v1 = &quests[0]._qactive; + do + { + if ( currlevel == *(v1 - 2) ) + { + v2 = v1[10]; + if ( v2 ) + { + if ( *v1 && plr[myplr].WorldX == *(_DWORD *)(v1 + 2) && plr[myplr].WorldY == *(_DWORD *)(v1 + 6) ) + { + if ( v1[1] != -1 ) + setlvltype = v1[1]; + StartNewLvl(myplr, WM_DIABSETLVL, v2); + } + } + } + v1 += 24; + } + while ( (signed int)v1 < (signed int)&quests[MAXQUESTS]._qactive ); + } +} +// 5BB1ED: using guessed type char leveltype; +// 5CCB10: using guessed type char setlvlnum; +// 5CF31C: using guessed type char setlvltype; +// 5CF31D: using guessed type char setlevel; +// 679660: using guessed type char gbMaxPlayers; +// 69BE90: using guessed type int qline; + +bool __cdecl ForceQuests() +{ + QuestStruct *v0; // eax + int v1; // esi + int v2; // edi + int v3; // edx + + if ( gbMaxPlayers != 1 ) + return 0; + v0 = (QuestStruct *)((char *)quests + 12); + while ( v0 == (QuestStruct *)&quests[15]._qslvl || currlevel != v0[-1]._qslvl || !v0->_qlevel ) + { +LABEL_10: + ++v0; + if ( (signed int)v0 >= (signed int)&quests[MAXQUESTS]._qslvl ) /* fix */ + return 0; + } + v1 = *(_DWORD *)&v0[-1]._qvar2; + v2 = v0[-1]._qlog; + v3 = 0; + while ( v1 + questxoff[v3] != cursmx || v2 + questyoff[v3] != cursmy ) + { + if ( ++v3 >= 7 ) + goto LABEL_10; + } + sprintf(infostr, "To %s", questtrigstr[(unsigned char)quests[(unsigned char)v0->_qtype]._qslvl - 1]); + cursmx = v1; + cursmy = v2; + return 1; +} +// 679660: using guessed type char gbMaxPlayers; + +BOOL __fastcall QuestStatus(int i) +{ + BOOL result; // al + + if ( setlevel + || currlevel != quests[i]._qlevel + || !quests[i]._qactive + || (result = 1, gbMaxPlayers != 1) && !(questlist[i]._qflags & 1) ) + { + result = FALSE; + } + return result; +} +// 5CF31D: using guessed type char setlevel; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall CheckQuestKill(int m, unsigned char sendmsg) +{ + int v2; // ecx + char v3; // al + char v4; // al + unsigned char v5; // dl + char v6; // al + char *v7; // ecx + char v8; // al + char v9; // al + int v10; // edi + int (*v11)[112]; // esi + signed int v12; // ecx + int *v13; // eax + int (*v14)[112]; // ebx + char v15; // al + char v16; // al + char v17; // al + + v2 = m; + v3 = monster[v2].MType->mtype; + if ( v3 == MT_SKING ) + { + quests[12]._qactive = 3; + sfxdelay = 30; + v4 = plr[myplr]._pClass; + if ( v4 ) + { + if ( v4 == 1 ) + { + sfxdnum = PS_ROGUE82; + } + else if ( v4 == 2 ) + { + sfxdnum = PS_MAGE82; + } + } + else + { + sfxdnum = PS_WARR82; + } + if ( sendmsg ) + { + v5 = 12; +LABEL_10: + NetSendCmdQuest(1u, v5); + return; + } + } + else + { + if ( v3 != MT_CLEAVER ) + { + v7 = monster[v2].mName; + if ( v7 == UniqMonst[0].mName ) + { + quests[2]._qactive = 3; + sfxdelay = 30; + v8 = plr[myplr]._pClass; + if ( v8 ) + { + if ( v8 == 1 ) + { + sfxdnum = PS_ROGUE61; + } + else if ( v8 == 2 ) + { + sfxdnum = PS_MAGE61; + } + } + else + { + sfxdnum = PS_WARR61; + } + return; + } + if ( v7 == UniqMonst[2].mName ) + { + quests[3]._qactive = 3; + sfxdelay = 30; + v9 = plr[myplr]._pClass; + if ( v9 ) + { + if ( v9 == 1 ) + { + sfxdnum = PS_ROGUE62; + } + else if ( v9 == 2 ) + { + sfxdnum = PS_MAGE62; + } + } + else + { + sfxdnum = PS_WARR62; + } + return; + } + if ( v7 == UniqMonst[4].mName ) + { + if ( gbMaxPlayers != 1 ) + { + quests[15]._qactive = 3; + quests[15]._qvar1 = 7; + sfxdelay = 30; + quests[5]._qactive = 2; + v10 = 0; + v11 = dPiece; + do + { + v12 = 0; + v13 = &trigs[trigflag[4]]._ty; + v14 = v11; + do + { + if ( (*v14)[0] == 370 ) + { + ++trigflag[4]; + *(v13 - 1) = v12; + *v13 = v10; + v13[1] = 1026; + v13 += 4; + } + ++v12; + ++v14; + } + while ( v12 < 112 ); + v11 = (int (*)[112])((char *)v11 + 4); + ++v10; + } + while ( (signed int)v11 < (signed int)dPiece[1] ); + v15 = plr[myplr]._pClass; + if ( v15 ) + { + if ( v15 == 1 ) + { + sfxdnum = PS_ROGUE83; + } + else if ( v15 == 2 ) + { + sfxdnum = PS_MAGE83; + } + } + else + { + sfxdnum = PS_WARR83; + } + if ( sendmsg ) + { + NetSendCmdQuest(1u, 0xFu); + v5 = 5; + goto LABEL_10; + } + return; + } + if ( v7 == UniqMonst[4].mName && gbMaxPlayers == 1 ) + { + quests[15]._qactive = 3; + sfxdelay = 30; + InitVPTriggers(); + quests[15]._qvar1 = 7; + quests[15]._qvar2 = 4; + quests[5]._qactive = 2; + AddMissile(35, 32, 35, 32, 0, 65, 0, myplr, 0, 0); + v16 = plr[myplr]._pClass; + if ( v16 ) + { + if ( v16 == 1 ) + { + sfxdnum = PS_ROGUE83; + } + else if ( v16 == 2 ) + { + sfxdnum = PS_MAGE83; + } + } + else + { + sfxdnum = PS_WARR83; + } + return; + } + } + if ( v7 == UniqMonst[8].mName ) + { + quests[11]._qactive = 3; + sfxdelay = 30; + v17 = plr[myplr]._pClass; + if ( v17 ) + { + if ( v17 == 1 ) + { + sfxdnum = PS_ROGUE94; + } + else if ( v17 == 2 ) + { + sfxdnum = PS_MAGE94; + } + } + else + { + sfxdnum = PS_WARR94; + } + } + return; + } + quests[6]._qactive = 3; + sfxdelay = 30; + v6 = plr[myplr]._pClass; + if ( v6 ) + { + if ( v6 == 1 ) + { + sfxdnum = PS_ROGUE80; + } + else if ( v6 == 2 ) + { + sfxdnum = PS_MAGE80; + } + } + else + { + sfxdnum = PS_WARR80; + } + if ( sendmsg ) + { + v5 = 6; + goto LABEL_10; + } + } +} +// 52A554: using guessed type int sfxdelay; +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl DrawButcher() +{ + DRLG_RectTrans(2 * setpc_x + 19, 2 * setpc_y + 19, 2 * setpc_x + 26, 2 * setpc_y + 26); +} + +void __fastcall DrawSkelKing(int q, int x, int y) +{ + int v3; // eax + + v3 = q; + quests[v3]._qtx = 2 * x + 28; + quests[v3]._qty = 2 * y + 23; +} + +void __fastcall DrawWarLord(int x, int y) +{ + int v2; // esi + int v3; // edi + unsigned char *v4; // eax + int v5; // ebx + int v6; // edx + int v7; // edx + char *v8; // eax + int v9; // ecx + char *v10; // esi + char v11; // bl + unsigned char *ptr; // [esp+Ch] [ebp-Ch] + int v13; // [esp+10h] [ebp-8h] + int v14; // [esp+14h] [ebp-4h] + + v2 = y; + v3 = x; + v4 = LoadFileInMem("Levels\\L4Data\\Warlord2.DUN", 0); + v5 = *v4; + ptr = v4; + v4 += 2; + v14 = v2; + v6 = *v4; + setpc_h = v6; + v7 = v2 + v6; + v8 = (char *)(v4 + 2); + setpc_w = v5; + setpc_x = v3; + setpc_y = v2; + if ( v2 < v7 ) + { + v13 = v3 + v5; + do + { + if ( v3 < v13 ) + { + v9 = v13 - v3; + v10 = &dungeon[v3][v14]; + do + { + v11 = *v8; + if ( !*v8 ) + v11 = 6; + *v10 = v11; + v8 += 2; + v10 += 40; + --v9; + } + while ( v9 ); + } + ++v14; + } + while ( v14 < v7 ); + } + mem_free_dbg(ptr); +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __fastcall DrawSChamber(int q, int x, int y) +{ + int v3; // esi + unsigned char *v4; // eax + int v5; // edi + int v6; // ebx + int v7; // eax + char *v8; // ecx + int v9; // eax + char *v10; // edx + char v11; // bl + int v12; // edx + unsigned char *ptr; // [esp+Ch] [ebp-10h] + int v14; // [esp+10h] [ebp-Ch] + int v15; // [esp+14h] [ebp-8h] + int v16; // [esp+18h] [ebp-4h] + + v3 = x; + v14 = q; + v4 = LoadFileInMem("Levels\\L2Data\\Bonestr1.DUN", 0); + v5 = y; + ptr = v4; + v6 = y; + v7 = *v4; + setpc_h = ptr[2]; + v8 = (char *)(ptr + 4); + setpc_w = v7; + setpc_x = v3; + setpc_y = y; + v15 = y + setpc_h; + if ( y < y + setpc_h ) + { + v16 = v3 + v7; + do + { + if ( v3 < v16 ) + { + v9 = v16 - v3; + v10 = &dungeon[v3][v6]; + do + { + v11 = *v8; + if ( !*v8 ) + v11 = 3; + *v10 = v11; + v8 += 2; + v10 += 40; + --v9; + } + while ( v9 ); + } + v6 = y++ + 1; + } + while ( y < v15 ); + } + v12 = v14; + quests[v12]._qtx = 2 * v3 + 22; + quests[v12]._qty = 2 * v5 + 23; + mem_free_dbg(ptr); +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __fastcall DrawLTBanner(int x, int y) +{ + int v2; // ebx + int v3; // esi + unsigned char *v4; // eax + unsigned char *v5; // ecx + int v6; // edi + int v7; // edx + int v8; // eax + char *v9; // edx + char *v10; // ecx + unsigned char *ptr; // [esp+Ch] [ebp-10h] + int v12; // [esp+10h] [ebp-Ch] + int v13; // [esp+14h] [ebp-8h] + int v14; // [esp+18h] [ebp-4h] + + v2 = y; + v3 = x; + v12 = y; + v4 = LoadFileInMem("Levels\\L1Data\\Banner1.DUN", 0); + v5 = v4; + v14 = 0; + ptr = v4; + v6 = *v4; + v7 = (int)(v4 + 2); + v8 = v4[2]; + setpc_w = v6; + v9 = (char *)(v7 + 2); + setpc_h = v8; + setpc_x = v3; + setpc_y = v2; + if ( v8 > 0 ) + { + do + { + if ( v6 > 0 ) + { + v13 = v6; + v10 = &pdungeon[v3][v14 + v12]; + do + { + if ( *v9 ) + *v10 = *v9; + v10 += 40; + v9 += 2; + --v13; + } + while ( v13 ); + v5 = ptr; + } + ++v14; + } + while ( v14 < v8 ); + } + mem_free_dbg(v5); +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __fastcall DrawBlind(int x, int y) +{ + int v2; // ebx + int v3; // esi + unsigned char *v4; // eax + unsigned char *v5; // ecx + int v6; // edi + int v7; // edx + int v8; // eax + char *v9; // edx + char *v10; // ecx + unsigned char *ptr; // [esp+Ch] [ebp-10h] + int v12; // [esp+10h] [ebp-Ch] + int v13; // [esp+14h] [ebp-8h] + int v14; // [esp+18h] [ebp-4h] + + v2 = y; + v3 = x; + v12 = y; + v4 = LoadFileInMem("Levels\\L2Data\\Blind1.DUN", 0); + v5 = v4; + v14 = 0; + ptr = v4; + v6 = *v4; + v7 = (int)(v4 + 2); + v8 = v4[2]; + setpc_x = v3; + v9 = (char *)(v7 + 2); + setpc_y = v2; + setpc_w = v6; + setpc_h = v8; + if ( v8 > 0 ) + { + do + { + if ( v6 > 0 ) + { + v13 = v6; + v10 = &pdungeon[v3][v14 + v12]; + do + { + if ( *v9 ) + *v10 = *v9; + v10 += 40; + v9 += 2; + --v13; + } + while ( v13 ); + v5 = ptr; + } + ++v14; + } + while ( v14 < v8 ); + } + mem_free_dbg(v5); +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __fastcall DrawBlood(int x, int y) +{ + int v2; // ebx + int v3; // esi + unsigned char *v4; // eax + unsigned char *v5; // ecx + int v6; // edi + int v7; // edx + int v8; // eax + char *v9; // edx + char *v10; // ecx + unsigned char *ptr; // [esp+Ch] [ebp-10h] + int v12; // [esp+10h] [ebp-Ch] + int v13; // [esp+14h] [ebp-8h] + int v14; // [esp+18h] [ebp-4h] + + v2 = y; + v3 = x; + v12 = y; + v4 = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", 0); + v5 = v4; + v14 = 0; + ptr = v4; + v6 = *v4; + v7 = (int)(v4 + 2); + v8 = v4[2]; + setpc_x = v3; + v9 = (char *)(v7 + 2); + setpc_y = v2; + setpc_w = v6; + setpc_h = v8; + if ( v8 > 0 ) + { + do + { + if ( v6 > 0 ) + { + v13 = v6; + v10 = &dungeon[v3][v14 + v12]; + do + { + if ( *v9 ) + *v10 = *v9; + v10 += 40; + v9 += 2; + --v13; + } + while ( v13 ); + v5 = ptr; + } + ++v14; + } + while ( v14 < v8 ); + } + mem_free_dbg(v5); +} +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __fastcall DRLG_CheckQuests(int x, int y) +{ + int v2; // esi + int v3; // edi + int v4; // ebx + unsigned char *v5; // ebp + //int v6; // eax + + v2 = y; + v3 = x; + v4 = 0; + v5 = &quests[0]._qtype; + do + { + //_LOBYTE(v6) = QuestStatus(v4); + if ( QuestStatus(v4) ) + { + switch ( *v5 ) + { + case QTYPE_BUTCH: + DrawButcher(); + break; + case QTYPE_BOL: + DrawLTBanner(v3, v2); + break; + case QTYPE_BLIND: + DrawBlind(v3, v2); + break; + case QTYPE_BLOOD: + DrawBlood(v3, v2); + break; + case QTYPE_WARLRD: + DrawWarLord(v3, v2); + break; + case QTYPE_KING: + DrawSkelKing(v4, v3, v2); + break; + case QTYPE_BONE: + DrawSChamber(v4, v3, v2); + break; + } + } + v5 += 24; + ++v4; + } + while ( (signed int)v5 < (signed int)&quests[MAXQUESTS]._qtype ); +} +// 69BE90: using guessed type int qline; + +void __cdecl SetReturnLvlPos() +{ + int v0; // eax + + switch ( setlvlnum ) + { + case SL_SKELKING: + ReturnLvlX = quests[12]._qtx + 1; + ReturnLvlY = quests[12]._qty; + v0 = (unsigned char)quests[12]._qlevel; + goto LABEL_9; + case SL_BONECHAMB: + ReturnLvlT = 2; + ReturnLvlX = quests[14]._qtx + 1; + ReturnLvlY = quests[14]._qty; + v0 = (unsigned char)quests[14]._qlevel; + goto LABEL_10; + case SL_POISONWATER: + ReturnLvlX = quests[13]._qtx; + ReturnLvlY = quests[13]._qty + 1; + v0 = (unsigned char)quests[13]._qlevel; +LABEL_9: + ReturnLvlT = 1; + goto LABEL_10; + } + if ( setlvlnum != 5 ) + return; + ReturnLvlT = 4; + ReturnLvlX = quests[15]._qtx + 1; + ReturnLvlY = quests[15]._qty - 1; + v0 = (unsigned char)quests[15]._qlevel; +LABEL_10: + ReturnLvl = v0; +} +// 5CCB10: using guessed type char setlvlnum; + +void __cdecl GetReturnLvlPos() +{ + if ( quests[15]._qactive == 3 ) + quests[15]._qvar2 = 2; + ViewX = ReturnLvlX; + ViewY = ReturnLvlY; + currlevel = ReturnLvl; + leveltype = ReturnLvlT; +} +// 5BB1ED: using guessed type char leveltype; + +void __cdecl ResyncMPQuests() +{ + if ( quests[12]._qactive == 1 + && currlevel >= (unsigned char)quests[12]._qlevel - 1 + && currlevel <= (unsigned char)quests[12]._qlevel + 1 ) + { + quests[12]._qactive = 2; + NetSendCmdQuest(1u, 0xCu); + } + if ( quests[6]._qactive == 1 + && currlevel >= (unsigned char)quests[6]._qlevel - 1 + && currlevel <= (unsigned char)quests[6]._qlevel + 1 ) + { + quests[6]._qactive = 2; + NetSendCmdQuest(1u, 6u); + } + if ( quests[15]._qactive == 1 && currlevel == (unsigned char)quests[15]._qlevel - 1 ) + { + quests[15]._qactive = 2; + NetSendCmdQuest(1u, 0xFu); + } + if ( QuestStatus(15) ) + AddObject(OBJ_ALTBOY, 2 * setpc_x + 20, 2 * setpc_y + 22); +} + +void __cdecl ResyncQuests() +{ + char *v0; // ecx + int v1; // esi + //int v2; // eax + int i; // esi + char v4; // bl + int j; // esi + char v6; // bl + int k; // esi + + if ( setlevel && setlvlnum == quests[13]._qslvl && quests[13]._qactive != 1 && leveltype == quests[13]._qlvltype ) + { + v0 = "Levels\\L3Data\\L3pwater.pal"; + if ( quests[13]._qactive != 3 ) + v0 = "Levels\\L3Data\\L3pfoul.pal"; + LoadPalette(v0); + v1 = 0; + do + palette_update_quest_palette(v1++); + while ( v1 <= 32 ); + } + //_LOBYTE(v2) = QuestStatus(7); + if ( QuestStatus(7) ) + { + if ( quests[7]._qvar1 == 1 ) + ObjChangeMapResync( + setpc_w + setpc_x - 2, + setpc_h + setpc_y - 2, + setpc_w + setpc_x + 1, + setpc_h + setpc_y + 1); + if ( quests[7]._qvar1 == 2 ) + { + ObjChangeMapResync( + setpc_w + setpc_x - 2, + setpc_h + setpc_y - 2, + setpc_w + setpc_x + 1, + setpc_h + setpc_y + 1); + ObjChangeMapResync(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 2, (setpc_h >> 1) + setpc_y - 2); + for ( i = 0; i < nobjects; ++i ) + SyncObjectAnim(objectactive[i]); + v4 = TransVal; + TransVal = 9; + DRLG_MRectTrans(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 4, setpc_y + (setpc_h >> 1)); + TransVal = v4; + } + if ( quests[7]._qvar1 == 3 ) + { + ObjChangeMapResync(setpc_x, setpc_y, setpc_w + setpc_x + 1, setpc_h + setpc_y + 1); + for ( j = 0; j < nobjects; ++j ) + SyncObjectAnim(objectactive[j]); + v6 = TransVal; + TransVal = 9; + DRLG_MRectTrans(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 4, setpc_y + (setpc_h >> 1)); + TransVal = v6; + } + } + if ( currlevel == quests[1]._qlevel ) + { + if ( quests[1]._qactive == 1 ) + { + if ( !quests[1]._qvar1 ) + { + SpawnQuestItem(19, 0, 0, 5, 1); + quests[1]._qvar1 = 1; + } + } + else if ( quests[1]._qactive == 2 ) + { + if ( quests[1]._qvar1 < 5u ) + { + if ( quests[1]._qvar1 >= 7u ) + Qtalklist[1]._qblkm = -1; + } + else + { + Qtalklist[6]._qblkm = -1; + Qtalklist[1]._qblkm = 123; + } + } + } + if ( currlevel == (unsigned char)quests[4]._qlevel + 1 && quests[4]._qactive == 2 && !quests[4]._qvar1 ) + { + quests[4]._qvar1 = 1; + SpawnQuestItem(15, 0, 0, 5, 1); + } + if ( setlevel && setlvlnum == 5 ) + { + if ( quests[15]._qvar1 >= 4u ) + ObjChangeMapResync(1, 11, 20, 18); + if ( quests[15]._qvar1 >= 6u ) + ObjChangeMapResync(1, 18, 20, 24); + if ( quests[15]._qvar1 >= 7u ) + InitVPTriggers(); + for ( k = 0; k < nobjects; ++k ) + SyncObjectAnim(objectactive[k]); + } + if ( currlevel == quests[15]._qlevel + && !setlevel + && (quests[15]._qvar2 == 1 || quests[15]._qvar2 >= 3u) + && (quests[15]._qactive == 2 || quests[15]._qactive == 3) ) + { + quests[15]._qvar2 = 2; + } +} +// 5A5590: using guessed type char TransVal; +// 5BB1ED: using guessed type char leveltype; +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; +// 5CF330: using guessed type int setpc_h; +// 5CF334: using guessed type int setpc_w; + +void __fastcall PrintQLString(int x, int y, unsigned char cjustflag, char *str, int col) +{ + int v5; // ebx + int v6; // edi + size_t v7; // eax + int v8; // esi + signed int v9; // ecx + signed int v10; // eax + int v11; // edx + int v12; // ecx + signed int v13; // ecx + unsigned char v14; // al + int v15; // edi + int v16; // ecx + int v17; // [esp+Ch] [ebp-14h] + int v18; // [esp+10h] [ebp-10h] + signed int v19; // [esp+14h] [ebp-Ch] + signed int v20; // [esp+18h] [ebp-8h] + int width; // [esp+1Ch] [ebp-4h] + + v5 = SStringY[y]; + v6 = x; + v18 = y; + v17 = x; + width = screen_y_times_768[v5 + 204] + x + 96; + v7 = strlen(str); + v8 = 0; + v9 = 0; + v20 = v7; + if ( cjustflag ) + { + v10 = 0; + if ( v20 <= 0 ) + goto LABEL_24; + do + { + v11 = (unsigned char)str[v9++]; + v10 += fontkern[fontframe[fontidx[v11]]] + 1; + } + while ( v9 < v20 ); + if ( v10 < 257 ) +LABEL_24: + v8 = (257 - v10) >> 1; + width += v8; + } + if ( qline == v18 ) + { + v12 = v8 + v6 + 76; + if ( !cjustflag ) + v12 = v6 + 76; + CelDecodeOnly(v12, v5 + 205, pCelBuff, ALLQUESTS, 12); + } + v13 = 0; + v19 = 0; + if ( v20 > 0 ) + { + do + { + v14 = fontframe[fontidx[(unsigned char)str[v13]]]; + v15 = v14; + v8 += fontkern[v14] + 1; + if ( v14 && v8 <= 257 ) + { + CPrintString(width, v14, col); + v13 = v19; + } + v19 = ++v13; + width += fontkern[v15] + 1; + } + while ( v13 < v20 ); + v6 = v17; + } + if ( qline == v18 ) + { + if ( cjustflag ) + v16 = v8 + v6 + 100; + else + v16 = 340 - v6; + CelDecodeOnly(v16, v5 + 205, pCelBuff, ALLQUESTS, 12); + } +} +// 69BE90: using guessed type int qline; + +void __cdecl DrawQuestLog() +{ + int v0; // edi + int i; // esi + + PrintQLString(0, 2, 1u, "Quest Log", 3); + CelDecodeOnly(64, 511, pQLogCel, 1, 320); + v0 = qtopline; + for ( i = 0; i < numqlines; ++i ) + { + PrintQLString(0, v0, 1u, questlist[qlist[i]]._qlstr, 0); + v0 += 2; + } + PrintQLString(0, 22, 1u, "Close Quest Log", 0); + ALLQUESTS = (ALLQUESTS & 7) + 1; +} +// 69BED4: using guessed type int numqlines; + +void __cdecl StartQuestlog() +{ + signed int v0; // eax + int v1; // edx + unsigned int v2; // ecx + int v3; // ecx + + v0 = 0; + v1 = 0; + numqlines = 0; + v2 = 0; + do + { + if ( quests[v2]._qactive == 2 && quests[v2]._qlog ) + qlist[v0++] = v1; + ++v2; + ++v1; + } + while ( v2 < MAXQUESTS ); + numqlines = v0; + if ( v0 <= 5 ) + v3 = 8; + else + v3 = 5 - (v0 >> 1); + qtopline = v3; + qline = 22; + if ( v0 ) + qline = v3; + questlog = 1; + ALLQUESTS = 1; +} +// 69BD04: using guessed type int questlog; +// 69BE90: using guessed type int qline; +// 69BED4: using guessed type int numqlines; + +void __cdecl QuestlogUp() +{ + if ( numqlines ) + { + if ( qline == qtopline ) + { + qline = 22; + } + else if ( qline == 22 ) + { + qline = qtopline + 2 * numqlines - 2; + } + else + { + qline -= 2; + } + PlaySFX(IS_TITLEMOV); + } +} +// 69BE90: using guessed type int qline; +// 69BED4: using guessed type int numqlines; + +void __cdecl QuestlogDown() +{ + if ( numqlines ) + { + if ( qline == 22 ) + { + qline = qtopline; + } + else if ( qline == qtopline + 2 * numqlines - 2 ) + { + qline = 22; + } + else + { + qline += 2; + } + PlaySFX(IS_TITLEMOV); + } +} +// 69BE90: using guessed type int qline; +// 69BED4: using guessed type int numqlines; + +void __cdecl QuestlogEnter() +{ + PlaySFX(IS_TITLSLCT); + if ( numqlines && qline != 22 ) + InitQTextMsg((unsigned char)quests[qlist[(qline - qtopline) >> 1]]._qmsg); + questlog = 0; +} +// 69BD04: using guessed type int questlog; +// 69BE90: using guessed type int qline; +// 69BED4: using guessed type int numqlines; + +void __cdecl QuestlogESC() +{ + int v0; // esi + int i; // edi + + v0 = (MouseY - 32) / 12; + if ( numqlines ) + { + for ( i = 0; i < numqlines; ++i ) + { + if ( v0 == qtopline + 2 * i ) + { + qline = v0; + QuestlogEnter(); + } + } + } + if ( v0 == 22 ) + { + qline = 22; + QuestlogEnter(); + } +} +// 69BE90: using guessed type int qline; +// 69BED4: using guessed type int numqlines; + +void __fastcall SetMultiQuest(int q, int s, unsigned char l, int v1) +{ + int v4; // eax + unsigned char *v5; // ecx + unsigned char *v6; // eax + + v4 = q; + v5 = &quests[q]._qactive; + if ( *v5 != 3 ) + { + if ( s > (unsigned char)*v5 ) + *v5 = s; + quests[v4]._qlog |= l; + v6 = &quests[v4]._qvar1; + if ( v1 > (unsigned char)*v6 ) + *v6 = v1; + } +} diff --git a/Source/quests.h b/Source/quests.h new file mode 100644 index 000000000..aca6a2e04 --- /dev/null +++ b/Source/quests.h @@ -0,0 +1,55 @@ +//HEADER_GOES_HERE +#ifndef __QUESTS_H__ +#define __QUESTS_H__ + +extern int qtopline; // idb +extern int questlog; // weak +extern void *pQLogCel; +extern QuestStruct quests[MAXQUESTS]; +extern int qline; // weak +extern int qlist[MAXQUESTS]; +extern int numqlines; // weak +extern int WaterDone; // idb +extern int ReturnLvlY; // idb +extern int ReturnLvlX; // idb +extern int ReturnLvlT; // idb +extern int ALLQUESTS; // idb +extern int ReturnLvl; // idb + +void __cdecl InitQuests(); +void __cdecl CheckQuests(); +bool __cdecl ForceQuests(); +BOOL __fastcall QuestStatus(int i); +void __fastcall CheckQuestKill(int m, unsigned char sendmsg); +void __cdecl DrawButcher(); +void __fastcall DrawSkelKing(int q, int x, int y); +void __fastcall DrawWarLord(int x, int y); +void __fastcall DrawSChamber(int q, int x, int y); +void __fastcall DrawLTBanner(int x, int y); +void __fastcall DrawBlind(int x, int y); +void __fastcall DrawBlood(int x, int y); +void __fastcall DRLG_CheckQuests(int x, int y); +void __cdecl SetReturnLvlPos(); +void __cdecl GetReturnLvlPos(); +void __cdecl ResyncMPQuests(); +void __cdecl ResyncQuests(); +void __fastcall PrintQLString(int x, int y, unsigned char cjustflag, char *str, int col); +void __cdecl DrawQuestLog(); +void __cdecl StartQuestlog(); +void __cdecl QuestlogUp(); +void __cdecl QuestlogDown(); +void __cdecl QuestlogEnter(); +void __cdecl QuestlogESC(); +void __fastcall SetMultiQuest(int q, int s, unsigned char l, int v1); + +/* rdata */ +extern QuestData questlist[MAXQUESTS]; +extern char questxoff[7]; +extern char questyoff[7]; +extern char *questtrigstr[5]; +extern int QuestGroup1[3]; +extern int QuestGroup2[3]; +extern int QuestGroup3[3]; +extern int QuestGroup4[2]; + +#endif /* __QUESTS_H__ */ diff --git a/Source/render.cpp b/Source/render.cpp new file mode 100644 index 000000000..1c511cda0 --- /dev/null +++ b/Source/render.cpp @@ -0,0 +1,9068 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int WorldBoolFlag = 0; +unsigned int gdwCurrentMask = 0; +// char world_4B3264 = 0; +unsigned char *gpCelFrame = NULL; +unsigned int *gpDrawMask = NULL; +// char world_4B326D[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +#endif + +unsigned int RightMask[32] = +{ + 0xEAAAAAAA, 0xF5555555, 0xFEAAAAAA, 0xFF555555, 0xFFEAAAAA, 0xFFF55555, 0xFFFEAAAA, 0xFFFF5555, + 0xFFFFEAAA, 0xFFFFF555, 0xFFFFFEAA, 0xFFFFFF55, 0xFFFFFFEA, 0xFFFFFFF5, 0xFFFFFFFE, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +}; + +unsigned int LeftMask[32] = +{ + 0xAAAAAAAB, 0x5555555F, 0xAAAAAABF, 0x555555FF, 0xAAAAABFF, 0x55555FFF, 0xAAAABFFF, 0x5555FFFF, + 0xAAABFFFF, 0x555FFFFF, 0xAABFFFFF, 0x55FFFFFF, 0xABFFFFFF, 0x5FFFFFFF, 0xBFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +}; + +unsigned int WallMask[32] = +{ + 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, + 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, + 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, + 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555 +}; + +int WorldTbl3x16[48] = +{ + 0, 0, 0, + 4, 4, 4, + 8, 8, 8, + 12, 12, 12, + 16, 16, 16, + 20, 20, 20, + 24, 24, 24, + 28, 28, 28, + 32, 32, 32, + 36, 36, 36, + 40, 40, 40, + 44, 44, 44, + 48, 48, 48, + 52, 52, 52, + 56, 56, 56, + 60, 60, 60 +}; + +// slope/angle tables, left and right +int WorldTbl17_1[17] = { 0, 4, 8, 16, 24, 36, 48, 64, 80, 100, 120, 144, 168, 196, 224, 256, 288 }; +int WorldTbl17_2[17] = { 0, 32, 60, 88, 112, 136, 156, 176, 192, 208, 220, 232, 240, 248, 252, 256, 288 }; + +/* + 32x32 arch types + add 8 if light index is 0 + + |-| 0x8 (0) + |-| + + /\ 0x9 (1) + \/ + + /| 0xA (2) + \| + + |\ 0xB (3) + |/ + + |-| 0xC (4) + \| + + |-| 0xD (5) + |/ +*/ + +void __fastcall drawTopArchesUpperScreen(unsigned char *pbDst) +{ + unsigned char *tmp_pbDst; // edi MAPDST + unsigned char *l_tbl; // ebx + unsigned char *pdung_cels; // esi MAPDST + short cel_type_16; // ax MAPDST + signed int xx_32; // ebp MAPDST + signed int yy_32; // edx MAPDST + unsigned int dung_and80; // eax MAPDST + unsigned int chk_sh_and; // ecx MAPDST + unsigned int n_draw_shift; // ecx MAPDST + unsigned int x_minus; // ecx MAPDST + unsigned int y_minus; // ecx MAPDST + signed int i; // edx MAPDST + signed int j; // ecx MAPDST + + gpCelFrame = (unsigned char *)speed_cel_frame_num_from_light_index_frame_num; + tmp_pbDst = pbDst; + if ( !(_BYTE)light_table_index ) + { + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = ((level_cel_block >> 12) & 7) + 8; + goto LABEL_11; + } + if ( (_BYTE)light_table_index != lightmax ) + { + if ( !(level_cel_block & 0x8000) ) + { + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + l_tbl = (unsigned char *)&pLightTbl[256 * light_table_index]; + cel_type_16 = (unsigned char)(level_cel_block >> 12); + switch ( cel_type_16 ) + { + case 0: // upper (top transparent), with lighting +/* + |--| + | | + |--| +*/ + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + case 1: // upper (top transparent), with lighting +/* + /\ + ( ) + \/ +*/ + WorldBoolFlag = (unsigned char)pbDst & 1; + xx_32 = 32; + do + { + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + if ( !yy_32 ) + goto LABEL_67; + } + if ( tmp_pbDst < gpBufEnd ) + return; + if ( ((unsigned char)tmp_pbDst & 1) == WorldBoolFlag ) + { + chk_sh_and = dung_and80 >> 1; + if ( dung_and80 & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = dung_and80 >> 2; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = dung_and80 >> 2; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + chk_sh_and = dung_and80 >> 1; + if ( dung_and80 & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = dung_and80 >> 2; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = dung_and80 >> 2; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + yy_32 -= dung_and80; + } + while ( yy_32 ); +LABEL_67: + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + tmp_pbDst -= 800; + --xx_32; + } + while ( xx_32 ); + break; + case 2: // upper (top transparent), with lighting +/* + /-| + ( | + \-| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + pdung_cels += x_minus & 2; + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels += x_minus & 2; + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + tmp_pbDst += yy_32; + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + pdung_cels += y_minus & 2; + chk_sh_and = y_minus >> 1; + if ( y_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels += y_minus & 2; + chk_sh_and = y_minus >> 1; + if ( y_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 3: // upper (top transparent), with lighting +/* + |-\ + | ) + |-/ +*/ + WorldBoolFlag = 0; + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + else + { + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + chk_sh_and = y_minus >> 1; + if ( y_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + else + { + chk_sh_and = y_minus >> 1; + if ( y_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 4: // upper (top transparent), with lighting +/* + /| + / | + |__| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + pdung_cels += x_minus & 2; + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels += x_minus & 2; + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + } + break; + default: // upper (top transparent), with lighting +/* + |\ + | \ + |__| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + else + { + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + } + break; + } + return; + } + pdung_cels = (unsigned char *)pSpeedCels + + *(_DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; + cel_type_16 = (unsigned char)(level_cel_block >> 12); +LABEL_11: + + switch ( cel_type_16 ) + { + case 8: // upper (top transparent), without lighting +/* + |--| + | | + |--| +*/ + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + case 9: // upper (top transparent), without lighting +/* + /\ + ( ) + \/ +*/ + WorldBoolFlag = (unsigned char)pbDst & 1; + yy_32 = 32; +LABEL_251: + xx_32 = 32; + while ( 1 ) + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + xx_32 -= dung_and80; + if ( !xx_32 ) + { +LABEL_271: + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + tmp_pbDst -= 800; + if ( !--yy_32 ) + return; + goto LABEL_251; + } + } + xx_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + return; + if ( ((unsigned char)tmp_pbDst & 1) == WorldBoolFlag ) + { + chk_sh_and = dung_and80 >> 1; + if ( !(dung_and80 & 1) ) + goto LABEL_258; + ++pdung_cels; + ++tmp_pbDst; + if ( chk_sh_and ) + { +LABEL_265: + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = pdung_cels[0]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + goto LABEL_268; + } + } + else + { + chk_sh_and = dung_and80 >> 1; + if ( !(dung_and80 & 1) ) + goto LABEL_265; + *tmp_pbDst++ = *pdung_cels++; + if ( chk_sh_and ) + { +LABEL_258: + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = pdung_cels[1]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + goto LABEL_268; + } + } +LABEL_268: + if ( !xx_32 ) + goto LABEL_271; + } + break; + case 10: // upper (top transparent), without lighting +/* + /-| + ( | + \-| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + tmp_pbDst += yy_32; + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[1] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[0] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 11: // upper (top transparent), without lighting +/* + |-\ + | ) + |-/ +*/ + WorldBoolFlag = 0; + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + for ( n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( x_minus & 2 ) + { + tmp_pbDst[1] = pdung_cels[1]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + else + { + for ( n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( x_minus & 2 ) + { + tmp_pbDst[0] = pdung_cels[0]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + for ( n_draw_shift = y_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( x_minus & 2 ) /// BUGFIX: change to `y_minus & 2` + { + tmp_pbDst[1] = pdung_cels[1]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + else + { + for ( n_draw_shift = y_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( x_minus & 2 ) /// BUGFIX: change to `y_minus & 2` + { + tmp_pbDst[0] = pdung_cels[0]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 12: // upper (top transparent), without lighting +/* + /| + / | + |__| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift) + { + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + } + break; + default: // upper (top transparent), without lighting +/* + |\ + | \ + |__| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + for ( n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + tmp_pbDst[1] = pdung_cels[1]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + else + { + for ( n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + tmp_pbDst[0] = pdung_cels[0]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + } + break; + } + return; + } + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = (level_cel_block >> 12) & 7; + switch ( cel_type_16 ) + { + case 0: // upper (top transparent), black +/* + |--| + | | + |--| +*/ + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + case 1: // upper (top transparent), black +/* + /\ + ( ) + \/ +*/ + WorldBoolFlag = (unsigned char)pbDst & 1; + xx_32 = 32; + while ( 1 ) + { + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) != 0 ) + break; + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + return; + pdung_cels += dung_and80; + if ( ((unsigned char)tmp_pbDst & 1) == WorldBoolFlag ) + { + chk_sh_and = dung_and80 >> 1; + if ( !(dung_and80 & 1) ) + goto LABEL_378; + ++tmp_pbDst; + if ( chk_sh_and ) + { +LABEL_385: + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + goto LABEL_388; + } + } + else + { + chk_sh_and = dung_and80 >> 1; + if ( !(dung_and80 & 1) ) + goto LABEL_385; + *tmp_pbDst++ = 0; + if ( chk_sh_and ) + { +LABEL_378: + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + goto LABEL_388; + } + } +LABEL_388: + if ( !yy_32 ) + goto LABEL_391; + } + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + } + while ( yy_32 ); +LABEL_391: + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + tmp_pbDst -= 800; + if ( !--xx_32 ) + return; + } + case 2: // upper (top transparent), black +/* + /-| + ( | + \-| +*/ + WorldBoolFlag = 0; + for ( xx_32 = 30; ; xx_32 -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + return; + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + if ( !xx_32 ) + break; + } + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + tmp_pbDst += yy_32; + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + break; + case 3: // upper (top transparent), black +/* + |-\ + | ) + |-/ +*/ + WorldBoolFlag = 0; + for ( xx_32 = 30; ; xx_32 -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + return; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + if ( !xx_32 ) + break; + tmp_pbDst += xx_32; + } + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + break; + case 4: // upper (top transparent), black +/* + /| + / | + |__| +*/ + WorldBoolFlag = 0; + for ( xx_32 = 30; ; xx_32 -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + return; + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + if ( !xx_32 ) + break; + } + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + default: // upper (top transparent), black +/* + |\ + | \ + |__| +*/ + WorldBoolFlag = 0; + for ( xx_32 = 30; ; xx_32 -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + return; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + if ( !xx_32 ) + break; + tmp_pbDst += xx_32; + } + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + } +} + +void __fastcall drawBottomArchesUpperScreen(unsigned char *pbDst, unsigned int *pMask) +{ + unsigned char *tmp_pbDst; // edi MAPDST + unsigned char *pdung_cels; // esi MAPDST + short cel_type_16; // ax MAPDST + int xx_32; // edx MAPDST + unsigned int left_shift; // edx MAPDST + int yy_32; // edx MAPDST + int dung_and80; // eax MAPDST + int and80_i; // ecx MAPDST + unsigned int n_draw_shift; // ecx MAPDST + signed int i; // ecx MAPDST + unsigned char *_EBX; + + gpCelFrame = (unsigned char *)speed_cel_frame_num_from_light_index_frame_num; + tmp_pbDst = pbDst; + gpDrawMask = pMask; + if ( !(_BYTE)light_table_index ) + { + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = ((level_cel_block >> 12) & 7) + 8; +LABEL_12: + switch ( cel_type_16 ) + { + case 8: // upper (bottom transparent), without lighting +/* + |--| + | | + |--| +*/ + xx_32 = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = pdung_cels[0]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + tmp_pbDst -= 800; + --gpDrawMask; + --xx_32; + } + while ( xx_32 ); + break; + case 9: // upper (bottom transparent), without lighting +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + gdwCurrentMask = *gpDrawMask; + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + if ( dung_and80 & 0x1F ) + gdwCurrentMask <<= dung_and80 & 0x1F; + yy_32 -= dung_and80; + if ( !yy_32 ) + goto LABEL_129; + } + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + return; + left_shift = gdwCurrentMask; + and80_i = dung_and80; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = pdung_cels[0]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --and80_i; + } + while ( and80_i ); + gdwCurrentMask = left_shift; + } + while ( yy_32 ); +LABEL_129: + tmp_pbDst -= 800; + --gpDrawMask; + --xx_32; + } + while ( xx_32 ); + break; + case 10: // upper (bottom transparent), without lighting +/* + /-| + ( | + \-| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + tmp_pbDst += yy_32; + n_draw_shift = (unsigned int)(32 - yy_32) >> 2; + if ( (32 - yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 11: // upper (bottom transparent), without lighting +/* + |-\ + | ) + |-/ +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + for ( n_draw_shift = (unsigned int)(32 - yy_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 12: // upper (bottom transparent), without lighting +/* + /| + / | + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = pdung_cels[0]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + return; + } + } + break; + default: // upper (bottom transparent), without lighting +/* + |\ + | \ + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = pdung_cels[0]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + pdung_cels += (unsigned char)pdung_cels & 2; + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + return; + } + } + break; + } + return; + } + if ( (_BYTE)light_table_index != lightmax ) + { + if ( !(level_cel_block & 0x8000) ) + { + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + _EBX = (unsigned char *)&pLightTbl[256 * light_table_index]; + cel_type_16 = (unsigned char)(level_cel_block >> 12); + switch ( cel_type_16 ) + { + case 0: // upper (bottom transparent), with lighting +/* + |--| + | | + |--| +*/ + xx_32 = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + tmp_pbDst -= 800; + --gpDrawMask; + --xx_32; + } + while ( xx_32 ); + break; + case 1: // upper (bottom transparent), with lighting +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + gdwCurrentMask = *gpDrawMask; + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + if ( dung_and80 & 0x1F ) + gdwCurrentMask <<= dung_and80 & 0x1F; + yy_32 -= dung_and80; + if ( !yy_32 ) + goto LABEL_50; + } + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + return; + and80_i = dung_and80; + left_shift = gdwCurrentMask; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --and80_i; + } + while ( and80_i ); + gdwCurrentMask = left_shift; + } + while ( yy_32 ); +LABEL_50: + tmp_pbDst -= 800; + --gpDrawMask; + --xx_32; + } + while ( xx_32 ); + break; + case 2: // upper (bottom transparent), with lighting +/* + /-| + ( | + \-| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[2]]; + tmp_pbDst[1] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + tmp_pbDst += yy_32; + n_draw_shift = (unsigned int)(32 - yy_32) >> 2; + if ( (32 - yy_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[2]]; + tmp_pbDst[1] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 3: // upper (bottom transparent), with lighting +/* + |-\ + | ) + |-/ +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + for ( n_draw_shift = (unsigned int)(32 - yy_32) >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)yy_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 4: // upper (bottom transparent), with lighting +/* + /| + / | + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[2]]; + tmp_pbDst[1] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + left_shift = *gpDrawMask; + i = 32; + pdung_cels += (unsigned char)pdung_cels & 2; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + return; + } + } + break; + default: // upper (bottom transparent), with lighting +/* + |\ + | \ + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + pdung_cels += (unsigned char)pdung_cels & 2; + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + return; + } + } + break; + } + return; + } + pdung_cels = (unsigned char *)pSpeedCels + + *(_DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; + cel_type_16 = (unsigned char)(level_cel_block >> 12); + goto LABEL_12; + } + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = (level_cel_block >> 12) & 7; + switch ( cel_type_16 ) + { + case 0: // upper (bottom transparent), black +/* + |--| + | | + |--| +*/ + xx_32 = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = 0; + left_shift *= 2; + ++tmp_pbDst; + --i; + } + while ( i ); + tmp_pbDst -= 800; + --gpDrawMask; + --xx_32; + } + while ( xx_32 ); + break; + case 1: // upper (bottom transparent), black +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + gdwCurrentMask = *gpDrawMask; + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + if ( dung_and80 & 0x1F ) + gdwCurrentMask <<= dung_and80 & 0x1F; + yy_32 -= dung_and80; + if ( !yy_32 ) + goto LABEL_208; + } + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + return; + left_shift = gdwCurrentMask; + and80_i = dung_and80; + pdung_cels += dung_and80; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = 0; + left_shift *= 2; + ++tmp_pbDst; + --and80_i; + } + while ( and80_i ); + gdwCurrentMask = left_shift; + } + while ( yy_32 ); +LABEL_208: + tmp_pbDst -= 800; + --gpDrawMask; + --xx_32; + } + while ( xx_32 ); + break; + case 2: // upper (bottom transparent), black +/* + /-| + ( | + \-| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + if ( !xx_32 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + tmp_pbDst += yy_32; + n_draw_shift = (unsigned int)(32 - yy_32) >> 2; + if ( (32 - yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + xx_32 -= 2; + } + break; + case 3: // upper (bottom transparent), black +/* + |-\ + | ) + |-/ +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + if ( !xx_32 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + n_draw_shift = (unsigned int)(32 - yy_32) >> 2; + if ( (32 - yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + tmp_pbDst += xx_32; + xx_32 -= 2; + } + break; + case 4: // upper (bottom transparent), black +/* + /| + / | + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + if ( !xx_32 ) + { + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = 0; + left_shift *= 2; + ++tmp_pbDst; + --i; + } + while ( i ); + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + return; + } + xx_32 -= 2; + } + break; + default: // upper (bottom transparent), black +/* + |\ + | \ + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + if ( !xx_32 ) + { + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = 0; + left_shift *= 2; + ++tmp_pbDst; + --i; + } + while ( i ); + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + return; + } + tmp_pbDst += xx_32; + xx_32 -= 2; + } + break; + } +} + +void __fastcall drawUpperScreen(unsigned char *pbDst) +{ + unsigned char *tmp_pbDst; // edi MAPDST + unsigned char *l_tbl; // ebx + unsigned char *pdung_cels; // esi MAPDST + short cel_type_16; // ax MAPDST + char base_4; // cl MAPDST + char x_minus; // cl MAPDST + char y_minus; // cl + signed int xx_32; // ebp MAPDST + signed int yy_32; // edx MAPDST + unsigned int dung_and80; // eax MAPDST + unsigned int chk_sh_and; // ecx MAPDST + unsigned int n_draw_shift; // ecx MAPDST + signed int i; // edx MAPDST + signed int j; // ecx MAPDST + + if ( cel_transparency_active ) + { + if ( !arch_draw_type ) + { + drawTopArchesUpperScreen(pbDst); + return; + } + if ( arch_draw_type == 1 ) + { + if ( block_lvid[level_piece_id] == 1 || block_lvid[level_piece_id] == 3 ) + { + drawBottomArchesUpperScreen(pbDst, &LeftMask[31]); + return; + } + } + if ( arch_draw_type == 2 ) + { + if ( block_lvid[level_piece_id] == 2 || block_lvid[level_piece_id] == 3 ) + { + drawBottomArchesUpperScreen(pbDst, &RightMask[31]); + return; + } + } + } + gpCelFrame = (unsigned char *)speed_cel_frame_num_from_light_index_frame_num; + tmp_pbDst = pbDst; + if ( !(_BYTE)light_table_index ) + { + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = ((level_cel_block >> 12) & 7) + 8; +LABEL_22: + switch ( cel_type_16 ) + { + case 8: // upper (solid), without lighting +/* + |--| + | | + |--| +*/ + i = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + case 9: // upper (solid), without lighting +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = *pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + if ( !yy_32 ) + goto LABEL_133; + } + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + return; + chk_sh_and = dung_and80 >> 1; + if ( dung_and80 & 1 ) + { + *tmp_pbDst++ = *pdung_cels++; + if ( !chk_sh_and ) + continue; + } + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 2; + tmp_pbDst += 2; + if ( !n_draw_shift ) + continue; + } + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + while ( yy_32 ); +LABEL_133: + tmp_pbDst -= 800; + --xx_32; + } + while ( xx_32 ); + break; + case 10: // upper (solid), without lighting +/* + /-| + ( | + \-| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + tmp_pbDst += yy_32; + n_draw_shift = (unsigned int)(32 - yy_32) >> 2; + if ( (32 - yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 11: // upper (solid), without lighting +/* + |-\ + | ) + |-/ +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + for ( n_draw_shift = (unsigned int)(32 - yy_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 12: // upper (solid), without lighting +/* + /| + / | + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + } + break; + default: // upper (solid), without lighting +/* + |\ + | \ + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + } + break; + } + return; + } + if ( (_BYTE)light_table_index != lightmax ) + { + if ( !(level_cel_block & 0x8000) ) + { + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + l_tbl = (unsigned char *)&pLightTbl[256 * light_table_index]; + cel_type_16 = (unsigned short)level_cel_block >> 12; + switch ( cel_type_16 ) + { + case 0: // upper (solid), with lighting +/* + |--| + | | + |--| +*/ + xx_32 = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + base_4 = 32; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + base_4 -= 4; + } + while ( base_4 >= 4 ); + tmp_pbDst -= 800; + --xx_32; + } + while ( xx_32 ); + break; + case 1: // upper (solid), with lighting +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = *pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + if ( !yy_32 ) + goto LABEL_58; + } + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + return; + for ( base_4 = dung_and80; base_4 >= 4; base_4 -= 4 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( base_4 >= 2 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( base_4 & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + } + } + while ( yy_32 ); +LABEL_58: + tmp_pbDst -= 800; + --xx_32; + } + while ( xx_32 ); + break; + case 2: // upper (solid), with lighting +/* + /-| + ( | + \-| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + pdung_cels += (32 - (_BYTE)xx_32) & 2; + if ( (char)(32 - xx_32) >= 4 ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + x_minus -= 4; + } + while ( x_minus >= 4 ); + } + if ( x_minus >= 2 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + tmp_pbDst += yy_32; + y_minus = 32 - yy_32; + pdung_cels += (32 - (_BYTE)yy_32) & 2; + if ( (char)(32 - yy_32) >= 4 ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + y_minus -= 4; + } + while ( y_minus >= 4 ); + } + if ( y_minus >= 2 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 3: // upper (solid), with lighting +/* + |-\ + | ) + |-/ +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + for ( base_4 = 32 - xx_32; base_4 >= 4; base_4 -= 4 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( base_4 >= 2 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + pdung_cels += (unsigned char)pdung_cels & 2; + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + for ( base_4 = 32 - yy_32; base_4 >= 4; base_4 -= 4 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( base_4 >= 2 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + pdung_cels += (unsigned char)pdung_cels & 2; + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + } + break; + case 4: // upper (solid), with lighting +/* + /| + / | + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + pdung_cels += (32 - (_BYTE)xx_32) & 2; + if ( (char)(32 - xx_32) >= 4 ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + x_minus -= 4; + } + while ( x_minus >= 4 ); + } + if ( x_minus >= 2 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + tmp_pbDst -= 800; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + base_4 = 32; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + base_4 -= 4; + } + while ( base_4 >= 4 ); + tmp_pbDst -= 800; + --yy_32; + } + while ( yy_32 ); + return; + } + } + break; + default: // upper (solid), with lighting +/* + |\ + | \ + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + for ( base_4 = 32 - xx_32; base_4 >= 4; base_4 -= 4 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( base_4 >= 2 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + pdung_cels += (unsigned char)pdung_cels & 2; + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + if ( xx_32 < 0 ) + { + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + base_4 = 32; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + base_4 -= 4; + } + while ( base_4 >= 4 ); + tmp_pbDst -= 800; + --yy_32; + } + while ( yy_32 ); + return; + } + } + break; + } + return; + } + pdung_cels = (unsigned char *)pSpeedCels + + *(_DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; + cel_type_16 = (unsigned short)level_cel_block >> 12; + goto LABEL_22; + } + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = ((unsigned int)level_cel_block >> 12) & 7; + switch ( cel_type_16 ) + { + case 0: // upper (solid), black +/* + |--| + | | + |--| +*/ + i = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + case 1: // upper (solid), black +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = *pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + if ( !yy_32 ) + goto LABEL_205; + } + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + return; + pdung_cels += dung_and80; + chk_sh_and = dung_and80 >> 1; + if ( dung_and80 & 1 ) + { + *tmp_pbDst++ = 0; + if ( !chk_sh_and ) + continue; + } + n_draw_shift = dung_and80 >> 2; + if ( chk_sh_and & 1 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + if ( !n_draw_shift ) + continue; + } + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + while ( yy_32 ); +LABEL_205: + tmp_pbDst -= 800; + --xx_32; + } + while ( xx_32 ); + break; + case 2: // upper (solid), black +/* + /-| + ( | + \-| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + if ( !xx_32 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + tmp_pbDst += yy_32; + n_draw_shift = (unsigned int)(32 - yy_32) >> 2; + if ( (32 - yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + xx_32 -= 2; + } + break; + case 3: // upper (solid), black +/* + |-\ + | ) + |-/ +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + if ( !xx_32 ) + { + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + n_draw_shift = (unsigned int)(32 - yy_32) >> 2; + if ( (32 - yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + tmp_pbDst += xx_32; + xx_32 -= 2; + } + break; + case 4: // upper (solid), black +/* + /| + / | + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + if ( !xx_32 ) + { + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + xx_32 -= 2; + } + break; + default: // upper (solid), black +/* + |\ + | \ + |__| +*/ + xx_32 = 30; + while ( tmp_pbDst >= gpBufEnd ) + { + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + if ( !xx_32 ) + { + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + break; + j = 8; + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + tmp_pbDst += xx_32; + xx_32 -= 2; + } + break; + } +} + +void __fastcall drawTopArchesLowerScreen(unsigned char *pbDst) +{ + unsigned char *tmp_pbDst; // edi MAPDST + unsigned char *l_tbl; // ebx + unsigned char *pdung_cels; // esi MAPDST + short cel_type_16; // ax MAPDST + signed int tile_42_45; // eax MAPDST + unsigned int world_tbl; // ecx MAPDST + int world_192; // eax MAPDST + unsigned int dung_and80; // eax MAPDST + unsigned int chk_sh_and; // ecx MAPDST + int xx_32; // edx MAPDST + unsigned int x_minus; // ecx MAPDST + unsigned int n_draw_shift; // ecx MAPDST + int yy_32; // edx MAPDST + unsigned int y_minus; // ecx MAPDST + signed int i; // edx MAPDST + signed int j; // ecx MAPDST + + gpCelFrame = (unsigned char *)speed_cel_frame_num_from_light_index_frame_num; + tmp_pbDst = pbDst; + if ( !(_BYTE)light_table_index ) + { + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = ((level_cel_block >> 12) & 7) + 8; + goto LABEL_11; + } + if ( (_BYTE)light_table_index == lightmax ) + { + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = (level_cel_block >> 12) & 7; + switch ( cel_type_16 ) + { + case 0: // lower (top transparent), black +/* + |--| + | | + |--| +*/ + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + case 1: // lower (top transparent), black +/* + /\ + ( ) + \/ +*/ + WorldBoolFlag = (unsigned char)pbDst & 1; + xx_32 = 32; +LABEL_412: + yy_32 = 32; + while ( 1 ) + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + if ( !yy_32 ) + { +LABEL_433: + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + tmp_pbDst -= 800; + if ( !--xx_32 ) + return; + goto LABEL_412; + } + } + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + { + pdung_cels += dung_and80; + if ( ((unsigned char)tmp_pbDst & 1) == WorldBoolFlag ) + { + chk_sh_and = dung_and80 >> 1; + if ( !(dung_and80 & 1) ) + goto LABEL_420; + ++tmp_pbDst; + if ( chk_sh_and ) + { +LABEL_427: + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + goto LABEL_430; + } + } + else + { + chk_sh_and = dung_and80 >> 1; + if ( !(dung_and80 & 1) ) + goto LABEL_427; + *tmp_pbDst++ = 0; + if ( chk_sh_and ) + { +LABEL_420: + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + goto LABEL_430; + } + } + } + else + { + pdung_cels += dung_and80; + tmp_pbDst += dung_and80; + } +LABEL_430: + if ( !yy_32 ) + goto LABEL_433; + } + break; + case 2: // lower (top transparent), black +/* + /-| + ( | + \-| +*/ + WorldBoolFlag = 0; + for ( xx_32 = 30; ; xx_32 -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels = &pdung_cels[-xx_32 + 32]; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( !xx_32 ) + break; + } + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + tmp_pbDst += yy_32; + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels = &pdung_cels[-yy_32 + 32]; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + break; + case 3: // lower (top transparent), black +/* + |-\ + | ) + |-/ +*/ + WorldBoolFlag = 0; + for ( xx_32 = 30; ; xx_32 -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels = &pdung_cels[-xx_32 + 32]; + tmp_pbDst = &tmp_pbDst[-xx_32 + 32]; + } + tmp_pbDst -= 800; + if ( !xx_32 ) + break; + tmp_pbDst += xx_32; + } + yy_32 = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels = &pdung_cels[-yy_32 + 32]; + tmp_pbDst = &tmp_pbDst[-yy_32 + 32]; + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + break; + case 4: // lower (top transparent), black +/* + /| + / | + |__| +*/ + WorldBoolFlag = 0; + for ( xx_32 = 30; ; xx_32 -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels = &pdung_cels[-xx_32 + 32]; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( !xx_32 ) + break; + } + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + default: // lower (top transparent), black +/* + |\ + | \ + |__| +*/ + WorldBoolFlag = 0; + for ( xx_32 = 30; ; xx_32 -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels = &pdung_cels[-xx_32 + 32]; + tmp_pbDst = &tmp_pbDst[-xx_32 + 32]; + } + tmp_pbDst -= 800; + if ( !xx_32 ) + break; + tmp_pbDst += xx_32; + } + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[1] = 0; + tmp_pbDst[3] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[0] = 0; + tmp_pbDst[2] = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + } + return; + } + if ( !(level_cel_block & 0x8000) ) + { + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + l_tbl = (unsigned char *)&pLightTbl[256 * light_table_index]; + cel_type_16 = (unsigned char)(level_cel_block >> 12); + switch ( cel_type_16 ) + { + case 0: // lower (top transparent), with lighting +/* + |--| + | | + |--| +*/ + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + case 1: // lower (top transparent), with lighting +/* + /\ + ( ) + \/ +*/ + WorldBoolFlag = (unsigned char)pbDst & 1; + xx_32 = 32; + do + { + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + if ( !yy_32 ) + goto LABEL_69; + } + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + { + if ( ((unsigned char)tmp_pbDst & 1) == WorldBoolFlag ) + { + chk_sh_and = dung_and80 >> 1; + if ( dung_and80 & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = dung_and80 >> 2; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = dung_and80 >> 2; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + chk_sh_and = dung_and80 >> 1; + if ( dung_and80 & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = dung_and80 >> 2; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = dung_and80 >> 2; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + } + else + { + pdung_cels += dung_and80; + tmp_pbDst += dung_and80; + } + } + while ( yy_32 ); +LABEL_69: + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + tmp_pbDst -= 800; + --xx_32; + } + while ( xx_32 ); + break; + case 2: // lower (top transparent), with lighting +/* + /-| + ( | + \-| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_98: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + yy_32 = world_tbl + 2; + WorldBoolFlag += world_tbl >> 1; + } + do + { + tmp_pbDst += yy_32; + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + pdung_cels += y_minus & 2; + chk_sh_and = y_minus >> 1; + if ( y_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels += y_minus & 2; + chk_sh_and = y_minus >> 1; + if ( y_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + xx_32 = 30 - world_tbl; + WorldBoolFlag += world_tbl >> 1; + } + do + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + pdung_cels += x_minus & 2; + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels += x_minus & 2; + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_98; + case 3: // lower (top transparent), with lighting +/* + |-\ + | ) + |-/ +*/ + WorldBoolFlag = 0; + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_154: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + yy_32 = world_tbl + 2; + WorldBoolFlag += world_tbl >> 1; + } + do + { + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + chk_sh_and = y_minus >> 1; + if ( y_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + else + { + chk_sh_and = y_minus >> 1; + if ( y_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + xx_32 = 30 - world_tbl; + WorldBoolFlag += world_tbl >> 1; + } + do + { + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + else + { + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_154; + case 4: // lower (top transparent), with lighting +/* + /| + / | + |__| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_210: + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + xx_32 = 30 - world_tbl; + WorldBoolFlag += world_tbl >> 1; + } + do + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + pdung_cels += x_minus & 2; + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels += x_minus & 2; + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_210; + default: // lower (top transparent), with lighting +/* + |\ + | \ + |__| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_249: + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + xx_32 = 30 - world_tbl; + WorldBoolFlag += world_tbl >> 1; + } + do + { + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + ++pdung_cels; + ++tmp_pbDst; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + else + { + chk_sh_and = x_minus >> 1; + if ( x_minus & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( (_BYTE)n_draw_shift ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + pdung_cels += (unsigned char)pdung_cels & 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_249; + } + return; + } + pdung_cels = (unsigned char *)pSpeedCels + *(_DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; + cel_type_16 = (unsigned char)(level_cel_block >> 12); +LABEL_11: + switch ( cel_type_16 ) + { + case 8: // lower (top transparent), without lighting +/* + |--| + | | + |--| +*/ + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + case 9: // lower (top transparent), without lighting +/* + /\ + ( ) + \/ +*/ + WorldBoolFlag = (unsigned char)pbDst & 1; + xx_32 = 32; + while ( 1 ) + { + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) != 0 ) + break; + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + { + if ( ((unsigned char)tmp_pbDst & 1) == WorldBoolFlag ) + { + chk_sh_and = dung_and80 >> 1; + if ( !(dung_and80 & 1) ) + goto LABEL_280; + ++pdung_cels; + ++tmp_pbDst; + if ( chk_sh_and ) + { +LABEL_287: + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[0] = pdung_cels[0]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + goto LABEL_290; + } + } + else + { + chk_sh_and = dung_and80 >> 1; + if ( !(dung_and80 & 1) ) + goto LABEL_287; + *tmp_pbDst++ = *pdung_cels++; + if ( chk_sh_and ) + { +LABEL_280: + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + tmp_pbDst[1] = pdung_cels[1]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + goto LABEL_290; + } + } + } + else + { + pdung_cels += dung_and80; + tmp_pbDst += dung_and80; + } +LABEL_290: + if ( !yy_32 ) + goto LABEL_293; + } + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + } + while ( yy_32 ); +LABEL_293: + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + tmp_pbDst -= 800; + if ( !--xx_32 ) + return; + } + case 10: // lower (top transparent), without lighting +/* + /-| + ( | + \-| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_308: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + yy_32 = world_tbl + 2; + WorldBoolFlag += world_tbl >> 1; + } + do + { + tmp_pbDst += yy_32; + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[1] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = y_minus >> 2; + if ( y_minus & 2 ) + { + tmp_pbDst[0] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 2; + --n_draw_shift; /// BUGFIX: delete this line + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + xx_32 = 30 - world_tbl; + WorldBoolFlag += world_tbl >> 1; + } + do + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_308; + case 11: // lower (top transparent), without lighting +/* + |-\ + | ) + |-/ +*/ + WorldBoolFlag = 0; + xx_32 = 30; + if ( pbDst < gpBufEnd ) + goto LABEL_326; + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 <= 45 ) + { + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + xx_32 = 30 - world_tbl; + WorldBoolFlag += world_tbl >> 1; + do + { +LABEL_326: + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + for ( n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + tmp_pbDst[1] = pdung_cels[1]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + else + { + for ( n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + tmp_pbDst[0] = pdung_cels[0]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_336; + } + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_336: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + yy_32 = world_tbl + 2; + WorldBoolFlag += world_tbl >> 1; + } + do + { + y_minus = 32 - yy_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + for ( n_draw_shift = y_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)yy_32) & 2 ) + { + tmp_pbDst[1] = pdung_cels[1]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + else + { + for ( n_draw_shift = y_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)yy_32) & 2 ) + { + tmp_pbDst[0] = pdung_cels[0]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + break; + case 12: // lower (top transparent), without lighting +/* + /| + / | + |__| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_364: + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + xx_32 = 30 - world_tbl; + WorldBoolFlag += world_tbl >> 1; + } + do + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[1] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + n_draw_shift = x_minus >> 2; + if ( x_minus & 2 ) + { + tmp_pbDst[0] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_364; + default: // lower (top transparent), without lighting +/* + |\ + | \ + |__| +*/ + WorldBoolFlag = 0; + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_389: + i = 8; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + world_192 = 192 * world_tbl; + world_tbl >>= 1; + tmp_pbDst -= world_192; + xx_32 = 30 - world_tbl; + WorldBoolFlag += world_tbl >> 1; + } + do + { + x_minus = 32 - xx_32; + WorldBoolFlag = ((_BYTE)WorldBoolFlag + 1) & 1; + if ( WorldBoolFlag ) + { + for ( n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[1] = pdung_cels[1]; + tmp_pbDst[3] = pdung_cels[3]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + tmp_pbDst[1] = pdung_cels[1]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + else + { + for ( n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = pdung_cels[0]; + tmp_pbDst[2] = pdung_cels[2]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + tmp_pbDst[0] = pdung_cels[0]; + pdung_cels += 4; + tmp_pbDst += 2; + } + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_389; + } +} + +void __fastcall drawBottomArchesLowerScreen(unsigned char *pbDst, unsigned int *pMask) +{ + unsigned char *tmp_pbDst; // edi MAPDST + short cel_type_16; // ax MAPDST + unsigned char *pdung_cels; // esi MAPDST + int and80_i; // ecx MAPDST + signed int tile_42_45; // eax MAPDST + unsigned int world_tbl; // ecx MAPDST + int xx_32; // ecx MAPDST + int yy_32; // edx MAPDST + int dung_and80; // eax MAPDST + unsigned int left_shift; // edx MAPDST + signed int i; // edx MAPDST + unsigned int n_draw_shift; // ecx MAPDST + unsigned char *_EBX; + + gpCelFrame = (unsigned char *)speed_cel_frame_num_from_light_index_frame_num; + tmp_pbDst = pbDst; + gpDrawMask = pMask; + if ( (_BYTE)light_table_index ) + { + if ( (_BYTE)light_table_index == lightmax ) + { + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = (level_cel_block >> 12) & 7; + switch ( cel_type_16 ) + { + case 0: // lower (bottom transparent), black +/* + |--| + | | + |--| +*/ + yy_32 = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = 0; + left_shift *= 2; + ++tmp_pbDst; + --i; + } + while ( i ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + break; + case 1: // lower (bottom transparent), black +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + gdwCurrentMask = *gpDrawMask; + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) != 0 ) + break; + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + { + and80_i = dung_and80; + pdung_cels += dung_and80; + left_shift = gdwCurrentMask; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = 0; + left_shift *= 2; + ++tmp_pbDst; + --and80_i; + } + while ( and80_i ); + gdwCurrentMask = left_shift; + } + else + { + pdung_cels += dung_and80; + tmp_pbDst += dung_and80; + } + if ( !yy_32 ) + goto LABEL_252; + } + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + if ( dung_and80 & 0x1F ) + gdwCurrentMask <<= dung_and80 & 0x1F; + yy_32 -= dung_and80; + } + while ( yy_32 ); +LABEL_252: + tmp_pbDst -= 800; + --gpDrawMask; + --xx_32; + } + while ( xx_32 ); + break; + case 2: // lower (bottom transparent), black +/* + /-| + ( | + \-| +*/ + for ( i = 30; ; i -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + tmp_pbDst += i; + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( !i ) + break; + } + i = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + tmp_pbDst += i; + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + i += 2; + } + while ( i != 32 ); + break; + case 3: // lower (bottom transparent), black +/* + |-\ + | ) + |-/ +*/ + for ( i = 30; ; i -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst = &tmp_pbDst[32 - i]; + } + tmp_pbDst -= 800; + if ( !i ) + break; + tmp_pbDst += i; + } + i = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst = &tmp_pbDst[32 - i]; + } + tmp_pbDst = &tmp_pbDst[i - 800]; + i += 2; + } + while ( i != 32 ); + break; + case 4: // lower (bottom transparent), black +/* + /| + / | + |__| +*/ + for ( i = 30; ; i -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + tmp_pbDst += i; + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( !i ) + break; + } + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = 0; + left_shift *= 2; + ++tmp_pbDst; + --i; + } + while ( i ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + break; + default: // lower (bottom transparent), black +/* + |\ + | \ + |__| +*/ + for ( i = 30; ; i -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst = &tmp_pbDst[32 - i]; + } + tmp_pbDst -= 800; + if ( !i ) + break; + tmp_pbDst += i; + } + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = 0; + left_shift *= 2; + ++tmp_pbDst; + --i; + } + while ( i ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + break; + } + return; + } + if ( !(level_cel_block & 0x8000) ) + { + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + _EBX = (unsigned char *)&pLightTbl[256 * light_table_index]; + cel_type_16 = (unsigned char)(level_cel_block >> 12); + switch ( cel_type_16 ) + { + case 0: // lower (bottom transparent), with lighting +/* + |--| + | | + |--| +*/ + yy_32 = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + break; + case 1: // lower (bottom transparent), with lighting +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + gdwCurrentMask = *gpDrawMask; + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) != 0 ) + break; + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + { + and80_i = dung_and80; + left_shift = gdwCurrentMask; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --and80_i; + } + while ( and80_i ); + gdwCurrentMask = left_shift; + } + else + { + pdung_cels += dung_and80; + tmp_pbDst += dung_and80; + } + if ( !yy_32 ) + goto LABEL_52; + } + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + if ( dung_and80 & 0x1F ) + gdwCurrentMask <<= dung_and80 & 0x1F; + yy_32 -= dung_and80; + } + while ( yy_32 ); +LABEL_52: + tmp_pbDst -= 800; + --gpDrawMask; + --xx_32; + } + while ( xx_32 ); + break; + case 2: // lower (bottom transparent), with lighting +/* + /-| + ( | + \-| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_62: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + yy_32 = (world_tbl >> 1) + 2; + } + do + { + tmp_pbDst += yy_32; + n_draw_shift = (unsigned int)(32 - yy_32) >> 2; + if ( (32 - yy_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[2]]; + tmp_pbDst[1] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[2]]; + tmp_pbDst[1] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_62; + case 3: // lower (bottom transparent), with lighting +/* + |-\ + | ) + |-/ +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_80: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + yy_32 = (world_tbl >> 1) + 2; + } + do + { + for ( n_draw_shift = (unsigned int)(32 - yy_32) >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)yy_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + pdung_cels += 2; /// BUGFIX: change to `pdung_cels += 4` + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_80; + case 4: // lower (bottom transparent), with lighting +/* + /| + / | + |__| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_98: + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[2]]; + tmp_pbDst[1] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_98; + default: // lower (bottom transparent), with lighting +/* + |\ + | \ + |__| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_117: + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + pdung_cels += (unsigned char)pdung_cels & 2; + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + tmp_pbDst[2] = _EBX[pdung_cels[2]]; + tmp_pbDst[3] = _EBX[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + tmp_pbDst[0] = _EBX[pdung_cels[0]]; + tmp_pbDst[1] = _EBX[pdung_cels[1]]; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_117; + } + return; + } + pdung_cels = (unsigned char *)pSpeedCels + + *(_DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; + cel_type_16 = (unsigned char)(level_cel_block >> 12); + } + else + { + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = ((level_cel_block >> 12) & 7) + 8; + } + switch ( cel_type_16 ) + { + case 8: // lower (bottom transparent), without lighting +/* + |--| + | | + |--| +*/ + yy_32 = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = pdung_cels[0]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + break; + case 9: // lower (bottom transparent), without lighting +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + gdwCurrentMask = *gpDrawMask; + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) != 0 ) + break; + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + { + and80_i = dung_and80; + left_shift = gdwCurrentMask; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = pdung_cels[0]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --and80_i; + } + while ( and80_i ); + gdwCurrentMask = left_shift; + } + else + { + pdung_cels += dung_and80; + tmp_pbDst += dung_and80; + } + if ( !yy_32 ) + goto LABEL_152; + } + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + if ( dung_and80 & 0x1F ) + gdwCurrentMask <<= dung_and80 & 0x1F; + yy_32 -= dung_and80; + } + while ( yy_32 ); +LABEL_152: + tmp_pbDst -= 800; + --gpDrawMask; + --xx_32; + } + while ( xx_32 ); + break; + case 10: // lower (bottom transparent), without lighting +/* + /-| + ( | + \-| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_162: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + yy_32 = (world_tbl >> 1) + 2; + } + do + { + tmp_pbDst += yy_32; + n_draw_shift = (unsigned int)(32 - yy_32) >> 2; + if ( (32 - yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_162; + case 11: // lower (bottom transparent), without lighting +/* + |-\ + | ) + |-/ +*/ + xx_32 = 30; + if ( pbDst < gpBufEnd ) + goto LABEL_175; + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 <= 45 ) + { + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + do + { +LABEL_175: + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_180; + } + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_180: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + yy_32 = (world_tbl >> 1) + 2; + } + do + { + for ( n_draw_shift = (unsigned int)(32 - yy_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + break; + case 12: // lower (bottom transparent), without lighting +/* + /| + / | + |__| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_198: + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = pdung_cels[0]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_198; + default: // lower (bottom transparent), without lighting +/* + |\ + | \ + |__| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_217: + gpDrawMask -= 16; + yy_32 = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + left_shift = *gpDrawMask; + i = 32; + do + { + if ( left_shift & 0x80000000 ) + tmp_pbDst[0] = pdung_cels[0]; + left_shift *= 2; + ++pdung_cels; + ++tmp_pbDst; + --i; + } + while ( i ); + pdung_cels += (unsigned char)pdung_cels & 2; + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --gpDrawMask; + --yy_32; + } + while ( yy_32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_217; + } +} + +void __fastcall drawLowerScreen(unsigned char *pbDst) +{ + unsigned char *tmp_pbDst; // edi MAPDST + unsigned char *pdung_cels; // esi MAPDST + unsigned char *l_tbl; // ebx + short cel_type_16; // ax MAPDST + int xx_32; // edx MAPDST + int yy_32; // ebp MAPDST + char block_4; // cl MAPDST + int x_minus; // ecx MAPDST + int y_minus; // ecx MAPDST + unsigned int chk_sh_and; // ecx MAPDST + signed int tile_42_45; // eax MAPDST + unsigned int world_tbl; // ecx MAPDST + unsigned int n_draw_shift; // ecx MAPDST + unsigned int dung_and80; // eax MAPDST + signed int i; // edx MAPDST + signed int j; // ecx MAPDST + + if ( cel_transparency_active ) + { + if ( !arch_draw_type ) + { + drawTopArchesLowerScreen(pbDst); + return; + } + if ( arch_draw_type == 1 ) + { + if ( block_lvid[level_piece_id] == 1 || block_lvid[level_piece_id] == 3 ) + { + drawBottomArchesLowerScreen(pbDst, &LeftMask[31]); + return; + } + } + if ( arch_draw_type == 2 ) + { + if ( block_lvid[level_piece_id] == 2 || block_lvid[level_piece_id] == 3 ) + { + drawBottomArchesLowerScreen(pbDst, &RightMask[31]); + return; + } + } + } + gpCelFrame = (unsigned char *)speed_cel_frame_num_from_light_index_frame_num; + tmp_pbDst = pbDst; + if ( (_BYTE)light_table_index ) + { + if ( (_BYTE)light_table_index == lightmax ) + { + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = (level_cel_block >> 12) & 7; + switch ( cel_type_16 ) + { + case 0: // lower (solid), black +/* + |--| + | | + |--| +*/ + i = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + case 1: // lower (solid), black +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + if ( !yy_32 ) + goto LABEL_232; + } + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + { + pdung_cels += dung_and80; + chk_sh_and = dung_and80 >> 1; + if ( dung_and80 & 1 ) + { + tmp_pbDst[0] = 0; + ++tmp_pbDst; + } + if ( chk_sh_and ) + { + n_draw_shift = dung_and80 >> 2; + if ( chk_sh_and & 1 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels += dung_and80; + tmp_pbDst += dung_and80; + } + } + while ( yy_32 ); +LABEL_232: + tmp_pbDst -= 800; + --xx_32; + } + while ( xx_32 ); + break; + case 2: // lower (solid), black +/* + /-| + ( | + \-| +*/ + for ( i = 30; ; i -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + tmp_pbDst += i; + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( !i ) + break; + } + i = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + tmp_pbDst += i; + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + i += 2; + } + while ( i != 32 ); + break; + case 3: // lower (solid), black +/* + |-\ + | ) + |-/ +*/ + for ( i = 30; ; i -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst = &tmp_pbDst[32 - i]; + } + tmp_pbDst -= 800; + if ( !i ) + break; + tmp_pbDst += i; + } + i = 2; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst = &tmp_pbDst[32 - i]; + } + tmp_pbDst = &tmp_pbDst[i - 800]; + i += 2; + } + while ( i != 32 ); + break; + case 4: // lower (solid), black +/* + /| + / | + |__| +*/ + for ( i = 30; ; i -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + tmp_pbDst += i; + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + if ( !i ) + break; + } + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + default: // lower (solid), black +/* + |\ + | \ + |__| +*/ + for ( i = 30; ; i -= 2 ) + { + if ( tmp_pbDst < gpBufEnd ) + { + n_draw_shift = (unsigned int)(32 - i) >> 2; + if ( (32 - i) & 2 ) + { + *(_WORD *)tmp_pbDst = 0; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + else + { + pdung_cels = &pdung_cels[32 - i]; + tmp_pbDst = &tmp_pbDst[32 - i]; + } + tmp_pbDst -= 800; + if ( !i ) + break; + tmp_pbDst += i; + } + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + } + return; + } + if ( !(level_cel_block & 0x8000) ) + { + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + l_tbl = (unsigned char *)&pLightTbl[256 * light_table_index]; + cel_type_16 = (unsigned short)level_cel_block >> 12; + switch ( cel_type_16 ) + { + case 0: // lower (solid), with lighting +/* + |--| + | | + |--| +*/ + xx_32 = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --xx_32; + } + while ( xx_32 ); + break; + case 1: // lower (solid), with lighting +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + yy_32 = 32; + do + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + { + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + { + for ( block_4 = dung_and80; block_4 >= 4; block_4 -= 4 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( block_4 >= 2 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( block_4 & 1 ) + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + } + } + else + { + pdung_cels += dung_and80; + tmp_pbDst += dung_and80; + } + } + else + { + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + } + } + while ( yy_32 ); + tmp_pbDst -= 800; + --xx_32; + } + while ( xx_32 ); + break; + case 2: // lower (solid), with lighting +/* + /-| + ( | + \-| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_68: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + yy_32 = (world_tbl >> 1) + 2; + } + do + { + tmp_pbDst += yy_32; + y_minus = 32 - yy_32; + pdung_cels += (32 - (_BYTE)yy_32) & 2; + do + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + --y_minus; + } + while ( y_minus ); + yy_32 += 2; + tmp_pbDst -= 800; + } + while ( yy_32 != 32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + tmp_pbDst += xx_32; + x_minus = 32 - xx_32; + pdung_cels += (32 - (_BYTE)xx_32) & 2; + do + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + --x_minus; + } + while ( x_minus ); + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_68; + case 3: // lower (solid), with lighting +/* + |-\ + | ) + |-/ +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_83: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + yy_32 = (world_tbl >> 1) + 2; + } + do + { + y_minus = 32 - yy_32; + do + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + --y_minus; + } + while ( y_minus ); + pdung_cels += (unsigned char)pdung_cels & 2; + tmp_pbDst = &tmp_pbDst[yy_32 - 800]; + yy_32 += 2; + } + while ( yy_32 != 32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + x_minus = 32 - xx_32; + do + { + *tmp_pbDst++ = l_tbl[*pdung_cels++]; + --x_minus; + } + while ( x_minus ); + pdung_cels += (unsigned char)pdung_cels & 2; + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_83; + case 4: // lower (solid), with lighting +/* + /| + / | + |__| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_100: + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + block_4 = 32; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + block_4 -= 4; + } + while ( block_4 >= 4 ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + tmp_pbDst += xx_32; + block_4 = 32 - xx_32; + pdung_cels += (32 - (_BYTE)xx_32) & 2; + if ( (char)(32 - xx_32) >= 4 ) + { + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + block_4 -= 4; + } + while ( block_4 >= 4 ); + } + if ( block_4 >= 2 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_100; + default: // lower (solid), with lighting +/* + |\ + | \ + |__| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_116: + j = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + block_4 = 32; + do + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + block_4 -= 4; + } + while ( block_4 >= 4 ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --j; + } + while ( j ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + for ( block_4 = 32 - xx_32; block_4 >= 4; block_4 -= 4 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + tmp_pbDst[2] = l_tbl[pdung_cels[2]]; + tmp_pbDst[3] = l_tbl[pdung_cels[3]]; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( block_4 >= 2 ) + { + tmp_pbDst[0] = l_tbl[pdung_cels[0]]; + tmp_pbDst[1] = l_tbl[pdung_cels[1]]; + pdung_cels += 2; + tmp_pbDst += 2; + } + pdung_cels += (unsigned char)pdung_cels & 2; + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_116; + } + return; + } + pdung_cels = (unsigned char *)pSpeedCels + + *(_DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; + cel_type_16 = (unsigned short)level_cel_block >> 12; + } + else + { + if ( level_cel_block & 0x8000 ) + level_cel_block = *(_DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + + (unsigned short)(level_cel_block & 0xF000); + pdung_cels = (unsigned char *)pDungeonCels + *((_DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); + cel_type_16 = (((unsigned int)level_cel_block >> 12) & 7) + 8; + } + switch ( cel_type_16 ) + { + case 8: // lower (solid), without lighting +/* + |--| + | | + |--| +*/ + i = 32; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + break; + case 9: // lower (solid), without lighting +/* + /\ + ( ) + \/ +*/ + xx_32 = 32; + do + { + yy_32 = 32; + do + { + while ( 1 ) + { + dung_and80 = (unsigned char)*pdung_cels++; + if ( (dung_and80 & 0x80u) == 0 ) + break; + _LOBYTE(dung_and80) = -(char)dung_and80; + tmp_pbDst += dung_and80; + yy_32 -= dung_and80; + if ( !yy_32 ) + goto LABEL_143; + } + yy_32 -= dung_and80; + if ( tmp_pbDst < gpBufEnd ) + { + chk_sh_and = dung_and80 >> 1; + if ( dung_and80 & 1 ) + { + tmp_pbDst[0] = pdung_cels[0]; + ++pdung_cels; + ++tmp_pbDst; + } + if ( chk_sh_and ) + { + n_draw_shift = chk_sh_and >> 1; + if ( chk_sh_and & 1 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 2; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + } + } + else + { + pdung_cels += dung_and80; + tmp_pbDst += dung_and80; + } + } + while ( yy_32 ); +LABEL_143: + tmp_pbDst -= 800; + --xx_32; + } + while ( xx_32 ); + break; + case 10: // lower (solid), without lighting +/* + /-| + ( | + \-| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_153: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + yy_32 = (world_tbl >> 1) + 2; + } + do + { + tmp_pbDst += yy_32; + n_draw_shift = (unsigned int)(32 - yy_32) >> 2; + if ( (32 - yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + yy_32 += 2; + tmp_pbDst -= 800; + } + while ( yy_32 < 32 ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_153; + case 11: // lower (solid), without lighting +/* + |-\ + | ) + |-/ +*/ + xx_32 = 30; + if ( pbDst < gpBufEnd ) + goto LABEL_166; + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 <= 45 ) + { + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + do + { +LABEL_166: + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_171; + } + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_171: + yy_32 = 2; + if ( tmp_pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(tmp_pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 42 ) + return; + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_2[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + yy_32 = (world_tbl >> 1) + 2; + } + do + { + for ( n_draw_shift = (unsigned int)(32 - yy_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)yy_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst += yy_32; + yy_32 += 2; + tmp_pbDst -= 800; + } + while ( yy_32 < 32 ); + break; + case 12: // lower (solid), without lighting +/* + /| + / | + |__| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_189: + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + tmp_pbDst += xx_32; + n_draw_shift = (unsigned int)(32 - xx_32) >> 2; + if ( (32 - xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *((_WORD *)pdung_cels + 1); + pdung_cels += 4; + tmp_pbDst += 2; + } + if ( n_draw_shift ) + { + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --n_draw_shift; + } + while ( n_draw_shift ); + } + tmp_pbDst -= 800; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_189; + default: // lower (solid), without lighting +/* + |\ + | \ + |__| +*/ + xx_32 = 30; + if ( pbDst >= gpBufEnd ) + { + tile_42_45 = (unsigned int)(pbDst - gpBufEnd + 1023) >> 8; + if ( tile_42_45 > 45 ) + { + tmp_pbDst = pbDst - 12288; + pdung_cels += 288; +LABEL_205: + i = 16; + do + { + if ( tmp_pbDst < gpBufEnd ) + { + j = 8; + do + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + --j; + } + while ( j ); + } + else + { + pdung_cels += 32; + tmp_pbDst += 32; + } + tmp_pbDst -= 800; + --i; + } + while ( i ); + return; + } + world_tbl = WorldTbl3x16[tile_42_45]; + pdung_cels += WorldTbl17_1[world_tbl >> 2]; + tmp_pbDst -= 192 * world_tbl; + xx_32 = 30 - (world_tbl >> 1); + } + do + { + for ( n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift ) + { + *(_DWORD *)tmp_pbDst = *(_DWORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 4; + } + if ( (32 - (_BYTE)xx_32) & 2 ) + { + *(_WORD *)tmp_pbDst = *(_WORD *)pdung_cels; + pdung_cels += 4; + tmp_pbDst += 2; + } + tmp_pbDst = &tmp_pbDst[xx_32 - 800]; + xx_32 -= 2; + } + while ( xx_32 >= 0 ); + goto LABEL_205; + } +} + +void __fastcall world_draw_black_tile(unsigned char *pbDst) +{ + unsigned char *tmp_pbDst; // edi MAPDST + signed int xx_32; // edx + signed int i; // ebx MAPDST + signed int j; // ecx MAPDST + signed int yy_32; // edx + + tmp_pbDst = pbDst; + xx_32 = 30; + for ( i = 1; ; ++i ) + { + tmp_pbDst += xx_32; + j = i; + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst = &tmp_pbDst[xx_32 - 832]; + if ( !xx_32 ) + break; + xx_32 -= 2; + } + yy_32 = 2; + i = 15; + do + { + tmp_pbDst += yy_32; + j = i; + do + { + *(_DWORD *)tmp_pbDst = 0; + tmp_pbDst += 4; + --j; + } + while ( j ); + tmp_pbDst = &tmp_pbDst[yy_32 - 832]; + --i; + yy_32 += 2; + } + while ( yy_32 != 32 ); +} diff --git a/Source/render.h b/Source/render.h new file mode 100644 index 000000000..bdc08b316 --- /dev/null +++ b/Source/render.h @@ -0,0 +1,28 @@ +//HEADER_GOES_HERE +#ifndef __RENDER_H__ +#define __RENDER_H__ + +void __fastcall drawTopArchesUpperScreen(unsigned char *pbDst); +void __fastcall drawBottomArchesUpperScreen(unsigned char *pbDst, unsigned int *pMask); +void __fastcall drawUpperScreen(unsigned char *pbDst); +void __fastcall drawTopArchesLowerScreen(unsigned char *pbDst); +void __fastcall drawBottomArchesLowerScreen(unsigned char *pbDst, unsigned int *pMask); +void __fastcall drawLowerScreen(unsigned char *pbDst); +void __fastcall world_draw_black_tile(unsigned char *pbDst); + +/* rdata */ + +extern int WorldBoolFlag; +extern unsigned int gdwCurrentMask; +// extern char world_4B3264; +extern unsigned char *gpCelFrame; +extern unsigned int *gpDrawMask; +// extern char world_4B326D[16]; +extern unsigned int RightMask[32]; +extern unsigned int LeftMask[32]; +extern unsigned int WallMask[32]; +extern int WorldTbl3x16[48]; +extern int WorldTbl17_1[17]; +extern int WorldTbl17_2[17]; + +#endif /* __RENDER_H__ */ diff --git a/Source/restrict.cpp b/Source/restrict.cpp new file mode 100644 index 000000000..69430a3fe --- /dev/null +++ b/Source/restrict.cpp @@ -0,0 +1,73 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +bool __cdecl SystemSupported() +{ + bool v0; // di + struct _OSVERSIONINFOA VersionInformation; // [esp+4h] [ebp-94h] + + v0 = 0; + memset(&VersionInformation, 0, 0x94u); + VersionInformation.dwOSVersionInfoSize = 148; + if ( GetVersionEx(&VersionInformation) + && VersionInformation.dwPlatformId == 2 + && VersionInformation.dwMajorVersion >= 5 ) + { + v0 = 1; + } + return v0; +} + +bool __cdecl RestrictedTest() +{ + bool v0; // si + FILE *v2; // eax + char Buffer[260]; // [esp+4h] [ebp-104h] + + v0 = 0; + if ( SystemSupported() && GetWindowsDirectory(Buffer, 0x104u) ) + { + strcat(Buffer, "\\Diablo1RestrictedTest.foo"); + v2 = fopen(Buffer, "wt"); + if ( v2 ) + { + fclose(v2); + remove(Buffer); + } + else + { + v0 = 1; + } + } + return v0; +} + +bool __cdecl ReadOnlyTest() +{ + bool v0; // si + char *v1; // eax + FILE *v2; // eax + char Filename[260]; // [esp+4h] [ebp-104h] + + v0 = 0; + if ( GetModuleFileName(ghInst, Filename, 0x104u) ) + { + v1 = strrchr(Filename, '\\'); + if ( v1 ) + { + strcpy(v1 + 1, "Diablo1ReadOnlyTest.foo"); + v2 = fopen(Filename, "wt"); + if ( v2 ) + { + fclose(v2); + remove(Filename); + } + else + { + v0 = 1; + } + } + } + return v0; +} diff --git a/Source/restrict.h b/Source/restrict.h new file mode 100644 index 000000000..fa69dccd8 --- /dev/null +++ b/Source/restrict.h @@ -0,0 +1,9 @@ +//HEADER_GOES_HERE +#ifndef __RESTRICT_H__ +#define __RESTRICT_H__ + +bool __cdecl SystemSupported(); +bool __cdecl RestrictedTest(); +bool __cdecl ReadOnlyTest(); + +#endif /* __RESTRICT_H__ */ diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp new file mode 100644 index 000000000..57387c24a --- /dev/null +++ b/Source/scrollrt.cpp @@ -0,0 +1,3395 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int light_table_index; // weak +int screen_y_times_768[1024]; +int scrollrt_cpp_init_value; // weak +unsigned int sgdwCursWdtOld; // idb +int sgdwCursX; // idb +int sgdwCursY; // idb +unsigned char *gpBufEnd; // weak +int sgdwCursHgt; +int level_cel_block; // weak +int sgdwCursXOld; // idb +int sgdwCursYOld; // idb +char arch_draw_type; // weak +DDSURFACEDESC DDS_desc; +int cel_transparency_active; // weak +int level_piece_id; // weak +int sgdwCursWdt; +int (__fastcall *DrawPlrProc)(int player_num, int x, int y, int screen_x, int screen_y, void *cl2_buf, int frame, int frame_width, int a9, int a10); +char sgSaveBack[8192]; +int draw_monster_num; // weak +int sgdwCursHgtOld; // idb +#endif + +const int scrollrt_inf = 0x7F800000; // weak + +/* data */ + +/* used in 1.00 debug */ +char *szMonModeAssert[18] = +{ + "standing", + "walking (1)", + "walking (2)", + "walking (3)", + "attacking", + "getting hit", + "dying", + "attacking (special)", + "fading in", + "fading out", + "attacking (ranged)", + "standing (special)", + "attacking (special ranged)", + "delaying", + "charging", + "stoned", + "healing", + "talking" +}; + +char *szPlrModeAssert[12] = +{ + "standing", + "walking (1)", + "walking (2)", + "walking (3)", + "attacking (melee)", + "attacking (ranged)", + "blocking", + "getting hit", + "dying", + "casting a spell", + "changing levels", + "quitting" +}; + +struct scrollrt_cpp_init +{ + scrollrt_cpp_init() + { + scrollrt_cpp_init_value = scrollrt_inf; + } +} _scrollrt_cpp_init; +// 47F238: using guessed type int scrollrt_inf; +// 69CEFC: using guessed type int scrollrt_cpp_init_value; + +void __cdecl ClearCursor() // CODE_FIX: this was supposed to be in cursor.cpp +{ + sgdwCursWdt = 0; + sgdwCursWdtOld = 0; +} + +void __fastcall DrawMissile(int x, int y, int sx, int sy, int a5, int a6, int del_flag) +{ + int v7; // ebx + char v8; // al + int v9; // eax + int v10; // eax + MissileStruct *v11; // eax + char *v12; // edi + int v13; // edx + int v14; // esi + int v15; // ecx + MissileStruct *v16; // eax + char *v17; // edi + int v18; // edx + int v19; // esi + int v20; // ecx + int v21; // [esp-10h] [ebp-28h] + int v22; // [esp-10h] [ebp-28h] + int v23; // [esp-Ch] [ebp-24h] + int v24; // [esp-Ch] [ebp-24h] + int v25; // [esp+Ch] [ebp-Ch] + int v26; // [esp+10h] [ebp-8h] + int i; // [esp+14h] [ebp-4h] + + v26 = x; + v7 = y; + v8 = dMissile[x][y]; + v25 = y; + if ( v8 == -1 ) + { + v9 = 0; + for ( i = 0; i < nummissiles; v9 = i++ + 1 ) + { + v10 = missileactive[v9]; + if ( v10 >= MAXMISSILES ) + break; + v11 = &missile[v10]; + if ( v11->_mix == v26 && v11->_miy == v7 && v11->_miPreFlag == del_flag && v11->_miDrawFlag ) + { + v12 = (char *)v11->_miAnimData; + if ( !v12 ) + return; + v13 = v11->_miAnimFrame; + if ( v13 < 1 || (unsigned int)*v12 > 0x32 || v13 > *v12 ) + return; + v14 = sy + v11->_miyoff; + v15 = sx + v11->_mixoff - v11->_miAnimWidth2; + if ( v11->_miUniqTrans ) + { + Cl2DecodeFrm3(v15, v14, v12, v13, v11->_miAnimWidth, a5, a6, _LOBYTE(v11->_miUniqTrans) + 3); + v7 = v25; + } + else + { + v23 = v11->_miAnimWidth; + v21 = v11->_miAnimFrame; + if ( v11->_miLightFlag ) + Cl2DecodeLightTbl(v15, v14, v12, v21, v23, a5, a6); + else + Cl2DecodeFrm1(v15, v14, v12, v21, v23, a5, a6); + } + } + } + } + else + { + v16 = &missile[v8-1]; + if ( v16->_miPreFlag == del_flag ) + { + if ( v16->_miDrawFlag ) + { + v17 = (char *)v16->_miAnimData; + if ( v17 ) + { + v18 = v16->_miAnimFrame; + if ( v18 >= 1 && (unsigned int)*v17 <= 0x32 && v18 <= *v17 ) + { + v19 = sy + v16->_miyoff; + v20 = sx + v16->_mixoff - v16->_miAnimWidth2; + if ( v16->_miUniqTrans ) + { + Cl2DecodeFrm3(v20, v19, v17, v18, v16->_miAnimWidth, a5, a6, LOBYTE(v16->_miUniqTrans) + 3); + } + else + { + v24 = v16->_miAnimWidth; + v22 = v16->_miAnimFrame; + if ( v16->_miLightFlag ) + Cl2DecodeLightTbl(v20, v19, v17, v22, v24, a5, a6); + else + Cl2DecodeFrm1(v20, v19, v17, v22, v24, a5, a6); + } + } + } + } + } + } +} + +void __fastcall DrawClippedMissile(int x, int y, int sx, int sy, int a5, int a6, int a7) +{ + int v7; // ebx + char v8; // al + int v9; // eax + int v10; // eax + MissileStruct *v11; // eax + char *v12; // edi + int v13; // edx + int v14; // esi + int v15; // ecx + MissileStruct *v16; // eax + char *v17; // edi + int v18; // edx + int v19; // esi + int v20; // ecx + int v21; // [esp-10h] [ebp-28h] + int v22; // [esp-10h] [ebp-28h] + int v23; // [esp-Ch] [ebp-24h] + int v24; // [esp-Ch] [ebp-24h] + int v25; // [esp+Ch] [ebp-Ch] + int v26; // [esp+10h] [ebp-8h] + int i; // [esp+14h] [ebp-4h] + + v26 = x; + v7 = y; + v8 = dMissile[x][y]; + v25 = y; + if ( v8 == -1 ) + { + v9 = 0; + for ( i = 0; i < nummissiles; v9 = i++ + 1 ) + { + v10 = missileactive[v9]; + if ( v10 >= MAXMISSILES ) + break; + v11 = &missile[v10]; + if ( v11->_mix == v26 && v11->_miy == v7 && v11->_miPreFlag == a7 && v11->_miDrawFlag ) + { + v12 = (char *)v11->_miAnimData; + if ( !v12 ) + return; + v13 = v11->_miAnimFrame; + if ( v13 < 1 || (unsigned int)*v12 > 0x32 || v13 > *v12 ) + return; + v14 = sy + v11->_miyoff; + v15 = sx + v11->_mixoff - v11->_miAnimWidth2; + if ( v11->_miUniqTrans ) + { + Cl2DecodeFrm5(v15, v14, v12, v13, v11->_miAnimWidth, a5, a6, _LOBYTE(v11->_miUniqTrans) + 3); + v7 = v25; + } + else + { + v23 = v11->_miAnimWidth; + v21 = v11->_miAnimFrame; + if ( v11->_miLightFlag ) + Cl2DecodeFrm6(v15, v14, v12, v21, v23, a5, a6); + else + Cl2DecodeFrm4(v15, v14, v12, v21, v23, a5, a6); + } + } + } + } + else + { + v16 = &missile[v8-1]; + if ( v16->_miPreFlag == a7 ) + { + if ( v16->_miDrawFlag ) + { + v17 = (char *)v16->_miAnimData; + if ( v17 ) + { + v18 = v16->_miAnimFrame; + if ( v18 >= 1 && (unsigned int)*v17 <= 0x32 && v18 <= *v17 ) + { + v19 = sy + v16->_miyoff; + v20 = sx + v16->_mixoff - v16->_miAnimWidth2; + if ( v16->_miUniqTrans ) + { + Cl2DecodeFrm5(v20, v19, v17, v18, v16->_miAnimWidth, a5, a6, LOBYTE(v16->_miUniqTrans) + 3); + } + else + { + v24 = v16->_miAnimWidth; + v22 = v16->_miAnimFrame; + if ( v16->_miLightFlag ) + Cl2DecodeFrm6(v20, v19, v17, v22, v24, a5, a6); + else + Cl2DecodeFrm4(v20, v19, v17, v22, v24, a5, a6); + } + } + } + } + } + } +} + +void __fastcall DrawDeadPlayer(int x, int y, int sx, int sy, int a5, int a6, bool clipped) +{ + int v7; // ebx + int *v8; // esi + char *v9; // edi + int *v10; // eax + int v11; // ecx + int xa; // [esp+Ch] [ebp-4h] + int player_num; // [esp+28h] [ebp+18h] + + v7 = y; + xa = x; + DrawPlrProc = (int (__fastcall *)(int, int, int, int, int, void *, int, int, int, int))DrawClippedPlayer; + if ( !clipped ) + DrawPlrProc = (int (__fastcall *)(int, int, int, int, int, void *, int, int, int, int))DrawPlayer; + v8 = &plr[0]._pHitPoints; + v9 = &dFlags[x][y]; + *v9 &= 0xFBu; + player_num = 0; + do + { + if ( !*((_BYTE *)v8 - 379) || *v8 || *(v8 - 89) != currlevel || *(v8 - 88) != xa || *(v8 - 87) != v7 ) + goto LABEL_14; + v10 = (int *)*(v8 - 71); + if ( !v10 ) + break; + v11 = *(v8 - 67); + if ( v11 < 1 || (unsigned int)*v10 > 0x32 || v11 > *v10 ) + break; + *v9 |= 4u; + DrawPlrProc(player_num, xa, v7, sx + *(v8 - 78) - *(v8 - 65), sy + *(v8 - 77), v10, v11, *(v8 - 66), a5, a6); +LABEL_14: + ++player_num; + v8 += 5430; + } + while ( (signed int)v8 < (signed int)&plr[4]._pHitPoints ); +} + +void __fastcall DrawPlayer(int pnum, int x, int y, int px, int py, unsigned char *animdata, int animframe, int animwidth, int a9, int a10) +{ + char *v10; // edx + int v11; // eax + char *v12; // ecx + int v13; // [esp+Ch] [ebp-4h] + int ya; // [esp+18h] [ebp+8h] + int animdataa; // [esp+24h] [ebp+14h] + + v10 = &dFlags[x][y]; + v11 = myplr; + v13 = pnum; + ya = (int)v10; + if ( *v10 & 0x40 || plr[myplr]._pInfraFlag || !setlevel && !currlevel ) + { + v12 = (char *)animdata; + if ( animdata ) + { + if ( animframe >= 1 && *(_DWORD *)animdata <= 0x32u && animframe <= *(_DWORD *)animdata ) + { + if ( v13 == pcursplr ) + { + Cl2DecodeFrm2(165, px, py, (char *)animdata, animframe, animwidth, a9, a10); + v11 = myplr; + v12 = (char *)animdata; + v10 = (char *)ya; + } + if ( v13 == v11 ) + { + Cl2DecodeFrm1(px, py, v12, animframe, animwidth, a9, a10); + if ( plr[v13].pManaShield ) + Cl2DecodeFrm1( + px + plr[v13]._pAnimWidth2 - misfiledata[9].mAnimWidth2[0], + py, + (char *)misfiledata[9].mAnimData[0], + 1, + misfiledata[9].mAnimWidth[0], + a9, + a10); + } + else if ( !(*v10 & 0x40) || plr[v11]._pInfraFlag && light_table_index > 8 ) + { + Cl2DecodeFrm3(px, py, v12, animframe, animwidth, a9, a10, 1); + if ( plr[v13].pManaShield ) + Cl2DecodeFrm3( + px + plr[v13]._pAnimWidth2 - misfiledata[9].mAnimWidth2[0], + py, + (char *)misfiledata[9].mAnimData[0], + 1, + misfiledata[9].mAnimWidth[0], + a9, + a10, + 1); + } + else + { + animdataa = light_table_index; + if ( light_table_index >= 5 ) + light_table_index -= 5; + else + light_table_index = 0; + Cl2DecodeLightTbl(px, py, v12, animframe, animwidth, a9, a10); + if ( plr[v13].pManaShield ) + Cl2DecodeLightTbl( + px + plr[v13]._pAnimWidth2 - misfiledata[9].mAnimWidth2[0], + py, + (char *)misfiledata[9].mAnimData[0], + 1, + misfiledata[9].mAnimWidth[0], + a9, + a10); + light_table_index = animdataa; + } + } + } + } +} +// 4B8CC2: using guessed type char pcursplr; +// 5CF31D: using guessed type char setlevel; +// 69BEF8: using guessed type int light_table_index; + +void __fastcall DrawClippedPlayer(int pnum, int x, int y, int px, int py, unsigned char *animdata, int animframe, int animwidth, int a9, int a10) +{ + char *v10; // edx + int v11; // eax + char *v12; // ecx + int v13; // [esp+Ch] [ebp-4h] + int ya; // [esp+18h] [ebp+8h] + int animdataa; // [esp+24h] [ebp+14h] + + v10 = &dFlags[x][y]; + v11 = myplr; + v13 = pnum; + ya = (int)v10; + if ( *v10 & 0x40 || plr[myplr]._pInfraFlag ) + { + v12 = (char *)animdata; + if ( animdata ) + { + if ( animframe >= 1 && *(_DWORD *)animdata <= 0x32u && animframe <= *(_DWORD *)animdata ) + { + if ( v13 == pcursplr ) + { + Cl2DecodeClrHL(165, px, py, (char *)animdata, animframe, animwidth, a9, a10); + v11 = myplr; + v12 = (char *)animdata; + v10 = (char *)ya; + } + if ( v13 == v11 ) + { + Cl2DecodeFrm4(px, py, v12, animframe, animwidth, a9, a10); + if ( plr[v13].pManaShield ) + Cl2DecodeFrm4( + px + plr[v13]._pAnimWidth2 - misfiledata[9].mAnimWidth2[0], + py, + (char *)misfiledata[9].mAnimData[0], + 1, + misfiledata[9].mAnimWidth[0], + a9, + a10); + } + else if ( !(*v10 & 0x40) || plr[v11]._pInfraFlag && light_table_index > 8 ) + { + Cl2DecodeFrm5(px, py, v12, animframe, animwidth, a9, a10, 1); + if ( plr[v13].pManaShield ) + Cl2DecodeFrm5( + px + plr[v13]._pAnimWidth2 - misfiledata[9].mAnimWidth2[0], + py, + (char *)misfiledata[9].mAnimData[0], + 1, + misfiledata[9].mAnimWidth[0], + a9, + a10, + 1); + } + else + { + animdataa = light_table_index; + if ( light_table_index >= 5 ) + light_table_index -= 5; + else + light_table_index = 0; + Cl2DecodeFrm6(px, py, v12, animframe, animwidth, a9, a10); + if ( plr[v13].pManaShield ) + Cl2DecodeFrm6( + px + plr[v13]._pAnimWidth2 - misfiledata[9].mAnimWidth2[0], + py, + (char *)misfiledata[9].mAnimData[0], + 1, + misfiledata[9].mAnimWidth[0], + a9, + a10); + light_table_index = animdataa; + } + } + } + } +} +// 4B8CC2: using guessed type char pcursplr; +// 69BEF8: using guessed type int light_table_index; + +void __fastcall DrawView(int StartX, int StartY) +{ + if ( zoomflag ) + DrawGame(StartX, StartY); + else + DrawZoom(StartX, StartY); + + if ( automapflag ) + DrawAutomap(); + + if ( invflag ) + DrawInv(); + else if ( sbookflag ) + DrawSpellBook(); + + DrawDurIcon(); + + if ( chrflag ) + DrawChr(); + else if ( questlog ) + DrawQuestLog(); + else if ( plr[myplr]._pStatPts && !spselflag ) + DrawLevelUpIcon(); + + if ( uitemflag ) + DrawUniqueInfo(); + if ( qtextflag ) + DrawQText(); + if ( spselflag ) + DrawSpellList(); + if ( dropGoldFlag ) + DrawGoldSplit(dropGoldValue); + if ( helpflag ) + DrawHelp(); + if ( msgflag ) + DrawDiabloMsg(); + + if ( deathflag ) + RedBack(); + else if ( PauseMode ) + gmenu_draw_pause(); + + DrawPlrMsg(); + gmenu_draw(); + doom_draw(); + DrawInfoBox(); + DrawLifeFlask(); + DrawManaFlask(); +} +// 4B84DC: using guessed type int dropGoldFlag; +// 4B8968: using guessed type int sbookflag; +// 4B8C98: using guessed type int spselflag; +// 52569C: using guessed type int zoomflag; +// 525740: using guessed type int PauseMode; +// 52B9F1: using guessed type char msgflag; +// 646D00: using guessed type char qtextflag; +// 69BD04: using guessed type int questlog; + +void __fastcall DrawGame(int x, int y) +{ + int v2; // esi + int v3; // ebx + int v4; // edi + int v5; // edi + int v6; // esi + int v7; // edi + int v8; // esi + int v9; // edi + int v10; // esi + signed int v11; // [esp+Ch] [ebp-10h] + signed int a6; // [esp+10h] [ebp-Ch] + signed int a6a; // [esp+10h] [ebp-Ch] + signed int a5; // [esp+14h] [ebp-8h] + int ya; // [esp+18h] [ebp-4h] + + dword_5C2FF8 = 10; + v2 = ScrollInfo._sxoff + 64; + v3 = x - 10; + ya = y - 1; + a5 = 10; + v4 = ScrollInfo._syoff + 175; + scr_pix_width = 640; + scr_pix_height = 352; + dword_5C2FFC = 11; + v11 = 8; + if ( chrflag || questlog ) + { + ya = y - 3; + v3 += 2; + v2 = ScrollInfo._sxoff + 352; + a5 = 6; + } + if ( invflag || sbookflag ) + { + ya -= 2; + v3 += 2; + v2 -= 32; + a5 = 6; + } + switch ( ScrollInfo._sdir ) + { + case DIR_SW: + goto LABEL_9; + case DIR_W: + ++a5; +LABEL_9: + v4 = ScrollInfo._syoff + 143; + --v3; + --ya; + goto LABEL_15; + case DIR_NW: + goto LABEL_13; + case DIR_N: + v11 = 9; + goto LABEL_13; + case DIR_NE: + goto LABEL_15; + case DIR_E: + v11 = 9; + goto LABEL_12; + case DIR_SE: +LABEL_12: + v2 -= 64; + --v3; + ++ya; +LABEL_13: + ++a5; + break; + case DIR_OMNI: + v2 -= 64; + v4 = ScrollInfo._syoff + 143; + v3 -= 2; + ++a5; +LABEL_15: + v11 = 9; + break; + default: + break; + } + a6 = 0; + gpBufEnd = (unsigned char *)gpBuffer + screen_y_times_768[160]; + do + { + scrollrt_draw_upper(v3, ya++, v2, v4, a5, a6, 0); + v5 = v4 + 16; + v6 = v2 - 32; + scrollrt_draw_upper(v3++, ya, v6, v5, a5, a6, 1); + v2 = v6 + 32; + v4 = v5 + 16; + ++a6; + } + while ( a6 < 4 ); + gpBufEnd = (unsigned char *)gpBuffer + screen_y_times_768[512]; + if ( v11 > 0 ) + { + do + { + scrollrt_draw_lower(v3, ya++, v2, v4, a5, 0); + v7 = v4 + 16; + v8 = v2 - 32; + scrollrt_draw_lower(v3++, ya, v8, v7, a5, 1); + v2 = v8 + 32; + v4 = v7 + 16; + --v11; + } + while ( v11 ); + } + arch_draw_type = 0; + a6a = 0; + do + { + scrollrt_draw_lower_2(v3, ya++, v2, v4, a5, a6a, 0); + v9 = v4 + 16; + v10 = v2 - 32; + scrollrt_draw_lower_2(v3++, ya, v10, v9, a5, a6a, 1); + v2 = v10 + 32; + v4 = v9 + 16; + ++a6a; + } + while ( a6a < 4 ); +} +// 4B8968: using guessed type int sbookflag; +// 5C2FF8: using guessed type int dword_5C2FF8; +// 5C2FFC: using guessed type int dword_5C2FFC; +// 5C3000: using guessed type int scr_pix_width; +// 5C3004: using guessed type int scr_pix_height; +// 69BD04: using guessed type int questlog; +// 69CF0C: using guessed type int gpBufEnd; +// 69CF20: using guessed type char arch_draw_type; + +void __fastcall scrollrt_draw_lower(int x, int y, int sx, int sy, int a5, int some_flag) +{ + unsigned int v6; // edi + unsigned int v7; // ebx + unsigned short *v8; // esi + unsigned int v9; // ebx + int v10; // eax + int v11; // ecx + int v12; // edx + char *v13; // edx + int v14; // edi + int v15; // eax + unsigned char *v16; // edi + unsigned char *v17; // edi + unsigned char *v18; // edi + unsigned char *v19; // edi + int v20; // eax + int v21; // edi + int v22; // ecx + int v23; // ecx + int v24; // eax + int *v25; // ebx + int v26; // ecx + int v27; // eax + int v28; // edi + unsigned char *v29; // edi + int v30; // eax + int v31; // eax + int v32; // eax + int v33; // ecx + int v34; // eax + int *v35; // edi + int v36; // ecx + int v37; // eax + char *v38; // edi + unsigned char *v39; // edi + int v40; // eax + unsigned char *v41; // edi + unsigned char *v42; // edi + unsigned char *v43; // edi + unsigned char *v44; // edi + int v45; // eax + int v46; // [esp+Ch] [ebp-10h] + int v47; // [esp+10h] [ebp-Ch] + signed int sya; // [esp+14h] [ebp-8h] + unsigned int sxa; // [esp+18h] [ebp-4h] + signed int i; // [esp+2Ch] [ebp+10h] + int *v51; // [esp+2Ch] [ebp+10h] + + v6 = y; + v7 = x; + sya = y; + sxa = x; + v8 = (unsigned short *)((char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(x, y)); + if ( some_flag ) + { + if ( v6 < 0x70 && v7 < 0x70 ) + { + v9 = v7; + v10 = dPiece[0][v9 * 112 + v6]; + light_table_index = dTransVal[v9][v6]; + level_piece_id = v10; + if ( v10 ) + { + v11 = (unsigned char)(nTransTable[v10] & TransList[dung_map[v9][v6]]); + arch_draw_type = 2; + v12 = screen_y_times_768[sy]; + cel_transparency_active = v11; + v13 = (char *)gpBuffer + v12; + level_cel_block = v8[1]; + v14 = (int)&v13[sx + 32]; + if ( level_cel_block ) + drawLowerScreen((unsigned char *)&v13[sx + 32]); + v15 = v8[3]; + arch_draw_type = 0; + v16 = (unsigned char *)(v14 - 24576); + level_cel_block = v15; + if ( v15 ) + drawLowerScreen(v16); + v17 = v16 - 24576; + level_cel_block = v8[5]; + if ( level_cel_block ) + drawLowerScreen(v17); + v18 = v17 - 24576; + level_cel_block = v8[7]; + if ( level_cel_block ) + drawLowerScreen(v18); + v19 = v18 - 24576; + level_cel_block = v8[9]; + if ( level_cel_block ) + drawLowerScreen(v19); + v20 = v8[11]; + level_cel_block = v8[11]; + if ( v20 && leveltype == DTYPE_HELL ) + drawLowerScreen(v19 - 24576); + v21 = sy; + scrollrt_draw_clipped_dungeon((char *)gpBuffer + screen_y_times_768[sy] + sx, sxa, sya, sx, sy, 0); + goto LABEL_21; + } + world_draw_black_tile((unsigned char *)gpBuffer + screen_y_times_768[sy] + sx); + } + v21 = sy; +LABEL_21: + ++sxa; + --sya; + sx += 64; + v8 += 16; + --a5; + goto LABEL_23; + } + v21 = sy; +LABEL_23: + v46 = a5; + if ( a5 ) + { + v22 = 112 * sxa; + v47 = 112 * sxa; + do + { + --v46; + if ( sya < 0 || v22 >= 12544 ) + break; + if ( sya < 112 && v22 >= 0 ) + { + v23 = sya + v22; + v24 = dPiece[0][v23]; + light_table_index = dTransVal[0][v23]; + level_piece_id = v24; + if ( v24 ) + { + v25 = &screen_y_times_768[v21]; + v26 = (unsigned char)(nTransTable[v24] & TransList[dung_map[0][v23]]); + v27 = *v8; + v28 = *v25; + cel_transparency_active = v26; + arch_draw_type = 1; + level_cel_block = v27; + v29 = (unsigned char *)gpBuffer + v28 + sx; + if ( v27 ) + drawLowerScreen(v29); + v30 = v8[1]; + arch_draw_type = 2; + level_cel_block = v30; + if ( v30 ) + drawLowerScreen(v29 + 32); + arch_draw_type = 0; + v31 = 2; + for ( i = 2; i < dword_5A5594; i += 2 ) + { + v29 -= 24576; + level_cel_block = v8[v31]; + if ( level_cel_block ) + drawLowerScreen(v29); + v32 = v8[i + 1]; + level_cel_block = v8[i + 1]; + if ( v32 ) + drawLowerScreen(v29 + 32); + v31 = i + 2; + } + scrollrt_draw_clipped_dungeon((char *)gpBuffer + *v25 + sx, sxa, sya, sx, sy, 1); + v21 = sy; + } + else + { + world_draw_black_tile((unsigned char *)gpBuffer + screen_y_times_768[v21] + sx); + } + v22 = v47; + } + ++sxa; + sx += 64; + v22 += 112; + --sya; + v8 += 16; + v47 = v22; + } + while ( v46 ); + } + if ( some_flag && (unsigned int)sya < 0x70 && sxa < 0x70 ) + { + v33 = sya + 112 * sxa; + v34 = dPiece[0][v33]; + light_table_index = dTransVal[0][v33]; + level_piece_id = v34; + if ( v34 ) + { + v35 = &screen_y_times_768[v21]; + v36 = (unsigned char)(nTransTable[v34] & TransList[dung_map[0][v33]]); + v37 = *v8; + v51 = v35; + v38 = (char *)gpBuffer + *v35; + cel_transparency_active = v36; + arch_draw_type = 1; + level_cel_block = v37; + v39 = (unsigned char *)&v38[sx]; + if ( v37 ) + drawLowerScreen(v39); + v40 = v8[2]; + arch_draw_type = 0; + v41 = v39 - 24576; + level_cel_block = v40; + if ( v40 ) + drawLowerScreen(v41); + v42 = v41 - 24576; + level_cel_block = v8[4]; + if ( level_cel_block ) + drawLowerScreen(v42); + v43 = v42 - 24576; + level_cel_block = v8[6]; + if ( level_cel_block ) + drawLowerScreen(v43); + v44 = v43 - 24576; + level_cel_block = v8[8]; + if ( level_cel_block ) + drawLowerScreen(v44); + v45 = v8[10]; + level_cel_block = v8[10]; + if ( v45 ) + { + if ( leveltype == DTYPE_HELL ) + drawLowerScreen(v44 - 24576); + } + scrollrt_draw_clipped_dungeon((char *)gpBuffer + *v51 + sx, sxa, sya, sx, sy, 0); + } + else + { + world_draw_black_tile((unsigned char *)gpBuffer + screen_y_times_768[v21] + sx); + } + } +} +// 5BB1ED: using guessed type char leveltype; +// 69BEF8: using guessed type int light_table_index; +// 69CF14: using guessed type int level_cel_block; +// 69CF20: using guessed type char arch_draw_type; +// 69CF94: using guessed type int cel_transparency_active; +// 69CF98: using guessed type int level_piece_id; + +void __fastcall scrollrt_draw_clipped_dungeon(char *a1, int sx, int sy, int a4, int a5, int a6) +{ + int v6; // eax + char v7; // bl + char v8; // cl + char v9; // dl + int *v10; // eax + DeadStruct *v11; // eax + int *v12; // esi + int v13; // ecx + int v14; // edx + char v15; // bl + ItemStruct *v16; // esi + char *v17; // eax + signed int v18; // ebx + int v19; // ebx + unsigned int v20; // ecx + PlayerStruct *v21; // esi + int v22; // esi + int v23; // eax + MonsterStruct *v24; // esi + CMonster *v25; // ecx + int v26; // ebx + int v27; // edi + unsigned int v28; // ecx + PlayerStruct *v29; // esi + int v30; // esi + int v31; // eax + MonsterStruct *v32; // esi + CMonster *v33; // ecx + int v34; // ebx + int v35; // edi + ItemStruct *v36; // esi + char *v37; // ecx + signed int v38; // ebx + int v39; // ebx + int v40; // [esp+Ch] [ebp-18h] + int v41; // [esp+10h] [ebp-14h] + char *dst_buf; // [esp+14h] [ebp-10h] + int a1a; // [esp+18h] [ebp-Ch] + char v44; // [esp+1Dh] [ebp-7h] + char v45; // [esp+1Eh] [ebp-6h] + char v46; // [esp+1Fh] [ebp-5h] + char v47; // [esp+20h] [ebp-4h] + char v48; // [esp+21h] [ebp-3h] + char v49; // [esp+22h] [ebp-2h] + char v50; // [esp+23h] [ebp-1h] + + a1a = sx; + dst_buf = a1; + v6 = 112 * sx + sy; + v7 = dDead[0][v6]; + v50 = dFlags[0][v6]; + v47 = dObject[0][v6]; + v49 = dItem[0][v6]; + v8 = dPlayer[0][v6 - 1]; + v48 = dPlayer[0][v6]; + v46 = dArch[0][v6]; + v9 = dung_map[0][v6]; + v10 = (int *)((char *)dMonster + 4 * v6); + v44 = v9; + v45 = v8; + v40 = *v10; + v41 = *(v10 - 1); + if ( visiondebug && v50 & 0x40 ) + Cel2DecodeHdrOnly(dst_buf, (char *)pSquareCel, 1, 64, 0, 8); + if ( MissilePreFlag && v50 & 1 ) + DrawClippedMissile(a1a, sy, a4, a5, 0, 8, 1); + if ( light_table_index < lightmax ) + { + if ( v7 ) + { + v11 = &dead[(v7 & 0x1F) - 1]; + v12 = (int *)v11->_deadData[(v7 >> 5) & 7]; + v13 = a4 - v11->_deadWidth2; + if ( v12 ) + { + v14 = v11->_deadFrame; + if ( v14 >= 1 && (unsigned int)*v12 <= 0x32 && v14 <= *v12 ) + { + v15 = v11->_deadtrans; + if ( v15 ) + Cl2DecodeFrm5(v13, a5, (char *)v12, v14, v11->_deadWidth, 0, 8, v15); + else + Cl2DecodeFrm6(v13, a5, (char *)v12, v14, v11->_deadWidth, 0, 8); + } + } + } + if ( v47 ) + DrawClippedObject(a1a, sy, a4, a5, 1, 0, 8); + } + if ( v49 ) + { + v16 = &item[v49-1]; + if ( !v16->_iPostDraw && (unsigned char)v49 <= MAXITEMS ) + { + v17 = (char *)v16->_iAnimData; + if ( v17 ) + { + v18 = v16->_iAnimFrame; + if ( v18 >= 1 && *(_DWORD *)v17 <= 0x32u && v18 <= *(_DWORD *)v17 ) + { + v19 = a4 - v16->_iAnimWidth2; + if ( v49 - 1 == pcursitem ) + CelDrawHdrClrHL(181, v19, a5, v17, v16->_iAnimFrame, v16->_iAnimWidth, 0, 8); + Cel2DecodeHdrLight(v19, a5, (char *)v16->_iAnimData, v16->_iAnimFrame, v16->_iAnimWidth, 0, 8); + } + } + } + } + if ( v50 & 0x20 ) + { + v20 = -1 - v45; + if ( v20 < 4 ) + { + v21 = &plr[v20]; + DrawClippedPlayer( + v20, + a1a, + sy - 1, + a4 + v21->_pxoff - v21->_pAnimWidth2, + a5 + v21->_pyoff, + v21->_pAnimData, + v21->_pAnimFrame, + v21->_pAnimWidth, + 0, + 8); + if ( a6 ) + { + v22 = v21->_peflag; + if ( v22 ) + { + if ( v22 == 2 ) + scrollrt_draw_clipped_e_flag(dst_buf - 12384, a1a - 2, sy + 1, a4 - 96, a5 - 16); + scrollrt_draw_clipped_e_flag(dst_buf - 64, a1a - 1, sy + 1, a4 - 64, a5); + } + } + } + } + if ( v50 & 0x10 && (v50 & 0x40 || plr[myplr]._pInfraFlag) && v41 < 0 ) + { + v23 = -1 - v41; + draw_monster_num = -1 - v41; + if ( (unsigned int)(-1 - v41) < MAXMONSTERS ) + { + v24 = &monster[v23]; + if ( !(v24->_mFlags & 1) ) + { + v25 = v24->MType; + if ( v25 ) + { + v26 = a5 + v24->_myoff; + v27 = a4 + v24->_mxoff - v25->flags_2; + if ( v23 == pcursmonst ) + { + Cl2DecodeClrHL(233, v27, v26, (char *)v24->_mAnimData, v24->_mAnimFrame, v25->flags_1, 0, 8); + v23 = draw_monster_num; + } + DrawClippedMonster(a1a, sy, v27, v26, v23, 0, 8); + if ( a6 && v24->_meflag ) + scrollrt_draw_clipped_e_flag(dst_buf - 64, a1a - 1, sy + 1, a4 - 64, a5); + } + } + } + } + if ( v50 & 4 ) + DrawDeadPlayer(a1a, sy, a4, a5, 0, 8, 1); + if ( v48 > 0 ) + { + v28 = v48 - 1; + if ( v28 < 4 ) + { + v29 = &plr[v28]; + DrawClippedPlayer( + v28, + a1a, + sy, + a4 + v29->_pxoff - v29->_pAnimWidth2, + a5 + v29->_pyoff, + v29->_pAnimData, + v29->_pAnimFrame, + v29->_pAnimWidth, + 0, + 8); + if ( a6 ) + { + v30 = v29->_peflag; + if ( v30 ) + { + if ( v30 == 2 ) + scrollrt_draw_clipped_e_flag(dst_buf - 12384, a1a - 2, sy + 1, a4 - 96, a5 - 16); + scrollrt_draw_clipped_e_flag(dst_buf - 64, a1a - 1, sy + 1, a4 - 64, a5); + } + } + } + } + if ( v40 > 0 && (v50 & 0x40 || plr[myplr]._pInfraFlag) ) + { + v31 = v40 - 1; + draw_monster_num = v40 - 1; + if ( (unsigned int)(v40 - 1) < MAXMONSTERS ) + { + v32 = &monster[v31]; + if ( !(v32->_mFlags & 1) ) + { + v33 = v32->MType; + if ( v33 ) + { + v34 = a5 + v32->_myoff; + v35 = a4 + v32->_mxoff - v33->flags_2; + if ( v31 == pcursmonst ) + { + Cl2DecodeClrHL(233, v35, v34, (char *)v32->_mAnimData, v32->_mAnimFrame, v33->flags_1, 0, 8); + v31 = draw_monster_num; + } + DrawClippedMonster(a1a, sy, v35, v34, v31, 0, 8); + if ( a6 && v32->_meflag ) + scrollrt_draw_clipped_e_flag(dst_buf - 64, a1a - 1, sy + 1, a4 - 64, a5); + } + } + } + } + if ( v50 & 1 ) + DrawClippedMissile(a1a, sy, a4, a5, 0, 8, 0); + if ( v47 && light_table_index < lightmax ) + DrawClippedObject(a1a, sy, a4, a5, 0, 0, 8); + if ( v49 ) + { + v36 = &item[v49-1]; + if ( v36->_iPostDraw ) + { + if ( (unsigned char)v49 <= MAXITEMS ) + { + v37 = (char *)v36->_iAnimData; + if ( v37 ) + { + v38 = v36->_iAnimFrame; + if ( v38 >= 1 && *(_DWORD *)v37 <= 0x32u && v38 <= *(_DWORD *)v37 ) + { + v39 = a4 - v36->_iAnimWidth2; + if ( v49 - 1 == pcursitem ) + CelDrawHdrClrHL(181, v39, a5, v37, v36->_iAnimFrame, v36->_iAnimWidth, 0, 8); + Cel2DecodeHdrLight( + v39, + a5, + (char *)v36->_iAnimData, + v36->_iAnimFrame, + v36->_iAnimWidth, + 0, + 8); + } + } + } + } + } + if ( v46 ) + { + cel_transparency_active = (unsigned char)TransList[v44]; + Cel2DecodeLightTrans(dst_buf, (char *)level_special_cel, v46, 64, 0, 8); + } +} +// 4B8CC0: using guessed type char pcursitem; +// 525720: using guessed type int visiondebug; +// 642A14: using guessed type char lightmax; +// 64CCD4: using guessed type int MissilePreFlag; +// 69BEF8: using guessed type int light_table_index; +// 69CF94: using guessed type int cel_transparency_active; +// 69EFA4: using guessed type int draw_monster_num; + +void __fastcall DrawClippedMonster(int x, int y, int a3, int a4, int mon_id, int a6, int a7) +{ + int v7; // eax + char *v8; // esi + signed int v9; // ebx + char v10; // cl + CMonster *v11; // eax + char mon_ida; // [esp+1Ch] [ebp+10h] + + if ( (unsigned int)mon_id < MAXMONSTERS ) + { + v7 = mon_id; + v8 = (char *)monster[mon_id]._mAnimData; + if ( v8 ) + { + v9 = monster[v7]._mAnimFrame; + if ( v9 >= 1 && (unsigned int)*v8 <= 0x32 && v9 <= *v8 ) + { + if ( dFlags[x][y] & 0x40 ) + { + v10 = 0; + mon_ida = 0; + if ( monster[v7]._uniqtype ) + { + v10 = monster[v7]._uniqtrans + 4; + mon_ida = monster[v7]._uniqtrans + 4; + } + if ( monster[v7]._mmode == MM_STONE ) + { + v10 = 2; + mon_ida = 2; + } + if ( plr[myplr]._pInfraFlag && light_table_index > 8 ) + { + v10 = 1; + mon_ida = 1; + } + v11 = monster[v7].MType; + if ( v10 ) + Cl2DecodeFrm5(a3, a4, v8, v9, v11->flags_1, a6, a7, mon_ida); + else + Cl2DecodeFrm6(a3, a4, v8, v9, v11->flags_1, a6, a7); + } + else + { + Cl2DecodeFrm5(a3, a4, v8, v9, monster[v7].MType->flags_1, a6, a7, 1); + } + } + } + } +} +// 69BEF8: using guessed type int light_table_index; + +void __fastcall DrawClippedObject(int x, int y, int a3, int a4, int pre_flag, int a6, int dir) +{ + int v7; // edi + char v8; // al + unsigned char v9; // dl + int v10; // esi + int v11; // ebx + int v12; // edi + int v13; // eax + int v14; // ecx + char *v15; // eax + signed int v16; // ecx + char *v17; // [esp-14h] [ebp-24h] + int v18; // [esp-10h] [ebp-20h] + int v19; // [esp-Ch] [ebp-1Ch] + char v20; // [esp+Fh] [ebp-1h] + + v7 = y; + v8 = dObject[x][y]; + if ( v8 <= 0 ) + { + v9 = -1 - v8; + v10 = (char)(-1 - v8); + v20 = -1 - v8; + if ( object[v10]._oPreFlag != pre_flag ) + return; + dir = 8; + v13 = object[v10]._ox - x; + v14 = object[v10]._oy - v7; + v12 = a3 + 32 * v13 - object[v10]._oAnimWidth2 - 32 * v14; + v11 = a4 + 16 * (v14 + v13); + a6 = 0; + } + else + { + v9 = v8 - 1; + v10 = (char)(v8 - 1); + v20 = v8 - 1; + if ( object[v10]._oPreFlag != pre_flag ) + return; + v11 = a4; + v12 = a3 - object[v10]._oAnimWidth2; + } + if ( v9 < MAXOBJECTS ) + { + v15 = (char *)object[v10]._oAnimData; + if ( v15 ) + { + v16 = object[v10]._oAnimFrame; + if ( v16 >= 1 && *(_DWORD *)v15 <= 0x32u && v16 <= *(_DWORD *)v15 ) + { + if ( v20 == pcursobj ) + CelDrawHdrClrHL(194, v12, v11, v15, v16, object[v10]._oAnimWidth, a6, dir); + v19 = object[v10]._oAnimWidth; + v18 = object[v10]._oAnimFrame; + v17 = (char *)object[v10]._oAnimData; + if ( object[v10]._oLight ) + Cel2DecodeHdrLight(v12, v11, v17, v18, v19, a6, dir); + else + Cel2DrawHdrOnly(v12, v11, v17, v18, v19, a6, dir); + } + } + } +} +// 4B8CC1: using guessed type char pcursobj; + +void __fastcall scrollrt_draw_clipped_e_flag(char *buffer, int x, int y, int a4, int a5) +{ + int v5; // eax + int v6; // ebx + int v7; // ecx + int v8; // esi + int v9; // eax + int v10; // edi + int v11; // eax + int v12; // eax + unsigned short *v13; // esi + int v14; // eax + int v15; // eax + int v16; // eax + int v17; // eax + int v18; // [esp+Ch] [ebp-14h] + int xa; // [esp+10h] [ebp-10h] + int i; // [esp+14h] [ebp-Ch] + unsigned char *a1; // [esp+18h] [ebp-8h] + unsigned char *pbDst; // [esp+1Ch] [ebp-4h] + + xa = x; + v18 = level_piece_id; + v5 = y + 112 * x; + a1 = (unsigned char *)buffer; + v6 = cel_transparency_active; + v7 = dPiece[0][v5]; + v8 = dTransVal[0][v5]; + v9 = dung_map[0][v5]; + v10 = light_table_index; + level_piece_id = v7; + v11 = (unsigned char)(nTransTable[v7] & TransList[v9]); + light_table_index = v8; + cel_transparency_active = v11; + v12 = gendung_get_dpiece_num_from_coord(x, y); + arch_draw_type = 1; + v13 = (unsigned short *)((char *)dpiece_defs_map_1 + 32 * v12); + v14 = *v13; + level_cel_block = *v13; + if ( v14 ) + drawLowerScreen(a1); + v15 = v13[1]; + arch_draw_type = 2; + level_cel_block = v15; + if ( v15 ) + drawLowerScreen(a1 + 32); + arch_draw_type = 0; + pbDst = a1; + v16 = 2; + for ( i = 2; i < dword_5A5594; i += 2 ) + { + pbDst -= 24576; + level_cel_block = v13[v16]; + if ( level_cel_block ) + drawLowerScreen(pbDst); + v17 = v13[i + 1]; + level_cel_block = v13[i + 1]; + if ( v17 ) + drawLowerScreen(pbDst + 32); + v16 = i + 2; + } + scrollrt_draw_clipped_dungeon((char *)a1, xa, y, a4, a5, 0); + light_table_index = v10; + cel_transparency_active = v6; + level_piece_id = v18; +} +// 69BEF8: using guessed type int light_table_index; +// 69CF14: using guessed type int level_cel_block; +// 69CF20: using guessed type char arch_draw_type; +// 69CF94: using guessed type int cel_transparency_active; +// 69CF98: using guessed type int level_piece_id; + +void __fastcall scrollrt_draw_lower_2(int x, int y, int sx, int sy, int a5, int a6, int some_flag) +{ + signed int v7; // ebx + int v8; // edi + int v9; // ecx + int v10; // eax + int v11; // eax + int v12; // eax + int v13; // ecx + int v14; // ecx + int v15; // eax + unsigned char *v16; // ebx + int v17; // eax + int v18; // eax + int v19; // ecx + int v20; // eax + int v21; // eax + int v22; // eax + int v23; // [esp+Ch] [ebp-14h] + unsigned short *v24; // [esp+10h] [ebp-10h] + int v25; // [esp+10h] [ebp-10h] + int a1; // [esp+14h] [ebp-Ch] + unsigned char *a1a; // [esp+14h] [ebp-Ch] + unsigned char *a1b; // [esp+14h] [ebp-Ch] + char *v29; // [esp+18h] [ebp-8h] + signed int xa; // [esp+1Ch] [ebp-4h] + int a6a; // [esp+28h] [ebp+8h] + int a6b; // [esp+28h] [ebp+8h] + int a6c; // [esp+28h] [ebp+8h] + unsigned short *a5a; // [esp+30h] [ebp+10h] + unsigned short *a5b; // [esp+30h] [ebp+10h] + + v7 = y; + a1 = y; + xa = x; + v8 = sx; + v29 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(x, y); + if ( some_flag ) + { + if ( v7 >= 0 && v7 < 112 && xa >= 0 && xa < 112 ) + { + v9 = 112 * xa + v7; + v10 = dPiece[0][v9]; + light_table_index = dTransVal[0][v9]; + level_piece_id = v10; + if ( v10 ) + { + a6a = 0; + cel_transparency_active = (unsigned char)(nTransTable[v10] & TransList[dung_map[0][v9]]); + a1a = (unsigned char *)gpBuffer + screen_y_times_768[sy] + v8 - 24544; + if ( (dword_5A5594 >> 1) - 1 > 0 ) + { + v24 = (unsigned short *)(v29 + 6); + do + { + if ( a6 <= a6a ) + { + v11 = *v24; + level_cel_block = *v24; + if ( v11 ) + drawLowerScreen(a1a); + } + a1a -= 24576; + ++a6a; + v24 += 2; + } + while ( a6a < (dword_5A5594 >> 1) - 1 ); + } + v12 = 2 * a6 + 2; + if ( v12 < 8 ) + scrollrt_draw_clipped_dungeon_2( + (char *)gpBuffer + screen_y_times_768[sy] - 12288 * v12 + v8, + xa, + v7, + a6, + 2 * a6 + 2, + v8, + sy, + 0); + } + } + ++xa; + --v7; + v8 += 64; + --a5; + v29 += 32; + a1 = v7; + } + v25 = a5; + if ( a5 ) + { + v13 = 112 * xa; + v23 = 112 * xa; + do + { + --v25; + if ( v13 >= 12544 || v7 < 0 ) + break; + if ( v7 < 112 && v13 >= 0 ) + { + v14 = v7 + v13; + v15 = dPiece[0][v14]; + light_table_index = dTransVal[0][v14]; + level_piece_id = v15; + if ( v15 ) + { + a6b = 0; + cel_transparency_active = (unsigned char)(nTransTable[v15] & TransList[dung_map[0][v14]]); + v16 = (unsigned char *)gpBuffer + screen_y_times_768[sy] + v8 - 24576; + if ( (dword_5A5594 >> 1) - 1 > 0 ) + { + a5a = (unsigned short *)(v29 + 6); + do + { + if ( a6 <= a6b ) + { + v17 = *(a5a - 1); + level_cel_block = *(a5a - 1); + if ( v17 ) + drawLowerScreen(v16); + v18 = *a5a; + level_cel_block = *a5a; + if ( v18 ) + drawLowerScreen(v16 + 32); + } + ++a6b; + a5a += 2; + v16 -= 24576; + } + while ( a6b < (dword_5A5594 >> 1) - 1 ); + } + if ( 2 * a6 + 2 < 8 ) + scrollrt_draw_clipped_dungeon_2( + (char *)gpBuffer + screen_y_times_768[sy] - ((3 * a6 + 3) << 13) + v8, + xa, + a1, + a6, + 2 * a6 + 2, + v8, + sy, + 1); + v7 = a1; + } + } + ++xa; + v29 += 32; + v13 = v23 + 112; + --v7; + v8 += 64; + v23 += 112; + a1 = v7; + } + while ( v25 ); + } + if ( some_flag ) + { + if ( (unsigned int)v7 < 0x70 && (unsigned int)xa < 0x70 ) + { + v19 = 112 * xa + v7; + v20 = dPiece[0][v19]; + light_table_index = dTransVal[0][v19]; + level_piece_id = v20; + if ( v20 ) + { + a6c = 0; + cel_transparency_active = (unsigned char)(nTransTable[v20] & TransList[dung_map[0][v19]]); + a1b = (unsigned char *)gpBuffer + screen_y_times_768[sy] + v8 - 24576; + if ( (dword_5A5594 >> 1) - 1 > 0 ) + { + a5b = (unsigned short *)(v29 + 4); + do + { + if ( a6 <= a6c ) + { + v21 = *a5b; + level_cel_block = *a5b; + if ( v21 ) + drawLowerScreen(a1b); + } + a1b -= 24576; + ++a6c; + a5b += 2; + } + while ( a6c < (dword_5A5594 >> 1) - 1 ); + } + v22 = 2 * a6 + 2; + if ( v22 < 8 ) + scrollrt_draw_clipped_dungeon_2( + (char *)gpBuffer + screen_y_times_768[sy] - 12288 * v22 + v8, + xa, + v7, + a6, + 2 * a6 + 2, + v8, + sy, + 0); + } + } + } +} +// 69BEF8: using guessed type int light_table_index; +// 69CF14: using guessed type int level_cel_block; +// 69CF94: using guessed type int cel_transparency_active; +// 69CF98: using guessed type int level_piece_id; + +void __fastcall scrollrt_draw_clipped_dungeon_2(char *buffer, int x, int y, int a4, int a5, int sx, int sy, int me_flag) +{ + int v8; // eax + char v9; // bl + char v10; // cl + char v11; // dl + int *v12; // eax + int v13; // edi + DeadStruct *v14; // eax + int *v15; // esi + int v16; // ecx + int v17; // edx + char v18; // bl + ItemStruct *v19; // esi + char *v20; // eax + signed int v21; // ebx + int v22; // ebx + unsigned int v23; // ecx + PlayerStruct *v24; // esi + int v25; // esi + int v26; // eax + MonsterStruct *v27; // esi + CMonster *v28; // ecx + int v29; // ebx + int v30; // edi + unsigned int v31; // ecx + PlayerStruct *v32; // esi + int v33; // esi + int v34; // eax + MonsterStruct *v35; // esi + CMonster *v36; // ecx + int v37; // ebx + int v38; // edi + ItemStruct *v39; // esi + char *v40; // eax + int v41; // ecx + int v42; // edi + int v43; // [esp+Ch] [ebp-18h] + int v44; // [esp+10h] [ebp-14h] + char *dst_buf; // [esp+14h] [ebp-10h] + int a1; // [esp+18h] [ebp-Ch] + char v47; // [esp+1Dh] [ebp-7h] + char v48; // [esp+1Eh] [ebp-6h] + char v49; // [esp+1Fh] [ebp-5h] + char v50; // [esp+20h] [ebp-4h] + char v51; // [esp+21h] [ebp-3h] + char v52; // [esp+22h] [ebp-2h] + char v53; // [esp+23h] [ebp-1h] + + a1 = x; + dst_buf = buffer; + v8 = 112 * x + y; + v9 = dDead[0][v8]; + v53 = dFlags[0][v8]; + v50 = dObject[0][v8]; + v52 = dItem[0][v8]; + v10 = dPlayer[0][v8 - 1]; + v51 = dPlayer[0][v8]; + v49 = dArch[0][v8]; + v11 = dung_map[0][v8]; + v12 = (int *)((char *)dMonster + 4 * v8); + v47 = v11; + v48 = v10; + v43 = *v12; + v44 = *(v12 - 1); + if ( visiondebug && v53 & 0x40 ) + Cel2DecodeHdrOnly(dst_buf, (char *)pSquareCel, 1, 64, a5, 8); + if ( MissilePreFlag && v53 & 1 ) + { + v13 = sx; + DrawClippedMissile(a1, y, sx, sy, a5, 8, 1); + } + else + { + v13 = sx; + } + if ( light_table_index < lightmax ) + { + if ( v9 ) + { + v14 = &dead[(v9 & 0x1F) - 1]; + v15 = (int *)v14->_deadData[(v9 >> 5) & 7]; + v16 = v13 - v14->_deadWidth2; + if ( v15 ) + { + v17 = v14->_deadFrame; + if ( v17 >= 1 && (unsigned int)*v15 <= 0x32 && v17 <= *v15 ) + { + v18 = v14->_deadtrans; + if ( v18 ) + Cl2DecodeFrm5(v16, sy, (char *)v15, v17, v14->_deadWidth, a5, 8, v18); + else + Cl2DecodeFrm6(v16, sy, (char *)v15, v17, v14->_deadWidth, a5, 8); + } + } + } + if ( v50 ) + DrawClippedObject(a1, y, v13, sy, 1, a5, 8); + } + if ( v52 ) + { + v19 = &item[v52-1]; + if ( !v19->_iPostDraw && (unsigned char)v52 <= MAXITEMS ) + { + v20 = (char *)v19->_iAnimData; + if ( v20 ) + { + v21 = v19->_iAnimFrame; + if ( v21 >= 1 && *(_DWORD *)v20 <= 0x32u && v21 <= *(_DWORD *)v20 ) + { + v22 = v13 - v19->_iAnimWidth2; + if ( v52 - 1 == pcursitem ) + CelDrawHdrClrHL(181, v22, sy, v20, v19->_iAnimFrame, v19->_iAnimWidth, a5, 8); + Cel2DecodeHdrLight(v22, sy, (char *)v19->_iAnimData, v19->_iAnimFrame, v19->_iAnimWidth, a5, 8); + } + } + } + } + if ( v53 & 0x20 ) + { + v23 = -1 - v48; + if ( v23 < 4 ) + { + v24 = &plr[v23]; + DrawClippedPlayer( + v23, + a1, + y - 1, + v13 + v24->_pxoff - v24->_pAnimWidth2, + sy + v24->_pyoff, + v24->_pAnimData, + v24->_pAnimFrame, + v24->_pAnimWidth, + a5, + 8); + if ( me_flag ) + { + v25 = v24->_peflag; + if ( v25 ) + { + if ( v25 == 2 ) + scrollrt_draw_clipped_e_flag_2(dst_buf - 12384, a1 - 2, y + 1, a4, a5, v13 - 96, sy - 16); + scrollrt_draw_clipped_e_flag_2(dst_buf - 64, a1 - 1, y + 1, a4, a5, v13 - 64, sy); + } + } + } + } + if ( v53 & 0x10 && (v53 & 0x40 || plr[myplr]._pInfraFlag) && v44 < 0 ) + { + v26 = -1 - v44; + draw_monster_num = -1 - v44; + if ( (unsigned int)(-1 - v44) < MAXMONSTERS ) + { + v27 = &monster[v26]; + if ( !(v27->_mFlags & 1) ) + { + v28 = v27->MType; + if ( v28 ) + { + v29 = sy + v27->_myoff; + v30 = sx + v27->_mxoff - v28->flags_2; + if ( v26 == pcursmonst ) + { + Cl2DecodeClrHL(233, v30, v29, (char *)v27->_mAnimData, v27->_mAnimFrame, v28->flags_1, a5, 8); + v26 = draw_monster_num; + } + DrawClippedMonster(a1, y, v30, v29, v26, a5, 8); + if ( me_flag && !v27->_meflag ) + scrollrt_draw_clipped_e_flag_2(dst_buf - 64, a1 - 1, y + 1, a4, a5, sx - 64, sy); + v13 = sx; + } + } + } + } + if ( v53 & 4 ) + DrawDeadPlayer(a1, y, v13, sy, a5, 8, 1); + if ( v51 > 0 ) + { + v31 = v51 - 1; + if ( v31 < 4 ) + { + v32 = &plr[v31]; + DrawClippedPlayer( + v31, + a1, + y, + v13 + v32->_pxoff - v32->_pAnimWidth2, + sy + v32->_pyoff, + v32->_pAnimData, + v32->_pAnimFrame, + v32->_pAnimWidth, + a5, + 8); + if ( me_flag ) + { + v33 = v32->_peflag; + if ( v33 ) + { + if ( v33 == 2 ) + scrollrt_draw_clipped_e_flag_2(dst_buf - 12384, a1 - 2, y + 1, a4, a5, v13 - 96, sy - 16); + scrollrt_draw_clipped_e_flag_2(dst_buf - 64, a1 - 1, y + 1, a4, a5, v13 - 64, sy); + } + } + } + } + if ( v43 > 0 && (v53 & 0x40 || plr[myplr]._pInfraFlag) ) + { + v34 = v43 - 1; + draw_monster_num = v43 - 1; + if ( (unsigned int)(v43 - 1) < MAXMONSTERS ) + { + v35 = &monster[v34]; + if ( !(v35->_mFlags & 1) ) + { + v36 = v35->MType; + if ( v36 ) + { + v37 = sy + v35->_myoff; + v38 = sx + v35->_mxoff - v36->flags_2; + if ( v34 == pcursmonst ) + { + Cl2DecodeClrHL(233, v38, v37, (char *)v35->_mAnimData, v35->_mAnimFrame, v36->flags_1, a5, 8); + v34 = draw_monster_num; + } + DrawClippedMonster(a1, y, v38, v37, v34, a5, 8); + if ( me_flag && !v35->_meflag ) + scrollrt_draw_clipped_e_flag_2(dst_buf - 64, a1 - 1, y + 1, a4, a5, sx - 64, sy); + v13 = sx; + } + } + } + } + if ( v53 & 1 ) + DrawClippedMissile(a1, y, v13, sy, a5, 8, 0); + if ( v50 && light_table_index < lightmax ) + DrawClippedObject(a1, y, v13, sy, 0, a5, 8); + if ( v52 ) + { + v39 = &item[v52-1]; + if ( v39->_iPostDraw ) + { + if ( (unsigned char)v52 <= MAXITEMS ) + { + v40 = (char *)v39->_iAnimData; + if ( v40 ) + { + v41 = v39->_iAnimFrame; + if ( v41 >= 1 && *(_DWORD *)v40 <= 0x32u && v41 <= *(_DWORD *)v40 ) + { + v42 = v13 - v39->_iAnimWidth2; + if ( v52 - 1 == pcursitem ) + CelDrawHdrClrHL(181, v42, sy, v40, v41, v39->_iAnimWidth, a5, 8); + Cel2DecodeHdrLight( + v42, + sy, + (char *)v39->_iAnimData, + v39->_iAnimFrame, + v39->_iAnimWidth, + a5, + 8); + } + } + } + } + } + if ( v49 ) + { + cel_transparency_active = (unsigned char)TransList[v47]; + Cel2DecodeLightTrans(dst_buf, (char *)level_special_cel, v49, 64, a5, 8); + } +} +// 4B8CC0: using guessed type char pcursitem; +// 525720: using guessed type int visiondebug; +// 642A14: using guessed type char lightmax; +// 64CCD4: using guessed type int MissilePreFlag; +// 69BEF8: using guessed type int light_table_index; +// 69CF94: using guessed type int cel_transparency_active; +// 69EFA4: using guessed type int draw_monster_num; + +void __fastcall scrollrt_draw_clipped_e_flag_2(char *buffer, int x, int y, int a4, signed int a5, int sx, int sy) +{ + int v7; // eax + int v8; // ecx + int v9; // esi + int v10; // eax + unsigned char *v11; // edi + int v12; // eax + unsigned short *v13; // esi + int v14; // eax + int v15; // eax + int v16; // eax + int v17; // eax + unsigned char *v18; // edi + int v19; // eax + int v20; // [esp+Ch] [ebp-14h] + int v21; // [esp+10h] [ebp-10h] + int v22; // [esp+14h] [ebp-Ch] + char *a1; // [esp+18h] [ebp-8h] + int xa; // [esp+1Ch] [ebp-4h] + + xa = x; + v22 = light_table_index; + v21 = cel_transparency_active; + v20 = level_piece_id; + v7 = y + 112 * x; + a1 = buffer; + v8 = dPiece[0][v7]; + v9 = dTransVal[0][v7]; + v10 = dung_map[0][v7]; + level_piece_id = v8; + v11 = (unsigned char *)&a1[24576 * a4]; + v12 = (unsigned char)(nTransTable[v8] & TransList[v10]); + light_table_index = v9; + cel_transparency_active = v12; + v13 = (unsigned short *)((char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(x, y)); + if ( !a4 ) + { + v14 = v13[2]; + level_cel_block = v13[2]; + if ( v14 ) + drawLowerScreen(v11); + v15 = v13[3]; + level_cel_block = v13[3]; + if ( v15 ) + drawLowerScreen(v11 + 32); + goto LABEL_10; + } + if ( a4 == 1 ) + { +LABEL_10: + v11 -= 24576; + level_cel_block = v13[4]; + if ( level_cel_block ) + drawLowerScreen(v11); + v16 = v13[5]; + level_cel_block = v13[5]; + if ( v16 ) + drawLowerScreen(v11 + 32); + goto LABEL_14; + } + if ( a4 != 2 ) + { + if ( a4 != 3 ) + goto LABEL_22; + goto LABEL_18; + } +LABEL_14: + v11 -= 24576; + level_cel_block = v13[6]; + if ( level_cel_block ) + drawLowerScreen(v11); + v17 = v13[7]; + level_cel_block = v13[7]; + if ( v17 ) + drawLowerScreen(v11 + 32); +LABEL_18: + v18 = v11 - 24576; + level_cel_block = v13[8]; + if ( level_cel_block ) + drawLowerScreen(v18); + v19 = v13[9]; + level_cel_block = v13[9]; + if ( v19 ) + drawLowerScreen(v18 + 32); +LABEL_22: + if ( a5 < 8 ) + scrollrt_draw_clipped_dungeon_2(a1, xa, y, a4, a5, sx, sy, 0); + light_table_index = v22; + cel_transparency_active = v21; + level_piece_id = v20; +} +// 69BEF8: using guessed type int light_table_index; +// 69CF14: using guessed type int level_cel_block; +// 69CF94: using guessed type int cel_transparency_active; +// 69CF98: using guessed type int level_piece_id; + +void __fastcall scrollrt_draw_upper(int x, int y, int sx, int sy, int a5, int a6, int some_flag) +{ + int v7; // edi + int v8; // esi + unsigned short *v9; // ebx + int v10; // ecx + int v11; // eax + char *v12; // edx + int v13; // edi + int v14; // eax + unsigned char *v15; // edi + int v16; // eax + unsigned char *v17; // edi + int v18; // eax + int v19; // eax + int v20; // esi + int v21; // eax + int v22; // ecx + int v23; // ecx + int v24; // eax + int v25; // esi + unsigned char *v26; // esi + int v27; // eax + int v28; // eax + int v29; // eax + bool v30; // zf + int v31; // ecx + int v32; // eax + unsigned char *v33; // esi + int v34; // eax + unsigned char *v35; // esi + int v36; // eax + unsigned char *v37; // esi + int v38; // eax + int v39; // eax + int v40; // [esp+Ch] [ebp-14h] + int v41; // [esp+10h] [ebp-10h] + int a5a; // [esp+14h] [ebp-Ch] + int ya; // [esp+18h] [ebp-8h] + signed int xa; // [esp+1Ch] [ebp-4h] + int i; // [esp+30h] [ebp+10h] + + v7 = y; + v8 = x; + ya = y; + xa = x; + v9 = (unsigned short *)((char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(x, y)); + a5a = 2 * a6 + 2; + if ( a5a > 8 ) + a5a = 8; + if ( some_flag ) + { + if ( v7 >= 0 && v7 < 112 && v8 >= 0 && v8 < 112 ) + { + v10 = 112 * v8 + v7; + v11 = dPiece[0][v10]; + light_table_index = dTransVal[0][v10]; + level_piece_id = v11; + if ( v11 ) + { + cel_transparency_active = (unsigned char)(nTransTable[v11] & TransList[dung_map[0][v10]]); + v12 = (char *)gpBuffer + screen_y_times_768[sy]; + v13 = (int)&v12[sx + 32]; + if ( a6 >= 0 ) + { + v14 = v9[1]; + level_cel_block = v9[1]; + if ( v14 ) + { + arch_draw_type = 2; + drawUpperScreen((unsigned char *)&v12[sx + 32]); + arch_draw_type = 0; + } + } + v15 = (unsigned char *)(v13 - 24576); + if ( a6 >= 1 ) + { + v16 = v9[3]; + level_cel_block = v9[3]; + if ( v16 ) + drawUpperScreen(v15); + } + v17 = v15 - 24576; + if ( a6 >= 2 ) + { + v18 = v9[5]; + level_cel_block = v9[5]; + if ( v18 ) + drawUpperScreen(v17); + } + if ( a6 >= 3 ) + { + v19 = v9[7]; + level_cel_block = v9[7]; + if ( v19 ) + drawUpperScreen(v17 - 24576); + } + v7 = ya; + scrollrt_draw_dungeon((char *)gpBuffer + screen_y_times_768[sy] + sx, xa, ya, a6, a5a, sx, sy, 0); + } + else + { + world_draw_black_tile((unsigned char *)gpBuffer + screen_y_times_768[sy] + sx); + } + } + sx += 64; + v8 = xa + 1; + --v7; + --a5; + ++xa; + ya = v7; + v9 += 16; + } + if ( a5 > 0 ) + { + v20 = 112 * v8; + v41 = v20; + v40 = a5; + do + { + if ( v7 >= 0 && v7 < 112 && v20 >= 0 && v20 < 12544 ) + { + v21 = dPiece[0][v20 + v7]; + light_table_index = dTransVal[0][v20 + v7]; + level_piece_id = v21; + if ( v21 ) + { + v22 = dung_map[0][v20 + v7]; + arch_draw_type = 1; + v23 = (unsigned char)(nTransTable[v21] & TransList[v22]); + v24 = *v9; + v25 = screen_y_times_768[sy]; + cel_transparency_active = v23; + level_cel_block = v24; + v26 = (unsigned char *)gpBuffer + v25 + sx; + if ( v24 ) + drawUpperScreen(v26); + v27 = v9[1]; + arch_draw_type = 2; + level_cel_block = v27; + if ( v27 ) + drawUpperScreen(v26 + 32); + arch_draw_type = 0; + for ( i = 1; i < (dword_5A5594 >> 1) - 1; ++i ) + { + v26 -= 24576; + if ( a6 >= i ) + { + v28 = v9[2 * i]; + level_cel_block = v9[2 * i]; + if ( v28 ) + drawUpperScreen(v26); + v29 = v9[2 * i + 1]; + level_cel_block = v9[2 * i + 1]; + if ( v29 ) + drawUpperScreen(v26 + 32); + } + } + scrollrt_draw_dungeon((char *)gpBuffer + screen_y_times_768[sy] + sx, xa, ya, a6, a5a, sx, sy, 1); + v7 = ya; + v20 = v41; + } + else + { + world_draw_black_tile((unsigned char *)gpBuffer + screen_y_times_768[sy] + sx); + } + } + ++xa; + sx += 64; + v20 += 112; + --v7; + v9 += 16; + v30 = v40-- == 1; + v41 = v20; + ya = v7; + } + while ( !v30 ); + } + if ( some_flag && v7 >= 0 && v7 < 112 && xa >= 0 && xa < 112 ) + { + v31 = 112 * xa + v7; + v32 = dPiece[0][v31]; + light_table_index = dTransVal[0][v31]; + level_piece_id = v32; + if ( v32 ) + { + arch_draw_type = 1; + cel_transparency_active = (unsigned char)(nTransTable[v32] & TransList[dung_map[0][v31]]); + v33 = (unsigned char *)gpBuffer + screen_y_times_768[sy] + sx; + if ( a6 >= 0 ) + { + v34 = *v9; + level_cel_block = *v9; + if ( v34 ) + drawUpperScreen(v33); + } + arch_draw_type = 0; + v35 = v33 - 24576; + if ( a6 >= 1 ) + { + v36 = v9[2]; + level_cel_block = v9[2]; + if ( v36 ) + drawUpperScreen(v35); + } + v37 = v35 - 24576; + if ( a6 >= 2 ) + { + v38 = v9[4]; + level_cel_block = v9[4]; + if ( v38 ) + drawUpperScreen(v37); + } + if ( a6 >= 3 ) + { + v39 = v9[6]; + level_cel_block = v9[6]; + if ( v39 ) + drawUpperScreen(v37 - 24576); + } + scrollrt_draw_dungeon((char *)gpBuffer + screen_y_times_768[sy] + sx, xa, ya, a6, a5a, sx, sy, 0); + } + else + { + world_draw_black_tile((unsigned char *)gpBuffer + screen_y_times_768[sy] + sx); + } + } +} +// 69BEF8: using guessed type int light_table_index; +// 69CF14: using guessed type int level_cel_block; +// 69CF20: using guessed type char arch_draw_type; +// 69CF94: using guessed type int cel_transparency_active; +// 69CF98: using guessed type int level_piece_id; + +void __fastcall scrollrt_draw_dungeon(char *buffer, int x, int y, int a4, int a5, int sx, int sy, int me_flag) +{ + int v8; // eax + char v9; // bl + char v10; // cl + char v11; // dl + int *v12; // eax + DeadStruct *v13; // eax + int *v14; // esi + int v15; // ecx + int v16; // edx + char v17; // bl + ItemStruct *v18; // esi + char *v19; // eax + signed int v20; // ebx + int v21; // ebx + unsigned int v22; // ecx + PlayerStruct *v23; // esi + int v24; // esi + int v25; // eax + MonsterStruct *v26; // esi + CMonster *v27; // ecx + int v28; // ebx + int v29; // edi + unsigned int v30; // ecx + PlayerStruct *v31; // esi + int v32; // esi + int v33; // eax + MonsterStruct *v34; // esi + CMonster *v35; // ecx + int v36; // ebx + int v37; // edi + ItemStruct *v38; // esi + char *v39; // ecx + signed int v40; // ebx + int v41; // ebx + int v42; // [esp+Ch] [ebp-18h] + int v43; // [esp+10h] [ebp-14h] + char *dst_buf; // [esp+14h] [ebp-10h] + int xa; // [esp+18h] [ebp-Ch] + char v46; // [esp+1Dh] [ebp-7h] + char v47; // [esp+1Eh] [ebp-6h] + char v48; // [esp+1Fh] [ebp-5h] + char v49; // [esp+20h] [ebp-4h] + char v50; // [esp+21h] [ebp-3h] + char v51; // [esp+22h] [ebp-2h] + char v52; // [esp+23h] [ebp-1h] + + xa = x; + dst_buf = buffer; + v8 = 112 * x + y; + v9 = dDead[0][v8]; + v52 = dFlags[0][v8]; + v49 = dObject[0][v8]; + v51 = dItem[0][v8]; + v10 = dPlayer[0][v8 - 1]; + v50 = dPlayer[0][v8]; + v48 = dArch[0][v8]; + v11 = dung_map[0][v8]; + v12 = (int *)((char *)dMonster + 4 * v8); + v46 = v11; + v47 = v10; + v42 = *v12; + v43 = *(v12 - 1); + if ( visiondebug && v52 & 0x40 ) + CelDecodeHdrOnly(dst_buf, (char *)pSquareCel, 1, 64, 0, a5); + if ( MissilePreFlag && v52 & 1 ) + DrawMissile(xa, y, sx, sy, 0, a5, 1); + if ( light_table_index < lightmax ) + { + if ( v9 ) + { + v13 = &dead[(v9 & 0x1F) - 1]; + v14 = (int *)v13->_deadData[(v9 >> 5) & 7]; + v15 = sx - v13->_deadWidth2; + if ( v14 ) + { + v16 = v13->_deadFrame; + if ( v16 >= 1 && (unsigned int)*v14 <= 0x32 && v16 <= *v14 ) + { + v17 = v13->_deadtrans; + if ( v17 ) + Cl2DecodeFrm3(v15, sy, (char *)v14, v16, v13->_deadWidth, 0, a5, v17); + else + Cl2DecodeLightTbl(v15, sy, (char *)v14, v16, v13->_deadWidth, 0, a5); + } + } + } + if ( v49 ) + DrawObject(xa, y, sx, sy, 1, 0, a5); + } + if ( v51 ) + { + v18 = &item[v51-1]; + if ( !v18->_iPostDraw && (unsigned char)v51 <= MAXITEMS ) + { + v19 = (char *)v18->_iAnimData; + if ( v19 ) + { + v20 = v18->_iAnimFrame; + if ( v20 >= 1 && *(_DWORD *)v19 <= 0x32u && v20 <= *(_DWORD *)v19 ) + { + v21 = sx - v18->_iAnimWidth2; + if ( v51 - 1 == pcursitem ) + CelDecodeClr(181, v21, sy, v19, v18->_iAnimFrame, v18->_iAnimWidth, 0, a5); + CelDecodeHdrLightOnly(v21, sy, (char *)v18->_iAnimData, v18->_iAnimFrame, v18->_iAnimWidth, 0, a5); + } + } + } + } + if ( v52 & 0x20 ) + { + v22 = -1 - v47; + if ( v22 < 4 ) + { + v23 = &plr[v22]; + DrawPlayer( + v22, + xa, + y - 1, + sx + v23->_pxoff - v23->_pAnimWidth2, + sy + v23->_pyoff, + v23->_pAnimData, + v23->_pAnimFrame, + v23->_pAnimWidth, + 0, + a5); + if ( me_flag ) + { + v24 = v23->_peflag; + if ( v24 ) + { + if ( v24 == 2 ) + scrollrt_draw_e_flag(dst_buf - 12384, xa - 2, y + 1, a4, a5, sx - 96, sy - 16); + scrollrt_draw_e_flag(dst_buf - 64, xa - 1, y + 1, a4, a5, sx - 64, sy); + } + } + } + } + if ( v52 & 0x10 && (v52 & 0x40 || plr[myplr]._pInfraFlag) && v43 < 0 ) + { + v25 = -1 - v43; + draw_monster_num = -1 - v43; + if ( (unsigned int)(-1 - v43) < MAXMONSTERS ) + { + v26 = &monster[v25]; + if ( !(v26->_mFlags & 1) ) + { + v27 = v26->MType; + if ( v27 ) + { + v28 = sy + v26->_myoff; + v29 = sx + v26->_mxoff - v27->flags_2; + if ( v25 == pcursmonst ) + { + Cl2DecodeFrm2(233, v29, v28, (char *)v26->_mAnimData, v26->_mAnimFrame, v27->flags_1, 0, a5); + v25 = draw_monster_num; + } + DrawMonster(xa, y, v29, v28, v25, 0, a5); + if ( me_flag && !v26->_meflag ) + scrollrt_draw_e_flag(dst_buf - 64, xa - 1, y + 1, a4, a5, sx - 64, sy); + } + } + } + } + if ( v52 & 4 ) + DrawDeadPlayer(xa, y, sx, sy, 0, a5, 0); + if ( v50 > 0 ) + { + v30 = v50 - 1; + if ( v30 < 4 ) + { + v31 = &plr[v30]; + DrawPlayer( + v30, + xa, + y, + sx + v31->_pxoff - v31->_pAnimWidth2, + sy + v31->_pyoff, + v31->_pAnimData, + v31->_pAnimFrame, + v31->_pAnimWidth, + 0, + a5); + if ( me_flag ) + { + v32 = v31->_peflag; + if ( v32 ) + { + if ( v32 == 2 ) + scrollrt_draw_e_flag(dst_buf - 12384, xa - 2, y + 1, a4, a5, sx - 96, sy - 16); + scrollrt_draw_e_flag(dst_buf - 64, xa - 1, y + 1, a4, a5, sx - 64, sy); + } + } + } + } + if ( v42 > 0 && (v52 & 0x40 || plr[myplr]._pInfraFlag) ) + { + v33 = v42 - 1; + draw_monster_num = v42 - 1; + if ( (unsigned int)(v42 - 1) < MAXMONSTERS ) + { + v34 = &monster[v33]; + if ( !(v34->_mFlags & 1) ) + { + v35 = v34->MType; + if ( v35 ) + { + v36 = sy + v34->_myoff; + v37 = sx + v34->_mxoff - v35->flags_2; + if ( v33 == pcursmonst ) + { + Cl2DecodeFrm2(233, v37, v36, (char *)v34->_mAnimData, v34->_mAnimFrame, v35->flags_1, 0, a5); + v33 = draw_monster_num; + } + DrawMonster(xa, y, v37, v36, v33, 0, a5); + if ( me_flag && !v34->_meflag ) + scrollrt_draw_e_flag(dst_buf - 64, xa - 1, y + 1, a4, a5, sx - 64, sy); + } + } + } + } + if ( v52 & 1 ) + DrawMissile(xa, y, sx, sy, 0, a5, 0); + if ( v49 && light_table_index < lightmax ) + DrawObject(xa, y, sx, sy, 0, 0, a5); + if ( v51 ) + { + v38 = &item[v51-1]; + if ( v38->_iPostDraw ) + { + if ( (unsigned char)v51 <= MAXITEMS ) + { + v39 = (char *)v38->_iAnimData; + if ( v39 ) + { + v40 = v38->_iAnimFrame; + if ( v40 >= 1 && *(_DWORD *)v39 <= 0x32u && v40 <= *(_DWORD *)v39 ) + { + v41 = sx - v38->_iAnimWidth2; + if ( v51 - 1 == pcursitem ) + CelDecodeClr(181, v41, sy, v39, v38->_iAnimFrame, v38->_iAnimWidth, 0, a5); + CelDecodeHdrLightOnly( + v41, + sy, + (char *)v38->_iAnimData, + v38->_iAnimFrame, + v38->_iAnimWidth, + 0, + a5); + } + } + } + } + } + if ( v48 ) + { + cel_transparency_active = (unsigned char)TransList[v46]; + CelDecodeHdrLightTrans(dst_buf, (char *)level_special_cel, v48, 64, 0, a5); + } +} +// 4B8CC0: using guessed type char pcursitem; +// 525720: using guessed type int visiondebug; +// 642A14: using guessed type char lightmax; +// 64CCD4: using guessed type int MissilePreFlag; +// 69BEF8: using guessed type int light_table_index; +// 69CF94: using guessed type int cel_transparency_active; +// 69EFA4: using guessed type int draw_monster_num; + +void __fastcall DrawMonster(int x, int y, int a3, int a4, int mon_id, int a6, int a7) +{ + int v7; // eax + char *v8; // esi + signed int v9; // ebx + char v10; // cl + CMonster *v11; // eax + char mon_ida; // [esp+1Ch] [ebp+10h] + + if ( (unsigned int)mon_id < MAXMONSTERS ) + { + v7 = mon_id; + v8 = (char *)monster[mon_id]._mAnimData; + if ( v8 ) + { + v9 = monster[v7]._mAnimFrame; + if ( v9 >= 1 && (unsigned int)*v8 <= 0x32 && v9 <= *v8 ) + { + if ( dFlags[x][y] & 0x40 ) + { + v10 = 0; + mon_ida = 0; + if ( monster[v7]._uniqtype ) + { + v10 = monster[v7]._uniqtrans + 4; + mon_ida = monster[v7]._uniqtrans + 4; + } + if ( monster[v7]._mmode == MM_STONE ) + { + v10 = 2; + mon_ida = 2; + } + if ( plr[myplr]._pInfraFlag && light_table_index > 8 ) + { + v10 = 1; + mon_ida = 1; + } + v11 = monster[v7].MType; + if ( v10 ) + Cl2DecodeFrm3(a3, a4, v8, v9, v11->flags_1, a6, a7, mon_ida); + else + Cl2DecodeLightTbl(a3, a4, v8, v9, v11->flags_1, a6, a7); + } + else + { + Cl2DecodeFrm3(a3, a4, v8, v9, monster[v7].MType->flags_1, a6, a7, 1); + } + } + } + } +} +// 69BEF8: using guessed type int light_table_index; + +void __fastcall DrawObject(int x, int y, int a3, int a4, int pre_flag, int a6, int dir) +{ + int v7; // edi + char v8; // al + unsigned char v9; // dl + int v10; // esi + int v11; // ebx + int v12; // edi + int v13; // eax + int v14; // ecx + char *v15; // eax + signed int v16; // ecx + char *v17; // eax + char v18; // [esp+Fh] [ebp-1h] + + v7 = y; + v8 = dObject[x][y]; + if ( v8 <= 0 ) + { + v9 = -1 - v8; + v10 = (char)(-1 - v8); + v18 = -1 - v8; + if ( object[v10]._oPreFlag != pre_flag ) + return; + dir = 8; + v13 = object[v10]._ox - x; + v14 = object[v10]._oy - v7; + v12 = a3 + 32 * v13 - object[v10]._oAnimWidth2 - 32 * v14; + v11 = a4 + 16 * (v14 + v13); + a6 = 0; + } + else + { + v9 = v8 - 1; + v10 = (char)(v8 - 1); + v18 = v8 - 1; + if ( object[v10]._oPreFlag != pre_flag ) + return; + v11 = a4; + v12 = a3 - object[v10]._oAnimWidth2; + } + if ( v9 < MAXOBJECTS ) + { + v15 = (char *)object[v10]._oAnimData; + if ( v15 ) + { + v16 = object[v10]._oAnimFrame; + if ( v16 >= 1 && *(_DWORD *)v15 <= 0x32u && v16 <= *(_DWORD *)v15 ) + { + if ( v18 == pcursobj ) + CelDecodeClr(194, v12, v11, v15, v16, object[v10]._oAnimWidth, a6, dir); + if ( object[v10]._oLight ) + { + CelDecodeHdrLightOnly( + v12, + v11, + (char *)object[v10]._oAnimData, + object[v10]._oAnimFrame, + object[v10]._oAnimWidth, + a6, + dir); + } + else + { + v17 = (char *)object[v10]._oAnimData; + if ( v17 ) + CelDrawHdrOnly(v12, v11, v17, object[v10]._oAnimFrame, object[v10]._oAnimWidth, a6, dir); + } + } + } + } +} +// 4B8CC1: using guessed type char pcursobj; + +void __fastcall scrollrt_draw_e_flag(char *buffer, int x, int y, int a4, int a5, int sx, int sy) +{ + int v7; // eax + char *v8; // esi + int v9; // ecx + int v10; // ebx + int v11; // edx + int v12; // eax + int v13; // eax + int v14; // ecx + int v15; // edi + int v16; // eax + unsigned short *v17; // esi + int v18; // eax + int v19; // eax + int v20; // eax + int v21; // eax + int v22; // [esp+Ch] [ebp-14h] + int xa; // [esp+10h] [ebp-10h] + unsigned char *a1; // [esp+14h] [ebp-Ch] + unsigned char *v25; // [esp+18h] [ebp-8h] + int i; // [esp+1Ch] [ebp-4h] + + xa = x; + v22 = level_piece_id; + v7 = 112 * x + y; + v8 = buffer; + v9 = dPiece[0][v7]; + v10 = cel_transparency_active; + v11 = dTransVal[0][v7]; + v12 = dung_map[0][v7]; + level_piece_id = v9; + v13 = (unsigned char)TransList[v12]; + v14 = (unsigned char)nTransTable[v9]; + v15 = light_table_index; + light_table_index = v11; + a1 = (unsigned char *)v8; + v25 = (unsigned char *)v8; + cel_transparency_active = v14 & v13; + v16 = gendung_get_dpiece_num_from_coord(xa, y); + arch_draw_type = 1; + v17 = (unsigned short *)((char *)dpiece_defs_map_1 + 32 * v16); + v18 = *v17; + level_cel_block = *v17; + if ( v18 ) + drawUpperScreen(a1); + v19 = v17[1]; + arch_draw_type = 2; + level_cel_block = v19; + if ( v19 ) + drawUpperScreen(a1 + 32); + arch_draw_type = 0; + for ( i = 1; i < (dword_5A5594 >> 1) - 1; ++i ) + { + v25 -= 24576; + if ( a4 >= i ) + { + v20 = v17[2 * i]; + level_cel_block = v17[2 * i]; + if ( v20 ) + drawUpperScreen(v25); + v21 = v17[2 * i + 1]; + level_cel_block = v17[2 * i + 1]; + if ( v21 ) + drawUpperScreen(v25 + 32); + } + } + scrollrt_draw_dungeon((char *)a1, xa, y, a4, a5, sx, sy, 0); + light_table_index = v15; + cel_transparency_active = v10; + level_piece_id = v22; +} +// 69BEF8: using guessed type int light_table_index; +// 69CF14: using guessed type int level_cel_block; +// 69CF20: using guessed type char arch_draw_type; +// 69CF94: using guessed type int cel_transparency_active; +// 69CF98: using guessed type int level_piece_id; + +void __fastcall DrawZoom(int x, int y) +{ + int v2; // edi + int v3; // ebx + int v4; // esi + int v5; // esi + int v6; // edi + int v7; // esi + int v8; // edi + int v9; // esi + int v10; // edi + _WORD *v11; // edi + char *v12; // esi + char *v13; // ebx + signed int v14; // edx + signed int v15; // ecx + short v16; // ax + int v17; // eax + signed int v18; // [esp+Ch] [ebp-10h] + signed int v19; // [esp+Ch] [ebp-10h] + signed int a5; // [esp+10h] [ebp-Ch] + int a5a; // [esp+10h] [ebp-Ch] + signed int a6; // [esp+14h] [ebp-8h] + signed int a6a; // [esp+14h] [ebp-8h] + int a6b; // [esp+14h] [ebp-8h] + int ya; // [esp+18h] [ebp-4h] + + v2 = ScrollInfo._sxoff + 64; + dword_5C2FF8 = 6; + dword_5C2FFC = 6; + v3 = x - 6; + ya = y - 1; + a5 = 6; + v4 = ScrollInfo._syoff + 143; + scr_pix_width = 384; + scr_pix_height = 192; + v18 = 3; + switch ( ScrollInfo._sdir ) + { + case DIR_SW: + goto LABEL_3; + case DIR_W: + a5 = 7; +LABEL_3: + v4 = ScrollInfo._syoff + 111; + v3 = x - 7; + ya = y - 2; + goto LABEL_9; + case DIR_NW: + goto LABEL_7; + case DIR_N: + v18 = 4; + goto LABEL_7; + case DIR_NE: + goto LABEL_9; + case DIR_E: + v18 = 4; + goto LABEL_6; + case DIR_SE: +LABEL_6: + v2 = ScrollInfo._sxoff; + v3 = x - 7; + ya = y; +LABEL_7: + a5 = 7; + break; + case DIR_OMNI: + v2 = ScrollInfo._sxoff; + v4 = ScrollInfo._syoff + 111; + a5 = 7; + v3 = x - 8; +LABEL_9: + v18 = 4; + break; + default: + break; + } + a6 = 0; + gpBufEnd = (unsigned char *)gpBuffer + screen_y_times_768[143]; + do + { + scrollrt_draw_upper(v3, ya++, v2, v4, a5, a6, 0); + v5 = v4 + 16; + v6 = v2 - 32; + scrollrt_draw_upper(v3++, ya, v6, v5, a5, a6, 1); + v2 = v6 + 32; + v4 = v5 + 16; + ++a6; + } + while ( a6 < 4 ); + gpBufEnd = (unsigned char *)gpBuffer + screen_y_times_768[320]; + if ( v18 > 0 ) + { + do + { + scrollrt_draw_lower(v3, ya++, v2, v4, a5, 0); + v7 = v4 + 16; + v8 = v2 - 32; + scrollrt_draw_lower(v3++, ya, v8, v7, a5, 1); + v2 = v8 + 32; + v4 = v7 + 16; + --v18; + } + while ( v18 ); + } + arch_draw_type = 0; + a6a = 0; + do + { + scrollrt_draw_lower_2(v3, ya++, v2, v4, a5, a6a, 0); + v9 = v4 + 16; + v10 = v2 - 32; + scrollrt_draw_lower_2(v3++, ya, v10, v9, a5, a6a, 1); + v2 = v10 + 32; + v4 = v9 + 16; + ++a6a; + } + while ( a6a < 4 ); + if ( chrflag || questlog ) + { + a6b = 392064; + goto LABEL_23; + } + if ( invflag || sbookflag ) + { + a6b = 391744; +LABEL_23: + a5a = 245168; + v19 = 160; + goto LABEL_24; + } + a5a = 245088; + a6b = 391744; + v19 = 320; +LABEL_24: + v11 = (_WORD *)((char *)gpBuffer + a6b); + v12 = (char *)gpBuffer + a5a; + v13 = &gpBuffer->row_unused_1[1].col_unused_1[a6b]; + v14 = 176; + do + { + v15 = v19; + do + { + _LOBYTE(v16) = *v12++; + _HIBYTE(v16) = v16; + *v11 = v16; + *(_WORD *)v13 = v16; + ++v11; + v13 += 2; + --v15; + } + while ( v15 ); + v12 += -v19 - 768; + v17 = 2 * (v19 + 768); + v13 -= v17; + v11 = (_WORD *)((char *)v11 - v17); + --v14; + } + while ( v14 ); +} +// 4B8968: using guessed type int sbookflag; +// 5C2FF8: using guessed type int dword_5C2FF8; +// 5C2FFC: using guessed type int dword_5C2FFC; +// 5C3000: using guessed type int scr_pix_width; +// 5C3004: using guessed type int scr_pix_height; +// 69BD04: using guessed type int questlog; +// 69CF0C: using guessed type int gpBufEnd; +// 69CF20: using guessed type char arch_draw_type; + +void __cdecl ClearScreenBuffer() +{ + int i; // edx + + lock_buf_priv(); + + for(i = 0; i < 480; i++) + memset(gpBuffer->row[i].pixels, 0, 640); + + unlock_buf_priv(); +} + +#ifdef _DEBUG +void __cdecl ScrollView() +{ + signed int v0; // esi + int v1; // edi + int v2; // edx + + if ( pcurs < 12 ) + { + v0 = 0; + if ( MouseX >= 20 ) + { + v2 = ViewX; + v1 = ViewY; + } + else + { + v1 = ViewY; + v2 = ViewX; + if ( ViewY >= dmaxy - 1 || dminx >= ViewX ) + { + if ( ViewY < dmaxy - 1 ) + { + v1 = ViewY + 1; + v0 = 1; + } + if ( dminx < ViewX ) + { + v2 = ViewX - 1; + v0 = 1; + } + } + else + { + v1 = ViewY + 1; + v2 = ViewX - 1; + v0 = 1; + } + } + if ( MouseX > 620 ) + { + if ( dmaxx - 1 > v2 ) + { + if ( dminy < v1 ) + { + --v1; + ++v2; + v0 = 1; + goto LABEL_19; + } + if ( dmaxx - 1 > v2 ) + { + ++v2; + v0 = 1; + } + } + if ( dminy < v1 ) + { + --v1; + v0 = 1; + } + } +LABEL_19: + if ( MouseY >= 20 ) + goto LABEL_28; + if ( dminy < v1 ) + { + if ( dminx < v2 ) + { + --v2; + --v1; + goto LABEL_27; + } + if ( dminy < v1 ) + { + --v1; + v0 = 1; + } + } + if ( dminx >= v2 ) + goto LABEL_28; + --v2; +LABEL_27: + v0 = 1; +LABEL_28: + ViewX = v2; + ViewY = v1; + if ( MouseY > 460 ) + { + if ( v1 >= dmaxy - 1 || dmaxx - 1 <= v2 ) + { + ViewY = v1; + if ( v1 < dmaxy - 1 ) + { + v0 = 1; + ViewY = v1 + 1; + } + ViewX = v2; + if ( dmaxx - 1 <= v2 ) + goto LABEL_37; + ViewX = v2 + 1; + } + else + { + ViewX = v2 + 1; + ViewY = v1 + 1; + } + v0 = 1; + } +LABEL_37: + if ( v0 ) + ScrollInfo._sdir = 0; + } +} + +void __cdecl EnableFrameCount() +{ + frameflag = frameflag == 0; + framestart = GetTickCount(); +} +#endif + +void __fastcall scrollrt_draw_game_screen(bool draw_cursor) +{ + int dwHgt; // edi + + if ( drawpanflag == 255 ) + { + drawpanflag = 0; + dwHgt = 480; + } + else + { + dwHgt = 0; + } + if ( draw_cursor ) + { + lock_buf_priv(); + scrollrt_draw_cursor_item(); + unlock_buf_priv(); + } + DrawMain(dwHgt, 0, 0, 0, 0, 0); + if ( draw_cursor ) + { + lock_buf_priv(); + scrollrt_draw_cursor_back_buffer(); + unlock_buf_priv(); + } +} +// 52571C: using guessed type int drawpanflag; + +void __cdecl scrollrt_draw_cursor_back_buffer() +{ + int v0; // edx + int v1; // eax + char *v2; // edi + char *v3; // esi + int v4; // ecx + int v5; // ebx + + v0 = sgdwCursWdt; + if ( sgdwCursWdt ) + { + v1 = sgdwCursY; + v2 = sgSaveBack; + v3 = &gpBuffer->row[sgdwCursY].pixels[sgdwCursX]; + v4 = sgdwCursHgt; + if ( sgdwCursHgt ) + { + v5 = sgdwCursHgt; + do + { + memcpy(v3, v2, v0); + v0 = sgdwCursWdt; + v2 += sgdwCursWdt; + v3 += 768; + --v5; + } + while ( v5 ); + v1 = sgdwCursY; + v4 = sgdwCursHgt; + } + sgdwCursWdt = 0; + sgdwCursXOld = sgdwCursX; + sgdwCursYOld = v1; + sgdwCursWdtOld = v0; + sgdwCursHgtOld = v4; + } +} + +void __cdecl scrollrt_draw_cursor_item() +{ + int v0; // ebp + int v1; // edx + int v2; // edi + int v3; // esi + unsigned int v4; // eax + unsigned int v5; // eax + int v6; // eax + char *v7; // ebx + int v8; // ebp + int v9; // edi + int v10; // esi + signed int v11; // ebx + int v12; // edi + int v13; // edx + char *v14; // [esp+10h] [ebp-4h] + + if ( pcurs > 0 ) + { + v0 = cursW; + if ( cursW ) + { + v1 = cursH; + if ( cursH ) + { + v2 = MouseX - 1; + if ( MouseX - 1 >= 0 ) + { + if ( v2 > 639 ) + return; + } + else + { + v2 = 0; + } + v3 = MouseY - 1; + if ( MouseY - 1 >= 0 ) + { + if ( v3 > 479 ) + return; + } + else + { + v3 = 0; + } + v4 = v2 + cursW + 1; + if ( v4 > 0x27F ) + v4 = 639; + _LOBYTE(v4) = v4 | 3; + sgdwCursY = v3; + sgdwCursX = v2 & 0xFFFFFFFC; + sgdwCursWdt = v4 - (v2 & 0xFFFFFFFC) + 1; + v5 = cursH + v3 + 1; + if ( v5 > 0x1DF ) + v5 = 479; + v14 = sgSaveBack; + v6 = 1 - v3 + v5; + sgdwCursHgt = v6; + v7 = &gpBuffer->row[v3].pixels[v2 & 0xFFFFFFFC]; + if ( v6 ) + { + v8 = v6; + do + { + memcpy(v14, v7, sgdwCursWdt); + v14 += sgdwCursWdt; + v7 += 768; + --v8; + } + while ( v8 ); + v0 = cursW; + v1 = cursH; + } + v9 = v2 + 1; + v10 = v3 + 1; + gpBufEnd = (unsigned char *)gpBuffer + screen_y_times_768[640] - v0 - 2; + if ( pcurs < 12 ) + { + Cel2DrawHdrOnly(v9 + 64, v1 + v10 + 159, (char *)pCursCels, pcurs, v0, 0, 8); + } + else + { + v11 = 197; + if ( plr[myplr].HoldItem._iMagical ) + v11 = 181; + if ( !plr[myplr].HoldItem._iStatFlag ) + v11 = 229; + v12 = v9 + 64; + CelDrawHdrClrHL(v11, v12, v1 + v10 + 159, (char *)pCursCels, pcurs, v0, 0, 8); + v13 = cursH + v10 + 159; + if ( v11 == 229 ) + Cel2DrawHdrLightRed(v12, v13, (char *)pCursCels, pcurs, cursW, 0, 8, 1); + else + Cel2DrawHdrOnly(v12, v13, (char *)pCursCels, pcurs, cursW, 0, 8); + } + } + } + } +} +// 4B8C9C: using guessed type int cursH; +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall DrawMain(int dwHgt, int draw_desc, int draw_hp, int draw_mana, int draw_sbar, int draw_btn) +{ + signed int v6; // ebp + DWORD v7; // ebx + int v8; // esi + int v9; // eax + signed int a4; // [esp+1Ch] [ebp-8h] + + a4 = dwHgt; + if ( gbActive && lpDDSPrimary ) + { + if ( lpDDSPrimary->IsLost() == DDERR_SURFACELOST ) + { + if ( lpDDSPrimary->Restore() ) + return; + ResetPal(); + a4 = 480; + } + if ( !lpDDSBackBuf ) + { + v6 = 1; +LABEL_8: + v7 = GetTickCount(); + while ( 1 ) + { + DDS_desc.dwSize = 108; + v8 = lpDDSPrimary->Lock(NULL, &DDS_desc, DDLOCK_WRITEONLY|DDLOCK_WAIT, NULL); + if ( !v8 ) + break; + if ( v7 - GetTickCount() > 5000 ) + goto LABEL_17; + Sleep(1u); + if ( v8 == DDERR_SURFACELOST ) + return; + if ( v8 != DDERR_WASSTILLDRAWING && v8 != DDERR_SURFACEBUSY ) + { + if ( v6 && v8 == E_FAIL ) + { + v6 = 0; + dx_reinit(); + a4 = 480; + goto LABEL_8; + } +LABEL_17: + if ( v8 != DDERR_SURFACELOST && v8 != DDERR_WASSTILLDRAWING && v8 != DDERR_SURFACEBUSY ) + { + DDErrMsg(v8, 3707, "C:\\Src\\Diablo\\Source\\SCROLLRT.CPP"); + break; + } + return; + } + } + } + if ( a4 > 0 ) + DoBlitScreen(0, 0, 640, a4); + if ( a4 < 480 ) + { + if ( draw_sbar ) + DoBlitScreen(204, 357, 232, 28); + if ( draw_desc ) + DoBlitScreen(176, 398, 288, 60); + if ( draw_mana ) + { + DoBlitScreen(460, 352, 88, 72); + DoBlitScreen(564, 416, 56, 56); + } + if ( draw_hp ) + DoBlitScreen(96, 352, 88, 72); + if ( draw_btn ) + { + DoBlitScreen(8, 357, 72, 119); + DoBlitScreen(556, 357, 72, 48); + if ( (unsigned char)gbMaxPlayers > 1u ) + { + DoBlitScreen(84, 443, 36, 32); + DoBlitScreen(524, 443, 36, 32); + } + } + if ( sgdwCursWdtOld ) + DoBlitScreen(sgdwCursXOld, sgdwCursYOld, sgdwCursWdtOld, sgdwCursHgtOld); + if ( sgdwCursWdt ) + DoBlitScreen(sgdwCursX, sgdwCursY, sgdwCursWdt, sgdwCursHgt); + } + if ( !lpDDSBackBuf ) + { + v9 = lpDDSPrimary->Unlock(NULL); + if ( v9 != DDERR_SURFACELOST ) + { + if ( v9 ) + DDErrMsg(v9, 3779, "C:\\Src\\Diablo\\Source\\SCROLLRT.CPP"); + } + } +#ifdef _DEBUG + DrawFPS(); +#endif + } +} +// 634980: using guessed type int gbActive; +// 679660: using guessed type char gbMaxPlayers; + +#ifdef _DEBUG +void __cdecl DrawFPS() +{ + DWORD v0; // eax + int v1; // esi + char String[12]; // [esp+8h] [ebp-10h] + HDC hdc; // [esp+14h] [ebp-4h] + + if ( frameflag && gbActive ) + { + ++frameend; + v0 = GetTickCount(); + v1 = v0 - framestart; + if ( v0 - framestart >= 1000 ) + { + framestart = v0; + framerate = 1000 * frameend / v1; + frameend = 0; + } + if ( framerate > 99 ) + framerate = 99; + wsprintf(String, "%2d", framerate); + if ( !lpDDSPrimary->GetDC(&hdc) ) + { + TextOut(hdc, 0, 400, String, strlen(String)); + lpDDSPrimary->ReleaseDC(hdc); + } + } +} +#endif + +void __fastcall DoBlitScreen(int dwX, int dwY, int dwWdt, int dwHgt) +{ + int v4; // esi + int v5; // edi + int v6; // ecx + char *v7; // esi + char *v8; // edi + int v9; // edx + RECT Rect; // [esp+Ch] [ebp-20h] + int v14; // [esp+1Ch] [ebp-10h] + LONG v15; // [esp+20h] [ebp-Ch] + int v16; // [esp+24h] [ebp-8h] + LONG v17; // [esp+28h] [ebp-4h] + HRESULT error_code; // [esp+34h] [ebp+8h] + int error_codea; // [esp+34h] [ebp+8h] + int a4; // [esp+38h] [ebp+Ch] + + v4 = dwY; + v5 = dwX; + if ( lpDDSBackBuf ) + { + Rect.left = dwX + 64; + Rect.right = dwX + 64 + dwWdt - 1; + Rect.top = dwY + 160; + Rect.bottom = dwY + 160 + dwHgt - 1; + a4 = GetTickCount(); + while ( 1 ) + { + error_code = lpDDSPrimary->BltFast(v5, v4, lpDDSBackBuf, &Rect, DDBLTFAST_WAIT); + if ( !error_code ) + break; + if ( a4 - GetTickCount() <= 5000 ) + { + Sleep(1u); + if ( error_code == DDERR_SURFACELOST ) + return; + if ( error_code == DDERR_WASSTILLDRAWING || error_code == DDERR_SURFACEBUSY ) + continue; + } + if ( error_code != DDERR_SURFACELOST && error_code != DDERR_WASSTILLDRAWING && error_code != DDERR_SURFACEBUSY ) + DDErrMsg(error_code, 3596, "C:\\Src\\Diablo\\Source\\SCROLLRT.CPP"); + return; + } + } + else + { + v14 = 768 * dwY + dwX + 0x1E040; + v17 = DDS_desc.lPitch - dwWdt; + v15 = dwX + dwY * DDS_desc.lPitch; + v6 = 768 - dwWdt; + error_codea = (unsigned int)dwWdt >> 2; + v16 = v6; + lock_buf_priv(); + v7 = (char *)gpBuffer + v14; + v8 = (char *)DDS_desc.lpSurface + v15; + v9 = dwHgt; + do + { + qmemcpy(v8, v7, 4 * error_codea); + v7 += 4 * error_codea + v16; + v8 += 4 * error_codea + v17; + --v9; + } + while ( v9 ); + unlock_buf_priv(); + } +} + +void __cdecl DrawAndBlit() +{ + bool ddsdesc; // ebp + bool ctrlPan; // esi + int dwHgt; // edi + + if ( gbRunGame ) + { + if ( drawpanflag == 255 ) + { + drawhpflag = 1; + drawmanaflag = 1; + drawbtnflag = 1; + drawsbarflag = 1; + ddsdesc = 0; + ctrlPan = 1; + dwHgt = 480; + } + else + { + if ( drawpanflag != 1 ) + return; + ddsdesc = 1; + ctrlPan = 0; + dwHgt = 352; + } + drawpanflag = 0; + lock_buf_priv(); + if ( leveltype ) + DrawView(ViewX, ViewY); + else + T_DrawView(ViewX, ViewY); + if ( ctrlPan ) + ClearCtrlPan(); + if ( drawhpflag ) + UpdateLifeFlask(); + if ( drawmanaflag ) + UpdateManaFlask(); + if ( drawbtnflag ) + DrawCtrlPan(); + if ( drawsbarflag ) + DrawInvBelt(); + if ( talkflag ) + { + DrawTalkPan(); + dwHgt = 480; + } + scrollrt_draw_cursor_item(); + unlock_buf_priv(); + DrawMain(dwHgt, ddsdesc, drawhpflag, drawmanaflag, drawsbarflag, drawbtnflag); + lock_buf_priv(); + scrollrt_draw_cursor_back_buffer(); + unlock_buf_priv(); + drawhpflag = 0; + drawmanaflag = 0; + drawbtnflag = 0; + drawsbarflag = 0; + } +} +// 4B8960: using guessed type int talkflag; +// 525650: using guessed type int gbRunGame; +// 52571C: using guessed type int drawpanflag; +// 5BB1ED: using guessed type char leveltype; diff --git a/Source/scrollrt.h b/Source/scrollrt.h new file mode 100644 index 000000000..8648e7849 --- /dev/null +++ b/Source/scrollrt.h @@ -0,0 +1,74 @@ +//HEADER_GOES_HERE +#ifndef __SCROLLRT_H__ +#define __SCROLLRT_H__ + +extern int light_table_index; // weak +extern int screen_y_times_768[1024]; +extern int scrollrt_cpp_init_value; // weak +extern unsigned int sgdwCursWdtOld; // idb +extern int sgdwCursX; // idb +extern int sgdwCursY; // idb +extern unsigned char *gpBufEnd; // weak +extern int sgdwCursHgt; +extern int level_cel_block; // weak +extern int sgdwCursXOld; // idb +extern int sgdwCursYOld; // idb +extern char arch_draw_type; // weak +extern DDSURFACEDESC DDS_desc; +extern int cel_transparency_active; // weak +extern int level_piece_id; // weak +extern int sgdwCursWdt; +extern int (__fastcall *DrawPlrProc)(int player_num, int x, int y, int screen_x, int screen_y, void *cl2_buf, int frame, int frame_width, int a9, int a10); +extern char sgSaveBack[8192]; +extern int draw_monster_num; // weak +extern int sgdwCursHgtOld; // idb + +void __cdecl scrollrt_cpp_init(); +void __cdecl ClearCursor(); +void __fastcall DrawMissile(int x, int y, int sx, int sy, int a5, int a6, int del_flag); +void __fastcall DrawClippedMissile(int x, int y, int sx, int sy, int a5, int a6, int a7); +void __fastcall DrawDeadPlayer(int x, int y, int sx, int sy, int a5, int a6, bool clipped); +void __fastcall DrawPlayer(int pnum, int x, int y, int px, int py, unsigned char *animdata, int animframe, int animwidth, int a9, int a10); +void __fastcall DrawClippedPlayer(int pnum, int x, int y, int px, int py, unsigned char *animdata, int animframe, int animwidth, int a9, int a10); +void __fastcall DrawView(int StartX, int StartY); +void __fastcall DrawGame(int x, int y); +void __fastcall scrollrt_draw_lower(int x, int y, int sx, int sy, int a5, int some_flag); +void __fastcall scrollrt_draw_clipped_dungeon(char *a1, int sx, int sy, int a4, int a5, int a6); +void __fastcall DrawClippedMonster(int x, int y, int a3, int a4, int mon_id, int a6, int a7); +void __fastcall DrawClippedObject(int x, int y, int a3, int a4, int pre_flag, int a6, int dir); +void __fastcall scrollrt_draw_clipped_e_flag(char *buffer, int x, int y, int a4, int a5); +void __fastcall scrollrt_draw_lower_2(int x, int y, int sx, int sy, int a5, int a6, int some_flag); +void __fastcall scrollrt_draw_clipped_dungeon_2(char *buffer, int x, int y, int a4, int a5, int sx, int sy, int me_flag); +void __fastcall scrollrt_draw_clipped_e_flag_2(char *buffer, int x, int y, int a4, signed int a5, int sx, int sy); +void __fastcall scrollrt_draw_upper(int x, int y, int sx, int sy, int a5, int a6, int some_flag); +void __fastcall scrollrt_draw_dungeon(char *buffer, int x, int y, int a4, int a5, int sx, int sy, int me_flag); +void __fastcall DrawMonster(int x, int y, int a3, int a4, int mon_id, int a6, int a7); +void __fastcall DrawObject(int x, int y, int a3, int a4, int pre_flag, int a6, int dir); +void __fastcall scrollrt_draw_e_flag(char *buffer, int x, int y, int a4, int a5, int sx, int sy); +void __fastcall DrawZoom(int x, int y); +void __cdecl ClearScreenBuffer(); +#ifdef _DEBUG +void __cdecl ScrollView(); +void __cdecl EnableFrameCount(); +#endif +void __fastcall scrollrt_draw_game_screen(bool draw_cursor); +void __cdecl scrollrt_draw_cursor_back_buffer(); +void __cdecl scrollrt_draw_cursor_item(); +void __fastcall DrawMain(int dwHgt, int draw_desc, int draw_hp, int draw_mana, int draw_sbar, int draw_btn); +#ifdef _DEBUG +void __cdecl DrawFPS(); +#endif +void __fastcall DoBlitScreen(int dwX, int dwY, int dwWdt, int dwHgt); +void __cdecl DrawAndBlit(); + +/* rdata */ + +extern const int scrollrt_inf; // weak + +/* data */ + +/* used in 1.00 debug */ +extern char *szMonModeAssert[18]; +extern char *szPlrModeAssert[12]; + +#endif /* __SCROLLRT_H__ */ diff --git a/Source/setmaps.cpp b/Source/setmaps.cpp new file mode 100644 index 000000000..1cacd26a0 --- /dev/null +++ b/Source/setmaps.cpp @@ -0,0 +1,233 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +unsigned char SkelKingTrans1[8] = +{ + 19, 47, 26, 55, + 26, 49, 30, 53 +}; + +unsigned char SkelKingTrans2[8] = +{ + 33, 19, 47, 29, + 37, 29, 43, 39 +}; + +unsigned char SkelKingTrans3[20] = +{ + 27, 53, 35, 61, + 27, 35, 34, 42, + 45, 35, 53, 43, + 45, 53, 53, 61, + 31, 39, 49, 57 +}; + +unsigned char SkelKingTrans4[28] = +{ + 49, 45, 58, 51, + 57, 31, 62, 37, + 63, 31, 69, 40, + 59, 41, 73, 55, + 63, 55, 69, 65, + 73, 45, 78, 51, + 79, 43, 89, 53 +}; + +unsigned char SkelChamTrans1[20] = +{ + 43, 19, 50, 26, + 51, 19, 59, 26, + 35, 27, 42, 34, + 43, 27, 49, 34, + 50, 27, 59, 34 +}; + +unsigned char SkelChamTrans2[8] = +{ + 19, 31, 34, 47, + 34, 35, 42, 42 +}; + +unsigned char SkelChamTrans3[36] = +{ + 43, 35, 50, 42, + 51, 35, 62, 42, + 63, 31, 66, 46, + 67, 31, 78, 34, + 67, 35, 78, 42, + 67, 43, 78, 46, + 35, 43, 42, 51, + 43, 43, 49, 51, + 50, 43, 59, 51 +}; + +char *quest_level_names[] = +{ + &empty_string, + "Skeleton King's Lair", + "Bone Chamber", + "Maze", + "Poisoned Water Supply", + "Archbishop Lazarus' Lair" +}; + +int __fastcall ObjIndex(int x, int y) +{ + int i; // edi + int oi; // esi + + i = 0; + + if ( nobjects > 0 ) + { + while ( 1 ) + { + oi = objectactive[i]; + if ( object[oi]._ox == x && object[oi]._oy == y ) + return oi; + if ( ++i >= nobjects ) + break; + } + } + TermMsg("ObjIndex: Active object not found at (%d,%d)", x, y); + return -1; +} + +void __cdecl AddSKingObjs() +{ + SetObjMapRange(ObjIndex(64, 34), 20, 7, 23, 10, 1); + SetObjMapRange(ObjIndex(64, 59), 20, 14, 21, 16, 2); + SetObjMapRange(ObjIndex(27, 37), 8, 1, 15, 11, 3); + SetObjMapRange(ObjIndex(46, 35), 8, 1, 15, 11, 3); + SetObjMapRange(ObjIndex(49, 53), 8, 1, 15, 11, 3); + SetObjMapRange(ObjIndex(27, 53), 8, 1, 15, 11, 3); +} + +void __cdecl AddSChamObjs() +{ + SetObjMapRange(ObjIndex(37, 30), 17, 0, 21, 5, 1); + SetObjMapRange(ObjIndex(37, 46), 13, 0, 16, 5, 2); +} + +void __cdecl AddVileObjs() +{ + SetObjMapRange(ObjIndex(26, 45), 1, 1, 9, 10, 1); + SetObjMapRange(ObjIndex(45, 46), 11, 1, 20, 10, 2); + SetObjMapRange(ObjIndex(35, 36), 7, 11, 13, 18, 3); +} + +void __fastcall DRLG_SetMapTrans(char *sFileName) +{ + unsigned char *pLevelMap; // ecx + int v2; // ebx + int v3; // edi + int v4; // eax + int v5; // edi + int v6; // eax + int v7; // ebx + char *v8; // esi + char *v9; // eax + int v10; // [esp+Ch] [ebp-8h] + int v11; // [esp+10h] [ebp-4h] + + pLevelMap = LoadFileInMem(sFileName, 0); + v11 = 0; + v2 = *pLevelMap; + v3 = pLevelMap[2]; + v4 = v3; + v5 = 2 * v3; + v6 = v2 * v4; + v7 = 2 * v2; + v8 = (char *)&pLevelMap[6 * v7 * v5 + 4 + 2 * v6]; + if ( v5 > 0 ) + { + do + { + if ( v7 > 0 ) + { + v10 = v7; + v9 = &dung_map[16][v11 + 16]; + do + { + *v9 = *v8; + v8 += 2; + v9 += 112; + --v10; + } + while ( v10 ); + } + ++v11; + } + while ( v11 < v5 ); + } + mem_free_dbg(pLevelMap); +} + +void __cdecl LoadSetMap() +{ + switch ( setlvlnum ) + { + case SL_SKELKING: + if ( quests[12]._qactive == 1 ) + { + quests[12]._qactive = 2; + quests[12]._qvar1 = 1; + } + LoadPreL1Dungeon("Levels\\L1Data\\SklKng1.DUN", 83, 45); + LoadL1Dungeon("Levels\\L1Data\\SklKng2.DUN", 83, 45); + LoadPalette("Levels\\L1Data\\L1_2.pal"); + DRLG_AreaTrans(2, SkelKingTrans1); + DRLG_ListTrans(2, SkelKingTrans2); + DRLG_AreaTrans(5, SkelKingTrans3); + DRLG_ListTrans(7, SkelKingTrans4); + AddL1Objs(0, 0, 112, 112); + AddSKingObjs(); + InitSKingTriggers(); + break; + case SL_BONECHAMB: + LoadPreL2Dungeon("Levels\\L2Data\\Bonecha2.DUN", 69, 39); + LoadL2Dungeon("Levels\\L2Data\\Bonecha1.DUN", 69, 39); + LoadPalette("Levels\\L2Data\\L2_2.pal"); + DRLG_ListTrans(5, SkelChamTrans1); + DRLG_AreaTrans(2, SkelChamTrans2); + DRLG_ListTrans(9, SkelChamTrans3); + AddL2Objs(0, 0, 112, 112); + AddSChamObjs(); + InitSChambTriggers(); + break; + case SL_MAZE: + LoadPreL1Dungeon("Levels\\L1Data\\Lv1MazeA.DUN", 20, 50); + LoadL1Dungeon("Levels\\L1Data\\Lv1MazeB.DUN", 20, 50); + LoadPalette("Levels\\L1Data\\L1_5.pal"); + AddL1Objs(0, 0, 112, 112); + DRLG_SetMapTrans("Levels\\L1Data\\Lv1MazeA.DUN"); + break; + case SL_POISONWATER: + if ( quests[13]._qactive == 1 ) + quests[13]._qactive = 2; + LoadPreL3Dungeon("Levels\\L3Data\\Foulwatr.DUN", 19, 50); + LoadL3Dungeon("Levels\\L3Data\\Foulwatr.DUN", 20, 50); + LoadPalette("Levels\\L3Data\\L3pfoul.pal"); + InitPWaterTriggers(); + break; + case SL_VILEBETRAYER: + if ( quests[15]._qactive == 3 ) + { + quests[15]._qvar2 = 4; + } + else if ( quests[15]._qactive == 2 ) + { + quests[15]._qvar2 = 3; + } + LoadPreL1Dungeon("Levels\\L1Data\\Vile1.DUN", 35, 36); + LoadL1Dungeon("Levels\\L1Data\\Vile2.DUN", 35, 36); + LoadPalette("Levels\\L1Data\\L1_2.pal"); + AddL1Objs(0, 0, 112, 112); + AddVileObjs(); + DRLG_SetMapTrans("Levels\\L1Data\\Vile1.DUN"); + InitNoTriggers(); + break; + } +} +// 5CCB10: using guessed type char setlvlnum; diff --git a/Source/setmaps.h b/Source/setmaps.h new file mode 100644 index 000000000..4feebe380 --- /dev/null +++ b/Source/setmaps.h @@ -0,0 +1,22 @@ +//HEADER_GOES_HERE +#ifndef __SETMAPS_H__ +#define __SETMAPS_H__ + +int __fastcall ObjIndex(int x, int y); +void __cdecl AddSKingObjs(); +void __cdecl AddSChamObjs(); +void __cdecl AddVileObjs(); +void __fastcall DRLG_SetMapTrans(char *sFileName); +void __cdecl LoadSetMap(); + +/* rdata */ +extern unsigned char SkelKingTrans1[8]; +extern unsigned char SkelKingTrans2[8]; +extern unsigned char SkelKingTrans3[20]; +extern unsigned char SkelKingTrans4[28]; +extern unsigned char SkelChamTrans1[20]; +extern unsigned char SkelChamTrans2[8]; +extern unsigned char SkelChamTrans3[36]; +extern char *quest_level_names[]; + +#endif /* __SETMAPS_H__ */ diff --git a/Source/sha.cpp b/Source/sha.cpp new file mode 100644 index 000000000..fe4c2adb0 --- /dev/null +++ b/Source/sha.cpp @@ -0,0 +1,154 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +SHA1Context sgSHA1[3]; +#endif + +void __cdecl SHA1Clear() +{ + memset(sgSHA1, 0, 0x114u); +} + +void __fastcall SHA1Result(int n, char Message_Digest[SHA1HashSize]) +{ + char *v2; // eax + SHA1Context *v3; // ecx + signed int i; // edx + int v5; // esi + + v2 = Message_Digest; + if ( Message_Digest ) + { + v3 = &sgSHA1[n]; + i = 5; + do + { + v5 = v3->state[0]; + v3 = (SHA1Context *)((char *)v3 + 4); + *(_DWORD *)v2 = v5; + v2 += 4; + --i; + } + while ( i ); + } +} + +void __fastcall SHA1Calculate(int n, const char *data, char Message_Digest[SHA1HashSize]) +{ + int v3; // esi + + v3 = n; + SHA1Input(&sgSHA1[n], data, 64); + if ( Message_Digest ) + SHA1Result(v3, (char *)Message_Digest); +} + +void __fastcall SHA1Input(SHA1Context *context, const char *message_array, int len) +{ + SHA1Context *v3; // esi + const char *v4; // ebx + int v5; // ecx + int v6; // edx + unsigned int v7; // ebp + + v3 = context; + v4 = message_array; + v5 = context->count[0]; + v6 = v5 + 8 * len; + if ( v6 < v5 ) + ++v3->count[1]; + v3->count[0] = v6; + v3->count[1] += len >> 29; + if ( len >= 64 ) + { + v7 = (unsigned int)len >> 6; + do + { + memcpy(v3->buffer, v4, 0x40u); + SHA1ProcessMessageBlock(v3); + v4 += 64; + --v7; + } + while ( v7 ); + } +} + +void __fastcall SHA1ProcessMessageBlock(SHA1Context *context) +{ + int i; // [esp+158h] [ebp-4h] + int temp; // esi + int W[80]; // [esp+Ch] [ebp-150h] + int A, B, C, D, E; // [esp+150h] [ebp-Ch] + + qmemcpy(W, context->buffer, 0x40u); + + for(i = 0; i < 64; i++) + { + W[i+16] = W[i] ^ W[i+2] ^ W[i+8] ^ W[i+13]; + } + + A = context->state[0]; + B = context->state[1]; + C = context->state[2]; + D = context->state[3]; + E = context->state[4]; + + for(i = 0; i < 20; i++) + { + temp = SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[i] + 0x5A827999; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(i = 20; i < 40; i++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(i = 40; i < 60; i++) + { + temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(i = 60; i < 80; i++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->state[0] += A; + context->state[1] += B; + context->state[2] += C; + context->state[3] += D; + context->state[4] += E; +} + +void __fastcall SHA1Reset(int n) +{ + sgSHA1[n].count[0] = 0; + sgSHA1[n].count[1] = 0; + sgSHA1[n].state[0] = 0x67452301; + sgSHA1[n].state[1] = 0xEFCDAB89; + sgSHA1[n].state[2] = 0x98BADCFE; + sgSHA1[n].state[3] = 0x10325476; + sgSHA1[n].state[4] = 0xC3D2E1F0; +} diff --git a/Source/sha.h b/Source/sha.h new file mode 100644 index 000000000..06c237584 --- /dev/null +++ b/Source/sha.h @@ -0,0 +1,22 @@ +//HEADER_GOES_HERE +#ifndef __SHA_H__ +#define __SHA_H__ + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) +#define SHA1HashSize 20 + +//sha +extern SHA1Context sgSHA1[3]; + +void __cdecl SHA1Clear(); +void __fastcall SHA1Result(int n, char Message_Digest[SHA1HashSize]); +void __fastcall SHA1Calculate(int n, const char *data, char Message_Digest[SHA1HashSize]); +void __fastcall SHA1Input(SHA1Context *context, const char *message_array, int len); +void __fastcall SHA1ProcessMessageBlock(SHA1Context *context); +void __fastcall SHA1Reset(int n); + +#endif /* __SHA_H__ */ diff --git a/Source/sound.cpp b/Source/sound.cpp new file mode 100644 index 000000000..18eafd452 --- /dev/null +++ b/Source/sound.cpp @@ -0,0 +1,508 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +float sound_cpp_init_value; + +#ifndef NO_GLOBALS +IDirectSoundBuffer *DSBs[8]; +IDirectSound *sglpDS; +char gbSndInited; +int sglMusicVolume; +int sglSoundVolume; +HMODULE hDsound_dll; // idb +void *sgpMusicTrack; +IDirectSoundBuffer *sglpDSB; +#endif + +const int sound_inf = 0x7F800000; // weak + +/* data */ + +UCHAR gbMusicOn = 1; // weak +UCHAR gbSoundOn = 1; // weak +char gbDupSounds = 1; // weak +int sgnMusicTrack = 6; +char *sgszMusicTracks[6] = +{ + "Music\\DTowne.wav", + "Music\\DLvlA.wav", + "Music\\DLvlB.wav", + "Music\\DLvlC.wav", + "Music\\DLvlD.wav", + "Music\\Dintro.wav" +}; +char unk_volume[4][2] = +{ + { 15, -16 }, + { 15, -16 }, + { 30, -31 }, + { 30, -31 } +}; + +struct sound_cpp_init +{ + sound_cpp_init() + { + sound_cpp_init_value = sound_inf; + } +} _sound_cpp_init; +// 47F24C: using guessed type int sound_inf; + +void __fastcall snd_update(bool bStopAll) +{ + BOOL v1; // edi + unsigned int v2; // esi + IDirectSoundBuffer *v3; // eax + unsigned long v4; // [esp+8h] [ebp-4h] + + v1 = bStopAll; + v2 = 0; + do + { + v3 = DSBs[v2]; + if ( v3 && (v1 || v3->GetStatus(&v4) || v4 != DSBSTATUS_PLAYING) ) // FIX_ME: double check + { + DSBs[v2]->Stop(); + DSBs[v2]->Release(); + DSBs[v2] = 0; + } + ++v2; + } + while ( v2 < 8 ); +} + +void __fastcall snd_stop_snd(TSnd *pSnd) +{ + IDirectSoundBuffer *v1; // eax + + if ( pSnd ) + { + v1 = pSnd->DSB; + if ( v1 ) + v1->Stop(); + } +} + +bool __fastcall snd_playing(TSnd *pSnd) +{ + IDirectSoundBuffer *v1; // eax + bool result; // al + unsigned long v3; // [esp+0h] [ebp-4h] + + v3 = (unsigned long)pSnd; + if ( pSnd + && (v1 = pSnd->DSB) != 0 + && !v1->GetStatus(&v3) ) + { + result = v3 == DSBSTATUS_PLAYING; + } + else + { + result = 0; + } + return result; +} + +void __fastcall snd_play_snd(TSnd *pSnd, int lVolume, int lPan) +{ + + + TSnd *v3; // edi + int v4; // ebp + IDirectSoundBuffer *v5; // esi + //int v6; // eax + int v7; // ebp + int v8; // eax + //int v9; // eax + DWORD v10; // [esp+30h] [ebp-4h] + + v3 = pSnd; + v4 = lVolume; + if ( pSnd ) + { + if ( gbSoundOn ) + { + v5 = pSnd->DSB; + if ( v5 ) + { + v10 = GetTickCount(); + if ( v10 - v3->start_tc >= 0x50 ) + { + //_LOBYTE(v6) = snd_playing(v3); + if ( !snd_playing(v3) || (v5 = sound_dup_channel(v3->DSB)) != 0 ) + { + v7 = sglSoundVolume + v4; + if ( v7 >= -1600 ) + { + if ( v7 > 0 ) + v7 = 0; + } + else + { + v7 = -1600; + } + v5->SetVolume(v7); + v5->SetPan(lPan); + v8 = v5->Play(0, 0, 0); + if ( v8 == DSERR_BUFFERLOST ) + { + //_LOBYTE(v9) = sound_file_reload(v3, v5); + if ( sound_file_reload(v3, v5) ) + v5->Play(0, 0, 0); + } + else if ( v8 ) + { + DSErrMsg(v8, 261, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); + } + v3->start_tc = v10; + } + } + else + { + GetTickCount(); + } + } + } + } +} +// 4A22D5: using guessed type char gbSoundOn; + +IDirectSoundBuffer *__fastcall sound_dup_channel(IDirectSoundBuffer *DSB) +{ + IDirectSoundBuffer *result; // eax + IDirectSoundBuffer **v2; // esi + + result = 0; + if ( gbDupSounds ) + { + while ( DSBs[(_DWORD)result] ) + { + result = (IDirectSoundBuffer *)((char *)result + 1); // result++ + if ( (unsigned int)result >= 8 ) + return 0; + } + v2 = &DSBs[(_DWORD)result]; + if ( sglpDS->DuplicateSoundBuffer(DSB, &DSBs[(_DWORD)result]) ) + { + return 0; + } + result = *v2; + } + return result; +} +// 4A22D6: using guessed type char gbDupSounds; + +bool __fastcall sound_file_reload(TSnd *sound_file, IDirectSoundBuffer *DSB) +{ + IDirectSoundBuffer *v2; // edi + TSnd *v3; // esi + char *v5; // ecx + void *aptr2; // [esp+8h] [ebp-18h] + unsigned long asize2; // [esp+Ch] [ebp-14h] + bool v8; // [esp+10h] [ebp-10h] + void *aptr1; // [esp+14h] [ebp-Ch] + unsigned long asize1; // [esp+18h] [ebp-8h] + void *a1; // [esp+1Ch] [ebp-4h] + + v2 = DSB; + v3 = sound_file; + if ( DSB->Restore() ) + return 0; + v5 = v3->sound_path; + v8 = 0; + WOpenFile(v5, &a1, 0); + WSetFilePointer(a1, v3->offset, 0, 0); + if ( !v2->Lock(0, v3->len, &aptr1, &asize1, &aptr2, &asize2, 0) ) + { + WReadFile(a1, (char *)aptr1, asize1); + if ( !v2->Unlock(aptr1, asize1, aptr2, asize2) ) + v8 = 1; + } + WCloseFile(a1); + return v8; +} + +TSnd *__fastcall sound_file_load(char *path) +{ +// int v1; // esi + char *v2; // edi + TSnd *v4; // esi + int v5; // eax + int v6; // eax +// int v7; // [esp-4h] [ebp-24h] + void *aptr2; // [esp+8h] [ebp-18h] + unsigned long asize2; // [esp+Ch] [ebp-14h] + void *a1; // [esp+10h] [ebp-10h] + void *ptr; // [esp+14h] [ebp-Ch] + void *aptr1; // [esp+18h] [ebp-8h] + unsigned long asize1; // [esp+1Ch] [ebp-4h] + + v2 = path; + if ( !sglpDS ) + return 0; +// v7 = v1; + WOpenFile(path, &a1, 0); + v4 = (TSnd *)DiabloAllocPtr(40); + memset(v4, 0, 0x28u); + v4->sound_path = v2; + v4->start_tc = GetTickCount() - 81; + ptr = LoadWaveFile(a1, &v4->fmt, &v4->len); + if ( !ptr ) + TermMsg("Invalid sound format on file %s", v4->sound_path); + sound_CreateSoundBuffer(v4); + v5 = v4->DSB->Lock(0, v4->len, &aptr1, &asize1, &aptr2, &asize2, 0); //v7); + if ( v5 ) + DSErrMsg(v5, 318, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); + memcpy(aptr1, (char *)ptr + v4->offset, asize1); + v6 = v4->DSB->Unlock(aptr1, asize1, aptr2, asize2); + if ( v6 ) + DSErrMsg(v6, 325, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); + mem_free_dbg(ptr); + WCloseFile(a1); + return v4; +} +// 456F07: could not find valid save-restore pair for esi + +void __fastcall sound_CreateSoundBuffer(TSnd *sound_file) +{ + TSnd *v1; // esi + int v2; // eax + DSBUFFERDESC v3; // [esp+4h] [ebp-14h] + + v1 = sound_file; + memset(&v3, 0, sizeof(DSBUFFERDESC)); + v3.dwBufferBytes = v1->len; + v3.lpwfxFormat = &v1->fmt; + v3.dwSize = sizeof(DSBUFFERDESC); + v3.dwFlags = DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN|DSBCAPS_STATIC; + v2 = sglpDS->CreateSoundBuffer(&v3, &v1->DSB, NULL); + if ( v2 ) + DSErrMsg(v2, 282, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); +} + +void __fastcall sound_file_cleanup(TSnd *sound_file) +{ + TSnd *v1; // esi + IDirectSoundBuffer *v2; // eax + + v1 = sound_file; + if ( sound_file ) + { + v2 = sound_file->DSB; + if ( v2 ) + { + sound_file->DSB->Stop(); + v1->DSB->Release(); + v1->DSB = 0; + } + mem_free_dbg(v1); + } +} + +void __fastcall snd_init(HWND hWnd) +{ + sound_load_volume("Sound Volume", &sglSoundVolume); + gbSoundOn = sglSoundVolume > -1600; + sound_load_volume("Music Volume", &sglMusicVolume); + gbMusicOn = sglMusicVolume > -1600; + if ( sound_DirectSoundCreate(NULL, &sglpDS, NULL) ) + sglpDS = 0; + if ( sglpDS && !sglpDS->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE) ) + sound_create_primary_buffer(0); + SVidInitialize(sglpDS); + SFileDdaInitialize(sglpDS); + gbSndInited = sglpDS != 0; +} +// 4A22D4: using guessed type char gbMusicOn; +// 4A22D5: using guessed type char gbSoundOn; + +void __fastcall sound_load_volume(char *value_name, int *value) +{ + int *v2; // esi + //int v3; // eax + int v4; // ecx + int valuea; // [esp+8h] [ebp-4h] + + v2 = value; + valuea = *value; + //_LOBYTE(v3) = SRegLoadValue("Diablo", value_name, 0, &valuea); + if ( SRegLoadValue("Diablo", value_name, 0, &valuea) ) + v4 = valuea; + else + v4 = 0; + *v2 = v4; + if ( v4 >= -1600 ) + { + if ( v4 > 0 ) + *v2 = 0; + } + else + { + *v2 = -1600; + } + *v2 -= *v2 % 100; +} + +void __fastcall sound_create_primary_buffer(int music_track) +{ + int v1; // eax + int v2; // eax + DSCAPS v3; // [esp+4h] [ebp-8Ch] + DSBUFFERDESC v4; // [esp+64h] [ebp-2Ch] + int a1; // [esp+78h] [ebp-18h] + WAVEFORMATEX a2; // [esp+7Ch] [ebp-14h] + + a1 = music_track; + if ( !music_track ) + { + memset(&v4, 0, sizeof(DSBUFFERDESC)); + v4.dwSize = sizeof(DSBUFFERDESC); + v4.dwFlags = DSBCAPS_PRIMARYBUFFER; + v1 = sglpDS->CreateSoundBuffer(&v4, &sglpDSB, NULL); + if ( v1 ) + DSErrMsg(v1, 375, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); + } + if ( sglpDSB ) + { + v3.dwSize = 96; + v2 = sglpDS->GetCaps(&v3); + if ( v2 ) + DSErrMsg(v2, 383, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); + if ( !a1 || !LoadWaveFormat((HANDLE)a1, &a2) ) + { + memset(&a2, 0, 0x12u); + a2.wFormatTag = WAVE_FORMAT_PCM; + a2.nSamplesPerSec = 22050; + a2.wBitsPerSample = 16; + a2.cbSize = 0; + } + a2.nChannels = 2; + a2.nBlockAlign = 2 * a2.wBitsPerSample / 8; /// BUGFIX: should be `a2.nChannels * a2.wBitsPerSample / 8` + a2.nAvgBytesPerSec = a2.nSamplesPerSec * a2.nBlockAlign; + sglpDSB->SetFormat(&a2); + } +} +// 69F100: using guessed type int sglpDSB; + +int __fastcall sound_DirectSoundCreate(GUID *guid, IDirectSound **DS, int always_null) +{ + IDirectSound **v3; // ebp + int v4; // eax + FARPROC v5; // ebx + int v6; // eax + GUID *v8; // [esp+10h] [ebp-4h] + + v3 = DS; + v8 = guid; + if ( !hDsound_dll ) + { + hDsound_dll = LoadLibrary("dsound.dll"); + if ( !hDsound_dll ) + { + v4 = GetLastError(); + ErrDlg(IDD_DIALOG5, v4, "C:\\Src\\Diablo\\Source\\SOUND.CPP", 422); + } + } + v5 = GetProcAddress(hDsound_dll, "DirectSoundCreate"); + if ( !v5 ) + { + v6 = GetLastError(); + ErrDlg(IDD_DIALOG5, v6, "C:\\Src\\Diablo\\Source\\SOUND.CPP", 427); + } + return ((int (__stdcall *)(GUID *, IDirectSound **, int))v5)(v8, v3, always_null); +} + +void __cdecl sound_cleanup() +{ + snd_update(1); + SVidDestroy(); + SFileDdaDestroy(); + if ( sglpDS ) + { + sglpDS->Release(); + sglpDS = 0; + } + if ( gbSndInited ) + { + gbSndInited = 0; + sound_store_volume("Sound Volume", sglSoundVolume); + sound_store_volume("Music Volume", sglMusicVolume); + } +} + +void __fastcall sound_store_volume(char *key, int value) +{ + SRegSaveValue("Diablo", key, 0, value); +} + +void __cdecl music_stop() +{ + if ( sgpMusicTrack ) + { + SFileDdaEnd(sgpMusicTrack); + SFileCloseFile(sgpMusicTrack); + sgpMusicTrack = 0; + sgnMusicTrack = 6; + } +} + +void __fastcall music_start(int nTrack) +{ + //int v1; // esi + //int v2; // eax + //int v3; // edi + + //v1 = nTrack; + music_stop(); + if ( sglpDS && gbMusicOn ) + { + //_LOBYTE(v2) = SFileOpenFile(sgszMusicTracks[v1], &sgpMusicTrack); + //v3 = v2; + sound_create_primary_buffer((int)sgpMusicTrack); + if ( SFileOpenFile(sgszMusicTracks[nTrack], &sgpMusicTrack) ) + { + SFileDdaBeginEx(sgpMusicTrack, 0x40000, 0x40000, 0, sglMusicVolume, 0, 0); + sgnMusicTrack = nTrack; + } + else + { + sgpMusicTrack = 0; + } + } +} +// 4A22D4: using guessed type char gbMusicOn; + +void __fastcall sound_disable_music(bool disable) +{ + if ( disable ) + { + music_stop(); + } + else if ( sgnMusicTrack != 6 ) + { + music_start(sgnMusicTrack); + } +} + +int __fastcall sound_get_or_set_music_volume(int volume) +{ + if ( volume != 1 ) + { + sglMusicVolume = volume; + if ( sgpMusicTrack ) + SFileDdaSetVolume(sgpMusicTrack, volume, 0); + } + return sglMusicVolume; +} + +int __fastcall sound_get_or_set_sound_volume(int volume) +{ + int result; // eax + + result = volume; + if ( volume == 1 ) + return sglSoundVolume; + sglSoundVolume = volume; + return result; +} diff --git a/Source/sound.h b/Source/sound.h new file mode 100644 index 000000000..3aacc0a3f --- /dev/null +++ b/Source/sound.h @@ -0,0 +1,58 @@ +//HEADER_GOES_HERE +#ifndef __SOUND_H__ +#define __SOUND_H__ + +extern float sound_cpp_init_value; +extern IDirectSoundBuffer *DSBs[8]; +extern IDirectSound *sglpDS; +extern char gbSndInited; +extern int sglMusicVolume; +extern int sglSoundVolume; +extern HMODULE hDsound_dll; // idb +extern void *sgpMusicTrack; +extern IDirectSoundBuffer *sglpDSB; + +void __cdecl sound_cpp_init(); +void __fastcall snd_update(bool bStopAll); +void __fastcall snd_stop_snd(TSnd *pSnd); +bool __fastcall snd_playing(TSnd *pSnd); +void __fastcall snd_play_snd(TSnd *pSnd, int lVolume, int lPan); +IDirectSoundBuffer *__fastcall sound_dup_channel(IDirectSoundBuffer *DSB); +bool __fastcall sound_file_reload(TSnd *sound_file, IDirectSoundBuffer *DSB); +TSnd *__fastcall sound_file_load(char *path); +void __fastcall sound_CreateSoundBuffer(TSnd *sound_file); +void __fastcall sound_file_cleanup(TSnd *sound_file); +void __fastcall snd_init(); +void __fastcall sound_load_volume(char *value_name, int *value); +void __fastcall sound_create_primary_buffer(int music_track); +int __fastcall sound_DirectSoundCreate(GUID *guid, IDirectSound **DS, int always_null); +void __cdecl sound_cleanup(); +void __fastcall sound_store_volume(char *key, int value); +void __cdecl music_stop(); +void __fastcall music_start(int nTrack); +void __fastcall sound_disable_music(bool disable); +int __fastcall sound_get_or_set_music_volume(int volume); +int __fastcall sound_get_or_set_sound_volume(int volume); + +/*SDL Global*/ + +void LoadAndPlaySound(char *FilePath, int lVolume, int lPan); + + + + + +/* rdata */ + +extern const int sound_inf; // weak + +/* data */ + +extern UCHAR gbMusicOn; +extern UCHAR gbSoundOn; +extern char gbDupSounds; // weak +extern int sgnMusicTrack; +extern char *sgszMusicTracks[6]; +extern char unk_volume[4][2]; + +#endif /* __SOUND_H__ */ diff --git a/Source/spells.cpp b/Source/spells.cpp new file mode 100644 index 000000000..9c6c9087e --- /dev/null +++ b/Source/spells.cpp @@ -0,0 +1,367 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +SpellData spelldata[37] = +{ + { 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, { 0, 0, 0 }, 0, 0, 40, 80, 0, 0 }, + { SPL_FIREBOLT, 6, STYPE_FIRE, "Firebolt", "Firebolt", 1, 1, 1, 0, 15, IS_CAST2, { MIS_FIREBOLT, 0, 0 }, 1, 3, 40, 80, 1000, 50 }, + { SPL_HEAL, 5, STYPE_MAGIC, "Healing", NULL, 1, 1, 0, 1, 17, IS_CAST8, { MIS_HEAL, 0, 0 }, 3, 1, 20, 40, 1000, 50 }, + { SPL_LIGHTNING, 10, STYPE_LIGHTNING, "Lightning", NULL, 4, 3, 1, 0, 20, IS_CAST4, { MIS_LIGHTCTRL, 0, 0 }, 1, 6, 20, 60, 3000, 150 }, + { SPL_FLASH, 30, STYPE_LIGHTNING, "Flash", NULL, 5, 4, 0, 0, 33, IS_CAST4, { MIS_FLASH, MIS_FLASH2, 0 }, 2, 16, 20, 40, 7500, 500 }, + { SPL_IDENTIFY, 13, STYPE_MAGIC, "Identify", "Identify", -1, -1, 0, 1, 23, IS_CAST6, { MIS_IDENTIFY, 0, 0 }, 2, 1, 8, 12, 0, 100 }, + { SPL_FIREWALL, 28, STYPE_FIRE, "Fire Wall", NULL, 3, 2, 1, 0, 27, IS_CAST2, { MIS_FIREWALLC, 0, 0 }, 2, 16, 8, 16, 6000, 400 }, + { SPL_TOWN, 35, STYPE_MAGIC, "Town Portal", NULL, 3, 3, 1, 0, 20, IS_CAST6, { MIS_TOWN, 0, 0 }, 3, 18, 8, 12, 3000, 200 }, + { SPL_STONE, 60, STYPE_MAGIC, "Stone Curse", NULL, 6, 5, 1, 0, 51, IS_CAST2, { MIS_STONE, 0, 0 }, 3, 40, 8, 16, 12000, 800 }, + { SPL_INFRA, 40, STYPE_MAGIC, "Infravision", NULL, -1, -1, 0, 0, 36, IS_CAST8, { MIS_INFRA, 0, 0 }, 5, 20, 0, 0, 0, 600 }, + { SPL_RNDTELEPORT, 12, STYPE_MAGIC, "Phasing", NULL, 7, 6, 0, 0, 39, IS_CAST2, { MIS_RNDTELEPORT, 0, 0 }, 2, 4, 40, 80, 3500, 200 }, + { SPL_MANASHIELD, 33, STYPE_MAGIC, "Mana Shield", NULL, 6, 5, 0, 0, 25, IS_CAST2, { MIS_MANASHIELD, 0, 0 }, 0, 33, 4, 10, 16000, 1200 }, + { SPL_FIREBALL, 16, STYPE_FIRE, "Fireball", NULL, 8, 7, 1, 0, 48, IS_CAST2, { MIS_FIREBALL, 0, 0 }, 1, 10, 40, 80, 8000, 300 }, + { SPL_GUARDIAN, 50, STYPE_FIRE, "Guardian", NULL, 9, 8, 1, 0, 61, IS_CAST2, { MIS_GUARDIAN, 0, 0 }, 2, 30, 16, 32, 14000, 950 }, + { SPL_CHAIN, 30, STYPE_LIGHTNING, "Chain Lightning", NULL, 8, 7, 0, 0, 54, IS_CAST2, { MIS_CHAIN, 0, 0 }, 1, 18, 20, 60, 11000, 750 }, + { SPL_WAVE, 35, STYPE_FIRE, "Flame Wave", NULL, 9, 8, 1, 0, 54, IS_CAST2, { MIS_WAVE, 0, 0 }, 3, 20, 20, 40, 10000, 650 }, + { SPL_DOOMSERP, 0, STYPE_LIGHTNING, "Doom Serpents", NULL, -1, -1, 0, 0, 0, IS_CAST2, { 0, 0, 0 }, 0, 0, 40, 80, 0, 0 }, + { SPL_BLODRIT, 0, STYPE_MAGIC, "Blood Ritual", NULL, -1, -1, 0, 0, 0, IS_CAST2, { 0, 0, 0 }, 0, 0, 40, 80, 0, 0 }, + { SPL_NOVA, 60, STYPE_MAGIC, "Nova", NULL, -1, 10, 0, 0, 87, IS_CAST4, { MIS_NOVA, 0, 0 }, 3, 35, 16, 32, 21000, 1300 }, + { SPL_INVISIBIL, 0, STYPE_MAGIC, "Invisibility", NULL, -1, -1, 0, 0, 0, IS_CAST2, { 0, 0, 0 }, 0, 0, 40, 80, 0, 0 }, + { SPL_FLAME, 11, STYPE_FIRE, "Inferno", NULL, 3, 2, 1, 0, 20, IS_CAST2, { MIS_FLAMEC, 0, 0 }, 1, 6, 20, 40, 2000, 100 }, + { SPL_GOLEM, 100, STYPE_FIRE, "Golem", NULL, 11, 9, 0, 0, 81, IS_CAST2, { MIS_GOLEM, 0, 0 }, 6, 60, 16, 32, 18000, 1100 }, + { SPL_BLODBOIL, 0, STYPE_LIGHTNING, "Blood Boil", NULL, -1, -1, 1, 0, 0, IS_CAST8, { 0, 0, 0 }, 0, 0, 0, 0, 0, 0 }, + { SPL_TELEPORT, 35, STYPE_MAGIC, "Teleport", NULL, 14, 12, 1, 0, 105, IS_CAST6, { MIS_TELEPORT, 0, 0 }, 3, 15, 16, 32, 20000, 1250 }, + { SPL_APOCA, 150, STYPE_FIRE, "Apocalypse", NULL, -1, 15, 0, 0, 149, IS_CAST2, { MIS_APOCA, 0, 0 }, 6, 90, 8, 12, 30000, 2000 }, + { SPL_ETHEREALIZE, 100, STYPE_MAGIC, "Etherealize", NULL, -1, -1, 0, 0, 93, IS_CAST2, { MIS_ETHEREALIZE, 0, 0 }, 0, 100, 2, 6, 26000, 1600 }, + { SPL_REPAIR, 0, STYPE_MAGIC, "Item Repair", "Item Repair", -1, -1, 0, 1, -1, IS_CAST6, { MIS_REPAIR, 0, 0 }, 0, 0, 40, 80, 0, 0 }, + { SPL_RECHARGE, 0, STYPE_MAGIC, "Staff Recharge", "Staff Recharge", -1, -1, 0, 1, -1, IS_CAST6, { MIS_RECHARGE, 0, 0 }, 0, 0, 40, 80, 0, 0 }, + { SPL_DISARM, 0, STYPE_MAGIC, "Trap Disarm", "Trap Disarm", -1, -1, 0, 0, -1, IS_CAST6, { MIS_DISARM, 0, 0 }, 0, 0, 40, 80, 0, 0 }, + { SPL_ELEMENT, 35, STYPE_FIRE, "Elemental", NULL, 8, 6, 0, 0, 68, IS_CAST2, { MIS_ELEMENT, 0, 0 }, 2, 20, 20, 60, 10500, 700 }, + { SPL_CBOLT, 6, STYPE_LIGHTNING, "Charged Bolt", NULL, 1, 1, 1, 0, 25, IS_CAST2, { MIS_CBOLT, 0, 0 }, 1, 6, 40, 80, 1000, 50 }, + { SPL_HBOLT, 7, STYPE_MAGIC, "Holy Bolt", NULL, 1, 1, 1, 0, 20, IS_CAST2, { MIS_HBOLT, 0, 0 }, 1, 3, 40, 80, 1000, 50 }, + { SPL_RESURRECT, 20, STYPE_MAGIC, "Resurrect", NULL, -1, 5, 0, 1, 30, IS_CAST8, { MIS_RESURRECT, 0, 0 }, 0, 20, 4, 10, 4000, 250 }, + { SPL_TELEKINESIS, 15, STYPE_MAGIC, "Telekinesis", NULL, 2, 2, 0, 0, 33, IS_CAST2, { MIS_TELEKINESIS, 0, 0 }, 2, 8, 20, 40, 2500, 200 }, + { SPL_HEALOTHER, 5, STYPE_MAGIC, "Heal Other", NULL, 1, 1, 0, 1, 17, IS_CAST8, { MIS_HEALOTHER, 0, 0 }, 3, 1, 20, 40, 1000, 50 }, + { SPL_FLARE, 25, STYPE_MAGIC, "Blood Star", NULL, 14, 13, 0, 0, 70, IS_CAST2, { MIS_FLARE, 0, 0 }, 2, 14, 20, 60, 27500, 1800 }, + { SPL_BONESPIRIT, 24, STYPE_MAGIC, "Bone Spirit", NULL, 9, 7, 0, 0, 34, IS_CAST2, { MIS_BONESPIRIT, 0, 0 }, 1, 12, 20, 60, 11500, 800 } +}; + +int __fastcall GetManaAmount(int id, int sn) +{ + int i; // "raw" mana cost + int ma; // mana amount + + // mana adjust + int adj = 0; + + // spell level + int sl = plr[id]._pSplLvl[sn] + plr[id]._pISplLvlAdd - 1; + + if ( sl < 0 ) + { + sl = 0; + } + + if ( sl > 0 ) + { + adj = sl * spelldata[sn].sManaAdj; + } + if ( sn == SPL_FIREBOLT ) + { + adj >>= 1; + } + if ( sn == SPL_RESURRECT && sl > 0 ) + { + adj = sl * (spelldata[SPL_RESURRECT].sManaCost / 8); + } + + if ( spelldata[sn].sManaCost == 255 ) // TODO: check sign + { + i = (BYTE)plr[id]._pMaxManaBase; + } + else + { + i = spelldata[sn].sManaCost; + } + + ma = (i - adj) << 6; + + if ( sn == SPL_HEAL ) + { + ma = (spelldata[SPL_HEAL].sManaCost + 2 * plr[id]._pLevel - adj) << 6; + } + if ( sn == SPL_HEALOTHER ) + { + ma = (spelldata[SPL_HEAL].sManaCost + 2 * plr[id]._pLevel - adj) << 6; + } + + if ( plr[id]._pClass == PC_ROGUE ) + { + ma -= ma >> 2; + } + + if ( spelldata[sn].sMinMana > ma >> 6 ) + { + ma = spelldata[sn].sMinMana << 6; + } + + return ma * (100 - plr[id]._pISplCost) / 100; +} + +void __fastcall UseMana(int id, int sn) +{ + int ma; // mana cost + + if ( id == myplr ) + { + switch ( plr[id]._pSplType ) + { + case RSPLTYPE_SPELL: +#ifdef _DEBUG + if ( !debug_mode_key_inverted_v ) + { +#endif + ma = GetManaAmount(id, sn); + plr[id]._pMana -= ma; + plr[id]._pManaBase -= ma; + drawmanaflag = 1; +#ifdef _DEBUG + } +#endif + break; + case RSPLTYPE_SCROLL: + RemoveScroll(id); + break; + case RSPLTYPE_CHARGES: + UseStaffCharge(id); + break; + } + } +} + +BOOL __fastcall CheckSpell(int id, int sn, BYTE st, BOOL manaonly) +{ +#ifdef _DEBUG + if ( debug_mode_key_inverted_v ) + return true; +#endif + + BOOL result = true; + if ( !manaonly && pcurs != 1 ) + { + result = false; + } + else + { + if ( st != RSPLTYPE_SKILL ) + { + if ( GetSpellLevel(id, sn) <= 0 ) + { + result = false; + } + else + { + result = plr[id]._pMana >= GetManaAmount(id, sn); + } + } + } + + return result; +} + +void __fastcall CastSpell(int id, int spl, int sx, int sy, int dx, int dy, BOOL caster, int spllvl) +{ + + int dir; // missile direction + + // ugly switch, but generates the right code + switch ( caster ) + { + case TRUE: + dir = monster[id]._mdir; + break; + case FALSE: + // caster must be 0 already in this case, but oh well, + // it's needed to generate the right code + caster = 0; + dir = plr[id]._pdir; + + if ( spl == SPL_FIREWALL ) + { + dir = plr[id]._pVar3; + } + break; + } + + for ( int i = 0; spelldata[spl].sMissiles[i] != MIS_ARROW && i < 3; i++ ) + { + AddMissile(sx, sy, dx, dy, dir, spelldata[spl].sMissiles[i], caster, id, 0, spllvl); + } + + if ( spelldata[spl].sMissiles[0] == MIS_TOWN ) + { + UseMana(id, SPL_TOWN); + } + if ( spelldata[spl].sMissiles[0] == MIS_CBOLT ) + { + UseMana(id, SPL_CBOLT); + + for ( int i = 0; i < (spllvl >> 1) + 3; i++ ) + { + AddMissile(sx, sy, dx, dy, dir, MIS_CBOLT, caster, id, 0, spllvl); + } + } +} + +// pnum: player index +// rid: target player index +void __fastcall DoResurrect(int pnum, int rid) +{ + if ( (char)rid != -1 ) + { + AddMissile(plr[rid].WorldX, plr[rid].WorldY, plr[rid].WorldX, plr[rid].WorldY, 0, MIS_RESURRECTBEAM, 0, pnum, 0, 0); + } + + if ( pnum == myplr ) + { + NewCursor(CURSOR_HAND); + } + + if ( (char)rid != -1 && plr[rid]._pHitPoints == 0 ) + { + if ( rid == myplr ) + { + deathflag = 0; + gamemenu_off(); + drawhpflag = 1; + drawmanaflag = 1; + } + + ClrPlrPath(rid); + plr[rid].destAction = -1; + plr[rid]._pInvincible = 0; + PlacePlayer(rid); + + int hp = 640; + if ( plr[rid]._pMaxHPBase < 640 ) + { + hp = plr[rid]._pMaxHPBase; + } + SetPlayerHitPoints(rid, hp); + + plr[rid]._pMana = 0; + plr[rid]._pHPBase = plr[rid]._pHitPoints + (plr[rid]._pMaxHPBase - plr[rid]._pMaxHP); + plr[rid]._pManaBase = plr[rid]._pMaxManaBase - plr[rid]._pMaxMana; + + CalcPlrInv(rid, TRUE); + + if ( plr[rid].plrlevel == currlevel ) + { + StartStand(rid, plr[rid]._pdir); + } + else + { + plr[rid]._pmode = 0; + } + } +} + +void __fastcall PlacePlayer(int pnum) +{ + int nx; + int ny; + + if ( plr[pnum].plrlevel == currlevel ) + { + for ( DWORD i = 0; i < 8; i++ ) + { + nx = plr[pnum].WorldX + plrxoff2[i]; + ny = plr[pnum].WorldY + plryoff2[i]; + + if ( PosOkPlayer(pnum, nx, ny) ) + { + break; + } + } + + if ( !PosOkPlayer(pnum, nx, ny) ) + { + BOOL done = FALSE; + + for ( int max = 1, min = -1; min > -50 && !done; max++, min-- ) + { + for ( int y = min; y <= max && !done; y++ ) + { + ny = plr[pnum].WorldY + y; + + for ( int x = min; x <= max && !done; x++ ) + { + nx = plr[pnum].WorldX + x; + + if ( PosOkPlayer(pnum, nx, ny) ) + { + done = TRUE; + } + } + } + } + } + + plr[pnum].WorldX = nx; + plr[pnum].WorldY = ny; + + dPlayer[nx][ny] = pnum + 1; + + if ( pnum == myplr ) + { + ViewX = nx; + ViewY = ny; + } + } +} + +void __fastcall DoHealOther(int pnum, int rid) +{ + if ( pnum == myplr ) + { + NewCursor(CURSOR_HAND); + } + + if ( (char)rid != -1 && (plr[rid]._pHitPoints >> 6) > 0 ) + { + int hp = (random(57, 10) + 1) << 6; + + for ( int i = 0; i < plr[pnum]._pLevel; i++ ) + { + hp += (random(57, 4) + 1) << 6; + } + + for ( int j = 0; j < GetSpellLevel(pnum, SPL_HEALOTHER); ++j ) + { + hp += (random(57, 6) + 1) << 6; + } + + if ( plr[pnum]._pClass == PC_WARRIOR ) + { + hp *= 2; + } + + if ( plr[pnum]._pClass == PC_ROGUE ) + { + hp += hp >> 1; + } + + plr[rid]._pHitPoints += hp; + + if ( plr[rid]._pHitPoints > plr[rid]._pMaxHP ) + { + plr[rid]._pHitPoints = plr[rid]._pMaxHP; + } + + plr[rid]._pHPBase += hp; + + if ( plr[rid]._pHPBase > plr[rid]._pMaxHPBase ) + { + plr[rid]._pHPBase = plr[rid]._pMaxHPBase; + } + + drawhpflag = 1; + } +} diff --git a/Source/spells.h b/Source/spells.h new file mode 100644 index 000000000..52aae6c95 --- /dev/null +++ b/Source/spells.h @@ -0,0 +1,17 @@ +//HEADER_GOES_HERE +#ifndef __SPELLS_H__ +#define __SPELLS_H__ + +int __fastcall GetManaAmount(int id, int sn); +void __fastcall UseMana(int id, int sn); +BOOL __fastcall CheckSpell(int id, int sn, BYTE st, BOOL manaonly); +void __fastcall CastSpell(int id, int spl, int sx, int sy, int dx, int dy, BOOL caster, int spllvl); +void __fastcall DoResurrect(int pnum, int rid); +void __fastcall PlacePlayer(int pnum); +void __fastcall DoHealOther(int pnum, int rid); + +/* rdata */ + +extern SpellData spelldata[37]; + +#endif /* __SPELLS_H__ */ diff --git a/Source/stores.cpp b/Source/stores.cpp new file mode 100644 index 000000000..34d2e1a60 --- /dev/null +++ b/Source/stores.cpp @@ -0,0 +1,4241 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int stextup; // weak +int storenumh; // weak +int stextlhold; // weak +ItemStruct boyitem; +int stextshold; // idb +ItemStruct premiumitem[6]; +void *pSTextBoxCels; +int premiumlevel; // idb +int talker; // weak +STextStruct stext[24]; +char stextsize; // weak +int stextsmax; // weak +int InStoreFlag; // idb +ItemStruct storehold[48]; +int gossipstart; // weak +ItemStruct witchitem[20]; +int stextscrl; // weak +int numpremium; // idb +ItemStruct healitem[20]; +ItemStruct golditem; +char storehidx[48]; +void *pSTextSlidCels; +int stextvhold; // weak +int stextsel; // weak +char stextscrldbtn; // weak +int gossipend; // weak +void *pCelBuff; +int stextsval; // idb +int boylevel; // weak +ItemStruct smithitem[20]; +int stextdown; // weak +char stextscrlubtn; // weak +char stextflag; // weak +#endif + +int SStringY[24] = +{ + 0, + 12, + 24, + 36, + 48, + 60, + 72, + 84, + 96, + 108, + 120, + 132, + 144, + 156, + 168, + 180, + 192, + 204, + 216, + 228, + 240, + 252, + 264, + 276 +}; +char *talkname[9] = +{ + "Griswold", + "Pepin", + &empty_string, + "Ogden", + "Cain", + "Farnham", + "Adria", + "Gillian", + "Wirt" +}; + +void __cdecl InitStores() +{ + int i; // eax + + pSTextBoxCels = LoadFileInMem("Data\\TextBox2.CEL", 0); + pCelBuff = LoadFileInMem("Data\\PentSpn2.CEL", 0); + pSTextSlidCels = LoadFileInMem("Data\\TextSlid.CEL", 0); + ClearSText(0, 24); + stextflag = 0; + InStoreFlag = 1; + premiumlevel = 1; + stextsize = 0; + stextscrl = 0; + numpremium = 0; + + for(i = 0; i < 6; i++) + premiumitem[i]._itype = -1; + + boyitem._itype = -1; + boylevel = 0; +} +// 69FB38: using guessed type int talker; +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; +// 6A8A3C: using guessed type int boylevel; +// 6AA705: using guessed type char stextflag; + +void __cdecl SetupTownStores() +{ + int i; // eax + int l; // esi + + SetRndSeed(glSeedTbl[currlevel] * GetTickCount()); + if ( gbMaxPlayers == 1 ) + { + l = 0; + for(i = 0; i < 17; i++) + { + if ( plr[myplr]._pLvlVisited[i] ) + l = i; + } + } + else + { + l = plr[myplr]._pLevel >> 1; + } + l += 2; + if ( l < 6 ) + l = 6; + if ( l > 16 ) + l = 16; + SpawnStoreGold(); + SpawnSmith(l); + SpawnWitch(l); + SpawnHealer(l); + SpawnBoy(plr[myplr]._pLevel); + SpawnPremium(plr[myplr]._pLevel); +} +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl FreeStoreMem() +{ + void *v0; // ecx + void *v1; // ecx + void *v2; // ecx + + v0 = pSTextBoxCels; + pSTextBoxCels = 0; + mem_free_dbg(v0); + v1 = pCelBuff; + pCelBuff = 0; + mem_free_dbg(v1); + v2 = pSTextSlidCels; + pSTextSlidCels = 0; + mem_free_dbg(v2); +} + +void __cdecl DrawSTextBack() +{ + char *v0; // edi + signed int v1; // edx + signed int v2; // ecx + int v3; // edi + signed int v4; // ecx + _BYTE *v5; // edi + signed int v6; // ecx + + CelDecodeOnly(408, 487, pSTextBoxCels, 1, 271); + v0 = &gpBuffer->row[324].pixels[347]; + v1 = 148; + do + { + v2 = 132; + do + { + *v0 = 0; + v0 += 2; + --v2; + } + while ( v2 ); + *v0 = 0; + v3 = (int)(v0 - 1032); + v4 = 132; + do + { + v5 = (_BYTE *)(v3 + 1); + *v5 = 0; + v3 = (int)(v5 + 1); + --v4; + } + while ( v4 ); + v0 = (char *)(v3 - 1032); + --v1; + } + while ( v1 ); + v6 = 132; + do + { + *v0 = 0; + v0 += 2; + --v6; + } + while ( v6 ); + *v0 = 0; +} + +void __fastcall PrintSString(int x, int y, unsigned char cjustflag, char *str, int col, int val) +{ + int v6; // edi + int v7; // eax + int v8; // ebx + int v9; // esi + int v10; // esi + int v11; // ecx + int v12; // eax + int v13; // edx + int v14; // ecx + unsigned char v15; // al + int v16; // ebx + int v17; // ecx + int v18; // eax + int v19; // esi + size_t v20; // ebx + unsigned char v21; // edx + int v22; // ecx + char valstr[32]; // [esp+Ch] [ebp-3Ch] + int v24; // [esp+2Ch] [ebp-1Ch] + int v25; // [esp+30h] [ebp-18h] + int v26; // [esp+34h] [ebp-14h] + int v27; // [esp+38h] [ebp-10h] + int v28; // [esp+3Ch] [ebp-Ch] + int v29; // [esp+40h] [ebp-8h] + int v30; // [esp+44h] [ebp-4h] + + v6 = SStringY[y] + stext[y]._syoff; + v7 = -(stextsize != 0); + v8 = x; + v9 = screen_y_times_768[v6 + 204]; + _LOWORD(v7) = v7 & 0xFEC0; + v24 = y; + v26 = x; + v27 = v7 + 416; + v10 = x + v7 + 416 + v9; + v28 = strlen(str); + v11 = 0; + v25 = stextsize != 0 ? 577 : 257; + v30 = 0; + if ( cjustflag ) + { + v12 = 0; + if ( v28 > 0 ) + { + do + { + v13 = (unsigned char)str[v11++]; + v12 += fontkern[fontframe[fontidx[v13]]] + 1; + } + while ( v11 < v28 ); + } + if ( v12 < v25 ) + v30 = (v25 - v12) >> 1; + v10 += v30; + } + if ( stextsel == v24 ) + { + if ( cjustflag ) + v14 = v27 + v30 + v8 - 20; + else + v14 = v27 + v8 - 20; + CelDecodeOnly(v14, v6 + 205, pCelBuff, InStoreFlag, 12); + } + v29 = 0; + if ( v28 > 0 ) + { + do + { + v15 = fontframe[fontidx[(unsigned char)str[v29]]]; + v16 = v15; + v17 = v30 + fontkern[v15] + 1; + v30 += fontkern[v15] + 1; + if ( v15 && v17 <= v25 ) + CPrintString(v10, v15, col); + v18 = fontkern[v16]; + ++v29; + v10 += v18 + 1; + } + while ( v29 < v28 ); + v8 = v26; + } + if ( !cjustflag && val >= 0 ) + { + sprintf(valstr, "%i", val); + v19 = screen_y_times_768[v6 + 204] - v8 + 656; + v20 = strlen(valstr); + while ( (--v20 & 0x80000000) == 0 ) + { + v21 = fontframe[fontidx[(unsigned char)valstr[v20]]]; + v19 += -1 - fontkern[v21]; + if ( fontframe[fontidx[(unsigned char)valstr[v20]]] ) + CPrintString(v19, v21, col); + } + v8 = v26; + } + if ( stextsel == v24 ) + { + if ( cjustflag ) + v22 = v27 + v30 + v8 + 4; + else + v22 = 660 - v8; + CelDecodeOnly(v22, v6 + 205, pCelBuff, InStoreFlag, 12); + } +} +// 6A09E0: using guessed type char stextsize; +// 6A8A28: using guessed type int stextsel; +// 457BD6: using guessed type char valstr[32]; + +void __fastcall DrawSLine(int y) +{ + int v1; // eax + int v2; // eax + char *v3; // esi + char *v4; // edi + signed int v5; // edx + char *v6; // edi + char *v7; // esi + signed int v8; // [esp+0h] [ebp-10h] + signed int v9; // [esp+8h] [ebp-8h] + signed int v10; // [esp+Ch] [ebp-4h] + + v1 = screen_y_times_768[SStringY[y] + 198]; + if ( stextsize == 1 ) + { + v8 = 142170; + v2 = v1 + 90; + v10 = 146; + v9 = 182; + } + else + { + v8 = 142490; + v2 = v1 + 410; + v10 = 66; + v9 = 502; + } + v3 = (char *)gpBuffer + v8; + v4 = (char *)gpBuffer + v2; + v5 = 3; + do + { + qmemcpy(v4, v3, 4 * v10); + v7 = &v3[4 * v10]; + v6 = &v4[4 * v10]; + *(_WORD *)v6 = *(_WORD *)v7; + v3 = &v7[v9 + 2]; + v4 = &v6[v9 + 2]; + --v5; + } + while ( v5 ); +} +// 6A09E0: using guessed type char stextsize; + +void __fastcall DrawSArrows(int y1, int y2) +{ + int *v2; // ebp + int v3; // ebx + int v4; // edi + int v5; // esi + int v6; // eax + int v7; // eax + + v2 = &SStringY[y2]; + v3 = y1; + v4 = SStringY[y1] + 204; + v5 = *v2 + 204; + if ( stextscrlubtn == -1 ) + CelDecodeOnly(665, v4, pSTextSlidCels, 10, 12); + else + CelDecodeOnly(665, v4, pSTextSlidCels, 12, 12); + if ( stextscrldbtn == -1 ) + CelDecodeOnly(665, v5, pSTextSlidCels, 9, 12); + else + CelDecodeOnly(665, v5, pSTextSlidCels, 11, 12); + while ( 1 ) + { + v4 += 12; + if ( v4 >= v5 ) + break; + CelDecodeOnly(665, v4, pSTextSlidCels, 14, 12); + } + v6 = stextsel; + if ( stextsel == 22 ) + v6 = stextlhold; + if ( storenumh <= 1 ) + v7 = 0; + else + v7 = (*v2 - SStringY[v3] - 24) * (1000 * (stextsval + ((v6 - stextup) >> 2)) / (storenumh - 1)) / 1000; + CelDecodeOnly(665, SStringY[v3 + 1] + v7 + 204, pSTextSlidCels, 13, 12); +} +// 69F108: using guessed type int stextup; +// 69F10C: using guessed type int storenumh; +// 69F110: using guessed type int stextlhold; +// 6A8A28: using guessed type int stextsel; +// 6A8A2C: using guessed type char stextscrldbtn; +// 6AA704: using guessed type char stextscrlubtn; + +void __cdecl DrawSTextHelp() +{ + stextsel = -1; + stextsize = 1; +} +// 6A09E0: using guessed type char stextsize; +// 6A8A28: using guessed type int stextsel; + +void __fastcall ClearSText(int s, int e) +{ + int v2; // edx + int *v3; // eax + + if ( s < e ) + { + v2 = e - s; + v3 = &stext[s]._syoff; + do + { + v3[37] = -1; + *(v3 - 1) = 0; + *v3 = 0; + *((_BYTE *)v3 + 4) = 0; + v3[33] = 0; + *((_BYTE *)v3 + 136) = 0; + v3[35] = 0; + v3[36] = 0; + v3 += 39; + --v2; + } + while ( v2 ); + } +} + +void __fastcall AddSLine(int y) +{ + int v1; // ecx + + v1 = y; + stext[v1]._sx = 0; + stext[v1]._syoff = 0; + stext[v1]._sstr[0] = 0; + stext[v1]._sline = 1; +} + +void __fastcall AddSTextVal(int y, int val) +{ + stext[y]._sval = val; +} + +void __fastcall OffsetSTextY(int y, int yo) +{ + stext[y]._syoff = yo; +} + +void __fastcall AddSText(int x, int y, unsigned char j, char *str, int clr, int sel) +{ + int v6; // esi + + v6 = y; + stext[v6]._syoff = 0; + stext[v6]._sx = x; + strcpy(stext[y]._sstr, str); + stext[v6]._sline = 0; + stext[v6]._sjust = j; + _LOBYTE(stext[v6]._sclr) = clr; + stext[v6]._ssel = sel; +} + +void __cdecl StoreAutoPlace() +{ + int v0; // edi + int v1; // eax + int v2; // edx + ItemStruct *v3; // ebp + int v4; // esi + int v5; // esi + int v6; // esi + int v7; // esi + int v8; // esi + int v9; // esi + int v10; // esi + int v11; // esi + int *v12; // esi + int v13; // esi + int v14; // esi + int v15; // esi + int v16; // esi + int v17; // esi + signed int v19; // [esp+10h] [ebp-Ch] + int v20; // [esp+14h] [ebp-8h] + int v21; // [esp+18h] [ebp-4h] + + SetICursor(plr[myplr].HoldItem._iCurs + 12); + v0 = icursH28; + v1 = 0; + v21 = icursW28; + v20 = icursH28; + if ( icursW28 == 1 ) + { + if ( icursH28 == 1 ) + { + v2 = myplr; + if ( plr[myplr].HoldItem._iStatFlag && AllItemsList[plr[v2].HoldItem.IDidx].iUsable ) + { + v19 = 0; + v3 = plr[v2].SpdList; + do + { + if ( v1 ) + break; + if ( v3->_itype == -1 ) + { + qmemcpy(v3, &plr[v2].HoldItem, sizeof(ItemStruct)); + v0 = v20; + v1 = 1; + } + ++v19; + ++v3; + } + while ( v19 < 8 ); + } + v4 = 30; + do + { + if ( v1 ) + break; + v1 = AutoPlace(myplr, v4++, 1, 1, 1); + } + while ( v4 <= 39 ); + v5 = 20; + do + { + if ( v1 ) + break; + v1 = AutoPlace(myplr, v5++, 1, 1, 1); + } + while ( v5 <= 29 ); + v6 = 10; + do + { + if ( v1 ) + break; + v1 = AutoPlace(myplr, v6++, 1, 1, 1); + } + while ( v6 <= 19 ); + v7 = 0; + while ( !v1 ) + { + v1 = AutoPlace(myplr, v7++, 1, 1, 1); + if ( v7 > 9 ) + goto LABEL_22; + } + } + else + { +LABEL_22: + if ( v0 == 2 ) + { + v8 = 29; + do + { + if ( v1 ) + break; + v1 = AutoPlace(myplr, v8--, 1, 2, 1); + } + while ( v8 >= 20 ); + v9 = 9; + do + { + if ( v1 ) + break; + v1 = AutoPlace(myplr, v9--, 1, 2, 1); + } + while ( v9 >= 0 ); + v10 = 19; + while ( !v1 ) + { + v1 = AutoPlace(myplr, v10--, 1, 2, 1); + if ( v10 < 10 ) + goto LABEL_32; + } + } + else + { +LABEL_32: + if ( v0 == 3 ) + { + v11 = 0; + while ( !v1 ) + { + v1 = AutoPlace(myplr, v11++, 1, 3, 1); + if ( v11 >= 20 ) + goto LABEL_36; + } + } + } + } + } + else + { +LABEL_36: + if ( v21 == 2 ) + { + if ( v0 == 2 ) + { + v12 = AP2x2Tbl; + do + { + if ( v1 ) + break; + v1 = AutoPlace(myplr, *v12, 2, 2, 1); + ++v12; + } + while ( (signed int)v12 < (signed int)&AP2x2Tbl[10] ); + v13 = 21; + do + { + if ( v1 ) + break; + v1 = AutoPlace(myplr, v13, 2, 2, 1); + v13 += 2; + } + while ( v13 < 29 ); + v14 = 1; + do + { + if ( v1 ) + break; + v1 = AutoPlace(myplr, v14, 2, 2, 1); + v14 += 2; + } + while ( v14 < 9 ); + v15 = 10; + while ( !v1 ) + { + v1 = AutoPlace(myplr, v15++, 2, 2, 1); + if ( v15 >= 19 ) + goto LABEL_50; + } + } + else + { +LABEL_50: + if ( v0 == 3 ) + { + v16 = 0; + do + { + if ( v1 ) + break; + v1 = AutoPlace(myplr, v16++, 2, 3, 1); + } + while ( v16 < 9 ); + v17 = 10; + do + { + if ( v1 ) + break; + v1 = AutoPlace(myplr, v17++, 2, 3, 1); + } + while ( v17 < 19 ); + } + } + } + } +} +// 48E9A8: using guessed type int AP2x2Tbl[10]; + +void __cdecl S_StartSmith() +{ + stextsize = 0; + stextscrl = 0; + AddSText(0, 1, 1u, "Welcome to the", COL_GOLD, 0); + AddSText(0, 3, 1u, "Blacksmith's shop", COL_GOLD, 0); + AddSText(0, 7, 1u, "Would you like to:", COL_GOLD, 0); + AddSText(0, 10, 1u, "Talk to Griswold", COL_BLUE, 1); + AddSText(0, 12, 1u, "Buy basic items", COL_WHITE, 1); + AddSText(0, 14, 1u, "Buy premium items", COL_WHITE, 1); + AddSText(0, 16, 1u, "Sell items", COL_WHITE, 1); + AddSText(0, 18, 1u, "Repair items", COL_WHITE, 1); + AddSText(0, 20, 1u, "Leave the shop", COL_WHITE, 1); + AddSLine(5); + storenumh = 20; +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +void __fastcall S_ScrollSBuy(int idx) +{ + int v1; // esi + int v2; // edi + char *v3; // esi + char *v4; // eax + int iclr; // [esp+Ch] [ebp-4h] + + v1 = idx; + v2 = 5; + ClearSText(5, 21); + v3 = &smithitem[v1]._iMagical; + stextup = 5; + do + { + if ( *((_DWORD *)v3 - 13) != -1 ) + { + _LOBYTE(iclr) = COL_WHITE; + if ( *v3 ) + _LOBYTE(iclr) = COL_BLUE; + if ( !*((_DWORD *)v3 + 74) ) + _LOBYTE(iclr) = COL_RED; + v4 = v3 + 65; + if ( !*v3 ) + v4 = v3 + 1; + AddSText(20, v2, 0, v4, iclr, 1); + AddSTextVal(v2, *((_DWORD *)v3 + 35)); + PrintStoreItem((ItemStruct *)(v3 - 60), v2 + 1, iclr); + stextdown = v2; + v3 += 368; + } + v2 += 4; + } + while ( v2 < 20 ); + if ( !stext[stextsel]._ssel && stextsel != 22 ) + stextsel = stextdown; +} +// 69F108: using guessed type int stextup; +// 6A8A28: using guessed type int stextsel; +// 6AA700: using guessed type int stextdown; + +void __fastcall PrintStoreItem(ItemStruct *x, int l, char iclr) +{ + ItemStruct *v3; // esi + bool v4; // zf + char v5; // cl + char v6; // cl + int v7; // eax + char v8; // al + unsigned char v9; // al + char v10; // al + int v11; // edi + char sstr[128]; // [esp+Ch] [ebp-84h] + int y; // [esp+8Ch] [ebp-4h] + + sstr[0] = 0; + v3 = x; + v4 = x->_iIdentified == 0; + y = l; + if ( !v4 ) + { + if ( x->_iMagical != 2 ) + { + v5 = x->_iPrePower; + if ( v5 != -1 ) + { + PrintItemPower(v5, v3); + strcat(sstr, tempstr); + } + } + v6 = v3->_iSufPower; + if ( v6 != -1 ) + { + PrintItemPower(v6, v3); + if ( sstr[0] ) + strcat(sstr, ", "); + strcat(sstr, tempstr); + } + } + if ( v3->_iMiscId == IMISC_STAFF && v3->_iMaxCharges ) + { + sprintf(tempstr, "Charges: %i/%i", v3->_iCharges, v3->_iMaxCharges); + if ( sstr[0] ) + strcat(sstr, ", "); + strcat(sstr, tempstr); + } + if ( sstr[0] ) + AddSText(40, y++, 0, sstr, iclr, 0); + sstr[0] = 0; + if ( v3->_iClass == 1 ) + sprintf(sstr, "Damage: %i-%i ", v3->_iMinDam, v3->_iMaxDam); + if ( v3->_iClass == 2 ) + sprintf(sstr, "Armor: %i ", v3->_iAC); + v7 = v3->_iMaxDur; + if ( v7 != 255 && v7 ) + { + sprintf(tempstr, "Dur: %i/%i, ", v3->_iDurability, v3->_iMaxDur); + strcat(sstr, tempstr); + } + else + { + strcat(sstr, "Indestructible, "); + } + if ( !v3->_itype ) + sstr[0] = 0; + if ( v3->_iMinStr + (unsigned char)v3->_iMinMag + v3->_iMinDex ) + { + strcpy(tempstr, "Required:"); + v8 = v3->_iMinStr; + if ( v8 ) + sprintf(tempstr, "%s %i Str", tempstr, v8); + v9 = v3->_iMinMag; + if ( v9 ) + sprintf(tempstr, "%s %i Mag", tempstr, v9); + v10 = v3->_iMinDex; + if ( v10 ) + sprintf(tempstr, "%s %i Dex", tempstr, v10); + strcat(sstr, tempstr); + } + else + { + strcat(sstr, "No required attributes"); + } + v11 = y; + AddSText(40, y, 0, sstr, iclr, 0); + if ( v3->_iMagical == 2 ) + { + if ( v3->_iIdentified ) + AddSText(40, v11 + 1, 0, "Unique Item", iclr, 0); + } +} + +void __cdecl S_StartSBuy() +{ + int v0; // ST10_4 + int v1; // eax + int *v2; // ecx + + v0 = plr[myplr]._pGold; + stextsize = 1; + stextscrl = 1; + stextsval = 0; + sprintf(tempstr, "I have these items for sale : Your gold : %i", v0); + AddSText(0, 1, 1u, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + S_ScrollSBuy(stextsval); + AddSText(0, 22, 1u, "Back", COL_WHITE, 0); + OffsetSTextY(22, 6); + v1 = 0; + storenumh = 0; + if ( smithitem[0]._itype != -1 ) + { + v2 = &smithitem[0]._itype; + do + { + v2 += 92; + ++v1; + } + while ( *v2 != -1 ); + storenumh = v1; + } + stextsmax = v1 - 4; + if ( v1 - 4 < 0 ) + stextsmax = 0; +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; + +void __fastcall S_ScrollSPBuy(int idx) +{ + int v1; // esi + int v2; // edi + int v3; // eax + int v4; // esi + int *v5; // ecx + char *v6; // esi + int iclr; // [esp+Ch] [ebp-4h] + + v1 = idx; + v2 = 5; + ClearSText(5, 21); + v3 = v1; + v4 = 0; + stextup = 5; + if ( v3 ) + { + v5 = &premiumitem[0]._itype; + do + { + if ( *v5 != -1 ) + --v3; + ++v4; + v5 += 92; + } + while ( v3 ); + } + v6 = &premiumitem[v4]._iMagical; + do + { + if ( (signed int)v6 >= (signed int)&premiumitem[6]._iMagical ) + break; + if ( *((_DWORD *)v6 - 13) == -1 ) + { + v2 -= 4; + } + else + { + _LOBYTE(iclr) = COL_WHITE; + if ( *v6 ) + _LOBYTE(iclr) = COL_BLUE; + if ( !*((_DWORD *)v6 + 74) ) + _LOBYTE(iclr) = COL_RED; + AddSText(20, v2, 0, v6 + 65, iclr, 1); + AddSTextVal(v2, *((_DWORD *)v6 + 35)); + PrintStoreItem((ItemStruct *)(v6 - 60), v2 + 1, iclr); + stextdown = v2; + } + v2 += 4; + v6 += 368; + } + while ( v2 < 20 ); + if ( !stext[stextsel]._ssel && stextsel != 22 ) + stextsel = stextdown; +} +// 69F108: using guessed type int stextup; +// 6A8A28: using guessed type int stextsel; +// 6AA700: using guessed type int stextdown; + +bool __cdecl S_StartSPBuy() +{ + int *v0; // eax + bool result; // al + int v2; // ST10_4 + + storenumh = 0; + v0 = &premiumitem[0]._itype; + do + { + if ( *v0 != -1 ) + ++storenumh; + v0 += 92; + } + while ( (signed int)v0 < (signed int)&premiumitem[6]._itype ); + if ( storenumh ) + { + v2 = plr[myplr]._pGold; + stextsval = 0; + stextsize = 1; + stextscrl = 1; + sprintf(tempstr, "I have these premium items for sale : Your gold : %i", v2); + AddSText(0, 1, 1u, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + AddSText(0, 22, 1u, "Back", COL_WHITE, 0); + OffsetSTextY(22, 6); + stextsmax = storenumh - 4; + if ( storenumh - 4 < 0 ) + stextsmax = 0; + S_ScrollSPBuy(stextsval); + result = 1; + } + else + { + StartStore(STORE_SMITH); + stextsel = 14; + result = 0; + } + return result; +} +// 69F10C: using guessed type int storenumh; +// 69FB38: using guessed type int talker; +// 6A09E0: using guessed type char stextsize; +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; +// 6A8A28: using guessed type int stextsel; + +bool __fastcall SmithSellOk(int i) +{ + if ( plr[myplr].InvList[i]._itype != ITYPE_NONE + && plr[myplr].InvList[i]._itype + && plr[myplr].InvList[i]._itype != ITYPE_GOLD + && plr[myplr].InvList[i]._itype != ITYPE_0E + && plr[myplr].InvList[i]._itype != ITYPE_STAFF ) + return plr[myplr].InvList[i].IDidx != IDI_LAZSTAFF; + else + return 0; +} + +void __fastcall S_ScrollSSell(int idx) +{ + int v1; // esi + int v2; // edi + char *v3; // esi + int v4; // edx + int v5; // [esp+Ch] [ebp-8h] + int iclr; // [esp+10h] [ebp-4h] + + v1 = idx; + v5 = idx; + v2 = 5; + ClearSText(5, 21); + v3 = &storehold[v1]._iMagical; + stextup = 5; + do + { + if ( v5 >= storenumh ) + break; + if ( *((_DWORD *)v3 - 13) != -1 ) + { + _LOBYTE(iclr) = 0; + if ( *v3 ) + _LOBYTE(iclr) = 1; + if ( !*((_DWORD *)v3 + 74) ) + _LOBYTE(iclr) = 2; + if ( *v3 && *((_DWORD *)v3 - 1) ) + { + AddSText(20, v2, 0, v3 + 65, iclr, 1); + v4 = *((_DWORD *)v3 + 35); + } + else + { + AddSText(20, v2, 0, v3 + 1, iclr, 1); + v4 = *((_DWORD *)v3 + 34); + } + AddSTextVal(v2, v4); + PrintStoreItem((ItemStruct *)(v3 - 60), v2 + 1, iclr); + stextdown = v2; + } + ++v5; + v2 += 4; + v3 += 368; + } + while ( v2 < 20 ); + stextsmax = storenumh - 4; + if ( storenumh - 4 < 0 ) + stextsmax = 0; +} +// 69F108: using guessed type int stextup; +// 69F10C: using guessed type int storenumh; +// 6A09E4: using guessed type int stextsmax; +// 6AA700: using guessed type int stextdown; + +void __cdecl S_StartSSell() +{ + int i; // eax + bool sellok; // [esp+14h] [ebp-4h] + + stextsize = 1; + sellok = 0; + storenumh = 0; + + for(i = 0; i < 48; i++) + storehold[i]._itype = -1; + + for(i = 0; i < plr[myplr]._pNumInv; i++) + { + if ( SmithSellOk(i) ) + { + sellok = 1; + qmemcpy(&storehold[storenumh], &plr[myplr].InvList[i], sizeof(ItemStruct)); + + if ( storehold[storenumh]._iMagical && storehold[storenumh]._iIdentified ) + storehold[storenumh]._ivalue = storehold[storenumh]._iIvalue; + + if ( !(storehold[storenumh]._ivalue >>= 2) ) + storehold[storenumh]._ivalue = 1; + + storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue; + storehidx[storenumh++] = i; + } + } + + if ( sellok ) + { + stextsmax = plr[myplr]._pNumInv; + stextscrl = 1; + stextsval = 0; + sprintf(tempstr, "Which item is for sale? Your gold : %i", plr[myplr]._pGold); + AddSText(0, 1, 1, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + S_ScrollSSell(stextsval); + AddSText(0, 22, 1, "Back", COL_WHITE, 1); + OffsetSTextY(22, 6); + } + else + { + stextscrl = 0; + sprintf(tempstr, "You have nothing I want. Your gold : %i", plr[myplr]._pGold); + AddSText(0, 1, 1, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + AddSText(0, 22, 1, "Back", COL_WHITE, 1); + OffsetSTextY(22, 6); + } +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; + +bool __fastcall SmithRepairOk(int i) +{ + if ( plr[myplr].InvList[i]._itype != ITYPE_NONE + && plr[myplr].InvList[i]._itype + && plr[myplr].InvList[i]._itype != ITYPE_GOLD + && plr[myplr].InvList[i]._itype != ITYPE_0E ) + return plr[myplr].InvList[i]._iDurability != plr[myplr].InvList[i]._iMaxDur; + else + return 0; +} + +void __cdecl S_StartSRepair() +{ + int v0; // ebp + int *v1; // eax + int v2; // esi + int v3; // eax + int v4; // eax + int v5; // eax + int v6; // eax + int v7; // edi + //int v8; // eax + int v9; // esi + int v10; // eax + int v11; // [esp-4h] [ebp-1Ch] + signed int v12; // [esp+10h] [ebp-8h] + int v13; // [esp+14h] [ebp-4h] + + v0 = 0; + stextsize = 1; + v12 = 0; + storenumh = 0; + v1 = &storehold[0]._itype; + do + { + *v1 = -1; + v1 += 92; + } + while ( (signed int)v1 < (signed int)&storehold[48]._itype ); + v2 = myplr; + v3 = myplr; + if ( plr[myplr].InvBody[0]._itype != -1 && plr[v3].InvBody[0]._iDurability != plr[v3].InvBody[0]._iMaxDur ) + { + v12 = 1; + AddStoreHoldRepair(plr[v3].InvBody, -1); + v2 = myplr; + } + v4 = v2; + if ( plr[v2].InvBody[6]._itype != -1 && plr[v4].InvBody[6]._iDurability != plr[v4].InvBody[6]._iMaxDur ) + { + v12 = 1; + AddStoreHoldRepair(&plr[v4].InvBody[6], -2); + v2 = myplr; + } + v5 = v2; + if ( plr[v2].InvBody[4]._itype != -1 && plr[v5].InvBody[4]._iDurability != plr[v5].InvBody[4]._iMaxDur ) + { + v12 = 1; + AddStoreHoldRepair(&plr[v5].InvBody[4], -3); + v2 = myplr; + } + v6 = v2; + if ( plr[v2].InvBody[5]._itype != -1 && plr[v6].InvBody[5]._iDurability != plr[v6].InvBody[5]._iMaxDur ) + { + v12 = 1; + AddStoreHoldRepair(&plr[v6].InvBody[5], -4); + v2 = myplr; + } + v7 = 21720 * v2; + if ( plr[v2]._pNumInv > 0 ) + { + v13 = 0; + do + { + //_LOBYTE(v8) = SmithRepairOk(v0); + if ( SmithRepairOk(v0) ) + { + v12 = 1; + AddStoreHoldRepair((ItemStruct *)((char *)&plr[0].InvList[v13] + v7), v0); + v2 = myplr; + } + ++v13; + v7 = 21720 * v2; + ++v0; + } + while ( v0 < plr[v2]._pNumInv ); + } + v9 = v2; + v11 = plr[v9]._pGold; + if ( v12 ) + { + stextsval = 0; + v10 = plr[v9]._pNumInv; + stextscrl = 1; + stextsmax = v10; + sprintf(tempstr, "Repair which item? Your gold : %i", v11); + AddSText(0, 1, 1u, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + S_ScrollSSell(stextsval); + } + else + { + stextscrl = 0; + sprintf(tempstr, "You have nothing to repair. Your gold : %i", v11); + AddSText(0, 1, 1u, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + } + AddSText(0, 22, 1u, "Back", COL_WHITE, 1); + OffsetSTextY(22, 6); +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; + +void __fastcall AddStoreHoldRepair(ItemStruct *itm, int i) +{ + int v2; // ebx + ItemStruct *v3; // ebp + int v4; // ecx + int v5; // eax + + v2 = storenumh; + v3 = &storehold[storenumh]; + qmemcpy(&storehold[storenumh], itm, sizeof(ItemStruct)); + v4 = (unsigned char)v3->_iMagical; + if ( (_BYTE)v4 && v3->_iIdentified ) + v3->_ivalue = 30 * v3->_iIvalue / 100; + v5 = v3->_ivalue * (100 * (v3->_iMaxDur - v3->_iDurability) / v3->_iMaxDur) / 100; + if ( !v5 ) + { + if ( (_BYTE)v4 && v3->_iIdentified ) + return; + v5 = 1; + } + if ( v5 > 1 ) + v5 >>= 1; + v3->_iIvalue = v5; + v3->_ivalue = v5; + storehidx[v2] = i; + storenumh = v2 + 1; +} +// 69F10C: using guessed type int storenumh; + +void __cdecl S_StartWitch() +{ + stextsize = 0; + stextscrl = 0; + AddSText(0, 2, 1u, "Witch's shack", COL_GOLD, 0); + AddSText(0, 9, 1u, "Would you like to:", COL_GOLD, 0); + AddSText(0, 12, 1u, "Talk to Adria", COL_BLUE, 1); + AddSText(0, 14, 1u, "Buy items", COL_WHITE, 1); + AddSText(0, 16, 1u, "Sell items", COL_WHITE, 1); + AddSText(0, 18, 1u, "Recharge staves", COL_WHITE, 1); + AddSText(0, 20, 1u, "Leave the shack", COL_WHITE, 1); + AddSLine(5); + storenumh = 20; +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +void __fastcall S_ScrollWBuy(int idx) +{ + int v1; // esi + int v2; // edi + char *v3; // esi + char *v4; // eax + int iclr; // [esp+Ch] [ebp-4h] + + v1 = idx; + v2 = 5; + ClearSText(5, 21); + v3 = &witchitem[v1]._iMagical; + stextup = 5; + do + { + if ( *((_DWORD *)v3 - 13) != -1 ) + { + _LOBYTE(iclr) = 0; + if ( *v3 ) + _LOBYTE(iclr) = 1; + if ( !*((_DWORD *)v3 + 74) ) + _LOBYTE(iclr) = 2; + v4 = v3 + 65; + if ( !*v3 ) + v4 = v3 + 1; + AddSText(20, v2, 0, v4, iclr, 1); + AddSTextVal(v2, *((_DWORD *)v3 + 35)); + PrintStoreItem((ItemStruct *)(v3 - 60), v2 + 1, iclr); + stextdown = v2; + v3 += 368; + } + v2 += 4; + } + while ( v2 < 20 ); + if ( !stext[stextsel]._ssel && stextsel != 22 ) + stextsel = stextdown; +} +// 69F108: using guessed type int stextup; +// 6A8A28: using guessed type int stextsel; +// 6AA700: using guessed type int stextdown; + +void __cdecl S_StartWBuy() +{ + int v0; // ST10_4 + int v1; // eax + int *v2; // ecx + + v0 = plr[myplr]._pGold; + stextsize = 1; + stextscrl = 1; + stextsval = 0; + stextsmax = 20; + sprintf(tempstr, "I have these items for sale : Your gold : %i", v0); + AddSText(0, 1, 1u, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + S_ScrollWBuy(stextsval); + AddSText(0, 22, 1u, "Back", COL_WHITE, 0); + OffsetSTextY(22, 6); + v1 = 0; + storenumh = 0; + if ( witchitem[0]._itype != -1 ) + { + v2 = &witchitem[0]._itype; + do + { + v2 += 92; + ++v1; + } + while ( *v2 != -1 ); + storenumh = v1; + } + stextsmax = v1 - 4; + if ( v1 - 4 < 0 ) + stextsmax = 0; +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; + +bool __fastcall WitchSellOk(int i) +{ + bool rv; // al + ItemStruct *pI; // edx + + rv = 0; + + if ( i < 0 ) + pI = &plr[myplr].SpdList[~i]; // -(i+1) + else + pI = &plr[myplr].InvList[i]; + + if ( pI->_itype == ITYPE_MISC ) + rv = 1; + if ( pI->_itype == ITYPE_STAFF ) + rv = 1; + if ( pI->IDidx >= IDI_FIRSTQUEST && pI->IDidx <= IDI_LASTQUEST ) + rv = 0; + if ( pI->IDidx == IDI_LAZSTAFF ) + rv = 0; + return rv; +} + +void __cdecl S_StartWSell() +{ + int i; // eax + bool sellok; // [esp+18h] [ebp-8h] + + stextsize = 1; + sellok = 0; + storenumh = 0; + + for(i = 0; i < 48; i++) + storehold[i]._itype = -1; + + for(i = 0; i < plr[myplr]._pNumInv; i++) + { + if ( WitchSellOk(i) ) + { + sellok = 1; + qmemcpy(&storehold[storenumh], &plr[myplr].InvList[i], sizeof(ItemStruct)); + + if ( storehold[storenumh]._iMagical && storehold[storenumh]._iIdentified ) + storehold[storenumh]._ivalue = storehold[storenumh]._iIvalue; + + if ( !(storehold[storenumh]._ivalue >>= 2) ) + storehold[storenumh]._ivalue = 1; + + storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue; + storehidx[storenumh++] = i; + } + } + + for(i = 0; i < 8; i++) + { + if ( plr[myplr].SpdList[i]._itype != -1 && WitchSellOk(~i) ) + { + sellok = 1; + qmemcpy(&storehold[storenumh], &plr[myplr].SpdList[i], sizeof(ItemStruct)); + + if ( storehold[storenumh]._iMagical && storehold[storenumh]._iIdentified ) + storehold[storenumh]._ivalue = storehold[storenumh]._iIvalue; + + if ( !(storehold[storenumh]._ivalue >>= 2) ) + storehold[storenumh]._ivalue = 1; + + storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue; + storehidx[storenumh++] = ~i; + } + } + + if ( sellok ) + { + stextscrl = 1; + stextsval = 0; + stextsmax = plr[myplr]._pNumInv; + sprintf(tempstr, "Which item is for sale? Your gold : %i", plr[myplr]._pGold); + AddSText(0, 1, 1, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + S_ScrollSSell(stextsval); + } + else + { + stextscrl = 0; + sprintf(tempstr, "You have nothing I want. Your gold : %i", plr[myplr]._pGold); + AddSText(0, 1, 1, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + } + + AddSText(0, 22, 1, "Back", COL_WHITE, 1); + OffsetSTextY(22, 6); +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; + +bool __fastcall WitchRechargeOk(int i) +{ + bool rv; // al + + rv = 0; + if ( plr[myplr].InvList[i]._itype == ITYPE_STAFF + && plr[myplr].InvList[i]._iCharges != plr[myplr].InvList[i]._iMaxCharges ) + { + rv = 1; + } + return rv; +} + +void __fastcall AddStoreHoldRecharge(ItemStruct itm, int i) +{ + int v2; // ebx + int v3; // eax + char v4; // ST10_1 + int v5; // ecx + int v6; // eax + + v2 = storenumh; + v3 = spelldata[itm._iSpell].sStaffCost; + v4 = i; + qmemcpy(&storehold[storenumh], &itm, sizeof(ItemStruct)); + storehold[v2]._ivalue += v3; + v5 = storenumh; + v6 = storehold[v2]._ivalue + * (100 + * (storehold[v2]._iMaxCharges - storehold[v2]._iCharges) + / storehold[v2]._iMaxCharges) + / 100 >> 1; + ++storenumh; + storehold[v2]._ivalue = v6; + storehold[v2]._iIvalue = v6; + storehidx[v5] = v4; +} +// 69F108: using guessed type int stextup; +// 69F10C: using guessed type int storenumh; + +void __cdecl S_StartWRecharge() +{ + int *v0; // eax + int v1; // ebp + int v2; // eax + //int v3; // eax + ItemStruct v4; // [esp-170h] [ebp-18Ch] + int v5; // [esp-4h] [ebp-20h] + int inv_num; // [esp+10h] [ebp-Ch] + ItemStruct *v7; // [esp+14h] [ebp-8h] + int v8; // [esp+18h] [ebp-4h] + + stextsize = 1; + v8 = 0; + storenumh = 0; + v0 = &storehold[0]._itype; + do + { + *v0 = -1; + v0 += 92; + } + while ( (signed int)v0 < (signed int)&storehold[48]._itype ); + v1 = myplr; + if ( plr[myplr].InvBody[4]._itype == ITYPE_STAFF && plr[v1].InvBody[4]._iCharges != plr[v1].InvBody[4]._iMaxCharges ) + { + v8 = 1; + qmemcpy(&v4, &plr[v1].InvBody[4], sizeof(v4)); + AddStoreHoldRecharge(v4, -1); + } + v2 = plr[v1]._pNumInv; + inv_num = 0; + if ( v2 > 0 ) + { + v7 = plr[v1].InvList; + do + { + //_LOBYTE(v3) = WitchRechargeOk(inv_num); + if ( WitchRechargeOk(inv_num) ) + { + v8 = 1; + qmemcpy(&v4, v7, sizeof(v4)); + AddStoreHoldRecharge(v4, inv_num); + } + ++inv_num; + v2 = plr[v1]._pNumInv; + ++v7; + } + while ( inv_num < v2 ); + } + v5 = plr[v1]._pGold; + if ( v8 ) + { + stextscrl = 1; + stextsval = 0; + stextsmax = v2; + sprintf(tempstr, "Recharge which item? Your gold : %i", v5); + AddSText(0, 1, 1u, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + S_ScrollSSell(stextsval); + } + else + { + stextscrl = 0; + sprintf(tempstr, "You have nothing to recharge. Your gold : %i", v5); + AddSText(0, 1, 1u, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + } + AddSText(0, 22, 1u, "Back", COL_WHITE, 1); + OffsetSTextY(22, 6); +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartNoMoney() +{ + StartStore((unsigned char)stextshold); + stextscrl = 0; + stextsize = 1; + ClearSText(5, 23); + AddSText(0, 14, 1u, "You do not have enough gold", COL_WHITE, 1); +} +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartNoRoom() +{ + StartStore((unsigned char)stextshold); + stextscrl = 0; + ClearSText(5, 23); + AddSText(0, 14, 1u, "You do not have enough room in inventory", COL_WHITE, 1); +} +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartConfirm() +{ + BOOL idprint; // esi + char iclr; // [esp+Ch] [ebp-4h] + + StartStore(stextshold); + stextscrl = 0; + ClearSText(5, 23); + iclr = COL_WHITE; + + if ( plr[myplr].HoldItem._iMagical ) + iclr = COL_BLUE; + if ( !plr[myplr].HoldItem._iStatFlag ) + iclr = COL_RED; + + idprint = plr[myplr].HoldItem._iMagical != 0; + + if ( stextshold == STORE_SIDENTIFY ) + idprint = 0; + if ( plr[myplr].HoldItem._iMagical && !plr[myplr].HoldItem._iIdentified ) + { + if ( stextshold == STORE_SSELL ) + idprint = 0; + if ( stextshold == STORE_WSELL ) + idprint = 0; + if ( stextshold == STORE_SREPAIR ) + idprint = 0; + if ( stextshold == STORE_WRECHARGE ) + idprint = 0; + } + if ( idprint ) + AddSText(20, 8, 0, plr[myplr].HoldItem._iIName, iclr, 0); + else + AddSText(20, 8, 0, plr[myplr].HoldItem._iName, iclr, 0); + + AddSTextVal(8, plr[myplr].HoldItem._iIvalue); + PrintStoreItem(&plr[myplr].HoldItem, 9, iclr); + + if ( stextshold > STORE_WRECHARGE ) + { + if ( stextshold == STORE_BBOY ) + { + strcpy(tempstr, "Do we have a deal?"); + goto LABEL_37; + } + if ( stextshold != STORE_HBUY ) + { + if ( stextshold == STORE_SIDENTIFY ) + { + strcpy(tempstr, "Are you sure you want to identify this item?"); + goto LABEL_37; + } + if ( stextshold != STORE_SPBUY ) + goto LABEL_37; + } +LABEL_34: + strcpy(tempstr, "Are you sure you want to buy this item?"); + goto LABEL_37; + } + switch ( stextshold ) + { + case STORE_WRECHARGE: + strcpy(tempstr, "Are you sure you want to recharge this item?"); + break; + case STORE_SBUY: + goto LABEL_34; + case STORE_SSELL: +LABEL_27: + strcpy(tempstr, "Are you sure you want to sell this item?"); + break; + case STORE_SREPAIR: + strcpy(tempstr, "Are you sure you want to repair this item?"); + break; + case STORE_WBUY: + goto LABEL_34; + case STORE_WSELL: + goto LABEL_27; + } +LABEL_37: + AddSText(0, 15, 1u, tempstr, COL_WHITE, 0); + AddSText(0, 18, 1u, "Yes", COL_WHITE, 1); + AddSText(0, 20, 1u, "No", COL_WHITE, 1); +} +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartBoy() +{ + stextsize = 0; + stextscrl = 0; + AddSText(0, 2, 1u, "Wirt the Peg-legged boy", COL_GOLD, 0); + AddSLine(5); + if ( boyitem._itype == -1 ) + { + AddSText(0, 12, 1u, "Talk to Wirt", COL_BLUE, 1); + AddSText(0, 18, 1u, "Say goodbye", COL_WHITE, 1); + } + else + { + AddSText(0, 8, 1u, "Talk to Wirt", COL_BLUE, 1); + AddSText(0, 12, 1u, "I have something for sale,", COL_GOLD, 0); + AddSText(0, 14, 1u, "but it will cost 50 gold", COL_GOLD, 0); + AddSText(0, 16, 1u, "just to take a look. ", COL_GOLD, 0); + AddSText(0, 18, 1u, "What have you got?", COL_WHITE, 1); + AddSText(0, 20, 1u, "Say goodbye", COL_WHITE, 1); + } +} +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartBBoy() +{ + int iclr; // esi + + stextsize = 1; + stextscrl = 0; + sprintf(tempstr, "I have this item for sale : Your gold : %i", plr[myplr]._pGold); + AddSText(0, 1, 1u, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + iclr = COL_WHITE; + + if ( boyitem._iMagical ) + iclr = COL_BLUE; + if ( !boyitem._iStatFlag ) + iclr = COL_RED; + if ( boyitem._iMagical ) + AddSText(20, 10, 0, boyitem._iIName, iclr, 1); + else + AddSText(20, 10, 0, boyitem._iName, iclr, 1); + + AddSTextVal(10, boyitem._iIvalue + (boyitem._iIvalue >> 1)); + PrintStoreItem(&boyitem, 11, iclr); + AddSText(0, 22, 1u, "Leave", COL_WHITE, 1); + OffsetSTextY(22, 6); +} +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartHealer() +{ + stextsize = 0; + stextscrl = 0; + AddSText(0, 1, 1u, "Welcome to the", COL_GOLD, 0); + AddSText(0, 3, 1u, "Healer's home", COL_GOLD, 0); + AddSText(0, 9, 1u, "Would you like to:", COL_GOLD, 0); + AddSText(0, 12, 1u, "Talk to Pepin", COL_BLUE, 1); + AddSText(0, 14, 1u, "Receive healing", COL_WHITE, 1); + AddSText(0, 16, 1u, "Buy items", COL_WHITE, 1); + AddSText(0, 18, 1u, "Leave Healer's home", COL_WHITE, 1); + AddSLine(5); + storenumh = 20; +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +void __fastcall S_ScrollHBuy(int idx) +{ + int v1; // esi + int v2; // edi + int *v3; // esi + int iclr; // [esp+8h] [ebp-4h] + + v1 = idx; + v2 = 5; + ClearSText(5, 21); + stextup = 5; + v3 = &healitem[v1]._iStatFlag; + do + { + if ( *(v3 - 87) != -1 ) + { + _LOBYTE(iclr) = COL_WHITE; + if ( !*v3 ) + _LOBYTE(iclr) = COL_RED; + AddSText(20, v2, 0, (char *)v3 - 295, iclr, 1); + AddSTextVal(v2, *(v3 - 39)); + PrintStoreItem((ItemStruct *)(v3 - 89), v2 + 1, iclr); + stextdown = v2; + v3 += 92; + } + v2 += 4; + } + while ( v2 < 20 ); + if ( !stext[stextsel]._ssel && stextsel != 22 ) + stextsel = stextdown; +} +// 69F108: using guessed type int stextup; +// 6A8A28: using guessed type int stextsel; +// 6AA700: using guessed type int stextdown; + +void __cdecl S_StartHBuy() +{ + int v0; // ST10_4 + int v1; // eax + int *v2; // ecx + + v0 = plr[myplr]._pGold; + stextsize = 1; + stextscrl = 1; + stextsval = 0; + sprintf(tempstr, "I have these items for sale : Your gold : %i", v0); + AddSText(0, 1, 1u, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + S_ScrollHBuy(stextsval); + AddSText(0, 22, 1u, "Back", COL_WHITE, 0); + OffsetSTextY(22, 6); + v1 = 0; + storenumh = 0; + if ( healitem[0]._itype != -1 ) + { + v2 = &healitem[0]._itype; + do + { + v2 += 92; + ++v1; + } + while ( *v2 != -1 ); + storenumh = v1; + } + stextsmax = v1 - 4; + if ( v1 - 4 < 0 ) + stextsmax = 0; +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartStory() +{ + stextsize = 0; + stextscrl = 0; + AddSText(0, 2, 1u, "The Town Elder", COL_GOLD, 0); + AddSText(0, 9, 1u, "Would you like to:", COL_GOLD, 0); + AddSText(0, 12, 1u, "Talk to Cain", COL_BLUE, 1); + AddSText(0, 14, 1u, "Identify an item", COL_WHITE, 1); + AddSText(0, 18, 1u, "Say goodbye", COL_WHITE, 1); + AddSLine(5); +} +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +bool __fastcall IdItemOk(ItemStruct *i) +{ + bool result; // al + + result = 0; + if ( i->_itype != -1 ) + { + if ( i->_iMagical ) + result = i->_iIdentified == 0; + } + return result; +} + +void __fastcall AddStoreHoldId(ItemStruct itm, int i) +{ + qmemcpy(&storehold[storenumh], &itm, sizeof(ItemStruct)); + storehold[storenumh]._ivalue = 100; + storehold[storenumh]._iIvalue = 100; + storehidx[storenumh++] = i; +} +// 69F108: using guessed type int stextup; +// 69F10C: using guessed type int storenumh; + +void __cdecl S_StartSIdentify() +{ + ItemStruct itm; // [esp-170h] [ebp-18Ch] + bool idok; // [esp+10h] [ebp-Ch] + int i; // [esp+14h] [ebp-8h] + + idok = 0; + storenumh = 0; + stextsize = 1; + + for(i = 0; i < 48; i++) + storehold[i]._itype = -1; + + if ( IdItemOk(plr[myplr].InvBody) ) + { + idok = 1; + qmemcpy(&itm, plr[myplr].InvBody, sizeof(ItemStruct)); + AddStoreHoldId(itm, -1); + } + if ( IdItemOk(&plr[myplr].InvBody[6]) ) + { + idok = 1; + qmemcpy(&itm, &plr[myplr].InvBody[6], sizeof(ItemStruct)); + AddStoreHoldId(itm, -2); + } + if ( IdItemOk(&plr[myplr].InvBody[4]) ) + { + idok = 1; + qmemcpy(&itm, &plr[myplr].InvBody[4], sizeof(ItemStruct)); + AddStoreHoldId(itm, -3); + } + if ( IdItemOk(&plr[myplr].InvBody[5]) ) + { + idok = 1; + qmemcpy(&itm, &plr[myplr].InvBody[5], sizeof(ItemStruct)); + AddStoreHoldId(itm, -4); + } + if ( IdItemOk(&plr[myplr].InvBody[1]) ) + { + idok = 1; + qmemcpy(&itm, &plr[myplr].InvBody[1], sizeof(ItemStruct)); + AddStoreHoldId(itm, -5); + } + if ( IdItemOk(&plr[myplr].InvBody[2]) ) + { + idok = 1; + qmemcpy(&itm, &plr[myplr].InvBody[2], sizeof(ItemStruct)); + AddStoreHoldId(itm, -6); + } + if ( IdItemOk(&plr[myplr].InvBody[3]) ) + { + idok = 1; + qmemcpy(&itm, &plr[myplr].InvBody[3], sizeof(ItemStruct)); + AddStoreHoldId(itm, -7); + } + + for(i = 0; i < plr[myplr]._pNumInv; i++) + { + if ( IdItemOk(&plr[myplr].InvList[i]) ) + { + idok = 1; + qmemcpy(&itm, &plr[myplr].InvList[i], sizeof(ItemStruct)); + AddStoreHoldId(itm, i); + } + } + + if ( idok ) + { + stextscrl = 1; + stextsval = 0; + stextsmax = plr[myplr]._pNumInv; + sprintf(tempstr, "Identify which item? Your gold : %i", plr[myplr]._pGold); + AddSText(0, 1, 1, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + S_ScrollSSell(stextsval); + } + else + { + stextscrl = 0; + sprintf(tempstr, "You have nothing to identify. Your gold : %i", plr[myplr]._pGold); + AddSText(0, 1, 1, tempstr, COL_GOLD, 0); + AddSLine(3); + AddSLine(21); + } + + AddSText(0, 22, 1, "Back", COL_WHITE, 1); + OffsetSTextY(22, 6); +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartIdShow() +{ + char iclr; // [esp+4h] [ebp-4h] + + StartStore(stextshold); + stextscrl = 0; + ClearSText(5, 23); + iclr = COL_WHITE; + + if ( plr[myplr].HoldItem._iMagical ) + iclr = COL_BLUE; + if ( !plr[myplr].HoldItem._iStatFlag ) + iclr = COL_RED; + + AddSText(0, 7, 1u, "This item is:", COL_WHITE, 0); + AddSText(20, 11, 0, plr[myplr].HoldItem._iIName, iclr, 0); + PrintStoreItem(&plr[myplr].HoldItem, 12, iclr); + AddSText(0, 18, 1u, "Done", COL_WHITE, 1); +} +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartTalk() +{ + int *v0; // edi + signed int v1; // eax + int v2; // edx + int *v3; // ecx + char **v4; // ebp + int v5; // esi + int v6; // ebx + signed int v7; // [esp-4h] [ebp-1Ch] + signed int v8; // [esp+10h] [ebp-8h] + int y; // [esp+14h] [ebp-4h] + + stextsize = 0; + stextscrl = 0; + sprintf(tempstr, "Talk to %s", talkname[talker]); + AddSText(0, 2, 1u, tempstr, COL_GOLD, 0); + AddSLine(5); + v0 = &quests[0]._qlog; + v1 = 0; + v2 = 0; + v3 = &quests[0]._qlog; + do + { + if ( *((_BYTE *)v3 - 18) == 2 && *((_DWORD *)&Qtalklist[0]._qinfra + v2 + 16 * talker) != -1 && *v3 ) + ++v1; + v3 += 6; + ++v2; + } + while ( (signed int)v3 < (signed int)&quests[16]._qlog ); + if ( v1 <= 6 ) + { + v7 = 15; + v8 = 2; + } + else + { + v1 >>= 1; + v7 = 14; + v8 = 1; + } + v4 = &questlist[0]._qlstr; + v5 = v7 - v1; + v6 = 0; + y = v7 - v1 - 2; + do + { + if ( *((_BYTE *)v0 - 18) == 2 && *((_DWORD *)&Qtalklist[0]._qinfra + v6 + 16 * talker) != -1 && *v0 ) + { + AddSText(0, v5, 1u, *v4, COL_WHITE, 1); + v5 += v8; + } + v0 += 6; + ++v6; + v4 += 5; + } + while ( (signed int)v0 < (signed int)&quests[16]._qlog ); + AddSText(0, y, 1u, "Gossip", COL_BLUE, 1); + AddSText(0, 22, 1u, "Back", COL_WHITE, 1); +} +// 69FB38: using guessed type int talker; +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartTavern() +{ + stextsize = 0; + stextscrl = 0; + AddSText(0, 1, 1u, "Welcome to the", COL_GOLD, 0); + AddSText(0, 3, 1u, "Rising Sun", COL_GOLD, 0); + AddSText(0, 9, 1u, "Would you like to:", COL_GOLD, 0); + AddSText(0, 12, 1u, "Talk to Ogden", COL_BLUE, 1); + AddSText(0, 18, 1u, "Leave the tavern", COL_WHITE, 1); + AddSLine(5); + storenumh = 20; +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartBarMaid() +{ + stextsize = 0; + stextscrl = 0; + AddSText(0, 2, 1u, "Gillian", COL_GOLD, 0); + AddSText(0, 9, 1u, "Would you like to:", COL_GOLD, 0); + AddSText(0, 12, 1u, "Talk to Gillian", COL_BLUE, 1); + AddSText(0, 18, 1u, "Say goodbye", COL_WHITE, 1); + AddSLine(5); + storenumh = 20; +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +void __cdecl S_StartDrunk() +{ + stextsize = 0; + stextscrl = 0; + AddSText(0, 2, 1u, "Farnham the Drunk", COL_GOLD, 0); + AddSText(0, 9, 1u, "Would you like to:", COL_GOLD, 0); + AddSText(0, 12, 1u, "Talk to Farnham", COL_BLUE, 1); + AddSText(0, 18, 1u, "Say Goodbye", COL_WHITE, 1); + AddSLine(5); + storenumh = 20; +} +// 69F10C: using guessed type int storenumh; +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; + +void __fastcall StartStore(char s) +{ + char t; // bl + int i; // ecx + + for ( t = s; ; t = 1 ) + { + sbookflag = 0; + invflag = 0; + chrflag = 0; + questlog = 0; + dropGoldFlag = 0; + ClearSText(0, 24); + ReleaseStoreBtn(); + switch ( t ) + { + case STORE_SMITH: + S_StartSmith(); + break; + case STORE_SBUY: + if ( storenumh > 0 ) + S_StartSBuy(); + break; + case STORE_SSELL: + S_StartSSell(); + break; + case STORE_SREPAIR: + S_StartSRepair(); + break; + case STORE_WITCH: + S_StartWitch(); + break; + case STORE_WBUY: + if ( storenumh > 0 ) + S_StartWBuy(); + break; + case STORE_WSELL: + S_StartWSell(); + break; + case STORE_WRECHARGE: + S_StartWRecharge(); + break; + case STORE_NOMONEY: + S_StartNoMoney(); + break; + case STORE_NOROOM: + S_StartNoRoom(); + break; + case STORE_CONFIRM: + S_StartConfirm(); + break; + case STORE_BOY: + S_StartBoy(); + break; + case STORE_BBOY: + S_StartBBoy(); + break; + case STORE_HEALER: + S_StartHealer(); + break; + case STORE_STORY: + S_StartStory(); + break; + case STORE_HBUY: + if ( storenumh > 0 ) + S_StartHBuy(); + break; + case STORE_SIDENTIFY: + S_StartSIdentify(); + break; + case STORE_SPBUY: + if ( !S_StartSPBuy() ) + return; + break; + case STORE_GOSSIP: + S_StartTalk(); + break; + case STORE_IDSHOW: + S_StartIdShow(); + break; + case STORE_TAVERN: + S_StartTavern(); + break; + case STORE_DRUNK: + S_StartDrunk(); + break; + case STORE_BARMAID: + S_StartBarMaid(); + break; + default: + break; + } + + for(i = 0; i < 24; i++) + { + if ( stext[i]._ssel ) + break; + } + + stextsel = i == 24 ? -1 : i; + stextflag = t; + if ( t != 2 || storenumh ) + break; + } +} +// 4B84DC: using guessed type int dropGoldFlag; +// 4B8968: using guessed type int sbookflag; +// 69BD04: using guessed type int questlog; +// 69F10C: using guessed type int storenumh; +// 6A8A28: using guessed type int stextsel; +// 6AA705: using guessed type char stextflag; + +void __cdecl DrawSText() +{ + int i; // edi + + if ( stextsize ) + DrawQTextBack(); + else + DrawSTextBack(); + if ( !stextscrl ) + goto LABEL_19; + if ( stextflag > (signed int)STORE_WRECHARGE ) + { + switch ( stextflag ) + { + case STORE_HBUY: + S_ScrollHBuy(stextsval); + break; + case STORE_SIDENTIFY: + goto LABEL_17; + case STORE_SPBUY: + S_ScrollSPBuy(stextsval); + break; + } + } + else + { + if ( stextflag >= (signed int)STORE_WSELL ) + goto LABEL_17; + if ( stextflag == STORE_SBUY ) + { + S_ScrollSBuy(stextsval); + goto LABEL_19; + } + if ( stextflag > (signed int)STORE_SBUY ) + { + if ( stextflag > (signed int)STORE_SREPAIR ) + { + if ( stextflag == STORE_WBUY ) + S_ScrollWBuy(stextsval); + goto LABEL_19; + } +LABEL_17: + S_ScrollSSell(stextsval); + goto LABEL_19; + } + } +LABEL_19: + + for(i = 0; i < 24; i++) + { + if ( stext[i]._sline ) + DrawSLine(i); + if ( stext[i]._sstr ) + PrintSString(stext[i]._sx, i, stext[i]._sjust, stext[i]._sstr, stext[i]._sclr, stext[i]._sval); + } + + if ( stextscrl ) + DrawSArrows(4, 20); + InStoreFlag = (InStoreFlag & 7) + 1; +} +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; +// 6AA705: using guessed type char stextflag; + +void __cdecl STextESC() +{ + char v0; // cl + char v1; // cl + char v2; // cl + + if ( qtextflag ) + { + qtextflag = 0; + if ( leveltype == DTYPE_TOWN ) + sfx_stop(); + } + else + { + switch ( stextflag ) + { + case STORE_SMITH: + case STORE_WITCH: + case STORE_BOY: + case STORE_BBOY: + case STORE_HEALER: + case STORE_STORY: + case STORE_TAVERN: + case STORE_DRUNK: + case STORE_BARMAID: + stextflag = 0; + return; + case STORE_SBUY: + StartStore(STORE_SMITH); + stextsel = 12; + return; + case STORE_SSELL: + v1 = STORE_SMITH; + goto LABEL_16; + case STORE_SREPAIR: + v2 = STORE_SMITH; + goto LABEL_14; + case STORE_WBUY: + v0 = STORE_WITCH; + goto LABEL_18; + case STORE_WSELL: + v1 = STORE_WITCH; + goto LABEL_16; + case STORE_WRECHARGE: + v2 = STORE_WITCH; +LABEL_14: + StartStore(v2); + stextsel = 18; + return; + case STORE_NOMONEY: + case STORE_NOROOM: + case STORE_CONFIRM: + StartStore((unsigned char)stextshold); + stextsel = stextlhold; + stextsval = stextvhold; + return; + case STORE_HBUY: + v1 = STORE_HEALER; +LABEL_16: + StartStore(v1); + stextsel = 16; + return; + case STORE_SIDENTIFY: + v0 = STORE_STORY; + goto LABEL_18; + case STORE_SPBUY: + v0 = STORE_SMITH; +LABEL_18: + StartStore(v0); + stextsel = 14; + break; + case STORE_GOSSIP: + StartStore((unsigned char)stextshold); + stextsel = stextlhold; + break; + case STORE_IDSHOW: + StartStore(STORE_SIDENTIFY); + break; + default: + return; + } + } +} +// 5BB1ED: using guessed type char leveltype; +// 646D00: using guessed type char qtextflag; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; +// 6AA705: using guessed type char stextflag; + +void __cdecl STextUp() +{ + int v0; // eax + + PlaySFX(IS_TITLEMOV); + if ( stextsel != -1 ) + { + if ( stextscrl ) + { + if ( stextsel == stextup ) + { + if ( stextsval ) + --stextsval; + return; + } + v0 = stextsel - 1; + stextsel = v0; + if ( stext[v0]._ssel ) + return; + do + { + if ( v0 ) + --v0; + else + v0 = 23; + } + while ( !stext[v0]._ssel ); +LABEL_20: + stextsel = v0; + return; + } + if ( stextsel ) + v0 = stextsel - 1; + else + v0 = 23; + stextsel = v0; + if ( !stext[v0]._ssel ) + { + do + { + if ( v0 ) + --v0; + else + v0 = 23; + } + while ( !stext[v0]._ssel ); + goto LABEL_20; + } + } +} +// 69F108: using guessed type int stextup; +// 6A6BB8: using guessed type int stextscrl; +// 6A8A28: using guessed type int stextsel; + +void __cdecl STextDown() +{ + int v0; // eax + + PlaySFX(IS_TITLEMOV); + if ( stextsel != -1 ) + { + if ( stextscrl ) + { + if ( stextsel == stextdown ) + { + if ( stextsval < stextsmax ) + ++stextsval; + return; + } + v0 = stextsel + 1; + stextsel = v0; + if ( stext[v0]._ssel ) + return; + do + { + if ( v0 == 23 ) + v0 = 0; + else + ++v0; + } + while ( !stext[v0]._ssel ); +LABEL_20: + stextsel = v0; + return; + } + if ( stextsel == 23 ) + v0 = 0; + else + v0 = stextsel + 1; + stextsel = v0; + if ( !stext[v0]._ssel ) + { + do + { + if ( v0 == 23 ) + v0 = 0; + else + ++v0; + } + while ( !stext[v0]._ssel ); + goto LABEL_20; + } + } +} +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; +// 6A8A28: using guessed type int stextsel; +// 6AA700: using guessed type int stextdown; + +void __cdecl STextPrior() +{ + PlaySFX(IS_TITLEMOV); + if ( stextsel != -1 && stextscrl ) + { + if ( stextsel == stextup ) + { + if ( stextsval ) + { + stextsval -= 4; + if ( stextsval < 0 ) + stextsval = 0; + } + } + else + { + stextsel = stextup; + } + } +} +// 69F108: using guessed type int stextup; +// 6A6BB8: using guessed type int stextscrl; +// 6A8A28: using guessed type int stextsel; + +void __cdecl STextNext() +{ + PlaySFX(IS_TITLEMOV); + if ( stextsel != -1 && stextscrl ) + { + if ( stextsel == stextdown ) + { + if ( stextsval < stextsmax ) + stextsval += 4; + if ( stextsval > stextsmax ) + stextsval = stextsmax; + } + else + { + stextsel = stextdown; + } + } +} +// 6A09E4: using guessed type int stextsmax; +// 6A6BB8: using guessed type int stextscrl; +// 6A8A28: using guessed type int stextsel; +// 6AA700: using guessed type int stextdown; + +void __cdecl S_SmithEnter() +{ + int v0; // ecx + + v0 = 10; + if ( stextsel == 10 ) + { + talker = 0; + stextlhold = 10; + stextshold = 1; + gossipstart = QUEST_GRISWOLD2; + gossipend = QUEST_GRISWOLD13; + _LOBYTE(v0) = STORE_GOSSIP; + goto LABEL_13; + } + v0 = STORE_SBUY; + switch ( stextsel ) + { + case 12: +LABEL_13: + StartStore(v0); + return; + case 14: + _LOBYTE(v0) = STORE_SPBUY; + goto LABEL_13; + case 16: + _LOBYTE(v0) = STORE_SSELL; + goto LABEL_13; + case 18: + _LOBYTE(v0) = STORE_SREPAIR; + goto LABEL_13; + case 20: + stextflag = 0; + break; + } +} +// 69F110: using guessed type int stextlhold; +// 69FB38: using guessed type int talker; +// 6A4EF0: using guessed type int gossipstart; +// 6A8A28: using guessed type int stextsel; +// 6A8A30: using guessed type int gossipend; +// 6AA705: using guessed type char stextflag; + +void __fastcall SetGoldCurs(int pnum, int i) +{ + if ( plr[pnum].InvList[i]._ivalue < 2500 ) + { + if ( plr[pnum].InvList[i]._ivalue > 1000 ) + plr[pnum].InvList[i]._iCurs = 5; + else + plr[pnum].InvList[i]._iCurs = 4; + } + else + { + plr[pnum].InvList[i]._iCurs = 6; + } +} + +void __fastcall SetSpdbarGoldCurs(int pnum, int i) +{ + if ( plr[pnum].SpdList[i]._ivalue < 2500 ) + { + if ( plr[pnum].SpdList[i]._ivalue > 1000 ) + plr[pnum].SpdList[i]._iCurs = 5; + else + plr[pnum].SpdList[i]._iCurs = 4; + } + else + { + plr[pnum].SpdList[i]._iCurs = 6; + } +} + +void __fastcall TakePlrsMoney(int cost) +{ + int v1; // edi + int v2; // eax + int v3; // esi + int v4; // ebx + int v5; // eax + _DWORD *v6; // ecx + int v7; // eax + int v8; // ebx + int v9; // eax + _DWORD *v10; // ecx + int v11; // eax + signed int v12; // ebx + int v13; // eax + int v14; // eax + _DWORD *v15; // ecx + int v16; // eax + signed int v17; // ebx + int v18; // eax + int v19; // eax + _DWORD *v20; // ecx + int v21; // eax + + v1 = cost; + v2 = CalculateGold(myplr); + v3 = myplr; + v4 = 0; + plr[myplr]._pGold = v2 - v1; + while ( v1 > 0 ) + { + v5 = 368 * v4 + 21720 * v3; + if ( *(int *)((char *)&plr[0].SpdList[0]._itype + v5) == ITYPE_GOLD ) + { + v6 = (unsigned int *)((char *)&plr[0].SpdList[0]._ivalue + v5); + v7 = *(int *)((char *)&plr[0].SpdList[0]._ivalue + v5); + if ( v7 != 5000 ) + { + if ( v1 >= v7 ) + { + v1 -= v7; + RemoveSpdBarItem(v3, v4); + v3 = myplr; + v4 = -1; + } + else + { + *v6 = v7 - v1; + SetSpdbarGoldCurs(v3, v4); + v1 = 0; + } + } + } + if ( ++v4 >= 8 ) + { + if ( v1 > 0 ) + { + v8 = 0; + do + { + if ( v1 <= 0 ) + break; + v9 = 368 * v8 + 21720 * v3; + if ( *(int *)((char *)&plr[0].SpdList[0]._itype + v9) == ITYPE_GOLD ) + { + v10 = (unsigned int *)((char *)&plr[0].SpdList[0]._ivalue + v9); + v11 = *(int *)((char *)&plr[0].SpdList[0]._ivalue + v9); + if ( v1 >= v11 ) + { + v1 -= v11; + RemoveSpdBarItem(v3, v8); + v3 = myplr; + v8 = -1; + } + else + { + *v10 = v11 - v1; + SetSpdbarGoldCurs(v3, v8); + v1 = 0; + } + } + ++v8; + } + while ( v8 < 8 ); + } + break; + } + } + v12 = 0; + drawpanflag = 255; + if ( v1 > 0 ) + { + v13 = 21720 * v3; + if ( plr[v3]._pNumInv <= 0 ) + { +LABEL_26: + v17 = 0; + if ( v1 > 0 ) + { + v18 = 21720 * v3; + if ( plr[v3]._pNumInv > 0 ) + { + do + { + if ( v1 <= 0 ) + break; + v19 = 368 * v17 + v18; + if ( *(int *)((char *)&plr[0].InvList[0]._itype + v19) == ITYPE_GOLD ) + { + v20 = (unsigned int *)((char *)&plr[0].InvList[0]._ivalue + v19); + v21 = *(int *)((char *)&plr[0].InvList[0]._ivalue + v19); + if ( v1 >= v21 ) + { + v1 -= v21; + RemoveInvItem(v3, v17); + v3 = myplr; + v17 = -1; + } + else + { + *v20 = v21 - v1; + SetGoldCurs(v3, v17); + v1 = 0; + } + } + ++v17; + v18 = 21720 * v3; + } + while ( v17 < plr[v3]._pNumInv ); + } + } + } + else + { + while ( v1 > 0 ) + { + v14 = 368 * v12 + v13; + if ( *(int *)((char *)&plr[0].InvList[0]._itype + v14) == ITYPE_GOLD ) + { + v15 = (unsigned int *)((char *)&plr[0].InvList[0]._ivalue + v14); + v16 = *(int *)((char *)&plr[0].InvList[0]._ivalue + v14); + if ( v16 != 5000 ) + { + if ( v1 >= v16 ) + { + v1 -= v16; + RemoveInvItem(v3, v12); + v3 = myplr; + v12 = -1; + } + else + { + *v15 = v16 - v1; + SetGoldCurs(v3, v12); + v1 = 0; + } + } + } + ++v12; + v13 = 21720 * v3; + if ( v12 >= plr[v3]._pNumInv ) + goto LABEL_26; + } + } + } +} +// 52571C: using guessed type int drawpanflag; + +void __cdecl SmithBuyItem() +{ + int idx; // eax + ItemStruct *v1; // edx + ItemStruct *v2; // edi + bool v3; // zf + + TakePlrsMoney(plr[myplr].HoldItem._iIvalue); + if ( !plr[myplr].HoldItem._iMagical ) + plr[myplr].HoldItem._iIdentified = 0; + StoreAutoPlace(); + idx = stextvhold + ((stextlhold - stextup) >> 2); + if ( idx == 19 ) + { + smithitem[19]._itype = -1; + } + else + { + if ( smithitem[idx + 1]._itype != -1 ) + { + v1 = &smithitem[idx]; + do + { + v2 = v1; + ++v1; + ++idx; + v3 = v1[1]._itype == -1; + qmemcpy(v2, v1, sizeof(ItemStruct)); + } + while ( !v3 ); + } + smithitem[idx]._itype = -1; + } + CalcPlrInv(myplr, 1u); +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; + +void __cdecl S_SBuyEnter() +{ + int v0; // eax + int idx; // ecx + int done; // eax + int i; // esi + char v4; // cl + + if ( stextsel == 22 ) + { + StartStore(STORE_SMITH); + stextsel = 12; + } + else + { + stextlhold = stextsel; + stextvhold = stextsval; + stextshold = 2; + v0 = myplr; + idx = stextsval + ((stextsel - stextup) >> 2); + if ( plr[myplr]._pGold >= smithitem[idx]._iIvalue ) + { + qmemcpy(&plr[v0].HoldItem, &smithitem[idx], sizeof(plr[v0].HoldItem)); + SetCursor(plr[v0].HoldItem._iCurs + 12); + done = 0; + i = 0; + do + { + if ( done ) + goto LABEL_9; + done = AutoPlace(myplr, i++, cursW / 28, cursH / 28, 0); + } + while ( i < 40 ); + if ( done ) + { +LABEL_9: + v4 = STORE_CONFIRM; + goto LABEL_11; + } + v4 = STORE_NOROOM; +LABEL_11: + StartStore(v4); + SetCursor(CURSOR_HAND); + } + else + { + StartStore(STORE_NOMONEY); + } + } +} +// 4B8C9C: using guessed type int cursH; +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; + +void __cdecl SmithBuyPItem() +{ + int xx; // ecx + int idx; // eax + bool v2; // sf + int v3; // eax + int i; // edx + + TakePlrsMoney(plr[myplr].HoldItem._iIvalue); + if ( !plr[myplr].HoldItem._iMagical ) + plr[myplr].HoldItem._iIdentified = 0; + StoreAutoPlace(); + xx = 0; + idx = (stextlhold - stextup) >> 2; + v2 = stextvhold + idx < 0; + v3 = stextvhold + idx; + i = 0; + if ( !v2 ) + { + do + { + if ( premiumitem[i]._itype != -1 ) + { + --v3; + xx = i; + } + ++i; + } + while ( v3 >= 0 ); + } + + premiumitem[xx]._itype = -1; + --numpremium; + SpawnPremium(plr[myplr]._pLevel); +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; + +void __cdecl S_SPBuyEnter() +{ + int v0; // eax + bool v1; // sf + int v2; // eax + int v3; // ecx + int v4; // edx + int *v5; // esi + int v6; // ecx + int v7; // eax + int v8; // eax + int v9; // esi + char v10; // cl + + if ( stextsel == 22 ) + { + StartStore(STORE_SMITH); + stextsel = 14; + } + else + { + stextlhold = stextsel; + stextshold = 18; + stextvhold = stextsval; + v0 = (stextsel - stextup) >> 2; + v1 = stextsval + v0 < 0; + v2 = stextsval + v0; + v3 = 0; + v4 = 0; + if ( !v1 ) + { + v5 = &premiumitem[0]._itype; + do + { + if ( *v5 != -1 ) + { + --v2; + v3 = v4; + } + ++v4; + v5 += 92; + } + while ( v2 >= 0 ); + } + v6 = v3; + v7 = myplr; + if ( plr[myplr]._pGold >= premiumitem[v6]._iIvalue ) + { + qmemcpy(&plr[v7].HoldItem, &premiumitem[v6], sizeof(plr[v7].HoldItem)); + SetCursor(plr[v7].HoldItem._iCurs + 12); + v8 = 0; + v9 = 0; + do + { + if ( v8 ) + goto LABEL_14; + v8 = AutoPlace(myplr, v9++, cursW / 28, cursH / 28, 0); + } + while ( v9 < 40 ); + if ( v8 ) + { +LABEL_14: + v10 = STORE_CONFIRM; + goto LABEL_16; + } + v10 = STORE_NOROOM; +LABEL_16: + StartStore(v10); + SetCursor(CURSOR_HAND); + } + else + { + StartStore(STORE_NOMONEY); + } + } +} +// 4B8C9C: using guessed type int cursH; +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; + +bool __fastcall StoreGoldFit(int idx) +{ + int cost; // edi + int i; // ecx + int sz; // eax + int numsqrs; // [esp+Ch] [ebp-4h] + + cost = storehold[idx]._iIvalue; + sz = cost / 5000; + if ( cost % 5000 ) + sz++; + + SetCursor(storehold[idx]._iCurs + 12); + numsqrs = cursW / 28 * (cursH / 28); + SetCursor(CURSOR_HAND); + + if ( numsqrs >= sz ) + return 1; + + for(i = 0; i < 40; i++) + { + if ( !plr[myplr].InvGrid[i] ) + numsqrs++; + } + + for(i = 0; i < plr[myplr]._pNumInv; i++) + { + if ( plr[myplr].InvList[i]._itype == ITYPE_GOLD && plr[myplr].InvList[i]._ivalue != 5000 ) + { + cost += plr[myplr].InvList[i]._ivalue; + if ( cost > 5000 ) + cost -= 5000; + else + cost = 0; + } + } + + sz = cost / 5000; + if ( cost % 5000 ) + sz++; + return numsqrs >= sz; +} +// 4B8C9C: using guessed type int cursH; + +void __fastcall PlaceStoreGold(int v) +{ + bool done; // ecx + int ii; // ebp + int xx; // esi + int yy; // ST20_4 + int i; // [esp+10h] [ebp-10h] + + done = 0; + + for(i = 0; i < 40; i++) + { + if ( done ) + break; + ii = 10 * (i / 10); + if ( !plr[myplr].InvGrid[i % 10 + ii] ) + { + xx = plr[myplr]._pNumInv; + yy = plr[myplr]._pNumInv; + GetGoldSeed(myplr, &golditem); + qmemcpy(&plr[myplr].InvList[xx], &golditem, sizeof(ItemStruct)); + ++plr[myplr]._pNumInv; + plr[myplr].InvGrid[i % 10 + ii] = plr[myplr]._pNumInv; + plr[myplr].InvList[xx]._ivalue = v; + SetGoldCurs(myplr, yy); + done = 1; + } + } +} + +void __cdecl StoreSellItem() +{ + int idx; // ebx + char v1; // al + int v2; // eax + int cost; // ebp + bool v4; // sf + unsigned char v5; // of + unsigned int v6; // eax + int v8; // edx + int *v10; // edi + int v11; // eax + unsigned int v12; // esi + int v13; // [esp+10h] [ebp-4h] + + idx = stextvhold + ((stextlhold - stextup) >> 2); + v1 = storehidx[idx]; + if ( v1 < 0 ) + RemoveSpdBarItem(myplr, -1 - v1); + else + RemoveInvItem(myplr, v1); + v2 = storenumh - 1; + cost = storehold[idx]._iIvalue; + v5 = __OFSUB__(idx, storenumh - 1); + v4 = idx - (storenumh-- - 1) < 0; + if ( v4 ^ v5 ) + { + v6 = v2 - idx; + qmemcpy(&storehidx[idx], &storehidx[idx + 1], v6); + qmemcpy(&storehold[idx], &storehold[idx + 1], 4 * (368 * v6 >> 2)); + } + v8 = 0; + v13 = 0; + plr[myplr]._pGold += cost; + if ( plr[myplr]._pNumInv <= 0 ) + { +LABEL_15: + if ( cost > 0 ) + { + if ( cost > 5000 ) + { + v12 = (cost - 5001) / 5000 + 1; + cost += -5000 * v12; + do + { + PlaceStoreGold(5000); + --v12; + } + while ( v12 ); + } + PlaceStoreGold(cost); + } + } + else + { + v10 = &plr[myplr].InvList[0]._ivalue; + while ( cost > 0 ) + { + if ( *(v10 - 47) == ITYPE_GOLD && *v10 != 5000 ) + { + v11 = cost + *v10; + if ( v11 > 5000 ) + { + *v10 = 5000; + cost = v11 - 5000; + SetGoldCurs(myplr, v8); + } + else + { + *v10 = v11; + SetGoldCurs(myplr, v8); + cost = 0; + } + } + v10 += 92; + v8 = v13++ + 1; + if ( v13 >= plr[myplr]._pNumInv ) + goto LABEL_15; + } + } +} +// 69F108: using guessed type int stextup; +// 69F10C: using guessed type int storenumh; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; + +void __cdecl S_SSellEnter() +{ + int idx; // eax + + if ( stextsel == 22 ) + { + StartStore(STORE_SMITH); + stextsel = 16; + } + else + { + stextlhold = stextsel; + idx = stextsval + ((stextsel - stextup) >> 2); + stextshold = 3; + stextvhold = stextsval; + + qmemcpy(&plr[myplr].HoldItem, &storehold[idx], sizeof(plr[myplr].HoldItem)); + + if ( !StoreGoldFit(idx) ) + StartStore(STORE_NOROOM); + else + StartStore(STORE_CONFIRM); + } +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; + +void __cdecl SmithRepairItem() +{ + int i; // edx + int idx; // eax + + TakePlrsMoney(plr[myplr].HoldItem._iIvalue); + + idx = stextvhold + ((stextlhold - stextup) >> 2); + i = storehidx[idx]; + storehold[idx]._iDurability = storehold[idx]._iMaxDur; + + if ( i >= 0 ) + { + plr[myplr].InvList[i]._iDurability = plr[myplr].InvList[i]._iMaxDur; + } + else + { + if ( i == -1 ) + plr[myplr].InvBody[0]._iDurability = plr[myplr].InvBody[0]._iMaxDur; + if ( i == -2 ) + plr[myplr].InvBody[6]._iDurability = plr[myplr].InvBody[6]._iMaxDur; + if ( i == -3 ) + plr[myplr].InvBody[4]._iDurability = plr[myplr].InvBody[4]._iMaxDur; + if ( i == -4 ) + plr[myplr].InvBody[5]._iDurability = plr[myplr].InvBody[5]._iMaxDur; + } +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; + +void __cdecl S_SRepairEnter() +{ + int idx; // eax + int v1; // edx + int v2; // ecx + bool v3; // sf + unsigned char v4; // of + char v5; // cl + + if ( stextsel == 22 ) + { + StartStore(STORE_SMITH); + stextsel = 18; + } + else + { + stextlhold = stextsel; + stextshold = 4; + idx = stextsval + ((stextsel - stextup) >> 2); + v1 = myplr; + stextvhold = stextsval; + qmemcpy(&plr[myplr].HoldItem, &storehold[idx], sizeof(plr[myplr].HoldItem)); + v2 = plr[v1]._pGold; + v4 = __OFSUB__(v2, storehold[idx]._iIvalue); + v3 = v2 - storehold[idx]._iIvalue < 0; + v5 = STORE_NOMONEY; + if ( !(v3 ^ v4) ) + v5 = STORE_CONFIRM; + StartStore(v5); + } +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; + +void __cdecl S_WitchEnter() +{ + int v0; // ecx + + v0 = 12; + if ( stextsel == 12 ) + { + stextlhold = 12; + talker = 6; + stextshold = 5; + gossipstart = QUEST_ADRIA2; + gossipend = QUEST_ADRIA13; + _LOBYTE(v0) = STORE_GOSSIP; + goto LABEL_12; + } + v0 = 2; + switch ( stextsel ) + { + case 14: + _LOBYTE(v0) = STORE_WBUY; + goto LABEL_12; + case 16: + _LOBYTE(v0) = STORE_WSELL; + goto LABEL_12; + case 18: + _LOBYTE(v0) = STORE_WRECHARGE; +LABEL_12: + StartStore(v0); + return; + case 20: + stextflag = 0; + break; + } +} +// 69F110: using guessed type int stextlhold; +// 69FB38: using guessed type int talker; +// 6A4EF0: using guessed type int gossipstart; +// 6A8A28: using guessed type int stextsel; +// 6A8A30: using guessed type int gossipend; +// 6AA705: using guessed type char stextflag; + +void __cdecl WitchBuyItem() +{ + int idx; // ebx + ItemStruct *v3; // eax + ItemStruct *v4; // edi + + idx = stextvhold + ((stextlhold - stextup) >> 2); + + if ( idx < 3 ) + plr[myplr].HoldItem._iSeed = GetRndSeed(); + + TakePlrsMoney(plr[myplr].HoldItem._iIvalue); + StoreAutoPlace(); + + if ( idx >= 3 ) + { + if ( idx == 19 ) + { + witchitem[19]._itype = -1; + } + else + { + if ( witchitem[idx + 1]._itype != -1 ) + { + v3 = &witchitem[idx]; + do + { + v4 = v3; + ++v3; + ++idx; + qmemcpy(v4, v3, sizeof(ItemStruct)); + } + while ( v3[1]._itype != -1 ); + } + witchitem[idx]._itype = -1; + } + } + CalcPlrInv(myplr, 1u); +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; + +void __cdecl S_WBuyEnter() +{ + int idx; // ecx + int done; // eax + int i; // esi + + if ( stextsel == 22 ) + { + StartStore(STORE_WITCH); + stextsel = 14; + } + else + { + stextlhold = stextsel; + stextvhold = stextsval; + stextshold = 6; + idx = stextsval + ((stextsel - stextup) >> 2); + + if ( plr[myplr]._pGold >= witchitem[idx]._iIvalue ) + { + qmemcpy(&plr[myplr].HoldItem, &witchitem[idx], sizeof(ItemStruct)); + SetCursor(plr[myplr].HoldItem._iCurs + 12); + done = 0; + + for(i = 0; i < 40; i++) + { + if ( done ) + break; + done = SpecialAutoPlace(myplr, i, cursW / 28, cursH / 28, 0); + } + + if ( done ) + StartStore(STORE_CONFIRM); + else + StartStore(STORE_NOROOM); + + SetCursor(CURSOR_HAND); + } + else + { + StartStore(STORE_NOMONEY); + } + } +} +// 4B8C9C: using guessed type int cursH; +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; + +void __cdecl S_WSellEnter() +{ + int idx; // eax + char v2; // cl + + if ( stextsel == 22 ) + { + StartStore(STORE_WITCH); + stextsel = 16; + } + else + { + stextlhold = stextsel; + idx = stextsval + ((stextsel - stextup) >> 2); + stextshold = 7; + stextvhold = stextsval; + qmemcpy(&plr[myplr].HoldItem, &storehold[idx], sizeof(plr[myplr].HoldItem)); + v2 = STORE_CONFIRM; + if ( !StoreGoldFit(idx) ) + v2 = STORE_NOROOM; + StartStore(v2); + } +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; + +void __cdecl WitchRechargeItem() +{ + int i; // ecx + int idx; // eax + + TakePlrsMoney(plr[myplr].HoldItem._iIvalue); + + idx = stextvhold + ((stextlhold - stextup) >> 2); + i = storehidx[idx]; + storehold[idx]._iCharges = storehold[idx]._iMaxCharges; + + if ( i >= 0 ) + plr[myplr].InvList[i]._iCharges = plr[myplr].InvList[i]._iMaxCharges; + else + plr[myplr].InvBody[4]._iCharges = plr[myplr].InvBody[4]._iMaxCharges; + + CalcPlrInv(myplr, 1u); +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; + +void __cdecl S_WRechargeEnter() +{ + int idx; // eax + int v1; // edx + int v2; // ecx + bool v3; // sf + unsigned char v4; // of + char v5; // cl + + if ( stextsel == 22 ) + { + StartStore(STORE_WITCH); + stextsel = 18; + } + else + { + stextlhold = stextsel; + stextshold = 8; + idx = stextsval + ((stextsel - stextup) >> 2); + v1 = myplr; + stextvhold = stextsval; + qmemcpy(&plr[myplr].HoldItem, &storehold[idx], sizeof(plr[myplr].HoldItem)); + v2 = plr[v1]._pGold; + v4 = __OFSUB__(v2, storehold[idx]._iIvalue); + v3 = v2 - storehold[idx]._iIvalue < 0; + v5 = STORE_NOMONEY; + if ( !(v3 ^ v4) ) + v5 = STORE_CONFIRM; + StartStore(v5); + } +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; + +void __cdecl S_BoyEnter() +{ + signed int v0; // ecx + + v0 = boyitem._itype; + if ( boyitem._itype != -1 && stextsel == 18 ) + { + v0 = 50; + if ( plr[myplr]._pGold >= 50 ) + { + TakePlrsMoney(50); + _LOBYTE(v0) = STORE_BBOY; + } + else + { + stextshold = 12; + stextlhold = 18; + stextvhold = stextsval; + _LOBYTE(v0) = STORE_NOMONEY; + } + goto LABEL_5; + } + if ( stextsel == 8 && boyitem._itype != -1 || stextsel == 12 && boyitem._itype == -1 ) + { + talker = 8; + stextshold = 12; + stextlhold = stextsel; + gossipstart = QUEST_WIRT2; + gossipend = QUEST_WIRT12; + _LOBYTE(v0) = STORE_GOSSIP; +LABEL_5: + StartStore(v0); + return; + } + stextflag = 0; +} +// 69F110: using guessed type int stextlhold; +// 69FB38: using guessed type int talker; +// 6A4EF0: using guessed type int gossipstart; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; +// 6A8A30: using guessed type int gossipend; +// 6AA705: using guessed type char stextflag; + +void __cdecl BoyBuyItem() +{ + TakePlrsMoney(plr[myplr].HoldItem._iIvalue); + StoreAutoPlace(); + boyitem._itype = -1; + stextshold = 12; + CalcPlrInv(myplr, 1u); +} + +void __cdecl HealerBuyItem() +{ + int idx; // esi + bool v1; // sf + unsigned char v2; // of + int v3; // eax + int v4; // ecx + bool v5; // sf + unsigned char v6; // of + int v7; // eax + ItemStruct *v8; // edx + ItemStruct *v9; // edi + bool v10; // zf + + idx = stextvhold + ((stextlhold - stextup) >> 2); + if ( gbMaxPlayers == 1 ) + { + v2 = __OFSUB__(idx, 2); + v1 = idx - 2 < 0; + } + else + { + v2 = __OFSUB__(idx, 3); + v1 = idx - 3 < 0; + } + if ( v1 ^ v2 ) + { + v3 = GetRndSeed(); + v4 = myplr; + plr[myplr].HoldItem._iSeed = v3; + } + else + { + v4 = myplr; + } + TakePlrsMoney(plr[v4].HoldItem._iIvalue); + if ( !plr[myplr].HoldItem._iMagical ) + plr[myplr].HoldItem._iIdentified = 0; + StoreAutoPlace(); + if ( gbMaxPlayers == 1 ) + { + v6 = __OFSUB__(idx, 2); + v5 = idx - 2 < 0; + } + else + { + v6 = __OFSUB__(idx, 3); + v5 = idx - 3 < 0; + } + if ( !(v5 ^ v6) ) + { + v7 = stextvhold + ((stextlhold - stextup) >> 2); + if ( v7 == 19 ) + { + healitem[19]._itype = -1; + } + else + { + if ( healitem[v7 + 1]._itype != -1 ) + { + v8 = &healitem[v7]; + do + { + v9 = v8; + ++v8; + ++v7; + v10 = v8[1]._itype == -1; + qmemcpy(v9, v8, sizeof(ItemStruct)); + } + while ( !v10 ); + } + healitem[v7]._itype = -1; + } + CalcPlrInv(myplr, 1u); + } +} +// 679660: using guessed type char gbMaxPlayers; +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; + +void __cdecl S_BBuyEnter() +{ + int v0; // ecx + int v1; // eax + int v2; // ecx + int v3; // eax + int v4; // esi + + if ( stextsel == 10 ) + { + v0 = boyitem._iIvalue; + stextvhold = stextsval; + v1 = myplr; + stextshold = 13; + stextlhold = 10; + if ( plr[myplr]._pGold >= boyitem._iIvalue + (boyitem._iIvalue >> 1) ) + { + qmemcpy(&plr[v1].HoldItem, &boyitem, sizeof(plr[v1].HoldItem)); + plr[v1].HoldItem._iIvalue += plr[v1].HoldItem._iIvalue >> 1; + SetCursor(plr[v1].HoldItem._iCurs + 12); + v3 = 0; + v4 = 0; + do + { + if ( v3 ) + goto LABEL_8; + v3 = AutoPlace(myplr, v4++, cursW / 28, cursH / 28, 0); + } + while ( v4 < 40 ); + if ( v3 ) + { +LABEL_8: + _LOBYTE(v2) = STORE_CONFIRM; + goto LABEL_10; + } + _LOBYTE(v2) = STORE_NOROOM; +LABEL_10: + StartStore(v2); + SetCursor(CURSOR_HAND); + } + else + { + _LOBYTE(v0) = STORE_NOMONEY; + StartStore(v0); + } + } + else + { + stextflag = 0; + } +} +// 4B8C9C: using guessed type int cursH; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; +// 6AA705: using guessed type char stextflag; + +void __cdecl StoryIdItem() +{ + int v0; // ecx + int v1; // eax + int v2; // eax + + v0 = storehidx[((stextlhold - stextup) >> 2) + stextvhold]; + v1 = myplr; + if ( v0 >= 0 ) + { + plr[myplr].InvList[v0]._iIdentified = 1; + } + else + { + if ( v0 == -1 ) + plr[myplr].InvBody[0]._iIdentified = 1; + if ( v0 == -2 ) + plr[v1].InvBody[6]._iIdentified = 1; + if ( v0 == -3 ) + plr[v1].InvBody[4]._iIdentified = 1; + if ( v0 == -4 ) + plr[v1].InvBody[5]._iIdentified = 1; + if ( v0 == -5 ) + plr[v1].InvBody[1]._iIdentified = 1; + if ( v0 == -6 ) + plr[v1].InvBody[2]._iIdentified = 1; + if ( v0 == -7 ) + plr[v1].InvBody[3]._iIdentified = 1; + } + v2 = v1; + plr[v2].HoldItem._iIdentified = 1; + TakePlrsMoney(plr[v2].HoldItem._iIvalue); + CalcPlrInv(myplr, 1u); +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; + +void __cdecl S_ConfirmEnter() +{ + char v0; // cl + + if ( stextsel == 18 ) + { + if ( stextshold > STORE_WRECHARGE ) + { + switch ( stextshold ) + { + case STORE_BBOY: + BoyBuyItem(); + break; + case STORE_HBUY: + HealerBuyItem(); + break; + case STORE_SIDENTIFY: + StoryIdItem(); + v0 = STORE_IDSHOW; +LABEL_20: + StartStore(v0); + return; + case STORE_SPBUY: + SmithBuyPItem(); + break; + } + } + else + { + switch ( stextshold ) + { + case STORE_WRECHARGE: + WitchRechargeItem(); + break; + case STORE_SBUY: + SmithBuyItem(); + break; + case STORE_SSELL: + goto LABEL_27; + case STORE_SREPAIR: + SmithRepairItem(); + break; + case STORE_WBUY: + WitchBuyItem(); + break; + case STORE_WSELL: +LABEL_27: + StoreSellItem(); + break; + } + } + v0 = stextshold; + goto LABEL_20; + } + StartStore((unsigned char)stextshold); + stextsel = stextlhold; + stextsval = stextvhold; +} +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; + +void __cdecl S_HealerEnter() +{ + int v0; // ecx + int v1; // eax + + v0 = 12; + if ( stextsel == 12 ) + { + stextlhold = 12; + talker = 1; + stextshold = 14; + gossipstart = QUEST_PEPIN2; + gossipend = QUEST_PEPIN11; + _LOBYTE(v0) = STORE_GOSSIP; + goto LABEL_12; + } + if ( stextsel != 14 ) + { + if ( stextsel != 16 ) + { + if ( stextsel == 18 ) + stextflag = 0; + return; + } + _LOBYTE(v0) = STORE_HBUY; +LABEL_12: + StartStore(v0); + return; + } + if ( plr[myplr]._pHitPoints != plr[myplr]._pMaxHP ) + PlaySFX(IS_CAST8); + drawhpflag = 1; + v1 = myplr; + plr[v1]._pHitPoints = plr[myplr]._pMaxHP; + plr[v1]._pHPBase = plr[v1]._pMaxHPBase; +} +// 69F110: using guessed type int stextlhold; +// 69FB38: using guessed type int talker; +// 6A4EF0: using guessed type int gossipstart; +// 6A8A28: using guessed type int stextsel; +// 6A8A30: using guessed type int gossipend; +// 6AA705: using guessed type char stextflag; + +void __cdecl S_HBuyEnter() +{ + int v0; // eax + int idx; // ecx + int done; // eax + int i; // esi + char v4; // cl + + if ( stextsel == 22 ) + { + StartStore(STORE_HEALER); + stextsel = 16; + } + else + { + stextlhold = stextsel; + stextvhold = stextsval; + stextshold = 16; + v0 = myplr; + idx = stextsval + ((stextsel - stextup) >> 2); + if ( plr[myplr]._pGold >= healitem[idx]._iIvalue ) + { + qmemcpy(&plr[v0].HoldItem, &healitem[idx], sizeof(plr[v0].HoldItem)); + SetCursor(plr[v0].HoldItem._iCurs + 12); + done = 0; + i = 0; + do + { + if ( done ) + goto LABEL_9; + done = SpecialAutoPlace(myplr, i++, cursW / 28, cursH / 28, 0); + } + while ( i < 40 ); + if ( done ) + { +LABEL_9: + v4 = STORE_CONFIRM; + goto LABEL_11; + } + v4 = STORE_NOROOM; +LABEL_11: + StartStore(v4); + SetCursor(CURSOR_HAND); + } + else + { + StartStore(STORE_NOMONEY); + } + } +} +// 4B8C9C: using guessed type int cursH; +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; + +void __cdecl S_StoryEnter() +{ + int v0; // ecx + + v0 = 12; + switch ( stextsel ) + { + case 12: + stextlhold = 12; + talker = 4; + stextshold = 15; + gossipstart = QUEST_STORY2; + gossipend = QUEST_STORY11; + _LOBYTE(v0) = STORE_GOSSIP; + goto LABEL_8; + case 14: + _LOBYTE(v0) = STORE_SIDENTIFY; +LABEL_8: + StartStore(v0); + return; + case 18: + stextflag = 0; + break; + } +} +// 69F110: using guessed type int stextlhold; +// 69FB38: using guessed type int talker; +// 6A4EF0: using guessed type int gossipstart; +// 6A8A28: using guessed type int stextsel; +// 6A8A30: using guessed type int gossipend; +// 6AA705: using guessed type char stextflag; + +void __cdecl S_SIDEnter() +{ + int idx; // eax + int v1; // edx + int v2; // ecx + bool v3; // sf + unsigned char v4; // of + char v5; // cl + + if ( stextsel == 22 ) + { + StartStore(STORE_STORY); + stextsel = 14; + } + else + { + stextlhold = stextsel; + stextshold = 17; + idx = stextsval + ((stextsel - stextup) >> 2); + v1 = myplr; + stextvhold = stextsval; + qmemcpy(&plr[myplr].HoldItem, &storehold[idx], sizeof(plr[myplr].HoldItem)); + v2 = plr[v1]._pGold; + v4 = __OFSUB__(v2, storehold[idx]._iIvalue); + v3 = v2 - storehold[idx]._iIvalue < 0; + v5 = STORE_NOMONEY; + if ( !(v3 ^ v4) ) + v5 = STORE_CONFIRM; + StartStore(v5); + } +} +// 69F108: using guessed type int stextup; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; + +void __cdecl S_TalkEnter() +{ + int v0; // edx + int *v1; // edi + signed int v2; // eax + int v3; // esi + int *v4; // ecx + int v5; // esi + signed int v6; // ebp + int v8; // eax + int v9; // ebx + int v10; // ecx + + if ( stextsel == 22 ) + { + StartStore((unsigned char)stextshold); + stextsel = stextlhold; + } + else + { + v0 = talker; + v1 = &quests[0]._qlog; + v2 = 0; + v3 = 0; + v4 = &quests[0]._qlog; + do + { + if ( *((_BYTE *)v4 - 18) == 2 && *((_DWORD *)&Qtalklist[0]._qinfra + v3 + 16 * talker) != -1 && *v4 ) + ++v2; + v4 += 6; + ++v3; + } + while ( (signed int)v4 < (signed int)&quests[16]._qlog ); + if ( v2 <= 6 ) + { + v5 = 15 - v2; + v6 = 2; + } + else + { + v5 = 14 - (v2 >> 1); + v6 = 1; + } + if ( stextsel == v5 - 2 ) + { + SetRndSeed(towner[talker]._tSeed); + v8 = random(0, gossipend - gossipstart + 1); + InitQTextMsg(gossipstart + v8); + } + else + { + v9 = 0; + do + { + if ( *((_BYTE *)v1 - 18) == 2 ) + { + v10 = *((_DWORD *)&Qtalklist[0]._qinfra + v9 + 16 * v0); + if ( v10 != -1 ) + { + if ( *v1 ) + { + if ( v5 == stextsel ) + { + InitQTextMsg(v10); + v0 = talker; + } + v5 += v6; + } + } + } + v1 += 6; + ++v9; + } + while ( (signed int)v1 < (signed int)&quests[16]._qlog ); + } + } +} +// 69F110: using guessed type int stextlhold; +// 69FB38: using guessed type int talker; +// 6A4EF0: using guessed type int gossipstart; +// 6A8A28: using guessed type int stextsel; +// 6A8A30: using guessed type int gossipend; + +void __cdecl S_TavernEnter() +{ + int v0; // ecx + + v0 = 12; + if ( stextsel == 12 ) + { + stextlhold = 12; + talker = 3; + stextshold = 21; + gossipstart = QUEST_OGDEN2; + gossipend = QUEST_OGDEN10; + _LOBYTE(v0) = STORE_GOSSIP; + StartStore(v0); + } + else if ( stextsel == 18 ) + { + stextflag = 0; + } +} +// 69F110: using guessed type int stextlhold; +// 69FB38: using guessed type int talker; +// 6A4EF0: using guessed type int gossipstart; +// 6A8A28: using guessed type int stextsel; +// 6A8A30: using guessed type int gossipend; +// 6AA705: using guessed type char stextflag; + +void __cdecl S_BarmaidEnter() +{ + int v0; // ecx + + v0 = 12; + if ( stextsel == 12 ) + { + stextlhold = 12; + talker = 7; + stextshold = 23; + gossipstart = QUEST_GILLIAN2; + gossipend = QUEST_GILLIAN10; + _LOBYTE(v0) = STORE_GOSSIP; + StartStore(v0); + } + else if ( stextsel == 18 ) + { + stextflag = 0; + } +} +// 69F110: using guessed type int stextlhold; +// 69FB38: using guessed type int talker; +// 6A4EF0: using guessed type int gossipstart; +// 6A8A28: using guessed type int stextsel; +// 6A8A30: using guessed type int gossipend; +// 6AA705: using guessed type char stextflag; + +void __cdecl S_DrunkEnter() +{ + int v0; // ecx + + v0 = 12; + if ( stextsel == 12 ) + { + stextlhold = 12; + talker = 5; + stextshold = 22; + gossipstart = QUEST_FARNHAM2; + gossipend = QUEST_FARNHAM13; + _LOBYTE(v0) = STORE_GOSSIP; + StartStore(v0); + } + else if ( stextsel == 18 ) + { + stextflag = 0; + } +} +// 69F110: using guessed type int stextlhold; +// 69FB38: using guessed type int talker; +// 6A4EF0: using guessed type int gossipstart; +// 6A8A28: using guessed type int stextsel; +// 6A8A30: using guessed type int gossipend; +// 6AA705: using guessed type char stextflag; + +void __cdecl STextEnter() +{ + if ( qtextflag ) + { + qtextflag = 0; + if ( leveltype == DTYPE_TOWN ) + sfx_stop(); + } + else + { + PlaySFX(IS_TITLSLCT); + switch ( stextflag ) + { + case STORE_SMITH: + S_SmithEnter(); + break; + case STORE_SBUY: + S_SBuyEnter(); + break; + case STORE_SSELL: + S_SSellEnter(); + break; + case STORE_SREPAIR: + S_SRepairEnter(); + break; + case STORE_WITCH: + S_WitchEnter(); + break; + case STORE_WBUY: + S_WBuyEnter(); + break; + case STORE_WSELL: + S_WSellEnter(); + break; + case STORE_WRECHARGE: + S_WRechargeEnter(); + break; + case STORE_NOMONEY: + case STORE_NOROOM: + StartStore(stextshold); + stextsel = stextlhold; + stextsval = stextvhold; + break; + case STORE_CONFIRM: + S_ConfirmEnter(); + break; + case STORE_BOY: + S_BoyEnter(); + break; + case STORE_BBOY: + S_BBuyEnter(); + break; + case STORE_HEALER: + S_HealerEnter(); + break; + case STORE_STORY: + S_StoryEnter(); + break; + case STORE_HBUY: + S_HBuyEnter(); + break; + case STORE_SIDENTIFY: + S_SIDEnter(); + break; + case STORE_SPBUY: + S_SPBuyEnter(); + break; + case STORE_GOSSIP: + S_TalkEnter(); + break; + case STORE_IDSHOW: + StartStore(STORE_SIDENTIFY); + break; + case STORE_TAVERN: + S_TavernEnter(); + break; + case STORE_DRUNK: + S_DrunkEnter(); + break; + case STORE_BARMAID: + S_BarmaidEnter(); + break; + default: + return; + } + } +} +// 5BB1ED: using guessed type char leveltype; +// 646D00: using guessed type char qtextflag; +// 69F110: using guessed type int stextlhold; +// 6A8A24: using guessed type int stextvhold; +// 6A8A28: using guessed type int stextsel; +// 6AA705: using guessed type char stextflag; + +void __cdecl CheckStoreBtn() +{ + bool v0; // sf + unsigned char v1; // of + int v2; // eax + int *v3; // ecx + + if ( qtextflag ) + { + qtextflag = 0; + if ( leveltype == DTYPE_TOWN ) + sfx_stop(); + } + else if ( stextsel != -1 && MouseY >= 32 && MouseY <= 320 ) + { + if ( stextsize ) + { + v1 = __OFSUB__(MouseX, 24); + v0 = MouseX - 24 < 0; + } + else + { + v1 = __OFSUB__(MouseX, 344); + v0 = MouseX - 344 < 0; + } + if ( !(v0 ^ v1) && MouseX <= 616 ) + { + v2 = (MouseY - 32) / 12; + if ( stextscrl && MouseX > 600 ) + { + if ( v2 == 4 ) + { + if ( stextscrlubtn <= 0 ) + { + STextUp(); + stextscrlubtn = 10; + return; + } + --stextscrlubtn; + } + if ( v2 == 20 ) + { + if ( stextscrldbtn > 0 ) + { + --stextscrldbtn; + } + else + { + STextDown(); + stextscrldbtn = 10; + } + } + } + else if ( v2 >= 5 ) + { + if ( v2 >= 23 ) + v2 = 22; + if ( stextscrl ) + { + if ( v2 < 21 ) + { + v3 = &stext[v2]._ssel; + if ( !*v3 ) + { + if ( stext[v2 - 2]._ssel ) + { + v2 -= 2; + } + else if ( *(v3 - 39) ) + { + --v2; + } + } + } + } + if ( stext[v2]._ssel || stextscrl && v2 == 22 ) + { + stextsel = v2; + STextEnter(); + } + } + } + } +} +// 5BB1ED: using guessed type char leveltype; +// 646D00: using guessed type char qtextflag; +// 6A09E0: using guessed type char stextsize; +// 6A6BB8: using guessed type int stextscrl; +// 6A8A28: using guessed type int stextsel; +// 6A8A2C: using guessed type char stextscrldbtn; +// 6AA704: using guessed type char stextscrlubtn; + +void __cdecl ReleaseStoreBtn() +{ + stextscrlubtn = -1; + stextscrldbtn = -1; +} +// 6A8A2C: using guessed type char stextscrldbtn; +// 6AA704: using guessed type char stextscrlubtn; diff --git a/Source/stores.h b/Source/stores.h new file mode 100644 index 000000000..16b0c0fd2 --- /dev/null +++ b/Source/stores.h @@ -0,0 +1,140 @@ +//HEADER_GOES_HERE +#ifndef __STORES_H__ +#define __STORES_H__ + +extern int stextup; // weak +extern int storenumh; // weak +extern int stextlhold; // weak +extern ItemStruct boyitem; +extern int stextshold; // idb +extern ItemStruct premiumitem[6]; +extern void *pSTextBoxCels; +extern int premiumlevel; // idb +extern int talker; // weak +extern STextStruct stext[24]; +extern char stextsize; // weak +extern int stextsmax; // weak +extern int InStoreFlag; // idb +extern ItemStruct storehold[48]; +extern int gossipstart; // weak +extern ItemStruct witchitem[20]; +extern int stextscrl; // weak +extern int numpremium; // idb +extern ItemStruct healitem[20]; +extern ItemStruct golditem; +extern char storehidx[48]; +extern void *pSTextSlidCels; +extern int stextvhold; // weak +extern int stextsel; // weak +extern char stextscrldbtn; // weak +extern int gossipend; // weak +extern void *pCelBuff; +extern int stextsval; // idb +extern int boylevel; // weak +extern ItemStruct smithitem[20]; +extern int stextdown; // weak +extern char stextscrlubtn; // weak +extern char stextflag; // weak + +void __cdecl InitStores(); +void __cdecl SetupTownStores(); +void __cdecl FreeStoreMem(); +void __cdecl DrawSTextBack(); +void __fastcall PrintSString(int x, int y, unsigned char cjustflag, char *str, int col, int val); +void __fastcall DrawSLine(int y); +void __fastcall DrawSArrows(int y1, int y2); +void __cdecl DrawSTextHelp(); +void __fastcall ClearSText(int s, int e); +void __fastcall AddSLine(int y); +void __fastcall AddSTextVal(int y, int val); +void __fastcall OffsetSTextY(int y, int yo); +void __fastcall AddSText(int x, int y, unsigned char j, char *str, int clr, int sel); +void __cdecl StoreAutoPlace(); +void __cdecl S_StartSmith(); +void __fastcall S_ScrollSBuy(int idx); +void __fastcall PrintStoreItem(ItemStruct *x, int l, char iclr); +void __cdecl S_StartSBuy(); +void __fastcall S_ScrollSPBuy(int idx); +bool __cdecl S_StartSPBuy(); +bool __fastcall SmithSellOk(int i); +void __fastcall S_ScrollSSell(int idx); +void __cdecl S_StartSSell(); +bool __fastcall SmithRepairOk(int i); +void __cdecl S_StartSRepair(); +void __fastcall AddStoreHoldRepair(ItemStruct *itm, int i); +void __cdecl S_StartWitch(); +void __fastcall S_ScrollWBuy(int idx); +void __cdecl S_StartWBuy(); +bool __fastcall WitchSellOk(int i); +void __cdecl S_StartWSell(); +bool __fastcall WitchRechargeOk(int i); +void __fastcall AddStoreHoldRecharge(ItemStruct itm, int i); +void __cdecl S_StartWRecharge(); +void __cdecl S_StartNoMoney(); +void __cdecl S_StartNoRoom(); +void __cdecl S_StartConfirm(); +void __cdecl S_StartBoy(); +void __cdecl S_StartBBoy(); +void __cdecl S_StartHealer(); +void __fastcall S_ScrollHBuy(int idx); +void __cdecl S_StartHBuy(); +void __cdecl S_StartStory(); +bool __fastcall IdItemOk(ItemStruct *i); +void __fastcall AddStoreHoldId(ItemStruct itm, int i); +void __cdecl S_StartSIdentify(); +void __cdecl S_StartIdShow(); +void __cdecl S_StartTalk(); +void __cdecl S_StartTavern(); +void __cdecl S_StartBarMaid(); +void __cdecl S_StartDrunk(); +void __fastcall StartStore(char s); +void __cdecl DrawSText(); +void __cdecl STextESC(); +void __cdecl STextUp(); +void __cdecl STextDown(); +void __cdecl STextPrior(); +void __cdecl STextNext(); +void __cdecl S_SmithEnter(); +void __fastcall SetGoldCurs(int pnum, int i); +void __fastcall SetSpdbarGoldCurs(int pnum, int i); +void __fastcall TakePlrsMoney(int cost); +void __cdecl SmithBuyItem(); +void __cdecl S_SBuyEnter(); +void __cdecl SmithBuyPItem(); +void __cdecl S_SPBuyEnter(); +bool __fastcall StoreGoldFit(int idx); +void __fastcall PlaceStoreGold(int v); +void __cdecl StoreSellItem(); +void __cdecl S_SSellEnter(); +void __cdecl SmithRepairItem(); +void __cdecl S_SRepairEnter(); +void __cdecl S_WitchEnter(); +void __cdecl WitchBuyItem(); +void __cdecl S_WBuyEnter(); +void __cdecl S_WSellEnter(); +void __cdecl WitchRechargeItem(); +void __cdecl S_WRechargeEnter(); +void __cdecl S_BoyEnter(); +void __cdecl BoyBuyItem(); +void __cdecl HealerBuyItem(); +void __cdecl S_BBuyEnter(); +void __cdecl StoryIdItem(); +void __cdecl S_ConfirmEnter(); +void __cdecl S_HealerEnter(); +void __cdecl S_HBuyEnter(); +void __cdecl S_StoryEnter(); +void __cdecl S_SIDEnter(); +void __cdecl S_TalkEnter(); +void __cdecl S_TavernEnter(); +void __cdecl S_BarmaidEnter(); +void __cdecl S_DrunkEnter(); +void __cdecl STextEnter(); +void __cdecl CheckStoreBtn(); +void __cdecl ReleaseStoreBtn(); + +/* rdata */ + +extern int SStringY[24]; +extern char *talkname[9]; + +#endif /* __STORES_H__ */ diff --git a/Source/sync.cpp b/Source/sync.cpp new file mode 100644 index 000000000..dd7fa6d18 --- /dev/null +++ b/Source/sync.cpp @@ -0,0 +1,384 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +short sync_word_6AA708[MAXMONSTERS]; +int syncmonsters; // weak +short sync_word_6AA89C[MAXMONSTERS]; +int syncitems; +int sgnSyncPInv; // weak +#endif + +int __fastcall sync_all_monsters(TSyncHeader *packet, int size) +{ + int result; // eax + TSyncHeader *v3; // esi + int v4; // ebx + TSyncMonster *v5; // edi + unsigned int v6; // [esp+4h] [ebp-4h] + + result = size; + if ( nummonsters >= 1 && (unsigned int)size >= 0x2B ) + { + v3 = packet; + v6 = size - 38; + v4 = 0; + packet->bCmd = CMD_SYNCDATA; + v5 = (TSyncMonster *)(&packet->bPInvId + 1); + packet->bLevel = currlevel; + packet->wLen = 0; + SyncPlrInv(packet); + sync_one_monster(); + if ( nummonsters > 0 ) + { + do + { + if ( v6 < 5 || (v4 >= 2 || !sync_monster_active2(v5)) && !sync_monster_active(v5) ) + break; + v3->wLen += 5; + v6 -= 5; + ++v5; + ++v4; + } + while ( v4 < nummonsters ); + } + result = v6; + } + return result; +} + +void __cdecl sync_one_monster() +{ + int i; // ebx + int v1; // edi + int v2; // esi + short v3; // bp + short v4; // ax + bool v5; // zf + short *v6; // edx + short *v7; // eax + + for ( i = 0; i < nummonsters; ++i ) + { + v1 = monstactive[i]; + v2 = monstactive[i]; + v3 = abs(plr[myplr].WorldY - monster[v2]._my); + v4 = abs(plr[myplr].WorldX - monster[v2]._mx); + v5 = monster[v2]._msquelch == 0; + v6 = &sync_word_6AA708[v1]; + *v6 = v4 + v3; + if ( v5 ) + { + *v6 = v4 + v3 + 4096; + } + else + { + v7 = &sync_word_6AA89C[v1]; + if ( *v7 ) + --*v7; + } + } +} + +int __fastcall sync_monster_active(TSyncMonster *packet) +{ + unsigned int v1; // ebx + int v2; // esi + int v3; // edx + int v4; // eax + + v1 = -1; + v2 = 0; + v3 = -1; + if ( nummonsters <= 0 ) + return 0; + do + { + v4 = monstactive[v2]; + if ( (unsigned short)sync_word_6AA708[v4] < v1 && (unsigned short)sync_word_6AA89C[v4] < 0xFFFEu ) + { + v1 = (unsigned short)sync_word_6AA708[v4]; + v3 = monstactive[v2]; + } + ++v2; + } + while ( v2 < nummonsters ); + if ( v3 == -1 ) + return 0; + sync_monster_pos(packet, v3); + return 1; +} + +void __fastcall sync_monster_pos(TSyncMonster *packet, int mon_id) +{ + int v2; // ebx + TSyncMonster *v3; // esi + int v4; // edi + int v5; // eax + short v6; // cx + char v7; // cl + + v2 = mon_id; + v3 = packet; + v4 = mon_id; + packet->_mndx = mon_id; + packet->_mx = monster[mon_id]._mx; + packet->_my = monster[mon_id]._my; + packet->_menemy = encode_enemy(mon_id); + v5 = v2; + v6 = sync_word_6AA708[v2]; + if ( (unsigned short)v6 > 0xFFu ) + _LOBYTE(v6) = -1; + v3->_mdelta = v6; + v7 = monster[v4]._msquelch; + sync_word_6AA708[v5] = -1; + sync_word_6AA89C[v5] = -(v7 != 0) - 1; +} + +int __fastcall sync_monster_active2(TSyncMonster *packet) +{ + int v1; // edx + unsigned int v2; // ebp + int v3; // eax + int v4; // esi + int v6; // [esp+8h] [ebp-4h] + + v1 = -1; + v2 = 65534; + if ( nummonsters <= 0 ) + return 0; + v3 = syncmonsters; + v6 = nummonsters; + do + { + if ( v3 >= nummonsters ) + v3 = 0; + v4 = monstactive[v3]; + if ( (unsigned short)sync_word_6AA89C[v4] < v2 ) + { + v2 = (unsigned short)sync_word_6AA89C[v4]; + v1 = monstactive[v3]; + } + ++v3; + --v6; + } + while ( v6 ); + syncmonsters = v3; + if ( v1 == -1 ) + return 0; + sync_monster_pos(packet, v1); + return 1; +} +// 6AA898: using guessed type int syncmonsters; + +void __fastcall SyncPlrInv(TSyncHeader *pSync) +{ + int v1; // edx + int v2; // eax + int v3; // eax + short v4; // dx + short v5; // bx + ItemStruct *pItem; // eax + + if ( numitems <= 0 ) + { + pSync->bItemI = -1; + } + else + { + v1 = syncitems; + if ( syncitems >= numitems ) + v1 = 0; + v2 = itemactive[v1]; + syncitems = v1 + 1; + pSync->bItemI = v2; + v3 = v2; + pSync->bItemX = item[v3]._ix; + pSync->bItemY = item[v3]._iy; + pSync->wItemIndx = item[v3].IDidx; + if ( item[v3].IDidx == IDI_EAR ) + { + _LOBYTE(v4) = 0; + _HIBYTE(v4) = item[v3]._iName[7]; + _LOBYTE(v5) = 0; + pSync->wItemCI = item[v3]._iName[8] | v4; + pSync->dwItemSeed = item[v3]._iName[12] | ((item[v3]._iName[11] | ((item[v3]._iName[10] | (item[v3]._iName[9] << 8)) << 8)) << 8); + pSync->bItemId = item[v3]._iName[13]; + pSync->bItemDur = item[v3]._iName[14]; + pSync->bItemMDur = item[v3]._iName[15]; + pSync->bItemCh = item[v3]._iName[16]; + pSync->bItemMCh = item[v3]._iName[17]; + _HIBYTE(v5) = item[v3]._iName[18]; + pSync->wItemVal = LOWORD(item[v3]._ivalue) | v5 | ((LOWORD(item[v3]._iCurs) - 19) << 6); + pSync->dwItemBuff = item[v3]._iName[22] | ((item[v3]._iName[21] | ((item[v3]._iName[20] | (item[v3]._iName[19] << 8)) << 8)) << 8); + } + else + { + pSync->wItemCI = item[v3]._iCreateInfo; + pSync->dwItemSeed = item[v3]._iSeed; + pSync->bItemId = item[v3]._iIdentified; + pSync->bItemDur = item[v3]._iDurability; + pSync->bItemMDur = item[v3]._iMaxDur; + pSync->bItemCh = item[v3]._iCharges; + pSync->bItemMCh = item[v3]._iMaxCharges; + if ( !item[v3].IDidx ) + pSync->wItemVal = item[v3]._ivalue; + } + } + pItem = &plr[myplr].InvBody[sgnSyncPInv]; + if ( pItem->_itype == -1 ) + { + pSync->bPInvLoc = -1; + } + else + { + pSync->bPInvLoc = sgnSyncPInv; + pSync->wPInvIndx = pItem->IDidx; + pSync->wPInvCI = pItem->_iCreateInfo; + pSync->dwPInvSeed = pItem->_iSeed; + pSync->bPInvId = pItem->_iIdentified; + } + if ( ++sgnSyncPInv >= 7 ) + sgnSyncPInv = 0; +} +// 6AAA34: using guessed type int sgnSyncPInv; + +int __fastcall SyncData(int pnum, TSyncHeader *packet) +{ + TSyncHeader *v2; // esi + TSyncMonster *v3; // edi + int v4; // ebp + unsigned short v5; // ax + unsigned int v6; // ebx + + v2 = packet; + v3 = (TSyncMonster *)(&packet->bPInvId + 1); + v4 = pnum; + if ( packet->bCmd != CMD_SYNCDATA ) + TermMsg("bad sync command"); + if ( gbBufferMsgs != 1 && v4 != myplr ) + { + v5 = v2->wLen; + if ( v5 >= 5u ) + { + v6 = v5 / 5u; + do + { + if ( currlevel == v2->bLevel ) + sync_monster_data(v4, v3); + delta_sync_monster((TCmdLocParam1 *)v3, v2->bLevel); + ++v3; + --v6; + } + while ( v6 ); + } + } + return v2->wLen + 38; +} +// 676194: using guessed type char gbBufferMsgs; + +void __fastcall sync_monster_data(int pnum, TSyncMonster *packet) +{ + TSyncMonster *v2; // edi + int v3; // ecx + int v4; // ebx + int v5; // esi + int v6; // ST18_4 + unsigned int v7; // ecx + unsigned int v8; // eax + int v9; // eax + int v10; // ecx + signed int v11; // ST14_4 + int v12; // eax + int v13; // eax + int v14; // eax + //int v15; // eax + int v16; // eax + int md; // [esp+Ch] [ebp-8h] + int mda; // [esp+Ch] [ebp-8h] + + v2 = packet; + md = pnum; + v3 = 0; + v4 = (unsigned char)packet->_mndx; + v5 = v4; + if ( monster[v5]._mhitpoints ) + { + if ( nummonsters > 0 ) + { + do + { + if ( monstactive[v3] == v4 ) + break; + ++v3; + } + while ( v3 < nummonsters ); + } + v6 = abs(plr[myplr].WorldY - monster[v5]._my); + v7 = abs(plr[myplr].WorldX - monster[v5]._mx) + v6; + if ( v7 > 0xFF ) + v7 = 255; + v8 = (unsigned char)v2->_mdelta; + if ( v7 >= v8 && (v7 != v8 || md <= myplr) ) + { + v9 = (unsigned char)v2->_mx; + if ( monster[v5]._mfutx != v9 || monster[v5]._mfuty != (unsigned char)v2->_my ) + { + v10 = monster[v5]._mmode; + if ( v10 != MM_CHARGE && v10 != MM_STONE ) + { + v11 = abs(monster[v5]._mx - v9); + v12 = abs(monster[v5]._my - (unsigned char)v2->_my); + if ( v11 > 2 || v12 > 2 ) + { + if ( dMonster[0][(unsigned char)v2->_my + 112 * (unsigned char)v2->_mx] ) + { +LABEL_23: + decode_enemy(v4, (unsigned char)v2->_menemy); + return; + } + M_ClearSquares(v4); + dMonster[0][(unsigned char)v2->_my + 112 * (unsigned char)v2->_mx] = v4 + 1; + monster[v5]._mx = (unsigned char)v2->_mx; + monster[v5]._my = (unsigned char)v2->_my; + decode_enemy(v4, (unsigned char)v2->_menemy); + v16 = GetDirection( + (unsigned char)v2->_mx, + (unsigned char)v2->_my, + (unsigned char)monster[v5]._menemyx, + (unsigned char)monster[v5]._menemyy); + M_StartStand(v4, v16); + } + else + { + v13 = monster[v5]._mmode; + if ( v13 >= MM_WALK && v13 <= MM_WALK3 ) + goto LABEL_23; + v14 = GetDirection( + monster[v5]._mx, + monster[v5]._my, + (unsigned char)v2->_mx, + (unsigned char)v2->_my); + mda = v14; + //_LOBYTE(v15) = DirOK(v4, v14); + if ( !DirOK(v4, v14) ) + goto LABEL_23; + M_ClearSquares(v4); + dMonster[0][monster[v5]._my + 112 * monster[v5]._mx] = v4 + 1; + M_WalkDir(v4, mda); + } + monster[v5]._msquelch = -1; + goto LABEL_23; + } + } + } + } +} + +void __cdecl sync_clear_pkt() +{ + syncmonsters = 16 * myplr; + memset(sync_word_6AA89C, 255, 0x190u); +} +// 6AA898: using guessed type int syncmonsters; diff --git a/Source/sync.h b/Source/sync.h new file mode 100644 index 000000000..b0d717ca9 --- /dev/null +++ b/Source/sync.h @@ -0,0 +1,21 @@ +//HEADER_GOES_HERE +#ifndef __SYNC_H__ +#define __SYNC_H__ + +extern short sync_word_6AA708[MAXMONSTERS]; +extern int syncmonsters; // weak +extern short sync_word_6AA89C[MAXMONSTERS]; +extern int syncitems; +extern int sgnSyncPInv; // weak + +int __fastcall sync_all_monsters(TSyncHeader *packet, int size); +void __cdecl sync_one_monster(); +int __fastcall sync_monster_active(TSyncMonster *packet); +void __fastcall sync_monster_pos(TSyncMonster *packet, int mon_id); +int __fastcall sync_monster_active2(TSyncMonster *packet); +void __fastcall SyncPlrInv(TSyncHeader *pSync); +int __fastcall SyncData(int pnum, TSyncHeader *packet); +void __fastcall sync_monster_data(int pnum, TSyncMonster *packet); +void __cdecl sync_clear_pkt(); + +#endif /* __SYNC_H__ */ diff --git a/Source/textdat.cpp b/Source/textdat.cpp new file mode 100644 index 000000000..3531b22f7 --- /dev/null +++ b/Source/textdat.cpp @@ -0,0 +1,512 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +/* todo: move text out of struct */ + +const TextDataStruct alltext[259] = +{ + { " Ahh, the story of our King, is it? The tragic fall of Leoric was a harsh blow to this land. The people always loved the King, and now they live in mortal fear of him. The question that I keep asking myself is how he could have fallen so far from the Light, as Leoric had always been the holiest of men. Only the vilest powers of Hell could so utterly destroy a man from within... |", + 1, 5, TSFX_STORY1 }, + { "The village needs your help, good master! Some months ago King Leoric's son, Prince Albrecht, was kidnapped. The King went into a rage and scoured the village for his missing child. With each passing day, Leoric seemed to slip deeper into madness. He sought to blame innocent townsfolk for the boy's disappearance and had them brutally executed. Less than half of us survived his insanity...\n \nThe King's Knights and Priests tried to placate him, but he turned against them and sadly, they were forced to kill him. With his dying breath the King called down a terrible curse upon his former followers. He vowed that they would serve him in darkness forever...\n \nThis is where things take an even darker twist than I thought possible! Our former King has risen from his eternal sleep and now commands a legion of undead minions within the Labyrinth. His body was buried in a tomb three levels beneath the Cathedral. Please, good master, put his soul at ease by destroying his now cursed form... |", + 1, 5, TSFX_TAVERN21 }, + { "As I told you, good master, the King was entombed three levels below. He's down there, waiting in the putrid darkness for his chance to destroy this land... |", + 1, 6, TSFX_TAVERN22 }, + { "The curse of our King has passed, but I fear that it was only part of a greater evil at work. However, we may yet be saved from the darkness that consumes our land, for your victory is a good omen. May Light guide you on your way, good master. |", + 1, 5, TSFX_TAVERN23 }, + { "The loss of his son was too much for King Leoric. I did what I could to ease his madness, but in the end it overcame him. A black curse has hung over this kingdom from that day forward, but perhaps if you were to free his spirit from his earthly prison, the curse would be lifted... |", + 1, 5, TSFX_HEALER1 }, + { "I don't like to think about how the King died. I like to remember him for the kind and just ruler that he was. His death was so sad and seemed very wrong, somehow. |", + 1, 6, TSFX_BMAID1 }, + { "I made many of the weapons and most of the armor that King Leoric used to outfit his knights. I even crafted a huge two-handed sword of the finest mithril for him, as well as a field crown to match. I still cannot believe how he died, but it must have been some sinister force that drove him insane! |", + 1, 5, TSFX_SMITH1 }, + { "I don't care about that. Listen, no skeleton is gonna be MY king. Leoric is King. King, so you hear me? HAIL TO THE KING! |", + 1, 5, TSFX_DRUNK1 }, + { "The dead who walk among the living follow the cursed King. He holds the power to raise yet more warriors for an ever growing army of the undead. If you do not stop his reign, he will surely march across this land and slay all who still live here. |", + 1, 5, TSFX_WITCH1 }, + { "Look, I'm running a business here. I don't sell information, and I don't care about some King that's been dead longer than I've been alive. If you need something to use against this King of the undead, then I can help you out... |", + 1, 5, TSFX_PEGBOY1 }, + { "The warmth of life has entered my tomb. Prepare yourself, mortal, to serve my Master for eternity! |", + 0, 5, USFX_SKING1 }, + { "I see that this strange behavior puzzles you as well. I would surmise that since many demons fear the light of the sun and believe that it holds great power, it may be that the rising sun depicted on the sign you speak of has led them to believe that it too holds some arcane powers. Hmm, perhaps they are not all as smart as we had feared... |", + 1, 5, TSFX_STORY2 }, + { "Master, I have a strange experience to relate. I know that you have a great knowledge of those monstrosities that inhabit the labyrinth, and this is something that I cannot understand for the very life of me... I was awakened during the night by a scraping sound just outside of my tavern. When I looked out from my bedroom, I saw the shapes of small demon-like creatures in the inn yard. After a short time, they ran off, but not before stealing the sign to my inn. I don't know why the demons would steal my sign but leave my family in peace... 'tis strange, no? |", + 1, 5, TSFX_TAVERN24 }, + { "Oh, you didn't have to bring back my sign, but I suppose that it does save me the expense of having another one made. Well, let me see, what could I give you as a fee for finding it? Hmmm, what have we here... ah, yes! This cap was left in one of the rooms by a magician who stayed here some time ago. Perhaps it may be of some value to you. |", + 1, 5, TSFX_TAVERN25 }, + { "My goodness, demons running about the village at night, pillaging our homes - is nothing sacred? I hope that Ogden and Garda are all right. I suppose that they would come to see me if they were hurt... |", + 1, 5, TSFX_HEALER2 }, + { "Oh my! Is that where the sign went? My Grandmother and I must have slept right through the whole thing. Thank the Light that those monsters didn't attack the inn. |", + 1, 6, TSFX_BMAID2 }, + { "Demons stole Ogden's sign, you say? That doesn't sound much like the atrocities I've heard of - or seen. \n \nDemons are concerned with ripping out your heart, not your signpost. |", + 1, 6, TSFX_SMITH2 }, + { "You know what I think? Somebody took that sign, and they gonna want lots of money for it. If I was Ogden... and I'm not, but if I was... I'd just buy a new sign with some pretty drawing on it. Maybe a nice mug of ale or a piece of cheese... |", + 1, 5, TSFX_DRUNK2 }, + { "No mortal can truly understand the mind of the demon. \n \nNever let their erratic actions confuse you, as that too may be their plan. |", + 1, 6, TSFX_WITCH2 }, + { "What - is he saying I took that? I suppose that Griswold is on his side, too. \n \nLook, I got over simple sign stealing months ago. You can't turn a profit on a piece of wood. |", + 1, 6, TSFX_PEGBOY2 }, + { "Hey - You that one that kill all! You get me Magic Banner or we attack! You no leave with life! You kill big uglies and give back Magic. Go past corner and door, find uglies. You give, you go! |", + 1, 5, USFX_SNOT1 }, + { "You kill uglies, get banner. You bring to me, or else... |", + 1, 6, USFX_SNOT2 }, + { "You give! Yes, good! Go now, we strong. We kill all with big Magic! |", + 1, 6, USFX_SNOT3 }, + { "This does not bode well, for it confirms my darkest fears. While I did not allow myself to believe the ancient legends, I cannot deny them now. Perhaps the time has come to reveal who I am.\n \nMy true name is Deckard Cain the Elder, and I am the last descendant of an ancient Brotherhood that was dedicated to safeguarding the secrets of a timeless evil. An evil that quite obviously has now been released.\n \nThe Archbishop Lazarus, once King Leoric's most trusted advisor, led a party of simple townsfolk into the Labyrinth to find the King's missing son, Albrecht. Quite some time passed before they returned, and only a few of them escaped with their lives.\n \nCurse me for a fool! I should have suspected his veiled treachery then. It must have been Lazarus himself who kidnapped Albrecht and has since hidden him within the Labyrinth. I do not understand why the Archbishop turned to the darkness, or what his interest is in the child. unless he means to sacrifice him to his dark masters!\n \nThat must be what he has planned! The survivors of his 'rescue party' say that Lazarus was last seen running into the deepest bowels of the labyrinth. You must hurry and save the prince from the sacrificial blade of this demented fiend! |", + 1, 3, TSFX_STORY36 }, + { "You must hurry and rescue Albrecht from the hands of Lazarus. The prince and the people of this kingdom are counting on you! |", + 1, 5, TSFX_STORY37 }, + { "Your story is quite grim, my friend. Lazarus will surely burn in Hell for his horrific deed. The boy that you describe is not our prince, but I believe that Albrecht may yet be in danger. The symbol of power that you speak of must be a portal in the very heart of the labyrinth.\n \nKnow this, my friend - The evil that you move against is the dark Lord of Terror. He is known to mortal men as Diablo. It was he who was imprisoned within the Labyrinth many centuries ago and I fear that he seeks to once again sow chaos in the realm of mankind. You must venture through the portal and destroy Diablo before it is too late! |", + 1, 5, TSFX_STORY38 }, + { "Lazarus was the Archbishop who led many of the townspeople into the labyrinth. I lost many good friends that day, and Lazarus never returned. I suppose he was killed along with most of the others. If you would do me a favor, good master - please do not talk to Farnham about that day. |", + 1, 6, TSFX_TAVERN1 }, + { "|", 1, 5, TSFX_STORY38 }, + { "|", 1, 5, TSFX_STORY38 }, + { "I was shocked when I heard of what the townspeople were planning to do that night. I thought that of all people, Lazarus would have had more sense than that. He was an Archbishop, and always seemed to care so much for the townsfolk of Tristram. So many were injured, I could not save them all... |", + 1, 5, TSFX_HEALER3 }, + { "I remember Lazarus as being a very kind and giving man. He spoke at my mother's funeral, and was supportive of my grandmother and myself in a very troubled time. I pray every night that somehow, he is still alive and safe. |", + 1, 5, TSFX_BMAID3 }, + { "I was there when Lazarus led us into the labyrinth. He spoke of holy retribution, but when we started fighting those hellspawn, he did not so much as lift his mace against them. He just ran deeper into the dim, endless chambers that were filled with the servants of darkness! |", + 1, 5, TSFX_SMITH3 }, + { "They stab, then bite, then they're all around you. Liar! LIAR! They're all dead! Dead! Do you hear me? They just keep falling and falling... their blood spilling out all over the floor... all his fault... |", + 1, 5, TSFX_DRUNK3 }, + { "I did not know this Lazarus of whom you speak, but I do sense a great conflict within his being. He poses a great danger, and will stop at nothing to serve the powers of darkness which have claimed him as theirs. |", + 1, 5, TSFX_WITCH3 }, + { "Yes, the righteous Lazarus, who was sooo effective against those monsters down there. Didn't help save my leg, did it? Look, I'll give you a free piece of advice. Ask Farnham, he was there. |", + 1, 5, TSFX_PEGBOY3 }, + { "Abandon your foolish quest. All that awaits you is the wrath of my Master! You are too late to save the child. Now you will join him in Hell! |", + 0, 5, USFX_LAZ1 }, + { " |", 0, 5, USFX_LAZ1 }, + { "Hmm, I don't know what I can really tell you about this that will be of any help. The water that fills our wells comes from an underground spring. I have heard of a tunnel that leads to a great lake - perhaps they are one and the same. Unfortunately, I do not know what would cause our water supply to be tainted. |", + 1, 5, TSFX_STORY4 }, + { "I have always tried to keep a large supply of foodstuffs and drink in our storage cellar, but with the entire town having no source of fresh water, even our stores will soon run dry. \n \nPlease, do what you can or I don't know what we will do. |", + 1, 6, TSFX_TAVERN2 }, + { "I'm glad I caught up to you in time! Our wells have become brackish and stagnant and some of the townspeople have become ill drinking from them. Our reserves of fresh water are quickly running dry. I believe that there is a passage that leads to the springs that serve our town. Please find what has caused this calamity, or we all will surely perish. |", + 1, 5, TSFX_HEALER20 }, + { "Please, you must hurry. Every hour that passes brings us closer to having no water to drink. \n \nWe cannot survive for long without your help. |", + 1, 6, TSFX_HEALER21 }, + { "What's that you say - the mere presence of the demons had caused the water to become tainted? Oh, truly a great evil lurks beneath our town, but your perseverance and courage gives us hope. Please take this ring - perhaps it will aid you in the destruction of such vile creatures. |", + 1, 5, TSFX_HEALER22 }, + { "My grandmother is very weak, and Garda says that we cannot drink the water from the wells. Please, can you do something to help us? |", + 1, 6, TSFX_BMAID4 }, + { "Pepin has told you the truth. We will need fresh water badly, and soon. I have tried to clear one of the smaller wells, but it reeks of stagnant filth. It must be getting clogged at the source. |", + 1, 5, TSFX_SMITH4 }, + { "You drink water? |", 1, 8, TSFX_DRUNK4 }, + { "The people of Tristram will die if you cannot restore fresh water to their wells. \n \nKnow this - demons are at the heart of this matter, but they remain ignorant of what they have spawned. |", + 1, 6, TSFX_WITCH4 }, + { "For once, I'm with you. My business runs dry - so to speak - if I have no market to sell to. You better find out what is going on, and soon! |", + 1, 6, TSFX_PEGBOY4 }, + { "A book that speaks of a chamber of human bones? Well, a Chamber of Bone is mentioned in certain archaic writings that I studied in the libraries of the East. These tomes inferred that when the Lords of the underworld desired to protect great treasures, they would create domains where those who died in the attempt to steal that treasure would be forever bound to defend it. A twisted, but strangely fitting, end? |", + 1, 4, TSFX_STORY7 }, + { "I am afraid that I don't know anything about that, good master. Cain has many books that may be of some help. |", + 1, 6, TSFX_TAVERN5 }, + { "This sounds like a very dangerous place. If you venture there, please take great care. |", + 1, 6, TSFX_HEALER5 }, + { "I am afraid that I haven't heard anything about that. Perhaps Cain the Storyteller could be of some help. |", + 1, 6, TSFX_BMAID6 }, + { "I know nothing of this place, but you may try asking Cain. He talks about many things, and it would not surprise me if he had some answers to your question. |", + 1, 6, TSFX_SMITH7 }, + { "Okay, so listen. There's this chamber of wood, see. And his wife, you know - her - tells the tree... cause you gotta wait. Then I says, that might work against him, but if you think I'm gonna PAY for this... you... uh... yeah. |", + 1, 5, TSFX_DRUNK7 }, + { "You will become an eternal servant of the dark lords should you perish within this cursed domain. \n \nEnter the Chamber of Bone at your own peril. |", + 1, 6, TSFX_WITCH7 }, + { "A vast and mysterious treasure, you say? Maybe I could be interested in picking up a few things from you... or better yet, don't you need some rare and expensive supplies to get you through this ordeal? |", + 1, 5, TSFX_PEGBOY7 }, + { "It seems that the Archbishop Lazarus goaded many of the townsmen into venturing into the Labyrinth to find the King's missing son. He played upon their fears and whipped them into a frenzied mob. None of them were prepared for what lay within the cold earth... Lazarus abandoned them down there - left in the clutches of unspeakable horrors - to die. |", + 1, 5, TSFX_STORY10 }, + { "Yes, Farnham has mumbled something about a hulking brute who wielded a fierce weapon. I believe he called him a butcher. |", + 1, 6, TSFX_TAVERN8 }, + { "By the Light, I know of this vile demon. There were many that bore the scars of his wrath upon their bodies when the few survivors of the charge led by Lazarus crawled from the Cathedral. I don't know what he used to slice open his victims, but it could not have been of this world. It left wounds festering with disease and even I found them almost impossible to treat. Beware if you plan to battle this fiend... |", + 1, 5, TSFX_HEALER8 }, + { "When Farnham said something about a butcher killing people, I immediately discounted it. But since you brought it up, maybe it is true. |", + 1, 6, TSFX_BMAID8 }, + { "I saw what Farnham calls the Butcher as it swathed a path through the bodies of my friends. He swung a cleaver as large as an axe, hewing limbs and cutting down brave men where they stood. I was separated from the fray by a host of small screeching demons and somehow found the stairway leading out. I never saw that hideous beast again, but his blood-stained visage haunts me to this day. |", + 1, 5, TSFX_SMITH10 }, + { "Big! Big cleaver killing all my friends. Couldn't stop him, had to run away, couldn't save them. Trapped in a room with so many bodies... so many friends... NOOOOOOOOOO! |", + 1, 5, TSFX_DRUNK10 }, + { "The Butcher is a sadistic creature that delights in the torture and pain of others. You have seen his handiwork in the drunkard Farnham. His destruction will do much to ensure the safety of this village. |", + 1, 5, TSFX_WITCH10 }, + { "I know more than you'd think about that grisly fiend. His little friends got a hold of me and managed to get my leg before Griswold pulled me out of that hole. \n \nI'll put it bluntly - kill him before he kills you and adds your corpse to his collection. |", + 1, 6, TSFX_PEGBOY10 }, + { "Please, listen to me. The Archbishop Lazarus, he led us down here to find the lost prince. The bastard led us into a trap! Now everyone is dead...killed by a demon he called the Butcher. Avenge us! Find this Butcher and slay him so that our souls may finally rest... |", + 1, 5, TSFX_WOUND }, + { " |", 1, 5, USFX_CLEAVER }, + { "You recite an interesting rhyme written in a style that reminds me of other works. Let me think now - what was it?\n \n...Darkness shrouds the Hidden. Eyes glowing unseen with only the sounds of razor claws briefly scraping to torment those poor souls who have been made sightless for all eternity. The prison for those so damned is named the Halls of the Blind... |", + 1, 5, TSFX_STORY12 }, + { "I never much cared for poetry. Occasionally, I had cause to hire minstrels when the inn was doing well, but that seems like such a long time ago now. \n \nWhat? Oh, yes... uh, well, I suppose you could see what someone else knows. |", + 1, 6, TSFX_TAVERN10 }, + { "This does seem familiar, somehow. I seem to recall reading something very much like that poem while researching the history of demonic afflictions. It spoke of a place of great evil that... wait - you're not going there are you? |", + 1, 5, TSFX_HEALER10 }, + { "If you have questions about blindness, you should talk to Pepin. I know that he gave my grandmother a potion that helped clear her vision, so maybe he can help you, too. |", + 1, 6, TSFX_BMAID10 }, + { "I am afraid that I have neither heard nor seen a place that matches your vivid description, my friend. Perhaps Cain the Storyteller could be of some help. |", + 1, 6, TSFX_SMITH12 }, + { "Look here... that's pretty funny, huh? Get it? Blind - look here? |", + 1, 6, TSFX_DRUNK12 }, + { "This is a place of great anguish and terror, and so serves its master well. \n \nTread carefully or you may yourself be staying much longer than you had anticipated. |", + 1, 6, TSFX_WITCH12 }, + { "Lets see, am I selling you something? No. Are you giving me money to tell you about this? No. Are you now leaving and going to talk to the storyteller who lives for this kind of thing? Yes. |", + 1, 5, TSFX_PEGBOY11 }, + { "You claim to have spoken with Lachdanan? He was a great hero during his life. Lachdanan was an honorable and just man who served his King faithfully for years. But of course, you already know that.\n \nOf those who were caught within the grasp of the King's Curse, Lachdanan would be the least likely to submit to the darkness without a fight, so I suppose that your story could be true. If I were in your place, my friend, I would find a way to release him from his torture. |", + 1, 5, TSFX_STORY13 }, + { "You speak of a brave warrior long dead! I'll have no such talk of speaking with departed souls in my inn yard, thank you very much. |", + 1, 6, TSFX_TAVERN11 }, + { "A golden elixir, you say. I have never concocted a potion of that color before, so I can't tell you how it would effect you if you were to try to drink it. As your healer, I strongly advise that should you find such an elixir, do as Lachdanan asks and DO NOT try to use it. |", + 1, 5, TSFX_HEALER11 }, + { "I've never heard of a Lachdanan before. I'm sorry, but I don't think that I can be of much help to you. |", + 1, 7, TSFX_BMAID11 }, + { "If it is actually Lachdanan that you have met, then I would advise that you aid him. I dealt with him on several occasions and found him to be honest and loyal in nature. The curse that fell upon the followers of King Leoric would fall especially hard upon him. |", + 1, 5, TSFX_SMITH13 }, + { " Lachdanan is dead. Everybody knows that, and you can't fool me into thinking any other way. You can't talk to the dead. I know! |", + 1, 5, TSFX_DRUNK13 }, + { "You may meet people who are trapped within the Labyrinth, such as Lachdanan. \n \nI sense in him honor and great guilt. Aid him, and you aid all of Tristram. |", + 1, 6, TSFX_WITCH13 }, + { "Wait, let me guess. Cain was swallowed up in a gigantic fissure that opened beneath him. He was incinerated in a ball of hellfire, and can't answer your questions anymore. Oh, that isn't what happened? Then I guess you'll be buying something or you'll be on your way. |", + 1, 5, TSFX_PEGBOY12 }, + { "Please, don't kill me, just hear me out. I was once Captain of King Leoric's Knights, upholding the laws of this land with justice and honor. Then his dark Curse fell upon us for the role we played in his tragic death. As my fellow Knights succumbed to their twisted fate, I fled from the King's burial chamber, searching for some way to free myself from the Curse. I failed...\n \nI have heard of a Golden Elixir that could lift the Curse and allow my soul to rest, but I have been unable to find it. My strength now wanes, and with it the last of my humanity as well. Please aid me and find the Elixir. I will repay your efforts - I swear upon my honor. |", + 1, 3, USFX_LACH1 }, + { "You have not found the Golden Elixir. I fear that I am doomed for eternity. Please, keep trying... |", + 1, 6, USFX_LACH2 }, + { "You have saved my soul from damnation, and for that I am in your debt. If there is ever a way that I can repay you from beyond the grave I will find it, but for now - take my helm. On the journey I am about to take I will have little use for it. May it protect you against the dark powers below. Go with the Light, my friend... |", + 1, 4, USFX_LACH3 }, + { "Griswold speaks of The Anvil of Fury - a legendary artifact long searched for, but never found. Crafted from the metallic bones of the Razor Pit demons, the Anvil of Fury was smelt around the skulls of the five most powerful magi of the underworld. Carved with runes of power and chaos, any weapon or armor forged upon this Anvil will be immersed into the realm of Chaos, imbedding it with magical properties. It is said that the unpredictable nature of Chaos makes it difficult to know what the outcome of this smithing will be... |", + 1, 4, TSFX_STORY14 }, + { "Don't you think that Griswold would be a better person to ask about this? He's quite handy, you know. |", + 1, 7, TSFX_TAVERN12 }, + { "If you had been looking for information on the Pestle of Curing or the Silver Chalice of Purification, I could have assisted you, my friend. However, in this matter, you would be better served to speak to either Griswold or Cain. |", + 1, 6, TSFX_HEALER12 }, + { "Griswold's father used to tell some of us when we were growing up about a giant anvil that was used to make mighty weapons. He said that when a hammer was struck upon this anvil, the ground would shake with a great fury. Whenever the earth moves, I always remember that story. |", + 1, 5, TSFX_BMAID12 }, + { "Greetings! It's always a pleasure to see one of my best customers! I know that you have been venturing deeper into the Labyrinth, and there is a story I was told that you may find worth the time to listen to...\n \nOne of the men who returned from the Labyrinth told me about a mystic anvil that he came across during his escape. His description reminded me of legends I had heard in my youth about the burning Hellforge where powerful weapons of magic are crafted. The legend had it that deep within the Hellforge rested the Anvil of Fury! This Anvil contained within it the very essence of the demonic underworld...\n \nIt is said that any weapon crafted upon the burning Anvil is imbued with great power. If this anvil is indeed the Anvil of Fury, I may be able to make you a weapon capable of defeating even the darkest lord of Hell! \n \nFind the Anvil for me, and I'll get to work! |", + 1, 5, TSFX_SMITH21 }, + { "Nothing yet, eh? Well, keep searching. A weapon forged upon the Anvil could be your best hope, and I am sure that I can make you one of legendary proportions. |", + 1, 5, TSFX_SMITH22 }, + { "I can hardly believe it! This is the Anvil of Fury - good work, my friend. Now we'll show those bastards that there are no weapons in Hell more deadly than those made by men! Take this and may Light protect you. |", + 1, 5, TSFX_SMITH23 }, + { "Griswold can't sell his anvil. What will he do then? And I'd be angry too if someone took my anvil! |", + 1, 6, TSFX_DRUNK14 }, + { "There are many artifacts within the Labyrinth that hold powers beyond the comprehension of mortals. Some of these hold fantastic power that can be used by either the Light or the Darkness. Securing the Anvil from below could shift the course of the Sin War towards the Light. |", + 1, 5, TSFX_WITCH14 }, + { "If you were to find this artifact for Griswold, it could put a serious damper on my business here. Awwww, you'll never find it. |", + 1, 6, TSFX_PEGBOY13 }, + { "The Gateway of Blood and the Halls of Fire are landmarks of mystic origin. Wherever this book you read from resides it is surely a place of great power.\n \nLegends speak of a pedestal that is carved from obsidian stone and has a pool of boiling blood atop its bone encrusted surface. There are also allusions to Stones of Blood that will open a door that guards an ancient treasure...\n \nThe nature of this treasure is shrouded in speculation, my friend, but it is said that the ancient hero Arkaine placed the holy armor Valor in a secret vault. Arkaine was the first mortal to turn the tide of the Sin War and chase the legions of darkness back to the Burning Hells.\n \nJust before Arkaine died, his armor was hidden away in a secret vault. It is said that when this holy armor is again needed, a hero will arise to don Valor once more. Perhaps you are that hero... |", + 1, 3, TSFX_STORY15 }, + { "Every child hears the story of the warrior Arkaine and his mystic armor known as Valor. If you could find its resting place, you would be well protected against the evil in the Labyrinth. |", + 1, 6, TSFX_TAVERN13 }, + { "Hmm... it sounds like something I should remember, but I've been so busy learning new cures and creating better elixirs that I must have forgotten. Sorry... |", + 1, 6, TSFX_HEALER13 }, + { "The story of the magic armor called Valor is something I often heard the boys talk about. You had better ask one of the men in the village. |", + 1, 6, TSFX_BMAID13 }, + { "The armor known as Valor could be what tips the scales in your favor. I will tell you that many have looked for it - including myself. Arkaine hid it well, my friend, and it will take more than a bit of luck to unlock the secrets that have kept it concealed oh, lo these many years. |", + 1, 5, TSFX_SMITH14 }, + { "Zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz... |", 1, 7, TSFX_DRUNK15 }, + { "Should you find these Stones of Blood, use them carefully. \n \nThe way is fraught with danger and your only hope rests within your self trust. |", + 1, 6, TSFX_WITCH15 }, + { "You intend to find the armor known as Valor? \n \nNo one has ever figured out where Arkaine stashed the stuff, and if my contacts couldn't find it, I seriously doubt you ever will either. |", + 1, 6, TSFX_PEGBOY14 }, + { "I know of only one legend that speaks of such a warrior as you describe. His story is found within the ancient chronicles of the Sin War...\n \nStained by a thousand years of war, blood and death, the Warlord of Blood stands upon a mountain of his tattered victims. His dark blade screams a black curse to the living; a tortured invitation to any who would stand before this Executioner of Hell.\n \nIt is also written that although he was once a mortal who fought beside the Legion of Darkness during the Sin War, he lost his humanity to his insatiable hunger for blood. |", + 1, 5, TSFX_STORY18 }, + { "I am afraid that I haven't heard anything about such a vicious warrior, good master. I hope that you do not have to fight him, for he sounds extremely dangerous. |", + 1, 6, TSFX_TAVERN16 }, + { "Cain would be able to tell you much more about something like this than I would ever wish to know. |", + 1, 7, TSFX_HEALER16 }, + { "If you are to battle such a fierce opponent, may Light be your guide and your defender. I will keep you in my thoughts. |", + 1, 6, TSFX_BMAID16 }, + { "Dark and wicked legends surrounds the one Warlord of Blood. Be well prepared, my friend, for he shows no mercy or quarter. |", + 1, 6, TSFX_SMITH17 }, + { "Always you gotta talk about Blood? What about flowers, and sunshine, and that pretty girl that brings the drinks. Listen here, friend - you're obsessive, you know that? |", + 1, 5, TSFX_DRUNK17 }, + { "His prowess with the blade is awesome, and he has lived for thousands of years knowing only warfare. I am sorry... I can not see if you will defeat him. |", + 1, 5, TSFX_WITCH18 }, + { "I haven't ever dealt with this Warlord you speak of, but he sounds like he's going through a lot of swords. Wouldn't mind supplying his armies... |", + 1, 6, TSFX_PEGBOY17 }, + { "My blade sings for your blood, mortal, and by my dark masters it shall not be denied. |", + 0, 6, USFX_WARLRD1 }, + { "Griswold speaks of the Heaven Stone that was destined for the enclave located in the east. It was being taken there for further study. This stone glowed with an energy that somehow granted vision beyond that which a normal man could possess. I do not know what secrets it holds, my friend, but finding this stone would certainly prove most valuable. |", + 1, 5, TSFX_STORY20 }, + { "The caravan stopped here to take on some supplies for their journey to the east. I sold them quite an array of fresh fruits and some excellent sweetbreads that Garda has just finished baking. Shame what happened to them... |", + 1, 6, TSFX_TAVERN18 }, + { "I don't know what it is that they thought they could see with that rock, but I will say this. If rocks are falling from the sky, you had better be careful! |", + 1, 6, TSFX_HEALER18 }, + { "Well, a caravan of some very important people did stop here, but that was quite a while ago. They had strange accents and were starting on a long journey, as I recall. \n \nI don't see how you could hope to find anything that they would have been carrying. |", + 1, 6, TSFX_BMAID18 }, + { "Stay for a moment - I have a story you might find interesting. A caravan that was bound for the eastern kingdoms passed through here some time ago. It was supposedly carrying a piece of the heavens that had fallen to earth! The caravan was ambushed by cloaked riders just north of here along the roadway. I searched the wreckage for this sky rock, but it was nowhere to be found. If you should find it, I believe that I can fashion something useful from it. |", + 1, 5, TSFX_SMITH24 }, + { "I am still waiting for you to bring me that stone from the heavens. I know that I can make something powerful out of it. |", + 1, 6, TSFX_SMITH25 }, + { "Let me see that - aye... aye, it is as I believed. Give me a moment...\n \nAh, Here you are. I arranged pieces of the stone within a silver ring that my father left me. I hope it serves you well. |", + 1, 5, TSFX_SMITH26 }, + { "I used to have a nice ring; it was a really expensive one, with blue and green and red and silver. Don't remember what happened to it, though. I really miss that ring... |", + 1, 5, TSFX_DRUNK19 }, + { "The Heaven Stone is very powerful, and were it any but Griswold who bid you find it, I would prevent it. He will harness its powers and its use will be for the good of us all. |", + 1, 5, TSFX_WITCH20 }, + { "If anyone can make something out of that rock, Griswold can. He knows what he is doing, and as much as I try to steal his customers, I respect the quality of his work. |", + 1, 6, TSFX_PEGBOY18 }, + { "The witch Adria seeks a black mushroom? I know as much about Black Mushrooms as I do about Red Herrings. Perhaps Pepin the Healer could tell you more, but this is something that cannot be found in any of my stories or books. |", + 1, 5, TSFX_STORY21 }, + { "Let me just say this. Both Garda and I would never, EVER serve black mushrooms to our honored guests. If Adria wants some mushrooms in her stew, then that is her business, but I can't help you find any. Black mushrooms... disgusting! |", + 1, 5, TSFX_TAVERN19 }, + { "The witch told me that you were searching for the brain of a demon to assist me in creating my elixir. It should be of great value to the many who are injured by those foul beasts, if I can just unlock the secrets I suspect that its alchemy holds. If you can remove the brain of a demon when you kill it, I would be grateful if you could bring it to me. |", + 1, 5, TSFX_HEALER26 }, + { "Excellent, this is just what I had in mind. I was able to finish the elixir without this, but it can't hurt to have this to study. Would you please carry this to the witch? I believe that she is expecting it. |", + 1, 5, TSFX_HEALER27 }, + { "I think Ogden might have some mushrooms in the storage cellar. Why don't you ask him? |", + 1, 7, TSFX_BMAID19 }, + { "If Adria doesn't have one of these, you can bet that's a rare thing indeed. I can offer you no more help than that, but it sounds like... a huge, gargantuan, swollen, bloated mushroom! Well, good hunting, I suppose. |", + 1, 5, TSFX_SMITH19 }, + { "Ogden mixes a MEAN black mushroom, but I get sick if I drink that. Listen, listen... here's the secret - moderation is the key! |", + 1, 5, TSFX_DRUNK20 }, + { "What do we have here? Interesting, it looks like a book of reagents. Keep your eyes open for a black mushroom. It should be fairly large and easy to identify. If you find it, bring it to me, won't you? |", + 1, 5, TSFX_WITCH22 }, + { "It's a big, black mushroom that I need. Now run off and get it for me so that I can use it for a special concoction that I am working on. |", + 1, 6, TSFX_WITCH23 }, + { "Yes, this will be perfect for a brew that I am creating. By the way, the healer is looking for the brain of some demon or another so he can treat those who have been afflicted by their poisonous venom. I believe that he intends to make an elixir from it. If you help him find what he needs, please see if you can get a sample of the elixir for me. |", + 1, 5, TSFX_WITCH24 }, + { "Why have you brought that here? I have no need for a demon's brain at this time. I do need some of the elixir that the Healer is working on. He needs that grotesque organ that you are holding, and then bring me the elixir. Simple when you think about it, isn't it? |", + 1, 5, TSFX_WITCH25 }, + { "What? Now you bring me that elixir from the healer? I was able to finish my brew without it. Why don't you just keep it... |", + 1, 6, TSFX_WITCH26 }, + { "I don't have any mushrooms of any size or color for sale. How about something a bit more useful? |", + 1, 6, TSFX_PEGBOY19 }, + { "So, the legend of the Map is real. Even I never truly believed any of it! I suppose it is time that I told you the truth about who I am, my friend. You see, I am not all that I seem...\n \nMy true name is Deckard Cain the Elder, and I am the last descendant of an ancient Brotherhood that was dedicated to keeping and safeguarding the secrets of a timeless evil. An evil that quite obviously has now been released...\n \nThe evil that you move against is the dark Lord of Terror - known to mortal men as Diablo. It was he who was imprisoned within the Labyrinth many centuries ago. The Map that you hold now was created ages ago to mark the time when Diablo would rise again from his imprisonment. When the two stars on that map align, Diablo will be at the height of his power. He will be all but invincible...\n \nYou are now in a race against time, my friend! Find Diablo and destroy him before the stars align, for we may never have a chance to rid the world of his evil again! |", + 1, 2, TSFX_STORY22 }, + { "Our time is running short! I sense his dark power building and only you can stop him from attaining his full might. |", + 1, 6, TSFX_STORY23 }, + { "I am sure that you tried your best, but I fear that even your strength and will may not be enough. Diablo is now at the height of his earthly power, and you will need all your courage and strength to defeat him. May the Light protect and guide you, my friend. I will help in any way that I am able. |", + 1, 5, TSFX_STORY24 }, + { "If the witch can't help you and suggests you see Cain, what makes you think that I would know anything? It sounds like this is a very serious matter. You should hurry along and see the storyteller as Adria suggests. |", + 1, 6, TSFX_TAVERN20 }, + { "I can't make much of the writing on this map, but perhaps Adria or Cain could help you decipher what this refers to. \n \nI can see that it is a map of the stars in our sky, but any more than that is beyond my talents. |", + 1, 6, TSFX_HEALER19 }, + { "The best person to ask about that sort of thing would be our storyteller. \n \nCain is very knowledgeable about ancient writings, and that is easily the oldest looking piece of paper that I have ever seen. |", + 1, 6, TSFX_BMAID20 }, + { "I have never seen a map of this sort before. Where'd you get it? Although I have no idea how to read this, Cain or Adria may be able to provide the answers that you seek. |", + 1, 6, TSFX_SMITH20 }, + { "Listen here, come close. I don't know if you know what I know, but you have really got somethin' here. That's a map. |", + 1, 5, TSFX_DRUNK21 }, + { "Oh, I'm afraid this does not bode well at all. This map of the stars portends great disaster, but its secrets are not mine to tell. The time has come for you to have a very serious conversation with the Storyteller... |", + 1, 5, TSFX_WITCH21 }, + { "I've been looking for a map, but that certainly isn't it. You should show that to Adria - she can probably tell you what it is. I'll say one thing; it looks old, and old usually means valuable. |", + 1, 5, TSFX_PEGBOY20 }, + { "Pleeeease, no hurt. No Kill. Keep alive and next time good bring to you. |", + 1, 6, USFX_GARBUD1 }, + { "Something for you I am making. Again, not kill Gharbad. Live and give good. \n \nYou take this as proof I keep word... |", + 1, 6, USFX_GARBUD2 }, + { "Nothing yet! Almost done. \n \nVery powerful, very strong. Live! Live! \n \nNo pain and promise I keep! |", + 1, 6, USFX_GARBUD3 }, + { "This too good for you. Very Powerful! You want - you take! |", + 1, 6, USFX_GARBUD4 }, + { "What?! Why are you here? All these interruptions are enough to make one insane. Here, take this and leave me to my work. Trouble me no more! |", + 1, 6, USFX_ZHAR1 }, + { "Arrrrgh! Your curiosity will be the death of you!!! |", 1, 7, USFX_ZHAR2 }, + { "Hello, my friend. Stay awhile and listen... |", 0, 5, TSFX_STORY25 }, + { "While you are venturing deeper into the Labyrinth you may find tomes of great knowledge hidden there. \n \nRead them carefully for they can tell you things that even I cannot. |", + 1, 6, TSFX_STORY26 }, + { "I know of many myths and legends that may contain answers to questions that may arise in your journeys into the Labyrinth. If you come across challenges and questions to which you seek knowledge, seek me out and I will tell you what I can. |", + 1, 5, TSFX_STORY27 }, + { "Griswold - a man of great action and great courage. I bet he never told you about the time he went into the Labyrinth to save Wirt, did he? He knows his fair share of the dangers to be found there, but then again - so do you. He is a skilled craftsman, and if he claims to be able to help you in any way, you can count on his honesty and his skill. |", + 1, 5, TSFX_STORY28 }, + { "Ogden has owned and run the Rising Sun Inn and Tavern for almost four years now. He purchased it just a few short months before everything here went to hell. He and his wife Garda do not have the money to leave as they invested all they had in making a life for themselves here. He is a good man with a deep sense of responsibility. |", + 1, 5, TSFX_STORY29 }, + { "Poor Farnham. He is a disquieting reminder of the doomed assembly that entered into the Cathedral with Lazarus on that dark day. He escaped with his life, but his courage and much of his sanity were left in some dark pit. He finds comfort only at the bottom of his tankard nowadays, but there are occasional bits of truth buried within his constant ramblings. |", + 1, 5, TSFX_STORY30 }, + { "The witch, Adria, is an anomaly here in Tristram. She arrived shortly after the Cathedral was desecrated while most everyone else was fleeing. She had a small hut constructed at the edge of town, seemingly overnight, and has access to many strange and arcane artifacts and tomes of knowledge that even I have never seen before. |", + 1, 5, TSFX_STORY31 }, + { "The story of Wirt is a frightening and tragic one. He was taken from the arms of his mother and dragged into the labyrinth by the small, foul demons that wield wicked spears. There were many other children taken that day, including the son of King Leoric. The Knights of the palace went below, but never returned. The Blacksmith found the boy, but only after the foul beasts had begun to torture him for their sadistic pleasures. |", + 1, 5, TSFX_STORY33 }, + { "Ah, Pepin. I count him as a true friend - perhaps the closest I have here. He is a bit addled at times, but never a more caring or considerate soul has existed. His knowledge and skills are equaled by few, and his door is always open. |", + 1, 5, TSFX_STORY34 }, + { "Gillian is a fine woman. Much adored for her high spirits and her quick laugh, she holds a special place in my heart. She stays on at the tavern to support her elderly grandmother who is too sick to travel. I sometimes fear for her safety, but I know that any man in the village would rather die than see her harmed. |", + 1, 5, TSFX_STORY35 }, + { "Greetings, good master. Welcome to the Tavern of the Rising Sun! |", + 0, 5, TSFX_TAVERN36 }, + { "Many adventurers have graced the tables of my tavern, and ten times as many stories have been told over as much ale. The only thing that I ever heard any of them agree on was this old axiom. Perhaps it will help you. You can cut the flesh, but you must crush the bone. |", + 1, 5, TSFX_TAVERN37 }, + { "Griswold the blacksmith is extremely knowledgeable about weapons and armor. If you ever need work done on your gear, he is definitely the man to see. |", + 1, 6, TSFX_TAVERN38 }, + { "Farnham spends far too much time here, drowning his sorrows in cheap ale. I would make him leave, but he did suffer so during his time in the Labyrinth. |", + 1, 6, TSFX_TAVERN39 }, + { "Adria is wise beyond her years, but I must admit - she frightens me a little. \n \nWell, no matter. If you ever have need to trade in items of sorcery, she maintains a strangely well-stocked hut just across the river. |", + 1, 6, TSFX_TAVERN40 }, + { "If you want to know more about the history of our village, the storyteller Cain knows quite a bit about the past. |", + 1, 6, TSFX_TAVERN41 }, + { "Wirt is a rapscallion and a little scoundrel. He was always getting into trouble, and it's no surprise what happened to him. \n \nHe probably went fooling about someplace that he shouldn't have been. I feel sorry for the boy, but I don't abide the company that he keeps. |", + 1, 6, TSFX_TAVERN43 }, + { "Pepin is a good man - and certainly the most generous in the village. He is always attending to the needs of others, but trouble of some sort or another does seem to follow him wherever he goes... |", + 1, 6, TSFX_TAVERN44 }, + { "Gillian, my Barmaid? If it were not for her sense of duty to her grand-dam, she would have fled from here long ago. \n \nGoodness knows I begged her to leave, telling her that I would watch after the old woman, but she is too sweet and caring to have done so. |", + 1, 6, TSFX_TAVERN45 }, + { "What ails you, my friend? |", 0, 5, TSFX_HEALER37 }, + { "I have made a very interesting discovery. Unlike us, the creatures in the Labyrinth can heal themselves without the aid of potions or magic. If you hurt one of the monsters, make sure it is dead or it very well may regenerate itself. |", + 1, 5, TSFX_HEALER38 }, + { "Before it was taken over by, well, whatever lurks below, the Cathedral was a place of great learning. There are many books to be found there. If you find any, you should read them all, for some may hold secrets to the workings of the Labyrinth. |", + 1, 5, TSFX_HEALER39 }, + { "Griswold knows as much about the art of war as I do about the art of healing. He is a shrewd merchant, but his work is second to none. Oh, I suppose that may be because he is the only blacksmith left here. |", + 1, 5, TSFX_HEALER40 }, + { "Cain is a true friend and a wise sage. He maintains a vast library and has an innate ability to discern the true nature of many things. If you ever have any questions, he is the person to go to. |", + 1, 5, TSFX_HEALER41 }, + { "Even my skills have been unable to fully heal Farnham. Oh, I have been able to mend his body, but his mind and spirit are beyond anything I can do. |", + 1, 5, TSFX_HEALER42 }, + { "While I use some limited forms of magic to create the potions and elixirs I store here, Adria is a true sorceress. She never seems to sleep, and she always has access to many mystic tomes and artifacts. I believe her hut may be much more than the hovel it appears to be, but I can never seem to get inside the place. |", + 1, 5, TSFX_HEALER43 }, + { "Poor Wirt. I did all that was possible for the child, but I know he despises that wooden peg that I was forced to attach to his leg. His wounds were hideous. No one - and especially such a young child - should have to suffer the way he did. |", + 1, 5, TSFX_HEALER45 }, + { "I really don't understand why Ogden stays here in Tristram. He suffers from a slight nervous condition, but he is an intelligent and industrious man who would do very well wherever he went. I suppose it may be the fear of the many murders that happen in the surrounding countryside, or perhaps the wishes of his wife that keep him and his family where they are. |", + 1, 5, TSFX_HEALER46 }, + { "Ogden's barmaid is a sweet girl. Her grandmother is quite ill, and suffers from delusions. \n \nShe claims that they are visions, but I have no proof of that one way or the other. |", + 1, 6, TSFX_HEALER47 }, + { "Good day! How may I serve you? |", 0, 5, TSFX_BMAID31 }, + { "My grandmother had a dream that you would come and talk to me. She has visions, you know and can see into the future. |", + 1, 6, TSFX_BMAID32 }, + { "The woman at the edge of town is a witch! She seems nice enough, and her name, Adria, is very pleasing to the ear, but I am very afraid of her. \n \nIt would take someone quite brave, like you, to see what she is doing out there. |", + 1, 6, TSFX_BMAID33 }, + { "Our Blacksmith is a point of pride to the people of Tristram. Not only is he a master craftsman who has won many contests within his guild, but he received praises from our King Leoric himself - may his soul rest in peace. Griswold is also a great hero; just ask Cain. |", + 1, 5, TSFX_BMAID34 }, + { "Cain has been the storyteller of Tristram for as long as I can remember. He knows so much, and can tell you just about anything about almost everything. |", + 1, 6, TSFX_BMAID35 }, + { "Farnham is a drunkard who fills his belly with ale and everyone else's ears with nonsense. \n \nI know that both Pepin and Ogden feel sympathy for him, but I get so frustrated watching him slip farther and farther into a befuddled stupor every night. |", + 1, 6, TSFX_BMAID36 }, + { "Pepin saved my grandmother's life, and I know that I can never repay him for that. His ability to heal any sickness is more powerful than the mightiest sword and more mysterious than any spell you can name. If you ever are in need of healing, Pepin can help you. |", + 1, 5, TSFX_BMAID37 }, + { "I grew up with Wirt's mother, Canace. Although she was only slightly hurt when those hideous creatures stole him, she never recovered. I think she died of a broken heart. Wirt has become a mean-spirited youngster, looking only to profit from the sweat of others. I know that he suffered and has seen horrors that I cannot even imagine, but some of that darkness hangs over him still. |", + 1, 5, TSFX_BMAID39 }, + { "Ogden and his wife have taken me and my grandmother into their home and have even let me earn a few gold pieces by working at the inn. I owe so much to them, and hope one day to leave this place and help them start a grand hotel in the east. |", + 1, 5, TSFX_BMAID40 }, + { "Well, what can I do for ya? |", 0, 5, TSFX_SMITH44 }, + { "If you're looking for a good weapon, let me show this to you. Take your basic blunt weapon, such as a mace. Works like a charm against most of those undying horrors down there, and there's nothing better to shatter skinny little skeletons! |", + 1, 5, TSFX_SMITH45 }, + { "The axe? Aye, that's a good weapon, balanced against any foe. Look how it cleaves the air, and then imagine a nice fat demon head in its path. Keep in mind, however, that it is slow to swing - but talk about dealing a heavy blow! |", + 1, 5, TSFX_SMITH46 }, + { "Look at that edge, that balance. A sword in the right hands, and against the right foe, is the master of all weapons. Its keen blade finds little to hack or pierce on the undead, but against a living, breathing enemy, a sword will better slice their flesh! |", + 1, 5, TSFX_SMITH47 }, + { "Your weapons and armor will show the signs of your struggles against the Darkness. If you bring them to me, with a bit of work and a hot forge, I can restore them to top fighting form. |", + 1, 6, TSFX_SMITH48 }, + { "While I have to practically smuggle in the metals and tools I need from caravans that skirt the edges of our damned town, that witch, Adria, always seems to get whatever she needs. If I knew even the smallest bit about how to harness magic as she did, I could make some truly incredible things. |", + 1, 5, TSFX_SMITH49 }, + { "Gillian is a nice lass. Shame that her gammer is in such poor health or I would arrange to get both of them out of here on one of the trading caravans. |", + 1, 6, TSFX_SMITH50 }, + { "Sometimes I think that Cain talks too much, but I guess that is his calling in life. If I could bend steel as well as he can bend your ear, I could make a suit of court plate good enough for an Emperor! |", + 1, 5, TSFX_SMITH51 }, + { "I was with Farnham that night that Lazarus led us into Labyrinth. I never saw the Archbishop again, and I may not have survived if Farnham was not at my side. I fear that the attack left his soul as crippled as, well, another did my leg. I cannot fight this battle for him now, but I would if I could. |", + 1, 5, TSFX_SMITH52 }, + { "A good man who puts the needs of others above his own. You won't find anyone left in Tristram - or anywhere else for that matter - who has a bad thing to say about the healer. |", + 1, 6, TSFX_SMITH53 }, + { "That lad is going to get himself into serious trouble... or I guess I should say, again. I've tried to interest him in working here and learning an honest trade, but he prefers the high profits of dealing in goods of dubious origin. I cannot hold that against him after what happened to him, but I do wish he would at least be careful. |", + 1, 5, TSFX_SMITH55 }, + { "The Innkeeper has little business and no real way of turning a profit. He manages to make ends meet by providing food and lodging for those who occasionally drift through the village, but they are as likely to sneak off into the night as they are to pay him. If it weren't for the stores of grains and dried meats he kept in his cellar, why, most of us would have starved during that first year when the entire countryside was overrun by demons. |", + 1, 5, TSFX_SMITH56 }, + { "Can't a fella drink in peace? |", 0, 5, TSFX_DRUNK27 }, + { "The gal who brings the drinks? Oh, yeah, what a pretty lady. So nice, too. |", + 1, 6, TSFX_DRUNK28 }, + { "Why don't that old crone do somethin' for a change. Sure, sure, she's got stuff, but you listen to me... she's unnatural. I ain't never seen her eat or drink - and you can't trust somebody who doesn't drink at least a little. |", + 1, 5, TSFX_DRUNK29 }, + { "Cain isn't what he says he is. Sure, sure, he talks a good story... some of 'em are real scary or funny... but I think he knows more than he knows he knows. |", + 1, 5, TSFX_DRUNK30 }, + { "Griswold? Good old Griswold. I love him like a brother! We fought together, you know, back when... we... Lazarus... Lazarus... Lazarus!!! |", + 1, 5, TSFX_DRUNK31 }, + { "Hehehe, I like Pepin. He really tries, you know. Listen here, you should make sure you get to know him. Good fella like that with people always wantin' help. Hey, I guess that would be kinda like you, huh hero? I was a hero too... |", + 1, 5, TSFX_DRUNK32 }, + { "Wirt is a kid with more problems than even me, and I know all about problems. Listen here - that kid is gotta sweet deal, but he's been there, you know? Lost a leg! Gotta walk around on a piece of wood. So sad, so sad... |", + 1, 5, TSFX_DRUNK34 }, + { "Ogden is the best man in town. I don't think his wife likes me much, but as long as she keeps tappin' kegs, I'll like her just fine. Seems like I been spendin' more time with Ogden than most, but he's so good to me... |", + 1, 5, TSFX_DRUNK35 }, + { "I wanna tell ya sumthin', 'cause I know all about this stuff. It's my specialty. This here is the best... theeeee best! That other ale ain't no good since those stupid dogs... |", + 1, 5, TSFX_DRUNK23 }, + { "No one ever lis... listens to me. Somewhere - I ain't too sure - but somewhere under the church is a whole pile o' gold. Gleamin' and shinin' and just waitin' for someone to get it. |", + 1, 5, TSFX_DRUNK24 }, + { "I know you gots your own ideas, and I know you're not gonna believe this, but that weapon you got there - it just ain't no good against those big brutes! Oh, I don't care what Griswold says, they can't make anything like they used to in the old days... |", + 1, 5, TSFX_DRUNK25 }, + { "If I was you... and I ain't... but if I was, I'd sell all that stuff you got and get out of here. That boy out there... He's always got somethin good, but you gotta give him some gold or he won't even show you what he's got. |", + 1, 5, TSFX_DRUNK26 }, + { "I sense a soul in search of answers... |", 0, 5, TSFX_WITCH38 }, + { "Wisdom is earned, not given. If you discover a tome of knowledge, devour its words. Should you already have knowledge of the arcane mysteries scribed within a book, remember - that level of mastery can always increase. |", + 1, 5, TSFX_WITCH39 }, + { "The greatest power is often the shortest lived. You may find ancient words of power written upon scrolls of parchment. The strength of these scrolls lies in the ability of either apprentice or adept to cast them with equal ability. Their weakness is that they must first be read aloud and can never be kept at the ready in your mind. Know also that these scrolls can be read but once, so use them with care. |", + 1, 5, TSFX_WITCH40 }, + { "Though the heat of the sun is beyond measure, the mere flame of a candle is of greater danger. No energies, no matter how great, can be used without the proper focus. For many spells, ensorcelled Staves may be charged with magical energies many times over. I have the ability to restore their power - but know that nothing is done without a price. |", + 1, 5, TSFX_WITCH41 }, + { "The sum of our knowledge is in the sum of its people. Should you find a book or scroll that you cannot decipher, do not hesitate to bring it to me. If I can make sense of it I will share what I find. |", + 1, 5, TSFX_WITCH42 }, + { "To a man who only knows Iron, there is no greater magic than Steel. The blacksmith Griswold is more of a sorcerer than he knows. His ability to meld fire and metal is unequaled in this land. |", + 1, 5, TSFX_WITCH43 }, + { "Corruption has the strength of deceit, but innocence holds the power of purity. The young woman Gillian has a pure heart, placing the needs of her matriarch over her own. She fears me, but it is only because she does not understand me. |", + 1, 5, TSFX_WITCH44 }, + { "A chest opened in darkness holds no greater treasure than when it is opened in the light. The storyteller Cain is an enigma, but only to those who do not look. His knowledge of what lies beneath the cathedral is far greater than even he allows himself to realize. |", + 1, 5, TSFX_WITCH45 }, + { "The higher you place your faith in one man, the farther it has to fall. Farnham has lost his soul, but not to any demon. It was lost when he saw his fellow townspeople betrayed by the Archbishop Lazarus. He has knowledge to be gleaned, but you must separate fact from fantasy. |", + 1, 5, TSFX_WITCH46 }, + { "The hand, the heart and the mind can perform miracles when they are in perfect harmony. The healer Pepin sees into the body in a way that even I cannot. His ability to restore the sick and injured is magnified by his understanding of the creation of elixirs and potions. He is as great an ally as you have in Tristram. |", + 1, 5, TSFX_WITCH47 }, + { "There is much about the future we cannot see, but when it comes it will be the children who wield it. The boy Wirt has a blackness upon his soul, but he poses no threat to the town or its people. His secretive dealings with the urchins and unspoken guilds of nearby towns gain him access to many devices that cannot be easily found in Tristram. While his methods may be reproachful, Wirt can provide assistance for your battle against the encroaching Darkness. |", + 1, 4, TSFX_WITCH49 }, + { "Earthen walls and thatched canopy do not a home create. The innkeeper Ogden serves more of a purpose in this town than many understand. He provides shelter for Gillian and her matriarch, maintains what life Farnham has left to him, and provides an anchor for all who are left in the town to what Tristram once was. His tavern, and the simple pleasures that can still be found there, provide a glimpse of a life that the people here remember. It is that memory that continues to feed their hopes for your success. |", + 1, 4, TSFX_WITCH50 }, + { "Pssst... over here... |", 0, 5, TSFX_PEGBOY32 }, + { "Not everyone in Tristram has a use - or a market - for everything you will find in the labyrinth. Not even me, as hard as that is to believe. \n \nSometimes, only you will be able to find a purpose for some things. |", + 1, 6, TSFX_PEGBOY33 }, + { "Don't trust everything the drunk says. Too many ales have fogged his vision and his good sense. |", + 1, 6, TSFX_PEGBOY34 }, + { "In case you haven't noticed, I don't buy anything from Tristram. I am an importer of quality goods. If you want to peddle junk, you'll have to see Griswold, Pepin or that witch, Adria. I'm sure that they will snap up whatever you can bring them... |", + 1, 5, TSFX_PEGBOY35 }, + { "I guess I owe the blacksmith my life - what there is of it. Sure, Griswold offered me an apprenticeship at the smithy, and he is a nice enough guy, but I'll never get enough money to... well, let's just say that I have definite plans that require a large amount of gold. |", + 1, 5, TSFX_PEGBOY36 }, + { "If I were a few years older, I would shower her with whatever riches I could muster, and let me assure you I can get my hands on some very nice stuff. Gillian is a beautiful girl who should get out of Tristram as soon as it is safe. Hmmm... maybe I'll take her with me when I go... |", + 1, 5, TSFX_PEGBOY37 }, + { "Cain knows too much. He scares the life out of me - even more than that woman across the river. He keeps telling me about how lucky I am to be alive, and how my story is foretold in legend. I think he's off his crock. |", + 1, 5, TSFX_PEGBOY38 }, + { "Farnham - now there is a man with serious problems, and I know all about how serious problems can be. He trusted too much in the integrity of one man, and Lazarus led him into the very jaws of death. Oh, I know what it's like down there, so don't even start telling me about your plans to destroy the evil that dwells in that Labyrinth. Just watch your legs... |", + 1, 5, TSFX_PEGBOY39 }, + { "As long as you don't need anything reattached, old Pepin is as good as they come. \n \nIf I'd have had some of those potions he brews, I might still have my leg... |", + 1, 6, TSFX_PEGBOY40 }, + { "Adria truly bothers me. Sure, Cain is creepy in what he can tell you about the past, but that witch can see into your past. She always has some way to get whatever she needs, too. Adria gets her hands on more merchandise than I've seen pass through the gates of the King's Bazaar during High Festival. |", + 1, 5, TSFX_PEGBOY42 }, + { "Ogden is a fool for staying here. I could get him out of town for a very reasonable price, but he insists on trying to make a go of it with that stupid tavern. I guess at the least he gives Gillian a place to work, and his wife Garda does make a superb Shepherd's pie... |", + 1, 5, TSFX_PEGBOY43 }, + { "Beyond the Hall of Heroes lies the Chamber of Bone. Eternal death awaits any who would seek to steal the treasures secured within this room. So speaks the Lord of Terror, and so it is written. |", + 1, 5, PS_WARR1 }, + { "...and so, locked beyond the Gateway of Blood and past the Hall of Fire, Valor awaits for the Hero of Light to awaken... |", + 1, 6, PS_WARR10 }, + { "I can see what you see not.\nVision milky then eyes rot.\nWhen you turn they will be gone,\nWhispering their hidden song.\nThen you see what cannot be,\nShadows move where light should be.\nOut of darkness, out of mind,\nCast down into the Halls of the Blind. |\n", + 1, 5, PS_WARR11 }, + { "The armories of Hell are home to the Warlord of Blood. In his wake lay the mutilated bodies of thousands. Angels and man alike have been cut down to fulfill his endless sacrifices to the Dark ones who scream for one thing - blood. |", + 1, 5, PS_WARR12 }, + { "Beyond the Hall of Heroes lies the Chamber of Bone. Eternal death awaits any who would seek to steal the treasures secured within this room. So speaks the Lord of Terror, and so it is written. |", + 1, 5, PS_MAGE1 }, + { "...and so, locked beyond the Gateway of Blood and past the Hall of Fire, Valor awaits for the Hero of Light to awaken... |", + 1, 6, PS_MAGE10 }, + { "I can see what you see not.\nVision milky then eyes rot.\nWhen you turn they will be gone,\nWhispering their hidden song.\nThen you see what cannot be,\nShadows move where light should be.\nOut of darkness, out of mind,\nCast down into the Halls of the Blind. |\n", + 1, 4, PS_MAGE11 }, + { "The armories of Hell are home to the Warlord of Blood. In his wake lay the mutilated bodies of thousands. Angels and man alike have been cut down to fulfill his endless sacrifices to the Dark ones who scream for one thing - blood. |", + 1, 5, PS_MAGE12 }, + { "Beyond the Hall of Heroes lies the Chamber of Bone. Eternal death awaits any who would seek to steal the treasures secured within this room. So speaks the Lord of Terror, and so it is written. |", + 1, 5, PS_ROGUE1 }, + { "...and so, locked beyond the Gateway of Blood and past the Hall of Fire, Valor awaits for the Hero of Light to awaken... |", + 1, 5, PS_ROGUE10 }, + { "I can see what you see not.\nVision milky then eyes rot.\nWhen you turn they will be gone,\nWhispering their hidden song.\nThen you see what cannot be,\nShadows move where light should be.\nOut of darkness, out of mind,\nCast down into the Halls of the Blind. |\n", + 1, 5, PS_ROGUE11 }, + { "The armories of Hell are home to the Warlord of Blood. In his wake lay the mutilated bodies of thousands. Angels and man alike have been cut down to fulfill his endless sacrifices to the Dark ones who scream for one thing - blood. |", + 1, 5, PS_ROGUE12 }, + { " |", 0, 5, TSFX_COW1 }, + { " |", 0, 5, TSFX_COW2 }, + { "Take heed and bear witness to the truths that lie herein, for they are the last legacy of the Horadrim. There is a war that rages on even now, beyond the fields that we know - between the utopian kingdoms of the High Heavens and the chaotic pits of the Burning Hells. This war is known as the Great Conflict, and it has raged and burned longer than any of the stars in the sky. Neither side ever gains sway for long as the forces of Light and Darkness constantly vie for control over all creation. |", + 1, 5, PS_NAR1 }, + { "Take heed and bear witness to the truths that lie herein, for they are the last legacy of the Horadrim. When the Eternal Conflict between the High Heavens and the Burning Hells falls upon mortal soil, it is called the Sin War. Angels and Demons walk amongst humanity in disguise, fighting in secret, away from the prying eyes of mortals. Some daring, powerful mortals have even allied themselves with either side, and helped to dictate the course of the Sin War. |", + 1, 4, PS_NAR2 }, + { "Take heed and bear witness to the truths that lie herein, for they are the last legacy of the Horadrim. Nearly three hundred years ago, it came to be known that the Three Prime Evils of the Burning Hells had mysteriously come to our world. The Three Brothers ravaged the lands of the east for decades, while humanity was left trembling in their wake. Our Order - the Horadrim - was founded by a group of secretive magi to hunt down and capture the Three Evils once and for all.\n \nThe original Horadrim captured two of the Three within powerful artifacts known as Soulstones and buried them deep beneath the desolate eastern sands. The third Evil escaped capture and fled to the west with many of the Horadrim in pursuit. The Third Evil - known as Diablo, the Lord of Terror - was eventually captured, his essence set in a Soulstone and buried within this Labyrinth.\n \nBe warned that the soulstone must be kept from discovery by those not of the faith. If Diablo were to be released, he would seek a body that is easily controlled as he would be very weak - perhaps that of an old man or a child. |", + 1, 3, PS_NAR3 }, + { "So it came to be that there was a great revolution within the Burning Hells known as The Dark Exile. The Lesser Evils overthrew the Three Prime Evils and banished their spirit forms to the mortal realm. The demons Belial (the Lord of Lies) and Azmodan (the Lord of Sin) fought to claim rulership of Hell during the absence of the Three Brothers. All of Hell polarized between the factions of Belial and Azmodan while the forces of the High Heavens continually battered upon the very Gates of Hell. |", + 1, 4, PS_NAR4 }, + { "Many demons traveled to the mortal realm in search of the Three Brothers. These demons were followed to the mortal plane by Angels who hunted them throughout the vast cities of the East. The Angels allied themselves with a secretive Order of mortal magi named the Horadrim, who quickly became adept at hunting demons. They also made many dark enemies in the underworlds. |", + 1, 5, PS_NAR5 }, + { "So it came to be that the Three Prime Evils were banished in spirit form to the mortal realm and after sewing chaos across the East for decades, they were hunted down by the cursed Order of the mortal Horadrim. The Horadrim used artifacts called Soulstones to contain the essence of Mephisto, the Lord of Hatred and his brother Baal, the Lord of Destruction. The youngest brother - Diablo, the Lord of Terror - escaped to the west.\n \nEventually the Horadrim captured Diablo within a Soulstone as well, and buried him under an ancient, forgotten Cathedral. There, the Lord of Terror sleeps and awaits the time of his rebirth. Know ye that he will seek a body of youth and power to possess - one that is innocent and easily controlled. He will then arise to free his Brothers and once more fan the flames of the Sin War... |", + 1, 3, PS_NAR6 }, + { "All praises to Diablo - Lord of Terror and Survivor of The Dark Exile. When he awakened from his long slumber, my Lord and Master spoke to me of secrets that few mortals know. He told me the kingdoms of the High Heavens and the pits of the Burning Hells engage in an eternal war. He revealed the powers that have brought this discord to the realms of man. My lord has named the battle for this world and all who exist here the Sin War. |", + 1, 4, PS_NAR7 }, + { "Glory and Approbation to Diablo - Lord of Terror and Leader of the Three. My Lord spoke to me of his two Brothers, Mephisto and Baal, who were banished to this world long ago. My Lord wishes to bide his time and harness his awesome power so that he may free his captive brothers from their tombs beneath the sands of the east. Once my Lord releases his Brothers, the Sin War will once again know the fury of the Three. |", + 1, 4, PS_NAR8 }, + { "Hail and Sacrifice to Diablo - Lord of Terror and Destroyer of Souls. When I awoke my Master from his sleep, he attempted to possess a mortal's form. Diablo attempted to claim the body of King Leoric, but my Master was too weak from his imprisonment. My Lord required a simple and innocent anchor to this world, and so found the boy Albrecht to be perfect for the task. While the good King Leoric was left maddened by Diablo's unsuccessful possession, I kidnapped his son Albrecht and brought him before my Master. I now await Diablo's call and pray that I will be rewarded when he at last emerges as the Lord of this world. |", + 1, 3, PS_NAR9 }, + { "Thank goodness you've returned!\nMuch has changed since you lived here, my friend. All was peaceful until the dark riders came and destroyed our village. Many were cut down where they stood, and those who took up arms were slain or dragged away to become slaves - or worse. The church at the edge of town has been desecrated and is being used for dark rituals. The screams that echo in the night are inhuman, but some of our townsfolk may yet survive. Follow the path that lies between my tavern and the blacksmith shop to find the church and save who you can. \n \nPerhaps I can tell you more if we speak again. Good luck.|", + 1, 5, TSFX_TAVERN0 } +}; +const int gdwAllTextEntries = 259; /* unused */ diff --git a/Source/textdat.h b/Source/textdat.h new file mode 100644 index 000000000..3b0a695c0 --- /dev/null +++ b/Source/textdat.h @@ -0,0 +1,8 @@ +//HEADER_GOES_HERE +#ifndef __TEXTDAT_H__ +#define __TEXTDAT_H__ + +extern const TextDataStruct alltext[259]; +extern const int gdwAllTextEntries; + +#endif /* __TEXTDAT_H__ */ diff --git a/Source/themes.cpp b/Source/themes.cpp new file mode 100644 index 000000000..47cb233b3 --- /dev/null +++ b/Source/themes.cpp @@ -0,0 +1,1503 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int numthemes; // idb +bool armorFlag; // weak +int ThemeGoodIn[4]; +bool weaponFlag; // weak +bool treasureFlag; // weak +bool mFountainFlag; // weak +bool cauldronFlag; // weak +bool tFountainFlag; // weak +int zharlib; // weak +int themex; // idb +int themey; // idb +int themeVar1; // idb +ThemeStruct themes[MAXTHEMES]; +bool pFountainFlag; // weak +bool bFountainFlag; // weak +bool bCrossFlag; // weak +#endif + +int ThemeGood[4] = { THEME_GOATSHRINE, THEME_SHRINE, THEME_SKELROOM, THEME_LIBRARY }; + +int trm5x[25] = +{ + -2, -1, 0, 1, 2, + -2, -1, 0, 1, 2, + -2, -1, 0, 1, 2, + -2, -1, 0, 1, 2, + -2, -1, 0, 1, 2 +}; + +int trm5y[25] = +{ + -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2 +}; + +int trm3x[9] = +{ + -1, 0, 1, + -1, 0, 1, + -1, 0, 1 +}; + +int trm3y[9] = +{ + -1, -1, -1, + 0, 0, 0, + 1, 1, 1 +}; + +bool __fastcall TFit_Shrine(int i) +{ + int v1; // ecx + int v2; // esi + int v3; // eax + int v4; // edx + signed int v6; // [esp+Ch] [ebp-8h] + int v7; // [esp+10h] [ebp-4h] + + v1 = themes[i].ttval; + v7 = 0; + v2 = 0; + v6 = 0; + while ( 1 ) + { + v3 = v2 + 112 * v7; + if ( dung_map[0][v3] != v1 ) /* check */ + goto LABEL_20; + v4 = dPiece[0][v3 - 1]; // *(_DWORD *)&dflags[39][4 * v3 + 36]; + if ( nTrapTable[v4] + && !nSolidTable[dPiece[-1][v3]] // !nSolidTable[*(_DWORD *)&dflags[28][4 * v3 + 32]] + && !nSolidTable[dPiece[1][v3]] + && dung_map[-1][v3] == v1 // block_lvid[v3 + 1940] == v1 + && dung_map[1][v3] == v1 + && !dObject[-1][v3 - 1] + && !dObject[0][v3 + 111] ) + { + v6 = 1; + } + if ( v6 ) + break; + if ( !nTrapTable[dPiece[-1][v3]] // !nTrapTable[*(_DWORD *)&dflags[28][4 * v3 + 32]] + || nSolidTable[v4] + || nSolidTable[dPiece[0][v3 + 1]] + || dung_map[0][v3 - 1] != v1 // *(&byte_5B78EB + v3) != v1 + || dung_map[0][v3 + 1] != v1 + || dObject[-1][v3 - 1] + || dObject[-1][v3 + 1] ) /* check */ + { + goto LABEL_21; + } + v6 = 2; +LABEL_20: + if ( v6 ) + break; +LABEL_21: + if ( ++v7 == 112 ) + { + ++v2; + v7 = 0; + if ( v2 == 112 ) + return 0; + } + } + themey = v2; + themex = v7; + themeVar1 = v6; + return 1; +} + +bool __fastcall TFit_Obj5(int t) +{ + int v2; // ebx + int v3; // esi + int v4; // eax + int v5; // edi + int v6; // ecx + signed int v7; // edx + int v8; // ecx + int v10; // [esp+Ch] [ebp-Ch] + int v11; // [esp+10h] [ebp-8h] + signed int v12; // [esp+14h] [ebp-4h] + + v2 = 0; + v3 = 0; + v4 = random(0, 5) + 1; + v10 = v4; + if ( v4 <= 0 ) + { +LABEL_19: + themex = v2; + themey = v3; + return 1; + } + v5 = themes[t].ttval; + v11 = v5; + while ( 1 ) + { + v6 = v3 + 112 * v2; + if ( dung_map[0][v6] == v5 && !nSolidTable[dPiece[0][v6]] ) + { + v12 = 1; + v7 = 0; + do + { + if ( v7 >= 25 ) + break; + v8 = v3 + trm5y[v7] + 112 * (v2 + trm5x[v7]); + if ( nSolidTable[dPiece[0][v8]] ) + v12 = 0; + v5 = v11; + if ( dung_map[0][v8] != v11 ) + v12 = 0; + ++v7; + } + while ( v12 ); + if ( v12 ) + { + --v4; + goto LABEL_18; + } + } + if ( ++v2 != 112 ) + goto LABEL_18; + v2 = 0; + if ( ++v3 != 112 ) + goto LABEL_18; + if ( v4 == v10 ) + return 0; + v3 = 0; +LABEL_18: + if ( v4 <= 0 ) + goto LABEL_19; + } +} + +bool __fastcall TFit_SkelRoom(int t) +{ + int i; // esi + + if ( leveltype != 1 && leveltype != 2 ) + return 0; + i = 0; + if ( nummtypes <= 0 ) + return 0; + + while ( !IsSkel(Monsters[i].mtype) ) + { + ++i; + if ( i >= nummtypes ) + return 0; + } + themeVar1 = i; + return TFit_Obj5(t); +} +// 5BB1ED: using guessed type char leveltype; + +bool __fastcall TFit_GoatShrine(int t) +{ + int i; // esi + + i = 0; + if ( nummtypes <= 0 ) + return 0; + + while ( !IsGoat(Monsters[i].mtype) ) + { + ++i; + if ( i >= nummtypes ) + return 0; + } + themeVar1 = i; + return TFit_Obj5(t); +} + +bool __fastcall CheckThemeObj3(int xp, int yp, int t, int f) +{ + int i; // edi + + i = 0; + while ( 1 ) + { + if ( xp + trm3x[i] < 0 ) + break; + if ( yp + trm3y[i] < 0 ) + break; + if ( nSolidTable[dPiece[xp + trm3x[i]][yp + trm3y[i]]] ) + break; + if ( dung_map[xp + trm3x[i]][yp + trm3y[i]] != themes[t].ttval ) + break; + if ( dObject[xp + trm3x[i]][yp + trm3y[i]] ) + break; + if ( f != -1 ) + { + if ( !random(0, f) ) + break; + } + ++i; + if ( i >= 9 ) + return 1; + } + return 0; +} + +bool __fastcall TFit_Obj3(int t) +{ + int yp; // edi + int xp; // esi + char objrnd[4]; // [esp+Bh] [ebp-5h] + + objrnd[0] = 4; + objrnd[1] = 4; + objrnd[2] = 3; + objrnd[3] = 5; + yp = 1; + while ( 2 ) + { + xp = 1; + do + { + if ( CheckThemeObj3(xp, yp, t, objrnd[leveltype-1]) ) + { + themex = xp; + themey = yp; + return 1; + } + ++xp; + } + while ( xp < 111 ); + if ( ++yp < 111 ) + continue; + break; + } + return 0; +} +// 5BB1ED: using guessed type char leveltype; + +bool __fastcall CheckThemeReqs(int t) +{ + bool rv; // al + int v2; // ecx + int v3; // ecx + int v4; // ecx + int v5; // ecx + bool v6; // zf + int v7; // ecx + int v8; // ecx + int v9; // ecx + + rv = 1; + if ( t <= 10 ) + { + if ( t != 10 ) + { + v2 = t - 1; + if ( v2 ) + { + v3 = v2 - 2; + if ( v3 ) + { + v4 = v3 - 2; + if ( v4 ) + { + v5 = v4 - 2; + if ( v5 ) + { + if ( v5 != 2 ) + return rv; + v6 = pFountainFlag == 0; + } + else + { + v6 = bFountainFlag == 0; + } +LABEL_21: + if ( !v6 ) + return rv; + return 0; + } + } + } + if ( leveltype != 3 ) + { + v6 = leveltype == DTYPE_HELL; + goto LABEL_21; + } + return 0; + } +LABEL_16: + v6 = leveltype == DTYPE_CATHEDRAL; + goto LABEL_21; + } + v7 = t - 12; + if ( v7 ) + { + v8 = v7 - 1; + if ( !v8 ) + { + v6 = mFountainFlag == 0; + goto LABEL_21; + } + v9 = v8 - 1; + if ( !v9 ) + { + v6 = tFountainFlag == 0; + goto LABEL_21; + } + if ( v9 != 2 ) + return rv; + goto LABEL_16; + } + if ( leveltype == DTYPE_HELL ) + { + v6 = cauldronFlag == 0; + goto LABEL_21; + } + return 0; +} +// 5BB1ED: using guessed type char leveltype; +// 6AAA58: using guessed type int mFountainFlag; +// 6AAA5C: using guessed type int cauldronFlag; +// 6AAA60: using guessed type int tFountainFlag; +// 6AAC08: using guessed type int pFountainFlag; +// 6AAC0C: using guessed type int bFountainFlag; + +bool __fastcall SpecialThemeFit(int i, int t) +{ + bool rv; // eax + + rv = CheckThemeReqs(t); + switch ( t ) + { + case THEME_SHRINE: + case THEME_LIBRARY: + if ( rv ) + rv = TFit_Shrine(i); + break; + case THEME_SKELROOM: + if ( rv ) + rv = TFit_SkelRoom(i); + break; + case THEME_TREASURE: + rv = treasureFlag; + if ( treasureFlag ) + treasureFlag = 0; + break; + case THEME_TORTURE: + case THEME_DECAPITATED: + case THEME_ARMORSTAND: + case THEME_BRNCROSS: + case THEME_WEAPONRACK: + if ( rv ) + rv = TFit_Obj3(i); + break; + case THEME_BLOODFOUNTAIN: + if ( rv ) + { + rv = TFit_Obj5(i); + if ( rv ) + bFountainFlag = 0; + } + break; + case THEME_PURIFYINGFOUNTAIN: + if ( rv ) + { + rv = TFit_Obj5(i); + if ( rv ) + pFountainFlag = 0; + } + break; + case THEME_GOATSHRINE: + if ( rv ) + rv = TFit_GoatShrine(i); + break; + case THEME_CAULDRON: + if ( rv ) + { + rv = TFit_Obj5(i); + if ( rv ) + cauldronFlag = 0; + } + break; + case THEME_MURKYFOUNTAIN: + if ( rv ) + { + rv = TFit_Obj5(i); + if ( rv ) + mFountainFlag = 0; + } + break; + case THEME_TEARFOUNTAIN: + if ( rv ) + { + rv = TFit_Obj5(i); + if ( rv ) + tFountainFlag = 0; + } + break; + default: + return rv; + } + return rv; +} +// 6AAA54: using guessed type int treasureFlag; +// 6AAA58: using guessed type int mFountainFlag; +// 6AAA5C: using guessed type int cauldronFlag; +// 6AAA60: using guessed type int tFountainFlag; +// 6AAC08: using guessed type int pFountainFlag; +// 6AAC0C: using guessed type int bFountainFlag; + +bool __fastcall CheckThemeRoom(int tv) +{ + int v1; // esi + int *v2; // edx + signed int v3; // edi + signed int v4; // esi + signed int v5; // edx + signed int v6; // eax + int v7; // edi + int *v8; // esi + char *v9; // eax + int *v10; // edx + signed int v12; // [esp+Ch] [ebp-8h] + + v1 = 0; + if ( trigflag[4] <= 0 ) + { +LABEL_5: + v3 = 0; + v4 = 0; + do + { + v5 = 0; + v6 = v4; + do + { + if ( dung_map[0][v6] == tv ) + { + if ( dFlags[0][v6] & 8 ) + return 0; + ++v3; + } + ++v5; + v6 += 112; + } + while ( v5 < 112 ); + ++v4; + } + while ( v4 < 112 ); + if ( leveltype != 1 || v3 >= 9 && v3 <= 100 ) + { + v7 = 0; + v8 = &dPiece[-1][111]; +LABEL_16: + v12 = 0; + v9 = &dung_map[-1][v7 + 111]; + v10 = v8; + while ( v9[1] != tv + || nSolidTable[v10[1]] + || (*(v9 - 111) == tv || nSolidTable[*(v10 - 111)]) /* check */ + && (v9[113] == tv || nSolidTable[v10[113]]) + && (*v9 == tv || nSolidTable[*v10]) + && (v9[2] == tv || nSolidTable[v10[2]]) ) + { + ++v12; + v10 += 112; + v9 += 112; + if ( v12 >= 112 ) + { + ++v8; + ++v7; + if ( (signed int)v8 < (signed int)&dPiece[0][111] ) + goto LABEL_16; + return 1; + } + } + } + } + else + { + v2 = &trigs[0]._ty; + while ( dung_map[*(v2 - 1)][*v2] != tv ) + { + ++v1; + v2 += 4; + if ( v1 >= trigflag[4] ) + goto LABEL_5; + } + } + return 0; +} +// 5BB1ED: using guessed type char leveltype; + +void __cdecl InitThemes() +{ + int v0; // esi + char v1; // bl + int v2; // edi + //int v3; // eax + int i; // ebx + //int v6; // eax + int v8; // esi + int v9; // ecx + int j; // eax + //int v11; // eax + int *v13; // edi + int v14; // esi + int *v15; // ebx + //int v16; // eax + int v17; // eax + int k; // esi + int l; // ebx + //int v20; // eax + + zharlib = -1; + v0 = 0; + bCrossFlag = 0; + numthemes = 0; + armorFlag = 1; + bFountainFlag = 1; + cauldronFlag = 1; + mFountainFlag = 1; + pFountainFlag = 1; + tFountainFlag = 1; + treasureFlag = 1; + weaponFlag = 1; + if ( currlevel != 16 ) + { + v1 = leveltype; + if ( leveltype == DTYPE_CATHEDRAL ) + { + ThemeGoodIn[0] = 0; + ThemeGoodIn[1] = 0; + ThemeGoodIn[2] = 0; + ThemeGoodIn[3] = 0; + v2 = 0; + do + { + if ( v0 >= MAXTHEMES ) + break; + //_LOBYTE(v3) = CheckThemeRoom(v2); + if ( CheckThemeRoom(v2) ) + { + themes[v0].ttval = v2; + for ( i = ThemeGood[random(0, 4)]; ; i = random(0, 17) ) + { + //_LOBYTE(v6) = SpecialThemeFit(numthemes, i); + if ( SpecialThemeFit(numthemes, i) ) + break; + } + v8 = numthemes; + themes[numthemes].ttype = i; + v1 = leveltype; + v0 = v8 + 1; + numthemes = v0; + } + ++v2; + } + while ( v2 < 256 ); + } + if ( v1 == 2 || v1 == 3 || v1 == 4 ) + { + v9 = themeCount; + for ( j = 0; j < v9; ++j ) + themes[j].ttype = -1; + //_LOBYTE(v11) = QuestStatus(3); + v13 = &themeLoc[0].ttval; + if ( QuestStatus(3) ) + { + v14 = 0; + if ( themeCount > 0 ) + { + v15 = &themeLoc[0].ttval; + while ( 1 ) + { + themes[v14].ttval = *v15; + //_LOBYTE(v16) = SpecialThemeFit(v14, 5); + if ( SpecialThemeFit(v14, 5) ) + break; + ++v14; + v15 += 5; + if ( v14 >= themeCount ) + goto LABEL_23; + } + themes[v14].ttype = 5; + zharlib = v14; + } + } +LABEL_23: + v17 = themeCount; + for ( k = 0; k < themeCount; v13 += 5 ) + { + if ( themes[k].ttype == -1 ) + { + themes[k].ttval = *v13; + for ( l = ThemeGood[random(0, 4)]; ; l = random(0, 17) ) + { + //_LOBYTE(v20) = SpecialThemeFit(k, l); + if ( SpecialThemeFit(k, l) ) + break; + } + themes[k].ttype = l; + } + v17 = themeCount; + ++k; + } + numthemes += v17; + } + } +} +// 5BB1ED: using guessed type char leveltype; +// 6AAA3C: using guessed type int armorFlag; +// 6AAA50: using guessed type int weaponFlag; +// 6AAA54: using guessed type int treasureFlag; +// 6AAA58: using guessed type int mFountainFlag; +// 6AAA5C: using guessed type int cauldronFlag; +// 6AAA60: using guessed type int tFountainFlag; +// 6AAA64: using guessed type int zharlib; +// 6AAC08: using guessed type int pFountainFlag; +// 6AAC0C: using guessed type int bFountainFlag; +// 6AAC10: using guessed type int bCrossFlag; + +void __cdecl HoldThemeRooms() +{ + int v0; // ebx + int i; // esi + char v2; // dl + signed int v3; // ecx + signed int v4; // eax + signed int v5; // edi + + if ( currlevel != 16 ) + { + if ( leveltype == DTYPE_CATHEDRAL ) + { + v0 = numthemes; + for ( i = 0; i < v0; ++i ) + { + v2 = themes[i].ttval; + v3 = 0; + do + { + v4 = v3; + v5 = 112; + do + { + if ( dung_map[0][v4] == v2 ) + dFlags[0][v4] |= 8u; + v4 += 112; + --v5; + } + while ( v5 ); + ++v3; + } + while ( v3 < 112 ); + } + } + else + { + DRLG_HoldThemeRooms(); + } + } +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall PlaceThemeMonsts(int t, int f) +{ + int numscattypes; // edx + int i; // ecx + int yp; // ebx + int xp; // edi + int scattertypes[111]; // [esp+Ch] [ebp-1D0h] + int mtype; // [esp+1CCh] [ebp-10h] + + numscattypes = 0; + + if ( nummtypes > 0 ) + { + for(i = 0; i < nummtypes; i++) + { + if ( Monsters[i].mPlaceFlags & 1 ) + scattertypes[numscattypes++] = i; + } + } + + mtype = scattertypes[random(0, numscattypes)]; + + for(yp = 0; yp < 112; yp++) + { + for(xp = 0; xp < 112; xp++) + { + if ( dung_map[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]] && !dItem[xp][yp] && !dObject[xp][yp] ) + { + if ( !random(0, f) ) + AddMonster(xp, yp, random(0, 8), mtype, 1); + } + } + } +} +// 45D0E1: using guessed type int var_1D0[111]; + +void __fastcall Theme_Barrel(int t) +{ + int yp; // edi + int xp; // ebx + int r; + char monstrnd[4]; + char barrnd[4]; + + barrnd[0] = 2; + barrnd[1] = 6; + barrnd[2] = 4; + barrnd[3] = 8; + monstrnd[0] = 5; + monstrnd[1] = 7; + monstrnd[2] = 3; + monstrnd[3] = 9; + + for(yp = 0; yp < 112; yp++) + { + for(xp = 0; xp < 112; xp++) + { + if ( dung_map[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]] ) + { + if ( !random(0, barrnd[leveltype-1]) ) + { + r = random(0, barrnd[leveltype-1]); + AddObject((r != 0) + OBJ_BARREL, xp, yp); + } + } + } + } + + PlaceThemeMonsts(t, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_Shrine(int t) +{ + char monstrnd[4]; // [esp+3h] [ebp-5h] + + monstrnd[0] = 6; + monstrnd[1] = 6; + monstrnd[2] = 3; + monstrnd[3] = 9; + TFit_Shrine(t); + if ( themeVar1 == 1 ) + { + AddObject(OBJ_CANDLE2, themex - 1, themey); + AddObject(OBJ_SHRINER, themex, themey); + AddObject(OBJ_CANDLE2, themex + 1, themey); + } + else + { + AddObject(OBJ_CANDLE2, themex, themey - 1); + AddObject(OBJ_SHRINEL, themex, themey); + AddObject(OBJ_CANDLE2, themex, themey + 1); + } + PlaceThemeMonsts(t, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_MonstPit(int t) +{ + int r; // eax + int ixp; // ecx + int iyp; // edx + char monstrnd[4]; // [esp+4h] [ebp-8h] + + monstrnd[0] = 6; + monstrnd[1] = 7; + monstrnd[2] = 3; + monstrnd[3] = 9; + r = random(0, 100) + 1; + ixp = 0; + iyp = 0; + if ( r > 0 ) + { + while ( 1 ) + { + if ( dung_map[ixp][iyp] == themes[t].ttval && !nSolidTable[dPiece[ixp][iyp]] ) + --r; + if ( r <= 0 ) + break; + if ( ++ixp == 112 ) + { + ixp = 0; + if ( ++iyp == 112 ) + iyp = 0; + } + } + } + CreateRndItem(ixp, iyp, 1u, 0, 1); + ItemNoFlippy(); + PlaceThemeMonsts(t, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_SkelRoom(int t) +{ + int yp; // esi + int xp; // edi + char monstrnd[4]; // [esp+Bh] [ebp-5h] + + monstrnd[0] = 6; + monstrnd[1] = 7; + monstrnd[2] = 3; + monstrnd[3] = 9; + TFit_SkelRoom(t); + yp = themey; + xp = themex; + AddObject(OBJ_SKFIRE, themex, themey); + + if ( random(0, monstrnd[leveltype-1]) ) + SpawnSkeleton(PreSpawnSkeleton(), xp - 1, yp - 1); + else + AddObject(OBJ_BANNERL, xp - 1, yp - 1); + + SpawnSkeleton(PreSpawnSkeleton(), xp, yp - 1); + + if ( random(0, monstrnd[leveltype-1]) ) + SpawnSkeleton(PreSpawnSkeleton(), xp + 1, yp - 1); + else + AddObject(OBJ_BANNERR, xp + 1, yp - 1); + + if ( random(0, monstrnd[leveltype-1]) ) + SpawnSkeleton(PreSpawnSkeleton(), xp - 1, yp); + else + AddObject(OBJ_BANNERM, xp - 1, yp); + + if ( random(0, monstrnd[leveltype-1]) ) + SpawnSkeleton(PreSpawnSkeleton(), xp + 1, yp); + else + AddObject(OBJ_BANNERM, xp + 1, yp); + + if ( random(0, monstrnd[leveltype-1]) ) + SpawnSkeleton(PreSpawnSkeleton(), xp - 1, yp + 1); + else + AddObject(OBJ_BANNERR, xp - 1, yp + 1); + + SpawnSkeleton(PreSpawnSkeleton(), xp, yp + 1); + + if ( random(0, monstrnd[leveltype-1]) ) + SpawnSkeleton(PreSpawnSkeleton(), xp + 1, yp + 1); + else + AddObject(OBJ_BANNERL, xp + 1, yp + 1); + + if ( !dObject[xp][yp - 3] ) // dungeon[xp + 39][yp + 37] ) /* fix */ + AddObject(OBJ_SKELBOOK, xp, yp - 2); + if ( !dObject[xp][yp + 3] ) + AddObject(OBJ_SKELBOOK, xp, yp + 2); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_Treasure(int t) +{ + int yp; // esi + int xp; // edi + int rv; // [esp+14h] [ebp-10h] + char monstrnd[4]; // [esp+18h] [ebp-Ch] + char treasrnd[4]; // [esp+20h] [ebp-4h] + + treasrnd[0] = 4; + treasrnd[1] = 9; + treasrnd[2] = 7; + treasrnd[3] = 10; + monstrnd[0] = 6; + monstrnd[1] = 8; + monstrnd[2] = 3; + monstrnd[3] = 7; + GetRndSeed(); + for(yp = 0; yp < 112; yp++) + { + for(xp = 0; xp < 112; xp++) + { + if ( dung_map[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]] ) + { + rv = random(0, treasrnd[leveltype-1]); + if ( !(2 * random(0, treasrnd[leveltype-1])) ) + { + CreateTypeItem(xp, yp, 0, ITYPE_GOLD, 0, 0, 1); + ItemNoFlippy(); + } + if ( !rv ) + { + CreateRndItem(xp, yp, 0, 0, 1); + ItemNoFlippy(); + } + if ( rv >= treasrnd[leveltype-1] - 2 && leveltype != 1 ) + item[ItemNoFlippy()]._ivalue >>= 1; /* check */ + } + } + } + PlaceThemeMonsts(t, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_Library(int t) +{ + int v1; // edi + int v2; // ebx + char *v3; // esi + //int v4; // eax + int v7; // eax + //int v8; // eax + int ta; // [esp+Ch] [ebp-14h] + int *v10; // [esp+10h] [ebp-10h] + int *v11; // [esp+14h] [ebp-Ch] + char monstrnd[4]; // [esp+18h] [ebp-8h] + char librnd[4]; // [esp+1Ch] [ebp-4h] + + ta = t; + librnd[0] = 1; + librnd[1] = 2; + librnd[2] = 2; + librnd[3] = 5; + monstrnd[0] = 5; + monstrnd[1] = 7; + monstrnd[2] = 3; + monstrnd[3] = 9; + TFit_Shrine(t); + v1 = 1; + if ( themeVar1 == 1 ) + { + AddObject(OBJ_BOOKCANDLE, themex - 1, themey); + AddObject(OBJ_BOOKCASER, themex, themey); + AddObject(OBJ_BOOKCANDLE, themex + 1, themey); + } + else + { + AddObject(OBJ_BOOKCANDLE, themex, themey - 1); + AddObject(OBJ_BOOKCASEL, themex, themey); + AddObject(OBJ_BOOKCANDLE, themex, themey + 1); + } + v11 = &dMonster[1][1]; + do + { + v2 = 1; + v3 = &dObject[1][v1]; + v10 = v11; + do + { + //LOBYTE(v4) = CheckThemeObj3(v2, v1, ta, -1); + if ( CheckThemeObj3(v2, v1, ta, -1) ) + { + if ( !*v10 ) + { + if ( !random(0, librnd[leveltype-1]) ) + { + AddObject(OBJ_BOOKSTAND, v2, v1); + if ( random(0, 2 * librnd[leveltype-1]) ) + { + v7 = *v3 - 1; + object[v7]._oSelFlag = 0; + object[v7]._oAnimFrame += 2; + } + } + } + } + v10 += 112; + ++v2; + v3 += 112; + } + while ( v2 < 111 ); + ++v11; + ++v1; + } + while ( (signed int)v11 < (signed int)&dMonster[1][111] ); + //LOBYTE(v8) = QuestStatus(3); + if ( !QuestStatus(3) || ta != zharlib ) + PlaceThemeMonsts(ta, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; +// 6AAA64: using guessed type int zharlib; + +void __fastcall Theme_Torture(int t) +{ + int v1; // ebx + int v2; // esi + char *v3; // edi + //int v4; // eax + int *x; // [esp+Ch] [ebp-14h] + char monstrnd[4]; // [esp+10h] [ebp-10h] + int *v8; // [esp+14h] [ebp-Ch] + char tortrnd[4]; // [esp+18h] [ebp-8h] + int v10; // [esp+1Ch] [ebp-4h] + + v1 = t; + tortrnd[0] = 6; + tortrnd[1] = 8; + tortrnd[2] = 3; + tortrnd[3] = 8; + monstrnd[0] = 6; + monstrnd[1] = 8; + monstrnd[2] = 3; + monstrnd[3] = 9; + v2 = 1; + v8 = &dPiece[1][1]; + do + { + v10 = 1; + v3 = &dung_map[1][v2]; + x = v8; + do + { + if ( *v3 == themes[v1].ttval && !nSolidTable[*x] ) + { + //LOBYTE(v4) = CheckThemeObj3(v10, v2, v1, -1); + if ( CheckThemeObj3(v10, v2, v1, -1) ) + { + if ( !random(0, tortrnd[leveltype-1]) ) + AddObject(OBJ_TNUDEM2, v10, v2); + } + } + ++v10; + x += 112; + v3 += 112; + } + while ( v10 < 111 ); + ++v8; + ++v2; + } + while ( (signed int)v8 < (signed int)&dPiece[1][111] ); + PlaceThemeMonsts(v1, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_BloodFountain(int t) +{ + char monstrnd[4]; // [esp+3h] [ebp-5h] + + monstrnd[0] = 6; + monstrnd[1] = 8; + monstrnd[2] = 3; + monstrnd[3] = 9; + TFit_Obj5(t); + AddObject(OBJ_BLOODFTN, themex, themey); + PlaceThemeMonsts(t, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_Decap(int t) +{ + int v1; // ebx + int v2; // esi + char *v3; // edi + //int v4; // eax + int *x; // [esp+Ch] [ebp-14h] + char monstrnd[4]; // [esp+10h] [ebp-10h] + int *v8; // [esp+14h] [ebp-Ch] + char decaprnd[4]; // [esp+18h] [ebp-8h] + int v10; // [esp+1Ch] [ebp-4h] + + v1 = t; + decaprnd[0] = 6; + decaprnd[1] = 8; + decaprnd[2] = 3; + decaprnd[3] = 8; + monstrnd[0] = 6; + monstrnd[1] = 8; + monstrnd[2] = 3; + monstrnd[3] = 9; + v2 = 1; + v8 = &dPiece[1][1]; + do + { + v10 = 1; + v3 = &dung_map[1][v2]; + x = v8; + do + { + if ( *v3 == themes[v1].ttval && !nSolidTable[*x] ) + { + //LOBYTE(v4) = CheckThemeObj3(v10, v2, v1, -1); + if ( CheckThemeObj3(v10, v2, v1, -1) ) + { + if ( !random(0, decaprnd[leveltype-1]) ) + AddObject(OBJ_DECAP, v10, v2); + } + } + ++v10; + x += 112; + v3 += 112; + } + while ( v10 < 111 ); + ++v8; + ++v2; + } + while ( (signed int)v8 < (signed int)&dPiece[1][111] ); + PlaceThemeMonsts(v1, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_PurifyingFountain(int t) +{ + char monstrnd[4]; // [esp+3h] [ebp-5h] + + monstrnd[0] = 6; + monstrnd[1] = 7; + monstrnd[2] = 3; + monstrnd[3] = 9; + TFit_Obj5(t); + AddObject(OBJ_PURIFYINGFTN, themex, themey); + PlaceThemeMonsts(t, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_ArmorStand(int t) +{ + int v1; // esi + int v2; // ebx + char *v3; // edi + //int v4; // eax + int ta; // [esp+Ch] [ebp-14h] + int *v7; // [esp+10h] [ebp-10h] + char monstrnd[4]; // [esp+14h] [ebp-Ch] + int *v9; // [esp+18h] [ebp-8h] + char armorrnd[4]; // [esp+1Ch] [ebp-4h] + + v1 = 0; + ta = t; + armorrnd[0] = 6; + armorrnd[1] = 8; + armorrnd[2] = 3; + armorrnd[3] = 8; + monstrnd[0] = 6; + monstrnd[1] = 7; + monstrnd[2] = 3; + monstrnd[3] = 9; + if ( armorFlag ) + { + TFit_Obj3(t); + AddObject(OBJ_ARMORSTAND, themex, themey); + } + v9 = (int *)dPiece; + do + { + v2 = 0; + v3 = (char *)dung_map + v1; + v7 = v9; + do + { + if ( *v3 == themes[ta].ttval && !nSolidTable[*v7] ) + { + //LOBYTE(v4) = CheckThemeObj3(v2, v1, ta, -1); + if ( CheckThemeObj3(v2, v1, ta, -1) ) + { + if ( !random(0, armorrnd[leveltype-1]) ) + AddObject(OBJ_ARMORSTANDN, v2, v1); + } + } + v7 += 112; + ++v2; + v3 += 112; + } + while ( v2 < 112 ); + ++v9; + ++v1; + } + while ( (signed int)v9 < (signed int)dPiece[1] ); + PlaceThemeMonsts(ta, monstrnd[leveltype-1]); + armorFlag = 0; +} +// 5BB1ED: using guessed type char leveltype; +// 6AAA3C: using guessed type int armorFlag; + +void __fastcall Theme_GoatShrine(int t) +{ + int v1; // edx + int v2; // esi + int v3; // ecx + int v4; // edi + int v5; // eax + char *v6; // ebx + _DWORD *v7; // [esp+4h] [ebp-8h] + + TFit_GoatShrine(t); + AddObject(OBJ_GOATSHRINE, themex, themey); + v1 = themey; + v2 = themey - 1; + if ( themey - 1 <= themey + 1 ) + { + v3 = themex; + do + { + v4 = v3 - 1; + if ( (unsigned char)(__OFSUB__(v3 - 1, v3 + 1) ^ 1) | (v3 - 1 == v3 + 1) ) + { + v5 = v2 + 112 * v4; + v6 = (char *)dung_map + v5; + v7 = (_DWORD *)((char *)dPiece + 4 * v5); + do + { + if ( *v6 == themes[t].ttval && !nSolidTable[*v7] && (v4 != v3 || v2 != v1) ) + { + AddMonster(v4, v2, 1, themeVar1, 1); + v1 = themey; + v3 = themex; + } + v7 += 112; + ++v4; + v6 += 112; + } + while ( v4 <= v3 + 1 ); + } + ++v2; + } + while ( v2 <= v1 + 1 ); + } +} + +void __fastcall Theme_Cauldron(int t) +{ + char monstrnd[4]; // [esp+3h] [ebp-5h] + + monstrnd[0] = 6; + monstrnd[1] = 7; + monstrnd[2] = 3; + monstrnd[3] = 9; + TFit_Obj5(t); + AddObject(OBJ_CAULDRON, themex, themey); + PlaceThemeMonsts(t, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_MurkyFountain(int t) +{ + char monstrnd[4]; // [esp+3h] [ebp-5h] + + monstrnd[0] = 6; + monstrnd[1] = 7; + monstrnd[2] = 3; + monstrnd[3] = 9; + TFit_Obj5(t); + AddObject(OBJ_MURKYFTN, themex, themey); + PlaceThemeMonsts(t, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_TearFountain(int t) +{ + char monstrnd[4]; // [esp+3h] [ebp-5h] + + monstrnd[0] = 6; + monstrnd[1] = 7; + monstrnd[2] = 3; + monstrnd[3] = 9; + TFit_Obj5(t); + AddObject(OBJ_TEARFTN, themex, themey); + PlaceThemeMonsts(t, monstrnd[leveltype-1]); +} +// 5BB1ED: using guessed type char leveltype; + +void __fastcall Theme_BrnCross(int t) +{ + int v1; // esi + int v2; // ebx + char *v3; // edi + //int v4; // eax + int ta; // [esp+Ch] [ebp-14h] + int *v7; // [esp+10h] [ebp-10h] + char monstrnd[4]; // [esp+14h] [ebp-Ch] + int *v9; // [esp+18h] [ebp-8h] + char bcrossrnd[4]; // [esp+1Ch] [ebp-4h] + + ta = t; + monstrnd[0] = 6; + monstrnd[1] = 8; + monstrnd[2] = 3; + monstrnd[3] = 9; + bcrossrnd[0] = 5; + bcrossrnd[1] = 7; + bcrossrnd[2] = 3; + bcrossrnd[3] = 8; + v1 = 0; + v9 = (int *)dPiece; + do + { + v2 = 0; + v3 = (char *)dung_map + v1; + v7 = v9; + do + { + if ( *v3 == themes[ta].ttval && !nSolidTable[*v7] ) + { + //LOBYTE(v4) = CheckThemeObj3(v2, v1, ta, -1); + if ( CheckThemeObj3(v2, v1, ta, -1) ) + { + if ( !random(0, bcrossrnd[leveltype-1]) ) + AddObject(OBJ_TBCROSS, v2, v1); + } + } + v7 += 112; + ++v2; + v3 += 112; + } + while ( v2 < 112 ); + ++v9; + ++v1; + } + while ( (signed int)v9 < (signed int)dPiece[1] ); + PlaceThemeMonsts(ta, monstrnd[leveltype-1]); + bCrossFlag = 1; +} +// 5BB1ED: using guessed type char leveltype; +// 6AAC10: using guessed type int bCrossFlag; + +void __fastcall Theme_WeaponRack(int t) +{ + int v1; // esi + int v2; // ebx + char *v3; // edi + //int v4; // eax + int ta; // [esp+Ch] [ebp-14h] + int *v7; // [esp+10h] [ebp-10h] + char monstrnd[4]; // [esp+14h] [ebp-Ch] + int *v9; // [esp+18h] [ebp-8h] + char weaponrnd[4]; // [esp+1Ch] [ebp-4h] + + v1 = 0; + ta = t; + weaponrnd[0] = 6; + weaponrnd[1] = 8; + weaponrnd[2] = 5; + weaponrnd[3] = 8; + monstrnd[0] = 6; + monstrnd[1] = 7; + monstrnd[2] = 3; + monstrnd[3] = 9; + if ( weaponFlag ) + { + TFit_Obj3(t); + AddObject(OBJ_WEAPONRACK, themex, themey); + } + v9 = (int *)dPiece; + do + { + v2 = 0; + v3 = (char *)dung_map + v1; + v7 = v9; + do + { + if ( *v3 == themes[ta].ttval && !nSolidTable[*v7] ) + { + //LOBYTE(v4) = CheckThemeObj3(v2, v1, ta, -1); + if ( CheckThemeObj3(v2, v1, ta, -1) ) + { + if ( !random(0, weaponrnd[leveltype-1]) ) + AddObject(OBJ_WEAPONRACKN, v2, v1); + } + } + v7 += 112; + ++v2; + v3 += 112; + } + while ( v2 < 112 ); + ++v9; + ++v1; + } + while ( (signed int)v9 < (signed int)dPiece[1] ); + PlaceThemeMonsts(ta, monstrnd[leveltype-1]); + weaponFlag = 0; +} +// 5BB1ED: using guessed type char leveltype; +// 6AAA50: using guessed type int weaponFlag; + +void __cdecl UpdateL4Trans() +{ + int i; // ecx + int j; // edx + + for(i = 0; i < 112; i++) + { + for(j = 0; j < 112; j++) + { + if ( dung_map[i][j] ) + dung_map[i][j] = 1; + } + } +} + +void __cdecl CreateThemeRooms() +{ + int i; // esi + + if ( currlevel != 16 ) + { + InitObjFlag = 1; + for ( i = 0; i < numthemes; i++ ) + { + themex = 0; + themey = 0; + switch ( themes[i].ttype ) + { + case THEME_BARREL: + Theme_Barrel(i); + break; + case THEME_SHRINE: + Theme_Shrine(i); + break; + case THEME_MONSTPIT: + Theme_MonstPit(i); + break; + case THEME_SKELROOM: + Theme_SkelRoom(i); + break; + case THEME_TREASURE: + Theme_Treasure(i); + break; + case THEME_LIBRARY: + Theme_Library(i); + break; + case THEME_TORTURE: + Theme_Torture(i); + break; + case THEME_BLOODFOUNTAIN: + Theme_BloodFountain(i); + break; + case THEME_DECAPITATED: + Theme_Decap(i); + break; + case THEME_PURIFYINGFOUNTAIN: + Theme_PurifyingFountain(i); + break; + case THEME_ARMORSTAND: + Theme_ArmorStand(i); + break; + case THEME_GOATSHRINE: + Theme_GoatShrine(i); + break; + case THEME_CAULDRON: + Theme_Cauldron(i); + break; + case THEME_MURKYFOUNTAIN: + Theme_MurkyFountain(i); + break; + case THEME_TEARFOUNTAIN: + Theme_TearFountain(i); + break; + case THEME_BRNCROSS: + Theme_BrnCross(i); + break; + case THEME_WEAPONRACK: + Theme_WeaponRack(i); + break; + default: + continue; + } + } + InitObjFlag = 0; + if ( leveltype == DTYPE_HELL && themeCount > 0 ) + UpdateL4Trans(); + } +} +// 5BB1ED: using guessed type char leveltype; +// 67D7C0: using guessed type int InitObjFlag; diff --git a/Source/themes.h b/Source/themes.h new file mode 100644 index 000000000..cacdff44f --- /dev/null +++ b/Source/themes.h @@ -0,0 +1,62 @@ +//HEADER_GOES_HERE +#ifndef __THEMES_H__ +#define __THEMES_H__ + +extern int numthemes; // idb +extern bool armorFlag; // weak +extern int ThemeGoodIn[4]; +extern bool weaponFlag; // weak +extern bool treasureFlag; // weak +extern bool mFountainFlag; // weak +extern bool cauldronFlag; // weak +extern bool tFountainFlag; // weak +extern int zharlib; // weak +extern int themex; // idb +extern int themey; // idb +extern int themeVar1; // idb +extern ThemeStruct themes[MAXTHEMES]; +extern bool pFountainFlag; // weak +extern bool bFountainFlag; // weak +extern bool bCrossFlag; // weak + +bool __fastcall TFit_Shrine(int i); +bool __fastcall TFit_Obj5(int t); +bool __fastcall TFit_SkelRoom(int t); +bool __fastcall TFit_GoatShrine(int t); +bool __fastcall CheckThemeObj3(int xp, int yp, int t, int f); +bool __fastcall TFit_Obj3(int t); +bool __fastcall CheckThemeReqs(int t); +bool __fastcall SpecialThemeFit(int i, int t); +bool __fastcall CheckThemeRoom(int tv); +void __cdecl InitThemes(); +void __cdecl HoldThemeRooms(); +void __fastcall PlaceThemeMonsts(int t, int f); +void __fastcall Theme_Barrel(int t); +void __fastcall Theme_Shrine(int t); +void __fastcall Theme_MonstPit(int t); +void __fastcall Theme_SkelRoom(int t); +void __fastcall Theme_Treasure(int t); +void __fastcall Theme_Library(int t); +void __fastcall Theme_Torture(int t); +void __fastcall Theme_BloodFountain(int t); +void __fastcall Theme_Decap(int t); +void __fastcall Theme_PurifyingFountain(int t); +void __fastcall Theme_ArmorStand(int t); +void __fastcall Theme_GoatShrine(int t); +void __fastcall Theme_Cauldron(int t); +void __fastcall Theme_MurkyFountain(int t); +void __fastcall Theme_TearFountain(int t); +void __fastcall Theme_BrnCross(int t); +void __fastcall Theme_WeaponRack(int t); +void __cdecl UpdateL4Trans(); +void __cdecl CreateThemeRooms(); + +/* rdata */ + +extern int ThemeGood[4]; +extern int trm5x[25]; +extern int trm5y[25]; +extern int trm3x[9]; +extern int trm3y[9]; + +#endif /* __THEMES_H__ */ diff --git a/Source/tmsg.cpp b/Source/tmsg.cpp new file mode 100644 index 000000000..8595e7413 --- /dev/null +++ b/Source/tmsg.cpp @@ -0,0 +1,79 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +TMsg *sgpTimedMsgHead; +#endif + +int __fastcall tmsg_get(unsigned char *pbMsg, unsigned int dwMaxLen) +{ + unsigned char *v2; // ebx + DWORD v3; // eax + TMsg *v4; // esi + size_t v6; // edi + + v2 = pbMsg; + if ( !sgpTimedMsgHead ) + return 0; + v3 = GetTickCount(); + v4 = sgpTimedMsgHead; + if ( (signed int)(sgpTimedMsgHead->hdr.dwTime - v3) >= 0 ) + return 0; + sgpTimedMsgHead = sgpTimedMsgHead->hdr.pNext; + v6 = v4->hdr.bLen; + memcpy(v2, v4->body, v6); + mem_free_dbg(v4); + return v6; +} + +void __fastcall tmsg_add(unsigned char *pbMsg, unsigned char bLen) +{ + unsigned char v2; // bl + unsigned char *v3; // ebp + size_t v4; // edi + TMsg *v5; // eax + TMsg *v6; // esi + DWORD v7; // eax + TMsg *v8; // ecx + TMsg **v9; // eax + + v2 = bLen; + v3 = pbMsg; + v4 = bLen; + v5 = (TMsg *)DiabloAllocPtr(bLen + 12); + v6 = v5; + v5->hdr.pNext = 0; + v7 = GetTickCount(); + v6->hdr.bLen = v2; + v6->hdr.dwTime = v7 + 500; + memcpy(v6->body, v3, v4); + v8 = sgpTimedMsgHead; + v9 = &sgpTimedMsgHead; + while ( v8 ) + { + v9 = &v8->hdr.pNext; + v8 = v8->hdr.pNext; + } + *v9 = v6; +} + +void __cdecl tmsg_cleanup() +{ + TMsg *v0; // eax + TMsg *v1; // esi + + v0 = sgpTimedMsgHead; + if ( sgpTimedMsgHead ) + { + do + { + v1 = v0->hdr.pNext; + sgpTimedMsgHead = 0; + mem_free_dbg(v0); + v0 = v1; + sgpTimedMsgHead = v1; + } + while ( v1 ); + } +} diff --git a/Source/tmsg.h b/Source/tmsg.h new file mode 100644 index 000000000..0396702c2 --- /dev/null +++ b/Source/tmsg.h @@ -0,0 +1,11 @@ +//HEADER_GOES_HERE +#ifndef __TMSG_H__ +#define __TMSG_H__ + +extern TMsg *sgpTimedMsgHead; + +int __fastcall tmsg_get(unsigned char *pbMsg, unsigned int dwMaxLen); +void __fastcall tmsg_add(unsigned char *pbMsg, unsigned char bLen); +void __cdecl tmsg_cleanup(); + +#endif /* __TMSG_H__ */ diff --git a/Source/town.cpp b/Source/town.cpp new file mode 100644 index 000000000..85f8fe269 --- /dev/null +++ b/Source/town.cpp @@ -0,0 +1,1725 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +void __fastcall town_clear_upper_buf(unsigned char *a1) +{ + unsigned char *v1; // edi + signed int v2; // edx + signed int v3; // ebx + unsigned char *v4; // edi + signed int v5; // edx + signed int v6; // ebx + unsigned char *v7; // edi + + v1 = a1; + v2 = 30; + v3 = 1; + while ( v1 >= gpBufEnd ) + { + v4 = &v1[v2]; + memset(v4, 0, 4 * v3); + v1 = &v4[4 * v3 - 832 + v2]; + if ( !v2 ) + { + v5 = 2; + v6 = 15; + do + { + if ( v1 < gpBufEnd ) + break; + v7 = &v1[v5]; + memset(v7, 0, 4 * v6); + v1 = &v7[4 * v6-- - 832 + v5]; + v5 += 2; + } + while ( v5 != 32 ); + return; + } + v2 -= 2; + ++v3; + } +} +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall town_clear_low_buf(unsigned char *y_related) +{ + unsigned char *v1; // edi + signed int v2; // edx + signed int i; // ebx + unsigned char *v4; // edi + unsigned char *v5; // edi + signed int v6; // edx + signed int v7; // ebx + unsigned char *v8; // edi + unsigned char *v9; // edi + + v1 = y_related; + v2 = 30; + for ( i = 1; ; ++i ) + { + if ( v1 < gpBufEnd ) + { + v5 = &v1[v2]; + memset(v5, 0, 4 * i); + v4 = &v5[4 * i + v2]; + } + else + { + v4 = v1 + 64; + } + v1 = v4 - 832; + if ( !v2 ) + break; + v2 -= 2; + } + v6 = 2; + v7 = 15; + do + { + if ( v1 < gpBufEnd ) + { + v9 = &v1[v6]; + memset(v9, 0, 4 * v7); + v8 = &v9[4 * v7 + v6]; + } + else + { + v8 = v1 + 64; + } + v1 = v8 - 832; + --v7; + v6 += 2; + } + while ( v6 != 32 ); +} +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall town_draw_clipped_e_flag(void *buffer, int x, int y, int sx, int sy) +{ + int v5; // ebx + char *v6; // esi + signed int v7; // edi + int v8; // eax + int v9; // eax + void *unused; // [esp+Ch] [ebp-8h] + unsigned char *a1; // [esp+10h] [ebp-4h] + + v5 = x; + unused = buffer; + a1 = (unsigned char *)buffer; + v6 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(x, y); + v7 = 0; + do + { + v8 = *(unsigned short *)&v6[2 * v7]; + level_cel_block = *(unsigned short *)&v6[2 * v7]; + if ( v8 ) + drawLowerScreen(a1); + v9 = *(unsigned short *)&v6[2 * v7 + 2]; + level_cel_block = *(unsigned short *)&v6[2 * v7 + 2]; + if ( v9 ) + drawLowerScreen(a1 + 32); + a1 -= 24576; + v7 += 2; + } + while ( v7 < 12 ); + town_draw_clipped_town(unused, v5, y, sx, sy, 0); +} +// 69CF14: using guessed type int level_cel_block; + +void __fastcall town_draw_clipped_town(void *unused, int x, int y, int sx, int sy, int some_flag) +{ + unsigned int v6; // edx + int v7; // edi + char v8; // al + char v9; // al + int v10; // esi + int v11; // ebx + int v12; // esi + int v13; // ebx + int v14; // eax + int v15; // eax + int v16; // esi + int v17; // ebx + char v18; // al + int v19; // esi + int v20; // ebx + int v21; // edi + char v22; // al + char v23; // al + int v24; // esi + int v25; // ebx + int v26; // edi + char *v27; // [esp+Ch] [ebp-Ch] + int xa; // [esp+10h] [ebp-8h] + int v29; // [esp+14h] [ebp-4h] + + xa = x; + v6 = 112 * x; + v27 = (char *)gpBuffer + screen_y_times_768[sy] + sx; + v7 = v6 + y; + v29 = v6 + y; + v8 = dItem[v6 / 0x70][y]; + if ( v8 ) + { + v9 = v8 - 1; + v10 = v9; + v11 = sx - item[v10]._iAnimWidth2; + if ( v9 == pcursitem ) + CelDrawHdrClrHL( + 181, + v11, + sy, + (char *)item[v10]._iAnimData, + item[v10]._iAnimFrame, + item[v10]._iAnimWidth, + 0, + 8); + Cel2DrawHdrOnly(v11, sy, (char *)item[v10]._iAnimData, item[v10]._iAnimFrame, item[v10]._iAnimWidth, 0, 8); + } + if ( dFlags[0][v7] & 0x10 ) + { + v12 = -1 - dMonster[x][y-1]; // -1 - *(&dword_52D204 + v7); /* check */ + v13 = sx - towner[v12]._tAnimWidth2; + if ( v12 == pcursmonst ) + CelDrawHdrClrHL( + 166, + v13, + sy, + (char *)towner[v12]._tAnimData, + towner[v12]._tAnimFrame, + towner[v12]._tAnimWidth, + 0, + 8); + Cel2DrawHdrOnly(v13, sy, (char *)towner[v12]._tAnimData, towner[v12]._tAnimFrame, towner[v12]._tAnimWidth, 0, 8); + } + v14 = dMonster[0][v7]; + if ( v14 > 0 ) + { + v15 = v14 - 1; + v16 = v15; + v17 = sx - towner[v15]._tAnimWidth2; + if ( v15 == pcursmonst ) + CelDrawHdrClrHL( + 166, + v17, + sy, + (char *)towner[v16]._tAnimData, + towner[v16]._tAnimFrame, + towner[v16]._tAnimWidth, + 0, + 8); + Cel2DrawHdrOnly(v17, sy, (char *)towner[v16]._tAnimData, towner[v16]._tAnimFrame, towner[v16]._tAnimWidth, 0, 8); + } + if ( dFlags[0][v7] & 0x20 ) + { + v18 = -1 - dPlayer[x][y-1]; // -1 - *((_BYTE *)&themeLoc[49].height + v7 + 3); + v19 = v18; + v20 = sy + plr[v19]._pyoff; + v21 = sx + plr[v19]._pxoff - plr[v19]._pAnimWidth2; + if ( v18 == pcursplr ) + Cl2DecodeClrHL(165, v21, v20, (char *)plr[v19]._pAnimData, plr[v19]._pAnimFrame, plr[v19]._pAnimWidth, 0, 8); + Cl2DecodeFrm4(v21, v20, (char *)plr[v19]._pAnimData, plr[v19]._pAnimFrame, plr[v19]._pAnimWidth, 0, 8); + if ( some_flag && plr[v19]._peflag ) + town_draw_clipped_e_flag(v27 - 64, xa - 1, y + 1, sx - 64, sy); + v7 = v29; + } + if ( dFlags[0][v7] & 4 ) + DrawDeadPlayer(xa, y, sx, sy, 0, 8, 1); + v22 = dPlayer[0][v7]; + if ( v22 > 0 ) + { + v23 = v22 - 1; + v24 = v23; + v25 = sy + plr[v24]._pyoff; + v26 = sx + plr[v24]._pxoff - plr[v24]._pAnimWidth2; + if ( v23 == pcursplr ) + Cl2DecodeClrHL(165, v26, v25, (char *)plr[v24]._pAnimData, plr[v24]._pAnimFrame, plr[v24]._pAnimWidth, 0, 8); + Cl2DecodeFrm4(v26, v25, (char *)plr[v24]._pAnimData, plr[v24]._pAnimFrame, plr[v24]._pAnimWidth, 0, 8); + if ( some_flag && plr[v24]._peflag ) + town_draw_clipped_e_flag(v27 - 64, xa - 1, y + 1, sx - 64, sy); + v7 = v29; + } + if ( dFlags[0][v7] & 1 ) + DrawClippedMissile(xa, y, sx, sy, 0, 8, 0); +} +// 4B8CC0: using guessed type char pcursitem; +// 4B8CC2: using guessed type char pcursplr; + +void __fastcall town_draw_lower(int x, int y, int sx, int sy, int a5, int some_flag) +{ + int v6; // ebx + int *v7; // edi + char *v8; // esi + int v9; // eax + int v10; // eax + int *v11; // ebx + int v12; // esi + unsigned char *v13; // esi + char *v14; // edi + int v15; // eax + int v16; // eax + bool v17; // zf + int *v18; // ebx + unsigned char *v19; // esi + char *v20; // edi + int v21; // eax + unsigned char *a1; // [esp+Ch] [ebp-10h] + int a1a; // [esp+Ch] [ebp-10h] + int ya; // [esp+10h] [ebp-Ch] + signed int v25; // [esp+14h] [ebp-8h] + signed int v26; // [esp+14h] [ebp-8h] + signed int v27; // [esp+14h] [ebp-8h] + signed int xa; // [esp+18h] [ebp-4h] + int a5a; // [esp+2Ch] [ebp+10h] + + ya = y; + xa = x; + if ( some_flag ) + { + if ( y >= 0 && y < 112 && x >= 0 && x < 112 && (level_cel_block = dPiece[0][y + 112 * x]) != 0 ) + { + v6 = sy; + v7 = &screen_y_times_768[sy]; + a1 = (unsigned char *)&gpBuffer->row_unused_1[0].col_unused_1[*v7 + 32 + sx]; + v25 = 1; + v8 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(x, y); + do + { + v9 = *(unsigned short *)&v8[2 * v25]; + level_cel_block = *(unsigned short *)&v8[2 * v25]; + if ( v9 ) + drawLowerScreen(a1); + v25 += 2; + a1 -= 24576; + } + while ( v25 < 17 ); + town_draw_clipped_town((char *)gpBuffer + *v7 + sx, xa, ya, sx, sy, 0); + } + else + { + town_clear_low_buf((unsigned char *)gpBuffer + screen_y_times_768[sy] + sx); + v6 = sy; + } + ++xa; + y = ya - 1; + sx += 64; + --ya; + } + else + { + v6 = sy; + } + v10 = a5 - some_flag; + if ( a5 - some_flag > 0 ) + { + v11 = &screen_y_times_768[v6]; + v12 = 112 * xa; + a5a = 112 * xa; + a1a = v10; + do + { + if ( y >= 0 && y < 112 && v12 >= 0 && v12 < 12544 && (level_cel_block = dPiece[0][v12 + y]) != 0 ) + { + v13 = (unsigned char *)gpBuffer + *v11 + sx; + v14 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(xa, ya); + v26 = 0; + do + { + v15 = *(unsigned short *)&v14[2 * v26]; + level_cel_block = *(unsigned short *)&v14[2 * v26]; + if ( v15 ) + drawLowerScreen(v13); + v16 = *(unsigned short *)&v14[2 * v26 + 2]; + level_cel_block = *(unsigned short *)&v14[2 * v26 + 2]; + if ( v16 ) + drawLowerScreen(v13 + 32); + v26 += 2; + v13 -= 24576; + } + while ( v26 < 16 ); + town_draw_clipped_town((char *)gpBuffer + *v11 + sx, xa, ya, sx, sy, 1); + v12 = a5a; + } + else + { + town_clear_low_buf((unsigned char *)gpBuffer + *v11 + sx); + } + ++xa; + sx += 64; + v12 += 112; + y = ya - 1; + v17 = a1a-- == 1; + a5a = v12; + --ya; + } + while ( !v17 ); + v6 = sy; + } + if ( some_flag ) + { + if ( y >= 0 && y < 112 && xa >= 0 && xa < 112 && (level_cel_block = dPiece[0][y + 112 * xa]) != 0 ) + { + v18 = &screen_y_times_768[v6]; + v19 = (unsigned char *)gpBuffer + *v18 + sx; + v20 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(xa, ya); + v27 = 0; + do + { + v21 = *(unsigned short *)&v20[2 * v27]; + level_cel_block = *(unsigned short *)&v20[2 * v27]; + if ( v21 ) + drawLowerScreen(v19); + v27 += 2; + v19 -= 24576; + } + while ( v27 < 16 ); + town_draw_clipped_town((char *)gpBuffer + *v18 + sx, xa, ya, sx, sy, 0); + } + else + { + town_clear_low_buf((unsigned char *)gpBuffer + screen_y_times_768[v6] + sx); + } + } +} +// 69CF14: using guessed type int level_cel_block; + +void __fastcall town_draw_clipped_e_flag_2(void *buffer, int x, int y, int a4, int a5, int sx, int sy) +{ + int v7; // ebx + unsigned char *v8; // edi + short *v9; // esi + int v10; // eax + int v11; // eax + void *v12; // [esp+8h] [ebp-8h] + int xa; // [esp+Ch] [ebp-4h] + int a4a; // [esp+1Ch] [ebp+Ch] + + v7 = a4; + xa = x; + v12 = buffer; + if ( a4 ) + v8 = (unsigned char *)buffer + 24576 * a4; + else + v8 = (unsigned char *)buffer; + a4a = 0; + v9 = &dpiece_defs_map_1[0][0][16 * gendung_get_dpiece_num_from_coord(x, y) + 3]; + do + { + if ( v7 <= a4a ) + { + v10 = (unsigned short)*(v9 - 1); + level_cel_block = (unsigned short)*(v9 - 1); + if ( v10 ) + drawLowerScreen(v8); + v11 = (unsigned short)*v9; + level_cel_block = (unsigned short)*v9; + if ( v11 ) + drawLowerScreen(v8 + 32); + } + v8 -= 24576; + ++a4a; + v9 += 2; + } + while ( a4a < 6 ); + if ( a5 < 8 ) + town_draw_clipped_town_2((int)v12, xa, y, v7, a5, sx, sy, 0); +} +// 69CF14: using guessed type int level_cel_block; + +void __fastcall town_draw_clipped_town_2(int x, int y, int a3, int a4, int a5, int sx, int sy, int some_flag) +{ + unsigned int v8; // edx + int v9; // ebx + char v10; // al + char v11; // al + int v12; // esi + int v13; // edi + int v14; // esi + int v15; // edi + int v16; // eax + int v17; // eax + int v18; // esi + int v19; // edi + char v20; // al + int v21; // esi + int v22; // ebx + int v23; // edi + char v24; // al + char v25; // al + int v26; // esi + int v27; // ebx + int v28; // edi + int v29; // [esp+Ch] [ebp-Ch] + int xa; // [esp+10h] [ebp-8h] + int v31; // [esp+14h] [ebp-4h] + + xa = y; + v8 = 112 * y; + v9 = v8 + a3; + v29 = x; + v31 = v8 + a3; + v10 = dItem[v8 / 0x70][a3]; + if ( v10 ) + { + v11 = v10 - 1; + v12 = v11; + v13 = sx - item[v12]._iAnimWidth2; + if ( v11 == pcursitem ) + CelDrawHdrClrHL( + 181, + v13, + sy, + (char *)item[v12]._iAnimData, + item[v12]._iAnimFrame, + item[v12]._iAnimWidth, + a5, + 8); + Cel2DrawHdrOnly(v13, sy, (char *)item[v12]._iAnimData, item[v12]._iAnimFrame, item[v12]._iAnimWidth, a5, 8); + } + if ( dFlags[0][v9] & 0x10 ) + { + v14 = -1 - dMonster[x][y-1]; // -1 - *(&dword_52D204 + v9); /* check */ + v15 = sx - towner[v14]._tAnimWidth2; + if ( v14 == pcursmonst ) + CelDrawHdrClrHL( + 166, + v15, + sy, + (char *)towner[v14]._tAnimData, + towner[v14]._tAnimFrame, + towner[v14]._tAnimWidth, + a5, + 8); + Cel2DrawHdrOnly(v15, sy, (char *)towner[v14]._tAnimData, towner[v14]._tAnimFrame, towner[v14]._tAnimWidth, a5, 8); + } + v16 = dMonster[0][v9]; + if ( v16 > 0 ) + { + v17 = v16 - 1; + v18 = v17; + v19 = sx - towner[v17]._tAnimWidth2; + if ( v17 == pcursmonst ) + CelDrawHdrClrHL( + 166, + v19, + sy, + (char *)towner[v18]._tAnimData, + towner[v18]._tAnimFrame, + towner[v18]._tAnimWidth, + a5, + 8); + Cel2DrawHdrOnly(v19, sy, (char *)towner[v18]._tAnimData, towner[v18]._tAnimFrame, towner[v18]._tAnimWidth, a5, 8); + } + if ( dFlags[0][v9] & 0x20 ) + { + v20 = -1 - dPlayer[x][y-1]; // -1 - *((_BYTE *)&themeLoc[49].height + v9 + 3); + v21 = v20; + v22 = sy + plr[v21]._pyoff; + v23 = sx + plr[v21]._pxoff - plr[v21]._pAnimWidth2; + if ( v20 == pcursplr ) + Cl2DecodeClrHL(165, v23, v22, (char *)plr[v21]._pAnimData, plr[v21]._pAnimFrame, plr[v21]._pAnimWidth, a5, 8); + Cl2DecodeFrm4(v23, v22, (char *)plr[v21]._pAnimData, plr[v21]._pAnimFrame, plr[v21]._pAnimWidth, a5, 8); + if ( some_flag && plr[v21]._peflag ) + town_draw_clipped_e_flag_2((void *)(v29 - 64), xa - 1, a3 + 1, a4, a5, sx - 64, sy); + v9 = v31; + } + if ( dFlags[0][v9] & 4 ) + DrawDeadPlayer(xa, a3, sx, sy, a5, 8, 1); + v24 = dPlayer[0][v9]; + if ( v24 > 0 ) + { + v25 = v24 - 1; + v26 = v25; + v27 = sy + plr[v26]._pyoff; + v28 = sx + plr[v26]._pxoff - plr[v26]._pAnimWidth2; + if ( v25 == pcursplr ) + Cl2DecodeClrHL(165, v28, v27, (char *)plr[v26]._pAnimData, plr[v26]._pAnimFrame, plr[v26]._pAnimWidth, a5, 8); + Cl2DecodeFrm4(v28, v27, (char *)plr[v26]._pAnimData, plr[v26]._pAnimFrame, plr[v26]._pAnimWidth, a5, 8); + if ( some_flag && plr[v26]._peflag ) + town_draw_clipped_e_flag_2((void *)(v29 - 64), xa - 1, a3 + 1, a4, a5, sx - 64, sy); + v9 = v31; + } + if ( dFlags[0][v9] & 1 ) + DrawClippedMissile(xa, a3, sx, sy, a5, 8, 0); +} +// 4B8CC0: using guessed type char pcursitem; +// 4B8CC2: using guessed type char pcursplr; + +void __fastcall town_draw_lower_2(int x, int y, int sx, int sy, int a5, int a6, int some_flag) +{ + int v7; // esi + int v8; // ebx + int *v9; // edi + short *v10; // eax + int v11; // esi + int v12; // eax + int *v13; // ebx + int v14; // edi + short *v15; // edi + int v16; // eax + int v17; // eax + int v18; // eax + bool v19; // zf + int *v20; // edi + short *v21; // ebx + int v22; // eax + short *v23; // [esp+Ch] [ebp-10h] + int v24; // [esp+Ch] [ebp-10h] + unsigned char *a1; // [esp+10h] [ebp-Ch] + unsigned char *a1a; // [esp+10h] [ebp-Ch] + unsigned char *a1b; // [esp+10h] [ebp-Ch] + signed int ya; // [esp+14h] [ebp-8h] + signed int xa; // [esp+18h] [ebp-4h] + signed int sxa; // [esp+24h] [ebp+8h] + signed int sxb; // [esp+24h] [ebp+8h] + signed int sxc; // [esp+24h] [ebp+8h] + int a5a; // [esp+2Ch] [ebp+10h] + + ya = y; + xa = x; + if ( some_flag ) + { + if ( y < 0 || y >= 112 || x < 0 || x >= 112 ) + { + v7 = sx; + } + else + { + v7 = sx; + level_cel_block = dPiece[0][y + 112 * x]; + if ( level_cel_block ) + { + v8 = sy; + v9 = &screen_y_times_768[sy]; + a1 = (unsigned char *)gpBuffer + *v9 + sx - 24544; + sxa = 0; + v10 = &dpiece_defs_map_1[0][0][16 * gendung_get_dpiece_num_from_coord(x, y) + 3]; + v23 = v10; + do + { + if ( a6 <= sxa ) + { + level_cel_block = (unsigned short)*v10; + if ( level_cel_block ) + drawLowerScreen(a1); + } + a1 -= 24576; + ++sxa; + v10 = v23 + 2; + v23 += 2; + } + while ( sxa < 7 ); + if ( 2 * a6 + 2 < 8 ) + town_draw_clipped_town_2((int)gpBuffer + *v9 + v7, xa, ya, a6, 2 * a6 + 2, v7, sy, 0); + goto LABEL_16; + } + } + town_clear_low_buf((unsigned char *)gpBuffer + screen_y_times_768[sy] + v7); + v8 = sy; +LABEL_16: + ++xa; + --ya; + v11 = v7 + 64; + goto LABEL_18; + } + v11 = sx; + v8 = sy; +LABEL_18: + v12 = a5 - some_flag; + if ( a5 - some_flag > 0 ) + { + v13 = &screen_y_times_768[v8]; + v14 = 112 * xa; + a5a = 112 * xa; + v24 = v12; + do + { + if ( ya >= 0 && ya < 112 && v14 >= 0 && v14 < 12544 && (level_cel_block = dPiece[0][v14 + ya]) != 0 ) + { + a1a = (unsigned char *)gpBuffer + *v13 + v11 - 24576; + sxb = 0; + v15 = &dpiece_defs_map_1[0][0][16 * gendung_get_dpiece_num_from_coord(xa, ya) + 3]; + do + { + if ( a6 <= sxb ) + { + v16 = (unsigned short)*(v15 - 1); + level_cel_block = (unsigned short)*(v15 - 1); + if ( v16 ) + drawLowerScreen(a1a); + v17 = (unsigned short)*v15; + level_cel_block = (unsigned short)*v15; + if ( v17 ) + drawLowerScreen(a1a + 32); + } + a1a -= 24576; + ++sxb; + v15 += 2; + } + while ( sxb < 7 ); + v18 = 2 * a6 + 2; + if ( v18 < 8 ) + town_draw_clipped_town_2((int)gpBuffer + *v13 - 12288 * v18 + v11, xa, ya, a6, 2 * a6 + 2, v11, sy, 1); + v14 = a5a; + } + else + { + town_clear_low_buf((unsigned char *)gpBuffer + *v13 + v11); + } + ++xa; + v14 += 112; + --ya; + v11 += 64; + v19 = v24-- == 1; + a5a = v14; + } + while ( !v19 ); + v8 = sy; + } + if ( some_flag ) + { + if ( ya >= 0 && ya < 112 && xa >= 0 && xa < 112 && (level_cel_block = dPiece[0][ya + 112 * xa]) != 0 ) + { + v20 = &screen_y_times_768[v8]; + a1b = (unsigned char *)gpBuffer + *v20 + v11 - 24576; + sxc = 0; + v21 = &dpiece_defs_map_1[0][0][16 * gendung_get_dpiece_num_from_coord(xa, ya) + 2]; + do + { + if ( a6 <= sxc ) + { + v22 = (unsigned short)*v21; + level_cel_block = (unsigned short)*v21; + if ( v22 ) + drawLowerScreen(a1b); + } + a1b -= 24576; + ++sxc; + v21 += 2; + } + while ( sxc < 7 ); + if ( 2 * a6 + 2 < 8 ) + town_draw_clipped_town_2((int)gpBuffer + *v20 + v11, xa, ya, a6, 2 * a6 + 2, v11, sy, 0); + } + else + { + town_clear_low_buf((unsigned char *)gpBuffer + screen_y_times_768[v8] + v11); + } + } +} +// 69CF14: using guessed type int level_cel_block; + +void __fastcall town_draw_e_flag(void *buffer, int x, int y, int a4, int dir, int sx, int sy) +{ + int v7; // ebx + char *v8; // esi + int v9; // edi + int v10; // eax + int v11; // eax + void *buffera; // [esp+Ch] [ebp-8h] + unsigned char *a1; // [esp+10h] [ebp-4h] + + v7 = x; + buffera = buffer; + a1 = (unsigned char *)buffer; + v8 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(x, y); + v9 = 0; + do + { + if ( a4 >= v9 ) + { + v10 = *(unsigned short *)&v8[4 * v9]; + level_cel_block = *(unsigned short *)&v8[4 * v9]; + if ( v10 ) + drawUpperScreen(a1); + v11 = *(unsigned short *)&v8[4 * v9 + 2]; + level_cel_block = *(unsigned short *)&v8[4 * v9 + 2]; + if ( v11 ) + drawUpperScreen(a1 + 32); + } + a1 -= 24576; + ++v9; + } + while ( v9 < 7 ); + town_draw_town_all(buffera, v7, y, a4, dir, sx, sy, 0); +} +// 69CF14: using guessed type int level_cel_block; + +void __fastcall town_draw_town_all(void *buffer, int x, int y, int a4, int dir, int sx, int sy, int some_flag) +{ + //int v9; // ebx + int id; // esi + int yy; // ebx + int xx; // edi + + //v9 = 112 * x + y; + if ( dItem[x][y] ) + { + id = dItem[x][y] - 1; + xx = sx - item[id]._iAnimWidth2; + if ( id == pcursitem ) + CelDecodeClr(181, xx, sy, (char *)item[id]._iAnimData, item[id]._iAnimFrame, item[id]._iAnimWidth, 0, dir); + CelDrawHdrOnly(xx, sy, (char *)item[id]._iAnimData, item[id]._iAnimFrame, item[id]._iAnimWidth, 0, dir); + } + if ( dFlags[x][y] & 0x10 ) + { + id = -1 - dMonster[x][y-1]; // -1 - *(&dword_52D204 + v9); /* check */ + xx = sx - towner[id]._tAnimWidth2; + if ( id == pcursmonst ) + CelDecodeClr(166, xx, sy, (char *)towner[id]._tAnimData, towner[id]._tAnimFrame, towner[id]._tAnimWidth, 0, dir); + CelDrawHdrOnly(xx, sy, (char *)towner[id]._tAnimData, towner[id]._tAnimFrame, towner[id]._tAnimWidth, 0, dir); + } + if ( dMonster[x][y] > 0 ) + { + id = dMonster[x][y] - 1; + xx = sx - towner[id]._tAnimWidth2; + if ( id == pcursmonst ) + CelDecodeClr(166, xx, sy, (char *)towner[id]._tAnimData, towner[id]._tAnimFrame, towner[id]._tAnimWidth, 0, dir); + CelDrawHdrOnly(xx, sy, (char *)towner[id]._tAnimData, towner[id]._tAnimFrame, towner[id]._tAnimWidth, 0, dir); + } + if ( dFlags[x][y] & 0x20 ) + { + id = -1 - dPlayer[x][y-1]; // -1 - *((_BYTE *)&themeLoc[49].height + v9 + 3); + yy = sy + plr[id]._pyoff; + xx = sx + plr[id]._pxoff - plr[id]._pAnimWidth2; + if ( id == pcursplr ) + Cl2DecodeFrm2(165, xx, yy, (char *)plr[id]._pAnimData, plr[id]._pAnimFrame, plr[id]._pAnimWidth, 0, dir); + Cl2DecodeFrm1(xx, yy, (char *)plr[id]._pAnimData, plr[id]._pAnimFrame, plr[id]._pAnimWidth, 0, dir); + if ( some_flag && plr[id]._peflag ) + town_draw_e_flag((char *)buffer - 64, x - 1, y + 1, a4, dir, sx - 64, sy); + } + if ( dFlags[x][y] & 4 ) + DrawDeadPlayer(x, y, sx, sy, 0, dir, 0); + if ( dPlayer[x][y] > 0 ) + { + id = dPlayer[x][y] - 1; + yy = sy + plr[id]._pyoff; + xx = sx + plr[id]._pxoff - plr[id]._pAnimWidth2; + if ( id == pcursplr ) + Cl2DecodeFrm2(165, xx, yy, (char *)plr[id]._pAnimData, plr[id]._pAnimFrame, plr[id]._pAnimWidth, 0, dir); + Cl2DecodeFrm1(xx, yy, (char *)plr[id]._pAnimData, plr[id]._pAnimFrame, plr[id]._pAnimWidth, 0, dir); + if ( some_flag && plr[id]._peflag ) + town_draw_e_flag((char *)buffer - 64, x - 1, y + 1, a4, dir, sx - 64, sy); + } + if ( dFlags[x][y] & 1 ) + DrawMissile(x, y, sx, sy, 0, dir, 0); +} +// 4B8CC0: using guessed type char pcursitem; +// 4B8CC2: using guessed type char pcursplr; + +void __fastcall town_draw_upper(int x, int y, int sx, int sy, int a5, int a6, int some_flag) +{ + signed int v7; // ebx + int v8; // esi + int v9; // eax + bool v10; // zf + int v11; // eax + short *v12; // ebx + int v13; // eax + int v14; // esi + int v15; // edi + int v16; // eax + Screen *v17; // eax + unsigned char *v18; // ebx + char *v19; // edi + int v20; // eax + int v21; // eax + int v22; // eax + int v23; // eax + unsigned char *v24; // edi + char *v25; // ebx + int v26; // eax + int *a1; // [esp+Ch] [ebp-10h] + int *a1a; // [esp+Ch] [ebp-10h] + int dir; // [esp+10h] [ebp-Ch] + int ya; // [esp+14h] [ebp-8h] + signed int xa; // [esp+18h] [ebp-4h] + signed int sxa; // [esp+24h] [ebp+8h] + signed int sxb; // [esp+24h] [ebp+8h] + signed int sxc; // [esp+24h] [ebp+8h] + int a5a; // [esp+2Ch] [ebp+10h] + + xa = x; + v7 = y; + ya = y; + dir = 2 * a6 + 2; + if ( dir > 8 ) + dir = 8; + if ( some_flag ) + { + if ( y < 0 || y >= 112 || x < 0 || x >= 112 ) + { + v11 = sy; + v8 = sx; + } + else + { + v8 = sx; + v9 = dPiece[0][y + 112 * x]; + level_cel_block = v9; + v10 = v9 == 0; + v11 = sy; + if ( !v10 ) + { + a1 = (int *)&gpBuffer->row_unused_1[0].col_unused_1[sx + 32 + screen_y_times_768[sy]]; + sxa = 0; + v12 = &dpiece_defs_map_1[0][0][16 * gendung_get_dpiece_num_from_coord(x, y) + 1]; + do + { + if ( a6 >= sxa ) + { + v13 = (unsigned short)*v12; + level_cel_block = (unsigned short)*v12; + if ( v13 ) + drawUpperScreen((unsigned char *)a1); + } + a1 -= 6144; + ++sxa; + v12 += 2; + } + while ( sxa < 7 ); + town_draw_town_all((char *)gpBuffer + v8 + screen_y_times_768[sy], xa, ya, a6, dir, v8, sy, 0); + v7 = ya; + goto LABEL_17; + } + } + town_clear_upper_buf((unsigned char *)gpBuffer + screen_y_times_768[v11] + v8); +LABEL_17: + ++xa; + ya = --v7; + v14 = v8 + 64; + goto LABEL_19; + } + v14 = sx; +LABEL_19: + if ( a5 - some_flag > 0 ) + { + a1a = (int *)(a5 - some_flag); + v15 = 112 * xa; + a5a = 112 * xa; + do + { + if ( v7 < 0 || v7 >= 112 || v15 < 0 || v15 >= 12544 ) + { + v17 = gpBuffer; + } + else + { + v16 = dPiece[0][v15 + v7]; + level_cel_block = v16; + v10 = v16 == 0; + v17 = gpBuffer; + if ( !v10 ) + { + v18 = (unsigned char *)gpBuffer + v14 + screen_y_times_768[sy]; + v19 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(xa, ya); + sxb = 0; + do + { + if ( a6 >= sxb ) + { + v20 = *(unsigned short *)&v19[4 * sxb]; + level_cel_block = *(unsigned short *)&v19[4 * sxb]; + if ( v20 ) + drawUpperScreen(v18); + v21 = *(unsigned short *)&v19[4 * sxb + 2]; + level_cel_block = *(unsigned short *)&v19[4 * sxb + 2]; + if ( v21 ) + drawUpperScreen(v18 + 32); + } + v18 -= 24576; + ++sxb; + } + while ( sxb < 7 ); + town_draw_town_all((char *)gpBuffer + v14 + screen_y_times_768[sy], xa, ya, a6, dir, v14, sy, 1); + v15 = a5a; + v7 = ya; + goto LABEL_36; + } + } + town_clear_upper_buf((unsigned char *)v17 + v14 + screen_y_times_768[sy]); +LABEL_36: + ++xa; + v15 += 112; + --v7; + v14 += 64; + v10 = a1a == (int *)1; + a1a = (int *)((char *)a1a - 1); + a5a = v15; + ya = v7; + } + while ( !v10 ); + } + if ( some_flag ) + { + if ( v7 < 0 || v7 >= 112 || xa < 0 || xa >= 112 ) + { + v23 = sy; + } + else + { + v22 = dPiece[0][v7 + 112 * xa]; + level_cel_block = v22; + v10 = v22 == 0; + v23 = sy; + if ( !v10 ) + { + v24 = (unsigned char *)gpBuffer + v14 + screen_y_times_768[sy]; + v25 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(xa, v7); + sxc = 0; + do + { + if ( a6 >= sxc ) + { + v26 = *(unsigned short *)&v25[4 * sxc]; + level_cel_block = *(unsigned short *)&v25[4 * sxc]; + if ( v26 ) + drawUpperScreen(v24); + } + v24 -= 24576; + ++sxc; + } + while ( sxc < 7 ); + town_draw_town_all((char *)gpBuffer + v14 + screen_y_times_768[sy], xa, ya, a6, dir, v14, sy, 0); + return; + } + } + town_clear_upper_buf((unsigned char *)gpBuffer + screen_y_times_768[v23] + v14); + } +} +// 69CF14: using guessed type int level_cel_block; + +void __fastcall T_DrawGame(int x, int y) +{ + int v2; // esi + int v3; // edi + int v4; // ebx + int v5; // ebx + int v6; // esi + int v7; // ebx + int v8; // esi + int v9; // ebx + int v10; // esi + signed int v11; // [esp+Ch] [ebp-10h] + signed int a6; // [esp+10h] [ebp-Ch] + signed int a6a; // [esp+10h] [ebp-Ch] + signed int a5; // [esp+14h] [ebp-8h] + int ya; // [esp+18h] [ebp-4h] + + v2 = ScrollInfo._sxoff + 64; + v3 = x - 10; + ya = y - 1; + v4 = ScrollInfo._syoff + 175; + dword_5C2FF8 = 10; + a5 = 10; + scr_pix_width = 640; + scr_pix_height = 352; + dword_5C2FFC = 11; + v11 = 5; + if ( chrflag || questlog ) + { + ya = y - 3; + v3 += 2; + v2 = ScrollInfo._sxoff + 352; + a5 = 6; + } + if ( invflag || sbookflag ) + { + ya -= 2; + v3 += 2; + v2 -= 32; + a5 = 6; + } + switch ( ScrollInfo._sdir ) + { + case DIR_SW: + v4 = ScrollInfo._syoff + 143; + --v3; + --ya; + goto LABEL_15; + case DIR_W: + v4 = ScrollInfo._syoff + 143; + --v3; + --ya; + goto LABEL_14; + case DIR_NW: + goto LABEL_12; + case DIR_N: + goto LABEL_14; + case DIR_NE: + goto LABEL_15; + case DIR_E: + v2 -= 64; + --v3; + ++ya; + goto LABEL_14; + case DIR_SE: + v2 -= 64; + --v3; + ++ya; +LABEL_12: + ++a5; + break; + case DIR_OMNI: + v2 -= 64; + v4 = ScrollInfo._syoff + 143; + v3 -= 2; +LABEL_14: + ++a5; +LABEL_15: + v11 = 6; + break; + default: + break; + } + a6 = 0; + gpBufEnd = (unsigned char *)gpBuffer + screen_y_times_768[160]; + do + { + town_draw_upper(v3, ya++, v2, v4, a5, a6, 0); + v5 = v4 + 16; + v6 = v2 - 32; + town_draw_upper(v3++, ya, v6, v5, a5, a6, 1); + v2 = v6 + 32; + v4 = v5 + 16; + ++a6; + } + while ( a6 < 7 ); + gpBufEnd = (unsigned char *)gpBuffer + screen_y_times_768[512]; + if ( v11 > 0 ) + { + do + { + town_draw_lower(v3, ya++, v2, v4, a5, 0); + v7 = v4 + 16; + v8 = v2 - 32; + town_draw_lower(v3++, ya, v8, v7, a5, 1); + v2 = v8 + 32; + v4 = v7 + 16; + --v11; + } + while ( v11 ); + } + a6a = 0; + do + { + town_draw_lower_2(v3, ya++, v2, v4, a5, a6a, 0); + v9 = v4 + 16; + v10 = v2 - 32; + town_draw_lower_2(v3++, ya, v10, v9, a5, a6a, 1); + v2 = v10 + 32; + v4 = v9 + 16; + ++a6a; + } + while ( a6a < 7 ); +} +// 4B8968: using guessed type int sbookflag; +// 5C2FF8: using guessed type int dword_5C2FF8; +// 5C2FFC: using guessed type int dword_5C2FFC; +// 5C3000: using guessed type int scr_pix_width; +// 5C3004: using guessed type int scr_pix_height; +// 69BD04: using guessed type int questlog; +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall T_DrawZoom(int x, int y) +{ + int v2; // edi + int v3; // ebx + int v4; // esi + int v5; // esi + int v6; // edi + int v7; // esi + int v8; // edi + int v9; // esi + int v10; // edi + _WORD *v11; // edi + char *v12; // esi + char *v13; // ebx + signed int v14; // edx + signed int v15; // ecx + short v16; // ax + int v17; // eax + signed int v18; // [esp+Ch] [ebp-10h] + signed int v19; // [esp+Ch] [ebp-10h] + signed int a6; // [esp+10h] [ebp-Ch] + signed int a6a; // [esp+10h] [ebp-Ch] + int a6b; // [esp+10h] [ebp-Ch] + signed int a5; // [esp+14h] [ebp-8h] + int a5a; // [esp+14h] [ebp-8h] + int ya; // [esp+18h] [ebp-4h] + + v18 = 0; + v2 = ScrollInfo._sxoff + 64; + dword_5C2FF8 = 6; + dword_5C2FFC = 6; + v3 = x - 6; + a5 = 6; + v4 = ScrollInfo._syoff + 143; + ya = y - 1; + scr_pix_width = 384; + scr_pix_height = 192; + switch ( ScrollInfo._sdir ) + { + case DIR_SW: + v4 = ScrollInfo._syoff + 111; + v3 = x - 7; + ya = y - 2; + goto LABEL_9; + case DIR_W: + v4 = ScrollInfo._syoff + 111; + v3 = x - 7; + ya = y - 2; + goto LABEL_8; + case DIR_NW: + goto LABEL_6; + case DIR_N: + goto LABEL_8; + case DIR_NE: + goto LABEL_9; + case DIR_E: + v2 = ScrollInfo._sxoff; + v3 = x - 7; + ya = y; + goto LABEL_8; + case DIR_SE: + v2 = ScrollInfo._sxoff; + v3 = x - 7; + ya = y; +LABEL_6: + a5 = 7; + break; + case DIR_OMNI: + v2 = ScrollInfo._sxoff; + v4 = ScrollInfo._syoff + 111; + v3 = x - 8; +LABEL_8: + a5 = 7; +LABEL_9: + v18 = 1; + break; + default: + break; + } + a6 = 0; + gpBufEnd = (unsigned char *)gpBuffer + screen_y_times_768[143]; + do + { + town_draw_upper(v3, ya++, v2, v4, a5, a6, 0); + v5 = v4 + 16; + v6 = v2 - 32; + town_draw_upper(v3++, ya, v6, v5, a5, a6, 1); + v2 = v6 + 32; + v4 = v5 + 16; + ++a6; + } + while ( a6 < 7 ); + gpBufEnd = (unsigned char *)gpBuffer + screen_y_times_768[320]; + if ( v18 > 0 ) + { + do + { + town_draw_lower(v3, ya++, v2, v4, a5, 0); + v7 = v4 + 16; + v8 = v2 - 32; + town_draw_lower(v3++, ya, v8, v7, a5, 1); + v2 = v8 + 32; + v4 = v7 + 16; + --v18; + } + while ( v18 ); + } + a6a = 0; + do + { + town_draw_lower_2(v3, ya++, v2, v4, a5, a6a, 0); + v9 = v4 + 16; + v10 = v2 - 32; + town_draw_lower_2(v3++, ya, v10, v9, a5, a6a, 1); + v2 = v10 + 32; + v4 = v9 + 16; + ++a6a; + } + while ( a6a < 7 ); + if ( chrflag || questlog ) + { + a5a = 392064; + goto LABEL_23; + } + if ( invflag || sbookflag ) + { + a5a = 391744; +LABEL_23: + a6b = 245168; + v19 = 160; + goto LABEL_24; + } + a6b = 245088; + a5a = 391744; + v19 = 320; +LABEL_24: + v11 = (_WORD *)((char *)gpBuffer + a5a); + v12 = (char *)gpBuffer + a6b; + v13 = &gpBuffer->row_unused_1[1].col_unused_1[a5a]; + v14 = 176; + do + { + v15 = v19; + do + { + _LOBYTE(v16) = *v12++; + _HIBYTE(v16) = v16; + *v11 = v16; + *(_WORD *)v13 = v16; + ++v11; + v13 += 2; + --v15; + } + while ( v15 ); + v12 += -v19 - 768; + v17 = 2 * (v19 + 768); + v13 -= v17; + v11 = (_WORD *)((char *)v11 - v17); + --v14; + } + while ( v14 ); +} +// 4B8968: using guessed type int sbookflag; +// 5C2FF8: using guessed type int dword_5C2FF8; +// 5C2FFC: using guessed type int dword_5C2FFC; +// 5C3000: using guessed type int scr_pix_width; +// 5C3004: using guessed type int scr_pix_height; +// 69BD04: using guessed type int questlog; +// 69CF0C: using guessed type int gpBufEnd; + +void __fastcall T_DrawView(int StartX, int StartY) +{ + light_table_index = 0; + cel_transparency_active = 0; + if ( zoomflag ) + T_DrawGame(StartX, StartY); + else + T_DrawZoom(StartX, StartY); + if ( automapflag ) + DrawAutomap(); + if ( stextflag && !qtextflag ) + DrawSText(); + if ( invflag ) + { + DrawInv(); + } + else if ( sbookflag ) + { + DrawSpellBook(); + } + DrawDurIcon(); + if ( chrflag ) + { + DrawChr(); + } + else if ( questlog ) + { + DrawQuestLog(); + } + else if ( plr[myplr]._pStatPts && !spselflag ) + { + DrawLevelUpIcon(); + } + if ( uitemflag ) + DrawUniqueInfo(); + if ( qtextflag ) + DrawQText(); + if ( spselflag ) + DrawSpellList(); + if ( dropGoldFlag ) + DrawGoldSplit(dropGoldValue); + if ( helpflag ) + DrawHelp(); + if ( msgflag ) + DrawDiabloMsg(); + if ( PauseMode && !deathflag ) + gmenu_draw_pause(); + DrawPlrMsg(); + gmenu_draw(); + doom_draw(); + DrawInfoBox(); + DrawLifeFlask(); + DrawManaFlask(); +} +// 4B84DC: using guessed type int dropGoldFlag; +// 4B8968: using guessed type int sbookflag; +// 4B8C98: using guessed type int spselflag; +// 52569C: using guessed type int zoomflag; +// 525740: using guessed type int PauseMode; +// 52B9F1: using guessed type char msgflag; +// 646D00: using guessed type char qtextflag; +// 69BD04: using guessed type int questlog; +// 69BEF8: using guessed type int light_table_index; +// 69CF94: using guessed type int cel_transparency_active; +// 6AA705: using guessed type char stextflag; + +void __cdecl town_init_dpiece_defs_map() +{ + int (*v0)[112]; // ebx + int v1; // ebp + int v2; // esi + char *v3; // edi + char *v4; // ecx + signed int v5; // eax + int (*v6)[112]; // [esp+10h] [ebp-8h] + int y; // [esp+14h] [ebp-4h] + + y = 0; + v6 = dPiece; + do + { + v0 = v6; + v1 = 0; + do + { + v2 = (*v0)[0]; + v3 = (char *)dpiece_defs_map_1 + 32 * gendung_get_dpiece_num_from_coord(v1, y); + if ( v2 ) + { + v4 = (char *)pLevelPieces + 32 * v2 - 32; + v5 = 0; + do + { + *(_WORD *)&v3[2 * v5] = *(_WORD *)&v4[2 * ((v5 & 1) - (v5 & 0xE)) + 28]; + ++v5; + } + while ( v5 < 16 ); + } + else + { + memset(v3, 0, 0x20u); + } + ++v1; + ++v0; + } + while ( v1 < 112 ); + v6 = (int (*)[112])((char *)v6 + 4); + ++y; + } + while ( (signed int)v6 < (signed int)dPiece[1] ); + if ( zoomflag ) + { + scr_pix_width = 640; + scr_pix_height = 352; + dword_5C2FF8 = 10; + dword_5C2FFC = 11; + } + else + { + scr_pix_width = 384; + scr_pix_height = 224; + dword_5C2FF8 = 6; + dword_5C2FFC = 7; + } +} +// 52569C: using guessed type int zoomflag; +// 5C2FF8: using guessed type int dword_5C2FF8; +// 5C2FFC: using guessed type int dword_5C2FFC; +// 5C3000: using guessed type int scr_pix_width; +// 5C3004: using guessed type int scr_pix_height; + +void __fastcall T_FillSector(unsigned char *P3Tiles, unsigned char *pSector, int xi, int yi, int w, int h) /* check 7 params: int AddSec */ +{ + int v7; // ebx + int v8; // edx + int v9; // edi + int *v10; // ecx + int v11; // eax + unsigned char *v12; // esi + unsigned short v13; // ax + int v14; // eax + int v15; // [esp+4h] [ebp-14h] + int v16; // [esp+8h] [ebp-10h] + unsigned char *v17; // [esp+Ch] [ebp-Ch] + unsigned char *v18; // [esp+10h] [ebp-8h] + signed int v19; // [esp+14h] [ebp-4h] + int a4; // [esp+24h] [ebp+Ch] + int a6; // [esp+2Ch] [ebp+14h] + + v7 = h; + v17 = pSector; + v8 = yi; + v18 = P3Tiles; + v19 = 4; + if ( h > 0 ) + { + do + { + v9 = w; + if ( w > 0 ) + { + v10 = &dPiece[1][v8 + 112 * xi]; + do + { + v11 = *(unsigned short *)&v17[v19]; + if ( (_WORD)v11 ) + { + v12 = &v18[8 * (v11 - 1)]; + v13 = *(_WORD *)v12; + v12 += 2; + v14 = v13 + 1; + a4 = v14; + _LOWORD(v14) = *(_WORD *)v12; + v12 += 2; + a6 = ++v14; + _LOWORD(v14) = *(_WORD *)v12; + v16 = ++v14; + _LOWORD(v14) = *((_WORD *)v12 + 1); + v15 = v14 + 1; + } + else + { + a4 = 0; + a6 = 0; + v16 = 0; + v15 = 0; + } + v19 += 2; + *(v10 - 112) = a4; + *v10 = a6; + *(v10 - 111) = v16; + v10[1] = v15; + v10 += 224; + --v9; + } + while ( v9 ); + } + v8 += 2; + --v7; + } + while ( v7 ); + } +} + +void __fastcall T_FillTile(unsigned char *P3Tiles, int xx, int yy, int t) +{ + unsigned char *v4; // esi + unsigned short v5; // ax + int v6; // eax + int v7; // ST10_4 + int v8; // ST0C_4 + int v9; // ST08_4 + + v4 = &P3Tiles[8 * (t - 1)]; + v5 = *(_WORD *)v4; + v4 += 2; + v6 = v5 + 1; + v7 = v6; + _LOWORD(v6) = *(_WORD *)v4; + v4 += 2; + v8 = ++v6; + _LOWORD(v6) = *(_WORD *)v4; + v9 = ++v6; + _LOWORD(v6) = *((_WORD *)v4 + 1); + dPiece[xx][yy] = v7; + dPiece[xx + 1][yy] = v8; + dPiece[xx][yy + 1] = v9; + dPiece[xx + 1][yy + 1] = v6 + 1; +} + +void __cdecl T_Pass3() +{ + int *v1; // esi + int *v2; // eax + signed int v3; // ecx + unsigned char *P3Tiles; // esi + unsigned char *pSector; // edi + int xx; // edi + + v1 = dPiece[1]; + do + { + v2 = v1; + v3 = 56; + do + { + *(v2 - 112) = 0; + *v2 = 0; + *(v2 - 111) = 0; + v2[1] = 0; + v2 += 224; + --v3; + } + while ( v3 ); + v1 += 2; + } + while ( (signed int)v1 < (signed int)dPiece[2] ); + P3Tiles = LoadFileInMem("Levels\\TownData\\Town.TIL", 0); + pSector = LoadFileInMem("Levels\\TownData\\Sector1s.DUN", 0); + T_FillSector(P3Tiles, pSector, 46, 46, 25, 25); + mem_free_dbg(pSector); + pSector = LoadFileInMem("Levels\\TownData\\Sector2s.DUN", 0); + T_FillSector(P3Tiles, pSector, 46, 0, 25, 23); + mem_free_dbg(pSector); + pSector = LoadFileInMem("Levels\\TownData\\Sector3s.DUN", 0); + T_FillSector(P3Tiles, pSector, 0, 46, 23, 25); + mem_free_dbg(pSector); + pSector = LoadFileInMem("Levels\\TownData\\Sector4s.DUN", 0); + T_FillSector(P3Tiles, pSector, 0, 0, 23, 23); + mem_free_dbg(pSector); + if ( gbMaxPlayers == 1 ) + { + if ( !(plr[myplr].pTownWarps & 1) ) + { + T_FillTile(P3Tiles, 48, 20, 320); + } + if ( !(plr[myplr].pTownWarps & 2) ) + { + T_FillTile(P3Tiles, 16, 68, 332); + T_FillTile(P3Tiles, 16, 70, 331); + } + if ( !(plr[myplr].pTownWarps & 4) ) + { + xx = 36; + do + { + T_FillTile(P3Tiles, xx++, 78, random(0, 4) + 1); + } + while ( xx < 46 ); + } + } + if ( quests[13]._qactive != 3 && quests[13]._qactive ) + T_FillTile(P3Tiles, 60, 70, 342); + else + T_FillTile(P3Tiles, 60, 70, 71); + mem_free_dbg(P3Tiles); +} +// 45FDE6: could not find valid save-restore pair for edi +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall CreateTown(int entry) +{ + int v1; // edi + int (*v2)[112]; // esi + _BYTE *v3; // eax + int (*v4)[112]; // edx + signed int v5; // ebp + int v6; // ecx + + v1 = 0; + dminx = 10; + dminy = 10; + dmaxx = 84; + dmaxy = 84; + if ( entry ) + { + if ( entry == 1 ) + { + ViewX = 25; + ViewY = 31; + } + else if ( entry == 7 ) + { + if ( TWarpFrom == 5 ) + { + ViewX = 49; + ViewY = 22; + } + if ( TWarpFrom == 9 ) + { + ViewX = 18; + ViewY = 69; + } + if ( TWarpFrom == 13 ) + { + ViewX = 41; + ViewY = 81; + } + } + } + else + { + ViewX = 75; + ViewY = 68; + } + T_Pass3(); + memset(dTransVal, 0, 0x3100u); + memset(dFlags, 0, 0x3100u); + memset(dPlayer, 0, 0x3100u); + memset(dMonster, 0, 0xC400u); + memset(dObject, 0, 0x3100u); + memset(dItem, 0, 0x3100u); + memset(dArch, 0, 0x3100u); + v2 = dPiece; + do + { + v3 = (unsigned char *)dArch + v1; + v4 = v2; + v5 = 112; + do + { + v6 = (*v4)[0]; + if ( (*v4)[0] == 360 ) + { + *v3 = 1; + } + else + { + switch ( v6 ) + { + case 358: + *v3 = 2; + break; + case 129: + *v3 = 6; + break; + case 130: + *v3 = 7; + break; + case 128: + *v3 = 8; + break; + case 117: + *v3 = 9; + break; + case 157: + *v3 = 10; + break; + case 158: + *v3 = 11; + break; + case 156: + *v3 = 12; + break; + case 162: + *v3 = 13; + break; + case 160: + *v3 = 14; + break; + case 214: + *v3 = 15; + break; + case 212: + *v3 = 16; + break; + case 217: + *v3 = 17; + break; + case 216: + *v3 = 18; + break; + } + } + ++v4; + v3 += 112; + --v5; + } + while ( v5 ); + v2 = (int (*)[112])((char *)v2 + 4); + ++v1; + } + while ( (signed int)v2 < (signed int)dPiece[1] ); + town_init_dpiece_defs_map(); +} +// 5CF328: using guessed type int dmaxx; +// 5CF32C: using guessed type int dmaxy; +// 5D2458: using guessed type int dminx; +// 5D245C: using guessed type int dminy; +// 6ABB30: using guessed type int TWarpFrom; diff --git a/Source/town.h b/Source/town.h new file mode 100644 index 000000000..9a8bcb042 --- /dev/null +++ b/Source/town.h @@ -0,0 +1,25 @@ +//HEADER_GOES_HERE +#ifndef __TOWN_H__ +#define __TOWN_H__ + +void __fastcall town_clear_upper_buf(unsigned char *a1); +void __fastcall town_clear_low_buf(unsigned char *y_related); +void __fastcall town_draw_clipped_e_flag(void *buffer, int x, int y, int sx, int sy); +void __fastcall town_draw_clipped_town(void *unused, int x, int y, int sx, int sy, int some_flag); +void __fastcall town_draw_lower(int x, int y, int sx, int sy, int a5, int some_flag); +void __fastcall town_draw_clipped_e_flag_2(void *buffer, int x, int y, int a4, int a5, int sx, int sy); +void __fastcall town_draw_clipped_town_2(int x, int y, int a3, int a4, int a5, int sx, int sy, int some_flag); +void __fastcall town_draw_lower_2(int x, int y, int sx, int sy, int a5, int a6, int some_flag); +void __fastcall town_draw_e_flag(void *buffer, int x, int y, int a4, int dir, int sx, int sy); +void __fastcall town_draw_town_all(void *buffer, int x, int y, int a4, int dir, int sx, int sy, int some_flag); +void __fastcall town_draw_upper(int x, int y, int sx, int sy, int a5, int a6, int some_flag); +void __fastcall T_DrawGame(int x, int y); +void __fastcall T_DrawZoom(int x, int y); +void __fastcall T_DrawView(int StartX, int StartY); +void __cdecl town_init_dpiece_defs_map(); +void __fastcall T_FillSector(unsigned char *P3Tiles, unsigned char *pSector, int xi, int yi, int w, int h); +void __fastcall T_FillTile(unsigned char *P3Tiles, int xx, int yy, int t); +void __cdecl T_Pass3(); +void __fastcall CreateTown(int entry); + +#endif /* __TOWN_H__ */ diff --git a/Source/towners.cpp b/Source/towners.cpp new file mode 100644 index 000000000..817c6e235 --- /dev/null +++ b/Source/towners.cpp @@ -0,0 +1,1494 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int storeflag; // weak +int sgnCowMsg; // weak +int numtowners; // idb +int sgdwCowClicks; // weak +int bannerflag; // weak // unused 0x6AAC28 +int boyloadflag; // weak +void *pCowCels; // idb +TownerStruct towner[16]; +#endif + + +const int snSFX[3][3] = +{ + { PS_WARR52, PS_ROGUE52, PS_MAGE52 }, + { PS_WARR49, PS_ROGUE49, PS_MAGE49 }, + { PS_WARR50, PS_ROGUE50, PS_MAGE50 } +}; + +/* data */ + +char AnimOrder[6][148] = +{ + { + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 5, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, + -1 + }, + { + 1, 2, 3, 3, 2, 1, 20, 19, 19, 20, + 1, 2, 3, 3, 2, 1, 20, 19, 19, 20, + 1, 2, 3, 3, 2, 1, 20, 19, 19, 20, + 1, 2, 3, 3, 2, 1, 20, 19, 19, 20, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 15, 14, 13, 12, + 11, 10, 9, 8, 7, 6, 5, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, + 5, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, -1 + }, + { + 1, 1, 25, 25, 24, 23, 22, 21, 20, 19, + 18, 17, 16, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 25, 25, 1, 1, 1, 25, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 14, 13, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, 1, -1 + }, + { + 1, 2, 3, 3, 2, 1, 16, 15, 14, 14, + 16, 1, 2, 3, 3, 2, 1, 16, 15, 14, + 14, 15, 16, 1, 2, 3, 3, 2, 1, 16, + 15, 14, 14, 15, 16, 1, 2, 3, 3, 2, + 1, 16, 15, 14, 14, 15, 16, 1, 2, 3, + 3, 2, 1, 16, 15, 14, 14, 15, 16, 1, + 2, 3, 3, 2, 1, 16, 15, 14, 14, 15, + 16, 1, 2, 3, 3, 2, 1, 16, 15, 14, + 14, 15, 16, 1, 2, 3, 2, 1, 16, 15, + 14, 14, 15, 16, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + -1 + }, + { + 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 11, 11, 11, 12, 13, 14, 15, + 16, 17, 18, 18, 1, 1, 1, 18, 17, 16, + 15, 14, 13, 12, 11, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 1, 2, 3, 4, 5, 5, + 5, 4, 3, 2, -1 + }, + { + 4, 4, 4, 5, 6, 6, 6, 5, 4, 15, + 14, 13, 13, 13, 14, 15, 4, 5, 6, 6, + 6, 5, 4, 4, 4, 5, 6, 6, 6, 5, + 4, 15, 14, 13, 13, 13, 14, 15, 4, 5, + 6, 6, 6, 5, 4, 4, 4, 5, 6, 6, + 6, 5, 4, 15, 14, 13, 13, 13, 14, 15, + 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, + 19, 18, 19, 1, 2, 1, 19, 18, 19, 1, + 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 15, 15, 14, 13, + 13, 13, 13, 14, 15, 15, 15, 14, 13, 12, + 12, 12, 11, 10, 10, 10, 9, 8, 9, 10, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 1, 2, 1, 19, 18, 19, 1, 2, 1, 2, + 3, -1 + } +}; +int TownCowX[3] = { 58, 56, 59 }; +int TownCowY[3] = { 16, 14, 20 }; +int TownCowDir[3] = { 1, 3, 4 }; +int cowoffx[8] = { -1, 0, -1, -1, -1, 0, -1, -1 }; +int cowoffy[8] = { -1, -1, -1, 0, -1, -1, -1, 0 }; +QuestTalkData Qtalklist[11] = +{ + { + QUEST_INFRA6, + QUEST_MUSH6, + -1, + -1, + QUEST_VEIL5, + -1, + QUEST_BUTCH5, + QUEST_BANNER6, + QUEST_BLIND5, + QUEST_BLOOD5, + QUEST_ANVIL6, + QUEST_WARLRD5, + QUEST_KING7, + QUEST_POISON7, + QUEST_BONE5, + QUEST_VILE9 + }, + { + QUEST_INFRA3, + -1, + -1, + -1, + QUEST_VEIL3, + -1, + QUEST_BUTCH3, + QUEST_BANNER4, + QUEST_BLIND3, + QUEST_BLOOD3, + QUEST_ANVIL3, + QUEST_WARLRD3, + QUEST_KING5, + QUEST_POISON4, + QUEST_BONE3, + QUEST_VILE7 + }, + { + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + }, + { + QUEST_INFRA2, + QUEST_MUSH2, + -1, + -1, + QUEST_VEIL2, + -1, + QUEST_BUTCH2, + -1, + QUEST_BLIND2, + QUEST_BLOOD2, + QUEST_ANVIL2, + QUEST_WARLRD2, + QUEST_KING3, + QUEST_POISON2, + QUEST_BONE2, + QUEST_VILE4 + }, + { + QUEST_INFRA1, + QUEST_MUSH1, + -1, + -1, + QUEST_VEIL1, + QUEST_VILE3, + QUEST_BUTCH1, + QUEST_BANNER1, + QUEST_BLIND1, + QUEST_BLOOD1, + QUEST_ANVIL1, + QUEST_WARLRD1, + QUEST_KING1, + QUEST_POISON1, + QUEST_BONE1, + QUEST_VILE2 + }, + { + QUEST_INFRA8, + QUEST_MUSH7, + -1, + -1, + QUEST_VEIL6, + -1, + QUEST_BUTCH6, + QUEST_BANNER7, + QUEST_BLIND6, + QUEST_BLOOD6, + QUEST_ANVIL8, + QUEST_WARLRD6, + QUEST_KING8, + QUEST_POISON8, + QUEST_BONE6, + QUEST_VILE10 + }, + { + QUEST_INFRA9, + QUEST_MUSH9, + -1, + -1, + QUEST_VEIL7, + -1, + QUEST_BUTCH7, + QUEST_BANNER8, + QUEST_BLIND7, + QUEST_BLOOD7, + QUEST_ANVIL9, + QUEST_WARLRD7, + QUEST_KING9, + QUEST_POISON9, + QUEST_BONE7, + QUEST_VILE11 + }, + { + QUEST_INFRA4, + QUEST_MUSH5, + -1, + -1, + QUEST_VEIL4, + -1, + QUEST_BUTCH4, + QUEST_BANNER5, + QUEST_BLIND4, + QUEST_BLOOD4, + QUEST_ANVIL4, + QUEST_WARLRD4, + QUEST_KING6, + QUEST_POISON6, + QUEST_BONE4, + QUEST_VILE8 + }, + { + QUEST_INFRA10, + QUEST_MUSH13, + -1, + -1, + QUEST_VEIL8, + -1, + QUEST_BUTCH8, + QUEST_BANNER9, + QUEST_BLIND8, + QUEST_BLOOD8, + QUEST_ANVIL10, + QUEST_WARLRD8, + QUEST_KING10, + QUEST_POISON10, + QUEST_BONE8, + QUEST_VILE12 + }, + { + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + }, + { + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1, + QUEST_KING1 + } +}; +int CowPlaying = -1; + +int __fastcall GetActiveTowner(int t) +{ + int i; // eax + + i = 0; + if ( numtowners <= 0 ) + return -1; + + while ( towner[i]._ttype != t ) + { + ++i; + if ( i >= numtowners ) + return -1; + } + return i; +} + +void __fastcall SetTownerGPtrs(void *pData, void **pAnim) +{ + void **v2; // esi + signed int v3; // edx + char *v4; // eax + signed int v5; // [esp+Ch] [ebp-4h] + + v5 = 0; + v2 = pAnim; + do + { + v3 = v5; + v4 = (char *)pData + *((_DWORD *)pData + v5++); + v2[v3] = v4; + } + while ( v5 < 8 ); +} + +void __fastcall NewTownerAnim(int tnum, unsigned char *pAnim, int numFrames, int Delay) +{ + int v4; // ecx + + v4 = tnum; + towner[v4]._tAnimCnt = 0; + towner[v4]._tAnimLen = numFrames; + towner[v4]._tAnimData = pAnim; + towner[v4]._tAnimFrame = 1; + towner[v4]._tAnimDelay = Delay; +} + +void __fastcall InitTownerInfo(int i, int w, bool sel, int t, int x, int y, int ao, int tp) +{ + int v8; // ebx + int v9; // esi + int v10; // edi + + v8 = i; + v9 = i; + v10 = w; + memset(&towner[i], 0, 0xE8u); + towner[v9]._tSelFlag = sel; + towner[v9]._ttype = t; + towner[v9]._tx = x; + towner[v9]._tMsgSaid = 0; + towner[v9]._tAnimWidth = v10; + towner[v9]._tAnimWidth2 = (v10 - 64) >> 1; + towner[v9]._ty = y; + dMonster[0][y + 112 * x] = v8 + 1; + _LOBYTE(towner[v9]._tAnimOrder) = ao; + towner[v9]._tTenPer = tp; + towner[v9]._tSeed = GetRndSeed(); +} + +void __fastcall InitQstSnds(int i) +{ + int v1; // eax + _BYTE *v2; // ecx + unsigned char *v3; // esi + QuestTalkData *v4; // eax + bool v5; // zf + + v1 = i; + if ( boyloadflag ) + v1 = i + 1; + v2 = (unsigned char *)&towner[i].qsts[0]._qstmsgact; + v3 = &quests[0]._qtype; + v4 = &Qtalklist[v1]; + do + { + v5 = v4->_qinfra == -1; + *(v2 - 2) = *v3; + *(v2 - 1) = v4->_qinfra; + *v2 = !v5; + v3 += 24; + v4 = (QuestTalkData *)((char *)v4 + 4); + v2 += 3; + } + while ( (signed int)v3 < (signed int)&quests[16]._qtype ); +} +// 69BE90: using guessed type int qline; +// 6AAC2C: using guessed type int boyloadflag; + +void __cdecl InitSmith() +{ + int v0; // esi + int v1; // esi + _DWORD *v2; // eax + signed int v3; // ecx + int v4; // ecx + + InitTownerInfo(numtowners, 96, 1, 0, 62, 63, 0, 10); + v0 = numtowners; + InitQstSnds(numtowners); + v1 = v0; + towner[v1]._tNData = LoadFileInMem("Towners\\Smith\\SmithN.CEL", 0); + v2 = (unsigned int *)towner[v1]._tNAnim; + v3 = 8; + do + { + *v2 = (unsigned int)towner[v1]._tNData; + ++v2; + --v3; + } + while ( v3 ); + v4 = numtowners; + towner[v1]._tNFrames = 16; + NewTownerAnim(v4, towner[v1]._tNAnim[1], 16, 3); + strcpy(towner[v1]._tName, "Griswold the Blacksmith"); + ++numtowners; +} + +void __cdecl InitBarOwner() +{ + int v0; // esi + int v1; // esi + _DWORD *v2; // eax + signed int v3; // ecx + int v4; // ecx + + bannerflag = 0; // unused + InitTownerInfo(numtowners, 96, 1, 3, 55, 62, 3, 10); + v0 = numtowners; + InitQstSnds(numtowners); + v1 = v0; + towner[v1]._tNData = LoadFileInMem("Towners\\TwnF\\TwnFN.CEL", 0); + v2 = (unsigned int *)towner[v1]._tNAnim; + v3 = 8; + do + { + *v2 = (unsigned int)towner[v1]._tNData; + ++v2; + --v3; + } + while ( v3 ); + v4 = numtowners; + towner[v1]._tNFrames = 16; + NewTownerAnim(v4, towner[v1]._tNAnim[1], 16, 3); + strcpy(towner[v1]._tName, "Ogden the Tavern owner"); + ++numtowners; +} +// 6AAC28: using guessed type int bannerflag; + +void __cdecl InitTownDead() +{ + int v0; // esi + int v1; // esi + _DWORD *v2; // eax + signed int v3; // ecx + int v4; // ecx + + InitTownerInfo(numtowners, 96, 1, 2, 24, 32, -1, 10); + v0 = numtowners; + InitQstSnds(numtowners); + v1 = v0; + towner[v1]._tNData = LoadFileInMem("Towners\\Butch\\Deadguy.CEL", 0); + v2 = (unsigned int *)towner[v1]._tNAnim; + v3 = 8; + do + { + *v2 = (unsigned int)towner[v1]._tNData; + ++v2; + --v3; + } + while ( v3 ); + v4 = numtowners; + towner[v1]._tNFrames = 8; + NewTownerAnim(v4, towner[v1]._tNAnim[4], 8, 6); + strcpy(towner[v1]._tName, "Wounded Townsman"); + ++numtowners; +} + +void __cdecl InitWitch() +{ + int v0; // esi + int v1; // esi + _DWORD *v2; // ecx + signed int v3; // edx + + InitTownerInfo(numtowners, 96, 1, 6, 80, 20, 5, 10); + v0 = numtowners; + InitQstSnds(numtowners); + v1 = v0; + towner[v1]._tNData = LoadFileInMem("Towners\\TownWmn1\\Witch.CEL", 0); + v2 = (unsigned int *)towner[v1]._tNAnim; + v3 = 8; + do + { + *v2 = (unsigned int)towner[v1]._tNData; + ++v2; + --v3; + } + while ( v3 ); + towner[v1]._tNFrames = 19; + NewTownerAnim(numtowners, towner[v1]._tNAnim[0], 19, 6); + strcpy(towner[v1]._tName, "Adria the Witch"); + ++numtowners; +} + +void __cdecl InitBarmaid() +{ + int v0; // esi + int v1; // esi + _DWORD *v2; // ecx + signed int v3; // edx + + InitTownerInfo(numtowners, 96, 1, 7, 43, 66, -1, 10); + v0 = numtowners; + InitQstSnds(numtowners); + v1 = v0; + towner[v1]._tNData = LoadFileInMem("Towners\\TownWmn1\\WmnN.CEL", 0); + v2 = (unsigned int *)towner[v1]._tNAnim; + v3 = 8; + do + { + *v2 = (unsigned int)towner[v1]._tNData; + ++v2; + --v3; + } + while ( v3 ); + towner[v1]._tNFrames = 18; + NewTownerAnim(numtowners, towner[v1]._tNAnim[0], 18, 6); + strcpy(towner[v1]._tName, "Gillian the Barmaid"); + ++numtowners; +} + +void __cdecl InitBoy() +{ + int v0; // esi + int v1; // esi + _DWORD *v2; // ecx + signed int v3; // edx + + boyloadflag = 1; + InitTownerInfo(numtowners, 96, 1, 8, 11, 53, -1, 10); + v0 = numtowners; + InitQstSnds(numtowners); + v1 = v0; + towner[v1]._tNData = LoadFileInMem("Towners\\TownBoy\\PegKid1.CEL", 0); + v2 = (unsigned int *)towner[v1]._tNAnim; + v3 = 8; + do + { + *v2 = (unsigned int)towner[v1]._tNData; + ++v2; + --v3; + } + while ( v3 ); + towner[v1]._tNFrames = 20; + NewTownerAnim(numtowners, towner[v1]._tNAnim[0], 20, 6); + strcpy(towner[v1]._tName, "Wirt the Peg-legged boy"); + ++numtowners; +} +// 6AAC2C: using guessed type int boyloadflag; + +void __cdecl InitHealer() +{ + int v0; // esi + int v1; // esi + _DWORD *v2; // eax + signed int v3; // ecx + int v4; // ecx + + InitTownerInfo(numtowners, 96, 1, 1, 55, 79, 1, 10); + v0 = numtowners; + InitQstSnds(numtowners); + v1 = v0; + towner[v1]._tNData = LoadFileInMem("Towners\\Healer\\Healer.CEL", 0); + v2 = (unsigned int *)towner[v1]._tNAnim; + v3 = 8; + do + { + *v2 = (unsigned int)towner[v1]._tNData; + ++v2; + --v3; + } + while ( v3 ); + v4 = numtowners; + towner[v1]._tNFrames = 20; + NewTownerAnim(v4, towner[v1]._tNAnim[7], 20, 6); + strcpy(towner[v1]._tName, "Pepin the Healer"); + ++numtowners; +} + +void __cdecl InitTeller() +{ + int v0; // esi + int v1; // esi + _DWORD *v2; // ecx + signed int v3; // edx + + InitTownerInfo(numtowners, 96, 1, 4, 62, 71, 2, 10); + v0 = numtowners; + InitQstSnds(numtowners); + v1 = v0; + towner[v1]._tNData = LoadFileInMem("Towners\\Strytell\\Strytell.CEL", 0); + v2 = (unsigned int *)towner[v1]._tNAnim; + v3 = 8; + do + { + *v2 = (unsigned int)towner[v1]._tNData; + ++v2; + --v3; + } + while ( v3 ); + towner[v1]._tNFrames = 25; + NewTownerAnim(numtowners, towner[v1]._tNAnim[0], 25, 3); + strcpy(towner[v1]._tName, "Cain the Elder"); + ++numtowners; +} + +void __cdecl InitDrunk() +{ + int v0; // esi + int v1; // esi + _DWORD *v2; // ecx + signed int v3; // edx + + InitTownerInfo(numtowners, 96, 1, 5, 71, 84, 4, 10); + v0 = numtowners; + InitQstSnds(numtowners); + v1 = v0; + towner[v1]._tNData = LoadFileInMem("Towners\\Drunk\\TwnDrunk.CEL", 0); + v2 = (unsigned int *)towner[v1]._tNAnim; + v3 = 8; + do + { + *v2 = (unsigned int)towner[v1]._tNData; + ++v2; + --v3; + } + while ( v3 ); + towner[v1]._tNFrames = 18; + NewTownerAnim(numtowners, towner[v1]._tNAnim[0], 18, 3); + strcpy(towner[v1]._tName, "Farnham the Drunk"); + ++numtowners; +} + +void __cdecl InitCows() +{ + unsigned char *v0; // eax + int v1; // ecx + signed int v2; // ebx + int v3; // esi + int v4; // ebp + int v5; // eax + void **v6; // ecx + int v7; // edi + int v9; // edx + int v10; // eax + int v11; // ecx + _DWORD *v12; // esi + int v13; // edx + _DWORD *v14; // esi + _DWORD *v15; // eax + int v16; // [esp+10h] [ebp-4h] + + v0 = LoadFileInMem("Towners\\Animals\\Cow.CEL", 0); + v1 = numtowners; + pCowCels = v0; + v2 = 0; + do + { + v3 = TownCowX[v2]; + v4 = TownCowDir[v2]; + v16 = TownCowY[v2]; + InitTownerInfo(v1, 128, 0, 9, TownCowX[v2], v16, -1, 10); + v5 = numtowners; + v6 = (void **)&towner[numtowners]._tNData; + *v6 = pCowCels; + SetTownerGPtrs(*v6, (void **)towner[v5]._tNAnim); + v7 = numtowners; + towner[numtowners]._tNFrames = 12; + NewTownerAnim(v7, towner[0]._tNAnim[v4 + 58 * v7], 12, 3); + v7 *= 232; + *(int *)((char *)&towner[0]._tAnimFrame + v7) = random(0, 11) + 1; + *(int *)((char *)&towner[0]._tSelFlag + v7) = 1; + strcpy(&towner[0]._tName[v7], "Cow"); + v9 = v3 + cowoffx[v4]; + v10 = v16 + cowoffy[v4]; + v11 = numtowners; + v12 = (_DWORD *)((char *)dMonster + 4 * (v10 + 112 * v3)); + if ( !*v12 ) + *v12 = -1 - numtowners; + v13 = 112 * v9; + v14 = (_DWORD *)((char *)dMonster + 4 * (v13 + v16)); + if ( !*v14 ) + *v14 = -1 - v11; + v15 = (_DWORD *)((char *)dMonster + 4 * (v10 + v13)); + if ( !*v15 ) + *v15 = -1 - v11; + ++v2; + v1 = v11 + 1; + numtowners = v1; + } + while ( v2 < 3 ); +} +// 6AAC2C: using guessed type int boyloadflag; + +void __cdecl InitTowners() +{ + numtowners = 0; + boyloadflag = 0; + InitSmith(); + InitHealer(); + if ( quests[6]._qactive && quests[6]._qactive != 3 ) + InitTownDead(); + InitBarOwner(); + InitTeller(); + InitDrunk(); + InitWitch(); + InitBarmaid(); + InitBoy(); + InitCows(); +} +// 6AAC2C: using guessed type int boyloadflag; + +void __cdecl FreeTownerGFX() +{ + void **v0; // esi + void *v1; // ecx + void *v2; // ecx + + v0 = (void **)&towner[0]._tNData; + do + { + v1 = *v0; + if ( *v0 == pCowCels ) + { + *v0 = 0; + } + else if ( v1 ) + { + *v0 = 0; + mem_free_dbg(v1); + } + v0 += 58; + } + while ( (signed int)v0 < (signed int)&towner[16]._tNData ); + v2 = pCowCels; + pCowCels = 0; + mem_free_dbg(v2); +} +// 6ABB9C: using guessed type int dword_6ABB9C; + +void __fastcall TownCtrlMsg(int i) +{ + int p; // edi + int dx; // ebx + int dy; // eax + + if ( towner[i]._tbtcnt ) + { + p = towner[i]._tVar1; + dx = abs(towner[i]._tx - plr[p].WorldX); + dy = abs(towner[i]._ty - plr[p].WorldY); + if ( dx >= 2 || dy >= 2 ) + towner[i]._tbtcnt = 0; + if ( !towner[i]._tbtcnt ) + { + qtextflag = 0; + sfx_stop(); + } + } +} +// 646D00: using guessed type char qtextflag; + +void __cdecl TownBlackSmith() +{ + int v0; // eax + + v0 = GetActiveTowner(TOWN_SMITH); + TownCtrlMsg(v0); +} + +void __cdecl TownBarOwner() +{ + int v0; // eax + + v0 = GetActiveTowner(TOWN_TAVERN); + TownCtrlMsg(v0); +} + +void __cdecl TownDead() +{ + int v0; // esi + int v1; // eax + + v0 = GetActiveTowner(TOWN_DEADGUY); + TownCtrlMsg(v0); + if ( qtextflag ) + goto LABEL_6; + if ( (quests[6]._qactive != 2 || quests[6]._qlog) && quests[6]._qactive != 1 ) + { + v1 = v0; + towner[v1]._tAnimDelay = 1000; + towner[v1]._tAnimFrame = 1; + strcpy(towner[v0]._tName, "Slain Townsman"); +LABEL_6: + if ( quests[6]._qactive != 1 ) + towner[v0]._tAnimCnt = 0; + } +} +// 646D00: using guessed type char qtextflag; + +void __cdecl TownHealer() +{ + int v0; // eax + + v0 = GetActiveTowner(TOWN_HEALER); + TownCtrlMsg(v0); +} + +void __cdecl TownStory() +{ + int v0; // eax + + v0 = GetActiveTowner(TOWN_STORY); + TownCtrlMsg(v0); +} + +void __cdecl TownDrunk() +{ + int v0; // eax + + v0 = GetActiveTowner(TOWN_DRUNK); + TownCtrlMsg(v0); +} + +void __cdecl TownBoy() +{ + int v0; // eax + + v0 = GetActiveTowner(TOWN_PEGBOY); + TownCtrlMsg(v0); +} + +void __cdecl TownWitch() +{ + int v0; // eax + + v0 = GetActiveTowner(TOWN_WITCH); + TownCtrlMsg(v0); +} + +void __cdecl TownBarMaid() +{ + int v0; // eax + + v0 = GetActiveTowner(TOWN_BMAID); + TownCtrlMsg(v0); +} + +void __cdecl TownCow() +{ + int v0; // eax + + v0 = GetActiveTowner(TOWN_COW); + TownCtrlMsg(v0); +} + +void __cdecl ProcessTowners() +{ + int *v0; // esi + char v1; // al + int v2; // ecx + _DWORD *v3; // eax + + v0 = &towner[0]._tAnimCnt; + do + { + switch ( *(v0 - 10) ) + { + case TOWN_SMITH: + TownBlackSmith(); + break; + case TOWN_HEALER: + TownHealer(); + break; + case TOWN_DEADGUY: + TownDead(); + break; + case TOWN_TAVERN: + TownBarOwner(); + break; + case TOWN_STORY: + TownStory(); + break; + case TOWN_DRUNK: + TownDrunk(); + break; + case TOWN_WITCH: + TownWitch(); + break; + case TOWN_BMAID: + TownBarMaid(); + break; + case TOWN_PEGBOY: + TownBoy(); + break; + case TOWN_COW: + TownCow(); + break; + default: + break; + } + if ( ++*v0 >= *(v0 - 1) ) + { + v1 = *((_BYTE *)v0 + 16); + *v0 = 0; + if ( v1 < 0 ) + { + if ( ++v0[2] > v0[1] ) + v0[2] = 1; + } + else + { + v2 = 148 * v1; + v3 = (unsigned int *)v0 + 3; + ++*v3; + if ( AnimOrder[0][v0[3] + v2] == -1 ) + *v3 = 0; + v0[2] = (char)AnimOrder[0][*v3 + v2]; + } + } + v0 += 58; + } + while ( (signed int)v0 < (signed int)&towner[16]._tAnimCnt ); +} + +ItemStruct *__fastcall PlrHasItem(int pnum, int item, int *i) +{ + unsigned int v3; // eax + int v4; // ecx + + v3 = 21720 * pnum; + *i = 0; + if ( plr[pnum]._pNumInv <= 0 ) + return 0; + while ( *(int *)((char *)&plr[0].InvList[*i].IDidx + v3) != item ) + { + v4 = *i + 1; + *i = v4; + if ( v4 >= plr[v3 / 0x54D8]._pNumInv ) + return 0; + } + return (ItemStruct *)((char *)&plr[0].InvList[*i] + v3); +} + +void __fastcall TownerTalk(int t) +{ + sgdwCowClicks = 0; + sgnCowMsg = 0; + storeflag = 1; + InitQTextMsg(t); +} +// 6AAC18: using guessed type int storeflag; +// 6AAC1C: using guessed type int sgnCowMsg; +// 6AAC24: using guessed type int sgdwCowClicks; + +void __fastcall TalkToTowner(int p, int t) +{ + int v2; // ebx + int v3; // edi + int v6; // ebp + int v7; // esi + int v8; // eax + int v9; // ecx + //char v10; // cl + bool v11; // zf + int v12; // edi + //int v13; // eax + //int v14; // eax + //int v15; // eax + //char v16; // cl + _speech_id v17; // ecx + ItemStruct *Item; // ebp + unsigned char v19; // dl + int inv_item_num; // [esp+10h] [ebp-8h] + int v21; // [esp+14h] [ebp-4h] + + v2 = t; + v3 = p; + v21 = t; + random(6, 3); /* figure out what these are for */ + random(6, 4); + random(6, 5); + v6 = v3; + v7 = v2; + inv_item_num = abs(plr[v3].WorldX - towner[v2]._tx); + v8 = abs(plr[v3].WorldY - towner[v2]._ty); + if ( inv_item_num >= 2 ) + return; + if ( v8 >= 2 ) + return; + if ( qtextflag ) + return; + towner[v7]._tMsgSaid = 0; + if ( pcurs >= CURSOR_FIRSTITEM && !DropItemBeforeTrig() ) + return; + if ( v2 == GetActiveTowner(TOWN_TAVERN) ) + { + if ( !plr[v6]._pLvlVisited[0] && !towner[v7]._tMsgSaid ) + { + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_INTRO); + towner[v7]._tMsgSaid = 1; + } + if ( (plr[v6]._pLvlVisited[2] || plr[v6]._pLvlVisited[4]) && quests[12]._qactive ) + { + if ( !quests[12]._qvar2 && !towner[v7]._tMsgSaid ) + { + quests[12]._qvar2 = 1; + quests[12]._qlog = 1; + if ( quests[12]._qactive == 1 ) + { + quests[12]._qactive = 2; + quests[12]._qvar1 = 1; + } + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_KING2); + towner[v7]._tMsgSaid = 1; + NetSendCmdQuest(1u, 0xCu); + } + if ( quests[12]._qactive == 3 && quests[12]._qvar2 == 1 && !towner[v7]._tMsgSaid ) + { + quests[12]._qvar2 = 2; + quests[12]._qvar1 = 2; + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_KING4); + towner[v7]._tMsgSaid = 1; + NetSendCmdQuest(1u, 0xCu); + } + } + if ( gbMaxPlayers == 1 && plr[v6]._pLvlVisited[3] && quests[7]._qactive ) + { + if ( (quests[7]._qactive == 1 || quests[7]._qactive == 2) && !quests[7]._qvar2 ) + { + if ( towner[v7]._tMsgSaid ) + goto LABEL_36; + quests[7]._qvar2 = 1; + if ( quests[7]._qactive == 1 ) + { + quests[7]._qvar1 = 1; + quests[7]._qactive = 2; + } + quests[7]._qlog = 1; + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_BANNER2); + towner[v7]._tMsgSaid = 1; + } + if ( quests[7]._qvar2 == 1 && PlrHasItem(v3, IDI_BANNER, &inv_item_num) && !towner[v7]._tMsgSaid ) + { + quests[7]._qactive = 3; + quests[7]._qvar1 = 3; + RemoveInvItem(v3, inv_item_num); + CreateItem(UITEM_HARCREST, towner[v7]._tx, towner[v7]._ty + 1); + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_BANNER3); + towner[v7]._tMsgSaid = 1; + } + } +LABEL_36: + if ( !qtextflag ) + { + TownerTalk(QUEST_OGDEN1); + if ( storeflag ) + { + _LOBYTE(v9) = STORE_TAVERN; +LABEL_39: + StartStore(v9); + return; + } + } + return; + } + if ( v2 == GetActiveTowner(TOWN_DEADGUY) ) + { + if ( quests[6]._qactive == 2 ) + { + if ( quests[6]._qvar1 == 1 ) + { + v11 = _LOBYTE(plr[v6]._pClass) == 0; + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + quests[6]._qvar1 = 1; + if ( v11 && (v12 = PS_WARR8, !effect_is_playing(PS_WARR8)) + || _LOBYTE(plr[v6]._pClass) == 1 && (v12 = PS_ROGUE8, !effect_is_playing(PS_ROGUE8)) + || _LOBYTE(plr[v6]._pClass) == 2 && (v12 = PS_MAGE8, !effect_is_playing(PS_MAGE8)) ) + { + PlaySFX(v12); + } +LABEL_53: + towner[v7]._tMsgSaid = 1; + return; + } + if ( quests[6]._qvar1 ) + return; + } + else + { + if ( quests[6]._qactive == 3 ) + { + if ( quests[6]._qvar1 != 1 ) + return; + quests[6]._qvar1 = 1; + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + goto LABEL_53; + } + if ( quests[6]._qactive != 1 ) + return; + } + quests[6]._qactive = 2; + quests[6]._qlog = 1; + quests[6]._qmsg = QUEST_BUTCH9; + quests[6]._qvar1 = 1; + towner[v7]._tbtcnt = 50; + towner[v7]._tVar1 = v3; + towner[v7]._tVar2 = 3; + InitQTextMsg(QUEST_BUTCH9); + towner[v7]._tMsgSaid = 1; + NetSendCmdQuest(1u, 6u); + return; + } + if ( v2 != GetActiveTowner(0) ) + { + if ( v2 == GetActiveTowner(TOWN_WITCH) ) + { + if ( quests[1]._qactive == 1 ) + { + if ( PlrHasItem(v3, IDI_FUNGALTM, &inv_item_num) ) + { + RemoveInvItem(v3, inv_item_num); + quests[1]._qactive = 2; + quests[1]._qlog = 1; + quests[1]._qvar1 = 2; + v17 = QUEST_MUSH8; +LABEL_105: + towner[v7]._tVar1 = v3; + towner[v7]._tbtcnt = 150; + InitQTextMsg(v17); + towner[v7]._tMsgSaid = 1; + goto LABEL_106; + } + } + else if ( quests[1]._qactive == 2 ) + { + if ( quests[1]._qvar1 >= 2u && quests[1]._qvar1 <= 4u ) + { + if ( PlrHasItem(v3, IDI_MUSHROOM, &inv_item_num) ) + { + RemoveInvItem(v3, inv_item_num); + Qtalklist[6]._qblkm = -1; + quests[1]._qvar1 = 5; + Qtalklist[1]._qblkm = 123; + v17 = QUEST_MUSH10; + } + else + { + v17 = QUEST_MUSH9; + if ( quests[1]._qmsg == QUEST_MUSH9 ) + goto LABEL_106; + } + quests[1]._qmsg = v17; + goto LABEL_105; + } + Item = PlrHasItem(v3, IDI_SPECELIX, &inv_item_num); + if ( Item ) + { + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_MUSH12); + quests[1]._qactive = 3; + towner[v7]._tMsgSaid = 1; + AllItemsList[Item->IDidx].iUsable = 1; + } + else if ( PlrHasItem(v3, IDI_BRAIN, &inv_item_num) ) + { + v17 = QUEST_MUSH11; + if ( quests[1]._qvar2 != QUEST_MUSH11 ) + { + quests[1]._qvar2 = QUEST_MUSH11; + goto LABEL_105; + } + } + } +LABEL_106: + if ( !qtextflag ) + { + TownerTalk(QUEST_ADRIA1); + if ( storeflag ) + { + _LOBYTE(v9) = STORE_WITCH; + goto LABEL_39; + } + } + return; + } + if ( v2 == GetActiveTowner(TOWN_BMAID) ) + { + if ( !qtextflag ) + { + TownerTalk(QUEST_GILLIAN1); + if ( storeflag ) + { + _LOBYTE(v9) = STORE_BARMAID; + goto LABEL_39; + } + } + return; + } + if ( v2 == GetActiveTowner(TOWN_DRUNK) ) + { + if ( !qtextflag ) + { + TownerTalk(QUEST_FARNHAM1); + if ( storeflag ) + { + _LOBYTE(v9) = STORE_DRUNK; + goto LABEL_39; + } + } + return; + } + if ( v21 == GetActiveTowner(1) ) + { + if ( gbMaxPlayers != 1 ) + goto LABEL_131; + if ( plr[v6]._pLvlVisited[1] && !towner[v7]._tMsgSaid ) + { + if ( quests[13]._qactive == 1 ) + { + quests[13]._qactive = 2; + quests[13]._qlog = 1; + quests[13]._qmsg = QUEST_POISON3; + quests[13]._qvar1 = 1; + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_POISON3); +LABEL_126: + towner[v7]._tMsgSaid = 1; + goto LABEL_127; + } + if ( quests[13]._qactive == 3 && quests[13]._qvar1 != 2 ) + { + quests[13]._qvar1 = 2; + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_POISON5); + CreateItem(UITEM_TRING, towner[v7]._tx, towner[v7]._ty + 1); + goto LABEL_126; + } + } +LABEL_127: + if ( quests[1]._qactive == 2 && quests[1]._qmsg == QUEST_MUSH10 && PlrHasItem(v3, IDI_BRAIN, &inv_item_num) ) + { + RemoveInvItem(v3, inv_item_num); + SpawnQuestItem(IDI_SPECELIX, towner[v7]._tx, towner[v7]._ty + 1, 0, 0); + InitQTextMsg(QUEST_MUSH4); + Qtalklist[1]._qblkm = -1; + quests[1]._qvar1 = 7; + } +LABEL_131: + if ( !qtextflag ) + { + TownerTalk(QUEST_PEPIN1); + if ( storeflag ) + { + _LOBYTE(v9) = STORE_HEALER; + goto LABEL_39; + } + } + return; + } + if ( v21 == GetActiveTowner(TOWN_PEGBOY) ) + { + if ( !qtextflag ) + { + TownerTalk(QUEST_WIRT1); + if ( storeflag ) + { + _LOBYTE(v9) = STORE_BOY; + goto LABEL_39; + } + } + return; + } + if ( v21 != GetActiveTowner(TOWN_STORY) ) + { + if ( towner[v7]._ttype == 9 && !qtextflag ) + CowSFX(v3); + return; + } + if ( gbMaxPlayers == 1 ) + { + if ( quests[15]._qactive == 1 ) + { + if ( !PlrHasItem(v3, IDI_LAZSTAFF, &inv_item_num) ) + goto LABEL_154; + RemoveInvItem(v3, inv_item_num); + quests[15]._qvar1 = 2; + towner[v7]._tbtcnt = QUEST_STORY1; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_VILE1); + quests[15]._qactive = 2; + quests[15]._qlog = 1; + } + else + { + if ( quests[15]._qactive != 3 || quests[15]._qvar1 != 7 ) + goto LABEL_154; + quests[15]._qvar1 = 8; + towner[v7]._tbtcnt = QUEST_STORY1; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_VILE3); + quests[5]._qlog = 1; + } + v11 = gbMaxPlayers == 1; + towner[v7]._tMsgSaid = 1; + if ( v11 ) + goto LABEL_154; + } + if ( quests[15]._qactive == 2 ) + { + if ( !quests[15]._qlog ) + { + towner[v7]._tbtcnt = QUEST_STORY1; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_VILE1); + towner[v7]._tMsgSaid = 1; + quests[15]._qlog = 1; + v19 = 15; +LABEL_153: + NetSendCmdQuest(1u, v19); + goto LABEL_154; + } + } + else if ( quests[15]._qactive == 3 && quests[15]._qvar1 == 7 ) + { + quests[15]._qvar1 = 8; + towner[v7]._tbtcnt = QUEST_STORY1; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_VILE3); + towner[v7]._tMsgSaid = 1; + NetSendCmdQuest(1u, 0xFu); + quests[5]._qlog = 1; + v19 = 5; + goto LABEL_153; + } +LABEL_154: + if ( !qtextflag ) + { + TownerTalk(QUEST_STORY1); + if ( storeflag ) + { + _LOBYTE(v9) = STORE_STORY; + goto LABEL_39; + } + } + return; + } + if ( gbMaxPlayers == 1 ) + { + if ( plr[v6]._pLvlVisited[4] != 0 && quests[0]._qactive ) + { + if ( quests[0]._qvar2 == 0 ) + { + quests[0]._qvar2 = 1; + quests[0]._qlog = 1; + if ( quests[0]._qactive == 1 ) + { + quests[0]._qactive = 2; + quests[0]._qvar1 = 1; + } + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_INFRA5); + towner[v7]._tMsgSaid = 1; + } + if ( quests[0]._qvar2 == 1 && PlrHasItem(v3, IDI_ROCK, &inv_item_num) && !towner[v7]._tMsgSaid ) + { + quests[0]._qactive = 3; + quests[0]._qvar2 = 2; + quests[0]._qvar1 = 2; + RemoveInvItem(v3, inv_item_num); + CreateItem(UITEM_INFRARING, towner[v7]._tx, towner[v7]._ty + 1); + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_INFRA7); + towner[v7]._tMsgSaid = 1; + } + } + if ( plr[v6]._pLvlVisited[9] && quests[10]._qactive ) + { + if ( (quests[10]._qactive == 1 || quests[10]._qactive == 2) && !quests[10]._qvar2 ) + { + if ( towner[v7]._tMsgSaid || quests[0]._qvar2 != 2 && (quests[0]._qactive != 2 || quests[0]._qvar2 != 1) ) + goto LABEL_86; + quests[10]._qvar2 = 1; + quests[10]._qlog = 1; + if ( quests[10]._qactive == 1 ) + { + quests[10]._qactive = 2; + quests[10]._qvar1 = 1; + } + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_ANVIL5); + towner[v7]._tMsgSaid = 1; + } + if ( quests[10]._qvar2 == 1 && PlrHasItem(v3, IDI_ANVIL, &inv_item_num) && !towner[v7]._tMsgSaid ) + { + quests[10]._qactive = 3; + quests[10]._qvar2 = 2; + quests[10]._qvar1 = 2; + RemoveInvItem(v3, inv_item_num); + CreateItem(UITEM_GRISWOLD, towner[v7]._tx, towner[v7]._ty + 1); + towner[v7]._tbtcnt = 150; + towner[v7]._tVar1 = v3; + InitQTextMsg(QUEST_ANVIL7); + towner[v7]._tMsgSaid = 1; + } + } + } +LABEL_86: + if ( !qtextflag ) + { + TownerTalk(QUEST_GRISWOLD1); + if ( storeflag ) + { + _LOBYTE(v9) = 1; + goto LABEL_39; + } + } +} +// 646D00: using guessed type char qtextflag; +// 679660: using guessed type char gbMaxPlayers; +// 6AAC18: using guessed type int storeflag; + +void __fastcall CowSFX(int pnum) +{ + if ( CowPlaying == -1 || !effect_is_playing(CowPlaying) ) + { + if ( sgdwCowClicks++ < 8 ) + { + CowPlaying = (sgdwCowClicks == 4) + TSFX_COW1; + } + else + { + PlaySfxLoc(TSFX_COW1, plr[pnum].WorldX, plr[pnum].WorldY + 5); + sgdwCowClicks = 4; + CowPlaying = snSFX[sgnCowMsg][plr[pnum]._pClass]; /* snSFX is local */ + if ( sgnCowMsg++ >= 2 ) + sgnCowMsg = 0; + } + PlaySfxLoc(CowPlaying, plr[pnum].WorldX, plr[pnum].WorldY); + } +} +// 6AAC1C: using guessed type int sgnCowMsg; +// 6AAC24: using guessed type int sgdwCowClicks; diff --git a/Source/towners.h b/Source/towners.h new file mode 100644 index 000000000..32dd4837d --- /dev/null +++ b/Source/towners.h @@ -0,0 +1,63 @@ +//HEADER_GOES_HERE +#ifndef __TOWNERS_H__ +#define __TOWNERS_H__ + +extern int storeflag; // weak +extern int sgnCowMsg; // weak +extern int numtowners; // idb +extern int sgdwCowClicks; // weak +extern int bannerflag; // weak // unused 0x6AAC28 +extern int boyloadflag; // weak +extern void *pCowCels; // idb +extern TownerStruct towner[16]; + +int __fastcall GetActiveTowner(int t); +void __fastcall SetTownerGPtrs(void *pData, void **pAnim); /* unsigned char *+** */ +void __fastcall NewTownerAnim(int tnum, unsigned char *pAnim, int numFrames, int Delay); +void __fastcall InitTownerInfo(int i, int w, bool sel, int t, int x, int y, int ao, int tp); +void __fastcall InitQstSnds(int i); +void __cdecl InitSmith(); +void __cdecl InitBarOwner(); +void __cdecl InitTownDead(); +void __cdecl InitWitch(); +void __cdecl InitBarmaid(); +void __cdecl InitBoy(); +void __cdecl InitHealer(); +void __cdecl InitTeller(); +void __cdecl InitDrunk(); +void __cdecl InitCows(); +void __cdecl InitTowners(); +void __cdecl FreeTownerGFX(); +void __fastcall TownCtrlMsg(int i); +void __cdecl TownBlackSmith(); +void __cdecl TownBarOwner(); +void __cdecl TownDead(); +void __cdecl TownHealer(); +void __cdecl TownStory(); +void __cdecl TownDrunk(); +void __cdecl TownBoy(); +void __cdecl TownWitch(); +void __cdecl TownBarMaid(); +void __cdecl TownCow(); +void __cdecl ProcessTowners(); +ItemStruct *__fastcall PlrHasItem(int pnum, int item, int *i); +void __fastcall TownerTalk(int t); +void __fastcall TalkToTowner(int p, int t); +void __fastcall CowSFX(int pnum); + +/* rdata */ + +extern const int snSFX[3][3]; + +/* data */ + +extern char AnimOrder[6][148]; +extern int TownCowX[3]; +extern int TownCowY[3]; +extern int TownCowDir[3]; +extern int cowoffx[8]; +extern int cowoffy[8]; +extern QuestTalkData Qtalklist[11]; +extern int CowPlaying; + +#endif /* __TOWNERS_H__ */ diff --git a/Source/track.cpp b/Source/track.cpp new file mode 100644 index 000000000..0d5a2553e --- /dev/null +++ b/Source/track.cpp @@ -0,0 +1,78 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +bool sgbIsScrolling; // weak +int track_cpp_init_value; // weak +int sgdwLastWalk; // weak +bool sgbIsWalking; // weak +#endif + +const int track_inf = 0x7F800000; // weak + +struct track_cpp_init +{ + track_cpp_init() + { + track_cpp_init_value = track_inf; + } +} _track_cpp_init; +// 4802D0: using guessed type int track_inf; +// 6ABABC: using guessed type int track_cpp_init_value; + +void __cdecl track_process() +{ + int v0; // eax + DWORD v1; // eax + + if ( sgbIsWalking ) + { + if ( cursmx >= 0 && cursmx < 111 && cursmy >= 0 && cursmy < 111 ) + { + v0 = myplr; + if ( (plr[myplr]._pVar8 > 6 || plr[v0]._pmode == PM_STAND) + && (cursmx != plr[v0]._ptargx || cursmy != plr[v0]._ptargy) ) + { + v1 = GetTickCount(); + if ( v1 - sgdwLastWalk >= 300 ) + { + sgdwLastWalk = v1; + NetSendCmdLoc(1u, CMD_WALKXY, cursmx, cursmy); + if ( !sgbIsScrolling ) + sgbIsScrolling = 1; + } + } + } + } +} +// 6ABAB8: using guessed type char sgbIsScrolling; +// 6ABAC0: using guessed type int sgdwLastWalk; +// 6ABAC4: using guessed type int sgbIsWalking; + +void __fastcall track_repeat_walk(bool rep) +{ + if ( sgbIsWalking != rep ) + { + sgbIsWalking = rep; + if ( rep ) + { + sgbIsScrolling = 0; + sgdwLastWalk = GetTickCount() - 50; + NetSendCmdLoc(1u, CMD_WALKXY, cursmx, cursmy); + } + else if ( sgbIsScrolling ) + { + sgbIsScrolling = 0; + } + } +} +// 6ABAB8: using guessed type char sgbIsScrolling; +// 6ABAC0: using guessed type int sgdwLastWalk; +// 6ABAC4: using guessed type int sgbIsWalking; + +bool __cdecl track_isscrolling() +{ + return sgbIsScrolling; +} +// 6ABAB8: using guessed type char sgbIsScrolling; diff --git a/Source/track.h b/Source/track.h new file mode 100644 index 000000000..461438dd5 --- /dev/null +++ b/Source/track.h @@ -0,0 +1,19 @@ +//HEADER_GOES_HERE +#ifndef __TRACK_H__ +#define __TRACK_H__ + +extern bool sgbIsScrolling; // weak +extern int track_cpp_init_value; // weak +extern int sgdwLastWalk; // weak +extern bool sgbIsWalking; // weak + +void __cdecl track_cpp_init(); +void __cdecl track_process(); +void __fastcall track_repeat_walk(bool rep); +bool __cdecl track_isscrolling(); + +/* rdata */ + +extern const int track_inf; // weak + +#endif /* __TRACK_H__ */ diff --git a/Source/trigs.cpp b/Source/trigs.cpp new file mode 100644 index 000000000..366068cbe --- /dev/null +++ b/Source/trigs.cpp @@ -0,0 +1,1384 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +#ifndef NO_GLOBALS +int trigflag[MAXTRIGGERS]; +TriggerStruct trigs[MAXTRIGGERS]; +int TWarpFrom; // weak +#endif + +int TownDownList[11] = { 716, 715, 719, 720, 721, 723, 724, 725, 726, 727, -1 }; +int TownWarp1List[13] = +{ + 1171, + 1172, + 1173, + 1174, + 1175, + 1176, + 1177, + 1178, + 1179, + 1181, + 1183, + 1185, + -1 +}; +int L1UpList[12] = { 127, 129, 130, 131, 132, 133, 135, 137, 138, 139, 140, -1 }; +int L1DownList[10] = { 106, 107, 108, 109, 110, 112, 114, 115, 118, -1 }; +int L2UpList[3] = { 266, 267, -1 }; +int L2DownList[5] = { 269, 270, 271, 272, -1 }; +int L2TWarpUpList[3] = { 558, 559, -1 }; +int L3UpList[15] = +{ + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + -1 +}; +int L3DownList[9] = { 162, 163, 164, 165, 166, 167, 168, 169, -1 }; +int L3TWarpUpList[14] = { 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, -1 }; +int L4UpList[4] = { 82, 83, 90, -1 }; +int L4DownList[6] = { 120, 130, 131, 132, 133, -1 }; +int L4TWarpUpList[4] = { 421, 422, 429, -1 }; +int L4PentaList[33] = +{ + 353, + 354, + 355, + 356, + 357, + 358, + 359, + 360, + 361, + 362, + 363, + 364, + 365, + 366, + 367, + 368, + 369, + 370, + 371, + 372, + 373, + 374, + 375, + 376, + 377, + 378, + 379, + 380, + 381, + 382, + 383, + 384, + -1 +}; + +void __cdecl InitNoTriggers() +{ + trigflag[4] = 0; + trigflag[3] = 0; +} + +void __cdecl InitTownTriggers() +{ + char v0; // bl + int v1; // eax + int v2; // eax + + trigs[0]._tx = 25; + trigs[0]._ty = 29; + trigs[0]._tmsg = WM_DIABNEXTLVL; + trigflag[4] = 1; + if ( gbMaxPlayers == 4 ) + { + trigs[1]._tx = 49; + trigflag[0] = 1; + trigflag[1] = 1; + trigflag[2] = 1; + trigs[1]._ty = 21; + trigs[1]._tmsg = WM_DIABTOWNWARP; + trigs[1]._tlvl = 5; + trigs[2]._tx = 17; + trigs[2]._ty = 69; + trigs[2]._tmsg = WM_DIABTOWNWARP; + trigs[2]._tlvl = 9; + trigs[3]._tx = 41; + trigs[3]._ty = 80; + trigs[3]._tmsg = WM_DIABTOWNWARP; + trigs[3]._tlvl = 13; + trigflag[4] = 4; + } + else + { + trigflag[0] = 0; + trigflag[1] = 0; + trigflag[2] = 0; + v0 = plr[myplr].pTownWarps; + if ( v0 & 1 ) + { + trigs[1]._tx = 49; + trigs[1]._ty = 21; + trigs[1]._tmsg = WM_DIABTOWNWARP; + trigs[1]._tlvl = 5; + trigflag[4] = 2; + trigflag[0] = 1; + } + if ( v0 & 2 ) + { + trigflag[1] = 1; + v1 = trigflag[4]++; + trigs[v1]._tx = 17; + trigs[v1]._ty = 69; + trigs[v1]._tmsg = WM_DIABTOWNWARP; + trigs[v1]._tlvl = 9; + } + if ( v0 & 4 ) + { + trigflag[2] = 1; + v2 = trigflag[4]++; + trigs[v2]._tx = 41; + trigs[v2]._ty = 80; + trigs[v2]._tmsg = WM_DIABTOWNWARP; + trigs[v2]._tlvl = 13; + } + } + trigflag[3] = 0; +} +// 679660: using guessed type char gbMaxPlayers; + +void __cdecl InitL1Triggers() +{ + int v0; // edi + signed int v1; // esi + int *v2; // edx + int *v3; // ecx + TriggerStruct *v4; // eax + int (*v5)[112]; // [esp+Ch] [ebp-8h] + int (*v6)[112]; // [esp+10h] [ebp-4h] + + v0 = 0; + trigflag[4] = 0; + v5 = dPiece; + do + { + v1 = 0; + v6 = v5; + v2 = &trigs[trigflag[4]]._tmsg; + v3 = &trigs[trigflag[4]]._ty; + v4 = &trigs[trigflag[4]]; + do + { + if ( (*v6)[0] == 129 ) + { + ++trigflag[4]; + v4->_tx = v1; + *v3 = v0; + *v2 = WM_DIABPREVLVL; + ++v4; + v3 += 4; + v2 += 4; + } + if ( (*v6)[0] == 115 ) + { + ++trigflag[4]; + v4->_tx = v1; + *v3 = v0; + *v2 = WM_DIABNEXTLVL; + ++v4; + v3 += 4; + v2 += 4; + } + ++v6; + ++v1; + } + while ( v1 < 112 ); + v5 = (int (*)[112])((char *)v5 + 4); + ++v0; + } + while ( (signed int)v5 < (signed int)dPiece[1] ); + trigflag[3] = 0; +} + +void __cdecl InitL2Triggers() +{ + signed int v0; // edi + int *v1; // esi + int *v2; // edx + TriggerStruct *v3; // ecx + int *v4; // eax + int (*v5)[112]; // [esp+Ch] [ebp-10h] + int (*v6)[112]; // [esp+10h] [ebp-Ch] + int v7; // [esp+14h] [ebp-8h] + int *v8; // [esp+18h] [ebp-4h] + + trigflag[4] = 0; + v7 = 0; + v5 = dPiece; + do + { + v0 = 0; + v1 = &trigs[trigflag[4]]._tmsg; + v2 = &trigs[trigflag[4]]._ty; + v3 = &trigs[trigflag[4]]; + v8 = &trigs[trigflag[4]]._tlvl; + v6 = v5; + do + { + if ( (*v6)[0] == 267 && (v0 != quests[14]._qtx || v7 != quests[14]._qty) ) + { + ++trigflag[4]; + v8 += 4; + v3->_tx = v0; + *v2 = v7; + *v1 = WM_DIABPREVLVL; + ++v3; + v2 += 4; + v1 += 4; + } + if ( (*v6)[0] == 559 ) + { + v3->_tx = v0; + *v2 = v7; + v4 = v8; + v8 += 4; + *v1 = WM_DIABTWARPUP; + *v4 = 0; + ++trigflag[4]; + ++v3; + v2 += 4; + v1 += 4; + } + if ( (*v6)[0] == 271 ) + { + ++trigflag[4]; + v8 += 4; + v3->_tx = v0; + *v2 = v7; + *v1 = WM_DIABNEXTLVL; + ++v3; + v2 += 4; + v1 += 4; + } + ++v6; + ++v0; + } + while ( v0 < 112 ); + v5 = (int (*)[112])((char *)v5 + 4); + ++v7; + } + while ( (signed int)v5 < (signed int)dPiece[1] ); + trigflag[3] = 0; +} + +void __cdecl InitL3Triggers() +{ + int v0; // edi + signed int v1; // esi + int *v2; // edx + int *v3; // ecx + TriggerStruct *v4; // eax + int (*v5)[112]; // [esp+Ch] [ebp-8h] + int (*v6)[112]; // [esp+10h] [ebp-4h] + + v0 = 0; + trigflag[4] = 0; + v5 = dPiece; + do + { + v1 = 0; + v6 = v5; + v2 = &trigs[trigflag[4]]._tmsg; + v3 = &trigs[trigflag[4]]._ty; + v4 = &trigs[trigflag[4]]; + do + { + if ( (*v6)[0] == 171 ) + { + ++trigflag[4]; + v4->_tx = v1; + *v3 = v0; + *v2 = WM_DIABPREVLVL; + ++v4; + v3 += 4; + v2 += 4; + } + if ( (*v6)[0] == 168 ) + { + ++trigflag[4]; + v4->_tx = v1; + *v3 = v0; + *v2 = WM_DIABNEXTLVL; + ++v4; + v3 += 4; + v2 += 4; + } + if ( (*v6)[0] == 549 ) + { + ++trigflag[4]; + v4->_tx = v1; + *v3 = v0; + *v2 = WM_DIABTWARPUP; + ++v4; + v3 += 4; + v2 += 4; + } + ++v6; + ++v1; + } + while ( v1 < 112 ); + v5 = (int (*)[112])((char *)v5 + 4); + ++v0; + } + while ( (signed int)v5 < (signed int)dPiece[1] ); + trigflag[3] = 0; +} + +void __cdecl InitL4Triggers() +{ + signed int v0; // edi + int *v1; // esi + int *v2; // edx + TriggerStruct *v3; // ecx + int *v4; // eax + int v5; // edx + int (*v6)[112]; // edi + signed int v7; // ecx + int *v8; // eax + int (*v9)[112]; // [esp+Ch] [ebp-Ch] + int (*v10)[112]; // [esp+Ch] [ebp-Ch] + int v11; // [esp+10h] [ebp-8h] + int (*v12)[112]; // [esp+14h] [ebp-4h] + + trigflag[4] = 0; + v11 = 0; + v9 = dPiece; + do + { + v0 = 0; + v12 = v9; + v1 = &trigs[trigflag[4]]._tmsg; + v2 = &trigs[trigflag[4]]._ty; + v3 = &trigs[trigflag[4]]; + v4 = &trigs[trigflag[4]]._tlvl; + do + { + if ( (*v12)[0] == 83 ) + { + ++trigflag[4]; + v3->_tx = v0; + *v2 = v11; + *v1 = WM_DIABPREVLVL; + v4 += 4; + ++v3; + v2 += 4; + v1 += 4; + } + if ( (*v12)[0] == 422 ) + { + v3->_tx = v0; + *v2 = v11; + *v1 = WM_DIABTWARPUP; + *v4 = 0; + ++trigflag[4]; + v4 += 4; + ++v3; + v2 += 4; + v1 += 4; + } + if ( (*v12)[0] == 120 ) + { + ++trigflag[4]; + v3->_tx = v0; + *v2 = v11; + *v1 = WM_DIABNEXTLVL; + v4 += 4; + ++v3; + v2 += 4; + v1 += 4; + } + ++v12; + ++v0; + } + while ( v0 < 112 ); + v9 = (int (*)[112])((char *)v9 + 4); + ++v11; + } + while ( (signed int)v9 < (signed int)dPiece[1] ); + v5 = 0; + v10 = dPiece; + do + { + v6 = v10; + v7 = 0; + v8 = &trigs[trigflag[4]]._ty; + do + { + if ( (*v6)[0] == 370 && quests[15]._qactive == 3 ) + { + ++trigflag[4]; + *(v8 - 1) = v7; + *v8 = v5; + v8[1] = WM_DIABNEXTLVL; + v8 += 4; + } + ++v7; + ++v6; + } + while ( v7 < 112 ); + v10 = (int (*)[112])((char *)v10 + 4); + ++v5; + } + while ( (signed int)v10 < (signed int)dPiece[1] ); + trigflag[3] = 0; +} + +void __cdecl InitSKingTriggers() +{ + trigflag[3] = 0; + trigflag[4] = 1; + trigs[0]._tx = 82; + trigs[0]._ty = 42; + trigs[0]._tmsg = WM_DIABRTNLVL; +} + +void __cdecl InitSChambTriggers() +{ + trigflag[3] = 0; + trigflag[4] = 1; + trigs[0]._tx = 70; + trigs[0]._ty = 39; + trigs[0]._tmsg = WM_DIABRTNLVL; +} + +void __cdecl InitPWaterTriggers() +{ + trigflag[3] = 0; + trigflag[4] = 1; + trigs[0]._tx = 30; + trigs[0]._ty = 83; + trigs[0]._tmsg = WM_DIABRTNLVL; +} + +void __cdecl InitVPTriggers() +{ + trigflag[3] = 0; + trigflag[4] = 1; + trigs[0]._tx = 35; + trigs[0]._ty = 32; + trigs[0]._tmsg = WM_DIABRTNLVL; +} + +unsigned char __cdecl ForceTownTrig() +{ + int v0; // edx + int *v1; // esi + int v2; // edx + int *v3; // esi + signed int v4; // esi + signed int v5; // edx + + v0 = TownDownList[0]; + if ( TownDownList[0] != -1 ) + { + v1 = TownDownList; + while ( dPiece[0][cursmy + 112 * cursmx] != v0 ) + { + ++v1; + v0 = *v1; + if ( *v1 == -1 ) + goto LABEL_5; + } + strcpy(infostr, "Down to dungeon"); + cursmx = 25; + cursmy = 29; + return 1; + } +LABEL_5: + if ( trigflag[0] ) + { + v2 = TownWarp1List[0]; + if ( TownWarp1List[0] != -1 ) + { + v3 = TownWarp1List; + while ( dPiece[0][cursmy + 112 * cursmx] != v2 ) + { + ++v3; + v2 = *v3; + if ( *v3 == -1 ) + goto LABEL_13; + } + strcpy(infostr, "Down to catacombs"); + cursmx = 49; + cursmy = 21; + return 1; + } + } +LABEL_13: + if ( trigflag[1] ) + { + v4 = 1199; + while ( dPiece[0][cursmy + 112 * cursmx] != v4 ) + { + if ( ++v4 > 1220 ) + goto LABEL_17; + } + strcpy(infostr, "Down to caves"); + cursmx = 17; + cursmy = 69; + return 1; + } +LABEL_17: + if ( trigflag[2] ) + { + v5 = 1240; + while ( dPiece[0][cursmy + 112 * cursmx] != v5 ) + { + if ( ++v5 > 1255 ) + return 0; + } + strcpy(infostr, "Down to hell"); + cursmx = 41; + cursmy = 80; + return 1; + } + return 0; +} + +unsigned char __cdecl ForceL1Trig() +{ + int *v0; // eax + int *v1; // esi + int v2; // eax + int *v3; // edx + int *v4; // eax + int *v5; // esi + int *v6; // edx + int v8; // eax + int v9; // ecx + + if ( L1UpList[0] == -1 ) + { +LABEL_12: + if ( L1DownList[0] == -1 ) + return 0; + v4 = L1DownList; + v5 = L1DownList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v4 ) + { + sprintf(infostr, "Down to level %i", currlevel + 1); + v2 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_19: + ++v5; + v4 = v5; + if ( *v5 == -1 ) + return 0; + } + v6 = &trigs[0]._tmsg; + while ( *v6 != WM_DIABNEXTLVL ) + { + ++v2; + v6 += 4; + if ( v2 >= trigflag[4] ) + goto LABEL_19; + } + } + else + { + v0 = L1UpList; + v1 = L1UpList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v0 ) + { + if ( currlevel <= 1u ) + strcpy(infostr, "Up to town"); + else + sprintf(infostr, "Up to level %i", currlevel - 1); + v2 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_11: + ++v1; + v0 = v1; + if ( *v1 == -1 ) + goto LABEL_12; + } + v3 = &trigs[0]._tmsg; + while ( *v3 != WM_DIABPREVLVL ) + { + ++v2; + v3 += 4; + if ( v2 >= trigflag[4] ) + goto LABEL_11; + } + } + v8 = v2; + v9 = trigs[v8]._tx; + cursmy = trigs[v8]._ty; + cursmx = v9; + return 1; +} + +unsigned char __cdecl ForceL2Trig() +{ + int *v0; // eax + int *v1; // ebp + int v2; // edi + TriggerStruct *v3; // esi + int v4; // ebx + int v5; // eax + int *v6; // eax + int *v7; // esi + int v8; // eax + int *v9; // ecx + int v10; // eax + int v11; // ecx + int v12; // eax + int *v13; // eax + int *v14; // ebp + TriggerStruct *v15; // esi + int v16; // ebx + int v17; // eax + int v19; // edi + + if ( L2UpList[0] == -1 ) + { +LABEL_11: + if ( L2DownList[0] != -1 ) + { + v6 = L2DownList; + v7 = L2DownList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v6 ) + { + sprintf(infostr, "Down to level %i", currlevel + 1); + v8 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_18: + ++v7; + v6 = v7; + if ( *v7 == -1 ) + goto LABEL_22; + } + v9 = &trigs[0]._tmsg; + while ( *v9 != WM_DIABNEXTLVL ) + { + ++v8; + v9 += 4; + if ( v8 >= trigflag[4] ) + goto LABEL_18; + } + v10 = v8; + v11 = trigs[v10]._tx; + v12 = trigs[v10]._ty; + cursmx = v11; + goto LABEL_37; + } +LABEL_22: + if ( currlevel != 5 || L2TWarpUpList[0] == -1 ) + return 0; + v13 = L2TWarpUpList; + v14 = L2TWarpUpList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v13 ) + { + v2 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_32: + ++v14; + v13 = v14; + if ( *v14 == -1 ) + return 0; + } + v15 = trigs; + while ( 1 ) + { + if ( v15->_tmsg == WM_DIABTWARPUP ) + { + v16 = abs(v15->_tx - cursmx); + v17 = abs(v15->_ty - cursmy); + if ( v16 < 4 && v17 < 4 ) + break; + } + ++v2; + ++v15; + if ( v2 >= trigflag[4] ) + goto LABEL_32; + } + strcpy(infostr, "Up to town"); + } + else + { + v0 = L2UpList; + v1 = L2UpList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v0 ) + { + v2 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_10: + ++v1; + v0 = v1; + if ( *v1 == -1 ) + goto LABEL_11; + } + v3 = trigs; + while ( 1 ) + { + if ( v3->_tmsg == WM_DIABPREVLVL ) + { + v4 = abs(v3->_tx - cursmx); + v5 = abs(v3->_ty - cursmy); + if ( v4 < 4 && v5 < 4 ) + break; + } + ++v2; + ++v3; + if ( v2 >= trigflag[4] ) + goto LABEL_10; + } + sprintf(infostr, "Up to level %i", currlevel - 1); + } + v19 = v2; + cursmx = trigs[v19]._tx; + v12 = trigs[v19]._ty; +LABEL_37: + cursmy = v12; + return 1; +} + +unsigned char __cdecl ForceL3Trig() +{ + int *v0; // eax + int *v1; // esi + int v2; // eax + int *v3; // ecx + int *v4; // ecx + int *v5; // esi + int v6; // ecx + int v7; // eax + int *v8; // ecx + int *v9; // eax + int *v10; // ebp + int v11; // edi + TriggerStruct *v12; // esi + int v13; // ebx + int v14; // eax + int v15; // eax + int v16; // ecx + int v17; // eax + int v18; // edi + + if ( L3UpList[0] != -1 ) + { + v0 = L3UpList; + v1 = L3UpList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v0 ) + { + sprintf(infostr, "Up to level %i", currlevel - 1); + v2 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_8: + ++v1; + v0 = v1; + if ( *v1 == -1 ) + goto LABEL_9; + } + v3 = &trigs[0]._tmsg; + while ( *v3 != WM_DIABPREVLVL ) + { + ++v2; + v3 += 4; + if ( v2 >= trigflag[4] ) + goto LABEL_8; + } + goto LABEL_31; + } +LABEL_9: + if ( L3DownList[0] != -1 ) + { + v4 = L3DownList; + v5 = L3DownList; + while ( 1 ) + { + v6 = *v4; + v7 = cursmy + 112 * cursmx; + if ( dPiece[0][v7] == v6 || dPiece[1][v7] == v6 || dPiece[2][v7] == v6 ) + { + sprintf(infostr, "Down to level %i", currlevel + 1); + v2 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_18: + ++v5; + v4 = v5; + if ( *v5 == -1 ) + goto LABEL_19; + } + v8 = &trigs[0]._tmsg; + while ( *v8 != WM_DIABNEXTLVL ) + { + ++v2; + v8 += 4; + if ( v2 >= trigflag[4] ) + goto LABEL_18; + } +LABEL_31: + v15 = v2; + v16 = trigs[v15]._tx; + v17 = trigs[v15]._ty; + cursmx = v16; +LABEL_33: + cursmy = v17; + return 1; + } +LABEL_19: + if ( currlevel == 9 && L3TWarpUpList[0] != -1 ) + { + v9 = L3TWarpUpList; + v10 = L3TWarpUpList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v9 ) + { + v11 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_29: + ++v10; + v9 = v10; + if ( *v10 == -1 ) + return 0; + } + v12 = trigs; + while ( 1 ) + { + if ( v12->_tmsg == WM_DIABTWARPUP ) + { + v13 = abs(v12->_tx - cursmx); + v14 = abs(v12->_ty - cursmy); + if ( v13 < 4 && v14 < 4 ) + break; + } + ++v11; + ++v12; + if ( v11 >= trigflag[4] ) + goto LABEL_29; + } + strcpy(infostr, "Up to town"); + v18 = v11; + cursmx = trigs[v18]._tx; + v17 = trigs[v18]._ty; + goto LABEL_33; + } + return 0; +} + +unsigned char __cdecl ForceL4Trig() +{ + int *v0; // eax + int *v1; // esi + int v2; // eax + int *v3; // ecx + int *v4; // eax + int *v5; // esi + int *v6; // ecx + int *v7; // eax + int *v8; // ebp + int v9; // edi + TriggerStruct *v10; // esi + int v11; // ebx + int v12; // eax + int *v13; // eax + int *v14; // esi + int *v15; // edx + int v16; // edi + int v17; // eax + int v18; // eax + int v19; // ecx + + if ( L4UpList[0] != -1 ) + { + v0 = L4UpList; + v1 = L4UpList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v0 ) + { + sprintf(infostr, "Up to level %i", currlevel - 1); + v2 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_8: + ++v1; + v0 = v1; + if ( *v1 == -1 ) + goto LABEL_9; + } + v3 = &trigs[0]._tmsg; + while ( *v3 != WM_DIABPREVLVL ) + { + ++v2; + v3 += 4; + if ( v2 >= trigflag[4] ) + goto LABEL_8; + } + goto LABEL_39; + } +LABEL_9: + if ( L4DownList[0] != -1 ) + { + v4 = L4DownList; + v5 = L4DownList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v4 ) + { + sprintf(infostr, "Down to level %i", currlevel + 1); + v2 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_16: + ++v5; + v4 = v5; + if ( *v5 == -1 ) + goto LABEL_17; + } + v6 = &trigs[0]._tmsg; + while ( *v6 != WM_DIABNEXTLVL ) + { + ++v2; + v6 += 4; + if ( v2 >= trigflag[4] ) + goto LABEL_16; + } + goto LABEL_39; + } +LABEL_17: + if ( currlevel == 13 ) + { + if ( L4TWarpUpList[0] != -1 ) + { + v7 = L4TWarpUpList; + v8 = L4TWarpUpList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v7 ) + { + v9 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_27: + ++v8; + v7 = v8; + if ( *v8 == -1 ) + goto LABEL_28; + } + v10 = trigs; + while ( 1 ) + { + if ( v10->_tmsg == WM_DIABTWARPUP ) + { + v11 = abs(v10->_tx - cursmx); + v12 = abs(v10->_ty - cursmy); + if ( v11 < 4 && v12 < 4 ) + break; + } + ++v9; + ++v10; + if ( v9 >= trigflag[4] ) + goto LABEL_27; + } + strcpy(infostr, "Up to town"); + v16 = v9; + cursmx = trigs[v16]._tx; + v17 = trigs[v16]._ty; + goto LABEL_40; + } + } + else + { +LABEL_28: + if ( currlevel == 15 && L4PentaList[0] != -1 ) + { + v13 = L4PentaList; + v14 = L4PentaList; + while ( 1 ) + { + if ( dPiece[0][cursmy + 112 * cursmx] == *v13 ) + { + strcpy(infostr, "Down to Diablo"); + v2 = 0; + if ( trigflag[4] > 0 ) + break; + } +LABEL_36: + ++v14; + v13 = v14; + if ( *v14 == -1 ) + return 0; + } + v15 = &trigs[0]._tmsg; + while ( *v15 != WM_DIABNEXTLVL ) + { + ++v2; + v15 += 4; + if ( v2 >= trigflag[4] ) + goto LABEL_36; + } +LABEL_39: + v18 = v2; + v19 = trigs[v18]._tx; + v17 = trigs[v18]._ty; + cursmx = v19; +LABEL_40: + cursmy = v17; + return 1; + } + } + return 0; +} + +void __cdecl Freeupstairs() +{ + int *v0; // ecx + int v1; // ebx + char *v2; // eax + signed int v3; // edi + char *v4; // edx + signed int v5; // esi + + if ( trigflag[4] > 0 ) + { + v0 = &trigs[0]._ty; + v1 = trigflag[4]; + do + { + v2 = &dFlags[*(v0 - 1)-2][*v0-2]; /* v2 = &nBlockTable[112 * *(v0 - 1) + 1830 + *v0]; check */ + v3 = 5; + do + { + v4 = v2; + v5 = 5; + do + { + *v4 |= 8u; + v4 += 112; + --v5; + } + while ( v5 ); + ++v2; + --v3; + } + while ( v3 ); + v0 += 4; + --v1; + } + while ( v1 ); + } +} + +unsigned char __cdecl ForceSKingTrig() +{ + int v0; // eax + int *v1; // ecx + + v0 = L1UpList[0]; + if ( L1UpList[0] == -1 ) + return 0; + v1 = L1UpList; + while ( dPiece[0][cursmy + 112 * cursmx] != v0 ) + { + ++v1; + v0 = *v1; + if ( *v1 == -1 ) + return 0; + } + sprintf(infostr, "Back to Level %i", (unsigned char)quests[12]._qlevel); + cursmx = trigs[0]._tx; + cursmy = trigs[0]._ty; + return 1; +} + +unsigned char __cdecl ForceSChambTrig() +{ + int v0; // eax + int *v1; // ecx + + v0 = L2DownList[0]; + if ( L2DownList[0] == -1 ) + return 0; + v1 = L2DownList; + while ( dPiece[0][cursmy + 112 * cursmx] != v0 ) + { + ++v1; + v0 = *v1; + if ( *v1 == -1 ) + return 0; + } + sprintf(infostr, "Back to Level %i", (unsigned char)quests[14]._qlevel); + cursmx = trigs[0]._tx; + cursmy = trigs[0]._ty; + return 1; +} + +unsigned char __cdecl ForcePWaterTrig() +{ + int v0; // eax + int *v1; // ecx + + v0 = L3DownList[0]; + if ( L3DownList[0] == -1 ) + return 0; + v1 = L3DownList; + while ( dPiece[0][cursmy + 112 * cursmx] != v0 ) + { + ++v1; + v0 = *v1; + if ( *v1 == -1 ) + return 0; + } + sprintf(infostr, "Back to Level %i", (unsigned char)quests[13]._qlevel); + cursmx = trigs[0]._tx; + cursmy = trigs[0]._ty; + return 1; +} + +void __cdecl CheckTrigForce() +{ + int v0; // eax + int v1; // eax + + trigflag[3] = 0; + if ( MouseY <= 351 ) + { + if ( setlevel ) + { + switch ( setlvlnum ) + { + case SL_SKELKING: + v1 = ForceSKingTrig(); + break; + case SL_BONECHAMB: + v1 = ForceSChambTrig(); + break; + case SL_POISONWATER: + v1 = ForcePWaterTrig(); + break; + default: + return; + } + goto LABEL_23; + } + if ( leveltype ) + { + switch ( leveltype ) + { + case DTYPE_CATHEDRAL: + v0 = ForceL1Trig(); + break; + case DTYPE_CATACOMBS: + v0 = ForceL2Trig(); + break; + case DTYPE_CAVES: + v0 = ForceL3Trig(); + break; + case DTYPE_HELL: + v0 = ForceL4Trig(); + break; + default: +LABEL_14: + if ( leveltype == DTYPE_TOWN ) + goto LABEL_24; + if ( trigflag[3] ) + { +LABEL_25: + ClearPanel(); + return; + } + v1 = ForceQuests(); +LABEL_23: + trigflag[3] = v1; +LABEL_24: + if ( !trigflag[3] ) + return; + goto LABEL_25; + } + } + else + { + v0 = ForceTownTrig(); + } + trigflag[3] = v0; + goto LABEL_14; + } +} +// 5BB1ED: using guessed type char leveltype; +// 5CCB10: using guessed type char setlvlnum; +// 5CF31D: using guessed type char setlevel; + +void __cdecl CheckTriggers() +{ + int *v0; // edi + int v1; // esi + int v2; // ecx + int v3; // eax + int v4; // edx + signed int v5; // edx + int v6; // eax + char v7; // al + int v8; // ecx + int v9; // [esp-4h] [ebp-20h] + int x; // [esp+Ch] [ebp-10h] + int y; // [esp+10h] [ebp-Ch] + int v12; // [esp+14h] [ebp-8h] + int error_id; // [esp+1Bh] [ebp-1h] + + if ( plr[myplr]._pmode ) + return; + v12 = 0; + if ( trigflag[4] <= 0 ) + return; + v0 = &trigs[0]._tmsg; + while ( 1 ) + { + v1 = myplr; + v2 = plr[myplr].WorldX; + if ( v2 != *(v0 - 2) ) + goto LABEL_34; + v3 = plr[v1].WorldY; + if ( v3 != *(v0 - 1) ) + goto LABEL_34; + v4 = *v0; + if ( *v0 == WM_DIABNEXTLVL ) + { + if ( pcurs >= CURSOR_FIRSTITEM && DropItemBeforeTrig() ) + return; + v6 = currlevel + 1; + goto LABEL_32; + } + if ( *v0 == WM_DIABPREVLVL ) + { + if ( pcurs >= CURSOR_FIRSTITEM && DropItemBeforeTrig() ) + return; + v6 = currlevel - 1; +LABEL_32: + v9 = v6; + goto LABEL_33; + } + if ( *v0 != WM_DIABRTNLVL ) + break; + StartNewLvl(myplr, v4, ReturnLvl); +LABEL_34: + ++v12; + v0 += 4; + if ( v12 >= trigflag[4] ) + return; + } + if ( *v0 != WM_DIABTOWNWARP ) + { + if ( *v0 == WM_DIABTWARPUP ) + { + TWarpFrom = currlevel; + StartNewLvl(myplr, v4, 0); + } + else + { + TermMsg("Unknown trigger msg"); + } + goto LABEL_34; + } + if ( gbMaxPlayers == 1 ) + goto LABEL_46; + v5 = 0; + if ( v0[1] == 5 && plr[v1]._pLevel < 8 ) + { + v5 = 1; + x = plr[myplr].WorldX; + _LOBYTE(y) = v3 + 1; + _LOBYTE(error_id) = 40; + } + if ( v0[1] == 9 && plr[v1]._pLevel < 13 ) + { + v5 = 1; + _LOBYTE(x) = v2 + 1; + y = plr[v1].WorldY; + _LOBYTE(error_id) = 41; + } + if ( v0[1] == 13 && plr[v1]._pLevel < 17 ) + { + x = plr[myplr].WorldX; + v5 = 1; + _LOBYTE(y) = v3 + 1; + _LOBYTE(error_id) = 42; + } + if ( !v5 ) + { +LABEL_46: + v9 = v0[1]; +LABEL_33: + StartNewLvl(myplr, *v0, v9); + goto LABEL_34; + } + v7 = plr[myplr]._pClass; + switch ( v7 ) + { + case UI_WARRIOR: + v8 = PS_WARR43; + goto LABEL_42; + case UI_ROGUE: + v8 = PS_ROGUE43; + goto LABEL_42; + case UI_SORCERER: + v8 = PS_MAGE43; +LABEL_42: + PlaySFX(v8); + break; + } + _LOBYTE(v2) = error_id; + InitDiabloMsg(v2); + NetSendCmdLoc(1u, 1u, x, y); +} +// 679660: using guessed type char gbMaxPlayers; +// 6ABB30: using guessed type int TWarpFrom; diff --git a/Source/trigs.h b/Source/trigs.h new file mode 100644 index 000000000..bfdbbd5f0 --- /dev/null +++ b/Source/trigs.h @@ -0,0 +1,48 @@ +//HEADER_GOES_HERE +#ifndef __TRIGS_H__ +#define __TRIGS_H__ + +extern int trigflag[MAXTRIGGERS]; +extern TriggerStruct trigs[MAXTRIGGERS]; +extern int TWarpFrom; // weak + +void __cdecl InitNoTriggers(); +void __cdecl InitTownTriggers(); +void __cdecl InitL1Triggers(); +void __cdecl InitL2Triggers(); +void __cdecl InitL3Triggers(); +void __cdecl InitL4Triggers(); +void __cdecl InitSKingTriggers(); +void __cdecl InitSChambTriggers(); +void __cdecl InitPWaterTriggers(); +void __cdecl InitVPTriggers(); +unsigned char __cdecl ForceTownTrig(); +unsigned char __cdecl ForceL1Trig(); +unsigned char __cdecl ForceL2Trig(); +unsigned char __cdecl ForceL3Trig(); +unsigned char __cdecl ForceL4Trig(); +void __cdecl Freeupstairs(); +unsigned char __cdecl ForceSKingTrig(); +unsigned char __cdecl ForceSChambTrig(); +unsigned char __cdecl ForcePWaterTrig(); +void __cdecl CheckTrigForce(); +void __cdecl CheckTriggers(); + +/* rdata */ + +extern int TownDownList[11]; +extern int TownWarp1List[13]; +extern int L1UpList[12]; +extern int L1DownList[10]; +extern int L2UpList[3]; +extern int L2DownList[5]; +extern int L2TWarpUpList[3]; +extern int L3UpList[15]; +extern int L3DownList[9]; +extern int L3TWarpUpList[14]; +extern int L4UpList[4]; +extern int L4DownList[6]; +extern int L4TWarpUpList[4]; +extern int L4PentaList[33]; + +#endif /* __TRIGS_H__ */ diff --git a/Source/wave.cpp b/Source/wave.cpp new file mode 100644 index 000000000..cbb1fb3c8 --- /dev/null +++ b/Source/wave.cpp @@ -0,0 +1,315 @@ +//HEADER_GOES_HERE + +#include "../types.h" + +int wave_cpp_init_value; // weak + +const int wave_inf = 0x7F800000; // weak + +struct wave_cpp_init +{ + wave_cpp_init() + { + wave_cpp_init_value = wave_inf; + } +} _wave_cpp_init; +// 4802D4: using guessed type int wave_inf; +// 6ABB34: using guessed type int wave_cpp_init_value; + +bool __fastcall WCloseFile(void *file) +{ + return SFileCloseFile(file); +} + +int __fastcall WGetFileSize(HANDLE hsFile, unsigned long *a2) +{ + unsigned long *v2; // edi + HANDLE i; // esi + int result; // eax + int a2a; // [esp+8h] [ebp-4h] + + a2a = 0; + v2 = a2; + for ( i = hsFile; ; WGetFileArchive(i, &a2a, 0) ) + { + result = SFileGetFileSize(i, v2); + if ( result ) + break; + } + return result; +} + +void __fastcall WGetFileArchive(HANDLE hsFile, int *a2, char *dwInitParam) +{ + int *v3; // esi + HANDLE v4; // edi + //int v5; // eax + //int v6; // eax + HANDLE archive; // [esp+8h] [ebp-4h] + + v3 = a2; + v4 = hsFile; + if ( (unsigned int)*a2 >= 5 ) + FileErrDlg(dwInitParam); + if ( v4 && SFileGetFileArchive(v4, &archive) && archive != diabdat_mpq ) + { + Sleep(0x14u); + ++*v3; + } + else + { + //_LOBYTE(v6) = InsertCDDlg(); + if ( !InsertCDDlg() ) + FileErrDlg(dwInitParam); + } +} + +int __fastcall WOpenFile(char *dwInitParam, HANDLE *phsFile, int a3) +{ + HANDLE *v3; // edi + char *i; // esi +// int v5; // eax + int a2a; // [esp+8h] [ebp-4h] + + a2a = 0; + v3 = phsFile; + for ( i = dwInitParam; ; WGetFileArchive(0, &a2a, i) ) + { + //_LOBYTE(v5) = SFileOpenFile(i, v3); + if ( SFileOpenFile(i, v3) ) + return 1; + if ( a3 && SErrGetLastError() == 2 ) + break; + } + return 0; +} + +char __fastcall WReadFile(HANDLE hsFile, char *buf, int a3) +{ + char *v3; // ebx + HANDLE v4; // edi + int v5; // eax + int nread; // [esp+Ch] [ebp-Ch] + int offset; // [esp+10h] [ebp-8h] + int a2a; // [esp+14h] [ebp-4h] + + v3 = buf; + v4 = hsFile; + a2a = 0; + for ( offset = WSetFilePointer(hsFile, 0, 0, 1); ; WSetFilePointer(v4, offset, 0, 0) ) + { + v5 = SFileReadFile(v4, v3, a3, (unsigned long *)&nread, 0); + if ( v5 ) + break; + WGetFileArchive(v4, &a2a, 0); + } + return v5; +} + +int __fastcall WSetFilePointer(HANDLE file1, int offset, HANDLE file2, int whence) +{ + int v4; // edi + HANDLE i; // esi + int result; // eax + int a2; // [esp+8h] [ebp-4h] + + a2 = 0; + v4 = offset; + for ( i = file1; ; WGetFileArchive(i, &a2, 0) ) + { + result = SFileSetFilePointer(i, v4, file2, whence); + if ( result != -1 ) + break; + } + return result; +} + +int __fastcall LoadWaveFormat(HANDLE hsFile, WAVEFORMATEX *pwfx) +{ + WAVEFORMATEX *v2; // esi + int v3; // esi + MEMFILE wave_file; // [esp+4h] [ebp-1Ch] + + v2 = pwfx; + AllocateMemFile(hsFile, &wave_file, 0); + v3 = ReadWaveFile(&wave_file, v2, 0); + FreeMemFile(&wave_file); + return v3; +} + +void *__fastcall AllocateMemFile(HANDLE hsFile, MEMFILE *pMemFile, unsigned int dwPos) +{ + MEMFILE *v3; // esi + HANDLE v4; // edi + unsigned int v5; // eax + unsigned int v6; // ecx + void *result; // eax + + v3 = pMemFile; + v4 = hsFile; + memset(pMemFile, 0, 0x1Cu); + v5 = WGetFileSize(v4, 0); + v6 = 4096; + v3->end = v5; + if ( dwPos > 0x1000 ) + v6 = dwPos; + v3->buf_len = v6; + if ( v6 >= v5 ) + v6 = v5; + v3->buf_len = v6; + result = DiabloAllocPtr(v6); + v3->file = (int)v4; + v3->buf = (char *)result; + return result; +} + +void __fastcall FreeMemFile(MEMFILE *pMemFile) +{ + MEMFILE *v1; // eax + char *v2; // ecx + + v1 = pMemFile; + v2 = pMemFile->buf; + v1->buf = 0; + mem_free_dbg(v2); +} + +int __fastcall ReadWaveFile(MEMFILE *pMemFile, WAVEFORMATEX *pwfx, int *a3) +{ + WAVEFORMATEX *v3; // esi + MEMFILE *v4; // edi + WORD v5; // ax + int result; // eax + int a2a[5]; // [esp+8h] [ebp-2Ch] + PCMWAVEFORMAT v8; // [esp+1Ch] [ebp-18h] + int v9[2]; // [esp+2Ch] [ebp-8h] + + v3 = pwfx; + v4 = pMemFile; + if ( !ReadMemFile(pMemFile, a2a, 0xCu) + || a2a[0] != 'FFIR' + || a2a[2] != 'EVAW' + || !ReadWaveSection(v4, ' tmf', v9) + || v9[0] < 0x10u + || !ReadMemFile(v4, &v8, 0x10u) + || SeekMemFile(v4, v9[0] - 16, FILE_CURRENT) == -1 ) + { + return 0; + } + v5 = v8.wf.wFormatTag; + v3->cbSize = 0; + v3->wFormatTag = v5; + v3->nChannels = v8.wf.nChannels; + v3->nSamplesPerSec = v8.wf.nSamplesPerSec; + v3->nAvgBytesPerSec = v8.wf.nAvgBytesPerSec; + v3->nBlockAlign = v8.wf.nBlockAlign; + v3->wBitsPerSample = v8.wBitsPerSample; + if ( a3 ) + result = ReadWaveSection(v4, 'atad', a3); + else + result = 1; + return result; +} + +int __fastcall ReadMemFile(MEMFILE *pMemFile, void *lpBuf, size_t a3) +{ + size_t v3; // ebx + void *v4; // ebp + MEMFILE *v5; // esi + size_t v6; // edi + + v3 = a3; + v4 = lpBuf; + v5 = pMemFile; + if ( !a3 ) + return 1; + while ( 1 ) + { + if ( !v5->bytes_to_read ) + FillMemFile(v5); + v6 = v5->bytes_to_read; + if ( v3 < v6 ) + v6 = v3; + if ( !v6 ) + break; + memcpy(v4, &v5->buf[v5->dist], v6); + v5->offset += v6; + v5->dist += v6; + v5->bytes_to_read -= v6; + v3 -= v6; + if ( !v3 ) + return 1; + } + return 0; +} + +void __fastcall FillMemFile(MEMFILE *pMemFile) +{ + MEMFILE *v1; // esi + unsigned int v2; // edi + + v1 = pMemFile; + WSetFilePointer((HANDLE)pMemFile->file, pMemFile->offset, 0, 0); + v2 = v1->end - v1->offset; + if ( v1->buf_len < v2 ) + v2 = v1->buf_len; + if ( v2 ) + WReadFile((HANDLE)v1->file, v1->buf, v2); + v1->dist = 0; + v1->bytes_to_read = v2; +} + +int __fastcall SeekMemFile(MEMFILE *pMemFile, unsigned int lDist, int dwMethod) +{ + unsigned int v3; // eax + + v3 = pMemFile->bytes_to_read; + if ( lDist >= v3 ) + { + pMemFile->bytes_to_read = 0; + } + else + { + pMemFile->dist += lDist; + pMemFile->bytes_to_read = v3 - lDist; + } + pMemFile->offset += lDist; + return pMemFile->offset; +} + +int __fastcall ReadWaveSection(MEMFILE *pMemFile, int a2, int *a3) +{ + int v3; // esi + MEMFILE *v4; // edi + int v6; // eax + int a2a[2]; // [esp+8h] [ebp-8h] + + v3 = a2; + v4 = pMemFile; + while ( 1 ) + { + if ( !ReadMemFile(v4, a2a, 8u) ) + return 0; + if ( a2a[0] == v3 ) + break; + if ( SeekMemFile(v4, a2a[1], FILE_CURRENT) == -1 ) + return 0; + } + *a3 = a2a[1]; + v6 = SeekMemFile(v4, 0, FILE_CURRENT); + a3[1] = v6; + return v6 != -1; +} + +void *__fastcall LoadWaveFile(HANDLE hsFile, WAVEFORMATEX *pwfx, int *a3) +{ + WAVEFORMATEX *v3; // esi + MEMFILE wave_file; // [esp+4h] [ebp-1Ch] + + v3 = pwfx; + AllocateMemFile(hsFile, &wave_file, 0xFFFFFFFF); + if ( ReadWaveFile(&wave_file, v3, a3) ) + return wave_file.buf; + FreeMemFile(&wave_file); + return 0; +} diff --git a/Source/wave.h b/Source/wave.h new file mode 100644 index 000000000..cc8211d11 --- /dev/null +++ b/Source/wave.h @@ -0,0 +1,30 @@ +//HEADER_GOES_HERE +#ifndef __WAVE_H__ +#define __WAVE_H__ + +extern int wave_cpp_init_value; // weak +//int dword_6ABB9C; // weak + +void __cdecl wave_cpp_init(); +bool __fastcall WCloseFile(void *file); +int __fastcall WGetFileSize(HANDLE hsFile, unsigned long *a2); +void __fastcall WGetFileArchive(HANDLE hsFile, int *a2, char *dwInitParam); +int __fastcall WOpenFile(char *dwInitParam, HANDLE *phsFile, int a3); +char __fastcall WReadFile(HANDLE hsFile, char *buf, int a3); +int __fastcall WSetFilePointer(HANDLE file1, int offset, HANDLE file2, int whence); +int __fastcall LoadWaveFormat(HANDLE hsFile, WAVEFORMATEX *pwfx); +void *__fastcall AllocateMemFile(HANDLE hsFile, MEMFILE *pMemFile, unsigned int dwPos); +void __fastcall FreeMemFile(MEMFILE *pMemFile); +int __fastcall ReadWaveFile(MEMFILE *pMemFile, WAVEFORMATEX *pwfx, int *a3); +int __fastcall ReadMemFile(MEMFILE *pMemFile, void *lpBuf, size_t a3); +void __fastcall FillMemFile(MEMFILE *pMemFile); +int __fastcall SeekMemFile(MEMFILE *pMemFile, unsigned int lDist, int dwMethod); +int __fastcall ReadWaveSection(MEMFILE *pMemFile, int a2, int *a3); +void *__fastcall LoadWaveFile(HANDLE hsFile, WAVEFORMATEX *pwfx, int *a3); +void __fastcall j_engine_mem_free(void *ptr); + +/* rdata */ + +extern const int wave_inf; // weak + +#endif /* __WAVE_H__ */ diff --git a/Stub/.clang-format b/Stub/.clang-format new file mode 100644 index 000000000..f54edb9db --- /dev/null +++ b/Stub/.clang-format @@ -0,0 +1,14 @@ +--- +IndentWidth: 4 +TabWidth: 4 +--- +Language: Cpp +UseTab: ForIndentation +AlignTrailingComments: false +BreakBeforeBraces: Linux +ColumnLimit: 120 +IncludeBlocks: Preserve +AlignEscapedNewlines: DontAlign +AlignOperands: true +AllowShortFunctionsOnASingleLine: Inline +Standard: Cpp11 diff --git a/Stub/SDL_FontCache.cpp b/Stub/SDL_FontCache.cpp new file mode 100644 index 000000000..4325c45a1 --- /dev/null +++ b/Stub/SDL_FontCache.cpp @@ -0,0 +1,2639 @@ +/* +SDL_FontCache: A font cache for SDL and SDL_ttf +by Jonathan Dearborn + +See SDL_FontCache.h for license info. +*/ + +#include "SDL_FontCache.h" + +#include +#include +#include + +// Visual C does not support static inline +#ifndef static_inline +#ifdef _MSC_VER +#define static_inline static +#else +#define static_inline static inline +#endif +#endif + +#if SDL_VERSION_ATLEAST(2,0,0) +#define FC_GET_ALPHA(sdl_color) ((sdl_color).a) +#else +#define FC_GET_ALPHA(sdl_color) ((sdl_color).unused) +#endif + +// Need SDL_RenderIsClipEnabled() for proper clipping support +#if SDL_VERSION_ATLEAST(2,0,4) +#define ENABLE_SDL_CLIPPING +#endif + +#define FC_MIN(a,b) ((a) < (b)? (a) : (b)) +#define FC_MAX(a,b) ((a) > (b)? (a) : (b)) + + +// vsnprintf replacement from Valentin Milea: +// http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#define snprintf c99_snprintf +#define vsnprintf c99_vsnprintf + +__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + + return count; +} + +#endif + + +#define FC_EXTRACT_VARARGS(buffer, start_args) \ +{ \ + va_list lst; \ + va_start(lst, start_args); \ + vsnprintf(buffer, fc_buffer_size, start_args, lst); \ + va_end(lst); \ +} + +// Extra pixels of padding around each glyph to avoid linear filtering artifacts +#define FC_CACHE_PADDING 1 + + + +static Uint8 has_clip(FC_Target* dest) +{ +#ifdef FC_USE_SDL_GPU + return dest->use_clip_rect; +#elif defined(ENABLE_SDL_CLIPPING) + return SDL_RenderIsClipEnabled(dest); +#else + return 0; +#endif +} + +static FC_Rect get_clip(FC_Target* dest) +{ +#ifdef FC_USE_SDL_GPU + return dest->clip_rect; +#elif defined(ENABLE_SDL_CLIPPING) + SDL_Rect r; + SDL_RenderGetClipRect(dest, &r); + return r; +#else + SDL_Rect r = { 0, 0, 0, 0 }; + return r; +#endif +} + +static void set_clip(FC_Target* dest, FC_Rect* rect) +{ +#ifdef FC_USE_SDL_GPU + if (rect != NULL) + GPU_SetClipRect(dest, *rect); + else + GPU_UnsetClip(dest); +#elif defined(ENABLE_SDL_CLIPPING) + SDL_RenderSetClipRect(dest, rect); +#endif +} + +static void set_color(FC_Image* src, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ +#ifdef FC_USE_SDL_GPU + GPU_SetRGBA(src, r, g, b, a); +#else + SDL_SetTextureColorMod(src, r, g, b); + SDL_SetTextureAlphaMod(src, a); +#endif +} + + + +static char* new_concat(const char* a, const char* b) +{ + // Create new buffer + unsigned int size = strlen(a) + strlen(b); + char* new_string = (char*)malloc(size + 1); + + // Concatenate strings in the new buffer + strcpy(new_string, a); + strcat(new_string, b); + + return new_string; +} + +static char* replace_concat(char** a, const char* b) +{ + char* new_string = new_concat(*a, b); + free(*a); + *a = new_string; + return *a; +} + + + + + +// Shared buffer for variadic text +static char* fc_buffer = NULL; +static unsigned int fc_buffer_size = 1024; + +static Uint8 fc_has_render_target_support = 0; + +char* FC_GetStringASCII(void) +{ + static char* buffer = NULL; + if (buffer == NULL) + { + int i; + char c; + buffer = (char*)malloc(512); + memset(buffer, 0, 512); + i = 0; + c = 32; + while (1) + { + buffer[i] = c; + if (c == 126) + break; + ++i; + ++c; + } + } + return U8_strdup(buffer); +} + +char* FC_GetStringLatin1(void) +{ + static char* buffer = NULL; + if (buffer == NULL) + { + int i; + unsigned char c; + buffer = (char*)malloc(512); + memset(buffer, 0, 512); + i = 0; + c = 0xA0; + while (1) + { + buffer[i] = 0xC2; + buffer[i + 1] = c; + if (c == 0xBF) + break; + i += 2; + ++c; + } + i += 2; + c = 0x80; + while (1) + { + buffer[i] = 0xC3; + buffer[i + 1] = c; + if (c == 0xBF) + break; + i += 2; + ++c; + } + } + return U8_strdup(buffer); +} + +char* FC_GetStringASCII_Latin1(void) +{ + static char* buffer = NULL; + if (buffer == NULL) + buffer = new_concat(FC_GetStringASCII(), FC_GetStringLatin1()); + + return U8_strdup(buffer); +} + +FC_Rect FC_MakeRect(float x, float y, float w, float h) +{ + FC_Rect r = { x, y, w, h }; + return r; +} + +FC_Scale FC_MakeScale(float x, float y) +{ + FC_Scale s = { x, y }; + + return s; +} + +SDL_Color FC_MakeColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + SDL_Color c = { r, g, b, a }; + + return c; +} + +FC_Effect FC_MakeEffect(FC_AlignEnum alignment, FC_Scale scale, SDL_Color color) +{ + FC_Effect e; + + e.alignment = alignment; + e.scale = scale; + e.color = color; + + return e; +} + +FC_GlyphData FC_MakeGlyphData(int cache_level, Sint16 x, Sint16 y, Uint16 w, Uint16 h) +{ + FC_GlyphData gd; + + gd.rect.x = x; + gd.rect.y = y; + gd.rect.w = w; + gd.rect.h = h; + gd.cache_level = cache_level; + + return gd; +} + +// Enough to hold all of the ascii characters and some. +#define FC_DEFAULT_NUM_BUCKETS 300 + +typedef struct FC_MapNode +{ + Uint32 key; + FC_GlyphData value; + struct FC_MapNode* next; + +} FC_MapNode; + +typedef struct FC_Map +{ + int num_buckets; + FC_MapNode** buckets; +} FC_Map; + + + +static FC_Map* FC_MapCreate(int num_buckets) +{ + int i; + FC_Map* map = (FC_Map*)malloc(sizeof(FC_Map)); + + map->num_buckets = num_buckets; + map->buckets = (FC_MapNode**)malloc(num_buckets * sizeof(FC_MapNode*)); + + for (i = 0; i < num_buckets; ++i) + { + map->buckets[i] = NULL; + } + + return map; +} + +/*static void FC_MapClear(FC_Map* map) +{ +int i; +if(map == NULL) +return; + +// Go through each bucket +for(i = 0; i < map->num_buckets; ++i) +{ +// Delete the nodes in order +FC_MapNode* node = map->buckets[i]; +while(node != NULL) +{ +FC_MapNode* last = node; +node = node->next; +free(last); +} +// Set the bucket to empty +map->buckets[i] = NULL; +} +}*/ + +static void FC_MapFree(FC_Map* map) +{ + int i; + if (map == NULL) + return; + + // Go through each bucket + for (i = 0; i < map->num_buckets; ++i) + { + // Delete the nodes in order + FC_MapNode* node = map->buckets[i]; + while (node != NULL) + { + FC_MapNode* last = node; + node = node->next; + free(last); + } + } + + free(map->buckets); + free(map); +} + +// Note: Does not handle duplicates in any special way. +static FC_GlyphData* FC_MapInsert(FC_Map* map, Uint32 codepoint, FC_GlyphData glyph) +{ + Uint32 index; + FC_MapNode* node; + if (map == NULL) + return NULL; + + // Get index for bucket + index = codepoint % map->num_buckets; + + // If this bucket is empty, create a node and return its value + if (map->buckets[index] == NULL) + { + node = map->buckets[index] = (FC_MapNode*)malloc(sizeof(FC_MapNode)); + node->key = codepoint; + node->value = glyph; + node->next = NULL; + return &node->value; + } + + for (node = map->buckets[index]; node != NULL; node = node->next) + { + // Find empty node and add a new one on. + if (node->next == NULL) + { + node->next = (FC_MapNode*)malloc(sizeof(FC_MapNode)); + node = node->next; + + node->key = codepoint; + node->value = glyph; + node->next = NULL; + return &node->value; + } + } + + return NULL; +} + +static FC_GlyphData* FC_MapFind(FC_Map* map, Uint32 codepoint) +{ + Uint32 index; + FC_MapNode* node; + if (map == NULL) + return NULL; + + // Get index for bucket + index = codepoint % map->num_buckets; + + // Go through list until we find a match + for (node = map->buckets[index]; node != NULL; node = node->next) + { + if (node->key == codepoint) + return &node->value; + } + + return NULL; +} + + + +struct FC_Font +{ +#ifndef FC_USE_SDL_GPU + SDL_Renderer* renderer; +#endif + + TTF_Font* ttf_source; // TTF_Font source of characters + Uint8 owns_ttf_source; // Can we delete the TTF_Font ourselves? + + FC_FilterEnum filter; + + SDL_Color default_color; + Uint16 height; + + Uint16 maxWidth; + Uint16 baseline; + int ascent; + int descent; + + int lineSpacing; + int letterSpacing; + + // Uses 32-bit (4-byte) Unicode codepoints to refer to each glyph + // Codepoints are little endian (reversed from UTF-8) so that something like 0x00000005 is ASCII 5 and the map can be indexed by ASCII values + FC_Map* glyphs; + + FC_GlyphData last_glyph; // Texture packing cursor + int glyph_cache_size; + int glyph_cache_count; + FC_Image** glyph_cache; + + char* loading_string; + +}; + +// Private +static FC_GlyphData* FC_PackGlyphData(FC_Font* font, Uint32 codepoint, Uint16 width, Uint16 maxWidth, Uint16 maxHeight); + + +static FC_Rect FC_RenderLeft(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text); +static FC_Rect FC_RenderCenter(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text); +static FC_Rect FC_RenderRight(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text); + + +static_inline SDL_Surface* FC_CreateSurface32(Uint32 width, Uint32 height) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); +#else + return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); +#endif +} + + +char* U8_alloc(unsigned int size) +{ + char* result; + if (size == 0) + return NULL; + + result = (char*)malloc(size); + result[0] = '\0'; + + return result; +} + +void U8_free(char* string) +{ + free(string); +} + +char* U8_strdup(const char* string) +{ + char* result; + if (string == NULL) + return NULL; + + result = (char*)malloc(strlen(string) + 1); + strcpy(result, string); + + return result; +} + +int U8_strlen(const char* string) +{ + int length = 0; + if (string == NULL) + return 0; + + while (*string != '\0') + { + string = U8_next(string); + ++length; + } + + return length; +} + +int U8_charsize(const char* character) +{ + if (character == NULL) + return 0; + + if ((unsigned char)*character <= 0x7F) + return 1; + else if ((unsigned char)*character < 0xE0) + return 2; + else if ((unsigned char)*character < 0xF0) + return 3; + else + return 4; + return 1; +} + +int U8_charcpy(char* buffer, const char* source, int buffer_size) +{ + int charsize; + if (buffer == NULL || source == NULL || buffer_size < 1) + return 0; + + charsize = U8_charsize(source); + if (charsize > buffer_size) + return 0; + + memcpy(buffer, source, charsize); + return charsize; +} + +const char* U8_next(const char* string) +{ + return string + U8_charsize(string); +} + +int U8_strinsert(char* string, int position, const char* source, int max_bytes) +{ + int pos_bytes; + int len; + int add_len; + int ulen; + + if (string == NULL || source == NULL) + return 0; + + len = strlen(string); + add_len = strlen(source); + ulen = U8_strlen(string); + + if (position == -1) + position = ulen; + + if (position < 0 || position > ulen || len + add_len + 1 > max_bytes) + return 0; + + // Move string pointer to the proper position + pos_bytes = 0; + while (*string != '\0' && pos_bytes < position) + { + string = (char*)U8_next(string); + ++pos_bytes; + } + + // Move the rest of the string out of the way + memmove(string + add_len, string, len - pos_bytes + 1); + + // Copy in the new characters + memcpy(string, source, add_len); + + return 1; +} + +void U8_strdel(char* string, int position) +{ + if (string == NULL || position < 0) + return; + + while (*string != '\0') + { + if (position == 0) + { + int chars_to_erase = U8_charsize(string); + int remaining_bytes = strlen(string) + 1; + memmove(string, string + chars_to_erase, remaining_bytes); + break; + } + + string = (char*)U8_next(string); + --position; + } +} + + + + + +static_inline FC_Rect FC_RectUnion(FC_Rect A, FC_Rect B) +{ + float x, x2, y, y2; + x = FC_MIN(A.x, B.x); + y = FC_MIN(A.y, B.y); + x2 = FC_MAX(A.x + A.w, B.x + B.w); + y2 = FC_MAX(A.y + A.h, B.y + B.h); + { + FC_Rect result = { x, y, FC_MAX(0, x2 - x), FC_MAX(0, y2 - y) }; + return result; + } +} + +// Adapted from SDL_IntersectRect +static_inline FC_Rect FC_RectIntersect(FC_Rect A, FC_Rect B) +{ + FC_Rect result; + float Amin, Amax, Bmin, Bmax; + + // Horizontal intersection + Amin = A.x; + Amax = Amin + A.w; + Bmin = B.x; + Bmax = Bmin + B.w; + if (Bmin > Amin) + Amin = Bmin; + result.x = Amin; + if (Bmax < Amax) + Amax = Bmax; + result.w = Amax - Amin > 0 ? Amax - Amin : 0; + + // Vertical intersection + Amin = A.y; + Amax = Amin + A.h; + Bmin = B.y; + Bmax = Bmin + B.h; + if (Bmin > Amin) + Amin = Bmin; + result.y = Amin; + if (Bmax < Amax) + Amax = Bmax; + result.h = Amax - Amin > 0 ? Amax - Amin : 0; + + return result; +} + + + + + + + + + + + + + + +FC_Rect FC_DefaultRenderCallback(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale) +{ + float w = srcrect->w * xscale; + float h = srcrect->h * yscale; + FC_Rect result; + + // FIXME: Why does the scaled offset look so wrong? +#ifdef FC_USE_SDL_GPU + { + GPU_Rect r = *srcrect; + GPU_BlitScale(src, &r, dest, x + xscale*r.w / 2.0f, y + r.h / 2.0f, xscale, yscale); + } +#else + { + SDL_RendererFlip flip = SDL_FLIP_NONE; + if (xscale < 0) + { + xscale = -xscale; + flip = (SDL_RendererFlip)((int)flip | (int)SDL_FLIP_HORIZONTAL); + } + if (yscale < 0) + { + yscale = -yscale; + flip = (SDL_RendererFlip)((int)flip | (int)SDL_FLIP_VERTICAL); + } + + SDL_Rect r = *srcrect; + SDL_Rect dr = { (int)x, (int)y, (int)(xscale*r.w), (int)(yscale*r.h) }; + SDL_RenderCopyEx(dest, src, &r, &dr, 0, NULL, flip); + } +#endif + + result.x = x; + result.y = y; + result.w = w; + result.h = h; + return result; +} + +static FC_Rect(*fc_render_callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale) = &FC_DefaultRenderCallback; + +void FC_SetRenderCallback(FC_Rect(*callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale)) +{ + if (callback == NULL) + fc_render_callback = &FC_DefaultRenderCallback; + else + fc_render_callback = callback; +} + +void FC_GetUTF8FromCodepoint(char* result, Uint32 codepoint) +{ + char a, b, c, d; + + if (result == NULL) + return; + + a = (codepoint >> 24) & 0xFF; + b = (codepoint >> 16) & 0xFF; + c = (codepoint >> 8) & 0xFF; + d = codepoint & 0xFF; + + if (a == 0) + { + if (b == 0) + { + if (c == 0) + { + result[0] = d; + result[1] = '\0'; + } + else + { + result[0] = c; + result[1] = d; + result[2] = '\0'; + } + } + else + { + result[0] = b; + result[1] = c; + result[2] = d; + result[3] = '\0'; + } + } + else + { + result[0] = a; + result[1] = b; + result[2] = c; + result[3] = d; + result[4] = '\0'; + } +} + +Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer) +{ + Uint32 result = 0; + const char* str; + if (c == NULL || *c == NULL) + return 0; + + str = *c; + if ((unsigned char)*str <= 0x7F) + result = *str; + else if ((unsigned char)*str < 0xE0) + { + result |= (unsigned char)(*str) << 8; + result |= (unsigned char)(*(str + 1)); + if (advance_pointer) + *c += 1; + } + else if ((unsigned char)*str < 0xF0) + { + result |= (unsigned char)(*str) << 16; + result |= (unsigned char)(*(str + 1)) << 8; + result |= (unsigned char)(*(str + 2)); + if (advance_pointer) + *c += 2; + } + else + { + result |= (unsigned char)(*str) << 24; + result |= (unsigned char)(*(str + 1)) << 16; + result |= (unsigned char)(*(str + 2)) << 8; + result |= (unsigned char)(*(str + 3)); + if (advance_pointer) + *c += 3; + } + return result; +} + + +void FC_SetLoadingString(FC_Font* font, const char* string) +{ + if (font == NULL) + return; + + free(font->loading_string); + font->loading_string = U8_strdup(string); +} + + +unsigned int FC_GetBufferSize(void) +{ + return fc_buffer_size; +} + +void FC_SetBufferSize(unsigned int size) +{ + free(fc_buffer); + if (size > 0) + { + fc_buffer_size = size; + fc_buffer = (char*)malloc(fc_buffer_size); + } + else + fc_buffer = (char*)malloc(fc_buffer_size); +} + + + + + +// Constructors + +static void FC_Init(FC_Font* font) +{ + if (font == NULL) + return; + +#ifndef FC_USE_SDL_GPU + font->renderer = NULL; +#endif + + font->ttf_source = NULL; + font->owns_ttf_source = 0; + + font->filter = FC_FILTER_NEAREST; + + font->default_color.r = 0; + font->default_color.g = 0; + font->default_color.b = 0; + FC_GET_ALPHA(font->default_color) = 255; + + font->height = 0; // ascent+descent + + font->maxWidth = 0; + font->baseline = 0; + font->ascent = 0; + font->descent = 0; + + font->lineSpacing = 0; + font->letterSpacing = 0; + + // Give a little offset for when filtering/mipmaps are used. Depending on mipmap level, this will still not be enough. + font->last_glyph.rect.x = FC_CACHE_PADDING; + font->last_glyph.rect.y = FC_CACHE_PADDING; + font->last_glyph.rect.w = 0; + font->last_glyph.rect.h = 0; + font->last_glyph.cache_level = 0; + + if (font->glyphs != NULL) + FC_MapFree(font->glyphs); + + font->glyphs = FC_MapCreate(FC_DEFAULT_NUM_BUCKETS); + + font->glyph_cache_size = 3; + font->glyph_cache_count = 0; + + + font->glyph_cache = (FC_Image**)malloc(font->glyph_cache_size * sizeof(FC_Image*)); + + if (font->loading_string == NULL) + font->loading_string = FC_GetStringASCII(); + + if (fc_buffer == NULL) + fc_buffer = (char*)malloc(fc_buffer_size); +} + +static Uint8 FC_GrowGlyphCache(FC_Font* font) +{ + if (font == NULL) + return 0; +#ifdef FC_USE_SDL_GPU + GPU_Image* new_level = GPU_CreateImage(font->height * 12, font->height * 12, GPU_FORMAT_RGBA); +#else + SDL_Texture* new_level = SDL_CreateTexture(font->renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, font->height * 12, font->height * 12); +#endif + if (new_level == NULL || !FC_SetGlyphCacheLevel(font, font->glyph_cache_count, new_level)) + { + FC_Log("Error: SDL_FontCache ran out of packing space and could not add another cache level.\n"); +#ifdef FC_USE_SDL_GPU + GPU_FreeImage(new_level); +#else + SDL_DestroyTexture(new_level); +#endif + return 0; + } + return 1; +} + +Uint8 FC_UploadGlyphCache(FC_Font* font, int cache_level, SDL_Surface* data_surface) +{ + if (font == NULL || data_surface == NULL) + return 0; +#ifdef FC_USE_SDL_GPU + GPU_Image* new_level = GPU_CopyImageFromSurface(data_surface); + if (FC_GetFilterMode(font) == FC_FILTER_LINEAR) + GPU_SetImageFilter(new_level, GPU_FILTER_LINEAR); + else + GPU_SetImageFilter(new_level, GPU_FILTER_NEAREST); +#else + SDL_Texture* new_level; + if (!fc_has_render_target_support) + new_level = SDL_CreateTextureFromSurface(font->renderer, data_surface); + else + { + // Must upload with render target enabled so we can put more glyphs on later + SDL_Renderer* renderer = font->renderer; + + // Set filter mode for new texture + char old_filter_mode[16]; // Save it so we can change the hint value in the meantime + snprintf(old_filter_mode, 16, "%s", SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY)); + + if (FC_GetFilterMode(font) == FC_FILTER_LINEAR) + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); + else + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); + + new_level = SDL_CreateTexture(renderer, data_surface->format->format, SDL_TEXTUREACCESS_TARGET, data_surface->w, data_surface->h); + SDL_SetTextureBlendMode(new_level, SDL_BLENDMODE_BLEND); + + // Reset filter mode for the temp texture + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); + + { + Uint8 r, g, b, a; + SDL_Texture* temp = SDL_CreateTextureFromSurface(renderer, data_surface); + SDL_SetTextureBlendMode(temp, SDL_BLENDMODE_NONE); + SDL_SetRenderTarget(renderer, new_level); + + SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_RenderClear(renderer); + SDL_SetRenderDrawColor(renderer, r, g, b, a); + + SDL_RenderCopy(renderer, temp, NULL, NULL); + SDL_SetRenderTarget(renderer, NULL); + + SDL_DestroyTexture(temp); + } + + // Reset to the old filter value + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, old_filter_mode); + + } +#endif + if (new_level == NULL || !FC_SetGlyphCacheLevel(font, cache_level, new_level)) + { + FC_Log("Error: SDL_FontCache ran out of packing space and could not add another cache level.\n"); +#ifdef FC_USE_SDL_GPU + GPU_FreeImage(new_level); +#else + SDL_DestroyTexture(new_level); +#endif + return 0; + } + return 1; +} + +static FC_GlyphData* FC_PackGlyphData(FC_Font* font, Uint32 codepoint, Uint16 width, Uint16 maxWidth, Uint16 maxHeight) +{ + FC_Map* glyphs = font->glyphs; + FC_GlyphData* last_glyph = &font->last_glyph; + Uint16 height = font->height + FC_CACHE_PADDING; + + if (last_glyph->rect.x + last_glyph->rect.w + width >= maxWidth - FC_CACHE_PADDING) + { + if (last_glyph->rect.y + height + height >= maxHeight - FC_CACHE_PADDING) + { + // Get ready to pack on the next cache level when it is ready + last_glyph->cache_level = font->glyph_cache_count; + last_glyph->rect.x = FC_CACHE_PADDING; + last_glyph->rect.y = FC_CACHE_PADDING; + last_glyph->rect.w = 0; + return NULL; + } + else + { + // Go to next row + last_glyph->rect.x = FC_CACHE_PADDING; + last_glyph->rect.y += height; + last_glyph->rect.w = 0; + } + } + + // Move to next space + last_glyph->rect.x += last_glyph->rect.w + 1 + FC_CACHE_PADDING; + last_glyph->rect.w = width; + + return FC_MapInsert(glyphs, codepoint, FC_MakeGlyphData(last_glyph->cache_level, last_glyph->rect.x, last_glyph->rect.y, last_glyph->rect.w, last_glyph->rect.h)); +} + + +FC_Image* FC_GetGlyphCacheLevel(FC_Font* font, int cache_level) +{ + if (font == NULL || cache_level < 0 || cache_level > font->glyph_cache_count) + return NULL; + + return font->glyph_cache[cache_level]; +} + +Uint8 FC_SetGlyphCacheLevel(FC_Font* font, int cache_level, FC_Image* cache_texture) +{ + if (font == NULL || cache_level < 0) + return 0; + + // Must be sequentially added + if (cache_level > font->glyph_cache_count + 1) + return 0; + + if (cache_level == font->glyph_cache_count) + { + font->glyph_cache_count++; + + // Grow cache? + if (font->glyph_cache_count > font->glyph_cache_size) + { + // Copy old cache to new one + int i; + FC_Image** new_cache; + new_cache = (FC_Image**)malloc(font->glyph_cache_count * sizeof(FC_Image*)); + for (i = 0; i < font->glyph_cache_size; ++i) + new_cache[i] = font->glyph_cache[i]; + + // Save new cache + free(font->glyph_cache); + font->glyph_cache_size = font->glyph_cache_count; + font->glyph_cache = new_cache; + } + } + + font->glyph_cache[cache_level] = cache_texture; + return 1; +} + + +FC_Font* FC_CreateFont(void) +{ + FC_Font* font; + + font = (FC_Font*)malloc(sizeof(FC_Font)); + memset(font, 0, sizeof(FC_Font)); + + FC_Init(font); + + return font; +} + + +// Assume this many will be enough... +#define FC_LOAD_MAX_SURFACES 10 + +#ifdef FC_USE_SDL_GPU +Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color) +#else +Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color) +#endif +{ + if (font == NULL || ttf == NULL) + return 0; +#ifndef FC_USE_SDL_GPU + if (renderer == NULL) + return 0; +#endif + + FC_ClearFont(font); + + + // Might as well check render target support here +#ifdef FC_USE_SDL_GPU + fc_has_render_target_support = GPU_IsFeatureEnabled(GPU_FEATURE_RENDER_TARGETS); +#else + SDL_RendererInfo info; + SDL_GetRendererInfo(renderer, &info); + fc_has_render_target_support = (info.flags & SDL_RENDERER_TARGETTEXTURE); + + font->renderer = renderer; +#endif + + font->ttf_source = ttf; + + //font->line_height = TTF_FontLineSkip(ttf); + font->height = TTF_FontHeight(ttf); + font->ascent = TTF_FontAscent(ttf); + font->descent = -TTF_FontDescent(ttf); + + font->baseline = font->height - font->descent; + + font->default_color = color; + + { + SDL_Color white = { 255, 255, 255, 255 }; + SDL_Surface* glyph_surf; + char buff[5]; + const char* buff_ptr = buff; + const char* source_string; + Uint8 packed = 0; + + // Copy glyphs from the surface to the font texture and store the position data + // Pack row by row into a square texture + // Try figuring out dimensions that make sense for the font size. + unsigned int w = font->height * 12; + unsigned int h = font->height * 12; + SDL_Surface* surfaces[FC_LOAD_MAX_SURFACES]; + int num_surfaces = 1; + surfaces[0] = FC_CreateSurface32(w, h); + font->last_glyph.rect.x = FC_CACHE_PADDING; + font->last_glyph.rect.y = FC_CACHE_PADDING; + font->last_glyph.rect.w = 0; + font->last_glyph.rect.h = font->height; + + memset(buff, 0, 5); + source_string = font->loading_string; + for (; *source_string != '\0'; source_string = U8_next(source_string)) + { + if (!U8_charcpy(buff, source_string, 5)) + continue; + glyph_surf = TTF_RenderUTF8_Blended(ttf, buff, white); + if (glyph_surf == NULL) + continue; + + // Try packing. If it fails, create a new surface for the next cache level. + packed = (FC_PackGlyphData(font, FC_GetCodepointFromUTF8(&buff_ptr, 0), glyph_surf->w, surfaces[num_surfaces - 1]->w, surfaces[num_surfaces - 1]->h) != NULL); + if (!packed) + { + int i = num_surfaces - 1; + if (num_surfaces >= FC_LOAD_MAX_SURFACES) + { + // Can't do any more! + FC_Log("SDL_FontCache error: Could not create enough cache surfaces to fit all of the loading string!\n"); + SDL_FreeSurface(glyph_surf); + break; + } + + // Upload the current surface to the glyph cache now so we can keep the cache level packing cursor up to date as we go. + FC_UploadGlyphCache(font, i, surfaces[i]); + SDL_FreeSurface(surfaces[i]); +#ifndef FC_USE_SDL_GPU + SDL_SetTextureBlendMode(font->glyph_cache[i], SDL_BLENDMODE_BLEND); +#endif + // Update the glyph cursor to the new cache level. We need to do this here because the actual cache lags behind our use of the packing above. + font->last_glyph.cache_level = num_surfaces; + + + surfaces[num_surfaces] = FC_CreateSurface32(w, h); + num_surfaces++; + } + + // Try packing for the new surface, then blit onto it. + if (packed || FC_PackGlyphData(font, FC_GetCodepointFromUTF8(&buff_ptr, 0), glyph_surf->w, surfaces[num_surfaces - 1]->w, surfaces[num_surfaces - 1]->h) != NULL) + { + SDL_SetSurfaceBlendMode(glyph_surf, SDL_BLENDMODE_NONE); + SDL_Rect srcRect = { 0, 0, glyph_surf->w, glyph_surf->h }; + SDL_Rect destrect = font->last_glyph.rect; + SDL_BlitSurface(glyph_surf, &srcRect, surfaces[num_surfaces - 1], &destrect); + } + + SDL_FreeSurface(glyph_surf); + } + + { + int i = num_surfaces - 1; + FC_UploadGlyphCache(font, i, surfaces[i]); + SDL_FreeSurface(surfaces[i]); +#ifndef FC_USE_SDL_GPU + SDL_SetTextureBlendMode(font->glyph_cache[i], SDL_BLENDMODE_BLEND); +#endif + } + } + + return 1; +} + + +#ifdef FC_USE_SDL_GPU +Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style) +#else +Uint8 FC_LoadFont(FC_Font* font, FC_Target* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style) +#endif +{ + SDL_RWops* rwops; + + if (font == NULL) + return 0; + + rwops = SDL_RWFromFile(filename_ttf, "rb"); + + if (rwops == NULL) + { + FC_Log("Unable to open file for reading: %s \n", SDL_GetError()); + return 0; + } + +#ifdef FC_USE_SDL_GPU + return FC_LoadFont_RW(font, rwops, 1, pointSize, color, style); +#else + return FC_LoadFont_RW(font, renderer, rwops, 1, pointSize, color, style); +#endif +} + +#ifdef FC_USE_SDL_GPU +Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style) +#else +Uint8 FC_LoadFont_RW(FC_Font* font, FC_Target* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style) +#endif +{ + Uint8 result; + TTF_Font* ttf; + Uint8 outline; + + if (font == NULL) + return 0; + + if (!TTF_WasInit() && TTF_Init() < 0) + { + FC_Log("Unable to initialize SDL_ttf: %s \n", TTF_GetError()); + if (own_rwops) + SDL_RWclose(file_rwops_ttf); + return 0; + } + + ttf = TTF_OpenFontRW(file_rwops_ttf, own_rwops, pointSize); + + if (ttf == NULL) + { + FC_Log("Unable to load TrueType font: %s \n", TTF_GetError()); + if (own_rwops) + SDL_RWclose(file_rwops_ttf); + return 0; + } + + outline = (style & TTF_STYLE_OUTLINE); + if (outline) + { + style &= ~TTF_STYLE_OUTLINE; + TTF_SetFontOutline(ttf, 1); + } + TTF_SetFontStyle(ttf, style); + +#ifdef FC_USE_SDL_GPU + result = FC_LoadFontFromTTF(font, ttf, color); +#else + result = FC_LoadFontFromTTF(font, renderer, ttf, color); +#endif + + // Can only load new (uncached) glyphs if we can keep the SDL_RWops open. + font->owns_ttf_source = own_rwops; + if (!own_rwops) + { + TTF_CloseFont(font->ttf_source); + font->ttf_source = NULL; + } + + return result; +} + + +void FC_ClearFont(FC_Font* font) +{ + int i; + if (font == NULL) + return; + + // Release resources + if (font->owns_ttf_source) + TTF_CloseFont(font->ttf_source); + + font->owns_ttf_source = 0; + font->ttf_source = NULL; + + // Delete glyph map + FC_MapFree(font->glyphs); + font->glyphs = NULL; + + // Delete glyph cache + for (i = 0; i < font->glyph_cache_count; ++i) + { +#ifdef FC_USE_SDL_GPU + GPU_FreeImage(font->glyph_cache[i]); +#else + SDL_DestroyTexture(font->glyph_cache[i]); +#endif + } + free(font->glyph_cache); + font->glyph_cache = NULL; + + // Reset font + FC_Init(font); +} + + +void FC_FreeFont(FC_Font* font) +{ + int i; + if (font == NULL) + return; + + // Release resources + if (font->owns_ttf_source) + TTF_CloseFont(font->ttf_source); + + // Delete glyph map + FC_MapFree(font->glyphs); + + // Delete glyph cache + for (i = 0; i < font->glyph_cache_count; ++i) + { +#ifdef FC_USE_SDL_GPU + GPU_FreeImage(font->glyph_cache[i]); +#else + SDL_DestroyTexture(font->glyph_cache[i]); +#endif + } + free(font->glyph_cache); + + free(font->loading_string); + + free(font); +} + +int FC_GetNumCacheLevels(FC_Font* font) +{ + return font->glyph_cache_count; +} + +Uint8 FC_AddGlyphToCache(FC_Font* font, SDL_Surface* glyph_surface) +{ + if (font == NULL || glyph_surface == NULL) + return 0; + + SDL_SetSurfaceBlendMode(glyph_surface, SDL_BLENDMODE_NONE); + FC_Image* dest = FC_GetGlyphCacheLevel(font, font->last_glyph.cache_level); + if (dest == NULL) + return 0; + +#ifdef FC_USE_SDL_GPU + { + GPU_Target* target = GPU_LoadTarget(dest); + if (target == NULL) + return 0; + GPU_Image* img = GPU_CopyImageFromSurface(glyph_surface); + GPU_SetImageFilter(img, GPU_FILTER_NEAREST); + GPU_SetBlendMode(img, GPU_BLEND_SET); + + SDL_Rect destrect = font->last_glyph.rect; + GPU_Blit(img, NULL, target, destrect.x + destrect.w / 2, destrect.y + destrect.h / 2); + + GPU_FreeImage(img); + GPU_FreeTarget(target); + } +#else + { + SDL_Renderer* renderer = font->renderer; + Uint8 use_clip; + FC_Rect clip_rect; + SDL_Texture* img; + SDL_Rect destrect; + + use_clip = has_clip(renderer); + if (use_clip) + { + clip_rect = get_clip(renderer); + set_clip(renderer, NULL); + } + + img = SDL_CreateTextureFromSurface(renderer, glyph_surface); + + destrect = font->last_glyph.rect; + SDL_SetRenderTarget(renderer, dest); + SDL_RenderCopy(renderer, img, NULL, &destrect); + SDL_SetRenderTarget(renderer, NULL); + SDL_DestroyTexture(img); + + if (use_clip) + set_clip(renderer, &clip_rect); + } +#endif + + return 1; +} + + +unsigned int FC_GetNumCodepoints(FC_Font* font) +{ + FC_Map* glyphs; + int i; + unsigned int result = 0; + if (font == NULL || font->glyphs == NULL) + return 0; + + glyphs = font->glyphs; + + for (i = 0; i < glyphs->num_buckets; ++i) + { + FC_MapNode* node; + for (node = glyphs->buckets[i]; node != NULL; node = node->next) + { + result++; + } + } + + return result; +} + +void FC_GetCodepoints(FC_Font* font, Uint32* result) +{ + FC_Map* glyphs; + int i; + unsigned int count = 0; + if (font == NULL || font->glyphs == NULL) + return; + + glyphs = font->glyphs; + + for (i = 0; i < glyphs->num_buckets; ++i) + { + FC_MapNode* node; + for (node = glyphs->buckets[i]; node != NULL; node = node->next) + { + result[count] = node->key; + count++; + } + } +} + +Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint) +{ + FC_GlyphData* e = FC_MapFind(font->glyphs, codepoint); + if (e == NULL) + { + char buff[5]; + int w, h; + SDL_Color white = { 255, 255, 255, 255 }; + SDL_Surface* surf; + FC_Image* cache_image; + + if (font->ttf_source == NULL) + return 0; + + FC_GetUTF8FromCodepoint(buff, codepoint); + + cache_image = FC_GetGlyphCacheLevel(font, font->last_glyph.cache_level); + if (cache_image == NULL) + { + FC_Log("SDL_FontCache: Failed to load cache image, so cannot add new glyphs!\n"); + return 0; + } + +#ifdef FC_USE_SDL_GPU + w = cache_image->w; + h = cache_image->h; +#else + SDL_QueryTexture(cache_image, NULL, NULL, &w, &h); +#endif + + surf = TTF_RenderUTF8_Blended(font->ttf_source, buff, white); + if (surf == NULL) + { + return 0; + } + + e = FC_PackGlyphData(font, codepoint, surf->w, w, h); + if (e == NULL) + { + // Grow the cache + FC_GrowGlyphCache(font); + + // Try packing again + e = FC_PackGlyphData(font, codepoint, surf->w, w, h); + if (e == NULL) + { + SDL_FreeSurface(surf); + return 0; + } + } + + // Render onto the cache texture + FC_AddGlyphToCache(font, surf); + + SDL_FreeSurface(surf); + } + + if (result != NULL && e != NULL) + *result = *e; + + return 1; +} + + +FC_GlyphData* FC_SetGlyphData(FC_Font* font, Uint32 codepoint, FC_GlyphData glyph_data) +{ + return FC_MapInsert(font->glyphs, codepoint, glyph_data); +} + + + +// Drawing +static FC_Rect FC_RenderLeft(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text) +{ + const char* c = text; + FC_Rect srcRect; + FC_Rect dstRect; + FC_Rect dirtyRect = FC_MakeRect(x, y, 0, 0); + + FC_GlyphData glyph; + Uint32 codepoint; + + float destX = x; + float destY = y; + float destH; + float destLineSpacing; + float destLetterSpacing; + + if (font == NULL) + return dirtyRect; + + destH = font->height * scale.y; + destLineSpacing = font->lineSpacing*scale.y; + destLetterSpacing = font->letterSpacing*scale.x; + + if (c == NULL || font->glyph_cache_count == 0 || dest == NULL) + return dirtyRect; + + int newlineX = x; + + for (; *c != '\0'; c++) + { + if (*c == '\n') + { + destX = newlineX; + destY += destH + destLineSpacing; + continue; + } + + codepoint = FC_GetCodepointFromUTF8(&c, 1); // Increments 'c' to skip the extra UTF-8 bytes + if (!FC_GetGlyphData(font, &glyph, codepoint)) + { + codepoint = ' '; + if (!FC_GetGlyphData(font, &glyph, codepoint)) + continue; // Skip bad characters + } + + if (codepoint == ' ') + { + destX += glyph.rect.w*scale.x + destLetterSpacing; + continue; + } + /*if(destX >= dest->w) + continue; + if(destY >= dest->h) + continue;*/ + +#ifdef FC_USE_SDL_GPU + srcRect.x = glyph.rect.x; + srcRect.y = glyph.rect.y; + srcRect.w = glyph.rect.w; + srcRect.h = glyph.rect.h; +#else + srcRect = glyph.rect; +#endif + dstRect = fc_render_callback(FC_GetGlyphCacheLevel(font, glyph.cache_level), &srcRect, dest, destX, destY, scale.x, scale.y); + if (dirtyRect.w == 0 || dirtyRect.h == 0) + dirtyRect = dstRect; + else + dirtyRect = FC_RectUnion(dirtyRect, dstRect); + + destX += glyph.rect.w*scale.x + destLetterSpacing; + } + + return dirtyRect; +} + +static void set_color_for_all_caches(FC_Font* font, SDL_Color color) +{ + // TODO: How can I predict which glyph caches are to be used? + FC_Image* img; + int i; + int num_levels = FC_GetNumCacheLevels(font); + for (i = 0; i < num_levels; ++i) + { + img = FC_GetGlyphCacheLevel(font, i); + set_color(img, color.r, color.g, color.b, FC_GET_ALPHA(color)); + } +} + +FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...) +{ + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(x, y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + set_color_for_all_caches(font, font->default_color); + + return FC_RenderLeft(font, dest, x, y, FC_MakeScale(1, 1), fc_buffer); +} + + + +typedef struct FC_StringList +{ + char* value; + struct FC_StringList* next; +} FC_StringList; + +void FC_StringListFree(FC_StringList* node) +{ + // Delete the nodes in order + while (node != NULL) + { + FC_StringList* last = node; + node = node->next; + + free(last->value); + free(last); + } +} + +FC_StringList** FC_StringListPushBack(FC_StringList** node, char* value, Uint8 copy) +{ + if (node == NULL) + { + return node; + } + + // Get to the last node + while (*node != NULL) + { + node = &(*node)->next; + } + + *node = (FC_StringList*)malloc(sizeof(FC_StringList)); + + (*node)->value = (copy ? U8_strdup(value) : value); + (*node)->next = NULL; + + return node; +} + +static FC_StringList* FC_Explode(const char* text, char delimiter) +{ + FC_StringList* head; + FC_StringList* new_node; + FC_StringList** node; + const char* start; + const char* end; + unsigned int size; + if (text == NULL) + return NULL; + + head = NULL; + node = &head; + + // Doesn't technically support UTF-8, but it's probably fine, right? + size = 0; + start = end = text; + while (1) + { + if (*end == delimiter || *end == '\0') + { + *node = (FC_StringList*)malloc(sizeof(FC_StringList)); + new_node = *node; + + new_node->value = (char*)malloc(size + 1); + memcpy(new_node->value, start, size); + new_node->value[size] = '\0'; + + new_node->next = NULL; + + if (*end == '\0') + break; + + node = &((*node)->next); + start = end + 1; + size = 0; + } + else + ++size; + + ++end; + } + + return head; +} + +static FC_StringList* FC_ExplodeAndKeep(const char* text, char delimiter) +{ + FC_StringList* head; + FC_StringList* new_node; + FC_StringList** node; + const char* start; + const char* end; + unsigned int size; + if (text == NULL) + return NULL; + + head = NULL; + node = &head; + + // Doesn't technically support UTF-8, but it's probably fine, right? + size = 0; + start = end = text; + while (1) + { + if (*end == delimiter || *end == '\0') + { + *node = (FC_StringList*)malloc(sizeof(FC_StringList)); + new_node = *node; + + new_node->value = (char*)malloc(size + 1); + memcpy(new_node->value, start, size); + new_node->value[size] = '\0'; + + new_node->next = NULL; + + if (*end == '\0') + break; + + node = &((*node)->next); + start = end; + size = 1; + } + else + ++size; + + ++end; + } + + return head; +} + +static void FC_RenderAlign(FC_Font* font, FC_Target* dest, float x, float y, int width, FC_Scale scale, FC_AlignEnum align, const char* text) +{ + switch (align) + { + case FC_ALIGN_LEFT: + FC_RenderLeft(font, dest, x, y, scale, text); + break; + case FC_ALIGN_CENTER: + FC_RenderCenter(font, dest, x + width / 2, y, scale, text); + break; + case FC_ALIGN_RIGHT: + FC_RenderRight(font, dest, x + width, y, scale, text); + break; + } +} + +static FC_StringList* FC_GetBufferFitToColumn(FC_Font* font, int width, FC_Scale scale, Uint8 keep_newlines) +{ + FC_StringList* result = NULL; + FC_StringList** current = &result; + + FC_StringList *ls, *iter; + + ls = (keep_newlines ? FC_ExplodeAndKeep(fc_buffer, '\n') : FC_Explode(fc_buffer, '\n')); + for (iter = ls; iter != NULL; iter = iter->next) + { + char* line = iter->value; + + // If line is too long, then add words one at a time until we go over. + if (width > 0 && FC_GetWidth(font, "%s", line) > width) + { + FC_StringList *words, *word_iter; + + words = FC_Explode(line, ' '); + // Skip the first word for the iterator, so there will always be at least one word per line + line = new_concat(words->value, " "); + for (word_iter = words->next; word_iter != NULL; word_iter = word_iter->next) + { + char* line_plus_word = new_concat(line, word_iter->value); + char* word_plus_space = new_concat(word_iter->value, " "); + if (FC_GetWidth(font, "%s", line_plus_word) > width) + { + current = FC_StringListPushBack(current, line, 0); + + line = word_plus_space; + } + else + { + replace_concat(&line, word_plus_space); + free(word_plus_space); + } + free(line_plus_word); + } + current = FC_StringListPushBack(current, line, 0); + FC_StringListFree(words); + } + else + { + current = FC_StringListPushBack(current, line, 0); + iter->value = NULL; + } + } + FC_StringListFree(ls); + + return result; +} + +static void FC_DrawColumnFromBuffer(FC_Font* font, FC_Target* dest, FC_Rect box, int* total_height, FC_Scale scale, FC_AlignEnum align) +{ + int y = box.y; + FC_StringList *ls, *iter; + + ls = FC_GetBufferFitToColumn(font, box.w, scale, 0); + for (iter = ls; iter != NULL; iter = iter->next) + { + FC_RenderAlign(font, dest, box.x, y, box.w, scale, align, iter->value); + y += FC_GetLineHeight(font); + } + FC_StringListFree(ls); + + if (total_height != NULL) + *total_height = y - box.y; +} + +FC_Rect FC_DrawBox(FC_Font* font, FC_Target* dest, FC_Rect box, const char* formatted_text, ...) +{ + Uint8 useClip; + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(box.x, box.y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + useClip = has_clip(dest); + FC_Rect oldclip, newclip; + if (useClip) + { + oldclip = get_clip(dest); + newclip = FC_RectIntersect(oldclip, box); + } + else + newclip = box; + + set_clip(dest, &newclip); + + set_color_for_all_caches(font, font->default_color); + + FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1, 1), FC_ALIGN_LEFT); + + if (useClip) + set_clip(dest, &oldclip); + else + set_clip(dest, NULL); + + return box; +} + +FC_Rect FC_DrawBoxAlign(FC_Font* font, FC_Target* dest, FC_Rect box, FC_AlignEnum align, const char* formatted_text, ...) +{ + Uint8 useClip; + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(box.x, box.y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + useClip = has_clip(dest); + FC_Rect oldclip, newclip; + if (useClip) + { + oldclip = get_clip(dest); + newclip = FC_RectIntersect(oldclip, box); + } + else + newclip = box; + set_clip(dest, &newclip); + + set_color_for_all_caches(font, font->default_color); + + FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1, 1), align); + + if (useClip) + set_clip(dest, &oldclip); + else + set_clip(dest, NULL); + + return box; +} + +FC_Rect FC_DrawBoxScale(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Scale scale, const char* formatted_text, ...) +{ + Uint8 useClip; + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(box.x, box.y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + useClip = has_clip(dest); + FC_Rect oldclip, newclip; + if (useClip) + { + oldclip = get_clip(dest); + newclip = FC_RectIntersect(oldclip, box); + } + else + newclip = box; + set_clip(dest, &newclip); + + set_color_for_all_caches(font, font->default_color); + + FC_DrawColumnFromBuffer(font, dest, box, NULL, scale, FC_ALIGN_LEFT); + + if (useClip) + set_clip(dest, &oldclip); + else + set_clip(dest, NULL); + + return box; +} + +FC_Rect FC_DrawBoxColor(FC_Font* font, FC_Target* dest, FC_Rect box, SDL_Color color, const char* formatted_text, ...) +{ + Uint8 useClip; + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(box.x, box.y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + useClip = has_clip(dest); + FC_Rect oldclip, newclip; + if (useClip) + { + oldclip = get_clip(dest); + newclip = FC_RectIntersect(oldclip, box); + } + else + newclip = box; + set_clip(dest, &newclip); + + set_color_for_all_caches(font, color); + + FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1, 1), FC_ALIGN_LEFT); + + if (useClip) + set_clip(dest, &oldclip); + else + set_clip(dest, NULL); + + return box; +} + +FC_Rect FC_DrawBoxEffect(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Effect effect, const char* formatted_text, ...) +{ + Uint8 useClip; + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(box.x, box.y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + useClip = has_clip(dest); + FC_Rect oldclip, newclip; + if (useClip) + { + oldclip = get_clip(dest); + newclip = FC_RectIntersect(oldclip, box); + } + else + newclip = box; + set_clip(dest, &newclip); + + set_color_for_all_caches(font, effect.color); + + FC_DrawColumnFromBuffer(font, dest, box, NULL, effect.scale, effect.alignment); + + if (useClip) + set_clip(dest, &oldclip); + else + set_clip(dest, NULL); + + return box; +} + +FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...) +{ + FC_Rect box = { x, y, width, 0 }; + int total_height; + + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(x, y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + set_color_for_all_caches(font, font->default_color); + + FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1, 1), FC_ALIGN_LEFT); + + return FC_MakeRect(box.x, box.y, width, total_height); +} + +FC_Rect FC_DrawColumnAlign(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_AlignEnum align, const char* formatted_text, ...) +{ + FC_Rect box = { x, y, width, 0 }; + int total_height; + + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(x, y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + set_color_for_all_caches(font, font->default_color); + + switch (align) + { + case FC_ALIGN_CENTER: + box.x -= width / 2; + break; + case FC_ALIGN_RIGHT: + box.x -= width; + break; + default: + break; + } + + FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1, 1), align); + + return FC_MakeRect(box.x, box.y, width, total_height); +} + +FC_Rect FC_DrawColumnScale(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Scale scale, const char* formatted_text, ...) +{ + FC_Rect box = { x, y, width, 0 }; + int total_height; + + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(x, y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + set_color_for_all_caches(font, font->default_color); + + FC_DrawColumnFromBuffer(font, dest, box, &total_height, scale, FC_ALIGN_LEFT); + + return FC_MakeRect(box.x, box.y, width, total_height); +} + +FC_Rect FC_DrawColumnColor(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, SDL_Color color, const char* formatted_text, ...) +{ + FC_Rect box = { x, y, width, 0 }; + int total_height; + + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(x, y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + set_color_for_all_caches(font, color); + + FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1, 1), FC_ALIGN_LEFT); + + return FC_MakeRect(box.x, box.y, width, total_height); +} + +FC_Rect FC_DrawColumnEffect(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Effect effect, const char* formatted_text, ...) +{ + FC_Rect box = { x, y, width, 0 }; + int total_height; + + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(x, y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + set_color_for_all_caches(font, effect.color); + + switch (effect.alignment) + { + case FC_ALIGN_CENTER: + box.x -= width / 2; + break; + case FC_ALIGN_RIGHT: + box.x -= width; + break; + default: + break; + } + + FC_DrawColumnFromBuffer(font, dest, box, &total_height, effect.scale, effect.alignment); + + return FC_MakeRect(box.x, box.y, width, total_height); +} + +static FC_Rect FC_RenderCenter(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text) +{ + FC_Rect result = { x, y, 0, 0 }; + if (text == NULL || font == NULL) + return result; + + char* str = U8_strdup(text); + char* del = str; + char* c; + + // Go through str, when you find a \n, replace it with \0 and print it + // then move down, back, and continue. + for (c = str; *c != '\0';) + { + if (*c == '\n') + { + *c = '\0'; + result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str) / 2.0f, y, scale, str), result); + *c = '\n'; + c++; + str = c; + y += scale.y*font->height; + } + else + c++; + } + + result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str) / 2.0f, y, scale, str), result); + + free(del); + return result; +} + +static FC_Rect FC_RenderRight(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text) +{ + FC_Rect result = { x, y, 0, 0 }; + if (text == NULL || font == NULL) + return result; + + char* str = U8_strdup(text); + char* del = str; + char* c; + + for (c = str; *c != '\0';) + { + if (*c == '\n') + { + *c = '\0'; + result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str), y, scale, str), result); + *c = '\n'; + c++; + str = c; + y += scale.y*font->height; + } + else + c++; + } + + result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str), y, scale, str), result); + + free(del); + return result; +} + + + +FC_Rect FC_DrawScale(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* formatted_text, ...) +{ + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(x, y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + set_color_for_all_caches(font, font->default_color); + + return FC_RenderLeft(font, dest, x, y, scale, fc_buffer); +} + +FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignEnum align, const char* formatted_text, ...) +{ + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(x, y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + set_color_for_all_caches(font, font->default_color); + + FC_Rect result; + switch (align) + { + case FC_ALIGN_LEFT: + result = FC_RenderLeft(font, dest, x, y, FC_MakeScale(1, 1), fc_buffer); + break; + case FC_ALIGN_CENTER: + result = FC_RenderCenter(font, dest, x, y, FC_MakeScale(1, 1), fc_buffer); + break; + case FC_ALIGN_RIGHT: + result = FC_RenderRight(font, dest, x, y, FC_MakeScale(1, 1), fc_buffer); + break; + default: + result = FC_MakeRect(x, y, 0, 0); + break; + } + + return result; +} + +FC_Rect FC_DrawColor(FC_Font* font, FC_Target* dest, float x, float y, SDL_Color color, const char* formatted_text, ...) +{ + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(x, y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + set_color_for_all_caches(font, color); + + return FC_RenderLeft(font, dest, x, y, FC_MakeScale(1, 1), fc_buffer); +} + + +FC_Rect FC_DrawEffect(FC_Font* font, FC_Target* dest, float x, float y, FC_Effect effect, const char* formatted_text, ...) +{ + if (formatted_text == NULL || font == NULL) + return FC_MakeRect(x, y, 0, 0); + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + set_color_for_all_caches(font, effect.color); + + FC_Rect result; + switch (effect.alignment) + { + case FC_ALIGN_LEFT: + result = FC_RenderLeft(font, dest, x, y, effect.scale, fc_buffer); + break; + case FC_ALIGN_CENTER: + result = FC_RenderCenter(font, dest, x, y, effect.scale, fc_buffer); + break; + case FC_ALIGN_RIGHT: + result = FC_RenderRight(font, dest, x, y, effect.scale, fc_buffer); + break; + default: + result = FC_MakeRect(x, y, 0, 0); + break; + } + + return result; +} + + + + +// Getters + + +FC_FilterEnum FC_GetFilterMode(FC_Font* font) +{ + if (font == NULL) + return FC_FILTER_NEAREST; + + return font->filter; +} + +Uint16 FC_GetLineHeight(FC_Font* font) +{ + if (font == NULL) + return 0; + + return font->height; +} + +Uint16 FC_GetHeight(FC_Font* font, const char* formatted_text, ...) +{ + if (formatted_text == NULL || font == NULL) + return 0; + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + Uint16 numLines = 1; + const char* c; + + for (c = fc_buffer; *c != '\0'; c++) + { + if (*c == '\n') + numLines++; + } + + // Actual height of letter region + line spacing + return font->height*numLines + font->lineSpacing*(numLines - 1); //height*numLines; +} + +Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...) +{ + if (formatted_text == NULL || font == NULL) + return 0; + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + const char* c; + Uint16 width = 0; + Uint16 bigWidth = 0; // Allows for multi-line strings + + for (c = fc_buffer; *c != '\0'; c++) + { + if (*c == '\n') + { + bigWidth = bigWidth >= width ? bigWidth : width; + width = 0; + continue; + } + + FC_GlyphData glyph; + Uint32 codepoint = FC_GetCodepointFromUTF8(&c, 1); + if (FC_GetGlyphData(font, &glyph, codepoint) || FC_GetGlyphData(font, &glyph, ' ')) + width += glyph.rect.w; + } + bigWidth = bigWidth >= width ? bigWidth : width; + + return bigWidth; +} + +// If width == -1, use no width limit +FC_Rect FC_GetCharacterOffset(FC_Font* font, Uint16 position_index, int column_width, const char* formatted_text, ...) +{ + FC_Rect result = { 0, 0, 1, FC_GetLineHeight(font) }; + FC_StringList *ls, *iter; + int num_lines = 0; + Uint8 done = 0; + + if (formatted_text == NULL || column_width == 0 || position_index == 0 || font == NULL) + return result; + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + ls = FC_GetBufferFitToColumn(font, column_width, FC_MakeScale(1, 1), 1); + for (iter = ls; iter != NULL;) + { + char* line; + int i = 0; + FC_StringList* next_iter = iter->next; + + ++num_lines; + for (line = iter->value; line != NULL && *line != '\0'; line = (char*)U8_next(line)) + { + ++i; + --position_index; + if (position_index == 0) + { + // FIXME: Doesn't handle box-wrapped newlines correctly + line = (char*)U8_next(line); + line[0] = '\0'; + result.x = FC_GetWidth(font, "%s", iter->value); + done = 1; + break; + } + } + if (done) + break; + + // Prevent line wrapping if there are no more lines + if (next_iter == NULL && !done) + result.x = FC_GetWidth(font, "%s", iter->value); + iter = next_iter; + } + FC_StringListFree(ls); + + if (num_lines > 1) + { + result.y = (num_lines - 1) * FC_GetLineHeight(font); + } + + return result; +} + + +Uint16 FC_GetColumnHeight(FC_Font* font, Uint16 width, const char* formatted_text, ...) +{ + int y = 0; + + FC_StringList *ls, *iter; + + if (font == NULL) + return 0; + + if (formatted_text == NULL || width == 0) + return font->height; + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + ls = FC_GetBufferFitToColumn(font, width, FC_MakeScale(1, 1), 0); + for (iter = ls; iter != NULL; iter = iter->next) + { + y += FC_GetLineHeight(font); + } + FC_StringListFree(ls); + + return y; +} + +static int FC_GetAscentFromCodepoint(FC_Font* font, Uint32 codepoint) +{ + FC_GlyphData glyph; + + if (font == NULL) + return 0; + + // FIXME: Store ascent so we can return it here + FC_GetGlyphData(font, &glyph, codepoint); + return glyph.rect.h; +} + +static int FC_GetDescentFromCodepoint(FC_Font* font, Uint32 codepoint) +{ + FC_GlyphData glyph; + + if (font == NULL) + return 0; + + // FIXME: Store descent so we can return it here + FC_GetGlyphData(font, &glyph, codepoint); + return glyph.rect.h; +} + +int FC_GetAscent(FC_Font* font, const char* formatted_text, ...) +{ + Uint32 codepoint; + int max, ascent; + const char* c; + + if (font == NULL) + return 0; + + if (formatted_text == NULL) + return font->ascent; + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + max = 0; + c = fc_buffer; + + while (*c != '\0') + { + codepoint = FC_GetCodepointFromUTF8(&c, 1); + if (codepoint != 0) + { + ascent = FC_GetAscentFromCodepoint(font, codepoint); + if (ascent > max) + max = ascent; + } + ++c; + } + return max; +} + +int FC_GetDescent(FC_Font* font, const char* formatted_text, ...) +{ + Uint32 codepoint; + int max, descent; + const char* c; + + if (font == NULL) + return 0; + + if (formatted_text == NULL) + return font->descent; + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + max = 0; + c = fc_buffer; + + while (*c != '\0') + { + codepoint = FC_GetCodepointFromUTF8(&c, 1); + if (codepoint != 0) + { + descent = FC_GetDescentFromCodepoint(font, codepoint); + if (descent > max) + max = descent; + } + ++c; + } + return max; +} + +int FC_GetBaseline(FC_Font* font) +{ + if (font == NULL) + return 0; + + return font->baseline; +} + +int FC_GetSpacing(FC_Font* font) +{ + if (font == NULL) + return 0; + + return font->letterSpacing; +} + +int FC_GetLineSpacing(FC_Font* font) +{ + if (font == NULL) + return 0; + + return font->lineSpacing; +} + +Uint16 FC_GetMaxWidth(FC_Font* font) +{ + if (font == NULL) + return 0; + + return font->maxWidth; +} + +SDL_Color FC_GetDefaultColor(FC_Font* font) +{ + if (font == NULL) + { + SDL_Color c = { 0,0,0,255 }; + return c; + } + + return font->default_color; +} + + +Uint8 FC_InRect(float x, float y, FC_Rect input_rect) +{ + return (input_rect.x <= x && x <= input_rect.x + input_rect.w && input_rect.y <= y && y <= input_rect.y + input_rect.h); +} + +// TODO: Make it work with alignment +Uint16 FC_GetPositionFromOffset(FC_Font* font, float x, float y, int column_width, FC_AlignEnum align, const char* formatted_text, ...) +{ + FC_StringList *ls, *iter; + Uint8 done = 0; + int height = FC_GetLineHeight(font); + Uint16 position = 0; + int current_x = 0; + int current_y = 0; + FC_GlyphData glyph_data; + + if (formatted_text == NULL || column_width == 0 || font == NULL) + return 0; + + FC_EXTRACT_VARARGS(fc_buffer, formatted_text); + + ls = FC_GetBufferFitToColumn(font, column_width, FC_MakeScale(1, 1), 1); + for (iter = ls; iter != NULL; iter = iter->next) + { + char* line; + + for (line = iter->value; line != NULL && *line != '\0'; line = (char*)U8_next(line)) + { + if (FC_GetGlyphData(font, &glyph_data, FC_GetCodepointFromUTF8((const char**)&line, 0))) + { + if (FC_InRect(x, y, FC_MakeRect(current_x, current_y, glyph_data.rect.w, glyph_data.rect.h))) + { + done = 1; + break; + } + + current_x += glyph_data.rect.w; + } + position++; + } + if (done) + break; + + current_x = 0; + current_y += height; + if (y < current_y) + break; + } + FC_StringListFree(ls); + + return position; +} + + + + +// Setters + + +void FC_SetFilterMode(FC_Font* font, FC_FilterEnum filter) +{ + if (font == NULL) + return; + + if (font->filter != filter) + { + font->filter = filter; + +#ifdef FC_USE_SDL_GPU + // Update each texture to use this filter mode + { + int i; + GPU_FilterEnum gpu_filter = GPU_FILTER_NEAREST; + if (FC_GetFilterMode(font) == FC_FILTER_LINEAR) + gpu_filter = GPU_FILTER_LINEAR; + + for (i = 0; i < font->glyph_cache_count; ++i) + { + GPU_SetImageFilter(font->glyph_cache[i], gpu_filter); + } + } +#endif + } +} + + +void FC_SetSpacing(FC_Font* font, int LetterSpacing) +{ + if (font == NULL) + return; + + font->letterSpacing = LetterSpacing; +} + +void FC_SetLineSpacing(FC_Font* font, int LineSpacing) +{ + if (font == NULL) + return; + + font->lineSpacing = LineSpacing; +} + +void FC_SetDefaultColor(FC_Font* font, SDL_Color color) +{ + if (font == NULL) + return; + + font->default_color = color; +} \ No newline at end of file diff --git a/Stub/SDL_FontCache.h b/Stub/SDL_FontCache.h new file mode 100644 index 000000000..e5e485fc7 --- /dev/null +++ b/Stub/SDL_FontCache.h @@ -0,0 +1,311 @@ +/* +SDL_FontCache v0.9.0: A font cache for SDL and SDL_ttf +by Jonathan Dearborn +Dedicated to the memory of Florian Hufsky + +License: + The short: + Use it however you'd like, but keep the copyright and license notice + whenever these files or parts of them are distributed in uncompiled form. + + The long: +Copyright (c) 2016 Jonathan Dearborn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef _SDL_FONTCACHE_H__ +#define _SDL_FONTCACHE_H__ + +#include "SDL.h" +#include "SDL_ttf.h" + +#ifdef FC_USE_SDL_GPU + #include "SDL_gpu.h" +#endif + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// Let's pretend this exists... +#define TTF_STYLE_OUTLINE 16 + + + +// Differences between SDL_Renderer and SDL_gpu +#ifdef FC_USE_SDL_GPU +#define FC_Rect GPU_Rect +#define FC_Target GPU_Target +#define FC_Image GPU_Image +#define FC_Log GPU_LogError +#else +#define FC_Rect SDL_Rect +#define FC_Target SDL_Renderer +#define FC_Image SDL_Texture +#define FC_Log SDL_Log +#endif + + +// SDL_FontCache types + +typedef enum +{ + FC_ALIGN_LEFT, + FC_ALIGN_CENTER, + FC_ALIGN_RIGHT +} FC_AlignEnum; + +typedef enum +{ + FC_FILTER_NEAREST, + FC_FILTER_LINEAR +} FC_FilterEnum; + +typedef struct FC_Scale +{ + float x; + float y; + +} FC_Scale; + +typedef struct FC_Effect +{ + FC_AlignEnum alignment; + FC_Scale scale; + SDL_Color color; + +} FC_Effect; + +// Opaque type +typedef struct FC_Font FC_Font; + + +typedef struct FC_GlyphData +{ + SDL_Rect rect; + int cache_level; + +} FC_GlyphData; + + + + +// Object creation + +FC_Rect FC_MakeRect(float x, float y, float w, float h); + +FC_Scale FC_MakeScale(float x, float y); + +SDL_Color FC_MakeColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +FC_Effect FC_MakeEffect(FC_AlignEnum alignment, FC_Scale scale, SDL_Color color); + +FC_GlyphData FC_MakeGlyphData(int cache_level, Sint16 x, Sint16 y, Uint16 w, Uint16 h); + + + +// Font object + +FC_Font* FC_CreateFont(void); + +#ifdef FC_USE_SDL_GPU +Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style); + +Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color); + +Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style); +#else +Uint8 FC_LoadFont(FC_Font* font, SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style); + +Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color); + +Uint8 FC_LoadFont_RW(FC_Font* font, SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style); +#endif + +void FC_ClearFont(FC_Font* font); + +void FC_FreeFont(FC_Font* font); + + + +// Built-in loading strings + +char* FC_GetStringASCII(void); + +char* FC_GetStringLatin1(void); + +char* FC_GetStringASCII_Latin1(void); + + +// UTF-8 to SDL_FontCache codepoint conversion + +/*! +Returns the Uint32 codepoint (not UTF-32) parsed from the given UTF-8 string. +\param c A pointer to a string of proper UTF-8 character values. +\param advance_pointer If true, the source pointer will be incremented to skip the extra bytes from multibyte codepoints. +*/ +Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer); + +/*! +Parses the given codepoint and stores the UTF-8 bytes in 'result'. The result is NULL terminated. +\param result A memory buffer for the UTF-8 values. Must be at least 5 bytes long. +\param codepoint The Uint32 codepoint to parse (not UTF-32). +*/ +void FC_GetUTF8FromCodepoint(char* result, Uint32 codepoint); + + +// UTF-8 string operations + +/*! Allocates a new string of 'size' bytes that is already NULL-terminated. The NULL byte counts toward the size limit, as usual. Returns NULL if size is 0. */ +char* U8_alloc(unsigned int size); + +/*! Deallocates the given string. */ +void U8_free(char* string); + +/*! Allocates a copy of the given string. */ +char* U8_strdup(const char* string); + +/*! Returns the number of UTF-8 characters in the given string. */ +int U8_strlen(const char* string); + +/*! Returns the number of bytes in the UTF-8 multibyte character pointed at by 'character'. */ +int U8_charsize(const char* character); + +/*! Copies the source multibyte character into the given buffer without overrunning it. Returns 0 on failure. */ +int U8_charcpy(char* buffer, const char* source, int buffer_size); + +/*! Returns a pointer to the next UTF-8 character. */ +const char* U8_next(const char* string); + +/*! Inserts a UTF-8 string into 'string' at the given position. Use a position of -1 to append. Returns 0 when unable to insert the string. */ +int U8_strinsert(char* string, int position, const char* source, int max_bytes); + +/*! Erases the UTF-8 character at the given position, moving the subsequent characters down. */ +void U8_strdel(char* string, int position); + + +// Internal settings + +/*! Sets the string from which to load the initial glyphs. Use this if you need upfront loading for any reason (such as lack of render-target support). */ +void FC_SetLoadingString(FC_Font* font, const char* string); + +/*! Returns the size of the internal buffer which is used for unpacking variadic text data. This buffer is shared by all FC_Fonts. */ +unsigned int FC_GetBufferSize(void); + +/*! Changes the size of the internal buffer which is used for unpacking variadic text data. This buffer is shared by all FC_Fonts. */ +void FC_SetBufferSize(unsigned int size); + +void FC_SetRenderCallback(FC_Rect (*callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale)); + +FC_Rect FC_DefaultRenderCallback(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale); + + +// Custom caching + +/*! Returns the number of cache levels that are active. */ +int FC_GetNumCacheLevels(FC_Font* font); + +/*! Returns the cache source texture at the given cache level. */ +FC_Image* FC_GetGlyphCacheLevel(FC_Font* font, int cache_level); + +// TODO: Specify ownership of the texture (should be shareable) +/*! Sets a cache source texture for rendering. New cache levels must be sequential. */ +Uint8 FC_SetGlyphCacheLevel(FC_Font* font, int cache_level, FC_Image* cache_texture); + +/*! Copies the given surface to the given cache level as a texture. New cache levels must be sequential. */ +Uint8 FC_UploadGlyphCache(FC_Font* font, int cache_level, SDL_Surface* data_surface); + + +/*! Returns the number of codepoints that are stored in the font's glyph data map. */ +unsigned int FC_GetNumCodepoints(FC_Font* font); + +/*! Copies the stored codepoints into the given array. */ +void FC_GetCodepoints(FC_Font* font, Uint32* result); + +/*! Stores the glyph data for the given codepoint in 'result'. Returns 0 if the codepoint was not found in the cache. */ +Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint); + +/*! Sets the glyph data for the given codepoint. Duplicates are not checked. Returns a pointer to the stored data. */ +FC_GlyphData* FC_SetGlyphData(FC_Font* font, Uint32 codepoint, FC_GlyphData glyph_data); + + +// Rendering + +FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...); +FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignEnum align, const char* formatted_text, ...); +FC_Rect FC_DrawScale(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* formatted_text, ...); +FC_Rect FC_DrawColor(FC_Font* font, FC_Target* dest, float x, float y, SDL_Color color, const char* formatted_text, ...); +FC_Rect FC_DrawEffect(FC_Font* font, FC_Target* dest, float x, float y, FC_Effect effect, const char* formatted_text, ...); + +FC_Rect FC_DrawBox(FC_Font* font, FC_Target* dest, FC_Rect box, const char* formatted_text, ...); +FC_Rect FC_DrawBoxAlign(FC_Font* font, FC_Target* dest, FC_Rect box, FC_AlignEnum align, const char* formatted_text, ...); +FC_Rect FC_DrawBoxScale(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Scale scale, const char* formatted_text, ...); +FC_Rect FC_DrawBoxColor(FC_Font* font, FC_Target* dest, FC_Rect box, SDL_Color color, const char* formatted_text, ...); +FC_Rect FC_DrawBoxEffect(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Effect effect, const char* formatted_text, ...); + +FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...); +FC_Rect FC_DrawColumnAlign(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_AlignEnum align, const char* formatted_text, ...); +FC_Rect FC_DrawColumnScale(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Scale scale, const char* formatted_text, ...); +FC_Rect FC_DrawColumnColor(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, SDL_Color color, const char* formatted_text, ...); +FC_Rect FC_DrawColumnEffect(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Effect effect, const char* formatted_text, ...); + + +// Getters + +FC_FilterEnum FC_GetFilterMode(FC_Font* font); +Uint16 FC_GetLineHeight(FC_Font* font); +Uint16 FC_GetHeight(FC_Font* font, const char* formatted_text, ...); +Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...); + +// Returns a 1-pixel wide box in front of the character in the given position (index) +FC_Rect FC_GetCharacterOffset(FC_Font* font, Uint16 position_index, int column_width, const char* formatted_text, ...); +Uint16 FC_GetColumnHeight(FC_Font* font, Uint16 width, const char* formatted_text, ...); + +int FC_GetAscent(FC_Font* font, const char* formatted_text, ...); +int FC_GetDescent(FC_Font* font, const char* formatted_text, ...); +int FC_GetBaseline(FC_Font* font); +int FC_GetSpacing(FC_Font* font); +int FC_GetLineSpacing(FC_Font* font); +Uint16 FC_GetMaxWidth(FC_Font* font); +SDL_Color FC_GetDefaultColor(FC_Font* font); + +Uint8 FC_InRect(float x, float y, FC_Rect input_rect); +// Given an offset (x,y) from the text draw position (the upper-left corner), returns the character position (UTF-8 index) +Uint16 FC_GetPositionFromOffset(FC_Font* font, float x, float y, int column_width, FC_AlignEnum align, const char* formatted_text, ...); + +// Setters + +void FC_SetFilterMode(FC_Font* font, FC_FilterEnum filter); +void FC_SetSpacing(FC_Font* font, int LetterSpacing); +void FC_SetLineSpacing(FC_Font* font, int LineSpacing); +void FC_SetDefaultColor(FC_Font* font, SDL_Color color); + + +#ifdef __cplusplus +} +#endif + + + +#endif \ No newline at end of file diff --git a/Stub/appfat.cpp b/Stub/appfat.cpp new file mode 100644 index 000000000..9646fdf29 --- /dev/null +++ b/Stub/appfat.cpp @@ -0,0 +1,55 @@ +#include "../types.h" +#include "stubs.h" + +char empty_string = 0; + +void TermMsg(char *pszFmt, ...) +{ + eprintf("%s: %s\n", __FUNCTION__, pszFmt); + abort(); +} + +void __fastcall ErrDlg(int template_id, int error_code, char *log_file_path, int log_line_nr) +{ + UNIMPLEMENTED(); +} + +void __fastcall ErrOkDlg(int template_id, int error_code, char *log_file_path, int log_line_nr) +{ + UNIMPLEMENTED(); +} + +void __fastcall DirErrorDlg(char *error) +{ + UNIMPLEMENTED(); +} + +bool __cdecl InsertCDDlg() +{ + UNIMPLEMENTED(); +} + +void __fastcall FileErrDlg(char *error) +{ + UNIMPLEMENTED(); +} + +void __fastcall DDErrMsg(int error_code, int log_line_nr, char *log_file_path) +{ + UNIMPLEMENTED(); +} + +void __fastcall DiskFreeDlg(char *error) +{ + UNIMPLEMENTED(); +} + +void DrawDlg(char *pszFmt, ...) +{ + UNIMPLEMENTED(); +} + +char *__cdecl TraceLastError() +{ + return NULL; +} diff --git a/Stub/capture.cpp b/Stub/capture.cpp new file mode 100644 index 000000000..6747fb6a8 --- /dev/null +++ b/Stub/capture.cpp @@ -0,0 +1,7 @@ +#include "../types.h" +#include "stubs.h" + +void __cdecl CaptureScreen() +{ + DUMMY(); +} diff --git a/Stub/diabloui.cpp b/Stub/diabloui.cpp new file mode 100644 index 000000000..021f59d69 --- /dev/null +++ b/Stub/diabloui.cpp @@ -0,0 +1,175 @@ +#include + +#include "../types.h" +#include "stubs.h" + +void __cdecl UiDestroy() +{ + DUMMY(); +} + +void __stdcall UiTitleDialog(int a1) +{ + printf("UiTitleDialog\n"); + DUMMY(); +} + +void __cdecl UiInitialize() +{ + DUMMY(); +} + +void __stdcall UiCopyProtError(int a1) +{ + UNIMPLEMENTED(); +} + +void __stdcall UiAppActivate(int a1) +{ + UNIMPLEMENTED(); +} + +int __stdcall UiValidPlayerName(char *a1) +{ + UNIMPLEMENTED(); +} + +int __stdcall UiSelHeroMultDialog(void *fninfo, void *fncreate, void *fnremove, void *fnstats, int *a5, int *a6, + char *name) +{ + UNIMPLEMENTED(); +} + +std::vector<_uiheroinfo> hero_infos; + +static void __stdcall ui_add_hero_info(_uiheroinfo *info) +{ + hero_infos.emplace_back(*info); +} + +int __stdcall UiSelHeroSingDialog(void (*fninfo)(void(__stdcall *ui_add_hero_info)(_uiheroinfo *)), + void (*fncreate)(_uiheroinfo *heroinfo), void (*fnremove)(), void (*fnstats)(), + int *a5, char *name, int *difficulty) +{ + DUMMY(); + + fninfo(&ui_add_hero_info); + + if (!hero_infos.empty()) { + //const char *hero_name = hero_infos[0].name; + DUMMY_PRINT("use hero: %s", chr_name_str); + strcpy(name, chr_name_str); + + *a5 = 2; + } else { + const char *test_name = "tester"; + DUMMY_PRINT("create hero: %s", test_name); + + strcpy(name, test_name); + + _uiheroinfo hero_info = {0}; + strcpy(hero_info.name, test_name); + hero_info.heroclass = 2; // Sorcerer + + fncreate(&hero_info); + } + + return TRUE; +} + +void __stdcall UiCreditsDialog(int a1) +{ + UNIMPLEMENTED(); +} + +int __stdcall UiMainMenuDialog(char *name, int *a2, void *fnSound, int a4) +{ + DUMMY(); + *a2 = MAINMENU_SINGLE_PLAYER; + return TRUE; +} + +int __stdcall UiProgressDialog(HWND window, char *msg, int a3, void *fnfunc, int a5) +{ + UNIMPLEMENTED(); +} + +int __cdecl UiProfileGetString() +{ + DUMMY(); + return 0; +} + +void __cdecl UiProfileCallback() +{ + UNIMPLEMENTED(); +} + +void __cdecl UiProfileDraw() +{ + UNIMPLEMENTED(); +} + +void __cdecl UiCategoryCallback() +{ + UNIMPLEMENTED(); +} + +void __cdecl UiGetDataCallback() +{ + UNIMPLEMENTED(); +} + +void __cdecl UiAuthCallback() +{ + UNIMPLEMENTED(); +} + +void __cdecl UiSoundCallback() +{ + UNIMPLEMENTED(); +} + +void __cdecl UiMessageBoxCallback() +{ + UNIMPLEMENTED(); +} + +void __cdecl UiDrawDescCallback() +{ + UNIMPLEMENTED(); +} + +void __cdecl UiCreateGameCallback() +{ + UNIMPLEMENTED(); +} + +void __cdecl UiArtCallback() +{ + UNIMPLEMENTED(); +} + +int __stdcall UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, + _SNETVERSIONDATA *file_info, int *a6) +{ + UNIMPLEMENTED(); +} + +int __stdcall UiSelectProvider(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, + _SNETVERSIONDATA *file_info, int *type) +{ + UNIMPLEMENTED(); +} + +int __stdcall UiCreatePlayerDescription(_uiheroinfo *info, int mode, char *desc) +{ + UNIMPLEMENTED(); +} + +int __stdcall UiSetupPlayerInfo(char *str, _uiheroinfo *info, int mode) +{ + printf("UiSetupPlayerInfo\n"); + DUMMY_PRINT("chr: %s", str); + return TRUE; +} diff --git a/Stub/dthread.cpp b/Stub/dthread.cpp new file mode 100644 index 000000000..5dc2fc75c --- /dev/null +++ b/Stub/dthread.cpp @@ -0,0 +1,22 @@ +#include "../types.h" +#include "stubs.h" + +void __cdecl dthread_start() +{ + DUMMY(); +} + +void __cdecl dthread_cleanup() +{ + DUMMY(); +} + +void __fastcall dthread_send_delta(int pnum, char cmd, void *pbSrc, int dwLen) +{ + DUMMY(); +} + +void __fastcall dthread_remove_player(int pnum) +{ + UNIMPLEMENTED(); +} diff --git a/Stub/dx.cpp b/Stub/dx.cpp new file mode 100644 index 000000000..4c840cf6e --- /dev/null +++ b/Stub/dx.cpp @@ -0,0 +1,263 @@ +#include "miniwin_sdl.h" + +#include "../types.h" +#include "stubs.h" + +Screen *gpBuffer; + +IDirectDraw *lpDDInterface; +IDirectDrawSurface *lpDDSPrimary; +IDirectDrawSurface *lpDDSBackBuf; +IDirectDrawPalette *lpDDPalette; + +char gbBackBuf; // unread +char gbEmulate; // unread + +SDL_Window *window; +SDL_Renderer *renderer; +SDL_Texture *texture; + +SDL_Surface *surface, *pal_surface; +SDL_Palette *palette; + +bool surface_dirty; + +class StubSurface : public IDirectDrawSurface +{ + virtual HRESULT QueryInterface(void *, void **) { UNIMPLEMENTED(); }; + virtual ULONG AddRef() { UNIMPLEMENTED(); }; + virtual ULONG Release() { UNIMPLEMENTED(); }; + + virtual HRESULT AddAttachedSurface(IDirectDrawSurface *) { UNIMPLEMENTED(); }; + virtual HRESULT AddOverlayDirtyRect(RECT *) { UNIMPLEMENTED(); }; + virtual HRESULT Blt(RECT *, IDirectDrawSurface *, RECT *, unsigned int, void *) { UNIMPLEMENTED(); }; + virtual HRESULT BltBatch(void *, unsigned int, unsigned int) { UNIMPLEMENTED(); }; + + virtual HRESULT BltFast(unsigned int x, unsigned int y, IDirectDrawSurface *surf, RECT *rect, unsigned int) + { + DUMMY_ONCE(); + + assert(surf == lpDDSBackBuf); + + int w = rect->right - rect->left + 1; + int h = rect->bottom - rect->top + 1; + SDL_Rect src_rect = {rect->left, rect->top, w, h}; + SDL_Rect dst_rect = {(int)x, (int)y, w, h}; + SDL_CHECK(SDL_BlitSurface(pal_surface, &src_rect, surface, &dst_rect)); + + surface_dirty = true; + return S_OK; + }; + + virtual HRESULT DeleteAttachedSurface(unsigned int, IDirectDrawSurface *) { UNIMPLEMENTED(); }; + virtual HRESULT EnumAttachedSurfaces(void *, void *) { UNIMPLEMENTED(); }; + virtual HRESULT EnumOverlayZOrders(unsigned int, void *, void *) { UNIMPLEMENTED(); }; + virtual HRESULT Flip(IDirectDrawSurface *, unsigned int) { UNIMPLEMENTED(); }; + virtual HRESULT GetAttachedSurface(_DDSCAPS *, IDirectDrawSurface **) { UNIMPLEMENTED(); }; + virtual HRESULT GetBltStatus(unsigned int) { UNIMPLEMENTED(); }; + virtual HRESULT GetCaps(_DDSCAPS *) { UNIMPLEMENTED(); }; + virtual HRESULT GetClipper(void **) { UNIMPLEMENTED(); }; + virtual HRESULT GetColorKey(unsigned int, _DDCOLORKEY *) { UNIMPLEMENTED(); }; + virtual HRESULT GetDC(void **) + { + DUMMY_ONCE(); + return S_OK; + }; + virtual HRESULT GetFlipStatus(unsigned int) { UNIMPLEMENTED(); }; + virtual HRESULT GetOverlayPosition(int *, int *) { UNIMPLEMENTED(); }; + virtual HRESULT GetPalette(IDirectDrawPalette **) { UNIMPLEMENTED(); }; + virtual HRESULT GetPixelFormat(_DDPIXELFORMAT *) { UNIMPLEMENTED(); }; + virtual HRESULT GetSurfaceDesc(_DDSURFACEDESC *) { UNIMPLEMENTED(); }; + virtual HRESULT Initialize(IDirectDraw *, _DDSURFACEDESC *) { UNIMPLEMENTED(); }; + + virtual HRESULT IsLost() + { + DUMMY_ONCE(); + return S_OK; + }; + + virtual HRESULT Lock(RECT *, _DDSURFACEDESC *, unsigned int, void *) { UNIMPLEMENTED(); }; + virtual HRESULT ReleaseDC(void *) + { + DUMMY_ONCE(); + return S_OK; + }; + virtual HRESULT Restore() { UNIMPLEMENTED(); }; + virtual HRESULT SetClipper(void *) { UNIMPLEMENTED(); }; + virtual HRESULT SetColorKey(unsigned int, _DDCOLORKEY *) { UNIMPLEMENTED(); }; + virtual HRESULT SetOverlayPosition(int, int) { UNIMPLEMENTED(); }; + virtual HRESULT SetPalette(IDirectDrawPalette *) { UNIMPLEMENTED(); }; + virtual HRESULT Unlock(void *) { UNIMPLEMENTED(); }; + virtual HRESULT UpdateOverlay(RECT *, IDirectDrawSurface *, RECT *, unsigned int, void *) { UNIMPLEMENTED(); }; + virtual HRESULT UpdateOverlayDisplay(unsigned int) { UNIMPLEMENTED(); }; + virtual HRESULT UpdateOverlayZOrder(unsigned int, IDirectDrawSurface *) { UNIMPLEMENTED(); }; +}; + +class StubPalette : public IDirectDrawPalette +{ + virtual HRESULT QueryInterface(void *, void **) { UNIMPLEMENTED(); }; + virtual ULONG AddRef() { UNIMPLEMENTED(); }; + virtual ULONG Release() { UNIMPLEMENTED(); }; + + virtual HRESULT GetCaps(LPDWORD) { UNIMPLEMENTED(); }; + virtual HRESULT GetEntries(DWORD, DWORD, DWORD, LPPALETTEENTRY) { UNIMPLEMENTED(); }; + virtual HRESULT Initialize(LPDIRECTDRAW, DWORD, LPPALETTEENTRY) { UNIMPLEMENTED(); }; + virtual HRESULT SetEntries(DWORD, DWORD, DWORD, LPPALETTEENTRY) { UNIMPLEMENTED(); }; +}; + +class StubDraw : public IDirectDraw +{ + virtual HRESULT QueryInterface(void *, void **) { UNIMPLEMENTED(); }; + virtual ULONG AddRef() { UNIMPLEMENTED(); }; + virtual ULONG Release() { UNIMPLEMENTED(); }; + + virtual HRESULT Compact() { UNIMPLEMENTED(); }; + virtual HRESULT CreateClipper(DWORD, void **, IUnknown *) { UNIMPLEMENTED(); }; + virtual HRESULT CreatePalette(DWORD, LPPALETTEENTRY, IDirectDrawPalette **, IUnknown *) { UNIMPLEMENTED(); }; + virtual HRESULT CreateSurface(LPDDSURFACEDESC, IDirectDrawSurface **, IUnknown *) { UNIMPLEMENTED(); }; + virtual HRESULT DuplicateSurface(LPDIRECTDRAWSURFACE, IDirectDrawSurface **) { UNIMPLEMENTED(); }; + virtual HRESULT EnumDisplayModes(DWORD, LPDDSURFACEDESC, LPVOID, LPDDENUMMODESCALLBACK) { UNIMPLEMENTED(); }; + virtual HRESULT EnumSurfaces(DWORD, LPDDSURFACEDESC, LPVOID, LPDDENUMSURFACESCALLBACK) { UNIMPLEMENTED(); }; + virtual HRESULT FlipToGDISurface() { UNIMPLEMENTED(); }; + virtual HRESULT GetCaps(LPDDCAPS, LPDDCAPS) { UNIMPLEMENTED(); }; + virtual HRESULT GetDisplayMode(LPDDSURFACEDESC) { UNIMPLEMENTED(); }; + virtual HRESULT GetFourCCCodes(LPDWORD, LPDWORD) { UNIMPLEMENTED(); }; + virtual HRESULT GetGDISurface(IDirectDrawSurface **) { UNIMPLEMENTED(); }; + virtual HRESULT GetMonitorFrequency(LPDWORD) { UNIMPLEMENTED(); }; + virtual HRESULT GetScanLine(LPDWORD) { UNIMPLEMENTED(); }; + virtual HRESULT GetVerticalBlankStatus(BOOL *) { UNIMPLEMENTED(); }; + virtual HRESULT Initialize(GUID *) { UNIMPLEMENTED(); }; + virtual HRESULT RestoreDisplayMode() { UNIMPLEMENTED(); }; + virtual HRESULT SetCooperativeLevel(HWND, DWORD) { UNIMPLEMENTED(); }; + virtual HRESULT SetDisplayMode(DWORD, DWORD, DWORD) { UNIMPLEMENTED(); }; + + virtual HRESULT WaitForVerticalBlank(DWORD, HANDLE) + { + DUMMY(); + return S_OK; + }; +}; + +StubDraw stub_draw; +StubSurface stub_surface; +StubPalette stub_palette; + +void __fastcall dx_init(HWND hWnd) +{ + DUMMY(); + + SDL_CHECK(SDL_Init(SDL_INIT_VIDEO)); + + window = SDL_CreateWindow("devil-test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN); + assert(window); + + // Hack since ShowCursor is called before dx_init() + SDL_ShowCursor(SDL_DISABLE); + + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC); + assert(renderer); + + // FUTURE: Use SDL_CreateRGBSurfaceWithFormat with SDL_PIXELFORMAT_RGBA8888 + surface = SDL_CreateRGBSurface(0, 640, 480, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); + assert(surface); + + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, 640, 480); + assert(texture); + + palette = SDL_AllocPalette(256); + assert(palette); + + gbActive = TRUE; + + lpDDInterface = &stub_draw; + lpDDSPrimary = &stub_surface; + lpDDSBackBuf = &stub_surface; + lpDDPalette = &stub_palette; +} + +static void sdl_update_entire_surface() +{ + assert(surface && pal_surface); + SDL_Rect src_rect = {64, 160, 640, 480}; + SDL_CHECK(SDL_BlitSurface(pal_surface, &src_rect, surface, NULL)); +} + +static void sdl_present_surface() +{ + assert(!SDL_MUSTLOCK(surface)); + SDL_CHECK(SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch)); + + SDL_CHECK(SDL_RenderCopy(renderer, texture, NULL, NULL)); + SDL_RenderPresent(renderer); + + surface_dirty = false; +} + +BOOL STORMAPI SDrawUpdatePalette(unsigned int firstentry, unsigned int numentries, PALETTEENTRY *pPalEntries, int a4) +{ + DUMMY_PRINT("first: %d num: %d", firstentry, numentries); + assert(palette); + + assert(firstentry == 0); + assert(numentries == 256); + + SDL_Color colors[256]; + for (int i = firstentry; i < numentries; i++) { + SDL_Color *c = &colors[i]; + PALETTEENTRY *p = &pPalEntries[i]; + c->r = p->peRed; + c->g = p->peGreen; + c->b = p->peBlue; + c->a = SDL_ALPHA_OPAQUE; + } + + SDL_CHECK(SDL_SetPaletteColors(palette, colors, firstentry, numentries)); + + if (pal_surface) { + sdl_update_entire_surface(); + sdl_present_surface(); + } + + return TRUE; +} + +const int pitch = 640 + 64 + 64; + +void __cdecl lock_buf_priv() +{ + if (!gpBuffer) { + gpBuffer = (Screen *)malloc(sizeof(Screen)); + gpBufEnd += (unsigned int)gpBuffer; + + pal_surface = SDL_CreateRGBSurfaceFrom(gpBuffer, pitch, 160 + 480 + 16, 8, pitch, 0, 0, 0, 0); + assert(pal_surface); + + SDL_CHECK(SDL_SetSurfacePalette(pal_surface, palette)); + } +} + +void __cdecl unlock_buf_priv() +{ + gpBufEnd -= (unsigned int)gpBufEnd; + + if (!surface_dirty) { + return; + } + + sdl_present_surface(); +} + +void __cdecl dx_reinit() +{ + UNIMPLEMENTED(); +} + +WINBOOL WINAPI TextOutA(HDC hdc, int x, int y, LPCSTR lpString, int c) +{ + DUMMY_ONCE(); + + assert(window); + SDL_SetWindowTitle(window, lpString); + + return TRUE; +} diff --git a/Stub/effects.cpp b/Stub/effects.cpp new file mode 100644 index 000000000..6ede17e6f --- /dev/null +++ b/Stub/effects.cpp @@ -0,0 +1,952 @@ +// HEADER_GOES_HERE + +#include "../types.h" + +int effects_cpp_init_value; // weak + +#ifndef NO_GLOBALS +int sfxdelay; // weak +int sfxdnum; +void *sfx_stream; +TSFX *sfx_data_cur; +#endif + +const int effects_inf = 0x7F800000; // weak +const char monster_action_sounds[] = {'a', 'h', 'd', 's'}; // idb + +/* data */ + +TSFX sgSFX[NUM_SFX] = {{2u, "Sfx\\Misc\\Walk1.wav", NULL}, {2u, "Sfx\\Misc\\Walk2.wav", NULL}, + {2u, "Sfx\\Misc\\Walk3.wav", NULL}, {2u, "Sfx\\Misc\\Walk4.wav", NULL}, + {2u, "Sfx\\Misc\\BFire.wav", NULL}, {2u, "Sfx\\Misc\\Fmag.wav", NULL}, + {2u, "Sfx\\Misc\\Tmag.wav", NULL}, {2u, "Sfx\\Misc\\Lghit.wav", NULL}, + {2u, "Sfx\\Misc\\Lghit1.wav", NULL}, {2u, "Sfx\\Misc\\Swing.wav", NULL}, + {2u, "Sfx\\Misc\\Swing2.wav", NULL}, {2u, "Sfx\\Misc\\Dead.wav", NULL}, + {1u, "Sfx\\Misc\\Questdon.wav", NULL}, {2u, "Sfx\\Items\\Armrfkd.wav", NULL}, + {2u, "Sfx\\Items\\Barlfire.wav", NULL}, {2u, "Sfx\\Items\\Barrel.wav", NULL}, + {2u, "Sfx\\Items\\Bhit.wav", NULL}, {2u, "Sfx\\Items\\Bhit1.wav", NULL}, + {2u, "Sfx\\Items\\Chest.wav", NULL}, {2u, "Sfx\\Items\\Doorclos.wav", NULL}, + {2u, "Sfx\\Items\\Dooropen.wav", NULL}, {2u, "Sfx\\Items\\Flipanvl.wav", NULL}, + {2u, "Sfx\\Items\\Flipaxe.wav", NULL}, {2u, "Sfx\\Items\\Flipblst.wav", NULL}, + {2u, "Sfx\\Items\\Flipbody.wav", NULL}, {2u, "Sfx\\Items\\Flipbook.wav", NULL}, + {2u, "Sfx\\Items\\Flipbow.wav", NULL}, {2u, "Sfx\\Items\\Flipcap.wav", NULL}, + {2u, "Sfx\\Items\\Flipharm.wav", NULL}, {2u, "Sfx\\Items\\Fliplarm.wav", NULL}, + {2u, "Sfx\\Items\\Flipmag.wav", NULL}, {2u, "Sfx\\Items\\Flipmag1.wav", NULL}, + {2u, "Sfx\\Items\\Flipmush.wav", NULL}, {2u, "Sfx\\Items\\Flippot.wav", NULL}, + {2u, "Sfx\\Items\\Flipring.wav", NULL}, {2u, "Sfx\\Items\\Fliprock.wav", NULL}, + {2u, "Sfx\\Items\\Flipscrl.wav", NULL}, {2u, "Sfx\\Items\\Flipshld.wav", NULL}, + {2u, "Sfx\\Items\\Flipsign.wav", NULL}, {2u, "Sfx\\Items\\Flipstaf.wav", NULL}, + {2u, "Sfx\\Items\\Flipswor.wav", NULL}, {2u, "Sfx\\Items\\Gold.wav", NULL}, + {2u, "Sfx\\Items\\Hlmtfkd.wav", NULL}, {2u, "Sfx\\Items\\Invanvl.wav", NULL}, + {2u, "Sfx\\Items\\Invaxe.wav", NULL}, {2u, "Sfx\\Items\\Invblst.wav", NULL}, + {2u, "Sfx\\Items\\Invbody.wav", NULL}, {2u, "Sfx\\Items\\Invbook.wav", NULL}, + {2u, "Sfx\\Items\\Invbow.wav", NULL}, {2u, "Sfx\\Items\\Invcap.wav", NULL}, + {2u, "Sfx\\Items\\Invgrab.wav", NULL}, {2u, "Sfx\\Items\\Invharm.wav", NULL}, + {2u, "Sfx\\Items\\Invlarm.wav", NULL}, {2u, "Sfx\\Items\\Invmush.wav", NULL}, + {2u, "Sfx\\Items\\Invpot.wav", NULL}, {2u, "Sfx\\Items\\Invring.wav", NULL}, + {2u, "Sfx\\Items\\Invrock.wav", NULL}, {2u, "Sfx\\Items\\Invscrol.wav", NULL}, + {2u, "Sfx\\Items\\Invshiel.wav", NULL}, {2u, "Sfx\\Items\\Invsign.wav", NULL}, + {2u, "Sfx\\Items\\Invstaf.wav", NULL}, {2u, "Sfx\\Items\\Invsword.wav", NULL}, + {2u, "Sfx\\Items\\Lever.wav", NULL}, {2u, "Sfx\\Items\\Magic.wav", NULL}, + {2u, "Sfx\\Items\\Magic1.wav", NULL}, {2u, "Sfx\\Items\\Readbook.wav", NULL}, + {2u, "Sfx\\Items\\Sarc.wav", NULL}, {2u, "Sfx\\Items\\Shielfkd.wav", NULL}, + {2u, "Sfx\\Items\\Swrdfkd.wav", NULL}, {4u, "Sfx\\Items\\Titlemov.wav", NULL}, + {4u, "Sfx\\Items\\Titlslct.wav", NULL}, {4u, "Sfx\\Misc\\blank.wav", NULL}, + {2u, "Sfx\\Items\\Trap.wav", NULL}, {2u, "Sfx\\Misc\\Cast1.wav", NULL}, + {2u, "Sfx\\Misc\\Cast10.wav", NULL}, {2u, "Sfx\\Misc\\Cast12.wav", NULL}, + {2u, "Sfx\\Misc\\Cast2.wav", NULL}, {2u, "Sfx\\Misc\\Cast3.wav", NULL}, + {2u, "Sfx\\Misc\\Cast4.wav", NULL}, {2u, "Sfx\\Misc\\Cast5.wav", NULL}, + {2u, "Sfx\\Misc\\Cast6.wav", NULL}, {2u, "Sfx\\Misc\\Cast7.wav", NULL}, + {2u, "Sfx\\Misc\\Cast8.wav", NULL}, {2u, "Sfx\\Misc\\Cast9.wav", NULL}, + {2u, "Sfx\\Misc\\Healing.wav", NULL}, {2u, "Sfx\\Misc\\Repair.wav", NULL}, + {2u, "Sfx\\Misc\\Acids1.wav", NULL}, {2u, "Sfx\\Misc\\Acids2.wav", NULL}, + {2u, "Sfx\\Misc\\Apoc.wav", NULL}, {2u, "Sfx\\Misc\\Arrowall.wav", NULL}, + {2u, "Sfx\\Misc\\Bldboil.wav", NULL}, {2u, "Sfx\\Misc\\Blodstar.wav", NULL}, + {2u, "Sfx\\Misc\\Blsimpt.wav", NULL}, {2u, "Sfx\\Misc\\Bonesp.wav", NULL}, + {2u, "Sfx\\Misc\\Bsimpct.wav", NULL}, {2u, "Sfx\\Misc\\Caldron.wav", NULL}, + {2u, "Sfx\\Misc\\Cbolt.wav", NULL}, {2u, "Sfx\\Misc\\Chltning.wav", NULL}, + {2u, "Sfx\\Misc\\DSerp.wav", NULL}, {2u, "Sfx\\Misc\\Elecimp1.wav", NULL}, + {2u, "Sfx\\Misc\\Elementl.wav", NULL}, {2u, "Sfx\\Misc\\Ethereal.wav", NULL}, + {2u, "Sfx\\Misc\\Fball.wav", NULL}, {2u, "Sfx\\Misc\\Fbolt1.wav", NULL}, + {2u, "Sfx\\Misc\\Fbolt2.wav", NULL}, {2u, "Sfx\\Misc\\Firimp1.wav", NULL}, + {2u, "Sfx\\Misc\\Firimp2.wav", NULL}, {2u, "Sfx\\Misc\\Flamwave.wav", NULL}, + {2u, "Sfx\\Misc\\Flash.wav", NULL}, {2u, "Sfx\\Misc\\Fountain.wav", NULL}, + {2u, "Sfx\\Misc\\Golum.wav", NULL}, {2u, "Sfx\\Misc\\Golumded.wav", NULL}, + {2u, "Sfx\\Misc\\Gshrine.wav", NULL}, {2u, "Sfx\\Misc\\Guard.wav", NULL}, + {2u, "Sfx\\Misc\\Grdlanch.wav", NULL}, {2u, "Sfx\\Misc\\Holybolt.wav", NULL}, + {2u, "Sfx\\Misc\\Hyper.wav", NULL}, {2u, "Sfx\\Misc\\Infravis.wav", NULL}, + {2u, "Sfx\\Misc\\Invisibl.wav", NULL}, {2u, "Sfx\\Misc\\Invpot.wav", NULL}, + {2u, "Sfx\\Misc\\Lning1.wav", NULL}, {2u, "Sfx\\Misc\\Ltning.wav", NULL}, + {2u, "Sfx\\Misc\\Mshield.wav", NULL}, {2u, "Sfx\\Misc\\Nova.wav", NULL}, + {2u, "Sfx\\Misc\\Portal.wav", NULL}, {2u, "Sfx\\Misc\\Puddle.wav", NULL}, + {2u, "Sfx\\Misc\\Resur.wav", NULL}, {2u, "Sfx\\Misc\\Scurse.wav", NULL}, + {2u, "Sfx\\Misc\\Scurimp.wav", NULL}, {2u, "Sfx\\Misc\\Sentinel.wav", NULL}, + {2u, "Sfx\\Misc\\Shatter.wav", NULL}, {2u, "Sfx\\Misc\\Soulfire.wav", NULL}, + {2u, "Sfx\\Misc\\Spoutlop.wav", NULL}, {2u, "Sfx\\Misc\\Spoutstr.wav", NULL}, + {2u, "Sfx\\Misc\\Storm.wav", NULL}, {2u, "Sfx\\Misc\\Trapdis.wav", NULL}, + {2u, "Sfx\\Misc\\Teleport.wav", NULL}, {2u, "Sfx\\Misc\\Vtheft.wav", NULL}, + {2u, "Sfx\\Misc\\Wallloop.wav", NULL}, {2u, "Sfx\\Misc\\Wallstrt.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid01.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid02.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid03.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid04.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid05.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid06.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid07.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid08.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid09.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid10.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid11.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid12.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid13.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid14.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid15.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid16.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid17.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid18.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid19.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid20.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid21.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid22.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid23.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid24.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid25.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid26.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid27.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid28.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid29.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid30.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid31.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid32.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid33.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid34.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid35.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid36.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid37.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid38.wav", NULL}, + {1u, "Sfx\\Towners\\Bmaid39.wav", NULL}, {1u, "Sfx\\Towners\\Bmaid40.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith01.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith02.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith03.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith04.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith05.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith06.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith07.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith08.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith09.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith10.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith11.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith12.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith13.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith14.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith15.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith16.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith17.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith18.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith19.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith20.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith21.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith22.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith23.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith24.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith25.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith26.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith27.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith28.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith29.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith30.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith31.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith32.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith33.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith34.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith35.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith36.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith37.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith38.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith39.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith40.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith41.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith42.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith43.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith44.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith45.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith46.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith47.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith48.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith49.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith50.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith51.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith52.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith53.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith54.wav", NULL}, + {1u, "Sfx\\Towners\\Bsmith55.wav", NULL}, {1u, "Sfx\\Towners\\Bsmith56.wav", NULL}, + {0u, "Sfx\\Towners\\Cow1.wav", NULL}, {0u, "Sfx\\Towners\\Cow2.wav", NULL}, + {1u, "Sfx\\Towners\\Deadguy2.wav", NULL}, {1u, "Sfx\\Towners\\Drunk01.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk02.wav", NULL}, {1u, "Sfx\\Towners\\Drunk03.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk04.wav", NULL}, {1u, "Sfx\\Towners\\Drunk05.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk06.wav", NULL}, {1u, "Sfx\\Towners\\Drunk07.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk08.wav", NULL}, {1u, "Sfx\\Towners\\Drunk09.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk10.wav", NULL}, {1u, "Sfx\\Towners\\Drunk11.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk12.wav", NULL}, {1u, "Sfx\\Towners\\Drunk13.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk14.wav", NULL}, {1u, "Sfx\\Towners\\Drunk15.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk16.wav", NULL}, {1u, "Sfx\\Towners\\Drunk17.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk18.wav", NULL}, {1u, "Sfx\\Towners\\Drunk19.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk20.wav", NULL}, {1u, "Sfx\\Towners\\Drunk21.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk22.wav", NULL}, {1u, "Sfx\\Towners\\Drunk23.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk24.wav", NULL}, {1u, "Sfx\\Towners\\Drunk25.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk26.wav", NULL}, {1u, "Sfx\\Towners\\Drunk27.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk28.wav", NULL}, {1u, "Sfx\\Towners\\Drunk29.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk30.wav", NULL}, {1u, "Sfx\\Towners\\Drunk31.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk32.wav", NULL}, {1u, "Sfx\\Towners\\Drunk33.wav", NULL}, + {1u, "Sfx\\Towners\\Drunk34.wav", NULL}, {1u, "Sfx\\Towners\\Drunk35.wav", NULL}, + {1u, "Sfx\\Towners\\Healer01.wav", NULL}, {1u, "Sfx\\Towners\\Healer02.wav", NULL}, + {1u, "Sfx\\Towners\\Healer03.wav", NULL}, {1u, "Sfx\\Towners\\Healer04.wav", NULL}, + {1u, "Sfx\\Towners\\Healer05.wav", NULL}, {1u, "Sfx\\Towners\\Healer06.wav", NULL}, + {1u, "Sfx\\Towners\\Healer07.wav", NULL}, {1u, "Sfx\\Towners\\Healer08.wav", NULL}, + {1u, "Sfx\\Towners\\Healer09.wav", NULL}, {1u, "Sfx\\Towners\\Healer10.wav", NULL}, + {1u, "Sfx\\Towners\\Healer11.wav", NULL}, {1u, "Sfx\\Towners\\Healer12.wav", NULL}, + {1u, "Sfx\\Towners\\Healer13.wav", NULL}, {1u, "Sfx\\Towners\\Healer14.wav", NULL}, + {1u, "Sfx\\Towners\\Healer15.wav", NULL}, {1u, "Sfx\\Towners\\Healer16.wav", NULL}, + {1u, "Sfx\\Towners\\Healer17.wav", NULL}, {1u, "Sfx\\Towners\\Healer18.wav", NULL}, + {1u, "Sfx\\Towners\\Healer19.wav", NULL}, {1u, "Sfx\\Towners\\Healer20.wav", NULL}, + {1u, "Sfx\\Towners\\Healer21.wav", NULL}, {1u, "Sfx\\Towners\\Healer22.wav", NULL}, + {1u, "Sfx\\Towners\\Healer23.wav", NULL}, {1u, "Sfx\\Towners\\Healer24.wav", NULL}, + {1u, "Sfx\\Towners\\Healer25.wav", NULL}, {1u, "Sfx\\Towners\\Healer26.wav", NULL}, + {1u, "Sfx\\Towners\\Healer27.wav", NULL}, {1u, "Sfx\\Towners\\Healer28.wav", NULL}, + {1u, "Sfx\\Towners\\Healer29.wav", NULL}, {1u, "Sfx\\Towners\\Healer30.wav", NULL}, + {1u, "Sfx\\Towners\\Healer31.wav", NULL}, {1u, "Sfx\\Towners\\Healer32.wav", NULL}, + {1u, "Sfx\\Towners\\Healer33.wav", NULL}, {1u, "Sfx\\Towners\\Healer34.wav", NULL}, + {1u, "Sfx\\Towners\\Healer35.wav", NULL}, {1u, "Sfx\\Towners\\Healer36.wav", NULL}, + {1u, "Sfx\\Towners\\Healer37.wav", NULL}, {1u, "Sfx\\Towners\\Healer38.wav", NULL}, + {1u, "Sfx\\Towners\\Healer39.wav", NULL}, {1u, "Sfx\\Towners\\Healer40.wav", NULL}, + {1u, "Sfx\\Towners\\Healer41.wav", NULL}, {1u, "Sfx\\Towners\\Healer42.wav", NULL}, + {1u, "Sfx\\Towners\\Healer43.wav", NULL}, {1u, "Sfx\\Towners\\Healer44.wav", NULL}, + {1u, "Sfx\\Towners\\Healer45.wav", NULL}, {1u, "Sfx\\Towners\\Healer46.wav", NULL}, + {1u, "Sfx\\Towners\\Healer47.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy01.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy02.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy03.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy04.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy05.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy06.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy07.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy08.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy09.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy10.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy11.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy12.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy13.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy14.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy15.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy16.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy17.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy18.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy19.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy20.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy21.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy22.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy23.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy24.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy25.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy26.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy27.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy28.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy29.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy30.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy31.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy32.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy33.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy34.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy35.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy36.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy37.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy38.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy39.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy40.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy41.wav", NULL}, + {1u, "Sfx\\Towners\\Pegboy42.wav", NULL}, {1u, "Sfx\\Towners\\Pegboy43.wav", NULL}, + {1u, "Sfx\\Towners\\Priest00.wav", NULL}, {1u, "Sfx\\Towners\\Priest01.wav", NULL}, + {1u, "Sfx\\Towners\\Priest02.wav", NULL}, {1u, "Sfx\\Towners\\Priest03.wav", NULL}, + {1u, "Sfx\\Towners\\Priest04.wav", NULL}, {1u, "Sfx\\Towners\\Priest05.wav", NULL}, + {1u, "Sfx\\Towners\\Priest06.wav", NULL}, {1u, "Sfx\\Towners\\Priest07.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt00.wav", NULL}, {1u, "Sfx\\Towners\\Storyt01.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt02.wav", NULL}, {1u, "Sfx\\Towners\\Storyt03.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt04.wav", NULL}, {1u, "Sfx\\Towners\\Storyt05.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt06.wav", NULL}, {1u, "Sfx\\Towners\\Storyt07.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt08.wav", NULL}, {1u, "Sfx\\Towners\\Storyt09.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt10.wav", NULL}, {1u, "Sfx\\Towners\\Storyt11.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt12.wav", NULL}, {1u, "Sfx\\Towners\\Storyt13.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt14.wav", NULL}, {1u, "Sfx\\Towners\\Storyt15.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt16.wav", NULL}, {1u, "Sfx\\Towners\\Storyt17.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt18.wav", NULL}, {1u, "Sfx\\Towners\\Storyt19.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt20.wav", NULL}, {1u, "Sfx\\Towners\\Storyt21.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt22.wav", NULL}, {1u, "Sfx\\Towners\\Storyt23.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt24.wav", NULL}, {1u, "Sfx\\Towners\\Storyt25.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt26.wav", NULL}, {1u, "Sfx\\Towners\\Storyt27.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt28.wav", NULL}, {1u, "Sfx\\Towners\\Storyt29.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt30.wav", NULL}, {1u, "Sfx\\Towners\\Storyt31.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt32.wav", NULL}, {1u, "Sfx\\Towners\\Storyt33.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt34.wav", NULL}, {1u, "Sfx\\Towners\\Storyt35.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt36.wav", NULL}, {1u, "Sfx\\Towners\\Storyt37.wav", NULL}, + {1u, "Sfx\\Towners\\Storyt38.wav", NULL}, {1u, "Sfx\\Towners\\Tavown00.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown01.wav", NULL}, {1u, "Sfx\\Towners\\Tavown02.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown03.wav", NULL}, {1u, "Sfx\\Towners\\Tavown04.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown05.wav", NULL}, {1u, "Sfx\\Towners\\Tavown06.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown07.wav", NULL}, {1u, "Sfx\\Towners\\Tavown08.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown09.wav", NULL}, {1u, "Sfx\\Towners\\Tavown10.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown11.wav", NULL}, {1u, "Sfx\\Towners\\Tavown12.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown13.wav", NULL}, {1u, "Sfx\\Towners\\Tavown14.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown15.wav", NULL}, {1u, "Sfx\\Towners\\Tavown16.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown17.wav", NULL}, {1u, "Sfx\\Towners\\Tavown18.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown19.wav", NULL}, {1u, "Sfx\\Towners\\Tavown20.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown21.wav", NULL}, {1u, "Sfx\\Towners\\Tavown22.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown23.wav", NULL}, {1u, "Sfx\\Towners\\Tavown24.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown25.wav", NULL}, {1u, "Sfx\\Towners\\Tavown26.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown27.wav", NULL}, {1u, "Sfx\\Towners\\Tavown28.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown29.wav", NULL}, {1u, "Sfx\\Towners\\Tavown30.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown31.wav", NULL}, {1u, "Sfx\\Towners\\Tavown32.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown33.wav", NULL}, {1u, "Sfx\\Towners\\Tavown34.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown35.wav", NULL}, {1u, "Sfx\\Towners\\Tavown36.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown37.wav", NULL}, {1u, "Sfx\\Towners\\Tavown38.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown39.wav", NULL}, {1u, "Sfx\\Towners\\Tavown40.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown41.wav", NULL}, {1u, "Sfx\\Towners\\Tavown42.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown43.wav", NULL}, {1u, "Sfx\\Towners\\Tavown44.wav", NULL}, + {1u, "Sfx\\Towners\\Tavown45.wav", NULL}, {1u, "Sfx\\Towners\\Witch01.wav", NULL}, + {1u, "Sfx\\Towners\\Witch02.wav", NULL}, {1u, "Sfx\\Towners\\Witch03.wav", NULL}, + {1u, "Sfx\\Towners\\Witch04.wav", NULL}, {1u, "Sfx\\Towners\\Witch05.wav", NULL}, + {1u, "Sfx\\Towners\\Witch06.wav", NULL}, {1u, "Sfx\\Towners\\Witch07.wav", NULL}, + {1u, "Sfx\\Towners\\Witch08.wav", NULL}, {1u, "Sfx\\Towners\\Witch09.wav", NULL}, + {1u, "Sfx\\Towners\\Witch10.wav", NULL}, {1u, "Sfx\\Towners\\Witch11.wav", NULL}, + {1u, "Sfx\\Towners\\Witch12.wav", NULL}, {1u, "Sfx\\Towners\\Witch13.wav", NULL}, + {1u, "Sfx\\Towners\\Witch14.wav", NULL}, {1u, "Sfx\\Towners\\Witch15.wav", NULL}, + {1u, "Sfx\\Towners\\Witch16.wav", NULL}, {1u, "Sfx\\Towners\\Witch17.wav", NULL}, + {1u, "Sfx\\Towners\\Witch18.wav", NULL}, {1u, "Sfx\\Towners\\Witch19.wav", NULL}, + {1u, "Sfx\\Towners\\Witch20.wav", NULL}, {1u, "Sfx\\Towners\\Witch21.wav", NULL}, + {1u, "Sfx\\Towners\\Witch22.wav", NULL}, {1u, "Sfx\\Towners\\Witch23.wav", NULL}, + {1u, "Sfx\\Towners\\Witch24.wav", NULL}, {1u, "Sfx\\Towners\\Witch25.wav", NULL}, + {1u, "Sfx\\Towners\\Witch26.wav", NULL}, {1u, "Sfx\\Towners\\Witch27.wav", NULL}, + {1u, "Sfx\\Towners\\Witch28.wav", NULL}, {1u, "Sfx\\Towners\\Witch29.wav", NULL}, + {1u, "Sfx\\Towners\\Witch30.wav", NULL}, {1u, "Sfx\\Towners\\Witch31.wav", NULL}, + {1u, "Sfx\\Towners\\Witch32.wav", NULL}, {1u, "Sfx\\Towners\\Witch33.wav", NULL}, + {1u, "Sfx\\Towners\\Witch34.wav", NULL}, {1u, "Sfx\\Towners\\Witch35.wav", NULL}, + {1u, "Sfx\\Towners\\Witch36.wav", NULL}, {1u, "Sfx\\Towners\\Witch37.wav", NULL}, + {1u, "Sfx\\Towners\\Witch38.wav", NULL}, {1u, "Sfx\\Towners\\Witch39.wav", NULL}, + {1u, "Sfx\\Towners\\Witch40.wav", NULL}, {1u, "Sfx\\Towners\\Witch41.wav", NULL}, + {1u, "Sfx\\Towners\\Witch42.wav", NULL}, {1u, "Sfx\\Towners\\Witch43.wav", NULL}, + {1u, "Sfx\\Towners\\Witch44.wav", NULL}, {1u, "Sfx\\Towners\\Witch45.wav", NULL}, + {1u, "Sfx\\Towners\\Witch46.wav", NULL}, {1u, "Sfx\\Towners\\Witch47.wav", NULL}, + {1u, "Sfx\\Towners\\Witch48.wav", NULL}, {1u, "Sfx\\Towners\\Witch49.wav", NULL}, + {1u, "Sfx\\Towners\\Witch50.wav", NULL}, {1u, "Sfx\\Towners\\Wound01.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage01.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage02.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage03.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage04.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage05.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage06.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage07.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage08.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage09.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage10.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage11.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage12.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage13.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage14.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage15.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage16.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage17.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage18.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage19.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage20.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage21.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage22.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage23.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage24.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage25.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage26.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage27.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage28.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage29.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage30.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage31.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage32.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage33.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage34.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage35.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage36.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage37.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage38.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage39.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage40.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage41.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage42.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage43.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage44.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage45.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage46.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage47.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage48.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage49.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage50.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage51.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage52.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage53.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage54.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage55.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage56.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage57.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage58.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage59.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage60.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage61.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage62.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage63.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage64.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage65.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage66.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage67.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage68.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage69.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage69b.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage70.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage71.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage72.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage73.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage74.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage75.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage76.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage77.wav", NULL}, + {64u, "Sfx\\Sorceror\\Mage78.wav", NULL}, {64u, "Sfx\\Sorceror\\Mage79.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage80.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage81.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage82.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage83.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage84.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage85.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage86.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage87.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage88.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage89.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage90.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage91.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage92.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage93.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage94.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage95.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage96.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage97.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage98.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage99.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage100.wav", NULL}, {65u, "Sfx\\Sorceror\\Mage101.wav", NULL}, + {65u, "Sfx\\Sorceror\\Mage102.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue01.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue02.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue03.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue04.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue05.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue06.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue07.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue08.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue09.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue10.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue11.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue12.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue13.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue14.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue15.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue16.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue17.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue18.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue19.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue20.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue21.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue22.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue23.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue24.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue25.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue26.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue27.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue28.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue29.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue30.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue31.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue32.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue33.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue34.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue35.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue36.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue37.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue38.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue39.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue40.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue41.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue42.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue43.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue44.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue45.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue46.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue47.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue48.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue49.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue50.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue51.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue52.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue53.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue54.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue55.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue56.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue57.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue58.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue59.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue60.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue61.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue62.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue63.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue64.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue65.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue66.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue67.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue68.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue69.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue69b.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue70.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue71.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue72.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue73.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue74.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue75.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue76.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue77.wav", NULL}, {16u, "Sfx\\Rogue\\Rogue78.wav", NULL}, + {16u, "Sfx\\Rogue\\Rogue79.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue80.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue81.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue82.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue83.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue84.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue85.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue86.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue87.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue88.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue89.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue90.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue91.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue92.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue93.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue94.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue95.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue96.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue97.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue98.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue99.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue100.wav", NULL}, + {17u, "Sfx\\Rogue\\Rogue101.wav", NULL}, {17u, "Sfx\\Rogue\\Rogue102.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior01.wav", NULL}, {33u, "Sfx\\Warrior\\Warior02.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior03.wav", NULL}, {33u, "Sfx\\Warrior\\Warior04.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior05.wav", NULL}, {33u, "Sfx\\Warrior\\Warior06.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior07.wav", NULL}, {33u, "Sfx\\Warrior\\Warior08.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior09.wav", NULL}, {33u, "Sfx\\Warrior\\Warior10.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior11.wav", NULL}, {33u, "Sfx\\Warrior\\Warior12.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior13.wav", NULL}, {32u, "Sfx\\Warrior\\Warior14.wav", NULL}, + {32u, "Sfx\\Warrior\\Wario14b.wav", NULL}, {32u, "Sfx\\Warrior\\Wario14c.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior15.wav", NULL}, {32u, "Sfx\\Warrior\\Wario15b.wav", NULL}, + {32u, "Sfx\\Warrior\\Wario15c.wav", NULL}, {32u, "Sfx\\Warrior\\Warior16.wav", NULL}, + {32u, "Sfx\\Warrior\\Wario16b.wav", NULL}, {32u, "Sfx\\Warrior\\Wario16c.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior17.wav", NULL}, {32u, "Sfx\\Warrior\\Warior18.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior19.wav", NULL}, {32u, "Sfx\\Warrior\\Warior20.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior21.wav", NULL}, {32u, "Sfx\\Warrior\\Warior22.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior23.wav", NULL}, {32u, "Sfx\\Warrior\\Warior24.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior25.wav", NULL}, {32u, "Sfx\\Warrior\\Warior26.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior27.wav", NULL}, {32u, "Sfx\\Warrior\\Warior28.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior29.wav", NULL}, {32u, "Sfx\\Warrior\\Warior30.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior31.wav", NULL}, {32u, "Sfx\\Warrior\\Warior32.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior33.wav", NULL}, {32u, "Sfx\\Warrior\\Warior34.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior35.wav", NULL}, {32u, "Sfx\\Warrior\\Warior36.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior37.wav", NULL}, {32u, "Sfx\\Warrior\\Warior38.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior39.wav", NULL}, {32u, "Sfx\\Warrior\\Warior40.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior41.wav", NULL}, {32u, "Sfx\\Warrior\\Warior42.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior43.wav", NULL}, {32u, "Sfx\\Warrior\\Warior44.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior45.wav", NULL}, {32u, "Sfx\\Warrior\\Warior46.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior47.wav", NULL}, {32u, "Sfx\\Warrior\\Warior48.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior49.wav", NULL}, {32u, "Sfx\\Warrior\\Warior50.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior51.wav", NULL}, {33u, "Sfx\\Warrior\\Warior52.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior53.wav", NULL}, {33u, "Sfx\\Warrior\\Warior54.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior55.wav", NULL}, {33u, "Sfx\\Warrior\\Warior56.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior57.wav", NULL}, {33u, "Sfx\\Warrior\\Warior58.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior59.wav", NULL}, {33u, "Sfx\\Warrior\\Warior60.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior61.wav", NULL}, {33u, "Sfx\\Warrior\\Warior62.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior63.wav", NULL}, {32u, "Sfx\\Warrior\\Warior64.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior65.wav", NULL}, {32u, "Sfx\\Warrior\\Warior66.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior67.wav", NULL}, {32u, "Sfx\\Warrior\\Warior68.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior69.wav", NULL}, {32u, "Sfx\\Warrior\\Wario69b.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior70.wav", NULL}, {32u, "Sfx\\Warrior\\Warior71.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior72.wav", NULL}, {32u, "Sfx\\Warrior\\Warior73.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior74.wav", NULL}, {32u, "Sfx\\Warrior\\Warior75.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior76.wav", NULL}, {32u, "Sfx\\Warrior\\Warior77.wav", NULL}, + {32u, "Sfx\\Warrior\\Warior78.wav", NULL}, {32u, "Sfx\\Warrior\\Warior79.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior80.wav", NULL}, {33u, "Sfx\\Warrior\\Warior81.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior82.wav", NULL}, {33u, "Sfx\\Warrior\\Warior83.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior84.wav", NULL}, {33u, "Sfx\\Warrior\\Warior85.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior86.wav", NULL}, {33u, "Sfx\\Warrior\\Warior87.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior88.wav", NULL}, {33u, "Sfx\\Warrior\\Warior89.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior90.wav", NULL}, {33u, "Sfx\\Warrior\\Warior91.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior92.wav", NULL}, {33u, "Sfx\\Warrior\\Warior93.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior94.wav", NULL}, {33u, "Sfx\\Warrior\\Warior95.wav", NULL}, + {33u, "Sfx\\Warrior\\Wario95b.wav", NULL}, {33u, "Sfx\\Warrior\\Wario95c.wav", NULL}, + {33u, "Sfx\\Warrior\\Wario95d.wav", NULL}, {33u, "Sfx\\Warrior\\Wario95e.wav", NULL}, + {33u, "Sfx\\Warrior\\Wario95f.wav", NULL}, {33u, "Sfx\\Warrior\\Wario96b.wav", NULL}, + {33u, "Sfx\\Warrior\\Wario97.wav", NULL}, {33u, "Sfx\\Warrior\\Wario98.wav", NULL}, + {33u, "Sfx\\Warrior\\Warior99.wav", NULL}, {33u, "Sfx\\Warrior\\Wario100.wav", NULL}, + {33u, "Sfx\\Warrior\\Wario101.wav", NULL}, {33u, "Sfx\\Warrior\\Wario102.wav", NULL}, + {1u, "Sfx\\Narrator\\Nar01.wav", NULL}, {1u, "Sfx\\Narrator\\Nar02.wav", NULL}, + {1u, "Sfx\\Narrator\\Nar03.wav", NULL}, {1u, "Sfx\\Narrator\\Nar04.wav", NULL}, + {1u, "Sfx\\Narrator\\Nar05.wav", NULL}, {1u, "Sfx\\Narrator\\Nar06.wav", NULL}, + {1u, "Sfx\\Narrator\\Nar07.wav", NULL}, {1u, "Sfx\\Narrator\\Nar08.wav", NULL}, + {1u, "Sfx\\Narrator\\Nar09.wav", NULL}, {1u, "Sfx\\Misc\\Lvl16int.wav", NULL}, + {1u, "Sfx\\Monsters\\Butcher.wav", NULL}, {1u, "Sfx\\Monsters\\Garbud01.wav", NULL}, + {1u, "Sfx\\Monsters\\Garbud02.wav", NULL}, {1u, "Sfx\\Monsters\\Garbud03.wav", NULL}, + {1u, "Sfx\\Monsters\\Garbud04.wav", NULL}, {1u, "Sfx\\Monsters\\Izual01.wav", NULL}, + {1u, "Sfx\\Monsters\\Lach01.wav", NULL}, {1u, "Sfx\\Monsters\\Lach02.wav", NULL}, + {1u, "Sfx\\Monsters\\Lach03.wav", NULL}, {1u, "Sfx\\Monsters\\Laz01.wav", NULL}, + {1u, "Sfx\\Monsters\\Laz02.wav", NULL}, {1u, "Sfx\\Monsters\\Sking01.wav", NULL}, + {1u, "Sfx\\Monsters\\Snot01.wav", NULL}, {1u, "Sfx\\Monsters\\Snot02.wav", NULL}, + {1u, "Sfx\\Monsters\\Snot03.wav", NULL}, {1u, "Sfx\\Monsters\\Warlrd01.wav", NULL}, + {1u, "Sfx\\Monsters\\Wlock01.wav", NULL}, {1u, "Sfx\\Monsters\\Zhar01.wav", NULL}, + {1u, "Sfx\\Monsters\\Zhar02.wav", NULL}, {1u, "Sfx\\Monsters\\DiabloD.wav", NULL}}; + +struct effects_cpp_init { + effects_cpp_init() { effects_cpp_init_value = effects_inf; } +} _effects_cpp_init; +// 47A468: using guessed type int effects_inf; +// 52A550: using guessed type int effects_cpp_init_value; + +bool __fastcall effect_is_playing(int nSFX) +{ + TSFX *v1; // eax + TSnd *v2; // ecx + + v1 = &sgSFX[nSFX]; + v2 = v1->pSnd; +// printf("DEBUG effect_is_playing %s\n", v2); + if (v2) + return snd_playing(v2); + if (v1->bFlags & 1) + return v1 == sfx_data_cur; + return 0; +} + +void __cdecl sfx_stop() +{ + if (sfx_stream) { + SFileDdaEnd(sfx_stream); + SFileCloseFile(sfx_stream); + sfx_stream = 0; + sfx_data_cur = 0; + } +} + +void __fastcall InitMonsterSND(int monst) +{ + signed int v1; // ebx + int v2; // eax + TSnd **v3; // esi + int v4; // edi + size_t v5; // eax + TSnd *v6; // eax + char v7[260]; // [esp+0h] [ebp-110h] + int v8; // [esp+104h] [ebp-Ch] + int v9; // [esp+108h] [ebp-8h] + char *ptr; // [esp+10Ch] [ebp-4h] + + v8 = monst; + if (gbSndInited) { + v1 = 0; + v9 = Monsters[monst].mtype << 7; + do { + if (monster_action_sounds[v1] != 's' || *(int *)((char *)&monsterdata[0].snd_special + v9)) { + v2 = 0; + v3 = &Monsters[0].Snds[2 * (v1 + 41 * v8)]; + do { + v4 = v2 + 1; + sprintf(v7, *(const char **)((char *)&monsterdata[0].sndfile + v9), monster_action_sounds[v1], + v2 + 1); + v5 = strlen(v7); + ptr = (char *)DiabloAllocPtr(v5 + 1); + strcpy(ptr, v7); + + printf("DEBUG InitMonsterSND\n"); + v6 = sound_file_load(ptr); + *v3 = v6; + if (!v6) + mem_free_dbg(ptr); + v2 = v4; + ++v3; + } while (v4 < 2); + } + ++v1; + } while (v1 < 4); + } +} + +void __cdecl FreeEffects() +{ + printf("FreeEffects"); + TSnd **v0; // esi + signed int v1; // ebp + signed int v2; // ebx + TSnd *v3; // ecx + void *v4; // edi + TSnd **v5; // [esp+0h] [ebp-8h] + int v6; // [esp+4h] [ebp-4h] + + v6 = 0; + if (nummtypes > 0) { + v5 = Monsters[0].Snds; + do { + v0 = v5; + v1 = 4; + do { + v2 = 2; + do { + v3 = *v0; + if (*v0) { + *v0 = 0; + v4 = (void *)v3->sound_path; + v3->sound_path = 0; + sound_file_cleanup(v3); + mem_free_dbg(v4); + } + ++v0; + --v2; + } while (v2); + --v1; + } while (v1); + ++v6; + v5 += 82; + } while (v6 < nummtypes); + } +} + +void __fastcall PlayEffect(int i, int mode) +{ + int v2; // edi + int v3; // esi + int v4; // eax + int v5; // esi + int v6; // eax + TSnd *v7; // edi + TSnd var; + + + // int v8; // eax + int volume_delta; // [esp+8h] [ebp-8h] + int pan; // [esp+Ch] [ebp-4h] + + foo meh; + + + + v2 = mode; + v3 = i; + if (!plr[myplr].pLvlLoad) { + v4 = random(164, 2); + if (gbSndInited) { + if (gbSoundOn) { + if (!gbBufferMsgs) { + v5 = v3; + v6 = v4 + 2 * (v2 + 41 * monster[v5]._mMTidx); + v7 = Monsters[0].Snds[v6]; + if (v7) { + //_LOBYTE(v8) = snd_playing(Monsters[0].Snds[v6]); + printf("DEBUG PlayEffect *sound_path %p\n", Monsters[0].Snds[v6]); + if (!snd_playing(Monsters[0].Snds[v6])) { + if (calc_snd_position(monster[v5]._mx, monster[v5]._my, &volume_delta, &pan)) + snd_play_snd(v7, volume_delta, pan); + } + } + } + } + } + } +} +// 4A22D5: using guessed type char gbSoundOn; +// 676194: using guessed type char gbBufferMsgs; + +int __fastcall calc_snd_position(int x, int y, int *plVolume, int *plPan) +{ + printf(" calc_snd_position activated\n"); + int v4; // edi + int v5; // esi + int v6; // eax + int v7; // ebx + int v8; // eax + int v9; // eax + + v4 = x - plr[myplr].WorldX; + v5 = y - plr[myplr].WorldY; + v6 = (v4 - v5) << 8; + *plPan = v6; + if (abs(v6) > 6400) + return 0; + v7 = abs(v4); + v8 = v7 <= abs(v5) ? abs(v5) : abs(v4); + v9 = v8 << 6; + *plVolume = v9; + if (v9 >= 6400) + return 0; + *plVolume = -v9; + return 1; +} + +void __fastcall PlaySFX(int psfx) +{ + //printf("HERE PlaySFX"); + int v1; // eax + v1 = RndSFX(psfx); + PlaySFX_priv(&sgSFX[v1], 0, 0, 0); +} + + + +void __fastcall PlaySFX_priv(TSFX *pSFX, char loc, int x, int y) +{ + //printf("PlaySFX_priv activated\n"); + int v4; // edi + TSFX *v5; // esi + TSnd *v6; // ecx + // int v7; // eax + TSnd *v8; // ecx + int volume_delta; // [esp+Ch] [ebp-8h] + int pan; // [esp+10h] [ebp-4h] + TSFX *sound; + + v4 = loc; + v5 = pSFX; + sound = pSFX; + char * wav = sound->pszName; + if(gbSndInited && gbSoundOn){ + printf("Sound I want to Play %s\n\n",wav ); + calc_snd_position(x, y, &volume_delta, &pan); + + LoadAndPlaySound(wav,volume_delta,pan); + + + } + + + + + + + + + + + // if (!plr[myplr].pLvlLoad || gbMaxPlayers == 1) { + // if (gbSndInited) { + // if (gbSoundOn) { + // if (!gbBufferMsgs) { + // if (pSFX->bFlags & 3 || (v6 = pSFX->pSnd) == 0 || !snd_playing(v6)) { + // pan = 0; + // volume_delta = 0; + // if (!v4 || calc_snd_position(x, y, &volume_delta, &pan)) { + // if (v5->bFlags & 1) { + + // // stream_play(v5, volume_delta, pan); // Debuf + // } else { + // if (!v5->pSnd) + // v5->pSnd = sound_file_load(v5->pszName); + // v8 = v5->pSnd; + // if (v8) + // // printf("Playing Sound If Not Loaded %d\n\n", v8); + // snd_play_snd(v8, volume_delta, pan); + // } + // } + // } + // } + // } + // } + // } +} +// 4A22D5: using guessed type char gbSoundOn; +// 676194: using guessed type char gbBufferMsgs; +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall stream_play(TSFX *pSFX, int lVolume, int lPan) +{ + printf("stream_play\n"); + // printf("stream_play\n"); + // int v3; // esi + // TSFX *v4; // edi + // int v5; // esi + // // int v6; // eax + // // int v7; // eax + + // v3 = lVolume; + // v4 = pSFX; + // sfx_stop(); + // v5 = sound_get_or_set_sound_volume(1) + v3; + // if (v5 >= -1600) { + // if (v5 > 0) + // v5 = 0; + // //_LOBYTE(v6) = SFileOpenFile(v4->pszName, &sfx_stream); + // if (SFileOpenFile(v4->pszName, &sfx_stream)) { + // //_LOBYTE(v7) = SFileDdaBeginEx(sfx_stream, 0x40000, 0, 0, v5, lPan, 0); + // if (SFileDdaBeginEx(sfx_stream, 0x40000, 0, 0, v5, lPan, + // 0)) // This shouldn't be called but it does get called + // sfx_data_cur = v4; + // else + // sfx_stop(); + // } else { + // sfx_stream = 0; + // } + // } +} + +int __fastcall RndSFX(int psfx) +{ + printf("RndSFX\n"); + int v1; // esi + int v3; // [esp-4h] [ebp-8h] + + v1 = psfx; + switch (psfx) { + case PS_WARR69: + goto LABEL_12; + case PS_WARR14: + case PS_WARR15: + case PS_WARR16: + goto LABEL_19; + case PS_MAGE69: + case PS_ROGUE69: + case PS_SWING: + case LS_ACID: + case IS_FMAG: + case IS_MAGIC: + case IS_BHIT: + LABEL_12: + v3 = 2; + LABEL_15: + + return v1 + random(165, v3); + case PS_WARR2: + LABEL_19: + v3 = 3; + goto LABEL_15; + } + return psfx; +} + +void __fastcall PlaySfxLoc(int psfx, int x, int y) +{ + printf("PlaySfxLoc\n"); + // int v3; // esi + // int v4; // eax + // TSnd *v5; // ecx + + // v3 = x; + // v4 = RndSFX(psfx); // Crash here.... + // if ( v4 >= 0 && v4 <= 3 ) + // { + // v5 = sgSFX[v4].pSnd; + // if ( v5 ) + // v5->start_tc = 0; + // } + // PlaySFX_priv(&sgSFX[v4], 1, v3, y); +} + +void __cdecl FreeMonsterSnd() +{ + printf("FreeMonsterSnd"); + TSnd **v0; // esi + signed int v1; // ebx + signed int v2; // edi + int v3; // [esp+0h] [ebp-8h] + TSnd **v4; // [esp+4h] [ebp-4h] + + snd_update(1); + sfx_stop(); + sound_stop(); + v3 = 0; + if (nummtypes > 0) { + v4 = Monsters[0].Snds; + do { + v0 = v4; + v1 = 4; + do { + v2 = 2; + do { + snd_stop_snd(*v0); + ++v0; + --v2; + } while (v2); + --v1; + } while (v1); + ++v3; + v4 += 82; + } while (v3 < nummtypes); + } +} + +void __cdecl sound_stop() +{ + + int i; // edi + + for (i = 0; i < NUM_SFX; i++) { + if (sgSFX[i].pSnd) + snd_stop_snd(sgSFX[i].pSnd); + } +} + +void __cdecl sound_update() +{// This is called + + // printf("sound_update\n"); + // unsigned int v3; // [esp-Ch] [ebp-Ch] + // unsigned int v4; // [esp-8h] [ebp-8h] + + // if (gbSndInited) { + // snd_update(0); + + // if (sfx_stream) { + // if (SFileDdaGetPos(sfx_stream, (int)&v4, (int)&v3)) { + // if (v4 >= v3) + // sfx_stop(); + // } + // } + // } +} +// 415DBA: could not find valid save-restore pair for ebp + +void __cdecl effects_cleanup_sfx() +{ + unsigned int v0; // edi + TSnd *v1; // ecx + + FreeMonsterSnd(); + v0 = 0; + do { + v1 = sgSFX[v0].pSnd; + if (v1) { + sound_file_cleanup(v1); + sgSFX[v0].pSnd = 0; + } + ++v0; + } while (v0 < NUM_SFX); +} + +void __cdecl stream_update() +{ + char v0; // bl + char v1; // al + + v0 = 0; + if ((unsigned char)gbMaxPlayers <= 1u) { + v1 = plr[myplr]._pClass; + if (v1) { + if (v1 == 1) { + v0 = 16; + } else if (v1 == 2) { + v0 = 64; + } else { + TermMsg("effects:1"); + } + } else { + v0 = 32; + } + } else { + v0 = 112; + } + priv_sound_init(v0); +} +// 679660: using guessed type char gbMaxPlayers; + +void __fastcall priv_sound_init(int bLoadMask) +{ + unsigned char v1; // bl + unsigned char v2; // cl + unsigned int v3; // esi + unsigned char v4; // al + TSnd *v5; // eax + unsigned char v6; // [esp+0h] [ebp-4h] + + if (gbSndInited) { + v1 = bLoadMask & 0x70; + v2 = bLoadMask & 0x70 ^ bLoadMask; + v3 = 0; + v6 = v2; + do { + if (!sgSFX[v3].pSnd) { + v4 = sgSFX[v3].bFlags; + if (!(v4 & 1) && (!v2 || v4 & v2) && (!(v4 & 0x70) || v4 & v1)) { + v5 = sound_file_load(sgSFX[v3].pszName); + v2 = v6; + sgSFX[v3].pSnd = v5; + } + } + ++v3; + } while (v3 < NUM_SFX); + } +} + +void __cdecl sound_init() +{ + priv_sound_init(4); +} + +void __stdcall effects_play_sound(char *snd_file) +{ + int v1; // edi + unsigned int v2; // esi + TSnd **v3; // esi + // int v4; // eax + + if (gbSndInited && gbSoundOn) { + v1 = 0; + v2 = 0; + while (_strcmpi(sgSFX[v2].pszName, snd_file) || !sgSFX[v2].pSnd) { + ++v2; + ++v1; + if (v2 >= NUM_SFX) + return; + } + v3 = &sgSFX[v1].pSnd; + //_LOBYTE(v4) = snd_playing(*v3); + if (!snd_playing(*v3)) + snd_play_snd(*v3, 0, 0); + } +} +// 4A22D5: using guessed type char gbSoundOn; diff --git a/Stub/fault.cpp b/Stub/fault.cpp new file mode 100644 index 000000000..3a0ad8c97 --- /dev/null +++ b/Stub/fault.cpp @@ -0,0 +1,8 @@ +#include "../types.h" + +#include "stubs.h" + +LPTOP_LEVEL_EXCEPTION_FILTER __cdecl exception_get_filter() +{ + return NULL; +} diff --git a/Stub/init.cpp b/Stub/init.cpp new file mode 100644 index 000000000..7d465f3ea --- /dev/null +++ b/Stub/init.cpp @@ -0,0 +1,91 @@ +#include +#include + +#include "../types.h" +#include "stubs.h" + +void *diabdat_mpq; +void *patch_rt_mpq; + +_SNETVERSIONDATA fileinfo; +int gbActive; +char gszVersionNumber[260]; +char gszProductName[260]; + +WNDPROC CurrentProc; + +/** Case insensitive search for a file name in a directory */ +static std::string find_file_in_directory(const char *dirpath, const char *file) +{ + DIR *dir = opendir(dirpath); + if (!dir) { + return ""; + } + + struct dirent *entry; + std::string result; + while ((entry = readdir(dir)) != NULL) { + if (strcasecmp(entry->d_name, file) == 0) { + result = std::string(dirpath) + "/" + entry->d_name; + break; + } + } + closedir(dir); + + return result; +} + +static std::string find_file_in_std_directories(const char *file) +{ + for (auto dir : {".", "..", "../.."}) { + auto path = find_file_in_directory(dir, file); + if (!path.empty()) { + return path; + } + } + eprintf("Required file %s not found\n", file); + abort(); +} + +void __fastcall init_create_window(int nCmdShow) +{ + DUMMY(); + + init_get_file_info(); + + // pfile_init_save_directory(); + + dx_init(NULL); + snd_init(); + + init_archives(); +} + +LRESULT __stdcall MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + UNIMPLEMENTED(); +} + +WNDPROC __stdcall SetWindowProc(WNDPROC NewProc) +{ + WNDPROC OldProc = CurrentProc; + CurrentProc = NewProc; + return OldProc; +} + +void __cdecl init_archives() +{ + DUMMY(); + + SFileOpenArchive(find_file_in_std_directories("diabdat.mpq").c_str(), 1000, 0, &diabdat_mpq); + assert(diabdat_mpq); + + SFileOpenArchive(find_file_in_std_directories("patch_rt.mpq").c_str(), 1000, 0, &patch_rt_mpq); + assert(patch_rt_mpq); +} + +void __cdecl init_get_file_info() +{ + strcpy(gszVersionNumber, "0.1"); + strcpy(gszProductName, "devil-test"); +} \ No newline at end of file diff --git a/Stub/main_test.cpp b/Stub/main_test.cpp new file mode 100644 index 000000000..2432cecf3 --- /dev/null +++ b/Stub/main_test.cpp @@ -0,0 +1,357 @@ +#include "../types.h" +#include "miniwin_sdl.h" +#include "stubs.h" + +#include + +static_assert(sizeof(plr) == 0x15360u, "sizeof(PlayerStruct) is wrong"); + +extern "C" { +const char *__asan_default_options() +{ + return "halt_on_error=0:print_legend=0"; +} +} + +static void init() +{ + init_archives(); + + encrypt_init_lookup_table(); + diablo_init_screen(); + + InitLightTable(); + + gdwNormalMsgSize = 512; +} + +static void test_levelgen() +{ + init(); + + SetRndSeed(123); + + currlevel = 2; + leveltype = DTYPE_CATACOMBS; + + // DRLG_Init_Globals(); + // LoadLvlGFX(); + // CreateLevel(0); + + // LoadGameLevel(TRUE, 0); +} + +static void test_newgame() +{ + init(); + + start_game(WM_DIABNEWGAME); +} + +void LoadCharNamesintoMemory(int start, int end) +{ + PkPlayerStruct pkplr; + int unused; + void *CharFile; + char *p_hero_names = *hero_names;// Not sure if this is correct + + memset(hero_names, 0, 0x140u); + + while (start != end) { + CharFile = pfile_open_save_archive(&unused, start); + if (CharFile) { + if (pfile_read_hero(CharFile, &pkplr)) { + strcpy(p_hero_names, pkplr.pName); + UnPackPlayer(&pkplr, 0, 0); + pfile_archive_contains_game(CharFile); + } + pfile_SFileCloseArchive(CharFile); + } + + p_hero_names += 32; + start++; + } + // memcpy(shero_names, hero_names, sizeof(hero_names)); +} + +void XStartGame() +{ + printf("Not Implemented\n"); + + + // pfile_read_player_from_save(); + + // int v2; // esi + // int v3; // edi + // int v4; // ecx + // int pfExitProgram; // [esp+Ch] [ebp-4h] + + // XNetInit(1, &pfExitProgram); + // while (1) + // { + + // printf("V2 STUFF : %i bSinglePlayer : %i", v2, &pfExitProgram); + // pfExitProgram = 0; + // dword_5256E8 = 0; + // byte_678640 = 0; + // InitLevels(); + // InitQuests(); + // InitPortals(); + // InitDungMsgs(myplr); + // v4 = WM_DIABLOADGAME; + // run_game_loop(v4); + // NetClose(); + + // } +} + +void HideCursor() +{ +Uint8 l_data[1]; +Uint8 l_mask[1]; + +l_data[0] = 0; +l_mask[0] = 0; + +SDL_Cursor * g_cursor = SDL_CreateCursor(l_data, l_mask, 1, 1, 0, 0); +SDL_SetCursor(g_cursor); +} + + + +void SDL_Diablo_UI() // I anticipate to move this later. +{ + snd_init(); + //music_start(5); + printf("This is Run And We need a Wile Loop"); + + int menu = 0; + SDL_Event event; + int x, y; + bool quit = false; + int CharsLoaded = 0; + /* Comment out these functions */ + printf("Main Menu Init\n"); + //SDL_ShowCursor(SDL_DISABLE);//Doesn't really work... Use HideCursor() instead. + SdlDiabloMainWindow(); + + SDLCreateDiabloCursor(); + HideCursor(); + // GetWorkingDirectory(); + /*comment out this*/ + + // a2 = option; // not used + + // mainmenu_refresh_music(); +// do { + + + + while (1 && quit == false) { + + if (menu == 0) { + + CreateMainDiabloMenu(); + SDL_RenderDiabloMainPage(); + // printf("I am 0\n"); + } + + if (menu == 2) { + + if (CharsLoaded == 0) { + LoadCharNamesintoMemory(0, 10); + CharsLoaded = 1; + } + + RenderCharNames(); + SDL_RenderDiabloSinglePlayerPage(); + gbMaxPlayers = 1; + } + + if (SDL_PollEvent(&event)) { + + if (event.type == SDL_QUIT) { + + quit = true; + SDL_Quit(); + // goto LABEL_16; + } + + if (event.type == SDL_MOUSEMOTION) { + // Get the mouse offsets + x = event.motion.x; + y = event.motion.y; + } + + // If a key was pressed + if (event.type == SDL_MOUSEBUTTONDOWN) { + + if (event.button.button == SDL_BUTTON_LEFT) { + x = event.button.x; + y = event.button.y; + printf("X %d , Y %d\n", x, y); + + if (menu == 0) { + + if ((x > SinglePlrBox.x) && (y > SinglePlrBox.y) && (x < SinglePlrBox.w) && + (y < SinglePlrBox.h)) { // Single clicked + printf("SinglePlayer Diablo\n"); + // effects_play_sound("Sfx\\Items\\Titlslct.wav"); + // a2 = 2; + menu = 2; + } + + if ((x > MultiPlrBox.x) && (y > MultiPlrBox.y) && (x < MultiPlrBox.w) && + (y < MultiPlrBox.h)) { // MultiBox clicked + printf("MultiPlayer Diablo\n"); + // effects_play_sound("Sfx\\Items\\Titlslct.wav"); + // v1 = mainmenu_multi_player(); + // goto LABEL_15; + } + if ((x > ReplayIntroBox.x) && (y > ReplayIntroBox.y) && (x < ReplayIntroBox.w) && + (y < ReplayIntroBox.h)) { // Reply Intro clicked + printf("Replay Intro\n"); + // effects_play_sound("Sfx\\Items\\Titlslct.wav"); + // goto LABEL_10; + } + if ((x > ShowCreditsBox.x) && (y > ShowCreditsBox.y) && (x < ShowCreditsBox.w) && + (y < ShowCreditsBox.h)) { // ShowCredits clicked + printf("Show Credits\n"); + // effects_play_sound("Sfx\\Items\\Titlslct.wav"); + UiCreditsDialog(16); + + } + + if ((x > ExitBox.x) && (y > ExitBox.y) && (x < ExitBox.w) && + (y < ExitBox.h)) { // ExitBox clicked + printf("Exiting Diablo\n"); + // effects_play_sound("Sfx\\Items\\Titlslct.wav"); + + quit = true; + SDL_Quit(); + exit(0); + //goto LABEL_16; + } + + } // End of this Menu0 + + else if (menu == 2) { + + // int x = 364; + // int y = 240; + int ClickListStart = 250; + int sizeOfBox = 30; + int WidthOfBox = 400; + int ClickListEnd = 343; + + // Render Clicks + if (TotalPlayers >= 1 && (x > ClickListStart) && (y > ClickListStart) && + (x < ClickListStart + WidthOfBox) && + (y < ClickListStart + sizeOfBox)) { // MultiBox clicked + printf("Player %s\n", hero_names[0]); + effects_play_sound("Sfx\\Items\\Titlslct.wav"); + strcpy(chr_name_str, hero_names[0]); + printf("Player %s\n", chr_name_str); + break; + } + + if (TotalPlayers >= 2 && (x > ClickListStart) && (y > ClickListStart + (sizeOfBox)) && + (x < ClickListStart + WidthOfBox) && + (y < ClickListStart + (sizeOfBox) + sizeOfBox)) { // MultiBox clicked + printf("Player 2 Diablo\n"); + effects_play_sound("Sfx\\Items\\Titlslct.wav"); + strcpy(chr_name_str, hero_names[1]); + printf("Player %s\n", chr_name_str); + //XStartGame(); + break; + } + if (TotalPlayers >= 3 && (x > ClickListStart) && (y > ClickListStart + (sizeOfBox * 2)) && + (x < ClickListStart + WidthOfBox) && + (y < ClickListStart + (sizeOfBox * 2) + sizeOfBox)) { // MultiBox clicked + printf("Player 3 Diablo\n"); + effects_play_sound("Sfx\\Items\\Titlslct.wav"); + strcpy(chr_name_str, hero_names[2]); + printf("Player %s\n", chr_name_str); + break; + //XStartGame(); + } + if (TotalPlayers >= 4 && (x > ClickListStart) && (y > ClickListStart + (sizeOfBox * 3)) && + (x < ClickListStart + WidthOfBox) && + (y < ClickListStart + (sizeOfBox * 3) + sizeOfBox)) { // MultiBox clicked + printf("Player 4 Diablo\n"); + effects_play_sound("Sfx\\Items\\Titlslct.wav"); + strcpy(chr_name_str, hero_names[3]); + printf("Player %s\n", chr_name_str); + break; + //XStartGame(); + } + if (TotalPlayers >= 5 && (x > ClickListStart) && (y > ClickListStart + (sizeOfBox * 4)) && + (x < ClickListStart + WidthOfBox) && + (y < ClickListStart + (sizeOfBox * 4) + sizeOfBox)) { // MultiBox clicked + printf("Player 5 Diablo\n"); + effects_play_sound("Sfx\\Items\\Titlslct.wav"); + strcpy(chr_name_str, hero_names[4]); + printf("Player %s\n", chr_name_str); + + break; + //XStartGame(); + } + if (TotalPlayers >= 6 && (x > ClickListStart) && (y > ClickListStart + (sizeOfBox * 5)) && + (x < ClickListStart + WidthOfBox) && + (y < ClickListStart + (sizeOfBox * 5) + sizeOfBox)) { // MultiBox clicked + printf("Player 6 Diablo\n"); + effects_play_sound("Sfx\\Items\\Titlslct.wav"); + strcpy(chr_name_str, hero_names[5]); + printf("Player %s\n", chr_name_str); + break; + //XStartGame(); + } + + if ((x > SinglePlayerMenuCancelBox.x) && (y > SinglePlayerMenuCancelBox.y) && + (x < SinglePlayerMenuCancelBox.w) && + (y < SinglePlayerMenuCancelBox.h)) { // ExitBox clicked + printf("CancelBox Diablo\n"); + effects_play_sound("Sfx\\Items\\Titlslct.wav"); + + // quit = true; + // goto LABEL_16; + menu = 0; + } + } + } + } + } + } + } + +int main(int argc, char **argv) +{ + music_start(5); + + + SDL_Diablo_UI(); + //#define O(f) fprintf(stderr, "offsetof(%s) = %d\n", #f, offsetof(PlayerStruct, f)) + // + // O(_pRSplType); + // O(_pSBkSplType); + // O(_pSplLvl); + // O(_pMemSpells64); + // O(_pAblSpells64); + // O(_pSpellFlags); + // O(_pClass); + // O(_pVar8); + // O(_pIBonusDamMod); + // O(_pISpells64); + // O(_pBData); + // + // printf("s %d\n", sizeof(UINT64)); + + // test_levelgen(); + // test_newgame(); + + WinMain(NULL, NULL, argc > 1 ? argv[1] : "", 0); + + eprintf("Done!\n"); + + return 0; +} diff --git a/Stub/miniwin.cpp b/Stub/miniwin.cpp new file mode 100644 index 000000000..3d7eac74d --- /dev/null +++ b/Stub/miniwin.cpp @@ -0,0 +1,290 @@ +#include +#include +#include + +#include "miniwin.h" +#include "stubs.h" + +DWORD last_error; + +DWORD WINAPI GetLastError(VOID) +{ + return last_error; +} + +VOID WINAPI SetLastError(DWORD dwErrCode) +{ + last_error = dwErrCode; +} + +char __cdecl *_strlwr(char *str) +{ + for (char *p = str; *p; ++p) { + *p = tolower(*p); + } + return str; +} + +DWORD WINAPI GetTickCount(VOID) +{ + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now)) + return 0; + return now.tv_sec * 1000.0 + now.tv_nsec / 1000000.0; +} + +VOID WINAPI Sleep(DWORD dwMilliseconds) +{ + usleep(dwMilliseconds * 1000); +} + +HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData) +{ + UNIMPLEMENTED(); +} + +WINBOOL WINAPI FindClose(HANDLE hFindFile) +{ + UNIMPLEMENTED(); +} + +UINT WINAPI GetWindowsDirectoryA(LPSTR lpBuffer, UINT uSize) +{ + UNIMPLEMENTED(); +} + +WINBOOL WINAPI GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, + LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters) +{ + UNIMPLEMENTED(); +} + +DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize) +{ + DUMMY(); + assert(nSize >= 16); + const char *name = ".\\diablo.exe"; + strncpy(lpFilename, name, nSize); + return strlen(name); +} + +WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer, LPDWORD nSize) +{ + UNIMPLEMENTED(); +} + +WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName) +{ + UNIMPLEMENTED(); +} + +WINBOOL WINAPI CopyFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, WINBOOL bFailIfExists) +{ + UNIMPLEMENTED(); +} + +HFILE WINAPI OpenFile(LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle) +{ + UNIMPLEMENTED(); +} + +VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + UNIMPLEMENTED(); +} + +VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + DUMMY_ONCE(); +} + +VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + DUMMY_ONCE(); +} + +VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + UNIMPLEMENTED(); +} + +DWORD WINAPI WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) +{ + UNIMPLEMENTED(); +} + +HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, WINBOOL bManualReset, WINBOOL bInitialState, + LPCSTR lpName) +{ + DUMMY_PRINT("%s", nullstr(lpName)); + return NULL; +} + +HWND WINAPI SetCapture(HWND hWnd) +{ + DUMMY_ONCE(); + return hWnd; +} + +WINBOOL WINAPI ReleaseCapture(VOID) +{ + DUMMY_ONCE(); + return TRUE; +} + +WINBOOL WINAPI DestroyWindow(HWND hWnd) +{ + UNIMPLEMENTED(); +} + +HWND WINAPI GetLastActivePopup(HWND hWnd) +{ + UNIMPLEMENTED(); +} + +HWND WINAPI GetTopWindow(HWND hWnd) +{ + UNIMPLEMENTED(); +} + +WINBOOL WINAPI SetForegroundWindow(HWND hWnd) +{ + UNIMPLEMENTED(); +} + +HWND WINAPI SetFocus(HWND hWnd) +{ + UNIMPLEMENTED(); +} + +HWND WINAPI FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName) +{ + DUMMY_PRINT("class: %s window: %s", nullstr(lpClassName), nullstr(lpWindowName)); + return NULL; +} + +HANDLE WINAPI GetCurrentThread(VOID) +{ + DUMMY_ONCE(); + return NULL; +} + +DWORD WINAPI GetCurrentThreadId(VOID) +{ + UNIMPLEMENTED(); +} + +WINBOOL WINAPI SetThreadPriority(HANDLE hThread, int nPriority) +{ + DUMMY_ONCE(); + return TRUE; +} + +VOID WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo) +{ + UNIMPLEMENTED(); +} + +HDC WINAPI GetDC(HWND hWnd) +{ + UNIMPLEMENTED(); +} + +int WINAPI ReleaseDC(HWND hWnd, HDC hDC) +{ + UNIMPLEMENTED(); +} + +int WINAPI GetDeviceCaps(HDC hdc, int index) +{ + UNIMPLEMENTED(); +} + +UINT WINAPI GetSystemPaletteEntries(HDC hdc, UINT iStart, UINT cEntries, LPPALETTEENTRY pPalEntries) +{ + UNIMPLEMENTED(); +} + +uintptr_t __cdecl _beginthreadex(void *_Security, unsigned _StackSize, unsigned(__stdcall *_StartAddress)(void *), + void *_ArgList, unsigned _InitFlag, unsigned *_ThrdAddr) +{ + UNIMPLEMENTED(); +} + +int WINAPIV wsprintfA(LPSTR dest, LPCSTR format, ...) +{ + va_list args; + va_start(args, format); + return vsprintf(dest, format, args); +} + +int __cdecl _strcmpi(const char *_Str1, const char *_Str2) +{ + return strcasecmp(_Str1, _Str2); +} + +char *__cdecl _itoa(int _Value, char *_Dest, int _Radix) +{ + UNIMPLEMENTED(); +} + +WINBOOL WINAPI CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, WINBOOL bInheritHandles, DWORD dwCreationFlags, + LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation) +{ + UNIMPLEMENTED(); +} + +VOID WINAPI ExitProcess(UINT uExitCode) +{ + UNIMPLEMENTED(); +} + +DWORD WINAPI GetCurrentProcessId(VOID) +{ + UNIMPLEMENTED(); +} + +HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, + DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName) +{ + UNIMPLEMENTED(); +} + +LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, + DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap) +{ + UNIMPLEMENTED(); +} + +WINBOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress) +{ + UNIMPLEMENTED(); +} + +DWORD WINAPI WaitForInputIdle(HANDLE hProcess, DWORD dwMilliseconds) +{ + UNIMPLEMENTED(); +} + +HWND WINAPI GetForegroundWindow(VOID) +{ + UNIMPLEMENTED(); +} + +HWND WINAPI GetWindow(HWND hWnd, UINT uCmd) +{ + UNIMPLEMENTED(); +} + +DWORD WINAPI GetWindowThreadProcessId(HWND hWnd, LPDWORD lpdwProcessId) +{ + UNIMPLEMENTED(); +} + +DWORD WINAPI GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, + DWORD nSize, LPCSTR lpFileName) +{ + UNIMPLEMENTED(); +} diff --git a/Stub/miniwin.h b/Stub/miniwin.h new file mode 100644 index 000000000..680d6d07d --- /dev/null +++ b/Stub/miniwin.h @@ -0,0 +1,554 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +// For _rotr() +#include + +// Constants +#define CONST const +#define TRUE true +#define FALSE false + +#define NO_ERROR 0 + +// Calling conventions +#define __cdecl +#define __fastcall +#define __stdcall +#define CALLBACK __stdcall +#define WINAPI __stdcall +#define WINAPIV __cdecl +#define APIENTRY __stdcall + +#define ALIGNED(n) __attribute__((aligned(n))) + +// Basic types +#define __int8 char +#define __int16 short +#define __int32 int +#define __int64 long long ALIGNED(8) + +#define VOID void + +typedef char CHAR; +typedef uint16_t SHORT; +typedef int32_t LONG; + +typedef LONG *PLONG; +typedef uint32_t ULONG; +typedef ULONG *PULONG; +typedef uint16_t USHORT; +typedef USHORT *PUSHORT; +typedef unsigned char UCHAR; +typedef UCHAR *PUCHAR; +typedef char *PSZ; + +typedef uint32_t DWORD; +typedef int BOOL, WINBOOL; +typedef unsigned char BYTE; +typedef uint16_t WORD; +typedef float FLOAT; +typedef FLOAT *PFLOAT; +typedef BOOL *LPBOOL; +typedef BYTE *LPBYTE; +typedef int *LPINT; +typedef WORD *LPWORD; +typedef int32_t *LPLONG; +typedef DWORD *LPDWORD; +typedef void *LPVOID; +typedef CONST void *LPCVOID; + +typedef int INT; +typedef unsigned int UINT; +typedef unsigned int *PUINT; + +// GCC qword alignment is 4, MSVC is 8, work around by introducing a more aligned type +typedef long long INT64 ALIGNED(8); +typedef unsigned long long UINT64 ALIGNED(8); + +typedef int INT_PTR, *PINT_PTR; +typedef unsigned int UINT_PTR, *PUINT_PTR; + +typedef int32_t LONG_PTR, *PLONG_PTR; +typedef uint32_t ULONG_PTR, *PULONG_PTR; +typedef ULONG_PTR SIZE_T; + +typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; + +typedef CHAR *LPSTR; +typedef CONST CHAR *LPCSTR; + +typedef UINT_PTR WPARAM; +typedef LONG_PTR LPARAM; +typedef LONG_PTR LRESULT; + +// +// Handles +// +typedef void *HANDLE; + +typedef HANDLE HWND, HGDIOBJ, HMODULE, HDC, HRGN, HINSTANCE, HPALETTE, HFILE; + +typedef LONG LCID; + +typedef LONG HRESULT; + +typedef LRESULT(CALLBACK *WNDPROC)(HWND, UINT, WPARAM, LPARAM); + +// +// Intrinsics +// +#define LOBYTE(w) ((BYTE)(((DWORD_PTR)(w)) & 0xff)) +#define HIBYTE(w) ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff)) +#define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff)) +#define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff)) + +static inline LONG InterlockedIncrement(LONG volatile *Addend) +{ + return __sync_add_and_fetch(Addend, 1); +} + +typedef struct waveformat_tag { + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; +} WAVEFORMAT, *PWAVEFORMAT, *LPWAVEFORMAT; + +typedef struct pcmwaveformat_tag { + WAVEFORMAT wf; + WORD wBitsPerSample; +} PCMWAVEFORMAT, *PPCMWAVEFORMAT, *LPPCMWAVEFORMAT; + +typedef struct tWAVEFORMATEX { + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; +} WAVEFORMATEX, *LPWAVEFORMATEX, *LPCWAVEFORMATEX; + +typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME, *LPFILETIME; + +typedef struct tagRECT { + LONG left; + LONG top; + LONG right; + LONG bottom; +} RECT; + +typedef RECT *LPRECT; + +typedef struct tagPOINT { + LONG x; + LONG y; +} POINT; + +typedef struct tagSIZE { + LONG cx; + LONG cy; +} SIZE; + +typedef struct tagVS_FIXEDFILEINFO { + DWORD dwSignature; + DWORD dwStrucVersion; + DWORD dwFileVersionMS; + DWORD dwFileVersionLS; + DWORD dwProductVersionMS; + DWORD dwProductVersionLS; + DWORD dwFileFlagsMask; + DWORD dwFileFlags; + DWORD dwFileOS; + DWORD dwFileType; + DWORD dwFileSubtype; + DWORD dwFileDateMS; + DWORD dwFileDateLS; +} VS_FIXEDFILEINFO; + +typedef struct tagMSG { + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + DWORD time; + POINT pt; +} MSG, *LPMSG; + +// +// COM +// +#define DECLARE_INTERFACE_(name, base) struct name : public base +#define THIS_ +#define THIS +#define PURE = 0 + +#define STDMETHOD(name) STDMETHOD_(HRESULT, name) +#define STDMETHOD_(type, name) virtual WINAPI type name + +typedef void *REFIID; + +struct IUnknown { + // clang-format off + STDMETHOD(QueryInterface)(THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + // clang-format on +}; + +#define MAKE_HRESULT(sev, fac, code) ((HRESULT)(((uint32_t)(sev) << 31) | ((uint32_t)(fac) << 16) | ((uint32_t)(code)))) +#define E_FAIL ((HRESULT)0x80004005L) +#define S_OK ((HRESULT)0) + +// +// Everything else +// +typedef struct tagPALETTEENTRY { + BYTE peRed; + BYTE peGreen; + BYTE peBlue; + BYTE peFlags; +} PALETTEENTRY, *PPALETTEENTRY, *LPPALETTEENTRY; + +typedef void *LPTOP_LEVEL_EXCEPTION_FILTER, *PEXCEPTION_POINTERS; + +typedef struct _SYSTEM_INFO { + union { + DWORD dwOemId; + struct { + WORD wProcessorArchitecture; + WORD wReserved; + }; + }; + DWORD dwPageSize; + LPVOID lpMinimumApplicationAddress; + LPVOID lpMaximumApplicationAddress; + DWORD_PTR dwActiveProcessorMask; + DWORD dwNumberOfProcessors; + DWORD dwProcessorType; + DWORD dwAllocationGranularity; + WORD wProcessorLevel; + WORD wProcessorRevision; +} SYSTEM_INFO, *LPSYSTEM_INFO; + +typedef void *LPSECURITY_ATTRIBUTES; + +#define ERROR_ALREADY_EXISTS 183 + +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; +} LIST_ENTRY, *PLIST_ENTRY; + +typedef struct _RTL_CRITICAL_SECTION_DEBUG { + WORD Type; + WORD CreatorBackTraceIndex; + struct _RTL_CRITICAL_SECTION *CriticalSection; + LIST_ENTRY ProcessLocksList; + DWORD EntryCount; + DWORD ContentionCount; + DWORD Flags; + WORD CreatorBackTraceIndexHigh; + WORD SpareWORD; +} RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG; + +typedef struct { + PRTL_CRITICAL_SECTION_DEBUG DebugInfo; + LONG LockCount; + LONG RecursionCount; + HANDLE OwningThread; + HANDLE LockSemaphore; + ULONG_PTR SpinCount; +} CRITICAL_SECTION, *LPCRITICAL_SECTION; + +VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + +DWORD WINAPI WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); + +DWORD WINAPI GetTickCount(VOID); + +DWORD WINAPI GetLastError(VOID); +VOID WINAPI SetLastError(DWORD dwErrCode); + +WINBOOL WINAPI CloseHandle(HANDLE hObject); + +HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, WINBOOL bManualReset, WINBOOL bInitialState, + LPCSTR lpName); +#define CreateEvent CreateEventA + +WINBOOL WINAPI SetCursorPos(int X, int Y); +int WINAPI ShowCursor(WINBOOL bShow); +HWND WINAPI SetCapture(HWND hWnd); +WINBOOL WINAPI ReleaseCapture(VOID); + +SHORT WINAPI GetAsyncKeyState(int vKey); + +#define PM_NOREMOVE 0x0000 +#define PM_REMOVE 0x0001 + +#define WM_QUIT 0x0012 + +WINBOOL WINAPI PeekMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg); +#define PeekMessage PeekMessageA +WINBOOL WINAPI TranslateMessage(CONST MSG *lpMsg); +LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg); +#define DispatchMessage DispatchMessageA +WINBOOL WINAPI PostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +#define PostMessage PostMessageA + +WINBOOL WINAPI DestroyWindow(HWND hWnd); +HWND WINAPI GetLastActivePopup(HWND hWnd); +HWND WINAPI GetTopWindow(HWND hWnd); +WINBOOL WINAPI SetForegroundWindow(HWND hWnd); +HWND WINAPI SetFocus(HWND hWnd); +HWND WINAPI FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName); +#define FindWindow FindWindowA + +#define THREAD_BASE_PRIORITY_MAX 2 +#define THREAD_PRIORITY_NORMAL 0 +#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX +#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST - 1) + +HANDLE WINAPI GetCurrentThread(VOID); +DWORD WINAPI GetCurrentThreadId(VOID); +WINBOOL WINAPI SetThreadPriority(HANDLE hThread, int nPriority); +VOID WINAPI Sleep(DWORD dwMilliseconds); + +VOID WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo); + +HDC WINAPI GetDC(HWND hWnd); +int WINAPI ReleaseDC(HWND hWnd, HDC hDC); +WINBOOL WINAPI TextOutA(HDC hdc, int x, int y, LPCSTR lpString, int c); +#define TextOut TextOutA + +#define NUMRESERVED 106 +int WINAPI GetDeviceCaps(HDC hdc, int index); +UINT WINAPI GetSystemPaletteEntries(HDC hdc, UINT iStart, UINT cEntries, LPPALETTEENTRY pPalEntries); + +uintptr_t __cdecl _beginthreadex(void *_Security, unsigned _StackSize, unsigned(__stdcall *_StartAddress)(void *), + void *_ArgList, unsigned _InitFlag, unsigned *_ThrdAddr); +int WINAPIV wsprintfA(LPSTR, LPCSTR, ...); +#define wsprintf wsprintfA +int __cdecl _strcmpi(const char *_Str1, const char *_Str2); +char *__cdecl _itoa(int _Value, char *_Dest, int _Radix); + +char *__cdecl _strlwr(char *str); + +// +// File I/O +// +#define FILE_BEGIN 0 +#define FILE_CURRENT 1 +#define FILE_FLAG_WRITE_THROUGH 0x80000000 +#define CREATE_ALWAYS 2 +#define GENERIC_READ 0x80000000L +#define GENERIC_WRITE 0x40000000L +#define OPEN_EXISTING 3 +#define ERROR_FILE_NOT_FOUND 2 +#define FILE_ATTRIBUTE_HIDDEN 0x00000002 +#define FILE_ATTRIBUTE_SYSTEM 0x00000004 + +struct _WIN32_FIND_DATAA { + FILETIME ftCreationTime; + FILETIME ftLastWriteTime; +}; + +typedef struct _WIN32_FIND_DATAA *LPWIN32_FIND_DATAA; + +typedef void *LPOVERLAPPED; + +#define OFS_MAXPATHNAME 128 + +typedef struct _OFSTRUCT { + BYTE cBytes; + BYTE fFixedDisk; + WORD nErrCode; + WORD Reserved1; + WORD Reserved2; + CHAR szPathName[OFS_MAXPATHNAME]; +} OFSTRUCT, *LPOFSTRUCT, *POFSTRUCT; + +#define SEC_COMMIT 0x8000000 +#define PAGE_READWRITE 0x04 + +#define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS +#define SECTION_QUERY 0x0001 +#define SECTION_MAP_WRITE 0x0002 +#define SECTION_MAP_READ 0x0004 +#define SECTION_MAP_EXECUTE 0x0008 +#define SECTION_EXTEND_SIZE 0x0010 +#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020 +#define STANDARD_RIGHTS_REQUIRED 0x000F0000 + +#define SECTION_ALL_ACCESS \ + (STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | \ + SECTION_EXTEND_SIZE) + +#define CREATE_NEW_PROCESS_GROUP 0x200 + +typedef struct _PROCESS_INFORMATION { + HANDLE hProcess; + HANDLE hThread; + DWORD dwProcessId; + DWORD dwThreadId; +} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; + +typedef void *LPSTARTUPINFOA; +WINBOOL WINAPI CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, WINBOOL bInheritHandles, DWORD dwCreationFlags, + LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation); +#define CreateProcess CreateProcessA +VOID WINAPI ExitProcess(UINT uExitCode); +DWORD WINAPI GetCurrentProcessId(VOID); + +HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, + DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName); +#define CreateFileMapping CreateFileMappingA +LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, + DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap); +WINBOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress); + +DWORD WINAPI WaitForInputIdle(HANDLE hProcess, DWORD dwMilliseconds); +HWND WINAPI GetForegroundWindow(VOID); +HWND WINAPI GetWindow(HWND hWnd, UINT uCmd); +DWORD WINAPI GetWindowThreadProcessId(HWND hWnd, LPDWORD lpdwProcessId); + +DWORD WINAPI GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, + DWORD nSize, LPCSTR lpFileName); +#define GetPrivateProfileString GetPrivateProfileStringA + +WINBOOL WINAPI WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, + LPOVERLAPPED lpOverlapped); +DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); +WINBOOL WINAPI SetEndOfFile(HANDLE hFile); +DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName); +#define GetFileAttributes GetFileAttributesA +WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes); +#define SetFileAttributes SetFileAttributesA +HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData); +#define FindFirstFile FindFirstFileA +WINBOOL WINAPI FindClose(HANDLE hFindFile); +HANDLE WINAPI CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); +#define CreateFile CreateFileA +WINBOOL WINAPI ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, + LPOVERLAPPED lpOverlapped); +DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh); +UINT WINAPI GetWindowsDirectoryA(LPSTR lpBuffer, UINT uSize); +#define GetWindowsDirectory GetWindowsDirectoryA +WINBOOL WINAPI GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, + LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters); +#define GetDiskFreeSpace GetDiskFreeSpaceA +DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize); +#define GetModuleFileName GetModuleFileNameA +WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer, LPDWORD nSize); +#define GetComputerName GetComputerNameA +WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName); +#define DeleteFile DeleteFileA +WINBOOL WINAPI CopyFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, WINBOOL bFailIfExists); +#define CopyFile CopyFileA +HFILE WINAPI OpenFile(LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle); + +// +// Events +// +#define WM_MOUSEFIRST 0x0200 +#define WM_MOUSEMOVE 0x0200 +#define WM_LBUTTONDOWN 0x0201 +#define WM_LBUTTONUP 0x0202 +#define WM_RBUTTONDOWN 0x0204 +#define WM_RBUTTONUP 0x0205 + +#define WM_KEYFIRST 0x0100 +#define WM_KEYDOWN 0x0100 +#define WM_KEYUP 0x0101 +#define WM_SYSKEYDOWN 0x0104 + +#define WM_SYSCOMMAND 0x0112 + +#define WM_CHAR 0x0102 +#define WM_CAPTURECHANGED 0x0215 + +#define SC_CLOSE 0xF060 + +#define VK_RETURN 0x0D +#define VK_BACK 0x08 +#define VK_LSHIFT 0xA0 +#define VK_SHIFT 0x10 +#define VK_ESCAPE 0x1B +#define VK_SPACE 0x20 +#define VK_LEFT 0x25 +#define VK_UP 0x26 +#define VK_RIGHT 0x27 +#define VK_DOWN 0x28 + +#define VK_F1 0x70 +#define VK_F2 0x71 +#define VK_F3 0x72 +#define VK_F4 0x73 +#define VK_F5 0x74 +#define VK_F6 0x75 +#define VK_F7 0x76 +#define VK_F8 0x77 +#define VK_F9 0x78 +#define VK_F10 0x79 +#define VK_F11 0x7A +#define VK_F12 0x7B + +#define VK_TAB 0x09 +#define VK_PAUSE 0x13 +#define VK_PRIOR 0x21 +#define VK_NEXT 0x22 +#define VK_SNAPSHOT 0x2C + +#define VK_OEM_1 0xBA +#define VK_OEM_PLUS 0xBB +#define VK_OEM_COMMA 0xBC +#define VK_OEM_MINUS 0xBD +#define VK_OEM_PERIOD 0xBE +#define VK_OEM_2 0xBF +#define VK_OEM_3 0xC0 +#define VK_OEM_4 0xDB +#define VK_OEM_5 0xDC +#define VK_OEM_6 0xDD +#define VK_OEM_7 0xDE +//#define VK_OEM_8 0xDF +//#define VK_OEM_102 0xE2 + +// +// Total fakes +// +typedef struct { +} SOCKADDR, GUID; + +typedef struct { + DWORD cb; +} STARTUPINFOA; + +// +// MSCVRT emulation +// + +int rand_miniwin(void); +void srand_miniwin(unsigned int seed); + +#include "miniwin_ddraw.h" +#include "miniwin_dsound.h" + diff --git a/Stub/miniwin_ddraw.h b/Stub/miniwin_ddraw.h new file mode 100644 index 000000000..35d83b2ef --- /dev/null +++ b/Stub/miniwin_ddraw.h @@ -0,0 +1,196 @@ +#pragma once + +#include "miniwin.h" + +typedef struct _DDCOLORKEY { + DWORD dwColorSpaceLowValue; + DWORD dwColorSpaceHighValue; +} DDCOLORKEY; + +typedef DDCOLORKEY *LPDDCOLORKEY; + +typedef struct _DDSCAPS { + DWORD dwCaps; +} DDSCAPS, *LPDDSCAPS; + +typedef struct _DDPIXELFORMAT { + DWORD dwSize; + DWORD dwFlags; + DWORD dwFourCC; + union { + DWORD dwRGBBitCount; + DWORD dwYUVBitCount; + DWORD dwZBufferBitDepth; + DWORD dwAlphaBitDepth; + }; + union { + DWORD dwRBitMask; + DWORD dwYBitMask; + }; + union { + DWORD dwGBitMask; + DWORD dwUBitMask; + }; + union { + DWORD dwBBitMask; + DWORD dwVBitMask; + }; + union { + DWORD dwRGBAlphaBitMask; + DWORD dwYUVAlphaBitMask; + DWORD dwRGBZBitMask; + DWORD dwYUVZBitMask; + }; +} DDPIXELFORMAT, *LPDDPIXELFORMAT; + +typedef struct _DDSURFACEDESC { + DWORD dwSize; + DWORD dwFlags; + DWORD dwHeight; + DWORD dwWidth; + union { + LONG lPitch; + DWORD dwLinearSize; + }; + DWORD dwBackBufferCount; + union { + DWORD dwMipMapCount; + DWORD dwZBufferBitDepth; + DWORD dwRefreshRate; + }; + DWORD dwAlphaBitDepth; + DWORD dwReserved; + LPVOID lpSurface; + DDCOLORKEY ddckCKDestOverlay; + DDCOLORKEY ddckCKDestBlt; + DDCOLORKEY ddckCKSrcOverlay; + DDCOLORKEY ddckCKSrcBlt; + DDPIXELFORMAT ddpfPixelFormat; + DDSCAPS ddsCaps; +} DDSURFACEDESC, *LPDDSURFACEDESC; + +#define _FACDD 0x876 +#define MAKE_DDHRESULT(code) MAKE_HRESULT(1, _FACDD, code) + +#define DDERR_SURFACELOST MAKE_DDHRESULT(450) +#define DDERR_WASSTILLDRAWING MAKE_DDHRESULT(540) +#define DDERR_SURFACEBUSY MAKE_DDHRESULT(430) + +typedef struct IDirectDrawPalette *LPDIRECTDRAWPALETTE; +typedef struct IDirectDrawSurface *LPDIRECTDRAWSURFACE; +typedef struct IDirectDraw *LPDIRECTDRAW; + +// No methods are actually used +DECLARE_INTERFACE_(IDirectDrawPalette, IUnknown) +{ + // clang-format off + STDMETHOD(GetCaps)(THIS_ LPDWORD lpdwCaps) PURE; + STDMETHOD(GetEntries)(THIS_ DWORD dwFlags, DWORD dwBase, DWORD dwNumEntries, LPPALETTEENTRY lpEntries) PURE; + STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW lpDD, DWORD dwFlags, LPPALETTEENTRY lpDDColorTable) PURE; + STDMETHOD(SetEntries)(THIS_ DWORD dwFlags, DWORD dwStartingEntry, DWORD dwCount, LPPALETTEENTRY lpEntries) PURE; + // clang-format on +}; + +/* +Actually used methods: + +DECLARE_INTERFACE_(IDirectDrawSurface, IUnknown) { + STDMETHOD(GetDC)(THIS_ HDC *); + STDMETHOD(IsLost)(THIS); + STDMETHOD(Lock)(THIS_ LPRECT, LPDDSURFACEDESC, DWORD, HANDLE); + STDMETHOD(ReleaseDC)(THIS_ HDC); + STDMETHOD(Restore)(THIS); + STDMETHOD(Unlock)(THIS_ LPVOID); + STDMETHOD(BltFast)(THIS_ DWORD, DWORD, LPDIRECTDRAWSURFACE, LPRECT, DWORD); + STDMETHOD(SetPalette)(THIS_ LPDIRECTDRAWPALETTE); +}; +*/ + +typedef void *LPDDBLTBATCH, *LPDDBLTFX, *LPDIRECTDRAWCLIPPER, *LPDDENUMSURFACESCALLBACK, *LPDDOVERLAYFX; +DECLARE_INTERFACE_(IDirectDrawSurface, IUnknown) +{ + // clang-format off + STDMETHOD(AddAttachedSurface)(THIS_ LPDIRECTDRAWSURFACE lpDDSAttachedSurface) PURE; + STDMETHOD(AddOverlayDirtyRect)(THIS_ LPRECT lpRect) PURE; + STDMETHOD(Blt)(THIS_ LPRECT lpDestRect, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFx) PURE; + STDMETHOD(BltBatch)(THIS_ LPDDBLTBATCH lpDDBltBatch, DWORD dwCount, DWORD dwFlags) PURE; + STDMETHOD(BltFast)(THIS_ DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans) PURE; + STDMETHOD(DeleteAttachedSurface)(THIS_ DWORD dwFlags, LPDIRECTDRAWSURFACE lpDDSAttachedSurface) PURE; + STDMETHOD(EnumAttachedSurfaces)(THIS_ LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) PURE; + STDMETHOD(EnumOverlayZOrders)(THIS_ DWORD dwFlags, LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpfnCallback) PURE; + STDMETHOD(Flip)(THIS_ LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride, DWORD dwFlags) PURE; + STDMETHOD(GetAttachedSurface)(THIS_ LPDDSCAPS lpDDSCaps, LPDIRECTDRAWSURFACE *lplpDDAttachedSurface) PURE; + STDMETHOD(GetBltStatus)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(GetCaps)(THIS_ LPDDSCAPS lpDDSCaps) PURE; + STDMETHOD(GetClipper)(THIS_ LPDIRECTDRAWCLIPPER *lplpDDClipper) PURE; + STDMETHOD(GetColorKey)(THIS_ DWORD dwFlags, LPDDCOLORKEY lpDDColorKey) PURE; + STDMETHOD(GetDC)(THIS_ HDC *lphDC) PURE; + STDMETHOD(GetFlipStatus)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(GetOverlayPosition)(THIS_ LPLONG lplX, LPLONG lplY) PURE; + STDMETHOD(GetPalette)(THIS_ LPDIRECTDRAWPALETTE *lplpDDPalette) PURE; + STDMETHOD(GetPixelFormat)(THIS_ LPDDPIXELFORMAT lpDDPixelFormat) PURE; + STDMETHOD(GetSurfaceDesc)(THIS_ LPDDSURFACEDESC lpDDSurfaceDesc) PURE; + STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW lpDD, LPDDSURFACEDESC lpDDSurfaceDesc) PURE; + STDMETHOD(IsLost)(THIS) PURE; + STDMETHOD(Lock)(THIS_ LPRECT lpDestRect, LPDDSURFACEDESC lpDDSurfaceDesc, DWORD dwFlags, HANDLE hEvent) PURE; + STDMETHOD(ReleaseDC)(THIS_ HDC hDC) PURE; + STDMETHOD(Restore)(THIS) PURE; + STDMETHOD(SetClipper)(THIS_ LPDIRECTDRAWCLIPPER lpDDClipper) PURE; + STDMETHOD(SetColorKey)(THIS_ DWORD dwFlags, LPDDCOLORKEY lpDDColorKey) PURE; + STDMETHOD(SetOverlayPosition)(THIS_ LONG lX, LONG lY) PURE; + STDMETHOD(SetPalette)(THIS_ LPDIRECTDRAWPALETTE lpDDPalette) PURE; + STDMETHOD(Unlock)(THIS_ LPVOID lpSurfaceData) PURE; + STDMETHOD(UpdateOverlay)(THIS_ LPRECT lpSrcRect, LPDIRECTDRAWSURFACE lpDDDestSurface, LPRECT lpDestRect, DWORD dwFlags, LPDDOVERLAYFX lpDDOverlayFx) PURE; + STDMETHOD(UpdateOverlayDisplay)(THIS_ DWORD dwFlags) PURE; + STDMETHOD(UpdateOverlayZOrder)(THIS_ DWORD dwFlags, LPDIRECTDRAWSURFACE lpDDSReference) PURE; + // clang-format off +}; + +#define DDBLTFAST_WAIT 0x00000010 + +#define DDLOCK_WRITEONLY 0x00000020L +#define DDLOCK_WAIT 0x00000001L + +#define DDPCAPS_ALLOW256 0x00000040l +#define DDPCAPS_8BIT 0x00000004l + +#define PC_RESERVED 0x01 +#define PC_NOCOLLAPSE 0x04 + +#define DDWAITVB_BLOCKBEGIN 0x00000001l + +/* +Actually used methods: + +DECLARE_INTERFACE_(IDirectDraw, IUnknown) { + STDMETHOD(CreatePalette)(THIS_ DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE *, IUnknown *); + STDMETHOD(WaitForVerticalBlank)(THIS_ DWORD, HANDLE); +}; +*/ + +typedef void *LPDDENUMMODESCALLBACK, *LPDDCAPS; +DECLARE_INTERFACE_(IDirectDraw,IUnknown) +{ + // clang-format off + STDMETHOD(Compact)(THIS) PURE; + STDMETHOD(CreateClipper)(THIS_ DWORD dwFlags, LPDIRECTDRAWCLIPPER *lplpDDClipper, IUnknown *pUnkOuter) PURE; + STDMETHOD(CreatePalette)(THIS_ DWORD dwFlags, LPPALETTEENTRY lpColorTable, LPDIRECTDRAWPALETTE *lplpDDPalette, IUnknown *pUnkOuter) PURE; + STDMETHOD(CreateSurface)(THIS_ LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE *lplpDDSurface, IUnknown *pUnkOuter) PURE; + STDMETHOD(DuplicateSurface)(THIS_ LPDIRECTDRAWSURFACE lpDDSurface, LPDIRECTDRAWSURFACE *lplpDupDDSurface) PURE; + STDMETHOD(EnumDisplayModes)(THIS_ DWORD dwFlags, LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext, LPDDENUMMODESCALLBACK lpEnumModesCallback) PURE; + STDMETHOD(EnumSurfaces)(THIS_ DWORD dwFlags, LPDDSURFACEDESC lpDDSD, LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) PURE; + STDMETHOD(FlipToGDISurface)(THIS) PURE; + STDMETHOD(GetCaps)(THIS_ LPDDCAPS lpDDDriverCaps, LPDDCAPS lpDDHELCaps) PURE; + STDMETHOD(GetDisplayMode)(THIS_ LPDDSURFACEDESC lpDDSurfaceDesc) PURE; + STDMETHOD(GetFourCCCodes)(THIS_ LPDWORD lpNumCodes, LPDWORD lpCodes) PURE; + STDMETHOD(GetGDISurface)(THIS_ LPDIRECTDRAWSURFACE *lplpGDIDDSurface) PURE; + STDMETHOD(GetMonitorFrequency)(THIS_ LPDWORD lpdwFrequency) PURE; + STDMETHOD(GetScanLine)(THIS_ LPDWORD lpdwScanLine) PURE; + STDMETHOD(GetVerticalBlankStatus)(THIS_ BOOL *lpbIsInVB) PURE; + STDMETHOD(Initialize)(THIS_ GUID *lpGUID) PURE; + STDMETHOD(RestoreDisplayMode)(THIS) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hWnd, DWORD dwFlags) PURE; + STDMETHOD(SetDisplayMode)(THIS_ DWORD dwWidth, DWORD dwHeight, DWORD dwBPP) PURE; + STDMETHOD(WaitForVerticalBlank)(THIS_ DWORD dwFlags, HANDLE hEvent) PURE; + // clang-format on +}; diff --git a/Stub/miniwin_dsound.h b/Stub/miniwin_dsound.h new file mode 100644 index 000000000..a21f722e2 --- /dev/null +++ b/Stub/miniwin_dsound.h @@ -0,0 +1,46 @@ +#pragma once + +#include "miniwin.h" + +typedef void *LPDSBCAPS, *LPDIRECTSOUND, *LPCDSBUFFERDESC; + +DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown) +{ + // clang-format off + STDMETHOD(GetCaps)(THIS_ LPDSBCAPS pDSBufferCaps); + STDMETHOD(GetCurrentPosition)(THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor); + STDMETHOD(GetFormat)(THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten); + STDMETHOD(GetVolume)(THIS_ LPLONG plVolume); + STDMETHOD(GetPan)(THIS_ LPLONG plPan); + STDMETHOD(GetFrequency)(THIS_ LPDWORD pdwFrequency); + STDMETHOD(GetStatus)(THIS_ LPDWORD pdwStatus); + STDMETHOD(Initialize)(THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc); + STDMETHOD(Lock)(THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, + LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags); + STDMETHOD(Play)(THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags); + STDMETHOD(SetCurrentPosition)(THIS_ DWORD dwNewPosition); + STDMETHOD(SetFormat)(THIS_ LPCWAVEFORMATEX pcfxFormat); + STDMETHOD(SetVolume)(THIS_ LONG lVolume); + STDMETHOD(SetPan)(THIS_ LONG lPan); + STDMETHOD(SetFrequency)(THIS_ DWORD dwFrequency); + STDMETHOD(Stop)(THIS); + STDMETHOD(Unlock)(THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2); + STDMETHOD(Restore)(THIS); + // clang-format on +}; + +typedef void *LPDIRECTSOUNDBUFFER, *LPDSCAPS, *LPUNKNOWN, *LPCGUID; + +DECLARE_INTERFACE_(IDirectSound, IUnknown) +{ + // clang-format off + STDMETHOD(CreateSoundBuffer)(THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter); + STDMETHOD(GetCaps)(THIS_ LPDSCAPS pDSCaps); + STDMETHOD(DuplicateSoundBuffer)(THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate); + STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwLevel); + STDMETHOD(Compact)(THIS); + STDMETHOD(GetSpeakerConfig)(THIS_ LPDWORD pdwSpeakerConfig); + STDMETHOD(SetSpeakerConfig)(THIS_ DWORD dwSpeakerConfig); + STDMETHOD(Initialize)(THIS_ LPCGUID pcGuidDevice); + // clang-format on +}; diff --git a/Stub/miniwin_io.cpp b/Stub/miniwin_io.cpp new file mode 100644 index 000000000..8bf099d3d --- /dev/null +++ b/Stub/miniwin_io.cpp @@ -0,0 +1,141 @@ +#include +#include +#include + +#include "miniwin.h" +#include "stubs.h" + +void TranslateFileName(char *dst, int dstLen, const char *src) +{ + for (int i = 0; i < dstLen; i++) { + char c = *src++; + dst[i] = c == '\\' ? '/' : c; + if (!c) { + break; + } + } +} + +HANDLE WINAPI CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) +{ + char name[260]; + TranslateFileName(name, sizeof(name), lpFileName); + + DUMMY_PRINT("file: %s (%s)", lpFileName, name); + + assert(dwDesiredAccess == GENERIC_READ | GENERIC_WRITE); + + int flags = O_RDWR; + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + if (dwCreationDisposition == OPEN_EXISTING) { + // Nothing + } else if (dwCreationDisposition == CREATE_ALWAYS) { + flags |= O_CREAT | O_TRUNC; + } else { + UNIMPLEMENTED(); + } + int fd = open(name, flags, mode); + + return (HANDLE)fd; +} + +WINBOOL WINAPI ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, + LPOVERLAPPED lpOverlapped) +{ + DUMMY_ONCE(); + + assert(!lpOverlapped); + int len = read((int)hFile, lpBuffer, nNumberOfBytesToRead); + assert(len != -1); + *lpNumberOfBytesRead = len; + return TRUE; +} + +DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) +{ + DUMMY_ONCE(); + + assert(!lpFileSizeHigh); + struct stat s; + int ret = fstat((int)hFile, &s); + assert(ret == 0); + return s.st_size; +} + +WINBOOL WINAPI WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, + LPOVERLAPPED lpOverlapped) +{ + DUMMY_ONCE(); + + assert(!lpOverlapped); + ssize_t len = write((int)hFile, lpBuffer, nNumberOfBytesToWrite); + if (len == -1) { + *lpNumberOfBytesWritten = 0; + return FALSE; + } + *lpNumberOfBytesWritten = (DWORD)len; + return TRUE; +} + +DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) +{ + DUMMY_ONCE(); + + assert(!lpDistanceToMoveHigh); + int whence; + if (dwMoveMethod == FILE_BEGIN) { + whence = SEEK_SET; + } else if (dwMoveMethod == FILE_CURRENT) { + whence = SEEK_CUR; + } else { + UNIMPLEMENTED(); + } + off_t ret = lseek((int)hFile, lDistanceToMove, whence); + return (DWORD)ret; +} + +WINBOOL WINAPI SetEndOfFile(HANDLE hFile) +{ + DUMMY_ONCE(); + + off_t cur = lseek((int)hFile, 0, SEEK_CUR); + assert(cur != -1); + int res = ftruncate((int)hFile, cur); + assert(res == 0); + return TRUE; +} + +DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName) +{ + char name[260]; + TranslateFileName(name, sizeof(name), lpFileName); + + DUMMY_PRINT("file: %s (%s)", lpFileName, name); + + struct stat s; + int res = stat(name, &s); + + if (res == -1) { + SetLastError(ERROR_FILE_NOT_FOUND); + return -1; + } + + return 0x80; +} + +WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes) +{ + DUMMY_PRINT("file: %s", lpFileName); + return TRUE; +} + +WINBOOL WINAPI CloseHandle(HANDLE hObject) +{ + DUMMY(); + + int ret = close((int)hObject); + assert(ret == 0); + return TRUE; +} diff --git a/Stub/miniwin_rand.cpp b/Stub/miniwin_rand.cpp new file mode 100644 index 000000000..2329d5982 --- /dev/null +++ b/Stub/miniwin_rand.cpp @@ -0,0 +1,16 @@ +#include "miniwin.h" + +#include "stubs.h" + +unsigned int rand_state = 1; + +int rand_miniwin(void) +{ + rand_state = rand_state * 214013 + 2531011; + return (rand_state >> 16) & 0x7FFF; +} + +void srand_miniwin(unsigned int seed) +{ + rand_state = seed; +} diff --git a/Stub/miniwin_sdl.cpp b/Stub/miniwin_sdl.cpp new file mode 100644 index 000000000..35bcb1a25 --- /dev/null +++ b/Stub/miniwin_sdl.cpp @@ -0,0 +1,292 @@ +#include + +#include "miniwin_sdl.h" + +#include "../types.h" +#include "stubs.h" + +static std::deque message_queue; + +static int translate_sdl_key(SDL_Keysym key) +{ + int sym = key.sym; + switch (sym) { + case SDLK_ESCAPE: + return VK_ESCAPE; + case SDLK_RETURN: + return VK_RETURN; + case SDLK_TAB: + return VK_TAB; + case SDLK_BACKSPACE: + return VK_BACK; + + + case SDLK_DOWN: + return VK_DOWN; + case SDLK_LEFT: + return VK_LEFT; + case SDLK_RIGHT: + return VK_RIGHT; + case SDLK_UP: + return VK_UP; + + case SDLK_PAGEUP: + return VK_PRIOR; + case SDLK_PAGEDOWN: + return VK_NEXT; + + case SDLK_PAUSE: + return VK_PAUSE; + + case SDLK_SEMICOLON: + return VK_OEM_1; + case SDLK_QUESTION: + return VK_OEM_2; + case SDLK_BACKQUOTE: + return VK_OEM_3; + case SDLK_LEFTBRACKET: + return VK_OEM_4; + case SDLK_BACKSLASH: + return VK_OEM_5; + case SDLK_RIGHTBRACKET: + return VK_OEM_6; + case SDLK_QUOTE: + return VK_OEM_7; + case SDLK_MINUS: + return VK_OEM_MINUS; + case SDLK_PLUS: + return VK_OEM_PLUS; + case SDLK_PERIOD: + return VK_OEM_PERIOD; + case SDLK_COMMA: + return VK_OEM_COMMA; + + case SDLK_LSHIFT: + printf("LEFT SHIFT\n"); + return VK_LSHIFT; + case SDLK_RSHIFT: + // Not handled yet + return -1; + + default: + if (sym >= SDLK_a && sym <= SDLK_z) { + return 'A' + (sym - SDLK_a); + } else if (sym >= SDLK_0 && sym <= SDLK_9) { + return '0' + (sym - SDLK_0); + } else if (sym >= SDLK_F1 && sym <= SDLK_F12) { + return VK_F1 + (sym - SDLK_F1); + } + + DUMMY_PRINT("unknown key: name=%s sym=0x%X scan=%d mod=0x%X", SDL_GetKeyName(sym), sym, key.scancode, key.mod); + return -1; + } +} + +WINBOOL WINAPI PeekMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg) +{ + // DUMMY_PRINT("hwnd: %d", hWnd); + assert(wMsgFilterMin == 0 && wMsgFilterMax == 0); + if (wRemoveMsg == PM_NOREMOVE) { + // XXX: This does not actually fill out lpMsg properly + lpMsg->hwnd = (HWND)-1; + lpMsg->message = 0; + + return !message_queue.empty() || SDL_PollEvent(NULL); + } else if (wRemoveMsg == PM_REMOVE) { + if (!message_queue.empty()) { + *lpMsg = message_queue.front(); + message_queue.pop_front(); + return TRUE; + } + + SDL_Event e; + int pending = SDL_PollEvent(&e); + if (!pending) { + return FALSE; + } + + lpMsg->hwnd = hWnd; + lpMsg->lParam = 0; + lpMsg->wParam = 0; + + switch (e.type) { + case SDL_QUIT: { + lpMsg->message = WM_QUIT; + break; + } + + case SDL_KEYDOWN: + case SDL_KEYUP: { + int key = translate_sdl_key(e.key.keysym); + if (key == -1) { + return FALSE; + } + + lpMsg->message = e.type == SDL_KEYDOWN ? WM_KEYFIRST : WM_KEYUP; + lpMsg->wParam = key; + // Hack: Encode modifier in lParam for TranslateMessage later + lpMsg->lParam = e.key.keysym.mod << 16; + break; + } + + case SDL_MOUSEMOTION: { + lpMsg->message = WM_MOUSEMOVE; + lpMsg->lParam = (e.motion.y << 16) | (e.motion.x & 0xFFFF); + break; + } + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: { + int button = e.button.button; + if (button != SDL_BUTTON_LEFT && button != SDL_BUTTON_RIGHT) { + return FALSE; + } + bool left = button == SDL_BUTTON_LEFT; + lpMsg->message = e.type == SDL_MOUSEBUTTONDOWN ? (left ? WM_LBUTTONDOWN : WM_RBUTTONDOWN) + : (left ? WM_LBUTTONUP : WM_RBUTTONUP); + lpMsg->lParam = (e.button.y << 16) | (e.button.x & 0xFFFF); + break; + } + + case SDL_TEXTINPUT: + case SDL_WINDOWEVENT: { + return FALSE; + } + + default: { + DUMMY_PRINT("unknown SDL message 0x%X", e.type); + return FALSE; + } + } + + return TRUE; + } + UNIMPLEMENTED(); +} + +WINBOOL WINAPI TranslateMessage(CONST MSG *lpMsg) +{ + DUMMY_ONCE(); + assert(lpMsg->hwnd == 0); + + if (lpMsg->message == WM_KEYDOWN) { + int key = lpMsg->wParam; + unsigned mod = (DWORD)lpMsg->lParam >> 16; + + bool shift = mod & KMOD_SHIFT; + bool upper = shift != (mod & KMOD_CAPS); + + bool is_alpha = (key >= 'A' && key <= 'Z'); + bool is_numeric = (key >= '0' && key <= '9'); + bool is_control = key == VK_SPACE || key == VK_BACK || key == VK_ESCAPE || key == VK_TAB || key == VK_RETURN; + bool is_oem = (key >= VK_OEM_1 && key <= VK_OEM_7); + + if (is_control || is_alpha || is_numeric || is_oem) { + if (!upper && is_alpha) { + key = tolower(key); + } else if (shift && is_numeric) { + key = key == '0' ? ')' : key - 0x10; + } else if (is_oem) { + // XXX: This probably only supports US keyboard layout + switch (key) { + case VK_OEM_1: + key = shift ? ':' : ';'; + break; + case VK_OEM_2: + key = shift ? '?' : '/'; + break; + case VK_OEM_3: + key = shift ? '~' : '`'; + break; + case VK_OEM_4: + key = shift ? '{' : '['; + break; + case VK_OEM_5: + key = shift ? '|' : '\\'; + break; + case VK_OEM_6: + key = shift ? '}' : ']'; + break; + case VK_OEM_7: + key = shift ? '"' : '\''; + break; + + case VK_OEM_MINUS: + key = shift ? '_' : '-'; + break; + case VK_OEM_PLUS: + key = shift ? '+' : '='; + break; + case VK_OEM_PERIOD: + key = shift ? '>' : '.'; + break; + case VK_OEM_COMMA: + key = shift ? '<' : ','; + break; + + default: + UNIMPLEMENTED(); + } + } + + if (key >= 32) { + DUMMY_PRINT("char: %c", key); + } + + // XXX: This does not add extended info to lParam + PostMessageA(lpMsg->hwnd, WM_CHAR, key, 0); + } + } + + return TRUE; +} + +SHORT WINAPI GetAsyncKeyState(int vKey) +{ + DUMMY_ONCE(); + return 0; +} + +LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg) +{ + DUMMY_ONCE(); + assert(lpMsg->hwnd == 0); + assert(CurrentProc); + // assert(CurrentProc == GM_Game); + + return CurrentProc(lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam); +} + +WINBOOL WINAPI SetCursorPos(int X, int Y) +{ + DUMMY(); + assert(window); + SDL_WarpMouseInWindow(window, X, Y); + return TRUE; +} + +int WINAPI ShowCursor(WINBOOL bShow) +{ + DUMMY_PRINT("%d", bShow); + if (window) { + SDL_ShowCursor(bShow ? SDL_ENABLE : SDL_DISABLE); + } + return bShow; +} + +WINBOOL WINAPI PostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + DUMMY(); + + assert(hWnd == 0); + + MSG msg; + msg.hwnd = hWnd; + msg.message = Msg; + msg.wParam = wParam; + msg.lParam = lParam; + + message_queue.push_back(msg); + + return TRUE; +} diff --git a/Stub/miniwin_sdl.h b/Stub/miniwin_sdl.h new file mode 100644 index 000000000..c68facc8b --- /dev/null +++ b/Stub/miniwin_sdl.h @@ -0,0 +1,62 @@ +#pragma once + +#include + +#include +#include +#include +#include "SDL_FontCache.h" + + +#define SDL_CHECK(e) assert(e == 0) + +extern SDL_Window *window; +extern SDL_Renderer *renderer; +extern SDL_Texture *texture; + + +#ifdef __WINDOWS__ +#include +#define GetCurrentDir _getcwd +#else +#include +#define GetCurrentDir getcwd +#endif + + + +//My SDL inclusions // + +extern int totalFrames; +//extern SDL_Texture* spriteSheet; +extern SDL_Surface* DiabloTitle; +extern SDL_Event input; +extern FC_Font* font; +extern int SCREEN_WIDTH; +extern int SCREEN_HEIGHT; +extern int TotalPlayers; + + +extern SDL_Rect textureRect; +extern SDL_Rect windowRect; + + +//Menu0 //Main Menu rects +extern SDL_Rect SinglePlrBox; +extern SDL_Rect MultiPlrBox; +extern SDL_Rect ReplayIntroBox; +extern SDL_Rect ShowCreditsBox; +extern SDL_Rect ExitBox; + +//Menu2 // Single player menu rects +extern SDL_Rect SinglePlayerMenuCancelBox; + + +void CreateDiabloMainMenuz(); +void SdlDiabloMainWindow(); +void SDL_RenderDiabloMainPage(); +char *GetWorkingDirectory(); +void CreateMainDiabloMenu(); +void SDLCreateDiabloCursor(); +void SDL_RenderDiabloSinglePlayerPage(); +void RenderCharNames(); \ No newline at end of file diff --git a/Stub/movie.cpp b/Stub/movie.cpp new file mode 100644 index 000000000..75d8d7927 --- /dev/null +++ b/Stub/movie.cpp @@ -0,0 +1,9 @@ +#include "../types.h" +#include "stubs.h" + +BOOL loop_movie; + +void __fastcall play_movie(char *pszMovie, BOOL user_can_close) +{ + DUMMY_PRINT("%s", pszMovie); +} diff --git a/Stub/nthread.cpp b/Stub/nthread.cpp new file mode 100644 index 000000000..4a874299c --- /dev/null +++ b/Stub/nthread.cpp @@ -0,0 +1,78 @@ +#include + +#include "../types.h" +#include "stubs.h" + +int gdwNormalMsgSize; +int gdwLargestMsgSize; +int gdwMsgLenTbl[4]; +int glpMsgTbl[4]; +int gdwTurnsInTransit; +char byte_679704; + +void __fastcall nthread_start(bool set_turn_upper_bit) +{ + DUMMY(); + byte_679704 = 1; + gdwTurnsInTransit = 1; + gdwLargestMsgSize = 496; + gdwNormalMsgSize = 496; +} + +void __cdecl nthread_cleanup() +{ + DUMMY(); +} + +void __fastcall nthread_terminate_game(char *pszFcn) +{ + UNIMPLEMENTED(); +} + +void __fastcall nthread_ignore_mutex(bool bStart) +{ + DUMMY(); +} + +bool __cdecl nthread_has_500ms_passed() +{ + DUMMY_ONCE(); + return TRUE; +} + +DWORD last_frame_time = 0; +const int MSEC_PER_FRAME = 1000 / 35; + +static void frame_rate_limiter() +{ + if (last_frame_time) { + int elapsed = GetTickCount() - last_frame_time; + int remaining = MSEC_PER_FRAME - elapsed; + if (remaining > 0) { + Sleep(std::max(remaining, MSEC_PER_FRAME)); + } + } + last_frame_time = GetTickCount(); +} + +int __fastcall nthread_send_and_recv_turn(int cur_turn, int turn_delta) +{ + DUMMY_ONCE(); + // DUMMY_PRINT("cur_turn: %d turn_delta: %d", cur_turn, turn_delta); + + frame_rate_limiter(); + + return 1; +} + +void __cdecl nthread_set_turn_upper_bit() +{ + UNIMPLEMENTED(); +} + +int __fastcall nthread_recv_turns(int *pfSendAsync) +{ + DUMMY_ONCE(); + *pfSendAsync = 0; + return TRUE; +} diff --git a/Stub/restrict.cpp b/Stub/restrict.cpp new file mode 100644 index 000000000..be5c4a264 --- /dev/null +++ b/Stub/restrict.cpp @@ -0,0 +1,12 @@ +#include "../types.h" +#include "stubs.h" + +bool __cdecl RestrictedTest() +{ + return FALSE; +} + +bool __cdecl ReadOnlyTest() +{ + return FALSE; +} diff --git a/Stub/sdlrender.cpp b/Stub/sdlrender.cpp new file mode 100644 index 000000000..095b2bceb --- /dev/null +++ b/Stub/sdlrender.cpp @@ -0,0 +1,540 @@ +#include "../types.h" +#include "stubs.h" +#include "miniwin_sdl.h" + + +#include +#include +#include +#include "SDL_FontCache.h" + +int SCREEN_WIDTH = 640; +int SCREEN_HEIGHT = 480; + +int LogoWidth; +int LogoHeight; + + +SDL_Texture *DiablologoAnimT; +FC_Font* font; + +SDL_Rect textureRect; +SDL_Rect windowRect; +SDL_Rect CusorLocation; + + SDL_Rect SinglePlrBox; + SDL_Rect MultiPlrBox; + SDL_Rect ReplayIntroBox; + SDL_Rect ShowCreditsBox; + SDL_Rect ExitBox; + SDL_Rect SinglePlayerMenuCancelBox; + +SDL_Surface* DiabloTitle; +SDL_Event input; +SDL_Texture * CursorTexture; + + +bool SinglePlayerMenuItemsLoaded = 0; +bool DiabloImageLoaded = 0; +bool DiabloMainMenuListLoaded = 0; +SDL_Texture * MenuSelectNewHeroTexture; + + + +struct timespec ts; + + + +//DiabloMenu Items +SDL_Surface* MainMenuItemsSurface; +SDL_Texture* MainMenuItemsTexture; +SDL_Rect MainMenuItemsWRect; +SDL_Rect MainMenuItemsTRect; + + + + + +uint32_t XgetTick() { + //struct timespec ts; + unsigned theTick = 0U; + printf("This is supposed to replace GitTicks()"); +// if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + //error +// } + return theTick; +} + + + + +void SDLCreateDiabloCursor() { + int x, y; + SDL_GetMouseState(&x, &y); + + CusorLocation.x = x; + CusorLocation.y = y; + CusorLocation.h = 29; + CusorLocation.w = 33; + + + char LDirectory[FILENAME_MAX]; + GetCurrentDir(LDirectory, FILENAME_MAX); + + char * filename = "/Xresources/cursor.png"; + + strcat(LDirectory, filename); + + + SDL_Surface * CursorImg = IMG_Load(LDirectory); + CursorTexture = SDL_CreateTextureFromSurface(renderer, CursorImg); + SDL_UpdateWindowSurface(window); +} + + + + + + + +void SDL_MAGICAL_RENDER(int x, int y, int w, int h) { + + printf("SDL_MAGICAL RENDER I Am Not Implemented\n"); + // if (window != 0) { + + // int depth = 12; + + // SDL_Surface * image = SDL_CreateRGBSurfaceFrom(destmemarea, SCREEN_WIDTH / 2, SCREEN_HEIGHT, depth, SCREEN_WIDTH, 0, 0, 0, 0); + // SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, image); + // SDL_RenderCopy(renderer, texture, NULL, NULL); + // SDL_RenderPresent(renderer); + // SDL_UpdateWindowSurface(window); + // } + + + +} + + + + +void SdlDiabloMainWindow() { + + SDL_Init(SDL_INIT_EVERYTHING); + IMG_Init(IMG_INIT_PNG); + window = SDL_CreateWindow("Diablo", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); + renderer = SDL_CreateRenderer(window, -1, 0); + printf("Window And Renderer Created!\n"); + + + + +} + + + +char *GetWorkingDirectory() { + char *buff= "wo work"; + //printf("Current working dir: "); + + return buff; +} + + + +void LoadDiabloMenuLogoImage() { + int LogoWidth; + int LogoHeight; + + + char LDirectory[FILENAME_MAX]; + GetCurrentDir(LDirectory, FILENAME_MAX); + + char * filename = "/Xresources/Diablo_Logo.png"; + + strcat(LDirectory, filename); + + + //spriteSheet = NULL; + DiabloTitle = IMG_Load(LDirectory); + DiablologoAnimT = SDL_CreateTextureFromSurface(renderer, DiabloTitle); + + //SDL_QueryTexture() method gets the width and height of the texture + //Now, LogoWidth and Logo Height are filled + //with respective dimensions of the image/texture + SDL_QueryTexture(DiablologoAnimT, NULL, NULL, &LogoWidth, &LogoHeight); + SDL_FreeSurface(DiabloTitle); + + +} + + +void DiabloMainMenuItemsLoaded() { + char LRDirectory[FILENAME_MAX]; + GetCurrentDir(LRDirectory, FILENAME_MAX); + + char * Lfilename = "/Xresources/DiabloMainMenu.png"; + + strcat(LRDirectory, Lfilename); + + SDL_Surface* MainMenuItemsSurface = IMG_Load(LRDirectory); + MainMenuItemsTexture = SDL_CreateTextureFromSurface(renderer, MainMenuItemsSurface); + +} + + +void CreateMainDiabloMenu(){ + + + int totalFrames = 4; + + + + //'windowRect' defines the dimensions of the rendering sprite on window + //SDL_Rect windowRect; + windowRect.x = 120;// 140 ///(SCREEN_WIDTH - LogoWidth / totalFrames) / 2; + windowRect.y = 0; + windowRect.w = 450;//320 + windowRect.h = 150; + + //'textureRect' defines the dimensions of the rendering sprite on texture + //SDL_Rect textureRect; + textureRect.x = 0; + textureRect.y = 0; + textureRect.w = 868; + textureRect.h = 150; + + + if (DiabloImageLoaded == 0) { + + LoadDiabloMenuLogoImage(); + DiabloImageLoaded = 1; + + + } + + // font = FC_CreateFont(); + // FC_LoadFont(font, renderer, "C:/Users/Krash/Desktop/devilutionX/fonts/Exocet.ttf", 40, FC_MakeColor(112, 106, 70, 255), TTF_STYLE_NORMAL); + + + //get the width of a frame by dividing with 4 + textureRect.w /= totalFrames; + //Height for each frame is the same as for the whole sheet/texture + + + // Load The Main Menu List Single Player, Multi Player, foo , bar , exit Diablo + + + int MainMenuItemsW; + int MainMenuItemsH; + + + if (DiabloMainMenuListLoaded == 0) { + + DiabloMainMenuItemsLoaded(); + DiabloMainMenuListLoaded = 1; + } + + + + + MainMenuItemsWRect.x = 0; + MainMenuItemsWRect.y = 0; + MainMenuItemsWRect.w = 470; + MainMenuItemsWRect.h = 320; + + MainMenuItemsTRect.x = 150; + MainMenuItemsTRect.y = 150; + MainMenuItemsTRect.w = 350; + MainMenuItemsTRect.h = 250; + + SDL_QueryTexture(MainMenuItemsTexture, NULL, NULL, &MainMenuItemsW, &MainMenuItemsH); + + +} + +void RenderDiabloLogo() { + int totalFrames = 4; + int delayPerFrame = 100; + int frame = (SDL_GetTicks() / delayPerFrame) % totalFrames; + textureRect.x = frame * textureRect.w; + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + + SDL_RenderClear(renderer); + int column = (SCREEN_WIDTH / 4); + //SDL_RenderCopy(renderer, MainMenuItemsTexture, &MainMenuItemsWRect, &MainMenuItemsTRect); + +} + + +int FontLoaded = 0; +FC_Font* Subfont = FC_CreateFont(); + +void SDL_RenderDiabloMainPage() { + SDL_RenderClear(renderer); + + SinglePlrBox.x = 169; + SinglePlrBox.y = 163; + SinglePlrBox.w = 491; + SinglePlrBox.h = 193; + + + MultiPlrBox.x = 166; + MultiPlrBox.y = 216; + MultiPlrBox.w = 484; + MultiPlrBox.h = 240; + + + ReplayIntroBox.x = 171; + ReplayIntroBox.y = 264; + ReplayIntroBox.w = 483; + ReplayIntroBox.h = 291; + + + ShowCreditsBox.x = 161; + ShowCreditsBox.y = 310; + ShowCreditsBox.w = 487; + ShowCreditsBox.h = 348; + + + ExitBox.x = 187; + ExitBox.y = 363; + ExitBox.w = 460; + ExitBox.h = 399; + + + + + RenderDiabloLogo(); + + + int cx, cy; + SDL_GetMouseState(&cx, &cy); + + CusorLocation.x = cx; + CusorLocation.y = cy; + CusorLocation.h = 29; + CusorLocation.w = 33; + + + + SDL_RenderCopy(renderer, DiablologoAnimT, &textureRect, &windowRect); + SDL_RenderCopy(renderer, MainMenuItemsTexture, &MainMenuItemsWRect, &MainMenuItemsTRect); + SDL_RenderCopy(renderer, CursorTexture, NULL, &CusorLocation); + + char LDirectory[FILENAME_MAX]; + GetCurrentDir(LDirectory, FILENAME_MAX); + char * filename = "/fonts/Exocet.ttf"; + strcat(LDirectory, filename); + + + + + if (FontLoaded == 0){ + + FC_LoadFont(Subfont, renderer, LDirectory, 12, FC_MakeColor(112, 106, 70, 255), TTF_STYLE_NORMAL); + + printf("LoadFont\n\n"); + FontLoaded = 1; + } + FC_Draw(Subfont, renderer, 10, SCREEN_HEIGHT - 40, "DedicaTed To David Brevik, Erich Schaefer, Max Schaefer, MaTT Uelman and"); + FC_Draw(Subfont, renderer, 10, SCREEN_HEIGHT - 25, "The Blizzard North Team ThaT Gave Us A Childhood."); + + + + SDL_RenderPresent(renderer); + +} + + + +void LoadSinglePlayerMenuItems() { + + + + + char LZDirectory[FILENAME_MAX]; + GetCurrentDir(LZDirectory, FILENAME_MAX); + + char * filename = "/Xresources/MenuSelectNewHero.png"; + + strcat(LZDirectory, filename); + + SDL_Surface * MenuSelectNewHeroSurface = IMG_Load(LZDirectory); + MenuSelectNewHeroTexture = SDL_CreateTextureFromSurface(renderer, MenuSelectNewHeroSurface); + SinglePlayerMenuItemsLoaded = 1; + + + +} + + + +void SDL_RenderDiabloSinglePlayerPage() { + RenderDiabloLogo(); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + + + + int cx, cy; + SDL_GetMouseState(&cx, &cy); + + CusorLocation.x = cx; + CusorLocation.y = cy; + CusorLocation.h = 29; + CusorLocation.w = 33; + + if (SinglePlayerMenuItemsLoaded == 0) + { + + LoadSinglePlayerMenuItems(); + + } + + SinglePlayerMenuCancelBox.x = 520; + SinglePlayerMenuCancelBox.y = 454; + SinglePlayerMenuCancelBox.w = 640; + SinglePlayerMenuCancelBox.h = 480; + /* + + X 520 , Y 454 + X 615 , Y 471 +*/ + + + + int MenuSelectNewHeroW = 907; + int MenuSelectNewHeroH = 469; + //W 907 H 469 + + SDL_Rect MenuSelectNewHeroWRect; + MenuSelectNewHeroWRect.x = 0; + MenuSelectNewHeroWRect.y = 140; + MenuSelectNewHeroWRect.w = 640; + MenuSelectNewHeroWRect.h = 350; + + + SDL_Rect MenuSelectNewHeroTRect; + MenuSelectNewHeroTRect.x = 0; + MenuSelectNewHeroTRect.y = 0; + MenuSelectNewHeroTRect.w = 907; + MenuSelectNewHeroTRect.h = 500; + + //SDL_QueryTexture(MenuSelectNewHeroTexture, NULL, NULL, &MenuSelectNewHeroW, &MenuSelectNewHeroH); + +// printf("W %d H %d \n", MenuSelectNewHeroW, MenuSelectNewHeroH); + + + + + SDL_RenderCopy(renderer, MenuSelectNewHeroTexture, &MenuSelectNewHeroTRect, &MenuSelectNewHeroWRect); + SDL_RenderCopy(renderer, DiablologoAnimT, &textureRect, &windowRect); + SDL_RenderCopy(renderer, CursorTexture, NULL, &CusorLocation); + + //SDL_RenderPresent(renderer); + +} + +void LoadFont() { + char LDirectory[FILENAME_MAX]; + GetCurrentDir(LDirectory, FILENAME_MAX); + char * filename = "/fonts/Exocet.ttf"; + strcat(LDirectory, filename); + + + font = FC_CreateFont(); + FC_LoadFont(font, renderer, LDirectory, 30, FC_MakeColor(112, 106, 70, 255), TTF_STYLE_NORMAL); + +} + +void LoadClickBoxes(int numberofchars) { + SDL_Rect Charpos1; + Charpos1.x = -1; + Charpos1.y = -1; + Charpos1.h = -1; + Charpos1.w = -1; + + SDL_Rect Charpos2; + Charpos2.x = -1; + Charpos2.y = -1; + Charpos2.h = -1; + Charpos2.w = -1; + + SDL_Rect Charpos3; + Charpos3.x = -1; + Charpos3.y = -1; + Charpos3.h = -1; + Charpos3.w = -1; + + SDL_Rect Charpos4; + Charpos4.x = -1; + Charpos4.y = -1; + Charpos4.h = -1; + Charpos4.w = -1; + + SDL_Rect Charpos5; + Charpos5.x = -1; + Charpos5.y = -1; + Charpos5.h = -1; + Charpos5.w = -1; + + SDL_Rect Charpos6; + Charpos6.x = -1; + Charpos6.y = -1; + Charpos6.h = -1; + Charpos6.w = -1; + + //The menu doesn't fit past 6 chars. + SDL_Rect Charpos7; + SDL_Rect Charpos8; + SDL_Rect Charpos9; + + +} + + + + + +int LoadedFont = 0; +int TotalPlayers = 0; +void RenderCharNames() { + if (LoadedFont == 0) { + LoadFont(); + LoadedFont = 1; + } + + +// SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + //X 355, Y 269 + int x = 364; + int y = 240; + TotalPlayers = 0; + for (int i = 0; i < 6; i++) { + if (hero_names[i][0] != 0) { + // Checking if section of array is empty. + //if array has something in this then draw name. + for (int j = 0; j < 32; j++) { + hero_names[i][j] = toupper(hero_names[i][j]);// making all the names uppercase... + + } + + + + const char * name = hero_names[i]; // getting the index of the name and drawing it to screen + FC_Draw(font, renderer, x, y, name); + + + y += 30; + TotalPlayers++; + } + + + } + + +SDL_RenderPresent(renderer); + + +} diff --git a/Stub/sdlrender.h b/Stub/sdlrender.h new file mode 100644 index 000000000..afacd3275 --- /dev/null +++ b/Stub/sdlrender.h @@ -0,0 +1,37 @@ +#pragma once + + + +extern int totalFrames; +//extern SDL_Texture* spriteSheet; +extern SDL_Surface* DiabloTitle; +extern SDL_Event input; +extern FC_Font* font; +extern int SCREEN_WIDTH; +extern int SCREEN_HEIGHT; +extern int TotalPlayers; + + +extern SDL_Rect textureRect; +extern SDL_Rect windowRect; + + +//Menu0 //Main Menu rects +extern SDL_Rect SinglePlrBox; +extern SDL_Rect MultiPlrBox; +extern SDL_Rect ReplayIntroBox; +extern SDL_Rect ShowCreditsBox; +extern SDL_Rect ExitBox; + +//Menu2 // Single player menu rects +extern SDL_Rect SinglePlayerMenuCancelBox; + + +void CreateDiabloMainMenuz(); +void SdlDiabloMainWindow(); +void SDL_RenderDiabloMainPage(); +char *GetWorkingDirectory(); +void CreateMainDiabloMenu(); +void SDLCreateDiabloCursor(); +void SDL_RenderDiabloSinglePlayerPage(); +void RenderCharNames(); \ No newline at end of file diff --git a/Stub/sound.cpp b/Stub/sound.cpp new file mode 100644 index 000000000..d669ef6cf --- /dev/null +++ b/Stub/sound.cpp @@ -0,0 +1,227 @@ +#include "../types.h" +#include "stubs.h" +#include +#include + +bool SoundInited; +char gbSndInited; +char gbDupSounds; +UCHAR gbMusicOn; +UCHAR gbSoundOn; +Mix_Music *gMusic = NULL; +Mix_Chunk *sample; +Mix_Music *music; + +char *sgszMusicTracks[6] = {"Music\\DTowne.wav", "Music\\DLvlA.wav", "Music\\DLvlB.wav", + "Music\\DLvlC.wav", "Music\\DLvlD.wav", "Music\\Dintro.wav"}; + +bool IsMusicPlaying = 0; + +void __fastcall snd_init() +{ + printf("SND INIT\n\n"); + // Initialize SDL. + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + + printf("ERROR : %s\n\n", SDL_GetError()); + } + if (Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 4096) < 0) { + printf("SDL_mixer could not initialize! SDL_mixer Error: %s\n", Mix_GetError()); + } + + gbSndInited = 1; + gbSoundOn = 1; + SoundInited = 1; +} + +void *sgpMusicTrack; +void *buffer; +int bytestoread; +int channel = 2; + + + +SDL_AudioSpec wanted; + static Uint8 *audio_chunk; + static Uint32 audio_len; + static Uint8 *audio_pos; + + +void fill_audio(void *udata, Uint8 *stream, int len) + { + /* Only play if we have data left */ + if ( audio_len == 0 ) + return; + + /* Mix as much data as possible */ + len = ( len > audio_len ? audio_len : len ); + SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME); + audio_pos += len; + audio_len -= len; + } + + +void __fastcall music_start(int nTrack) +{ + wanted.freq = 22050; + wanted.format = AUDIO_S8; + wanted.channels = 5; /* 1 = mono, 2 = stereo */ + wanted.samples = 1024; /* Good low-latency value for callback */ + wanted.callback = fill_audio; + wanted.userdata = NULL; + + + gbSoundOn = true; + gbMusicOn = true; + int nread; + void *file; + int v6; + + if (buffer != NULL) { + music_stop(); + } + + if (SoundInited) { + /// I know this needs clean up... I haven't the time to do this. + SFileOpenFile(sgszMusicTracks[nTrack], &sgpMusicTrack); + + // This is a hack.... I don't like it . + // If you know this better than I , please help clean it up. + + + + //SDL_OpenAudio(&wanted, NULL); + + if (nTrack == 0) { + Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 16); + + channel = 2; + } + if (nTrack == 1) { + Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 1, 16); + channel = 1; + } + + file = sgpMusicTrack; + bytestoread = (int)SFileGetFileSize((HANDLE)file, 0); + buffer = DiabloAllocPtr(bytestoread); + SFileReadFile(file, (char *)buffer, bytestoread, (unsigned long *)&nread, 0); + Mix_Chunk *Music = Mix_QuickLoad_WAV((Uint8 *)buffer); + + + + Mix_PlayChannel(channel, Music, 0); + } +} + +void IsPlayMusic() +{ + // if (Mix_PlayingMusic() == 0) { + // // Play the music + // Mix_PlayMusic(gMusic, -1); + // } +} + +void __cdecl music_stop() +{ + + // memset(buffer, 0, sizeof(bytestoread)); + // Mix_HaltMusic(); + // DUMMY(); +} + +bool __fastcall snd_playing(TSnd *pSnd) +{ + printf("snd_playing!!!!\n"); + // UNIMPLEMENTED(); +} + +void *SFXbuffer; +int SFXsoundch = 1; +void LoadAndPlaySound(char *FilePath, int lVolume, int lPan) +{ + int nrread; + void *file; + + SFileOpenFile(FilePath, &SFXbuffer); + //Mix_OpenAudio(20000, AUDIO_S8, 3, 4096); + file = SFXbuffer; + bytestoread = (int)SFileGetFileSize((HANDLE)file, 0); + SFXbuffer = DiabloAllocPtr(bytestoread); + SFileReadFile(file, (char *)SFXbuffer, bytestoread, (unsigned long *)&nrread, 0); + Mix_Chunk *SoundFX = Mix_QuickLoad_WAV((Uint8 *)SFXbuffer); + + Mix_PlayChannel(3, SoundFX, 0); + //Mix_FreeChunk(SoundFX); +} + +void __fastcall snd_play_snd(TSnd *pSnd, int lVolume, int lPan) +{ + + void *file; + + file = pSnd; + + // bytestoread = (int)SFileGetFileSize((HANDLE)file, 0); + // sbuffer = DiabloAllocPtr(bytestoread); + // SFileReadFile(file, (char *)sbuffer, bytestoread, (unsigned long *)&nrread, 0); + // Mix_Chunk *sound = Mix_QuickLoad_WAV((Uint8 *)sbuffer); + // Mix_PlayChannel(channel, sound, 0); + + printf("snd_play_snd!!!!\n"); + + // UNIMPLEMENTED(); +} + +void __fastcall snd_stop_snd(TSnd *pSnd) +{ + DUMMY(); +} +// effects_play_sound +// void effects_play_sound() + +// added +void __fastcall SDL_PlayEffect(int i, int mode) +{ + + printf("113Debug Mode delete me\n\n"); + UNIMPLEMENTED(); +} + +// void *ptr[900]; +TSnd *__fastcall sound_file_load(char *path) +{ + printf("File Is Being Loaded %s\n", path); + + SFileOpenFile(path, &SFXbuffer); + + // UNIMPLEMENTED(); +} + +void __fastcall sound_file_cleanup(TSnd *sound_file) +{ + printf("125Debug Mode delete me\n\n"); + UNIMPLEMENTED(); +} + +int __fastcall sound_get_or_set_sound_volume(int volume) +{ + printf("131Debug Mode delete me\n\n"); + DUMMY_PRINT("volume: %d", volume); + return volume; +} + +int __fastcall sound_get_or_set_music_volume(int volume) +{ + printf("138Debug Mode delete me\n\n"); + Mix_Volume(1, MIX_MAX_VOLUME / 2); + + DUMMY_PRINT("volume: %d", volume); + return volume; +} + +void __fastcall snd_update(bool bStopAll) +{ + // printf("147Debug Mode delete me\n\n"); + // DUMMY_PRINT("stopall: %d", bStopAll); +} diff --git a/Stub/sound.h b/Stub/sound.h new file mode 100644 index 000000000..019f22d6e --- /dev/null +++ b/Stub/sound.h @@ -0,0 +1 @@ +extern void IsPlayMusic(); \ No newline at end of file diff --git a/Stub/storm.cpp b/Stub/storm.cpp new file mode 100644 index 000000000..f9a44b338 --- /dev/null +++ b/Stub/storm.cpp @@ -0,0 +1,365 @@ +#include "../types.h" +#include "stubs.h" + +DWORD nLastError = 0; + +BOOL STORMAPI SNetCreateGame(const char *pszGameName, const char *pszGamePassword, const char *pszGameStatString, + DWORD dwGameType, char *GameTemplateData, int GameTemplateSize, int playerCount, + char *creatorName, char *a11, int *playerID) +{ + DUMMY(); + return TRUE; +} + +BOOL STORMAPI SNetDestroy() +{ + DUMMY(); + return TRUE; +} + +BOOL STORMAPI SNetDropPlayer(int playerid, DWORD flags) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SNetGetGameInfo(int type, void *dst, size_t length, size_t *byteswritten) +{ + DUMMY(); + return TRUE; +} + +BOOL STORMAPI SNetGetTurnsInTransit(int *turns) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SNetLeaveGame(int type) +{ + DUMMY(); + return TRUE; +} + +BOOL STORMAPI SNetPerformUpgrade(DWORD *upgradestatus) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SNetReceiveTurns(int a1, int arraysize, char **arraydata, unsigned int *arraydatabytes, + DWORD *arrayplayerstatus) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SNetSendTurn(char *data, size_t databytes) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SNetSetGameMode(DWORD modeFlags, bool makePublic) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SNetSendServerChatCommand(const char *command) +{ + UNIMPLEMENTED(); +} + +// BOOL STORMAPI SFileCloseArchive(HANDLE hArchive) +// { +// UNIMPLEMENTED(); +// } + +// BOOL STORMAPI SFileCloseFile(HANDLE hFile) +// { +// UNIMPLEMENTED(); +// } + +BOOL STORMAPI SFileDdaBeginEx(HANDLE directsound, DWORD flags, DWORD mask, unsigned __int32 lDistanceToMove, + signed __int32 volume, signed int a6, int a7) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SFileDdaDestroy() +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SFileDdaEnd(HANDLE directsound) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SFileDdaGetPos(HANDLE directsound, int a2, int a3) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SFileDdaInitialize(HANDLE directsound) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SFileDdaSetVolume(HANDLE directsound, signed int bigvolume, signed int volume) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SFileGetFileArchive(HANDLE hFile, HANDLE archive) +{ + UNIMPLEMENTED(); +} + +// LONG STORMAPI SFileGetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) +// { +// UNIMPLEMENTED(); +// } + +// BOOL STORMAPI SFileOpenArchive(const char *szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE +// *phMpq) +// { +// UNIMPLEMENTED(); +// } + +BOOL STORMAPI SFileOpenFile(const char *filename, HANDLE *phFile) +{ + BOOL result; + //eprintf("%s: %s\n", __FUNCTION__, filename); + + result = SFileOpenFileEx((HANDLE)patch_rt_mpq, filename, 0, phFile); + if (!result) { + result = SFileOpenFileEx((HANDLE)diabdat_mpq, filename, 0, phFile); + } + + if (!result || !*phFile) { + // eprintf("%s: Not found: %s\n", __FUNCTION__, filename); + } + return result; +} + +// BOOL STORMAPI SFileOpenFileEx(HANDLE hMpq, const char *szFileName, DWORD dwSearchScope, HANDLE +// *phFile) +// { +// UNIMPLEMENTED(); +// } + +// BOOL STORMAPI SFileReadFile(HANDLE hFile, void *buffer, DWORD nNumberOfBytesToRead, DWORD *read, +// LONG lpDistanceToMoveHigh) +// { +// UNIMPLEMENTED(); +// } + +// int __stdcall SFileSetFilePointer(HANDLE, int, HANDLE, int) +// { +// UNIMPLEMENTED(); +// } + +HWND STORMAPI SDrawGetFrameWindow(HWND *sdraw_framewindow) +{ + DUMMY(); + return NULL; +} + +// BOOL STORMAPI SDrawManualInitialize(HWND hWnd, LPDIRECTDRAW ddInterface, LPDIRECTDRAWSURFACE +// primarySurface, LPDIRECTDRAWSURFACE surface2, LPDIRECTDRAWSURFACE surface3, LPDIRECTDRAWSURFACE +// backSurface, LPDIRECTDRAWPALETTE ddPalette, HPALETTE hPalette) +//{ +// UNIMPLEMENTED(); +//} + +void *STORMAPI SMemAlloc(size_t amount, char *logfilename, int logline, char defaultValue) +{ + // fprintf(stderr, "%s: %d (%s:%d)\n", __FUNCTION__, amount, logfilename, logline); + assert(amount != -1); + return malloc(amount); +} + +BOOL STORMAPI SMemFree(void *location, char *logfilename, int logline, char defaultValue) +{ + // fprintf(stderr, "%s: (%s:%d)\n", __FUNCTION__, logfilename, logline); + assert(location); + free(location); + return TRUE; +} + +void *STORMAPI SMemReAlloc(void *location, size_t amount, char *logfilename, int logline, char defaultValue) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SRegLoadData(const char *keyname, const char *valuename, int size, LPBYTE lpData, BYTE flags, + LPDWORD lpcbData) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SRegLoadString(const char *keyname, const char *valuename, BYTE flags, char *buffer, size_t buffersize) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SRegLoadValue(const char *keyname, const char *valuename, BYTE flags, int *value) +{ + DUMMY_PRINT("key: %s value: %s", keyname, valuename); + return FALSE; +} + +BOOL STORMAPI SRegSaveData(const char *keyname, const char *valuename, int size, BYTE *lpData, DWORD cbData) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SRegSaveString(const char *keyname, const char *valuename, BYTE flags, char *string) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SRegSaveValue(const char *keyname, const char *valuename, BYTE flags, DWORD result) +{ + DUMMY_PRINT("key: %s value: %s", keyname, valuename); + return TRUE; +} + +// BOOL STORMAPI SVidDestroy() +//{ +// UNIMPLEMENTED(); +//} +// +// BOOL STORMAPI SVidInitialize(HANDLE video) +//{ +// UNIMPLEMENTED(); +//} +// +// BOOL STORMAPI SVidPlayBegin(char *filename, int arg4, int a3, int a4, int a5, int a6, HANDLE +// *video) +//{ +// UNIMPLEMENTED(); +//} +// +// BOOL STORMAPI SVidPlayEnd(HANDLE video) +//{ +// UNIMPLEMENTED(); +//} + +BOOL STORMAPI SErrDisplayError(DWORD dwErrMsg, const char *logfilename, int logline, const char *message, + BOOL allowOption, int exitCode) +{ + UNIMPLEMENTED(); +} + +BOOL STORMAPI SErrGetErrorStr(DWORD dwErrCode, char *buffer, size_t bufferchars) +{ + UNIMPLEMENTED(); +} + +DWORD STORMAPI SErrGetLastError() +{ + return nLastError; +} + +void STORMAPI SErrSetLastError(DWORD dwErrCode) +{ + nLastError = dwErrCode; +} + +void STORMAPI SMemCopy(void *dest, const void *source, size_t size) +{ + UNIMPLEMENTED(); +} + +void STORMAPI SMemFill(void *location, size_t length, char fillWith) +{ + UNIMPLEMENTED(); +} + +void STORMAPI SMemZero(void *location, DWORD length) +{ + UNIMPLEMENTED(); +} + +int STORMAPI SMemCmp(void *location1, void *location2, DWORD size) +{ + UNIMPLEMENTED(); +} + +int STORMAPI SStrCopy(char *dest, const char *src, int max_length) +{ + UNIMPLEMENTED(); +} + +int STORMAPI SStrCmp(const char *string1, const char *string2, size_t size) +{ + UNIMPLEMENTED(); +} + +int STORMAPI SStrCmpI(const char *string1, const char *string2, size_t size) +{ + UNIMPLEMENTED(); +} + +// void __stdcall SDrawMessageBox(char *, char *, int) +//{ +// UNIMPLEMENTED(); +//} +// +// void __cdecl SDrawDestroy(void) +//{ +// UNIMPLEMENTED(); +//} +// +// bool __cdecl StormDestroy(void) +//{ +// UNIMPLEMENTED(); +//} +// +// bool __stdcall SFileSetBasePath(char *) +//{ +// UNIMPLEMENTED(); +//} + +void __cdecl SDrawRealizePalette(void) +{ + DUMMY(); +} + +// bool __cdecl SVidPlayContinue(void) +//{ +// UNIMPLEMENTED(); +//} + +bool __stdcall SNetGetOwnerTurnsWaiting(int *) +{ + UNIMPLEMENTED(); +} + +void *__stdcall SNetUnregisterEventHandler(int, void(__stdcall *)(struct _SNETEVENT *)) +{ + DUMMY(); + return (void *)-1; +} + +void *__stdcall SNetRegisterEventHandler(int, void(__stdcall *)(struct _SNETEVENT *)) +{ + UNIMPLEMENTED(); +} + +bool __stdcall SNetSetBasePlayer(int) +{ + DUMMY(); + return TRUE; +} + +int __stdcall SNetInitializeProvider(unsigned long a1, struct _SNETPROGRAMDATA *client_info, + struct _SNETPLAYERDATA *user_info, struct _SNETUIDATA *ui_info, + struct _SNETVERSIONDATA *fileinfo) +{ + DUMMY(); + ui_info->selectnamecallback(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + return TRUE; +} + +int __stdcall SNetGetProviderCaps(struct _SNETCAPS *) +{ + UNIMPLEMENTED(); +} diff --git a/Stub/storm_net.cpp b/Stub/storm_net.cpp new file mode 100644 index 000000000..5b116ed41 --- /dev/null +++ b/Stub/storm_net.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include "../types.h" +#include "stubs.h" + +struct StubMessage { + int playerid; + std::string data; + + StubMessage(const &StubMessage) = delete; +}; + +std::deque messages; +StubMessage current_message{0, ""}; + +BOOL STORMAPI SNetReceiveMessage(int *senderplayerid, char **data, int *databytes) +{ + DUMMY_ONCE(); + if (messages.size() == 0) { + SErrSetLastError(STORM_ERROR_NO_MESSAGES_WAITING); + return FALSE; + } + + current_message = std::move(messages.front()); + messages.pop_front(); + + *senderplayerid = current_message.playerid; + *data = const_cast(current_message.data.data()); + *databytes = current_message.data.size(); + + return TRUE; +} + +BOOL STORMAPI SNetSendMessage(int playerID, void *data, size_t databytes) +{ + DUMMY(); + messages.push_back(StubMessage{playerID, std::string((char *)data, databytes)}); + return TRUE; +} diff --git a/Stub/stubs.h b/Stub/stubs.h new file mode 100644 index 000000000..0778e3358 --- /dev/null +++ b/Stub/stubs.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include "SDL_FontCache.h" + + + +#include +#include + +#define eprintf(...) fprintf(stderr, __VA_ARGS__) + +#define UNIMPLEMENTED() \ + { \ + eprintf("UNIMPLEMENTED: %s @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + abort(); \ + } + +#define DUMMY() //eprintf("DUMMY: %s @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__) + +#define DUMMY_ONCE() \ + { \ + static bool dummy_shown = false; \ + if (!dummy_shown) { \ + DUMMY(); \ + dummy_shown = true; \ + } \ + } + +#define DUMMY_PRINT(fmt, ...) eprintf("DUMMY: %s : " fmt "\n", __FUNCTION__, __VA_ARGS__) + +static inline const char *nullstr(const char *a) +{ + return a ? a : "(null)"; +} + diff --git a/Support/CONTRIBUTING.md b/Support/CONTRIBUTING.md new file mode 100644 index 000000000..d0c51286a --- /dev/null +++ b/Support/CONTRIBUTING.md @@ -0,0 +1,203 @@ +# Contribution Guide + +This guide outlines useful resources, tools and processes for contribution to +Devilution. + +## Useful Repos + +* [diasurgical/scalpel](https://github.com/diasurgical/scalpel) - uploaded .SYM files from each release of Diablo 1 on Playstation +* [diasurgical/devilution-comparer](https://github.com/diasurgical/devilution-comparer) - small helper tool to aid comparing functions between devilution and the original binary +* [sanctuary/notes](https://github.com/sanctuary/notes) - documented Windows-specific Diablo code +* [sanctuary/psx](https://github.com/sanctuary/psx) - .SYM files converted to C headers + +## Software and Utils + +* A clean installation of Diablo patched to version 1.09b (Diablo.exe) +* Download IDA (Interactive Disassembler) [Hex-Rays](https://www.hex-rays.com/products/ida/support/download_freeware.shtml) +* Download IDC script from sanctuary/notes repository: [notes.idc](http://sanctuary.github.io/notes/notes.idc) + +## How To... + +Described below are steps for using the IDA and SYM files to reverse the Diablo +source. + +### Understanding Devilution and Sanctuary Notes + +Both Devilution and the Sanctuary Notes repo have the intended aim to get as +close as possible to document the original game. Devilution is closer in the +sense that the same names have been used for functions as based on the SYM +debug info. The notes repo has tried to use consistent naming for functions, +e.g. prefix with source file name. + +See for instance [drlg_l1_load_dun](http://sanctuary.github.io/notes/#function/drlg_l1_load_dun), +which is defined in `drlg_l1.cpp`. This function has the PSX signature +`void LoadL1Dungeon__FPcii(char *sFileName, int vx, int vy)`, but is documented +in the Sanctuary Notes repo as follows for consistency: + +```cpp +/// address: 0x40AE79 +/// +/// drlg_l1_load_dun loads tile IDs, monsters and objects from the given +/// dungeon file. +/// +/// PSX ref: 0x8013CF64 +/// PSX def: void LoadL1Dungeon__FPcii(char *sFileName, int vx, int vy) +void __fastcall drlg_l1_load_dun(char *dun_path, int view_x, int view_y); +``` + +### Interactive Disassembler Usage + +* Open the `Diablo.exe` (verison 1.09b in IDA) and wait for it to finish + analysis + * Open as "Portable Executable" + * Processor type i386 (80386) +* Run the IDC script in IDA on the fresh IDB database to import names for + variables and functions, type definitions, etc. (Note: run the IDC script + **only** on new IDB databases as it removes all variable names before adding new + ones.); for more info, see [#79 (comment)](https://github.com/diasurgical/devilution/pull/79#issuecomment-400536087) +* Example: search for `drlg_l1_load_dun` + * Starting memory address `0x40AE79` + * Function name `drlg_l1_load_dun` + * Function arguments `(char *dun_path, int view_x, int view_y)` + * #TODO what else can be inferred from below? + +```asm +; drlg_l1_load_dun loads tile IDs, monsters and objects from the given +; dungeon file. +; Attributes: bp-based frame + +; void __fastcall drlg_l1_load_dun(char *dun_path, int view_x, int view_y) +drlg_l1_load_dun proc near + +var_C= dword ptr -0Ch +var_8= dword ptr -8 +var_4= dword ptr -4 +view_y= dword ptr 8 + +push ebp +mov ebp, esp +sub esp, 0Ch +push ebx +push esi +push edi +push 10h +pop eax +mov [ebp+var_C], edx +push 60h +mov dword_5D2458, eax +mov dword_5D245C, eax +pop eax +mov esi, ecx +mov dword_5CF328, eax +mov dword_5CF32C, eax +call gendung_init_transparency +xor edx, edx ; size +mov ecx, esi ; file_path +call engine_mem_load_file +mov esi, eax +xor ecx, ecx +``` + +### About the SYM + +The [diasurgical/scalpel](https://github.com/diasurgical/scalpel) repository includes a copy of a symbolic file that was +accidentally left on the Japanese release of Diablo on Playstation 1. The CD +contained debug information in a .SYM file, the format of which has been +reversed, so we can recover type information, variable names, etc, for the PSX +release. + +* Download and open [jap_05291998.out](https://raw.githubusercontent.com/diasurgical/scalpel/master/psx/symbols/jap_05291998.out) +* Example: search for `LoadL1Dungeon__FPcii` + * Starting memory address `0x8013CF64` + * Function name `LoadL1Dungeon` + * Function arguments `(*char sFilename, int vx, int, vy)` + * #TODO what else can be inferred from below? + +``` +135ea8: $8013cf64 8c Function_start + fp = 29 + fsize = 48 + retreg = 31 + mask = $80070000 + maskoffs = -4 + line = 905 + file = C:\diabpsx\SOURCE\DRLG_L1.CPP + name = LoadL1Dungeon__FPcii +135ef4: $00000010 94 Def class REGPARM type PTR CHAR size 0 name sFileName +135f0b: $00000011 94 Def class REGPARM type INT size 0 name vx +135f1b: $00000012 94 Def class REGPARM type INT size 0 name vy +135f2b: $8013cf64 90 Block_start line = 1 +135f34: $00000005 94 Def class REG type INT size 0 name i +135f43: $00000007 94 Def class REG type INT size 0 name j +135f52: $0000000b 94 Def class REG type INT size 0 name rw +135f62: $0000000c 94 Def class REG type INT size 0 name rh +135f72: $00000010 94 Def class REG type PTR UCHAR size 0 name pLevelMap +135f89: $00000008 94 Def class REG type PTR UCHAR size 0 name lm +135f99: $8013d0c4 90 Block_start line = 44 +135fa2: $8013d11c 92 Block_end line = 60 +135fab: $8013d11c 92 Block_end line = 60 +135fb4: $8013d138 8e Function_end +``` + +## Comparing a function with the original exe + +### Using Riivaaja + +* Step 1: +https://docs.docker.com/install/ +* Step 2: +Download latest devilution-comparer: https://github.com/diasurgical/devilution-comparer/releases (build from src if on Mac) +* Step 3: +Get the Diablo 1.09 exe +* Step 4: +If not on Windows Devilution-comparer requires Wine, either install Wine or use Riivaaja as a proxy (more on this later if you would like to go this route). +* Step 5: + +#### To get a function for comparison + +Build: +`docker run --rm -v $(pwd):/root/devilution -e MAKE_BUILD=pdb diasurgical/riivaaja` +Generate diff: +`devilution-comparer Diablo_original.exe Diablo.exe ` +You can add `--no-mem-disp` if you want a cleaner output but this can also hide valuable details +This will generate an `orig.asm` and `compare.asm` that you can compare in your favorit `diff` application, in the folder that you can the command from. + +To use Riivaaja instead of installing Wine, create `wine` in your `$PATH` and add this content: + +```bash +#!/bin/sh +docker run --rm -v $(pwd):/root/devilution --entrypoint "/usr/bin/wine" diasurgical/riivaaja:stable $(basename $1) $2 $3 +``` + +(Don't forget to also set exec permissions on the file) + +### Using devilution-comparer with Wine + +Install dependencies: +1. Install Wine if not on Windows (e.g. `sudo pacman -S wine`) +2. Install MS VC+ 5 + SP3 and MS VC+ 6 + SP5 + PP. (for more information see the [building instructions](https://github.com/diasurgical/devil-nightly#building-with-visual-c-6) of the readme) + +Install `devililution-comparer` from release (or from source below): +1. Download and extract the latest release from https://github.com/diasurgical/devilution-comparer/releases + +Or install `devililution-comparer` from source: +1. `git clone https://github.com/diasurgical/devililution-comparer` +2. `cd devililution-comparer` +3. `cargo build --release` +4. `cp cvdump.exe target/release/` +5. `cp comparer-config.toml target/release/` + +Clone Devilution nightly, build and compare against the original Diablo binary: +1. `git clone https://github.com/diasurgical/devil-nightly` +2. `make MAKE_BUILD=pdb -f MakefileVC` +3. `cp /path/to/diablo-v1.09b.exe .` +4. `../devilution-comparer/target/debug/devilution-comparer diablo-v1.09b.exe Diablo.exe ` (replace `` with e.g. `InitMonsterTRN`) +5. `code --diff orig.asm compare.asm` (or `diff -u orig.asm compare.asm`) + +To watch build directory for changes use the `-w` command line flag: + +```bash +$ ./devilution-comparer -w diablo-v1.09b.exe Diablo.exe InitMonsterTRN +Found InitMonsterTRN at 0x4322EC, size: 0x8C; orig size: 0x8C +Started watching Diablo.pdb for changes. CTRL+C to quit. +``` diff --git a/Support/INSTALL_linux.md b/Support/INSTALL_linux.md new file mode 100755 index 000000000..efbdcd681 --- /dev/null +++ b/Support/INSTALL_linux.md @@ -0,0 +1,49 @@ +# Installation + +## Dependencies + +Ubuntu +```bash +sudo apt install g++-mingw-w64-i686 +``` + +Arch Linux +```bash +pacman -S mingw-w64-gcc mingw-w64-binutils +``` + +Fedora 28: +```bash +sudo dnf install mingw32-gcc-c++ wine +``` + +elementary OS: +```bash +sudo apt install mingw-w64 wine +``` + + +## Building + +```bash +git clone https://github.com/galaxyhaxz/devilution +cd devilution +cp /path/to/diablo_game_dir/diabloui.dll . +cp /path/to/diablo_game_dir/storm.dll . +make +``` + +On a 32-bit host, `$ make MINGW32=mingw32` should be used, to specify the 32-bit +toolchain. + +## Install + +```bash +cp devilution.exe /path/to/diablo_game_dir/ +``` + +## Run + +```bash +wine devilution.exe +``` diff --git a/Support/INSTALL_mac.md b/Support/INSTALL_mac.md new file mode 100644 index 000000000..ef2d34d2d --- /dev/null +++ b/Support/INSTALL_mac.md @@ -0,0 +1,32 @@ +# Installation + +## Dependencies + +[Homebrew](https://brew.sh/) + +```bash +brew install wine +brew install mingw-w64 +``` + +## Building + +```bash +git clone https://github.com/galaxyhaxz/devilution +cd devilution +cp /path/to/diablo_game_dir/diabloui.dll . +cp /path/to/diablo_game_dir/Storm.dll . +make +``` + +## Install + +```bash +cp devilution.exe /path/to/diablo_game_dir/ +``` + +## Run + +```bash +wine devilution.exe +``` diff --git a/Support/INSTALL_windows.md b/Support/INSTALL_windows.md new file mode 100644 index 000000000..8b4fea962 --- /dev/null +++ b/Support/INSTALL_windows.md @@ -0,0 +1,46 @@ +# Installation + +## Dependencies and Initial Environment Configuration + +* Install [MSYS2](https://www.msys2.org/) + +```bash +# Start the *MSYS2 MinGW 32-bit* terminal. + +# If this is the first time, go ahead and update all of your components, and +# follow and instructions about restarting the terminal and running the update again: +pacman -Syu + +# After everything is updated, let's download all of the components needed +# to build it and set up any dependency symlinks: +pacman -Sy git make mingw-w64-i686-gcc mingw-w64-i686-binutils + +ln -s /mingw32/i686-w64-mingw32/bin/dlltool.exe /usr/bin/i686-w64-mingw32-dlltool.exe +ln -s /mingw32/i686-w64-mingw32/bin/as.exe /usr/bin/i686-w64-mingw32-as.exe +ln -s /mingw32/bin/windres.exe /usr/bin/i686-w64-mingw32-windres.exe +``` + +## Building + +```bash +git clone https://github.com/galaxyhaxz/devilution +cd devilution +cp /path/to/diablo_game_dir/diabloui.dll . +cp /path/to/diablo_game_dir/storm.dll . + +# If you only have a single core machine or if building in parallel +# causes issues, simply run the following command: +make + +# If you want to compile faster, then use the following command (Substitute # for +# your number of processors + 1. So if you have an 8 core processor, use 9: +make -j# +``` + +## Install + +```bash +# The Devilution executable will be placed in the root of your Devilution repository. +# Simply copy this over to your Diablo installation folder: +cp devilution.exe /path/to/diablo_game_dir/ +``` \ No newline at end of file diff --git a/Support/TODO.md b/Support/TODO.md new file mode 100644 index 000000000..bcc6c210d --- /dev/null +++ b/Support/TODO.md @@ -0,0 +1,21 @@ +### Comments +- `BUGFIX` known bugs in original (vanilla) code +- `/* */` block comments are things to be fixed/checked +- `FIX_ME` bad data + +### Known Bugs +Serious bugs (crash/fault) +- TBA + +Minor bugs (noticeable but can be avoided) +- Server commands are broken and have been disabled `msgcmd.cpp` + +Code issues (incorrect code that still works) +- Critical sections should be constructors using `CCritSect` +- Some code uses macros such as `__PAIR__` or `__ROL4__` +- Some functions/structures have incorrect signing (signed/unsigned BYTE) +- Function `GetLevelMTypes`, decompile and check `monster.cpp` +- Function `SetAutomapView`, decompile and check `automap.cpp` +- Function `engine_draw_automap_pixels`, decompile and check `engine.cpp` +- Double check `UseMana` references +- Double check `LOBYTE` of function `random(int, int)` diff --git a/Support/compatibility_matrix.md b/Support/compatibility_matrix.md new file mode 100755 index 000000000..de415c065 --- /dev/null +++ b/Support/compatibility_matrix.md @@ -0,0 +1,39 @@ +# Compatibility Matrix, Compilations, Platform Statuses, Etc + +Please use UTC times for all entries. The Z ending represents UTC time. + +## Status Cheat Sheet + +[Modeled after Wine HQ's Rating System](https://wiki.winehq.org/AppDB_Rating_Definitions) + +| Rank | Description | +| --- | --- | +| Platinum | Works perfectly right after compilation either better or equal to Native Diablo Executable. | +| Gold | Works right after compilation with no crashes during gameplay but workarounds needed. | +| Silver | Works right after compilation with no crashes during gameplay but issues exist where no workarounds exist. | +| Bronze | Mostly works but there are still some problems remaining that prevent a full playthrough.| +| Trash | Game has severe problems and cannot be played. | + +## Windows + +| Date | Status | OS | Bitness | Version (OS) | Build (OS) | Compiler | Build Platform | User | Workaround | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 2018-06-24 @ 17:05 Z| Gold | 10 | x64 | 1803 | 17134.112 | i686-w64-mingw32-gcc-7.3.0 | MSYS 2 i686 | fearedbliss | Needed to use ddraw patch. | +| 2018-06-24 @ 12:52 Z| Platinum | 7 | x64 | 6.1 | 7601 | Visual C++ 6.0 | VC++ | Sergi4UA | None | +| 2018-06-24 @ 01:00 Z| Platinum | 7 | x64 | 6.1 | 7601 | Visual C++ 5.10 | VC++ | galaxyhaxz | None | +| 2018-06-24 @ 18:00 Z| Gold | 10 | x64 | 1803 | 17134.112 | Visual Studio 2017 (Community) | VC++ | MadHed | Disable DEP in linker options | +| 2018-06-24 @ 16:00 Z| Gold | 7 | x64 | 6.1 | 7601 | Visual Studio 2017 (Community) | VC++ | StephenCWills | Disable DEP in linker options | +| 2018-06-26 @ 19:30 Z| Platinum | 7 | x64 | 6.1 | 7601 | i686-w64-mingw32-g++ (GCC) 6.4.0 | Cygwin | StephenCWills | None | +| 2018-07-05 @ 23:54 Z| Gold | 10 | x64 | 1803 | 17134.112 | Visual Studio 2017 (Community) | VC++ | fearedbliss | Disable DEP in linker options | + +## Linux + +| Date | Status | OS | Bitness | Version (OS) | Build (OS) | Compiler | Build Platform | User | Workaround | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 2018-08-20 @ 12:05 Z| Gold | Ubuntu (WSL) | x64 | xenial | 16.04.4 LTS | i686-w64-mingw32-g++ (GCC) 5.3.1 20160211 | Mingw64-x86 | ChaosMarc | Needed to use ddraw patch. | +| 2018-08-20 @ 12:05 Z| Trash | Ubuntu (WSL) | x64 | bionic | 18.04 LTS | i686-w64-mingw32-g++ (GCC) 7.3-win32 20180312 | Mingw64-x86 | ChaosMarc | Crashes on startup (#107) | + +## Mac OS X + +| Date | Status | OS | Bitness | Version (OS) | Build (OS) | Compiler | Build Platform | User | Workaround | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | diff --git a/Support/debug.md b/Support/debug.md new file mode 100644 index 000000000..7adb07656 --- /dev/null +++ b/Support/debug.md @@ -0,0 +1,54 @@ +There are debug features available through both in-game and through the command-line. These have been ported from the 12-21-96 debug build. Note that not all of them are available yet. + +Command-line parameters +- `-^` : enable god mode and debug tools +- `-$` : enable god mode with less stuff (further documenting needed) [NOT YET IMPLEMENTED] +- `-b` : enables item drop log [NOT YET IMPLEMENTED] +- `-d` : disable startup video + increased item drops [PARTIALLY IMPLEMENTED] +- `-f` : display frames per second +- `-i` : disable network timeout +- `-n` : disable startup video +- `-s` : unused +- `-v` : draw yellow debug tiles +- `-w` : enable cheats +- `-x` : disable exclusive DirectDraw access [NOT YET IMPLEMENTED] +- `-j <##>` : init trigger at level [NOT YET IMPLEMENTED] +- `-l <#> <##>` : start in level as type +- `-m <###>` : add debug monster, up to 10 allowed +- `-q <#>` : force a certain quest +- `-r <##########>` : set map seed to +- `-t <##>` : sets current quest level + +In-game hotkeys +- `?` -> enter quest text mode [NOT YET IMPLEMENTED] + - `-`/`_` -> decrease message number/speed + - `+`/`=` -> increase message number/speed + - `Enter` -> play selected message + - `Esc` -> stop quest text mode +- `Shift` -> while holding, use the mouse to scroll screen +- `F2` -> display dungeon information [NOT YET IMPLEMENTED] +- `F3` -> display number of items on the ground/cursor item +- `F4` -> display quest status information +- `0`/`)` -> cycle between regular/magic arrows +- `8`/`*` -> level up character +- `~` -> refresh vendor items (Griswold premium and Adria) +- `]` -> all spells level 10 +- `:` -> all spells preset level +- `[` -> delete all gold in inventory +- `|` -> fill inventory with gold (5000 piece piles) +- `.` -> display dungeon Y/sum [NOT YET IMPLEMENTED] +- `a` -> increase level of the last spell casted and enable `Teleport` in town +- `A` -> display "Mid" monster related +- `d` -> print debug player info +- `D` -> switch current debug player +- `e` -> display "EFlag" +- `l`/`L` -> toggle lighting in dungeon +- `m` -> print debug monster info +- `M` -> switch current debug monster +- `r`/`R` -> display game seeds +- `t`/`T` -> display player and cursor coordinates + +Multiplayer hotkeys [NOT YET IMPLEMENTED] +- `Ctrl`+`C` -> trigger breakpoint +- `Ctrl`+`P` -> print mouse clicks and frame counter for each player +- `Ctrl`+`S` -> sleep the network thread diff --git a/Support/troubleshooting.md b/Support/troubleshooting.md new file mode 100644 index 000000000..3231ec527 --- /dev/null +++ b/Support/troubleshooting.md @@ -0,0 +1,23 @@ +# Troubleshooting + +While Devilution should produce a binary close to the original (compatible with Windows 95/NT), it may cause issues on newer systems. It has been reported to frequently crash on some setups, although for many it appears to be running flawless otherwise. Windows 7, Linux-WINE, and Windows 10 have all reported success. + +Note that newer compilers may need to be tweaked to properly produce an executable. Currently this is being worked on to provide multiple Makefiles for a variety of systems. To ensure the best results, either MinGW or Visual Studio 2003/older should be used for the time being. + +## Compilations with Different Toolchains +Compiling with different compilers (Visual C++, MinGW, Etc) will lead lead to different +results with how the executable interacts with the operating system, and may lead to either +weird crashes or different types of problems either during startup or runtime. + +For example, for fearedbliss, on his Windows 10 x64 machine where he compiled Devilution +with MSYS2/MinGW32, he was getting the following messages: + +![Screenshot 1: Windows 2000 Advisory](https://i.imgur.com/ScFLGu5.png) + +![Screenshot 2: DirectDraw Error ](https://i.imgur.com/kiWkBuk.png) + +For the first issue, it is annoying but doesn't seem to stop you from playing the game. + +The second issue simply requires you to use the DirectDraw patch (ddraw.dll). Once the +dll is placed in your Diablo directory, and all of it's dependencies are installed +(DirectX 9 Runtime, and VC++ 2010 x86 Redistributable), it will work. \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..2ba66073d --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,9 @@ +version: 1.0.{build} +pull_requests: + do_not_increment_build_number: true +image: Visual Studio 2017 +configuration: Release +platform: x86 +build: + project: Diablo.sln + verbosity: minimal diff --git a/defs.h b/defs.h new file mode 100644 index 000000000..8671cd043 --- /dev/null +++ b/defs.h @@ -0,0 +1,237 @@ +// some global definitions, found in debug release + +#define DMAXX 40 +#define DMAXY 40 + +#define LIGHTSIZE 6912 // 27 * 256 + +// must be unsigned to generate unsigned comparisons with pnum +#define MAX_PLRS 4 + +#define MAX_CHARACTERS 10 +#define MAX_LVLMTYPES 16 +// #define MAX_PATH 260 +#define MAX_SEND_STR_LEN 80 + +#define MAXDEAD 31 +#define MAXDUNX 112 +#define MAXDUNY 112 +#define MAXITEMS 127 +#define MAXMISSILES 125 +#define MAXMONSTERS 200 +#define MAXMULTIQUESTS 4 +#define MAXOBJECTS 127 +#define MAXPORTAL 4 +#define MAXQUESTS 16 +#define MAXTHEMES 50 +#define MAXTILES 2048 +#define MAXTRIGGERS 5 +#define MDMAXX 40 +#define MDMAXY 40 + + +// number of inventory grid cells +#define NUM_INV_GRID_ELEM 40 +#define INV_SLOT_SIZE_PX 28 + +// todo: enums +#define NUM_SFX 858 +#define NUMLEVELS 17 + +// from diablo 2 beta +#define MAXEXP 2000000000 + +#define PLR_NAME_LEN 32 + +// Diablo uses a 256 color palette +// Entry 0-127 (0x00-0x7F) are level specific +// Entry 128-255 (0x80-0xFF) are global + +// standard palette for all levels +// 8 or 16 shades per color +// example (dark blue): PAL16_BLUE+14, PAL8_BLUE+7 +// example (light red): PAL16_RED+2, PAL8_RED +// example (orange): PAL16_ORANGE+8, PAL8_ORANGE+4 +#define PAL8_BLUE 128 +#define PAL8_RED 136 +#define PAL8_YELLOW 144 +#define PAL8_ORANGE 152 +#define PAL16_BEIGE 160 +#define PAL16_BLUE 176 +#define PAL16_YELLOW 192 +#define PAL16_ORANGE 208 +#define PAL16_RED 224 +#define PAL16_GRAY 240 + + + + + +///////////////////////////////////////////////////////////////////////// +/* temporary stuff from the decompiler */ +/* remove all the garbage below in the future */ +///////////////////////////////////////////////////////////////////////// +#ifndef IDA_GARBAGE +#define IDA_GARBAGE + +inline void memset32(void *s, unsigned int c, size_t n) +{ + unsigned int *p = (unsigned int *)s; + for (int i = 0; i < n; i++) { + p[i] = c; + } +} + +typedef __int64 ll; +typedef unsigned __int64 ull; + +typedef unsigned int uint; +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; + +typedef char int8; +typedef signed char sint8; +typedef unsigned char uint8; +typedef short int16; +typedef signed short sint16; +typedef unsigned short uint16; +typedef int int32; +typedef signed int sint32; +typedef unsigned int uint32; +typedef ll int64; +typedef ll sint64; +typedef ull uint64; + +// Partially defined types. They are used when the decompiler does not know +// anything about the type except its size. +#define _BYTE uint8 +#define _WORD uint16 +#define _DWORD uint32 +#define _QWORD uint64 + +// Some convenience macros to make partial accesses nicer +#define LAST_IND(x,part_type) (sizeof(x)/sizeof(part_type) - 1) +#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN +# define LOW_IND(x,part_type) LAST_IND(x,part_type) +# define HIGH_IND(x,part_type) 0 +#else +# define HIGH_IND(x,part_type) LAST_IND(x,part_type) +# define LOW_IND(x,part_type) 0 +#endif +// first unsigned macros: +#define BYTEn(x, n) (*((_BYTE*)&(x)+n)) +#define WORDn(x, n) (*((_WORD*)&(x)+n)) +#define DWORDn(x, n) (*((_DWORD*)&(x)+n)) + +#define _LOBYTE(x) BYTEn(x,LOW_IND(x,_BYTE)) +#define _LOWORD(x) WORDn(x,LOW_IND(x,_WORD)) +#define LODWORD(x) DWORDn(x,LOW_IND(x,_DWORD)) +#define _HIBYTE(x) BYTEn(x,HIGH_IND(x,_BYTE)) +#define _HIWORD(x) WORDn(x,HIGH_IND(x,_WORD)) +#define HIDWORD(x) DWORDn(x,HIGH_IND(x,_DWORD)) +#define BYTE1(x) BYTEn(x, 1) // byte 1 (counting from 0) +#define BYTE2(x) BYTEn(x, 2) + + +// now signed macros (the same but with sign extension) +#define SBYTEn(x, n) (*((int8*)&(x)+n)) +#define SWORDn(x, n) (*((int16*)&(x)+n)) + +#define SLOBYTE(x) SBYTEn(x,LOW_IND(x,int8)) +#define SHIWORD(x) SWORDn(x,HIGH_IND(x,int16)) + + + +// Helper functions to represent some assembly instructions. + +#ifdef __cplusplus + +#ifdef FAST_MEMCPY +#define qmemcpy memcpy +#else +inline void *qmemcpy(void *dst, const void *src, size_t cnt) +{ + char *out = (char *)dst; + const char *in = (const char *)src; + while ( cnt > 0 ) + { + *out++ = *in++; + --cnt; + } + return dst; +} +#endif + +// Generate a reference to pair of operands +template int16 __PAIR__( int8 high, T low) { return ((( int16)high) << sizeof(high)*8) | uint8(low); } +template int32 __PAIR__( int16 high, T low) { return ((( int32)high) << sizeof(high)*8) | uint16(low); } +template int64 __PAIR__( int32 high, T low) { return ((( int64)high) << sizeof(high)*8) | uint32(low); } +template uint16 __PAIR__(uint8 high, T low) { return (((uint16)high) << sizeof(high)*8) | uint8(low); } +template uint32 __PAIR__(uint16 high, T low) { return (((uint32)high) << sizeof(high)*8) | uint16(low); } +template uint64 __PAIR__(uint32 high, T low) { return (((uint64)high) << sizeof(high)*8) | uint32(low); } + +// rotate left +template T __ROL__(T value, int count) +{ + const uint nbits = sizeof(T) * 8; + + if ( count > 0 ) + { + count %= nbits; + T high = value >> (nbits - count); + if ( T(-1) < 0 ) // signed value + high &= ~((T(-1) << count)); + value <<= count; + value |= high; + } + else + { + count = -count % nbits; + T low = value << (nbits - count); + value >>= count; + value |= low; + } + return value; +} + +inline uint16 __ROR2__(uint16 value, int count) { return __ROL__((uint16)value, -count); } +inline uint32 __ROR4__(uint32 value, int count) { return __ROL__((uint32)value, -count); } + +// sign flag +template int8 __SETS__(T x) +{ + if ( sizeof(T) == 1 ) + return int8(x) < 0; + if ( sizeof(T) == 2 ) + return int16(x) < 0; + if ( sizeof(T) == 4 ) + return int32(x) < 0; + return int64(x) < 0; +} + +// overflow flag of subtraction (x-y) +template int8 __OFSUB__(T x, U y) +{ + if ( sizeof(T) < sizeof(U) ) + { + U x2 = x; + int8 sx = __SETS__(x2); + return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2-y)); + } + else + { + T y2 = y; + int8 sx = __SETS__(x); + return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x-y2)); + } +} + +#endif + +#endif /* IDA_GARBAGE */ + +#ifndef INFINITY +#include +#define INFINITY std::numeric_limits::infinity() +#endif diff --git a/enums.h b/enums.h new file mode 100644 index 000000000..4178f28b8 --- /dev/null +++ b/enums.h @@ -0,0 +1,2572 @@ +enum unique_base_item +{ + UITYPE_NONE = 0x0, + UITYPE_SHORTBOW = 0x1, + UITYPE_LONGBOW = 0x2, + UITYPE_HUNTBOW = 0x3, + UITYPE_COMPBOW = 0x4, + UITYPE_WARBOW = 0x5, + UITYPE_BATTLEBOW = 0x6, + UITYPE_DAGGER = 0x7, + UITYPE_FALCHION = 0x8, + UITYPE_CLAYMORE = 0x9, + UITYPE_BROADSWR = 0xA, + UITYPE_SABRE = 0xB, + UITYPE_SCIMITAR = 0xC, + UITYPE_LONGSWR = 0xD, + UITYPE_BASTARDSWR = 0xE, + UITYPE_TWOHANDSWR = 0xF, + UITYPE_GREATSWR = 0x10, + UITYPE_CLEAVER = 0x11, + UITYPE_LARGEAXE = 0x12, + UITYPE_BROADAXE = 0x13, + UITYPE_SMALLAXE = 0x14, + UITYPE_BATTLEAXE = 0x15, + UITYPE_GREATAXE = 0x16, + UITYPE_MACE = 0x17, + UITYPE_MORNSTAR = 0x18, + UITYPE_SPIKCLUB = 0x19, + UITYPE_MAUL = 0x1A, + UITYPE_WARHAMMER = 0x1B, + UITYPE_FLAIL = 0x1C, + UITYPE_LONGSTAFF = 0x1D, + UITYPE_SHORTSTAFF = 0x1E, + UITYPE_COMPSTAFF = 0x1F, + UITYPE_QUARSTAFF = 0x20, + UITYPE_WARSTAFF = 0x21, + UITYPE_SKULLCAP = 0x22, + UITYPE_HELM = 0x23, + UITYPE_GREATHELM = 0x24, + UITYPE_CROWN = 0x25, + UITYPE_38 = 0x26, + UITYPE_RAGS = 0x27, + UITYPE_STUDARMOR = 0x28, + UITYPE_CLOAK = 0x29, + UITYPE_ROBE = 0x2A, + UITYPE_CHAINMAIL = 0x2B, + UITYPE_LEATHARMOR = 0x2C, + UITYPE_BREASTPLATE = 0x2D, + UITYPE_CAPE = 0x2E, + UITYPE_PLATEMAIL = 0x2F, + UITYPE_FULLPLATE = 0x30, + UITYPE_BUCKLER = 0x31, + UITYPE_SMALLSHIELD = 0x32, + UITYPE_LARGESHIELD = 0x33, + UITYPE_KITESHIELD = 0x34, + UITYPE_GOTHSHIELD = 0x35, + UITYPE_RING = 0x36, + UITYPE_55 = 0x37, + UITYPE_AMULET = 0x38, + UITYPE_SKCROWN = 0x39, + UITYPE_INFRARING = 0x3A, + UITYPE_OPTAMULET = 0x3B, + UITYPE_TRING = 0x3C, + UITYPE_HARCREST = 0x3D, + UITYPE_MAPOFDOOM = 0x3E, + UITYPE_ELIXIR = 0x3F, + UITYPE_ARMOFVAL = 0x40, + UITYPE_STEELVEIL = 0x41, + UITYPE_GRISWOLD = 0x42, + UITYPE_LGTFORGE = 0x43, + UITYPE_LAZSTAFF = 0x44, + UITYPE_INVALID = -1, +}; + +enum item_effect_type +{ + IPL_TOHIT = 0x0, + IPL_TOHIT_CURSE = 0x1, + IPL_DAMP = 0x2, + IPL_DAMP_CURSE = 0x3, + IPL_TOHIT_DAMP = 0x4, + IPL_TOHIT_DAMP_CURSE = 0x5, + IPL_ACP = 0x6, + IPL_ACP_CURSE = 0x7, + IPL_FIRERES = 0x8, + IPL_LIGHTRES = 0x9, + IPL_MAGICRES = 0xA, + IPL_ALLRES = 0xB, + IPL_SPLLVLADD = 0xE, + IPL_CHARGES = 0xF, + IPL_FIREDAM = 0x10, + IPL_LIGHTDAM = 0x11, + IPL_STR = 0x13, + IPL_STR_CURSE = 0x14, + IPL_MAG = 0x15, + IPL_MAG_CURSE = 0x16, + IPL_DEX = 0x17, + IPL_DEX_CURSE = 0x18, + IPL_VIT = 0x19, + IPL_VIT_CURSE = 0x1A, + IPL_ATTRIBS = 0x1B, + IPL_ATTRIBS_CURSE = 0x1C, + IPL_GETHIT_CURSE = 0x1D, + IPL_GETHIT = 0x1E, + IPL_LIFE = 0x1F, + IPL_LIFE_CURSE = 0x20, + IPL_MANA = 0x21, + IPL_MANA_CURSE = 0x22, + IPL_DUR = 0x23, + IPL_DUR_CURSE = 0x24, + IPL_INDESTRUCTIBLE = 0x25, + IPL_LIGHT = 0x26, + IPL_LIGHT_CURSE = 0x27, + IPL_MULT_ARROWS = 0x29, /* only used in hellfire */ + IPL_FIRE_ARROWS = 0x2A, + IPL_LIGHT_ARROWS = 0x2B, + IPL_INVCURS = 0x2C, + IPL_THORNS = 0x2D, + IPL_NOMANA = 0x2E, + IPL_NOHEALPLR = 0x2F, + IPL_ABSHALFTRAP = 0x34, + IPL_KNOCKBACK = 0x35, + IPL_NOHEALMON = 0x36, + IPL_STEALMANA = 0x37, + IPL_STEALLIFE = 0x38, + IPL_TARGAC = 0x39, + IPL_FASTATTACK = 0x3A, + IPL_FASTRECOVER = 0x3B, + IPL_FASTBLOCK = 0x3C, + IPL_DAMMOD = 0x3D, + IPL_RNDARROWVEL = 0x3E, + IPL_SETDAM = 0x3F, + IPL_SETDUR = 0x40, + IPL_NOMINSTR = 0x41, + IPL_SPELL = 0x42, + IPL_FASTSWING = 0x43, + IPL_ONEHAND = 0x44, + IPL_3XDAMVDEM = 0x45, + IPL_ALLRESZERO = 0x46, + IPL_DRAINLIFE = 0x48, + IPL_RNDSTEALLIFE = 0x49, + IPL_INFRAVISION = 0x4A, + IPL_SETAC = 0x4B, + IPL_ADDACLIFE = 0x4C, + IPL_ADDMANAAC = 0x4D, + IPL_FIRERESCLVL = 0x4E, + IPL_AC_CURSE = 0x4F, + IPL_INVALID = -1, +}; + +enum affix_item_type +{ + PLT_MISC = 0x1, + PLT_BOW = 0x10, + PLT_STAFF = 0x100, + PLT_WEAP = 0x1000, + PLT_SHLD = 0x10000, + PLT_ARMO = 0x100000, +}; + +enum _sfx_id +{ + PS_WALK1 = 0x0, + PS_WALK2 = 0x1, + PS_WALK3 = 0x2, + PS_WALK4 = 0x3, + PS_BFIRE = 0x4, + PS_FMAG = 0x5, + PS_TMAG = 0x6, + PS_LGHIT = 0x7, + PS_LGHIT1 = 0x8, + PS_SWING = 0x9, + PS_SWING2 = 0xA, + PS_DEAD = 0xB, + IS_QUESTDN = 0xC, + IS_ARMRFKD = 0xD, + IS_BARLFIRE = 0xE, + IS_BARREL = 0xF, + IS_BHIT = 0x10, + IS_BHIT1 = 0x11, + IS_CHEST = 0x12, + IS_DOORCLOS = 0x13, + IS_DOOROPEN = 0x14, + IS_FANVL = 0x15, + IS_FAXE = 0x16, + IS_FBLST = 0x17, + IS_FBODY = 0x18, + IS_FBOOK = 0x19, + IS_FBOW = 0x1A, + IS_FCAP = 0x1B, + IS_FHARM = 0x1C, + IS_FLARM = 0x1D, + IS_FMAG = 0x1E, + IS_FMAG1 = 0x1F, + IS_FMUSH = 0x20, + IS_FPOT = 0x21, + IS_FRING = 0x22, + IS_FROCK = 0x23, + IS_FSCRL = 0x24, + IS_FSHLD = 0x25, + IS_FSIGN = 0x26, + IS_FSTAF = 0x27, + IS_FSWOR = 0x28, + IS_GOLD = 0x29, + IS_HLMTFKD = 0x2A, + IS_IANVL = 0x2B, + IS_IAXE = 0x2C, + IS_IBLST = 0x2D, + IS_IBODY = 0x2E, + IS_IBOOK = 0x2F, + IS_IBOW = 0x30, + IS_ICAP = 0x31, + IS_IGRAB = 0x32, + IS_IHARM = 0x33, + IS_ILARM = 0x34, + IS_IMUSH = 0x35, + IS_IPOT = 0x36, + IS_IRING = 0x37, + IS_IROCK = 0x38, + IS_ISCROL = 0x39, + IS_ISHIEL = 0x3A, + IS_ISIGN = 0x3B, + IS_ISTAF = 0x3C, + IS_ISWORD = 0x3D, + IS_LEVER = 0x3E, + IS_MAGIC = 0x3F, + IS_MAGIC1 = 0x40, + IS_RBOOK = 0x41, + IS_SARC = 0x42, + IS_SHLDFKD = 0x43, + IS_SWRDFKD = 0x44, + IS_TITLEMOV = 0x45, + IS_TITLSLCT = 0x46, + SFX_SILENCE = 0x47, + IS_TRAP = 0x48, + IS_CAST1 = 0x49, + IS_CAST10 = 0x4A, + IS_CAST12 = 0x4B, + IS_CAST2 = 0x4C, + IS_CAST3 = 0x4D, + IS_CAST4 = 0x4E, + IS_CAST5 = 0x4F, + IS_CAST6 = 0x50, + IS_CAST7 = 0x51, + IS_CAST8 = 0x52, + IS_CAST9 = 0x53, + LS_HEALING = 0x54, + IS_REPAIR = 0x55, + LS_ACID = 0x56, + LS_ACIDS = 0x57, + LS_APOC = 0x58, + LS_ARROWALL = 0x59, + LS_BLODBOIL = 0x5A, + LS_BLODSTAR = 0x5B, + LS_BLSIMPT = 0x5C, + LS_BONESP = 0x5D, + LS_BSIMPCT = 0x5E, + LS_CALDRON = 0x5F, + LS_CBOLT = 0x60, + LS_CHLTNING = 0x61, + LS_DSERP = 0x62, + LS_ELECIMP1 = 0x63, + LS_ELEMENTL = 0x64, + LS_ETHEREAL = 0x65, + LS_FBALL = 0x66, + LS_FBOLT1 = 0x67, + LS_FBOLT2 = 0x68, + LS_FIRIMP1 = 0x69, + LS_FIRIMP2 = 0x6A, + LS_FLAMWAVE = 0x6B, + LS_FLASH = 0x6C, + LS_FOUNTAIN = 0x6D, + LS_GOLUM = 0x6E, + LS_GOLUMDED = 0x6F, + LS_GSHRINE = 0x70, + LS_GUARD = 0x71, + LS_GUARDLAN = 0x72, + LS_HOLYBOLT = 0x73, + LS_HYPER = 0x74, + LS_INFRAVIS = 0x75, + LS_INVISIBL = 0x76, + LS_INVPOT = 0x77, + LS_LNING1 = 0x78, + LS_LTNING = 0x79, + LS_MSHIELD = 0x7A, + LS_NOVA = 0x7B, + LS_PORTAL = 0x7C, + LS_PUDDLE = 0x7D, + LS_RESUR = 0x7E, + LS_SCURSE = 0x7F, + LS_SCURIMP = 0x80, + LS_SENTINEL = 0x81, + LS_SHATTER = 0x82, + LS_SOULFIRE = 0x83, + LS_SPOUTLOP = 0x84, + LS_SPOUTSTR = 0x85, + LS_STORM = 0x86, + LS_TRAPDIS = 0x87, + LS_TELEPORT = 0x88, + LS_VTHEFT = 0x89, + LS_WALLLOOP = 0x8A, + LS_WALLSTRT = 0x8B, + TSFX_BMAID1 = 0x8C, + TSFX_BMAID2 = 0x8D, + TSFX_BMAID3 = 0x8E, + TSFX_BMAID4 = 0x8F, + TSFX_BMAID5 = 0x90, + TSFX_BMAID6 = 0x91, + TSFX_BMAID7 = 0x92, + TSFX_BMAID8 = 0x93, + TSFX_BMAID9 = 0x94, + TSFX_BMAID10 = 0x95, + TSFX_BMAID11 = 0x96, + TSFX_BMAID12 = 0x97, + TSFX_BMAID13 = 0x98, + TSFX_BMAID14 = 0x99, + TSFX_BMAID15 = 0x9A, + TSFX_BMAID16 = 0x9B, + TSFX_BMAID17 = 0x9C, + TSFX_BMAID18 = 0x9D, + TSFX_BMAID19 = 0x9E, + TSFX_BMAID20 = 0x9F, + TSFX_BMAID21 = 0xA0, + TSFX_BMAID22 = 0xA1, + TSFX_BMAID23 = 0xA2, + TSFX_BMAID24 = 0xA3, + TSFX_BMAID25 = 0xA4, + TSFX_BMAID26 = 0xA5, + TSFX_BMAID27 = 0xA6, + TSFX_BMAID28 = 0xA7, + TSFX_BMAID29 = 0xA8, + TSFX_BMAID30 = 0xA9, + TSFX_BMAID31 = 0xAA, + TSFX_BMAID32 = 0xAB, + TSFX_BMAID33 = 0xAC, + TSFX_BMAID34 = 0xAD, + TSFX_BMAID35 = 0xAE, + TSFX_BMAID36 = 0xAF, + TSFX_BMAID37 = 0xB0, + TSFX_BMAID38 = 0xB1, + TSFX_BMAID39 = 0xB2, + TSFX_BMAID40 = 0xB3, + TSFX_SMITH1 = 0xB4, + TSFX_SMITH2 = 0xB5, + TSFX_SMITH3 = 0xB6, + TSFX_SMITH4 = 0xB7, + TSFX_SMITH5 = 0xB8, + TSFX_SMITH6 = 0xB9, + TSFX_SMITH7 = 0xBA, + TSFX_SMITH8 = 0xBB, + TSFX_SMITH9 = 0xBC, + TSFX_SMITH10 = 0xBD, + TSFX_SMITH11 = 0xBE, + TSFX_SMITH12 = 0xBF, + TSFX_SMITH13 = 0xC0, + TSFX_SMITH14 = 0xC1, + TSFX_SMITH15 = 0xC2, + TSFX_SMITH16 = 0xC3, + TSFX_SMITH17 = 0xC4, + TSFX_SMITH18 = 0xC5, + TSFX_SMITH19 = 0xC6, + TSFX_SMITH20 = 0xC7, + TSFX_SMITH21 = 0xC8, + TSFX_SMITH22 = 0xC9, + TSFX_SMITH23 = 0xCA, + TSFX_SMITH24 = 0xCB, + TSFX_SMITH25 = 0xCC, + TSFX_SMITH26 = 0xCD, + TSFX_SMITH27 = 0xCE, + TSFX_SMITH28 = 0xCF, + TSFX_SMITH29 = 0xD0, + TSFX_SMITH30 = 0xD1, + TSFX_SMITH31 = 0xD2, + TSFX_SMITH32 = 0xD3, + TSFX_SMITH33 = 0xD4, + TSFX_SMITH34 = 0xD5, + TSFX_SMITH35 = 0xD6, + TSFX_SMITH36 = 0xD7, + TSFX_SMITH37 = 0xD8, + TSFX_SMITH38 = 0xD9, + TSFX_SMITH39 = 0xDA, + TSFX_SMITH40 = 0xDB, + TSFX_SMITH41 = 0xDC, + TSFX_SMITH42 = 0xDD, + TSFX_SMITH43 = 0xDE, + TSFX_SMITH44 = 0xDF, + TSFX_SMITH45 = 0xE0, + TSFX_SMITH46 = 0xE1, + TSFX_SMITH47 = 0xE2, + TSFX_SMITH48 = 0xE3, + TSFX_SMITH49 = 0xE4, + TSFX_SMITH50 = 0xE5, + TSFX_SMITH51 = 0xE6, + TSFX_SMITH52 = 0xE7, + TSFX_SMITH53 = 0xE8, + TSFX_SMITH54 = 0xE9, + TSFX_SMITH55 = 0xEA, + TSFX_SMITH56 = 0xEB, + TSFX_COW1 = 0xEC, + TSFX_COW2 = 0xED, + TSFX_DEADGUY = 0xEE, + TSFX_DRUNK1 = 0xEF, + TSFX_DRUNK2 = 0xF0, + TSFX_DRUNK3 = 0xF1, + TSFX_DRUNK4 = 0xF2, + TSFX_DRUNK5 = 0xF3, + TSFX_DRUNK6 = 0xF4, + TSFX_DRUNK7 = 0xF5, + TSFX_DRUNK8 = 0xF6, + TSFX_DRUNK9 = 0xF7, + TSFX_DRUNK10 = 0xF8, + TSFX_DRUNK11 = 0xF9, + TSFX_DRUNK12 = 0xFA, + TSFX_DRUNK13 = 0xFB, + TSFX_DRUNK14 = 0xFC, + TSFX_DRUNK15 = 0xFD, + TSFX_DRUNK16 = 0xFE, + TSFX_DRUNK17 = 0xFF, + TSFX_DRUNK18 = 0x100, + TSFX_DRUNK19 = 0x101, + TSFX_DRUNK20 = 0x102, + TSFX_DRUNK21 = 0x103, + TSFX_DRUNK22 = 0x104, + TSFX_DRUNK23 = 0x105, + TSFX_DRUNK24 = 0x106, + TSFX_DRUNK25 = 0x107, + TSFX_DRUNK26 = 0x108, + TSFX_DRUNK27 = 0x109, + TSFX_DRUNK28 = 0x10A, + TSFX_DRUNK29 = 0x10B, + TSFX_DRUNK30 = 0x10C, + TSFX_DRUNK31 = 0x10D, + TSFX_DRUNK32 = 0x10E, + TSFX_DRUNK33 = 0x10F, + TSFX_DRUNK34 = 0x110, + TSFX_DRUNK35 = 0x111, + TSFX_HEALER1 = 0x112, + TSFX_HEALER2 = 0x113, + TSFX_HEALER3 = 0x114, + TSFX_HEALER4 = 0x115, + TSFX_HEALER5 = 0x116, + TSFX_HEALER6 = 0x117, + TSFX_HEALER7 = 0x118, + TSFX_HEALER8 = 0x119, + TSFX_HEALER9 = 0x11A, + TSFX_HEALER10 = 0x11B, + TSFX_HEALER11 = 0x11C, + TSFX_HEALER12 = 0x11D, + TSFX_HEALER13 = 0x11E, + TSFX_HEALER14 = 0x11F, + TSFX_HEALER15 = 0x120, + TSFX_HEALER16 = 0x121, + TSFX_HEALER17 = 0x122, + TSFX_HEALER18 = 0x123, + TSFX_HEALER19 = 0x124, + TSFX_HEALER20 = 0x125, + TSFX_HEALER21 = 0x126, + TSFX_HEALER22 = 0x127, + TSFX_HEALER23 = 0x128, + TSFX_HEALER24 = 0x129, + TSFX_HEALER25 = 0x12A, + TSFX_HEALER26 = 0x12B, + TSFX_HEALER27 = 0x12C, + TSFX_HEALER28 = 0x12D, + TSFX_HEALER29 = 0x12E, + TSFX_HEALER30 = 0x12F, + TSFX_HEALER31 = 0x130, + TSFX_HEALER32 = 0x131, + TSFX_HEALER33 = 0x132, + TSFX_HEALER34 = 0x133, + TSFX_HEALER35 = 0x134, + TSFX_HEALER36 = 0x135, + TSFX_HEALER37 = 0x136, + TSFX_HEALER38 = 0x137, + TSFX_HEALER39 = 0x138, + TSFX_HEALER40 = 0x139, + TSFX_HEALER41 = 0x13A, + TSFX_HEALER42 = 0x13B, + TSFX_HEALER43 = 0x13C, + TSFX_HEALER44 = 0x13D, + TSFX_HEALER45 = 0x13E, + TSFX_HEALER46 = 0x13F, + TSFX_HEALER47 = 0x140, + TSFX_PEGBOY1 = 0x141, + TSFX_PEGBOY2 = 0x142, + TSFX_PEGBOY3 = 0x143, + TSFX_PEGBOY4 = 0x144, + TSFX_PEGBOY5 = 0x145, + TSFX_PEGBOY6 = 0x146, + TSFX_PEGBOY7 = 0x147, + TSFX_PEGBOY8 = 0x148, + TSFX_PEGBOY9 = 0x149, + TSFX_PEGBOY10 = 0x14A, + TSFX_PEGBOY11 = 0x14B, + TSFX_PEGBOY12 = 0x14C, + TSFX_PEGBOY13 = 0x14D, + TSFX_PEGBOY14 = 0x14E, + TSFX_PEGBOY15 = 0x14F, + TSFX_PEGBOY16 = 0x150, + TSFX_PEGBOY17 = 0x151, + TSFX_PEGBOY18 = 0x152, + TSFX_PEGBOY19 = 0x153, + TSFX_PEGBOY20 = 0x154, + TSFX_PEGBOY21 = 0x155, + TSFX_PEGBOY22 = 0x156, + TSFX_PEGBOY23 = 0x157, + TSFX_PEGBOY24 = 0x158, + TSFX_PEGBOY25 = 0x159, + TSFX_PEGBOY26 = 0x15A, + TSFX_PEGBOY27 = 0x15B, + TSFX_PEGBOY28 = 0x15C, + TSFX_PEGBOY29 = 0x15D, + TSFX_PEGBOY30 = 0x15E, + TSFX_PEGBOY31 = 0x15F, + TSFX_PEGBOY32 = 0x160, + TSFX_PEGBOY33 = 0x161, + TSFX_PEGBOY34 = 0x162, + TSFX_PEGBOY35 = 0x163, + TSFX_PEGBOY36 = 0x164, + TSFX_PEGBOY37 = 0x165, + TSFX_PEGBOY38 = 0x166, + TSFX_PEGBOY39 = 0x167, + TSFX_PEGBOY40 = 0x168, + TSFX_PEGBOY41 = 0x169, + TSFX_PEGBOY42 = 0x16A, + TSFX_PEGBOY43 = 0x16B, + TSFX_PRIEST0 = 0x16C, + TSFX_PRIEST1 = 0x16D, + TSFX_PRIEST2 = 0x16E, + TSFX_PRIEST3 = 0x16F, + TSFX_PRIEST4 = 0x170, + TSFX_PRIEST5 = 0x171, + TSFX_PRIEST6 = 0x172, + TSFX_PRIEST7 = 0x173, + TSFX_STORY0 = 0x174, + TSFX_STORY1 = 0x175, + TSFX_STORY2 = 0x176, + TSFX_STORY3 = 0x177, + TSFX_STORY4 = 0x178, + TSFX_STORY5 = 0x179, + TSFX_STORY6 = 0x17A, + TSFX_STORY7 = 0x17B, + TSFX_STORY8 = 0x17C, + TSFX_STORY9 = 0x17D, + TSFX_STORY10 = 0x17E, + TSFX_STORY11 = 0x17F, + TSFX_STORY12 = 0x180, + TSFX_STORY13 = 0x181, + TSFX_STORY14 = 0x182, + TSFX_STORY15 = 0x183, + TSFX_STORY16 = 0x184, + TSFX_STORY17 = 0x185, + TSFX_STORY18 = 0x186, + TSFX_STORY19 = 0x187, + TSFX_STORY20 = 0x188, + TSFX_STORY21 = 0x189, + TSFX_STORY22 = 0x18A, + TSFX_STORY23 = 0x18B, + TSFX_STORY24 = 0x18C, + TSFX_STORY25 = 0x18D, + TSFX_STORY26 = 0x18E, + TSFX_STORY27 = 0x18F, + TSFX_STORY28 = 0x190, + TSFX_STORY29 = 0x191, + TSFX_STORY30 = 0x192, + TSFX_STORY31 = 0x193, + TSFX_STORY32 = 0x194, + TSFX_STORY33 = 0x195, + TSFX_STORY34 = 0x196, + TSFX_STORY35 = 0x197, + TSFX_STORY36 = 0x198, + TSFX_STORY37 = 0x199, + TSFX_STORY38 = 0x19A, + TSFX_TAVERN0 = 0x19B, + TSFX_TAVERN1 = 0x19C, + TSFX_TAVERN2 = 0x19D, + TSFX_TAVERN3 = 0x19E, + TSFX_TAVERN4 = 0x19F, + TSFX_TAVERN5 = 0x1A0, + TSFX_TAVERN6 = 0x1A1, + TSFX_TAVERN7 = 0x1A2, + TSFX_TAVERN8 = 0x1A3, + TSFX_TAVERN9 = 0x1A4, + TSFX_TAVERN10 = 0x1A5, + TSFX_TAVERN11 = 0x1A6, + TSFX_TAVERN12 = 0x1A7, + TSFX_TAVERN13 = 0x1A8, + TSFX_TAVERN14 = 0x1A9, + TSFX_TAVERN15 = 0x1AA, + TSFX_TAVERN16 = 0x1AB, + TSFX_TAVERN17 = 0x1AC, + TSFX_TAVERN18 = 0x1AD, + TSFX_TAVERN19 = 0x1AE, + TSFX_TAVERN20 = 0x1AF, + TSFX_TAVERN21 = 0x1B0, + TSFX_TAVERN22 = 0x1B1, + TSFX_TAVERN23 = 0x1B2, + TSFX_TAVERN24 = 0x1B3, + TSFX_TAVERN25 = 0x1B4, + TSFX_TAVERN26 = 0x1B5, + TSFX_TAVERN27 = 0x1B6, + TSFX_TAVERN28 = 0x1B7, + TSFX_TAVERN29 = 0x1B8, + TSFX_TAVERN30 = 0x1B9, + TSFX_TAVERN31 = 0x1BA, + TSFX_TAVERN32 = 0x1BB, + TSFX_TAVERN33 = 0x1BC, + TSFX_TAVERN34 = 0x1BD, + TSFX_TAVERN35 = 0x1BE, + TSFX_TAVERN36 = 0x1BF, + TSFX_TAVERN37 = 0x1C0, + TSFX_TAVERN38 = 0x1C1, + TSFX_TAVERN39 = 0x1C2, + TSFX_TAVERN40 = 0x1C3, + TSFX_TAVERN41 = 0x1C4, + TSFX_TAVERN42 = 0x1C5, + TSFX_TAVERN43 = 0x1C6, + TSFX_TAVERN44 = 0x1C7, + TSFX_TAVERN45 = 0x1C8, + TSFX_WITCH1 = 0x1C9, + TSFX_WITCH2 = 0x1CA, + TSFX_WITCH3 = 0x1CB, + TSFX_WITCH4 = 0x1CC, + TSFX_WITCH5 = 0x1CD, + TSFX_WITCH6 = 0x1CE, + TSFX_WITCH7 = 0x1CF, + TSFX_WITCH8 = 0x1D0, + TSFX_WITCH9 = 0x1D1, + TSFX_WITCH10 = 0x1D2, + TSFX_WITCH11 = 0x1D3, + TSFX_WITCH12 = 0x1D4, + TSFX_WITCH13 = 0x1D5, + TSFX_WITCH14 = 0x1D6, + TSFX_WITCH15 = 0x1D7, + TSFX_WITCH16 = 0x1D8, + TSFX_WITCH17 = 0x1D9, + TSFX_WITCH18 = 0x1DA, + TSFX_WITCH19 = 0x1DB, + TSFX_WITCH20 = 0x1DC, + TSFX_WITCH21 = 0x1DD, + TSFX_WITCH22 = 0x1DE, + TSFX_WITCH23 = 0x1DF, + TSFX_WITCH24 = 0x1E0, + TSFX_WITCH25 = 0x1E1, + TSFX_WITCH26 = 0x1E2, + TSFX_WITCH27 = 0x1E3, + TSFX_WITCH28 = 0x1E4, + TSFX_WITCH29 = 0x1E5, + TSFX_WITCH30 = 0x1E6, + TSFX_WITCH31 = 0x1E7, + TSFX_WITCH32 = 0x1E8, + TSFX_WITCH33 = 0x1E9, + TSFX_WITCH34 = 0x1EA, + TSFX_WITCH35 = 0x1EB, + TSFX_WITCH36 = 0x1EC, + TSFX_WITCH37 = 0x1ED, + TSFX_WITCH38 = 0x1EE, + TSFX_WITCH39 = 0x1EF, + TSFX_WITCH40 = 0x1F0, + TSFX_WITCH41 = 0x1F1, + TSFX_WITCH42 = 0x1F2, + TSFX_WITCH43 = 0x1F3, + TSFX_WITCH44 = 0x1F4, + TSFX_WITCH45 = 0x1F5, + TSFX_WITCH46 = 0x1F6, + TSFX_WITCH47 = 0x1F7, + TSFX_WITCH48 = 0x1F8, + TSFX_WITCH49 = 0x1F9, + TSFX_WITCH50 = 0x1FA, + TSFX_WOUND = 0x1FB, + PS_MAGE1 = 0x1FC, + PS_MAGE2 = 0x1FD, + PS_MAGE3 = 0x1FE, + PS_MAGE4 = 0x1FF, + PS_MAGE5 = 0x200, + PS_MAGE6 = 0x201, + PS_MAGE7 = 0x202, + PS_MAGE8 = 0x203, + PS_MAGE9 = 0x204, + PS_MAGE10 = 0x205, + PS_MAGE11 = 0x206, + PS_MAGE12 = 0x207, + PS_MAGE13 = 0x208, + PS_MAGE14 = 0x209, + PS_MAGE15 = 0x20A, + PS_MAGE16 = 0x20B, + PS_MAGE17 = 0x20C, + PS_MAGE18 = 0x20D, + PS_MAGE19 = 0x20E, + PS_MAGE20 = 0x20F, + PS_MAGE21 = 0x210, + PS_MAGE22 = 0x211, + PS_MAGE23 = 0x212, + PS_MAGE24 = 0x213, + PS_MAGE25 = 0x214, + PS_MAGE26 = 0x215, + PS_MAGE27 = 0x216, + PS_MAGE28 = 0x217, + PS_MAGE29 = 0x218, + PS_MAGE30 = 0x219, + PS_MAGE31 = 0x21A, + PS_MAGE32 = 0x21B, + PS_MAGE33 = 0x21C, + PS_MAGE34 = 0x21D, + PS_MAGE35 = 0x21E, + PS_MAGE36 = 0x21F, + PS_MAGE37 = 0x220, + PS_MAGE38 = 0x221, + PS_MAGE39 = 0x222, + PS_MAGE40 = 0x223, + PS_MAGE41 = 0x224, + PS_MAGE42 = 0x225, + PS_MAGE43 = 0x226, + PS_MAGE44 = 0x227, + PS_MAGE45 = 0x228, + PS_MAGE46 = 0x229, + PS_MAGE47 = 0x22A, + PS_MAGE48 = 0x22B, + PS_MAGE49 = 0x22C, + PS_MAGE50 = 0x22D, + PS_MAGE51 = 0x22E, + PS_MAGE52 = 0x22F, + PS_MAGE53 = 0x230, + PS_MAGE54 = 0x231, + PS_MAGE55 = 0x232, + PS_MAGE56 = 0x233, + PS_MAGE57 = 0x234, + PS_MAGE58 = 0x235, + PS_MAGE59 = 0x236, + PS_MAGE60 = 0x237, + PS_MAGE61 = 0x238, + PS_MAGE62 = 0x239, + PS_MAGE63 = 0x23A, + PS_MAGE64 = 0x23B, + PS_MAGE65 = 0x23C, + PS_MAGE66 = 0x23D, + PS_MAGE67 = 0x23E, + PS_MAGE68 = 0x23F, + PS_MAGE69 = 0x240, + PS_MAGE69B = 0x241, + PS_MAGE70 = 0x242, + PS_MAGE71 = 0x243, + PS_MAGE72 = 0x244, + PS_MAGE73 = 0x245, + PS_MAGE74 = 0x246, + PS_MAGE75 = 0x247, + PS_MAGE76 = 0x248, + PS_MAGE77 = 0x249, + PS_MAGE78 = 0x24A, + PS_MAGE79 = 0x24B, + PS_MAGE80 = 0x24C, + PS_MAGE81 = 0x24D, + PS_MAGE82 = 0x24E, + PS_MAGE83 = 0x24F, + PS_MAGE84 = 0x250, + PS_MAGE85 = 0x251, + PS_MAGE86 = 0x252, + PS_MAGE87 = 0x253, + PS_MAGE88 = 0x254, + PS_MAGE89 = 0x255, + PS_MAGE90 = 0x256, + PS_MAGE91 = 0x257, + PS_MAGE92 = 0x258, + PS_MAGE93 = 0x259, + PS_MAGE94 = 0x25A, + PS_MAGE95 = 0x25B, + PS_MAGE96 = 0x25C, + PS_MAGE97 = 0x25D, + PS_MAGE98 = 0x25E, + PS_MAGE99 = 0x25F, + PS_MAGE100 = 0x260, + PS_MAGE101 = 0x261, + PS_MAGE102 = 0x262, + PS_ROGUE1 = 0x263, + PS_ROGUE2 = 0x264, + PS_ROGUE3 = 0x265, + PS_ROGUE4 = 0x266, + PS_ROGUE5 = 0x267, + PS_ROGUE6 = 0x268, + PS_ROGUE7 = 0x269, + PS_ROGUE8 = 0x26A, + PS_ROGUE9 = 0x26B, + PS_ROGUE10 = 0x26C, + PS_ROGUE11 = 0x26D, + PS_ROGUE12 = 0x26E, + PS_ROGUE13 = 0x26F, + PS_ROGUE14 = 0x270, + PS_ROGUE15 = 0x271, + PS_ROGUE16 = 0x272, + PS_ROGUE17 = 0x273, + PS_ROGUE18 = 0x274, + PS_ROGUE19 = 0x275, + PS_ROGUE20 = 0x276, + PS_ROGUE21 = 0x277, + PS_ROGUE22 = 0x278, + PS_ROGUE23 = 0x279, + PS_ROGUE24 = 0x27A, + PS_ROGUE25 = 0x27B, + PS_ROGUE26 = 0x27C, + PS_ROGUE27 = 0x27D, + PS_ROGUE28 = 0x27E, + PS_ROGUE29 = 0x27F, + PS_ROGUE30 = 0x280, + PS_ROGUE31 = 0x281, + PS_ROGUE32 = 0x282, + PS_ROGUE33 = 0x283, + PS_ROGUE34 = 0x284, + PS_ROGUE35 = 0x285, + PS_ROGUE36 = 0x286, + PS_ROGUE37 = 0x287, + PS_ROGUE38 = 0x288, + PS_ROGUE39 = 0x289, + PS_ROGUE40 = 0x28A, + PS_ROGUE41 = 0x28B, + PS_ROGUE42 = 0x28C, + PS_ROGUE43 = 0x28D, + PS_ROGUE44 = 0x28E, + PS_ROGUE45 = 0x28F, + PS_ROGUE46 = 0x290, + PS_ROGUE47 = 0x291, + PS_ROGUE48 = 0x292, + PS_ROGUE49 = 0x293, + PS_ROGUE50 = 0x294, + PS_ROGUE51 = 0x295, + PS_ROGUE52 = 0x296, + PS_ROGUE53 = 0x297, + PS_ROGUE54 = 0x298, + PS_ROGUE55 = 0x299, + PS_ROGUE56 = 0x29A, + PS_ROGUE57 = 0x29B, + PS_ROGUE58 = 0x29C, + PS_ROGUE59 = 0x29D, + PS_ROGUE60 = 0x29E, + PS_ROGUE61 = 0x29F, + PS_ROGUE62 = 0x2A0, + PS_ROGUE63 = 0x2A1, + PS_ROGUE64 = 0x2A2, + PS_ROGUE65 = 0x2A3, + PS_ROGUE66 = 0x2A4, + PS_ROGUE67 = 0x2A5, + PS_ROGUE68 = 0x2A6, + PS_ROGUE69 = 0x2A7, + PS_ROGUE69B = 0x2A8, + PS_ROGUE70 = 0x2A9, + PS_ROGUE71 = 0x2AA, + PS_ROGUE72 = 0x2AB, + PS_ROGUE73 = 0x2AC, + PS_ROGUE74 = 0x2AD, + PS_ROGUE75 = 0x2AE, + PS_ROGUE76 = 0x2AF, + PS_ROGUE77 = 0x2B0, + PS_ROGUE78 = 0x2B1, + PS_ROGUE79 = 0x2B2, + PS_ROGUE80 = 0x2B3, + PS_ROGUE81 = 0x2B4, + PS_ROGUE82 = 0x2B5, + PS_ROGUE83 = 0x2B6, + PS_ROGUE84 = 0x2B7, + PS_ROGUE85 = 0x2B8, + PS_ROGUE86 = 0x2B9, + PS_ROGUE87 = 0x2BA, + PS_ROGUE88 = 0x2BB, + PS_ROGUE89 = 0x2BC, + PS_ROGUE90 = 0x2BD, + PS_ROGUE91 = 0x2BE, + PS_ROGUE92 = 0x2BF, + PS_ROGUE93 = 0x2C0, + PS_ROGUE94 = 0x2C1, + PS_ROGUE95 = 0x2C2, + PS_ROGUE96 = 0x2C3, + PS_ROGUE97 = 0x2C4, + PS_ROGUE98 = 0x2C5, + PS_ROGUE99 = 0x2C6, + PS_ROGUE100 = 0x2C7, + PS_ROGUE101 = 0x2C8, + PS_ROGUE102 = 0x2C9, + PS_WARR1 = 0x2CA, + PS_WARR2 = 0x2CB, + PS_WARR3 = 0x2CC, + PS_WARR4 = 0x2CD, + PS_WARR5 = 0x2CE, + PS_WARR6 = 0x2CF, + PS_WARR7 = 0x2D0, + PS_WARR8 = 0x2D1, + PS_WARR9 = 0x2D2, + PS_WARR10 = 0x2D3, + PS_WARR11 = 0x2D4, + PS_WARR12 = 0x2D5, + PS_WARR13 = 0x2D6, + PS_WARR14 = 0x2D7, + PS_WARR14B = 0x2D8, + PS_WARR14C = 0x2D9, + PS_WARR15 = 0x2DA, + PS_WARR15B = 0x2DB, + PS_WARR15C = 0x2DC, + PS_WARR16 = 0x2DD, + PS_WARR16B = 0x2DE, + PS_WARR16C = 0x2DF, + PS_WARR17 = 0x2E0, + PS_WARR18 = 0x2E1, + PS_WARR19 = 0x2E2, + PS_WARR20 = 0x2E3, + PS_WARR21 = 0x2E4, + PS_WARR22 = 0x2E5, + PS_WARR23 = 0x2E6, + PS_WARR24 = 0x2E7, + PS_WARR25 = 0x2E8, + PS_WARR26 = 0x2E9, + PS_WARR27 = 0x2EA, + PS_WARR28 = 0x2EB, + PS_WARR29 = 0x2EC, + PS_WARR30 = 0x2ED, + PS_WARR31 = 0x2EE, + PS_WARR32 = 0x2EF, + PS_WARR33 = 0x2F0, + PS_WARR34 = 0x2F1, + PS_WARR35 = 0x2F2, + PS_WARR36 = 0x2F3, + PS_WARR37 = 0x2F4, + PS_WARR38 = 0x2F5, + PS_WARR39 = 0x2F6, + PS_WARR40 = 0x2F7, + PS_WARR41 = 0x2F8, + PS_WARR42 = 0x2F9, + PS_WARR43 = 0x2FA, + PS_WARR44 = 0x2FB, + PS_WARR45 = 0x2FC, + PS_WARR46 = 0x2FD, + PS_WARR47 = 0x2FE, + PS_WARR48 = 0x2FF, + PS_WARR49 = 0x300, + PS_WARR50 = 0x301, + PS_WARR51 = 0x302, + PS_WARR52 = 0x303, + PS_WARR53 = 0x304, + PS_WARR54 = 0x305, + PS_WARR55 = 0x306, + PS_WARR56 = 0x307, + PS_WARR57 = 0x308, + PS_WARR58 = 0x309, + PS_WARR59 = 0x30A, + PS_WARR60 = 0x30B, + PS_WARR61 = 0x30C, + PS_WARR62 = 0x30D, + PS_WARR63 = 0x30E, + PS_WARR64 = 0x30F, + PS_WARR65 = 0x310, + PS_WARR66 = 0x311, + PS_WARR67 = 0x312, + PS_WARR68 = 0x313, + PS_WARR69 = 0x314, + PS_WARR69B = 0x315, + PS_WARR70 = 0x316, + PS_WARR71 = 0x317, + PS_WARR72 = 0x318, + PS_WARR73 = 0x319, + PS_WARR74 = 0x31A, + PS_WARR75 = 0x31B, + PS_WARR76 = 0x31C, + PS_WARR77 = 0x31D, + PS_WARR78 = 0x31E, + PS_WARR79 = 0x31F, + PS_WARR80 = 0x320, + PS_WARR81 = 0x321, + PS_WARR82 = 0x322, + PS_WARR83 = 0x323, + PS_WARR84 = 0x324, + PS_WARR85 = 0x325, + PS_WARR86 = 0x326, + PS_WARR87 = 0x327, + PS_WARR88 = 0x328, + PS_WARR89 = 0x329, + PS_WARR90 = 0x32A, + PS_WARR91 = 0x32B, + PS_WARR92 = 0x32C, + PS_WARR93 = 0x32D, + PS_WARR94 = 0x32E, + PS_WARR95 = 0x32F, + PS_WARR95B = 0x330, + PS_WARR95C = 0x331, + PS_WARR95D = 0x332, + PS_WARR95E = 0x333, + PS_WARR95F = 0x334, + PS_WARR96B = 0x335, + PS_WARR97 = 0x336, + PS_WARR98 = 0x337, + PS_WARR99 = 0x338, + PS_WARR100 = 0x339, + PS_WARR101 = 0x33A, + PS_WARR102 = 0x33B, + PS_NAR1 = 0x33C, + PS_NAR2 = 0x33D, + PS_NAR3 = 0x33E, + PS_NAR4 = 0x33F, + PS_NAR5 = 0x340, + PS_NAR6 = 0x341, + PS_NAR7 = 0x342, + PS_NAR8 = 0x343, + PS_NAR9 = 0x344, + PS_DIABLVLINT = 0x345, + USFX_CLEAVER = 0x346, + USFX_GARBUD1 = 0x347, + USFX_GARBUD2 = 0x348, + USFX_GARBUD3 = 0x349, + USFX_GARBUD4 = 0x34A, + USFX_IZUAL1 = 0x34B, + USFX_LACH1 = 0x34C, + USFX_LACH2 = 0x34D, + USFX_LACH3 = 0x34E, + USFX_LAZ1 = 0x34F, + USFX_LAZ2 = 0x350, + USFX_SKING1 = 0x351, + USFX_SNOT1 = 0x352, + USFX_SNOT2 = 0x353, + USFX_SNOT3 = 0x354, + USFX_WARLRD1 = 0x355, + USFX_WLOCK1 = 0x356, + USFX_ZHAR1 = 0x357, + USFX_ZHAR2 = 0x358, + USFX_DIABLOD = 0x359, +}; + +enum item_equip_type +{ + ILOC_NONE = 0x0, + ILOC_ONEHAND = 0x1, + ILOC_TWOHAND = 0x2, + ILOC_ARMOR = 0x3, + ILOC_HELM = 0x4, + ILOC_RING = 0x5, + ILOC_AMULET = 0x6, + ILOC_UNEQUIPABLE = 0x7, + ILOC_BELT = 0x8, + ILOC_INVALID = -1, +}; + +enum missile_id +{ + MIS_ARROW = 0x0, + MIS_FIREBOLT = 0x1, + MIS_GUARDIAN = 0x2, + MIS_RNDTELEPORT = 0x3, + MIS_LIGHTBALL = 0x4, + MIS_FIREWALL = 0x5, + MIS_FIREBALL = 0x6, + MIS_LIGHTCTRL = 0x7, + MIS_LIGHTNING = 0x8, + MIS_MISEXP = 0x9, + MIS_TOWN = 0xA, + MIS_FLASH = 0xB, + MIS_FLASH2 = 0xC, + MIS_MANASHIELD = 0xD, + MIS_FIREMOVE = 0xE, + MIS_CHAIN = 0xF, + MIS_NULL_10 = 0x10, // sentinal? + MIS_NULL_11 = 0x11, + MIS_NULL_12 = 0x12, + MIS_NULL_13 = 0x13, + MIS_RHINO = 0x14, + MIS_MAGMABALL = 0x15, + MIS_LIGHTCTRL2 = 0x16, + MIS_LIGHTNING2 = 0x17, + MIS_FLARE = 0x18, + MIS_MISEXP2 = 0x19, + MIS_TELEPORT = 0x1A, + MIS_FARROW = 0x1B, + MIS_DOOMSERP = 0x1C, + MIS_NULL_1D = 0x1D, + MIS_STONE = 0x1E, + MIS_NULL_1F = 0x1F, + MIS_INVISIBL = 0x20, + MIS_GOLEM = 0x21, + MIS_ETHEREALIZE = 0x22, + MIS_NULL_23 = 0x23, + MIS_BOOM = 0x24, + MIS_HEAL = 0x25, + MIS_FIREWALLC = 0x26, + MIS_INFRA = 0x27, + MIS_IDENTIFY = 0x28, + MIS_WAVE = 0x29, + MIS_NOVA = 0x2A, + MIS_BLODBOIL = 0x2B, + MIS_APOCA = 0x2C, + MIS_REPAIR = 0x2D, + MIS_RECHARGE = 0x2E, + MIS_DISARM = 0x2F, + MIS_FLAME = 0x30, + MIS_FLAMEC = 0x31, + MIS_NULL_32 = 0x32, + MIS_NULL_33 = 0x33, + MIS_CBOLT = 0x34, + MIS_HBOLT = 0x35, + MIS_RESURRECT = 0x36, + MIS_TELEKINESIS = 0x37, + MIS_LARROW = 0x38, + MIS_ACID = 0x39, + MIS_MISEXP3 = 0x3A, + MIS_ACIDPUD = 0x3B, + MIS_HEALOTHER = 0x3C, + MIS_ELEMENT = 0x3D, + MIS_RESURRECTBEAM = 0x3E, + MIS_BONESPIRIT = 0x3F, + MIS_WEAPEXP = 0x40, + MIS_RPORTAL = 0x41, + MIS_BOOM2 = 0x42, + MIS_DIABAPOCA = 0x43, +}; + +enum missile_graphic_id +{ + MFILE_ARROWS = 0x0, + MFILE_FIREBA = 0x1, + MFILE_GUARD = 0x2, + MFILE_LGHNING = 0x3, + MFILE_FIREWAL = 0x4, + MFILE_MAGBLOS = 0x5, + MFILE_PORTAL = 0x6, + MFILE_BLUEXFR = 0x7, + MFILE_BLUEXBK = 0x8, + MFILE_MANASHLD = 0x9, + MFILE_BLOOD = 0xA, + MFILE_BONE = 0xB, + MFILE_METLHIT = 0xC, + MFILE_FARROW = 0xD, + MFILE_DOOM = 0xE, + MFILE_0F = 0xF, + MFILE_BLODBUR = 0x10, + MFILE_NEWEXP = 0x11, + MFILE_SHATTER1 = 0x12, + MFILE_BIGEXP = 0x13, + MFILE_INFERNO = 0x14, + MFILE_THINLGHT = 0x15, + MFILE_FLARE = 0x16, + MFILE_FLAREEXP = 0x17, + MFILE_MAGBALL = 0x18, + MFILE_KRULL = 0x19, + MFILE_MINILTNG = 0x1A, + MFILE_HOLY = 0x1B, + MFILE_HOLYEXPL = 0x1C, + MFILE_LARROW = 0x1D, + MFILE_FIRARWEX = 0x1E, + MFILE_ACIDBF = 0x1F, + MFILE_ACIDSPLA = 0x20, + MFILE_ACIDPUD = 0x21, + MFILE_ETHRSHLD = 0x22, + MFILE_FIRERUN = 0x23, + MFILE_RESSUR1 = 0x24, + MFILE_SKLBALL = 0x25, + MFILE_RPORTAL = 0x26, + MFILE_FIREPLAR = 0x27, + MFILE_SCUBMISB = 0x28, + MFILE_SCBSEXPB = 0x29, + MFILE_SCUBMISC = 0x2A, + MFILE_SCBSEXPC = 0x2B, + MFILE_SCUBMISD = 0x2C, + MFILE_SCBSEXPD = 0x2D, + MFILE_NULL = 0x2E, + MFILE_INVALID = 0x2F, + MFILE_NONE = 0xFF, +}; + +enum _mai_id +{ + AI_ZOMBIE = 0, + AI_FAT = 1, + AI_SKELSD = 2, + AI_SKELBOW = 3, + AI_SCAV = 4, + AI_RHINO = 5, + AI_GOATMC = 6, + AI_GOATBOW = 7, + AI_FALLEN = 8, + AI_MAGMA = 9, + AI_SKELKING = 10, + AI_BAT = 11, + AI_GARG = 12, + AI_CLEAVER = 13, + AI_SUCC = 14, + AI_SNEAK = 15, + AI_STORM = 16, + AI_FIREMAN = 17, + AI_GARBUD = 18, + AI_ACID = 19, + AI_ACIDUNIQ = 20, + AI_GOLUM = 21, + AI_ZHAR = 22, + AI_SNOTSPIL = 23, + AI_SNAKE = 24, + AI_COUNSLR = 25, + AI_MEGA = 26, + AI_DIABLO = 27, + AI_LAZURUS = 28, + AI_LAZHELP = 29, + AI_LACHDAN = 30, + AI_WARLORD = 31, +}; + +enum _mc_id +{ + MC_UNDEAD = 0, + MC_DEMON = 1, + MC_ANIMAL = 2, +}; + +enum _monster_id +{ + MT_NZOMBIE = 0x0, + MT_BZOMBIE = 0x1, + MT_GZOMBIE = 0x2, + MT_YZOMBIE = 0x3, + MT_RFALLSP = 0x4, + MT_DFALLSP = 0x5, + MT_YFALLSP = 0x6, + MT_BFALLSP = 0x7, + MT_WSKELAX = 0x8, + MT_TSKELAX = 0x9, + MT_RSKELAX = 0xA, + MT_XSKELAX = 0xB, + MT_RFALLSD = 0xC, + MT_DFALLSD = 0xD, + MT_YFALLSD = 0xE, + MT_BFALLSD = 0xF, + MT_NSCAV = 0x10, + MT_BSCAV = 0x11, + MT_WSCAV = 0x12, + MT_YSCAV = 0x13, + MT_WSKELBW = 0x14, + MT_TSKELBW = 0x15, + MT_RSKELBW = 0x16, + MT_XSKELBW = 0x17, + MT_WSKELSD = 0x18, + MT_TSKELSD = 0x19, + MT_RSKELSD = 0x1A, + MT_XSKELSD = 0x1B, + MT_INVILORD = 0x1C, + MT_SNEAK = 0x1D, + MT_STALKER = 0x1E, + MT_UNSEEN = 0x1F, + MT_ILLWEAV = 0x20, + MT_LRDSAYTR = 0x21, + MT_NGOATMC = 0x22, + MT_BGOATMC = 0x23, + MT_RGOATMC = 0x24, + MT_GGOATMC = 0x25, + MT_FIEND = 0x26, + MT_BLINK = 0x27, + MT_GLOOM = 0x28, + MT_FAMILIAR = 0x29, + MT_NGOATBW = 0x2A, + MT_BGOATBW = 0x2B, + MT_RGOATBW = 0x2C, + MT_GGOATBW = 0x2D, + MT_NACID = 0x2E, + MT_RACID = 0x2F, + MT_BACID = 0x30, + MT_XACID = 0x31, + MT_SKING = 0x32, + MT_CLEAVER = 0x33, + MT_FAT = 0x34, + MT_MUDMAN = 0x35, + MT_TOAD = 0x36, + MT_FLAYED = 0x37, + MT_WYRM = 0x38, + MT_CAVSLUG = 0x39, + MT_DVLWYRM = 0x3A, + MT_DEVOUR = 0x3B, + MT_NMAGMA = 0x3C, + MT_YMAGMA = 0x3D, + MT_BMAGMA = 0x3E, + MT_WMAGMA = 0x3F, + MT_HORNED = 0x40, + MT_MUDRUN = 0x41, + MT_FROSTC = 0x42, + MT_OBLORD = 0x43, + MT_BONEDMN = 0x44, + MT_REDDTH = 0x45, + MT_LTCHDMN = 0x46, + MT_UDEDBLRG = 0x47, + MT_INCIN = 0x48, + MT_FLAMLRD = 0x49, + MT_DOOMFIRE = 0x4A, + MT_HELLBURN = 0x4B, + MT_STORM = 0x4C, + MT_RSTORM = 0x4D, + MT_STORML = 0x4E, + MT_MAEL = 0x4F, + MT_BIGFALL = 0x50, + MT_WINGED = 0x51, + MT_GARGOYLE = 0x52, + MT_BLOODCLW = 0x53, + MT_DEATHW = 0x54, + MT_MEGA = 0x55, + MT_GUARD = 0x56, + MT_VTEXLRD = 0x57, + MT_BALROG = 0x58, + MT_NSNAKE = 0x59, + MT_RSNAKE = 0x5A, + MT_BSNAKE = 0x5B, + MT_GSNAKE = 0x5C, + MT_NBLACK = 0x5D, + MT_RTBLACK = 0x5E, + MT_BTBLACK = 0x5F, + MT_RBLACK = 0x60, + MT_UNRAV = 0x61, + MT_HOLOWONE = 0x62, + MT_PAINMSTR = 0x63, + MT_REALWEAV = 0x64, + MT_SUCCUBUS = 0x65, + MT_SNOWWICH = 0x66, + MT_HLSPWN = 0x67, + MT_SOLBRNR = 0x68, + MT_COUNSLR = 0x69, + MT_MAGISTR = 0x6A, + MT_CABALIST = 0x6B, + MT_ADVOCATE = 0x6C, + MT_GOLEM = 0x6D, + MT_DIABLO = 0x6E, + MT_DARKMAGE = 0x6F, + NUM_MTYPES +}; + +enum _speech_id +{ + QUEST_KING1 = 0x0, + QUEST_KING2 = 0x1, + QUEST_KING3 = 0x2, + QUEST_KING4 = 0x3, + QUEST_KING5 = 0x4, + QUEST_KING6 = 0x5, + QUEST_KING7 = 0x6, + QUEST_KING8 = 0x7, + QUEST_KING9 = 0x8, + QUEST_KING10 = 0x9, + QUEST_KING11 = 0xA, + QUEST_BANNER1 = 0xB, + QUEST_BANNER2 = 0xC, + QUEST_BANNER3 = 0xD, + QUEST_BANNER4 = 0xE, + QUEST_BANNER5 = 0xF, + QUEST_BANNER6 = 0x10, + QUEST_BANNER7 = 0x11, + QUEST_BANNER8 = 0x12, + QUEST_BANNER9 = 0x13, + QUEST_BANNER10 = 0x14, + QUEST_BANNER11 = 0x15, + QUEST_BANNER12 = 0x16, + QUEST_VILE1 = 0x17, + QUEST_VILE2 = 0x18, + QUEST_VILE3 = 0x19, + QUEST_VILE4 = 0x1A, + QUEST_VILE5 = 0x1B, + QUEST_VILE6 = 0x1C, + QUEST_VILE7 = 0x1D, + QUEST_VILE8 = 0x1E, + QUEST_VILE9 = 0x1F, + QUEST_VILE10 = 0x20, + QUEST_VILE11 = 0x21, + QUEST_VILE12 = 0x22, + QUEST_VILE13 = 0x23, + QUEST_VILE14 = 0x24, + QUEST_POISON1 = 0x25, + QUEST_POISON2 = 0x26, + QUEST_POISON3 = 0x27, + QUEST_POISON4 = 0x28, + QUEST_POISON5 = 0x29, + QUEST_POISON6 = 0x2A, + QUEST_POISON7 = 0x2B, + QUEST_POISON8 = 0x2C, + QUEST_POISON9 = 0x2D, + QUEST_POISON10 = 0x2E, + QUEST_BONE1 = 0x2F, + QUEST_BONE2 = 0x30, + QUEST_BONE3 = 0x31, + QUEST_BONE4 = 0x32, + QUEST_BONE5 = 0x33, + QUEST_BONE6 = 0x34, + QUEST_BONE7 = 0x35, + QUEST_BONE8 = 0x36, + QUEST_BUTCH1 = 0x37, + QUEST_BUTCH2 = 0x38, + QUEST_BUTCH3 = 0x39, + QUEST_BUTCH4 = 0x3A, + QUEST_BUTCH5 = 0x3B, + QUEST_BUTCH6 = 0x3C, + QUEST_BUTCH7 = 0x3D, + QUEST_BUTCH8 = 0x3E, + QUEST_BUTCH9 = 0x3F, + QUEST_BUTCH10 = 0x40, + QUEST_BLIND1 = 0x41, + QUEST_BLIND2 = 0x42, + QUEST_BLIND3 = 0x43, + QUEST_BLIND4 = 0x44, + QUEST_BLIND5 = 0x45, + QUEST_BLIND6 = 0x46, + QUEST_BLIND7 = 0x47, + QUEST_BLIND8 = 0x48, + QUEST_VEIL1 = 0x49, + QUEST_VEIL2 = 0x4A, + QUEST_VEIL3 = 0x4B, + QUEST_VEIL4 = 0x4C, + QUEST_VEIL5 = 0x4D, + QUEST_VEIL6 = 0x4E, + QUEST_VEIL7 = 0x4F, + QUEST_VEIL8 = 0x50, + QUEST_VEIL9 = 0x51, + QUEST_VEIL10 = 0x52, + QUEST_VEIL11 = 0x53, + QUEST_ANVIL1 = 0x54, + QUEST_ANVIL2 = 0x55, + QUEST_ANVIL3 = 0x56, + QUEST_ANVIL4 = 0x57, + QUEST_ANVIL5 = 0x58, + QUEST_ANVIL6 = 0x59, + QUEST_ANVIL7 = 0x5A, + QUEST_ANVIL8 = 0x5B, + QUEST_ANVIL9 = 0x5C, + QUEST_ANVIL10 = 0x5D, + QUEST_BLOOD1 = 0x5E, + QUEST_BLOOD2 = 0x5F, + QUEST_BLOOD3 = 0x60, + QUEST_BLOOD4 = 0x61, + QUEST_BLOOD5 = 0x62, + QUEST_BLOOD6 = 0x63, + QUEST_BLOOD7 = 0x64, + QUEST_BLOOD8 = 0x65, + QUEST_WARLRD1 = 0x66, + QUEST_WARLRD2 = 0x67, + QUEST_WARLRD3 = 0x68, + QUEST_WARLRD4 = 0x69, + QUEST_WARLRD5 = 0x6A, + QUEST_WARLRD6 = 0x6B, + QUEST_WARLRD7 = 0x6C, + QUEST_WARLRD8 = 0x6D, + QUEST_WARLRD9 = 0x6E, + QUEST_INFRA1 = 0x6F, + QUEST_INFRA2 = 0x70, + QUEST_INFRA3 = 0x71, + QUEST_INFRA4 = 0x72, + QUEST_INFRA5 = 0x73, + QUEST_INFRA6 = 0x74, + QUEST_INFRA7 = 0x75, + QUEST_INFRA8 = 0x76, + QUEST_INFRA9 = 0x77, + QUEST_INFRA10 = 0x78, + QUEST_MUSH1 = 0x79, + QUEST_MUSH2 = 0x7A, + QUEST_MUSH3 = 0x7B, + QUEST_MUSH4 = 0x7C, + QUEST_MUSH5 = 0x7D, + QUEST_MUSH6 = 0x7E, + QUEST_MUSH7 = 0x7F, + QUEST_MUSH8 = 0x80, + QUEST_MUSH9 = 0x81, + QUEST_MUSH10 = 0x82, + QUEST_MUSH11 = 0x83, + QUEST_MUSH12 = 0x84, + QUEST_MUSH13 = 0x85, + QUEST_DOOM1 = 0x86, + QUEST_DOOM2 = 0x87, + QUEST_DOOM3 = 0x88, + QUEST_DOOM4 = 0x89, + QUEST_DOOM5 = 0x8A, + QUEST_DOOM6 = 0x8B, + QUEST_DOOM7 = 0x8C, + QUEST_DOOM8 = 0x8D, + QUEST_DOOM9 = 0x8E, + QUEST_DOOM10 = 0x8F, + QUEST_GARBUD1 = 0x90, + QUEST_GARBUD2 = 0x91, + QUEST_GARBUD3 = 0x92, + QUEST_GARBUD4 = 0x93, + QUEST_ZHAR1 = 0x94, + QUEST_ZHAR2 = 0x95, + QUEST_STORY1 = 0x96, + QUEST_STORY2 = 0x97, + QUEST_STORY3 = 0x98, + QUEST_STORY4 = 0x99, + QUEST_STORY5 = 0x9A, + QUEST_STORY6 = 0x9B, + QUEST_STORY7 = 0x9C, + QUEST_STORY9 = 0x9D, + QUEST_STORY10 = 0x9E, + QUEST_STORY11 = 0x9F, + QUEST_OGDEN1 = 0xA0, + QUEST_OGDEN2 = 0xA1, + QUEST_OGDEN3 = 0xA2, + QUEST_OGDEN4 = 0xA3, + QUEST_OGDEN5 = 0xA4, + QUEST_OGDEN6 = 0xA5, + QUEST_OGDEN8 = 0xA6, + QUEST_OGDEN9 = 0xA7, + QUEST_OGDEN10 = 0xA8, + QUEST_PEPIN1 = 0xA9, + QUEST_PEPIN2 = 0xAA, + QUEST_PEPIN3 = 0xAB, + QUEST_PEPIN4 = 0xAC, + QUEST_PEPIN5 = 0xAD, + QUEST_PEPIN6 = 0xAE, + QUEST_PEPIN7 = 0xAF, + QUEST_PEPIN9 = 0xB0, + QUEST_PEPIN10 = 0xB1, + QUEST_PEPIN11 = 0xB2, + QUEST_GILLIAN1 = 0xB3, + QUEST_GILLIAN2 = 0xB4, + QUEST_GILLIAN3 = 0xB5, + QUEST_GILLIAN4 = 0xB6, + QUEST_GILLIAN5 = 0xB7, + QUEST_GILLIAN6 = 0xB8, + QUEST_GILLIAN7 = 0xB9, + QUEST_GILLIAN9 = 0xBA, + QUEST_GILLIAN10 = 0xBB, + QUEST_GRISWOLD1 = 0xBC, + QUEST_GRISWOLD2 = 0xBD, + QUEST_GRISWOLD3 = 0xBE, + QUEST_GRISWOLD4 = 0xBF, + QUEST_GRISWOLD5 = 0xC0, + QUEST_GRISWOLD6 = 0xC1, + QUEST_GRISWOLD7 = 0xC2, + QUEST_GRISWOLD8 = 0xC3, + QUEST_GRISWOLD9 = 0xC4, + QUEST_GRISWOLD10 = 0xC5, + QUEST_GRISWOLD12 = 0xC6, + QUEST_GRISWOLD13 = 0xC7, + QUEST_FARNHAM1 = 0xC8, + QUEST_FARNHAM2 = 0xC9, + QUEST_FARNHAM3 = 0xCA, + QUEST_FARNHAM4 = 0xCB, + QUEST_FARNHAM5 = 0xCC, + QUEST_FARNHAM6 = 0xCD, + QUEST_FARNHAM8 = 0xCE, + QUEST_FARNHAM9 = 0xCF, + QUEST_FARNHAM10 = 0xD0, + QUEST_FARNHAM11 = 0xD1, + QUEST_FARNHAM12 = 0xD2, + QUEST_FARNHAM13 = 0xD3, + QUEST_ADRIA1 = 0xD4, + QUEST_ADRIA2 = 0xD5, + QUEST_ADRIA3 = 0xD6, + QUEST_ADRIA4 = 0xD7, + QUEST_ADRIA5 = 0xD8, + QUEST_ADRIA6 = 0xD9, + QUEST_ADRIA7 = 0xDA, + QUEST_ADRIA8 = 0xDB, + QUEST_ADRIA9 = 0xDC, + QUEST_ADRIA10 = 0xDD, + QUEST_ADRIA12 = 0xDE, + QUEST_ADRIA13 = 0xDF, + QUEST_WIRT1 = 0xE0, + QUEST_WIRT2 = 0xE1, + QUEST_WIRT3 = 0xE2, + QUEST_WIRT4 = 0xE3, + QUEST_WIRT5 = 0xE4, + QUEST_WIRT6 = 0xE5, + QUEST_WIRT7 = 0xE6, + QUEST_WIRT8 = 0xE7, + QUEST_WIRT9 = 0xE8, + QUEST_WIRT11 = 0xE9, + QUEST_WIRT12 = 0xEA, + QUEST_BONER = 0xEB, + QUEST_BLOODY = 0xEC, + QUEST_BLINDING = 0xED, + QUEST_BLOODWAR = 0xEE, + QUEST_MBONER = 0xEF, + QUEST_MBLOODY = 0xF0, + QUEST_MBLINDING = 0xF1, + QUEST_MBLOODWAR = 0xF2, + QUEST_RBONER = 0xF3, + QUEST_RBLOODY = 0xF4, + QUEST_RBLINDING = 0xF5, + QUEST_RBLOODWAR = 0xF6, + QUEST_COW1 = 0xF7, + QUEST_COW2 = 0xF8, + QUEST_BOOK11 = 0xF9, + QUEST_BOOK12 = 0xFA, + QUEST_BOOK13 = 0xFB, + QUEST_BOOK21 = 0xFC, + QUEST_BOOK22 = 0xFD, + QUEST_BOOK23 = 0xFE, + QUEST_BOOK31 = 0xFF, + QUEST_BOOK32 = 0x100, + QUEST_BOOK33 = 0x101, + QUEST_INTRO = 0x102 +}; + +enum object_graphic_id +{ + OFILE_L1BRAZ = 0x0, + OFILE_L1DOORS = 0x1, + OFILE_LEVER = 0x2, + OFILE_CHEST1 = 0x3, + OFILE_CHEST2 = 0x4, + OFILE_BANNER = 0x5, + OFILE_SKULPILE = 0x6, + OFILE_SKULFIRE = 0x7, + OFILE_SKULSTIK = 0x8, + OFILE_CRUXSK1 = 0x9, + OFILE_CRUXSK2 = 0xA, + OFILE_CRUXSK3 = 0xB, + OFILE_BOOK1 = 0xC, + OFILE_BOOK2 = 0xD, + OFILE_ROCKSTAN = 0xE, + OFILE_ANGEL = 0xF, + OFILE_CHEST3 = 0x10, + OFILE_BURNCROS = 0x11, + OFILE_CANDLE2 = 0x12, + OFILE_NUDE2 = 0x13, + OFILE_SWITCH4 = 0x14, + OFILE_TNUDEM = 0x15, + OFILE_TNUDEW = 0x16, + OFILE_TSOUL = 0x17, + OFILE_L2DOORS = 0x18, + OFILE_WTORCH4 = 0x19, + OFILE_WTORCH3 = 0x1A, + OFILE_SARC = 0x1B, + OFILE_FLAME1 = 0x1C, + OFILE_PRSRPLT1 = 0x1D, + OFILE_TRAPHOLE = 0x1E, + OFILE_MINIWATR = 0x1F, + OFILE_WTORCH2 = 0x20, + OFILE_WTORCH1 = 0x21, + OFILE_BCASE = 0x22, + OFILE_BSHELF = 0x23, + OFILE_WEAPSTND = 0x24, + OFILE_BARREL = 0x25, + OFILE_BARRELEX = 0x26, + OFILE_LSHRINEG = 0x27, + OFILE_RSHRINEG = 0x28, + OFILE_BLOODFNT = 0x29, + OFILE_DECAP = 0x2A, + OFILE_PEDISTL = 0x2B, + OFILE_L3DOORS = 0x2C, + OFILE_PFOUNTN = 0x2D, + OFILE_ARMSTAND = 0x2E, + OFILE_GOATSHRN = 0x2F, + OFILE_CAULDREN = 0x30, + OFILE_MFOUNTN = 0x31, + OFILE_TFOUNTN = 0x32, + OFILE_ALTBOY = 0x33, + OFILE_MCIRL = 0x34, + OFILE_BKSLBRNT = 0x35, + OFILE_MUSHPTCH = 0x36, + OFILE_LZSTAND = 0x37, +}; + +enum dungeon_type +{ + DTYPE_TOWN = 0x0, + DTYPE_CATHEDRAL = 0x1, + DTYPE_CATACOMBS = 0x2, + DTYPE_CAVES = 0x3, + DTYPE_HELL = 0x4, + DTYPE_NONE = 0xFF, +}; + +enum magic_type +{ + STYPE_FIRE = 0x0, + STYPE_LIGHTNING = 0x1, + STYPE_MAGIC = 0x2, +}; + +enum theme_id +{ + THEME_BARREL = 0x0, + THEME_SHRINE = 0x1, + THEME_MONSTPIT = 0x2, + THEME_SKELROOM = 0x3, + THEME_TREASURE = 0x4, + THEME_LIBRARY = 0x5, + THEME_TORTURE = 0x6, + THEME_BLOODFOUNTAIN = 0x7, + THEME_DECAPITATED = 0x8, + THEME_PURIFYINGFOUNTAIN = 0x9, + THEME_ARMORSTAND = 0xA, + THEME_GOATSHRINE = 0xB, + THEME_CAULDRON = 0xC, + THEME_MURKYFOUNTAIN = 0xD, + THEME_TEARFOUNTAIN = 0xE, + THEME_BRNCROSS = 0xF, + THEME_WEAPONRACK = 0x10, + THEME_NONE = 0xFF, +}; + +enum event_type +{ + EVENT_TYPE_PLAYER_CREATE_GAME = 1, + EVENT_TYPE_2 = 2, + EVENT_TYPE_PLAYER_LEAVE_GAME = 3, + EVENT_TYPE_PLAYER_MESSAGE = 4, + EVENT_TYPE_5 = 5, + EVENT_TYPE_6 = 6, + EVENT_TYPE_7 = 7, + EVENT_TYPE_8 = 8, + EVENT_TYPE_9 = 9, + EVENT_TYPE_10 = 10, + EVENT_TYPE_11 = 11, + EVENT_TYPE_12 = 12, + EVENT_TYPE_13 = 13, + EVENT_TYPE_14 = 14, + EVENT_TYPE_15 = 15, +}; + +enum _copyprot_results +{ + COPYPROT_OK = 1, + COPYPROT_CANCEL = 2, +}; + +enum text_color +{ + COL_WHITE = 0x0, + COL_BLUE = 0x1, + COL_RED = 0x2, + COL_GOLD = 0x3, +}; + +enum _difficulty +{ + DIFF_NORMAL = 0x0, + DIFF_NIGHTMARE = 0x1, + DIFF_HELL = 0x2, + NUM_DIFFICULTIES = 0x3, +}; + +enum MON_MODE +{ + MM_STAND = 0, + MM_WALK = 1, + MM_WALK2 = 2, + MM_WALK3 = 3, + MM_ATTACK = 4, + MM_GOTHIT = 5, + MM_DEATH = 6, + MM_SATTACK = 7, + MM_FADEIN = 8, + MM_FADEOUT = 9, + MM_RATTACK = 10, + MM_SPSTAND = 11, + MM_RSPATTACK = 12, + MM_DELAY = 13, + MM_CHARGE = 14, + MM_STONE = 15, + MM_HEAL = 16, + MM_TALK = 17, +}; + +enum PLR_MODE +{ + PM_STAND = 0, + PM_WALK = 1, + PM_WALK2 = 2, + PM_WALK3 = 3, + PM_ATTACK = 4, + PM_RATTACK = 5, + PM_BLOCK = 6, + PM_GOTHIT = 7, + PM_DEATH = 8, + PM_SPELL = 9, + PM_NEWLVL = 10, + PM_QUIT = 11, +}; + +enum spell_type +{ + RSPLTYPE_SKILL = 0x0, + RSPLTYPE_SPELL = 0x1, + RSPLTYPE_SCROLL = 0x2, + RSPLTYPE_CHARGES = 0x3, + RSPLTYPE_INVALID = 0x4, +}; + +enum cursor_id +{ + CURSOR_NONE = 0x0, + CURSOR_HAND = 0x1, + CURSOR_IDENTIFY = 0x2, + CURSOR_REPAIR = 0x3, + CURSOR_RECHARGE = 0x4, + CURSOR_DISARM = 0x5, + CURSOR_OIL = 0x6, + CURSOR_TELEKINESIS = 0x7, + CURSOR_RESURRECT = 0x8, + CURSOR_TELEPORT = 0x9, + CURSOR_HEALOTHER = 0xA, + CURSOR_HOURGLASS = 0xB, + CURSOR_FIRSTITEM = 0xC, +}; + +enum direction +{ + DIR_S = 0x0, + DIR_SW = 0x1, + DIR_W = 0x2, + DIR_NW = 0x3, + DIR_N = 0x4, + DIR_NE = 0x5, + DIR_E = 0x6, + DIR_SE = 0x7, + DIR_OMNI = 0x8, +}; + +enum interface_mode +{ + WM_DIAB = 0x401, + WM_DIABNEXTLVL = 0x402, // WM_USER+2 + WM_DIABPREVLVL = 0x403, + WM_DIABRTNLVL = 0x404, + WM_DIABSETLVL = 0x405, + WM_DIABWARPLVL = 0x406, + WM_DIABTOWNWARP = 0x407, + WM_DIABTWARPUP = 0x408, + WM_DIABRETOWN = 0x409, + WM_DIABNEWGAME = 0x40A, + WM_DIABLOADGAME = 0x40B + // WM_LEIGHSKIP = 0x40C, // psx only + // WM_DIAVNEWLVL = 0x40D, // psx only +}; + +enum game_info +{ + GAMEINFO_NAME = 1, + GAMEINFO_PASSWORD = 2, + GAMEINFO_STATS = 3, + GAMEINFO_MODEFLAG = 4, + GAMEINFO_GAMETEMPLATE = 5, + GAMEINFO_PLAYERS = 6, +}; + +enum spell_id +{ + SPL_NULL = 0x0, + SPL_FIREBOLT = 0x1, + SPL_HEAL = 0x2, + SPL_LIGHTNING = 0x3, + SPL_FLASH = 0x4, + SPL_IDENTIFY = 0x5, + SPL_FIREWALL = 0x6, + SPL_TOWN = 0x7, + SPL_STONE = 0x8, + SPL_INFRA = 0x9, + SPL_RNDTELEPORT = 0xA, + SPL_MANASHIELD = 0xB, + SPL_FIREBALL = 0xC, + SPL_GUARDIAN = 0xD, + SPL_CHAIN = 0xE, + SPL_WAVE = 0xF, + SPL_DOOMSERP = 0x10, + SPL_BLODRIT = 0x11, + SPL_NOVA = 0x12, + SPL_INVISIBIL = 0x13, + SPL_FLAME = 0x14, + SPL_GOLEM = 0x15, + SPL_BLODBOIL = 0x16, + SPL_TELEPORT = 0x17, + SPL_APOCA = 0x18, + SPL_ETHEREALIZE = 0x19, + SPL_REPAIR = 0x1A, + SPL_RECHARGE = 0x1B, + SPL_DISARM = 0x1C, + SPL_ELEMENT = 0x1D, + SPL_CBOLT = 0x1E, + SPL_HBOLT = 0x1F, + SPL_RESURRECT = 0x20, + SPL_TELEKINESIS = 0x21, + SPL_HEALOTHER = 0x22, + SPL_FLARE = 0x23, + SPL_BONESPIRIT = 0x24, + SPL_INVALID = 0xFFFFFFFF, +}; + +enum _cmd_id +{ + CMD_STAND = 0, + CMD_WALKXY = 1, + CMD_ACK_PLRINFO = 2, + CMD_ADDSTR = 3, + CMD_ADDMAG = 4, + CMD_ADDDEX = 5, + CMD_ADDVIT = 6, + CMD_SBSPELL = 7, + CMD_GETITEM = 8, + CMD_AGETITEM = 9, + CMD_PUTITEM = 10, + CMD_RESPAWNITEM = 11, + CMD_ATTACKXY = 12, + CMD_RATTACKXY = 13, + CMD_SPELLXY = 14, + CMD_TSPELLXY = 15, + CMD_OPOBJXY = 16, + CMD_DISARMXY = 17, + CMD_ATTACKID = 18, + CMD_ATTACKPID = 19, + CMD_RATTACKID = 20, + CMD_RATTACKPID = 21, + CMD_SPELLID = 22, + CMD_SPELLPID = 23, + CMD_TSPELLID = 24, + CMD_TSPELLPID = 25, + CMD_RESURRECT = 26, + CMD_OPOBJT = 27, + CMD_KNOCKBACK = 28, + CMD_TALKXY = 29, + CMD_NEWLVL = 30, + CMD_WARP = 31, + CMD_CHEAT_EXPERIENCE = 32, + CMD_CHEAT_SPELL_LEVEL = 33, + CMD_DEBUG = 34, + CMD_SYNCDATA = 35, + CMD_MONSTDEATH = 36, + CMD_MONSTDAMAGE = 37, + CMD_PLRDEAD = 38, + CMD_REQUESTGITEM = 39, + CMD_REQUESTAGITEM = 40, + CMD_GOTOGETITEM = 41, + CMD_GOTOAGETITEM = 42, + CMD_OPENDOOR = 43, + CMD_CLOSEDOOR = 44, + CMD_OPERATEOBJ = 45, + CMD_PLROPOBJ = 46, + CMD_BREAKOBJ = 47, + CMD_CHANGEPLRITEMS = 48, + CMD_DELPLRITEMS = 49, + CMD_PLRDAMAGE = 50, + CMD_PLRLEVEL = 51, + CMD_DROPITEM = 52, + CMD_PLAYER_JOINLEVEL = 53, + CMD_SEND_PLRINFO = 54, + CMD_SATTACKXY = 55, + CMD_ACTIVATEPORTAL = 56, + CMD_DEACTIVATEPORTAL = 57, + CMD_DLEVEL_0 = 58, + CMD_DLEVEL_1 = 59, + CMD_DLEVEL_2 = 60, + CMD_DLEVEL_3 = 61, + CMD_DLEVEL_4 = 62, + CMD_DLEVEL_5 = 63, + CMD_DLEVEL_6 = 64, + CMD_DLEVEL_7 = 65, + CMD_DLEVEL_8 = 66, + CMD_DLEVEL_9 = 67, + CMD_DLEVEL_10 = 68, + CMD_DLEVEL_11 = 69, + CMD_DLEVEL_12 = 70, + CMD_DLEVEL_13 = 71, + CMD_DLEVEL_14 = 72, + CMD_DLEVEL_15 = 73, + CMD_DLEVEL_16 = 74, + CMD_DLEVEL_JUNK = 75, + CMD_DLEVEL_END = 76, + CMD_HEALOTHER = 77, + CMD_STRING = 78, + CMD_SETSTR = 79, + CMD_SETMAG = 80, + CMD_SETDEX = 81, + CMD_SETVIT = 82, + CMD_RETOWN = 83, + CMD_SPELLXYD = 84, + CMD_ITEMEXTRA = 85, + CMD_SYNCPUTITEM = 86, + CMD_KILLGOLEM = 87, + CMD_SYNCQUEST = 88, + CMD_ENDSHIELD = 89, + CMD_AWAKEGOLEM = 90, + CMD_NOVA = 91, + CMD_SETSHIELD = 92, + CMD_REMSHIELD = 93, + FAKE_CMD_SETID = 94, + FAKE_CMD_DROPID = 95, + NUM_CMDS = 96, +}; + +enum _talker_id +{ + TOWN_SMITH = 0x0, + TOWN_HEALER = 0x1, + TOWN_DEADGUY = 0x2, + TOWN_TAVERN = 0x3, + TOWN_STORY = 0x4, + TOWN_DRUNK = 0x5, + TOWN_WITCH = 0x6, + TOWN_BMAID = 0x7, + TOWN_PEGBOY = 0x8, + TOWN_COW = 0x9, + TOWN_PRIEST = 0xA, +}; + +enum _music_id +{ + TMUSIC_TOWN = 0, + TMUSIC_L1 = 1, + TMUSIC_L2 = 2, + TMUSIC_L3 = 3, + TMUSIC_L4 = 4, + TMUSIC_INTRO = 5, + NUM_MUSIC = 6, +}; + +enum _mainmenu_selections +{ + MAINMENU_SINGLE_PLAYER = 1, + MAINMENU_MULTIPLAYER = 2, + MAINMENU_REPLAY_INTRO = 3, + MAINMENU_SHOW_CREDITS = 4, + MAINMENU_EXIT_DIABLO = 5, + MAINMENU_ATTRACT_MODE = 6, +}; + +enum panel_button_id +{ + PANBTN_CHARINFO = 0, + PANBTN_QLOG = 1, + PANBTN_AUTOMAP = 2, + PANBTN_MAINMENU = 3, + PANBTN_INVENTORY = 4, + PANBTN_SPELLBOOK = 5, + PANBTN_SENDMSG = 6, + PANBTN_FRIENDLY = 7, +}; + +enum attribute_id +{ + ATTRIB_STR = 0, + ATTRIB_MAG = 1, + ATTRIB_DEX = 2, + ATTRIB_VIT = 3, +}; + +enum _object_id +{ + OBJ_L1LIGHT = 0x0, + OBJ_L1LDOOR = 0x1, + OBJ_L1RDOOR = 0x2, + OBJ_SKFIRE = 0x3, + OBJ_LEVER = 0x4, + OBJ_CHEST1 = 0x5, + OBJ_CHEST2 = 0x6, + OBJ_CHEST3 = 0x7, + OBJ_CANDLE1 = 0x8, + OBJ_CANDLE2 = 0x9, + OBJ_CANDLEO = 0xA, + OBJ_BANNERL = 0xB, + OBJ_BANNERM = 0xC, + OBJ_BANNERR = 0xD, + OBJ_SKPILE = 0xE, + OBJ_SKSTICK1 = 0xF, + OBJ_SKSTICK2 = 0x10, + OBJ_SKSTICK3 = 0x11, + OBJ_SKSTICK4 = 0x12, + OBJ_SKSTICK5 = 0x13, + OBJ_CRUX1 = 0x14, + OBJ_CRUX2 = 0x15, + OBJ_CRUX3 = 0x16, + OBJ_STAND = 0x17, + OBJ_ANGEL = 0x18, + OBJ_BOOK2L = 0x19, + OBJ_BCROSS = 0x1A, + OBJ_NUDEW2R = 0x1B, + OBJ_SWITCHSKL = 0x1C, + OBJ_TNUDEM1 = 0x1D, + OBJ_TNUDEM2 = 0x1E, + OBJ_TNUDEM3 = 0x1F, + OBJ_TNUDEM4 = 0x20, + OBJ_TNUDEW1 = 0x21, + OBJ_TNUDEW2 = 0x22, + OBJ_TNUDEW3 = 0x23, + OBJ_TORTURE1 = 0x24, + OBJ_TORTURE2 = 0x25, + OBJ_TORTURE3 = 0x26, + OBJ_TORTURE4 = 0x27, + OBJ_TORTURE5 = 0x28, + OBJ_BOOK2R = 0x29, + OBJ_L2LDOOR = 0x2A, + OBJ_L2RDOOR = 0x2B, + OBJ_TORCHL = 0x2C, + OBJ_TORCHR = 0x2D, + OBJ_TORCHL2 = 0x2E, + OBJ_TORCHR2 = 0x2F, + OBJ_SARC = 0x30, + OBJ_FLAMEHOLE = 0x31, + OBJ_FLAMELVR = 0x32, + OBJ_WATER = 0x33, + OBJ_BOOKLVR = 0x34, + OBJ_TRAPL = 0x35, + OBJ_TRAPR = 0x36, + OBJ_BOOKSHELF = 0x37, + OBJ_WEAPRACK = 0x38, + OBJ_BARREL = 0x39, + OBJ_BARRELEX = 0x3A, + OBJ_SHRINEL = 0x3B, + OBJ_SHRINER = 0x3C, + OBJ_SKELBOOK = 0x3D, + OBJ_BOOKCASEL = 0x3E, + OBJ_BOOKCASER = 0x3F, + OBJ_BOOKSTAND = 0x40, + OBJ_BOOKCANDLE = 0x41, + OBJ_BLOODFTN = 0x42, + OBJ_DECAP = 0x43, + OBJ_TCHEST1 = 0x44, + OBJ_TCHEST2 = 0x45, + OBJ_TCHEST3 = 0x46, + OBJ_BLINDBOOK = 0x47, + OBJ_BLOODBOOK = 0x48, + OBJ_PEDISTAL = 0x49, + OBJ_L3LDOOR = 0x4A, + OBJ_L3RDOOR = 0x4B, + OBJ_PURIFYINGFTN = 0x4C, + OBJ_ARMORSTAND = 0x4D, + OBJ_ARMORSTANDN = 0x4E, + OBJ_GOATSHRINE = 0x4F, + OBJ_CAULDRON = 0x50, + OBJ_MURKYFTN = 0x51, + OBJ_TEARFTN = 0x52, + OBJ_ALTBOY = 0x53, + OBJ_MCIRCLE1 = 0x54, + OBJ_MCIRCLE2 = 0x55, + OBJ_STORYBOOK = 0x56, + OBJ_STORYCANDLE = 0x57, + OBJ_STEELTOME = 0x58, + OBJ_WARARMOR = 0x59, + OBJ_WARWEAP = 0x5A, + OBJ_TBCROSS = 0x5B, + OBJ_WEAPONRACK = 0x5C, + OBJ_WEAPONRACKN = 0x5D, + OBJ_MUSHPATCH = 0x5E, + OBJ_LAZSTAND = 0x5F, + OBJ_SLAINHERO = 0x60, + OBJ_SIGNCHEST = 0x61, + OBJ_NULL_98 = 0x62, +}; + +enum item_misc_id +{ + IMISC_NONE = 0x0, + IMISC_USEFIRST = 0x1, + IMISC_FULLHEAL = 0x2, + IMISC_HEAL = 0x3, + IMISC_OLDHEAL = 0x4, + IMISC_DEADHEAL = 0x5, + IMISC_MANA = 0x6, + IMISC_FULLMANA = 0x7, + IMISC_POTEXP = 0x8, /* add experience */ + IMISC_POTFORG = 0x9, /* remove experience */ + IMISC_ELIXSTR = 0xA, + IMISC_ELIXMAG = 0xB, + IMISC_ELIXDEX = 0xC, + IMISC_ELIXVIT = 0xD, + IMISC_ELIXWEAK = 0xE, /* double check with alpha */ + IMISC_ELIXDIS = 0xF, + IMISC_ELIXCLUM = 0x10, + IMISC_ELIXSICK = 0x11, + IMISC_REJUV = 0x12, + IMISC_FULLREJUV = 0x13, + IMISC_USELAST = 0x14, + IMISC_SCROLL = 0x15, + IMISC_SCROLLT = 0x16, + IMISC_STAFF = 0x17, + IMISC_BOOK = 0x18, + IMISC_RING = 0x19, + IMISC_AMULET = 0x1A, + IMISC_UNIQUE = 0x1B, + IMISC_HEAL_1C = 0x1C, + IMISC_OILFIRST = 0x1D, + IMISC_OILOF = 0x1E, /* oils are beta or hellfire only */ + IMISC_OILACC = 0x1F, + IMISC_OILMAST = 0x20, + IMISC_OILSHARP = 0x21, + IMISC_OILDEATH = 0x22, + IMISC_OILSKILL = 0x23, + IMISC_OILBSMTH = 0x24, + IMISC_OILFORT = 0x25, + IMISC_OILPERM = 0x26, + IMISC_OILHARD = 0x27, + IMISC_OILIMP = 0x28, + IMISC_OILLAST = 0x29, + IMISC_MAPOFDOOM = 0x2A, + IMISC_EAR = 0x2B, + IMISC_SPECELIX = 0x2C, + IMISC_INVALID = 0xFFFFFFFF, +}; + +enum item_type +{ + ITYPE_MISC = 0x0, + ITYPE_SWORD = 0x1, + ITYPE_AXE = 0x2, + ITYPE_BOW = 0x3, + ITYPE_MACE = 0x4, + ITYPE_SHIELD = 0x5, + ITYPE_LARMOR = 0x6, + ITYPE_HELM = 0x7, + ITYPE_MARMOR = 0x8, + ITYPE_HARMOR = 0x9, + ITYPE_STAFF = 0xA, + ITYPE_GOLD = 0xB, + ITYPE_RING = 0xC, + ITYPE_AMULET = 0xD, + ITYPE_0E = 0xE, + ITYPE_NONE = 0xFFFFFFFF, +}; + +enum _item_indexes +{ + IDI_GOLD = 0x0, + IDI_WARRIOR = 0x1, + IDI_WARRSHLD = 0x2, + IDI_WARRCLUB = 0x3, + IDI_ROGUE = 0x4, + IDI_SORCEROR = 0x5, + IDI_CLEAVER = 0x6, + IDI_FIRSTQUEST = 0x6, + IDI_SKCROWN = 0x7, + IDI_INFRARING = 0x8, + IDI_ROCK = 0x9, + IDI_OPTAMULET = 0xA, + IDI_TRING = 0xB, + IDI_BANNER = 0xC, + IDI_HARCREST = 0xD, + IDI_STEELVEIL = 0xE, + IDI_GLDNELIX = 0xF, + IDI_ANVIL = 0x10, + IDI_MUSHROOM = 0x11, + IDI_BRAIN = 0x12, + IDI_FUNGALTM = 0x13, + IDI_SPECELIX = 0x14, + IDI_BLDSTONE = 0x15, + IDI_LASTQUEST = 0x16, + IDI_MAPOFDOOM = 0x16, + IDI_EAR = 0x17, + IDI_HEAL = 0x18, + IDI_MANA = 0x19, + IDI_IDENTIFY = 0x1A, + IDI_PORTAL = 0x1B, + IDI_ARMOFVAL = 0x1C, + IDI_FULLHEAL = 0x1D, + IDI_FULLMANA = 0x1E, + IDI_GRISWOLD = 0x1F, + IDI_LGTFORGE = 0x20, + IDI_LAZSTAFF = 0x21, + IDI_RESURRECT = 0x22, +}; + +enum _setlevels +{ + //SL_BUTCHCHAMB = 0x0, + SL_SKELKING = 0x1, + SL_BONECHAMB = 0x2, + SL_MAZE = 0x3, + SL_POISONWATER = 0x4, + SL_VILEBETRAYER = 0x5, +}; + +enum quest_id +{ + QTYPE_INFRA = 0x0, + QTYPE_BLKM = 0x1, + QTYPE_GARB = 0x2, + QTYPE_ZHAR = 0x3, + QTYPE_VEIL = 0x4, + QTYPE_MOD = 0x5, + QTYPE_BUTCH = 0x6, + QTYPE_BOL = 0x7, + QTYPE_BLIND = 0x8, + QTYPE_BLOOD = 0x9, + QTYPE_ANVIL = 0xA, + QTYPE_WARLRD = 0xB, + QTYPE_KING = 0xC, + QTYPE_PW = 0xD, + QTYPE_BONE = 0xE, + QTYPE_VB = 0xF, + QTYPE_INVALID = 0xFFFFFFFF, +}; + +enum talk_id +{ + STORE_NONE = 0x0, + STORE_SMITH = 0x1, + STORE_SBUY = 0x2, + STORE_SSELL = 0x3, + STORE_SREPAIR = 0x4, + STORE_WITCH = 0x5, + STORE_WBUY = 0x6, + STORE_WSELL = 0x7, + STORE_WRECHARGE = 0x8, + STORE_NOMONEY = 0x9, + STORE_NOROOM = 0xA, + STORE_CONFIRM = 0xB, + STORE_BOY = 0xC, + STORE_BBOY = 0xD, + STORE_HEALER = 0xE, + STORE_STORY = 0xF, + STORE_HBUY = 0x10, + STORE_SIDENTIFY = 0x11, + STORE_SPBUY = 0x12, + STORE_GOSSIP = 0x13, + STORE_IDSHOW = 0x14, + STORE_TAVERN = 0x15, + STORE_DRUNK = 0x16, + STORE_BARMAID = 0x17, +}; + +enum _unique_items +{ + UITEM_CLEAVER = 0x0, + UITEM_SKCROWN = 0x1, + UITEM_INFRARING = 0x2, + UITEM_OPTAMULET = 0x3, + UITEM_TRING = 0x4, + UITEM_HARCREST = 0x5, + UITEM_STEELVEIL = 0x6, + UITEM_ARMOFVAL = 0x7, + UITEM_GRISWOLD = 0x8, + UITEM_LGTFORGE = 0x9, + UITEM_RIFTBOW = 0xA, + UITEM_NEEDLER = 0xB, + UITEM_CELESTBOW = 0xC, + UITEM_DEADLYHUNT = 0xD, + UITEM_BOWOFDEAD = 0xE, + UITEM_BLKOAKBOW = 0xF, + UITEM_FLAMEDART = 0x10, + UITEM_FLESHSTING = 0x11, + UITEM_WINDFORCE = 0x12, + UITEM_EAGLEHORN = 0x13, + UITEM_GONNAGALDIRK = 0x14, + UITEM_DEFENDER = 0x15, + UITEM_GRYPHONCLAW = 0x16, + UITEM_BLACKRAZOR = 0x17, + UITEM_GIBBOUSMOON = 0x18, + UITEM_ICESHANK = 0x19, + UITEM_EXECUTIONER = 0x1A, + UITEM_BONESAW = 0x1B, + UITEM_SHADHAWK = 0x1C, + UITEM_WIZSPIKE = 0x1D, + UITEM_LGTSABRE = 0x1E, + UITEM_FALCONTALON = 0x1F, + UITEM_INFERNO = 0x20, + UITEM_DOOMBRINGER = 0x21, + UITEM_GRIZZLY = 0x22, + UITEM_GRANDFATHER = 0x23, + UITEM_MANGLER = 0x24, + UITEM_SHARPBEAK = 0x25, + UITEM_BLOODLSLAYER = 0x26, + UITEM_CELESTAXE = 0x27, + UITEM_WICKEDAXE = 0x28, + UITEM_STONECLEAV = 0x29, + UITEM_AGUHATCHET = 0x2A, + UITEM_HELLSLAYER = 0x2B, + UITEM_MESSERREAVER = 0x2C, + UITEM_CRACKRUST = 0x2D, + UITEM_JHOLMHAMM = 0x2E, + UITEM_CIVERBS = 0x2F, + UITEM_CELESTSTAR = 0x30, + UITEM_BARANSTAR = 0x31, + UITEM_GNARLROOT = 0x32, + UITEM_CRANBASH = 0x33, + UITEM_SCHAEFHAMM = 0x34, + UITEM_DREAMFLANGE = 0x35, + UITEM_STAFFOFSHAD = 0x36, + UITEM_IMMOLATOR = 0x37, + UITEM_STORMSPIRE = 0x38, + UITEM_GLEAMSONG = 0x39, + UITEM_THUNDERCALL = 0x3A, + UITEM_PROTECTOR = 0x3B, + UITEM_NAJPUZZLE = 0x3C, + UITEM_MINDCRY = 0x3D, + UITEM_RODOFONAN = 0x3E, + UITEM_SPIRITSHELM = 0x3F, + UITEM_THINKINGCAP = 0x40, + UITEM_OVERLORDHELM = 0x41, + UITEM_FOOLSCREST = 0x42, + UITEM_GOTTERDAM = 0x43, + UITEM_ROYCIRCLET = 0x44, + UITEM_TORNFLESH = 0x45, + UITEM_GLADBANE = 0x46, + UITEM_RAINCLOAK = 0x47, + UITEM_LEATHAUT = 0x48, + UITEM_WISDWRAP = 0x49, + UITEM_SPARKMAIL = 0x4A, + UITEM_SCAVCARAP = 0x4B, + UITEM_NIGHTSCAPE = 0x4C, + UITEM_NAJPLATE = 0x4D, + UITEM_DEMONSPIKE = 0x4E, + UITEM_DEFLECTOR = 0x4F, + UITEM_SKULLSHLD = 0x50, + UITEM_DRAGONBRCH = 0x51, + UITEM_BLKOAKSHLD = 0x52, + UITEM_HOLYDEF = 0x53, + UITEM_STORMSHLD = 0x54, + UITEM_BRAMBLE = 0x55, + UITEM_REGHA = 0x56, + UITEM_BLEEDER = 0x57, + UITEM_CONSTRICT = 0x58, + UITEM_ENGAGE = 0x59, + UITEM_INVALID = 0x5A, +}; + +enum plr_class +{ + PC_WARRIOR = 0x0, + PC_ROGUE = 0x1, + PC_SORCERER = 0x2, + NUM_CLASSES +}; + +enum _ui_classes +{ + UI_WARRIOR = 0x0, + UI_ROGUE = 0x1, + UI_SORCERER = 0x2, + UI_NUM_CLASSES = 0x3, +}; + +enum _walk_path +{ + WALK_NONE = 0x0, + WALK_NE = 0x1, + WALK_NW = 0x2, + WALK_SE = 0x3, + WALK_SW = 0x4, + WALK_N = 0x5, + WALK_E = 0x6, + WALK_S = 0x7, + WALK_W = 0x8, +}; + +enum item_class { + ICLASS_NONE = 0, + ICLASS_WEAPON = 1, + ICLASS_ARMOR = 2, + ICLASS_MISC = 3, + ICLASS_GOLD = 4, + ICLASS_QUEST = 5, +}; + +enum item_drop_rate { + IDROP_NEVER = 0, + IDROP_REGULAR = 1, + IDROP_DOUBLE = 2, +}; + +enum item_special_effect { + ISPL_NONE = 0x00000000, + ISPL_INFRAVISION = 0x00000001, + ISPL_RNDSTEALLIFE = 0x00000002, + ISPL_RNDARROWVEL = 0x00000004, + ISPL_FIRE_ARROWS = 0x00000008, + ISPL_FIREDAM = 0x00000010, + ISPL_LIGHTDAM = 0x00000020, + ISPL_DRAINLIFE = 0x00000040, + ISPL_UNKNOWN_1 = 0x00000080, + ISPL_NOHEALPLR = 0x00000100, + ISPL_UNKNOWN_2 = 0x00000200, + ISPL_UNKNOWN_3 = 0x00000400, + ISPL_KNOCKBACK = 0x00000800, + ISPL_NOHEALMON = 0x00001000, + ISPL_STEALMANA_3 = 0x00002000, + ISPL_STEALMANA_5 = 0x00004000, + ISPL_STEALLIFE_3 = 0x00008000, + ISPL_STEALLIFE_5 = 0x00010000, + ISPL_QUICKATTACK = 0x00020000, + ISPL_FASTATTACK = 0x00040000, + ISPL_FASTERATTACK = 0x00080000, + ISPL_FASTESTATTACK = 0x00100000, + ISPL_FASTRECOVER = 0x00200000, + ISPL_FASTERRECOVER = 0x00400000, + ISPL_FASTESTRECOVER = 0x00800000, + ISPL_FASTBLOCK = 0x01000000, + ISPL_LIGHT_ARROWS = 0x02000000, + ISPL_THORNS = 0x04000000, + ISPL_NOMANA = 0x08000000, + ISPL_ABSHALFTRAP = 0x10000000, + ISPL_UNKNOWN_4 = 0x20000000, + ISPL_3XDAMVDEM = 0x40000000, + ISPL_ALLRESZERO = 0x80000000, +}; + +// Logical equipment locations +enum inv_body_loc { + INVLOC_HEAD = 0, + INVLOC_RING_LEFT = 1, + INVLOC_RING_RIGHT = 2, + INVLOC_AMULET = 3, + INVLOC_HAND_LEFT = 4, + INVLOC_HAND_RIGHT = 5, + INVLOC_CHEST = 6, + NUM_INVLOC, +}; + +enum inv_item { + INVITEM_HEAD = 0, + INVITEM_RING_LEFT = 1, + INVITEM_RING_RIGHT = 2, + INVITEM_AMULET = 3, + INVITEM_HAND_LEFT = 4, + INVITEM_HAND_RIGHT = 5, + INVITEM_CHEST = 6, + INVITEM_INV_FIRST = 7, + INVITEM_INV_LAST = 46, + INVITEM_BELT_FIRST = 47, + INVITEM_BELT_LAST = 54, + NUM_INVELEM +}; + +// identifiers for each of the inventory squares +// see https://github.com/sanctuary/graphics/blob/master/inventory.png +enum inv_xy_slot { + SLOTXY_HEAD_FIRST = 0, + SLOTXY_HEAD_LAST = 3, + SLOTXY_RING_LEFT = 4, + SLOTXY_RING_RIGHT = 5, + SLOTXY_AMULET = 6, + SLOTXY_HAND_LEFT_FIRST = 7, + SLOTXY_HAND_LEFT_LAST = 12, + SLOTXY_HAND_RIGHT_FIRST = 13, + SLOTXY_HAND_RIGHT_LAST = 18, + SLOTXY_CHEST_FIRST = 19, + SLOTXY_CHEST_LAST = 24, + + // regular inventory + SLOTXY_INV_FIRST = 25, + SLOTXY_INV_LAST = 64, + + // belt items + SLOTXY_BELT_FIRST = 65, + SLOTXY_BELT_LAST = 72, + NUM_XY_SLOTS = 73 +}; + +enum player_graphic +{ + PFILE_STAND = 1 << 0, + PFILE_WALK = 1 << 1, + PFILE_ATTACK = 1 << 2, + PFILE_HIT = 1 << 3, + PFILE_LIGHTNING = 1 << 4, + PFILE_FIRE = 1 << 5, + PFILE_MAGIC = 1 << 6, + PFILE_DEATH = 1 << 7, + PFILE_BLOCK = 1 << 8, + // everything except PFILE_DEATH + // 0b1_0111_1111 + PFILE_NONDEATH = 0x17F +}; + +enum shrine_type { + SHRINE_MYSTERIOUS = 0, + SHRINE_HIDDEN = 1, + SHRINE_GLOOMY = 2, + SHRINE_WEIRD = 3, + SHRINE_MAGICAL = 4, + SHRINE_STONE = 5, + SHRINE_RELIGIOUS = 6, + SHRINE_ENCHANTED = 7, + SHRINE_THAUMATURGIC = 8, + SHRINE_FASCINATING = 9, + SHRINE_CRYPTIC = 10, + SHRINE_MAGICAL2 = 11, + SHRINE_ELDRITCH = 12, + SHRINE_EERIE = 13, + SHRINE_DIVINE = 14, + SHRINE_HOLY = 15, + SHRINE_SACRED = 16, + SHRINE_SPIRITUAL = 17, + SHRINE_SPOOKY = 18, + SHRINE_ABANDONED = 19, + SHRINE_CREEPY = 20, + SHRINE_QUIET = 21, + SHRINE_SECLUDED = 22, + SHRINE_ORNATE = 23, + SHRINE_GLIMMERING = 24, + SHRINE_TAINTED = 25, + NUM_SHRINETYPE +}; diff --git a/resource.h b/resource.h new file mode 100644 index 000000000..bcfe205ac --- /dev/null +++ b/resource.h @@ -0,0 +1,27 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Diablo.rc +// +#define IDI_ICON1 101 +#define IDD_DIALOG1 104 // DX +#define IDD_DIALOG2 105 // NOMEMORY +#define IDD_DIALOG3 106 // NOFILE +#define IDD_DIALOG4 107 // DDRAW +#define IDD_DIALOG5 108 // DSOUND +#define IDD_DIALOG6 109 // PENTIUM (deprecated in 1.00) +#define IDD_DIALOG7 110 // DISKSPACE +#define IDD_DIALOG8 111 // VIDEOMODE +#define IDD_DIALOG9 112 // INSERTCD +#define IDD_DIALOG10 113 // RESTRICTED +#define IDD_DIALOG11 114 // READONLY + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/structs.h b/structs.h new file mode 100644 index 000000000..6fad0b9a4 --- /dev/null +++ b/structs.h @@ -0,0 +1,1695 @@ +////////////////////////////////////////////////// +// items +////////////////////////////////////////////////// + +struct PLStruct +{ + const char *PLName; + char PLPower; + int PLParam1; + int PLParam2; + int PLMinLvl; + int PLIType; + int PLGOE; + int PLDouble; + int PLOk; + int PLMinVal; + int PLMaxVal; + int PLMultVal; +}; + +struct UItemStruct +{ + char *UIName; + char UIItemId; + char UIMinLvl; + char UINumPL; + int UIValue; + char UIPower1; + int UIParam1; + int UIParam2; + char UIPower2; + int UIParam3; + int UIParam4; + char UIPower3; + int UIParam5; + int UIParam6; + char UIPower4; + int UIParam7; + int UIParam8; + char UIPower5; + int UIParam9; + int UIParam10; + char UIPower6; + int UIParam11; + int UIParam12; +}; + +struct ItemDataStruct +{ + int iRnd; + char iClass; + char iLoc; + int iCurs; + char itype; + char iItemId; + char *iName; + char *iSName; + int iMinMLvl; + int iDurability; + int iMinDam; + int iMaxDam; + int iMinAC; + int iMaxAC; + char iMinStr; + char iMinMag; + char iMinDex; + // item_special_effect + int iFlags; + // item_misc_id + int iMiscId; + // spell_id + int iSpell; + int iUsable; + int iValue; + int iMaxValue; +}; + +struct ItemGetRecordStruct +{ + int nSeed; + unsigned short wCI; + int nIndex; + int dwTimestamp; +}; + +struct ItemStruct +{ + int _iSeed; + unsigned short _iCreateInfo; + int _itype; + int _ix; + int _iy; + int _iAnimFlag; + unsigned char *_iAnimData; // PSX name -> ItemFrame + int _iAnimLen; + int _iAnimFrame; + int _iAnimWidth; + int _iAnimWidth2; // width 2? + int _isin; // set when item is flagged for deletion, deprecated in 1.02 + char _iSelFlag; + int _iPostDraw; + BOOL _iIdentified; + char _iMagical; + char _iName[64]; + char _iIName[64]; + char _iLoc; + // item_class enum + char _iClass; + int _iCurs; + int _ivalue; + int _iIvalue; + int _iMinDam; + int _iMaxDam; + int _iAC; + // item_special_effect + int _iFlags; + // item_misc_id + int _iMiscId; + // spell_id + int _iSpell; + int _iCharges; + int _iMaxCharges; + int _iDurability; + int _iMaxDur; + int _iPLDam; + int _iPLToHit; + int _iPLAC; + int _iPLStr; + int _iPLMag; + int _iPLDex; + int _iPLVit; + int _iPLFR; + int _iPLLR; + int _iPLMR; + int _iPLMana; + int _iPLHP; + int _iPLDamMod; + int _iPLGetHit; + int _iPLLight; + char _iSplLvlAdd; + char _iRequest; + int _iUid; + int _iFMinDam; + int _iFMaxDam; + int _iLMinDam; + int _iLMaxDam; + int _iPLEnAc; + char _iPrePower; + char _iSufPower; + int _iVAdd1; + int _iVMult1; + int _iVAdd2; + int _iVMult2; + char _iMinStr; + unsigned char _iMinMag; + char _iMinDex; + BOOL _iStatFlag; + int IDidx; + int offs016C; // _oldlight or _iInvalid +}; + +////////////////////////////////////////////////// +// player +////////////////////////////////////////////////// + +struct PlayerStruct +{ + int _pmode; + char walkpath[25]; + unsigned char plractive; + int destAction; + int destParam1; + int destParam2; + int destParam3; + int destParam4; + int plrlevel; + int WorldX; + int WorldY; + int _px; + int _py; + int _ptargx; + int _ptargy; + int _pownerx; + int _pownery; + int _poldx; + int _poldy; + int _pxoff; + int _pyoff; + int _pxvel; + int _pyvel; + int _pdir; + int _nextdir; + int _pgfxnum; + unsigned char *_pAnimData; + int _pAnimDelay; + int _pAnimCnt; + int _pAnimLen; + int _pAnimFrame; + int _pAnimWidth; + int _pAnimWidth2; + int _peflag; + int _plid; + int _pvid; + int _pSpell; + char _pSplType; + char _pSplFrom; + int _pTSpell; + int _pTSplType; + int _pRSpell; + // enum spell_type + char _pRSplType; + int _pSBkSpell; + char _pSBkSplType; + char _pSplLvl[64]; + union + { + UINT64 _pMemSpells64; + int _pMemSpells[2]; + }; + union + { + UINT64 _pAblSpells64; + int _pAblSpells[2]; + }; + union + { + UINT64 _pScrlSpells64; + int _pScrlSpells[2]; + }; + int _pSpellFlags; + int _pSplHotKey[4]; + char _pSplTHotKey[4]; + int _pwtype; + unsigned char _pBlockFlag; + unsigned char _pInvincible; + char _pLightRad; + unsigned char _pLvlChanging; + char _pName[32]; + // plr_class enum value. + // TODO: this could very well be `enum plr_class _pClass` + // since there are 3 bytes of alingment after this field. + // it could just be that the compiler optimized away all accesses to + // the higher bytes by using byte instructions, since all possible values + // of plr_class fit into one byte. + char _pClass; + int _pStrength; + int _pBaseStr; + int _pMagic; + int _pBaseMag; + int _pDexterity; + int _pBaseDex; + int _pVitality; + int _pBaseVit; + int _pStatPts; + int _pDamageMod; + int _pBaseToBlk; + int _pHPBase; + int _pMaxHPBase; + int _pHitPoints; + int _pMaxHP; + int _pHPPer; + int _pManaBase; + int _pMaxManaBase; + int _pMana; + int _pMaxMana; + int _pManaPer; + char _pLevel; + char _pMaxLvl; + int _pExperience; + int _pMaxExp; + int _pNextExper; + char _pArmorClass; + char _pMagResist; + char _pFireResist; + char _pLghtResist; + int _pGold; + int _pInfraFlag; + int _pVar1; + int _pVar2; + int _pVar3; + int _pVar4; + int _pVar5; + int _pVar6; + int _pVar7; + int _pVar8; + unsigned char _pLvlVisited[NUMLEVELS]; + unsigned char _pSLvlVisited[NUMLEVELS]; // only 10 used + int _pGFXLoad; + unsigned char *_pNAnim[8]; + int _pNFrames; + int _pNWidth; + unsigned char *_pWAnim[8]; + int _pWFrames; + int _pWWidth; + unsigned char *_pAAnim[8]; + int _pAFrames; + int _pAWidth; + int _pAFNum; + unsigned char *_pLAnim[8]; + unsigned char *_pFAnim[8]; + unsigned char *_pTAnim[8]; + int _pSFrames; + int _pSWidth; + int _pSFNum; + unsigned char *_pHAnim[8]; + int _pHFrames; + int _pHWidth; + unsigned char *_pDAnim[8]; + int _pDFrames; + int _pDWidth; + unsigned char *_pBAnim[8]; + int _pBFrames; + int _pBWidth; + ItemStruct InvBody[NUM_INVLOC]; + ItemStruct InvList[NUM_INV_GRID_ELEM]; + int _pNumInv; + char InvGrid[NUM_INV_GRID_ELEM]; + ItemStruct SpdList[8]; + ItemStruct HoldItem; + int _pIMinDam; + int _pIMaxDam; + int _pIAC; + int _pIBonusDam; + int _pIBonusToHit; + int _pIBonusAC; + int _pIBonusDamMod; + union { + UINT64 _pISpells64; + int _pISpells[2]; + }; + int _pIFlags; + int _pIGetHit; + char _pISplLvlAdd; + char _pISplCost; + int _pISplDur; + int _pIEnAc; + int _pIFMinDam; + int _pIFMaxDam; + int _pILMinDam; + int _pILMaxDam; + int _pOilType; + unsigned char pTownWarps; + unsigned char pDungMsgs; + unsigned char pLvlLoad; + unsigned char pBattleNet; + unsigned char pManaShield; + char bReserved[3]; + short wReserved[8]; + int pDiabloKillLevel; + int dwReserved[7]; + unsigned char *_pNData; + unsigned char *_pWData; + unsigned char *_pAData; + unsigned char *_pLData; + unsigned char *_pFData; + unsigned char *_pTData; + unsigned char *_pHData; + unsigned char *_pDData; + unsigned char *_pBData; + int unused_54D4; +}; + +////////////////////////////////////////////////// +// textdat +////////////////////////////////////////////////// + +struct TextDataStruct +{ + char *txtstr; + int scrlltxt; + int txtspd; + int sfxnr; +}; + +////////////////////////////////////////////////// +// missiles +////////////////////////////////////////////////// + +// TPDEF PTR FCN VOID MIADDPRC +// TPDEF PTR FCN VOID MIPROC + +struct MissileData +{ + unsigned char mName; + void (__fastcall *mAddProc)(int, int, int, int, int, int, int, int, int); + void (__fastcall *mProc)(int); + int mDraw; + unsigned char mType; + unsigned char mResist; + unsigned char mFileNum; + int mlSFX; + int miSFX; +}; + +struct MisFileData +{ + unsigned char mAnimName; + unsigned char mAnimFAmt; + char *mName; + int mFlags; + unsigned char *mAnimData[16]; + unsigned char mAnimDelay[16]; + unsigned char mAnimLen[16]; + int mAnimWidth[16]; + int mAnimWidth2[16]; +}; + +struct ChainStruct +{ + int idx; + int _mitype; + int _mirange; +}; + +struct MissileStruct +{ + int _mitype; + int _mix; + int _miy; + int _mixoff; + int _miyoff; + int _mixvel; + int _miyvel; + int _misx; + int _misy; + int _mitxoff; + int _mityoff; + int _mimfnum; + int _mispllvl; + int _miDelFlag; + int _miAnimType; + int _miAnimFlags; + unsigned char *_miAnimData; + int _miAnimDelay; + int _miAnimLen; + int _miAnimWidth; + int _miAnimWidth2; + int _miAnimCnt; + int _miAnimAdd; + int _miAnimFrame; + int _miDrawFlag; + int _miLightFlag; + int _miPreFlag; + int _miUniqTrans; + int _mirange; + int _misource; + int _micaster; + int _midam; + int _miHitFlag; + int _midist; + int _mlid; + int _mirnd; + int _miVar1; + int _miVar2; + int _miVar3; + int _miVar4; + int _miVar5; + int _miVar6; + int _miVar7; + int _miVar8; +}; + +////////////////////////////////////////////////// +// effects/sound +////////////////////////////////////////////////// +struct foo{ + char * text; + +}; + + +struct TSnd +{ + WAVEFORMATEX fmt; + int len; + int offset; + char *sound_path; + IDirectSoundBuffer *DSB; + int start_tc; +}; + +struct TSFX +{ + unsigned char bFlags; + char *pszName; + TSnd *pSnd; +}; + +////////////////////////////////////////////////// +// monster +////////////////////////////////////////////////// + +struct AnimStruct // note: wrong names +{ + unsigned char *CMem; + unsigned char *Frames[8]; // probably Data[8] + int Rate; + int Delay; +}; + +struct MonsterData +{ + int flags; // width? + int mType; + char *GraphicType; + BOOL has_special; + char *sndfile; + int snd_special; + int has_trans; + char *TransFile; + int Frames[6]; + int Rate[6]; + char *mName; + char mMinDLvl; + char mMaxDLvl; + char mLevel; + int mMinHP; + int mMaxHP; + char mAi; + int mFlags; + unsigned char mInt; + unsigned char mHit; + unsigned char mAFNum; + unsigned char mMinDamage; + unsigned char mMaxDamage; + unsigned char mHit2; + unsigned char mAFNum2; + unsigned char mMinDamage2; + unsigned char mMaxDamage2; + char mArmorClass; + char mMonstClass; + unsigned short mMagicRes; + unsigned short mMagicRes2; + unsigned short mTreasure; + char mSelFlag; + unsigned short mExp; +}; + +struct CMonster +{ + unsigned char mtype; + // TODO: Add enum for place flags + unsigned char mPlaceFlags; + AnimStruct Anims[6]; + TSnd *Snds[8]; + int flags_1; // width + int flags_2; // width 2 + unsigned char mMinHP; + unsigned char mMaxHP; + int has_special; + unsigned char mAFNum; + char mdeadval; + MonsterData *MData; + // A TRN file contains a sequence of colour transitions, represented + // as indexes into a palette. (a 256 byte array of palette indices) + unsigned char *trans_file; +}; + +struct MonsterStruct // note: missing field _mAFNum +{ + int _mMTidx; + int _mmode; /* MON_MODE */ + unsigned char _mgoal; + int _mgoalvar1; + int _mgoalvar2; + int _mgoalvar3; + int field_18; + unsigned char _pathcount; + int _mx; + int _my; + int _mfutx; + int _mfuty; + int _moldx; + int _moldy; + int _mxoff; + int _myoff; + int _mxvel; + int _myvel; + int _mdir; + int _menemy; + unsigned char _menemyx; + unsigned char _menemyy; + short falign_52; + unsigned char *_mAnimData; + int _mAnimDelay; + int _mAnimCnt; + int _mAnimLen; + int _mAnimFrame; + int _meflag; + int _mDelFlag; + int _mVar1; + int _mVar2; + int _mVar3; + int _mVar4; + int _mVar5; + int _mVar6; + int _mVar7; + int _mVar8; + int _mmaxhp; + int _mhitpoints; + unsigned char _mAi; + unsigned char _mint; + short falign_9A; + int _mFlags; + char _msquelch; /* unsigned char */ + int falign_A4; + int _lastx; + int _lasty; + int _mRndSeed; + int _mAISeed; + int falign_B8; + unsigned char _uniqtype; + unsigned char _uniqtrans; + char _udeadval; + char mWhoHit; + char mLevel; + unsigned short mExp; + unsigned char mHit; + unsigned char mMinDamage; + unsigned char mMaxDamage; + unsigned char mHit2; + unsigned char mMinDamage2; + unsigned char mMaxDamage2; + char mArmorClass; + char falign_CB; + unsigned short mMagicRes; + int mtalkmsg; + unsigned char leader; + unsigned char leaderflag; + unsigned char unpackfilesize; + unsigned char mlid; + char *mName; + CMonster *MType; + MonsterData *MData; +}; + +struct UniqMonstStruct +{ + char mtype; + char *mName; + char *mMode; + unsigned char mlevel; + unsigned short mmaxhp; + unsigned char mAi; + unsigned char mint; + unsigned char mMinDamage; + unsigned char mMaxDamage; + unsigned short mMagicRes; + unsigned short mUnqAttr; + unsigned char mUnqVar1; + unsigned char mUnqVar2; + int mtalkmsg; +}; + +////////////////////////////////////////////////// +// objects +////////////////////////////////////////////////// + +struct ObjDataStruct +{ + char oload; + char ofindex; + char ominlvl; + char omaxlvl; + char olvltype; + char otheme; + char oquest; + int oAnimFlag; + int oAnimDelay; + int oAnimLen; + int oAnimWidth; + int oSolidFlag; + int oMissFlag; + int oLightFlag; + char oBreak; + char oSelFlag; + int oTrapFlag; +}; + +struct ObjectStruct +{ + int _otype; + int _ox; + int _oy; + int _oLight; + int _oAnimFlag; + unsigned char *_oAnimData; + int _oAnimDelay; + int _oAnimCnt; + int _oAnimLen; + int _oAnimFrame; + int _oAnimWidth; + int _oAnimWidth2; + int _oDelFlag; + char _oBreak; // check + int _oSolidFlag; + int _oMissFlag; + char _oSelFlag; // check + int _oPreFlag; + int _oTrapFlag; + int _oDoorFlag; + int _olid; + int _oRndSeed; + int _oVar1; + int _oVar2; + int _oVar3; + int _oVar4; + int _oVar5; + int _oVar6; + int _oVar7; + int _oVar8; +}; + +////////////////////////////////////////////////// +// portal +////////////////////////////////////////////////// + +struct PortalStruct +{ + int open; + int x; + int y; + int level; + int ltype; + int setlvl; +}; + +////////////////////////////////////////////////// +// msg +////////////////////////////////////////////////// + +#pragma pack(push, 1) +struct TCmd +{ + unsigned char bCmd; +}; + +struct TCmdLoc +{ + unsigned char bCmd; + unsigned char x; + unsigned char y; +}; + +struct TCmdLocParam1 +{ + unsigned char bCmd; + unsigned char x; + unsigned char y; + unsigned short wParam1; +}; + +struct TCmdLocParam2 +{ + unsigned char bCmd; + unsigned char x; + unsigned char y; + unsigned short wParam1; + unsigned short wParam2; +}; + +struct TCmdLocParam3 +{ + unsigned char bCmd; + unsigned char x; + unsigned char y; + unsigned short wParam1; + unsigned short wParam2; + unsigned short wParam3; +}; + +struct TCmdParam1 +{ + unsigned char bCmd; + unsigned short wParam1; +}; + +struct TCmdParam2 +{ + unsigned char bCmd; + unsigned short wParam1; + unsigned short wParam2; +}; + +struct TCmdParam3 +{ + unsigned char bCmd; + unsigned short wParam1; + unsigned short wParam2; + unsigned short wParam3; +}; + +struct TCmdGolem +{ + unsigned char bCmd; + unsigned char _mx; + unsigned char _my; + unsigned char _mdir; + unsigned char _menemy; + int _mhitpoints; + unsigned char _currlevel; +}; + +struct TCmdQuest +{ + unsigned char bCmd; + unsigned char q; + unsigned char qstate; + unsigned char qlog; + unsigned char qvar1; +}; + +struct TCmdGItem +{ + unsigned char bCmd; + unsigned char bMaster; + unsigned char bPnum; + unsigned char bCursitem; + unsigned char bLevel; + unsigned char x; + unsigned char y; + unsigned short wIndx; + unsigned short wCI; + int dwSeed; + unsigned char bId; + unsigned char bDur; + unsigned char bMDur; + unsigned char bCh; + unsigned char bMCh; + unsigned short wValue; + int dwBuff; + int dwTime; +}; + +struct TCmdPItem +{ + char bCmd; /* unsigned */ + unsigned char x; + unsigned char y; + unsigned short wIndx; + unsigned short wCI; + int dwSeed; + unsigned char bId; + unsigned char bDur; + unsigned char bMDur; + unsigned char bCh; + unsigned char bMCh; + unsigned short wValue; + int dwBuff; +}; + +struct TCmdChItem +{ + unsigned char bCmd; + unsigned char bLoc; + unsigned short wIndx; + unsigned short wCI; + int dwSeed; + unsigned char bId; +}; + +struct TCmdDelItem +{ + unsigned char bCmd; + unsigned char bLoc; +}; + +struct TCmdDamage +{ + unsigned char bCmd; + unsigned char bPlr; + int dwDam; +}; + +struct TCmdPlrInfoHdr +{ + unsigned char bCmd; + unsigned short wOffset; + unsigned short wBytes; +}; + +struct TCmdString +{ + unsigned char bCmd; + char str[80]; +}; + +struct TFakeCmdPlr +{ + unsigned char bCmd; + unsigned char bPlr; +}; + +struct TFakeDropPlr +{ + unsigned char bCmd; + unsigned char bPlr; + int dwReason; +}; + +struct TSyncHeader +{ + unsigned char bCmd; + unsigned char bLevel; + unsigned short wLen; + unsigned char bObjId; + unsigned char bObjCmd; + unsigned char bItemI; + unsigned char bItemX; + unsigned char bItemY; + unsigned short wItemIndx; + unsigned short wItemCI; + int dwItemSeed; + unsigned char bItemId; + unsigned char bItemDur; + unsigned char bItemMDur; + unsigned char bItemCh; + unsigned char bItemMCh; + unsigned short wItemVal; + unsigned int dwItemBuff; + unsigned char bPInvLoc; + unsigned short wPInvIndx; + unsigned short wPInvCI; + int dwPInvSeed; + unsigned char bPInvId; +}; + +struct TSyncMonster +{ + unsigned char _mndx; + unsigned char _mx; + unsigned char _my; + unsigned char _menemy; + unsigned char _mdelta; +}; + +struct TPktHdr +{ + unsigned char px; + unsigned char py; + unsigned char targx; + unsigned char targy; + int php; + int pmhp; + unsigned char bstr; + unsigned char bmag; + unsigned char bdex; + unsigned short wCheck; + unsigned short wLen; +}; + +struct TPkt +{ + TPktHdr hdr; + unsigned char body[493]; +}; + +struct DMonsterStr +{ + char _mx; /* these might be unsigned */ + char _my; + char _mdir; + char _menemy; + char _mactive; + int _mhitpoints; +}; + +struct DObjectStr +{ + unsigned char bCmd; +}; + +struct DLevel +{ + TCmdPItem item[MAXITEMS]; + DObjectStr object[MAXOBJECTS]; + DMonsterStr monster[MAXMONSTERS]; +}; + +struct LocalLevel +{ + unsigned char automapsv[40][40]; +}; + +struct DPortal +{ + unsigned char x; + unsigned char y; + unsigned char level; + unsigned char ltype; + unsigned char setlvl; +}; + +struct MultiQuests +{ + unsigned char qstate; + unsigned char qlog; + unsigned char qvar1; +}; + +struct DJunk +{ + DPortal portal[MAXPORTAL]; + MultiQuests quests[MAXMULTIQUESTS]; +}; +#pragma pack(pop) + +struct TMegaPkt +{ + TMegaPkt *pNext; + int dwSpaceLeft; + unsigned char data[32000]; +}; + +////////////////////////////////////////////////// +// quests +////////////////////////////////////////////////// + +struct QuestStruct +{ + unsigned char _qlevel; + unsigned char _qtype; + unsigned char _qactive; + unsigned char _qlvltype; + int _qtx; + int _qty; + unsigned char _qslvl; + unsigned char _qidx; + unsigned char _qmsg; + unsigned char _qvar1; + unsigned char _qvar2; + int _qlog; /* char */ +}; + +struct QuestData +{ + unsigned char _qdlvl; + char _qdmultlvl; + unsigned char _qlvlt; + unsigned char _qdtype; + unsigned char _qdrnd; + unsigned char _qslvl; + int _qflags; /* unsigned char */ + int _qdmsg; + char *_qlstr; +}; + +////////////////////////////////////////////////// +// gamemenu/gmenu +////////////////////////////////////////////////// + +// TPDEF PTR FCN VOID TMenuFcn + +struct TMenuItem +{ + unsigned int dwFlags; + char *pszStr; + void (__cdecl *fnMenu)(); /* fix, should have one arg */ +}; + +// TPDEF PTR FCN VOID TMenuUpdateFcn + +////////////////////////////////////////////////// +// spells +////////////////////////////////////////////////// + +struct SpellData +{ + unsigned char sName; + unsigned char sManaCost; + unsigned char sType; + char *sNameText; + char *sSkillText; + int sBookLvl; + int sStaffLvl; + int sTargeted; + unsigned char sTownSpell; + int sMinInt; + unsigned char sSFX; + unsigned char sMissiles[3]; + unsigned char sManaAdj; + unsigned char sMinMana; + int sStaffMin; + int sStaffMax; + int sBookCost; + int sStaffCost; +}; + +////////////////////////////////////////////////// +// towners +////////////////////////////////////////////////// + +struct TNQ +{ + unsigned char _qsttype; + unsigned char _qstmsg; + unsigned char _qstmsgact; +}; + +struct TownerStruct +{ + int _tmode; + int _ttype; + int _tx; + int _ty; + int _txoff; + int _tyoff; + int _txvel; + int _tyvel; + int _tdir; + unsigned char *_tAnimData; + int _tAnimDelay; + int _tAnimCnt; + int _tAnimLen; + int _tAnimFrame; + int _tAnimFrameCnt; + int _tAnimOrder; + int _tAnimWidth; + int _tAnimWidth2; + int _tTenPer; + int _teflag; + int _tbtcnt; + int _tSelFlag; + int _tMsgSaid; + TNQ qsts[16]; + int _tSeed; + int _tVar1; + int _tVar2; + int _tVar3; + int _tVar4; + char _tName[32]; + unsigned char *_tNAnim[8]; + int _tNFrames; + unsigned char *_tNData; +}; + +struct QuestTalkData +{ + int _qinfra; + int _qblkm; + int _qgarb; + int _qzhar; + int _qveil; + int _qmod; + int _qbutch; + int _qbol; + int _qblind; + int _qblood; + int _qanvil; + int _qwarlrd; + int _qking; + int _qpw; + int _qbone; + int _qvb; +}; + +////////////////////////////////////////////////// +// gendung +////////////////////////////////////////////////// + +struct ScrollStruct +{ + int _sxoff; + int _syoff; + int _sdx; + int _sdy; + int _sdir; +}; + +struct THEME_LOC +{ + int x; + int y; + int ttval; + int width; + int height; +}; + +////////////////////////////////////////////////// +// drlg +////////////////////////////////////////////////// + +struct ShadowStruct +{ + unsigned char strig; + unsigned char s1; + unsigned char s2; + unsigned char s3; + unsigned char nv1; + unsigned char nv2; + unsigned char nv3; +}; + +struct HALLNODE +{ + int nHallx1; + int nHally1; + int nHallx2; + int nHally2; + int nHalldir; + HALLNODE *pNext; +}; + +struct ROOMNODE +{ + int nRoomx1; + int nRoomy1; + int nRoomx2; + int nRoomy2; + int nRoomDest; +}; + +////////////////////////////////////////////////// +// themes +////////////////////////////////////////////////// + +struct ThemeStruct +{ + char ttype; /* aligned 4 */ + int ttval; +}; + +////////////////////////////////////////////////// +// inv +////////////////////////////////////////////////// + +struct InvXY +{ + int X; + int Y; +}; + +////////////////////////////////////////////////// +// lighting +////////////////////////////////////////////////// + +struct LightListStruct +{ + int _lx; + int _ly; + int _lradius; + int _lid; + int _ldel; + int _lunflag; + int field_18; + int _lunx; + int _luny; + int _lunr; + int _xoff; + int _yoff; + int _lflags; +}; + +////////////////////////////////////////////////// +// dead +////////////////////////////////////////////////// + +struct DeadStruct +{ + unsigned char *_deadData[8]; + int _deadFrame; + int _deadWidth; + int _deadWidth2; + int _deadtrans; +}; + +////////////////////////////////////////////////// +// dx +////////////////////////////////////////////////// + +struct ScreenRow +{ + char col_unused_1[64]; + char pixels[640]; + char col_unused_2[64]; +}; + +struct Screen /* create union for work data vs visible data */ +{ + ScreenRow row_unused_1[160]; + ScreenRow row[480]; + ScreenRow row_unused_2[16]; +}; + +////////////////////////////////////////////////// +// storm +////////////////////////////////////////////////// + +// TPDEF PTR FCN VOID SEVTHANDLER + +// TPDEF PTR FCN UCHAR SMSGIDLEPROC +// TPDEF PTR FCN VOID SMSGHANDLER + +struct _SNETCAPS +{ + int size; + int flags; + int maxmessagesize; + int maxqueuesize; + int maxplayers; + int bytessec; + int latencyms; + int defaultturnssec; + int defaultturnsintransit; +}; + +struct _SNETEVENT +{ + int eventid; + int playerid; + void *data; + int databytes; +}; + +// TPDEF PTR FCN UCHAR SNETABORTPROC +// TPDEF PTR FCN UCHAR SNETCATEGORYPROC +// TPDEF PTR FCN UCHAR SNETCHECKAUTHPROC +// TPDEF PTR FCN UCHAR SNETCREATEPROC +// TPDEF PTR FCN UCHAR SNETDRAWDESCPROC +// TPDEF PTR FCN UCHAR SNETENUMDEVICESPROC +// TPDEF PTR FCN UCHAR SNETENUMGAMESPROC +// TPDEF PTR FCN UCHAR SNETENUMPROVIDERSPROC +// TPDEF PTR FCN VOID SNETEVENTPROC +// TPDEF PTR FCN UCHAR SNETGETARTPROC +// TPDEF PTR FCN UCHAR SNETGETDATAPROC +// TPDEF PTR FCN INT SNETMESSAGEBOXPROC +// TPDEF PTR FCN UCHAR SNETPLAYSOUNDPROC +// TPDEF PTR FCN UCHAR SNETSELECTEDPROC +// TPDEF PTR FCN UCHAR SNETSTATUSPROC + +struct _SNETPLAYERDATA +{ + int size; + char *playername; + char *playerdescription; + int reserved; +}; + +struct _SNETPROGRAMDATA +{ + int size; + char *programname; + char *programdescription; + int programid; + int versionid; + int reserved1; + int maxplayers; + void *initdata; + int initdatabytes; + void *reserved2; + int optcategorybits; + char *cdkey; + char *registereduser; + int spawned; + int lcid; +}; + +struct _SNETUIDATA +{ + int size; + int uiflags; + HWND parentwindow; + void (__cdecl *artcallback)(); + void (__cdecl *authcallback)(); + void (__cdecl *createcallback)(); + void (__cdecl *drawdesccallback)(); + void (__cdecl *selectedcallback)(); + void (__cdecl *messageboxcallback)(); + void (__cdecl *soundcallback)(); + void (__cdecl *statuscallback)(); + void (__cdecl *getdatacallback)(); + void (__cdecl *categorycallback)(); + void (__cdecl *categorylistcallback)(); + void (__cdecl *newaccountcallback)(); + void (__cdecl *profilecallback)(); + int profilefields; + void (__cdecl *profilebitmapcallback)(); + void (__cdecl *selectnamecallback)(int u1, int u2, int u3, int u4, int mode, char *cname, int clen, char *cdesc, int cdlen, int *multi); + void (__cdecl *changenamecallback)(); +}; + +struct _SNETVERSIONDATA +{ + int size; + char *versionstring; + char *executablefile; + char *originalarchivefile; + char *patcharchivefile; +}; + +// TPDEF PTR FCN UCHAR SNETSPIBIND +// TPDEF PTR FCN UCHAR SNETSPIQUERY + +////////////////////////////////////////////////// +// diabloui +////////////////////////////////////////////////// + +// TPDEF PTR FCN VOID PLAYSND + +struct _gamedata +{ + int dwSeed; + unsigned char bDiff; +}; + +struct _uidefaultstats +{ + unsigned short strength; + unsigned short magic; + unsigned short dexterity; + unsigned short vitality; +}; + +struct _uiheroinfo +{ + _uiheroinfo *next; + char name[16]; + unsigned short level; + unsigned char heroclass; + unsigned char herorank; + unsigned short strength; + unsigned short magic; + unsigned short dexterity; + unsigned short vitality; + int gold; + int hassaved; + int spawned; +}; + +// TPDEF PTR FCN UCHAR ENUMHEROPROC +// TPDEF PTR FCN UCHAR ENUMHEROS +// TPDEF PTR FCN UCHAR CREATEHERO +// TPDEF PTR FCN UCHAR DELETEHERO +// TPDEF PTR FCN UCHAR GETDEFHERO + +// TPDEF PTR FCN INT PROGRESSFCN + +////////////////////////////////////////////////// +// pack +////////////////////////////////////////////////// + +#pragma pack(push, 1) +struct PkItemStruct +{ + int iSeed; + short iCreateInfo; + short idx; + char bId; + char bDur; + char bMDur; + char bCh; + char bMCh; + short wValue; + int dwBuff; +}; + +struct PkPlayerStruct +{ + FILETIME archiveTime; + char destAction; + char destParam1; + char destParam2; + char plrlevel; + char px; + char py; + char targx; + char targy; + char pName[32]; + char pClass; + char pBaseStr; + char pBaseMag; + char pBaseDex; + char pBaseVit; + char pLevel; + char pStatPts; + int pExperience; + int pGold; + int pHPBase; + int pMaxHPBase; + int pManaBase; + int pMaxManaBase; + char pSplLvl[37]; + int pMemSpells; /* __int64 */ + int pMemSpells2; + PkItemStruct InvBody[7]; + PkItemStruct InvList[40]; + char InvGrid[40]; + char _pNumInv; + PkItemStruct SpdList[8]; + char pTownWarps; + char pDungMsgs; + char pLvlLoad; + char pBattleNet; + char pManaShield; + char bReserved[3]; + short wReserved[8]; + int pDiabloKillLevel; + int dwReserved[7]; +}; +#pragma pack(pop) + +////////////////////////////////////////////////// +// path +////////////////////////////////////////////////// + +struct PATHNODE +{ + char f; + char h; + short g; + int x; + int y; + struct PATHNODE *Parent; + struct PATHNODE *Child[8]; + struct PATHNODE *NextNode; +}; + +// TPDEF PTR FCN UCHAR CHECKFUNC1 + +// TPDEF PTR FCN UCHAR CHECKFUNC + +////////////////////////////////////////////////// +// sha +////////////////////////////////////////////////// + +struct SHA1Context +{ + int state[5]; + int count[2]; + char buffer[64]; +}; + +////////////////////////////////////////////////// +// tmsg +////////////////////////////////////////////////// + +#pragma pack(push, 1) +struct TMsg; + +struct TMsgHdr +{ + TMsg *pNext; + unsigned int dwTime; + unsigned char bLen; +}; + +struct TMsg +{ + TMsgHdr hdr; + unsigned char body[3]; +}; +#pragma pack(pop) + +////////////////////////////////////////////////// +// mpqapi +////////////////////////////////////////////////// + +struct _FILEHEADER +{ + int signature; + int headersize; + int filesize; + short version; + short sectorsizeid; + int hashoffset; + int blockoffset; + int hashcount; + int blockcount; + char pad[72]; +}; + +struct _HASHENTRY +{ + int hashcheck[2]; + int lcid; + int block; +}; + +struct _BLOCKENTRY +{ + int offset; + int sizealloc; + int sizefile; + int flags; +}; + +// TPDEF PTR FCN UCHAR TGetNameFcn + +// TPDEF PTR FCN VOID TCrypt + +////////////////////////////////////////////////// +// trigs +////////////////////////////////////////////////// + +struct TriggerStruct +{ + int _tx; + int _ty; + int _tmsg; + int _tlvl; +}; + +////////////////////////////////////////////////// +// stores +////////////////////////////////////////////////// + +struct STextStruct +{ + int _sx; + int _syoff; + char _sstr[128]; + int _sjust; + int _sclr; + int _sline; + int _ssel; + int _sval; +}; + +////////////////////////////////////////////////// +// wave +////////////////////////////////////////////////// + +struct MEMFILE +{ + int end; + int offset; + int buf_len; + int dist; + int bytes_to_read; + char *buf; + int file; +}; + +////////////////////////////////////////////////// +// plrmsg +////////////////////////////////////////////////// + +struct _plrmsg +{ + int time; + char player; + char str[144]; +}; + +////////////////////////////////////////////////// +// capture +////////////////////////////////////////////////// + +struct PCXHeader +{ + char manufacturer; + char version; + char encoding; + char bitsPerPixel; + short xmin, ymin; + short xmax, ymax; + short horzRes, vertRes; + char palette[48]; + char reserved; + char numColorPlanes; + short bytesPerScanLine; + short paletteType; + short horzSize, vertSize; + char padding[54]; +}; + +////////////////////////////////////////////////// +// encrypt +////////////////////////////////////////////////// + +struct TDataInfo +{ + unsigned char *pbInBuff; + unsigned char *pbInBuffEnd; + unsigned char *pbOutBuff; + unsigned char *pbOutBuffEnd; + unsigned char *pbSize; +}; + +////////////////////////////////////////////////// +// msgcmd +////////////////////////////////////////////////// + +struct ServerCommand +{ + int field_0; + int field_4; + char command[128]; +}; + +struct ChatCmd +{ + struct ChatCmd *next; + ServerCommand *extern_msgs[2]; +}; diff --git a/types.h b/types.h new file mode 100644 index 000000000..589dc78a8 --- /dev/null +++ b/types.h @@ -0,0 +1,140 @@ +// temporary file + +#ifndef _TYPES_H +#define _TYPES_H + + +#include "resource.h" + +#ifdef MINIWIN +#include "miniwin.h" +#include "sound.h" +#else +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#ifdef __GNUC__ +#include +#endif + +// tell Visual C++ to shut the hell up +#ifdef _MSC_VER +#pragma warning (disable : 4309) // truncation of constant value +#pragma warning (disable : 4305) // truncation of int +#pragma warning (disable : 4018) // signed/unsigned mismatch +#pragma warning (disable : 4700) // used without having been initialized +#pragma warning (disable : 4804) // unsafe use of type 'bool' in operation +#pragma warning (disable : 4805) // unsafe bool mix +#pragma warning (disable : 4244) // conversion loss +#pragma warning (disable : 4800) // bool perf +#pragma warning (disable : 4146) // negative unsigned +#endif + +#include "defs.h" +#include "enums.h" +#include "structs.h" + +#include "DiabloUI/diabloui.h" +#include "3rdParty/Storm/Source/storm.h" +#include "3rdParty/PKWare/pkware.h" + +// If defined, use copy protection [Default -> Defined] +//#define COPYPROT +// If defined, don't reload for debuggers [Default -> Undefined] +// Note that with patch 1.03 the command line was hosed, this is required to pass arguments to the game +#ifdef _DEBUG +#define DEBUGGER +#endif +// If defined, don't fry the CPU [Default -> Undefined] +#define SLEEP +// If defined, use standard memcpy() in place of qmemcpy() [Default -> Undefined] +// Will be replaced with [rep movsd] if optimization is used +#define FAST_MEMCPY + + +/* temp macro for asm XLAT */ +#define ASM_XLAT(eax,ebx) eax = (eax & 0xFFFFFF00) + LOBYTE(ebx[LOBYTE(eax)]) + +// header files +#include "Source/appfat.h" +#include "Source/automap.h" +#include "Source/capture.h" +#include "Source/codec.h" +#include "Source/control.h" +#include "Source/cursor.h" +#include "Source/dead.h" +#include "Source/debug.h" +#include "Source/diablo.h" +#include "Source/doom.h" +#include "Source/drlg_l1.h" +#include "Source/drlg_l2.h" +#include "Source/drlg_l3.h" +#include "Source/drlg_l4.h" +#include "Source/dthread.h" +#include "Source/dx.h" +#include "Source/effects.h" +#include "Source/encrypt.h" +#include "Source/engine.h" +#include "Source/error.h" +#include "Source/fault.h" +#include "Source/gamemenu.h" +#include "Source/gendung.h" +#include "Source/gmenu.h" +#include "Source/help.h" +#include "Source/init.h" +#include "Source/interfac.h" +#include "Source/inv.h" +#include "Source/items.h" +#include "Source/lighting.h" +#include "Source/loadsave.h" +#include "Source/logging.h" +#include "Source/mainmenu.h" +#include "Source/minitext.h" +#include "Source/missiles.h" +#include "Source/monster.h" +#include "Source/movie.h" +#include "Source/mpqapi.h" +#include "Source/msg.h" +#include "Source/msgcmd.h" +#include "Source/multi.h" +#include "Source/nthread.h" +#include "Source/objects.h" +#include "Source/pack.h" +#include "Source/palette.h" +#include "Source/path.h" +#include "Source/pfile.h" +#include "Source/player.h" +#include "Source/plrmsg.h" +#include "Source/portal.h" +#include "Source/quests.h" +#include "Source/restrict.h" +#include "Source/scrollrt.h" +#include "Source/setmaps.h" +#include "Source/sha.h" +#include "Source/sound.h" +#include "Source/spells.h" +#include "Source/stores.h" +#include "Source/sync.h" +#include "Source/textdat.h" // check file name +#include "Source/themes.h" +#include "Source/tmsg.h" +#include "Source/town.h" +#include "Source/towners.h" +#include "Source/track.h" +#include "Source/trigs.h" +#include "Source/wave.h" +#include "Source/render.h" // linked last, likely .s/.asm + +#endif