Repository: diasurgical/devilution Branch: master Commit: 9f0175724341 Files: 252 Total size: 4.1 MB Directory structure: gitextract_qfpcrvhg/ ├── .circleci/ │ ├── are-we-d1-yet.sh │ └── config.yml ├── .clang-format ├── .editorconfig ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ └── bug_report.md │ └── workflows/ │ └── build_mac.yml ├── .gitignore ├── 3rdParty/ │ ├── PKWare/ │ │ ├── Makefile │ │ ├── PKWare.vcxproj │ │ ├── PKWare.vcxproj.filters │ │ ├── Pkware.dsp │ │ ├── explode.cpp │ │ ├── implode.cpp │ │ └── pkware.h │ └── Storm/ │ ├── Makefile │ └── Source/ │ ├── Storm.dsp │ ├── Storm.vcxproj │ ├── storm.cpp │ ├── storm.def │ ├── storm.h │ └── storm_gcc.def ├── Diablo.dsp ├── Diablo.dsw ├── Diablo.rc ├── Diablo.sln ├── Diablo.vcxproj ├── Diablo.vcxproj.filters ├── DiabloUI/ │ ├── DiabloUI.dsp │ ├── DiabloUI.vcxproj │ ├── Makefile │ ├── _temp_data.cpp │ ├── _temp_funcs.h │ ├── artfont.cpp │ ├── bn_prof.cpp │ ├── bnetgw.cpp │ ├── connect.cpp │ ├── copyprot.cpp │ ├── cr8game.cpp │ ├── creadung.cpp │ ├── creastat.cpp │ ├── credits.cpp │ ├── diabedit.cpp │ ├── diabloui.cpp │ ├── diabloui.def │ ├── diabloui.h │ ├── diabloui_gcc.def │ ├── dirlink.cpp │ ├── disclaim.cpp │ ├── doom.cpp │ ├── entdial.cpp │ ├── entname.cpp │ ├── fade.cpp │ ├── focus.cpp │ ├── local.cpp │ ├── mainmenu.cpp │ ├── modem.cpp │ ├── modmstat.cpp │ ├── okcancel.cpp │ ├── progress.cpp │ ├── sbar.cpp │ ├── selclass.cpp │ ├── selconn.cpp │ ├── seldial.cpp │ ├── selgame.cpp │ ├── selhero.cpp │ ├── selipx.cpp │ ├── sellist.cpp │ ├── selload.cpp │ ├── selmodem.cpp │ ├── selregn.cpp │ ├── selyesno.cpp │ ├── title.cpp │ └── titlesnd.cpp ├── Hellfire.dsp ├── Hellfire.dsw ├── Hellfire.rc ├── LICENSE.md ├── Makefile ├── MakefileVC ├── README.md ├── Source/ │ ├── .clang-format │ ├── _asm.cpp │ ├── _render.cpp │ ├── all.h │ ├── appfat.cpp │ ├── appfat.h │ ├── asm_trans_rect.inc │ ├── automap.cpp │ ├── automap.h │ ├── capture.cpp │ ├── capture.h │ ├── codec.cpp │ ├── codec.h │ ├── control.cpp │ ├── control.h │ ├── cursor.cpp │ ├── cursor.h │ ├── dead.cpp │ ├── dead.h │ ├── debug.cpp │ ├── debug.h │ ├── diablo.cpp │ ├── diablo.h │ ├── doom.cpp │ ├── doom.h │ ├── drlg_l1.cpp │ ├── drlg_l1.h │ ├── drlg_l2.cpp │ ├── drlg_l2.h │ ├── drlg_l3.cpp │ ├── drlg_l3.h │ ├── drlg_l4.cpp │ ├── drlg_l4.h │ ├── dthread.cpp │ ├── dthread.h │ ├── dx.cpp │ ├── dx.h │ ├── effects.cpp │ ├── effects.h │ ├── encrypt.cpp │ ├── encrypt.h │ ├── engine.cpp │ ├── engine.h │ ├── error.cpp │ ├── error.h │ ├── fault.cpp │ ├── fault.h │ ├── gamemenu.cpp │ ├── gamemenu.h │ ├── gendung.cpp │ ├── gendung.h │ ├── gmenu.cpp │ ├── gmenu.h │ ├── help.cpp │ ├── help.h │ ├── init.cpp │ ├── init.h │ ├── interfac.cpp │ ├── interfac.h │ ├── inv.cpp │ ├── inv.h │ ├── itemdat.cpp │ ├── itemdat.h │ ├── items.cpp │ ├── items.h │ ├── lighting.cpp │ ├── lighting.h │ ├── list.h │ ├── loadsave.cpp │ ├── loadsave.h │ ├── logging.cpp │ ├── logging.h │ ├── mainmenu.cpp │ ├── mainmenu.h │ ├── minitext.cpp │ ├── minitext.h │ ├── misdat.cpp │ ├── misdat.h │ ├── missiles.cpp │ ├── missiles.h │ ├── monstdat.cpp │ ├── monstdat.h │ ├── monster.cpp │ ├── monster.h │ ├── movie.cpp │ ├── movie.h │ ├── mpqapi.cpp │ ├── mpqapi.h │ ├── msg.cpp │ ├── msg.h │ ├── msgcmd.cpp │ ├── msgcmd.h │ ├── multi.cpp │ ├── multi.h │ ├── nthread.cpp │ ├── nthread.h │ ├── objdat.cpp │ ├── objdat.h │ ├── objects.cpp │ ├── objects.h │ ├── pack.cpp │ ├── pack.h │ ├── palette.cpp │ ├── palette.h │ ├── path.cpp │ ├── path.h │ ├── pfile.cpp │ ├── pfile.h │ ├── player.cpp │ ├── player.h │ ├── plrmsg.cpp │ ├── plrmsg.h │ ├── portal.cpp │ ├── portal.h │ ├── quests.cpp │ ├── quests.h │ ├── render.cpp │ ├── render.h │ ├── restrict.cpp │ ├── restrict.h │ ├── scrollrt.cpp │ ├── scrollrt.h │ ├── setmaps.cpp │ ├── setmaps.h │ ├── sha.cpp │ ├── sha.h │ ├── sound.cpp │ ├── sound.h │ ├── spelldat.cpp │ ├── spelldat.h │ ├── spells.cpp │ ├── spells.h │ ├── stores.cpp │ ├── stores.h │ ├── sync.cpp │ ├── sync.h │ ├── textdat.cpp │ ├── textdat.h │ ├── themes.cpp │ ├── themes.h │ ├── tmsg.cpp │ ├── tmsg.h │ ├── town.cpp │ ├── town.h │ ├── towners.cpp │ ├── towners.h │ ├── track.cpp │ ├── track.h │ ├── trigs.cpp │ ├── trigs.h │ ├── wave.cpp │ └── wave.h ├── appveyor.yml ├── comparer-config/ │ ├── diablo.toml │ ├── hellfire.toml │ └── spawn.toml ├── defs.h ├── docs/ │ ├── BACKGROUND.md │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ ├── INSTALL_linux.md │ ├── INSTALL_mac.md │ ├── INSTALL_windows.md │ ├── TODO.md │ ├── compatibility_matrix.md │ ├── debug.md │ └── troubleshooting.md ├── doxygen.config ├── enums.h ├── resource.h ├── structs.h └── types.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .circleci/are-we-d1-yet.sh ================================================ #!/bin/bash # based on https://github.com/k3rn31p4nic/travis-ci-discord-webhook # Only run for commits/builds on master, not for PRs for now if [[ "$CIRCLE_BRANCH" != "master" ]]; then exit fi # Webhook URL missing, do nothing if [ -z "$2" ]; then exit fi echo -e "[Webhook]: Sending webhook to Discord...\\n"; AUTHOR_NAME="$(git log -1 "$CIRCLE_SHA1" --pretty="%aN")" COMMITTER_NAME="$(git log -1 "$CIRCLE_SHA1" --pretty="%cN")" COMMIT_SUBJECT="$(git log -1 "$CIRCLE_SHA1" --pretty="%s")" COMMIT_MESSAGE="$(git log -1 "$CIRCLE_SHA1" --pretty="%b")" if [ "$AUTHOR_NAME" == "$COMMITTER_NAME" ]; then CREDITS="$AUTHOR_NAME authored & committed" else CREDITS="$AUTHOR_NAME authored & $COMMITTER_NAME committed" fi TIMESTAMP=$(date --utc +%FT%TZ) WEBHOOK_DATA='{ "avatar_url": "https://www.saaves.com/storage/brochure/logo-circleci-icon1583764538.png", "embeds": [ { "author": { "name": "'"$3"' (Build #'"$CIRCLE_BUILD_NUM"')", "url": "'"$CIRCLE_BUILD_URL"'", "icon_url": "https://www.saaves.com/storage/brochure/logo-circleci-icon1583764538.png" }, "title": "['"\`${CIRCLE_SHA1:0:7}\`"'] '"$COMMIT_SUBJECT"'", "url": "'"https://github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/commit/$CIRCLE_SHA1"'", "description": "'"$CREDITS"'", "fields": [ { "name": "Binary accuracy", "value": "'"$1"'", "inline": true } ], "timestamp": "'"$TIMESTAMP"'" } ] }' (curl --fail --progress-bar -A "TravisCI-Webhook" -H Content-Type:application/json -H X-Author:diasurgical -d "$WEBHOOK_DATA" "$2" \ && echo -e "\\n[Webhook]: Successfully sent the webhook.") || echo -e "\\n[Webhook]: Unable to send webhook." ================================================ FILE: .circleci/config.yml ================================================ version: 2 jobs: diablo_109b: docker: - image: diasurgical/riivaaja:stable steps: - checkout - run: make -f MakefileVC diablo_109b_diff: machine: true steps: - checkout - run: | set -e wget https://github.com/diasurgical/devilution-comparer/releases/download/v0.4.0/devilution-comparer-v0.4.0-x86_64-unknown-linux-gnu.tar.xz tar xf devilution-comparer-v0.4.0-x86_64-unknown-linux-gnu.tar.xz mv comparer-config/diablo.toml comparer-config.toml echo '#!/bin/sh' | sudo tee /bin/wine echo 'docker run -v $(pwd):/root/devilution --entrypoint "/usr/bin/wine" diasurgical/riivaaja:stable $(basename $1) $2 $3' | sudo tee --append /bin/wine sudo chmod +x /bin/wine docker run -v $(pwd):/root/devilution -e MAKE_BUILD=pdb diasurgical/riivaaja:stable ./devilution-comparer generate-full Diablo.exe --no-mem-disp --truncate-to-original docker run -v $(pwd):/root/devilution diasurgical/riivaaja:stable ../status.sh .circleci/are-we-d1-yet.sh "$(< accuracy.txt)" $DISCORD_WEBHOOK "Diablo 1.09b" spawn_109b_diff: machine: true steps: - checkout - run: | set -e wget https://github.com/diasurgical/devilution-comparer/releases/download/v0.4.0/devilution-comparer-v0.4.0-x86_64-unknown-linux-gnu.tar.xz tar xf devilution-comparer-v0.4.0-x86_64-unknown-linux-gnu.tar.xz mv comparer-config/spawn.toml comparer-config.toml echo '#!/bin/sh' | sudo tee /bin/wine echo 'docker run -v $(pwd):/root/devilution --entrypoint "/usr/bin/wine" diasurgical/riivaaja:stable $(basename $1) $2 $3' | sudo tee --append /bin/wine sudo chmod +x /bin/wine docker run -v $(pwd):/root/devilution -e MAKE_BUILD=pdb -e SPAWN=1 diasurgical/riivaaja:stable ./devilution-comparer generate-full Diablo.exe --no-mem-disp --truncate-to-original docker run -v $(pwd):/root/devilution diasurgical/riivaaja:stable ../spawn-status.sh .circleci/are-we-d1-yet.sh "$(< accuracy.txt)" $DISCORD_WEBHOOK "Spawn 1.09b" hellfire_101_diff: machine: true steps: - checkout - run: | set -e wget https://github.com/diasurgical/devilution-comparer/releases/download/v0.4.0/devilution-comparer-v0.4.0-x86_64-unknown-linux-gnu.tar.xz tar xf devilution-comparer-v0.4.0-x86_64-unknown-linux-gnu.tar.xz mv comparer-config/hellfire.toml comparer-config.toml echo '#!/bin/sh' | sudo tee /bin/wine echo 'docker run -v $(pwd):/root/devilution --entrypoint "/usr/bin/wine" diasurgical/riivaaja:stable $(basename $1) $2 $3' | sudo tee --append /bin/wine sudo chmod +x /bin/wine docker run -v $(pwd):/root/devilution -e MAKE_BUILD=pdb -e HELLFIRE=1 diasurgical/riivaaja:stable dd if=/dev/zero bs=1 count=3072 of=hellfire.exe dd if=Diablo.exe >> hellfire.exe ./devilution-comparer generate-full hellfire.exe --no-mem-disp --truncate-to-original docker run -v $(pwd):/root/devilution diasurgical/riivaaja:stable ../hellfire-status.sh .circleci/are-we-d1-yet.sh "$(< accuracy.txt)" $DISCORD_WEBHOOK "Hellfire 1.01" linux: docker: - image: debian:stretch-backports steps: - checkout - run: apt-get update -y - run: apt-get install -y mingw-w64 make - run: make -j2 - run: make clean - run: make debug -j2 workflows: version: 2 testflow: jobs: - diablo_109b - diablo_109b_diff - spawn_109b_diff - hellfire_101_diff - linux ================================================ FILE: .clang-format ================================================ BasedOnStyle: webkit AlignTrailingComments: true AllowShortBlocksOnASingleLine: true AllowShortFunctionsOnASingleLine: None PointerAlignment: Right AlignConsecutiveAssignments: true TabWidth: 4 UseTab: ForIndentation SortIncludes: false ================================================ FILE: .editorconfig ================================================ root = true [*] indent_style = tab end_of_line = crlf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.sh] end_of_line = lf ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- Before creating a bug report, please note that this bug tracker is only intended for the original devilution project, which is binary exact function-wise. Please report bugs in ports of devilution in their respective repositories: [Browser port](https://github.com/d07RiV/diabloweb/issues), [Crossplatform port](https://github.com/diasurgical/devilutionX/issues) **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Additional context** Add any other context about the problem here. ================================================ FILE: .github/workflows/build_mac.yml ================================================ name: macOS Build on: push: branches: - master pull_request: jobs: xcode: runs-on: macos-11 steps: - uses: actions/checkout@v2 - name: Install dependencies run: brew install mingw-w64 - name: Build run: make -j8 ================================================ FILE: .gitignore ================================================ # Generated by VC++ 6 builds /vc60.idb *.asm *.idb # macOS .DS_Store # CodeLite .CodeLite *.project *.workspace # Devilution Comparer devilution-comparer comparer-config.toml # 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 /docs/html/ # MPQ files *.mpq # ddraw wrapper configuration file ddraw_settings.ini ================================================ FILE: 3rdParty/PKWare/Makefile ================================================ 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 copied to the # $(VS6_DIR)/VC98/Bin directory. # # - $(VS6_DIR)/Common/MSDev98/Bin/MSPDB60.DLL # # And to the $(VC5_DIR)/bin directory. # # - $(VC5_DIR)/SharedIDE/bin/MSDIS100.DLL # - $(VC5_DIR)/SharedIDE/bin/MSPDB50.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" /YX /Gm /Zi LINKFLAGS=/nologo /subsystem:windows /machine:I386 /incremental:no VC_LINK=$(VC5_LINK) LINKFLAGS+= /LIBPATH:$(VC5_LIB_DIR) all: pkware.lib PKWARE_SRC=$(sort $(wildcard *.cpp)) PKWARE_OBJS=$(PKWARE_SRC:.cpp=.obj) pkware.lib: $(PKWARE_OBJS) $(VC_LINK) -lib /OUT:$@ $^ /nologo %.obj: %.cpp $(CL) $(CFLAGS) /Fo$@ $< clean: @$(RM) -v $(PKWARE_OBJS) pkware.lib vc60.{idb,pch,pdb} .PHONY: clean all ================================================ FILE: 3rdParty/PKWare/PKWare.vcxproj ================================================ Debug Win32 Release Win32 15.0 {C7F9F3B4-2F7C-4672-9586-94D8BA0950B6} Win32Proj PKWare 10.0.17763.0 StaticLibrary true v141 Unicode StaticLibrary false v141 true Unicode true .\WinDebug\ .\WinDebug\ false .\WinRel .\WinRel NotUsing Level3 Disabled true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true MultiThreadedDebug Windows true NotUsing Level3 MaxSpeed true true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true MultiThreaded Windows true true true ================================================ FILE: 3rdParty/PKWare/PKWare.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Source Files Header Files ================================================ FILE: 3rdParty/PKWare/Pkware.dsp ================================================ # Microsoft Developer Studio Project File - Name="Pkware" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Static Library" 0x0104 CFG=Pkware - 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 "Pkware.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 "Pkware.mak" CFG="Pkware - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "Pkware - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "Pkware - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "Pkware - 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ELSEIF "$(CFG)" == "Pkware - 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ENDIF # Begin Target # Name "Pkware - Win32 Release" # Name "Pkware - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\explode.cpp # End Source File # Begin Source File SOURCE=.\implode.cpp # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # End Target # End Project ================================================ FILE: 3rdParty/PKWare/explode.cpp ================================================ /*****************************************************************************/ /* 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 PKWAREAPI 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 PKWAREAPI 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 PKWAREAPI 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 PKWAREAPI 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 PKWAREAPI 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 PKWAREAPI 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 PKWAREAPI explode( unsigned int (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param), void (PKWAREAPI *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; } ================================================ FILE: 3rdParty/PKWare/implode.cpp ================================================ /*****************************************************************************/ /* 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 PKWAREAPI 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 PKWAREAPI 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 PKWAREAPI 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 PKWAREAPI 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 PKWAREAPI 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 PKWAREAPI implode( unsigned int (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param), void (PKWAREAPI *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; } ================================================ FILE: 3rdParty/PKWare/pkware.h ================================================ /*****************************************************************************/ /* 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 PKWAREAPI #ifdef WIN32 #define PKWAREAPI __cdecl // Use for normal __cdecl calling #else #define PKWAREAPI #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 (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param); // 9B4 void (PKWAREAPI *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 (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param); // Pointer to function that reads data from the input stream void (PKWAREAPI *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 PKWAREAPI implode( unsigned int (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param), void (PKWAREAPI *write_buf)(char *buf, unsigned int *size, void *param), char *work_buf, void *param, unsigned int *type, unsigned int *dsize); unsigned int PKWAREAPI explode( unsigned int (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param), void (PKWAREAPI *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__ ================================================ FILE: 3rdParty/Storm/Makefile ================================================ 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 copied to the # $(VS6_DIR)/VC98/Bin directory. # # - $(VS6_DIR)/Common/MSDev98/Bin/MSPDB60.DLL # # And to the $(VC5_DIR)/bin directory. # # - $(VC5_DIR)/SharedIDE/bin/MSDIS100.DLL # - $(VC5_DIR)/SharedIDE/bin/MSPDB50.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" /YX /Gm /Zi LINKFLAGS=/nologo /subsystem:windows /machine:I386 /incremental:no VC_LINK=$(VC5_LINK) LINKFLAGS+= /LIBPATH:$(VC5_LIB_DIR) all: storm.lib STORM_SRC=$(sort $(wildcard Source/*.cpp)) STORM_OBJS=$(STORM_SRC:.cpp=.obj) storm.lib: $(STORM_OBJS) $(CL) $^ /link /LINK50COMPAT /nologo /dll /subsystem:windows /machine:I386 /LIBPATH:$(VC6_LIB_DIR) /def:"Source/storm.def" /out:storm.dll %.obj: %.cpp $(CL) $(CFLAGS) /Fo$@ $< clean: @$(RM) -v $(STORM_OBJS) storm.{exp,lib,dll} vc60.{idb,pch,pdb} .PHONY: clean all ================================================ FILE: 3rdParty/Storm/Source/Storm.dsp ================================================ # 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 ================================================ FILE: 3rdParty/Storm/Source/Storm.vcxproj ================================================ 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) ================================================ FILE: 3rdParty/Storm/Source/storm.cpp ================================================ #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, const char *creatorName, const char *a11, int *playerID) rBool; BOOL STORMAPI SNetDestroy() 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, DWORD *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 SDlgBltToWindowI(HWND hWnd, HRGN a2, char *a3, int a4, void *buffer, RECT *rct, SIZE *size, int a8, int a9, DWORD rop) 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 hFile, DWORD flags, DWORD mask, unsigned __int32 lDistanceToMove, signed __int32 volume, signed int a6, int a7) rBool; BOOL STORMAPI SFileDdaDestroy() rBool; BOOL STORMAPI SFileDdaEnd(HANDLE hFile) rBool; BOOL STORMAPI SFileDdaGetPos(HANDLE hFile, DWORD *current, DWORD *end) rBool; BOOL STORMAPI SFileDdaInitialize(HANDLE directsound) rBool; BOOL STORMAPI SFileDdaSetVolume(HANDLE hFile, 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 SBltROP3Tiled(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, BYTE *pBuffer, DWORD dwBuffersize, DWORD *pdwWidth, DWORD *pdwHeight, 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, const char *logfilename, int logline, int defaultValue) rPVoid; BOOL STORMAPI SMemFree(void *location, const char *logfilename, int logline, char defaultValue) rBool; void* STORMAPI SMemReAlloc(void *location, size_t amount, const 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 STransCreateI(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(const char *filename, int a2, int a3, int a4, int a5, int flags, 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 SStrPack(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(const char *,const char *,int) rVoid; void __cdecl SDrawDestroy(void) rVoid; BOOLEAN __cdecl StormDestroy(void) rBool; BOOL __stdcall SFileSetBasePath(const char *) rBool; void __cdecl SDrawRealizePalette(void) rVoid; BOOL __cdecl SVidPlayContinue(void) rBool; BOOL __stdcall SNetGetOwnerTurnsWaiting(DWORD *) rBool; BOOL __stdcall SNetUnregisterEventHandler(int,SEVTHANDLER) rPVoid; BOOL __stdcall SNetRegisterEventHandler(int,SEVTHANDLER) rPVoid; BOOLEAN __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; void __stdcall SDrawClearSurface(int a1) rVoid; BOOL __stdcall SDlgSetBitmapI(HWND hWnd, int a2, char *src, int mask1, int flags, void *pBuff, int a7, int width, int height, int mask2) rBool; void __stdcall SDlgBeginPaint(HWND hWnd, char *a2) rVoid; void __stdcall SDlgEndPaint(HWND hWnd, char *a2) rVoid; void __stdcall SDlgSetSystemCursor(BYTE *a1, BYTE *a2, int *a3, int a4) rVoid; void __stdcall SDlgSetCursor(HWND hWnd, HCURSOR a2, int a3, int *a4) rVoid; BOOL __stdcall SDlgSetTimer(int a1, int a2, int a3, void (__stdcall *a4)(int, int, int, int)) rBool; BOOL __stdcall SDlgKillTimer(int a1, int a2) rBool; BOOL __stdcall SDlgDrawBitmap(HWND hWnd, int a2, int a3, int a4, int a5, int a6, int a7) rBool; BOOL __stdcall SDlgDialogBoxParam(HINSTANCE hInst, char *szDialog, int hWnd, WNDPROC func, int selhero_is_good) rBool; BOOL __stdcall SGdiTextOut(void *pBuffer, int x, int y, int mask, char *str, int len) rBool; BOOL __stdcall SFileEnableDirectAccess(BOOL enable) rBool; ================================================ FILE: 3rdParty/Storm/Source/storm.def ================================================ LIBRARY "Storm" EXPORTS SNetCreateGame @101 NONAME SNetDestroy @102 NONAME ;SNetEnumDevices @103 NONAME ;SNetEnumGames @104 NONAME ;SNetEnumProviders @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 SStrPack @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 ================================================ FILE: 3rdParty/Storm/Source/storm.h ================================================ #pragma once #ifndef __BLIZZARD_STORM_HEADER #define __BLIZZARD_STORM_HEADER #include #include #include #include #include // 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; #ifdef __cplusplus static float infinity = std::numeric_limits::infinity(); struct CCritSect { CRITICAL_SECTION m_critsect; CCritSect() { InitializeCriticalSection(&m_critsect); } ~CCritSect() { DeleteCriticalSection(&m_critsect); } void Enter() { EnterCriticalSection(&m_critsect); } void Leave() { LeaveCriticalSection(&m_critsect); } }; #endif // Game states #define GAMESTATE_PRIVATE 0x01 #define GAMESTATE_FULL 0x02 #define GAMESTATE_ACTIVE 0x04 #define GAMESTATE_STARTED 0x08 #define GAMESTATE_REPLAY 0x80 #define PS_CONNECTED 0x10000 #define PS_TURN_ARRIVED 0x20000 #define PS_ACTIVE 0x40000 #define LEAVE_ENDING 0x40000004 #define LEAVE_DROP 0x40000006 #if defined(__GNUC__) || defined(__cplusplus) extern "C" { #endif BOOL STORMAPI SNetCreateGame(const char *pszGameName, const char *pszGamePassword, const char *pszGameStatString, DWORD dwGameType, char *GameTemplateData, int GameTemplateSize, int playerCount, const char *creatorName, const char *a11, int *playerID); BOOL STORMAPI SNetDestroy(); /* 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, unsigned int length, unsigned int *byteswritten); #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, unsigned int 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]; struct _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, DWORD *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; typedef void (STORMAPI *SEVTHANDLER)(struct _SNETEVENT *); // @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, unsigned int 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, unsigned int 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, BOOLEAN makePublic); #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, unsigned int 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 SDlgBltToWindowI(HWND hWnd, HRGN a2, char *a3, int a4, void *buffer, RECT *rct, SIZE *size, int a8, int a9, DWORD rop); 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 hFile, DWORD flags, DWORD mask, unsigned __int32 lDistanceToMove, signed __int32 volume, signed int pan, int a7); BOOL STORMAPI SFileDdaDestroy(); BOOL STORMAPI SFileDdaEnd(HANDLE hFile); BOOL STORMAPI SFileDdaGetPos(HANDLE hFile, DWORD *current, DWORD *end); BOOL STORMAPI SFileDdaInitialize(HANDLE directsound); BOOL STORMAPI SFileDdaSetVolume(HANDLE hFile, 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, unsigned int *pSize); //BOOL STORMAPI StormSetOption(int type, void *pValue, unsigned int 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); BOOL STORMAPI SBltROP3Tiled(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, void *pDstBuffer, DWORD dwDstBuffersize, DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwBpp); /* 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 , BYTE *pBuffer, DWORD dwBuffersize, DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwBpp); /* 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); 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); /* 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 , LPDIRECTDRAWSURFACE *primarySurface, LPDIRECTDRAWSURFACE *surface2, LPDIRECTDRAWSURFACE *surface3, LPDIRECTDRAWSURFACE *backSurface , LPDIRECTDRAWPALETTE *ddPalette, HPALETTE *hPalette); /* 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, LPDIRECTDRAW ddInterface, LPDIRECTDRAWSURFACE primarySurface, LPDIRECTDRAWSURFACE surface2, LPDIRECTDRAWSURFACE surface3, LPDIRECTDRAWSURFACE backSurface, LPDIRECTDRAWPALETTE ddPalette, HPALETTE hPalette); /* 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( unsigned int amount, const char *logfilename, int logline, int defaultValue); #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, const char *logfilename, int logline, char defaultValue); #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, unsigned int amount, const char *logfilename, int logline, char defaultValue); #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, unsigned int 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 STransCreateI(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(const char *filename, int a2, int a3, int a4, int a5, int flags, 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, BOOL allowOption, int exitCode); #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, unsigned int 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); // // 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, unsigned int 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, unsigned int length, char fillWith); #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, unsigned int 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); #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, DWORD Seed); int STORMAPI SStrPack(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, unsigned int 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, unsigned int 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 __cdecl 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. */ unsigned int __cdecl SStrVPrintf( char *dest, unsigned int size, const char *format, ...); int STORMAPI SBigDel(void *buffer); int STORMAPI SBigFromBinary(void *buffer, const void *str, unsigned int 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(const char *,const char *,int); void __cdecl SDrawDestroy(void); BOOLEAN __cdecl StormDestroy(void); BOOL __stdcall SFileSetBasePath(const char *); void __cdecl SDrawRealizePalette(void); BOOL __cdecl SVidPlayContinue(void); BOOL __stdcall SNetGetOwnerTurnsWaiting(DWORD *); BOOL __stdcall SNetUnregisterEventHandler(int,SEVTHANDLER); BOOL __stdcall SNetRegisterEventHandler(int,SEVTHANDLER); BOOLEAN __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); void __stdcall SDrawClearSurface(int a1); BOOL __stdcall SDlgSetBitmapI(HWND hWnd, int a2, char *src, int mask1, int flags, void *pBuff, int a7, int width, int height, int mask2); void __stdcall SDlgBeginPaint(HWND hWnd, char *a2); void __stdcall SDlgEndPaint(HWND hWnd, char *a2); void __stdcall SDlgSetSystemCursor(BYTE *a1, BYTE *a2, int *a3, int a4); void __stdcall SDlgSetCursor(HWND hWnd, HCURSOR a2, int a3, int *a4); BOOL __stdcall SDlgSetTimer(int a1, int a2, int a3, void (__stdcall *a4)(int, int, int, int)); BOOL __stdcall SDlgKillTimer(int a1, int a2); BOOL __stdcall SDlgDrawBitmap(HWND hWnd, int a2, int a3, int a4, int a5, int a6, int a7); BOOL __stdcall SDlgDialogBoxParam(HINSTANCE hInst, char *szDialog, int hWnd, WNDPROC func, int selhero_is_good); BOOL __stdcall SGdiTextOut(void *pBuffer, int x, int y, int mask, char *str, int len); BOOL __stdcall SFileEnableDirectAccess(BOOL enable); #if defined(__GNUC__) || defined(__cplusplus) } #endif #endif ================================================ FILE: 3rdParty/Storm/Source/storm_gcc.def ================================================ LIBRARY "Storm" EXPORTS SNetCreateGame @101 NONAME SNetCreateGame@40 @101 NONAME SNetDestroy @102 NONAME SNetDestroy@0 @102 NONAME ;SNetEnumDevices @103 NONAME ;SNetEnumGames @104 NONAME ;SNetEnumProviders @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 SDlgBeginPaint@8 @201 NONAME SDlgBltToWindowI @202 NONAME SDlgBltToWindowI@40 @202 NONAME ;SDlgCheckTimers @203 NONAME ;SDlgCreateDialogIndirectParam @204 NONAME ;SDlgCreateDialogParam @205 NONAME SDlgDefDialogProc @206 NONAME SDlgDefDialogProc@16 @206 NONAME SDlgDialogBoxIndirectParam @208 NONAME SDlgDialogBoxParam @209 NONAME SDlgDialogBoxParam@20 @209 NONAME SDlgDrawBitmap @210 NONAME SDlgDrawBitmap@28 @210 NONAME SDlgEndDialog @211 NONAME SDlgEndDialog@8 @211 NONAME SDlgEndPaint @212 NONAME SDlgEndPaint@8 @212 NONAME SDlgKillTimer @213 NONAME SDlgKillTimer@8 @213 NONAME ;SDlgSetBaseFont @214 NONAME SDlgSetBitmapI @215 NONAME SDlgSetBitmapI@40 @215 NONAME SDlgSetControlBitmaps @216 NONAME SDlgSetControlBitmaps@28 @216 NONAME SDlgSetCursor @217 NONAME SDlgSetCursor@16 @217 NONAME SDlgSetSystemCursor @218 NONAME SDlgSetSystemCursor@16 @218 NONAME SDlgSetTimer @219 NONAME SDlgSetTimer@16 @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 SFileEnableDirectAccess@4 @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 SBltROP3@32 @313 NONAME SBltROP3Clipped @314 NONAME SBltROP3Tiled @315 NONAME SBltROP3Tiled@40 @315 NONAME SBmpDecodeImage @321 NONAME SBmpLoadImage @323 NONAME SBmpLoadImage@28 @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 SDrawClearSurface@4 @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 SGdiDeleteObject@4 @383 NONAME ;SGdiDestroy @384 NONAME SGdiExtTextOut @385 NONAME SGdiImportFont @386 NONAME SGdiImportFont@8 @386 NONAME ;SGdiLoadFont @387 NONAME ;SGdiRectangle @388 NONAME SGdiSelectObject @389 NONAME SGdiSelectObject@4 @389 NONAME SGdiSetPitch @390 NONAME SGdiSetPitch@4 @390 NONAME SGdiTextOut @391 NONAME SGdiTextOut@24 @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 STransBlt@20 @431 NONAME STransBltUsingMask @432 NONAME STransCreateI @433 NONAME STransCreateI@28 @433 NONAME STransDelete @434 NONAME STransDelete@4 @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 SStrPack @503 NONAME SStrPack@12 @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 ================================================ FILE: Diablo.dsp ================================================ # 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 /Gr /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 /machine:I386 # ADD LINK32 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c # ADD CPP /nologo /Gr /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 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 /Gr /MT /W3 /GX /Zi /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FAs /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 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 3rdParty/PKWare/WinRel/pkware.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\itemdat.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\misdat.cpp # End Source File # Begin Source File SOURCE=.\Source\missiles.cpp # End Source File # Begin Source File SOURCE=.\Source\monstdat.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\objdat.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\spelldat.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=.\defs.h # End Source File # Begin Source File SOURCE=.\enums.h # End Source File # Begin Source File SOURCE=.\structs.h # End Source File # Begin Source File SOURCE=.\types.h # End Source File # Begin Source File SOURCE=.\Source\appfat.h # End Source File # Begin Source File SOURCE=.\Source\automap.h # End Source File # Begin Source File SOURCE=.\Source\capture.h # End Source File # Begin Source File SOURCE=.\Source\codec.h # End Source File # Begin Source File SOURCE=.\Source\control.h # End Source File # Begin Source File SOURCE=.\Source\cursor.h # End Source File # Begin Source File SOURCE=.\Source\dead.h # End Source File # Begin Source File SOURCE=.\Source\debug.h # End Source File # Begin Source File SOURCE=.\Source\diablo.h # End Source File # Begin Source File SOURCE=.\Source\doom.h # End Source File # Begin Source File SOURCE=.\Source\drlg_l1.h # End Source File # Begin Source File SOURCE=.\Source\drlg_l2.h # End Source File # Begin Source File SOURCE=.\Source\drlg_l3.h # End Source File # Begin Source File SOURCE=.\Source\drlg_l4.h # End Source File # Begin Source File SOURCE=.\Source\dthread.h # End Source File # Begin Source File SOURCE=.\Source\dx.h # End Source File # Begin Source File SOURCE=.\Source\effects.h # End Source File # Begin Source File SOURCE=.\Source\encrypt.h # End Source File # Begin Source File SOURCE=.\Source\engine.h # End Source File # Begin Source File SOURCE=.\Source\error.h # End Source File # Begin Source File SOURCE=.\Source\fault.h # End Source File # Begin Source File SOURCE=.\Source\gamemenu.h # End Source File # Begin Source File SOURCE=.\Source\gendung.h # End Source File # Begin Source File SOURCE=.\Source\gmenu.h # End Source File # Begin Source File SOURCE=.\Source\help.h # End Source File # Begin Source File SOURCE=.\Source\init.h # End Source File # Begin Source File SOURCE=.\Source\interfac.h # End Source File # Begin Source File SOURCE=.\Source\inv.h # End Source File # Begin Source File SOURCE=.\Source\items.h # End Source File # Begin Source File SOURCE=.\Source\lighting.h # End Source File # Begin Source File SOURCE=.\Source\loadsave.h # End Source File # Begin Source File SOURCE=.\Source\logging.h # End Source File # Begin Source File SOURCE=.\Source\mainmenu.h # End Source File # Begin Source File SOURCE=.\Source\minitext.h # End Source File # Begin Source File SOURCE=.\Source\missiles.h # End Source File # Begin Source File SOURCE=.\Source\monster.h # End Source File # Begin Source File SOURCE=.\Source\movie.h # End Source File # Begin Source File SOURCE=.\Source\mpqapi.h # End Source File # Begin Source File SOURCE=.\Source\msg.h # End Source File # Begin Source File SOURCE=.\Source\msgcmd.h # End Source File # Begin Source File SOURCE=.\Source\multi.h # End Source File # Begin Source File SOURCE=.\Source\nthread.h # End Source File # Begin Source File SOURCE=.\Source\objects.h # End Source File # Begin Source File SOURCE=.\Source\pack.h # End Source File # Begin Source File SOURCE=.\Source\palette.h # End Source File # Begin Source File SOURCE=.\Source\path.h # End Source File # Begin Source File SOURCE=.\Source\pfile.h # End Source File # Begin Source File SOURCE=.\Source\player.h # End Source File # Begin Source File SOURCE=.\Source\plrmsg.h # End Source File # Begin Source File SOURCE=.\Source\portal.h # End Source File # Begin Source File SOURCE=.\Source\quests.h # End Source File # Begin Source File SOURCE=.\Source\render.h # End Source File # Begin Source File SOURCE=.\Source\restrict.h # End Source File # Begin Source File SOURCE=.\Source\scrollrt.h # End Source File # Begin Source File SOURCE=.\Source\setmaps.h # End Source File # Begin Source File SOURCE=.\Source\sha.h # End Source File # Begin Source File SOURCE=.\Source\sound.h # End Source File # Begin Source File SOURCE=.\Source\spells.h # End Source File # Begin Source File SOURCE=.\Source\stores.h # End Source File # Begin Source File SOURCE=.\Source\sync.h # End Source File # Begin Source File SOURCE=.\Source\textdat.h # End Source File # Begin Source File SOURCE=.\Source\themes.h # End Source File # Begin Source File SOURCE=.\Source\tmsg.h # End Source File # Begin Source File SOURCE=.\Source\town.h # End Source File # Begin Source File SOURCE=.\Source\towners.h # End Source File # Begin Source File SOURCE=.\Source\track.h # End Source File # Begin Source File SOURCE=.\Source\trigs.h # End Source File # Begin Source File SOURCE=.\Source\wave.h # End Source File # Begin Source File SOURCE=.\resource.h # End Source File # End Group # End Target # End Project ================================================ FILE: Diablo.dsw ================================================ 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 Begin Project Dependency Project_Dep_Name Pkware End Project Dependency }}} ############################################################################### Project: "DiabloUI"=".\DiabloUI\DiabloUI.dsp" - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name Storm End Project Dependency }}} ############################################################################### Project: "Pkware"=".\3rdParty\PKWare\Pkware.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> {{{ }}} ############################################################################### ================================================ FILE: Diablo.rc ================================================ //Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include ///////////////////////////////////////////////////////////////////////////// #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 ================================================ FILE: Diablo.sln ================================================  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}" ProjectSection(ProjectDependencies) = postProject {C7F9F3B4-2F7C-4672-9586-94D8BA0950B6} = {C7F9F3B4-2F7C-4672-9586-94D8BA0950B6} EndProjectSection 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 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PKWare", "3rdParty\PKWare\PKWare.vcxproj", "{C7F9F3B4-2F7C-4672-9586-94D8BA0950B6}" 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 {C7F9F3B4-2F7C-4672-9586-94D8BA0950B6}.Debug|x86.ActiveCfg = Debug|Win32 {C7F9F3B4-2F7C-4672-9586-94D8BA0950B6}.Debug|x86.Build.0 = Debug|Win32 {C7F9F3B4-2F7C-4672-9586-94D8BA0950B6}.Release|x86.ActiveCfg = Release|Win32 {C7F9F3B4-2F7C-4672-9586-94D8BA0950B6}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6252549D-BED6-405B-9D6D-42C9074D0684} EndGlobalSection EndGlobal ================================================ FILE: Diablo.vcxproj ================================================ 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 None true NDEBUG;%(PreprocessorDefinitions) .\Source/WinRel\Diablo.tlb true NUL Win32 0x0409 NDEBUG;%(PreprocessorDefinitions) .\Source/WinRel\Diablo.bsc Windows .\Source/WinRel\Diablo.exe 3rdParty/Storm/Source/WinRel/Storm.lib;3rdParty/PKWare/WinRel/PKWare.lib;version.lib;%(AdditionalDependencies) false 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;3rdParty/PKWare/WinDebug/PKWare.lib;version.lib;%(AdditionalDependencies) false false {b28f69ce-15a1-424d-bbb5-2727258d675b} false {8408e35e-3cf5-4d4e-b873-af3952cdabd4} false ================================================ FILE: Diablo.vcxproj.filters ================================================ {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 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 Source Files Source Files Source Files Source Files Source Files 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 Header Files Header Files Header Files Header Files Header Files ================================================ FILE: DiabloUI/DiabloUI.dsp ================================================ # 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 Ignore_Export_Lib 0 # 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 Ignore_Export_Lib 0 # 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 # Begin Source File SOURCE=.\diabloui.res # End Source File # End Target # End Project ================================================ FILE: DiabloUI/DiabloUI.vcxproj ================================================ 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 ../3rdParty/Storm/Source/WinRel/Storm.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 ../3rdParty/Storm/Source/WinDebug/Storm.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) ================================================ FILE: DiabloUI/Makefile ================================================ 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 copied to the # $(VS6_DIR)/VC98/Bin directory. # # - $(VS6_DIR)/Common/MSDev98/Bin/MSPDB60.DLL # # And to the $(VC5_DIR)/bin directory. # # - $(VC5_DIR)/SharedIDE/bin/MSDIS100.DLL # - $(VC5_DIR)/SharedIDE/bin/MSPDB50.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" /YX /Gm /Zi LINKFLAGS=/nologo /subsystem:windows /machine:I386 /incremental:no VC_LINK=$(VC5_LINK) LINKFLAGS+= /LIBPATH:$(VC5_LIB_DIR) all: diabloui.lib DIABLOUI_SRC=diabloui.cpp DIABLOUI_OBJS=$(DIABLOUI_SRC:.cpp=.obj) diabloui.lib: $(DIABLOUI_OBJS) ../3rdParty/Storm/storm.lib $(CL) $^ /link /LINK50COMPAT /nologo /dll /subsystem:windows /machine:I386 /LIBPATH:$(VC6_LIB_DIR) /LIBPATH:../3rdParty/Storm diabloui.res advapi32.lib gdi32.lib shell32.lib user32.lib version.lib storm.lib /def:"diabloui.def" /out:diabloui.dll ../3rdParty/Storm/storm.lib: make -C ../3rdParty/Storm %.obj: %.cpp $(CL) $(CFLAGS) /Fo$@ $< clean: @$(RM) -v $(DIABLOUI_OBJS) diabloui.{exp,lib,dll} vc50.{idb,pch,pdb} .PHONY: clean all ================================================ FILE: DiabloUI/_temp_data.cpp ================================================ //rdata ProfileStruct bnprofiles[4] = { { "profile\\sex", '\x01', 1128, 8 }, { "profile\\age", '\x01', 1130, 4 }, { "profile\\location", '\x01', 1132, 40 }, { "profile\\description", '\x01', 1134, 200 } }; int profilemsg1[6] = { 1125, 1127, 1129, 1131, 1133, 0 }; int profilemsg2[6] = { 1126, 1128, 1130, 1132, 1134, 0 }; int Connect_cpp_float_value = 2139095040; // weak int CopyProt_cpp_float_value = 2139095040; // weak int cr8game_cpp_float_value = 2139095040; // weak int CreaDung_cpp_float_value = 2139095040; // weak int CreaStat_cpp_float_value = 2139095040; // weak int credits_cpp_float_value = 2139095040; // weak int DiabEdit_cpp_float_value = 2139095040; // weak int DiabloUI_cpp_float_value = 2139095040; // weak int disclaim_cpp_float_value = 2139095040; // weak int doom_cpp_float_value = 2139095040; // weak int EntName_cpp_float_value = 2139095040; // weak int fade_cpp_float_value = 2139095040; // weak int focus_cpp_float_value = 2139095040; // weak int local_cpp_float_value = 2139095040; // weak int mainmenu_cpp_float_value = 2139095040; // weak int OkCancel_cpp_float_value = 2139095040; // weak int Sbar_cpp_float_value = 2139095040; // weak int Sbar_cpp_float_value2 = 2139095040; // weak int SelClass_cpp_float_value = 2139095040; // weak int SelHero_cpp_float_value = 2139095040; // weak int SelList_cpp_float_value = 2139095040; // weak int SelLoad_cpp_float_value = 2139095040; // weak int SelYesNo_cpp_float_value = 2139095040; // weak int Title_cpp_float_value = 2139095040; // weak int titlesnd_cpp_float_value = 2139095040; // weak int dword_10022258 = 4; // weak ProfFntStruct proffnts[4] = { { 8, "Arial", 400 }, { 10, "Arial", 400 }, { 10, "Arial", 700 }, { 13, "Time New Roman", 400 } }; unsigned char connect_subnet_ip[4][4] = { { 13, 0, 0, 0 }, // 13.0.0.0 { 128, 128, 128, 0 }, // 128.128.128.0 { 14, 0, 0, 0 }, // 14.0.0.0 { 255, 255, 255, 0 } // 255.255.255.0 }; int creadung_msgtbl1[3] = { 1038, 1080, 0 }; int creadung_msgtbl2[2] = { 1097, 0 }; int creadung_msgtbl3[2] = { 1099, 0 }; int creadung_msgtbl4[3] = { 1056, 1054, 0 }; int creadung_msgtbl5[4] = { 1094, 1095, 1096, 0 }; short defstats[3][4] = { { 30, 15, 20, 30 }, { 25, 20, 30, 20 }, { 15, 35, 25, 20 } }; int dword_10022A2C[3] = { 1038, 1080, 0 }; int dword_10022A38[2] = { 1097, 0 }; int dword_10022A40[2] = { 1102, 0 }; int dword_10022A48[3] = { 1056, 1054, 0 }; int dword_10022A54[3] = { 1100, 1101, 0 }; int disclaim_msgtbl1[3] = { 1082, 1083, 0 }; int disclaim_msgtbl2[4] = { 1084, 1085, 1086, 0 }; int dword_10022AFC[2] = { 1038, 0 }; int dword_10022B04[3] = { 1056, 1054, 0 }; int dword_10022B10[2] = { 1116, 0 }; int entname_msgtbl1[2] = { 1038, 0 }; int entname_msgtbl2[3] = { 1056, 1054, 0 }; int entname_msgtbl3[2] = { 1065, 0 }; int menumsgs_1option[2] = { 1042, 0 }; int menumsgs_5options[6] = { 1044, 1001, 1002, 1003, 2, 0 }; int dword_10022C4C[2] = { 1038, 0 }; int dword_10022C54[2] = { 1080, 0 }; int dword_10022C5C[2] = { 1108, 0 }; int dword_10022CAC[2] = { 1026, 0 }; int dword_10022CB4[2] = { 2, 0 }; int selclass_msgtbl1[2] = { 1038, 0 }; int selclass_msgtbl2[3] = { 1056, 1054, 0 }; int selclass_msgtbl3[4] = { 1062, 1063, 1064, 0 }; int dword_10022ED8[3] = { 1038, 1080, 0 }; int dword_10022EE4[3] = { 1143, 1147, 0 }; int dword_10022EF0[4] = { 1081, 1076, 1144, 0 }; int dword_10022F00[2] = { 1075, 0 }; int dword_10022F08[4] = { 1056, 1054, 1145, 0 }; int dword_10022F18[7] = { 1069, 1070, 1071, 1072, 1073, 1074, 0 }; char *off_10022F8C[4] = { "Entry1", "Entry2", "Entry3", "Entry4" }; int dword_10022F9C[2] = { 1038, 0 }; int dword_10022FA4[3] = { 1056, 1054, 0 }; int dword_10022FB0[7] = { 1117, 1118, 1119, 1120, 1121, 1122, 0 }; int selhero_msgtbl_string[2] = { 1038, 0 }; int selhero_msgtbl_3[6] = { 1057, 1058, 1059, 1060, 1061, 0 }; int selhero_msgtbl_info[6] = { 1014, 1018, 1017, 1016, 1015, 0 }; int dword_100230F0[3] = { 1038, 1080, 0 }; int dword_100230FC[2] = { 1097, 0 }; int dword_10023104[2] = { 1098, 0 }; int dword_1002310C[3] = { 1056, 1054, 0 }; int dword_10023118[7] = { 1088, 1089, 1090, 1091, 1092, 1093, 0 }; int sellist_msgtbl1[2] = { 1038, 0 }; int sellist_msgtbl2[3] = { 1056, 1054, 0 }; int sellist_msgtbl3[2] = { 1006, 0 }; int sellist_msgtbl4[7] = { 1047, 1048, 1049, 1050, 1051, 1052, 0 }; int selload_msgtbl1[2] = { 1038, 0 }; int selload_msgtbl2[3] = { 1056, 1054, 0 }; int selload_msgtbl3[3] = { 1106, 1107, 0 }; int dword_100231CC[2] = { 1038, 0 }; int dword_100231D4[3] = { 1080, 1097, 0 }; int dword_100231E0[2] = { 1123, 0 }; int dword_100231E8[3] = { 1056, 1054, 0 }; int dword_100231F4[7] = { 1110, 1111, 1112, 1113, 1114, 1115, 0 }; int dword_10023244[3] = { 1038, 1080, 0 }; int dword_10023250[2] = { 1142, 0 }; int dword_10023258[2] = { 1146, 0 }; int dword_10023260[3] = { 1056, 1054, 0 }; int dword_1002326C[7] = { 1135, 1136, 1137, 1138, 1139, 1140, 0 }; int yesno_msgtbl2[2] = { 1026, 0 }; int yesno_msgtbl1[3] = { 1109, 2, 0 }; int titlemsgtbl[2] = { 1067, 0 }; //data+bss int artfont_cpp_float = 0; // weak FontStruct font42g; FontStruct *sgpCurrFont; FontStruct font30g; FontStruct font16s; FontStruct font24s; FontStruct font16g; FontStruct font24g; FontStruct font30s; FontStruct font42y; LPARAM dword_10029400; // idb int dword_10029404; // weak int dword_10029408; // weak int dword_1002940C; // weak BYTE *dword_10029410; // idb int dword_10029414; // weak int dword_10029418; // weak int dword_1002941C; // weak HGDIOBJ dword_10029420; // idb HGDIOBJ dword_10029424; // idb BYTE *dword_10029428; // idb void *dword_1002942C; // idb int(__stdcall *dword_10029430)(DWORD, DWORD, DWORD, DWORD); // weak void *dword_10029434; // idb int dword_10029438[4]; // weak char nullcharacter; /* check */ HGDIOBJ dword_10029450; // idb int dword_10029454; // weak int dword_10029458; // weak int dword_10029460[3]; // idb int dword_1002946C; // weak HGDIOBJ dword_10029470; // idb int dword_10029478; // weak int dword_10029480; // weak int dword_10029488; // weak int dword_1002948C; // weak int Connect_cpp_float; // weak int special_frames; // weak DWORD heroport_data[2]; char connect_categorystr[128]; char connect_plrinfostr[128]; int heronum_frames2; // weak DWORD special_data[2]; int heroport_frames; // weak DWORD heronum_data[2]; int heronum_frames; // idb int connect_draw_height; // idb BYTE *connect_data1; // idb BYTE *connect_data2; // idb BYTE *connect_data3; // idb void *connect_data4; // idb HANDLE connect_trans[10]; char *connect_charname; int connect_color_text; // weak HGLOBAL copyprot_popupart; // idb HGLOBAL copyprot_artpal; // idb int CopyProt_cpp_float; // weak HGLOBAL copyprot_btnart; // idb HGDIOBJ cr8game_hobject; // idb int cr8game_cpp_float; // weak int cr8_playercount; // weak DWORD *cr8_somegamestruct; int cr8_dword_10029638; // weak int cr8_dword_1002963C; // weak int cr8_dword_10029640; // weak int *cr8game_playerID; // idb _gamedata cr8_gamedata; HWND cr8_sendmsg1; // idb HWND cr8_sendmsg2; // idb int cr8_dword_10029658; // weak DWORD cr8diffbtns_size[2]; int cr8_dword_10029668; // weak int cr8_dword_1002966C; // idb char cr8_gamename[32]; char cr8_gamepassword[32]; BYTE *cr8_creat_bg_ptr; BYTE *cr8_but_xsm_ptr; // idb BYTE *cr8_diffbtns_ptr; // idb int creadung_playername; // weak int *creadung_playerID; // idb int CreaDung_cpp_float; // weak int creadung_dword_100296C8; // weak int creadung_delspinners; // weak DWORD *crea_somegamestruct; int creadung_lasterror; // weak int creadung_dword_100296D8; // weak char *creadung_gamename; int CreaStat_cpp_float; // weak int credittext_size; // weak int credits_cpp_float; // weak HGLOBAL credittext_rsrc; // idb int credit_vertical_pos2; // idb int credit_horz_pos; // idb int credit_vertical_pos1; // weak int credit_line_count; // weak void *credit_back_img; // idb HANDLE creditsobj; // idb int DiabEdit_cpp_float; // weak int DiabloUI_cpp_float; // weak int sgbUiIsInitialized; // weak HINSTANCE ghUiInst; // idb int backbmp_flag1; // weak int backbmp_flag2; // weak int backbmp_flag3; // weak int app_is_active; // weak int sgbIsSpawn; // weak int dword_10029730; // weak int dword_10029738; // weak char byte_1002973C; // idb char byte_100297BC; // idb int dword_1002983C; // weak int dword_10029840; // weak int gnDlinkPlayerid; // weak void *dword_10029848; // idb int dword_1002984C; // weak int disclaim_cpp_float; // weak int doom_cpp_float; // weak LPSTR dword_10029858; // idb int dword_1002985C; // weak int EntName_cpp_float; // weak char *entname_charname; int fade_cpp_float; // weak int sgbFadeRange; // idb tagPALETTEENTRY fadepal[256]; int sgbIsFading; // weak HANDLE SpinnerTransOut[8]; int focus_spin_width; // idb int focus_spin_height; // weak int focus_cpp_float; // weak int sgbSpinnersLoaded; // weak int dword_10029CA8; // weak int dword_10029CAC; // weak int sgnSpinnerFrame; // weak int local_cpp_float; // weak DWORD gdwCursData[2]; // weak tagPALETTEENTRY artpal[256]; HGDIOBJ objPalette; // idb BYTE *gpCursorArt; BYTE *gpCursorArt2; int mainmenu_cpp_float; // weak char menu_version_str[64]; int menu_item_timer; // weak int dword_1002A120; // weak int dword_1002A124; // weak int dword_1002A128; // weak int dword_1002A12C; // weak int dword_1002A130; // weak int dword_1002A134; // weak int dword_1002A138; // weak int dword_1002A13C; // weak int gnModemPlayerid; // weak int dword_1002A144; // weak int dword_1002A148; // weak void *dword_1002A14C; // idb int dword_1002A150; // weak char byte_1002A154; // idb char byte_1002A1D4; // idb int dword_1002A254; // weak int dword_1002A258; // weak int dword_1002A25C; // weak int (*dword_1002A260)(void); // weak char byte_1002A264; // idb int OkCancel_cpp_float; // weak int dword_1002A2E8; // weak int dword_1002A2EC; // weak int dword_1002A2F0; // weak int (*dword_1002A2F4)(void); // weak int dword_1002A2F8; // weak BOOL dword_1002A2FC; // idb int dword_1002A300; // weak int dword_1002A304; // weak DWORD dword_1002A308; // idb DWORD dword_1002A310; // idb BYTE *dword_1002A318; // idb BYTE *dword_1002A31C; // idb BYTE *dword_1002A320; // idb BYTE *dword_1002A324; // idb void *dword_1002A328; // idb int Sbar_cpp_float; // weak int Sbar_cpp_float2; // weak int SelClass_cpp_float; // weak int dword_1002A34C; // idb int dword_1002A350; // weak int dword_1002A354; // weak char *dword_1002A358; // idb int dword_1002A35C; // weak int dword_1002A360; // idb int dword_1002A364; // weak int dword_1002A368; // weak int dword_1002A36C; // weak int dword_1002A370; // weak int dword_1002A374; // weak char *dword_1002A378; // idb int dword_1002A37C; // weak char byte_1002A380[128]; // weak int dword_1002A400; // weak int dword_1002A404; // weak int dword_1002A408; // weak BOOL(__stdcall *selhero_fnstats) (unsigned int, _uidefaultstats *); int SelHero_cpp_float; // weak DWORD selhero_sizedata[2]; // idb int selhero_difficulty; // weak int selhero_hero_hassaved; // weak int selhero_numheroesleft; // weak char selhero_herolevel[4]; BOOL(__stdcall *selhero_fnremove) (_uiheroinfo *); BOOL(__stdcall *selhero_fninfo) (BOOL(__stdcall *fninfo)(_uiheroinfo *)); char selhero_heromag[4]; char selhero_heronamestr[16]; BOOL(__stdcall *selhero_fncreate) (_uiheroinfo *); char selhero_herodex[4]; _uiheroinfo *sgpHeroInfo; int selhero_is_created; // weak _uiheroinfo heroinfo_create; int selhero_is_good; // idb char selhero_herostr[4]; char selhero_herovit[4]; BYTE *selhero_buffer; int dword_1002A49C; // weak void *dword_1002A4A0; // idb int dword_1002A4A4; // weak int gnIpxPlayerid; // weak int dword_1002A4AC; // weak int dword_1002A4B0; // weak int dword_1002A4B4; // weak int dword_1002A4B8; // idb int dword_1002A4BC; // weak int SelList_cpp_float; // weak _uiheroinfo *sellist_pheroinfo; int SelLoad_cpp_float; // weak int dword_1002A4CC; // weak int dword_1002A4D0; // weak void *dword_1002A4D4; // idb int dword_1002A4D8; // idb int dword_1002A4DC; // weak int dword_1002A4E0; // weak int dword_1002A4E4; // weak int dword_1002A4E8; // weak _uiheroinfo *dword_1002A4EC; // idb int dword_1002A4F0; // weak int dword_1002A4F4; // idb char *yesno_dialog_string; int SelYesNo_cpp_float; // weak int yesno_remove_focus; // weak char *yesno_hero_name; int (*YesNoFunc)(void); // weak int yesno_is_popup; // weak HANDLE titlePHTrans[30]; int Title_cpp_float; // weak int titleTransIdx; // weak int titlesnd_cpp_float; // weak void(__stdcall *gfnSoundFunction)(const char *file); ================================================ FILE: DiabloUI/_temp_funcs.h ================================================ void __fastcall artfont_SetArtFont(int nFont); void __cdecl artfont_InitAllFonts(); void __cdecl artfont_FreeAllFonts(); void __fastcall artfont_FreeArtFont(FontStruct *pFont); BOOL __cdecl artfont_LoadAllFonts(); void __fastcall artfont_LoadArtFont(FontStruct *pFont, const char *pszBinFile, const char *pszFileName); int __cdecl artfont_GetFontMaxHeight(); int __cdecl artfont_GetFontDefWidth(); int __fastcall artfont_GetFontWidth(char *str); void __cdecl j_artfont_cpp_init(); void __cdecl artfont_cpp_init(); int __fastcall artfont_GetFontBreak(char *str); void __cdecl artfont_delete_operator(void *ptr); void __fastcall artfont_PrintFontStr(char *str, DWORD **pSurface, int sx, int sy); signed int bn_prof_100014E8(); //const char *UiProfileGetString(); //BOOL __stdcall UiProfileCallback(int a1, int a2, int a3, int a4, LPARAM a5, int a6, int a7, int a8, int (__stdcall *a9)(DWORD, DWORD, DWORD, DWORD)); HGDIOBJ __stdcall bn_prof_1000155F(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void UNKCALL bn_prof_100016DD(HWND arg); void __fastcall bn_prof_100018CE(int a1, int a2); int __fastcall bn_prof_10001938(HDC a1, DWORD *a2, char *a3, int a4, int a5); int __fastcall bn_prof_10001A10(HWND a1, HWND a2); HINSTANCE __fastcall bn_prof_10001B0A(HWND a1, const CHAR *a2); HWND UNKCALL bn_prof_10001C0E(HWND hWnd); void __fastcall bn_prof_10001CB9(DWORD *a1, int a2, void(__fastcall *a3)(BYTE *, DWORD, int), int a4); BOOL UNKCALL bn_prof_10001CF3(HWND hWnd); HFONT __fastcall bn_prof_10001D81(HWND hWnd, int a2, int a3); void UNKCALL bn_prof_10001E34(void *arg); void __fastcall bn_prof_10001E4C(char *a1, LPARAM lParam, HWND hDlg); void __fastcall bn_prof_10001ED0(char *a1, BYTE *a2, int a3); void *bn_prof_10001F29(); BYTE *bn_prof_10001F84(); //int __stdcall UiProfileDraw(int, int, int, int, HGDIOBJ ho, int, int, int, int, int, int); // idb BOOL bn_prof_100021C4(); void *bn_prof_10002247(); int j_bn_prof_10002282(); DWORD *bn_prof_10002282(); void __cdecl bn_prof_10002298(); // idb int UNKCALL bn_prof_100022A2(HWND hWnd); // idb int UNKCALL bn_prof_10002353(HGDIOBJ h); // idb HGDIOBJ bn_prof_100023D8(); DWORD *__fastcall bn_prof_10002410(HDC hdc, DWORD *a2); signed int __fastcall bn_prof_10002456(int a1, const CHAR *a2, char a3, DWORD *a4); signed int bn_prof_100026B9(); signed int UNKCALL bn_prof_100026C4(DWORD *arg); void UNKCALL bn_prof_100026F0(DWORD *arg); int UNKCALL bn_prof_10002749(DWORD *arg, DWORD *location); DWORD *UNKCALL bn_prof_10002782(int *arg, int a2, int a3, char a4); DWORD *UNKCALL bn_prof_100027CE(DWORD *arg); void UNKCALL bn_prof_100027D8(DWORD *arg); DWORD *UNKCALL bn_prof_1000280C(int *arg, DWORD *a2, int a3, DWORD *a4); void UNKCALL bn_prof_1000287D(DWORD *arg); void UNKCALL bn_prof_10002890(DWORD *arg); void UNKCALL BNetGW_100028C2(DWORD *arg); void UNKCALL BNetGW_100029BF(DWORD *arg, int a2); void *UNKCALL BNetGW_10002A07(DWORD *arg); DWORD *UNKCALL BNetGW_10002A84(DWORD *arg, signed int a2); signed int BNetGW_10002AE5(); int UNKCALL BNetGW_10002AF0(DWORD *arg, char *a2); BYTE *UNKCALL BNetGW_10002B21(DWORD *arg, signed int a2); void UNKCALL BNetGW_10002B51(DWORD *arg, signed int a2); char *UNKCALL BNetGW_10002B78(void *arg, char *a2); char *UNKCALL BNetGW_10002C23(DWORD *arg); int UNKCALL BNetGW_10002C51(DWORD *arg); int UNKCALL BNetGW_10002DBF(DWORD *arg); char *__stdcall BNetGW_10002DEB(char *a1, unsigned int a2); char *__stdcall BNetGW_10002E0B(char *a1, unsigned int a2); void __cdecl Connect_FreeConnectData(); BOOL __cdecl Connect_LoadGFXAndStuff(); BOOL __stdcall UiArtCallback(int game_type, unsigned int art_code, PALETTEENTRY *pPalette, void *pBuffer, DWORD dwBuffersize, DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwBpp); void __cdecl j_Connect_cpp_init(); void __cdecl Connect_cpp_init(); BOOL __stdcall UiGetDataCallback(int game_type, int data_code, void *a3, int a4, int a5); BOOL __stdcall UiSoundCallback(int a1, int type, int a3); BOOL __stdcall UiAuthCallback(int a1, char *a2, char *a3, char a4, char *a5, LPSTR lpBuffer, int cchBufferMax); BOOL __stdcall UiDrawDescCallback(int game_type, COLORREF color, LPCSTR lpString, char *a4, int a5, UINT align, time_t a7, HDC *a8); BOOL __stdcall UiCategoryCallback(int a1, int a2, int a3, int a4, int a5, DWORD *a6, DWORD *a7); int __fastcall Connect_GetRankFromLevel(char *str); BOOL __fastcall Connect_DiffFromString(char *str, _gamedata *gamedata, int a3, int a4); void __fastcall Connect_SetDiffString(_gamedata *gamedata, const char *str1, char *str2, char *str3, int size); BOOL __fastcall Connect_GetHeroInfoConc(const char *a1, _uiheroinfo *pInfo); void __fastcall Connect_MakeDescString(_uiheroinfo *a1, char *name, size_t size); void __stdcall UiCreateGameCriteria(_uiheroinfo *pInfo, char *str); BOOL __stdcall UiCreatePlayerDescription(_uiheroinfo *info, DWORD mode, char *desc); void __stdcall UiSetupPlayerInfo(char *infostr, _uiheroinfo *pInfo, DWORD type); void __fastcall Connect_CopyPlrDescStrings(char *str1, int size1, char *str2, int size2); BOOL __stdcall UiCopyProtError(int *pdwResult); LRESULT __stdcall CopyProt_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __cdecl CopyProt_FreeCopyResrcs(); BOOL __fastcall CopyProt_LoadCopyStuff(HWND hWnd, int a2); void __fastcall CopyProt_EndCopyDlg(HWND hWnd, int a2); void __cdecl j_CopyProt_cpp_init(); void __cdecl CopyProt_cpp_init(); void __cdecl j_cr8game_cpp_init(); void __cdecl cr8game_cpp_init(); BOOL __fastcall cr8game_GetSnetCreaGame(HWND hWnd); BOOL __stdcall UiCreateGameCallback(int a1, int a2, int a3, int a4, int a5, int a6); LRESULT __stdcall cr8game_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __cdecl cr8game_FreeCreaStuff(); BOOL __fastcall cr8game_LoadCreaGFX(HWND hWnd); void __fastcall cr8game_FreeMainMem(HWND hWnd); void __fastcall cr8game_AllocMainMem(HWND hWnd); void __fastcall cr8game_DoAROP3Blit(HWND hWnd, int frame, int size); void __fastcall cr8game_SendMessageF5(HWND hWnd); void __fastcall cr8game_BlitCr8Dialog(HWND hWnd, int a2); void __fastcall cr8game_SetWindowStr(HWND hWnd, int dlgitem, int a3); int __fastcall cr8game_CheckValidGameName(char *name); HFONT __fastcall cr8game_GetCr8Object(HWND hWnd); void __fastcall CreaDung_SetDelSpin(int a1); void __cdecl j_CreaDung_cpp_init(); void __cdecl CreaDung_cpp_init(); LRESULT __stdcall CreaDung_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall CreaDung_ParseDungProcs(HWND hWnd, int dlg); void __fastcall CreaDung_FreeDungProcs(HWND hWnd); void __fastcall CreaDung_LoadDungGFX(HWND hWnd); void __fastcall CreaDung_PlaySndAndKill(HWND hWnd, int a2); void __fastcall CreaDung_DoAllPlaySnd(HWND hWnd); void __fastcall CreaDung_DoSnetCreaGame(HWND hWnd); void __fastcall CreaDung_CheckDlgForSnd(HWND hWnd, int a2, int a3); BOOL __fastcall CreaDung_SelDungDiff(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8); BOOL __stdcall UiGetDefaultStats(int pclass, _uidefaultstats *pStats); void __cdecl j_CreaStat_cpp_init(); void __cdecl CreaStat_cpp_init(); void __cdecl j_credits_cpp_init(); void __cdecl credits_cpp_init(); BOOL __stdcall UiCreditsDialog(int a1); LRESULT __stdcall credits_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall credits_FreeCreditResrc(HWND hWnd); void __fastcall credits_LoadImgCreditTxt(HWND hWnd, LPARAM lParam); void __fastcall credits_CalcPosROP3(HWND hWnd); void __fastcall credits_PrintCredLines(HWND hWnd); int __fastcall credits_GetCredLineBreak(char *str); char *__fastcall credits_GetAdjustText(char *str, int len); void __fastcall DiabEdit_DoPaintBMP(HWND hWnd); void __cdecl j_DiabEdit_cpp_init(); void __cdecl DiabEdit_cpp_init(); void __cdecl DiabEdit_SetupWindow(); LRESULT __stdcall DiabEdit_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall DiabEdit_SendWndCommand(HWND hWnd, WORD a2); void __fastcall DiabEdit_GetCursorProp(HWND hWnd); void __fastcall DiabEdit_RestrictAndLimit(HWND hWnd, WPARAM wParam, LPARAM lParam); void __fastcall DiabEdit_SetTextAndProp(HWND hWnd, WPARAM wParam, LPARAM lParam); void __fastcall DiabEdit_SetRestrictString(HWND hWnd, LPARAM lParam); void __fastcall DiabEdit_SetRestrictTimer(HWND hWnd); void __fastcall DiabEdit_RemoveAllProps(HWND hWnd); int __cdecl DiabloUI_GetSpawned(); void __stdcall UiOnPaint(int a1); void __stdcall UiSetBackgroundBitmap(int a1, PALETTEENTRY *a2, int a3, int a4, int a5); void __stdcall UiSetSpawned(BOOL bSpawned); void __stdcall UiInitialize(); void __stdcall UiDestroy(); void __stdcall UiAppActivate(BOOL bActive); BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); void __cdecl j_DiabloUI_cpp_init(); void __cdecl DiabloUI_cpp_init(); signed int DirLink_10005CFA(); BOOL __fastcall DirLink_10005D05(int a1, int a2, int a3, DWORD *a4, int a5, int playerid); int __stdcall DirLink_10005D63(HWND hWnd, UINT Msg, WPARAM wParam, unsigned int lParam); int __fastcall DirLink_10005EB2(HWND hDlg, int a2); int UNKCALL DirLink_10005F1F(HWND hDlg); // idb int UNKCALL DirLink_10005F7B(HWND hWnd); // idb int __fastcall DirLink_10006047(int a1, int a2); void UNKCALL DirLink_10006073(void *arg); HWND UNKCALL DirLink_100060D1(HWND arg); int UNKCALL DirLink_10006141(void *arg); int UNKCALL DirLink_100061E1(void *arg); int UNKCALL DirLink_100062BF(void *arg, int a2, char *a3, char *a4); signed int __stdcall DirLink_1000632B(int a1, char *a2, char *a3); HWND __fastcall DirLink_10006359(HWND hWnd, int a2, int height); BOOL __stdcall UiBetaDisclaimer(int a1); LRESULT __stdcall disclaim_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall disclaim_DelDisclaimProcs(HWND hWnd); void __fastcall disclaim_LoadDisclaimGFX(HWND hWnd); void __fastcall disclaim_FadeFromDisclaim(HWND hWnd); void __cdecl j_disclaim_cpp_init(); void __cdecl disclaim_cpp_init(); void __cdecl j_Doom_cpp_init(); void __cdecl Doom_cpp_init(); void __fastcall Doom_ParseWndProcs(HWND hWnd, int *msgtbl, int nFont, int a4); void __fastcall Doom_GetSetWndText(HWND hWnd, int msg, int nFont, int a4); void __fastcall Doom_PrintStrWithSpin(HWND hWnd, BOOL a2); void __fastcall Doom_AllocAndSetBMP(HWND hWnd, int a2, int bmp_flags); /* check args, __stdcall? */ void __fastcall Doom_GetWindowROP3(HWND hWnd1, HWND hWnd2); void __fastcall Doom_ParseWndProc2(HWND hWnd, int *msgtbl, int nFont, int a4); void __fastcall Doom_GetSetWndTxt2(HWND hWnd, int msg, int nFont, int a4); void __fastcall Doom_ParseWndProc3(HWND hWnd, int *msgtbl, int nFont); void __fastcall Doom_GetSetWndTxt3(HWND hWnd, int msg, int nFont); void __fastcall Doom_PrintStrWithSpn2(HWND hWnd, int justify_type); void __fastcall Doom_ParseWndProc4(HWND hWnd, int *msgtbl, int nFont); void __fastcall Doom_GetSetWndTxt4(HWND hWnd, int msg, int nFont); void __fastcall Doom_ParseWndProc5(HWND hWnd, int *msgtbl, int nFont); void __fastcall Doom_GetSetWndTxt5(HWND hWnd, int msg, int nFont); void __fastcall Doom_PrintTextMsg403(HWND hWnd); void __fastcall Doom_ParseWndProc6(HWND hWnd, int *msgtbl, int nFont); void __fastcall Doom_GetSetWndTxt6(HWND hWnd, int msg, int nFont); void __fastcall Doom_DeleteFreeProcs(HWND hWnd, int *msgtbl); int __stdcall EntDial_10006C96(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam); // idb HWND UNKCALL EntDial_10006D78(HWND hDlg); HWND USERCALL EntDial_10006DB8(HWND hWnd, int a2); int __fastcall EntDial_10006EA7(HWND hDlg, int a2); void __fastcall EntDial_10006EE8(HWND hWnd, unsigned int a2, int a3); int __fastcall EntDial_10006F16(HWND hDlg, int, int); // idb signed int EntDial_10006F71(); LRESULT __stdcall EntName_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall EntName_DelEntNameMsgs(HWND hWnd); void __fastcall EntName_LoadFocusChkName(HWND hWnd); void __fastcall EntName_SetCharName(HWND hWnd, int a2); void __fastcall EntName_GetMessageName(HWND hWnd, unsigned int a2, int a3); void __cdecl j_EntName_cpp_init(); void __cdecl EntName_cpp_init(); void __fastcall Fade_ApplyPaletteRange(int range1, int range2); void __fastcall Fade_UpdatePaletteRange(int range); BOOL __cdecl Fade_CheckRange5(); void __cdecl Fade_Range5SetZero(); void __fastcall Fade_NoInputAndArt(HWND hWnd, BOOL bShowCurs); void __fastcall Fade_SetInputWindow(HWND hWnd); void __fastcall Fade_SetFadeTimer(int nTime); void __stdcall Fade_TimerFunctionDlg(int a1, int a2, int a3, int a4); void __cdecl j_Fade_cpp_init(); void __cdecl Fade_cpp_init(); void __fastcall Focus_CheckPlayMove(LPARAM lParam); int __cdecl Focus_GetSpinWidthOrZero(); void __fastcall Focus_BlitSpinner(HWND hWnd1, HWND hWnd2); void __fastcall Focus_CenterSpinFromSide(HWND hWnd); void __fastcall Focus_GetAndBlitSpin(HWND hWnd, LPARAM lParam); BOOL __fastcall Focus_DoBlitSpinIncFrame(HWND hWnd1, HWND hWnd2); void __cdecl Focus_DeleteSpinners(); void __cdecl Focus_ResetSpinToZero(); void __cdecl j_Focus_cpp_init(); void __cdecl Focus_cpp_init(); void __fastcall Focus_LoadSpinner(const char *pszFileName); void __fastcall Focus_SetFocusTimer(HWND hWnd, const char *pszFileName); void __stdcall Focus_SetFocusAndBlit(int hWnd, int a2, int a3, int a4); void __fastcall Focus_KillFocusTimer(HWND hWnd); void __cdecl local_InitUiPalette(); void __cdecl local_DelUiPalette(); tagPALETTEENTRY *__fastcall local_GetArtPalEntry(int entry); void __fastcall local_ClearPalette(PALETTEENTRY *pPal); void __cdecl local_ClearSurface(); BOOL __fastcall local_LoadArtImage(const char *pszFileName, BYTE **pBuffer, DWORD *pdwSize); BOOL __fastcall local_LoadArtWithPal(HWND hWnd, int a2, char *src, int mask, int flags, const char *pszFileName, BYTE **pBuffer, DWORD *pdwSize, BOOL a9); void __fastcall local_AdjustRectSize(tagRECT *pRect, int a2, int a3); BOOL __fastcall local_SetStaticBmp(HWND hWnd, int nIDDlgItem, BYTE *pBuffer, DWORD *pdwSize); void __cdecl j_local_cpp_init(); void __cdecl local_cpp_init(); BOOL __fastcall local_SetButtonBmp(HWND hWnd, int flags, int a7, void *pBuffer, DWORD *pdwSize); void __fastcall local_FitButtonDlg(HWND hWnd, int *a2, void *pBuffer, DWORD *pdwSize); void __fastcall local_SetWhiteText(HDC hdc); BOOL __fastcall local_GetBottomRect(HWND hWnd1, HWND hWnd2, int width, int height); void __fastcall local_DlgDoPaint(HWND hWnd); void __fastcall local_DoUiWndProc(HWND hWnd, DWORD *pdwMsgTbl); LRESULT __stdcall local_PostUiWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void __fastcall local_DoUiWndProc2(HWND hWnd, DWORD *pdwMsgTbl); LRESULT __stdcall local_PostUiWndProc2(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL __fastcall local_DisableKeyWaitMouse(HWND hWnd); DWORD *__cdecl local_AllocWndLongData(); void __fastcall local_FreeMemPtr(void **p); void __fastcall local_SetWndLongStr(int WndLongData, const char *pszStr); void __cdecl local_LoadArtCursor(); void __cdecl local_InitArtCursor(); void __cdecl local_FreeArtCursor(); void __cdecl local_SetCursorArt(); void __cdecl local_SetCursorDefault(); void __fastcall local_SetDiabloCursor(HWND hWnd); void __cdecl j_MainMenu_cpp_init(); void __cdecl MainMenu_cpp_init(); BOOL __stdcall UiMainMenuDialog(char *name, int *pdwResult, void(__stdcall *fnSound)(char *file), int attractTimeOut); LRESULT __stdcall MainMenu_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall MainMenu_KillAndFreeMenu(HWND hWnd); void __fastcall MainMenu_SetMenuTimer(HWND hWnd); void __fastcall MainMenu_LoadMenuGFX(HWND hWnd); void __fastcall MainMenu_DoOptions(HWND hWnd, int option, int PlaySelect); BOOL __cdecl MainMenu_CheckEnoughMemory(); void __fastcall MainMenu_CheckWParamFocus(HWND hWnd, WPARAM wParam); int Modem_1000855D(); HWND __fastcall Modem_10008563(HWND hDlg, const char *edx0, int a2); int __stdcall Modem_100085D8(int, char *, char *); // idb BOOL Modem_10008606(); char *Modem_1000863D(); signed int Modem_10008648(); int Modem_10008653(); int Modem_10008659(); int UNKCALL Modem_1000865F(char *); // idb BOOL __fastcall Modem_10008680(int a1, int a2, int a3, DWORD *a4, int a5, int playerid); int __stdcall Modem_100086DE(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); // idb void **UNKCALL Modem_1000879E(HWND hDlg); BOOL UNKCALL Modem_100087DB(HWND hWnd); int Modem_10008888(); int UNKCALL Modem_100088DB(HWND hWnd); // idb int UNKCALL Modem_1000893D(HWND hWnd); // idb int __fastcall Modem_10008A38(HWND hWnd, int); // idb void __cdecl Modem_10008B42(char *a1); int UNKCALL Modem_10008BB7(HWND hWnd); // idb int UNKCALL Modem_10008BFE(HWND hWnd); // idb int __stdcall ModmStat_10008C62(char *, int, int, int, int); // idb int UNKCALL ModmStat_10008C87(void *arg); int __stdcall ModmStat_10008CA0(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); // idb int UNKCALL ModmStat_10008DB3(HWND hDlg); // idb BOOL UNKCALL ModmStat_10008DE4(HWND hWnd); int __fastcall ModmStat_10008E89(int a1, int a2); void UNKCALL ModmStat_10008EBF(HWND hDlg); signed int ModmStat_10008F26(); BOOL __fastcall OkCancel_DrawString(HWND hWnd, char *str); void __cdecl j_OkCancel_cpp_init(); void __cdecl OkCancel_cpp_init(); LRESULT __stdcall OkCancel_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall OkCancel_FreeDlgBmp(HWND hWnd); BOOL __fastcall OkCancel_LoadOkCancGFX(HWND hWnd, DWORD *lParam); void __fastcall OkCancel_PlaySndEndDlg(HWND hWnd, int a2); void __fastcall OkCancel_DoOkDialog(HWND hWnd, char *str, int a3); void __stdcall UiMessageBoxCallback(HWND hWnd, char *lpText, LPCSTR lpCaption, UINT uType); signed int Progress_10009480(); //BOOL __stdcall UiProgressDialog(int a1, int a2, BOOL a3, int (*a4)(void), int a5); int __stdcall Progress_100094F4(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); // idb void *Progress_100095EC(); BOOL __fastcall Progress_10009675(HWND hWnd, const CHAR *edx0); BOOL __fastcall Progress_10009805(HWND hWnd, int a2); void Progress_100098B0(); void UNKCALL Progress_100098C5(HWND hWnd); BOOL UNKCALL Progress_1000991C(HWND hWnd); void __cdecl j_Sbar_cpp_init(); void __cdecl Sbar_cpp_init(); BOOL __fastcall Sbar_CheckIfNextHero(HWND hWnd); int __fastcall Sbar_NumScrollLines(HWND hWnd, int width, int height); void __fastcall Sbar_DrawScrollBar(HWND hWnd, int nIDDlgItem, int width, int height); void __fastcall Sbar_LoadScrBarGFX(HWND hWnd, int nIDDlgItem); void __cdecl j_Sbar_cpp_init2(); void __cdecl Sbar_cpp_init2(); void __fastcall Sbar_FreeScrollBar(HWND hWnd, int nIDDlgItem); LRESULT __stdcall SelClass_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall SelClass_FreeClassMsgTbl(HWND hWnd); void __fastcall SelClass_LoadClassFocus(HWND hWnd); void __fastcall SelClass_SetDefaultStats(HWND hWnd, int a2); void __fastcall SelClass_CheckClassSpawn(HWND hWnd, int a2); void __cdecl j_SelClass_cpp_init(); void __cdecl SelClass_cpp_init(); void *SelConn_1000A082(); signed int SelConn_1000A09B(); int __stdcall SelConn_1000A0A6(HWND hWnd, UINT Msg, WPARAM wParam, unsigned int lParam); HWND __fastcall SelConn_1000A226(HWND hDlg, int nIDDlgItem); HWND UNKCALL SelConn_1000A3E2(HWND hDlg); int SelConn_1000A3FF(); void UNKCALL SelConn_1000A43A(HWND hDlg); BOOL __fastcall SelConn_1000A4B9(DWORD *a1); BOOL UNKCALL SelConn_1000A4CD(void *location); HWND UNKCALL SelConn_1000A4E4(HWND hWnd, char *a2, int a3); signed int __stdcall SelConn_1000A5F3(int a1, char *a2, char *a3, int a4); int __fastcall SelConn_1000A670(HWND a1, const char *a2); void UNKCALL SelConn_1000A6EC(HWND hDlg); LRESULT __stdcall SelConn_1000A73E(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); HWND UNKCALL SelConn_1000A866(HWND hWnd); HWND UNKCALL SelConn_1000A8D7(HWND hWnd); HWND UNKCALL SelConn_1000A948(HWND hWnd); int UNKCALL SelConn_1000A9F3(HWND hWnd); // idb DWORD *__fastcall SelConn_1000AA28(int a1); HWND UNKCALL SelConn_1000AA3B(HWND hWnd); HWND UNKCALL SelConn_1000AAEB(HWND hWnd); HWND UNKCALL SelConn_1000AB83(HWND hWnd); int __fastcall SelConn_1000AC07(int a1, int a2); int UNKCALL SelConn_1000AC30(HWND arg); int UNKCALL SelConn_1000AC9E(HWND hWnd); // idb int UNKCALL SelConn_1000ADA8(HWND hWnd); // idb BOOL UNKCALL SelConn_1000ADD0(HWND hWnd); int __fastcall SelConn_1000AE19(int a1, UINT a2); HWND __fastcall SelConn_1000AE59(HWND hWnd, int a2, int height); //signed int __stdcall UiSelectProvider(int a1, int a2, int a3, int a4, char *a5, int *a6); int UNKCALL SelDial_1000B011(char *arg); signed int SelDial_1000B0C4(); int __stdcall SelDial_1000B0CF(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); // idb HWND __fastcall SelDial_1000B1FB(HWND hWnd, int a2); HWND UNKCALL SelDial_1000B29A(HWND hDlg); int __fastcall SelDial_1000B2D8(int a1, int a2); HWND UNKCALL SelDial_1000B354(HWND hDlg); HWND UNKCALL SelDial_1000B3D8(HWND hDlg); HWND UNKCALL SelDial_1000B44C(HWND hDlg); HWND USERCALL SelDial_1000B483(HWND hWnd, int a2); int SelDial_1000B5D9(); int __fastcall SelDial_1000B614(HWND hWnd, int, int); // idb void UNKCALL SelGame_1000B66A(void *arg); int SelGame_1000B671(); void UNKCALL SelGame_1000B677(void *arg); int SelGame_1000B67E(); //int __stdcall UiSelectGame(int, int, void *, int, int, int); // idb signed int SelGame_1000B795(); _uiheroinfo *__cdecl SelHero_GetCurrentHeroInfo(); int __cdecl SelHero_GetNumHeroesLeft(); void __fastcall SelHero_SetHeroDifficulty(int diff); char *__cdecl SelHero_GetHeroNameStr(); _uiheroinfo *__cdecl SelHero_AllocHeroInfo(); int __cdecl SelHero_GetHeroIsGood(); int __fastcall SelHero_SetClassStats(int heroclass, _uidefaultstats *pStats); void __cdecl j_SelHero_cpp_init(); void __cdecl SelHero_cpp_init(); void __fastcall SelHero_SetStaticBMP(HWND hWnd, int adjust_size); void __fastcall SelHero_PrintHeroInfo(HWND hWnd, _uiheroinfo *pInfo); void __fastcall SelHero_SetStringWithMsg(HWND hWnd, const char *str); BOOL __fastcall SelHero_IsNameReserved(const char *name); void __fastcall SelHero_SetLastNamePos(char *name); BOOL __fastcall SelHero_NameHasChar(const char *name, char *illegalchrs); BOOL __fastcall UiValidPlayerName(const char *name); BOOL __stdcall UiSelHeroMultDialog(BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *)), BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *), BOOL(__stdcall *fnstats)(int, _uidefaultstats *), int *dlgresult, int *a6, char *name); LRESULT __stdcall SelHero_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall SelHero_DoStuffWithStrings(HWND hWnd); _uiheroinfo *__fastcall SelHero_GetNextHeroFromStr(_uiheroinfo *pInfo, char *name); void __fastcall SelHero_FreeSomeMemory(void *ptr); _uiheroinfo *__fastcall SelHero_GetHeroSlotFromName(_uiheroinfo *pInfo, const char *name); void __fastcall SelHero_DoHeroSelList(HWND hWnd); void __fastcall SelHero_DoHeroSelClass(HWND hWnd); void __fastcall SelHero_DoEnterName(HWND hWnd); BOOL __fastcall SelHero_CreateHero(HWND hWnd, char *name); void __fastcall SelHero_DoSelLoad(HWND hWnd); void __fastcall SelHero_DoSelDiff(HWND hWnd); void __fastcall SelHero_DeleteAndFree(HWND hWnd); void __fastcall SelHero_FreeAllHeroes(_uiheroinfo *pInfo); void __fastcall SelHero_DoHeroEndFade(HWND hWnd, int a2); void __fastcall SelHero_LoadHeroGFX(HWND hWnd); void __fastcall SelHero_SelectHeroRegion(HWND hWnd); BOOL __stdcall SelHero_GetHeroInfo(_uiheroinfo *pInfo); BOOL __stdcall UiSelHeroSingDialog(BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *)), BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *), BOOL(__stdcall *fnstats)(int, _uidefaultstats *), int *dlgresult, char *name, int *difficulty); void *SelIPX_1000C610(); signed int SelIPX_1000C629(); BOOL __fastcall SelIPX_1000C634(int a1, int a2, int a3, DWORD *a4, int a5, int playerid); int __stdcall SelIPX_1000C692(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); // idb LONG __fastcall SelIPX_1000C818(HWND hDlg, int nIDDlgItem); HWND UNKCALL SelIPX_1000C982(HWND hDlg); int SelIPX_1000C99F(); const char *UNKCALL SelIPX_1000C9DA(HWND hDlg); void __fastcall SelIPX_1000CA64(DWORD *a1); DWORD **__fastcall SelIPX_1000CA71(DWORD *a1); BOOL UNKCALL SelIPX_1000CAC1(void *location); void *__stdcall SelIPX_1000CAD5(int a1, char *a2, char *a3); DWORD *__fastcall SelIPX_1000CB50(DWORD *a1, DWORD *a2); DWORD *__fastcall SelIPX_1000CB73(DWORD *a1, int a2); int __fastcall SelIPX_1000CB83(HWND a1, const char *a2); int UNKCALL SelIPX_1000CC41(HWND hDlg); // idb BOOL __fastcall SelIPX_1000CCC5(DWORD *a1); HWND UNKCALL SelIPX_1000CCD9(HWND hWnd); HWND UNKCALL SelIPX_1000CD4A(HWND hWnd); void UNKCALL SelIPX_1000CEE6(HWND hDlg); LRESULT __stdcall SelIPX_1000CF38(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); HWND UNKCALL SelIPX_1000D070(HWND hWnd); HWND UNKCALL SelIPX_1000D0E1(HWND hWnd); int UNKCALL SelIPX_1000D18C(HWND hWnd); // idb DWORD *__fastcall SelIPX_1000D1C1(int a1); HWND UNKCALL SelIPX_1000D1D4(HWND hWnd); HWND UNKCALL SelIPX_1000D284(HWND hWnd); HWND UNKCALL SelIPX_1000D31C(HWND hWnd); int __fastcall SelIPX_1000D3A0(int a1, int a2); HWND USERCALL SelIPX_1000D3C5(HWND hDlg, int a2); BOOL __fastcall SelIPX_1000D4CA(HWND hDlg, int a2); char *UNKCALL SelIPX_1000D520(char *arg); const char *__fastcall SelIPX_1000D58D(const char *a1, const char *a2); int __fastcall SelIPX_1000D5B0(int a1, int a2); HWND __fastcall SelIPX_1000D696(HWND hDlg, int a2, int height); void __cdecl j_SelList_cpp_init(); void __cdecl SelList_cpp_init(); LRESULT __stdcall SelList_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall SelList_DeleteFreeProcs(HWND hWnd); void __fastcall SelList_GetHeroStats(HWND hWnd, int nIDDlgItem); void __fastcall SelList_CountHeroList(HWND hWnd); int __fastcall SelList_GetNextHeroLong(HWND hWnd); void __fastcall SelList_LoadFocus16(HWND hWnd); void __fastcall SelList_KillFocus16(HWND hWnd); void __fastcall SelList_ShowListWindow(HWND hWnd); void __fastcall SelList_SetHeroDlgLong(HWND hWnd, _uiheroinfo *pInfo); void __fastcall SelList_DoListOldProc(HWND hWnd); LRESULT __stdcall SelList_OldListWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall SelList_ShiftHeroDlgItems(HWND hWnd); void __fastcall SelList_ShiftHeroDlgItm2(HWND hWnd); void __fastcall SelList_HeroesWithBigDialogs(HWND hWnd); _uiheroinfo *__fastcall SelList_GetHeroFromNum(int heronum); void __fastcall SelList_HeroesWithHugeDlg(HWND hWnd); void __fastcall SelList_HeroDlgWithSound(HWND hWnd); void __fastcall SelList_HeroDlgWithSnd2(HWND hWnd); void __fastcall SelList_ChooseDlgFromSize(HWND hWnd, int width, int height); LRESULT __stdcall SelLoad_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall SelLoad_DeleteProcsAndSpin(HWND hWnd); void __fastcall SelLoad_LoadFocusAndMsg(HWND hWnd); void __fastcall SelLoad_SelectSndLoad(HWND hWnd, int a2); void __cdecl j_SelLoad_cpp_init(); void __cdecl SelLoad_cpp_init(); signed int SelModem_1000E42A(); int __fastcall SelModem_1000E435(void *a1, int a2, int a3, char *a4, char *a5); char *__stdcall SelModem_1000E497(int a1, char *a2, char *a3); void *SelModem_1000E4EC(); DWORD *__fastcall SelModem_1000E500(int a1, DWORD *a2); signed int UNKCALL SelModem_1000E505(void *arg); signed int SelModem_1000E51E(); BOOL __fastcall SelModem_1000E553(DWORD *a1); BOOL UNKCALL SelModem_1000E567(void *location); int __fastcall SelModem_1000E57B(int a1, int a2); signed int SelModem_1000E5CC(); int __stdcall SelModem_1000E63E(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam); // idb void UNKCALL SelModem_1000E783(HWND hDlg); HWND UNKCALL SelModem_1000E7E9(HWND hDlg); int UNKCALL SelModem_1000E80E(HWND hWnd); // idb HWND UNKCALL SelModem_1000E843(HWND hWnd); int __fastcall SelModem_1000E932(HWND a1, const char *a2); void UNKCALL SelModem_1000E9B2(HWND hDlg); LRESULT __stdcall SelModem_1000EA04(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); HWND UNKCALL SelModem_1000EB2C(HWND hWnd); HWND UNKCALL SelModem_1000EB9D(HWND hWnd); HWND UNKCALL SelModem_1000EC0E(HWND hWnd); DWORD *__fastcall SelModem_1000EC9F(int a1); HWND UNKCALL SelModem_1000ECB2(HWND hWnd); HWND UNKCALL SelModem_1000ED3B(HWND hWnd); HWND UNKCALL SelModem_1000EDBC(HWND hWnd); int __fastcall SelModem_1000EE29(int a1, int a2); HWND __fastcall SelModem_1000EE78(HWND hWnd, int a2, int height); void *SelRegn_1000EF42(); _uiheroinfo *__fastcall SelRegn_SetNextHero(_uiheroinfo *pNext, _uiheroinfo *pCurrent); signed int SelRegn_1000EF60(); int __stdcall SelRegn_1000EF6B(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); // idb HWND __fastcall SelRegn_1000F0D7(HWND hDlg, int nIDDlgItem); HWND UNKCALL SelRegn_1000F109(HWND hDlg); int SelRegn_1000F126(); void UNKCALL SelRegn_1000F161(HWND hDlg); BOOL __fastcall SelRegn_1000F1D4(DWORD *a1); BOOL UNKCALL SelRegn_1000F1E8(void *location); HWND UNKCALL SelRegn_1000F1FC(HWND hWnd); signed int SelRegn_1000F2ED(); int __fastcall SelRegn_1000F346(HWND a1, const char *a2); void UNKCALL SelRegn_1000F3C2(HWND hDlg); LRESULT __stdcall SelRegn_1000F414(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); HWND UNKCALL SelRegn_1000F53C(HWND hWnd); HWND UNKCALL SelRegn_1000F5AD(HWND hWnd); HWND UNKCALL SelRegn_1000F61E(HWND hWnd); int UNKCALL SelRegn_1000F6C9(HWND hWnd); // idb DWORD *__fastcall SelRegn_1000F6FE(int a1); HWND UNKCALL SelRegn_1000F711(HWND hWnd); HWND UNKCALL SelRegn_1000F7C1(HWND hWnd); HWND UNKCALL SelRegn_1000F859(HWND hWnd); signed int UNKCALL SelRegn_1000F8DD(void *arg); signed int SelRegn_1000F8F6(); HWND __fastcall SelRegn_1000F929(HWND hWnd, int a2, int height); //signed int __stdcall UiSelectRegion(DWORD *a1); int __fastcall SelYesNo_YesNoDialog(HWND hWnd, char *dialogstr, char *hero, int nofocus); /* void */ LRESULT __stdcall SelYesNo_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void __fastcall SelYesNo_RemoveYNDialog(HWND hWnd); void __fastcall SelYesNo_LoadSelYN_GFX(HWND hWnd); void __fastcall SelYesNo_DoSelectYesNo(HWND hWnd, int option); int __fastcall SelYesNo_SelOkDialog(HWND hWnd, char *dialogstr, char *hero, int nofocus); /* void */ int __fastcall SelYesNo_SpawnErrDialog(HWND hWnd, int string_rsrc, int is_popup); /* void */ void __cdecl j_SelYesNo_cpp_init(); void __cdecl SelYesNo_cpp_init(); void __fastcall Title_BlitTitleBuffer(HWND hWnd); void __cdecl Title_DeletePhTrans(); void __fastcall Title_FreeTransMem(HWND hWnd); void __fastcall Title_SetTitleBMP(HWND hWnd); void __fastcall Title_LoadTitleImage(HWND hWnd, const char *pszFileName); void __fastcall Title_LoadImgSetTimer(HWND hWnd, const char *pszFileName); void __stdcall Title_BlitTitleBufFnc(int hWnd, int a2, int a3, int a4); void __cdecl j_Title_cpp_init(); void __cdecl Title_cpp_init(); void __fastcall Title_KillTitleTimer(HWND hWnd); BOOL __stdcall UiTitleDialog(int a1); LRESULT __stdcall Title_MainProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void __fastcall Title_KillTimerAndFree(HWND hWnd); void __fastcall Title_LoadAllTitleImgs(HWND hWnd, int time); void __fastcall Title_KillAndFadeDlg(HWND hWnd); void __fastcall TitleSnd_SetSoundFunction(void(__stdcall *func)(const char *file)); void __cdecl TitleSnd_InitSoundFunc(); void __cdecl TitleSnd_PlayMoveSound(); void __cdecl TitleSnd_PlaySelectSound(); void __cdecl j_TitleSnd_cpp_init(); void __cdecl TitleSnd_cpp_init(); ================================================ FILE: DiabloUI/artfont.cpp ================================================ // ref: 0x10001058 void __fastcall artfont_SetArtFont(int nFont) { switch (nFont) { case AF_SMALL: sgpCurrFont = &font16g; break; case AF_MED: sgpCurrFont = &font24g; break; case AF_MEDGRAY: sgpCurrFont = &font24s; break; case AF_BIG: sgpCurrFont = &font30g; break; case AF_BIGGRAY: sgpCurrFont = &font30s; break; case AF_HUGE: sgpCurrFont = &font42g; break; case AF_HUGEGRAY: sgpCurrFont = &font42y; break; default: sgpCurrFont = &font16s; break; } } // ref: 0x10001098 void __cdecl artfont_InitAllFonts() { font42g.active = 0; font42y.active = 0; font30g.active = 0; font30s.active = 0; font24g.active = 0; font24s.active = 0; font16g.active = 0; font16s.active = 0; sgpCurrFont = 0; } // ref: 0x100010C8 void __cdecl artfont_FreeAllFonts() { artfont_FreeArtFont(&font42g); artfont_FreeArtFont(&font42y); artfont_FreeArtFont(&font30g); artfont_FreeArtFont(&font30s); artfont_FreeArtFont(&font24g); artfont_FreeArtFont(&font24s); artfont_FreeArtFont(&font16g); artfont_FreeArtFont(&font16s); sgpCurrFont = 0; } // ref: 0x10001120 void __fastcall artfont_FreeArtFont(FontStruct *pFont) { HANDLE *v2; // esi signed int v3; // ebx if (pFont->active) { v2 = pFont->fonttrans; v3 = 256; do { if (*v2) { STransDelete(*v2); *v2 = 0; } ++v2; --v3; } while (v3); pFont->active = 0; } } // ref: 0x10001159 BOOL __cdecl artfont_LoadAllFonts() { artfont_LoadArtFont(&font30g, "ui_art\\font30.bin", "ui_art\\font30g.pcx"); artfont_LoadArtFont(&font30s, "ui_art\\font30.bin", "ui_art\\font30s.pcx"); artfont_LoadArtFont(&font24g, "ui_art\\font24.bin", "ui_art\\font24g.pcx"); artfont_LoadArtFont(&font24s, "ui_art\\font24.bin", "ui_art\\font24s.pcx"); artfont_LoadArtFont(&font16g, "ui_art\\font16.bin", "ui_art\\font16g.pcx"); artfont_LoadArtFont(&font16s, "ui_art\\font16.bin", "ui_art\\font16s.pcx"); artfont_LoadArtFont(&font42g, "ui_art\\font42.bin", "ui_art\\font42g.pcx"); artfont_LoadArtFont(&font42y, "ui_art\\font42.bin", "ui_art\\font42y.pcx"); return 1; } // ref: 0x100011FB void __fastcall artfont_LoadArtFont(FontStruct *pFont, const char *pszBinFile, const char *pszFileName) { LONG v4; // eax signed int v5; // edi unsigned char v6; // al int v7; // ecx int a5[4]; // [esp+8h] [ebp-20h] DWORD size[2]; // [esp+18h] [ebp-10h] BYTE *pBuffer; // [esp+20h] [ebp-8h] HANDLE phFile; // [esp+24h] [ebp-4h] HANDLE *a1a; // [esp+30h] [ebp+8h] if (!pFont->active && SFileOpenFile(pszBinFile, &phFile)) { v4 = SFileGetFileSize(phFile, 0); if (SFileReadFile(phFile, pFont, v4, 0, NULL)) { SFileCloseFile(phFile); local_LoadArtImage(pszFileName, &pBuffer, size); memset(pFont->fonttrans, 0, 0x400u); if (pBuffer) { v5 = 0; a1a = pFont->fonttrans; do { v6 = pFont->fontbin[v5 + 2]; if (v6) { v7 = pFont->fontbin[1]; a5[2] = v6; a5[1] = v5 * v7; a5[0] = 0; a5[3] = v7 + v5 * v7 - 1; STransCreateI(pBuffer, size[0], size[1], 8, (int)a5, 16777248, a1a); } ++a1a; ++v5; } while (v5 <= 256); pFont->active = 1; SMemFree(pBuffer, "C:\\Src\\Diablo\\DiabloUI\\artfont.cpp", 206, 0); } } else { SFileCloseFile(phFile); } } } // ref: 0x100012F6 int __cdecl artfont_GetFontMaxHeight() { int result; // eax if (sgpCurrFont && sgpCurrFont->active) result = sgpCurrFont->fontbin[1]; else result = 0; return result; } // ref: 0x10001310 int __cdecl artfont_GetFontDefWidth() { int result; // eax if (sgpCurrFont && sgpCurrFont->active) result = sgpCurrFont->fontbin[0]; else result = 0; return result; } // ref: 0x10001329 int __fastcall artfont_GetFontWidth(char *str) { int result; // eax unsigned char i; // bl unsigned char v3; // bl int v4; // esi result = 0; if (!sgpCurrFont || !sgpCurrFont->active) return 0; for (i = *str; *str; i = *str) { v3 = sgpCurrFont->fontbin[i + 2]; if (v3) v4 = v3; else v4 = sgpCurrFont->fontbin[0]; result += v4; ++str; } return result; } // ref: 0x1000136C void __cdecl artfont_cpp_init() { artfont_cpp_float = 2139095040; } // 10026BB0: using guessed type int artfont_cpp_float; // ref: 0x10001377 int __fastcall artfont_GetFontBreak(char *str) { int result; // eax unsigned char v2; // dl unsigned char v3; // dl result = 0; if (!sgpCurrFont || !sgpCurrFont->active) return 0; while (1) { v3 = *str; if (!*str) break; if (v3 == '\n') break; if (v3 == ' ') break; v2 = sgpCurrFont->fontbin[v3 + 2]; if (!v2) break; result += v2; ++str; } return result; } // ref: 0x100013B3 void __cdecl artfont_delete_operator(void *ptr) { if (ptr) SMemFree(ptr, "delete", -1, 0); } // ref: 0x100013CD void __fastcall artfont_PrintFontStr(char *str, DWORD **pSurface, int sx, int sy) { FontStruct *v5; // esi unsigned char v6; // cl int v7; // edi unsigned char v8; // dl int v9; // edi DWORD *v10; // ecx HANDLE hTrans; // [esp+Ch] [ebp-8h] HANDLE hTransa; // [esp+Ch] [ebp-8h] if (pSurface) { if (*pSurface) { v5 = sgpCurrFont; if (sgpCurrFont) { if (sgpCurrFont->active) { if (sx < 0) sx = 0; if (sy < 0) sy = 0; v6 = *str; if (*str) { while (1) { hTrans = (HANDLE)(sy + v5->fontbin[1]); if (sy + v5->fontbin[1] > (signed int)pSurface[2]) return; if (v6 == '\n') break; v7 = v6; v8 = v5->fontbin[v6 + 2]; if (!v8) { v9 = v5->fontbin[0]; if (sx + v9 + artfont_GetFontBreak(++str) < (signed int)pSurface[1]) { sx += v9; } else { sx = 0; sy = (int)hTrans; } goto LABEL_23; } hTransa = v5->fonttrans[v6]; if (v5->fonttrans[v6]) { v10 = pSurface[1]; if (sx + v8 <= (signed int)v10) { STransBlt(*pSurface, sx, sy, (int)v10, hTransa); v5 = sgpCurrFont; sx += sgpCurrFont->fontbin[v7 + 2]; goto LABEL_22; } sx = 0; sy += v5->fontbin[1]; } LABEL_23: v6 = *str; if (!*str) return; } sx = 0; sy += v5->fontbin[1]; LABEL_22: ++str; goto LABEL_23; } } } } } } ================================================ FILE: DiabloUI/bn_prof.cpp ================================================ // ref: 0x100014E8 signed int bn_prof_100014E8() { return 0; } /* { signed int result; // eax result = 2139095040; dword_10029404 = 2139095040; return result; } */ // 10029404: using guessed type int dword_10029404; // ref: 0x100014F3 const char **__stdcall UiProfileGetString() { return NULL; } //const char *UiProfileGetString() { return 0; } /* { return "profile\\sex"; } */ // ref: 0x100014F9 void __cdecl UiProfileCallback() { return; } //BOOL __stdcall UiProfileCallback(int a1, int a2, int a3, int a4, LPARAM a5, int a6, int a7, int a8, int (__stdcall *a9)(DWORD, DWORD, DWORD, DWORD)) { return 0; } /* { const char *v9; // eax int v10; // eax lParam = a5; dword_10029408 = a6; dword_1002941C = a7; dword_10029418 = a8; dword_10029430 = a9; v9 = "DIALOG_PROFILE"; if ( !a9 ) v9 = "DIALOG_STATIC_PROFILE"; v10 = SDlgDialogBoxParam(hInstance, v9, *(DWORD *)(a3 + 8), bn_prof_1000155F, 0); return v10 && v10 != -1; } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // 10029408: using guessed type int dword_10029408; // 10029418: using guessed type int dword_10029418; // 1002941C: using guessed type int dword_1002941C; // 10029430: using guessed type int (__stdcall *dword_10029430)(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000155F HGDIOBJ __stdcall bn_prof_1000155F(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { HWND v4; // eax HWND v6; // edi if ( Msg <= 0x110 ) { switch ( Msg ) { case 0x110u: bn_prof_10001C0E(hWnd); break; case 2u: bn_prof_10001F29(); break; case 0x2Bu: if ( wParam == 1134 ) { bn_prof_100018CE((int)hWnd, lParam); return (HGDIOBJ)1; } return (HGDIOBJ)SDlgDefDialogProc(hWnd, Msg, wParam, lParam); default: if ( Msg > 0x103 && Msg <= 0x105 ) { v4 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v4, Msg, wParam, lParam); } return (HGDIOBJ)SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } return 0; } if ( Msg == 273 ) { if ( (unsigned short)wParam == 1 ) { EnableWindow((HWND)lParam, 0); TitleSnd_10010315(); if ( dword_10029430 ) bn_prof_100016DD(hWnd); SDlgEndDialog(hWnd, 1); } else if ( (unsigned short)wParam == 2 ) { EnableWindow((HWND)lParam, 0); TitleSnd_10010315(); SDlgEndDialog(hWnd, 0); } else { if ( (unsigned short)wParam != 1134 || HIWORD(wParam) || dword_10029430 ) return (HGDIOBJ)SDlgDefDialogProc(hWnd, Msg, wParam, lParam); bn_prof_10001A10(hWnd, (HWND)lParam); } return 0; } if ( Msg == 274 ) { if ( wParam != 61536 ) return (HGDIOBJ)SDlgDefDialogProc(hWnd, Msg, wParam, lParam); v6 = GetParent(hWnd); SDlgEndDialog(hWnd, 0); PostMessageA(v6, 0x112u, 0xF060u, lParam); return 0; } if ( Msg != 312 || GetWindowLongA((HWND)lParam, -12) != 1124 ) return (HGDIOBJ)SDlgDefDialogProc(hWnd, Msg, wParam, lParam); SetTextColor((HDC)wParam, 0xFFFFu); return GetStockObject(5); } */ // 10010376: using guessed type int __stdcall SDlgEndDialog(DWORD, DWORD); // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 10029430: using guessed type int (__stdcall *dword_10029430)(DWORD, DWORD, DWORD, DWORD); // ref: 0x100016DD void UNKCALL bn_prof_100016DD(HWND arg) { return; } /* { int v1; // ebx int v2; // eax const char **v3; // edi int v4; // eax int v5; // ebx int *v6; // ebx LRESULT v7; // eax LPARAM v8; // eax size_t v9; // eax char *v10; // eax int v11; // ebx DWORD *v12; // edi int v13; // eax int v14; // ebx size_t v15; // [esp+4h] [ebp-28h] char *v16; // [esp+8h] [ebp-24h] HWND hDlg; // [esp+Ch] [ebp-20h] int v18; // [esp+10h] [ebp-1Ch] int v19; // [esp+14h] [ebp-18h] int v20; // [esp+18h] [ebp-14h] char *v21; // [esp+1Ch] [ebp-10h] int v22; // [esp+20h] [ebp-Ch] int v23; // [esp+24h] [ebp-8h] char *v24; // [esp+28h] [ebp-4h] size_t v25; // [esp+28h] [ebp-4h] v1 = 0; hDlg = arg; if ( dword_10029430 ) { v2 = SMemAlloc(4 * dword_10029408, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 193, 0); v3 = (const char **)v2; v22 = v2; v4 = SMemAlloc(4 * dword_10029408, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 195, 0); v18 = v4; v20 = 0; v23 = 0; if ( dword_10029408 > 0 ) { v19 = v4 - (DWORD)v3; do { v5 = 0; v24 = byte_1001F37C; v16 = *(char **)(4 * v23 + dword_10029418); v21 = *(char **)(4 * v23 + dword_1002941C); while ( 1 ) { if ( !_strcmpi(v21, *((const char **)v24 - 1)) ) { v15 = strlen(v16); if ( *v24 & 1 ) break; } v24 += 16; ++v5; if ( (signed int)v24 >= (signed int)&unk_1001F3BC ) goto LABEL_13; } v6 = &dword_1001F380[4 * v5]; v7 = SendDlgItemMessageA(hDlg, *v6, 0xEu, 0, 0); v25 = v7; v8 = SMemAlloc(v7 + 1, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 218, 0); *v3 = (const char *)v8; SendDlgItemMessageA(hDlg, *v6, 0xDu, v25 + 1, v8); (*v3)[v25] = 0; if ( v25 == v15 && !_strnicmp(v16, *v3, v25) ) { SMemFree(*v3, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 236, 0); } else { v9 = strlen(v21); v10 = (char *)SMemAlloc(v9 + 1, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 232, 0); *(const char **)((char *)v3 + v19) = v10; strcpy(v10, v21); ++v20; ++v3; } LABEL_13: ++v23; } while ( v23 < dword_10029408 ); v1 = v20; } dword_10029430(&byte_10029448, v1, v18, v22); v11 = v1 - 1; if ( v11 >= 0 ) { v12 = (DWORD *)(v22 + 4 * v11); v13 = v18 - v22; v14 = v11 + 1; while ( 1 ) { SMemFree(*(DWORD *)((char *)v12 + v13), "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 250, 0); SMemFree(*v12, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 251, 0); --v12; if ( !--v14 ) break; v13 = v18 - v22; } } SMemFree(v18, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 253, 0); SMemFree(v22, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 254, 0); } } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // 1001F380: using guessed type int dword_1001F380[]; // 10029408: using guessed type int dword_10029408; // 10029418: using guessed type int dword_10029418; // 1002941C: using guessed type int dword_1002941C; // 10029430: using guessed type int (__stdcall *dword_10029430)(DWORD, DWORD, DWORD, DWORD); // ref: 0x100018CE void __fastcall bn_prof_100018CE(int a1, int a2) { return; } /* { int v2; // esi LRESULT v3; // eax WPARAM v4; // edi char *v5; // ebx v2 = a2; if ( *(DWORD *)(a2 + 24) && *(DWORD *)a2 == 5 ) { v3 = SendMessageA(*(HWND *)(a2 + 20), 0xEu, 0, 0); v4 = v3 + 1; if ( v3 != 0 ) { v5 = (char *)SMemAlloc(v3 + 1, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 362, 0); SendMessageA(*(HWND *)(v2 + 20), 0xDu, v4, (LPARAM)v5); bn_prof_10001938(*(HDC *)(v2 + 24), (DWORD *)(v2 + 28), v5, 0, 0); SMemFree(v5, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 367, 0); } } } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // ref: 0x10001938 int __fastcall bn_prof_10001938(HDC a1, DWORD *a2, char *a3, int a4, int a5) { return 0; } /* { int result; // eax char *v6; // edi char *v7; // eax char *v8; // esi char v9; // bl char *v10; // eax RECT rc; // [esp+Ch] [ebp-14h] DWORD *v12; // [esp+1Ch] [ebp-4h] char *v13; // [esp+28h] [ebp+8h] result = (int)bn_prof_10002410(a1, a2); v12 = (DWORD *)result; if ( result ) { v6 = a3; if ( a3 ) { v13 = (char *)(a4 != 0 ? (unsigned int)&rc : 0); while ( 1 ) { v7 = strstr(v6, "http://"); v8 = v7; v9 = 0; if ( v7 ) { v9 = *v7; *v7 = 0; } if ( !bn_prof_10002456((int)v12, v6, 1, v13) || !v8 ) break; *v8 = v9; v10 = strpbrk(v8, " \n\r\t"); v6 = v10; if ( v10 ) { v9 = *v10; *v10 = 0; } if ( !bn_prof_10002456((int)v12, v8, 2, v13) ) break; if ( a4 && PtInRect(&rc, *(POINT *)a4) ) { if ( a5 ) *(DWORD *)a5 = v8; return 1; } if ( !v6 ) break; *v6 = v9; } } bn_prof_100026C4(v12); result = a4 == 0; } return result; } */ // ref: 0x10001A10 int __fastcall bn_prof_10001A10(HWND a1, HWND a2) { return 0; } /* { HWND v2; // esi int result; // eax WPARAM v4; // esi HWND v5; // eax HDC v6; // edi HWND v7; // eax struct tagRECT v8; // [esp+Ch] [ebp-3Ch] struct tagRECT Rect; // [esp+1Ch] [ebp-2Ch] struct tagPOINT Point; // [esp+2Ch] [ebp-1Ch] HWND v11; // [esp+34h] [ebp-14h] int v12; // [esp+38h] [ebp-10h] int v13; // [esp+3Ch] [ebp-Ch] HWND hWnd; // [esp+40h] [ebp-8h] char *v15; // [esp+44h] [ebp-4h] v2 = a2; hWnd = a2; v11 = a1; result = GetCursorPos(&Point); if ( result ) { result = GetWindowRect(v2, &Rect); if ( result ) { result = GetClientRect(v2, &v8); if ( result ) { Point.x -= Rect.left; Point.y -= Rect.top; result = SendMessageA(v2, 0xEu, 0, 0); v4 = result + 1; if ( result + 1 > 1 ) { v15 = (char *)SMemAlloc(result + 1, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 438, 0); SendMessageA(hWnd, 0xDu, v4, (LPARAM)v15); v5 = GetDesktopWindow(); v6 = GetDC(v5); hWnd = (HWND)CreateCompatibleDC(v6); v13 = bn_prof_10001938((HDC)hWnd, &v8, v15, (int)&Point, (int)&v12); DeleteDC((HDC)hWnd); v7 = GetDesktopWindow(); ReleaseDC(v7, v6); if ( v13 ) bn_prof_10001B0A(v11, (const CHAR *)v12); result = SMemFree(v15, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 450, 0); } } } } return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // ref: 0x10001B0A HINSTANCE __fastcall bn_prof_10001B0A(HWND a1, const CHAR *a2) { return 0; } /* { const CHAR *v2; // ebp HWND v3; // eax HWND v4; // eax HINSTANCE result; // eax FILE *v6; // eax HWND v7; // eax HWND v8; // eax HWND v9; // eax HWND hWnd; // [esp+10h] [ebp-348h] CHAR Caption; // [esp+14h] [ebp-344h] CHAR Result; // [esp+54h] [ebp-304h] CHAR Buffer; // [esp+158h] [ebp-200h] v2 = a2; hWnd = a1; v3 = GetDesktopWindow(); SetForegroundWindow(v3); v4 = (HWND)SDrawGetFrameWindow(NULL); result = ShellExecuteA(v4, "open", v2, 0, 0, 1); if ( (unsigned int)result <= 0x20 ) { v6 = fopen("battle.htm", "wb"); if ( v6 ) fclose(v6); if ( (unsigned int)FindExecutableA("battle.htm", 0, &Result) <= 0x20 ) { v7 = (HWND)SDrawGetFrameWindow(NULL); if ( (unsigned int)ShellExecuteA(v7, "open", &Result, v2, 0, 1) <= 0x20 ) { v8 = (HWND)SDrawGetFrameWindow(NULL); SetActiveWindow(v8); v9 = (HWND)SDrawGetFrameWindow(NULL); ShowWindow(v9, 0); LoadStringA(hInstance, 0x50u, &Buffer, 512); LoadStringA(hInstance, 0x51u, &Caption, 64); UiMessageBoxCallback(hWnd, &Buffer, &Caption, 0x30u); } } result = (HINSTANCE)DeleteFileA("battle.htm"); } return result; } */ // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x10001C0E HWND UNKCALL bn_prof_10001C0E(HWND hWnd) { return 0; } /* { HWND v1; // esi LPARAM v2; // ST10_4 HWND v3; // eax HWND v4; // eax HWND v5; // eax HWND v6; // eax v1 = hWnd; bn_prof_10001CF3(hWnd); ho = bn_prof_10001D81(v1, 2, (int)&unk_1001F3B8); dword_10029424 = bn_prof_10001D81(v1, 1, (int)&unk_1001F3D0); v2 = lParam; v3 = GetDlgItem(v1, 1126); SendMessageA(v3, 0xCu, 0, v2); bn_prof_10001CB9( (DWORD *)dword_1002941C, dword_10029418, (void (__fastcall *)(BYTE *, DWORD, int))bn_prof_10001ED0, 0); bn_prof_10001E34(v1); if ( dword_10029430 ) { v4 = GetDlgItem(v1, 1128); } else { v5 = GetDlgItem(v1, 1134); bn_prof_100022A2(v5); v6 = GetDlgItem(v1, 1); EnableWindow(v6, 0); v4 = GetDlgItem(v1, 2); } return SetFocus(v4); } */ // 10029418: using guessed type int dword_10029418; // 1002941C: using guessed type int dword_1002941C; // 10029430: using guessed type int (__stdcall *dword_10029430)(DWORD, DWORD, DWORD, DWORD); // ref: 0x10001CB9 void __fastcall bn_prof_10001CB9(DWORD *a1, int a2, void (__fastcall *a3)(BYTE *, DWORD, int), int a4) { return; } /* { BYTE *v4; // eax DWORD *v5; // esi int v6; // edi if ( a1 ) { if ( a2 ) { if ( a3 ) { v4 = (BYTE *)*a1; if ( *(BYTE *)*a1 ) { v5 = a1; v6 = a2 - (DWORD)a1; do { a3(v4, *(DWORD *)((char *)v5 + v6), a4); ++v5; v4 = (BYTE *)*v5; } while ( *(BYTE *)*v5 ); } } } } } */ // ref: 0x10001CF3 int UNKCALL bn_prof_10001CF3(HWND hWnd) { return 0; } /* { HWND v1; // edi const char *v2; // eax int v3; // ST10_4 HWND v4; // eax int v6; // [esp+8h] [ebp-14h] int v7; // [esp+Ch] [ebp-10h] int v8; // [esp+10h] [ebp-Ch] char v9; // [esp+14h] [ebp-8h] v8 = 0; v1 = hWnd; v6 = 1; v7 = 2; v2 = "ui_art\\bnprofile.pcx"; if ( !dword_10029430 ) v2 = "ui_art\\bnstaticprofile.pcx"; v3 = (int)v2; v4 = GetParent(hWnd); local_10007944((int)v1, (int)v4, "Popup", -1, 1, v3, &dword_10029410, &v9, 1); local_10007944(0, 0, "Button", -1, 1, (int)"ui_art\\but_xsm.pcx", &dword_10029428, &v9, 1); return SDlgSetControlBitmaps(v1, &v6, 0, dword_10029428, &v9, 1, -1); } */ // 10010388: using guessed type int __stdcall SDlgSetControlBitmaps(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // 10029410: using guessed type int dword_10029410; // 10029428: using guessed type int dword_10029428; // 10029430: using guessed type int (__stdcall *dword_10029430)(DWORD, DWORD, DWORD, DWORD); // ref: 0x10001D81 HFONT __fastcall bn_prof_10001D81(HWND hWnd, int a2, int a3) { return 0; } /* { int v3; // esi void *v4; // ebx int v5; // esi int v6; // eax const char *v7; // ST10_4 HFONT v8; // ebx int *v10; // esi int pv; // [esp+8h] [ebp-40h] int v12; // [esp+18h] [ebp-30h] char v13; // [esp+24h] [ebp-24h] HWND hDlg; // [esp+44h] [ebp-4h] v3 = a2; hDlg = hWnd; v4 = (void *)SendMessageA(hWnd, 0x31u, 0, 0); if ( !v4 ) return 0; memset(&pv, 0, 0x3Cu); if ( !GetObjectA(v4, 60, &pv) ) return 0; v5 = 3 * v3; v6 = MulDiv(dword_10022260[v5], 96, 72); v7 = (&off_10022264)[v5]; pv = -v6; v12 = dword_10022268[v5]; strcpy(&v13, v7); v8 = CreateFontIndirectA((const LOGFONTA *)&pv); if ( !v8 ) return 0; v10 = (int *)a3; if ( a3 ) { while ( *v10 ) { SendDlgItemMessageA(hDlg, *v10, 0x30u, (WPARAM)v8, 0); ++v10; } } return v8; } */ // 10022260: using guessed type int dword_10022260[]; // 10022264: using guessed type char *off_10022264; // 10022268: using guessed type int dword_10022268[]; // ref: 0x10001E34 void UNKCALL bn_prof_10001E34(void *arg) { return; } /* { bn_prof_10001CB9( (DWORD *)dword_1002941C, dword_10029418, (void (__fastcall *)(BYTE *, DWORD, int))bn_prof_10001E4C, (int)arg); } */ // 10029418: using guessed type int dword_10029418; // 1002941C: using guessed type int dword_1002941C; // ref: 0x10001E4C void __fastcall bn_prof_10001E4C(char *a1, LPARAM lParam, HWND hDlg) { return; } /* { int v3; // esi bool v4; // zf LPARAM v5; // ebp char *v6; // ebx const char **v7; // edi int v8; // esi HWND v9; // ebx v3 = 0; v4 = dword_10022258 == 0; v5 = lParam; v6 = a1; if ( dword_10022258 > 0 ) { v7 = (const char **)&off_1001F378; do { if ( !_strcmpi(v6, *v7) ) break; ++v3; v7 += 4; } while ( v3 < dword_10022258 ); v4 = v3 == dword_10022258; } if ( !v4 ) { v8 = 4 * v3; if ( !(byte_1001F37C[v8 * 4] & 4) ) { v9 = GetDlgItem(hDlg, dword_1001F380[v8]); SendMessageA(v9, 0xCu, 0, v5); if ( dword_10029430 ) SendMessageA(v9, 0xC5u, dword_1001F384[v8], 0); } } } */ // 1001F378: using guessed type char *off_1001F378; // 1001F380: using guessed type int dword_1001F380[]; // 1001F384: using guessed type int dword_1001F384[]; // 10022258: using guessed type int dword_10022258; // 10029430: using guessed type int (__stdcall *dword_10029430)(DWORD, DWORD, DWORD, DWORD); // ref: 0x10001ED0 void __fastcall bn_prof_10001ED0(char *a1, BYTE *a2, int a3) { return; } /* { int v3; // esi bool v4; // zf BYTE *v5; // edi char *v6; // ebp const char **v7; // ebx v3 = 0; v4 = dword_10022258 == 0; v5 = a2; v6 = a1; if ( dword_10022258 > 0 ) { v7 = (const char **)&off_1001F378; do { if ( !_strcmpi(v6, *v7) ) break; ++v3; v7 += 4; } while ( v3 < dword_10022258 ); v4 = v3 == dword_10022258; } if ( !v4 ) { if ( *v5 ) dword_10029438[v3] = (int)v5; else dword_10029438[v3] = (int)"0"; } } */ // 1001F378: using guessed type char *off_1001F378; // 10022258: using guessed type int dword_10022258; // ref: 0x10001F29 void *bn_prof_10001F29() { return 0; } /* { int result; // eax bn_prof_100023D8(); bn_prof_10001F84(); if ( ho ) DeleteObject(ho); ho = 0; if ( dword_10029424 ) DeleteObject(dword_10029424); result = dword_10029434; dword_10029424 = 0; if ( dword_10029434 ) result = SMemFree(dword_10029434, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 509, 0); dword_10029434 = 0; return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // 10029434: using guessed type int dword_10029434; // ref: 0x10001F84 BYTE *bn_prof_10001F84() { return 0; } /* { int result; // eax if ( dword_10029410 ) { SMemFree(dword_10029410, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 129, 0); dword_10029410 = 0; } result = dword_10029428; if ( dword_10029428 ) { result = SMemFree(dword_10029428, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 133, 0); dword_10029428 = 0; } return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // 10029410: using guessed type int dword_10029410; // 10029428: using guessed type int dword_10029428; // ref: 0x10001FC8 void __cdecl UiProfileDraw() { return; } //int __stdcall UiProfileDraw(int a1, int a2, int a3, int a4, HGDIOBJ ho, int a6, int a7, int a8, int a9, int a10, int a11) { return 0; } /* { int v11; // eax HFONT v12; // eax int v14; // eax CHAR *v15; // edi int v16; // esi CHAR v17; // al int v18; // ecx int v19; // eax int v20; // edx CHAR Buffer[256]; // [esp+Ch] [ebp-150h] int v22; // [esp+10Ch] [ebp-50h] int v23; // [esp+110h] [ebp-4Ch] int v24; // [esp+114h] [ebp-48h] int v25; // [esp+118h] [ebp-44h] int v26; // [esp+11Ch] [ebp-40h] int v27; // [esp+120h] [ebp-3Ch] int v28; // [esp+124h] [ebp-38h] int v29; // [esp+128h] [ebp-34h] int v30; // [esp+12Ch] [ebp-30h] int v31; // [esp+130h] [ebp-2Ch] int v32; // [esp+134h] [ebp-28h] int v33; // [esp+138h] [ebp-24h] int v34; // [esp+13Ch] [ebp-20h] int v35; // [esp+140h] [ebp-1Ch] int v36; // [esp+144h] [ebp-18h] int v37; // [esp+148h] [ebp-14h] int v38; // [esp+14Ch] [ebp-10h] int v39; // [esp+150h] [ebp-Ch] int v40; // [esp+154h] [ebp-8h] int v41; // [esp+158h] [ebp-4h] HFONT hoa; // [esp+174h] [ebp+18h] int hob; // [esp+174h] [ebp+18h] if ( ho ) return 0; if ( !a9 ) return 0; if ( !a10 ) return 0; if ( !a11 ) return 0; v24 = dword_1002940C; v34 = dword_1002940C; v30 = 0; v31 = 0; v32 = a10; v33 = a11; v36 = a10; v37 = a11; v22 = 0; v23 = 0; v25 = dword_10029414; v35 = dword_10029414; if ( !SBltROP3Clipped(a9, &v30, &v36, a10, dword_1002942C, &v22, &v34, dword_1002940C, 0, 13369376) ) return 0; if ( !LoadStringA(hInstance, 0x4Fu, Buffer, 255) ) return 0; v11 = MulDiv(12, 96, 72); v12 = CreateFontA(-v11, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0x20u, "Arial"); hoa = v12; if ( !v12 ) return 0; v41 = 0; if ( !SGdiImportFont(v12, &v41) ) return 0; DeleteObject(hoa); if ( !v41 || !SGdiSelectObject(v41) ) return 0; v26 = 0; v27 = 0; v28 = a10; v29 = a11; SGdiSetPitch(a10); v14 = SStrLen(Buffer); v15 = Buffer; hob = v14 + 1; v40 = 8; Buffer[v14 + 1] = 0; v16 = v14 + 1; do { if ( v15[v16 - 1] ) { v17 = v15[v16 - 1]; do { if ( v17 == 32 ) break; if ( v17 == 10 ) break; if ( v17 == 9 ) break; if ( v16 <= 1 ) break; v17 = v15[v16-- - 2]; } while ( v17 ); } SGdiGetTextExtent(v15, v16, &v38); if ( v38 >= a10 - 8 ) { v20 = a10 * hob % v38; if ( --v16 >= a10 * hob / v38 ) v16 = a10 * hob / v38; } else { v19 = v16 - 1; if ( v15[v16 - 1] ) v19 = v16; SGdiExtTextOut(a9, 8, v40, &v26, 16777471, 1, 0, v15, v19); if ( v15[v16] == 32 ) ++v16; v15 += v16; v40 += v39; hob -= v16; v16 = hob; } } while ( v16 && hob && v40 < a11 - 8 ); SGdiDeleteObject(v18, v20, v41); return 1; } */ // 1001038E: using guessed type int __fastcall SGdiDeleteObject(DWORD, DWORD, DWORD); // 10010394: using guessed type int __stdcall SGdiExtTextOut(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // 1001039A: using guessed type int __stdcall SGdiGetTextExtent(DWORD, DWORD, DWORD); // 100103A0: using guessed type int __stdcall SStrLen(DWORD); // 100103A6: using guessed type int __stdcall SGdiSetPitch(DWORD); // 100103AC: using guessed type int __stdcall SGdiSelectObject(DWORD); // 100103B2: using guessed type int __stdcall SGdiImportFont(DWORD, DWORD); // 100103B8: using guessed type int __stdcall SBltROP3Clipped(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // 1002940C: using guessed type int dword_1002940C; // 10029414: using guessed type int dword_10029414; // 1002942C: using guessed type int dword_1002942C; // 10001FC8: using guessed type CHAR Buffer[256]; // ref: 0x100021C4 int bn_prof_100021C4() { return 0; } /* { int v0; // edi int v2; // [esp+4h] [ebp-8h] int v3; // [esp+8h] [ebp-4h] v3 = 0; v2 = 0; if ( !SBmpLoadImage("ui_Art\\profilebkg.pcx", 0, 0, 0, &v3, &v2, 0) || !v3 || !v2 ) return 0; v0 = v3 * v2; dword_1002942C = SMemAlloc(v3 * v2, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 760, 0); dword_1002940C = v3; dword_10029414 = v2; return SBmpLoadImage("ui_Art\\profilebkg.pcx", 0, dword_1002942C, v0, &v3, &v2, 0); } */ // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // 100103BE: using guessed type int __stdcall SBmpLoadImage(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // 1002940C: using guessed type int dword_1002940C; // 10029414: using guessed type int dword_10029414; // 1002942C: using guessed type int dword_1002942C; // ref: 0x10002247 void *bn_prof_10002247() { return 0; } /* { int result; // eax result = dword_1002942C; if ( dword_1002942C ) { result = SMemFree(dword_1002942C, "C:\\Src\\Diablo\\DiabloUI\\bn_prof.cpp", 776, 0); dword_1002942C = 0; dword_1002940C = 0; dword_10029414 = 0; } return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // 1002940C: using guessed type int dword_1002940C; // 10029414: using guessed type int dword_10029414; // 1002942C: using guessed type int dword_1002942C; // ref: 0x10002278 int j_bn_prof_10002282() { return 0; } /* { bn_prof_10002282(); return atexit(bn_prof_10002298); } */ // ref: 0x10002282 DWORD *bn_prof_10002282() { return 0; } /* { DWORD *result; // eax DWORD *v1; // edx result = dword_10029460; v1 = &dword_10029460[1]; *v1 = 0; v1[1] = 0; *v1 = v1; dword_10029460[0] = 0; dword_10029460[2] = ~(unsigned int)&dword_10029460[1]; return result; } */ // ref: 0x10002298 void __cdecl bn_prof_10002298() { return; } /* { bn_prof_100026F0(dword_10029460); } */ // ref: 0x100022A2 int UNKCALL bn_prof_100022A2(HWND hWnd) { return 0; } /* { HFONT v2; // eax HFONT v3; // eax char pv; // [esp+4h] [ebp-40h] char v5; // [esp+19h] [ebp-2Bh] HANDLE h; // [esp+40h] [ebp-4h] if ( !hWnd ) return 0; h = (HANDLE)SendMessageA(hWnd, 0x31u, 0, 0); if ( !h ) return 0; memset(&pv, 0, 0x3Cu); if ( GetObjectA(h, 60, &pv) ) { v2 = CreateFontIndirectA((const LOGFONTA *)&pv); if ( v2 ) { dword_10029450 = v2; dword_10029458 = bn_prof_10002353(v2); } } memset(&pv, 0, 0x3Cu); if ( GetObjectA(h, 60, &pv) ) { v5 = 1; v3 = CreateFontIndirectA((const LOGFONTA *)&pv); if ( v3 ) { ::h = v3; dword_1002946C = bn_prof_10002353(v3); } } return 1; } */ // 10029458: using guessed type int dword_10029458; // 1002946C: using guessed type int dword_1002946C; // ref: 0x10002353 int UNKCALL bn_prof_10002353(HGDIOBJ h) { return 0; } /* { HGDIOBJ v1; // ebx HWND v2; // eax HDC v3; // ebp HDC v4; // esi HWND v5; // eax int v7; // [esp+10h] [ebp-10h] HGDIOBJ ha; // [esp+14h] [ebp-Ch] struct tagSIZE psizl; // [esp+18h] [ebp-8h] v1 = h; v2 = GetDesktopWindow(); v3 = GetDC(v2); v4 = CreateCompatibleDC(v3); v7 = 0; ha = SelectObject(v4, v1); if ( GetTextExtentPoint32A(v4, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &psizl) ) v7 = (psizl.cx / 26 + 1) / 2; SelectObject(v4, ha); DeleteDC(v4); v5 = GetDesktopWindow(); ReleaseDC(v5, v3); return v7; } */ // ref: 0x100023D8 HGDIOBJ bn_prof_100023D8() { return 0; } /* { HGDIOBJ result; // eax int v1; // esi if ( dword_10029450 ) { DeleteObject(dword_10029450); dword_10029450 = 0; } result = h; if ( h ) { result = (HGDIOBJ)DeleteObject(h); h = 0; } while ( 1 ) { v1 = dword_10029460[2]; if ( v1 <= 0 ) break; bn_prof_100027D8((DWORD *)dword_10029460[2]); result = (HGDIOBJ)SMemFree(v1, ".?AU_DRAWTEXT@@", -2, 0); } return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // ref: 0x10002410 DWORD *__fastcall bn_prof_10002410(HDC hdc, DWORD *a2) { return 0; } /* { HDC v2; // ebp DWORD *v3; // esi DWORD *v4; // eax DWORD *v5; // ebx DWORD *v6; // esi v2 = hdc; v3 = a2; v4 = bn_prof_10002782(dword_10029460, 2, 0, 0); v5 = v4; v4[2] = v2; v4[3] = *v3; ++v3; v4[4] = *v3; ++v3; v4[5] = *v3; v4[6] = v3[1]; v4[7] = 0; v4[8] = 0; v6 = v4 + 9; GetTextMetricsA(v2, (LPTEXTMETRICA)(v4 + 9)); v5[23] = *v6 + v5[13]; return v5; } */ // ref: 0x10002456 signed int __fastcall bn_prof_10002456(int a1, const CHAR *a2, char a3, DWORD *a4) { return 0; } /* { int v4; // esi HGDIOBJ v6; // edi int v7; // eax int v8; // ecx int v9; // edi int v10; // eax int v11; // eax int v12; // eax LPCSTR v13; // ebx LONG v14; // ecx int v15; // eax int v16; // eax int v17; // eax int v18; // ecx const CHAR *v19; // eax int v20; // eax int v21; // eax COLORREF v22; // [esp-Ch] [ebp-2Ch] struct tagSIZE Size; // [esp+4h] [ebp-1Ch] COLORREF color; // [esp+Ch] [ebp-14h] HGDIOBJ h; // [esp+10h] [ebp-10h] int cchString; // [esp+14h] [ebp-Ch] LPCSTR lpszString; // [esp+18h] [ebp-8h] int nFit; // [esp+1Ch] [ebp-4h] int v29; // [esp+28h] [ebp+8h] v4 = a1; lpszString = a2; if ( !a1 ) return 0; cchString = strlen(a2); if ( a4 ) memset(a4, 0, 0x10u); h = 0; if ( a3 & 2 ) { v6 = ::h; v7 = dword_1002946C; v22 = 16711680; } else { v6 = dword_10029450; v7 = dword_10029458; v22 = 0xFFFFFF; } v29 = v7; color = SetTextColor(*(HDC *)(v4 + 8), v22); if ( v6 ) h = SelectObject(*(HDC *)(v4 + 8), v6); if ( a4 ) { *a4 = *(DWORD *)(v4 + 28); a4[1] = *(DWORD *)(v4 + 32); } do { while ( cchString > 0 && *(WORD *)lpszString == 2573 ) { v8 = *(DWORD *)(v4 + 92); cchString -= 2; *(DWORD *)(v4 + 32) += v8; lpszString += 2; *(DWORD *)(v4 + 28) = 0; } if ( !cchString ) break; nFit = 0; GetTextExtentExPointA( *(HDC *)(v4 + 8), lpszString, cchString, *(DWORD *)(v4 + 20) - *(DWORD *)(v4 + 28) - *(DWORD *)(v4 + 12) - v29 + 1, &nFit, 0, &Size); v9 = nFit; if ( nFit ) { if ( nFit < cchString ) { if ( nFit > 0 ) { do { if ( isspace(lpszString[v9]) ) break; --v9; } while ( v9 > 0 ); if ( v9 > 0 ) { LABEL_26: ++v9; goto LABEL_27; } } if ( *(DWORD *)(v4 + 28) > 0 ) { if ( isspace(lpszString[v9]) ) goto LABEL_26; LABEL_27: nFit = v9; } } v11 = 0; if ( nFit > 0 ) { while ( *(WORD *)&lpszString[v11] != 2573 && lpszString[v11] != 9 ) { if ( ++v11 >= nFit ) goto LABEL_34; } nFit = v11; } LABEL_34: if ( a4 ) { v12 = *(DWORD *)(v4 + 28); if ( v12 < *a4 ) *a4 = v12; } else { ExtTextOutA( *(HDC *)(v4 + 8), *(DWORD *)(v4 + 28), *(DWORD *)(v4 + 32), 4u, (const RECT *)(v4 + 12), lpszString, nFit, 0); } v13 = lpszString; GetTextExtentPoint32A(*(HDC *)(v4 + 8), lpszString, nFit, &Size); v14 = Size.cx; if ( a4 ) { v15 = Size.cx + *(DWORD *)(v4 + 28); if ( v15 > a4[2] ) a4[2] = v15; v16 = Size.cy + *(DWORD *)(v4 + 32); if ( v16 > a4[3] ) a4[3] = v16; } v17 = nFit; *(DWORD *)(v4 + 28) += v14; v18 = *(DWORD *)(v4 + 28); if ( v17 < cchString ) { v19 = &v13[v17]; if ( *v19 == 9 ) { ++nFit; *(DWORD *)(v4 + 28) = 8 * v29 + v18 - v18 % (8 * v29); } else { if ( *(WORD *)v19 == 2573 ) nFit += 2; v20 = *(DWORD *)(v4 + 92); *(DWORD *)(v4 + 28) = 0; *(DWORD *)(v4 + 32) += v20; } } cchString -= nFit; lpszString += nFit; continue; } v10 = *(DWORD *)(v4 + 92); *(DWORD *)(v4 + 28) &= nFit; *(DWORD *)(v4 + 32) += v10; } while ( cchString > 0 ); if ( *(DWORD *)(v4 + 28) > *(DWORD *)(v4 + 20) - *(DWORD *)(v4 + 12) - v29 + 1 ) { v21 = *(DWORD *)(v4 + 92); *(DWORD *)(v4 + 28) = 0; *(DWORD *)(v4 + 32) += v21; } if ( h ) SelectObject(*(HDC *)(v4 + 8), h); SetTextColor(*(HDC *)(v4 + 8), color); return 1; } */ // 10029458: using guessed type int dword_10029458; // 1002946C: using guessed type int dword_1002946C; // ref: 0x100026B9 signed int bn_prof_100026B9() { return 0; } /* { signed int result; // eax result = 2139095040; dword_10029454 = 2139095040; return result; } */ // 10029454: using guessed type int dword_10029454; // ref: 0x100026C4 signed int UNKCALL bn_prof_100026C4(DWORD *arg) { return 0; } /* { if ( !arg ) return 0; bn_prof_10002749((char *)dword_10029460, arg); return 1; } */ // ref: 0x100026F0 void UNKCALL bn_prof_100026F0(DWORD *arg) { return; } /* { DWORD *v1; // esi v1 = arg; bn_prof_1000287D(arg); bn_prof_10002890(v1 + 1); } */ // ref: 0x10002749 int UNKCALL bn_prof_10002749(char *arg, DWORD *a2) { return 0; } /* { int v2; // eax int v3; // eax int v4; // esi v2 = (int)a2; if ( !a2 ) v2 = (int)(arg + 4); v3 = *(DWORD *)(v2 + 4); if ( v3 > 0 ) v4 = v3; else v4 = 0; bn_prof_100027D8(a2); SMemFree(a2, ".?AU_DRAWTEXT@@", -2, 0); return v4; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // ref: 0x10002782 DWORD *UNKCALL bn_prof_10002782(int *arg, int a2, int a3, int a4) { return 0; } /* { int v4; // eax int *v5; // edi DWORD *v6; // eax DWORD *v7; // esi v4 = a4; LOBYTE(v4) = a4 | 8; v5 = arg; v6 = (DWORD *)SMemAlloc(a3 + 96, ".?AU_DRAWTEXT@@", -2, v4); if ( v6 ) v7 = bn_prof_100027CE(v6); else v7 = 0; if ( a2 ) bn_prof_1000280C(v5, v7, a2, 0); return v7; } */ // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // ref: 0x100027CE DWORD *UNKCALL bn_prof_100027CE(DWORD *arg) { return 0; } /* { DWORD *result; // eax result = arg; *arg = 0; arg[1] = 0; return result; } */ // ref: 0x100027D8 void UNKCALL bn_prof_100027D8(DWORD *arg) { return; } /* { DWORD *v1; // ST00_4 v1 = arg; bn_prof_10002890(arg); bn_prof_10002890(v1); } */ // ref: 0x1000280C DWORD *UNKCALL bn_prof_1000280C(int *arg, DWORD *a2, int a3, DWORD *a4) { return 0; } /* { int *v4; // edi DWORD *v5; // esi DWORD *result; // eax int v7; // ecx int v8; // edx int v9; // ecx int v10; // edx v4 = arg; v5 = a2; if ( !a2 ) v5 = arg + 1; if ( *v5 ) bn_prof_10002890(v5); result = a4; if ( !a4 ) result = v4 + 1; if ( a3 == 1 ) { *v5 = result; v5[1] = result[1]; v8 = result[1]; v9 = *v4; if ( v8 > 0 ) { if ( v9 < 0 ) v9 = (int)result - *(DWORD *)(*result + 4); v10 = v9 + v8; } else { v10 = ~v8; } *(DWORD *)v10 = v5; result[1] = a2; } else if ( a3 == 2 ) { v7 = *result; *v5 = *result; v5[1] = *(DWORD *)(v7 + 4); *(DWORD *)(v7 + 4) = a2; *result = v5; } return result; } */ // ref: 0x1000287D void UNKCALL bn_prof_1000287D(DWORD *arg) { return; } /* { DWORD *v1; // esi DWORD *v2; // ecx v1 = arg; while ( 1 ) { v2 = (DWORD *)v1[2]; if ( (signed int)v2 <= 0 ) break; bn_prof_10002890(v2); } } */ // ref: 0x10002890 void UNKCALL bn_prof_10002890(DWORD *arg) { return; } /* { int v1; // esi int v2; // edx int v3; // edx v1 = *arg; if ( *arg ) { v2 = arg[1]; if ( v2 > 0 ) v3 = (int)arg + v2 - *(DWORD *)(v1 + 4); else v3 = ~v2; *(DWORD *)v3 = v1; *(DWORD *)(*arg + 4) = arg[1]; *arg = 0; arg[1] = 0; } } */ ================================================ FILE: DiabloUI/bnetgw.cpp ================================================ // ref: 0x100028C2 void UNKCALL BNetGW_100028C2(DWORD *arg) { return; } /* { DWORD *v1; // esi bool v2; // zf bool v3; // sf int v4; // edi int v5; // eax int v6; // edi int v7; // ST08_4 int v8; // eax signed int v9; // eax struct _TIME_ZONE_INFORMATION TimeZoneInformation; // [esp+Ch] [ebp-B8h] char *v11; // [esp+B8h] [ebp-Ch] int v12; // [esp+BCh] [ebp-8h] int v13; // [esp+C0h] [ebp-4h] v1 = arg; arg[2] = 0; arg[3] = 0; arg[4] = 0; arg[5] = 0; arg[6] = 0; *(BYTE *)arg = 0; BNetGW_10002C23(arg); if ( !v1[4] ) goto LABEL_15; if ( v1[6] < 0x3E8u ) { v1[1] = 0; BNetGW_10002A07(v1); SRegDeleteValue("Configuration", "Battle.net gateways", 2u); } if ( !v1[4] ) LABEL_15: BNetGW_10002C51(v1); if ( v1[6] >= 0x3E8u ) { v2 = v1[5] == 0; v3 = v1[5] < 0; v4 = v1[4]; v13 = -2; v12 = 0; if ( !v3 && !v2 ) { do { v5 = SStrLen(v4) + 1; v12 += v5; v4 += v5; ++v13; } while ( v12 < v1[5] ); } v6 = v1[4]; v7 = v1[4]; v1[2] = v13 / 3; v8 = SStrLen(v7); v9 = strtoul((const char *)(v6 + v8 + 1), &v11, 10); v1[3] = v9; v1[1] = 0; if ( v9 < 1 || v9 > v1[2] ) { SMemZero(&TimeZoneInformation, 172); GetTimeZoneInformation(&TimeZoneInformation); BNetGW_100029BF(v1, TimeZoneInformation.Bias); } } else { v1[2] = 0; v1[3] = 0; } } */ // 100103A0: using guessed type int __stdcall SStrLen(DWORD); // 100103C4: using guessed type int __stdcall SMemZero(DWORD, DWORD); // 100103CA: using guessed type int __stdcall SRegDeleteValue(const char *, const char *, unsigned int); // ref: 0x100029BF void UNKCALL BNetGW_100029BF(DWORD *arg, int a2) { return; } /* { DWORD *v2; // esi char *v3; // edi signed int v4; // ebx signed int v5; // ebp int v6; // eax int v7; // eax v2 = arg; v3 = (char *)1; v4 = 1380; v5 = 1; if ( arg[2] >= 1 ) { do { v6 = BNetGW_10002AF0(v2, v3); v7 = abs(60 * v6 - a2); if ( v7 < v4 ) { v4 = v7; v5 = (signed int)v3; } ++v3; } while ( (signed int)v3 <= v2[2] ); } BNetGW_10002B51(v2, v5); } */ // ref: 0x10002A07 void *UNKCALL BNetGW_10002A07(DWORD *arg) { return 0; } /* { DWORD *v1; // esi int v2; // edi BYTE *v3; // ecx const char *v4; // eax int result; // eax v1 = arg; if ( arg[1] ) { v2 = arg[4]; if ( v2 ) { v3 = (BYTE *)(v2 + SStrLen(arg[4]) + 1); *v3 = v1[3] / 10 + 48; v4 = "Override Battle.net gateways"; v3[1] = v1[3] % 10 + 48; if ( !v1[7] ) v4 = "Battle.net gateways"; SRegSaveData("Configuration", v4, 0x82u, (void *)v1[4], v1[5]); } } result = v1[4]; if ( result ) { result = SMemFree(result, "C:\\Src\\Diablo\\DiabloUI\\BNetGW.cpp", 152, 0); v1[4] = 0; v1[5] = 0; } return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // 100103A0: using guessed type int __stdcall SStrLen(DWORD); // 100103D0: using guessed type int __stdcall SRegSaveData(const char *, const char *, unsigned int, void *, unsigned int); // ref: 0x10002A84 DWORD *UNKCALL BNetGW_10002A84(DWORD *arg, signed int a2) { return 0; } /* { signed int v2; // eax signed int v3; // ebx int v4; // esi int v5; // edi bool v6; // sf unsigned char v7; // of int v8; // eax DWORD *result; // eax DWORD *v10; // [esp+8h] [ebp-4h] DWORD *v11; // [esp+14h] [ebp+8h] v10 = arg; if ( !arg[4] ) return arg; v2 = a2; v3 = 1; if ( a2 < 1 || a2 > arg[2] ) return arg; v4 = 3 * a2; v5 = 0; v11 = (DWORD *)arg[4]; if ( 3 * v2 <= 1 ) { LABEL_7: v7 = __OFSUB__(v5, arg[5]); v6 = v5 - arg[5] < 0; } else { while ( 1 ) { v7 = __OFSUB__(v5, arg[5]); v6 = v5 - arg[5] < 0; if ( v5 >= arg[5] ) break; v8 = SStrLen(v11); arg = v10; v11 = (DWORD *)((char *)v11 + ++v8); v5 += v8; if ( ++v3 >= v4 ) goto LABEL_7; } } if ( !(v6 ^ v7) ) return arg; result = v11; if ( v3 > v4 ) return arg; return result; } */ // 100103A0: using guessed type int __stdcall SStrLen(DWORD); // ref: 0x10002AE5 signed int BNetGW_10002AE5() { return 0; } /* { signed int result; // eax result = 2139095040; dword_10029478 = 2139095040; return result; } */ // 10029478: using guessed type int dword_10029478; // ref: 0x10002AF0 int UNKCALL BNetGW_10002AF0(DWORD *arg, char *a2) { return 0; } /* { const char *v2; // eax const char *v3; // esi v2 = (const char *)BNetGW_10002A84(arg, (signed int)a2); v3 = v2; if ( *v2 ) v3 = &v2[SStrLen(v2) + 1]; return strtol(v3, &a2, 10); } */ // 100103A0: using guessed type int __stdcall SStrLen(DWORD); // ref: 0x10002B21 BYTE *UNKCALL BNetGW_10002B21(DWORD *arg, signed int a2) { return 0; } /* { DWORD *v2; // eax BYTE *v3; // esi v2 = BNetGW_10002A84(arg, a2); v3 = v2; if ( *(BYTE *)v2 ) { v3 = (char *)v2 + SStrLen(v2) + 1; if ( *v3 ) v3 += SStrLen(v3) + 1; } return v3; } */ // 100103A0: using guessed type int __stdcall SStrLen(DWORD); // ref: 0x10002B51 void UNKCALL BNetGW_10002B51(DWORD *arg, signed int a2) { return; } /* { signed int v2; // eax if ( arg[4] ) { v2 = a2; if ( a2 >= 1 && a2 <= arg[2] ) { if ( a2 > 99 ) v2 = 99; arg[3] = v2; arg[1] = 1; } } } */ // ref: 0x10002B78 char *UNKCALL BNetGW_10002B78(DWORD *arg, char *a2) { return 0; } /* { DWORD *v2; // esi char *result; // eax char *v4; // ST08_4 void *v5; // eax char *v6; // [esp+Ch] [ebp-4h] v2 = arg; v6 = 0; result = (char *)SRegLoadData("Configuration", a2, 0x82u, 0, 0, (unsigned int *)&v6); if ( result ) { result = v6; if ( v6 ) { v4 = v6; v2[5] = v6; v5 = (void *)SMemAlloc(v4, "C:\\Src\\Diablo\\DiabloUI\\BNetGW.cpp", 263, 0); v2[4] = v5; if ( !SRegLoadData("Configuration", a2, 0x82u, v5, v2[5], 0) ) { SMemFree(v2[4], "C:\\Src\\Diablo\\DiabloUI\\BNetGW.cpp", 271, 0); v2[4] = 0; v2[5] = 0; } result = (char *)v2[4]; v2[6] = 0; if ( result ) { a2 = result; v2[6] = strtoul(result, &a2, 10); result = (char *)v2[4]; if ( result == a2 ) v2[6] = 0; } } } return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // 100103D6: using guessed type int __stdcall SRegLoadData(const char *, const char *, unsigned int, void *, unsigned int, unsigned int *); // ref: 0x10002C23 char *UNKCALL BNetGW_10002C23(DWORD *arg) { return 0; } /* { DWORD *v1; // esi char *result; // eax v1 = arg; arg[7] = 0; result = BNetGW_10002B78(arg, "Override Battle.net gateways"); if ( !v1[4] ) return BNetGW_10002B78(v1, "Battle.net gateways"); v1[7] = 1; return result; } */ // ref: 0x10002C51 int UNKCALL BNetGW_10002C51(DWORD *arg) { return 0; } /* { int result; // eax char *v2; // edi char *v3; // esi unsigned int v4; // ebx char *v5; // esi BYTE *v6; // esi char *v7; // eax char *v8; // eax BYTE *v9; // esi char *v10; // esi char v11; // al unsigned int v12; // esi char *v13; // [esp+4h] [ebp-10h] int v14; // [esp+8h] [ebp-Ch] int v15; // [esp+Ch] [ebp-8h] DWORD *v16; // [esp+10h] [ebp-4h] v15 = 0; v16 = arg; result = BNetGW_10002DBF(&v15); v2 = (char *)result; v14 = result; if ( result ) { v3 = (char *)SMemAlloc(2 * v15, "C:\\Src\\Diablo\\DiabloUI\\BNetGW.cpp", 358, 0); v13 = v3; v4 = (unsigned int)&v2[v15]; sprintf(v3, "%d", 1000); v5 = &v3[SStrLen(v3) + 1]; *v5++ = 48; *v5++ = 48; *v5 = 0; v6 = v5 + 1; if ( (unsigned int)v2 < v4 ) { if ( (unsigned int)v2 >= v4 ) goto LABEL_8; do { if ( *v2 == 35 ) { v7 = BNetGW_10002DEB(v2, v4); v8 = BNetGW_10002E0B(v7, v4); } else { do { if ( isspace(*v2) ) break; *v6++ = *v2++; } while ( (unsigned int)v2 < v4 ); LABEL_8: *v6 = 0; v9 = v6 + 1; if ( (unsigned int)v2 < v4 ) { do { if ( !isspace(*v2) ) break; ++v2; } while ( (unsigned int)v2 < v4 ); while ( (unsigned int)v2 < v4 && !isspace(*v2) ) *v9++ = *v2++; } *v9 = 0; v10 = v9 + 1; if ( (unsigned int)v2 < v4 ) { do { if ( !isspace(*v2) ) break; ++v2; } while ( (unsigned int)v2 < v4 ); while ( (unsigned int)v2 < v4 ) { v11 = *v2; if ( *v2 == 13 || v11 == 10 ) break; *v10++ = v11; ++v2; } } *v10 = 0; v6 = v10 + 1; v8 = BNetGW_10002E0B(v2, v4); } v2 = v8; } while ( (unsigned int)v8 < v4 ); } *v6 = 0; v12 = v6 - v13 + 1; SRegSaveData("Configuration", "Battle.net gateways", 0x82u, v13, v12); SMemFree(v14, "C:\\Src\\Diablo\\DiabloUI\\BNetGW.cpp", 429, 0); result = (int)v16; v16[5] = v12; *(DWORD *)(result + 16) = v13; *(DWORD *)(result + 24) = 1000; } return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // 100103A0: using guessed type int __stdcall SStrLen(DWORD); // 100103D0: using guessed type int __stdcall SRegSaveData(const char *, const char *, unsigned int, void *, unsigned int); // ref: 0x10002DBF int UNKCALL BNetGW_10002DBF(DWORD *arg) { return 0; } /* { DWORD *v1; // esi int v3; // [esp+4h] [ebp-8h] int v4; // [esp+8h] [ebp-4h] v4 = 0; v1 = arg; SFileLoadFile("rez\\gateways.txt", &v3, &v4, 0, 0); *v1 = v4; return v3; } */ // 100103DC: using guessed type int __stdcall SFileLoadFile(DWORD, DWORD, DWORD, DWORD, DWORD); // ref: 0x10002DEB char *__stdcall BNetGW_10002DEB(char *a1, unsigned int a2) { return 0; } /* { char *result; // eax char v3; // cl for ( result = a1; (unsigned int)result < a2; ++result ) { v3 = *result; if ( !*result || v3 == 13 || v3 == 10 ) break; } return result; } */ // ref: 0x10002E0B char *__stdcall BNetGW_10002E0B(char *a1, unsigned int a2) { return 0; } /* { char *result; // eax char v3; // cl for ( result = a1; (unsigned int)result < a2; ++result ) { v3 = *result; if ( !*result || v3 != 13 && v3 != 10 ) break; } return result; } */ ================================================ FILE: DiabloUI/connect.cpp ================================================ // ref: 0x10002E2B void __cdecl Connect_FreeConnectData() { HANDLE *v0; // edi if (connect_data1) { SMemFree(connect_data1, "C:\\Src\\Diablo\\DiabloUI\\Connect.cpp", 124, 0); connect_data1 = 0; } if (connect_data2) { SMemFree(connect_data2, "C:\\Src\\Diablo\\DiabloUI\\Connect.cpp", 129, 0); connect_data2 = 0; } v0 = connect_trans; do { if (*v0) { STransDelete(*v0); *v0 = 0; } ++v0; } while ((signed int)v0 < (signed int)&connect_trans[10]); if (connect_data3) { SMemFree(connect_data3, "C:\\Src\\Diablo\\DiabloUI\\Connect.cpp", 141, 0); connect_data3 = 0; } if (connect_data4) { SMemFree(connect_data4, "C:\\Src\\Diablo\\DiabloUI\\Connect.cpp", 146, 0); connect_data4 = 0; } } // ref: 0x10002EC4 BOOL __cdecl Connect_LoadGFXAndStuff() { HANDLE *v0; // esi int v1; // ebx int a5[4]; // [esp+4h] [ebp-14h] BYTE *a2; // [esp+14h] [ebp-4h] a2 = 0; if (!connect_data1 && !connect_trans[0]) { local_LoadArtImage("ui_art\\heroport.pcx", &connect_data1, heroport_data); local_LoadArtImage("ui_art\\spwnport.pcx", &connect_data2, 0); local_LoadArtImage("ui_art\\heronum.pcx", &a2, heronum_data); local_LoadArtImage("ui_art\\special.pcx", &connect_data3, special_data); connect_draw_height = 14; heronum_frames = (signed int)heronum_data[1] / 10; special_frames = (signed int)special_data[1] / 8; heronum_frames2 = (signed int)heronum_data[1] / 10 * heronum_data[0]; heroport_frames = 14 * heroport_data[0]; v0 = connect_trans; connect_data4 = SMemAlloc(14 * heroport_data[0], "C:\\Src\\Diablo\\DiabloUI\\Connect.cpp", 194, 0); memset(connect_trans, 0, 0x28u); if (a2) { v1 = 0; do { a5[0] = 0; a5[2] = heronum_data[0] - 1; a5[1] = v1 * heronum_frames; a5[3] = heronum_frames + v1 * heronum_frames - 1; STransCreateI(a2, heronum_data[0], heronum_frames, 8, (int)a5, 16777455, v0); ++v0; ++v1; } while ((signed int)v0 < (signed int)&connect_trans[10]); SMemFree(a2, "C:\\Src\\Diablo\\DiabloUI\\Connect.cpp", 218, 0); } } return 1; } // 100294A4: using guessed type int special_frames; // 100295B0: using guessed type int heronum_frames2; // 100295C0: using guessed type int heroport_frames; // ref: 0x10003009 BOOL __stdcall UiArtCallback(int game_type, unsigned int art_code, PALETTEENTRY *pPalette, BYTE *pBuffer, DWORD dwBuffersize, DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwBpp) { BOOL result; // eax char pszFileName[MAX_PATH]; // [esp+8h] [ebp-104h] pszFileName[0] = nullcharacter; memset(&pszFileName[1], 0, 0x100u); *(WORD *)&pszFileName[257] = 0; pszFileName[259] = 0; SStrCopy(pszFileName, "ui_art\\", sizeof(pszFileName)); if (game_type == 'BNET') { if (art_code > 0x80000004) { switch (art_code) { case 0x80000005: SStrPack(pszFileName, "bnconnbg.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x80000006: SStrPack(pszFileName, "bnselchn.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x80000007: SStrPack(pszFileName, "bnlogin.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x80000008: SStrPack(pszFileName, "newaccount.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x80000009: SStrPack(pszFileName, "changepassword.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x8000000A: SStrPack(pszFileName, "bnladder.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x8000000B: SStrPack(pszFileName, "badconn.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x8000000C: SStrPack(pszFileName, "welcome.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x8000000D: SStrPack(pszFileName, "lepopup.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x8000000E: SStrPack(pszFileName, "tos.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); } } else { if (art_code == 0x80000004) { SStrPack(pszFileName, "redlag.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); } if (art_code > 7) { switch (art_code) { case 8u: LABEL_48: SStrPack(pszFileName, "but_lrg.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x80000000: SStrPack(pszFileName, "bnbuttns.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x80000001: SStrPack(pszFileName, "chat_bkg.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x80000002: SStrPack(pszFileName, "greenlag.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x80000003: SStrPack(pszFileName, "yellolag.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); } } else { switch (art_code) { case 7u: LABEL_47: SStrPack(pszFileName, "but_med.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0u: SStrPack(pszFileName, "bn_bkg.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 2u: SStrPack(pszFileName, "bnjoinbg.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 3u: SStrPack(pszFileName, "hpopup.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 5u: LABEL_46: SStrPack(pszFileName, "but_xsm.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 6u: LABEL_11: SStrPack(pszFileName, "but_sml.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); } } } } else if (game_type == 'IPXN') { if (!art_code) { SStrPack(pszFileName, "ipx_bkg.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); } } else if (!game_type && !art_code) { SStrPack(pszFileName, "connect.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); } switch (art_code) { case 0u: case 2u: SStrPack(pszFileName, "menu.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 1u: case 8u: goto LABEL_48; case 3u: case 4u: SStrPack(pszFileName, "lpopup.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 5u: goto LABEL_46; case 6u: goto LABEL_11; case 7u: goto LABEL_47; case 9u: SStrPack(pszFileName, "xsmlogo.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0xAu: SStrPack(pszFileName, "prog_bg.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0xBu: SStrPack(pszFileName, "prog_fil.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0xCu: SStrPack(pszFileName, "spopup.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0xDu: SStrPack(pszFileName, "scrlarrw.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0xEu: SStrPack(pszFileName, "scrlthmb.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0xFu: SStrPack(pszFileName, "scrlbar.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x10u: SStrPack(pszFileName, "cmel.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x11u: SStrPack(pszFileName, "cmml.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x12u: SStrPack(pszFileName, "cmbl.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x13u: SStrPack(pszFileName, "cmec.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x14u: SStrPack(pszFileName, "cmmc.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x15u: SStrPack(pszFileName, "cmbc.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x16u: SStrPack(pszFileName, "cmer.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x17u: SStrPack(pszFileName, "cmmr.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x18u: SStrPack(pszFileName, "cmbr.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x19u: SStrPack(pszFileName, "slgray.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x1Au: SStrPack(pszFileName, "slthumb.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x1Bu: SStrPack(pszFileName, "slfocus.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x1Cu: SStrPack(pszFileName, "slleft.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x1Du: SStrPack(pszFileName, "slmiddle.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x1Eu: SStrPack(pszFileName, "slright.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x20u: SStrPack(pszFileName, "but_checkoff.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); case 0x21u: SStrPack(pszFileName, "but_checkon.pcx", sizeof(pszFileName)); return SBmpLoadImage(pszFileName, pPalette, pBuffer, dwBuffersize, pdwWidth, pdwHeight, pdwBpp); default: result = 0; break; } return result; } // 100103E2: using guessed type unsigned int __stdcall SStrPack(char *, const char *, unsigned int); // ref: 0x100033D1 void __cdecl Connect_cpp_init() { Connect_cpp_float = Connect_cpp_float_value; } // 1001F3F4: using guessed type int Connect_cpp_float_value; // 100294A0: using guessed type int Connect_cpp_float; // ref: 0x100033DC BOOL __stdcall UiGetDataCallback(int game_type, int data_code, void *a3, int a4, int a5) { signed int v5; // edi DWORD *v6; // esi HCURSOR v7; // eax v5 = 0; if (game_type != 'BNET' || data_code != 0x80000000) { switch (data_code) { case 1: v5 = 16; if (!a3) goto LABEL_24; if ((unsigned int)a4 >= 0x10) { memcpy(a3, connect_subnet_ip, 0x10u); goto LABEL_24; } return 0; case 2: v6 = (DWORD *)a3; v5 = 4; if (!a3) goto LABEL_24; if ((unsigned int)a4 < 4) return 0; v7 = LoadCursorA(ghUiInst, "DIABLO_LINKCURSOR"); break; case 3: v6 = (DWORD *)a3; v5 = 4; if (!a3) goto LABEL_24; if ((unsigned int)a4 < 4) return 0; v7 = LoadCursorA(ghUiInst, "DIABLO_ARROWCURSOR"); break; case 4: v6 = (DWORD *)a3; v5 = 4; if (!a3) goto LABEL_24; if ((unsigned int)a4 < 4) return 0; v7 = LoadCursorA(ghUiInst, "DIABLOIBEAM"); break; default: goto LABEL_24; } *v6 = (DWORD)v7; if (v7) goto LABEL_24; return 0; } v5 = 4; if (a3) { if ((unsigned int)a4 >= 4) { *(DWORD *)a3 = 54; goto LABEL_24; } return 0; } LABEL_24: if (a5) *(DWORD *)a5 = v5; return v5 != 0; } // ref: 0x100034AB BOOL __stdcall UiSoundCallback(int a1, int type, int a3) { if (type) { if (type == 1) TitleSnd_PlaySelectSound(); } else { TitleSnd_PlayMoveSound(); } return 0; } // ref: 0x100034C8 BOOL __stdcall UiAuthCallback(int a1, char *a2, char *a3, char a4, char *a5, LPSTR lpBuffer, int cchBufferMax) { size_t v7; // edi size_t v8; // ebx int v9; // ebx char *v10; // ebx size_t v11; // eax int v12; // eax int v14; // eax char v15[256]; // [esp+0h] [ebp-434h] char a1a[256]; // [esp+100h] [ebp-334h] char v17[256]; // [esp+200h] [ebp-234h] char Buffer[256]; // [esp+300h] [ebp-134h] _uiheroinfo heroinfo; // [esp+400h] [ebp-34h] _gamedata GameData; // [esp+42Ch] [ebp-8h] *(DWORD *)&GameData.bDiff = 0; if (cchBufferMax) *lpBuffer = 0; v7 = strlen(a3) + 1; v8 = strlen(a5) + 1; if (v7 > 0x100 || v8 > 0x100) { if (lpBuffer) LoadStringA(ghUiInst, 0x413u, lpBuffer, cchBufferMax); return 0; } memcpy(a1a, a3, v7); memcpy(v17, a5, v8); if (Connect_GetHeroInfoConc(a1a, &heroinfo)) { if (a1 == 1) { if (!(a4 & 9)) { v9 = 0; while (1) { LoadStringA(ghUiInst, v9 + 4, Buffer, 256); if (strstr(v17, Buffer)) break; if (++v9 >= 3) goto LABEL_16; } if (heroinfo.heroclass != v9) goto LABEL_20; *(DWORD *)&GameData.bDiff = 1; LABEL_16: LoadStringA(ghUiInst, 0x408u, Buffer, 256); v10 = strstr(v17, Buffer); if (v10) { v11 = strlen(Buffer); v12 = atoi(&v10[v11]); if (heroinfo.level >= v12) return 1; } if (*(DWORD *)&GameData.bDiff) return 1; LABEL_20: if (lpBuffer) { LoadStringA(ghUiInst, 0x415u, v15, 256); v14 = sprintf(Buffer, v15, v17) + 1; if (cchBufferMax >= v14) { memcpy(lpBuffer, Buffer, v14); } else { memcpy(lpBuffer, Buffer, cchBufferMax); lpBuffer[cchBufferMax - 1] = 0; } } return 0; } } else if (!(a4 & 8)) { Connect_DiffFromString(v17, &GameData, 0, 0); if (GameData.bDiff == 1) { if (heroinfo.level < 20u) { if (lpBuffer) LoadStringA(ghUiInst, 0x411u, lpBuffer, cchBufferMax); return 0; } } else if (GameData.bDiff == 2 && heroinfo.level < 30u) { if (lpBuffer) LoadStringA(ghUiInst, 0x412u, lpBuffer, cchBufferMax); return 0; } } return 1; } if (lpBuffer) LoadStringA(ghUiInst, 0x414u, lpBuffer, cchBufferMax); return 0; } // ref: 0x10003710 BOOL __stdcall UiDrawDescCallback(int game_type, COLORREF color, LPCSTR lpString, char *a4, int a5, UINT align, time_t a7, HDC *a8) { HDC *v8; // ebx HDC v9; // esi int v10; // esi size_t v11; // eax UINT v13; // eax BOOL v14; // esi int v15; // eax int v16; // eax HDC v17; // ST20_4 struct tm *v18; // eax struct tm *v19; // edi signed int v20; // eax int v21; // eax int v22; // eax UINT v23; // eax int v24; // esi int v25; // eax int v26; // eax signed int v27; // [esp-4h] [ebp-2E8h] char a1[256]; // [esp+Ch] [ebp-2D8h] char String[128]; // [esp+10Ch] [ebp-1D8h] char Buffer[128]; // [esp+18Ch] [ebp-158h] CHAR v31[32]; // [esp+20Ch] [ebp-D8h] HDC a8a[12]; // [esp+22Ch] [ebp-B8h] struct tagTEXTMETRICA tm; // [esp+25Ch] [ebp-88h] _uiheroinfo heroinfo; // [esp+294h] [ebp-50h] struct tagPOINT pt; // [esp+2C0h] [ebp-24h] _gamedata gamedata; // [esp+2C8h] [ebp-1Ch] struct tagRECT rc; // [esp+2D0h] [ebp-14h] COLORREF v38; // [esp+2E0h] [ebp-4h] LPCSTR lpStringa; // [esp+2F4h] [ebp+10h] Buffer[0] = nullcharacter; v8 = a8; memset(&Buffer[1], 0, 0x7Cu); v9 = a8[4]; *(WORD *)&Buffer[125] = 0; Buffer[127] = 0; v10 = (unsigned char)v9 & 1; v11 = strlen(a4) + 1; if (v11 > 0x100) return 0; memcpy(a1, a4, v11); if (color == 1) { a8 = 0; a4 = 0; if (!Connect_DiffFromString(a1, &gamedata, (int)&a8, (int)&a4)) return 0; color = SetTextColor(v8[6], 0xFFFFFFu); v38 = SetBkColor(v8[6], v10 != 0 ? 0x808080 : 0); if (align & 1) { v13 = strlen(lpString); ExtTextOutA(v8[6], (int)v8[7], (int)v8[8], 6u, (const RECT *)(v8 + 7), lpString, v13, 0); } else { v14 = a8 && a4; if (gamedata.bDiff < 3u) LoadStringA(ghUiInst, gamedata.bDiff + 1003, Buffer, 128); if (align & 2 && v14) { GetTextMetricsA(v8[6], &tm); lpStringa = (LPCSTR)(tm.tmHeight + tm.tmExternalLeading); MoveToEx(v8[6], (int)v8[7], (int)v8[8], &pt); align = SetTextAlign(v8[6], 1u); v15 = strlen(Buffer); TextOutA(v8[6], 0, 0, Buffer, v15); LoadStringA(ghUiInst, 0x409u, String, 128); MoveToEx(v8[6], (int)v8[7], (int)v8[8] + (DWORD)lpStringa, 0); v16 = strlen(String); TextOutA(v8[6], 0, 0, String, v16); v17 = v8[6]; memcpy(a8a, v8, sizeof(a8a)); GetCurrentPositionEx(v17, (LPPOINT)&a8a[7]); SetTextAlign(v8[6], 0); connect_color_text = 1; UiDrawDescCallback(game_type, 2u, (LPCSTR)a8, a4, 0, 1u, 0, a8a); connect_color_text = 0; if (a7) { SetTextAlign(v8[6], 1u); LoadStringA(ghUiInst, 0x40Cu, &heroinfo.name[8], 32); LoadStringA(ghUiInst, 0x40Du, v31, 32); v18 = localtime(&a7); v19 = v18; if (v18) { LoadStringA(ghUiInst, (v18->tm_hour > 12) + 1034, (LPSTR)&rc.top, 10); v20 = v19->tm_hour; if (v20 > 12) v19->tm_hour = v20 - 12; if (!v19->tm_hour) v19->tm_hour = 12; sprintf(String, &heroinfo.name[8], v31, v19->tm_hour, v19->tm_min, &rc.top); MoveToEx(v8[6], (int)v8[7], (int)v8[8] + 2 * (DWORD)lpStringa, 0); v21 = strlen(String); TextOutA(v8[6], 0, 0, String, v21); } } MoveToEx(v8[6], pt.x, pt.y, 0); SetTextAlign(v8[6], align); } else { v22 = strlen(Buffer); TextOutA(v8[6], (int)v8[7], (int)v8[8], Buffer, v22); } } goto LABEL_56; } GetTextMetricsA(v8[6], &tm); a4 = (char *)((tm.tmHeight - connect_draw_height) / 2 + 1); if (!connect_color_text) { color = SetTextColor(v8[6], 0xFFFFu); v38 = SetBkColor(v8[6], v10 != 0 ? 0x808080 : 0); } if (align & 1) { v23 = strlen(lpString); ExtTextOutA(v8[6], (int)v8[7] + heroport_data[0] + 2, (int)v8[8], 6u, (const RECT *)(v8 + 7), lpString, v23, 0); } if (a5) { if (a5 & 0x20) { v27 = 5; LABEL_45: v24 = v27; goto LABEL_46; } if (a5 & 1) { v24 = 0; LABEL_46: SetRect(&rc, 0, 0, special_data[0] - 1, special_frames - 1); OffsetRect(&rc, 0, special_frames * v24); SDlgBltToWindowI( (HWND)v8[5], 0, (char *)v8[7], (int)v8[8] + (DWORD)a4, connect_data3, &rc, (SIZE *)special_data, -1, 0, 0xCC0020u); goto LABEL_55; } if (a5 & 2) { v27 = 2; goto LABEL_45; } if (a5 & 4) { v27 = 3; goto LABEL_45; } if (a5 & 8) { v25 = (game_type != 'BNET') - 1; v25 = v25 & 0xFD; v24 = v25 + 4; goto LABEL_46; } } if (*(DWORD *)a1 == 'CHAT') { v27 = 6; goto LABEL_45; } if (*(DWORD *)a1 == 'SEXP' || *(DWORD *)a1 == 'SSHR' || *(DWORD *)a1 == 'STAR') { v27 = 7; goto LABEL_45; } if (Connect_GetHeroInfoConc(a1, &heroinfo)) { if (heroinfo.spawned) { if (connect_data2) SBltROP3( connect_data4, connect_data2, heroport_data[0], connect_draw_height, heroport_data[0], heroport_data[0], 0, 0xCC0020u); } else { SBltROP3( connect_data4, &connect_data1[heroport_frames * (heroinfo.heroclass + 3 * heroinfo.herorank)], heroport_data[0], connect_draw_height, heroport_data[0], heroport_data[0], 0, 0xCC0020u); } v26 = heroinfo.level / 10; if (v26) STransBlt( (char *)connect_data4 + 4 * heroport_data[0] + heroport_data[0] + 14, 0, 0, heroport_data[0], connect_trans[v26]); STransBlt( (char *)connect_data4 + 4 * (heroport_data[0] + 4) + heroport_data[0] + 4, 0, 0, heroport_data[0], connect_trans[heroinfo.level % 10]); SetRect(&rc, 0, 0, heroport_data[0] - 1, connect_draw_height - 1); SDlgBltToWindowI( (HWND)v8[5], 0, (char *)v8[7], (int)v8[8] + (DWORD)a4, connect_data4, &rc, (SIZE *)heroport_data, -1, 0, 0xCC0020u); } LABEL_55: if (!connect_color_text) { LABEL_56: SetTextColor(v8[6], color); SetBkColor(v8[6], v38); } return 1; } // 100294A4: using guessed type int special_frames; // 100295C0: using guessed type int heroport_frames; // 10029614: using guessed type int connect_color_text; // ref: 0x10003CE4 BOOL __stdcall UiCategoryCallback(int a1, int a2, int a3, int a4, int a5, DWORD *a6, DWORD *a7) { *a7 = 0xFFFF; *a6 = Connect_GetRankFromLevel(connect_categorystr); return 1; } // ref: 0x10003D04 int __fastcall Connect_GetRankFromLevel(char *str) { char a1[512]; // [esp+0h] [ebp-22Ch] _uiheroinfo a2; // [esp+200h] [ebp-2Ch] strcpy(a1, str); if (!Connect_GetHeroInfoConc(a1, &a2) || a2.level == 1) return 0; if ((signed int)a2.level < 4) return 1; if ((signed int)a2.level < 6) return 2; if ((signed int)a2.level < 8) return 3; if ((signed int)a2.level < 10) return 4; if ((signed int)a2.level < 13) return 5; if ((signed int)a2.level < 17) return 6; if ((signed int)a2.level < 20) return 7; if ((signed int)a2.level < 25) return 8; if ((signed int)a2.level < 30) return 9; if ((signed int)a2.level < 35) return 10; if ((signed int)a2.level < 40) return 11; return ((signed int)a2.level >= 48) + 12; } // ref: 0x10003DAF BOOL __fastcall Connect_DiffFromString(char *str, _gamedata *gamedata, int a3, int a4) { unsigned char v6; // al char *v8; // eax const char *v9; // eax char *v10; // eax if (!*str) return 0; v6 = atoi(str); gamedata->bDiff = v6; if (v6 >= 3u) return 0; v8 = strchr(str, 13); if (v8) { *v8 = 0; v9 = v8 + 1; if (a3) *(DWORD *)a3 = (DWORD)v9; v10 = (char *)strchr(v9, 13); if (v10) { *v10 = 0; if (a4) *(DWORD *)a4 = (DWORD)v10 + 1; } } return 1; } // ref: 0x10003E0C void __fastcall Connect_SetDiffString(_gamedata *gamedata, const char *str1, char *str2, char *str3, int size) { size_t v7; // ebx size_t v8; // eax unsigned char v9; // zf unsigned char v10; // sf int v12; // eax v7 = strlen(str1); v8 = v7 + strlen(str2) + 5; v9 = size == v8; v10 = (signed int)(size - v8) < 0; v12 = gamedata->bDiff; if (v10 | v9) _itoa(v12, str3, 10); else sprintf(str3, "%d\r%s\r%s", v12, str1, str2); } // ref: 0x10003E61 BOOL __fastcall Connect_GetHeroInfoConc(const char *a1, _uiheroinfo *pInfo) { int v4; // eax int v5; // edi int v6; // edx unsigned short v7; // di unsigned char v8; // cl int v10; // [esp+Ch] [ebp-24h] unsigned int v11; // [esp+10h] [ebp-20h] unsigned int v12; // [esp+14h] [ebp-1Ch] unsigned int v13; // [esp+18h] [ebp-18h] int v14; // [esp+1Ch] [ebp-14h] int v15; // [esp+20h] [ebp-10h] int v16; // [esp+24h] [ebp-Ch] int v17; // [esp+28h] [ebp-8h] int v18; // [esp+2Ch] [ebp-4h] memset(pInfo, 0, 0x2Cu); if (!*a1) return 0; v4 = *(DWORD *)a1; if (*(DWORD *)a1 != 'DRTL' && v4 != 'DSHR' && v4 != 'DTST') return 0; if (sscanf(a1 + 4, "%d %d %d %d %d %d %d %d %d", &v13, &v12, &v11, &v18, &v17, &v16, &v15, &v10, &v14) != 9) return 0; v5 = *(DWORD *)a1; v6 = v14; if (v5 == 'DRTL') { if (v14) return 0; } if (v5 == 'DSHR' && !v14) return 0; v7 = v13; if (!v13) return 0; if (v13 > 0x63) return 0; v8 = v12; if (v12 >= 3 || v11 > 3 || v18 < 0 || v17 < 0 || v16 < 0 || v15 < 0) return 0; pInfo->herorank = v11; pInfo->level = v7; pInfo->strength = (unsigned char)v18; pInfo->heroclass = v8; pInfo->magic = (unsigned char)v17; pInfo->spawned = v6; pInfo->dexterity = (unsigned char)v16; pInfo->vitality = (unsigned char)v15; pInfo->gold = v10; return 1; } // ref: 0x10003F6F void __fastcall Connect_MakeDescString(_uiheroinfo *a1, char *name, size_t size) { *(DWORD *)name = (DWORD)connect_charname; _snprintf( name + 4, size, " %d %d %d %d %d %d %d %d %d", a1->level, a1->heroclass, a1->herorank, a1->strength, a1->magic, a1->dexterity, a1->vitality, a1->gold, a1->spawned); } // ref: 0x10003FB7 void __stdcall UiCreateGameCriteria(_uiheroinfo *pInfo, char *str) { sprintf(str, "#%d?%d", 3, pInfo->level); } // ref: 0x10003FD6 BOOL __stdcall UiCreatePlayerDescription(_uiheroinfo *info, DWORD mode, char *desc) { connect_charname = (char *)mode; Connect_MakeDescString(info, desc, 0x80u); return 1; } // ref: 0x10003FF7 void __stdcall UiSetupPlayerInfo(char *infostr, _uiheroinfo *pInfo, DWORD type) { connect_charname = (char *)type; SStrCopy(connect_plrinfostr, infostr, 128); Connect_MakeDescString(pInfo, connect_categorystr, 0x80u); } // ref: 0x10004028 void __fastcall Connect_CopyPlrDescStrings(char *str1, int size1, char *str2, int size2) { if (str1) SStrCopy(str1, connect_plrinfostr, size1); if (str2) SStrCopy(str2, connect_categorystr, size2); } ================================================ FILE: DiabloUI/copyprot.cpp ================================================ // ref: 0x10004054 BOOL __stdcall UiCopyProtError(int *pdwResult) { int v1; // eax int v2; // eax char Buffer[128]; // [esp+0h] [ebp-80h] if (DiabloUI_GetSpawned()) LoadStringA(ghUiInst, 0x3Fu, Buffer, 127); else LoadStringA(ghUiInst, 0x1Bu, Buffer, 127); v1 = (int)SDrawGetFrameWindow(NULL); v2 = SDlgDialogBoxParam(ghUiInst, "OKCANCEL_DIALOG", v1, CopyProt_WndProc, (int)Buffer); if (pdwResult) *pdwResult = v2; return 1; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x100040AF LRESULT __stdcall CopyProt_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v4; // ecx int v5; // edx HWND v6; // eax LONG v7; // eax HWND v9; // eax if (Msg == 2) { CopyProt_FreeCopyResrcs(); Fade_UpdatePaletteRange(10); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg <= 0x103) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); if (Msg <= 0x105) { v9 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v9, Msg, wParam, lParam); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg == 272) { CopyProt_LoadCopyStuff(hWnd, lParam); return 1; } if (Msg != 273) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); switch ((unsigned short)wParam) { case 1u: v6 = GetFocus(); v7 = GetWindowLongA(v6, -12); v4 = hWnd; if (v7 == 1109) { v5 = 1; goto LABEL_13; } goto LABEL_12; case 2u: v4 = hWnd; LABEL_12: v5 = 2; goto LABEL_13; case 0x455u: v4 = hWnd; v5 = 1; LABEL_13: CopyProt_EndCopyDlg(v4, v5); break; } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x10004173 void __cdecl CopyProt_FreeCopyResrcs() { if (copyprot_artpal) { FreeResource(copyprot_artpal); copyprot_artpal = 0; } if (copyprot_btnart) { FreeResource(copyprot_btnart); copyprot_btnart = 0; } if (copyprot_popupart) { FreeResource(copyprot_popupart); copyprot_popupart = 0; } } // ref: 0x100041B5 BOOL __fastcall CopyProt_LoadCopyStuff(HWND hWnd, int a2) { HRSRC v2; // eax HRSRC v3; // eax HRSRC v4; // eax void *v5; // edi void *v6; // ebx HWND v7; // eax PALETTEENTRY pPalEntries[256]; // [esp+Ch] [ebp-420h] int msgs[3]; // [esp+40Ch] [ebp-20h] DWORD data[2]; // [esp+418h] [ebp-14h] LPCSTR lpString; // [esp+420h] [ebp-Ch] void *v13; // [esp+424h] [ebp-8h] msgs[2] = 0; lpString = (LPCSTR)a2; data[0] = 112; data[1] = 140; msgs[0] = 1109; msgs[1] = 2; v2 = FindResourceA(ghUiInst, "IDR_POPUPART", "ART_FILES"); copyprot_popupart = LoadResource(ghUiInst, v2); v3 = FindResourceA(ghUiInst, "IDR_BTNART", "ART_FILES"); copyprot_btnart = LoadResource(ghUiInst, v3); v4 = FindResourceA(ghUiInst, "IDR_ARTPAL", "ART_FILES"); copyprot_artpal = LoadResource(ghUiInst, v4); v5 = LockResource(copyprot_popupart); v6 = LockResource(copyprot_btnart); v13 = LockResource(copyprot_artpal); if (v5) SDlgSetBitmapI(hWnd, 0, &nullcharacter, -1, 1, v5, 0, 284, 148, -1); ShowCursor(TRUE); Fade_SetInputWindow(hWnd); if (v6) local_FitButtonDlg(hWnd, msgs, v6, data); if (v13) { memcpy(pPalEntries, v13, 0x400u); SDrawUpdatePalette(0, 0x100u, pPalEntries, 1); } v7 = GetDlgItem(hWnd, 1026); SetWindowTextA(v7, lpString); return 1; } // ref: 0x1000430C void __fastcall CopyProt_EndCopyDlg(HWND hWnd, int a2) { ShowCursor(FALSE); SDlgEndDialog(hWnd, (HANDLE)a2); } // ref: 0x10004329 void __cdecl CopyProt_cpp_init() { CopyProt_cpp_float = CopyProt_cpp_float_value; } // 1001F3F8: using guessed type int CopyProt_cpp_float_value; // 10029620: using guessed type int CopyProt_cpp_float; ================================================ FILE: DiabloUI/cr8game.cpp ================================================ // ref: 0x10004339 void __cdecl cr8game_cpp_init() { cr8game_cpp_float = cr8game_cpp_float_value; } // 1001F3FC: using guessed type int cr8game_cpp_float_value; // 1002962C: using guessed type int cr8game_cpp_float; // ref: 0x10004344 BOOL __fastcall cr8game_GetSnetCreaGame(HWND hWnd) { BOOL result; // eax DWORD *v2; // eax int *v3; // ST24_4 int v4; // ST18_4 int v5; // ST14_4 char *v6; // ST10_4 int v7; // eax char Buffer[128]; // [esp+Ch] [ebp-308h] char Text[256]; // [esp+8Ch] [ebp-288h] char a4[128]; // [esp+18Ch] [ebp-188h] char a2[128]; // [esp+20Ch] [ebp-108h] char str[128]; // [esp+28Ch] [ebp-88h] BOOL v13; // [esp+30Ch] [ebp-8h] Connect_CopyPlrDescStrings(a2, 128, str, 128); Connect_SetDiffString(&cr8_gamedata, a2, str, a4, 128); if (UiAuthCallback(2, a2, str, 0, a4, Text, 256)) { v2 = cr8_somegamestruct; if (cr8_somegamestruct[8] >= 8) { *(BYTE *)(cr8_somegamestruct[7] + 4) = cr8_gamedata.bDiff; v2 = cr8_somegamestruct; } v3 = cr8game_playerID; v4 = *(DWORD *)(cr8_playercount + 8); v5 = v2[8]; v6 = (char *)v2[7]; v7 = Connect_GetRankFromLevel(str); v13 = SNetCreateGame(cr8_gamename, cr8_gamepassword, a4, v7, v6, v5, v4, a2, 0, v3); if (!v13) { if (SErrGetLastError() == 183) { LoadStringA(ghUiInst, 0x40Fu, Buffer, 128); sprintf(Text, Buffer, cr8_gamename); } else { LoadStringA(ghUiInst, 0x410u, Text, 256); } UiMessageBoxCallback(hWnd, Text, 0, 0x30u); } result = v13; } else { UiMessageBoxCallback(hWnd, Text, 0, 0x30u); result = 0; } return result; } // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // 10029630: using guessed type int cr8_playercount; // ref: 0x100044AA BOOL __stdcall UiCreateGameCallback(int a1, int a2, int a3, int a4, int a5, int a6) { BOOL v6; // eax cr8_playercount = a1; cr8_somegamestruct = (DWORD *)a2; cr8_dword_10029638 = a3; cr8_dword_10029640 = a5; cr8_dword_1002963C = a4; cr8game_playerID = (int *)a6; v6 = SDlgDialogBoxParam(ghUiInst, "DIALOG_CREATE_GAME", *(DWORD *)(a4 + 8), cr8game_WndProc, 0); return v6 != -1 ? v6 : 0; } // 10029630: using guessed type int cr8_playercount; // 10029638: using guessed type int cr8_dword_10029638; // 1002963C: using guessed type int cr8_dword_1002963C; // 10029640: using guessed type int cr8_dword_10029640; // ref: 0x10004506 LRESULT __stdcall cr8game_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { signed int v4; // ebx HWND v6; // eax HWND v7; // eax HWND v8; // eax char Buffer[256]; // [esp+Ch] [ebp-104h] int a2; // [esp+10Ch] [ebp-4h] v4 = Msg; if (Msg == 2) { cr8game_FreeCreaStuff(); cr8game_FreeMainMem(hWnd); if (cr8game_hobject) DeleteObject(cr8game_hobject); cr8_sendmsg1 = 0; cr8_sendmsg2 = 0; return (LRESULT)SDlgDefDialogProc(hWnd, v4, (HDC)wParam, (HWND)lParam); } if (Msg > 0x103) { if (Msg > 0x105) { if (Msg == 272) { cr8_sendmsg2 = GetDlgItem(hWnd, 1010); cr8_sendmsg1 = GetDlgItem(hWnd, 1011); cr8game_LoadCreaGFX(hWnd); cr8game_AllocMainMem(hWnd); cr8game_SendMessageF5(hWnd); cr8game_hobject = cr8game_GetCr8Object(hWnd); SendMessageA(cr8_sendmsg2, 0xC5u, 0x1Fu, 0); SendMessageA(cr8_sendmsg1, 0xC5u, 0x1Fu, 0); return 1; } if (Msg != 273) { if (Msg == 312 && GetWindowLongA((HWND)lParam, -12) == 1030) { local_SetWhiteText((HDC)wParam); return (LRESULT)GetStockObject(5); } return (LRESULT)SDlgDefDialogProc(hWnd, v4, (HDC)wParam, (HWND)lParam); } if ((unsigned short)wParam == 1) { if (SendMessageA(cr8_sendmsg2, 0xEu, 0, 0)) { SendMessageA(cr8_sendmsg2, 0xDu, 0x20u, (LPARAM)cr8_gamename); if (SelHero_IsNameReserved(cr8_gamename) || SelHero_NameHasChar(cr8_gamename, &nullcharacter) || !cr8game_CheckValidGameName(cr8_gamename)) { LoadStringA(ghUiInst, 0x404u, Buffer, 256); OkCancel_DoOkDialog(hWnd, Buffer, 1); cr8_gamename[0] = 0; } else { cr8_gamepassword[0] = 0; if (SendMessageA(cr8_sendmsg1, 0xEu, 0, 0)) SendMessageA(cr8_sendmsg1, 0xDu, 0x20u, (LPARAM)cr8_gamepassword); cr8_gamedata.bDiff = cr8_dword_1002966C; TitleSnd_PlaySelectSound(); if (cr8game_GetSnetCreaGame(hWnd)) SDlgEndDialog(hWnd, (void *)HANDLE_FLAG_INHERIT); } } else { LoadStringA(ghUiInst, 0x3F0u, Buffer, 256); OkCancel_DoOkDialog(hWnd, Buffer, 1); } } else { if ((unsigned short)wParam != 2) { if ((signed int)(unsigned short)wParam > 1031 && (signed int)(unsigned short)wParam <= 1034) { a2 = (unsigned short)wParam - 1032; if (HIWORD(wParam) == 6) SetFocus(cr8_sendmsg2); if (cr8_dword_1002966C != (unsigned short)wParam - 1032) { if (cr8_dword_1002966C != -1) { v6 = GetDlgItem(hWnd, cr8_dword_1002966C + 1032); SendMessageA(v6, 0xF3u, 0, 0); TitleSnd_PlayMoveSound(); } cr8game_BlitCr8Dialog(hWnd, a2); v7 = GetDlgItem(hWnd, 1040); cr8game_SetWindowStr(v7, 1029, a2); v4 = 273; cr8_dword_1002966C = a2; } SendMessageA((HWND)lParam, 0xF3u, 1u, 0); } return (LRESULT)SDlgDefDialogProc(hWnd, v4, (HDC)wParam, (HWND)lParam); } TitleSnd_PlaySelectSound(); SDlgEndDialog(hWnd, 0); } return 0; } v8 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v8, Msg, wParam, lParam); } return (LRESULT)SDlgDefDialogProc(hWnd, v4, (HDC)wParam, (HWND)lParam); } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x10004828 void __cdecl cr8game_FreeCreaStuff() { if (cr8_creat_bg_ptr) { SMemFree(cr8_creat_bg_ptr, "C:\\Src\\Diablo\\DiabloUI\\cr8game.cpp", 55, 0); cr8_creat_bg_ptr = 0; } if (cr8_but_xsm_ptr) { SMemFree(cr8_but_xsm_ptr, "C:\\Src\\Diablo\\DiabloUI\\cr8game.cpp", 60, 0); cr8_but_xsm_ptr = 0; } if (cr8_diffbtns_ptr) { SMemFree(cr8_diffbtns_ptr, "C:\\Src\\Diablo\\DiabloUI\\cr8game.cpp", 65, 0); cr8_diffbtns_ptr = 0; } } // ref: 0x1000487F BOOL __fastcall cr8game_LoadCreaGFX(HWND hWnd) { int id[3]; // [esp+8h] [ebp-1Ch] DWORD a8[2]; // [esp+14h] [ebp-10h] DWORD a3[2]; // [esp+1Ch] [ebp-8h] id[0] = 0; id[0] = 1; id[1] = 2; local_LoadArtWithPal(hWnd, 0, "Dialog", -1, 1, "ui_art\\creat_bg.pcx", &cr8_creat_bg_ptr, a8, 1); local_LoadArtImage("ui_art\\but_xsm.pcx", &cr8_but_xsm_ptr, a3); SDlgSetControlBitmaps(hWnd, id, 0, (char *)cr8_but_xsm_ptr, (char *)a3, 1, -1); local_LoadArtImage("ui_art\\diffbtns.pcx", &cr8_diffbtns_ptr, cr8diffbtns_size); local_SetStaticBmp(hWnd, 1040, cr8_creat_bg_ptr, a8); return 1; } // ref: 0x10004914 void __fastcall cr8game_FreeMainMem(HWND hWnd) { signed int v2; // edi HWND v3; // esi void **v4; // eax MAPDST void *v6; // eax struct tagRECT Rect; // [esp+10h] [ebp-10h] v2 = 0; do { v3 = GetDlgItem(hWnd, v2 + 1032); GetClientRect(v3, &Rect); v4 = (void **)GetWindowLongA(v3, -21); if (v4) { v6 = *v4; if (*v4) SMemFree(v6, "C:\\Src\\Diablo\\DiabloUI\\cr8game.cpp", 160, 0); SMemFree(v4, "C:\\Src\\Diablo\\DiabloUI\\cr8game.cpp", 162, 0); } ++v2; } while (v2 < 3); } // ref: 0x1000497F void __fastcall cr8game_AllocMainMem(HWND hWnd) { int v1; // ebx void **v2; // esi HWND v3; // ST1C_4 LONG v4; // eax struct tagRECT Rect; // [esp+Ch] [ebp-18h] HWND hWnda; // [esp+20h] [ebp-4h] v1 = 0; do { hWnda = GetDlgItem(hWnd, v1 + 1032); GetClientRect(hWnda, &Rect); v2 = (void **)SMemAlloc(0x110u, "C:\\Src\\Diablo\\DiabloUI\\cr8game.cpp", 177, 0); *v2 = SMemAlloc(Rect.right * Rect.bottom, "C:\\Src\\Diablo\\DiabloUI\\cr8game.cpp", 178, 0); v3 = hWnda; v2[1] = (void *)Rect.right; v4 = Rect.bottom; v2[3] = 0; v2[2] = (void *)v4; SetWindowLongA(v3, -21, (LONG)v2); SDlgSetBitmapI(hWnda, 0, &nullcharacter, -1, 241, *v2, 0, (int)v2[1], (int)v2[2], -1); cr8game_DoAROP3Blit(hWnda, v1++, 0); } while (v1 < 3); } // ref: 0x10004A34 void __fastcall cr8game_DoAROP3Blit(HWND hWnd, int frame, int size) { DWORD *v5; // eax v5 = (DWORD *)GetWindowLongA(hWnd, -21); if (v5) { if (cr8_diffbtns_ptr) { SBltROP3( (void *)*v5, &cr8_diffbtns_ptr[cr8diffbtns_size[0] * v5[2] * (size + 2 * frame)], v5[1], v5[2], v5[1], cr8diffbtns_size[0], 0, 0xCC0020u); InvalidateRect(hWnd, 0, 0); } } } // ref: 0x10004A93 void __fastcall cr8game_SendMessageF5(HWND hWnd) { cr8_dword_1002966C = -1; cr8_dword_10029658 = 0; cr8_dword_10029668 = 0; SendDlgItemMessageA(hWnd, 1032, 0xF5u, 0, 0); } // 10029658: using guessed type int cr8_dword_10029658; // 10029668: using guessed type int cr8_dword_10029668; // ref: 0x10004ABA void __fastcall cr8game_BlitCr8Dialog(HWND hWnd, int a2) { HWND v4; // eax HWND v5; // eax if (cr8_dword_1002966C != -1) { v4 = GetDlgItem(hWnd, cr8_dword_1002966C + 1032); cr8game_DoAROP3Blit(v4, cr8_dword_1002966C, 0); } v5 = GetDlgItem(hWnd, a2 + 1032); cr8game_DoAROP3Blit(v5, a2, 1); } // ref: 0x10004B02 void __fastcall cr8game_SetWindowStr(HWND hWnd, int dlgitem, int a3) { char Buffer[256]; // [esp+4h] [ebp-100h] LoadStringA(ghUiInst, a3 + dlgitem, Buffer, 256); SetWindowTextA(hWnd, Buffer); } // ref: 0x10004B3F int __fastcall cr8game_CheckValidGameName(char *name) { signed int v1; // edi char v2; // al signed int v3; // esi int result; // eax char v5[32]; // [esp+8h] [ebp-24h] strcpy(v5, name); v1 = 0; if (v5[0] == 32) { v2 = 32; while (v2) { v2 = v5[v1++ + 1]; if (v2 != 32) goto LABEL_5; } LABEL_9: result = 0; } else { LABEL_5: v3 = strlen(v5); while (v5[--v3] == 32) { if (v3 <= v1) goto LABEL_9; } v5[v3 + 1] = 0; strcpy(name, &v5[v1]); result = v3 + 1 - v1; } return result; } // ref: 0x10004BA8 HFONT __fastcall cr8game_GetCr8Object(HWND hWnd) { HFONT v2; // eax MAPDST int pv[15]; // [esp+8h] [ebp-40h] v2 = (HFONT)SendMessageA(hWnd, 0x31u, 0, 0); if (v2) { if (GetObjectA(v2, 60, pv)) { pv[0] = -MulDiv(12, 96, 72); pv[1] = 0; v2 = CreateFontIndirectA((const LOGFONTA *)pv); if (v2) { SendDlgItemMessageA(hWnd, 1032, 0x30u, (WPARAM)v2, 0); SendDlgItemMessageA(hWnd, 1033, 0x30u, (WPARAM)v2, 0); SendDlgItemMessageA(hWnd, 1034, 0x30u, (WPARAM)v2, 0); } } } return v2; } ================================================ FILE: DiabloUI/creadung.cpp ================================================ // ref: 0x10004C33 void __fastcall CreaDung_SetDelSpin(int a1) { creadung_delspinners = a1; } // 100296CC: using guessed type int creadung_delspinners; // ref: 0x10004C3F void __cdecl CreaDung_cpp_init() { CreaDung_cpp_float = CreaDung_cpp_float_value; } // 1001F400: using guessed type int CreaDung_cpp_float_value; // 100296C4: using guessed type int CreaDung_cpp_float; // ref: 0x10004C4A LRESULT __stdcall CreaDung_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v4; // eax HWND v6; // eax if (Msg == 2) { CreaDung_FreeDungProcs(hWnd); } else if (Msg > 0x103) { if (Msg > 0x105) { if (Msg == 272) { creadung_dword_100296D8 = lParam; CreaDung_LoadDungGFX(hWnd); } else { if (Msg == 273) { if (HIWORD(wParam) == 7) { Focus_GetAndBlitSpin(hWnd, lParam); } else if (HIWORD(wParam) == 6) { Focus_CheckPlayMove(lParam); Focus_DoBlitSpinIncFrame(hWnd, (HWND)lParam); CreaDung_ParseDungProcs(hWnd, (unsigned short)wParam); } else if (HIWORD(wParam) == 5 || (WORD)wParam == 1) { CreaDung_DoAllPlaySnd(hWnd); } else if ((WORD)wParam == 2) { CreaDung_PlaySndAndKill(hWnd, 2); } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg != 275) { if (Msg == 513) CreaDung_CheckDlgForSnd(hWnd, (unsigned short)lParam, (unsigned int)lParam >> 16); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (wParam == 1) { v4 = GetFocus(); Focus_DoBlitSpinIncFrame(hWnd, v4); } } return 0; } v6 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v6, Msg, wParam, lParam); } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 100296D8: using guessed type int creadung_dword_100296D8; // ref: 0x10004D75 void __fastcall CreaDung_ParseDungProcs(HWND hWnd, int dlg) { HWND v3; // eax int v4; // eax HWND v5; // eax int v6; // eax char Buffer[256]; // [esp+4h] [ebp-100h] LoadStringA(ghUiInst, dlg - 1055, Buffer, 255); v3 = GetDlgItem(hWnd, 1097); if (v3) { v4 = GetWindowLongA(v3, -21); local_SetWndLongStr(v4, Buffer); } Doom_ParseWndProc4(hWnd, creadung_msgtbl2, AF_BIGGRAY); LoadStringA(ghUiInst, dlg - 65, Buffer, 255); v5 = GetDlgItem(hWnd, 1099); if (v5) { v6 = GetWindowLongA(v5, -21); local_SetWndLongStr(v6, Buffer); } Doom_ParseWndProc4(hWnd, creadung_msgtbl3, AF_SMALLGRAY); } // ref: 0x10004E2E void __fastcall CreaDung_FreeDungProcs(HWND hWnd) { void **v2; // eax Doom_DeleteFreeProcs(hWnd, creadung_msgtbl5); Doom_DeleteFreeProcs(hWnd, creadung_msgtbl4); Doom_DeleteFreeProcs(hWnd, creadung_msgtbl3); Doom_DeleteFreeProcs(hWnd, creadung_msgtbl2); Doom_DeleteFreeProcs(hWnd, creadung_msgtbl1); v2 = (void **)GetWindowLongA(hWnd, -21); local_FreeMemPtr(v2); if (creadung_delspinners) Focus_DeleteSpinners(); } // 100296CC: using guessed type int creadung_delspinners; // ref: 0x10004E8B void __fastcall CreaDung_LoadDungGFX(HWND hWnd) { DWORD *v2; // eax MAPDST if (creadung_delspinners) Focus_LoadSpinner("ui_art\\focus16.pcx"); else Focus_ResetSpinToZero(); SDlgSetTimer((int)hWnd, 1, 55, 0); v2 = local_AllocWndLongData(); if (v2) { SetWindowLongA(hWnd, -21, (LONG)v2); local_LoadArtWithPal(hWnd, 0, "popup", -1, 1, "ui_art\\seldiff.pcx", (BYTE **)v2, v2 + 1, 0); } local_DoUiWndProc(hWnd, (DWORD *)creadung_msgtbl5); Doom_ParseWndProc3(hWnd, creadung_msgtbl1, AF_BIGGRAY); Doom_ParseWndProc3(hWnd, creadung_msgtbl2, AF_BIGGRAY); Doom_ParseWndProc3(hWnd, creadung_msgtbl3, AF_SMALLGRAY); Doom_ParseWndProcs(hWnd, creadung_msgtbl4, AF_BIG, 0); Doom_ParseWndProcs(hWnd, creadung_msgtbl5, AF_MED, 1); } // 100296CC: using guessed type int creadung_delspinners; // ref: 0x10004F40 void __fastcall CreaDung_PlaySndAndKill(HWND hWnd, int a2) { TitleSnd_PlaySelectSound(); SDlgKillTimer((int)hWnd, 1); SDlgEndDialog(hWnd, (HANDLE)a2); } // ref: 0x10004F5D void __fastcall CreaDung_DoAllPlaySnd(HWND hWnd) { //int v1; // ebp HWND v2; // esi HWND v3; // eax LONG v4; // eax HWND v5; // edi HWND v6; // eax int v7; // [esp-288h] [ebp-28Ch] int v8; // [esp-188h] [ebp-18Ch] char *v9; // [esp-108h] [ebp-10Ch] char *v10; // [esp-88h] [ebp-8Ch] int v11; // [esp-8h] [ebp-Ch] char v12; // [esp-4h] [ebp-8h] //int v13; // [esp+0h] [ebp-4h] /* note: stack is hosed, fix me */ v2 = hWnd; if (creadung_dword_100296D8 == 1) { //v13 = v1; v5 = hWnd; Connect_CopyPlrDescStrings((char *)&v10, 128, (char *)&v9, 128); v6 = GetFocus(); v12 = GetWindowLongA(v6, -12) - 70; Connect_SetDiffString((_gamedata *)&v11, (const char *)&v10, (char *)&v9, (char *)&v8, 128); if (UiAuthCallback(2, (char *)&v10, (char *)&v9, 0, (char *)&v8, (LPSTR)&v7, 256)) CreaDung_DoSnetCreaGame(v5); else SelYesNo_SelOkDialog(v5, (char *)&v7, 0, 0); } else { v3 = GetFocus(); v4 = GetWindowLongA(v3, -12); SelHero_SetHeroDifficulty(v4 - 1094); CreaDung_PlaySndAndKill(v2, 1); } } // 10004F5D: could not find valid save-restore pair for ebp // 100296D8: using guessed type int creadung_dword_100296D8; // ref: 0x10005037 void __fastcall CreaDung_DoSnetCreaGame(HWND hWnd) { HWND v1; // ebx DWORD *v2; // eax DWORD v3; // edi char a4[256]; // [esp+8h] [ebp-34Ch] char v5[128]; // [esp+108h] [ebp-24Ch] char Buffer[192]; // [esp+188h] [ebp-1CCh] char a3[128]; // [esp+248h] [ebp-10Ch] char a2[128]; // [esp+2C8h] [ebp-8Ch] _gamedata a1; // [esp+348h] [ebp-Ch] v1 = GetFocus(); if (hWnd == GetParent(v1)) { Connect_CopyPlrDescStrings(a2, 128, a3, 128); a1.bDiff = GetWindowLongA(v1, -12) - 70; Connect_SetDiffString(&a1, a2, a3, a4, 256); v2 = crea_somegamestruct; if (crea_somegamestruct[8] >= 8) { v3 = crea_somegamestruct[7]; *(BYTE *)(v3 + 4) = GetWindowLongA(v1, -12) - 70; v2 = crea_somegamestruct; } if (SNetCreateGame( creadung_gamename, 0, a4, 0, (char *)v2[7], v2[8], *(DWORD *)(creadung_playername + 8), a2, 0, creadung_playerID)) { CreaDung_PlaySndAndKill(hWnd, 1); } else { creadung_lasterror = SErrGetLastError(); if (creadung_lasterror == 183) { LoadStringA(ghUiInst, 0x49u, v5, 127); wsprintfA(Buffer, v5, creadung_gamename); } else { LoadStringA(ghUiInst, 0x26u, Buffer, 191); } SelYesNo_SelOkDialog(hWnd, Buffer, 0, 0); } } } // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // 100296BC: using guessed type int creadung_playername; // 100296D4: using guessed type int creadung_lasterror; // ref: 0x1000517E void __fastcall CreaDung_CheckDlgForSnd(HWND hWnd, int a2, int a3) { HWND v6; // eax HWND v7; // eax v6 = GetDlgItem(hWnd, 1056); if (local_GetBottomRect(hWnd, v6, a2, a3)) { CreaDung_DoAllPlaySnd(hWnd); } else { v7 = GetDlgItem(hWnd, 1054); if (local_GetBottomRect(hWnd, v7, a2, a3)) CreaDung_PlaySndAndKill(hWnd, 2); } } // ref: 0x100051D8 BOOL __fastcall CreaDung_SelDungDiff(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { int v8; // ST10_4 BOOL result; // eax creadung_playername = a1; creadung_dword_100296C8 = a3; creadung_playerID = (int *)a6; creadung_delspinners = a7; crea_somegamestruct = (DWORD *)a2; creadung_gamename = (char *)a8; v8 = SelHero_GetHeroIsGood(); result = SDlgDialogBoxParam(ghUiInst, "SELDIFF_DIALOG", *(DWORD *)(a4 + 8), CreaDung_WndProc, v8); if (result != 1) { SErrSetLastError(creadung_lasterror); result = 0; } return result; } // 1001041E: using guessed type int __stdcall SErrSetLastError(DWORD); // 100296BC: using guessed type int creadung_playername; // 100296C8: using guessed type int creadung_dword_100296C8; // 100296CC: using guessed type int creadung_delspinners; // 100296D4: using guessed type int creadung_lasterror; ================================================ FILE: DiabloUI/creastat.cpp ================================================ // ref: 0x1000523E BOOL __stdcall UiGetDefaultStats(int pclass, _uidefaultstats *pStats) { if (!pStats) return 0; pStats->strength = defstats[pclass][0]; pStats->magic = defstats[pclass][1]; pStats->dexterity = defstats[pclass][2]; pStats->vitality = defstats[pclass][3]; return 1; } // ref: 0x10005287 void __cdecl CreaStat_cpp_init() { CreaStat_cpp_float = CreaStat_cpp_float_value; } // 1001F404: using guessed type int CreaStat_cpp_float_value; // 100296E0: using guessed type int CreaStat_cpp_float; ================================================ FILE: DiabloUI/credits.cpp ================================================ // ref: 0x10005297 void __cdecl credits_cpp_init() { credits_cpp_float = credits_cpp_float_value; } // 1001F408: using guessed type int credits_cpp_float_value; // 100296EC: using guessed type int credits_cpp_float; // ref: 0x100052A2 BOOL __stdcall UiCreditsDialog(int a1) { int v1; // eax v1 = (int)SDrawGetFrameWindow(NULL); SDlgDialogBoxParam(ghUiInst, "CREDITS_DIALOG", v1, credits_WndProc, 25); return 1; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x100052C7 LRESULT __stdcall credits_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v5; // eax if (Msg > 0x111) { if (Msg == 275) { credits_CalcPosROP3(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg == 513 || Msg == 516) goto LABEL_12; if (Msg != 528) { if (Msg == 2024) { if (!Fade_CheckRange5()) Fade_SetFadeTimer((int)hWnd); return 0; } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if ((WORD)wParam != 513 && (WORD)wParam != 516) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); LABEL_25: Title_KillAndFadeDlg(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg == 273) goto LABEL_25; if (Msg != 2) { if (Msg == 135) return 4; if (Msg != 256) { if (Msg > 0x103) { if (Msg <= 0x105) { v5 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v5, Msg, wParam, lParam); } else if (Msg == 272) { credits_LoadImgCreditTxt(hWnd, lParam); PostMessageA(hWnd, 0x7E8u, 0, 0); return 1; } } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (wParam != 32) return 0; LABEL_12: Title_KillAndFadeDlg(hWnd); return 0; } credits_FreeCreditResrc(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x100053D9 void __fastcall credits_FreeCreditResrc(HWND hWnd) { void **v2; // eax if (creditsobj) { SGdiDeleteObject(creditsobj); creditsobj = 0; } if (credit_back_img) { SMemFree(credit_back_img, "C:\\Src\\Diablo\\DiabloUI\\credits.cpp", 46, 0); credit_back_img = 0; } v2 = (void **)GetWindowLongA(hWnd, -21); local_FreeMemPtr(v2); if (credittext_rsrc) { FreeResource(credittext_rsrc); credittext_rsrc = 0; } } // ref: 0x1000543A void __fastcall credits_LoadImgCreditTxt(HWND hWnd, LPARAM lParam) { signed int v2; // eax HRSRC v3; // eax HRSRC v4; // eax DWORD *v5; // eax DWORD *v6; // esi int v7; // ebx int v8; // esi HFONT v9; // eax MAPDST BOOL v11; // ebx struct tagRECT Rect; // [esp+Ch] [ebp-18h] HWND v13; // [esp+1Ch] [ebp-8h] if (lParam) v2 = 1000 / lParam; else v2 = 50; SDlgSetTimer((int)hWnd, 1, v2, 0); v3 = FindResourceA(ghUiInst, "IDR_CREDITS", "TEXT_FILES"); credittext_rsrc = LoadResource(ghUiInst, v3); v4 = FindResourceA(ghUiInst, "IDR_CREDITS", "TEXT_FILES"); credittext_size = SizeofResource(ghUiInst, v4); v5 = local_AllocWndLongData(); v6 = v5; if (v5) { SetWindowLongA(hWnd, -21, (LONG)v5); local_LoadArtWithPal(hWnd, 0, &nullcharacter, -1, 1, "ui_art\\credits.pcx", (BYTE **)v6, v6 + 1, 0); Fade_NoInputAndArt(hWnd, 0); } v13 = GetDlgItem(hWnd, 1000); GetWindowRect(v13, &Rect); v7 = Rect.right - Rect.left; v8 = Rect.bottom - Rect.top + 60; credit_back_img = SMemAlloc((Rect.right - Rect.left) * v8, "C:\\Src\\Diablo\\DiabloUI\\credits.cpp", 122, 0); credit_horz_pos = v7; credit_vertical_pos1 = v8; local_AdjustRectSize(&Rect, 0, 30); SDlgSetBitmapI(v13, 0, 0, -1, 1, credit_back_img, (int)&Rect, v7, v8, -1); credit_vertical_pos2 = v8 - 30; credits_CalcPosROP3(hWnd); v9 = CreateFontA(-17, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, VARIABLE_PITCH | (FF_SCRIPT << 2), "Times New Roman"); if (!v9 || (v11 = SGdiImportFont(v9, (int)&creditsobj), DeleteObject(v9), !v11)) Title_KillAndFadeDlg(hWnd); } // 100296E8: using guessed type int credittext_size; // 100296FC: using guessed type int credit_vertical_pos1; // ref: 0x100055C0 void __fastcall credits_CalcPosROP3(HWND hWnd) { DWORD *v2; // edi struct tagRECT Rect; // [esp+Ch] [ebp-14h] HWND hWnda; // [esp+1Ch] [ebp-4h] hWnda = GetDlgItem(hWnd, 1000); v2 = (DWORD *)GetWindowLongA(hWnd, -21); GetWindowRect(hWnda, &Rect); ScreenToClient(hWnd, (LPPOINT)&Rect); ScreenToClient(hWnd, (LPPOINT)&Rect.right); SBltROP3( (char *)credit_back_img + 30 * credit_horz_pos, (void *)(Rect.left + *v2 + Rect.top * v2[1]), credit_horz_pos, Rect.bottom - Rect.top, credit_horz_pos, v2[1], 0, 0xCC0020u); --credit_vertical_pos2; credits_PrintCredLines(hWnd); InvalidateRect(hWnda, 0, 0); UpdateWindow(hWnda); } // ref: 0x10005660 void __fastcall credits_PrintCredLines(HWND hWnd) { char *v1; // esi int i; // edi int v3; // ebp int v4; // ebx v1 = (char *)LockResource(credittext_rsrc); credit_line_count = credittext_size; SGdiSelectObject((int)creditsobj); SGdiSetPitch(credit_horz_pos); for (i = credit_vertical_pos2; credit_line_count > 0; v1 = credits_GetAdjustText(v1, v4)) { v3 = 0; while (*v1 == 9) { v3 += 40; ++v1; --credit_line_count; } v4 = credits_GetCredLineBreak(v1); if (v4 == -1) break; if (i >= 0) { if (i > credit_vertical_pos1 - 30) break; if (v4) { SGdiTextOut(credit_back_img, v3 + 2, i + 2, 0x1000000, v1, v4); SGdiTextOut(credit_back_img, v3, i, 16777440, v1, v4); } } i += 22; } if (i < 0) Title_KillAndFadeDlg(hWnd); } // 100103A6: using guessed type int __stdcall SGdiSetPitch(DWORD); // 100103AC: using guessed type int __stdcall SGdiSelectObject(DWORD); // 100296E8: using guessed type int credittext_size; // 100296FC: using guessed type int credit_vertical_pos1; // 10029700: using guessed type int credit_line_count; // ref: 0x10005736 int __fastcall credits_GetCredLineBreak(char *str) { int result; // eax result = 0; while (*str != 13 && *str != 10) { ++result; ++str; if (result > credit_line_count) return -1; } return result; } // 10029700: using guessed type int credit_line_count; // ref: 0x10005755 char *__fastcall credits_GetAdjustText(char *str, int len) { credit_line_count += -2 - len; return &str[len + 2]; } // 10029700: using guessed type int credit_line_count; ================================================ FILE: DiabloUI/diabedit.cpp ================================================ // ref: 0x10005765 void __fastcall DiabEdit_DoPaintBMP(HWND hWnd) { struct tagPAINTSTRUCT Paint; // [esp+4h] [ebp-40h] BeginPaint(hWnd, &Paint); SDlgDrawBitmap(hWnd, 1, 0, 0, 0, 0, 0); EndPaint(hWnd, &Paint); } // ref: 0x1000579B void __cdecl DiabEdit_cpp_init() { DiabEdit_cpp_float = DiabEdit_cpp_float_value; } // 1001F40C: using guessed type int DiabEdit_cpp_float_value; // 1002970C: using guessed type int DiabEdit_cpp_float; // ref: 0x100057A6 void __cdecl DiabEdit_SetupWindow() { WNDCLASSA WndClass; // [esp+0h] [ebp-28h] memset(&WndClass, 0, 0x28u); WndClass.style = 64; WndClass.lpfnWndProc = DiabEdit_WndProc; WndClass.hInstance = GetModuleHandleA(0); WndClass.lpszClassName = "DIABLOEDIT"; RegisterClassA(&WndClass); } // ref: 0x100057E8 LRESULT __stdcall DiabEdit_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { if (Msg <= 0x113) { if (Msg == 275) { DiabEdit_GetCursorProp(hWnd); return 0; } if (Msg == 1) { DiabEdit_SetRestrictTimer(hWnd); } else if (Msg == 2) { DiabEdit_RemoveAllProps(hWnd); } else { if (Msg != 7) { if (Msg == 15) { DiabEdit_DoPaintBMP(hWnd); } else { if (Msg == 135) return 129; if (Msg != 256) { if (Msg == 258) DiabEdit_RestrictAndLimit(hWnd, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam); } DiabEdit_SetTextAndProp(hWnd, wParam, lParam); } return 0; } DiabEdit_SendWndCommand(hWnd, 1u); } return DefWindowProcA(hWnd, Msg, wParam, lParam); } switch (Msg) { case 0x201u: SetFocus(hWnd); return DefWindowProcA(hWnd, Msg, wParam, lParam); case 0x400u: SetWindowTextA(hWnd, &nullcharacter); DiabEdit_SendWndCommand(hWnd, 3u); return 0; case 0x401u: SetPropA(hWnd, "LIMIT", (HANDLE)wParam); return 0; case 0x402u: return (LRESULT)GetPropA(hWnd, "LIMIT"); } if (Msg != 1027) { if (Msg == 1028) { DiabEdit_SetRestrictString(hWnd, lParam); return 0; } return DefWindowProcA(hWnd, Msg, wParam, lParam); } return (LRESULT)GetPropA(hWnd, "CURSOR"); } // ref: 0x1000591C void __fastcall DiabEdit_SendWndCommand(HWND hWnd, WORD a2) { int v4; // ST08_4 HWND v5; // eax v4 = (a2 << 16) | (unsigned short)GetWindowLongA(hWnd, -12); v5 = GetParent(hWnd); SendMessageA(v5, 0x111u, v4, (LPARAM)hWnd); } // ref: 0x1000594E void __fastcall DiabEdit_GetCursorProp(HWND hWnd) { size_t v2; // eax char *v3; // esi char String[256]; // [esp+Ch] [ebp-100h] String[0] = nullcharacter; memset(&String[1], 0, 0xFCu); *(WORD *)&String[253] = 0; String[255] = 0; if (GetPropA(hWnd, "CURSOR")) { SetPropA(hWnd, "CURSOR", 0); DiabEdit_SendWndCommand(hWnd, 3u); } else { SetPropA(hWnd, "CURSOR", (void *)HANDLE_FLAG_INHERIT); GetWindowTextA(hWnd, String, 255); String[254] = 0; v2 = strlen(String); String[v2 + 1] = 0; v3 = &String[v2]; String[v2] = 124; SetWindowTextA(hWnd, String); DiabEdit_SendWndCommand(hWnd, 3u); *v3 = 0; SetWindowTextA(hWnd, String); } } // ref: 0x10005A0A void __fastcall DiabEdit_RestrictAndLimit(HWND hWnd, WPARAM wParam, LPARAM lParam) { unsigned char v3; // bl char *v4; // eax char v5; // cl signed int v6; // eax signed int v7; // esi //char v8; // [esp+7h] [ebp-105h] char String[256]; // [esp+8h] [ebp-104h] String[0] = nullcharacter; v3 = wParam; memset(&String[1], 0, 0xFCu); *(WORD *)&String[253] = 0; String[255] = 0; if ((BYTE)wParam == 8) goto LABEL_9; if ((unsigned char)wParam < 0x20u || (unsigned char)wParam > 0x7Eu && (unsigned char)wParam < 0xC0u) return; v4 = (char *)GetPropA(hWnd, "RESTRICTED"); if (!v4 || (v5 = *v4) == 0) { LABEL_9: GetWindowTextA(hWnd, String, 255); String[254] = 0; v6 = strlen(String); v7 = v6; if (v3 == 8) { if (v6) { String[v6 - 1] = 0; // *(&v8 + v6) = 0; goto LABEL_14; } } else if (v6 < (signed int)GetPropA(hWnd, "LIMIT")) { String[v7] = v3; String[v7 + 1] = 0; LABEL_14: SetWindowTextA(hWnd, String); goto LABEL_15; } LABEL_15: DiabEdit_GetCursorProp(hWnd); return; } while (v3 != v5) { v5 = *++v4; if (!*v4) goto LABEL_9; } } // ref: 0x10005AF4 void __fastcall DiabEdit_SetTextAndProp(HWND hWnd, WPARAM wParam, LPARAM lParam) { WPARAM v4; // ebx size_t v5; // eax //char v6; // [esp+Bh] [ebp-101h] char String[256]; // [esp+Ch] [ebp-100h] String[0] = nullcharacter; memset(&String[1], 0, 0xFCu); *(WORD *)&String[253] = 0; String[255] = 0; v4 = wParam; GetWindowTextA(hWnd, String, 255); String[254] = 0; v5 = strlen(String); if (v4 == 37) { if (v5) { String[v5 - 1] = 0; // *(&v6 + v5) = 0; SetWindowTextA(hWnd, String); } DiabEdit_GetCursorProp(hWnd); } } // ref: 0x10005B70 void __fastcall DiabEdit_SetRestrictString(HWND hWnd, LPARAM lParam) { const char *v2; // edi char *v3; // eax MAPDST v2 = (const char *)lParam; v3 = (char *)GetPropA(hWnd, "RESTRICTED"); if (v3) { strncpy(v3, v2, 0xFFu); v3[255] = 0; } } // ref: 0x10005B9F void __fastcall DiabEdit_SetRestrictTimer(HWND hWnd) { unsigned char *v2; // eax SDlgSetTimer((int)hWnd, 1, 500, 0); SetPropA(hWnd, "CURSOR", 0); v2 = (unsigned char *)SMemAlloc(0x100u, "C:\\Src\\Diablo\\DiabloUI\\DiabEdit.cpp", 185, 0); *v2 = 0; SetPropA(hWnd, "RESTRICTED", v2); } // ref: 0x10005BE7 void __fastcall DiabEdit_RemoveAllProps(HWND hWnd) { HANDLE v2; // eax SDlgKillTimer((int)hWnd, 1); RemovePropA(hWnd, "LIMIT"); RemovePropA(hWnd, "CURSOR"); v2 = RemovePropA(hWnd, "RESTRICTED"); if (v2) SMemFree(v2, "C:\\Src\\Diablo\\DiabloUI\\DiabEdit.cpp", 200, 0); } ================================================ FILE: DiabloUI/diabloui.cpp ================================================ #define STRICT // for WNDPROC. ref: Remarks in https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-callwindowproca #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 "..\3rdParty\Storm\Source\storm.h" #include "diabloui.h" #define UNKCALL __fastcall #define USERCALL __fastcall #define USERPURGE __fastcall //temporarily include everything directly #include "_temp_data.cpp" #include "_temp_funcs.h" #include "artfont.cpp" #include "bn_prof.cpp" #include "bnetgw.cpp" #include "connect.cpp" #include "copyprot.cpp" #include "cr8game.cpp" #include "creadung.cpp" #include "creastat.cpp" #include "credits.cpp" #include "diabedit.cpp" #include "dirlink.cpp" #include "disclaim.cpp" #include "doom.cpp" #include "entdial.cpp" #include "entname.cpp" #include "fade.cpp" #include "focus.cpp" #include "local.cpp" #include "mainmenu.cpp" #include "modem.cpp" #include "modmstat.cpp" #include "okcancel.cpp" #include "progress.cpp" #include "sbar.cpp" #include "selclass.cpp" #include "selconn.cpp" #include "seldial.cpp" #include "selgame.cpp" #include "selhero.cpp" #include "selipx.cpp" #include "sellist.cpp" #include "selload.cpp" #include "selmodem.cpp" #include "selregn.cpp" #include "selyesno.cpp" #include "title.cpp" #include "titlesnd.cpp" // ref: 0x10005C2A int __cdecl DiabloUI_GetSpawned() { return sgbIsSpawn; } // 1002972C: using guessed type int sgbIsSpawn; // ref: 0x10005C30 void __stdcall UiOnPaint(int a1) { return; } // ref: 0x10005C33 void __stdcall UiSetBackgroundBitmap(int a1, PALETTEENTRY *a2, int a3, int a4, int a5) { backbmp_flag1 = a3; backbmp_flag2 = a4; backbmp_flag3 = a5; SDrawUpdatePalette(0xAu, 0xECu, a2 + 10, 0); } // 1002971C: using guessed type int backbmp_flag1; // 10029720: using guessed type int backbmp_flag2; // 10029724: using guessed type int backbmp_flag3; // ref: 0x10005C67 void __stdcall UiSetSpawned(BOOL bSpawned) { sgbIsSpawn = bSpawned; } // 1002972C: using guessed type int sgbIsSpawn; // ref: 0x10005C73 void __stdcall UiInitialize() { sgbUiIsInitialized = 1; TitleSnd_InitSoundFunc(); artfont_InitAllFonts(); Connect_LoadGFXAndStuff(); local_LoadArtCursor(); bn_prof_100021C4(); } // 10029714: using guessed type int sgbUiIsInitialized; // ref: 0x10005C96 void __stdcall UiDestroy() { bn_prof_10002247(); local_FreeArtCursor(); Connect_FreeConnectData(); sgbUiIsInitialized = 0; } // 10029714: using guessed type int sgbUiIsInitialized; // ref: 0x10005CAD void __stdcall UiAppActivate(BOOL bActive) { app_is_active = bActive; } // 10029728: using guessed type int app_is_active; // ref: 0x10005CB9 BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if (fdwReason) { if (fdwReason == 1) { ghUiInst = hinstDLL; DiabEdit_SetupWindow(); local_InitUiPalette(); } } else { local_DelUiPalette(); } return TRUE; } // ref: 0x10005CEA void __cdecl DiabloUI_cpp_init() { DiabloUI_cpp_float = DiabloUI_cpp_float_value; } // 1001F410: using guessed type int DiabloUI_cpp_float_value; // 10029710: using guessed type int DiabloUI_cpp_float; ================================================ FILE: DiabloUI/diabloui.def ================================================ LIBRARY "DiabloUI" EXPORTS UiValidPlayerName UiAppActivate UiArtCallback UiAuthCallback UiBetaDisclaimer UiCategoryCallback UiCopyProtError UiCreateGameCallback UiCreateGameCriteria UiCreatePlayerDescription UiCreditsDialog UiDestroy UiDrawDescCallback UiGetDataCallback UiGetDefaultStats UiInitialize UiMainMenuDialog UiMessageBoxCallback UiOnPaint UiProfileCallback UiProfileDraw UiProfileGetString UiProgressDialog UiSelHeroMultDialog UiSelHeroSingDialog UiSelectGame UiSelectProvider UiSelectRegion UiSetBackgroundBitmap UiSetSpawned UiSetupPlayerInfo UiSoundCallback UiTitleDialog ================================================ FILE: DiabloUI/diabloui.h ================================================ //HEADER_GOES_HERE #ifndef __DIABLOUI_H__ #define __DIABLOUI_H__ #if defined(__GNUC__) || defined(__cplusplus) extern "C" { #endif struct FontStruct { unsigned char fontbin[258]; HANDLE fonttrans[256]; BOOL active; }; struct ProfileStruct { const char *name; char field_4; int msg; int field_C; }; struct ProfFntStruct { int size; const char *fontname; int field_8; }; void __stdcall UiDestroy(); BOOL __stdcall UiTitleDialog(int a1); void __stdcall UiSetSpawned(BOOL bSpawned); void __stdcall UiInitialize(); BOOL __stdcall UiCopyProtError(int *pdwResult); void __stdcall UiAppActivate(BOOL bActive); BOOL __fastcall UiValidPlayerName(const char *name); /* check __stdcall */ BOOL __stdcall UiSelHeroMultDialog(BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *)), BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *), BOOL(__stdcall *fnstats)(unsigned int, _uidefaultstats *), int *dlgresult, BOOL *hero_is_created, char *name); BOOL __stdcall UiSelHeroSingDialog(BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *)), BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *), BOOL(__stdcall *fnstats)(unsigned int, _uidefaultstats *), int *dlgresult, char *name, int *difficulty); BOOL __stdcall UiCreditsDialog(int a1); BOOL __stdcall UiMainMenuDialog(const char *name, int *pdwResult, void(__stdcall *fnSound)(const char *file), int attractTimeOut); BOOL __stdcall UiProgressDialog(HWND window, const char *msg, int enable, int(*fnfunc)(), int rate); const char **__stdcall UiProfileGetString(); void __cdecl UiProfileCallback(); void __cdecl UiProfileDraw(); BOOL __stdcall UiCategoryCallback(int a1, int a2, int a3, int a4, int a5, DWORD *a6, DWORD *a7); BOOL __stdcall UiGetDataCallback(int game_type, int data_code, void *a3, int a4, int a5); BOOL __stdcall UiAuthCallback(int a1, char *a2, char *a3, char a4, char *a5, LPSTR lpBuffer, int cchBufferMax); BOOL __stdcall UiSoundCallback(int a1, int type, int a3); void __stdcall UiMessageBoxCallback(HWND hWnd, char *lpText, LPCSTR lpCaption, UINT uType); BOOL __stdcall UiDrawDescCallback(int game_type, COLORREF color, LPCSTR lpString, char *a4, int a5, UINT align, time_t a7, HDC *a8); BOOL __stdcall UiCreateGameCallback(int a1, int a2, int a3, int a4, int a5, int a6); BOOL __stdcall UiArtCallback(int game_type, unsigned int art_code, PALETTEENTRY *pPalette, BYTE *pBuffer, DWORD dwBuffersize, DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwBpp); 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); BOOL __stdcall UiCreatePlayerDescription(_uiheroinfo *info, DWORD mode, char *desc); void __stdcall UiSetupPlayerInfo(char *infostr, _uiheroinfo *pInfo, DWORD type); void __stdcall UiCreateGameCriteria(_uiheroinfo *pInfo, char *str); BOOL __stdcall UiGetDefaultStats(int pclass, _uidefaultstats *pStats); BOOL __stdcall UiBetaDisclaimer(int a1); #if defined(__GNUC__) || defined(__cplusplus) } #endif #endif /* __DIABLOUI_H__ */ ================================================ FILE: DiabloUI/diabloui_gcc.def ================================================ LIBRARY "DiabloUI" EXPORTS UiValidPlayerName @1 @UiValidPlayerName@4 @1 NONAME UiAppActivate @2 UiAppActivate@4 @2 NONAME UiArtCallback @3 UiArtCallback@32 @3 NONAME UiAuthCallback @4 UiAuthCallback@28 @4 NONAME UiBetaDisclaimer @5 UiBetaDisclaimer@4 @5 NONAME UiCategoryCallback @6 UiCategoryCallback@28 @6 NONAME UiCopyProtError @7 UiCopyProtError@4 @7 NONAME UiCreateGameCallback @8 UiCreateGameCallback@24 @8 NONAME UiCreateGameCriteria @9 UiCreatePlayerDescription @10 UiCreatePlayerDescription@12 @10 NONAME UiCreditsDialog @11 UiCreditsDialog@4 @11 NONAME UiDestroy @12 UiDestroy@0 @12 NONAME UiDrawDescCallback @13 UiDrawDescCallback@32 @13 NONAME UiGetDataCallback @14 UiGetDataCallback@20 @14 NONAME UiGetDefaultStats @15 UiInitialize @16 UiInitialize@0 @16 NONAME UiMainMenuDialog @17 UiMainMenuDialog@16 @17 NONAME UiMessageBoxCallback @18 UiMessageBoxCallback@16 @18 NONAME UiOnPaint @19 UiProfileCallback @20 UiProfileDraw @21 UiProfileGetString @22 UiProfileGetString@0 @22 NONAME UiProgressDialog @23 UiProgressDialog@20 @23 NONAME UiSelHeroMultDialog @24 UiSelHeroMultDialog@28 @24 NONAME UiSelHeroSingDialog @25 UiSelHeroSingDialog@28 @25 NONAME UiSelectGame @26 UiSelectGame@24 @26 NONAME UiSelectProvider @27 UiSelectProvider@24 @27 NONAME UiSelectRegion @28 UiSetBackgroundBitmap @29 UiSetSpawned @30 UiSetSpawned@4 @30 NONAME UiSetupPlayerInfo @31 UiSetupPlayerInfo@12 @31 NONAME UiSoundCallback @32 UiSoundCallback@12 @32 NONAME UiTitleDialog @33 UiTitleDialog@4 @33 NONAME ================================================ FILE: DiabloUI/dirlink.cpp ================================================ // ref: 0x10005CFA signed int DirLink_10005CFA() { return 0; } /* { signed int result; // eax result = 2139095040; dword_10029730 = 2139095040; return result; } */ // 10029730: using guessed type int dword_10029730; // ref: 0x10005D05 BOOL __fastcall DirLink_10005D05(int a1, int a2, int a3, DWORD *a4, int a5, int playerid) { return 0; } /* { int v6; // esi dword_1002983C = a3; dword_1002984C = a2; dword_10029840 = a5; dword_10029848 = a4; gnDlinkPlayerid = playerid; artfont_10001159(); v6 = SDlgDialogBoxParam(hInstance, "DIRLINK_DIALOG", a4[2], DirLink_10005D63, 0); artfont_100010C8(); return v6 == 1; } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // 1002983C: using guessed type int dword_1002983C; // 10029840: using guessed type int dword_10029840; // 10029844: using guessed type int gnDlinkPlayerid; // 1002984C: using guessed type int dword_1002984C; // ref: 0x10005D63 int __stdcall DirLink_10005D63(HWND hWnd, UINT Msg, WPARAM wParam, unsigned int lParam) { return 0; } /* { HWND v4; // eax int v6; // [esp+0h] [ebp-Ch] char *v7; // [esp+4h] [ebp-8h] char *v8; // [esp+8h] [ebp-4h] if ( Msg > 0x111 ) { switch ( Msg ) { case 0x113u: if ( wParam == 3 ) { DirLink_100062BF(hWnd, v6, v7, v8); DirLink_10006073(hWnd); } return 0; case 0x201u: DirLink_10006359(hWnd, (unsigned short)lParam, lParam >> 16); break; case 0x7E8u: if ( !Fade_1000739F() ) Fade_100073FD(hWnd, v6); return 0; } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg == 273 ) { if ( HIWORD(wParam) == 7 ) { Focus_100075B7(hWnd, (HWND)lParam); } else if ( HIWORD(wParam) == 6 ) { Focus_10007458((void *)lParam); Focus_100075DC(hWnd, (HWND)lParam); DirLink_10005EB2(hWnd, (unsigned short)wParam); } else if ( wParam == 327681 ) { DirLink_100060D1(hWnd); } else if ( (WORD)wParam == 2 ) { DirLink_10006047((int)hWnd, 2); } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg == 2 ) { DirLink_10005F1F(hWnd); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg <= 0x103 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); if ( Msg <= 0x105 ) { v4 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v4, Msg, wParam, lParam); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg != 272 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); PostMessageA(hWnd, 0x7E8u, 0, 0); DirLink_10005F7B(hWnd); return 0; } */ // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x10005EB2 int __fastcall DirLink_10005EB2(HWND hDlg, int a2) { return 0; } /* { HWND v2; // esi int v3; // edi HWND v4; // ebx int v5; // eax CHAR Buffer; // [esp+Ch] [ebp-100h] v2 = hDlg; v3 = a2; v4 = GetDlgItem(hDlg, 1102); if ( v3 == 1100 ) LoadStringA(hInstance, 0x2Au, &Buffer, 255); else LoadStringA(hInstance, 0x2Fu, &Buffer, 255); v5 = GetWindowLongA(v4, -21); local_10007FA4(v5, &Buffer); return Doom_10006A13(v2, (int *)&unk_10022A40, 1); } */ // ref: 0x10005F1F int UNKCALL DirLink_10005F1F(HWND hDlg) { return 0; } /* { HWND v1; // esi DWORD *v2; // eax v1 = hDlg; Doom_10006C53(hDlg, (int *)&unk_10022A54); Doom_10006C53(v1, (int *)&unk_10022A48); Doom_10006C53(v1, (int *)&unk_10022A40); Doom_10006C53(v1, (int *)&unk_10022A38); Doom_10006C53(v1, (int *)&unk_10022A2C); v2 = (DWORD *)GetWindowLongA(v1, -21); local_10007F72(v2); Title_100100E7(v1); return Focus_10007818(v1); } */ // ref: 0x10005F7B int UNKCALL DirLink_10005F7B(HWND hWnd) { return 0; } /* { HWND v1; // esi HWND v2; // ST1C_4 int v3; // eax int *v4; // edi HWND v6; // [esp-4h] [ebp-Ch] int v7; // [esp-4h] [ebp-Ch] char *v8; // [esp+0h] [ebp-8h] char *v9; // [esp+4h] [ebp-4h] v1 = hWnd; Focus_100077E9((int)hWnd, "ui_art\\focus16.pcx", v6); Title_1001009E(v1, (int)"ui_art\\smlogo.pcx", v2); v3 = local_10007F46(); v4 = (int *)v3; if ( v3 ) { SetWindowLongA(v1, -21, v3); local_10007944((int)v1, 0, &byte_10029448, -1, 1, (int)"ui_art\\selgame.pcx", v4, v4 + 1, 0); Fade_100073C5(v1, 1); } local_10007CB5(v1, (int *)&unk_10022A54); Doom_100068AB(v1, (int *)&unk_10022A2C, 5); Doom_100068AB(v1, (int *)&unk_10022A38, 3); Doom_100068AB(v1, (int *)&unk_10022A40, 1); Doom_1000658C(v1, (int *)&unk_10022A48, 4, 0); Doom_1000658C(v1, (int *)&unk_10022A54, 2, 1); DirLink_100062BF(v1, v7, v8, v9); DirLink_10006073(v1); return SDlgSetTimer(v1, 3, 2000, 0); } */ // 10010412: using guessed type int __stdcall SDlgSetTimer(DWORD, DWORD, DWORD, DWORD); // ref: 0x10006047 int __fastcall DirLink_10006047(int a1, int a2) { return 0; } /* { int v2; // edi int v3; // esi v2 = a2; v3 = a1; TitleSnd_1001031F(); Fade_100073B4(); SDlgKillTimer(v3, 3); Fade_100072BE(10); return SDlgEndDialog(v3, v2); } */ // 10010376: using guessed type int __stdcall SDlgEndDialog(DWORD, DWORD); // 10010418: using guessed type int __stdcall SDlgKillTimer(DWORD, DWORD); // ref: 0x10006073 void UNKCALL DirLink_10006073(void *arg) { return; } /* { int v1; // esi char v2; // [esp+4h] [ebp-100h] char v3; // [esp+84h] [ebp-80h] v1 = (int)arg; if ( dword_10029738 ) { Connect_10004028((int)&v2, 128, (int)&v3, 128); if ( SNetJoinGame(dword_10029738, &byte_1002973C, 0, &v2, &v3, gnDlinkPlayerid) ) DirLink_10006047(v1, 1); } } */ // 10010430: using guessed type int __stdcall SNetJoinGame(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // 10029738: using guessed type int dword_10029738; // 10029844: using guessed type int gnDlinkPlayerid; // ref: 0x100060D1 HWND UNKCALL DirLink_100060D1(HWND arg) { return 0; } /* { HWND v1; // esi HWND v2; // eax HWND v3; // edi HWND result; // eax CHAR Buffer; // [esp+8h] [ebp-80h] v1 = arg; v2 = GetFocus(); v3 = v2; result = GetParent(v2); if ( v1 == result ) { if ( GetWindowLongA(v3, -12) == 1100 ) { result = (HWND)DirLink_10006141(v1); } else if ( dword_10029738 ) { result = (HWND)DirLink_100061E1(v1); } else { LoadStringA(hInstance, 0x2Bu, &Buffer, 127); result = (HWND)SelYesNo_1000FD39((int)v1, &Buffer, 0, 0); } } return result; } */ // 10029738: using guessed type int dword_10029738; // ref: 0x10006141 int UNKCALL DirLink_10006141(void *arg) { return 0; } /* { int v1; // edi int result; // eax char v3; // [esp+8h] [ebp-E0h] int v4; // [esp+88h] [ebp-60h] int v5; // [esp+90h] [ebp-58h] int v6; // [esp+D8h] [ebp-10h] int v7; // [esp+DCh] [ebp-Ch] int v8; // [esp+E0h] [ebp-8h] int v9; // [esp+E4h] [ebp-4h] v1 = (int)arg; Connect_10004028((int)&v3, 128, 0, 0); memcpy(&v4, dword_10029848, 0x50u); v4 = 80; v5 = v1; memset(&v6, 0, 0x10u); v6 = 16; v7 = 1396916812; v8 = *(DWORD *)(dword_1002984C + 24); v9 = 0; result = CreaDung_100051D8( (int)&v6, dword_1002984C, dword_1002983C, (int)&v4, dword_10029840, gnDlinkPlayerid, 0, (int)&v3); if ( result ) result = DirLink_10006047(v1, 1); return result; } */ // 1002983C: using guessed type int dword_1002983C; // 10029840: using guessed type int dword_10029840; // 10029844: using guessed type int gnDlinkPlayerid; // 1002984C: using guessed type int dword_1002984C; // ref: 0x100061E1 int UNKCALL DirLink_100061E1(void *arg) { return 0; } /* { int v1; // ebx CHAR *v2; // edx CHAR v4; // [esp+Ch] [ebp-380h] CHAR v5; // [esp+10Ch] [ebp-280h] int v6; // [esp+20Ch] [ebp-180h] char v7; // [esp+28Ch] [ebp-100h] CHAR Buffer; // [esp+30Ch] [ebp-80h] v1 = (int)arg; Connect_10004028((int)&v6, 128, (int)&v7, 128); if ( UiAuthCallback(2, (int)&v6, &v7, 0, &byte_100297BC, &v5, 256) ) { if ( SNetJoinGame(dword_10029738, &byte_1002973C, 0, &v6, &v7, gnDlinkPlayerid) ) return DirLink_10006047(v1, 1); if ( SErrGetLastError() == -2062548871 ) LoadStringA(hInstance, 0x32u, &Buffer, 127); else LoadStringA(hInstance, 0x25u, &Buffer, 127); wsprintfA(&v4, &Buffer, &byte_1002973C); v2 = &v4; } else { v2 = &v5; } return SelYesNo_1000FD39(v1, v2, 0, 0); } */ // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // 10010430: using guessed type int __stdcall SNetJoinGame(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // 10029738: using guessed type int dword_10029738; // 10029844: using guessed type int gnDlinkPlayerid; // ref: 0x100062BF int UNKCALL DirLink_100062BF(void *arg, int a2, char *a3, char *a4) { return 0; } /* { int v4; // esi int result; // eax CHAR Buffer; // [esp+8h] [ebp-80h] v4 = (int)arg; dword_10029738 = 0; byte_1002973C = 0; byte_100297BC = 0; result = SNetEnumGames(0, 0, DirLink_1000632B, 0); if ( !result ) { result = SErrGetLastError(); if ( result == -2062548871 ) { LoadStringA(hInstance, 0x32u, &Buffer, 127); SelYesNo_1000FD39(v4, &Buffer, 0, 0); result = DirLink_10006047(v4, 2); } } return result; } */ // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // 10010436: using guessed type int __stdcall SNetEnumGames(DWORD, DWORD, DWORD, DWORD); // 10029738: using guessed type int dword_10029738; // ref: 0x1000632B signed int __stdcall DirLink_1000632B(int a1, char *a2, char *a3) { return 0; } /* { dword_10029738 = a1; strcpy(&byte_1002973C, a2); strcpy(&byte_100297BC, a3); return 1; } */ // 10029738: using guessed type int dword_10029738; // ref: 0x10006359 HWND __fastcall DirLink_10006359(HWND hWnd, int a2, int a3) { return 0; } /* { int v3; // ebx HWND v4; // esi int v5; // ST08_4 HWND v6; // eax HWND result; // eax HWND v8; // eax v3 = a2; v4 = hWnd; v5 = a2; v6 = GetDlgItem(hWnd, 1056); if ( local_10007C3B(v4, v6, v5, a3) ) return DirLink_100060D1(v4); v8 = GetDlgItem(v4, 1054); result = (HWND)local_10007C3B(v4, v8, v3, a3); if ( result ) result = (HWND)DirLink_10006047((int)v4, 2); return result; } */ ================================================ FILE: DiabloUI/disclaim.cpp ================================================ // ref: 0x100063B3 BOOL __stdcall UiBetaDisclaimer(int a1) { int v1; // eax v1 = (int)SDrawGetFrameWindow(NULL); SDlgDialogBoxParam(ghUiInst, "DISCLAIMER_DIALOG", v1, disclaim_WndProc, a1); return 1; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x100063DA LRESULT __stdcall disclaim_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v5; // eax if (Msg > 0x111) { if (Msg != 513 && Msg != 516) { if (Msg == 528) { if ((WORD)wParam == 513 || (WORD)wParam == 516) disclaim_FadeFromDisclaim(hWnd); } else if (Msg == 2024) { if (!Fade_CheckRange5()) Fade_SetFadeTimer((int)hWnd); return 0; } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } } else if (Msg != 273) { if (Msg != 2) { if (Msg != 256) { if (Msg > 0x103) { if (Msg <= 0x105) { v5 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v5, Msg, wParam, lParam); } else if (Msg == 272) { disclaim_LoadDisclaimGFX(hWnd); PostMessageA(hWnd, 0x7E8u, 0, 0); return 1; } } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } goto LABEL_21; } disclaim_DelDisclaimProcs(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } LABEL_21: disclaim_FadeFromDisclaim(hWnd); return 0; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x100064C9 void __fastcall disclaim_DelDisclaimProcs(HWND hWnd) { void **v2; // eax Doom_DeleteFreeProcs(hWnd, disclaim_msgtbl2); Doom_DeleteFreeProcs(hWnd, disclaim_msgtbl1); v2 = (void **)GetWindowLongA(hWnd, -21); local_FreeMemPtr(v2); } // ref: 0x100064F3 void __fastcall disclaim_LoadDisclaimGFX(HWND hWnd) { DWORD *v2; // eax MAPDST v2 = local_AllocWndLongData(); if (v2) { SetWindowLongA(hWnd, -21, (LONG)v2); local_LoadArtWithPal(hWnd, 0, &nullcharacter, -1, 1, "ui_art\\disclaim.pcx", (BYTE **)v2, v2 + 1, 0); Fade_NoInputAndArt(hWnd, 0); } Doom_ParseWndProc3(hWnd, disclaim_msgtbl1, AF_BIGGRAY); Doom_ParseWndProc3(hWnd, disclaim_msgtbl2, AF_MED); } // ref: 0x10006552 void __fastcall disclaim_FadeFromDisclaim(HWND hWnd) { Fade_Range5SetZero(); Fade_UpdatePaletteRange(10); SDlgEndDialog(hWnd, (void *)HANDLE_FLAG_INHERIT); } // ref: 0x10006571 void __cdecl disclaim_cpp_init() { disclaim_cpp_float = disclaim_cpp_float_value; } // 1001F418: using guessed type int disclaim_cpp_float_value; // 10029850: using guessed type int disclaim_cpp_float; ================================================ FILE: DiabloUI/doom.cpp ================================================ // ref: 0x10006581 void __cdecl Doom_cpp_init() { doom_cpp_float = doom_cpp_float_value; } // 1001F41C: using guessed type int doom_cpp_float_value; // 10029854: using guessed type int doom_cpp_float; // ref: 0x1000658C void __fastcall Doom_ParseWndProcs(HWND hWnd, int *msgtbl, int nFont, int a4) { HWND msg; // eax while (*msgtbl) { msg = GetDlgItem(hWnd, *msgtbl); Doom_GetSetWndText(hWnd, (int)msg, nFont, a4); ++msgtbl; } } // ref: 0x100065BB void __fastcall Doom_GetSetWndText(HWND hWnd, int msg, int nFont, int a4) { HWND v4; // esi HWND v5; // edi int v6; // eax char String[256]; // [esp+8h] [ebp-100h] v4 = (HWND)msg; v5 = hWnd; if (msg) { Doom_AllocAndSetBMP(hWnd, msg, 1521); Doom_GetWindowROP3(v5, v4); artfont_SetArtFont(nFont); Doom_PrintStrWithSpin(v4, a4); GetWindowTextA(v4, String, 255); if (strlen(String)) { v6 = GetWindowLongA(v4, -21); local_SetWndLongStr(v6, String); SetWindowTextA(v4, &nullcharacter); } } } // ref: 0x1000663F void __fastcall Doom_PrintStrWithSpin(HWND hWnd, BOOL a2) { DWORD *v3; // eax DWORD *v4; // esi char *v5; // ebx int v6; // edi size_t v7; // eax char *i; // eax int v9; // kr04_4 int v10; // eax char String[256]; // [esp+8h] [ebp-10Ch] char *v12; // [esp+108h] [ebp-Ch] int v14; // [esp+110h] [ebp-4h] v3 = (DWORD *)GetWindowLongA(hWnd, -21); v4 = v3; if (v3 && *v3) { GetWindowTextA(hWnd, String, 255); v5 = String; if (!strlen(String)) v5 = (char *)(v4 + 4); v14 = artfont_GetFontWidth(v5); if (a2) { v6 = v4[1] - 2 * Focus_GetSpinWidthOrZero(); v7 = strlen(v5); if (v14 > v6) { for (i = &v5[v7];; i = v12) { v12 = i - 1; *v12 = 0; v14 = artfont_GetFontWidth(v5); if (v14 <= v6) break; } } } v9 = v4[1] - v14 - 1; v10 = artfont_GetFontMaxHeight(); artfont_PrintFontStr(v5, (DWORD **)v4, v9 / 2, (v4[2] - v10) / 2); InvalidateRect(hWnd, 0, 0); } } // ref: 0x10006719 void __fastcall Doom_AllocAndSetBMP(HWND hWnd, int a2, int bmp_flags) { DWORD *v4; // esi struct tagRECT Rect; // [esp+8h] [ebp-10h] GetClientRect((HWND)a2, &Rect); v4 = local_AllocWndLongData(); v4[1] = Rect.right; v4[2] = Rect.bottom; *v4 = (DWORD)SMemAlloc(Rect.right * Rect.bottom, "C:\\Src\\Diablo\\DiabloUI\\Doom.cpp", 139, 0); SetWindowLongA((HWND)a2, -21, (LONG)v4); SDlgSetBitmapI((HWND)a2, 0, &nullcharacter, -1, bmp_flags, (void *)*v4, 0, v4[1], v4[2], -1); } // ref: 0x1000678A void __fastcall Doom_GetWindowROP3(HWND hWnd1, HWND hWnd2) { DWORD *v3; // ebx LONG v4; // eax MAPDST struct tagRECT Rect; // [esp+Ch] [ebp-14h] v3 = (DWORD *)GetWindowLongA(hWnd1, -21); v4 = GetWindowLongA(hWnd2, -21); if (v3 && *v3 && v4) { if (*(DWORD *)v4) { GetWindowRect(hWnd2, &Rect); ScreenToClient(hWnd1, (LPPOINT)&Rect); ScreenToClient(hWnd1, (LPPOINT)&Rect.right); SBltROP3( *(void **)v4, (void *)(Rect.left + *v3 + Rect.top * v3[1]), *(DWORD *)(v4 + 4), *(DWORD *)(v4 + 8), *(DWORD *)(v4 + 4), v3[1], 0, 0xCC0020u); } } } // ref: 0x1000680A void __fastcall Doom_ParseWndProc2(HWND hWnd, int *msgtbl, int nFont, int a4) { HWND msg; // eax while (*msgtbl) { msg = GetDlgItem(hWnd, *msgtbl); Doom_GetSetWndTxt2(hWnd, (int)msg, nFont, a4); ++msgtbl; } } // ref: 0x10006839 void __fastcall Doom_GetSetWndTxt2(HWND hWnd, int msg, int nFont, int a4) { HWND v4; // esi int v5; // eax char String[256]; // [esp+4h] [ebp-100h] v4 = (HWND)msg; if (msg) { Doom_GetWindowROP3(hWnd, (HWND)msg); artfont_SetArtFont(nFont); Doom_PrintStrWithSpin(v4, a4); GetWindowTextA(v4, String, 255); if (strlen(String)) { v5 = GetWindowLongA(v4, -21); local_SetWndLongStr(v5, String); SetWindowTextA(v4, &nullcharacter); } } } // ref: 0x100068AB void __fastcall Doom_ParseWndProc3(HWND hWnd, int *msgtbl, int nFont) { HWND msg; // eax while (*msgtbl) { msg = GetDlgItem(hWnd, *msgtbl); Doom_GetSetWndTxt3(hWnd, (int)msg, nFont); ++msgtbl; } } // ref: 0x100068D6 void __fastcall Doom_GetSetWndTxt3(HWND hWnd, int msg, int nFont) { HWND v3; // esi HWND v4; // edi int v5; // eax int v6; // eax char String[256]; // [esp+8h] [ebp-100h] v3 = (HWND)msg; v4 = hWnd; if (msg) { Doom_AllocAndSetBMP(hWnd, msg, 1); Doom_GetWindowROP3(v4, v3); artfont_SetArtFont(nFont); v5 = GetWindowLongA(v3, -16); Doom_PrintStrWithSpn2(v3, v5); GetWindowTextA(v3, String, 255); if (strlen(String)) { v6 = GetWindowLongA(v3, -21); local_SetWndLongStr(v6, String); SetWindowTextA(v3, &nullcharacter); } } } // ref: 0x1000695D void __fastcall Doom_PrintStrWithSpn2(HWND hWnd, int justify_type) { DWORD *v2; // eax DWORD *v3; // esi char *v4; // edi int v5; // eax char String[256]; // [esp+4h] [ebp-108h] v2 = (DWORD *)GetWindowLongA(hWnd, -21); v3 = v2; if (v2 && *v2) { GetWindowTextA(hWnd, String, 255); v4 = String; if (!strlen(String)) v4 = (char *)(v3 + 4); if (justify_type & 2) { v5 = v3[1] - artfont_GetFontWidth(v4) - 1; } else if (justify_type & 1) { v5 = (v3[1] - artfont_GetFontWidth(v4) - 1) / 2; } else { v5 = 0; } artfont_PrintFontStr(v4, (DWORD **)v3, v5, 0); InvalidateRect(hWnd, 0, 0); } } // ref: 0x10006A13 void __fastcall Doom_ParseWndProc4(HWND hWnd, int *msgtbl, int nFont) { HWND msg; // eax while (*msgtbl) { msg = GetDlgItem(hWnd, *msgtbl); Doom_GetSetWndTxt4(hWnd, (int)msg, nFont); ++msgtbl; } } // ref: 0x10006A3E void __fastcall Doom_GetSetWndTxt4(HWND hWnd, int msg, int nFont) { HWND v3; // edi int v4; // eax int v5; // eax char String[256]; // [esp+8h] [ebp-100h] v3 = (HWND)msg; if (msg) { Doom_GetWindowROP3(hWnd, (HWND)msg); artfont_SetArtFont(nFont); v4 = GetWindowLongA(v3, -16); Doom_PrintStrWithSpn2(v3, v4); GetWindowTextA(v3, String, 255); if (strlen(String)) { v5 = GetWindowLongA(v3, -21); local_SetWndLongStr(v5, String); SetWindowTextA(v3, &nullcharacter); } } } // ref: 0x10006AB8 void __fastcall Doom_ParseWndProc5(HWND hWnd, int *msgtbl, int nFont) { HWND msg; // eax while (*msgtbl) { msg = GetDlgItem(hWnd, *msgtbl); Doom_GetSetWndTxt5(hWnd, (int)msg, nFont); ++msgtbl; } } // ref: 0x10006AE3 void __fastcall Doom_GetSetWndTxt5(HWND hWnd, int msg, int nFont) { HWND v3; // esi v3 = (HWND)msg; if (msg) { Doom_AllocAndSetBMP(hWnd, msg, 1); Doom_GetWindowROP3(hWnd, v3); artfont_SetArtFont(nFont); Doom_PrintTextMsg403(v3); } } // ref: 0x10006B12 void __fastcall Doom_PrintTextMsg403(HWND hWnd) { BYTE *v2; // eax int v3; // edi int v4; // edi int v5; // esi int v6; // esi char *i; // ebx int v8; // eax //char v9; // [esp+3h] [ebp-11Dh] char String[256]; // [esp+4h] [ebp-11Ch] struct tagRECT Rect; // [esp+104h] [ebp-1Ch] LRESULT v12; // [esp+114h] [ebp-Ch] BYTE *pWidthBin; // [esp+118h] [ebp-8h] size_t v14; // [esp+11Ch] [ebp-4h] v2 = (BYTE *)GetWindowLongA(hWnd, -21); pWidthBin = v2; if (v2 && *(DWORD *)v2) { GetWindowTextA(hWnd, String, 255); v14 = strlen(String); v3 = Focus_GetSpinWidthOrZero(); v4 = artfont_GetFontDefWidth() + v3; GetClientRect(hWnd, &Rect); v5 = Focus_GetSpinWidthOrZero(); v6 = Rect.right - 2 * (artfont_GetFontDefWidth() + v5); v12 = SendMessageA(hWnd, 0x403u, 0, 0); if (v12 == 1) String[v14 - 1] = 0; // *(&v9 + v14) = 0; for (i = String; *i; ++i) { if (artfont_GetFontWidth(i) <= v6) break; } if (v12) String[v14 - 1] = 124; // *(&v9 + v14) = 124; v8 = artfont_GetFontMaxHeight(); artfont_PrintFontStr(i, (DWORD **)pWidthBin, v4, (*((DWORD *)pWidthBin + 2) - v8) / 2); } } // ref: 0x10006C08 void __fastcall Doom_ParseWndProc6(HWND hWnd, int *msgtbl, int nFont) { HWND msg; // eax while (*msgtbl) { msg = GetDlgItem(hWnd, *msgtbl); Doom_GetSetWndTxt6(hWnd, (int)msg, nFont); ++msgtbl; } } // ref: 0x10006C33 void __fastcall Doom_GetSetWndTxt6(HWND hWnd, int msg, int nFont) { HWND v3; // esi v3 = (HWND)msg; if (msg) { Doom_GetWindowROP3(hWnd, (HWND)msg); artfont_SetArtFont(nFont); Doom_PrintTextMsg403(v3); } } // ref: 0x10006C53 void __fastcall Doom_DeleteFreeProcs(HWND hWnd, int *msgtbl) { int i; // eax HWND v5; // eax MAPDST void **v7; // eax for (i = *msgtbl; *msgtbl; i = *msgtbl) { v5 = GetDlgItem(hWnd, i); if (v5) { v7 = (void **)GetWindowLongA(v5, -21); local_FreeMemPtr(v7); SetWindowLongA(v5, -21, 0); } ++msgtbl; } } ================================================ FILE: DiabloUI/entdial.cpp ================================================ // ref: 0x10006C96 int __stdcall EntDial_10006C96(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { int v4; // edx HWND v5; // eax HWND v7; // eax int savedregs; // [esp+Ch] [ebp+0h] v4 = 2; if ( Msg == 2 ) { EntDial_10006D78(hDlg); } else if ( Msg > 0x103 ) { if ( Msg <= 0x105 ) { v7 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v7, Msg, wParam, lParam); } else { if ( Msg == 272 ) { lpString = (LPSTR)lParam; EntDial_10006DB8(hDlg, (int)&savedregs); return 0; } if ( Msg != 273 ) { if ( Msg != 275 ) { if ( Msg == 513 ) EntDial_10006F16(hDlg, (unsigned short)lParam, (unsigned int)lParam >> 16); return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); } v5 = GetFocus(); Focus_100075DC(hDlg, v5); return 0; } if ( (unsigned short)wParam == 1 ) { v4 = 1; } else if ( (unsigned short)wParam != 2 ) { if ( (unsigned short)wParam == 1116 ) EntDial_10006EE8(hDlg, wParam, lParam); return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); } EntDial_10006EA7(hDlg, v4); } } return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); } */ // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x10006D78 HWND UNKCALL EntDial_10006D78(HWND hDlg) { return 0; } /* { HWND v1; // esi HWND v2; // eax v1 = hDlg; Focus_100076C3(); Doom_10006C53(v1, (int *)&unk_10022B10); Doom_10006C53(v1, (int *)&unk_10022B04); Doom_10006C53(v1, (int *)&unk_10022AFC); v2 = GetParent(v1); return Modem_10008563(v2, 0, 0); } */ // ref: 0x10006DB8 HWND USERCALL EntDial_10006DB8(HWND hWnd, int a2) { return 0; } /* { HWND v2; // esi HWND v3; // eax LONG v4; // eax HWND v5; // ebx HWND v6; // eax int v8; // [esp-138h] [ebp-144h] int v9; // [esp-38h] [ebp-44h] int v10; // [esp+8h] [ebp-4h] v2 = hWnd; v3 = GetParent(hWnd); v4 = GetWindowLongA(v3, -21); SetWindowLongA(v2, -21, v4); Doom_100068AB(v2, (int *)&unk_10022AFC, 5); Doom_1000658C(v2, (int *)&unk_10022B04, 4, 0); Doom_10006AB8(v2, (int *)&unk_10022B10, 2); Focus_10007719("ui_art\\focus.pcx"); SDlgSetTimer(v2, 1, 55, 0); v5 = GetDlgItem(v2, 1116); SendMessageA(v5, 0x401u, 0x1Fu, 0); SendMessageA(v5, 0x404u, 0, (LPARAM)"<>%&?"); v10 = a2; LoadStringA(hInstance, 0x3Bu, (LPSTR)&v9, 63); LoadStringA(hInstance, 0x3Au, (LPSTR)&v8, 255); v6 = GetParent(v2); return Modem_10008563(v6, (const char *)&v9, (int)&v8); } */ // 10006DB8: could not find valid save-restore pair for ebp // 10010412: using guessed type int __stdcall SDlgSetTimer(DWORD, DWORD, DWORD, DWORD); // ref: 0x10006EA7 int __fastcall EntDial_10006EA7(HWND hDlg, int a2) { return 0; } /* { int v2; // edi HWND v3; // esi CHAR *v4; // ST08_4 HWND v5; // eax v2 = a2; v3 = hDlg; TitleSnd_1001031F(); SDlgKillTimer(v3, 1); v4 = lpString; v5 = GetDlgItem(v3, 1116); GetWindowTextA(v5, v4, 32); lpString[31] = 0; return SDlgEndDialog(v3, v2); } */ // 10010376: using guessed type int __stdcall SDlgEndDialog(DWORD, DWORD); // 10010418: using guessed type int __stdcall SDlgKillTimer(DWORD, DWORD); // ref: 0x10006EE8 void __fastcall EntDial_10006EE8(HWND hWnd, unsigned int a2, int a3) { return; } /* { int v3; // edx HWND v4; // esi HWND v5; // eax v3 = (a2 >> 16) - 1; v4 = hWnd; if ( v3 ) { if ( v3 == 2 ) Doom_10006C08(hWnd, (int *)&unk_10022B10, 2); } else { v5 = GetFocus(); Focus_100075DC(v4, v5); } } */ // ref: 0x10006F16 int __fastcall EntDial_10006F16(HWND hDlg, int a2, int a3) { return 0; } /* { int v3; // ebx HWND v4; // esi int v5; // ST08_4 HWND v6; // eax int v7; // edx HWND v8; // eax int result; // eax v3 = a2; v4 = hDlg; v5 = a2; v6 = GetDlgItem(hDlg, 1056); if ( local_10007C3B(v4, v6, v5, a3) ) { v7 = 1; } else { v8 = GetDlgItem(v4, 1054); result = local_10007C3B(v4, v8, v3, a3); if ( !result ) return result; v7 = 2; } return EntDial_10006EA7(v4, v7); } */ // ref: 0x10006F71 signed int EntDial_10006F71() { return 0; } /* { signed int result; // eax result = 2139095040; dword_1002985C = 2139095040; return result; } */ // 1002985C: using guessed type int dword_1002985C; ================================================ FILE: DiabloUI/entname.cpp ================================================ // ref: 0x10006F7C LRESULT __stdcall EntName_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { int v4; // edx HWND v5; // eax HWND v6; // eax HWND v7; // eax HWND v9; // eax v4 = 2; if (Msg == 2) { EntName_DelEntNameMsgs(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg <= 0x103) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); if (Msg <= 0x105) { v9 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v9, Msg, wParam, lParam); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } switch (Msg) { case 0x110u: entname_charname = (char *)lParam; EntName_LoadFocusChkName(hWnd); return 0; case 0x111u: if ((unsigned short)wParam != 1) { if ((unsigned short)wParam != 2) { if ((unsigned short)wParam == 1065) EntName_GetMessageName(hWnd, wParam, lParam); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } goto LABEL_11; } goto LABEL_18; case 0x113u: v7 = GetFocus(); Focus_DoBlitSpinIncFrame(hWnd, v7); return 0; } if (Msg != 513) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); v5 = GetDlgItem(hWnd, 1056); if (local_GetBottomRect(hWnd, v5, (unsigned short)lParam, (unsigned int)lParam >> 16)) { LABEL_18: v4 = 1; goto LABEL_11; } v6 = GetDlgItem(hWnd, 1054); if (local_GetBottomRect(hWnd, v6, (unsigned short)lParam, (unsigned int)lParam >> 16)) { v4 = 2; LABEL_11: EntName_SetCharName(hWnd, v4); } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x1000709E void __fastcall EntName_DelEntNameMsgs(HWND hWnd) { HWND v2; // eax Focus_DeleteSpinners(); Doom_DeleteFreeProcs(hWnd, entname_msgtbl3); Doom_DeleteFreeProcs(hWnd, entname_msgtbl2); Doom_DeleteFreeProcs(hWnd, entname_msgtbl1); v2 = GetParent(hWnd); SelHero_SetStringWithMsg(v2, 0); } // ref: 0x100070DB void __fastcall EntName_LoadFocusChkName(HWND hWnd) { HWND v2; // edi LONG v3; // eax HWND v4; // ebx char Buffer[32]; // [esp+Ch] [ebp-20h] v2 = GetParent(hWnd); if (SelHero_GetHeroIsGood() == 1) LoadStringA(ghUiInst, 0x20u, Buffer, 31); else LoadStringA(ghUiInst, 0x1Fu, Buffer, 31); SelHero_SetStringWithMsg(v2, Buffer); v3 = GetWindowLongA(v2, -21); SetWindowLongA(hWnd, -21, v3); Doom_ParseWndProc3(hWnd, entname_msgtbl1, AF_BIGGRAY); Doom_ParseWndProcs(hWnd, entname_msgtbl2, AF_BIG, 0); Doom_ParseWndProc5(hWnd, entname_msgtbl3, AF_MED); Focus_LoadSpinner("ui_art\\focus.pcx"); SDlgSetTimer((int)hWnd, 1, 55, 0); v4 = GetDlgItem(hWnd, 1065); SendMessageA(v4, 0x401u, 0xFu, 0); if (SelHero_GetHeroIsGood() == 1) SendMessageA(v4, 0x404u, 0, (LPARAM) " ,<>%&\\\"?*#/"); } // ref: 0x100071AC void __fastcall EntName_SetCharName(HWND hWnd, int a2) { char *v4; // ST08_4 HWND v5; // eax TitleSnd_PlaySelectSound(); SDlgKillTimer((int)hWnd, 1); v4 = entname_charname; v5 = GetDlgItem(hWnd, 1065); GetWindowTextA(v5, v4, 16); entname_charname[15] = 0; SDlgEndDialog(hWnd, (HANDLE)a2); } // ref: 0x100071ED void __fastcall EntName_GetMessageName(HWND hWnd, unsigned int a2, int a3) { unsigned int v3; // edx HWND v5; // eax v3 = (a2 >> 16) - 1; if (v3) { if (v3 == 2) Doom_ParseWndProc6(hWnd, entname_msgtbl3, AF_MED); } else { v5 = GetFocus(); Focus_DoBlitSpinIncFrame(hWnd, v5); } } // ref: 0x10007220 void __cdecl EntName_cpp_init() { EntName_cpp_float = EntName_cpp_float_value; } // 1001F424: using guessed type int EntName_cpp_float_value; // 10029860: using guessed type int EntName_cpp_float; ================================================ FILE: DiabloUI/fade.cpp ================================================ // ref: 0x1000722B void __fastcall Fade_ApplyPaletteRange(int range1, int range2) { tagPALETTEENTRY *v4; // eax MAPDST BYTE *v6; // esi BYTE v7; // al v4 = local_GetArtPalEntry(0); if (range1 == range2) { memcpy(fadepal, v4, 0x400u); } else if (range2) { v6 = &fadepal[0].peGreen; do { v7 = range2 * v4->peRed / range1; ++v4; *(v6 - 1) = v7; *v6 = range2 * v4[-1].peGreen / range1; v6 += 4; *(v6 - 3) = range2 * v4[-1].peBlue / range1; } while ((signed int)v6 < (signed int)&fadepal[256].peGreen); } else { memcpy(fadepal, v4, 0x400u); local_ClearPalette(fadepal); } SDrawUpdatePalette(0, 0x100u, fadepal, 1); } // ref: 0x100072BE void __fastcall Fade_UpdatePaletteRange(int range) { tagPALETTEENTRY *v2; // eax tagPALETTEENTRY *v3; // edi BYTE *v4; // ecx BYTE v5; // al HPALETTE v6; // ebx int v7; // [esp+10h] [ebp-4h] v2 = local_GetArtPalEntry(0); memcpy(fadepal, v2, 0x400u); if (range > 0) { v7 = range; do { v3 = local_GetArtPalEntry(0); v4 = &fadepal[0].peGreen; do { v5 = v3->peRed / range; ++v3; *(v4 - 1) -= v5; *v4 -= v3[-1].peGreen / range; v4 += 4; *(v4 - 3) -= v3[-1].peBlue / range; } while ((signed int)v4 < (signed int)&fadepal[256].peGreen); SDrawUpdatePalette(0, 0x100u, fadepal, 1); --v7; } while (v7); } local_ClearPalette(fadepal); SDrawUpdatePalette(0, 0x100u, fadepal, 1); local_SetCursorDefault(); SDrawClearSurface(0); v6 = (HPALETTE)GetStockObject(15); GetPaletteEntries(v6, 0, 0xAu, fadepal); GetPaletteEntries(v6, 0xAu, 0xAu, &fadepal[246]); SDrawUpdatePalette(0, 0x100u, fadepal, 1); } // 1001043C: using guessed type int __stdcall SDrawClearSurface(DWORD); // ref: 0x1000739F BOOL __cdecl Fade_CheckRange5() { BOOL result; // eax result = 0; if (sgbIsFading) { if (sgbFadeRange <= 5) result = 1; } return result; } // 10029C70: using guessed type int sgbIsFading; // ref: 0x100073B4 void __cdecl Fade_Range5SetZero() { if (Fade_CheckRange5()) sgbIsFading = 0; } // 10029C70: using guessed type int sgbIsFading; // ref: 0x100073C5 void __fastcall Fade_NoInputAndArt(HWND hWnd, BOOL bShowCurs) { HWND v3; // eax v3 = GetParent(hWnd); local_DisableKeyWaitMouse(v3); if (bShowCurs) local_SetCursorArt(); sgbIsFading = 0; sgbFadeRange = 0; } // 10029C70: using guessed type int sgbIsFading; // ref: 0x100073EF void __fastcall Fade_SetInputWindow(HWND hWnd) { HWND v1; // eax v1 = GetParent(hWnd); local_DisableKeyWaitMouse(v1); } // ref: 0x100073FD void __fastcall Fade_SetFadeTimer(int nTime) { if (!sgbIsFading) { SDlgSetTimer(nTime, 16, 50, Fade_TimerFunctionDlg); sgbIsFading = 1; } } // 10029C70: using guessed type int sgbIsFading; // ref: 0x10007420 void __stdcall Fade_TimerFunctionDlg(int a1, int a2, int a3, int a4) { if (sgbFadeRange > 5) { SDlgKillTimer(a1, 16); } else { Fade_ApplyPaletteRange(5, sgbFadeRange); ++sgbFadeRange; } } // ref: 0x1000744D void __cdecl Fade_cpp_init() { fade_cpp_float = fade_cpp_float_value; } // 1001F428: using guessed type int fade_cpp_float_value; // 10029868: using guessed type int fade_cpp_float; ================================================ FILE: DiabloUI/focus.cpp ================================================ // ref: 0x10007458 void __fastcall Focus_CheckPlayMove(LPARAM lParam) { if (sgbSpinnersLoaded && lParam != dword_10029CA8) { if (dword_10029CAC) TitleSnd_PlayMoveSound(); dword_10029CA8 = lParam; } } // 10029CA4: using guessed type int sgbSpinnersLoaded; // 10029CA8: using guessed type int dword_10029CA8; // 10029CAC: using guessed type int dword_10029CAC; // ref: 0x10007482 int __cdecl Focus_GetSpinWidthOrZero() { return sgbSpinnersLoaded != 0 ? focus_spin_width : 0; } // 10029CA4: using guessed type int sgbSpinnersLoaded; // ref: 0x10007492 void __fastcall Focus_BlitSpinner(HWND hWnd1, HWND hWnd2) { DWORD *v2; // edi LONG v3; // eax MAPDST int v5; // eax MAPDST int v7; // eax struct tagRECT Rect; // [esp+8h] [ebp-18h] char *v9; // [esp+18h] [ebp-8h] v9 = (char *)hWnd1; v2 = (DWORD *)GetWindowLongA(hWnd1, -21); v3 = GetWindowLongA(hWnd2, -21); if (v2 && v3 && *v2) { if (*(DWORD *)v3) { GetWindowRect(hWnd2, &Rect); ScreenToClient((HWND)v9, (LPPOINT)&Rect); ScreenToClient((HWND)v9, (LPPOINT)&Rect.right); SBltROP3( *(void **)v3, (void *)(Rect.left + *v2 + Rect.top * v2[1]), focus_spin_width, *(DWORD *)(v3 + 8), *(DWORD *)(v3 + 4), v2[1], 0, 0xCC0020u); v5 = v2[1]; v7 = *v2 + Rect.top * v5; v9 = *(char **)(v3 + 4); SBltROP3( &v9[*(DWORD *)v3 - focus_spin_width], &v9[v7 - focus_spin_width + Rect.left], focus_spin_width, *(DWORD *)(v3 + 8), (int)v9, v5, 0, 0xCC0020u); Focus_CenterSpinFromSide(hWnd2); } } } // ref: 0x10007566 void __fastcall Focus_CenterSpinFromSide(HWND hWnd) { struct tagRECT Rect; // [esp+8h] [ebp-10h] GetClientRect(hWnd, &Rect); --Rect.bottom; Rect.left = --Rect.right - focus_spin_width; InvalidateRect(hWnd, &Rect, 0); Rect.left = 0; Rect.right = focus_spin_width - 1; InvalidateRect(hWnd, &Rect, 0); } // ref: 0x100075B7 void __fastcall Focus_GetAndBlitSpin(HWND hWnd, LPARAM lParam) { HWND v2; // esi v2 = (HWND)lParam; GetWindowLongA((HWND)lParam, -12); Focus_BlitSpinner(hWnd, v2); dword_10029CAC = 1; } // 10029CAC: using guessed type int dword_10029CAC; // ref: 0x100075DC BOOL __fastcall Focus_DoBlitSpinIncFrame(HWND hWnd1, HWND hWnd2) { void **v4; // eax void **v5; // esi int v7; // edi struct tagRECT Rect; // [esp+Ch] [ebp-14h] if (!sgbSpinnersLoaded) return 0; if (!hWnd2) return 0; GetWindowLongA(hWnd2, -12); if (hWnd1 != GetParent(hWnd2)) return 0; Focus_BlitSpinner(hWnd1, hWnd2); v4 = (void **)GetWindowLongA(hWnd2, -21); v5 = v4; if (!v4 || !*v4) return 0; GetWindowRect(hWnd2, &Rect); ScreenToClient(hWnd1, (LPPOINT)&Rect); ScreenToClient(hWnd1, (LPPOINT)&Rect.right); if (SpinnerTransOut[sgnSpinnerFrame]) { v7 = ((signed int)v5[2] - focus_spin_height) / 2; STransBlt(*v5, 0, v7, (int)v5[1], SpinnerTransOut[sgnSpinnerFrame]); STransBlt(*v5, (int)v5[1] - focus_spin_width, v7, (int)v5[1], SpinnerTransOut[sgnSpinnerFrame]); Focus_CenterSpinFromSide(hWnd2); } if (++sgnSpinnerFrame >= 8) sgnSpinnerFrame = 0; return 1; } // 10029C9C: using guessed type int focus_spin_height; // 10029CA4: using guessed type int sgbSpinnersLoaded; // 10029CB0: using guessed type int sgnSpinnerFrame; // ref: 0x100076C3 void __cdecl Focus_DeleteSpinners() { HANDLE *v0; // esi v0 = SpinnerTransOut; do { if (*v0) { STransDelete(*v0); *v0 = 0; } ++v0; } while ((signed int)v0 < (signed int)&SpinnerTransOut[8]); dword_10029CAC = 0; dword_10029CA8 = 0; sgbSpinnersLoaded = 0; } // 10029CA4: using guessed type int sgbSpinnersLoaded; // 10029CA8: using guessed type int dword_10029CA8; // 10029CAC: using guessed type int dword_10029CAC; // ref: 0x100076FA void __cdecl Focus_ResetSpinToZero() { dword_10029CAC = 0; dword_10029CA8 = 0; } // 10029CA8: using guessed type int dword_10029CA8; // 10029CAC: using guessed type int dword_10029CAC; // ref: 0x1000770E void __cdecl Focus_cpp_init() { focus_cpp_float = focus_cpp_float_value; } // 1001F42C: using guessed type int focus_cpp_float_value; // 10029CA0: using guessed type int focus_cpp_float; // ref: 0x10007719 void __fastcall Focus_LoadSpinner(const char *pszFileName) { HANDLE *v1; // esi int v2; // ecx int v3; // eax int v4; // ebx int a5[4]; // [esp+4h] [ebp-1Ch] DWORD data[2]; // [esp+14h] [ebp-Ch] BYTE *pBuffer; // [esp+1Ch] [ebp-4h] if (!sgbSpinnersLoaded) { pBuffer = 0; dword_10029CAC = 0; dword_10029CA8 = 0; local_LoadArtImage(pszFileName, &pBuffer, data); v1 = SpinnerTransOut; memset(SpinnerTransOut, 0, 0x20u); if (pBuffer) { v2 = data[0]; focus_spin_width = data[0]; v3 = (signed int)data[1] / 8; v4 = 0; focus_spin_height = (signed int)data[1] / 8; while (1) { a5[2] = v2 - 1; a5[1] = v4 * v3; a5[0] = 0; a5[3] = v3 + v4 * v3 - 1; STransCreateI(pBuffer, v2, v3, 8, (int)a5, 16777466, v1); ++v1; ++v4; if ((signed int)v1 >= (signed int)&SpinnerTransOut[8]) break; v3 = focus_spin_height; v2 = focus_spin_width; } SMemFree(pBuffer, "C:\\Src\\Diablo\\DiabloUI\\Focus.cpp", 246, 0); } sgnSpinnerFrame = 0; sgbSpinnersLoaded = 1; } } // 10029C9C: using guessed type int focus_spin_height; // 10029CA4: using guessed type int sgbSpinnersLoaded; // 10029CA8: using guessed type int dword_10029CA8; // 10029CAC: using guessed type int dword_10029CAC; // 10029CB0: using guessed type int sgnSpinnerFrame; // ref: 0x100077E9 void __fastcall Focus_SetFocusTimer(HWND hWnd, const char *pszFileName) { Focus_LoadSpinner(pszFileName); SDlgSetTimer((int)hWnd, 1, 55, Focus_SetFocusAndBlit); } // ref: 0x10007804 void __stdcall Focus_SetFocusAndBlit(int hWnd, int a2, int a3, int a4) { HWND v1; // eax v1 = GetFocus(); Focus_DoBlitSpinIncFrame((HWND)hWnd, v1); } // ref: 0x10007818 void __fastcall Focus_KillFocusTimer(HWND hWnd) { SDlgKillTimer((int)hWnd, 1); Focus_DeleteSpinners(); } ================================================ FILE: DiabloUI/local.cpp ================================================ // ref: 0x10007825 void __cdecl local_InitUiPalette() { LOGPALETTE *v0; // eax MAPDST PALETTEENTRY *v2; // eax int v3; // ecx v0 = (LOGPALETTE *)SMemAlloc(0x404u, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 27, 0); if (v0) { v0->palVersion = 768; v0->palNumEntries = 256; v2 = v0->palPalEntry; v3 = 0; do { v2[v3].peFlags = 2; ++v3; } while (v3 < 256); objPalette = CreatePalette(v0); SMemFree(v0, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 41, 0); } } // ref: 0x1000787D void __cdecl local_DelUiPalette() { if (objPalette) { DeleteObject(objPalette); objPalette = 0; } } // ref: 0x10007895 tagPALETTEENTRY *__fastcall local_GetArtPalEntry(int entry) { return &artpal[entry]; } // ref: 0x1000789D void __fastcall local_ClearPalette(PALETTEENTRY *pPal) { BYTE *v1; // eax signed int v2; // ecx v1 = &pPal->peBlue; v2 = 256; do { *(v1 - 2) = 0; *(v1 - 1) = 0; *v1 = 0; v1 += 4; --v2; } while (v2); } // ref: 0x100078B6 void __cdecl local_ClearSurface() { SDrawClearSurface(0); } // 1001043C: using guessed type int __stdcall SDrawClearSurface(DWORD); // ref: 0x100078BE BOOL __fastcall local_LoadArtImage(const char *pszFileName, BYTE **pBuffer, DWORD *pdwSize) { BYTE *v4; // eax DWORD v5; // ecx DWORD dwHeight; // [esp+10h] [ebp-8h] DWORD dwWidth; // [esp+14h] [ebp-4h] *pBuffer = 0; if (!SBmpLoadImage(pszFileName, 0, 0, 0, &dwWidth, &dwHeight, 0)) return 0; v4 = (BYTE *)SMemAlloc(dwHeight * dwWidth, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 93, 0); v5 = dwWidth; *pBuffer = v4; if (!SBmpLoadImage(pszFileName, 0, v4, dwHeight * v5, 0, 0, 0)) { SMemFree(*pBuffer, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 95, 0); *pBuffer = 0; return 0; } if (pdwSize) { *pdwSize = dwWidth; pdwSize[1] = dwHeight; } return 1; } // ref: 0x10007944 BOOL __fastcall local_LoadArtWithPal(HWND hWnd, int a2, char *src, int mask, int flags, const char *pszFileName, BYTE **pBuffer, DWORD *pdwSize, BOOL a9) { BYTE *v10; // eax DWORD v11; // ST18_4 HPALETTE v13; // edi tagPALETTEENTRY pPalEntries[256]; // [esp+Ch] [ebp-40Ch] DWORD pdwWidth; // [esp+410h] [ebp-8h] DWORD dwHeight; // [esp+414h] [ebp-4h] if (!SBmpLoadImage(pszFileName, 0, 0, 0, &pdwWidth, &dwHeight, 0)) return 0; v10 = (BYTE *)SMemAlloc(dwHeight * pdwWidth, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 129, 0); v11 = dwHeight * pdwWidth; *pBuffer = v10; if (!SBmpLoadImage(pszFileName, pPalEntries, v10, v11, 0, 0, 0) || !SDlgSetBitmapI(hWnd, a2, src, mask, flags, *pBuffer, 0, pdwWidth, dwHeight, -1)) { return 0; } if (!src || !*src) { v13 = (HPALETTE)GetStockObject(15); GetPaletteEntries(v13, 0, 0xAu, pPalEntries); GetPaletteEntries(v13, 0xAu, 0xAu, &pPalEntries[246]); memcpy(artpal, pPalEntries, 0x400u); if (a9) { SDrawUpdatePalette(0, 255, artpal, 1); } else { local_ClearPalette(pPalEntries); SDrawUpdatePalette(0, 256, pPalEntries, 1); } } if (pdwSize) { *pdwSize = pdwWidth; pdwSize[1] = dwHeight; } return 1; } // 100103FA: using guessed type int __stdcall SDrawUpdatePalette(DWORD, DWORD, DWORD, DWORD); // ref: 0x10007A68 void __fastcall local_AdjustRectSize(tagRECT *pRect, int a2, int a3) { int v3; // eax int v4; // edx v3 = a2 - pRect->left; pRect->left = a2; pRect->right += v3 - 1; v4 = a3 - pRect->top; pRect->top = a3; pRect->bottom += v4 - 1; } // ref: 0x10007A85 BOOL __fastcall local_SetStaticBmp(HWND hWnd, int nIDDlgItem, BYTE *pBuffer, DWORD *pdwSize) { HWND v4; // edi HWND v5; // ebx struct tagRECT Rect; // [esp+Ch] [ebp-10h] v4 = hWnd; v5 = GetDlgItem(hWnd, nIDDlgItem); GetWindowRect(v5, &Rect); ScreenToClient(v4, (LPPOINT)&Rect); ScreenToClient(v4, (LPPOINT)&Rect.right); SDlgSetBitmapI(v5, 0, "Static", -1, 1, pBuffer, (int)&Rect, *pdwSize, pdwSize[1], -1); return 1; } // ref: 0x10007AEA void __cdecl local_cpp_init() { local_cpp_float = 0x7F800000; } // 10029CB8: using guessed type int local_cpp_float; // ref: 0x10007AF5 BOOL __fastcall local_SetButtonBmp(HWND hWnd, int flags, int a7, void *pBuffer, DWORD *pdwSize) { return SDlgSetBitmapI(hWnd, 0, "Button", -1, flags, pBuffer, a7, *pdwSize, pdwSize[1], -1); } // ref: 0x10007B1B void __fastcall local_FitButtonDlg(HWND hWnd, int *a2, void *pBuffer, DWORD *pdwSize) { int v4; // eax HWND v5; // esi struct tagRECT Rect; // [esp+0h] [ebp-1Ch] int a3; // [esp+14h] [ebp-8h] int *v9; // [esp+18h] [ebp-4h] v4 = *a2; a3 = 0; v9 = a2; if (v4) { do { v5 = GetDlgItem(hWnd, v4); if (v5) { GetClientRect(v5, &Rect); local_AdjustRectSize(&Rect, 0, a3); local_SetButtonBmp(v5, 16, (int)&Rect, pBuffer, pdwSize); ++Rect.bottom; ++Rect.right; local_AdjustRectSize(&Rect, 0, Rect.bottom); local_SetButtonBmp(v5, 64, (int)&Rect, pBuffer, pdwSize); ++Rect.bottom; ++Rect.right; local_AdjustRectSize(&Rect, 0, Rect.bottom); local_SetButtonBmp(v5, 32, (int)&Rect, pBuffer, pdwSize); ++Rect.bottom; ++Rect.right; local_AdjustRectSize(&Rect, 0, Rect.bottom); local_SetButtonBmp(v5, 128, (int)&Rect, pBuffer, pdwSize); ++Rect.bottom; ++Rect.right; local_AdjustRectSize(&Rect, 0, Rect.bottom); local_SetButtonBmp(v5, 1280, (int)&Rect, pBuffer, pdwSize); ++Rect.bottom; ++Rect.right; a3 = Rect.bottom; } ++v9; v4 = *v9; } while (*v9); } } // ref: 0x10007C2E void __fastcall local_SetWhiteText(HDC hdc) { SetTextColor(hdc, 0xFFFFu); } // ref: 0x10007C3B BOOL __fastcall local_GetBottomRect(HWND hWnd1, HWND hWnd2, int width, int height) { BOOL result; // eax struct tagRECT Rect; // [esp+4h] [ebp-10h] if (hWnd1 && hWnd2 && (GetWindowRect(hWnd2, &Rect), ScreenToClient(hWnd1, (LPPOINT)&Rect), ScreenToClient(hWnd1, (LPPOINT)&Rect.right), width >= Rect.left) && width < Rect.right && height >= Rect.top) { result = height < Rect.bottom; } else { result = 0; } return result; } // ref: 0x10007C95 void __fastcall local_DlgDoPaint(HWND hWnd) { char v2[64]; // [esp+4h] [ebp-40h] SDlgBeginPaint(hWnd, v2); SDlgEndPaint(hWnd, v2); } // 10010442: using guessed type int __stdcall SDlgEndPaint(DWORD, DWORD); // 10010448: using guessed type int __stdcall SDlgBeginPaint(DWORD, DWORD); // ref: 0x10007CB5 void __fastcall local_DoUiWndProc(HWND hWnd, DWORD *pdwMsgTbl) { DWORD *v2; // edi int i; // eax HWND v5; // eax HWND v6; // esi void *v7; // eax v2 = pdwMsgTbl; for (i = *pdwMsgTbl; *v2; i = *v2) { v5 = GetDlgItem(hWnd, i); v6 = v5; if (v5) { v7 = (void *)GetWindowLongA(v5, -4); SetPropA(v6, "UIWNDPROC", v7); SetWindowLongA(v6, -4, (LONG)local_PostUiWndProc); } ++v2; } } // ref: 0x10007D01 LRESULT __stdcall local_PostUiWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { WNDPROC v4; HWND v5; // eax HWND v6; // eax HWND v7; // eax WPARAM v9; // [esp-8h] [ebp-14h] BOOL v10; // [esp-4h] [ebp-10h] v4 = (WNDPROC)GetPropA(hWnd, "UIWNDPROC"); switch (uMsg) { case 2u: RemovePropA(hWnd, "UIWNDPROC"); if (!v4) return DefWindowProcA(hWnd, uMsg, wParam, lParam); SetWindowLongA(hWnd, -4, (LONG)v4); goto LABEL_21; case 0xFu: local_DlgDoPaint(hWnd); return 0; case 0x87u: return 4; } if (uMsg != 256) goto LABEL_21; switch (wParam) { case 0xDu: goto LABEL_26; case 0x1Bu: v9 = 2; LABEL_15: v7 = GetParent(hWnd); SendMessageA(v7, 0x111u, v9, 0); goto LABEL_21; case 0x20u: LABEL_26: v9 = 1; goto LABEL_15; } if (wParam <= 0x24) goto LABEL_21; if (wParam <= 0x26) { v10 = 1; } else { if (wParam > 0x28) goto LABEL_21; v10 = 0; } v5 = GetParent(hWnd); v6 = GetNextDlgGroupItem(v5, hWnd, v10); SetFocus(v6); LABEL_21: if (v4) return CallWindowProcA(v4, hWnd, uMsg, wParam, lParam); return DefWindowProcA(hWnd, uMsg, wParam, lParam); } // ref: 0x10007DE9 void __fastcall local_DoUiWndProc2(HWND hWnd, DWORD *pdwMsgTbl) { DWORD *v2; // edi int i; // eax HWND v5; // eax HWND v6; // esi void *v7; // eax v2 = pdwMsgTbl; for (i = *pdwMsgTbl; *v2; i = *v2) { v5 = GetDlgItem(hWnd, i); v6 = v5; if (v5) { v7 = (void *)GetWindowLongA(v5, -4); SetPropA(v6, "UIWNDPROC", v7); SetWindowLongA(v6, -4, (LONG)local_PostUiWndProc2); } ++v2; } } // ref: 0x10007E35 LRESULT __stdcall local_PostUiWndProc2(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT(__stdcall * v4) (HWND, UINT, WPARAM, LPARAM); // ebx WPARAM v5; // ST0C_4 HWND v6; // eax HWND v8; // [esp+18h] [ebp+Ch] v4 = (LRESULT(__stdcall *)(HWND, UINT, WPARAM, LPARAM))GetPropA(hWnd, "UIWNDPROC"); switch (uMsg) { case 2u: RemovePropA(hWnd, "UIWNDPROC"); if (!v4) return DefWindowProcA(hWnd, uMsg, wParam, lParam); SetWindowLongA(hWnd, -4, (LONG)v4); break; case 0xFu: local_DlgDoPaint(hWnd); return 0; case 0x201u: v8 = GetFocus(); SetFocus(hWnd); InvalidateRect(v8, 0, 0); InvalidateRect(hWnd, 0, 0); UpdateWindow(v8); UpdateWindow(hWnd); v5 = (unsigned short)GetWindowLongA(hWnd, -12); v6 = GetParent(hWnd); PostMessageA(v6, 0x111u, v5, (LPARAM)hWnd); return 0; } if (v4) return CallWindowProcA(v4, hWnd, uMsg, wParam, lParam); return DefWindowProcA(hWnd, uMsg, wParam, lParam); } // ref: 0x10007F04 BOOL __fastcall local_DisableKeyWaitMouse(HWND hWnd) { BOOL result; // eax struct tagMSG Msg; // [esp+8h] [ebp-1Ch] do { while (PeekMessageA(&Msg, hWnd, 0x100u, 0x108u, 1u)) ; result = PeekMessageA(&Msg, hWnd, 0x200u, 0x209u, 1u); } while (result); return result; } // ref: 0x10007F46 DWORD *__cdecl local_AllocWndLongData() { DWORD *result; // eax result = (DWORD *)SMemAlloc(0x110u, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 480, 0); if (result) { *result = 0; result[1] = 0; result[2] = 0; result[3] = 0; *((BYTE *)result + 16) = 0; } return result; } // ref: 0x10007F72 void __fastcall local_FreeMemPtr(void **p) { if (p) { if (*p) SMemFree(*p, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 498, 0); SMemFree(p, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 499, 0); } } // ref: 0x10007FA4 void __fastcall local_SetWndLongStr(int WndLongData, const char *pszStr) { if (WndLongData) { if (pszStr) { strncpy((char *)(WndLongData + 16), pszStr, 0xFFu); *(BYTE *)(WndLongData + 271) = 0; } else { *(BYTE *)(WndLongData + 16) = 0; } } } // ref: 0x10007FD0 void __cdecl local_LoadArtCursor() { DWORD dwHeight; // [esp+8h] [ebp-8h] DWORD dwWidth; // [esp+Ch] [ebp-4h] if (SBmpLoadImage("ui_art\\cursor.pcx", 0, 0, 0, &dwWidth, &dwHeight, 0)) { gpCursorArt = (BYTE *)SMemAlloc(dwHeight * dwWidth, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 553, 0); gpCursorArt2 = (BYTE *)SMemAlloc(dwHeight * dwWidth, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 554, 0); if (SBmpLoadImage("ui_art\\cursor.pcx", 0, gpCursorArt, dwHeight * dwWidth, 0, 0, 0)) { gdwCursData[0] = dwWidth; gdwCursData[1] = dwHeight; local_InitArtCursor(); } } } // ref: 0x10008062 void __cdecl local_InitArtCursor() { BYTE *v0; // eax BYTE *v1; // ecx int i; // esi char v3; // dl v0 = gpCursorArt2; v1 = gpCursorArt; if (gpCursorArt2) { if (gpCursorArt) { for (i = 0; i < gdwCursData[0] * gdwCursData[1]; ++i) { v3 = *v1++; if (v3) *v0 = 0; else *v0 = -1; ++v0; } } } } // ref: 0x100080AD void __cdecl local_FreeArtCursor() { if (gpCursorArt) { SMemFree(gpCursorArt, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 571, 0); gpCursorArt = 0; } if (gpCursorArt2) { SMemFree(gpCursorArt2, "C:\\Src\\Diablo\\DiabloUI\\local.cpp", 575, 0); gpCursorArt2 = 0; } } // ref: 0x100080F1 void __cdecl local_SetCursorArt() { if (!gpCursorArt) local_LoadArtCursor(); SDlgSetSystemCursor(gpCursorArt2, gpCursorArt, (int *)gdwCursData, 32512); } // 1001044E: using guessed type int __stdcall SDlgSetSystemCursor(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000811B void __cdecl local_SetCursorDefault() { SDlgSetSystemCursor(0, 0, 0, 32512); } // 1001044E: using guessed type int __stdcall SDlgSetSystemCursor(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000812B void __fastcall local_SetDiabloCursor(HWND hWnd) { HCURSOR v2; // eax int v3; // [esp+4h] [ebp-4h] v3 = 0; local_SetCursorDefault(); v2 = LoadCursorA(ghUiInst, "DIABLOCURSOR"); SDlgSetCursor(hWnd, v2, 32512, &v3); } // 10010454: using guessed type int __stdcall SDlgSetCursor(DWORD, DWORD, DWORD, DWORD); ================================================ FILE: DiabloUI/mainmenu.cpp ================================================ // ref: 0x10008164 void __cdecl MainMenu_cpp_init() { mainmenu_cpp_float = mainmenu_cpp_float_value; } // 1001F434: using guessed type int mainmenu_cpp_float_value; // 1002A0D4: using guessed type int mainmenu_cpp_float; // ref: 0x1000816F BOOL __stdcall UiMainMenuDialog(const char *name, int *pdwResult, void(__stdcall *fnSound)(const char *file), int attractTimeOut) { int v4; // eax int v5; // esi menu_item_timer = attractTimeOut; TitleSnd_SetSoundFunction(fnSound); artfont_LoadAllFonts(); menu_version_str[0] = 0; if (name) strncpy(menu_version_str, name, 0x40u); v4 = (int)SDrawGetFrameWindow(NULL); v5 = SDlgDialogBoxParam(ghUiInst, "MAINMENU_DIALOG", v4, MainMenu_WndProc, 0); if (v5 == 5) artfont_FreeAllFonts(); if (pdwResult) *pdwResult = v5; return 1; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 1002A118: using guessed type int menu_item_timer; // ref: 0x100081E3 LRESULT __stdcall MainMenu_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v5; // eax if (Msg <= 0x113) { if (Msg != 275) { if (Msg == 2) { MainMenu_KillAndFreeMenu(hWnd); } else if (Msg > 0x103) { if (Msg <= 0x105) { v5 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v5, Msg, wParam, lParam); } else { if (Msg == 272) { MainMenu_LoadMenuGFX(hWnd); PostMessageA(hWnd, 0x7E8u, 0, 0); return 1; } if (Msg == 273) { MainMenu_SetMenuTimer(hWnd); switch (HIWORD(wParam)) { case 7: Focus_GetAndBlitSpin(hWnd, lParam); break; case 6: Focus_CheckPlayMove(lParam); Focus_DoBlitSpinIncFrame(hWnd, (HWND)lParam); break; case 0: MainMenu_CheckWParamFocus(hWnd, (unsigned short)wParam); break; } } } } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (wParam == 3 && !DiabloUI_GetSpawned()) { if (app_is_active) MainMenu_DoOptions(hWnd, 6, 0); else MainMenu_SetMenuTimer(hWnd); } return 0; } if (Msg >= 0x200) { if (Msg <= 0x202) goto LABEL_34; if (Msg <= 0x203) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); if (Msg <= 0x205) { LABEL_34: MainMenu_SetMenuTimer(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg == 2024) { if (!Fade_CheckRange5()) Fade_SetFadeTimer((int)hWnd); return 0; } } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 10029728: using guessed type int app_is_active; // ref: 0x10008354 void __fastcall MainMenu_KillAndFreeMenu(HWND hWnd) { void **v2; // eax Title_KillTitleTimer(hWnd); Focus_KillFocusTimer(hWnd); Doom_DeleteFreeProcs(hWnd, menumsgs_5options); Doom_DeleteFreeProcs(hWnd, menumsgs_1option); v2 = (void **)GetWindowLongA(hWnd, -21); local_FreeMemPtr(v2); local_SetCursorDefault(); } // ref: 0x10008391 void __fastcall MainMenu_SetMenuTimer(HWND hWnd) { SDlgSetTimer((int)hWnd, 3, 1000 * menu_item_timer, 0); } // 1002A118: using guessed type int menu_item_timer; // ref: 0x100083A8 void __fastcall MainMenu_LoadMenuGFX(HWND hWnd) { DWORD *v2; // eax MAPDST bool v4; // zf const char *v5; // eax HWND v6; // eax v2 = local_AllocWndLongData(); if (v2) { SetWindowLongA(hWnd, -21, (LONG)v2); v4 = DiabloUI_GetSpawned() == 0; v5 = "ui_art\\swmmenu.pcx"; if (v4) v5 = "ui_art\\mainmenu.pcx"; local_LoadArtWithPal(hWnd, 0, &nullcharacter, -1, 1, v5, (BYTE **)v2, v2 + 1, 0); Fade_NoInputAndArt(hWnd, 1); } v6 = GetDlgItem(hWnd, 1042); SetWindowTextA(v6, menu_version_str); Doom_ParseWndProc3(hWnd, menumsgs_1option, AF_SMALLGRAY); Doom_ParseWndProcs(hWnd, menumsgs_5options, AF_HUGE, 1); Focus_SetFocusTimer(hWnd, "ui_art\\focus42.pcx"); Title_LoadImgSetTimer(hWnd, "ui_art\\smlogo.pcx"); MainMenu_SetMenuTimer(hWnd); local_DoUiWndProc2(hWnd, (DWORD *)menumsgs_5options); } // ref: 0x1000845A void __fastcall MainMenu_DoOptions(HWND hWnd, int option, int PlaySelect) { SDlgKillTimer((int)hWnd, 3); if (DiabloUI_GetSpawned() && option == 3) { SelYesNo_SpawnErrDialog(hWnd, 70, 1); LABEL_7: SDlgSetTimer((int)hWnd, 3, 1000 * menu_item_timer, 0); return; } if (option == 2 && !MainMenu_CheckEnoughMemory()) { SelYesNo_SpawnErrDialog(hWnd, 78, 1); goto LABEL_7; } Fade_Range5SetZero(); if (PlaySelect) TitleSnd_PlaySelectSound(); Fade_UpdatePaletteRange(10); SDlgEndDialog(hWnd, (HANDLE)option); } // 1002A118: using guessed type int menu_item_timer; // ref: 0x100084D5 BOOL __cdecl MainMenu_CheckEnoughMemory() { struct _MEMORYSTATUS Buffer; // [esp+0h] [ebp-20h] Buffer.dwLength = 32; GlobalMemoryStatus(&Buffer); return Buffer.dwTotalPhys > 0xDAC000; } // ref: 0x100084FA void __fastcall MainMenu_CheckWParamFocus(HWND hWnd, WPARAM wParam) { HWND v3; // eax LONG v4; // eax int v5; // [esp-8h] [ebp-Ch] switch (wParam) { case 1u: v3 = GetFocus(); v4 = GetWindowLongA(v3, -12); SendMessageA(hWnd, 0x111u, v4, 0); return; case 2u: v5 = 5; goto LABEL_12; case 0x3E9u: v5 = 2; goto LABEL_12; case 0x3EAu: v5 = 3; goto LABEL_12; case 0x3EBu: v5 = 4; LABEL_12: MainMenu_DoOptions(hWnd, v5, 1); return; case 0x414u: MainMenu_DoOptions(hWnd, 1, 1); break; } } ================================================ FILE: DiabloUI/modem.cpp ================================================ // ref: 0x1000855D int Modem_1000855D() { return 0; } /* { return dword_1002A124; } */ // 1002A124: using guessed type int dword_1002A124; // ref: 0x10008563 HWND __fastcall Modem_10008563(HWND hDlg, const char *a2, int a3) { return 0; } /* { HWND v3; // esi const char *v4; // ebp HWND result; // eax v3 = hDlg; v4 = a2; result = GetDlgItem(hDlg, 1108); if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { local_10007FA4((int)result, (const char *)a3); Doom_10006A13(v3, (int *)&unk_10022C5C, 1); result = GetDlgItem(v3, 1080); if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { local_10007FA4((int)result, v4); result = (HWND)Doom_10006A13(v3, (int *)&unk_10022C54, 3); } } } } return result; } */ // ref: 0x100085D8 int __stdcall Modem_100085D8(int a1, char *a2, char *a3) { return 0; } /* { dword_1002A150 = a1; strcpy(&byte_1002A154, a2); strcpy(&byte_1002A1D4, a3); return 1; } */ // 1002A150: using guessed type int dword_1002A150; // ref: 0x10008606 BOOL Modem_10008606() { return 0; } /* { BOOL result; // eax dword_1002A150 = 0; byte_1002A154 = 0; byte_1002A1D4 = 0; if ( SNetEnumGames(0, 0, Modem_100085D8, 0) ) result = dword_1002A150 != 0; else result = 0; return result; } */ // 10010436: using guessed type int __stdcall SNetEnumGames(DWORD, DWORD, DWORD, DWORD); // 1002A150: using guessed type int dword_1002A150; // ref: 0x1000863D char *Modem_1000863D() { return 0; } /* { return &byte_1002A154; } */ // ref: 0x10008648 signed int Modem_10008648() { return 0; } /* { signed int result; // eax result = 2139095040; dword_1002A128 = 2139095040; return result; } */ // 1002A128: using guessed type int dword_1002A128; // ref: 0x10008653 int Modem_10008653() { return 0; } /* { return dword_1002A148; } */ // 1002A148: using guessed type int dword_1002A148; // ref: 0x10008659 int Modem_10008659() { return 0; } /* { return dword_1002A134; } */ // 1002A134: using guessed type int dword_1002A134; // ref: 0x1000865F int UNKCALL Modem_1000865F(char *arg) { return 0; } /* { char v1; // al int result; // eax while ( 1 ) { v1 = *arg; if ( !*arg || (unsigned char)v1 >= 0x30u && (unsigned char)v1 <= 0x39u ) break; ++arg; } if ( *arg ) result = atoi(arg); else result = 0; return result; } */ // ref: 0x10008680 BOOL __fastcall Modem_10008680(int a1, int a2, int a3, DWORD *a4, int a5, int playerid) { return 0; } /* { int v6; // esi dword_1002A13C = a3; dword_1002A138 = a2; dword_1002A144 = a5; dword_1002A14C = a4; gnModemPlayerid = playerid; artfont_10001159(); v6 = SDlgDialogBoxParam(hInstance, "MODEM_DIALOG", a4[2], Modem_100086DE, 0); artfont_100010C8(); return v6 == 1; } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // 1002A138: using guessed type int dword_1002A138; // 1002A13C: using guessed type int dword_1002A13C; // 1002A140: using guessed type int gnModemPlayerid; // 1002A144: using guessed type int dword_1002A144; // ref: 0x100086DE int __stdcall Modem_100086DE(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { HWND v4; // eax int v6; // [esp+0h] [ebp-8h] if ( Msg > 0x7E8 ) { switch ( Msg ) { case 0xBD0u: Modem_100088DB(hWnd); return 0; case 0xBD1u: Modem_10008BB7(hWnd); return 0; case 0xBD2u: Modem_10008BFE(hWnd); return 0; } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg == 2024 ) { if ( !Fade_1000739F() ) Fade_100073FD(hWnd, v6); return 0; } if ( Msg == 2 ) { Modem_1000879E(hWnd); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg <= 0x103 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); if ( Msg <= 0x105 ) { v4 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v4, Msg, wParam, lParam); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg != 272 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); Modem_100087DB(hWnd); PostMessageA(hWnd, 0x7E8u, 0, 0); return 0; } */ // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x1000879E void **UNKCALL Modem_1000879E(HWND hDlg) { return 0; } /* { HWND v1; // esi DWORD *v2; // eax v1 = hDlg; Doom_10006C53(hDlg, (int *)&unk_10022C5C); Doom_10006C53(v1, (int *)&unk_10022C54); Doom_10006C53(v1, (int *)&unk_10022C4C); v2 = (DWORD *)GetWindowLongA(v1, -21); local_10007F72(v2); return Title_100100E7(v1); } */ // ref: 0x100087DB BOOL UNKCALL Modem_100087DB(HWND hWnd) { return 0; } /* { HWND v1; // esi int v2; // eax int *v3; // edi HWND v5; // [esp+0h] [ebp-10h] v1 = hWnd; Title_1001009E(hWnd, (int)"ui_art\\smlogo.pcx", v5); v2 = local_10007F46(); v3 = (int *)v2; if ( v2 ) { SetWindowLongA(v1, -21, v2); local_10007944((int)v1, 0, &byte_10029448, -1, 1, (int)"ui_art\\selgame.pcx", v3, v3 + 1, 0); Fade_100073C5(v1, 1); } Doom_100068AB(v1, (int *)&unk_10022C4C, 5); Doom_100068AB(v1, (int *)&unk_10022C54, 3); Doom_100068AB(v1, (int *)&unk_10022C5C, 1); Modem_10008888(); if ( dword_1002A124 ) return PostMessageA(v1, 0xBD2u, 0, 0); dword_1002A134 = 1; dword_1002A130 = 1; return PostMessageA(v1, 0xBD0u, 0, 0); } */ // 1002A124: using guessed type int dword_1002A124; // 1002A130: using guessed type int dword_1002A130; // 1002A134: using guessed type int dword_1002A134; // ref: 0x10008888 int Modem_10008888() { return 0; } /* { int result; // eax dword_1002A150 = 0; byte_1002A154 = 0; byte_1002A1D4 = 0; result = SNetEnumGames(0, 0, Modem_100085D8, 0); if ( result ) { dword_1002A124 = 1; } else { result = SErrGetLastError(); if ( result == 1222 ) { dword_1002A124 = 0; result = 1; dword_1002A134 = 1; dword_1002A130 = 1; } } return result; } */ // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // 10010436: using guessed type int __stdcall SNetEnumGames(DWORD, DWORD, DWORD, DWORD); // 1002A124: using guessed type int dword_1002A124; // 1002A130: using guessed type int dword_1002A130; // 1002A134: using guessed type int dword_1002A134; // 1002A150: using guessed type int dword_1002A150; // ref: 0x100088DB int UNKCALL Modem_100088DB(HWND hWnd) { return 0; } /* { HWND v1; // esi int v2; // eax int v3; // eax int v5; // [esp+4h] [ebp-20h] v1 = hWnd; v2 = SDlgDialogBoxParam(hInstance, "SELDIAL_DIALOG", hWnd, SelDial_1000B0CF, &v5) - 3; if ( !v2 ) return Modem_1000893D(v1); v3 = v2 - 1; if ( !v3 ) return Modem_10008A38(v1, (int)&v5); if ( v3 == 1 ) return PostMessageA(v1, 0xBD1u, 0, 0); return SelHero_1000C3E2((int)v1, 2); } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // ref: 0x1000893D int UNKCALL Modem_1000893D(HWND hWnd) { return 0; } /* { HWND v1; // esi int v2; // eax int result; // eax CHAR v4; // [esp+8h] [ebp-C0h] int v5; // [esp+48h] [ebp-80h] HWND v6; // [esp+50h] [ebp-78h] CHAR Buffer; // [esp+98h] [ebp-30h] int v8; // [esp+B8h] [ebp-10h] int v9; // [esp+BCh] [ebp-Ch] int v10; // [esp+C0h] [ebp-8h] int v11; // [esp+C4h] [ebp-4h] v1 = hWnd; memcpy(&v5, dword_1002A14C, 0x50u); v5 = 80; v6 = v1; memset(&v8, 0, 0x10u); v8 = 16; v9 = 1297040461; v2 = *(DWORD *)(dword_1002A138 + 24); v11 = 0; v10 = v2; LoadStringA(hInstance, 0x47u, &Buffer, 31); wsprintfA(&v4, &Buffer, dword_1002A130); if ( CreaDung_100051D8( (int)&v8, dword_1002A138, dword_1002A13C, (int)&v5, dword_1002A144, gnModemPlayerid, 1, (int)&v4) ) { ++dword_1002A130; result = SelHero_1000C3E2((int)v1, 1); } else if ( dword_1002A124 ) { if ( SErrGetLastError() == 183 ) ++dword_1002A130; result = PostMessageA(v1, 0xBD2u, 0, 0); } else { result = PostMessageA(v1, 0xBD0u, 0, 0); } return result; } */ // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // 1002A124: using guessed type int dword_1002A124; // 1002A130: using guessed type int dword_1002A130; // 1002A138: using guessed type int dword_1002A138; // 1002A13C: using guessed type int dword_1002A13C; // 1002A140: using guessed type int gnModemPlayerid; // 1002A144: using guessed type int dword_1002A144; // ref: 0x10008A38 int __fastcall Modem_10008A38(HWND hWnd, int a2) { return 0; } /* { char *v2; // ebx HWND v3; // edi int v4; // eax int result; // eax CHAR Buffer; // [esp+Ch] [ebp-80h] v2 = (char *)a2; v3 = hWnd; dword_1002A148 = 0; _beginthread((int)Modem_10008B42, 0, a2); ModmStat_10008C87(v3); if ( !dword_1002A120 ) { switch ( dword_1002A12C ) { case -2062548871: LoadStringA(hInstance, 0x32u, &Buffer, 127); break; case 54: LoadStringA(hInstance, 0x42u, &Buffer, 127); break; case 1204: LoadStringA(hInstance, 0x4Cu, &Buffer, 127); break; case 1222: LoadStringA(hInstance, 0x41u, &Buffer, 127); break; case 1223: goto LABEL_18; case 2250: LoadStringA(hInstance, 0x40u, &Buffer, 127); break; default: LoadStringA(hInstance, 0x33u, &Buffer, 127); break; } SelYesNo_1000FD39((int)v3, &Buffer, 0, 1); LABEL_18: if ( dword_1002A124 ) result = PostMessageA(v3, 0xBD2u, 0, 0); else result = PostMessageA(v3, 0xBD0u, 0, 0); return result; } if ( !dword_1002A124 ) { SelDial_1000B011(v2); Modem_10008606(); } v4 = Modem_1000865F(&byte_1002A154); dword_1002A134 = v4; dword_1002A130 = v4 + 1; return SelHero_1000C3E2((int)v3, 1); } */ // 1002A120: using guessed type int dword_1002A120; // 1002A124: using guessed type int dword_1002A124; // 1002A12C: using guessed type int dword_1002A12C; // 1002A130: using guessed type int dword_1002A130; // 1002A134: using guessed type int dword_1002A134; // 1002A148: using guessed type int dword_1002A148; // ref: 0x10008B42 void __cdecl Modem_10008B42(char *a1) { return; } /* { char *v1; // eax char v2; // [esp+0h] [ebp-100h] char v3; // [esp+80h] [ebp-80h] Connect_10004028((int)&v2, 128, (int)&v3, 128); dword_1002A148 = 0; v1 = &byte_1002A154; if ( !dword_1002A124 ) v1 = a1; dword_1002A120 = SNetJoinGame(0, v1, 0, &v2, &v3, gnModemPlayerid); if ( !dword_1002A120 ) dword_1002A12C = SErrGetLastError(); dword_1002A148 = 1; _endthread(); } */ // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // 10010430: using guessed type int __stdcall SNetJoinGame(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // 10011E20: using guessed type int _endthread(void); // 1002A120: using guessed type int dword_1002A120; // 1002A124: using guessed type int dword_1002A124; // 1002A12C: using guessed type int dword_1002A12C; // 1002A140: using guessed type int gnModemPlayerid; // 1002A148: using guessed type int dword_1002A148; // ref: 0x10008BB7 int UNKCALL Modem_10008BB7(HWND hWnd) { return 0; } /* { HWND v1; // esi int result; // eax int v3; // [esp+4h] [ebp-20h] v1 = hWnd; if ( SDlgDialogBoxParam(hInstance, "ENTERDIAL_DIALOG", hWnd, EntDial_10006C96, &v3) == 1 ) result = Modem_10008A38(v1, (int)&v3); else result = PostMessageA(v1, 0xBD0u, 0, 0); return result; } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // ref: 0x10008BFE int UNKCALL Modem_10008BFE(HWND hWnd) { return 0; } /* { HWND v1; // esi int v2; // eax int v3; // eax v1 = hWnd; v2 = SDlgDialogBoxParam(hInstance, "SELCRE8JOIN_DIALOG", hWnd, SelDial_1000B0CF, 0) - 3; if ( !v2 ) return Modem_1000893D(v1); v3 = v2 - 2; if ( !v3 ) return Modem_10008A38(v1, (int)&byte_1002A154); if ( v3 != 1217 ) return SelHero_1000C3E2((int)v1, 2); dword_1002A124 = 0; return PostMessageA(v1, 0xBD0u, 0, 0); } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // 1002A124: using guessed type int dword_1002A124; ================================================ FILE: DiabloUI/modmstat.cpp ================================================ // ref: 0x10008C62 int __stdcall ModmStat_10008C62(char *a1, int a2, int a3, int a4, int a5) { return 0; } /* { int result; // eax strcpy(&byte_1002A264, a1); result = 1; dword_1002A258 = 1; dword_1002A260 = (int (*)(void))a5; return result; } */ // 1002A258: using guessed type int dword_1002A258; // 1002A260: using guessed type int (*dword_1002A260)(void); // ref: 0x10008C87 int UNKCALL ModmStat_10008C87(void *arg) { return 0; } /* { return SDlgDialogBoxParam(hInstance, "MODMSTAT_DIALOG", arg, ModmStat_10008CA0, 0); } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // ref: 0x10008CA0 int __stdcall ModmStat_10008CA0(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { HWND v4; // eax HWND v6; // eax if ( Msg == 2 ) { ModmStat_10008DB3(hWnd); } else if ( Msg > 0x103 ) { if ( Msg <= 0x105 ) { v6 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v6, Msg, wParam, lParam); } else { switch ( Msg ) { case 0x110u: ModmStat_10008DE4(hWnd); return 0; case 0x111u: if ( HIWORD(wParam) == 7 ) { Focus_100075B7(hWnd, (HWND)lParam); } else if ( HIWORD(wParam) == 6 ) { Focus_10007458((void *)lParam); Focus_100075DC(hWnd, (HWND)lParam); } else if ( (WORD)wParam == 1 || (WORD)wParam == 2 ) { ModmStat_10008E89((int)hWnd, 1); } break; case 0x113u: if ( dword_1002A258 ) ModmStat_10008EBF(hWnd); if ( Modem_10008653() ) { dword_1002A25C = 1; ModmStat_10008E89((int)hWnd, 0); } v4 = GetFocus(); Focus_100075DC(hWnd, v4); return 0; } } } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } */ // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 1002A258: using guessed type int dword_1002A258; // 1002A25C: using guessed type int dword_1002A25C; // ref: 0x10008DB3 int UNKCALL ModmStat_10008DB3(HWND hDlg) { return 0; } /* { HWND v1; // esi DWORD *v2; // eax v1 = hDlg; v2 = (DWORD *)GetWindowLongA(hDlg, -21); local_10007F72(v2); Focus_100076C3(); Doom_10006C53(v1, (int *)&unk_10022CB4); return Doom_10006C53(v1, (int *)&unk_10022CAC); } */ // ref: 0x10008DE4 BOOL UNKCALL ModmStat_10008DE4(HWND hWnd) { return 0; } /* { HWND v1; // esi int v2; // eax int *v3; // edi HWND v4; // eax BOOL result; // eax v1 = hWnd; v2 = local_10007F46(); v3 = (int *)v2; if ( v2 ) { SetWindowLongA(v1, -21, v2); local_10007944((int)v1, 0, "Popup", -1, 1, (int)"ui_art\\black.pcx", v3, v3 + 1, 1); } Doom_100068AB(v1, (int *)&unk_10022CAC, 3); Doom_1000658C(v1, (int *)&unk_10022CB4, 4, 1); Focus_10007719("ui_art\\focus.pcx"); SDlgSetTimer(v1, 1, 55, 0); local_10007DE9(v1, (int *)&unk_10022CB4); byte_1002A264 = 0; dword_1002A258 = 0; dword_1002A260 = 0; v4 = GetDlgItem(v1, 2); result = ShowWindow(v4, 0); dword_1002A25C = 0; return result; } */ // 10010412: using guessed type int __stdcall SDlgSetTimer(DWORD, DWORD, DWORD, DWORD); // 1002A258: using guessed type int dword_1002A258; // 1002A25C: using guessed type int dword_1002A25C; // 1002A260: using guessed type int (*dword_1002A260)(void); // ref: 0x10008E89 int __fastcall ModmStat_10008E89(int a1, int a2) { return 0; } /* { int v2; // edi int v3; // esi int result; // eax v2 = a2; v3 = a1; if ( dword_1002A25C ) { TitleSnd_1001031F(); SDlgKillTimer(v3, 1); if ( v2 ) { if ( dword_1002A260 ) dword_1002A260(); } result = SDlgEndDialog(v3, 0); } return result; } */ // 1002A260: invalid function type has been ignored // 10010376: using guessed type int __stdcall SDlgEndDialog(DWORD, DWORD); // 10010418: using guessed type int __stdcall SDlgKillTimer(DWORD, DWORD); // 1002A25C: using guessed type int dword_1002A25C; // 1002A260: using guessed type int (*dword_1002A260)(void); // ref: 0x10008EBF void UNKCALL ModmStat_10008EBF(HWND hDlg) { return; } /* { HWND v1; // edi HWND v2; // eax int v3; // eax HWND v4; // eax dword_1002A258 = 0; v1 = hDlg; if ( dword_1002A260 ) { v2 = GetDlgItem(hDlg, 1026); if ( v2 ) { v3 = GetWindowLongA(v2, -21); local_10007FA4(v3, &byte_1002A264); Doom_10006A13(v1, (int *)&unk_10022CAC, 3); v4 = GetDlgItem(v1, 2); ShowWindow(v4, 1); dword_1002A25C = 1; } } } */ // 1002A258: using guessed type int dword_1002A258; // 1002A25C: using guessed type int dword_1002A25C; // 1002A260: using guessed type int (*dword_1002A260)(void); // ref: 0x10008F26 signed int ModmStat_10008F26() { return 0; } /* { signed int result; // eax result = 2139095040; dword_1002A254 = 2139095040; return result; } */ // 1002A254: using guessed type int dword_1002A254; ================================================ FILE: DiabloUI/okcancel.cpp ================================================ // ref: 0x10008F31 BOOL __fastcall OkCancel_DrawString(HWND hWnd, char *str) { HDC v3; // edi void *v4; // eax int v5; // eax BOOL result; // eax LONG v7; // [esp+14h] [ebp-20h] LONG v8; // [esp+18h] [ebp-1Ch] struct tagRECT Rect; // [esp+1Ch] [ebp-18h] HGDIOBJ h; // [esp+2Ch] [ebp-8h] if (!str || !*str) goto LABEL_13; if (!hWnd) goto LABEL_14; GetClientRect(hWnd, &Rect); --Rect.right; --Rect.bottom; v7 = Rect.right; v8 = Rect.bottom; v3 = GetDC(hWnd); v4 = (void *)SendMessageA(hWnd, 0x31u, 0, 0); h = SelectObject(v3, v4); if (!v3) goto LABEL_13; v5 = strlen(str); DrawTextA(v3, str, v5, &Rect, 0x410u); if (h) SelectObject(v3, h); ReleaseDC(hWnd, v3); if (Rect.bottom > v8 || Rect.right > v7) LABEL_14: result = 1; else LABEL_13: result = 0; return result; } // ref: 0x10008FEC void __cdecl OkCancel_cpp_init() { OkCancel_cpp_float = OkCancel_cpp_float_value; } // 1001F440: using guessed type int OkCancel_cpp_float_value; // 1002A2E4: using guessed type int OkCancel_cpp_float; // ref: 0x10008FF7 LRESULT __stdcall OkCancel_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v5; // ecx int v6; // edx HWND v7; // eax LONG v8; // eax HWND v9; // eax if (Msg == 2) { ShowCursor(FALSE); OkCancel_FreeDlgBmp(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg <= 0x103) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); if (Msg <= 0x105) { v9 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v9, Msg, wParam, lParam); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg != 272) { if (Msg != 273) { if (Msg == 312 && GetWindowLongA((HWND)lParam, -12) == 1038) { local_SetWhiteText((HDC)wParam); return (LRESULT)GetStockObject(5); } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if ((unsigned short)wParam == 1) { v7 = GetFocus(); v8 = GetWindowLongA(v7, -12); v5 = hWnd; if (v8 == 1109) { v6 = 1; goto LABEL_16; } } else { if ((unsigned short)wParam != 2) { if ((unsigned short)wParam == 1109) { v5 = hWnd; v6 = 1; LABEL_16: OkCancel_PlaySndEndDlg(v5, v6); } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } v5 = hWnd; } v6 = 2; goto LABEL_16; } ShowCursor(TRUE); if (!OkCancel_LoadOkCancGFX(hWnd, (DWORD *)lParam)) SDlgEndDialog(hWnd, (HANDLE)0xFF000000); return 1; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x10009117 void __fastcall OkCancel_FreeDlgBmp(HWND hWnd) { void **v1; // eax MAPDST void *v3; // eax void *v4; // eax v1 = (void **)RemovePropA(hWnd, "DLGBMP"); if (v1) { v3 = *v1; if (v3) SMemFree(v3, "C:\\Src\\Diablo\\DiabloUI\\OkCancel.cpp", 48, 0); v4 = v1[1]; if (v4) SMemFree(v4, "C:\\Src\\Diablo\\DiabloUI\\OkCancel.cpp", 50, 0); SMemFree(v1, "C:\\Src\\Diablo\\DiabloUI\\OkCancel.cpp", 51, 0); } } // ref: 0x10009161 BOOL __fastcall OkCancel_LoadOkCancGFX(HWND hWnd, DWORD *lParam) { bool v3; // zf HWND v4; // edi tagPALETTEENTRY *v5; // edi HWND v6; // eax HWND v7; // edi BYTE **v8; // edi HWND v9; // eax const CHAR *v10; // ST1C_4 HWND v11; // eax HWND v12; // edi int a2a; // [esp+Ch] [ebp-20h] int v15; // [esp+10h] [ebp-1Ch] int v16; // [esp+14h] [ebp-18h] DWORD data[2]; // [esp+18h] [ebp-14h] BYTE **pBuffer; // [esp+20h] [ebp-Ch] char *pszFileName; // [esp+24h] [ebp-8h] a2a = 1109; v15 = 2; v16 = 0; pBuffer = (BYTE **)SMemAlloc(8u, "C:\\Src\\Diablo\\DiabloUI\\OkCancel.cpp", 110, 0); SetPropA(hWnd, "DLGBMP", pBuffer); if (lParam[2]) { v3 = lParam[3] == 0; pszFileName = "ui_art\\lrpopup.pcx"; if (v3) pszFileName = "ui_art\\lpopup.pcx"; } else if (lParam[3]) { pszFileName = "ui_art\\srpopup.pcx"; } else { pszFileName = "ui_art\\spopup.pcx"; } v4 = GetParent(hWnd); if ((HWND)SDrawGetFrameWindow(NULL) == v4) { local_LoadArtWithPal(hWnd, 0, &nullcharacter, -1, 1, pszFileName, pBuffer, 0, 1); v5 = local_GetArtPalEntry(0); SDrawUpdatePalette(0, 0xAu, v5, 0); SDrawUpdatePalette(0x70u, 0x90u, v5 + 112, 1); } else { v6 = GetParent(hWnd); local_LoadArtWithPal(hWnd, (int)v6, "Popup", -1, 1, pszFileName, pBuffer, 0, 1); } v7 = GetParent(hWnd); if ((HWND)SDrawGetFrameWindow(NULL) == v7) Fade_SetInputWindow(hWnd); v8 = pBuffer + 1; local_LoadArtImage("ui_art\\but_sml.pcx", pBuffer + 1, data); local_FitButtonDlg(hWnd, &a2a, *v8, data); v9 = GetDlgItem(hWnd, 1026); v10 = (const CHAR *)lParam[1]; pBuffer = (BYTE **)v9; SetWindowTextA(v9, v10); if (lParam[4] && OkCancel_DrawString((HWND)pBuffer, (char *)lParam[1])) return 0; if (*lParam) { v11 = GetDlgItem(hWnd, 1038); v12 = v11; if (lParam[4] && OkCancel_DrawString(v11, (char *)*lParam)) return 0; if (v12) SetWindowTextA(v12, (LPCSTR)*lParam); } return 1; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x100092F5 void __fastcall OkCancel_PlaySndEndDlg(HWND hWnd, int a2) { TitleSnd_PlaySelectSound(); SDlgEndDialog(hWnd, (HANDLE)a2); } // ref: 0x1000930A void __fastcall OkCancel_DoOkDialog(HWND hWnd, char *str, int a3) { int a5[5]; // [esp+0h] [ebp-14h] a5[1] = (int)str; a5[2] = 0; a5[0] = 0; a5[4] = 0; a5[3] = a3; SDlgDialogBoxParam(ghUiInst, "OK_DIALOG", (int)hWnd, OkCancel_WndProc, (int)a5); } // ref: 0x10009342 void __stdcall UiMessageBoxCallback(HWND hWnd, char *lpText, LPCSTR lpCaption, UINT uType) { int v4; // eax unsigned char v5; // sf size_t v7; // eax char *v8; // eax int v9; // ecx int a5[5]; // [esp+0h] [ebp-24h] int v11; // [esp+14h] [ebp-10h] void *location; // [esp+18h] [ebp-Ch] char *szDialog; // [esp+1Ch] [ebp-8h] char *v14; // [esp+20h] [ebp-4h] a5[0] = (int)lpCaption; a5[1] = (int)lpText; szDialog = "OK_DIALOG"; a5[4] = 1; if (uType & 0xF) szDialog = "OKCANCEL_DIALOG"; a5[3] = (uType & 0xF0) == 16 || (uType & 0xF0) == 48; v4 = 0; a5[2] = 0; while (1) { v14 = (char *)SDlgDialogBoxParam(ghUiInst, &szDialog[32 * v4], (int)hWnd, OkCancel_WndProc, (int)a5); if (v14 != (char *)0xFF000000) break; v4 = a5[2] + 1; v5 = a5[2]++ - 1 < 0; if (!v5) { v7 = strlen(lpText); v8 = (char *)SMemAlloc(v7 + 256, "C:\\Src\\Diablo\\DiabloUI\\OkCancel.cpp", 392, 0); v11 = 0; /* check */ location = v8; v14 = lpText; if (*lpText) { v9 = v11; do { if (*v14 <= 32) v9 = 0; *v8++ = *v14; if (++v9 > 18) { *v8++ = 10; v9 = 0; } ++v14; } while (*v14); } *v8 = 0; a5[1] = (int)location; v14 = (char *)SDlgDialogBoxParam(ghUiInst, szDialog, (int)hWnd, OkCancel_WndProc, (int)a5); SMemFree(location, "C:\\Src\\Diablo\\DiabloUI\\OkCancel.cpp", 416, 0); if (v14 == (char *)0xFF000000) MessageBoxA(hWnd, lpText, lpCaption, uType); return; } } } ================================================ FILE: DiabloUI/progress.cpp ================================================ // ref: 0x10009480 signed int Progress_10009480() { return 0; } /* { signed int result; // eax result = 2139095040; dword_1002A2EC = 2139095040; return result; } */ // 1002A2EC: using guessed type int dword_1002A2EC; // ref: 0x1000948B BOOL __stdcall UiProgressDialog(HWND window, const char *msg, int enable, int(*fnfunc)(), int rate) { return 0; } /* { HWND v5; // eax BOOL result; // eax dword_1002A2E8 = -1; dword_1002A2F8 = 0; dword_1002A2F4 = a4; bEnable = a3; dword_1002A2F0 = a5; v5 = (HWND)SDlgCreateDialogParam(hInstance, "PROGRESS_DIALOG", a1, Progress_100094F4, a2); result = 0; if ( v5 ) { Progress_1000991C(v5); if ( dword_1002A2E8 != 2 && dword_1002A2E8 != -1 ) result = 1; } return result; } */ // 1001045A: using guessed type int __stdcall SDlgCreateDialogParam(DWORD, DWORD, DWORD, DWORD, DWORD); // 1002A2E8: using guessed type int dword_1002A2E8; // 1002A2F0: using guessed type int dword_1002A2F0; // 1002A2F4: using guessed type int (*dword_1002A2F4)(void); // 1002A2F8: using guessed type int dword_1002A2F8; // ref: 0x100094F4 int __stdcall Progress_100094F4(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { HWND v4; // eax void *v5; // eax HWND v7; // eax if ( Msg == 2 ) { ShowCursor(FALSE); Progress_100095EC(); } else if ( Msg > 0x103 ) { if ( Msg <= 0x105 ) { v7 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v7, Msg, wParam, lParam); } else { switch ( Msg ) { case 0x110u: Progress_10009675(hWnd, (const CHAR *)lParam); v5 = (void *)SDrawGetFrameWindow(NULL); local_1000812B(v5); local_1000812B(hWnd); ShowCursor(TRUE); return 1; case 0x111u: if ( (WORD)wParam == 2 ) { SDlgKillTimer(hWnd, 1); v4 = GetParent(hWnd); if ( (HWND)SDrawGetFrameWindow(NULL) == v4 ) Fade_100072BE(10); Progress_100098B0(); } break; case 0x113u: Progress_100098C5(hWnd); break; } } } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } */ // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 10010418: using guessed type int __stdcall SDlgKillTimer(DWORD, DWORD); // ref: 0x100095EC void *Progress_100095EC() { return 0; } /* { int result; // eax if ( dword_1002A318 ) { SMemFree(dword_1002A318, "C:\\Src\\Diablo\\DiabloUI\\Progress.cpp", 88, 0); dword_1002A318 = 0; } if ( dword_1002A31C ) { SMemFree(dword_1002A31C, "C:\\Src\\Diablo\\DiabloUI\\Progress.cpp", 92, 0); dword_1002A31C = 0; } if ( dword_1002A320 ) { SMemFree(dword_1002A320, "C:\\Src\\Diablo\\DiabloUI\\Progress.cpp", 96, 0); dword_1002A320 = 0; } if ( dword_1002A324 ) { SMemFree(dword_1002A324, "C:\\Src\\Diablo\\DiabloUI\\Progress.cpp", 100, 0); dword_1002A324 = 0; } result = dword_1002A328; if ( dword_1002A328 ) { result = SMemFree(dword_1002A328, "C:\\Src\\Diablo\\DiabloUI\\Progress.cpp", 104, 0); dword_1002A328 = 0; } return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // 1002A318: using guessed type int dword_1002A318; // 1002A31C: using guessed type int dword_1002A31C; // 1002A320: using guessed type int dword_1002A320; // 1002A324: using guessed type int dword_1002A324; // 1002A328: using guessed type int dword_1002A328; // ref: 0x10009675 BOOL __fastcall Progress_10009675(HWND hWnd, const CHAR *a2) { return 0; } /* { HWND v2; // ebx HWND v3; // esi char *v4; // esi HWND v5; // eax HWND v6; // esi struct tagRECT Rect; // [esp+Ch] [ebp-28h] char v9; // [esp+1Ch] [ebp-18h] int v10; // [esp+24h] [ebp-10h] int v11; // [esp+28h] [ebp-Ch] LPCSTR lpString; // [esp+2Ch] [ebp-8h] HWND v13; // [esp+30h] [ebp-4h] v2 = hWnd; lpString = a2; v10 = 2; v11 = 0; if ( dword_1002A2F0 ) SDlgSetTimer(hWnd, 1, 0x3E8u / dword_1002A2F0, 0); else SDlgSetTimer(hWnd, 1, 50, 0); local_10007944((int)v2, 0, &byte_10029448, -1, 1, (int)"ui_art\\spopup.pcx", &dword_1002A318, 0, 0); v3 = GetParent(v2); if ( (HWND)SDrawGetFrameWindow(NULL) == v3 ) Fade_100073EF(v2); v4 = local_10007895(0); SDrawUpdatePalette(0, 10, v4, 0); SDrawUpdatePalette(112, 144, v4 + 448, 1); local_100078BE((int)"ui_art\\but_sml.pcx", &dword_1002A31C, &v9); local_10007B1B(v2, &v10, dword_1002A31C, &v9); local_100078BE((int)"ui_art\\prog_bg.pcx", &dword_1002A320, &dword_1002A310); local_100078BE((int)"ui_art\\prog_fil.pcx", &dword_1002A324, &dword_1002A308); v13 = GetDlgItem(v2, 1030); GetClientRect(v13, &Rect); dword_1002A328 = SMemAlloc(Rect.right * Rect.bottom, "C:\\Src\\Diablo\\DiabloUI\\Progress.cpp", 170, 0); dword_1002A300 = Rect.right; dword_1002A304 = Rect.bottom; SDlgSetBitmapI(v13, 0, 0, -1, 1, dword_1002A328, 0, Rect.right, Rect.bottom, -1); Progress_10009805(v2, 0); v5 = GetDlgItem(v2, 1031); SetWindowTextA(v5, lpString); v6 = GetDlgItem(v2, 2); ShowWindow(v6, bEnable != 0); return EnableWindow(v6, bEnable); } */ // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 100103FA: using guessed type int __stdcall SDrawUpdatePalette(DWORD, DWORD, DWORD, DWORD); // 10010400: using guessed type int __stdcall SDlgSetBitmapI(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // 10010412: using guessed type int __stdcall SDlgSetTimer(DWORD, DWORD, DWORD, DWORD); // 1002A2F0: using guessed type int dword_1002A2F0; // 1002A300: using guessed type int dword_1002A300; // 1002A304: using guessed type int dword_1002A304; // 1002A308: using guessed type int dword_1002A308; // 1002A310: using guessed type int dword_1002A310; // 1002A318: using guessed type int dword_1002A318; // 1002A31C: using guessed type int dword_1002A31C; // 1002A320: using guessed type int dword_1002A320; // 1002A324: using guessed type int dword_1002A324; // 1002A328: using guessed type int dword_1002A328; // ref: 0x10009805 BOOL __fastcall Progress_10009805(HWND hWnd, int a2) { return 0; } /* { HWND v2; // edi struct tagRECT Rect; // [esp+8h] [ebp-18h] HWND hWnda; // [esp+18h] [ebp-8h] int v6; // [esp+1Ch] [ebp-4h] v2 = hWnd; v6 = a2; hWnda = GetDlgItem(hWnd, 1030); SBltROP3( dword_1002A328, dword_1002A320, dword_1002A300, dword_1002A304, dword_1002A300, dword_1002A310, 0, 13369376); SBltROP3( dword_1002A328, dword_1002A324, v6 * dword_1002A300 / 100, dword_1002A304, dword_1002A300, dword_1002A308, 0, 13369376); GetWindowRect(hWnda, &Rect); ScreenToClient(v2, (LPPOINT)&Rect); ScreenToClient(v2, (LPPOINT)&Rect.right); return InvalidateRect(v2, &Rect, 0); } */ // 100103F4: using guessed type int __stdcall SBltROP3(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // 1002A300: using guessed type int dword_1002A300; // 1002A304: using guessed type int dword_1002A304; // 1002A308: using guessed type int dword_1002A308; // 1002A310: using guessed type int dword_1002A310; // 1002A320: using guessed type int dword_1002A320; // 1002A324: using guessed type int dword_1002A324; // 1002A328: using guessed type int dword_1002A328; // ref: 0x100098B0 void Progress_100098B0() { return; } /* { dword_1002A2E8 = 2; dword_1002A2F8 = 1; } */ // 1002A2E8: using guessed type int dword_1002A2E8; // 1002A2F8: using guessed type int dword_1002A2F8; // ref: 0x100098C5 void UNKCALL Progress_100098C5(HWND hWnd) { return; } /* { HWND v1; // esi int v2; // eax HWND v3; // edi int v4; // edx v1 = hWnd; v2 = dword_1002A2F4(); if ( v2 >= 100 ) { SDlgKillTimer(v1, 1); v3 = GetParent(v1); if ( (HWND)SDrawGetFrameWindow(NULL) == v3 ) Fade_100072BE(10); Progress_100098B0(); dword_1002A2E8 &= v4; } else { Progress_10009805(v1, v2); } } */ // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 10010418: using guessed type int __stdcall SDlgKillTimer(DWORD, DWORD); // 1002A2E8: using guessed type int dword_1002A2E8; // 1002A2F4: using guessed type int (*dword_1002A2F4)(void); // ref: 0x1000991C BOOL UNKCALL Progress_1000991C(HWND hWnd) { return 0; } /* { HWND v1; // edi BOOL result; // eax struct tagMSG Msg; // [esp+Ch] [ebp-1Ch] v1 = hWnd; for ( result = IsWindow(hWnd); result; result = IsWindow(v1) ) { if ( dword_1002A2F8 ) goto LABEL_12; if ( PeekMessageA(&Msg, 0, 0, 0, 1u) ) { if ( Msg.message == 18 ) { PostQuitMessage(Msg.wParam); } else if ( !IsDialogMessageA(v1, &Msg) ) { TranslateMessage(&Msg); DispatchMessageA(&Msg); } } else { SDlgCheckTimers(); SDlgUpdateCursor(); } } if ( !dword_1002A2F8 ) return result; LABEL_12: result = DestroyWindow(v1); dword_1002A2F8 = 0; return result; } */ // 10010460: using guessed type DWORD __stdcall SDlgUpdateCursor(); // 10010466: using guessed type DWORD __stdcall SDlgCheckTimers(); // 1002A2F8: using guessed type int dword_1002A2F8; ================================================ FILE: DiabloUI/sbar.cpp ================================================ // ref: 0x100099B5 void __cdecl Sbar_cpp_init() { Sbar_cpp_float = Sbar_cpp_float_value; } // 1001F448: using guessed type int Sbar_cpp_float_value; // 1002A338: using guessed type int Sbar_cpp_float; // ref: 0x100099C0 BOOL __fastcall Sbar_CheckIfNextHero(HWND hWnd) { _uiheroinfo *v1; // eax v1 = (_uiheroinfo *)GetWindowLongA(hWnd, -21); if (!v1 || !v1->next) return 0; v1->next = 0; return 1; } // ref: 0x100099DC int __fastcall Sbar_NumScrollLines(HWND hWnd, int width, int height) { DWORD *v4; // eax DWORD *v5; // esi int result; // eax signed int v7; // ecx LONG v8; // ebx LONG v9; // edi int v10; // [esp-4h] [ebp-1Ch] struct tagPOINT Point; // [esp+Ch] [ebp-Ch] Point.x = width; Point.y = height; if (!hWnd) return 0; if (!IsWindowVisible(hWnd)) return 0; v4 = (DWORD *)GetWindowLongA(hWnd, -21); v5 = v4; if (!v4) return 0; v7 = v4[13]; if (v7 <= 1) v8 = 22; else v8 = v4[14] * (v4[3] - v4[9] - 44) / (v7 - 1) + 22; v9 = v8 + v4[9]; ScreenToClient(hWnd, &Point); if (Point.y >= 22) { if (Point.y >= v8) { if (Point.y >= v9) { if (Point.y >= v5[3] - 22) { *v5 = 4; v10 = 2; } else { *v5 = 8; v10 = 4; } } else { *v5 = 16; v10 = 5; } } else { *v5 = 2; v10 = 3; } result = v10; } else { result = 1; *v5 = 1; } return result; } // ref: 0x10009A99 void __fastcall Sbar_DrawScrollBar(HWND hWnd, int nIDDlgItem, int width, int height) { HWND v4; // eax LONG v5; // eax MAPDST bool v7; // zf int v8; // eax tagRECT DstRect; // [esp+Ch] [ebp-24h] tagRECT SrcBuffer; // [esp+1Ch] [ebp-14h] HWND hWnda; // [esp+2Ch] [ebp-4h] v4 = GetDlgItem(hWnd, nIDDlgItem); hWnda = v4; if (v4) { v5 = GetWindowLongA(v4, -21); if (v5) { if (*(DWORD *)(v5 + 4)) { v7 = *(DWORD *)(v5 + 16) == 0; *(DWORD *)(v5 + 52) = width; *(DWORD *)(v5 + 56) = height; if (!v7) { SrcBuffer.left = 0; DstRect.left = 0; SrcBuffer.top = 0; DstRect.top = 0; DstRect.right = *(DWORD *)(v5 + 8) - 1; DstRect.bottom = *(DWORD *)(v5 + 12) - 1; SrcBuffer.right = *(DWORD *)(v5 + 8) - 1; SrcBuffer.bottom = *(DWORD *)(v5 + 24) - 1; SBltROP3Tiled( *(void **)(v5 + 4), &DstRect, *(POINT **)(v5 + 8), *(DWORD *)(v5 + 16), &SrcBuffer, *(RECT **)(v5 + 20), 0, 0, 0, 0xCC0020u); if (*(DWORD *)(v5 + 28)) { if (width <= 1) v8 = 22; else v8 = height * (*(DWORD *)(v5 + 12) - *(DWORD *)(v5 + 36) - 44) / (width - 1) + 22; SBltROP3( (void *)(v8 * *(DWORD *)(v5 + 8) + *(DWORD *)(v5 + 4) + 3), *(void **)(v5 + 28), 18, *(DWORD *)(v5 + 36), *(DWORD *)(v5 + 8), *(DWORD *)(v5 + 32), 0, 0xCC0020u); SBltROP3( *(void **)(v5 + 4), (void *)(*(DWORD *)(v5 + 40) + 22 * (~*(BYTE *)v5 & 1) * *(DWORD *)(v5 + 44)), *(DWORD *)(v5 + 8), 22, *(DWORD *)(v5 + 8), *(DWORD *)(v5 + 44), 0, 0xCC0020u); SBltROP3( (void *)(*(DWORD *)(v5 + 4) + *(DWORD *)(v5 + 8) * (*(DWORD *)(v5 + 12) - 22)), (void *)(*(DWORD *)(v5 + 40) + 22 * ((~*(BYTE *)v5 & 4 | 8u) >> 2) * *(DWORD *)(v5 + 44)), *(DWORD *)(v5 + 8), 22, *(DWORD *)(v5 + 8), *(DWORD *)(v5 + 44), 0, 0xCC0020u); InvalidateRect(hWnda, 0, 0); } } } } } } // ref: 0x10009BF1 void __fastcall Sbar_LoadScrBarGFX(HWND hWnd, int nIDDlgItem) { DWORD *v2; // eax MAPDST void *v4; // eax struct tagRECT Rect; // [esp+Ch] [ebp-14h] HWND hWnda; // [esp+1Ch] [ebp-4h] hWnda = GetDlgItem(hWnd, nIDDlgItem); if (hWnda) { v2 = (DWORD *)SMemAlloc(0x3Cu, "C:\\Src\\Diablo\\DiabloUI\\Sbar.cpp", 221, 0); if (v2) { SetWindowLongA(hWnda, -21, (LONG)v2); *v2 = 0; GetClientRect(hWnda, &Rect); v2[2] = Rect.right; v2[3] = Rect.bottom; v4 = SMemAlloc(Rect.right * Rect.bottom, "C:\\Src\\Diablo\\DiabloUI\\Sbar.cpp", 230, 0); v2[1] = (DWORD)v4; if (v4) { SDlgSetBitmapI(hWnda, 0, &nullcharacter, -1, 1, v4, 0, v2[2], v2[3], -1); local_LoadArtImage("ui_art\\sb_bg.pcx", (BYTE **)v2 + 4, v2 + 5); local_LoadArtImage("ui_art\\sb_thumb.pcx", (BYTE **)v2 + 7, v2 + 8); local_LoadArtImage("ui_art\\sb_arrow.pcx", (BYTE **)v2 + 10, v2 + 11); } } } } // ref: 0x10009CC7 void __cdecl Sbar_cpp_init2() { Sbar_cpp_float2 = Sbar_cpp_float_value2; } // 1001F44C: using guessed type int Sbar_cpp_float_value2; // 1002A344: using guessed type int Sbar_cpp_float2; // ref: 0x10009CD2 void __fastcall Sbar_FreeScrollBar(HWND hWnd, int nIDDlgItem) { HWND v2; // eax MAPDST DWORD *v4; // eax MAPDST void *v6; // eax void *v7; // eax void *v8; // eax void *v9; // eax v2 = GetDlgItem(hWnd, nIDDlgItem); if (v2) { v4 = (DWORD *)GetWindowLongA(v2, -21); if (v4) { v6 = (void *)v4[1]; if (v6) SMemFree(v6, "C:\\Src\\Diablo\\DiabloUI\\Sbar.cpp", 267, 0); v7 = (void *)v4[4]; if (v7) SMemFree(v7, "C:\\Src\\Diablo\\DiabloUI\\Sbar.cpp", 269, 0); v8 = (void *)v4[7]; if (v8) SMemFree(v8, "C:\\Src\\Diablo\\DiabloUI\\Sbar.cpp", 271, 0); v9 = (void *)v4[10]; if (v9) SMemFree(v9, "C:\\Src\\Diablo\\DiabloUI\\Sbar.cpp", 273, 0); SMemFree(v4, "C:\\Src\\Diablo\\DiabloUI\\Sbar.cpp", 275, 0); SetWindowLongA(v2, -21, 0); } } } ================================================ FILE: DiabloUI/selclass.cpp ================================================ // ref: 0x10009D66 LRESULT __stdcall SelClass_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v4; // eax int v5; // edx HWND v6; // eax HWND v7; // eax HWND v9; // eax if (Msg == 2) { SelClass_FreeClassMsgTbl(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg <= 0x103) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); if (Msg <= 0x105) { v9 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v9, Msg, wParam, lParam); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg == 272) { SelClass_LoadClassFocus(hWnd); return 0; } if (Msg != 273) { if (Msg != 275) { if (Msg == 513) { v4 = GetDlgItem(hWnd, 1056); if (local_GetBottomRect(hWnd, v4, (unsigned short)lParam, (unsigned int)lParam >> 16)) { v5 = 1; LABEL_19: SelClass_CheckClassSpawn(hWnd, v5); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } v6 = GetDlgItem(hWnd, 1054); if (local_GetBottomRect(hWnd, v6, (unsigned short)lParam, (unsigned int)lParam >> 16)) { LABEL_21: v5 = 2; goto LABEL_19; } } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } v7 = GetFocus(); Focus_DoBlitSpinIncFrame(hWnd, v7); return 0; } if (HIWORD(wParam) == 7) { Focus_GetAndBlitSpin(hWnd, lParam); } else { if (HIWORD(wParam) != 6) { v5 = 1; if (HIWORD(wParam) == 5 || (WORD)wParam == 1) goto LABEL_19; if ((WORD)wParam != 2) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); goto LABEL_21; } Focus_CheckPlayMove(lParam); Focus_DoBlitSpinIncFrame(hWnd, (HWND)lParam); SelClass_SetDefaultStats(hWnd, (unsigned short)wParam); } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x10009EC0 void __fastcall SelClass_FreeClassMsgTbl(HWND hWnd) { HWND v2; // eax Focus_DeleteSpinners(); Doom_DeleteFreeProcs(hWnd, selclass_msgtbl3); Doom_DeleteFreeProcs(hWnd, selclass_msgtbl2); Doom_DeleteFreeProcs(hWnd, selclass_msgtbl1); v2 = GetParent(hWnd); SelHero_SetStringWithMsg(v2, 0); } // ref: 0x10009EFD void __fastcall SelClass_LoadClassFocus(HWND hWnd) { HWND v1; // edi HWND v2; // esi LONG v3; // eax char Buffer[32]; // [esp+8h] [ebp-20h] v1 = hWnd; v2 = GetParent(hWnd); if (SelHero_GetHeroIsGood() == 1) LoadStringA(ghUiInst, 0x20u, Buffer, 31); else LoadStringA(ghUiInst, 0x1Fu, Buffer, 31); SelHero_SetStringWithMsg(v2, Buffer); v3 = GetWindowLongA(v2, -21); SetWindowLongA(v1, -21, v3); local_DoUiWndProc(v1, (DWORD *)selclass_msgtbl3); Doom_ParseWndProc3(v1, selclass_msgtbl1, AF_BIGGRAY); Doom_ParseWndProcs(v1, selclass_msgtbl2, AF_BIG, 0); Doom_ParseWndProcs(v1, selclass_msgtbl3, AF_MED, 1); Focus_LoadSpinner("ui_art\\focus.pcx"); SDlgSetTimer((int)v1, 1, 55, 0); } // ref: 0x10009FA2 void __fastcall SelClass_SetDefaultStats(HWND hWnd, int a2) { char v2; // bl HWND v4; // eax _uiheroinfo pInfo; // [esp+8h] [ebp-34h] _uidefaultstats a2a; // [esp+34h] [ebp-8h] v2 = a2; SelHero_SetClassStats(a2 - 1062, &a2a); memset(&pInfo, 0, 0x2Cu); pInfo.strength = a2a.strength; pInfo.magic = a2a.magic; pInfo.dexterity = a2a.dexterity; pInfo.vitality = a2a.vitality; pInfo.level = 1; pInfo.heroclass = v2 - 38; v4 = GetParent(hWnd); SelHero_PrintHeroInfo(v4, &pInfo); } // ref: 0x1000A00D void __fastcall SelClass_CheckClassSpawn(HWND hWnd, int a2) { HWND v4; // eax HWND v5; // eax if (DiabloUI_GetSpawned() && a2 == 1 && (v4 = GetFocus(), GetWindowLongA(v4, -12) != 1062)) { SelYesNo_SpawnErrDialog(hWnd, 69, 0); } else { TitleSnd_PlaySelectSound(); SDlgKillTimer((int)hWnd, 1); if (a2 == 1) { v5 = GetFocus(); a2 = GetWindowLongA(v5, -12); } SDlgEndDialog(hWnd, (HANDLE)a2); } } // ref: 0x1000A077 void __cdecl SelClass_cpp_init() { SelClass_cpp_float = SelClass_cpp_float_value; } // 1001F450: using guessed type int SelClass_cpp_float_value; // 1002A348: using guessed type int SelClass_cpp_float; ================================================ FILE: DiabloUI/selconn.cpp ================================================ // ref: 0x1000A082 void *SelConn_1000A082() { return 0; } /* { return SMemAlloc(272, "C:\\Src\\Diablo\\DiabloUI\\SelConn.cpp", 124, 0); } */ // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000A09B signed int SelConn_1000A09B() { return 0; } /* { signed int result; // eax result = 2139095040; dword_1002A350 = 2139095040; return result; } */ // 1002A350: using guessed type int dword_1002A350; // ref: 0x1000A0A6 int __stdcall SelConn_1000A0A6(HWND hWnd, UINT Msg, WPARAM wParam, unsigned int lParam) { return 0; } /* { HWND v4; // eax HWND v6; // eax char *v7; // [esp+0h] [ebp-Ch] int v8; // [esp+4h] [ebp-8h] if ( Msg > 0x201 ) { if ( Msg == 514 ) { v6 = GetDlgItem(hWnd, 1105); if ( !Sbar_100099C0(v6) ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); goto LABEL_27; } if ( Msg != 515 ) { if ( Msg != 2024 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); if ( !Fade_1000739F() ) Fade_100073FD(hWnd, (int)v7); return 0; } LABEL_25: SelConn_1000AE59(hWnd, (unsigned short)lParam, lParam >> 16); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg == 513 ) goto LABEL_25; if ( Msg == 2 ) { SelConn_1000A43A(hWnd); BNetGW_10002A07(&unk_10029480); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg <= 0x103 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); if ( Msg <= 0x105 ) { v4 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v4, Msg, wParam, lParam); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg == 272 ) { BNetGW_100028C2(&unk_10029480); SelConn_1000A4E4(hWnd, v7, v8); PostMessageA(hWnd, 0x7E8u, 0, 0); return 0; } if ( Msg == 273 ) { if ( HIWORD(wParam) == 7 ) { Focus_100075B7(hWnd, (HWND)lParam); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( HIWORD(wParam) != 6 ) { if ( wParam == 327681 ) { SelConn_1000AC30(hWnd); } else if ( (WORD)wParam == 2 ) { SelConn_1000AC07((int)hWnd, 2); } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } Focus_10007458((void *)lParam); Focus_100075DC(hWnd, (HWND)lParam); SelConn_1000A226(hWnd, (unsigned short)wParam); LABEL_27: SelConn_1000A3E2(hWnd); } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } */ // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x1000A226 HWND __fastcall SelConn_1000A226(HWND hDlg, int nIDDlgItem) { return 0; } /* { HWND v2; // edi HWND result; // eax int v4; // ebx int v5; // eax HWND v6; // ebp unsigned int v7; // eax int v8; // eax const char *v9; // ebx int v10; // eax HWND v11; // eax HWND v12; // eax HWND v13; // eax HWND v14; // eax HWND v15; // eax HWND v16; // eax HWND v17; // eax HWND v18; // eax HWND hWnd; // [esp+10h] [ebp-8Ch] CHAR Buffer; // [esp+14h] [ebp-88h] CHAR v21; // [esp+54h] [ebp-48h] v2 = hDlg; result = GetDlgItem(hDlg, nIDDlgItem); if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { v4 = *((DWORD *)result + 3); if ( v4 ) { result = GetDlgItem(v2, 1081); if ( result ) { v5 = GetWindowLongA(result, -21); local_10007FA4(v5, (const char *)(v4 + 144)); result = GetDlgItem(v2, 1076); v6 = result; if ( result ) { LoadStringA(hInstance, 0x21u, &Buffer, 63); if ( dword_1002A370 ) { v7 = *(DWORD *)(dword_1002A370 + 24); if ( v7 >= *(DWORD *)(v4 + 12) ) v7 = *(DWORD *)(v4 + 12); wsprintfA(&v21, &Buffer, v7); } else { wsprintfA(&v21, &Buffer, *(DWORD *)(v4 + 12)); } v8 = GetWindowLongA(v6, -21); local_10007FA4(v8, &v21); if ( *(DWORD *)(v4 + 8) == 1112425812 ) { hWnd = GetDlgItem(v2, 1144); v9 = BNetGW_10002B21(&unk_10029480, dword_1002948C); if ( !v9 ) v9 = &byte_10029448; if ( hWnd ) { v10 = GetWindowLongA(hWnd, -21); local_10007FA4(v10, v9); } v11 = GetDlgItem(v2, 1143); ShowWindow(v11, 5); v12 = GetDlgItem(v2, 1147); ShowWindow(v12, 0); v13 = GetDlgItem(v2, 1144); ShowWindow(v13, 5); v14 = GetDlgItem(v2, 1145); ShowWindow(v14, 5); dword_1002A354 = 1; } else { v15 = GetDlgItem(v2, 1143); ShowWindow(v15, 0); v16 = GetDlgItem(v2, 1147); ShowWindow(v16, 5); v17 = GetDlgItem(v2, 1144); ShowWindow(v17, 0); v18 = GetDlgItem(v2, 1145); ShowWindow(v18, 0); dword_1002A354 = 0; } result = (HWND)Doom_10006A13(v2, (int *)&unk_10022EF0, 1); } } } } } return result; } */ // 1002948C: using guessed type int dword_1002948C; // 1002A354: using guessed type int dword_1002A354; // 1002A370: using guessed type int dword_1002A370; // ref: 0x1000A3E2 HWND UNKCALL SelConn_1000A3E2(HWND hDlg) { return 0; } /* { HWND v1; // esi int v2; // eax v1 = hDlg; v2 = SelConn_1000A3FF(); return Sbar_10009A99(v1, 1105, dword_1002A360, v2); } */ // ref: 0x1000A3FF int SelConn_1000A3FF() { return 0; } /* { HWND v0; // eax LONG v1; // eax DWORD *v2; // ecx DWORD *v3; // eax int v5; // edx v0 = GetFocus(); if ( !v0 ) return 0; v1 = GetWindowLongA(v0, -21); if ( !v1 ) return 0; v2 = (DWORD *)dword_1002A35C; if ( !dword_1002A35C ) return 0; v3 = *(DWORD **)(v1 + 12); if ( !v3 ) return 0; v5 = 0; do { if ( v2 == v3 ) break; v2 = (DWORD *)*v2; ++v5; } while ( v2 ); return v5; } */ // 1002A35C: using guessed type int dword_1002A35C; // ref: 0x1000A43A void UNKCALL SelConn_1000A43A(HWND hDlg) { return; } /* { HWND v1; // esi DWORD *v2; // eax v1 = hDlg; Title_100100E7(hDlg); Focus_10007818(v1); Sbar_10009CD2(v1, 1105); SelConn_1000A4B9((DWORD *)dword_1002A35C); Doom_10006C53(v1, &dword_10022F18); Doom_10006C53(v1, (int *)&unk_10022F08); Doom_10006C53(v1, (int *)&unk_10022ED8); Doom_10006C53(v1, (int *)&unk_10022EE4); Doom_10006C53(v1, (int *)&unk_10022F00); Doom_10006C53(v1, (int *)&unk_10022EF0); v2 = (DWORD *)GetWindowLongA(v1, -21); local_10007F72(v2); } */ // 10022F18: using guessed type int dword_10022F18; // 1002A35C: using guessed type int dword_1002A35C; // ref: 0x1000A4B9 int __fastcall SelConn_1000A4B9(DWORD *a1) { return 0; } /* { DWORD *v1; // esi int result; // eax if ( a1 ) { do { v1 = (DWORD *)*a1; result = SelConn_1000A4CD(a1); a1 = v1; } while ( v1 ); } return result; } */ // ref: 0x1000A4CD int UNKCALL SelConn_1000A4CD(void *arg) { return 0; } /* { int result; // eax if ( arg ) result = SMemFree(arg, "C:\\Src\\Diablo\\DiabloUI\\SelConn.cpp", 130, 0); return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000A4E4 HWND UNKCALL SelConn_1000A4E4(HWND hWnd, char *a2, int a3) { return 0; } /* { HWND v3; // esi HWND v4; // ST1C_4 int v5; // eax int *v6; // edi HWND result; // eax HWND v8; // eax HWND v9; // [esp+0h] [ebp-Ch] v3 = hWnd; SelConn_1000A6EC(hWnd); Focus_100077E9((int)v3, "ui_art\\focus16.pcx", v9); Title_1001009E(v3, (int)"ui_art\\smlogo.pcx", v4); v5 = local_10007F46(); v6 = (int *)v5; if ( v5 ) { SetWindowLongA(v3, -21, v5); local_10007944((int)v3, 0, &byte_10029448, -1, 1, (int)"ui_art\\selconn.pcx", v6, v6 + 1, 0); Fade_100073C5(v3, 1); } Doom_100068AB(v3, (int *)&unk_10022EF0, 1); Doom_100068AB(v3, (int *)&unk_10022F00, 1); Doom_100068AB(v3, (int *)&unk_10022ED8, 5); Doom_100068AB(v3, (int *)&unk_10022EE4, 3); Doom_1000658C(v3, (int *)&unk_10022F08, 4, 0); Doom_1000658C(v3, &dword_10022F18, 0, 1); dword_1002A360 = 0; dword_1002A368 = dword_10029488; dword_1002A35C = 0; SNetEnumProviders(0, SelConn_1000A5F3); SelConn_1000A670(v3, (const char *)dword_1002A35C); result = Sbar_10009BF1(v3, 1105); if ( dword_1002A360 <= 6 ) { v8 = GetDlgItem(v3, 1105); result = (HWND)ShowWindow(v8, 0); } return result; } */ // 10010472: using guessed type int __stdcall SNetEnumProviders(DWORD, DWORD); // 10022F18: using guessed type int dword_10022F18; // 10029488: using guessed type int dword_10029488; // 1002A35C: using guessed type int dword_1002A35C; // 1002A368: using guessed type int dword_1002A368; // ref: 0x1000A5F3 signed int __stdcall SelConn_1000A5F3(int a1, char *a2, char *a3, int a4) { return 0; } /* { int v4; // esi int v6; // edx DWORD *v7; // eax v4 = SelConn_1000A082(); if ( !v4 || a1 == 1112425812 && !dword_1002A368 ) return 0; *(DWORD *)v4 = 0; v6 = *(DWORD *)(a4 + 4); *(DWORD *)(v4 + 8) = a1; *(DWORD *)(v4 + 4) = v6 & 2; *(DWORD *)(v4 + 12) = *(DWORD *)(a4 + 16); strcpy((char *)(v4 + 16), a2); strcpy((char *)(v4 + 144), a3); v7 = SelRegn_1000EF56(dword_1002A35C, (DWORD *)v4); ++dword_1002A360; dword_1002A35C = (int)v7; return 1; } */ // 1002A35C: using guessed type int dword_1002A35C; // 1002A368: using guessed type int dword_1002A368; // ref: 0x1000A670 int __fastcall SelConn_1000A670(HWND a1, const char *a2) { return 0; } /* { const char *v2; // edi int *v3; // ebx HWND v4; // eax HWND v5; // esi int v6; // eax HWND hDlg; // [esp+8h] [ebp-4h] v2 = a2; hDlg = a1; v3 = &dword_10022F18; if ( dword_10022F18 ) { do { v4 = GetDlgItem(hDlg, *v3); v5 = v4; if ( v4 ) { if ( v2 ) { EnableWindow(v4, 1); v6 = GetWindowLongA(v5, -21); if ( v6 ) { *(DWORD *)(v6 + 12) = v2; local_10007FA4(v6, v2 + 16); v2 = *(const char **)v2; } } else { EnableWindow(v4, 0); } } ++v3; } while ( *v3 ); } return Doom_1000680A(hDlg, &dword_10022F18, 0, 1); } */ // 10022F18: using guessed type int dword_10022F18; // ref: 0x1000A6EC void UNKCALL SelConn_1000A6EC(HWND hDlg) { return; } /* { HWND v1; // ebx int *v2; // edi HWND v3; // eax HWND v4; // esi void *v5; // eax v1 = hDlg; v2 = &dword_10022F18; if ( dword_10022F18 ) { do { v3 = GetDlgItem(v1, *v2); v4 = v3; if ( v3 ) { v5 = (void *)GetWindowLongA(v3, -4); SetPropA(v4, "UIOLDPROC", v5); SetWindowLongA(v4, -4, (LONG)SelConn_1000A73E); } ++v2; } while ( *v2 ); } } */ // 10022F18: using guessed type int dword_10022F18; // ref: 0x1000A73E LRESULT __stdcall SelConn_1000A73E(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { LRESULT (__stdcall *v4)(HWND, UINT, WPARAM, LPARAM); // edi HWND v5; // eax WPARAM v7; // [esp-8h] [ebp-14h] v4 = (LRESULT (__stdcall *)(HWND, UINT, WPARAM, LPARAM))GetPropA(hWnd, "UIOLDPROC"); switch ( Msg ) { case 2u: RemovePropA(hWnd, "UIOLDPROC"); if ( !v4 ) return DefWindowProcA(hWnd, Msg, wParam, lParam); SetWindowLongA(hWnd, -4, (LONG)v4); break; case 0xFu: local_10007C95(hWnd); return 0; case 0x87u: return 4; case 0x100u: if ( wParam > 0x21 ) { if ( wParam == 34 ) { SelConn_1000A948(hWnd); } else if ( wParam > 0x24 ) { if ( wParam <= 0x26 ) { SelConn_1000AB83(hWnd); } else if ( wParam <= 0x28 ) { SelConn_1000AAEB(hWnd); } } return 0; } if ( wParam == 33 ) { SelConn_1000AA3B(hWnd); return 0; } if ( wParam == 9 ) { if ( GetKeyState(16) >= 0 ) SelConn_1000A866(hWnd); else SelConn_1000A8D7(hWnd); return 0; } if ( wParam != 13 ) { if ( wParam == 27 ) { v7 = 2; goto LABEL_13; } if ( wParam != 32 ) return 0; } v7 = 1; LABEL_13: v5 = GetParent(hWnd); SendMessageA(v5, 0x111u, v7, 0); return 0; } if ( v4 ) return CallWindowProcA(v4, hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam); } */ // ref: 0x1000A866 HWND UNKCALL SelConn_1000A866(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND v2; // ebx int nIDDlgItem[1066]; // [esp+0h] [ebp-10CCh] int v5; // [esp+10A8h] [ebp-24h] int v6; // [esp+10B4h] [ebp-18h] int v7; // [esp+10B8h] [ebp-14h] int v8; // [esp+10BCh] [ebp-10h] int v9; // [esp+10C0h] [ebp-Ch] int v10; // [esp+10C4h] [ebp-8h] int v11; // [esp+10C8h] [ebp-4h] v1 = hWnd; v6 = 1070; v7 = 1071; v8 = 1072; v9 = 1073; v10 = 1074; v11 = 1069; v2 = GetParent(hWnd); do { v5 = nIDDlgItem[GetWindowLongA(v1, -12)]; v1 = GetDlgItem(v2, v5); } while ( !IsWindowEnabled(v1) ); return SetFocus(v1); } */ // 1000A866: using guessed type int nIDDlgItem[1066]; // ref: 0x1000A8D7 HWND UNKCALL SelConn_1000A8D7(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND v2; // ebx int nIDDlgItem[1066]; // [esp+0h] [ebp-10CCh] int v5; // [esp+10A8h] [ebp-24h] int v6; // [esp+10B4h] [ebp-18h] int v7; // [esp+10B8h] [ebp-14h] int v8; // [esp+10BCh] [ebp-10h] int v9; // [esp+10C0h] [ebp-Ch] int v10; // [esp+10C4h] [ebp-8h] int v11; // [esp+10C8h] [ebp-4h] v1 = hWnd; v6 = 1074; v7 = 1069; v8 = 1070; v9 = 1071; v10 = 1072; v11 = 1073; v2 = GetParent(hWnd); do { v5 = nIDDlgItem[GetWindowLongA(v1, -12)]; v1 = GetDlgItem(v2, v5); } while ( !IsWindowEnabled(v1) ); return SetFocus(v1); } */ // 1000A8D7: using guessed type int nIDDlgItem[1066]; // ref: 0x1000A948 HWND UNKCALL SelConn_1000A948(HWND hWnd) { return 0; } /* { HWND v1; // ebp HWND result; // eax HWND v3; // esi HWND v4; // ebx HWND v5; // eax DWORD *v6; // eax int v7; // eax const char *v8; // ebx int v9; // eax v1 = hWnd; result = GetParent(hWnd); v3 = result; if ( result ) { result = GetDlgItem(result, 1069); v4 = result; if ( result ) { v5 = GetDlgItem(v3, 1074); result = (HWND)GetWindowLongA(v5, -21); if ( result ) { v6 = (DWORD *)*((DWORD *)result + 3); if ( v6 && *v6 ) { v7 = SelConn_1000A9F3(v4) + 6; if ( v7 > dword_1002A360 - 6 ) v7 = dword_1002A360 - 6; result = (HWND)SelConn_1000AA28(v7); v8 = (const char *)result; if ( result ) { TitleSnd_10010315(); SelConn_1000A670(v3, v8); v9 = GetWindowLongA(v1, -12); SelConn_1000A226(v3, v9); result = SelConn_1000A3E2(v3); } } else { result = SelConn_1000A8D7(v4); } } } } return result; } */ // ref: 0x1000A9F3 int UNKCALL SelConn_1000A9F3(HWND hWnd) { return 0; } /* { LONG v1; // eax DWORD *v2; // ecx DWORD *v3; // eax int v5; // edx if ( !hWnd ) return 0; v1 = GetWindowLongA(hWnd, -21); if ( !v1 ) return 0; v2 = (DWORD *)dword_1002A35C; if ( !dword_1002A35C ) return 0; v3 = *(DWORD **)(v1 + 12); if ( !v3 ) return 0; v5 = 0; do { if ( v2 == v3 ) break; v2 = (DWORD *)*v2; ++v5; } while ( v2 ); return v5; } */ // 1002A35C: using guessed type int dword_1002A35C; // ref: 0x1000AA28 DWORD *__fastcall SelConn_1000AA28(int a1) { return 0; } /* { DWORD *result; // eax result = (DWORD *)dword_1002A35C; while ( result && a1 ) { result = (DWORD *)*result; --a1; } return result; } */ // 1002A35C: using guessed type int dword_1002A35C; // ref: 0x1000AA3B HWND UNKCALL SelConn_1000AA3B(HWND hWnd) { return 0; } /* { HWND result; // eax HWND v2; // esi HWND v3; // edi HWND v4; // eax int v5; // eax const char *v6; // edi int v7; // eax HWND hWnda; // [esp+10h] [ebp-4h] hWnda = hWnd; result = GetParent(hWnd); v2 = result; if ( result ) { result = GetDlgItem(result, 1069); v3 = result; if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { if ( result == (HWND)dword_1002A35C ) { v4 = GetDlgItem(v2, 1074); result = SelConn_1000A866(v4); } else { v5 = SelConn_1000A9F3(v3) - 6; if ( v5 < 0 ) v5 = 0; result = (HWND)SelConn_1000AA28(v5); v6 = (const char *)result; if ( result ) { TitleSnd_10010315(); SelConn_1000A670(v2, v6); v7 = GetWindowLongA(hWnda, -12); SelConn_1000A226(v2, v7); result = SelConn_1000A3E2(v2); } } } } } } return result; } */ // 1002A35C: using guessed type int dword_1002A35C; // ref: 0x1000AAEB HWND UNKCALL SelConn_1000AAEB(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND result; // eax HWND v3; // eax const char *v4; // ebp HWND v5; // eax int v6; // ebx HWND v7; // eax HWND v8; // eax v1 = hWnd; result = (HWND)GetWindowLongA(hWnd, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { if ( *(DWORD *)result ) { if ( GetWindowLongA(v1, -12) >= 1074 ) { v3 = GetParent(v1); result = GetDlgItem(v3, 1070); if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { v4 = (const char *)*((DWORD *)result + 3); if ( v4 ) { TitleSnd_10010315(); v5 = GetParent(v1); SelConn_1000A670(v5, v4); v6 = GetWindowLongA(v1, -12); v7 = GetParent(v1); SelConn_1000A226(v7, v6); v8 = GetParent(v1); result = SelConn_1000A3E2(v8); } } } } else { result = SelConn_1000A866(v1); } } } } return result; } */ // ref: 0x1000AB83 HWND UNKCALL SelConn_1000AB83(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND result; // eax const char *v3; // ebx HWND v4; // eax int v5; // ebx HWND v6; // eax HWND v7; // eax v1 = hWnd; if ( GetWindowLongA(hWnd, -12) > 1069 ) return SelConn_1000A8D7(v1); result = (HWND)GetWindowLongA(v1, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { v3 = (const char *)dword_1002A35C; if ( result != (HWND)dword_1002A35C ) { while ( v3 && *(HWND *)v3 != result ) v3 = *(const char **)v3; TitleSnd_10010315(); v4 = GetParent(v1); SelConn_1000A670(v4, v3); v5 = GetWindowLongA(v1, -12); v6 = GetParent(v1); SelConn_1000A226(v6, v5); v7 = GetParent(v1); result = SelConn_1000A3E2(v7); } } } return result; } */ // 1002A35C: using guessed type int dword_1002A35C; // ref: 0x1000AC07 int __fastcall SelConn_1000AC07(int a1, int a2) { return 0; } /* { int v2; // esi int v3; // edi v2 = a2; v3 = a1; if ( a2 == 2 ) TitleSnd_1001031F(); Fade_100073B4(); Fade_100072BE(10); return SDlgEndDialog(v3, v2); } */ // 10010376: using guessed type int __stdcall SDlgEndDialog(DWORD, DWORD); // ref: 0x1000AC30 int UNKCALL SelConn_1000AC30(HWND arg) { return 0; } /* { int v1; // esi int v2; // edx int result; // eax int v4; // eax int v5; // ecx UINT v6; // [esp-4h] [ebp-8h] v1 = (int)arg; if ( SelConn_1000AC9E(arg) ) { v2 = 1; return SelConn_1000AC07(v1, v2); } if ( SErrGetLastError() == -2062548873 ) { dword_1002A374 = 1; v2 = 0; return SelConn_1000AC07(v1, v2); } result = SelGame_1000B67E(); switch ( result ) { case 1230002254: goto LABEL_17; case 1297040461: v4 = SErrGetLastError(); v5 = v1; if ( v4 == 1222 ) v6 = 46; else v6 = 53; goto LABEL_14; case 1396916812: LABEL_17: v6 = 44; v5 = v1; LABEL_14: result = SelConn_1000AE19(v5, v6); break; } return result; } */ // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // 1002A374: using guessed type int dword_1002A374; // ref: 0x1000AC9E int UNKCALL SelConn_1000AC9E(HWND hWnd) { return 0; } /* { HWND v1; // ebx HWND v2; // eax LONG v3; // eax int v4; // esi char *v6; // ST10_4 int v7; // ST08_4 int v8; // eax int v9; // esi char *v10; // ST14_4 int v11; // ST0C_4 void *v12; // eax char v13; // [esp+8h] [ebp-8Ch] HWND v14; // [esp+10h] [ebp-84h] char v15; // [esp+58h] [ebp-3Ch] v1 = hWnd; TitleSnd_1001031F(); SelGame_1000B677(0); SelGame_1000B66A(0); v2 = GetFocus(); v3 = GetWindowLongA(v2, -21); if ( !v3 ) return 0; v4 = *(DWORD *)(v3 + 12); if ( !v4 ) return 0; SelGame_1000B677(*(void **)(v4 + 8)); SelGame_1000B66A(*(void **)(v4 + 4)); if ( SelGame_1000B67E() == 1112425812 ) { BNetGW_10002A07(&unk_10029480); BNetGW_100028C2(&unk_10029480); } if ( dword_1002A364 ) memcpy(&v13, (const void *)dword_1002A364, 0x50u); v14 = v1; if ( dword_1002A370 ) memcpy(&v15, (const void *)dword_1002A370, 0x3Cu); SelConn_1000ADA8(v1); v6 = dword_1002A358; v7 = dword_1002A34C; v8 = SelGame_1000B67E(); v9 = SNetInitializeProvider(v8, &v15, v7, &v13, v6); if ( v9 ) { v10 = dword_1002A358; v11 = dword_1002A34C; v12 = (void *)SelGame_1000B67E(); v9 = SelModem_1000E435(v12, (int)&v15, v11, &v13, v10); } else { SNetDestroy(); } if ( !v9 ) SelConn_1000ADD0(v1); return v9; } */ // 10010478: using guessed type DWORD __stdcall SNetDestroy(); // 1001047E: using guessed type int __stdcall SNetInitializeProvider(DWORD, DWORD, DWORD, DWORD, DWORD); // 1002A364: using guessed type int dword_1002A364; // 1002A370: using guessed type int dword_1002A370; // ref: 0x1000ADA8 int UNKCALL SelConn_1000ADA8(HWND hWnd) { return 0; } /* { HWND v1; // esi v1 = hWnd; Fade_100072BE(10); local_1000811B(); ShowWindow(v1, 0); Title_100100E7(v1); return Focus_10007818(v1); } */ // ref: 0x1000ADD0 BOOL UNKCALL SelConn_1000ADD0(HWND hWnd) { return 0; } /* { HWND v1; // esi HWND v2; // ST10_4 HWND v4; // [esp+0h] [ebp-4h] v1 = hWnd; Focus_100077E9((int)hWnd, "ui_art\\focus16.pcx", v4); Title_1001009E(v1, (int)"ui_art\\smlogo.pcx", v2); local_100080F1(); Fade_100073C5(v1, 0); PostMessageA(v1, 0x7E8u, 0, 0); ShowWindow(v1, 5); return UpdateWindow(v1); } */ // ref: 0x1000AE19 int __fastcall SelConn_1000AE19(int a1, UINT a2) { return 0; } /* { UINT v2; // esi int v3; // edi int result; // eax CHAR Buffer; // [esp+8h] [ebp-80h] v2 = a2; v3 = a1; result = SErrGetLastError(); if ( result != 1223 ) { LoadStringA(hInstance, v2, &Buffer, 127); result = SelYesNo_1000FD39(v3, &Buffer, 0, 0); } return result; } */ // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // ref: 0x1000AE59 HWND __fastcall SelConn_1000AE59(HWND hWnd, int a2, int a3) { return 0; } /* { int v3; // ebp int v4; // ebx int v5; // ST0C_4 HWND v6; // esi int v7; // ST08_4 HWND v8; // eax HWND result; // eax HWND v10; // eax HWND v11; // eax HWND v12; // eax HWND v13; // eax int v14; // eax int v15; // eax int v16; // eax HWND v17; // eax HWND v18; // eax HWND v19; // eax HWND v20; // eax v3 = a3; v4 = a2; v5 = a3; v6 = hWnd; v7 = a2; v8 = GetDlgItem(hWnd, 1056); if ( local_10007C3B(v6, v8, v7, v5) ) return (HWND)SelConn_1000AC30(v6); v10 = GetDlgItem(v6, 1054); if ( local_10007C3B(v6, v10, v4, v3) ) return (HWND)SelConn_1000AC07((int)v6, 2); if ( dword_1002A354 && (v11 = GetDlgItem(v6, 1145), local_10007C3B(v6, v11, v4, v3)) ) { SelConn_1000ADA8(v6); TitleSnd_1001031F(); UiSelectRegion(&a3); result = (HWND)SelConn_1000ADD0(v6); } else { v12 = GetDlgItem(v6, 1105); result = (HWND)local_10007C3B(v6, v12, v4, v3); if ( result ) { v13 = GetDlgItem(v6, 1105); v14 = Sbar_100099DC(v13, v4, v3) - 1; if ( v14 ) { v15 = v14 - 1; if ( v15 ) { v16 = v15 - 1; if ( v16 ) { result = (HWND)(v16 - 1); if ( !result ) { v17 = GetFocus(); result = SelConn_1000A948(v17); } } else { v18 = GetFocus(); result = SelConn_1000AA3B(v18); } } else { v19 = GetFocus(); result = SelConn_1000AAEB(v19); } } else { v20 = GetFocus(); result = SelConn_1000AB83(v20); } } } return result; } */ // 1002A354: using guessed type int dword_1002A354; // ref: 0x1000AF69 int __stdcall UiSelectProvider(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, _SNETVERSIONDATA *file_info, int *type) { return 0; } /* { int v6; // eax int v7; // ebx dword_1002A374 = 0; dword_1002A36C = a1; dword_1002A370 = a2; dword_1002A34C = a3; dword_1002A364 = a4; dword_1002A358 = a5; artfont_10001159(); v6 = SDrawGetFrameWindow(NULL); v7 = SDlgDialogBoxParam(hInstance, "SELCONNECT_DIALOG", v6, SelConn_1000A0A6, 0); if ( a6 ) *a6 = SelGame_1000B67E(); if ( dword_1002A374 ) { artfont_100010C8(); local_100078B6(); SErrSetLastError(-2062548873); } else { if ( v7 == 1 ) { artfont_100010C8(); local_100078B6(); return 1; } SErrSetLastError(1223); } return 0; } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 1001041E: using guessed type int __stdcall SErrSetLastError(DWORD); // 1002A364: using guessed type int dword_1002A364; // 1002A36C: using guessed type int dword_1002A36C; // 1002A370: using guessed type int dword_1002A370; // 1002A374: using guessed type int dword_1002A374; ================================================ FILE: DiabloUI/seldial.cpp ================================================ // ref: 0x1000B011 int UNKCALL SelDial_1000B011(char *arg) { return 0; } /* { signed int v1; // edi int i; // edi char v4; // [esp+8h] [ebp-24h] char v5; // [esp+27h] [ebp-5h] char *v6; // [esp+28h] [ebp-4h] v6 = arg; v1 = 0; do { if ( SRegLoadString("Diablo\\Phone Book", off_10022F8C[v1], 1u, &v4, 0x20u) ) { v5 = 0; if ( !strcmp(&v4, v6) ) break; } ++v1; } while ( v1 < 4 ); if ( v1 == 4 ) v1 = 3; for ( i = v1 - 1; i >= 0; --i ) { v4 = 0; if ( SRegLoadString("Diablo\\Phone Book", off_10022F8C[i], 1u, &v4, 0x20u) ) { v5 = 0; if ( strlen(&v4) ) SRegSaveString("Diablo\\Phone Book", off_10022F90[i], 1u, &v4); } } return SRegSaveString("Diablo\\Phone Book", off_10022F8C[0], 1u, v6); } */ // 10010484: using guessed type int __stdcall SRegSaveString(const char *, const char *, unsigned int, const char *); // 1001048A: using guessed type int __stdcall SRegLoadString(const char *, const char *, unsigned int, char *, unsigned int); // 10022F8C: using guessed type char *off_10022F8C[4]; // 10022F90: using guessed type char *off_10022F90[3]; // ref: 0x1000B0C4 signed int SelDial_1000B0C4() { return 0; } /* { signed int result; // eax result = 2139095040; dword_1002A37C = 2139095040; return result; } */ // 1002A37C: using guessed type int dword_1002A37C; // ref: 0x1000B0CF int __stdcall SelDial_1000B0CF(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { HWND v4; // eax int v6; // edx HWND v7; // eax int savedregs; // [esp+Ch] [ebp+0h] if ( Msg == 2 ) { SelDial_1000B29A(hWnd); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg > 0x103 ) { if ( Msg <= 0x105 ) { v7 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v7, Msg, wParam, lParam); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg == 272 ) { dword_1002A378 = (char *)lParam; SelDial_1000B483(hWnd, (int)&savedregs); return 0; } if ( Msg != 273 ) { if ( Msg != 275 ) { if ( Msg == 513 ) SelDial_1000B614(hWnd, (unsigned short)lParam, (unsigned int)lParam >> 16); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( wParam == 1 ) { v4 = GetFocus(); Focus_100075DC(hWnd, v4); } else if ( wParam == 2 ) { SelDial_1000B354(hWnd); } return 0; } if ( HIWORD(wParam) == 7 ) { Focus_100075B7(hWnd, (HWND)lParam); } else if ( HIWORD(wParam) == 6 ) { Focus_10007458((void *)lParam); Focus_100075DC(hWnd, (HWND)lParam); SelDial_1000B1FB(hWnd, (unsigned short)wParam); } else { v6 = 1; if ( wParam != 327681 ) { if ( (WORD)wParam != 2 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); v6 = 2; } SelDial_1000B2D8((int)hWnd, v6); } } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } */ // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x1000B1FB HWND __fastcall SelDial_1000B1FB(HWND hWnd, int a2) { return 0; } /* { int v2; // edi HWND v3; // ebx HWND v4; // eax CHAR v6; // [esp+Ch] [ebp-140h] CHAR Buffer; // [esp+10Ch] [ebp-40h] v2 = a2; v3 = hWnd; LoadStringA(hInstance, 0x39u, &Buffer, 63); if ( v2 == 1117 ) { if ( Modem_1000855D() ) LoadStringA(hInstance, 0x43u, &v6, 255); else LoadStringA(hInstance, 0x36u, &v6, 255); } else if ( v2 == 1118 ) { if ( Modem_1000855D() ) LoadStringA(hInstance, 0x44u, &v6, 255); else LoadStringA(hInstance, 0x37u, &v6, 255); } else { LoadStringA(hInstance, 0x38u, &v6, 255); } v4 = GetParent(v3); return Modem_10008563(v4, &Buffer, (int)&v6); } */ // ref: 0x1000B29A HWND UNKCALL SelDial_1000B29A(HWND hDlg) { return 0; } /* { HWND v1; // esi HWND v2; // eax v1 = hDlg; Doom_10006C53(hDlg, (int *)&unk_10022FB0); Doom_10006C53(v1, (int *)&unk_10022FA4); Doom_10006C53(v1, (int *)&unk_10022F9C); Focus_100076C3(); v2 = GetParent(v1); return Modem_10008563(v2, 0, 0); } */ // ref: 0x1000B2D8 int __fastcall SelDial_1000B2D8(int a1, int a2) { return 0; } /* { int v2; // esi int v3; // edi HWND v4; // eax LONG v5; // eax v2 = a2; v3 = a1; if ( a2 == 1 || a2 == 2 ) TitleSnd_1001031F(); SDlgKillTimer(v3, 1); SDlgKillTimer(v3, 2); if ( v2 != 1 ) return SDlgEndDialog(v3, v2); v4 = GetFocus(); v5 = GetWindowLongA(v4, -12); if ( v5 == 1117 ) return SDlgEndDialog(v3, 3); if ( v5 == 1118 ) return SDlgEndDialog(v3, 5); if ( dword_1002A378 ) strcpy(dword_1002A378, &byte_1002A380[32 * (v5 - 1119)]); return SDlgEndDialog(v3, 4); } */ // 10010376: using guessed type int __stdcall SDlgEndDialog(DWORD, DWORD); // 10010418: using guessed type int __stdcall SDlgKillTimer(DWORD, DWORD); // ref: 0x1000B354 HWND UNKCALL SelDial_1000B354(HWND hDlg) { return 0; } /* { HWND v1; // edi HWND result; // eax HWND v3; // esi HWND v4; // eax v1 = hDlg; result = GetDlgItem(hDlg, 1118); v3 = result; if ( result ) { if ( Modem_10008606() ) { SelDial_1000B3D8(v1); EnableWindow(v3, 1); result = (HWND)ShowWindow(v3, 1); } else if ( SErrGetLastError() == 1222 ) { result = (HWND)SelDial_1000B2D8((int)v1, 1222); } else { if ( GetFocus() == v3 ) { v4 = GetDlgItem(v1, 1117); SetFocus(v4); } SelDial_1000B44C(v1); EnableWindow(v3, 0); result = (HWND)ShowWindow(v3, 0); } } return result; } */ // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // ref: 0x1000B3D8 HWND UNKCALL SelDial_1000B3D8(HWND hDlg) { return 0; } /* { HWND v1; // esi HWND result; // eax HWND v3; // edi char *v4; // eax int v5; // ebx int v6; // eax CHAR Buffer; // [esp+8h] [ebp-40h] v1 = hDlg; result = GetDlgItem(hDlg, 1118); v3 = result; if ( result ) { v4 = Modem_1000863D(); v5 = Modem_1000865F(v4); if ( v5 <= Modem_10008659() ) LoadStringA(hInstance, 0x4Au, &Buffer, 63); else LoadStringA(hInstance, 0x4Bu, &Buffer, 63); v6 = GetWindowLongA(v3, -21); local_10007FA4(v6, &Buffer); result = (HWND)Doom_1000680A(v1, (int *)&unk_10022FB0, 0, 1); } return result; } */ // ref: 0x1000B44C HWND UNKCALL SelDial_1000B44C(HWND hDlg) { return 0; } /* { HWND v1; // esi HWND result; // eax int v3; // eax v1 = hDlg; result = GetDlgItem(hDlg, 1118); if ( result ) { v3 = GetWindowLongA(result, -21); local_10007FA4(v3, 0); result = (HWND)Doom_1000680A(v1, (int *)&unk_10022FB0, 0, 1); } return result; } */ // ref: 0x1000B483 HWND USERCALL SelDial_1000B483(HWND hWnd, int a2) { return 0; } /* { HWND v2; // esi HWND v3; // eax LONG v4; // eax HWND result; // eax char *v6; // eax int v7; // ebx HWND v8; // eax HWND v9; // edi int v10; // esi const char *v11; // edx int v12; // [esp-64h] [ebp-6Ch] int v13; // [esp-24h] [ebp-2Ch] HWND v14; // [esp-4h] [ebp-Ch] const char *v15; // [esp+0h] [ebp-8h] int v16; // [esp+4h] [ebp-4h] v2 = hWnd; v3 = GetParent(hWnd); v4 = GetWindowLongA(v3, -21); SetWindowLongA(v2, -21, v4); Focus_10007719("ui_art\\focus16.pcx"); SDlgSetTimer(v2, 1, 55, 0); local_10007CB5(v2, (int *)&unk_10022FB0); Doom_100068AB(v2, (int *)&unk_10022F9C, 5); Doom_1000658C(v2, (int *)&unk_10022FA4, 4, 0); Doom_1000658C(v2, (int *)&unk_10022FB0, 0, 1); if ( Modem_1000855D() ) { SDlgSetTimer(v2, 2, 2000, 0); result = SelDial_1000B354(v2); } else { v16 = a2; v14 = v2; v6 = byte_1002A380; do { *v6 = 0; v6 += 32; } while ( (signed int)v6 < (signed int)&dword_1002A400 ); SelDial_1000B5D9(); LoadStringA(hInstance, 0x34u, (LPSTR)&v13, 31); v7 = 0; v15 = byte_1002A380; do { v8 = GetDlgItem(v14, v7 + 1119); v9 = v8; if ( v8 ) { v10 = GetWindowLongA(v8, -21); if ( v10 ) { if ( strlen(v15) ) { wsprintfA((LPSTR)&v12, (LPCSTR)&v13, v15); v11 = (const char *)&v12; } else { EnableWindow(v9, 0); v11 = 0; } local_10007FA4(v10, v11); } } v15 += 32; ++v7; } while ( (signed int)v15 < (signed int)&dword_1002A400 ); result = (HWND)Doom_1000680A(v14, (int *)&unk_10022FB0, 0, 1); } return result; } */ // 1000B483: could not find valid save-restore pair for ebp // 10010412: using guessed type int __stdcall SDlgSetTimer(DWORD, DWORD, DWORD, DWORD); // 1002A400: using guessed type int dword_1002A400; // ref: 0x1000B5D9 int SelDial_1000B5D9() { return 0; } /* { char *v0; // esi const char **v1; // edi int result; // eax v0 = byte_1002A380; v1 = (const char **)off_10022F8C; do { result = SRegLoadString("Diablo\\Phone Book", *v1, 1u, v0, 0x20u); if ( result ) v0[31] = 0; else *v0 = 0; ++v1; v0 += 32; } while ( (signed int)v1 < (signed int)&unk_10022F9C ); return result; } */ // 1001048A: using guessed type int __stdcall SRegLoadString(const char *, const char *, unsigned int, char *, unsigned int); // 10022F8C: using guessed type char *off_10022F8C[4]; // ref: 0x1000B614 int __fastcall SelDial_1000B614(HWND hWnd, int a2, int a3) { return 0; } /* { int v3; // ebx HWND v4; // esi int v5; // ST08_4 HWND v6; // eax int v7; // edx HWND v8; // eax int result; // eax v3 = a2; v4 = hWnd; v5 = a2; v6 = GetDlgItem(hWnd, 1056); if ( local_10007C3B(v4, v6, v5, a3) ) { v7 = 1; } else { v8 = GetDlgItem(v4, 1054); result = local_10007C3B(v4, v8, v3, a3); if ( !result ) return result; v7 = 2; } return SelDial_1000B2D8((int)v4, v7); } */ ================================================ FILE: DiabloUI/selgame.cpp ================================================ // ref: 0x1000B66A void UNKCALL SelGame_1000B66A(void *arg) { return; } /* { dword_1002A408 = (int)arg; } */ // 1002A408: using guessed type int dword_1002A408; // ref: 0x1000B671 int SelGame_1000B671() { return 0; } /* { return dword_1002A408; } */ // 1002A408: using guessed type int dword_1002A408; // ref: 0x1000B677 void UNKCALL SelGame_1000B677(void *arg) { return; } /* { dword_1002A404 = (int)arg; } */ // 1002A404: using guessed type int dword_1002A404; // ref: 0x1000B67E int SelGame_1000B67E() { return 0; } /* { return dword_1002A404; } */ // 1002A404: using guessed type int dword_1002A404; // ref: 0x1000B684 int __stdcall UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, _SNETVERSIONDATA *file_info, int *playerid) { return 0; } /* { int v6; // eax CHAR v8; // [esp+4h] [ebp-110h] char v9; // [esp+5h] [ebp-10Fh] short v10; // [esp+81h] [ebp-93h] char v11; // [esp+83h] [ebp-91h] CHAR v12; // [esp+84h] [ebp-90h] char v13; // [esp+85h] [ebp-8Fh] short v14; // [esp+101h] [ebp-13h] char v15; // [esp+103h] [ebp-11h] int v16; // [esp+104h] [ebp-10h] CHAR *v17; // [esp+108h] [ebp-Ch] CHAR *v18; // [esp+10Ch] [ebp-8h] v12 = byte_10029448; memset(&v13, 0, 0x7Cu); v14 = 0; v15 = 0; v8 = byte_10029448; memset(&v9, 0, 0x7Cu); v10 = 0; v11 = 0; Connect_10004028((int)&v12, 128, (int)&v8, 128); memset(&v16, 0, 0x10u); if ( a3 ) memcpy(&v16, a3, 0x10u); v16 = 16; v17 = &v12; v18 = &v8; if ( SelGame_1000B671() ) return SelIPX_1000C634(a1, a2, (int)&v16, (DWORD *)a4, a5, playerid); v6 = SelGame_1000B67E(); switch ( v6 ) { case 1230002254: return SelIPX_1000C634(a1, a2, (int)&v16, (DWORD *)a4, a5, playerid); case 1297040461: return Modem_10008680(a1, a2, (int)&v16, (DWORD *)a4, a5, playerid); case 1396916812: return DirLink_10005D05(a1, a2, (int)&v16, (DWORD *)a4, a5, playerid); } return SNetSelectGame(a1, a2, &v16, a4, a5, playerid); } */ // 10010490: using guessed type int __stdcall SNetSelectGame(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // ref: 0x1000B795 signed int SelGame_1000B795() { return 0; } /* { signed int result; // eax result = 2139095040; dword_1002A400 = 2139095040; return result; } */ // 1002A400: using guessed type int dword_1002A400; ================================================ FILE: DiabloUI/selhero.cpp ================================================ // ref: 0x1000B7A0 _uiheroinfo *__cdecl SelHero_GetCurrentHeroInfo() { return sgpHeroInfo; } // ref: 0x1000B7A6 int __cdecl SelHero_GetNumHeroesLeft() { return selhero_numheroesleft; } // 1002A428: using guessed type int selhero_numheroesleft; // ref: 0x1000B7AC void __fastcall SelHero_SetHeroDifficulty(int diff) { selhero_difficulty = diff; } // 1002A420: using guessed type int selhero_difficulty; // ref: 0x1000B7B3 char *__cdecl SelHero_GetHeroNameStr() { return selhero_heronamestr; } // ref: 0x1000B7B9 _uiheroinfo *__cdecl SelHero_AllocHeroInfo() { return (_uiheroinfo *)SMemAlloc(0x2Cu, "C:\\Src\\Diablo\\DiabloUI\\SelHero.cpp", 123, 0); } // ref: 0x1000B7CA int __cdecl SelHero_GetHeroIsGood() { return selhero_is_good; } // ref: 0x1000B7D0 int __fastcall SelHero_SetClassStats(int heroclass, _uidefaultstats *pStats) { return selhero_fnstats(heroclass, pStats); } // ref: 0x1000B7DE void __cdecl SelHero_cpp_init() { SelHero_cpp_float = SelHero_cpp_float_value; } // 1001F460: using guessed type int SelHero_cpp_float_value; // 1002A414: using guessed type int SelHero_cpp_float; // ref: 0x1000B899 void __fastcall SelHero_SetStaticBMP(HWND hWnd, int adjust_size) { HWND v3; // esi struct tagRECT Rect; // [esp+8h] [ebp-10h] v3 = GetDlgItem(hWnd, 1040); InvalidateRect(v3, 0, 0); GetClientRect(v3, &Rect); local_AdjustRectSize(&Rect, 0, adjust_size * Rect.bottom); SDlgSetBitmapI(v3, 0, "Static", -1, 1, selhero_buffer, (int)&Rect, selhero_sizedata[0], selhero_sizedata[1], -1); } // ref: 0x1000B905 void __fastcall SelHero_PrintHeroInfo(HWND hWnd, _uiheroinfo *pInfo) { HWND v3; // eax int v4; // eax HWND v5; // eax int v6; // eax HWND v7; // eax int v8; // eax HWND v9; // eax int v10; // eax HWND v11; // eax int v12; // eax HWND v15; // ebp int v16; // eax HWND v17; // ST1C_4 int v18; // eax HWND v19; // ST1C_4 int v20; // eax HWND v21; // ST1C_4 int v22; // eax HWND v23; // ST1C_4 int v24; // eax if (pInfo->level) { selhero_hero_hassaved = pInfo->hassaved; strcpy(selhero_heronamestr, pInfo->name); v15 = GetDlgItem(hWnd, 1014); wsprintfA(selhero_herolevel, "%d", pInfo->level); v16 = GetWindowLongA(v15, -21); local_SetWndLongStr(v16, selhero_herolevel); v17 = GetDlgItem(hWnd, 1018); wsprintfA(selhero_herostr, "%d", pInfo->strength); v18 = GetWindowLongA(v17, -21); local_SetWndLongStr(v18, selhero_herostr); v19 = GetDlgItem(hWnd, 1017); wsprintfA(selhero_heromag, "%d", pInfo->magic); v20 = GetWindowLongA(v19, -21); local_SetWndLongStr(v20, selhero_heromag); v21 = GetDlgItem(hWnd, 1016); wsprintfA(selhero_herodex, "%d", pInfo->dexterity); v22 = GetWindowLongA(v21, -21); local_SetWndLongStr(v22, selhero_herodex); v23 = GetDlgItem(hWnd, 1015); wsprintfA(selhero_herovit, "%d", pInfo->vitality); v24 = GetWindowLongA(v23, -21); local_SetWndLongStr(v24, selhero_herovit); SelHero_SetStaticBMP(hWnd, pInfo->heroclass); Doom_ParseWndProc4(hWnd, selhero_msgtbl_info, AF_SMALLGRAY); } else { selhero_hero_hassaved = 0; selhero_heronamestr[0] = 0; v3 = GetDlgItem(hWnd, 1014); v4 = GetWindowLongA(v3, -21); local_SetWndLongStr(v4, "--"); v5 = GetDlgItem(hWnd, 1018); v6 = GetWindowLongA(v5, -21); local_SetWndLongStr(v6, "--"); v7 = GetDlgItem(hWnd, 1017); v8 = GetWindowLongA(v7, -21); local_SetWndLongStr(v8, "--"); v9 = GetDlgItem(hWnd, 1016); v10 = GetWindowLongA(v9, -21); local_SetWndLongStr(v10, "--"); v11 = GetDlgItem(hWnd, 1015); v12 = GetWindowLongA(v11, -21); local_SetWndLongStr(v12, "--"); SelHero_SetStaticBMP(hWnd, 3); Doom_ParseWndProc4(hWnd, selhero_msgtbl_info, AF_SMALLGRAY); } } // 1002A424: using guessed type int selhero_hero_hassaved; // ref: 0x1000BA7B void __fastcall SelHero_SetStringWithMsg(HWND hWnd, const char *str) { HWND v4; // eax int v5; // eax v4 = GetDlgItem(hWnd, 1038); if (v4) { v5 = GetWindowLongA(v4, -21); local_SetWndLongStr(v5, str); Doom_ParseWndProc4(hWnd, selhero_msgtbl_string, AF_BIGGRAY); } } // ref: 0x1000BAB4 BOOL __fastcall SelHero_IsNameReserved(const char *name) { UINT v1; // esi BOOL result; // eax char SrcStr[128]; // [esp+4h] [ebp-90h] char Buffer[16]; // [esp+84h] [ebp-10h] strcpy(SrcStr, name); _strlwr(SrcStr); v1 = 19; while (1) { LoadStringA(ghUiInst, v1, Buffer, 15); SelHero_SetLastNamePos(Buffer); _strlwr(Buffer); result = (BOOL)strstr(SrcStr, Buffer); if (result) break; if ((signed int)++v1 > 26) return result; } return 1; } // ref: 0x1000BB26 void __fastcall SelHero_SetLastNamePos(char *name) { while (*name) --*name++; } // ref: 0x1000BB34 BOOL __fastcall SelHero_NameHasChar(const char *name, char *illegalchrs) { char v5; // al if (strpbrk(name, ",<>%&\\\"?*#/:") || strpbrk(name, illegalchrs)) return 1; while (1) { v5 = *name; if (!*name) break; if ((unsigned char)v5 < 0x20u || (unsigned char)v5 > 0x7Eu && (unsigned char)v5 < 0xC0u) return 1; ++name; } return 0; } // ref: 0x1000BB75 BOOL __fastcall UiValidPlayerName(const char *name) { BOOL v2; // edi v2 = 1; if (!strlen(name)) v2 = 0; if (selhero_is_good == 1 && (SelHero_IsNameReserved(name) || SelHero_NameHasChar(name, " "))) v2 = 0; return v2; } // ref: 0x1000BBB4 BOOL __stdcall UiSelHeroMultDialog( BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *)), BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *), BOOL(__stdcall *fnstats)(unsigned int, _uidefaultstats *), int *dlgresult, int *hero_is_created, char *name) { int v7; // eax int v8; // eax artfont_LoadAllFonts(); selhero_fninfo = fninfo; selhero_fncreate = fncreate; selhero_fnremove = fnremove; selhero_fnstats = fnstats; sgpHeroInfo = 0; selhero_is_good = 1; selhero_is_created = 0; v7 = (int)SDrawGetFrameWindow(NULL); v8 = SDlgDialogBoxParam(ghUiInst, "SELHERO_DIALOG", v7, SelHero_WndProc, 0); if (dlgresult) *dlgresult = v8; if (name) strcpy(name, selhero_heronamestr); if (hero_is_created) *hero_is_created = selhero_is_created; return 1; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 1002A45C: using guessed type int selhero_is_created; // ref: 0x1000BC46 LRESULT __stdcall SelHero_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v4; // eax int v6; // edx HWND v7; // ecx signed int v8; // [esp-4h] [ebp-8h] if (Msg > 0xBD2) { switch (Msg) { case 0xBD3u: SelHero_DoSelLoad(hWnd); return 0; case 0xBD4u: SelHero_DoSelDiff(hWnd); return 0; case 0xBD5u: v7 = hWnd; if (selhero_is_good != 1) { v8 = 2; goto LABEL_30; } break; case 0xBD6u: strcpy(selhero_heronamestr, heroinfo_create.name); v6 = 1; v7 = hWnd; if (selhero_is_good != 1) { selhero_difficulty = 0; LABEL_31: SelHero_DoHeroEndFade(v7, v6); return 0; } break; case 0xBD7u: SelHero_DoStuffWithStrings(hWnd); return 0; default: return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } v8 = 3; LABEL_30: v6 = v8; goto LABEL_31; } if (Msg == 3026) { SelHero_DoEnterName(hWnd); return 0; } if (Msg == 2) { SelHero_DeleteAndFree(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg <= 0x103) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); if (Msg <= 0x105) { v4 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v4, Msg, wParam, lParam); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } switch (Msg) { case 0x110u: SelHero_LoadHeroGFX(hWnd); PostMessageA(hWnd, 0x7E8u, 0, 0); return 0; case 0x7E8u: if (!Fade_CheckRange5()) Fade_SetFadeTimer((int)hWnd); return 0; case 0xBD0u: SelHero_DoHeroSelList(hWnd); return 0; } if (Msg != 3025) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); SelHero_DoHeroSelClass(hWnd); return 0; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 1002A420: using guessed type int selhero_difficulty; // ref: 0x1000BDAD void __fastcall SelHero_DoStuffWithStrings(HWND hWnd) { _uiheroinfo *v1; // eax char dialogstr[80]; // [esp+Ch] [ebp-B4h] char string64[64]; // [esp+5Ch] [ebp-64h] char Buffer[32]; // [esp+9Ch] [ebp-24h] if (SelHero_GetHeroIsGood() == 1) LoadStringA(ghUiInst, 0x23u, Buffer, 31); else LoadStringA(ghUiInst, 0x22u, Buffer, 31); LoadStringA(ghUiInst, 7u, string64, 63); wsprintfA(dialogstr, string64, selhero_heronamestr); if (SelYesNo_YesNoDialog(hWnd, dialogstr, Buffer, 1) != 2) { v1 = SelHero_GetHeroSlotFromName(sgpHeroInfo, selhero_heronamestr); if (v1) { if (selhero_fnremove(v1)) { sgpHeroInfo = SelHero_GetNextHeroFromStr(sgpHeroInfo, selhero_heronamestr); --selhero_numheroesleft; LoadStringA(ghUiInst, 0x1Eu, string64, 15); if (!strcmp(string64, sgpHeroInfo->name)) { PostMessageA(hWnd, 0xBD1u, 0, 0); return; } SelHero_PrintHeroInfo(hWnd, sgpHeroInfo); } else { LoadStringA(ghUiInst, 0x11u, string64, 63); SelYesNo_SelOkDialog(hWnd, string64, Buffer, 1); } } } PostMessageA(hWnd, 0xBD0u, 0, 0); } // 1002A428: using guessed type int selhero_numheroesleft; // ref: 0x1000BEDB _uiheroinfo *__fastcall SelHero_GetNextHeroFromStr(_uiheroinfo *pInfo, char *name) { _uiheroinfo *v2; // ebx _uiheroinfo *v3; // ebp _uiheroinfo *v4; // edi v2 = pInfo; v3 = 0; v4 = 0; if (pInfo) { while (!v4) { if (!strcmp(pInfo->name, name)) { v4 = pInfo; } else { v3 = pInfo; pInfo = pInfo->next; } if (!pInfo) { if (!v4) return v2; break; } } if (v3) v3->next = v4->next; else v2 = v4->next; SelHero_FreeSomeMemory(v4); } return v2; } // ref: 0x1000BF33 void __fastcall SelHero_FreeSomeMemory(void *ptr) { if (ptr) SMemFree(ptr, "C:\\Src\\Diablo\\DiabloUI\\SelHero.cpp", 131, 0); } // ref: 0x1000BF4A _uiheroinfo *__fastcall SelHero_GetHeroSlotFromName(_uiheroinfo *pInfo, const char *name) { _uiheroinfo *i; // esi for (i = pInfo; i && _strcmpi(i->name, name); i = i->next) ; return i; } // ref: 0x1000BF6D void __fastcall SelHero_DoHeroSelList(HWND hWnd) { BOOL v2; // eax int v3; // edx v2 = SDlgDialogBoxParam(ghUiInst, "SELLIST_DIALOG", (int)hWnd, SelList_WndProc, 0); if (v2 == 1) { if (!strlen(selhero_heronamestr)) { PostMessageA(hWnd, 0xBD1u, 0, 0); return; } if (selhero_is_good == 1) { PostMessageA(hWnd, 0xBD5u, 0, 0); return; } if (selhero_hero_hassaved) { PostMessageA(hWnd, 0xBD3u, 0, 0); return; } selhero_difficulty = 0; v3 = 1; LABEL_13: SelHero_DoHeroEndFade(hWnd, v3); return; } if (v2 != 1006) { v3 = 4; goto LABEL_13; } PostMessageA(hWnd, 0xBD7u, 0, 0); } // 1002A420: using guessed type int selhero_difficulty; // 1002A424: using guessed type int selhero_hero_hassaved; // ref: 0x1000BFF9 void __fastcall SelHero_DoHeroSelClass(HWND hWnd) { BOOL v2; // eax int v3; // eax char Buffer[32]; // [esp+8h] [ebp-20h] v2 = SDlgDialogBoxParam(ghUiInst, "SELCLASS_DIALOG", (int)hWnd, SelClass_WndProc, 0); if (v2 == -1 || v2 == 2) { LoadStringA(ghUiInst, 0x1Eu, Buffer, 31); if (!strcmp(Buffer, sgpHeroInfo->name)) SelHero_DoHeroEndFade(hWnd, 4); else PostMessageA(hWnd, 0xBD0u, 0, 0); } else { v3 = v2 - 1063; if (v3) { if (v3 == 1) heroinfo_create.heroclass = 2; else heroinfo_create.heroclass = 0; } else { heroinfo_create.heroclass = 1; } PostMessageA(hWnd, 0xBD2u, 0, 0); } } // ref: 0x1000C09B void __fastcall SelHero_DoEnterName(HWND hWnd) { char namestr[16]; // [esp+8h] [ebp-10h] if (SDlgDialogBoxParam(ghUiInst, "ENTERNAME_DIALOG", (int)hWnd, EntName_WndProc, (int)namestr) == 1) { namestr[15] = 0; if (SelHero_CreateHero(hWnd, namestr)) PostMessageA(hWnd, 0xBD6u, 0, 0); else PostMessageA(hWnd, 0xBD2u, 0, 0); } else { PostMessageA(hWnd, 0xBD1u, 0, 0); } } // ref: 0x1000C0F9 BOOL __fastcall SelHero_CreateHero(HWND hWnd, char *name) { _uiheroinfo *v2; // edi char dialogstr[144]; // [esp+Ch] [ebp-138h] char v5[128]; // [esp+9Ch] [ebp-A8h] char Buffer[32]; // [esp+11Ch] [ebp-28h] if (SelHero_GetHeroIsGood() == 1) LoadStringA(ghUiInst, 0x20u, Buffer, 31); else LoadStringA(ghUiInst, 0x1Fu, Buffer, 31); if (!UiValidPlayerName(name)) { LoadStringA(ghUiInst, 0xFu, v5, 127); SelYesNo_SelOkDialog(hWnd, v5, Buffer, 1); return 0; } v2 = SelHero_GetHeroSlotFromName(sgpHeroInfo, name); if (v2) { LoadStringA(ghUiInst, 8u, v5, 127); wsprintfA(dialogstr, v5, v2->name); if (SelYesNo_YesNoDialog(hWnd, dialogstr, Buffer, 1) == 2) return 0; } strcpy(heroinfo_create.name, name); heroinfo_create.hassaved = 0; if (!selhero_fncreate(&heroinfo_create)) { LoadStringA(ghUiInst, 0x10u, v5, 127); OkCancel_DoOkDialog(hWnd, v5, 1); return 0; } selhero_is_created = 1; return 1; } // 1002A45C: using guessed type int selhero_is_created; // ref: 0x1000C21A void __fastcall SelHero_DoSelLoad(HWND hWnd) { BOOL v2; // eax v2 = SDlgDialogBoxParam(ghUiInst, "SELLOAD_DIALOG", (int)hWnd, SelLoad_WndProc, 0); if (v2 == -1 || v2 == 2) { PostMessageA(hWnd, 0xBD0u, 0, 0); } else if (v2 == 1106) { PostMessageA(hWnd, 0xBD5u, 0, 0); } else { PostMessageA(hWnd, 0xBD4u, 0, 0); } } // ref: 0x1000C269 void __fastcall SelHero_DoSelDiff(HWND hWnd) { _uiheroinfo *v3; // eax int v4; // eax char Buffer[256]; // [esp+4h] [ebp-208h] char v6[128]; // [esp+104h] [ebp-108h] char v7[128]; // [esp+184h] [ebp-88h] _gamedata gameData; // [esp+204h] [ebp-8h] if (!SelHero_GetHeroIsGood()) { SelHero_SetHeroDifficulty(0); LABEL_3: SelHero_DoHeroEndFade(hWnd, 1); return; } CreaDung_SetDelSpin(1); if (SDlgDialogBoxParam(ghUiInst, "SELDIFF_DIALOG", (int)hWnd, CreaDung_WndProc, selhero_is_good) == 1) { v3 = SelHero_GetHeroSlotFromName(sgpHeroInfo, selhero_heronamestr); UiCreatePlayerDescription(v3, 'DBLO', v7); gameData.bDiff = selhero_difficulty; Connect_SetDiffString(&gameData, selhero_heronamestr, v7, v6, 128); v4 = UiAuthCallback(2, selhero_heronamestr, v7, 0, v6, Buffer, 256); if (v4) goto LABEL_3; SelYesNo_SelOkDialog(hWnd, Buffer, 0, 1); PostMessageA(hWnd, 0xBD4u, 0, 0); } else { PostMessageA(hWnd, 0xBD3u, 0, 0); } } // 1002A420: using guessed type int selhero_difficulty; // ref: 0x1000C364 void __fastcall SelHero_DeleteAndFree(HWND hWnd) { void **v2; // eax Doom_DeleteFreeProcs(hWnd, selhero_msgtbl_info); Doom_DeleteFreeProcs(hWnd, selhero_msgtbl_3); Doom_DeleteFreeProcs(hWnd, selhero_msgtbl_string); Title_KillTitleTimer(hWnd); SelHero_FreeAllHeroes(sgpHeroInfo); if (selhero_buffer) { SMemFree(selhero_buffer, "C:\\Src\\Diablo\\DiabloUI\\SelHero.cpp", 744, 0); selhero_buffer = 0; } v2 = (void **)GetWindowLongA(hWnd, -21); local_FreeMemPtr(v2); } // ref: 0x1000C3CE void __fastcall SelHero_FreeAllHeroes(_uiheroinfo *pInfo) { _uiheroinfo *v1; // esi if (pInfo) { do { v1 = pInfo->next; SelHero_FreeSomeMemory(pInfo); pInfo = v1; } while (v1); } } // ref: 0x1000C3E2 void __fastcall SelHero_DoHeroEndFade(HWND hWnd, int a2) { void *v2; // edi v2 = (void *)a2; Fade_Range5SetZero(); Fade_UpdatePaletteRange(10); SDlgEndDialog(hWnd, v2); } // ref: 0x1000C3FF void __fastcall SelHero_LoadHeroGFX(HWND hWnd) { HWND v1; // eax int v2; // eax HWND v3; // eax int v4; // eax HWND v5; // eax int v6; // eax HWND v7; // eax int v8; // eax HWND v9; // eax int v10; // eax DWORD *v12; // eax MAPDST SelHero_SelectHeroRegion(hWnd); v12 = local_AllocWndLongData(); if (v12) { SetWindowLongA(hWnd, -21, (LONG)v12); local_LoadArtWithPal(hWnd, 0, &nullcharacter, -1, 1, "ui_art\\selhero.pcx", (BYTE **)v12, v12 + 1, 0); Fade_NoInputAndArt(hWnd, 1); } local_LoadArtImage("ui_art\\heros.pcx", &selhero_buffer, selhero_sizedata); SetActiveWindow(hWnd); Title_LoadImgSetTimer(hWnd, "ui_art\\smlogo.pcx"); Doom_ParseWndProc3(hWnd, selhero_msgtbl_string, AF_BIGGRAY); Doom_ParseWndProc3(hWnd, selhero_msgtbl_3, AF_SMALLGRAY); Doom_ParseWndProc3(hWnd, selhero_msgtbl_info, AF_SMALLGRAY); selhero_hero_hassaved = 0; selhero_heronamestr[0] = 0; v1 = GetDlgItem(hWnd, 1014); v2 = GetWindowLongA(v1, -21); local_SetWndLongStr(v2, "--"); v3 = GetDlgItem(hWnd, 1018); v4 = GetWindowLongA(v3, -21); local_SetWndLongStr(v4, "--"); v5 = GetDlgItem(hWnd, 1017); v6 = GetWindowLongA(v5, -21); local_SetWndLongStr(v6, "--"); v7 = GetDlgItem(hWnd, 1016); v8 = GetWindowLongA(v7, -21); local_SetWndLongStr(v8, "--"); v9 = GetDlgItem(hWnd, 1015); v10 = GetWindowLongA(v9, -21); local_SetWndLongStr(v10, "--"); SelHero_SetStaticBMP(hWnd, 3); Doom_ParseWndProc4(hWnd, selhero_msgtbl_info, AF_SMALLGRAY); } // 1002A424: using guessed type int selhero_hero_hassaved; // ref: 0x1000C49F void __fastcall SelHero_SelectHeroRegion(HWND hWnd) { _uiheroinfo *v2; // esi _uiheroinfo *v3; // [esp+10h] [ebp-44h] char Buffer[64]; // [esp+14h] [ebp-40h] v2 = SelHero_AllocHeroInfo(); v2->next = 0; LoadStringA(ghUiInst, 0x1Eu, v2->name, 15); v2->level = 0; sgpHeroInfo = SelRegn_SetNextHero(sgpHeroInfo, v2); v3 = sgpHeroInfo; selhero_numheroesleft = 1; if (!selhero_fninfo(SelHero_GetHeroInfo)) { LoadStringA(ghUiInst, 0x12u, Buffer, 64); OkCancel_DoOkDialog(hWnd, Buffer, 1); } if (v3 == sgpHeroInfo) PostMessageA(hWnd, 0xBD1u, 0, 0); else PostMessageA(hWnd, 0xBD0u, 0, 0); } // 1002A428: using guessed type int selhero_numheroesleft; // ref: 0x1000C541 BOOL __stdcall SelHero_GetHeroInfo(_uiheroinfo *pInfo) { _uiheroinfo *v1; // esi _uiheroinfo *v2; // eax v1 = SelHero_AllocHeroInfo(); memcpy(v1, pInfo, 0x2Cu); v1->next = 0; v2 = SelRegn_SetNextHero(sgpHeroInfo, v1); ++selhero_numheroesleft; sgpHeroInfo = v2; return 1; } // 1002A428: using guessed type int selhero_numheroesleft; // ref: 0x1000C57A BOOL __stdcall UiSelHeroSingDialog( BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *)), BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *), BOOL(__stdcall *fnstats)(unsigned int, _uidefaultstats *), int *dlgresult, char *name, int *difficulty) { int v7; // eax int v8; // edi artfont_LoadAllFonts(); selhero_fninfo = fninfo; selhero_fncreate = fncreate; selhero_fnremove = fnremove; selhero_fnstats = fnstats; sgpHeroInfo = 0; selhero_is_good = 0; v7 = (int)SDrawGetFrameWindow(NULL); v8 = SDlgDialogBoxParam(ghUiInst, "SELHERO_DIALOG", v7, SelHero_WndProc, 0); if (dlgresult) *dlgresult = v8; if (name) strcpy(name, selhero_heronamestr); if (difficulty) *difficulty = selhero_difficulty; if (v8 != 4) artfont_FreeAllFonts(); return 1; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 1002A420: using guessed type int selhero_difficulty; ================================================ FILE: DiabloUI/selipx.cpp ================================================ // ref: 0x1000C610 void *SelIPX_1000C610() { return 0; } /* { return SMemAlloc(268, "C:\\Src\\Diablo\\DiabloUI\\SelIPX.cpp", 105, 0); } */ // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000C629 signed int SelIPX_1000C629() { return 0; } /* { signed int result; // eax result = 2139095040; dword_1002A4A4 = 2139095040; return result; } */ // 1002A4A4: using guessed type int dword_1002A4A4; // ref: 0x1000C634 BOOL __fastcall SelIPX_1000C634(int a1, int a2, int a3, DWORD *a4, int a5, int playerid) { return 0; } /* { int v6; // esi dword_1002A49C = a3; dword_1002A4AC = a2; dword_1002A4BC = a5; dword_1002A4A0 = a4; gnIpxPlayerid = playerid; artfont_10001159(); v6 = SDlgDialogBoxParam(hInstance, "SELIPXGAME_DIALOG", a4[2], SelIPX_1000C692, 0); artfont_100010C8(); return v6 == 1; } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // 1002A49C: using guessed type int dword_1002A49C; // 1002A4A8: using guessed type int gnIpxPlayerid; // 1002A4AC: using guessed type int dword_1002A4AC; // 1002A4BC: using guessed type int dword_1002A4BC; // ref: 0x1000C692 int __stdcall SelIPX_1000C692(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { HWND v4; // eax HWND v6; // eax int v7; // [esp+0h] [ebp-Ch] int savedregs; // [esp+Ch] [ebp+0h] if ( Msg > 0x113 ) { switch ( Msg ) { case 0x201u: goto LABEL_35; case 0x202u: v6 = GetDlgItem(hWnd, 1105); if ( !Sbar_100099C0(v6) ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); goto LABEL_12; case 0x203u: LABEL_35: SelIPX_1000D696(hWnd, (unsigned short)lParam, (unsigned int)lParam >> 16); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg != 2024 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); if ( !Fade_1000739F() ) Fade_100073FD(hWnd, v7); return 0; } if ( Msg == 275 ) { if ( wParam == 3 ) SelIPX_1000C9DA(hWnd); return 0; } if ( Msg == 2 ) { SelIPX_1000CC41(hWnd); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg <= 0x103 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); if ( Msg <= 0x105 ) { v4 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v4, Msg, wParam, lParam); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg == 272 ) { SelIPX_1000CD4A(hWnd); PostMessageA(hWnd, 0x7E8u, 0, 0); return 0; } if ( Msg == 273 ) { if ( HIWORD(wParam) == 7 ) { Focus_100075B7(hWnd, (HWND)lParam); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( HIWORD(wParam) != 6 ) { if ( wParam == 327681 ) { SelIPX_1000D3C5(hWnd, (int)&savedregs); } else if ( (WORD)wParam == 2 ) { SelIPX_1000D3A0((int)hWnd, 2); } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } Focus_10007458((void *)lParam); Focus_100075DC(hWnd, (HWND)lParam); SelIPX_1000C818(hWnd, (unsigned short)wParam); LABEL_12: SelIPX_1000C982(hWnd); } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } */ // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x1000C818 LONG __fastcall SelIPX_1000C818(HWND hDlg, int nIDDlgItem) { return 0; } /* { HWND v2; // ebx HWND v3; // edi LONG result; // eax const char *v5; // edi int v6; // eax CHAR *v7; // edx CHAR v8; // [esp+Ch] [ebp-280h] CHAR v9; // [esp+10Ch] [ebp-180h] char v10; // [esp+18Ch] [ebp-100h] CHAR Buffer; // [esp+20Ch] [ebp-80h] CHAR v12; // [esp+22Ch] [ebp-60h] char v13; // [esp+24Ch] [ebp-40h] unsigned short v14; // [esp+260h] [ebp-2Ch] unsigned char v15; // [esp+262h] [ebp-2Ah] char v16; // [esp+278h] [ebp-14h] unsigned char v17; // [esp+27Ch] [ebp-10h] int v18; // [esp+280h] [ebp-Ch] int v19; // [esp+284h] [ebp-8h] HWND hWnd; // [esp+288h] [ebp-4h] v2 = hDlg; v3 = GetDlgItem(hDlg, nIDDlgItem); hWnd = GetDlgItem(v2, 1098); result = GetWindowLongA(v3, -21); if ( result ) { result = *(DWORD *)(result + 12); if ( result ) { v5 = (const char *)(result + 140); if ( *(DWORD *)(result + 4) ) { if ( result == -140 || strlen((const char *)(result + 140)) < 0x10 ) { v6 = GetWindowLongA(hWnd, -21); v7 = (CHAR *)&byte_10029448; } else { v19 = (int)&byte_10029448; v18 = (int)&byte_10029448; strcpy(&v10, v5); if ( Connect_10003DAF(&v10, (int)&v16, (int)&v19, (int)&v18) && Connect_10003E61((const char *)v18, &v13) ) { LoadStringA(hInstance, v17 + 1003, &Buffer, 31); LoadStringA(hInstance, v15 + 4, &v12, 31); LoadStringA(hInstance, 0x31u, &v9, 127); wsprintfA(&v8, &v9, &Buffer, v19, v14, &v12); v6 = GetWindowLongA(hWnd, -21); v7 = &v8; } else { v6 = GetWindowLongA(hWnd, -21); v7 = 0; } } } else { v6 = GetWindowLongA(hWnd, -21); v7 = (CHAR *)v5; } local_10007FA4(v6, v7); result = Doom_10006A13(v2, (int *)&unk_10023104, 1); } } return result; } */ // ref: 0x1000C982 HWND UNKCALL SelIPX_1000C982(HWND hDlg) { return 0; } /* { HWND v1; // esi int v2; // eax v1 = hDlg; v2 = SelIPX_1000C99F(); return Sbar_10009A99(v1, 1105, dword_1002A4B8, v2); } */ // ref: 0x1000C99F int SelIPX_1000C99F() { return 0; } /* { HWND v0; // eax LONG v1; // eax DWORD *v2; // ecx DWORD *v3; // eax int v5; // edx v0 = GetFocus(); if ( !v0 ) return 0; v1 = GetWindowLongA(v0, -21); if ( !v1 ) return 0; v2 = (DWORD *)dword_1002A4B4; if ( !dword_1002A4B4 ) return 0; v3 = *(DWORD **)(v1 + 12); if ( !v3 ) return 0; v5 = 0; do { if ( v2 == v3 ) break; v2 = (DWORD *)*v2; ++v5; } while ( v2 ); return v5; } */ // 1002A4B4: using guessed type int dword_1002A4B4; // ref: 0x1000C9DA const char *UNKCALL SelIPX_1000C9DA(HWND hDlg) { return 0; } /* { HWND v1; // esi const char *result; // eax int v3; // ST0C_4 HWND v4; // eax HWND v5; // eax int v6; // eax v1 = hDlg; dword_1002A4B0 = 0; SelIPX_1000CA64((DWORD *)dword_1002A4B4); SNetEnumGames(0, 0, SelIPX_1000CAD5, 0); result = (const char *)SelIPX_1000CA71((DWORD *)dword_1002A4B4); dword_1002A4B4 = (int)result; if ( dword_1002A4B0 ) { SelIPX_1000CB83(v1, result); v3 = dword_1002A4B8 > 6; v4 = GetDlgItem(v1, 1105); ShowWindow(v4, v3); v5 = GetFocus(); v6 = GetWindowLongA(v5, -12); SelIPX_1000C818(v1, v6); result = (const char *)SelIPX_1000C982(v1); } return result; } */ // 10010436: using guessed type int __stdcall SNetEnumGames(DWORD, DWORD, DWORD, DWORD); // 1002A4B0: using guessed type int dword_1002A4B0; // 1002A4B4: using guessed type int dword_1002A4B4; // ref: 0x1000CA64 void __fastcall SelIPX_1000CA64(DWORD *a1) { return; } /* { while ( a1 ) { a1[2] = 0; a1 = (DWORD *)*a1; } } */ // ref: 0x1000CA71 DWORD **__fastcall SelIPX_1000CA71(DWORD *a1) { return 0; } /* { DWORD **v1; // edi DWORD *v2; // esi v1 = (DWORD **)a1; v2 = 0; while ( a1 ) { if ( a1[2] || !a1[1] ) { v2 = a1; a1 = (DWORD *)*a1; } else { if ( v2 ) *v2 = *a1; else v1 = (DWORD **)*a1; SelIPX_1000CAC1(a1); --dword_1002A4B8; dword_1002A4B0 = 1; if ( v2 ) a1 = (DWORD *)*v2; else a1 = *v1; } } return v1; } */ // 1002A4B0: using guessed type int dword_1002A4B0; // ref: 0x1000CAC1 int UNKCALL SelIPX_1000CAC1(void *arg) { return 0; } /* { int result; // eax if ( arg ) result = SMemFree(arg, "C:\\Src\\Diablo\\DiabloUI\\SelIPX.cpp", 110, 0); return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000CAD5 void *__stdcall SelIPX_1000CAD5(int a1, char *a2, char *a3) { return 0; } /* { DWORD *v3; // eax int result; // eax int v5; // esi DWORD *v6; // eax v3 = SelIPX_1000CB73((DWORD *)dword_1002A4B4, a1); if ( v3 ) { v3[2] = 1; } else { result = SelIPX_1000C610(); v5 = result; if ( !result ) return result; *(DWORD *)result = 0; *(DWORD *)(result + 4) = a1; *(DWORD *)(result + 8) = 1; strcpy((char *)(result + 12), a2); strcpy((char *)(v5 + 140), a3); v6 = SelIPX_1000CB50((DWORD *)dword_1002A4B4, (DWORD *)v5); ++dword_1002A4B8; dword_1002A4B4 = (int)v6; dword_1002A4B0 = 1; } return 1; } */ // 1002A4B0: using guessed type int dword_1002A4B0; // 1002A4B4: using guessed type int dword_1002A4B4; // ref: 0x1000CB50 DWORD *__fastcall SelIPX_1000CB50(DWORD *a1, DWORD *a2) { return 0; } /* { DWORD *result; // eax DWORD *v3; // edi DWORD *i; // esi result = a1; v3 = 0; for ( i = a1; i; i = (DWORD *)*i ) v3 = i; *a2 = i; if ( !v3 ) return a2; *v3 = a2; return result; } */ // ref: 0x1000CB73 DWORD *__fastcall SelIPX_1000CB73(DWORD *a1, int a2) { return 0; } /* { DWORD *result; // eax for ( result = a1; result && result[1] != a2; result = (DWORD *)*result ) ; return result; } */ // ref: 0x1000CB83 int __fastcall SelIPX_1000CB83(HWND a1, const char *a2) { return 0; } /* { int *v2; // ebp HWND v3; // eax HWND v4; // esi int v5; // eax int v6; // eax const char *v8; // [esp+4h] [ebp-8h] HWND hDlg; // [esp+8h] [ebp-4h] v8 = a2; hDlg = a1; v2 = &dword_10023118; if ( dword_10023118 ) { do { v3 = GetDlgItem(hDlg, *v2); v4 = v3; if ( v3 ) { if ( v8 ) { EnableWindow(v3, 1); v6 = GetWindowLongA(v4, -21); if ( v6 ) { *(DWORD *)(v6 + 12) = v8; local_10007FA4(v6, v8 + 12); } v8 = *(const char **)v8; } else { if ( v3 == GetFocus() ) SelIPX_1000CCD9(v4); EnableWindow(v4, 0); v5 = GetWindowLongA(v4, -21); if ( v5 ) { *(DWORD *)(v5 + 12) = 0; local_10007FA4(v5, &byte_10029448); } } } ++v2; } while ( *v2 ); } return Doom_1000680A(hDlg, &dword_10023118, 2, 1); } */ // 10023118: using guessed type int dword_10023118; // ref: 0x1000CC41 int UNKCALL SelIPX_1000CC41(HWND hDlg) { return 0; } /* { HWND v1; // esi DWORD *v2; // eax v1 = hDlg; SelIPX_1000CCC5((DWORD *)dword_1002A4B4); dword_1002A4B4 = 0; Sbar_10009CD2(v1, 1105); Doom_10006C53(v1, &dword_10023118); Doom_10006C53(v1, (int *)&unk_1002310C); Doom_10006C53(v1, (int *)&unk_10023104); Doom_10006C53(v1, (int *)&unk_100230FC); Doom_10006C53(v1, (int *)&unk_100230F0); v2 = (DWORD *)GetWindowLongA(v1, -21); local_10007F72(v2); Title_100100E7(v1); Focus_10007818(v1); return SDrawClearSurface(); } */ // 1001043C: using guessed type DWORD __stdcall SDrawClearSurface(); // 10023118: using guessed type int dword_10023118; // 1002A4B4: using guessed type int dword_1002A4B4; // ref: 0x1000CCC5 int __fastcall SelIPX_1000CCC5(DWORD *a1) { return 0; } /* { DWORD *v1; // esi int result; // eax if ( a1 ) { do { v1 = (DWORD *)*a1; result = SelIPX_1000CAC1(a1); a1 = v1; } while ( v1 ); } return result; } */ // ref: 0x1000CCD9 HWND UNKCALL SelIPX_1000CCD9(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND v2; // ebx int nIDDlgItem[1085]; // [esp+0h] [ebp-1118h] int v5; // [esp+10F4h] [ebp-24h] int v6; // [esp+1100h] [ebp-18h] int v7; // [esp+1104h] [ebp-14h] int v8; // [esp+1108h] [ebp-10h] int v9; // [esp+110Ch] [ebp-Ch] int v10; // [esp+1110h] [ebp-8h] int v11; // [esp+1114h] [ebp-4h] v1 = hWnd; v6 = 1093; v7 = 1088; v8 = 1089; v9 = 1090; v10 = 1091; v11 = 1092; v2 = GetParent(hWnd); do { v5 = nIDDlgItem[GetWindowLongA(v1, -12)]; v1 = GetDlgItem(v2, v5); } while ( !IsWindowEnabled(v1) ); return SetFocus(v1); } */ // 1000CCD9: using guessed type int nIDDlgItem[1085]; // ref: 0x1000CD4A HWND UNKCALL SelIPX_1000CD4A(HWND hWnd) { return 0; } /* { HWND v1; // esi HWND v2; // ST1C_4 int v3; // eax int *v4; // edi HWND v5; // ebp int v6; // eax HWND result; // eax HWND v8; // eax HWND v9; // [esp+0h] [ebp-4Ch] CHAR Buffer; // [esp+Ch] [ebp-40h] v1 = hWnd; SelIPX_1000CEE6(hWnd); Focus_100077E9((int)v1, "ui_art\\focus16.pcx", v9); Title_1001009E(v1, (int)"ui_art\\smlogo.pcx", v2); v3 = local_10007F46(); v4 = (int *)v3; if ( v3 ) { SetWindowLongA(v1, -21, v3); local_10007944((int)v1, 0, &byte_10029448, -1, 1, (int)"ui_art\\selgame.pcx", v4, v4 + 1, 0); Fade_100073C5(v1, 1); } if ( SelGame_1000B67E() != 1230002254 ) { v5 = GetDlgItem(v1, 1038); LoadStringA(hInstance, 0x4Du, &Buffer, 63); SetWindowTextA(v5, &Buffer); } Doom_100068AB(v1, (int *)&unk_100230F0, 5); Doom_100068AB(v1, (int *)&unk_100230FC, 3); Doom_100068AB(v1, (int *)&unk_10023104, 1); Doom_1000658C(v1, (int *)&unk_1002310C, 4, 0); Doom_1000658C(v1, &dword_10023118, 2, 1); dword_1002A4B8 = 0; v6 = SelIPX_1000C610(); dword_1002A4B4 = v6; if ( v6 ) { ++dword_1002A4B8; *(DWORD *)(v6 + 4) = 0; *(BYTE *)(dword_1002A4B4 + 140) = 0; *(DWORD *)dword_1002A4B4 = 0; LoadStringA(hInstance, 0x24u, (LPSTR)(dword_1002A4B4 + 12), 127); LoadStringA(hInstance, 0x2Au, (LPSTR)(dword_1002A4B4 + 140), 127); } SNetEnumGames(0, 0, SelIPX_1000CAD5, 0); SelIPX_1000CB83(v1, (const char *)dword_1002A4B4); SDlgSetTimer(v1, 3, 1000, 0); result = Sbar_10009BF1(v1, 1105); if ( dword_1002A4B8 <= 6 ) { v8 = GetDlgItem(v1, 1105); result = (HWND)ShowWindow(v8, 0); } return result; } */ // 10010412: using guessed type int __stdcall SDlgSetTimer(DWORD, DWORD, DWORD, DWORD); // 10010436: using guessed type int __stdcall SNetEnumGames(DWORD, DWORD, DWORD, DWORD); // 10023118: using guessed type int dword_10023118; // 1002A4B4: using guessed type int dword_1002A4B4; // ref: 0x1000CEE6 void UNKCALL SelIPX_1000CEE6(HWND hDlg) { return; } /* { HWND v1; // ebx int *v2; // edi HWND v3; // eax HWND v4; // esi void *v5; // eax v1 = hDlg; v2 = &dword_10023118; if ( dword_10023118 ) { do { v3 = GetDlgItem(v1, *v2); v4 = v3; if ( v3 ) { v5 = (void *)GetWindowLongA(v3, -4); SetPropA(v4, "UIOLDPROC", v5); SetWindowLongA(v4, -4, (LONG)SelIPX_1000CF38); } ++v2; } while ( *v2 ); } } */ // 10023118: using guessed type int dword_10023118; // ref: 0x1000CF38 LRESULT __stdcall SelIPX_1000CF38(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { LRESULT (__stdcall *v4)(HWND, UINT, WPARAM, LPARAM); // edi HWND v5; // eax UINT v7; // [esp-Ch] [ebp-18h] WPARAM v8; // [esp-8h] [ebp-14h] LPARAM v9; // [esp-4h] [ebp-10h] v4 = (LRESULT (__stdcall *)(HWND, UINT, WPARAM, LPARAM))GetPropA(hWnd, "UIOLDPROC"); switch ( Msg ) { case 2u: RemovePropA(hWnd, "UIOLDPROC"); if ( !v4 ) return DefWindowProcA(hWnd, Msg, wParam, lParam); SetWindowLongA(hWnd, -4, (LONG)v4); break; case 0xFu: local_10007C95(hWnd); return 0; case 0x87u: return 4; case 0x100u: if ( wParam > 0x21 ) { if ( wParam == 34 ) { SelIPX_1000D0E1(hWnd); return 0; } if ( wParam > 0x24 ) { if ( wParam <= 0x26 ) { SelIPX_1000D31C(hWnd); return 0; } if ( wParam <= 0x28 ) { SelIPX_1000D284(hWnd); return 0; } if ( wParam == 46 ) { v9 = lParam; v8 = 46; v7 = 256; goto LABEL_24; } } } else { switch ( wParam ) { case 0x21u: SelIPX_1000D1D4(hWnd); break; case 9u: if ( GetKeyState(16) >= 0 ) SelIPX_1000D070(hWnd); else SelIPX_1000CCD9(hWnd); return 0; case 0xDu: goto LABEL_38; case 0x1Bu: v9 = 0; v8 = 2; goto LABEL_12; case 0x20u: LABEL_38: v9 = 0; v8 = 1; LABEL_12: v7 = 273; LABEL_24: v5 = GetParent(hWnd); SendMessageA(v5, v7, v8, v9); return 0; } } return 0; } if ( v4 ) return CallWindowProcA(v4, hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam); } */ // ref: 0x1000D070 HWND UNKCALL SelIPX_1000D070(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND v2; // ebx int nIDDlgItem[1085]; // [esp+0h] [ebp-1118h] int v5; // [esp+10F4h] [ebp-24h] int v6; // [esp+1100h] [ebp-18h] int v7; // [esp+1104h] [ebp-14h] int v8; // [esp+1108h] [ebp-10h] int v9; // [esp+110Ch] [ebp-Ch] int v10; // [esp+1110h] [ebp-8h] int v11; // [esp+1114h] [ebp-4h] v1 = hWnd; v6 = 1089; v7 = 1090; v8 = 1091; v9 = 1092; v10 = 1093; v11 = 1088; v2 = GetParent(hWnd); do { v5 = nIDDlgItem[GetWindowLongA(v1, -12)]; v1 = GetDlgItem(v2, v5); } while ( !IsWindowEnabled(v1) ); return SetFocus(v1); } */ // 1000D070: using guessed type int nIDDlgItem[1085]; // ref: 0x1000D0E1 HWND UNKCALL SelIPX_1000D0E1(HWND hWnd) { return 0; } /* { HWND v1; // ebp HWND result; // eax HWND v3; // esi HWND v4; // ebx HWND v5; // eax DWORD *v6; // eax int v7; // eax const char *v8; // ebx int v9; // eax v1 = hWnd; result = GetParent(hWnd); v3 = result; if ( result ) { result = GetDlgItem(result, 1088); v4 = result; if ( result ) { v5 = GetDlgItem(v3, 1093); result = (HWND)GetWindowLongA(v5, -21); if ( result ) { v6 = (DWORD *)*((DWORD *)result + 3); if ( v6 && *v6 ) { v7 = SelIPX_1000D18C(v4) + 6; if ( v7 > dword_1002A4B8 - 6 ) v7 = dword_1002A4B8 - 6; result = (HWND)SelIPX_1000D1C1(v7); v8 = (const char *)result; if ( result ) { TitleSnd_10010315(); SelIPX_1000CB83(v3, v8); v9 = GetWindowLongA(v1, -12); SelIPX_1000C818(v3, v9); result = SelIPX_1000C982(v3); } } else { result = SelIPX_1000CCD9(v4); } } } } return result; } */ // ref: 0x1000D18C int UNKCALL SelIPX_1000D18C(HWND hWnd) { return 0; } /* { LONG v1; // eax DWORD *v2; // ecx DWORD *v3; // eax int v5; // edx if ( !hWnd ) return 0; v1 = GetWindowLongA(hWnd, -21); if ( !v1 ) return 0; v2 = (DWORD *)dword_1002A4B4; if ( !dword_1002A4B4 ) return 0; v3 = *(DWORD **)(v1 + 12); if ( !v3 ) return 0; v5 = 0; do { if ( v2 == v3 ) break; v2 = (DWORD *)*v2; ++v5; } while ( v2 ); return v5; } */ // 1002A4B4: using guessed type int dword_1002A4B4; // ref: 0x1000D1C1 DWORD *__fastcall SelIPX_1000D1C1(int a1) { return 0; } /* { DWORD *result; // eax result = (DWORD *)dword_1002A4B4; while ( result && a1 ) { result = (DWORD *)*result; --a1; } return result; } */ // 1002A4B4: using guessed type int dword_1002A4B4; // ref: 0x1000D1D4 HWND UNKCALL SelIPX_1000D1D4(HWND hWnd) { return 0; } /* { HWND result; // eax HWND v2; // esi HWND v3; // edi HWND v4; // eax int v5; // eax const char *v6; // edi int v7; // eax HWND hWnda; // [esp+10h] [ebp-4h] hWnda = hWnd; result = GetParent(hWnd); v2 = result; if ( result ) { result = GetDlgItem(result, 1088); v3 = result; if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { if ( result == (HWND)dword_1002A4B4 ) { v4 = GetDlgItem(v2, 1093); result = SelIPX_1000D070(v4); } else { v5 = SelIPX_1000D18C(v3) - 6; if ( v5 < 0 ) v5 = 0; result = (HWND)SelIPX_1000D1C1(v5); v6 = (const char *)result; if ( result ) { TitleSnd_10010315(); SelIPX_1000CB83(v2, v6); v7 = GetWindowLongA(hWnda, -12); SelIPX_1000C818(v2, v7); result = SelIPX_1000C982(v2); } } } } } } return result; } */ // 1002A4B4: using guessed type int dword_1002A4B4; // ref: 0x1000D284 HWND UNKCALL SelIPX_1000D284(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND result; // eax HWND v3; // eax const char *v4; // ebp HWND v5; // eax int v6; // ebx HWND v7; // eax HWND v8; // eax v1 = hWnd; result = (HWND)GetWindowLongA(hWnd, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { if ( *(DWORD *)result ) { if ( GetWindowLongA(v1, -12) >= 1093 ) { v3 = GetParent(v1); result = GetDlgItem(v3, 1089); if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { v4 = (const char *)*((DWORD *)result + 3); if ( v4 ) { TitleSnd_10010315(); v5 = GetParent(v1); SelIPX_1000CB83(v5, v4); v6 = GetWindowLongA(v1, -12); v7 = GetParent(v1); SelIPX_1000C818(v7, v6); v8 = GetParent(v1); result = SelIPX_1000C982(v8); } } } } else { result = SelIPX_1000D070(v1); } } } } return result; } */ // ref: 0x1000D31C HWND UNKCALL SelIPX_1000D31C(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND result; // eax const char *v3; // ebx HWND v4; // eax int v5; // ebx HWND v6; // eax HWND v7; // eax v1 = hWnd; if ( GetWindowLongA(hWnd, -12) > 1088 ) return SelIPX_1000CCD9(v1); result = (HWND)GetWindowLongA(v1, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { v3 = (const char *)dword_1002A4B4; if ( result != (HWND)dword_1002A4B4 ) { while ( v3 && *(HWND *)v3 != result ) v3 = *(const char **)v3; TitleSnd_10010315(); v4 = GetParent(v1); SelIPX_1000CB83(v4, v3); v5 = GetWindowLongA(v1, -12); v6 = GetParent(v1); SelIPX_1000C818(v6, v5); v7 = GetParent(v1); result = SelIPX_1000C982(v7); } } } return result; } */ // 1002A4B4: using guessed type int dword_1002A4B4; // ref: 0x1000D3A0 int __fastcall SelIPX_1000D3A0(int a1, int a2) { return 0; } /* { int v2; // edi int v3; // esi v2 = a2; v3 = a1; Fade_100073B4(); SDlgKillTimer(v3, 3); Fade_100072BE(10); return SDlgEndDialog(v3, v2); } */ // 10010376: using guessed type int __stdcall SDlgEndDialog(DWORD, DWORD); // 10010418: using guessed type int __stdcall SDlgKillTimer(DWORD, DWORD); // ref: 0x1000D3C5 HWND USERCALL SelIPX_1000D3C5(HWND hDlg, int a2) { return 0; } /* { HWND v2; // edi HWND v3; // eax HWND v4; // esi HWND result; // eax int v6; // esi HWND v7; // esi int v8; // eax HWND v9; // edi int v10; // [esp-DCh] [ebp-E4h] signed int v11; // [esp-5Ch] [ebp-64h] HWND v12; // [esp-54h] [ebp-5Ch] signed int v13; // [esp-Ch] [ebp-14h] signed int v14; // [esp-8h] [ebp-10h] int v15; // [esp-4h] [ebp-Ch] int v16; // [esp+0h] [ebp-8h] int v17; // [esp+4h] [ebp-4h] v2 = hDlg; v3 = GetFocus(); v4 = v3; result = GetParent(v3); if ( v2 == result ) { result = (HWND)GetWindowLongA(v4, -21); if ( result ) { v6 = *((DWORD *)result + 3); TitleSnd_1001031F(); if ( *(DWORD *)(v6 + 4) ) { result = (HWND)SelIPX_1000D5B0((int)v2, v6); } else { v17 = a2; v7 = v2; SelIPX_1000C9DA(v2); memcpy(&v11, dword_1002A4A0, 0x50u); v11 = 80; v12 = v2; memset(&v13, 0, 0x10u); v13 = 16; v14 = 1230002254; v8 = *(DWORD *)(dword_1002A4AC + 24); v16 = 0; v15 = v8; v9 = GetFocus(); SelIPX_1000D4CA(v7, 0); SelIPX_1000D520((char *)&v10); if ( CreaDung_100051D8( (int)&v13, dword_1002A4AC, dword_1002A49C, (int)&v11, dword_1002A4BC, gnIpxPlayerid, 0, (int)&v10) ) { result = (HWND)SelIPX_1000D3A0((int)v7, 1); } else { SelIPX_1000D4CA(v7, 1); result = SetFocus(v9); } } } } return result; } */ // 1000D3C5: could not find valid save-restore pair for ebp // 1002A49C: using guessed type int dword_1002A49C; // 1002A4A8: using guessed type int gnIpxPlayerid; // 1002A4AC: using guessed type int dword_1002A4AC; // 1002A4BC: using guessed type int dword_1002A4BC; // ref: 0x1000D4CA BOOL __fastcall SelIPX_1000D4CA(HWND hDlg, int a2) { return 0; } /* { HWND v2; // ebx int v3; // ebp HWND v4; // eax HWND v5; // eax BOOL result; // eax int nCmdShow; // [esp+10h] [ebp-4h] nCmdShow = a2; v2 = hDlg; v3 = 1088; do { v4 = GetDlgItem(v2, v3); if ( v4 ) ShowWindow(v4, nCmdShow); ++v3; } while ( v3 <= 1093 ); v5 = GetDlgItem(v2, 1105); if ( dword_1002A4B8 > 6 ) result = ShowWindow(v5, nCmdShow); else result = ShowWindow(v5, 0); return result; } */ // ref: 0x1000D520 char *UNKCALL SelIPX_1000D520(char *arg) { return 0; } /* { char *v1; // esi char *result; // eax signed int v3; // edi signed int v4; // eax char v5; // [esp+4h] [ebp-80h] v1 = arg; Connect_10004028((int)&v5, 128, 0, 0); if ( !SelIPX_1000D58D((const char *)dword_1002A4B4, &v5) ) return strcpy(v1, &v5); v3 = 2; do { v4 = v3++; wsprintfA(v1, "%s %d", &v5, v4); result = (char *)SelIPX_1000D58D((const char *)dword_1002A4B4, v1); } while ( result ); return result; } */ // 1002A4B4: using guessed type int dword_1002A4B4; // ref: 0x1000D58D const char *__fastcall SelIPX_1000D58D(const char *a1, const char *a2) { return 0; } /* { const char *v2; // edi const char *i; // esi v2 = a2; for ( i = a1; i && _strcmpi(i + 12, v2); i = *(const char **)i ) ; return i; } */ // ref: 0x1000D5B0 int __fastcall SelIPX_1000D5B0(int a1, int a2) { return 0; } /* { int v2; // esi CHAR *v3; // edx CHAR v5; // [esp+Ch] [ebp-384h] CHAR v6; // [esp+10Ch] [ebp-284h] char v7; // [esp+20Ch] [ebp-184h] CHAR Buffer; // [esp+28Ch] [ebp-104h] int v9; // [esp+30Ch] [ebp-84h] int v10; // [esp+38Ch] [ebp-4h] v2 = a2; v10 = a1; Connect_10004028((int)&v9, 128, (int)&v7, 128); if ( UiAuthCallback(2, (int)&v9, &v7, 0, (char *)(v2 + 140), &v6, 256) ) { if ( SNetJoinGame(*(DWORD *)(v2 + 4), v2 + 12, 0, &v9, &v7, gnIpxPlayerid) ) return SelIPX_1000D3A0(v10, 1); if ( SErrGetLastError() == -2062548871 ) LoadStringA(hInstance, 0x32u, &Buffer, 127); else LoadStringA(hInstance, 0x25u, &Buffer, 127); wsprintfA(&v5, &Buffer, v2 + 12); v3 = &v5; } else { v3 = &v6; } return SelYesNo_1000FD39(v10, v3, 0, 0); } */ // 10010406: using guessed type DWORD __stdcall SErrGetLastError(); // 10010430: using guessed type int __stdcall SNetJoinGame(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); // 1002A4A8: using guessed type int gnIpxPlayerid; // ref: 0x1000D696 HWND __fastcall SelIPX_1000D696(HWND hDlg, int a2, int a3) { return 0; } /* { int v3; // ebx HWND v4; // esi int v5; // ST08_4 HWND v6; // eax HWND result; // eax HWND v8; // eax HWND v9; // eax HWND v10; // eax int v11; // eax int v12; // eax int v13; // eax HWND v14; // eax HWND v15; // eax HWND v16; // eax HWND v17; // eax v3 = a2; v4 = hDlg; v5 = a2; v6 = GetDlgItem(hDlg, 1056); if ( local_10007C3B(v4, v6, v5, a3) ) return SelIPX_1000D3C5(v4, a3); v8 = GetDlgItem(v4, 1054); if ( local_10007C3B(v4, v8, v3, a3) ) return (HWND)SelIPX_1000D3A0((int)v4, 2); v9 = GetDlgItem(v4, 1105); result = (HWND)local_10007C3B(v4, v9, v3, a3); if ( result ) { v10 = GetDlgItem(v4, 1105); v11 = Sbar_100099DC(v10, v3, a3) - 1; if ( v11 ) { v12 = v11 - 1; if ( v12 ) { v13 = v12 - 1; if ( v13 ) { result = (HWND)(v13 - 1); if ( !result ) { v14 = GetFocus(); result = SelIPX_1000D0E1(v14); } } else { v15 = GetFocus(); result = SelIPX_1000D1D4(v15); } } else { v16 = GetFocus(); result = SelIPX_1000D284(v16); } } else { v17 = GetFocus(); result = SelIPX_1000D31C(v17); } } return result; } */ ================================================ FILE: DiabloUI/sellist.cpp ================================================ // ref: 0x1000D769 void __cdecl SelList_cpp_init() { SelList_cpp_float = SelList_cpp_float_value; } // 1001F468: using guessed type int SelList_cpp_float_value; // 1002A4C0: using guessed type int SelList_cpp_float; // ref: 0x1000D774 LRESULT __stdcall SelList_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v4; // eax char *v5; // eax int v6; // edx HWND v8; // eax HWND v9; // eax if (Msg > 0x111) { if (Msg == 275) { v9 = GetFocus(); Focus_DoBlitSpinIncFrame(hWnd, v9); return 0; } if (Msg != 513) { if (Msg == 514) { v8 = GetDlgItem(hWnd, 1105); if (!Sbar_CheckIfNextHero(v8)) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); goto LABEL_23; } if (Msg != 515) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } SelList_ChooseDlgFromSize(hWnd, (unsigned short)lParam, (unsigned int)lParam >> 16); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } switch (Msg) { case 0x111u: if (HIWORD(wParam) == 7) { Focus_GetAndBlitSpin(hWnd, lParam); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (HIWORD(wParam) != 6) { v6 = 1; if (HIWORD(wParam) != 5 && (WORD)wParam != 1) { v6 = 2; if ((WORD)wParam != 2) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } LABEL_25: OkCancel_PlaySndEndDlg(hWnd, v6); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } Focus_CheckPlayMove(lParam); Focus_DoBlitSpinIncFrame(hWnd, (HWND)lParam); SelList_GetHeroStats(hWnd, (unsigned short)wParam); LABEL_23: SelList_CountHeroList(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); case 2u: SelList_DeleteFreeProcs(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); case 6u: if ((WORD)wParam == 1 || (WORD)wParam == 2) SelList_LoadFocus16(hWnd); else SelList_KillFocus16(hWnd); return 0; case 0x100u: if (wParam != 46) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); v5 = SelHero_GetHeroNameStr(); if (!strlen(v5)) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); v6 = 1006; goto LABEL_25; } if (Msg <= 0x103) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); if (Msg <= 0x105) { v4 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v4, Msg, wParam, lParam); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg != 272) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); SelList_ShowListWindow(hWnd); return 0; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x1000D916 void __fastcall SelList_DeleteFreeProcs(HWND hWnd) { HWND v2; // eax Sbar_FreeScrollBar(hWnd, 1105); Doom_DeleteFreeProcs(hWnd, sellist_msgtbl4); Doom_DeleteFreeProcs(hWnd, sellist_msgtbl3); Doom_DeleteFreeProcs(hWnd, sellist_msgtbl2); Doom_DeleteFreeProcs(hWnd, sellist_msgtbl1); v2 = GetParent(hWnd); SelHero_SetStringWithMsg(v2, 0); } // ref: 0x1000D964 void __fastcall SelList_GetHeroStats(HWND hWnd, int nIDDlgItem) { HWND v2; // ebp HWND v3; // eax int v4; // eax HWND v5; // eax int v6; // eax HWND v7; // eax int v8; // eax HWND v9; // eax int v10; // eax HWND v11; // eax int v12; // eax HWND v14; // eax LONG v15; // eax _uiheroinfo *v16; // edi HWND v17; // eax HWND v18; // eax v14 = GetDlgItem(hWnd, nIDDlgItem); if (v14) { v15 = GetWindowLongA(v14, -21); if (v15) { v16 = *(_uiheroinfo **)(v15 + 12); if (v16) { if (v16->level) Doom_ParseWndProc2(hWnd, sellist_msgtbl3, AF_BIG, 0); else Doom_ParseWndProc2(hWnd, sellist_msgtbl3, AF_BIGGRAY, 0); v17 = GetParent(hWnd); SelHero_PrintHeroInfo(v17, v16); } else { Doom_ParseWndProc2(hWnd, sellist_msgtbl3, AF_BIGGRAY, 0); v18 = GetParent(hWnd); selhero_hero_hassaved = 0; selhero_heronamestr[0] = 0; v2 = v18; v3 = GetDlgItem(v18, 1014); v4 = GetWindowLongA(v3, -21); local_SetWndLongStr(v4, "--"); v5 = GetDlgItem(v2, 1018); v6 = GetWindowLongA(v5, -21); local_SetWndLongStr(v6, "--"); v7 = GetDlgItem(v2, 1017); v8 = GetWindowLongA(v7, -21); local_SetWndLongStr(v8, "--"); v9 = GetDlgItem(v2, 1016); v10 = GetWindowLongA(v9, -21); local_SetWndLongStr(v10, "--"); v11 = GetDlgItem(v2, 1015); v12 = GetWindowLongA(v11, -21); local_SetWndLongStr(v12, "--"); SelHero_SetStaticBMP(v2, 3); Doom_ParseWndProc4(v2, selhero_msgtbl_info, AF_SMALLGRAY); } } } } // 1002A424: using guessed type int selhero_hero_hassaved; // ref: 0x1000D9CF void __fastcall SelList_CountHeroList(HWND hWnd) { HWND v2; // eax int v3; // ST04_4 int v4; // eax v2 = GetFocus(); v3 = SelList_GetNextHeroLong(v2); v4 = SelHero_GetNumHeroesLeft(); Sbar_DrawScrollBar(hWnd, 1105, v4, v3); } // ref: 0x1000D9F4 int __fastcall SelList_GetNextHeroLong(HWND hWnd) { LONG v1; // esi _uiheroinfo *v2; // eax _uiheroinfo *v3; // esi int v5; // ecx if (!hWnd) return 0; v1 = GetWindowLongA(hWnd, -21); if (!v1) return 0; v2 = SelHero_GetCurrentHeroInfo(); if (!v2) return 0; v3 = *(_uiheroinfo **)(v1 + 12); if (!v3) return 0; v5 = 0; do { if (v2 == v3) break; v2 = v2->next; ++v5; } while (v2); return v5; } // ref: 0x1000DA2D void __fastcall SelList_LoadFocus16(HWND hWnd) { Focus_LoadSpinner("ui_art\\focus16.pcx"); SDlgSetTimer((int)hWnd, 1, 55, 0); } // ref: 0x1000DA48 void __fastcall SelList_KillFocus16(HWND hWnd) { SDlgKillTimer((int)hWnd, 1); Focus_DeleteSpinners(); } // ref: 0x1000DA55 void __fastcall SelList_ShowListWindow(HWND hWnd) { HWND v2; // edi LONG v3; // eax HWND v4; // eax char Buffer[32]; // [esp+8h] [ebp-20h] v2 = GetParent(hWnd); SelList_DoListOldProc(hWnd); if (SelHero_GetHeroIsGood() == 1) LoadStringA(ghUiInst, 0x1Cu, Buffer, 31); else LoadStringA(ghUiInst, 0x1Du, Buffer, 31); SelHero_SetStringWithMsg(v2, Buffer); v3 = GetWindowLongA(v2, -21); SetWindowLongA(hWnd, -21, v3); Doom_ParseWndProc3(hWnd, sellist_msgtbl1, AF_BIGGRAY); Doom_ParseWndProcs(hWnd, sellist_msgtbl2, AF_BIG, 0); Doom_ParseWndProcs(hWnd, sellist_msgtbl3, AF_BIG, 0); Doom_ParseWndProcs(hWnd, sellist_msgtbl4, AF_MED, 1); sellist_pheroinfo = SelHero_GetCurrentHeroInfo(); SelList_SetHeroDlgLong(hWnd, sellist_pheroinfo); Sbar_LoadScrBarGFX(hWnd, 1105); if (SelHero_GetNumHeroesLeft() <= 6) { v4 = GetDlgItem(hWnd, 1105); ShowWindow(v4, 0); } } // ref: 0x1000DB2C void __fastcall SelList_SetHeroDlgLong(HWND hWnd, _uiheroinfo *pInfo) { int *i; // ebp HWND v4; // eax MAPDST int v6; // esi for (i = sellist_msgtbl4; *i; ++i) { v4 = GetDlgItem(hWnd, *i); if (v4) { if (pInfo) { EnableWindow(v4, 1); v6 = GetWindowLongA(v4, -21); local_SetWndLongStr(v6, pInfo->name); if (v6) *(DWORD *)(v6 + 12) = (unsigned int)pInfo; pInfo = pInfo->next; } else { EnableWindow(v4, 0); } } } Doom_ParseWndProc2(hWnd, sellist_msgtbl4, AF_MED, 1); } // ref: 0x1000DBAC void __fastcall SelList_DoListOldProc(HWND hWnd) { int *i; // edi HWND v3; // eax MAPDST void *v5; // eax for (i = sellist_msgtbl4; *i; ++i) { v3 = GetDlgItem(hWnd, *i); if (v3) { v5 = (void *)GetWindowLongA(v3, -4); SetPropA(v3, "UIOLDPROC", v5); SetWindowLongA(v3, -4, (LONG)SelList_OldListWndProc); } } } // ref: 0x1000DBFE LRESULT __stdcall SelList_OldListWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { LRESULT(__stdcall * v4) (HWND, UINT, WPARAM, LPARAM); // edi HWND v5; // eax UINT v7; // [esp-Ch] [ebp-18h] WPARAM v8; // [esp-8h] [ebp-14h] LPARAM v9; // [esp-4h] [ebp-10h] v4 = (LRESULT(__stdcall *)(HWND, UINT, WPARAM, LPARAM))GetPropA(hWnd, "UIOLDPROC"); switch (Msg) { case 2u: RemovePropA(hWnd, "UIOLDPROC"); if (!v4) return DefWindowProcA(hWnd, Msg, wParam, lParam); SetWindowLongA(hWnd, -4, (LONG)v4); break; case 0xFu: local_DlgDoPaint(hWnd); return 0; case 0x87u: return 4; case 0x100u: if (wParam > 0x21) { if (wParam == 34) { SelList_HeroesWithBigDialogs(hWnd); return 0; } if (wParam > 0x24) { if (wParam <= 0x26) { SelList_HeroDlgWithSnd2(hWnd); return 0; } if (wParam <= 0x28) { SelList_HeroDlgWithSound(hWnd); return 0; } if (wParam == 46) { v9 = lParam; v8 = 46; v7 = 256; goto LABEL_24; } } } else { switch (wParam) { case 0x21u: SelList_HeroesWithHugeDlg(hWnd); break; case 9u: if (GetKeyState(16) >= 0) SelList_ShiftHeroDlgItems(hWnd); else SelList_ShiftHeroDlgItm2(hWnd); return 0; case 0xDu: goto LABEL_38; case 0x1Bu: v9 = 0; v8 = 2; goto LABEL_12; case 0x20u: LABEL_38: v9 = 0; v8 = 1; LABEL_12: v7 = 273; LABEL_24: v5 = GetParent(hWnd); SendMessageA(v5, v7, v8, v9); return 0; } } return 0; } if (v4) return CallWindowProcA(v4, hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam); } // ref: 0x1000DD36 void __fastcall SelList_ShiftHeroDlgItems(HWND hWnd) { HWND v2; // ebx int nIDDlgItem[1053]; // [esp+0h] [ebp-1074h] nIDDlgItem[1047] = 1048; nIDDlgItem[1048] = 1049; nIDDlgItem[1049] = 1050; nIDDlgItem[1050] = 1051; nIDDlgItem[1051] = 1052; nIDDlgItem[1052] = 1047; v2 = GetParent(hWnd); do { nIDDlgItem[1044] = nIDDlgItem[GetWindowLongA(hWnd, -12)]; hWnd = GetDlgItem(v2, nIDDlgItem[1044]); } while (!IsWindowEnabled(hWnd)); SetFocus(hWnd); } // ref: 0x1000DDA7 void __fastcall SelList_ShiftHeroDlgItm2(HWND hWnd) { HWND v2; // ebx int nIDDlgItem[1053]; // [esp+0h] [ebp-1074h] nIDDlgItem[1047] = 1052; nIDDlgItem[1048] = 1047; nIDDlgItem[1049] = 1048; nIDDlgItem[1050] = 1049; nIDDlgItem[1051] = 1050; nIDDlgItem[1052] = 1051; v2 = GetParent(hWnd); do { nIDDlgItem[1044] = nIDDlgItem[GetWindowLongA(hWnd, -12)]; hWnd = GetDlgItem(v2, nIDDlgItem[1044]); } while (!IsWindowEnabled(hWnd)); SetFocus(hWnd); } // ref: 0x1000DE18 void __fastcall SelList_HeroesWithBigDialogs(HWND hWnd) { HWND v1; // eax MAPDST HWND v3; // ebp HWND v4; // eax LONG v5; // eax _uiheroinfo *v6; // eax int v7; // esi _uiheroinfo *v8; // esi int v9; // eax v1 = GetParent(hWnd); if (v1) { v3 = GetDlgItem(v1, 1047); if (v3) { v4 = GetDlgItem(v1, 1052); v5 = GetWindowLongA(v4, -21); if (v5) { v6 = *(_uiheroinfo **)(v5 + 12); if (v6 && v6->next) { v7 = SelList_GetNextHeroLong(v3) + 6; if (v7 > SelHero_GetNumHeroesLeft() - 6) v7 = SelHero_GetNumHeroesLeft() - 6; v8 = SelList_GetHeroFromNum(v7); if (v8) { TitleSnd_PlayMoveSound(); SelList_SetHeroDlgLong(v1, v8); v9 = GetWindowLongA(hWnd, -12); SelList_GetHeroStats(v1, v9); SelList_CountHeroList(v1); } } else { SelList_ShiftHeroDlgItm2(v3); } } } } } // ref: 0x1000DEDD _uiheroinfo *__fastcall SelList_GetHeroFromNum(int heronum) { _uiheroinfo *result; // eax result = SelHero_GetCurrentHeroInfo(); while (result && heronum) { result = result->next; --heronum; } return result; } // ref: 0x1000DEF4 void __fastcall SelList_HeroesWithHugeDlg(HWND hWnd) { HWND v1; // eax MAPDST HWND v3; // eax MAPDST LONG v5; // eax _uiheroinfo *v6; // ebp HWND v7; // eax int v8; // eax _uiheroinfo *v9; // edi int v10; // eax v1 = GetParent(hWnd); if (v1) { v3 = GetDlgItem(v1, 1047); if (v3) { v5 = GetWindowLongA(v3, -21); if (v5) { v6 = *(_uiheroinfo **)(v5 + 12); if (v6) { if (v6 == SelHero_GetCurrentHeroInfo()) { v7 = GetDlgItem(v1, 1052); SelList_ShiftHeroDlgItems(v7); } else { v8 = SelList_GetNextHeroLong(v3) - 6; if (v8 < 0) v8 = 0; v9 = SelList_GetHeroFromNum(v8); if (v9) { TitleSnd_PlayMoveSound(); SelList_SetHeroDlgLong(v1, v9); v10 = GetWindowLongA(hWnd, -12); SelList_GetHeroStats(v1, v10); SelList_CountHeroList(v1); } } } } } } } // ref: 0x1000DFAB void __fastcall SelList_HeroDlgWithSound(HWND hWnd) { LONG v2; // eax _uiheroinfo *v3; // eax HWND v4; // eax HWND v5; // eax LONG v6; // eax _uiheroinfo *v7; // ebp HWND v8; // eax int v9; // ebx HWND v10; // eax HWND v11; // eax v2 = GetWindowLongA(hWnd, -21); if (v2) { v3 = *(_uiheroinfo **)(v2 + 12); if (v3) { if (v3->next) { if (GetWindowLongA(hWnd, -12) >= 1052) { v4 = GetParent(hWnd); v5 = GetDlgItem(v4, 1048); if (v5) { v6 = GetWindowLongA(v5, -21); if (v6) { v7 = *(_uiheroinfo **)(v6 + 12); if (v7) { TitleSnd_PlayMoveSound(); v8 = GetParent(hWnd); SelList_SetHeroDlgLong(v8, v7); v9 = GetWindowLongA(hWnd, -12); v10 = GetParent(hWnd); SelList_GetHeroStats(v10, v9); v11 = GetParent(hWnd); SelList_CountHeroList(v11); } } } } else { SelList_ShiftHeroDlgItems(hWnd); } } } } } // ref: 0x1000E043 void __fastcall SelList_HeroDlgWithSnd2(HWND hWnd) { LONG v2; // eax _uiheroinfo *v3; // esi _uiheroinfo *v4; // ebx HWND v5; // eax int v6; // ebx HWND v7; // eax HWND v8; // eax if (GetWindowLongA(hWnd, -12) <= 1047) { v2 = GetWindowLongA(hWnd, -21); if (v2) { v3 = *(_uiheroinfo **)(v2 + 12); if (v3) { v4 = SelHero_GetCurrentHeroInfo(); if (v3 != v4) { while (v4 && v4->next != v3) v4 = v4->next; TitleSnd_PlayMoveSound(); v5 = GetParent(hWnd); SelList_SetHeroDlgLong(v5, v4); v6 = GetWindowLongA(hWnd, -12); v7 = GetParent(hWnd); SelList_GetHeroStats(v7, v6); v8 = GetParent(hWnd); SelList_CountHeroList(v8); } } } } else { SelList_ShiftHeroDlgItm2(hWnd); } } // ref: 0x1000E0CA void __fastcall SelList_ChooseDlgFromSize(HWND hWnd, int width, int height) { HWND v6; // eax int v7; // edx HWND v8; // eax HWND v9; // eax char *v10; // eax HWND v11; // eax HWND v12; // eax int v13; // eax int v14; // eax int v15; // eax HWND v16; // eax HWND v17; // eax HWND v18; // eax HWND v19; // eax v6 = GetDlgItem(hWnd, 1056); if (local_GetBottomRect(hWnd, v6, width, height)) { v7 = 1; LABEL_3: OkCancel_PlaySndEndDlg(hWnd, v7); return; } v8 = GetDlgItem(hWnd, 1054); if (local_GetBottomRect(hWnd, v8, width, height)) { v7 = 2; goto LABEL_3; } v9 = GetDlgItem(hWnd, 1006); if (local_GetBottomRect(hWnd, v9, width, height)) { v10 = SelHero_GetHeroNameStr(); if (strlen(v10)) { v7 = 1006; goto LABEL_3; } } else { v11 = GetDlgItem(hWnd, 1105); if (local_GetBottomRect(hWnd, v11, width, height)) { v12 = GetDlgItem(hWnd, 1105); v13 = Sbar_NumScrollLines(v12, width, height) - 1; if (v13) { v14 = v13 - 1; if (v14) { v15 = v14 - 1; if (v15) { if (v15 == 1) { v16 = GetFocus(); SelList_HeroesWithBigDialogs(v16); } } else { v17 = GetFocus(); SelList_HeroesWithHugeDlg(v17); } } else { v18 = GetFocus(); SelList_HeroDlgWithSound(v18); } } else { v19 = GetFocus(); SelList_HeroDlgWithSnd2(v19); } } } } ================================================ FILE: DiabloUI/selload.cpp ================================================ // ref: 0x1000E1C2 LRESULT __stdcall SelLoad_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v4; // eax int v5; // edx HWND v6; // eax HWND v7; // eax HWND v9; // eax if (Msg == 2) { SelLoad_DeleteProcsAndSpin(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg <= 0x103) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); if (Msg <= 0x105) { v9 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v9, Msg, wParam, lParam); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg == 272) { SelLoad_LoadFocusAndMsg(hWnd); return 0; } if (Msg != 273) { if (Msg != 275) { if (Msg == 513) { v4 = GetDlgItem(hWnd, 1056); if (local_GetBottomRect(hWnd, v4, (unsigned short)lParam, (unsigned int)lParam >> 16)) { v5 = 1; LABEL_19: SelLoad_SelectSndLoad(hWnd, v5); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } v6 = GetDlgItem(hWnd, 1054); if (local_GetBottomRect(hWnd, v6, (unsigned short)lParam, (unsigned int)lParam >> 16)) { LABEL_21: v5 = 2; goto LABEL_19; } } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } v7 = GetFocus(); Focus_DoBlitSpinIncFrame(hWnd, v7); return 0; } if (HIWORD(wParam) == 7) { Focus_GetAndBlitSpin(hWnd, lParam); } else { if (HIWORD(wParam) != 6) { v5 = 1; if (HIWORD(wParam) == 5 || (WORD)wParam == 1) goto LABEL_19; if ((WORD)wParam != 2) return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); goto LABEL_21; } Focus_CheckPlayMove(lParam); Focus_DoBlitSpinIncFrame(hWnd, (HWND)lParam); } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x1000E30E void __fastcall SelLoad_DeleteProcsAndSpin(HWND hWnd) { HWND v2; // eax Focus_DeleteSpinners(); Doom_DeleteFreeProcs(hWnd, selload_msgtbl3); Doom_DeleteFreeProcs(hWnd, selload_msgtbl2); Doom_DeleteFreeProcs(hWnd, selload_msgtbl1); v2 = GetParent(hWnd); SelHero_SetStringWithMsg(v2, 0); } // ref: 0x1000E34B void __fastcall SelLoad_LoadFocusAndMsg(HWND hWnd) { HWND v2; // edi LONG v3; // eax char Buffer[32]; // [esp+8h] [ebp-20h] v2 = GetParent(hWnd); LoadStringA(ghUiInst, 0x1Du, Buffer, 31); SelHero_SetStringWithMsg(v2, Buffer); v3 = GetWindowLongA(v2, -21); SetWindowLongA(hWnd, -21, v3); local_DoUiWndProc(hWnd, (DWORD *)selload_msgtbl3); Doom_ParseWndProc3(hWnd, selload_msgtbl1, AF_BIGGRAY); Doom_ParseWndProcs(hWnd, selload_msgtbl2, AF_BIG, 0); Doom_ParseWndProcs(hWnd, selload_msgtbl3, AF_MED, 1); Focus_LoadSpinner("ui_art\\focus16.pcx"); SDlgSetTimer((int)hWnd, 1, 55, 0); } // ref: 0x1000E3E2 void __fastcall SelLoad_SelectSndLoad(HWND hWnd, int a2) { int v2; // esi HWND v4; // eax v2 = a2; TitleSnd_PlaySelectSound(); SDlgKillTimer((int)hWnd, 1); if (v2 == 1) { v4 = GetFocus(); v2 = GetWindowLongA(v4, -12); } SDlgEndDialog(hWnd, (HANDLE)v2); } // ref: 0x1000E41A void __cdecl SelLoad_cpp_init() { SelLoad_cpp_float = SelLoad_cpp_float_value; } // 1001F46C: using guessed type int SelLoad_cpp_float_value; // 1002A4C8: using guessed type int SelLoad_cpp_float; ================================================ FILE: DiabloUI/selmodem.cpp ================================================ // ref: 0x1000E42A signed int SelModem_1000E42A() { return 0; } /* { signed int result; // eax result = 2139095040; dword_1002A4CC = 2139095040; return result; } */ // 1002A4CC: using guessed type int dword_1002A4CC; // ref: 0x1000E435 int __fastcall SelModem_1000E435(void *a1, int a2, int a3, char *a4, char *a5) { return 0; } /* { void *v5; // edi dword_1002A4DC = 0; dword_1002A4D8 = 0; dword_1002A4E8 = a3; dword_1002A4D4 = a4; v5 = a1; dword_1002A4E0 = a2; dword_1002A4D0 = (int)a5; SNetEnumDevices(SelModem_1000E497); if ( !dword_1002A4D8 ) return SelModem_1000E505(v5); if ( dword_1002A4D8 == 1 ) return SelModem_1000E51E(); return SelModem_1000E5CC(); } */ // 10010496: using guessed type int __stdcall SNetEnumDevices(DWORD); // 1002A4D0: using guessed type int dword_1002A4D0; // 1002A4DC: using guessed type int dword_1002A4DC; // 1002A4E0: using guessed type int dword_1002A4E0; // 1002A4E8: using guessed type int dword_1002A4E8; // ref: 0x1000E497 char *__stdcall SelModem_1000E497(int a1, char *a2, char *a3) { return 0; } /* { int result; // eax int v4; // esi DWORD *v5; // eax result = SelModem_1000E4EC(); v4 = result; if ( result ) { *(DWORD *)result = 0; *(DWORD *)(result + 4) = a1; strcpy((char *)(result + 8), a2); strcpy((char *)(v4 + 136), a3); v5 = SelModem_1000E500(dword_1002A4DC, (DWORD *)v4); ++dword_1002A4D8; dword_1002A4DC = (int)v5; result = 1; } return result; } */ // 1002A4DC: using guessed type int dword_1002A4DC; // ref: 0x1000E4EC void *SelModem_1000E4EC() { return 0; } /* { return SMemAlloc(264, "C:\\Src\\Diablo\\DiabloUI\\SelModem.cpp", 72, 0); } */ // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000E500 DWORD *__fastcall SelModem_1000E500(int a1, DWORD *a2) { return 0; } /* { DWORD *result; // eax result = a2; *a2 = a1; return result; } */ // ref: 0x1000E505 signed int UNKCALL SelModem_1000E505(void *arg) { return 0; } /* { if ( arg != (void *)1297040461 ) return 1; SErrSetLastError(1222); return 0; } */ // 1001041E: using guessed type int __stdcall SErrSetLastError(DWORD); // ref: 0x1000E51E signed int SelModem_1000E51E() { return 0; } /* { signed int result; // eax if ( SelModem_1000E57B(*((DWORD *)dword_1002A4D4 + 2), *(DWORD *)(dword_1002A4DC + 4)) ) { SelModem_1000E553((DWORD *)dword_1002A4DC); result = 1; } else { SErrSetLastError(-2062548879); result = 0; } return result; } */ // 1001041E: using guessed type int __stdcall SErrSetLastError(DWORD); // 1002A4DC: using guessed type int dword_1002A4DC; // ref: 0x1000E553 int __fastcall SelModem_1000E553(DWORD *a1) { return 0; } /* { DWORD *v1; // esi int result; // eax if ( a1 ) { do { v1 = (DWORD *)*a1; result = SelModem_1000E567(a1); a1 = v1; } while ( v1 ); } return result; } */ // ref: 0x1000E567 int UNKCALL SelModem_1000E567(void *arg) { return 0; } /* { int result; // eax if ( arg ) result = SMemFree(arg, "C:\\Src\\Diablo\\DiabloUI\\SelModem.cpp", 77, 0); return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000E57B int __fastcall SelModem_1000E57B(int a1, int a2) { return 0; } /* { int v2; // ebx int v3; // esi int v5; // [esp+8h] [ebp-50h] int v6; // [esp+10h] [ebp-48h] int (__stdcall *v7)(char *, int, int, int, int); // [esp+30h] [ebp-28h] v2 = a2; v3 = a1; memcpy(&v5, dword_1002A4D4, 0x50u); v7 = ModmStat_10008C62; v5 = 80; v6 = v3; return SNetInitializeDevice(v2, dword_1002A4E0, dword_1002A4E8, &v5, dword_1002A4D0); } */ // 1001049C: using guessed type int __stdcall SNetInitializeDevice(DWORD, DWORD, DWORD, DWORD, DWORD); // 1002A4D0: using guessed type int dword_1002A4D0; // 1002A4E0: using guessed type int dword_1002A4E0; // 1002A4E8: using guessed type int dword_1002A4E8; // ref: 0x1000E5CC signed int SelModem_1000E5CC() { return 0; } /* { signed int v0; // esi signed int result; // eax v0 = 1; if ( SDlgDialogBoxParam(hInstance, "SELMODEM_DIALOG", *((DWORD *)dword_1002A4D4 + 2), SelModem_1000E63E, 0) == 1 ) { if ( !SelModem_1000E57B(*((DWORD *)dword_1002A4D4 + 2), dword_1002A4E4) ) { SErrSetLastError(-2062548879); v0 = 0; } SelModem_1000E553((DWORD *)dword_1002A4DC); result = v0; } else { SelModem_1000E553((DWORD *)dword_1002A4DC); SErrSetLastError(1223); result = 0; } return result; } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // 1001041E: using guessed type int __stdcall SErrSetLastError(DWORD); // 1002A4DC: using guessed type int dword_1002A4DC; // 1002A4E4: using guessed type int dword_1002A4E4; // ref: 0x1000E63E int __stdcall SelModem_1000E63E(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { int v4; // edx HWND v5; // eax HWND v7; // eax int v8; // [esp+0h] [ebp-Ch] if ( Msg > 0x201 ) { if ( Msg == 514 ) { v7 = GetDlgItem(hDlg, 1105); if ( !Sbar_100099C0(v7) ) return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); LABEL_27: SelModem_1000E7E9(hDlg); return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); } if ( Msg != 515 ) { if ( Msg != 2024 ) return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); if ( !Fade_1000739F() ) Fade_100073FD(hDlg, v8); return 0; } LABEL_25: SelModem_1000EE78(hDlg, (unsigned short)lParam, (unsigned int)lParam >> 16); return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); } if ( Msg == 513 ) goto LABEL_25; if ( Msg == 2 ) { SelModem_1000E783(hDlg); return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); } if ( Msg <= 0x103 ) return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); if ( Msg <= 0x105 ) { v5 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v5, Msg, wParam, lParam); return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); } if ( Msg == 272 ) { SelModem_1000E843(hDlg); return 0; } if ( Msg == 273 ) { if ( HIWORD(wParam) == 7 ) { Focus_100075B7(hDlg, (HWND)lParam); return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); } if ( HIWORD(wParam) == 6 ) { Focus_10007458((void *)lParam); Focus_100075DC(hDlg, (HWND)lParam); goto LABEL_27; } v4 = 1; if ( wParam != 327681 ) { if ( (WORD)wParam != 2 ) return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); v4 = 2; } SelModem_1000EE29((int)hDlg, v4); } return SDlgDefDialogProc(hDlg, Msg, wParam, lParam); } */ // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x1000E783 void UNKCALL SelModem_1000E783(HWND hDlg) { return; } /* { HWND v1; // esi DWORD *v2; // eax v1 = hDlg; Sbar_10009CD2(hDlg, 1105); Doom_10006C53(v1, &dword_100231F4); Doom_10006C53(v1, (int *)&unk_100231E8); Doom_10006C53(v1, (int *)&unk_100231CC); Doom_10006C53(v1, (int *)&unk_100231D4); Doom_10006C53(v1, (int *)&unk_100231E0); Focus_10007818(v1); local_1000811B(); v2 = (DWORD *)GetWindowLongA(v1, -21); local_10007F72(v2); } */ // 100231F4: using guessed type int dword_100231F4; // ref: 0x1000E7E9 HWND UNKCALL SelModem_1000E7E9(HWND hDlg) { return 0; } /* { HWND v1; // esi HWND v2; // eax int v3; // eax v1 = hDlg; v2 = GetFocus(); v3 = SelModem_1000E80E(v2); return Sbar_10009A99(v1, 1105, dword_1002A4D8, v3); } */ // ref: 0x1000E80E int UNKCALL SelModem_1000E80E(HWND hWnd) { return 0; } /* { LONG v1; // eax DWORD *v2; // ecx DWORD *v3; // eax int v5; // edx if ( !hWnd ) return 0; v1 = GetWindowLongA(hWnd, -21); if ( !v1 ) return 0; v2 = (DWORD *)dword_1002A4DC; if ( !dword_1002A4DC ) return 0; v3 = *(DWORD **)(v1 + 12); if ( !v3 ) return 0; v5 = 0; do { if ( v2 == v3 ) break; v2 = (DWORD *)*v2; ++v5; } while ( v2 ); return v5; } */ // 1002A4DC: using guessed type int dword_1002A4DC; // ref: 0x1000E843 HWND UNKCALL SelModem_1000E843(HWND hWnd) { return 0; } /* { HWND v1; // esi int v2; // eax int *v3; // edi HWND result; // eax HWND v5; // eax HWND v6; // [esp+0h] [ebp-Ch] v1 = hWnd; GetParent(hWnd); SelModem_1000E9B2(v1); Focus_100077E9((int)v1, "ui_art\\focus16.pcx", v6); local_100080F1(); v2 = local_10007F46(); v3 = (int *)v2; if ( v2 ) { SetWindowLongA(v1, -21, v2); local_10007944((int)v1, 0, "popup", -1, 1, (int)"ui_art\\seldiff.pcx", v3, v3 + 1, 0); } Fade_100073C5(v1, 0); PostMessageA(v1, 0x7E8u, 0, 0); Doom_100068AB(v1, (int *)&unk_100231E0, 1); Doom_100068AB(v1, (int *)&unk_100231D4, 3); Doom_100068AB(v1, (int *)&unk_100231CC, 5); Doom_1000658C(v1, (int *)&unk_100231E8, 4, 0); Doom_1000658C(v1, &dword_100231F4, 0, 1); SelModem_1000E932(v1, (const char *)dword_1002A4DC); result = Sbar_10009BF1(v1, 1105); if ( dword_1002A4D8 <= 6 ) { v5 = GetDlgItem(v1, 1105); result = (HWND)ShowWindow(v5, 0); } return result; } */ // 100231F4: using guessed type int dword_100231F4; // 1002A4DC: using guessed type int dword_1002A4DC; // ref: 0x1000E932 int __fastcall SelModem_1000E932(HWND a1, const char *a2) { return 0; } /* { const char *v2; // edi int *v3; // ebp HWND v4; // eax HWND v5; // esi int v6; // esi HWND hDlg; // [esp+8h] [ebp-4h] v2 = a2; hDlg = a1; v3 = &dword_100231F4; if ( dword_100231F4 ) { do { v4 = GetDlgItem(hDlg, *v3); v5 = v4; if ( v4 ) { if ( v2 ) { EnableWindow(v4, 1); v6 = GetWindowLongA(v5, -21); local_10007FA4(v6, v2 + 8); if ( v6 ) *(DWORD *)(v6 + 12) = v2; v2 = *(const char **)v2; } else { EnableWindow(v4, 0); } } ++v3; } while ( *v3 ); } return Doom_1000680A(hDlg, &dword_100231F4, 0, 1); } */ // 100231F4: using guessed type int dword_100231F4; // ref: 0x1000E9B2 void UNKCALL SelModem_1000E9B2(HWND hDlg) { return; } /* { HWND v1; // ebx int *v2; // edi HWND v3; // eax HWND v4; // esi void *v5; // eax v1 = hDlg; v2 = &dword_100231F4; if ( dword_100231F4 ) { do { v3 = GetDlgItem(v1, *v2); v4 = v3; if ( v3 ) { v5 = (void *)GetWindowLongA(v3, -4); SetPropA(v4, "UIOLDPROC", v5); SetWindowLongA(v4, -4, (LONG)SelModem_1000EA04); } ++v2; } while ( *v2 ); } } */ // 100231F4: using guessed type int dword_100231F4; // ref: 0x1000EA04 LRESULT __stdcall SelModem_1000EA04(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { LRESULT (__stdcall *v4)(HWND, UINT, WPARAM, LPARAM); // edi HWND v5; // eax WPARAM v7; // [esp-8h] [ebp-14h] v4 = (LRESULT (__stdcall *)(HWND, UINT, WPARAM, LPARAM))GetPropA(hWnd, "UIOLDPROC"); switch ( Msg ) { case 2u: RemovePropA(hWnd, "UIOLDPROC"); if ( !v4 ) return DefWindowProcA(hWnd, Msg, wParam, lParam); SetWindowLongA(hWnd, -4, (LONG)v4); break; case 0xFu: local_10007C95(hWnd); return 0; case 0x87u: return 4; case 0x100u: if ( wParam > 0x21 ) { if ( wParam == 34 ) { SelModem_1000EC0E(hWnd); } else if ( wParam > 0x24 ) { if ( wParam <= 0x26 ) { SelModem_1000EDBC(hWnd); } else if ( wParam <= 0x28 ) { SelModem_1000ED3B(hWnd); } } return 0; } if ( wParam == 33 ) { SelModem_1000ECB2(hWnd); return 0; } if ( wParam == 9 ) { if ( GetKeyState(16) >= 0 ) SelModem_1000EB2C(hWnd); else SelModem_1000EB9D(hWnd); return 0; } if ( wParam != 13 ) { if ( wParam == 27 ) { v7 = 2; goto LABEL_13; } if ( wParam != 32 ) return 0; } v7 = 1; LABEL_13: v5 = GetParent(hWnd); SendMessageA(v5, 0x111u, v7, 0); return 0; } if ( v4 ) return CallWindowProcA(v4, hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam); } */ // ref: 0x1000EB2C HWND UNKCALL SelModem_1000EB2C(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND v2; // ebx int nIDDlgItem[1107]; // [esp+0h] [ebp-1170h] int v5; // [esp+114Ch] [ebp-24h] int v6; // [esp+1158h] [ebp-18h] int v7; // [esp+115Ch] [ebp-14h] int v8; // [esp+1160h] [ebp-10h] int v9; // [esp+1164h] [ebp-Ch] int v10; // [esp+1168h] [ebp-8h] int v11; // [esp+116Ch] [ebp-4h] v1 = hWnd; v6 = 1111; v7 = 1112; v8 = 1113; v9 = 1114; v10 = 1115; v11 = 1110; v2 = GetParent(hWnd); do { v5 = nIDDlgItem[GetWindowLongA(v1, -12)]; v1 = GetDlgItem(v2, v5); } while ( !IsWindowEnabled(v1) ); return SetFocus(v1); } */ // 1000EB2C: using guessed type int nIDDlgItem[1107]; // ref: 0x1000EB9D HWND UNKCALL SelModem_1000EB9D(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND v2; // ebx int nIDDlgItem[1107]; // [esp+0h] [ebp-1170h] int v5; // [esp+114Ch] [ebp-24h] int v6; // [esp+1158h] [ebp-18h] int v7; // [esp+115Ch] [ebp-14h] int v8; // [esp+1160h] [ebp-10h] int v9; // [esp+1164h] [ebp-Ch] int v10; // [esp+1168h] [ebp-8h] int v11; // [esp+116Ch] [ebp-4h] v1 = hWnd; v6 = 1115; v7 = 1110; v8 = 1111; v9 = 1112; v10 = 1113; v11 = 1114; v2 = GetParent(hWnd); do { v5 = nIDDlgItem[GetWindowLongA(v1, -12)]; v1 = GetDlgItem(v2, v5); } while ( !IsWindowEnabled(v1) ); return SetFocus(v1); } */ // 1000EB9D: using guessed type int nIDDlgItem[1107]; // ref: 0x1000EC0E HWND UNKCALL SelModem_1000EC0E(HWND hWnd) { return 0; } /* { HWND result; // eax HWND v2; // edi HWND v3; // ebx HWND v4; // eax DWORD *v5; // eax int v6; // eax const char *v7; // esi result = GetParent(hWnd); v2 = result; if ( result ) { result = GetDlgItem(result, 1110); v3 = result; if ( result ) { v4 = GetDlgItem(v2, 1115); result = (HWND)GetWindowLongA(v4, -21); if ( result ) { v5 = (DWORD *)*((DWORD *)result + 3); if ( v5 && *v5 ) { v6 = SelModem_1000E80E(v3) + 6; if ( v6 > dword_1002A4D8 - 6 ) v6 = dword_1002A4D8 - 6; result = (HWND)SelModem_1000EC9F(v6); v7 = (const char *)result; if ( result ) { TitleSnd_10010315(); SelModem_1000E932(v2, v7); result = SelModem_1000E7E9(v2); } } else { result = SelModem_1000EB9D(v3); } } } } return result; } */ // ref: 0x1000EC9F DWORD *__fastcall SelModem_1000EC9F(int a1) { return 0; } /* { DWORD *result; // eax result = (DWORD *)dword_1002A4DC; while ( result && a1 ) { result = (DWORD *)*result; --a1; } return result; } */ // 1002A4DC: using guessed type int dword_1002A4DC; // ref: 0x1000ECB2 HWND UNKCALL SelModem_1000ECB2(HWND hWnd) { return 0; } /* { HWND result; // eax HWND v2; // edi HWND v3; // esi HWND v4; // eax int v5; // eax const char *v6; // esi result = GetParent(hWnd); v2 = result; if ( result ) { result = GetDlgItem(result, 1110); v3 = result; if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { if ( result == (HWND)dword_1002A4DC ) { v4 = GetDlgItem(v2, 1115); result = SelModem_1000EB2C(v4); } else { v5 = SelModem_1000E80E(v3) - 6; if ( v5 < 0 ) v5 = 0; result = (HWND)SelModem_1000EC9F(v5); v6 = (const char *)result; if ( result ) { TitleSnd_10010315(); SelModem_1000E932(v2, v6); result = SelModem_1000E7E9(v2); } } } } } } return result; } */ // 1002A4DC: using guessed type int dword_1002A4DC; // ref: 0x1000ED3B HWND UNKCALL SelModem_1000ED3B(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND result; // eax HWND v3; // eax const char *v4; // esi HWND v5; // eax HWND v6; // eax v1 = hWnd; result = (HWND)GetWindowLongA(hWnd, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { if ( *(DWORD *)result ) { if ( GetWindowLongA(v1, -12) >= 1115 ) { v3 = GetParent(v1); result = GetDlgItem(v3, 1111); if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { v4 = (const char *)*((DWORD *)result + 3); if ( v4 ) { TitleSnd_10010315(); v5 = GetParent(v1); SelModem_1000E932(v5, v4); v6 = GetParent(v1); result = SelModem_1000E7E9(v6); } } } } else { result = SelModem_1000EB2C(v1); } } } } return result; } */ // ref: 0x1000EDBC HWND UNKCALL SelModem_1000EDBC(HWND hWnd) { return 0; } /* { HWND v1; // ebx HWND result; // eax const char *v3; // esi HWND v4; // eax HWND v5; // eax v1 = hWnd; if ( GetWindowLongA(hWnd, -12) > 1110 ) return SelModem_1000EB9D(v1); result = (HWND)GetWindowLongA(v1, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { v3 = (const char *)dword_1002A4DC; if ( result != (HWND)dword_1002A4DC ) { while ( v3 && *(HWND *)v3 != result ) v3 = *(const char **)v3; TitleSnd_10010315(); v4 = GetParent(v1); SelModem_1000E932(v4, v3); v5 = GetParent(v1); result = SelModem_1000E7E9(v5); } } } return result; } */ // 1002A4DC: using guessed type int dword_1002A4DC; // ref: 0x1000EE29 int __fastcall SelModem_1000EE29(int a1, int a2) { return 0; } /* { int v2; // esi int v3; // edi HWND v4; // eax LONG v5; // eax int v6; // eax v2 = a2; v3 = a1; TitleSnd_1001031F(); if ( v2 == 1 ) { v4 = GetFocus(); if ( v4 ) { v5 = GetWindowLongA(v4, -21); if ( v5 ) { v6 = *(DWORD *)(v5 + 12); if ( v6 ) dword_1002A4E4 = *(DWORD *)(v6 + 4); } } } Fade_100073B4(); Fade_100072BE(10); return SDlgEndDialog(v3, v2); } */ // 10010376: using guessed type int __stdcall SDlgEndDialog(DWORD, DWORD); // 1002A4E4: using guessed type int dword_1002A4E4; // ref: 0x1000EE78 HWND __fastcall SelModem_1000EE78(HWND hWnd, int a2, int a3) { return 0; } /* { int v3; // ebx HWND v4; // esi int v5; // ST08_4 HWND v6; // eax int v7; // edx HWND result; // eax HWND v9; // eax HWND v10; // eax HWND v11; // eax int v12; // eax int v13; // eax int v14; // eax HWND v15; // eax HWND v16; // eax HWND v17; // eax HWND v18; // eax v3 = a2; v4 = hWnd; v5 = a2; v6 = GetDlgItem(hWnd, 1056); if ( local_10007C3B(v4, v6, v5, a3) ) { v7 = 1; return (HWND)SelModem_1000EE29((int)v4, v7); } v9 = GetDlgItem(v4, 1054); if ( local_10007C3B(v4, v9, v3, a3) ) { v7 = 2; return (HWND)SelModem_1000EE29((int)v4, v7); } v10 = GetDlgItem(v4, 1105); result = (HWND)local_10007C3B(v4, v10, v3, a3); if ( result ) { v11 = GetDlgItem(v4, 1105); v12 = Sbar_100099DC(v11, v3, a3) - 1; if ( v12 ) { v13 = v12 - 1; if ( v13 ) { v14 = v13 - 1; if ( v14 ) { result = (HWND)(v14 - 1); if ( !result ) { v15 = GetFocus(); result = SelModem_1000EC0E(v15); } } else { v16 = GetFocus(); result = SelModem_1000ECB2(v16); } } else { v17 = GetFocus(); result = SelModem_1000ED3B(v17); } } else { v18 = GetFocus(); result = SelModem_1000EDBC(v18); } } return result; } */ ================================================ FILE: DiabloUI/selregn.cpp ================================================ // ref: 0x1000EF42 void *SelRegn_1000EF42() { return 0; } /* { return SMemAlloc(136, "C:\\Src\\Diablo\\DiabloUI\\SelRegn.cpp", 76, 0); } */ // 10010364: using guessed type int __stdcall SMemAlloc(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000EF56 _uiheroinfo *__fastcall SelRegn_SetNextHero(_uiheroinfo *pNext, _uiheroinfo *pCurrent) { _uiheroinfo *result; // eax result = pCurrent; pCurrent->next = pNext; return result; } // ref: 0x1000EF60 signed int SelRegn_1000EF60() { return 0; } /* { signed int result; // eax result = 2139095040; dword_1002A4F0 = 2139095040; return result; } */ // 1002A4F0: using guessed type int dword_1002A4F0; // ref: 0x1000EF6B int __stdcall SelRegn_1000EF6B(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { HWND v4; // eax HWND v6; // eax int v7; // [esp+0h] [ebp-Ch] if ( Msg > 0x201 ) { if ( Msg == 514 ) { v6 = GetDlgItem(hWnd, 1105); if ( !Sbar_100099C0(v6) ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); goto LABEL_27; } if ( Msg != 515 ) { if ( Msg != 2024 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); if ( !Fade_1000739F() ) Fade_100073FD(hWnd, v7); return 0; } LABEL_25: SelRegn_1000F929(hWnd, (unsigned short)lParam, (unsigned int)lParam >> 16); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg == 513 ) goto LABEL_25; if ( Msg == 2 ) { SelRegn_1000F161(hWnd); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg <= 0x103 ) return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); if ( Msg <= 0x105 ) { v4 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v4, Msg, wParam, lParam); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( Msg == 272 ) { SelRegn_1000F1FC(hWnd); PostMessageA(hWnd, 0x7E8u, 0, 0); return 0; } if ( Msg == 273 ) { if ( HIWORD(wParam) == 7 ) { Focus_100075B7(hWnd, (HWND)lParam); return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } if ( HIWORD(wParam) != 6 ) { if ( wParam == 327681 ) { SelRegn_1000F8DD(hWnd); } else if ( (WORD)wParam == 2 ) { SelConn_1000AC07((int)hWnd, 2); } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } Focus_10007458((void *)lParam); Focus_100075DC(hWnd, (HWND)lParam); SelRegn_1000F0D7(hWnd, (unsigned short)wParam); LABEL_27: SelRegn_1000F109(hWnd); } return SDlgDefDialogProc(hWnd, Msg, wParam, lParam); } */ // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x1000F0D7 HWND __fastcall SelRegn_1000F0D7(HWND hDlg, int nIDDlgItem) { return 0; } /* { HWND v2; // esi HWND result; // eax v2 = hDlg; result = GetDlgItem(hDlg, nIDDlgItem); if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { if ( *((DWORD *)result + 3) ) result = (HWND)Doom_10006A13(v2, (int *)&unk_10023250, 1); } } return result; } */ // ref: 0x1000F109 HWND UNKCALL SelRegn_1000F109(HWND hDlg) { return 0; } /* { HWND v1; // esi int v2; // eax v1 = hDlg; v2 = SelRegn_1000F126(); return Sbar_10009A99(v1, 1105, dword_1002A4F4, v2); } */ // ref: 0x1000F126 int SelRegn_1000F126() { return 0; } /* { HWND v0; // eax LONG v1; // eax DWORD *v2; // ecx DWORD *v3; // eax int v5; // edx v0 = GetFocus(); if ( !v0 ) return 0; v1 = GetWindowLongA(v0, -21); if ( !v1 ) return 0; v2 = (DWORD *)dword_1002A4EC; if ( !dword_1002A4EC ) return 0; v3 = *(DWORD **)(v1 + 12); if ( !v3 ) return 0; v5 = 0; do { if ( v2 == v3 ) break; v2 = (DWORD *)*v2; ++v5; } while ( v2 ); return v5; } */ // 1002A4EC: using guessed type int dword_1002A4EC; // ref: 0x1000F161 void UNKCALL SelRegn_1000F161(HWND hDlg) { return; } /* { HWND v1; // esi DWORD *v2; // eax v1 = hDlg; Title_100100E7(hDlg); Focus_10007818(v1); Sbar_10009CD2(v1, 1105); SelRegn_1000F1D4((DWORD *)dword_1002A4EC); Doom_10006C53(v1, &dword_1002326C); Doom_10006C53(v1, (int *)&unk_10023260); Doom_10006C53(v1, (int *)&unk_10023244); Doom_10006C53(v1, (int *)&unk_10023258); Doom_10006C53(v1, (int *)&unk_10023250); v2 = (DWORD *)GetWindowLongA(v1, -21); local_10007F72(v2); } */ // 1002326C: using guessed type int dword_1002326C; // 1002A4EC: using guessed type int dword_1002A4EC; // ref: 0x1000F1D4 int __fastcall SelRegn_1000F1D4(DWORD *a1) { return 0; } /* { DWORD *v1; // esi int result; // eax if ( a1 ) { do { v1 = (DWORD *)*a1; result = SelRegn_1000F1E8(a1); a1 = v1; } while ( v1 ); } return result; } */ // ref: 0x1000F1E8 int UNKCALL SelRegn_1000F1E8(void *arg) { return 0; } /* { int result; // eax if ( arg ) result = SMemFree(arg, "C:\\Src\\Diablo\\DiabloUI\\SelRegn.cpp", 82, 0); return result; } */ // 10010340: using guessed type int __stdcall SMemFree(DWORD, DWORD, DWORD, DWORD); // ref: 0x1000F1FC HWND UNKCALL SelRegn_1000F1FC(HWND hWnd) { return 0; } /* { HWND v1; // esi HWND v2; // ST1C_4 int v3; // eax int *v4; // edi HWND result; // eax HWND v6; // eax HWND v7; // [esp+0h] [ebp-Ch] v1 = hWnd; SelRegn_1000F3C2(hWnd); Focus_100077E9((int)v1, "ui_art\\focus16.pcx", v7); Title_1001009E(v1, (int)"ui_art\\smlogo.pcx", v2); v3 = local_10007F46(); v4 = (int *)v3; if ( v3 ) { SetWindowLongA(v1, -21, v3); local_10007944((int)v1, 0, &byte_10029448, -1, 1, (int)"ui_art\\selregn.pcx", v4, v4 + 1, 0); Fade_100073C5(v1, 1); } Doom_100068AB(v1, (int *)&unk_10023250, 1); Doom_100068AB(v1, (int *)&unk_10023258, 1); Doom_100068AB(v1, (int *)&unk_10023244, 5); Doom_1000658C(v1, (int *)&unk_10023260, 4, 0); Doom_1000658C(v1, &dword_1002326C, 0, 1); dword_1002A4F4 = 0; dword_1002A4EC = 0; SelRegn_1000F2ED(); SelRegn_1000F346(v1, (const char *)dword_1002A4EC); result = Sbar_10009BF1(v1, 1105); if ( dword_1002A4F4 <= 6 ) { v6 = GetDlgItem(v1, 1105); result = (HWND)ShowWindow(v6, 0); } return result; } */ // 1002326C: using guessed type int dword_1002326C; // 1002A4EC: using guessed type int dword_1002A4EC; // ref: 0x1000F2ED signed int SelRegn_1000F2ED() { return 0; } /* { signed int i; // edi char *v1; // eax char *v2; // esi const char *v3; // eax DWORD *v4; // eax for ( i = dword_10029488; ; --i ) { if ( i <= 0 ) return 1; v1 = (char *)SelRegn_1000EF42(); v2 = v1; if ( !v1 ) break; *(DWORD *)v1 = 0; *((DWORD *)v1 + 1) = i; v3 = BNetGW_10002B21(&unk_10029480, i); strcpy(v2 + 8, v3); v4 = SelRegn_1000EF56(dword_1002A4EC, v2); ++dword_1002A4F4; dword_1002A4EC = (int)v4; } return 0; } */ // 10029488: using guessed type int dword_10029488; // 1002A4EC: using guessed type int dword_1002A4EC; // ref: 0x1000F346 int __fastcall SelRegn_1000F346(HWND a1, const char *a2) { return 0; } /* { const char *v2; // edi int *v3; // ebx HWND v4; // eax HWND v5; // esi int v6; // eax HWND hDlg; // [esp+8h] [ebp-4h] v2 = a2; hDlg = a1; v3 = &dword_1002326C; if ( dword_1002326C ) { do { v4 = GetDlgItem(hDlg, *v3); v5 = v4; if ( v4 ) { if ( v2 ) { EnableWindow(v4, 1); v6 = GetWindowLongA(v5, -21); if ( v6 ) { *(DWORD *)(v6 + 12) = v2; local_10007FA4(v6, v2 + 8); v2 = *(const char **)v2; } } else { EnableWindow(v4, 0); } } ++v3; } while ( *v3 ); } return Doom_1000680A(hDlg, &dword_1002326C, 0, 1); } */ // 1002326C: using guessed type int dword_1002326C; // ref: 0x1000F3C2 void UNKCALL SelRegn_1000F3C2(HWND hDlg) { return; } /* { HWND v1; // ebx int *v2; // edi HWND v3; // eax HWND v4; // esi void *v5; // eax v1 = hDlg; v2 = &dword_1002326C; if ( dword_1002326C ) { do { v3 = GetDlgItem(v1, *v2); v4 = v3; if ( v3 ) { v5 = (void *)GetWindowLongA(v3, -4); SetPropA(v4, "UIOLDPROC", v5); SetWindowLongA(v4, -4, (LONG)SelRegn_1000F414); } ++v2; } while ( *v2 ); } } */ // 1002326C: using guessed type int dword_1002326C; // ref: 0x1000F414 LRESULT __stdcall SelRegn_1000F414(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return 0; } /* { LRESULT (__stdcall *v4)(HWND, UINT, WPARAM, LPARAM); // edi HWND v5; // eax WPARAM v7; // [esp-8h] [ebp-14h] v4 = (LRESULT (__stdcall *)(HWND, UINT, WPARAM, LPARAM))GetPropA(hWnd, "UIOLDPROC"); switch ( Msg ) { case 2u: RemovePropA(hWnd, "UIOLDPROC"); if ( !v4 ) return DefWindowProcA(hWnd, Msg, wParam, lParam); SetWindowLongA(hWnd, -4, (LONG)v4); break; case 0xFu: local_10007C95(hWnd); return 0; case 0x87u: return 4; case 0x100u: if ( wParam > 0x21 ) { if ( wParam == 34 ) { SelRegn_1000F61E(hWnd); } else if ( wParam > 0x24 ) { if ( wParam <= 0x26 ) { SelRegn_1000F859(hWnd); } else if ( wParam <= 0x28 ) { SelRegn_1000F7C1(hWnd); } } return 0; } if ( wParam == 33 ) { SelRegn_1000F711(hWnd); return 0; } if ( wParam == 9 ) { if ( GetKeyState(16) >= 0 ) SelRegn_1000F53C(hWnd); else SelRegn_1000F5AD(hWnd); return 0; } if ( wParam != 13 ) { if ( wParam == 27 ) { v7 = 2; goto LABEL_13; } if ( wParam != 32 ) return 0; } v7 = 1; LABEL_13: v5 = GetParent(hWnd); SendMessageA(v5, 0x111u, v7, 0); return 0; } if ( v4 ) return CallWindowProcA(v4, hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam); } */ // ref: 0x1000F53C HWND UNKCALL SelRegn_1000F53C(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND v2; // ebx int nIDDlgItem[1132]; // [esp+0h] [ebp-11D4h] int v5; // [esp+11B0h] [ebp-24h] int v6; // [esp+11BCh] [ebp-18h] int v7; // [esp+11C0h] [ebp-14h] int v8; // [esp+11C4h] [ebp-10h] int v9; // [esp+11C8h] [ebp-Ch] int v10; // [esp+11CCh] [ebp-8h] int v11; // [esp+11D0h] [ebp-4h] v1 = hWnd; v6 = 1136; v7 = 1137; v8 = 1138; v9 = 1139; v10 = 1140; v11 = 1135; v2 = GetParent(hWnd); do { v5 = nIDDlgItem[GetWindowLongA(v1, -12)]; v1 = GetDlgItem(v2, v5); } while ( !IsWindowEnabled(v1) ); return SetFocus(v1); } */ // 1000F53C: using guessed type int nIDDlgItem[1132]; // ref: 0x1000F5AD HWND UNKCALL SelRegn_1000F5AD(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND v2; // ebx int nIDDlgItem[1132]; // [esp+0h] [ebp-11D4h] int v5; // [esp+11B0h] [ebp-24h] int v6; // [esp+11BCh] [ebp-18h] int v7; // [esp+11C0h] [ebp-14h] int v8; // [esp+11C4h] [ebp-10h] int v9; // [esp+11C8h] [ebp-Ch] int v10; // [esp+11CCh] [ebp-8h] int v11; // [esp+11D0h] [ebp-4h] v1 = hWnd; v6 = 1140; v7 = 1135; v8 = 1136; v9 = 1137; v10 = 1138; v11 = 1139; v2 = GetParent(hWnd); do { v5 = nIDDlgItem[GetWindowLongA(v1, -12)]; v1 = GetDlgItem(v2, v5); } while ( !IsWindowEnabled(v1) ); return SetFocus(v1); } */ // 1000F5AD: using guessed type int nIDDlgItem[1132]; // ref: 0x1000F61E HWND UNKCALL SelRegn_1000F61E(HWND hWnd) { return 0; } /* { HWND v1; // ebp HWND result; // eax HWND v3; // esi HWND v4; // ebx HWND v5; // eax DWORD *v6; // eax int v7; // eax const char *v8; // ebx int v9; // eax v1 = hWnd; result = GetParent(hWnd); v3 = result; if ( result ) { result = GetDlgItem(result, 1135); v4 = result; if ( result ) { v5 = GetDlgItem(v3, 1140); result = (HWND)GetWindowLongA(v5, -21); if ( result ) { v6 = (DWORD *)*((DWORD *)result + 3); if ( v6 && *v6 ) { v7 = SelRegn_1000F6C9(v4) + 6; if ( v7 > dword_1002A4F4 - 6 ) v7 = dword_1002A4F4 - 6; result = (HWND)SelRegn_1000F6FE(v7); v8 = (const char *)result; if ( result ) { TitleSnd_10010315(); SelRegn_1000F346(v3, v8); v9 = GetWindowLongA(v1, -12); SelRegn_1000F0D7(v3, v9); result = SelRegn_1000F109(v3); } } else { result = SelRegn_1000F5AD(v4); } } } } return result; } */ // ref: 0x1000F6C9 int UNKCALL SelRegn_1000F6C9(HWND hWnd) { return 0; } /* { LONG v1; // eax DWORD *v2; // ecx DWORD *v3; // eax int v5; // edx if ( !hWnd ) return 0; v1 = GetWindowLongA(hWnd, -21); if ( !v1 ) return 0; v2 = (DWORD *)dword_1002A4EC; if ( !dword_1002A4EC ) return 0; v3 = *(DWORD **)(v1 + 12); if ( !v3 ) return 0; v5 = 0; do { if ( v2 == v3 ) break; v2 = (DWORD *)*v2; ++v5; } while ( v2 ); return v5; } */ // 1002A4EC: using guessed type int dword_1002A4EC; // ref: 0x1000F6FE DWORD *__fastcall SelRegn_1000F6FE(int a1) { return 0; } /* { DWORD *result; // eax result = (DWORD *)dword_1002A4EC; while ( result && a1 ) { result = (DWORD *)*result; --a1; } return result; } */ // 1002A4EC: using guessed type int dword_1002A4EC; // ref: 0x1000F711 HWND UNKCALL SelRegn_1000F711(HWND hWnd) { return 0; } /* { HWND result; // eax HWND v2; // esi HWND v3; // edi HWND v4; // eax int v5; // eax const char *v6; // edi int v7; // eax HWND hWnda; // [esp+10h] [ebp-4h] hWnda = hWnd; result = GetParent(hWnd); v2 = result; if ( result ) { result = GetDlgItem(result, 1135); v3 = result; if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { if ( result == (HWND)dword_1002A4EC ) { v4 = GetDlgItem(v2, 1140); result = SelRegn_1000F53C(v4); } else { v5 = SelRegn_1000F6C9(v3) - 6; if ( v5 < 0 ) v5 = 0; result = (HWND)SelRegn_1000F6FE(v5); v6 = (const char *)result; if ( result ) { TitleSnd_10010315(); SelRegn_1000F346(v2, v6); v7 = GetWindowLongA(hWnda, -12); SelRegn_1000F0D7(v2, v7); result = SelRegn_1000F109(v2); } } } } } } return result; } */ // 1002A4EC: using guessed type int dword_1002A4EC; // ref: 0x1000F7C1 HWND UNKCALL SelRegn_1000F7C1(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND result; // eax HWND v3; // eax const char *v4; // ebp HWND v5; // eax int v6; // ebx HWND v7; // eax HWND v8; // eax v1 = hWnd; result = (HWND)GetWindowLongA(hWnd, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { if ( *(DWORD *)result ) { if ( GetWindowLongA(v1, -12) >= 1140 ) { v3 = GetParent(v1); result = GetDlgItem(v3, 1136); if ( result ) { result = (HWND)GetWindowLongA(result, -21); if ( result ) { v4 = (const char *)*((DWORD *)result + 3); if ( v4 ) { TitleSnd_10010315(); v5 = GetParent(v1); SelRegn_1000F346(v5, v4); v6 = GetWindowLongA(v1, -12); v7 = GetParent(v1); SelRegn_1000F0D7(v7, v6); v8 = GetParent(v1); result = SelRegn_1000F109(v8); } } } } else { result = SelRegn_1000F53C(v1); } } } } return result; } */ // ref: 0x1000F859 HWND UNKCALL SelRegn_1000F859(HWND hWnd) { return 0; } /* { HWND v1; // edi HWND result; // eax const char *v3; // ebx HWND v4; // eax int v5; // ebx HWND v6; // eax HWND v7; // eax v1 = hWnd; if ( GetWindowLongA(hWnd, -12) > 1135 ) return SelRegn_1000F5AD(v1); result = (HWND)GetWindowLongA(v1, -21); if ( result ) { result = (HWND)*((DWORD *)result + 3); if ( result ) { v3 = (const char *)dword_1002A4EC; if ( result != (HWND)dword_1002A4EC ) { while ( v3 && *(HWND *)v3 != result ) v3 = *(const char **)v3; TitleSnd_10010315(); v4 = GetParent(v1); SelRegn_1000F346(v4, v3); v5 = GetWindowLongA(v1, -12); v6 = GetParent(v1); SelRegn_1000F0D7(v6, v5); v7 = GetParent(v1); result = SelRegn_1000F109(v7); } } } return result; } */ // 1002A4EC: using guessed type int dword_1002A4EC; // ref: 0x1000F8DD signed int UNKCALL SelRegn_1000F8DD(void *arg) { return 0; } /* { int v1; // esi signed int result; // eax v1 = (int)arg; result = SelRegn_1000F8F6(); if ( result ) result = SelConn_1000AC07(v1, 1); return result; } */ // ref: 0x1000F8F6 signed int SelRegn_1000F8F6() { return 0; } /* { HWND v0; // eax LONG v1; // eax int v2; // eax TitleSnd_1001031F(); v0 = GetFocus(); v1 = GetWindowLongA(v0, -21); if ( !v1 ) return 0; v2 = *(DWORD *)(v1 + 12); if ( !v2 ) return 0; BNetGW_10002B51(&unk_10029480, *(DWORD *)(v2 + 4)); return 1; } */ // ref: 0x1000F929 HWND __fastcall SelRegn_1000F929(HWND hWnd, int a2, int a3) { return 0; } /* { int v3; // ebx HWND v4; // esi int v5; // ST08_4 HWND v6; // eax HWND result; // eax HWND v8; // eax HWND v9; // eax HWND v10; // eax int v11; // eax int v12; // eax int v13; // eax HWND v14; // eax HWND v15; // eax HWND v16; // eax HWND v17; // eax v3 = a2; v4 = hWnd; v5 = a2; v6 = GetDlgItem(hWnd, 1056); if ( local_10007C3B(v4, v6, v5, a3) ) return (HWND)SelRegn_1000F8DD(v4); v8 = GetDlgItem(v4, 1054); if ( local_10007C3B(v4, v8, v3, a3) ) return (HWND)SelConn_1000AC07((int)v4, 2); v9 = GetDlgItem(v4, 1105); result = (HWND)local_10007C3B(v4, v9, v3, a3); if ( result ) { v10 = GetDlgItem(v4, 1105); v11 = Sbar_100099DC(v10, v3, a3) - 1; if ( v11 ) { v12 = v11 - 1; if ( v12 ) { v13 = v12 - 1; if ( v13 ) { result = (HWND)(v13 - 1); if ( !result ) { v14 = GetFocus(); result = SelRegn_1000F61E(v14); } } else { v15 = GetFocus(); result = SelRegn_1000F711(v15); } } else { v16 = GetFocus(); result = SelRegn_1000F7C1(v16); } } else { v17 = GetFocus(); result = SelRegn_1000F859(v17); } } return result; } */ // ref: 0x1000F9F7 signed int __stdcall UiSelectRegion(DWORD *a1) { return 0; } /* { int v1; // eax int v2; // eax signed int result; // eax artfont_10001159(); v1 = SDrawGetFrameWindow(NULL); v2 = SDlgDialogBoxParam(hInstance, "SELREGION_DIALOG", v1, SelRegn_1000EF6B, 0); if ( a1 ) *a1 = dword_1002948C; if ( v2 == 1 ) { local_100078B6(); result = 1; } else { SErrSetLastError(1223); result = 0; } return result; } */ // 10010370: using guessed type int __stdcall SDlgDialogBoxParam(DWORD, DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // 1001041E: using guessed type int __stdcall SErrSetLastError(DWORD); // 1002948C: using guessed type int dword_1002948C; ================================================ FILE: DiabloUI/selyesno.cpp ================================================ // ref: 0x1000FA49 int __fastcall SelYesNo_YesNoDialog(HWND hWnd, char *dialogstr, char *hero, int nofocus) { yesno_dialog_string = dialogstr; yesno_hero_name = hero; yesno_remove_focus = nofocus; yesno_is_popup = 0; YesNoFunc = 0; return SDlgDialogBoxParam(ghUiInst, "SELYESNO_DIALOG", (int)hWnd, SelYesNo_WndProc, 0); } // 1002A500: using guessed type int yesno_remove_focus; // 1002A508: using guessed type int (*YesNoFunc)(void); // 1002A50C: using guessed type int yesno_is_popup; // ref: 0x1000FA87 LRESULT __stdcall SelYesNo_WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND v4; // eax HWND v5; // eax int v7; // edx HWND v8; // eax LONG v9; // eax HWND v10; // ecx HWND v11; // eax if (Msg == 2) { SelYesNo_RemoveYNDialog(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } if (Msg > 0x103) { if (Msg <= 0x105) { v11 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v11, Msg, wParam, lParam); return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } switch (Msg) { case 0x110u: SelYesNo_LoadSelYN_GFX(hWnd); return 0; case 0x111u: if (HIWORD(wParam) == 7) { Focus_GetAndBlitSpin(hWnd, lParam); } else if (HIWORD(wParam) == 6) { Focus_CheckPlayMove(lParam); Focus_DoBlitSpinIncFrame(hWnd, (HWND)lParam); } else { v7 = 1; if ((WORD)wParam == 1) { v8 = GetFocus(); v9 = GetWindowLongA(v8, -12); v10 = hWnd; if (v9 == 1109) v7 = 1; else v7 = 2; } else { if ((WORD)wParam == 2) { v7 = 2; } else if ((WORD)wParam != 1109) { return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } v10 = hWnd; } SelYesNo_DoSelectYesNo(v10, v7); } break; case 0x113u: v4 = GetFocus(); if (!Focus_DoBlitSpinIncFrame(hWnd, v4)) { v5 = GetDlgItem(hWnd, 1109); if (!v5) v5 = GetDlgItem(hWnd, 2); SetFocus(v5); } return 0; } } return (LRESULT)SDlgDefDialogProc(hWnd, Msg, (HDC)wParam, (HWND)lParam); } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x1000FBC7 void __fastcall SelYesNo_RemoveYNDialog(HWND hWnd) { HWND v1; // esi void **v2; // eax HWND v3; // eax v1 = hWnd; v2 = (void **)GetWindowLongA(hWnd, -21); local_FreeMemPtr(v2); if (yesno_remove_focus) Focus_DeleteSpinners(); Doom_DeleteFreeProcs(v1, yesno_msgtbl1); Doom_DeleteFreeProcs(v1, yesno_msgtbl2); if (yesno_hero_name) { v3 = GetParent(v1); SelHero_SetStringWithMsg(v3, 0); } } // 1002A500: using guessed type int yesno_remove_focus; // ref: 0x1000FC1C void __fastcall SelYesNo_LoadSelYN_GFX(HWND hWnd) { HWND v2; // eax DWORD *v3; // eax DWORD *v4; // edi const char *v5; // eax char *v6; // ST18_4 HWND v7; // eax v2 = GetParent(hWnd); if (yesno_hero_name) SelHero_SetStringWithMsg(v2, yesno_hero_name); v3 = local_AllocWndLongData(); v4 = v3; if (v3) { SetWindowLongA(hWnd, -21, (LONG)v3); if (yesno_is_popup) { if (DiabloUI_GetSpawned()) v5 = "ui_art\\swmmpop.pcx"; else v5 = "ui_art\\mmpopup.pcx"; } else { v5 = "ui_art\\black.pcx"; } local_LoadArtWithPal(hWnd, 0, "Popup", -1, 1, v5, (BYTE **)v4, v4 + 1, 1); } v6 = yesno_dialog_string; v7 = GetDlgItem(hWnd, 1026); SetWindowTextA(v7, v6); Doom_ParseWndProc3(hWnd, yesno_msgtbl2, AF_MEDGRAY); Doom_ParseWndProcs(hWnd, yesno_msgtbl1, AF_BIG, 1); if (yesno_remove_focus) Focus_LoadSpinner("ui_art\\focus.pcx"); else Focus_ResetSpinToZero(); SDlgSetTimer((int)hWnd, 1, 55, 0); local_DoUiWndProc2(hWnd, (DWORD *)yesno_msgtbl1); } // 1002A500: using guessed type int yesno_remove_focus; // 1002A50C: using guessed type int yesno_is_popup; // ref: 0x1000FCF6 void __fastcall SelYesNo_DoSelectYesNo(HWND hWnd, int option) { HWND v4; // eax TitleSnd_PlaySelectSound(); SDlgKillTimer((int)hWnd, 1); if (option == 2) { if (!YesNoFunc) goto LABEL_6; YesNoFunc(); } if (option == 1) { v4 = GetFocus(); option = GetWindowLongA(v4, -12); } LABEL_6: SDlgEndDialog(hWnd, (HANDLE)option); } // 1002A508: using guessed type int (*YesNoFunc)(void); // ref: 0x1000FD39 int __fastcall SelYesNo_SelOkDialog(HWND hWnd, char *dialogstr, char *hero, int nofocus) { yesno_dialog_string = dialogstr; yesno_hero_name = hero; yesno_remove_focus = nofocus; yesno_is_popup = 0; YesNoFunc = 0; return SDlgDialogBoxParam(ghUiInst, "SELOK_DIALOG", (int)hWnd, SelYesNo_WndProc, 0); } // 1002A500: using guessed type int yesno_remove_focus; // 1002A508: using guessed type int (*YesNoFunc)(void); // 1002A50C: using guessed type int yesno_is_popup; // ref: 0x1000FD77 int __fastcall SelYesNo_SpawnErrDialog(HWND hWnd, int string_rsrc, int is_popup) { char Buffer[256]; // [esp+4h] [ebp-100h] LoadStringA(ghUiInst, string_rsrc, Buffer, 255); yesno_is_popup = is_popup; yesno_remove_focus = 0; yesno_hero_name = 0; yesno_dialog_string = Buffer; YesNoFunc = 0; return SDlgDialogBoxParam(ghUiInst, "SPAWNERR_DIALOG", (int)hWnd, SelYesNo_WndProc, 0); } // 1002A500: using guessed type int yesno_remove_focus; // 1002A508: using guessed type int (*YesNoFunc)(void); // 1002A50C: using guessed type int yesno_is_popup; // ref: 0x1000FDE3 void __cdecl SelYesNo_cpp_init() { SelYesNo_cpp_float = SelYesNo_cpp_float_value; } // 1001F478: using guessed type int SelYesNo_cpp_float_value; // 1002A4FC: using guessed type int SelYesNo_cpp_float; ================================================ FILE: DiabloUI/title.cpp ================================================ // ref: 0x1000FDEE void __fastcall Title_BlitTitleBuffer(HWND hWnd) { DWORD *v2; // edi int v3; // eax HANDLE v4; // esi struct tagRECT Rect; // [esp+Ch] [ebp-18h] HWND hWnda; // [esp+20h] [ebp-4h] v2 = (DWORD *)GetWindowLongA(hWnd, -21); hWnda = GetDlgItem(hWnd, 1043); if (IsWindowVisible(hWnd) && hWnda && v2 && *v2 && titlePHTrans[0]) { v3 = titleTransIdx + 1; titleTransIdx = v3; if (!titlePHTrans[v3] || v3 >= 30) titleTransIdx = 0; GetWindowRect(hWnda, &Rect); ScreenToClient(hWnd, (LPPOINT)&Rect); ScreenToClient(hWnd, (LPPOINT)&Rect.right); v4 = GetPropA(hWnd, "TITLE_BUFFER"); if (v4) { SBltROP3( *(void **)v4, (void *)(Rect.left + *v2 + Rect.top * v2[1]), *((DWORD *)v4 + 1), *((DWORD *)v4 + 2), *((DWORD *)v4 + 1), v2[1], 0, 0xCC0020u); STransBlt(*(void **)v4, 0, 0, *((DWORD *)v4 + 1), (HANDLE)titlePHTrans[titleTransIdx]); InvalidateRect(hWnda, 0, 0); } } } // 1002A58C: using guessed type int titleTransIdx; // ref: 0x1000FEED void __cdecl Title_DeletePhTrans() { int *v0; // esi v0 = (int *)titlePHTrans; do { if (*v0) { STransDelete((HANDLE)*v0); *v0 = 0; } ++v0; } while ((signed int)v0 < (signed int)&titlePHTrans[30]); } // ref: 0x1000FF0F void __fastcall Title_FreeTransMem(HWND hWnd) { void **v2; // eax MAPDST void *v4; // eax Title_DeletePhTrans(); v2 = (void **)RemovePropA(hWnd, "TITLE_BUFFER"); if (v2) { v4 = *v2; if (v4) { SMemFree(v4, "C:\\Src\\Diablo\\DiabloUI\\Title.cpp", 114, 0); *v2 = 0; } SMemFree(v2, "C:\\Src\\Diablo\\DiabloUI\\Title.cpp", 117, 0); } } // ref: 0x1000FF51 void __fastcall Title_SetTitleBMP(HWND hWnd) { HWND v1; // eax MAPDST DWORD *v2; // esi void *v3; // eax struct tagRECT Rect; // [esp+0h] [ebp-18h] Title_FreeTransMem(hWnd); v1 = GetDlgItem(hWnd, 1043); if (v1) { GetClientRect(v1, &Rect); v2 = (DWORD *)SMemAlloc(0xCu, "C:\\Src\\Diablo\\DiabloUI\\Title.cpp", 134, 0); v3 = SMemAlloc(Rect.right * Rect.bottom, "C:\\Src\\Diablo\\DiabloUI\\Title.cpp", 136, 8); *v2 = (DWORD)v3; v2[1] = Rect.right; v2[2] = Rect.bottom; SDlgSetBitmapI(v1, 0, 0, -1, 1, v3, 0, Rect.right, Rect.bottom, -1); SetPropA(hWnd, "TITLE_BUFFER", v2); } } // ref: 0x1000FFE8 void __fastcall Title_LoadTitleImage(HWND hWnd, const char *pszFileName) { int v3; // edi DWORD *v4; // eax DWORD *v5; // esi int v6; // ebx int a5[4]; // [esp+8h] [ebp-20h] int data[2]; // [esp+18h] [ebp-10h] HANDLE *phTransOut; // [esp+20h] [ebp-8h] BYTE *pBuffer; // [esp+24h] [ebp-4h] v3 = 0; pBuffer = 0; local_LoadArtImage(pszFileName, &pBuffer, (DWORD *)data); v4 = (DWORD *)GetPropA(hWnd, "TITLE_BUFFER"); v5 = v4; if (pBuffer) { if (v4) { v6 = data[1] / v4[2]; if (v6 > 30) v6 = 30; if (v6 > 0) { phTransOut = (HANDLE *)titlePHTrans; do { a5[0] = 0; a5[2] = v5[1] - 1; a5[1] = v3 * v5[2]; a5[3] = v5[2] + a5[1] - 1; STransCreateI(pBuffer, v5[1], v5[2], 8, (int)a5, 16777466, phTransOut); ++phTransOut; ++v3; } while (v3 < v6); } } SMemFree(pBuffer, "C:\\Src\\Diablo\\DiabloUI\\Title.cpp", 197, 0); } titleTransIdx = 0; } // 1002A58C: using guessed type int titleTransIdx; // ref: 0x1001009E void __fastcall Title_LoadImgSetTimer(HWND hWnd, const char *pszFileName) { Title_SetTitleBMP(hWnd); Title_LoadTitleImage(hWnd, pszFileName); Title_BlitTitleBuffer(hWnd); SDlgSetTimer((int)hWnd, 2, 55, Title_BlitTitleBufFnc); } // ref: 0x100100CB void __stdcall Title_BlitTitleBufFnc(int hWnd, int a2, int a3, int a4) { Title_BlitTitleBuffer((HWND)hWnd); } // ref: 0x100100DC void __cdecl Title_cpp_init() { Title_cpp_float = Title_cpp_float_value; } // 1001F47C: using guessed type int Title_cpp_float_value; // 1002A588: using guessed type int Title_cpp_float; // ref: 0x100100E7 void __fastcall Title_KillTitleTimer(HWND hWnd) { HWND v1; // esi v1 = hWnd; SDlgKillTimer((int)hWnd, 2); Title_FreeTransMem(v1); } // ref: 0x100100FA BOOL __stdcall UiTitleDialog(int a1) { int v1; // eax artfont_LoadAllFonts(); v1 = (int)SDrawGetFrameWindow(NULL); SDlgDialogBoxParam(ghUiInst, "TITLESCREEN_DIALOG", v1, Title_MainProc, a1); return 1; } // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x10010126 LRESULT __stdcall Title_MainProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HWND v5; // eax if (uMsg <= 0x111) { if (uMsg != 273) { if (uMsg != 2) { if (uMsg == 135) return 4; if (uMsg != 256) { if (uMsg > 0x103) { if (uMsg <= 0x105) { v5 = (HWND)SDrawGetFrameWindow(NULL); SendMessageA(v5, uMsg, wParam, lParam); } else if (uMsg == 272) { Title_LoadAllTitleImgs(hWnd, lParam); PostMessageA(hWnd, 0x7E8u, 0, 0); return 1; } } return (LRESULT)SDlgDefDialogProc(hWnd, uMsg, (HDC)wParam, (HWND)lParam); } goto LABEL_25; } Title_KillTimerAndFree(hWnd); return (LRESULT)SDlgDefDialogProc(hWnd, uMsg, (HDC)wParam, (HWND)lParam); } goto LABEL_25; } if (uMsg != 275) { if (uMsg != 513 && uMsg != 516) { if (uMsg == 528) { if ((WORD)wParam == 513 || (WORD)wParam == 516) Title_KillAndFadeDlg(hWnd); } else if (uMsg == 2024) { if (!Fade_CheckRange5()) Fade_SetFadeTimer((int)hWnd); return 0; } return (LRESULT)SDlgDefDialogProc(hWnd, uMsg, (HDC)wParam, (HWND)lParam); } LABEL_25: Title_KillAndFadeDlg(hWnd); return 0; } if (wParam == 1) goto LABEL_25; return 0; } // 1001037C: using guessed type int __stdcall SDlgDefDialogProc(DWORD, DWORD, DWORD, DWORD); // 10010382: using guessed type DWORD __stdcall SDrawGetFrameWindow(); // ref: 0x10010235 void __fastcall Title_KillTimerAndFree(HWND hWnd) { void **v2; // eax Title_KillTitleTimer(hWnd); Doom_DeleteFreeProcs(hWnd, titlemsgtbl); v2 = (void **)GetWindowLongA(hWnd, -21); local_FreeMemPtr(v2); } // ref: 0x1001025A void __fastcall Title_LoadAllTitleImgs(HWND hWnd, int time) { DWORD *v4; // edi v4 = local_AllocWndLongData(); SetWindowLongA(hWnd, -21, (LONG)v4); if (v4) { local_LoadArtWithPal(hWnd, 0, &nullcharacter, -1, 1, "ui_art\\title.pcx", (BYTE **)v4, v4 + 1, 0); Fade_NoInputAndArt(hWnd, 0); } Doom_ParseWndProc3(hWnd, titlemsgtbl, AF_MEDGRAY); Title_LoadImgSetTimer(hWnd, "ui_art\\logo.pcx"); if (time) SDlgSetTimer((int)hWnd, 1, 1000 * time, 0); else SDlgSetTimer((int)hWnd, 1, 5000, 0); } // ref: 0x100102D7 void __fastcall Title_KillAndFadeDlg(HWND hWnd) { Fade_Range5SetZero(); SDlgKillTimer((int)hWnd, 1); Fade_UpdatePaletteRange(10); SDlgEndDialog(hWnd, (void *)HANDLE_FLAG_INHERIT); } ================================================ FILE: DiabloUI/titlesnd.cpp ================================================ // ref: 0x10010306 void __fastcall TitleSnd_SetSoundFunction(void(__stdcall *func)(const char *file)) { gfnSoundFunction = func; } // ref: 0x1001030D void __cdecl TitleSnd_InitSoundFunc() { gfnSoundFunction = 0; } // ref: 0x10010315 void __cdecl TitleSnd_PlayMoveSound() { if (gfnSoundFunction) gfnSoundFunction("sfx\\items\\titlemov.wav"); } // ref: 0x1001031F void __cdecl TitleSnd_PlaySelectSound() { if (gfnSoundFunction) gfnSoundFunction("sfx\\items\\titlslct.wav"); } // ref: 0x1001032E void __cdecl TitleSnd_cpp_init() { titlesnd_cpp_float = titlesnd_cpp_float_value; } // 1001F480: using guessed type int titlesnd_cpp_float_value; // 1002A590: using guessed type int titlesnd_cpp_float; ================================================ FILE: Hellfire.dsp ================================================ # Microsoft Developer Studio Project File - Name="Hellfire" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 5.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Application" 0x0101 CFG=Hellfire - 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 "Hellfire.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 "Hellfire.mak" CFG="Hellfire - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "Hellfire - Win32 Release" (based on "Win32 (x86) Application") !MESSAGE "Hellfire - Win32 Debug" (based on "Win32 (x86) Application") !MESSAGE "Hellfire - Win32 Release with PDB" (based on\ "Win32 (x86) Application") !MESSAGE # Begin Project # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "Hellfire - 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 /Gr /MT /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "HELLFIRE" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" # 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 kernel32.lib user32.lib gdi32.lib advapi32.lib shell32.lib version.lib /nologo /subsystem:windows /machine:I386 !ELSEIF "$(CFG)" == "Hellfire - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Hellfire__" # PROP BASE Intermediate_Dir "Hellfire__" # 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 /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c # ADD CPP /nologo /Gr /MTd /W3 /Gm /GX /Zi /O1 /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "HELLFIRE" /YX /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE 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 /debug /machine:I386 !ELSEIF "$(CFG)" == "Hellfire - Win32 Release with PDB" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Hellfire___Win32_Release_with_PDB" # PROP BASE Intermediate_Dir "Hellfire___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 /Gr /MT /W3 /GX /Zi /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "HELLFIRE" /FAs /YX /FD /c # SUBTRACT CPP /WX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" # 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 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 3rdParty/PKWare/WinRel/pkware.lib /nologo /subsystem:windows /debug /machine:I386 !ENDIF # Begin Target # Name "Hellfire - Win32 Release" # Name "Hellfire - Win32 Debug" # Name "Hellfire - 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\itemdat.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\misdat.cpp # End Source File # Begin Source File SOURCE=.\Source\missiles.cpp # End Source File # Begin Source File SOURCE=.\Source\monstdat.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\objdat.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\render.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\spelldat.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 # 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=.\Hellfire.ico # End Source File # Begin Source File SOURCE=.\Hellfire.rc # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\Source\appfat.h # End Source File # Begin Source File SOURCE=.\Source\automap.h # End Source File # Begin Source File SOURCE=.\Source\capture.h # End Source File # Begin Source File SOURCE=.\Source\codec.h # End Source File # Begin Source File SOURCE=.\Source\control.h # End Source File # Begin Source File SOURCE=.\Source\cursor.h # End Source File # Begin Source File SOURCE=.\Source\dead.h # End Source File # Begin Source File SOURCE=.\Source\debug.h # End Source File # Begin Source File SOURCE=.\defs.h # End Source File # Begin Source File SOURCE=.\Source\diablo.h # End Source File # Begin Source File SOURCE=.\Source\doom.h # End Source File # Begin Source File SOURCE=.\Source\drlg_l1.h # End Source File # Begin Source File SOURCE=.\Source\drlg_l2.h # End Source File # Begin Source File SOURCE=.\Source\drlg_l3.h # End Source File # Begin Source File SOURCE=.\Source\drlg_l4.h # End Source File # Begin Source File SOURCE=.\Source\dthread.h # End Source File # Begin Source File SOURCE=.\Source\dx.h # End Source File # Begin Source File SOURCE=.\Source\effects.h # End Source File # Begin Source File SOURCE=.\Source\encrypt.h # End Source File # Begin Source File SOURCE=.\Source\engine.h # End Source File # Begin Source File SOURCE=.\enums.h # End Source File # Begin Source File SOURCE=.\Source\error.h # End Source File # Begin Source File SOURCE=.\Source\fault.h # End Source File # Begin Source File SOURCE=.\Source\gamemenu.h # End Source File # Begin Source File SOURCE=.\Source\gendung.h # End Source File # Begin Source File SOURCE=.\Source\gmenu.h # End Source File # Begin Source File SOURCE=.\Source\help.h # End Source File # Begin Source File SOURCE=.\Source\init.h # End Source File # Begin Source File SOURCE=.\Source\interfac.h # End Source File # Begin Source File SOURCE=.\Source\inv.h # End Source File # Begin Source File SOURCE=.\Source\items.h # End Source File # Begin Source File SOURCE=.\Source\lighting.h # End Source File # Begin Source File SOURCE=.\Source\loadsave.h # End Source File # Begin Source File SOURCE=.\Source\logging.h # End Source File # Begin Source File SOURCE=.\Source\mainmenu.h # End Source File # Begin Source File SOURCE=.\Source\minitext.h # End Source File # Begin Source File SOURCE=.\Source\missiles.h # End Source File # Begin Source File SOURCE=.\Source\monster.h # End Source File # Begin Source File SOURCE=.\Source\movie.h # End Source File # Begin Source File SOURCE=.\Source\mpqapi.h # End Source File # Begin Source File SOURCE=.\Source\msg.h # End Source File # Begin Source File SOURCE=.\Source\msgcmd.h # End Source File # Begin Source File SOURCE=.\Source\multi.h # End Source File # Begin Source File SOURCE=.\Source\nthread.h # End Source File # Begin Source File SOURCE=.\Source\objects.h # End Source File # Begin Source File SOURCE=.\Source\pack.h # End Source File # Begin Source File SOURCE=.\Source\palette.h # End Source File # Begin Source File SOURCE=.\Source\path.h # End Source File # Begin Source File SOURCE=.\Source\pfile.h # End Source File # Begin Source File SOURCE=.\Source\player.h # End Source File # Begin Source File SOURCE=.\Source\plrmsg.h # End Source File # Begin Source File SOURCE=.\Source\portal.h # End Source File # Begin Source File SOURCE=.\Source\quests.h # End Source File # Begin Source File SOURCE=.\Source\render.h # End Source File # Begin Source File SOURCE=.\resource.h # End Source File # Begin Source File SOURCE=.\Source\restrict.h # End Source File # Begin Source File SOURCE=.\Source\scrollrt.h # End Source File # Begin Source File SOURCE=.\Source\setmaps.h # End Source File # Begin Source File SOURCE=.\Source\sha.h # End Source File # Begin Source File SOURCE=.\Source\sound.h # End Source File # Begin Source File SOURCE=.\Source\spells.h # End Source File # Begin Source File SOURCE=.\Source\stores.h # End Source File # Begin Source File SOURCE=.\structs.h # End Source File # Begin Source File SOURCE=.\Source\sync.h # End Source File # Begin Source File SOURCE=.\Source\textdat.h # End Source File # Begin Source File SOURCE=.\Source\themes.h # End Source File # Begin Source File SOURCE=.\Source\tmsg.h # End Source File # Begin Source File SOURCE=.\Source\town.h # End Source File # Begin Source File SOURCE=.\Source\towners.h # End Source File # Begin Source File SOURCE=.\Source\track.h # End Source File # Begin Source File SOURCE=.\Source\trigs.h # End Source File # Begin Source File SOURCE=.\types.h # End Source File # Begin Source File SOURCE=.\Source\wave.h # End Source File # End Group # End Target # End Project ================================================ FILE: Hellfire.dsw ================================================ Microsoft Developer Studio Workspace File, Format Version 5.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "Hellfire"=".\Hellfire.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 Begin Project Dependency Project_Dep_Name Pkware End Project Dependency }}} ############################################################################### Project: "DiabloUI"=".\DiabloUI\DiabloUI.dsp" - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name Storm End Project Dependency }}} ############################################################################### Project: "Pkware"=".\3rdParty\PKWare\Pkware.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> {{{ }}} ############################################################################### ================================================ FILE: Hellfire.rc ================================================ //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 "Hellfire.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 "Hellfire 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.sierracom", -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 "Hellfire 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 "Hellfire 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 Hellfire using the program ""SETUP.EXE"" on the Hellfire 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 "Hellfire 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 "Hellfire 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 "Hellfire 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 Hellfire 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 "Hellfire 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 Hellfire 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 "Hellfire 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 #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,0 PRODUCTVERSION 97,5,23,1 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", "Synergistic Software\0" VALUE "FileDescription", "Hellfire\0" VALUE "FileVersion", "1, 0, 1, 0\0" VALUE "InternalName", "Hellfire\0" VALUE "LegalCopyright", "Copyright 1997\0" VALUE "OriginalFilename", "hellfire.exe\0" VALUE "ProductName", "Synergistic Software Hellfire\0" VALUE "ProductVersion", "98, 1, 13, 1\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 ================================================ FILE: LICENSE.md ================================================ # Sustainable Use License Version 1.0 ## Acceptance By using the software, you agree to all of the terms and conditions below. ## Copyright License The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below. ## Limitations You may use or modify the software only for your own internal business purposes or for non-commercial or personal use. You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes. You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law. ## Patents The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company. ## Notices You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software. ## No Other Rights These terms do not imply any licenses other than those expressly granted in these terms. ## Termination If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently. ## No Liability As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim. ## Definitions The “licensor” is the entity offering these terms. The “software” is the software the licensor makes available under these terms, including any portion of it. “You” refers to the individual or entity agreeing to these terms. “Your company” is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect. “Your license” is the license granted to you for the software under these terms. “Use” means anything you do with the software requiring your license. “Trademark” means trademarks, service marks, and similar rights. ================================================ FILE: Makefile ================================================ # 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 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=$(sort $(filter-out Source/_asm.cpp Source/_render.cpp, $(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 ================================================ FILE: MakefileVC ================================================ # The $(VC5_DIR)/.. and $(VS6_DIR) directories are copies "Microsoft Visual Studio". # # To get a working setup on Linux or other "portable" copies of VS, # the following DLLs have to be copied to the # $(VS6_DIR)/VC98/Bin directory. # # - $(VS6_DIR)/Common/MSDev98/Bin/MSPDB60.DLL # # And to the $(VC5_DIR)/bin directory. # # - $(VC5_DIR)/SharedIDE/bin/MSDIS100.DLL # - $(VC5_DIR)/SharedIDE/bin/MSPDB50.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_DIR ?= $(HOME)/DevStudio_5.10/VC VC5_BIN_DIR = $(VC5_DIR)/bin VC5_INC_DIR = $(VC5_DIR)/include VC5_LIB_DIR = $(VC5_DIR)/lib IDE_DIR ?= $(VS6_DIR)/Common/MSDev98 IDE_BIN_DIR = $(IDE_DIR)/bin ifeq ($(OS),Windows_NT) CL5 = $(VC5_BIN_DIR)/CL.EXE CL6 = $(VC6_BIN_DIR)/CL.EXE RC = $(IDE_BIN_DIR)/RC.EXE VC5_LINK = $(VC5_BIN_DIR)/link.exe VC6_LINK = $(VC6_BIN_DIR)/link.exe else CL5 = wine $(VC5_BIN_DIR)/CL.EXE CL6 = wine $(VC6_BIN_DIR)/CL.EXE RC = wine $(IDE_BIN_DIR)/RC.EXE VC5_LINK = wine $(VC5_BIN_DIR)/link.exe VC6_LINK = wine $(VC6_BIN_DIR)/link.exe endif ifeq ($(HELLFIRE),1) CL = $(CL5) VC_INC_DIR = $(VC5_INC_DIR) else CL = $(CL6) VC_INC_DIR = $(VC6_INC_DIR) endif CFLAGS=/nologo /c /GX /W3 /O1 /I $(VC_INC_DIR) /FD /Gr /MT /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fp"Diablo.pch" /YX /G5 /Zi /FAs LINKFLAGS=/nologo /subsystem:windows /machine:I386 /incremental:no VERSION := 109 CFLAGS += /D "VERSION=$(VERSION)" ifeq ($(HELLFIRE),1) CFLAGS += /D "HELLFIRE" endif ifeq ($(SPAWN),1) CFLAGS += /D "SPAWN" endif ifeq ($(MAKE_BUILD),pdb) ifeq ($(HELLFIRE),1) VC_LINK = $(VC5_LINK) LINKFLAGS += /pdb:"hellfire.pdb" /LIBPATH:$(VC5_LIB_DIR) /debug else VC_LINK = $(VC6_LINK) LINKFLAGS += /pdb:"Diablo.pdb" /LIBPATH:$(VC6_LIB_DIR) /debug endif else VC_LINK = $(VC5_LINK) LINKFLAGS += /LIBPATH:$(VC5_LIB_DIR) endif all: Diablo.exe debug: CFLAGS += /D "_DEBUG" debug: Diablo.exe # fix compilation order to match the VC6 workspace files and exclude local assembly functions DIABLO_SRC=$(sort $(filter-out Source/_asm.cpp Source/_render.cpp Source/render.cpp, $(wildcard Source/*.cpp))) DIABLO_SRC += Source/render.cpp OBJS=$(DIABLO_SRC:.cpp=.obj) Diablo.exe: main_files diablo.res DiabloUI/diabloui.lib 3rdParty/Storm/storm.lib 3rdParty/PKWare/pkware.lib $(VC_LINK) /OUT:$@ $(LINKFLAGS) $(OBJS) diablo.res DiabloUI/diabloui.lib 3rdParty/Storm/storm.lib kernel32.lib user32.lib gdi32.lib advapi32.lib shell32.lib version.lib 3rdParty/PKWare/pkware.lib DiabloUI/diabloui.lib: make -C DiabloUI 3rdParty/Storm/storm.lib: make -C 3rdParty/Storm 3rdParty/PKWare/pkware.lib: make -C 3rdParty/PKWare # 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 $(VC_INC_DIR) /l 0x409 /fo $@ $< clean: @$(RM) -v $(OBJS) vc60.idb vc60.pdb Diablo.pdb Diablo.pch vc50.idb vc50.pdb hellfire.pdb make -C DiabloUI clean make -C 3rdParty/Storm clean make -C 3rdParty/PKWare clean .PHONY: clean all ================================================ FILE: README.md ================================================ [![Build Status](https://circleci.com/gh/diasurgical/devilution.svg?style=svg)](https://circleci.com/gh/diasurgical/devilution) [![Build Status](https://www.travis-ci.com/diasurgical/devilution.svg?branch=master)](https://www.travis-ci.com/diasurgical/devilution) [![Build status](https://ci.appveyor.com/api/projects/status/ce9wnf46gqqk6prp?svg=true)](https://ci.appveyor.com/project/AJenbo/devilution) [![Downloads](https://img.shields.io/github/downloads/diasurgical/devilution/total.svg)](https://github.com/diasurgical/devilution/releases) [![github stars](https://img.shields.io/github/stars/diasurgical/devilution.svg)](https://github.com/diasurgical/devilution/stargazers) ![Discord Channel](https://avatars3.githubusercontent.com/u/1965106?s=16&v=4) [Discord Chat Channel](https://discord.gg/YQKCAYQ) # Devilution Diablo devolved - magic behind the 1996 computer game **Note**, Devilution requires an original copy of `diabdat.mpq`. None of the Diablo 1 game assets are provided by this project. To get a legitimate copy of the game assets, please refer to the [GoG release of Diablo 1](https://www.gog.com/game/diablo). # 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 made in Diablo II also laid it to rest. At first the game appeared to be a lost cause, but thankfully a little oversight in 1997 made it not so. Diablo's development team moved on to Diablo II while passing the source code down to **Synergistic Software** for Hellfire. 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 entire game source codes 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 aims to be compatible with both the original and modern tools, but will adhere to standards used for the original compiler. ### 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 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 generation!**) 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 was 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 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](docs/INSTALL_linux.md) | [Windows](docs/INSTALL_windows.md) | [Mac](docs/INSTALL_mac.md). [Debug Build Features](docs/debug.md) | [Compatibility Matrix](docs/compatibility_matrix.md) | [Troubleshooting](docs/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 Devilution is functional over both GoG's Battle.net server and IPX using an ipx-wrapper. Additionally if `Standard.snp` from StarCraft 1.16.1 is used, local UDP play also becomes available. There are programs like ZeroTier to connect UDP globally. # Contributing [Guidelines](docs/CONTRIBUTING.md) # Modding Below are a few examples of some simple improvements made to the game. It is planned in the future to create tools for designing dungeons and graphics.
Example 1: Monster lifebar and item highlighting ![Monster lifebar+items](https://github.com/diasurgical/scalpel/blob/master/screens/mod1.png)
Example 2: New Diablo 2-like trade screen ![New trade screen](https://github.com/diasurgical/scalpel/blob/master/screens/mod2.png)
# F.A.Q.
Click to reveal > 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. If you don't have an original CD then you can [buy Diablo from GoG.com](https://www.gog.com/game/diablo). Alternatively you can also use `spawn.mpq` from the [http://ftp.blizzard.com/pub/demos/diablosw.exe](shareware) version and compile the with the SPAWN flag defined. > 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! This has been done as a side project, please see [DevilutionX](https://github.com/diasurgical/devilutionX). > What about Hellfire? Hellfire was a bit of a flop on the developer's part. Support may come in the future once the base game is finished. > 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 - Reverse engineered by GalaXyHaXz in 2018 - [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 - Diablodin - providing additional info about the PSX release - 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 ;) And a special thanks to all the support and people who work on this project to make it possible! <3 # Changelog [From the beginning until release](docs/CHANGELOG.md) # Legal Devilution is made publicly available and released under the Sustainable Use License (see [LICENSE](LICENSE.md)) The source code in this repository is for non-commerical use only. If you use the source code you may not charge others for access to it or any derivative work thereof. 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. Devilution and any of its' maintainers are in no way associated with or endorsed by Blizzard Entertainment(R). ================================================ FILE: Source/.clang-format ================================================ BasedOnStyle: webkit AlignTrailingComments: true AllowShortBlocksOnASingleLine: true AllowShortFunctionsOnASingleLine: None PointerAlignment: Right TabWidth: 4 UseTab: ForIndentation SortIncludes: false ================================================ FILE: Source/_asm.cpp ================================================ static __inline void asm_cel_light_edge(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src); static __inline void asm_cel_light_square(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src); static __inline void asm_trans_light_cel_0_2(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src); static __inline void asm_trans_light_edge_0_2(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src); static __inline void asm_trans_light_square_0_2(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src); static __inline void asm_trans_light_cel_1_3(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src); static __inline void asm_trans_light_edge_1_3(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src); static __inline void asm_trans_light_square_1_3(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src); static __inline unsigned int asm_trans_light_mask(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src, unsigned int mask); static __inline void asm_cel_light_edge(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src) { unsigned char l = w >> 1; if (w & 1) { (*dst)[0] = tbl[(*src)[0]]; (*src)++; (*dst)++; } if (l & 1) { (*dst)[0] = tbl[(*src)[0]]; (*dst)[1] = tbl[(*src)[1]]; *src += 2; *dst += 2; } asm_cel_light_square(l >> 1, tbl, dst, src); } static __inline void asm_cel_light_square(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src) { for (; w; --w) { (*dst)[0] = tbl[(*src)[0]]; (*dst)[1] = tbl[(*src)[1]]; (*dst)[2] = tbl[(*src)[2]]; (*dst)[3] = tbl[(*src)[3]]; *src += 4; *dst += 4; } } static __inline void asm_trans_light_cel_0_2(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src) { if (!(w & 1)) { asm_trans_light_edge_1_3(w >> 1, tbl, dst, src); } else { (*src)++; (*dst)++; asm_trans_light_edge_0_2(w >> 1, tbl, dst, src); } } static __inline void asm_trans_light_edge_0_2(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src) { unsigned char l = w >> 1; if (w & 1) { (*dst)[0] = tbl[(*src)[0]]; *src += 2; *dst += 2; } if (l) { asm_trans_light_square_0_2(l, tbl, dst, src); } } static __inline void asm_trans_light_square_0_2(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src) { for (; w; --w) { (*dst)[0] = tbl[(*src)[0]]; (*dst)[2] = tbl[(*src)[2]]; *src += 4; *dst += 4; } } static __inline void asm_trans_light_cel_1_3(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src) { if (!(w & 1)) { asm_trans_light_edge_0_2(w >> 1, tbl, dst, src); } else { (*dst)[0] = tbl[(*src)[0]]; (*src)++; (*dst)++; asm_trans_light_edge_1_3(w >> 1, tbl, dst, src); } } static __inline void asm_trans_light_edge_1_3(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src) { unsigned char l = w >> 1; if (w & 1) { (*dst)[1] = tbl[(*src)[1]]; *src += 2; *dst += 2; } if (l) { asm_trans_light_square_1_3(l, tbl, dst, src); } } static __inline void asm_trans_light_square_1_3(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src) { for (; w; --w) { (*dst)[1] = tbl[(*src)[1]]; (*dst)[3] = tbl[(*src)[3]]; *src += 4; *dst += 4; } } static __inline unsigned int asm_trans_light_mask(unsigned char w, BYTE *tbl, BYTE **dst, BYTE **src, unsigned int mask) { for (; w; --w, (*src)++, (*dst)++, mask *= 2) { if (mask & 0x80000000) (*dst)[0] = tbl[(*src)[0]]; } return mask; } ================================================ FILE: Source/_render.cpp ================================================ __declspec(naked) void drawTopArchesUpperScreen(BYTE *pBuff) { __asm { push ebx push edx push edi push esi mov edi, offset SpeedFrameTbl mov gpCelFrame, edi mov edi, ecx mov eax, light_table_index test al, al jz loc_46316A cmp al, lightmax jz loc_4631CA mov eax, level_cel_block and eax, 8000h jnz loc_4630FE mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov ebx, light_table_index shl ebx, 8 add ebx, pLightTbl mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 0Fh jz loc_463255 cmp ax, 1 jz loc_4632C5 cmp ax, 2 jz loc_463425 cmp ax, 3 jz loc_463698 cmp ax, 4 jz loc_46390B jmp loc_463AB3 loc_4630FE: mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 4 add eax, light_table_index shl eax, 2 add esi, eax mov eax, [esi] mov esi, pSpeedCels add esi, eax mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 0Fh loc_463133: cmp ax, 8 jz loc_463C5B cmp ax, 9 jz loc_463CC2 cmp ax, 0Ah jz loc_463DA3 cmp ax, 0Bh jz loc_463ED8 cmp ax, 0Ch jz loc_464011 jmp loc_464112 loc_46316A: mov eax, level_cel_block and eax, 8000h jz loc_46319C mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_46319C: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 7 add eax, 8 jmp loc_463133 loc_4631CA: mov eax, level_cel_block and eax, 8000h jz loc_4631FC mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_4631FC: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 7 jz loc_46420F cmp ax, 1 jz loc_464263 cmp ax, 2 jz loc_464321 cmp ax, 3 jz loc_46440E cmp ax, 4 jz loc_4644FB jmp loc_4645C7 loc_463255: push ebp mov ebp, 10h loc_46325B: cmp edi, gpBufEnd jb loc_4632BF mov ecx, 8 loc_463268: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463268 sub edi, 320h cmp edi, gpBufEnd jb loc_4632BF mov ecx, 8 loc_463299: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_463299 sub edi, 320h dec ebp jnz loc_46325B loc_4632BF: pop ebp jmp loc_464688 loc_4632C5: push ebp mov eax, edi and eax, 1 mov WorldBoolFlag, eax mov ebp, 20h loc_4632D5: mov edx, 20h loc_4632DA: xor eax, eax mov al, [esi] inc esi test al, al js loc_4633F8 sub edx, eax cmp edi, gpBufEnd jb loc_46341F mov ecx, eax mov eax, edi and eax, 1 cmp eax, WorldBoolFlag jnz loc_463377 push edx shr ecx, 1 jb loc_463340 shr ecx, 1 jnb loc_46331C mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_46331C: test cl, cl jz loc_46333E loc_463320: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463320 loc_46333E: jmp loc_463374 loc_463340: inc esi inc edi shr ecx, 1 jnb loc_463353 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_463353: test cl, cl jz loc_463374 loc_463357: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_463357 loc_463374: pop edx jmp loc_4633EF loc_463377: push edx shr ecx, 1 jb loc_4633B0 shr ecx, 1 jnb loc_46338D mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_46338D: test cl, cl jz loc_4633AE loc_463391: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_463391 loc_4633AE: jmp loc_4633EE loc_4633B0: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_4633CC mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_4633CC: test cl, cl jz loc_4633EE loc_4633D0: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_4633D0 loc_4633EE: pop edx loc_4633EF: test edx, edx jz loc_463404 jmp loc_4632DA loc_4633F8: neg al add edi, eax sub edx, eax jnz loc_4632DA loc_463404: mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax sub edi, 320h dec ebp jnz loc_4632D5 loc_46341F: pop ebp jmp loc_464688 loc_463425: push ebp xor eax, eax mov WorldBoolFlag, eax mov ebp, 1Eh loc_463432: cmp edi, gpBufEnd jb loc_463692 add edi, ebp mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_4634D2 mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_463499 shr ecx, 1 jnb loc_463475 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_463475: test cl, cl jz loc_463497 loc_463479: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463479 loc_463497: jmp loc_4634CD loc_463499: inc esi inc edi shr ecx, 1 jnb loc_4634AC mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_4634AC: test cl, cl jz loc_4634CD loc_4634B0: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_4634B0 loc_4634CD: jmp $+82h loc_4634D2: mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_463511 shr ecx, 1 jnb loc_4634EE mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_4634EE: test cl, cl jz loc_46350F loc_4634F2: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_4634F2 loc_46350F: jmp loc_46354F loc_463511: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_46352D mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_46352D: test cl, cl jz loc_46354F loc_463531: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463531 loc_46354F: sub edi, 320h sub ebp, 2 jge loc_463432 mov ebp, 2 loc_463563: cmp edi, gpBufEnd jb loc_463692 add edi, ebp mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_463603 mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_4635CA shr ecx, 1 jnb loc_4635A6 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_4635A6: test cl, cl jz loc_4635C8 loc_4635AA: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_4635AA loc_4635C8: jmp loc_4635FE loc_4635CA: inc esi inc edi shr ecx, 1 jnb loc_4635DD mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_4635DD: test cl, cl jz loc_4635FE loc_4635E1: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_4635E1 loc_4635FE: jmp $+82h loc_463603: mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_463642 shr ecx, 1 jnb loc_46361F mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_46361F: test cl, cl jz loc_463640 loc_463623: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_463623 loc_463640: jmp loc_463680 loc_463642: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_46365E mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_46365E: test cl, cl jz loc_463680 loc_463662: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463662 loc_463680: sub edi, 320h add ebp, 2 cmp ebp, 20h jnz loc_463563 loc_463692: pop ebp jmp loc_464688 loc_463698: push ebp xor eax, eax mov WorldBoolFlag, eax mov ebp, 1Eh loc_4636A5: cmp edi, gpBufEnd jb loc_463905 mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_463743 shr ecx, 1 jb loc_463703 shr ecx, 1 jnb loc_4636DF mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_4636DF: test cl, cl jz loc_463701 loc_4636E3: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_4636E3 loc_463701: jmp loc_463737 loc_463703: inc esi inc edi shr ecx, 1 jnb loc_463716 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_463716: test cl, cl jz loc_463737 loc_46371A: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_46371A loc_463737: mov edx, esi and edx, 2 add esi, edx jmp $+82h loc_463743: shr ecx, 1 jb loc_46377B shr ecx, 1 jnb loc_463758 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_463758: test cl, cl jz loc_463779 loc_46375C: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_46375C loc_463779: jmp loc_4637B9 loc_46377B: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_463797 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_463797: test cl, cl jz loc_4637B9 loc_46379B: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_46379B loc_4637B9: mov edx, esi and edx, 2 add esi, edx // loc_4637C0: sub edi, 320h add edi, ebp sub ebp, 2 jge loc_4636A5 mov ebp, 2 loc_4637D6: cmp edi, gpBufEnd jb loc_463905 mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_463874 shr ecx, 1 jb loc_463834 shr ecx, 1 jnb loc_463810 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_463810: test cl, cl jz loc_463832 loc_463814: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463814 loc_463832: jmp loc_463868 loc_463834: inc esi inc edi shr ecx, 1 jnb loc_463847 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_463847: test cl, cl jz loc_463868 loc_46384B: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_46384B loc_463868: mov edx, esi and edx, 2 add esi, edx jmp $+82h loc_463874: shr ecx, 1 jb loc_4638AC shr ecx, 1 jnb loc_463889 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_463889: test cl, cl jz loc_4638AA loc_46388D: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_46388D loc_4638AA: jmp loc_4638EA loc_4638AC: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_4638C8 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_4638C8: test cl, cl jz loc_4638EA loc_4638CC: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_4638CC loc_4638EA: mov edx, esi and edx, 2 add esi, edx // loc_4638F1: sub edi, 320h add edi, ebp add ebp, 2 cmp ebp, 20h jnz loc_4637D6 loc_463905: pop ebp jmp loc_464688 loc_46390B: push ebp xor eax, eax mov WorldBoolFlag, eax mov ebp, 1Eh loc_463918: cmp edi, gpBufEnd jb loc_463AAD add edi, ebp mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_4639B8 mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_46397F shr ecx, 1 jnb loc_46395B mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_46395B: test cl, cl jz loc_46397D loc_46395F: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_46395F loc_46397D: jmp loc_4639B3 loc_46397F: inc esi inc edi shr ecx, 1 jnb loc_463992 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_463992: test cl, cl jz loc_4639B3 loc_463996: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_463996 loc_4639B3: jmp $+82h loc_4639B8: mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_4639F7 shr ecx, 1 jnb loc_4639D4 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_4639D4: test cl, cl jz loc_4639F5 loc_4639D8: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_4639D8 loc_4639F5: jmp loc_463A35 loc_4639F7: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_463A13 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_463A13: test cl, cl jz loc_463A35 loc_463A17: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463A17 loc_463A35: sub edi, 320h sub ebp, 2 jge loc_463918 mov ebp, 8 loc_463A49: cmp edi, gpBufEnd jb loc_463AAD mov ecx, 8 loc_463A56: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463A56 sub edi, 320h cmp edi, gpBufEnd jb loc_463AAD mov ecx, 8 loc_463A87: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_463A87 sub edi, 320h dec ebp jnz loc_463A49 loc_463AAD: pop ebp jmp loc_464688 loc_463AB3: push ebp xor eax, eax mov WorldBoolFlag, eax mov ebp, 1Eh loc_463AC0: cmp edi, gpBufEnd jb loc_463C55 mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_463B5E shr ecx, 1 jb loc_463B1E shr ecx, 1 jnb loc_463AFA mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_463AFA: test cl, cl jz loc_463B1C loc_463AFE: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463AFE loc_463B1C: jmp loc_463B52 loc_463B1E: inc esi inc edi shr ecx, 1 jnb loc_463B31 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_463B31: test cl, cl jz loc_463B52 loc_463B35: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_463B35 loc_463B52: mov edx, esi and edx, 2 add esi, edx jmp $+82h loc_463B5E: shr ecx, 1 jb loc_463B96 shr ecx, 1 jnb loc_463B73 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_463B73: test cl, cl jz loc_463B94 loc_463B77: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_463B77 loc_463B94: jmp loc_463BD4 loc_463B96: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_463BB2 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_463BB2: test cl, cl jz loc_463BD4 loc_463BB6: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463BB6 loc_463BD4: mov edx, esi and edx, 2 add esi, edx // loc_463BDB: sub edi, 320h add edi, ebp sub ebp, 2 jge loc_463AC0 mov ebp, 8 loc_463BF1: cmp edi, gpBufEnd jb loc_463C55 mov ecx, 8 loc_463BFE: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_463BFE sub edi, 320h cmp edi, gpBufEnd jb loc_463C55 mov ecx, 8 loc_463C2F: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_463C2F sub edi, 320h dec ebp jnz loc_463BF1 loc_463C55: pop ebp jmp loc_464688 loc_463C5B: mov edx, 10h loc_463C60: cmp edi, gpBufEnd jb loc_464688 mov ecx, 8 loc_463C71: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_463C71 sub edi, 320h cmp edi, gpBufEnd jb loc_464688 mov ecx, 8 loc_463C9F: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_463C9F sub edi, 320h dec edx jnz loc_463C60 jmp loc_464688 loc_463CC2: push ebp mov eax, edi and eax, 1 mov WorldBoolFlag, eax mov ebp, 20h loc_463CD2: mov edx, 20h loc_463CD7: xor eax, eax mov al, [esi] inc esi test al, al js loc_463D76 sub edx, eax cmp edi, gpBufEnd jb loc_463D9D mov ecx, eax mov eax, edi and eax, 1 cmp eax, WorldBoolFlag jnz loc_463D36 shr ecx, 1 jnb loc_463D0D inc esi inc edi test ecx, ecx jz loc_463D6D jmp loc_463D46 loc_463D0D: shr ecx, 1 jnb loc_463D1D inc esi inc edi mov al, [esi] inc esi mov [edi], al inc edi test ecx, ecx jz loc_463D6D loc_463D1D: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_463D1D jmp loc_463D6D loc_463D36: shr ecx, 1 jnb loc_463D46 mov al, [esi] inc esi mov [edi], al inc edi test ecx, ecx jz loc_463D6D jmp loc_463D0D loc_463D46: shr ecx, 1 jnb loc_463D58 mov al, [esi] add esi, 2 mov [edi], al add edi, 2 test ecx, ecx jz loc_463D6D loc_463D58: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_463D58 loc_463D6D: test edx, edx jz loc_463D82 jmp loc_463CD7 loc_463D76: neg al add edi, eax sub edx, eax jnz loc_463CD7 loc_463D82: mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax sub edi, 320h dec ebp jnz loc_463CD2 loc_463D9D: pop ebp jmp loc_464688 loc_463DA3: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_463DAF: cmp edi, gpBufEnd jb loc_464688 add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_463E04 shr ecx, 2 jnb loc_463DEB mov ax, [esi+2] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi test ecx, ecx jz loc_463E2E loc_463DEB: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_463DEB jmp loc_463E2E loc_463E04: shr ecx, 2 jnb loc_463E19 mov ax, [esi+2] add esi, 4 mov [edi], al add edi, 2 test ecx, ecx jz loc_463E2E loc_463E19: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_463E19 loc_463E2E: sub edi, 320h sub edx, 2 jge loc_463DAF mov edx, 2 loc_463E42: cmp edi, gpBufEnd jb loc_464688 add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_463E97 shr ecx, 2 jnb loc_463E7E mov ax, [esi+2] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi test ecx, ecx jz loc_463EC1 loc_463E7E: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_463E7E jmp loc_463EC1 loc_463E97: shr ecx, 2 jnb loc_463EAC mov ax, [esi+2] add esi, 4 mov [edi], al add edi, 2 test ecx, ecx jz loc_463EC1 loc_463EAC: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_463EAC loc_463EC1: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_463E42 jmp loc_464688 loc_463ED8: push ebp xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_463EE5: cmp edi, gpBufEnd jb loc_46400B mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov ebp, ecx mov WorldBoolFlag, eax jz loc_463F3A shr ecx, 2 jz loc_463F26 loc_463F0F: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_463F0F loc_463F26: and ebp, 2 jz loc_463F64 mov ax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi jmp loc_463F64 loc_463F3A: shr ecx, 2 jz loc_463F54 loc_463F3F: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_463F3F loc_463F54: and ebp, 2 jz loc_463F64 mov ax, [esi] add esi, 4 mov [edi], al add edi, 2 loc_463F64: sub edi, 320h add edi, edx sub edx, 2 jge loc_463EE5 mov edx, 2 loc_463F7A: cmp edi, gpBufEnd jb loc_46400B mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_463FCD shr ecx, 2 jz loc_463FB9 loc_463FA2: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_463FA2 loc_463FB9: and ebp, 2 jz loc_463FF7 mov ax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi jmp loc_463FF7 loc_463FCD: shr ecx, 2 jz loc_463FE7 loc_463FD2: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_463FD2 loc_463FE7: and ebp, 2 jz loc_463FF7 mov ax, [esi] add esi, 4 mov [edi], al add edi, 2 loc_463FF7: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_463F7A loc_46400B: pop ebp jmp loc_464688 loc_464011: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_46401D: cmp edi, gpBufEnd jb loc_464688 add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_464072 shr ecx, 2 jnb loc_464059 mov ax, [esi+2] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi test ecx, ecx jz loc_46409C loc_464059: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_464059 jmp loc_46409C loc_464072: shr ecx, 2 jnb loc_464087 mov ax, [esi+2] add esi, 4 mov [edi], al add edi, 2 test ecx, ecx jz loc_46409C loc_464087: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_464087 loc_46409C: sub edi, 320h sub edx, 2 jge loc_46401D mov edx, 8 loc_4640B0: cmp edi, gpBufEnd jb loc_464688 mov ecx, 8 loc_4640C1: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_4640C1 sub edi, 320h cmp edi, gpBufEnd jb loc_464688 mov ecx, 8 loc_4640EF: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_4640EF sub edi, 320h dec edx jnz loc_4640B0 jmp loc_464688 loc_464112: push ebp xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_46411F: cmp edi, gpBufEnd jb loc_464209 mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov ebp, ecx mov WorldBoolFlag, eax jz loc_464174 shr ecx, 2 jz loc_464160 loc_464149: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_464149 loc_464160: and ebp, 2 jz loc_46419E mov ax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi jmp loc_46419E loc_464174: shr ecx, 2 jz loc_46418E loc_464179: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_464179 loc_46418E: and ebp, 2 jz loc_46419E mov ax, [esi] add esi, 4 mov [edi], al add edi, 2 loc_46419E: sub edi, 320h add edi, edx sub edx, 2 jge loc_46411F mov edx, 8 loc_4641B4: cmp edi, gpBufEnd jb loc_464209 mov ecx, 8 loc_4641C1: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_4641C1 sub edi, 320h cmp edi, gpBufEnd jb loc_464209 mov ecx, 8 loc_4641EB: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_4641EB sub edi, 320h dec edx jnz loc_4641B4 loc_464209: pop ebp jmp loc_464688 loc_46420F: mov edx, 10h xor eax, eax loc_464216: cmp edi, gpBufEnd jb loc_464688 mov ecx, 8 loc_464227: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_464227 sub edi, 320h cmp edi, gpBufEnd jb loc_464688 mov ecx, 8 loc_46424A: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_46424A sub edi, 320h dec edx jnz loc_464216 jmp loc_464688 loc_464263: push ebp mov eax, edi and eax, 1 mov WorldBoolFlag, eax mov ebp, 20h loc_464273: mov edx, 20h loc_464278: xor eax, eax mov al, [esi] inc esi test al, al js loc_4642F4 sub edx, eax cmp edi, gpBufEnd jb loc_46431B mov ecx, eax add esi, ecx mov eax, edi and eax, 1 cmp eax, WorldBoolFlag jnz loc_4642C7 xor eax, eax shr ecx, 1 jnb loc_4642AD inc edi test ecx, ecx jz loc_4642EE jmp loc_4642D6 loc_4642AD: shr ecx, 1 jnb loc_4642B9 inc edi mov [edi], al inc edi test ecx, ecx jz loc_4642EE loc_4642B9: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_4642B9 jmp loc_4642EE loc_4642C7: xor eax, eax shr ecx, 1 jnb loc_4642D6 mov [edi], al inc edi test ecx, ecx jz loc_4642EE jmp loc_4642AD loc_4642D6: shr ecx, 1 jnb loc_4642E3 mov [edi], al add edi, 2 test ecx, ecx jz loc_4642EE loc_4642E3: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_4642E3 loc_4642EE: test edx, edx jz loc_464300 jmp loc_464278 loc_4642F4: neg al add edi, eax sub edx, eax jnz loc_464278 loc_464300: mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax sub edi, 320h dec ebp jnz loc_464273 loc_46431B: pop ebp jmp loc_464688 loc_464321: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_46432D: cmp edi, gpBufEnd jb loc_464688 add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_46436F xor eax, eax shr ecx, 2 jnb loc_464361 inc edi mov [edi], al inc edi test ecx, ecx jz loc_46438A loc_464361: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_464361 jmp loc_46438A loc_46436F: xor eax, eax shr ecx, 2 jnb loc_46437F mov [edi], al add edi, 2 test ecx, ecx jz loc_46438A loc_46437F: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_46437F loc_46438A: sub edi, 320h test edx, edx jz loc_464399 sub edx, 2 jmp loc_46432D loc_464399: mov edx, 2 loc_46439E: cmp edi, gpBufEnd jb loc_464688 add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_4643E0 xor eax, eax shr ecx, 2 jnb loc_4643D2 inc edi mov [edi], al inc edi test ecx, ecx jz loc_4643FB loc_4643D2: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_4643D2 jmp loc_4643FB loc_4643E0: xor eax, eax shr ecx, 2 jnb loc_4643F0 mov [edi], al add edi, 2 test ecx, ecx jz loc_4643FB loc_4643F0: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_4643F0 loc_4643FB: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_46439E jmp loc_464688 loc_46440E: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_46441A: cmp edi, gpBufEnd jb loc_464688 mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_46445A xor eax, eax shr ecx, 2 jnb loc_46444C inc edi mov [edi], al inc edi test ecx, ecx jz loc_464475 loc_46444C: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_46444C jmp loc_464475 loc_46445A: xor eax, eax shr ecx, 2 jnb loc_46446A mov [edi], al add edi, 2 test ecx, ecx jz loc_464475 loc_46446A: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_46446A loc_464475: sub edi, 320h test edx, edx jz loc_464486 add edi, edx sub edx, 2 jmp loc_46441A loc_464486: mov edx, 2 loc_46448B: cmp edi, gpBufEnd jb loc_464688 mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_4644CB xor eax, eax shr ecx, 2 jnb loc_4644BD inc edi mov [edi], al inc edi test ecx, ecx jz loc_4644E6 loc_4644BD: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_4644BD jmp loc_4644E6 loc_4644CB: xor eax, eax shr ecx, 2 jnb loc_4644DB mov [edi], al add edi, 2 test ecx, ecx jz loc_4644E6 loc_4644DB: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_4644DB loc_4644E6: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_46448B jmp loc_464688 loc_4644FB: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_464507: cmp edi, gpBufEnd jb loc_464688 add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_464549 xor eax, eax shr ecx, 2 jnb loc_46453B inc edi mov [edi], al inc edi test ecx, ecx jz loc_464564 loc_46453B: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_46453B jmp loc_464564 loc_464549: xor eax, eax shr ecx, 2 jnb loc_464559 mov [edi], al add edi, 2 test ecx, ecx jz loc_464564 loc_464559: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_464559 loc_464564: sub edi, 320h test edx, edx jz loc_464573 sub edx, 2 jmp loc_464507 loc_464573: mov edx, 8 xor eax, eax loc_46457A: cmp edi, gpBufEnd jb loc_464688 mov ecx, 8 loc_46458B: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_46458B sub edi, 320h cmp edi, gpBufEnd jb loc_464688 mov ecx, 8 loc_4645AE: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_4645AE sub edi, 320h dec edx jnz loc_46457A jmp loc_464688 loc_4645C7: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_4645D3: cmp edi, gpBufEnd jb loc_464688 mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_464613 xor eax, eax shr ecx, 2 jnb loc_464605 inc edi mov [edi], al inc edi test ecx, ecx jz loc_46462E loc_464605: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_464605 jmp loc_46462E loc_464613: xor eax, eax shr ecx, 2 jnb loc_464623 mov [edi], al add edi, 2 test ecx, ecx jz loc_46462E loc_464623: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_464623 loc_46462E: sub edi, 320h test edx, edx jz loc_46463F add edi, edx sub edx, 2 jmp loc_4645D3 loc_46463F: mov edx, 8 xor eax, eax loc_464646: cmp edi, gpBufEnd jb loc_464688 mov ecx, 8 loc_464653: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_464653 sub edi, 320h cmp edi, gpBufEnd jb loc_464688 mov ecx, 8 loc_464672: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_464672 sub edi, 320h dec edx jnz loc_464646 jmp loc_464688 loc_464688: pop esi pop edi pop edx pop ebx retn } } __declspec(naked) void drawBottomArchesUpperScreen(BYTE *pBuff, DWORD *pMask) { __asm { push ebx push edi push esi mov edi, offset SpeedFrameTbl mov gpCelFrame, edi mov edi, ecx mov gpDrawMask, edx mov eax, light_table_index test al, al jz loc_4647A2 cmp al, lightmax jz loc_464802 mov eax, level_cel_block and eax, 8000h jnz loc_464736 mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov ebx, light_table_index shl ebx, 8 add ebx, pLightTbl mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 0Fh jz loc_46488D jz loc_464FBC cmp ax, 1 jz loc_4648D5 cmp ax, 2 jz loc_464964 cmp ax, 3 jz loc_464A30 cmp ax, 4 jz loc_464AFE jmp loc_464BBC loc_464736: mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 4 add eax, light_table_index shl eax, 2 add esi, eax mov eax, [esi] mov esi, pSpeedCels add esi, eax mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 0Fh loc_46476B: cmp ax, 8 jz loc_464C7A cmp ax, 9 jz loc_464CC1 cmp ax, 0Ah jz loc_464D4B cmp ax, 0Bh jz loc_464DE3 cmp ax, 0Ch jz loc_464E7D jmp loc_464F19 loc_4647A2: mov eax, level_cel_block and eax, 8000h jz loc_4647D4 mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_4647D4: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 7 add eax, 8 jmp loc_46476B loc_464802: mov eax, level_cel_block and eax, 8000h jz loc_464834 mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_464834: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 7 jz loc_464FBC cmp ax, 1 jz loc_465002 cmp ax, 2 jz loc_465091 cmp ax, 3 jz loc_465117 cmp ax, 4 jz loc_46519D jmp loc_465232 loc_46488D: mov edx, 20h loc_464892: cmp edi, gpBufEnd jb loc_4652C1 push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_4648AB: mov al, [esi] inc esi shl edx, 1 jnb loc_4648B5 xlat mov [edi], al loc_4648B5: inc edi dec ecx jnz loc_4648AB pop edx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_464892 jmp loc_4652C1 loc_4648D5: mov ecx, 20h loc_4648DA: push ecx mov eax, gpDrawMask mov eax, [eax] mov gdwCurrentMask, eax mov edx, 20h loc_4648EC: xor eax, eax mov al, [esi] inc esi test al, al js loc_464927 sub edx, eax cmp edi, gpBufEnd jb loc_4652C0 mov ecx, eax push edx mov edx, gdwCurrentMask loc_46490C: mov al, [esi] inc esi shl edx, 1 jnb loc_464916 xlat mov [edi], al loc_464916: inc edi dec ecx jnz loc_46490C mov gdwCurrentMask, edx pop edx test edx, edx jz loc_464944 jmp loc_4648EC loc_464927: neg al add edi, eax mov ecx, eax and ecx, 1Fh jz loc_464940 push eax mov eax, gdwCurrentMask shl eax, cl mov gdwCurrentMask, eax pop eax loc_464940: sub edx, eax jnz loc_4648EC loc_464944: pop ecx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec ecx jnz loc_4648DA jmp loc_4652C1 loc_464964: mov edx, 1Eh loc_464969: cmp edi, gpBufEnd jb loc_4652C1 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_46499E mov ax, [esi+2] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 test ecx, ecx jz loc_4649BB loc_46499E: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_46499E loc_4649BB: sub edi, 320h sub edx, 2 jge loc_464969 mov edx, 2 loc_4649CB: cmp edi, gpBufEnd jb loc_4652C1 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_464A00 mov ax, [esi+2] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 test ecx, ecx jz loc_464A1D loc_464A00: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_464A00 loc_464A1D: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_4649CB jmp loc_4652C1 loc_464A30: push ebp mov edx, 1Eh loc_464A36: cmp edi, gpBufEnd jb loc_464AF8 mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_464A6D loc_464A50: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_464A50 loc_464A6D: and ebp, 2 jz loc_464A88 mov ax, [esi] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 loc_464A88: sub edi, 320h add edi, edx sub edx, 2 jge loc_464A36 mov edx, 2 loc_464A9A: cmp edi, gpBufEnd jb loc_464AF8 mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_464ACD loc_464AB0: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_464AB0 loc_464ACD: and ebp, 2 jz loc_464AE8 mov ax, [esi] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 loc_464AE8: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_464A9A loc_464AF8: pop ebp jmp loc_4652C1 loc_464AFE: mov edx, 1Eh loc_464B03: cmp edi, gpBufEnd jb loc_4652C1 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_464B38 mov ax, [esi+2] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 test ecx, ecx jz loc_464B55 loc_464B38: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_464B38 loc_464B55: sub edi, 320h sub edx, 2 jge loc_464B03 mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_464B72: cmp edi, gpBufEnd jb loc_4652C1 push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h mov eax, esi and eax, 2 add esi, eax loc_464B92: mov al, [esi] inc esi shl edx, 1 jnb loc_464B9C xlat mov [edi], al loc_464B9C: inc edi dec ecx jnz loc_464B92 pop edx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_464B72 jmp loc_4652C1 loc_464BBC: push ebp mov edx, 1Eh loc_464BC2: cmp edi, gpBufEnd jb loc_464C74 mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_464BF9 loc_464BDC: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_464BDC loc_464BF9: and ebp, 2 jz loc_464C14 mov ax, [esi] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 loc_464C14: sub edi, 320h add edi, edx sub edx, 2 jge loc_464BC2 mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_464C33: cmp edi, gpBufEnd jb loc_464C74 push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_464C48: mov al, [esi] inc esi shl edx, 1 jnb loc_464C52 xlat mov [edi], al loc_464C52: inc edi dec ecx jnz loc_464C48 mov ebp, esi and ebp, 2 add esi, ebp pop edx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_464C33 loc_464C74: pop ebp jmp loc_4652C1 loc_464C7A: mov edx, 20h loc_464C7F: cmp edi, gpBufEnd jb loc_4652C1 push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_464C98: mov al, [esi] inc esi shl edx, 1 jnb loc_464CA1 mov [edi], al loc_464CA1: inc edi dec ecx jnz loc_464C98 pop edx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_464C7F jmp loc_4652C1 loc_464CC1: mov ecx, 20h loc_464CC6: push ecx mov eax, gpDrawMask mov eax, [eax] mov gdwCurrentMask, eax mov edx, 20h loc_464CD8: xor eax, eax mov al, [esi] inc esi test al, al js loc_464D12 sub edx, eax cmp edi, gpBufEnd jb loc_4652C0 push edx mov edx, gdwCurrentMask mov ecx, eax loc_464CF8: mov al, [esi] inc esi shl edx, 1 jnb loc_464D01 mov [edi], al loc_464D01: inc edi dec ecx jnz loc_464CF8 mov gdwCurrentMask, edx pop edx test edx, edx jz loc_464D2F jmp loc_464CD8 loc_464D12: neg al add edi, eax mov ecx, eax and ecx, 1Fh jz loc_464D2B mov ebx, gdwCurrentMask shl ebx, cl mov gdwCurrentMask, ebx loc_464D2B: sub edx, eax jnz loc_464CD8 loc_464D2F: pop ecx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec ecx jnz loc_464CC6 jmp loc_4652C1 loc_464D4B: mov edx, 1Eh loc_464D50: cmp edi, gpBufEnd jb loc_4652C1 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_464D7B mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_464D88 loc_464D7B: mov eax, [esi] add esi, 4 mov [edi], eax dec ecx lea edi, [edi+4] jnz loc_464D7B loc_464D88: sub edi, 320h sub edx, 2 jge loc_464D50 mov edx, 2 loc_464D98: cmp edi, gpBufEnd jb loc_4652C1 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_464DC3 mov ax, [esi+2] add esi, 4 mov [edi], ax test ecx, ecx lea edi, [edi+2] jz loc_464DD0 loc_464DC3: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_464DC3 loc_464DD0: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_464D98 jmp loc_4652C1 loc_464DE3: push ebp mov edx, 1Eh loc_464DE9: cmp edi, gpBufEnd jb loc_464E77 mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_464E10 loc_464E03: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_464E03 loc_464E10: and ebp, 2 jz loc_464E21 mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_464E21: sub edi, 320h add edi, edx sub edx, 2 jge loc_464DE9 mov edx, 2 loc_464E33: cmp edi, gpBufEnd jb loc_464E77 mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_464E56 loc_464E49: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_464E49 loc_464E56: and ebp, 2 jz loc_464E67 mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_464E67: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_464E33 loc_464E77: pop ebp jmp loc_4652C1 loc_464E7D: mov edx, 1Eh loc_464E82: cmp edi, gpBufEnd jb loc_4652C1 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_464EAD mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_464EBA loc_464EAD: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_464EAD loc_464EBA: sub edi, 320h sub edx, 2 jge loc_464E82 mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_464ED7: cmp edi, gpBufEnd jb loc_4652C1 push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_464EF0: mov al, [esi] inc esi shl edx, 1 jnb loc_464EF9 mov [edi], al loc_464EF9: inc edi dec ecx jnz loc_464EF0 pop edx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_464ED7 jmp loc_4652C1 loc_464F19: push ebp mov edx, 1Eh loc_464F1F: cmp edi, gpBufEnd jb loc_464FB6 mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_464F46 loc_464F39: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_464F39 loc_464F46: and ebp, 2 jz loc_464F57 mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_464F57: sub edi, 320h add edi, edx sub edx, 2 jge loc_464F1F mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_464F76: cmp edi, gpBufEnd jb loc_464FB6 push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_464F8B: mov al, [esi] inc esi shl edx, 1 jnb loc_464F94 mov [edi], al loc_464F94: inc edi dec ecx jnz loc_464F8B mov ebp, esi and ebp, 2 add esi, ebp pop edx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_464F76 loc_464FB6: pop ebp jmp loc_4652C1 loc_464FBC: mov edx, 20h loc_464FC1: cmp edi, gpBufEnd jb loc_4652C1 push edx mov eax, gpDrawMask mov edx, [eax] xor eax, eax mov ecx, 20h loc_464FDC: shl edx, 1 jnb loc_464FE2 mov [edi], al loc_464FE2: inc edi dec ecx jnz loc_464FDC pop edx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_464FC1 jmp loc_4652C1 loc_465002: mov ecx, 20h loc_465007: push ecx mov eax, gpDrawMask mov eax, [eax] mov gdwCurrentMask, eax mov edx, 20h loc_465019: xor eax, eax mov al, [esi] inc esi test al, al js loc_465054 sub edx, eax cmp edi, gpBufEnd jb loc_4652C0 push edx mov edx, gdwCurrentMask mov ecx, eax add esi, ecx xor eax, eax loc_46503D: shl edx, 1 jnb loc_465043 mov [edi], al loc_465043: inc edi dec ecx jnz loc_46503D mov gdwCurrentMask, edx pop edx test edx, edx jz loc_465071 jmp loc_465019 loc_465054: neg al add edi, eax mov ecx, eax and ecx, 1Fh jz loc_46506D mov ebx, gdwCurrentMask shl ebx, cl mov gdwCurrentMask, ebx loc_46506D: sub edx, eax jnz loc_465019 loc_465071: pop ecx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec ecx jnz loc_465007 jmp loc_4652C1 loc_465091: mov edx, 1Eh xor eax, eax loc_465098: cmp edi, gpBufEnd jb loc_4652C1 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_4650BC mov [edi], ax add edi, 2 test ecx, ecx jz loc_4650C4 loc_4650BC: mov [edi], eax add edi, 4 dec ecx jnz loc_4650BC loc_4650C4: sub edi, 320h test edx, edx jz loc_4650D3 sub edx, 2 jmp loc_465098 loc_4650D3: mov edx, 2 loc_4650D8: cmp edi, gpBufEnd jb loc_4652C1 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_4650FC mov [edi], ax add edi, 2 test ecx, ecx jz loc_465104 loc_4650FC: mov [edi], eax add edi, 4 dec ecx jnz loc_4650FC loc_465104: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_4650D8 jmp loc_4652C1 loc_465117: mov edx, 1Eh xor eax, eax loc_46511E: cmp edi, gpBufEnd jb loc_4652C1 mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465140 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465148 loc_465140: mov [edi], eax add edi, 4 dec ecx jnz loc_465140 loc_465148: sub edi, 320h test edx, edx jz loc_465159 add edi, edx sub edx, 2 jmp loc_46511E loc_465159: mov edx, 2 loc_46515E: cmp edi, gpBufEnd jb loc_4652C1 mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465180 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465188 loc_465180: mov [edi], eax add edi, 4 dec ecx jnz loc_465180 loc_465188: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_46515E jmp loc_4652C1 loc_46519D: mov edx, 1Eh xor eax, eax loc_4651A4: cmp edi, gpBufEnd jb loc_4652C1 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_4651C8 mov [edi], ax add edi, 2 test ecx, ecx jz loc_4651D0 loc_4651C8: mov [edi], eax add edi, 4 dec ecx jnz loc_4651C8 loc_4651D0: sub edi, 320h test edx, edx jz loc_4651DF sub edx, 2 jmp loc_4651A4 loc_4651DF: mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_4651F1: cmp edi, gpBufEnd jb loc_4652C1 push edx mov eax, gpDrawMask mov edx, [eax] xor eax, eax mov ecx, 20h loc_46520C: shl edx, 1 jnb loc_465212 mov [edi], al loc_465212: inc edi dec ecx jnz loc_46520C pop edx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_4651F1 jmp loc_4652C1 loc_465232: mov edx, 1Eh xor eax, eax loc_465239: cmp edi, gpBufEnd jb $+82h mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_46525B mov [edi], ax add edi, 2 test ecx, ecx jz loc_465263 loc_46525B: mov [edi], eax add edi, 4 dec ecx jnz loc_46525B loc_465263: sub edi, 320h test edx, edx jz loc_465274 add edi, edx sub edx, 2 jmp loc_465239 loc_465274: mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_465286: cmp edi, gpBufEnd jb loc_4652C1 push edx mov eax, gpDrawMask mov edx, [eax] xor eax, eax mov ecx, 20h loc_46529D: shl edx, 1 jnb loc_4652A3 mov [edi], al loc_4652A3: inc edi dec ecx jnz loc_46529D pop edx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_465286 jmp loc_4652C1 loc_4652C0: pop eax loc_4652C1: pop esi pop edi pop ebx retn } } __declspec(naked) void drawUpperScreen(BYTE *pBuff) { __asm { push ebx push edx push edi push esi mov edx, cel_transparency_active test edx, edx jz loc_465372 mov dl, arch_draw_type cmp dl, 0 jnz loc_4652EC call drawTopArchesUpperScreen jmp loc_465F33 loc_4652EC: cmp dl, 1 jnz loc_46532F mov ebx, level_piece_id mov al, block_lvid[ebx] cmp al, 1 jz loc_465307 cmp al, 3 jz loc_465307 jmp loc_46532F loc_465307: mov edx, offset LeftMask add edx, 7Ch call drawBottomArchesUpperScreen jmp loc_465F33 cmp al, 4 jnz loc_46532F mov edx, offset RightMask add edx, 7Ch call drawBottomArchesUpperScreen jmp loc_465F33 loc_46532F: cmp dl, 2 jnz loc_465372 mov ebx, level_piece_id mov al, block_lvid[ebx] cmp al, 2 jz loc_46534A cmp al, 3 jz loc_46534A jmp loc_465372 loc_46534A: mov edx, offset RightMask add edx, 7Ch call drawBottomArchesUpperScreen jmp loc_465F33 cmp al, 4 jnz loc_465372 mov edx, offset LeftMask add edx, 7Ch call drawBottomArchesUpperScreen jmp loc_465F33 loc_465372: mov edi, offset SpeedFrameTbl mov gpCelFrame, edi mov edi, ecx mov eax, light_table_index test al, al jz loc_465474 cmp al, lightmax jz loc_4654D4 mov eax, level_cel_block and eax, 8000h jnz loc_46540A mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov ebx, light_table_index shl ebx, 8 add ebx, pLightTbl mov eax, level_cel_block shr eax, 0Ch and eax, 0Fh jz loc_46555D cmp ax, 1 jz loc_4655B5 cmp ax, 2 jz loc_465663 cmp ax, 3 jz loc_465765 cmp ax, 4 jz loc_465867 jmp loc_465939 loc_46540A: mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 4 add eax, light_table_index shl eax, 2 add esi, eax mov eax, [esi] mov esi, pSpeedCels add esi, eax mov eax, level_cel_block shr eax, 0Ch and eax, 0Fh loc_46543D: cmp ax, 8 jz loc_465A0B cmp ax, 9 jz loc_465A3C cmp ax, 0Ah jz loc_465AA8 cmp ax, 0Bh jz loc_465B40 cmp ax, 0Ch jz loc_465BDA jmp loc_465C53 loc_465474: mov eax, level_cel_block and eax, 8000h jz loc_4654A6 mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_4654A6: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 7 add eax, 8 jmp loc_46543D loc_4654D4: mov eax, level_cel_block and eax, 8000h jz loc_465506 mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_465506: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block shr eax, 0Ch and eax, 7 jz loc_465CC8 cmp ax, 1 jz loc_465CF6 cmp ax, 2 jz loc_465D58 cmp ax, 3 jz loc_465DDE cmp ax, 4 jz loc_465E64 jmp loc_465ECF loc_46555D: mov edx, 20h loc_465562: cmp edi, gpBufEnd jb loc_465F33 mov ecx, 20h push edx loc_465574: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_465574 pop edx sub edi, 320h dec edx jnz loc_465562 jmp loc_465F33 loc_4655B5: push ebp mov ebp, 20h loc_4655BB: mov edx, 20h loc_4655C0: xor eax, eax mov al, [esi] inc esi test al, al js loc_465644 sub edx, eax cmp edi, gpBufEnd jb loc_46565D mov ecx, eax push edx cmp cl, 4 jl loc_465611 loc_4655DF: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_4655DF loc_465611: cmp cl, 2 jl loc_46562C mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 loc_46562C: and cl, 1 jz loc_46563A mov dl, [esi] inc esi mov dl, [ebx+edx] mov [edi], dl inc edi loc_46563A: pop edx test edx, edx jz loc_465650 jmp loc_4655C0 loc_465644: neg al add edi, eax sub edx, eax jnz loc_4655C0 loc_465650: sub edi, 320h dec ebp jnz loc_4655BB loc_46565D: pop ebp jmp loc_465F33 loc_465663: push ebp mov ebp, 1Eh loc_465669: cmp edi, gpBufEnd jb loc_46575F add edi, ebp mov ecx, 20h sub ecx, ebp mov edx, ecx and edx, 2 add esi, edx cmp cl, 4 jl loc_4656BC loc_46568A: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_46568A loc_4656BC: cmp cl, 2 jl loc_4656D7 mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 loc_4656D7: sub edi, 320h sub ebp, 2 jge loc_465669 mov ebp, 2 loc_4656E7: cmp edi, gpBufEnd jb loc_46575F add edi, ebp mov ecx, 20h sub ecx, ebp mov edx, ecx and edx, 2 add esi, edx cmp cl, 4 jl loc_465736 loc_465704: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_465704 loc_465736: cmp cl, 2 jl loc_465751 mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 loc_465751: sub edi, 320h add ebp, 2 cmp ebp, 20h jnz loc_4656E7 loc_46575F: pop ebp jmp loc_465F33 loc_465765: push ebp mov ebp, 1Eh loc_46576B: cmp edi, gpBufEnd jb loc_465861 mov ecx, 20h sub ecx, ebp cmp cl, 4 jl loc_4657B5 loc_465783: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_465783 loc_4657B5: cmp cl, 2 jl loc_4657D0 mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 loc_4657D0: mov edx, esi and edx, 2 add esi, edx sub edi, 320h add edi, ebp sub ebp, 2 jge loc_46576B mov ebp, 2 loc_4657E9: cmp edi, gpBufEnd jb loc_465861 mov ecx, 20h sub ecx, ebp cmp cl, 4 jl loc_46582F loc_4657FD: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_4657FD loc_46582F: cmp cl, 2 jl loc_46584A mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 loc_46584A: mov edx, esi and edx, 2 add esi, edx sub edi, 320h add edi, ebp add ebp, 2 cmp ebp, 20h jnz loc_4657E9 loc_465861: pop ebp jmp loc_465F33 loc_465867: push ebp mov ebp, 1Eh loc_46586D: cmp edi, gpBufEnd jb loc_465933 add edi, ebp mov ecx, 20h sub ecx, ebp mov edx, ecx and edx, 2 add esi, edx cmp cl, 4 jl loc_4658C0 loc_46588E: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_46588E loc_4658C0: cmp cl, 2 jl loc_4658DB mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 loc_4658DB: sub edi, 320h sub ebp, 2 jge loc_46586D mov ebp, 10h loc_4658EB: cmp edi, gpBufEnd jb loc_465933 mov ecx, 20h loc_4658F8: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_4658F8 sub edi, 320h dec ebp jnz loc_4658EB loc_465933: pop ebp jmp loc_465F33 loc_465939: push ebp mov ebp, 1Eh loc_46593F: cmp edi, gpBufEnd jb loc_465A05 mov ecx, 20h sub ecx, ebp cmp cl, 4 jl loc_465989 loc_465957: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_465957 loc_465989: cmp cl, 2 jl loc_4659A4 mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 loc_4659A4: mov edx, esi and edx, 2 add esi, edx sub edi, 320h add edi, ebp sub ebp, 2 jge loc_46593F mov ebp, 10h loc_4659BD: cmp edi, gpBufEnd jb loc_465A05 mov ecx, 20h loc_4659CA: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_4659CA sub edi, 320h dec ebp jnz loc_4659BD loc_465A05: pop ebp jmp loc_465F33 loc_465A0B: mov edx, 20h loc_465A10: cmp edi, gpBufEnd jb loc_465F33 mov ecx, 8 loc_465A21: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_465A21 sub edi, 320h dec edx jnz loc_465A10 jmp loc_465F33 loc_465A3C: push ebp mov ebp, 20h loc_465A42: mov edx, 20h loc_465A47: xor eax, eax mov al, [esi] inc esi test al, al js loc_465A91 sub edx, eax cmp edi, gpBufEnd jb loc_465AA2 mov ecx, eax shr ecx, 1 jnb loc_465A6A mov al, [esi] inc esi mov [edi], al inc edi test ecx, ecx jz loc_465A8B loc_465A6A: shr ecx, 1 jnb loc_465A7E mov ax, [esi] add esi, 2 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465A8B loc_465A7E: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_465A7E loc_465A8B: test edx, edx jz loc_465A99 jmp loc_465A47 loc_465A91: neg al add edi, eax sub edx, eax jnz loc_465A47 loc_465A99: sub edi, 320h dec ebp jnz loc_465A42 loc_465AA2: pop ebp jmp loc_465F33 loc_465AA8: mov edx, 1Eh loc_465AAD: cmp edi, gpBufEnd jb loc_465F33 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465AD8 mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465AE5 loc_465AD8: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_465AD8 loc_465AE5: sub edi, 320h sub edx, 2 jge loc_465AAD mov edx, 2 loc_465AF5: cmp edi, gpBufEnd jb loc_465F33 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465B20 mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465B2D loc_465B20: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_465B20 loc_465B2D: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_465AF5 jmp loc_465F33 loc_465B40: push ebp mov edx, 1Eh loc_465B46: cmp edi, gpBufEnd jb loc_465BD4 mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_465B6D loc_465B60: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_465B60 loc_465B6D: and ebp, 2 jz loc_465B7E mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_465B7E: sub edi, 320h add edi, edx sub edx, 2 jge loc_465B46 mov edx, 2 loc_465B90: cmp edi, gpBufEnd jb loc_465BD4 mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_465BB3 loc_465BA6: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_465BA6 loc_465BB3: and ebp, 2 jz loc_465BC4 mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_465BC4: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_465B90 loc_465BD4: pop ebp jmp loc_465F33 loc_465BDA: mov edx, 1Eh loc_465BDF: cmp edi, gpBufEnd jb loc_465F33 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465C0A mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465C17 loc_465C0A: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_465C0A loc_465C17: sub edi, 320h sub edx, 2 jge loc_465BDF mov edx, 10h loc_465C27: cmp edi, gpBufEnd jb loc_465F33 mov ecx, 8 loc_465C38: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_465C38 sub edi, 320h dec edx jnz loc_465C27 jmp loc_465F33 loc_465C53: push ebp mov edx, 1Eh loc_465C59: cmp edi, gpBufEnd jb loc_465CC2 mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_465C7C loc_465C6F: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_465C6F loc_465C7C: and ebp, 2 jz loc_465C8D mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_465C8D: sub edi, 320h add edi, edx sub edx, 2 jge loc_465C59 mov edx, 10h loc_465C9F: cmp edi, gpBufEnd jb loc_465CC2 mov ecx, 8 loc_465CAC: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_465CAC sub edi, 320h dec edx jnz loc_465C9F loc_465CC2: pop ebp jmp loc_465F33 loc_465CC8: mov edx, 20h xor eax, eax loc_465CCF: cmp edi, gpBufEnd jb loc_465F33 mov ecx, 8 loc_465CE0: mov [edi], eax add edi, 4 dec ecx jnz loc_465CE0 sub edi, 320h dec edx jnz loc_465CCF jmp loc_465F33 loc_465CF6: push ebp mov ebp, 20h loc_465CFC: mov edx, 20h loc_465D01: xor eax, eax mov al, [esi] inc esi test al, al js loc_465D41 sub edx, eax cmp edi, gpBufEnd jb loc_465D52 mov ecx, eax add esi, ecx xor eax, eax shr ecx, 1 jnb loc_465D25 mov [edi], al inc edi test ecx, ecx jz loc_465D3B loc_465D25: shr ecx, 1 jnb loc_465D33 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465D3B loc_465D33: mov [edi], eax add edi, 4 dec ecx jnz loc_465D33 loc_465D3B: test edx, edx jz loc_465D49 jmp loc_465D01 loc_465D41: neg al add edi, eax sub edx, eax jnz loc_465D01 loc_465D49: sub edi, 320h dec ebp jnz loc_465CFC loc_465D52: pop ebp jmp loc_465F33 loc_465D58: mov edx, 1Eh xor eax, eax loc_465D5F: cmp edi, gpBufEnd jb loc_465F33 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465D83 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465D8B loc_465D83: mov [edi], eax add edi, 4 dec ecx jnz loc_465D83 loc_465D8B: sub edi, 320h test edx, edx jz loc_465D9A sub edx, 2 jmp loc_465D5F loc_465D9A: mov edx, 2 loc_465D9F: cmp edi, gpBufEnd jb loc_465F33 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465DC3 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465DCB loc_465DC3: mov [edi], eax add edi, 4 dec ecx jnz loc_465DC3 loc_465DCB: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_465D9F jmp loc_465F33 loc_465DDE: mov edx, 1Eh xor eax, eax loc_465DE5: cmp edi, gpBufEnd jb loc_465F33 mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465E07 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465E0F loc_465E07: mov [edi], eax add edi, 4 dec ecx jnz loc_465E07 loc_465E0F: sub edi, 320h test edx, edx jz loc_465E20 add edi, edx sub edx, 2 jmp loc_465DE5 loc_465E20: mov edx, 2 loc_465E25: cmp edi, gpBufEnd jb loc_465F33 mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465E47 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465E4F loc_465E47: mov [edi], eax add edi, 4 dec ecx jnz loc_465E47 loc_465E4F: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_465E25 jmp loc_465F33 loc_465E64: mov edx, 1Eh xor eax, eax loc_465E6B: cmp edi, gpBufEnd jb loc_465F33 add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465E8F mov [edi], ax add edi, 2 test ecx, ecx jz loc_465E97 loc_465E8F: mov [edi], eax add edi, 4 dec ecx jnz loc_465E8F loc_465E97: sub edi, 320h test edx, edx jz loc_465EA6 sub edx, 2 jmp loc_465E6B loc_465EA6: mov edx, 10h loc_465EAB: cmp edi, gpBufEnd jb $+82h mov ecx, 8 loc_465EBC: mov [edi], eax add edi, 4 dec ecx jnz loc_465EBC sub edi, 320h dec edx jnz loc_465EAB jmp loc_465F33 loc_465ECF: mov edx, 1Eh xor eax, eax loc_465ED6: cmp edi, gpBufEnd jb loc_465F33 mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_465EF4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_465EFC loc_465EF4: mov [edi], eax add edi, 4 dec ecx jnz loc_465EF4 loc_465EFC: sub edi, 320h test edx, edx jz loc_465F0D add edi, edx sub edx, 2 jmp loc_465ED6 loc_465F0D: mov edx, 10h loc_465F12: cmp edi, gpBufEnd jb loc_465F33 mov ecx, 8 loc_465F1F: mov [edi], eax add edi, 4 dec ecx jnz loc_465F1F sub edi, 320h dec edx jnz loc_465F12 jmp loc_465F33 pop eax loc_465F33: pop esi pop edi pop edx pop ebx retn } } __declspec(naked) void drawTopArchesLowerScreen(BYTE *pBuff) { __asm { push ebx push edx push edi push esi mov edi, offset SpeedFrameTbl mov gpCelFrame, edi mov edi, ecx mov eax, light_table_index test al, al jz loc_466042 cmp al, lightmax jz loc_4660A2 mov eax, level_cel_block and eax, 8000h jnz loc_465FD6 mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov ebx, light_table_index shl ebx, 8 add ebx, pLightTbl mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 0Fh jz loc_46612D cmp ax, 1 jz loc_4661AD cmp ax, 2 jz loc_466310 cmp ax, 3 jz loc_466611 cmp ax, 4 jz loc_466912 jmp loc_466B11 loc_465FD6: mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 4 add eax, light_table_index shl eax, 2 add esi, eax mov eax, [esi] mov esi, pSpeedCels add esi, eax mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 0Fh loc_46600B: cmp ax, 8 jz loc_466D10 cmp ax, 9 jz loc_466D7F cmp ax, 0Ah jz loc_466E62 cmp ax, 0Bh jz loc_46701C cmp ax, 0Ch jz loc_4671E1 jmp loc_46732D loc_466042: mov eax, level_cel_block and eax, 8000h jz loc_466074 mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_466074: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 7 add eax, 8 jmp loc_46600B loc_4660A2: mov eax, level_cel_block and eax, 8000h jz loc_4660D4 mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_4660D4: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 7 jz loc_46747D cmp ax, 1 jz loc_4674D9 cmp ax, 2 jz loc_467599 cmp ax, 3 jz loc_467692 cmp ax, 4 jz loc_46778F jmp loc_46786B loc_46612D: push ebp mov ebp, 10h loc_466133: cmp edi, gpBufEnd jb loc_466143 add esi, 20h add edi, 20h jmp loc_466166 loc_466143: mov ecx, 8 loc_466148: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_466148 loc_466166: sub edi, 320h cmp edi, gpBufEnd jb loc_46617C add esi, 20h add edi, 20h jmp loc_46619E loc_46617C: mov ecx, 8 loc_466181: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_466181 loc_46619E: sub edi, 320h dec ebp jnz loc_466133 pop ebp jmp loc_467944 loc_4661AD: push ebp mov eax, edi and eax, 1 mov WorldBoolFlag, eax mov ecx, 20h loc_4661BD: push ecx mov ebp, 20h loc_4661C3: xor eax, eax mov al, [esi] inc esi test al, al js loc_4662E2 sub ebp, eax cmp edi, gpBufEnd jb loc_4661E3 add esi, eax add edi, eax jmp loc_4662D9 loc_4661E3: mov ecx, eax mov eax, edi and eax, 1 cmp eax, WorldBoolFlag jnz loc_466263 shr ecx, 1 jb loc_46622D shr ecx, 1 jnb loc_466209 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_466209: test cl, cl jz loc_46622B loc_46620D: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_46620D loc_46622B: jmp loc_466261 loc_46622D: inc esi inc edi shr ecx, 1 jnb loc_466240 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_466240: test cl, cl jz loc_466261 loc_466244: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_466244 loc_466261: jmp loc_4662D9 loc_466263: shr ecx, 1 jb loc_46629B shr ecx, 1 jnb loc_466278 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_466278: test cl, cl jz loc_466299 loc_46627C: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_46627C loc_466299: jmp loc_4662D9 loc_46629B: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_4662B7 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_4662B7: test cl, cl jz loc_4662D9 loc_4662BB: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_4662BB loc_4662D9: test ebp, ebp jz loc_4662EE jmp loc_4661C3 loc_4662E2: neg al add edi, eax sub ebp, eax jnz loc_4661C3 loc_4662EE: pop ecx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax sub edi, 320h dec ecx jnz loc_4661BD pop ebp jmp loc_467944 loc_466310: push ebp xor eax, eax mov WorldBoolFlag, eax mov ebp, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_466370 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_46635F mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub ebp, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_466370 loc_46635F: sub edi, 3000h add esi, 120h jmp loc_466490 loc_466370: add edi, ebp mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_466404 mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_4663CB shr ecx, 1 jnb loc_4663A7 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_4663A7: test cl, cl jz loc_4663C9 loc_4663AB: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_4663AB loc_4663C9: jmp loc_4663FF loc_4663CB: inc esi inc edi shr ecx, 1 jnb loc_4663DE mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_4663DE: test cl, cl jz loc_4663FF loc_4663E2: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_4663E2 loc_4663FF: jmp $+82h loc_466404: mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_466443 shr ecx, 1 jnb loc_466420 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_466420: test cl, cl jz loc_466441 loc_466424: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_466424 loc_466441: jmp loc_466481 loc_466443: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_46645F mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_46645F: test cl, cl jz loc_466481 loc_466463: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_466463 loc_466481: sub edi, 320h sub ebp, 2 jge loc_466370 loc_466490: mov ebp, 2 mov eax, edi sub eax, gpBufEnd jb loc_4664E8 add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_4664D7 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add ebp, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_4664E8 loc_4664D7: sub edi, 2D00h add esi, 100h jmp loc_46660B loc_4664E8: add edi, ebp mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_46657C mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_466543 shr ecx, 1 jnb loc_46651F mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_46651F: test cl, cl jz loc_466541 loc_466523: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_466523 loc_466541: jmp loc_466577 loc_466543: inc esi inc edi shr ecx, 1 jnb loc_466556 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_466556: test cl, cl jz loc_466577 loc_46655A: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_46655A loc_466577: jmp $+82h loc_46657C: mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_4665BB shr ecx, 1 jnb loc_466598 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_466598: test cl, cl jz loc_4665B9 loc_46659C: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_46659C loc_4665B9: jmp loc_4665F9 loc_4665BB: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_4665D7 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_4665D7: test cl, cl jz loc_4665F9 loc_4665DB: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_4665DB loc_4665F9: sub edi, 320h add ebp, 2 cmp ebp, 20h jnz loc_4664E8 loc_46660B: pop ebp jmp loc_467944 loc_466611: push ebp xor eax, eax mov WorldBoolFlag, eax mov ebp, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_466671 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_466660 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub ebp, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_466671 loc_466660: sub edi, 3000h add esi, 120h jmp loc_466791 loc_466671: mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_466703 shr ecx, 1 jb loc_4666C3 shr ecx, 1 jnb loc_46669F mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_46669F: test cl, cl jz loc_4666C1 loc_4666A3: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_4666A3 loc_4666C1: jmp loc_4666F7 loc_4666C3: inc esi inc edi shr ecx, 1 jnb loc_4666D6 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_4666D6: test cl, cl jz loc_4666F7 loc_4666DA: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_4666DA loc_4666F7: mov edx, esi and edx, 2 add esi, edx jmp $+82h loc_466703: shr ecx, 1 jb loc_46673B shr ecx, 1 jnb loc_466718 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_466718: test cl, cl jz loc_466739 loc_46671C: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_46671C loc_466739: jmp loc_466779 loc_46673B: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_466757 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_466757: test cl, cl jz loc_466779 loc_46675B: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_46675B loc_466779: mov edx, esi and edx, 2 add esi, edx // loc_466780: sub edi, 320h add edi, ebp sub ebp, 2 jge loc_466671 loc_466791: mov ebp, 2 mov eax, edi sub eax, gpBufEnd jb loc_4667E9 add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_4667D8 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add ebp, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_4667E9 loc_4667D8: sub edi, 2D00h add esi, 100h jmp loc_46690C loc_4667E9: mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_46687B shr ecx, 1 jb loc_46683B shr ecx, 1 jnb loc_466817 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_466817: test cl, cl jz loc_466839 loc_46681B: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_46681B loc_466839: jmp loc_46686F loc_46683B: inc esi inc edi shr ecx, 1 jnb loc_46684E mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_46684E: test cl, cl jz loc_46686F loc_466852: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_466852 loc_46686F: mov edx, esi and edx, 2 add esi, edx jmp $+82h loc_46687B: shr ecx, 1 jb loc_4668B3 shr ecx, 1 jnb loc_466890 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_466890: test cl, cl jz loc_4668B1 loc_466894: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_466894 loc_4668B1: jmp loc_4668F1 loc_4668B3: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_4668CF mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_4668CF: test cl, cl jz loc_4668F1 loc_4668D3: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_4668D3 loc_4668F1: mov edx, esi and edx, 2 add esi, edx // loc_4668F8: sub edi, 320h add edi, ebp add ebp, 2 cmp ebp, 20h jnz loc_4667E9 loc_46690C: pop ebp jmp loc_467944 loc_466912: push ebp xor eax, eax mov WorldBoolFlag, eax mov ebp, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_466972 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_466961 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub ebp, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_466972 loc_466961: sub edi, 3000h add esi, 120h jmp loc_466A92 loc_466972: add edi, ebp mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_466A06 mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_4669CD shr ecx, 1 jnb loc_4669A9 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_4669A9: test cl, cl jz loc_4669CB loc_4669AD: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_4669AD loc_4669CB: jmp loc_466A01 loc_4669CD: inc esi inc edi shr ecx, 1 jnb loc_4669E0 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_4669E0: test cl, cl jz loc_466A01 loc_4669E4: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_4669E4 loc_466A01: jmp $+82h loc_466A06: mov edx, ecx and edx, 2 add esi, edx shr ecx, 1 jb loc_466A45 shr ecx, 1 jnb loc_466A22 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_466A22: test cl, cl jz loc_466A43 loc_466A26: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_466A26 loc_466A43: jmp loc_466A83 loc_466A45: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_466A61 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_466A61: test cl, cl jz loc_466A83 loc_466A65: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_466A65 loc_466A83: sub edi, 320h sub ebp, 2 jge loc_466972 loc_466A92: mov ebp, 8 loc_466A97: cmp edi, gpBufEnd jb loc_466AA7 add esi, 20h add edi, 20h jmp loc_466ACA loc_466AA7: mov ecx, 8 loc_466AAC: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_466AAC loc_466ACA: sub edi, 320h cmp edi, gpBufEnd jb loc_466AE0 add esi, 20h add edi, 20h jmp loc_466B02 loc_466AE0: mov ecx, 8 loc_466AE5: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_466AE5 loc_466B02: sub edi, 320h dec ebp jnz loc_466A97 pop ebp jmp loc_467944 loc_466B11: push ebp xor eax, eax mov WorldBoolFlag, eax mov ebp, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_466B71 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_466B60 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub ebp, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_466B71 loc_466B60: sub edi, 3000h add esi, 120h jmp loc_466C91 loc_466B71: mov ecx, 20h sub ecx, ebp mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_466C03 shr ecx, 1 jb loc_466BC3 shr ecx, 1 jnb loc_466B9F mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_466B9F: test cl, cl jz loc_466BC1 loc_466BA3: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_466BA3 loc_466BC1: jmp loc_466BF7 loc_466BC3: inc esi inc edi shr ecx, 1 jnb loc_466BD6 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_466BD6: test cl, cl jz loc_466BF7 loc_466BDA: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_466BDA loc_466BF7: mov edx, esi and edx, 2 add esi, edx jmp $+82h loc_466C03: shr ecx, 1 jb loc_466C3B shr ecx, 1 jnb loc_466C18 mov dl, [esi] mov dl, [ebx+edx] add esi, 2 mov [edi], dl add edi, 2 loc_466C18: test cl, cl jz loc_466C39 loc_466C1C: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_466C1C loc_466C39: jmp loc_466C79 loc_466C3B: mov dl, [esi] mov dl, [ebx+edx] inc esi mov [edi], dl inc edi shr ecx, 1 jnb loc_466C57 mov dl, [esi+1] mov dl, [ebx+edx] add esi, 2 mov [edi+1], dl add edi, 2 loc_466C57: test cl, cl jz loc_466C79 loc_466C5B: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_466C5B loc_466C79: mov edx, esi and edx, 2 add esi, edx // loc_466C80: sub edi, 320h add edi, ebp sub ebp, 2 jge loc_466B71 loc_466C91: mov ebp, 8 loc_466C96: cmp edi, gpBufEnd jb loc_466CA6 add esi, 20h add edi, 20h jmp loc_466CC9 loc_466CA6: mov ecx, 8 loc_466CAB: mov eax, [esi] add esi, 4 mov dl, ah shr eax, 10h mov dl, [ebx+edx] mov [edi+1], dl mov dl, ah add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-1], dl jnz loc_466CAB loc_466CC9: sub edi, 320h cmp edi, gpBufEnd jb loc_466CDF add esi, 20h add edi, 20h jmp loc_466D01 loc_466CDF: mov ecx, 8 loc_466CE4: mov eax, [esi] add esi, 4 mov dl, al shr eax, 10h mov dl, [ebx+edx] mov [edi], dl mov dl, al add edi, 4 mov dl, [ebx+edx] dec ecx mov [edi-2], dl jnz loc_466CE4 loc_466D01: sub edi, 320h dec ebp jnz loc_466C96 pop ebp jmp loc_467944 loc_466D10: mov edx, 10h loc_466D15: cmp edi, gpBufEnd jb loc_466D25 add esi, 20h add edi, 20h jmp loc_466D41 loc_466D25: mov ecx, 8 loc_466D2A: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_466D2A loc_466D41: sub edi, 320h cmp edi, gpBufEnd jb loc_466D57 add esi, 20h add edi, 20h jmp loc_466D71 loc_466D57: mov ecx, 8 loc_466D5C: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_466D5C loc_466D71: sub edi, 320h dec edx jnz loc_466D15 jmp loc_467944 loc_466D7F: mov eax, edi and eax, 1 mov WorldBoolFlag, eax mov ecx, 20h loc_466D8E: push ecx mov edx, 20h loc_466D94: xor eax, eax mov al, [esi] inc esi test al, al js loc_466E35 sub edx, eax cmp edi, gpBufEnd jb loc_466DB1 add esi, eax add edi, eax jmp loc_466E2C loc_466DB1: mov ecx, eax mov eax, edi and eax, 1 cmp eax, WorldBoolFlag jnz loc_466DF5 shr ecx, 1 jnb loc_466DCC inc esi inc edi test ecx, ecx jz loc_466E2C jmp loc_466E05 loc_466DCC: shr ecx, 1 jnb loc_466DDC inc esi inc edi mov al, [esi] inc esi mov [edi], al inc edi test ecx, ecx jz loc_466E2C loc_466DDC: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_466DDC jmp loc_466E2C loc_466DF5: shr ecx, 1 jnb loc_466E05 mov al, [esi] inc esi mov [edi], al inc edi test ecx, ecx jz loc_466E2C jmp loc_466DCC loc_466E05: shr ecx, 1 jnb loc_466E17 mov al, [esi] add esi, 2 mov [edi], al add edi, 2 test ecx, ecx jz loc_466E2C loc_466E17: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_466E17 loc_466E2C: test edx, edx jz loc_466E41 jmp loc_466D94 loc_466E35: neg al add edi, eax sub edx, eax jnz loc_466D94 loc_466E41: pop ecx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax sub edi, 320h dec ecx jnz loc_466D8E jmp loc_467944 loc_466E62: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_466EC1 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_466EB0 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_466EC1 loc_466EB0: sub edi, 3000h add esi, 120h jmp $+83h loc_466EC1: add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_466F0A shr ecx, 2 jnb loc_466EF1 mov ax, [esi+2] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi test ecx, ecx jz loc_466F34 loc_466EF1: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_466EF1 jmp loc_466F34 loc_466F0A: shr ecx, 2 jnb loc_466F1F mov ax, [esi+2] add esi, 4 mov [edi], al add edi, 2 test ecx, ecx jz loc_466F34 loc_466F1F: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_466F1F loc_466F34: sub edi, 320h sub edx, 2 jge loc_466EC1 // loc_466F3F: mov edx, 2 mov eax, edi sub eax, gpBufEnd jb loc_466F97 add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_466F86 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add edx, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_466F97 loc_466F86: sub edi, 2D00h add esi, 100h jmp loc_467944 loc_466F97: add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_466FE0 shr ecx, 2 jnb loc_466FC7 mov ax, [esi+2] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi test ecx, ecx jz loc_467009 loc_466FC7: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_466FC7 jmp loc_467009 loc_466FE0: shr ecx, 2 jnb loc_466FF4 mov ax, [esi+2] add esi, 4 mov [edi], al add edi, 2 dec ecx jz loc_467009 loc_466FF4: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_466FF4 loc_467009: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_466F97 jmp loc_467944 loc_46701C: push ebp xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_46707C add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_46706B mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_46707C loc_46706B: sub edi, 3000h add esi, 120h jmp loc_4670FC loc_46707C: mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov ebp, ecx mov WorldBoolFlag, eax jz loc_4670C5 shr ecx, 2 jz loc_4670B1 loc_46709A: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_46709A loc_4670B1: and ebp, 2 jz loc_4670EF mov ax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi jmp loc_4670EF loc_4670C5: shr ecx, 2 jz loc_4670DF loc_4670CA: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_4670CA loc_4670DF: and ebp, 2 jz loc_4670EF mov ax, [esi] add esi, 4 mov [edi], al add edi, 2 loc_4670EF: sub edi, 320h add edi, edx sub edx, 2 jge loc_46707C loc_4670FC: mov edx, 2 mov eax, edi sub eax, gpBufEnd jb loc_467154 add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_467143 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add edx, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_467154 loc_467143: sub edi, 2D00h add esi, 100h jmp loc_4671DB loc_467154: mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov ebp, ecx mov WorldBoolFlag, eax jz loc_46719D shr ecx, 2 jz loc_467189 loc_467172: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_467172 loc_467189: and ebp, 2 jz loc_4671C7 mov ax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi jmp loc_4671C7 loc_46719D: shr ecx, 2 jz loc_4671B7 loc_4671A2: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_4671A2 loc_4671B7: and ebp, 2 jz loc_4671C7 mov ax, [esi] add esi, 4 mov [edi], al add edi, 2 loc_4671C7: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_467154 loc_4671DB: pop ebp jmp loc_467944 loc_4671E1: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_467240 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_46722F mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_467240 loc_46722F: sub edi, 3000h add esi, 120h jmp $+83h loc_467240: add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_467289 shr ecx, 2 jnb loc_467270 mov ax, [esi+2] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi test ecx, ecx jz loc_4672B3 loc_467270: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_467270 jmp loc_4672B3 loc_467289: shr ecx, 2 jnb loc_46729E mov ax, [esi+2] add esi, 4 mov [edi], al test ecx, ecx lea edi, [edi+2] jz loc_4672B3 loc_46729E: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al dec ecx lea edi, [edi+2] jnz loc_46729E loc_4672B3: sub edi, 320h sub edx, 2 jge loc_467240 // loc_4672BE: mov edx, 8 loc_4672C3: cmp edi, gpBufEnd jb loc_4672D3 add esi, 20h add edi, 20h jmp loc_4672EF loc_4672D3: mov ecx, 8 loc_4672D8: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_4672D8 loc_4672EF: sub edi, 320h cmp edi, gpBufEnd jb loc_467305 add esi, 20h add edi, 20h jmp loc_46731F loc_467305: mov ecx, 8 loc_46730A: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_46730A loc_46731F: sub edi, 320h dec edx jnz loc_4672C3 jmp loc_467944 loc_46732D: push ebp xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_46738D add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_46737C mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx mov eax, WorldBoolFlag shr ecx, 1 add eax, ecx mov WorldBoolFlag, eax jmp loc_46738D loc_46737C: sub edi, 3000h add esi, 120h jmp loc_46740D loc_46738D: mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov ebp, ecx mov WorldBoolFlag, eax jz loc_4673D6 shr ecx, 2 jz loc_4673C2 loc_4673AB: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_4673AB loc_4673C2: and ebp, 2 jz loc_467400 mov ax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al inc edi jmp loc_467400 loc_4673D6: shr ecx, 2 jz loc_4673F0 loc_4673DB: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_4673DB loc_4673F0: and ebp, 2 jz loc_467400 mov ax, [esi] add esi, 4 mov [edi], al add edi, 2 loc_467400: sub edi, 320h add edi, edx sub edx, 2 jge loc_46738D loc_46740D: mov edx, 8 loc_467412: cmp edi, gpBufEnd jb loc_467422 add esi, 20h add edi, 20h jmp loc_46743E loc_467422: mov ecx, 8 loc_467427: mov eax, [esi] add esi, 4 inc edi ror eax, 8 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al inc edi dec ecx jnz loc_467427 loc_46743E: sub edi, 320h cmp edi, gpBufEnd jb loc_467454 add esi, 20h add edi, 20h jmp loc_46746E loc_467454: mov ecx, 8 loc_467459: mov eax, [esi] add esi, 4 mov [edi], al add edi, 2 ror eax, 10h mov [edi], al add edi, 2 dec ecx jnz loc_467459 loc_46746E: sub edi, 320h dec edx jnz loc_467412 pop ebp jmp loc_467944 loc_46747D: mov edx, 10h xor eax, eax loc_467484: cmp edi, gpBufEnd jb loc_467494 add esi, 20h add edi, 20h jmp loc_4674A5 loc_467494: mov ecx, 8 loc_467499: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_467499 loc_4674A5: sub edi, 320h cmp edi, gpBufEnd jb loc_4674BB add esi, 20h add edi, 20h jmp loc_4674CB loc_4674BB: mov ecx, 8 loc_4674C0: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_4674C0 loc_4674CB: sub edi, 320h dec edx jnz loc_467484 jmp loc_467944 loc_4674D9: mov eax, edi and eax, 1 mov WorldBoolFlag, eax mov ecx, 20h loc_4674E8: push ecx mov edx, 20h loc_4674EE: xor eax, eax mov al, [esi] inc esi test al, al js loc_46756C sub edx, eax cmp edi, gpBufEnd jb loc_467507 add esi, eax add edi, eax jmp loc_467566 loc_467507: mov ecx, eax add esi, ecx mov eax, edi and eax, 1 cmp eax, WorldBoolFlag jnz loc_46753F xor eax, eax shr ecx, 1 jnb loc_467525 inc edi test ecx, ecx jz loc_467566 jmp loc_46754E loc_467525: shr ecx, 1 jnb loc_467531 inc edi mov [edi], al inc edi test ecx, ecx jz loc_467566 loc_467531: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_467531 jmp loc_467566 loc_46753F: xor eax, eax shr ecx, 1 jnb loc_46754E mov [edi], al inc edi test ecx, ecx jz loc_467566 jmp loc_467525 loc_46754E: shr ecx, 1 jnb loc_46755B mov [edi], al add edi, 2 test ecx, ecx jz loc_467566 loc_46755B: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_46755B loc_467566: test edx, edx jz loc_467578 jmp loc_4674EE loc_46756C: neg al add edi, eax sub edx, eax jnz loc_4674EE loc_467578: pop ecx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax sub edi, 320h dec ecx jnz loc_4674E8 jmp loc_467944 loc_467599: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_4675A5: cmp edi, gpBufEnd jb loc_4675B7 add esi, 20h sub esi, edx add edi, 20h jmp loc_467608 loc_4675B7: add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_4675ED xor eax, eax shr ecx, 2 jnb loc_4675DF inc edi mov [edi], al inc edi test ecx, ecx jz loc_467608 loc_4675DF: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_4675DF jmp loc_467608 loc_4675ED: xor eax, eax shr ecx, 2 jnb loc_4675FD mov [edi], al add edi, 2 test ecx, ecx jz loc_467608 loc_4675FD: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_4675FD loc_467608: sub edi, 320h test edx, edx jz loc_467617 sub edx, 2 jmp loc_4675A5 loc_467617: mov edx, 2 loc_46761C: cmp edi, gpBufEnd jb loc_46762E add esi, 20h sub esi, edx add edi, 20h jmp loc_46767F loc_46762E: add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_467664 xor eax, eax shr ecx, 2 jnb loc_467656 inc edi mov [edi], al inc edi test ecx, ecx jz loc_46767F loc_467656: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_467656 jmp loc_46767F loc_467664: xor eax, eax shr ecx, 2 jnb loc_467674 mov [edi], al add edi, 2 test ecx, ecx jz loc_46767F loc_467674: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_467674 loc_46767F: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_46761C jmp loc_467944 loc_467692: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_46769E: cmp edi, gpBufEnd jb loc_4676B2 add esi, 20h sub esi, edx add edi, 20h sub edi, edx jmp loc_467701 loc_4676B2: mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_4676E6 xor eax, eax shr ecx, 2 jnb loc_4676D8 inc edi mov [edi], al inc edi test ecx, ecx jz loc_467701 loc_4676D8: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_4676D8 jmp loc_467701 loc_4676E6: xor eax, eax shr ecx, 2 jnb loc_4676F6 mov [edi], al add edi, 2 test ecx, ecx jz loc_467701 loc_4676F6: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_4676F6 loc_467701: sub edi, 320h test edx, edx jz loc_467712 add edi, edx sub edx, 2 jmp loc_46769E loc_467712: mov edx, 2 loc_467717: cmp edi, gpBufEnd jb loc_46772B add esi, 20h sub esi, edx add edi, 20h sub edi, edx jmp loc_46777A loc_46772B: mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_46775F xor eax, eax shr ecx, 2 jnb loc_467751 inc edi mov [edi], al inc edi test ecx, ecx jz loc_46777A loc_467751: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_467751 jmp loc_46777A loc_46775F: xor eax, eax shr ecx, 2 jnb loc_46776F mov [edi], al add edi, 2 test ecx, ecx jz loc_46777A loc_46776F: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_46776F loc_46777A: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_467717 jmp loc_467944 loc_46778F: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_46779B: cmp edi, gpBufEnd jb loc_4677AD add esi, 20h sub esi, edx add edi, 20h jmp loc_4677FE loc_4677AD: add edi, edx mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_4677E3 xor eax, eax shr ecx, 2 jnb loc_4677D5 inc edi mov [edi], al inc edi test ecx, ecx jz loc_4677FE loc_4677D5: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_4677D5 jmp loc_4677FE loc_4677E3: xor eax, eax shr ecx, 2 jnb loc_4677F3 mov [edi], al add edi, 2 test ecx, ecx jz loc_4677FE loc_4677F3: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_4677F3 loc_4677FE: sub edi, 320h test edx, edx jz loc_46780D sub edx, 2 jmp loc_46779B loc_46780D: mov edx, 8 loc_467812: cmp edi, gpBufEnd jb loc_467822 add esi, 20h add edi, 20h jmp loc_467835 loc_467822: mov ecx, 8 xor eax, eax loc_467829: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_467829 loc_467835: sub edi, 320h cmp edi, gpBufEnd jb loc_46784B add esi, 20h add edi, 20h jmp loc_46785D loc_46784B: mov ecx, 8 xor eax, eax loc_467852: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_467852 loc_46785D: sub edi, 320h dec edx jnz loc_467812 jmp loc_467944 loc_46786B: xor eax, eax mov WorldBoolFlag, eax mov edx, 1Eh loc_467877: cmp edi, gpBufEnd jb loc_46788B add esi, 20h sub esi, edx add edi, 20h sub edi, edx jmp loc_4678DA loc_46788B: mov ecx, 20h sub ecx, edx mov eax, WorldBoolFlag inc eax and eax, 1 mov WorldBoolFlag, eax jz loc_4678BF xor eax, eax shr ecx, 2 jnb loc_4678B1 inc edi mov [edi], al inc edi test ecx, ecx jz loc_4678DA loc_4678B1: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_4678B1 jmp loc_4678DA loc_4678BF: xor eax, eax shr ecx, 2 jnb loc_4678CF mov [edi], al add edi, 2 test ecx, ecx jz loc_4678DA loc_4678CF: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_4678CF loc_4678DA: sub edi, 320h test edx, edx jz loc_4678EB add edi, edx sub edx, 2 jmp loc_467877 loc_4678EB: mov edx, 8 loc_4678F0: cmp edi, gpBufEnd jb loc_467900 add esi, 20h add edi, 20h jmp loc_467913 loc_467900: mov ecx, 8 xor eax, eax loc_467907: mov [edi+1], al mov [edi+3], al add edi, 4 dec ecx jnz loc_467907 loc_467913: sub edi, 320h cmp edi, gpBufEnd jb loc_467929 add esi, 20h add edi, 20h jmp loc_46793B loc_467929: mov ecx, 8 xor eax, eax loc_467930: mov [edi], al mov [edi+2], al add edi, 4 dec ecx jnz loc_467930 loc_46793B: sub edi, 320h dec edx jnz loc_4678F0 loc_467944: pop esi pop edi pop edx pop ebx retn } } __declspec(naked) void drawBottomArchesLowerScreen(BYTE *pBuff, DWORD *pMask) { __asm { push ebx push edi push esi mov edi, offset SpeedFrameTbl mov gpCelFrame, edi mov edi, ecx mov gpDrawMask, edx mov eax, light_table_index test al, al jz loc_467A58 cmp al, lightmax jz loc_467AB8 mov eax, level_cel_block and eax, 8000h jnz loc_4679EC mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov ebx, light_table_index shl ebx, 8 add ebx, pLightTbl mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 0Fh jz loc_467B43 cmp ax, 1 jz loc_467B8F cmp ax, 2 jz loc_467C20 cmp ax, 3 jz loc_467D5B cmp ax, 4 jz loc_467E99 jmp loc_467F8A loc_4679EC: mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 4 add eax, light_table_index shl eax, 2 add esi, eax mov eax, [esi] mov esi, pSpeedCels add esi, eax mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 0Fh loc_467A21: cmp ax, 8 jz loc_468086 cmp ax, 9 jz loc_4680D1 cmp ax, 0Ah jz loc_468161 cmp ax, 0Bh jz loc_468268 cmp ax, 0Ch jz loc_468372 jmp loc_468448 loc_467A58: mov eax, level_cel_block and eax, 8000h jz loc_467A8A mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_467A8A: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 7 add eax, 8 jmp loc_467A21 loc_467AB8: mov eax, level_cel_block and eax, 8000h jz loc_467AEA mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_467AEA: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 7 jz loc_468529 cmp ax, 1 jz loc_468573 cmp ax, 2 jz loc_468604 cmp ax, 3 jz loc_468696 cmp ax, 4 jz loc_46872C jmp loc_4687CB loc_467B43: push ebp mov ebp, 20h loc_467B49: cmp edi, gpBufEnd jb loc_467B59 add esi, 20h add edi, 20h jmp loc_467B73 loc_467B59: mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_467B65: mov al, [esi] inc esi shl edx, 1 jnb loc_467B6F xlat mov [edi], al loc_467B6F: inc edi dec ecx jnz loc_467B65 loc_467B73: sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec ebp jnz loc_467B49 pop ebp jmp loc_468867 loc_467B8F: mov ecx, 20h loc_467B94: push ecx mov eax, gpDrawMask mov eax, [eax] mov gdwCurrentMask, eax mov edx, 20h loc_467BA6: xor eax, eax mov al, [esi] inc esi test al, al js loc_467BE3 sub edx, eax cmp edi, gpBufEnd jb loc_467BBF add esi, eax add edi, eax jmp loc_467BDD loc_467BBF: mov ecx, eax push edx mov edx, gdwCurrentMask loc_467BC8: mov al, [esi] inc esi shl edx, 1 jnb loc_467BD2 xlat mov [edi], al loc_467BD2: inc edi dec ecx jnz loc_467BC8 mov gdwCurrentMask, edx pop edx loc_467BDD: test edx, edx jz loc_467C00 jmp loc_467BA6 loc_467BE3: neg al add edi, eax mov ecx, eax and ecx, 1Fh jz loc_467BFC push eax mov eax, gdwCurrentMask shl eax, cl mov gdwCurrentMask, eax pop eax loc_467BFC: sub edx, eax jnz loc_467BA6 loc_467C00: pop ecx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec ecx jnz loc_467B94 jmp loc_468867 loc_467C20: mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_467C67 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_467C59 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_467C67 loc_467C59: sub edi, 3000h add esi, 120h jmp loc_467CB8 loc_467C67: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_467C90 mov ax, [esi+2] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 test ecx, ecx jz loc_467CAD loc_467C90: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_467C90 loc_467CAD: sub edi, 320h sub edx, 2 jge loc_467C67 loc_467CB8: mov edx, 2 mov eax, edi sub eax, gpBufEnd jb loc_467D02 add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_467CF1 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add edx, ecx jmp loc_467D02 loc_467CF1: sub edi, 2D00h add esi, 100h jmp loc_468867 loc_467D02: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_467D2B mov ax, [esi+2] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 test ecx, ecx jz loc_467D48 loc_467D2B: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_467D2B loc_467D48: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_467D02 jmp loc_468867 loc_467D5B: push ebp mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_467DA3 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_467D95 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_467DA3 loc_467D95: sub edi, 3000h add esi, 120h jmp loc_467DF6 loc_467DA3: mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_467DCE loc_467DB1: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_467DB1 loc_467DCE: and ebp, 2 jz loc_467DE9 mov ax, [esi] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 loc_467DE9: sub edi, 320h add edi, edx sub edx, 2 jge loc_467DA3 loc_467DF6: mov edx, 2 mov eax, edi sub eax, gpBufEnd jb loc_467E3D add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_467E2F mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add edx, ecx jmp loc_467E3D loc_467E2F: sub edi, 2D00h add esi, 100h jmp loc_467E93 loc_467E3D: mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_467E68 loc_467E4B: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_467E4B loc_467E68: and ebp, 2 jz loc_467E83 mov ax, [esi] add esi, 2 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 loc_467E83: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_467E3D loc_467E93: pop ebp jmp loc_468867 loc_467E99: mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_467EE0 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_467ED2 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_467EE0 loc_467ED2: sub edi, 3000h add esi, 120h jmp loc_467F31 loc_467EE0: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_467F09 mov ax, [esi+2] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 test ecx, ecx jz loc_467F26 loc_467F09: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_467F09 loc_467F26: sub edi, 320h sub edx, 2 jge loc_467EE0 loc_467F31: mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_467F43: cmp edi, gpBufEnd jb loc_467F53 add esi, 20h add edi, 20h jmp loc_467F6F loc_467F53: push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_467F60: mov al, [esi] inc esi shl edx, 1 jnb loc_467F6A xlat mov [edi], al loc_467F6A: inc edi dec ecx jnz loc_467F60 pop edx loc_467F6F: sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_467F43 jmp loc_468867 loc_467F8A: push ebp mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_467FD2 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_467FC4 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_467FD2 loc_467FC4: sub edi, 3000h add esi, 120h jmp loc_468025 loc_467FD2: mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_467FFD loc_467FE0: mov eax, [esi] add esi, 4 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 mov [edi], eax add edi, 4 dec ecx jnz loc_467FE0 loc_467FFD: and ebp, 2 jz loc_468018 mov ax, [esi] add esi, 4 xlat ror ax, 8 xlat ror ax, 8 mov [edi], ax add edi, 2 loc_468018: sub edi, 320h add edi, edx sub edx, 2 jge loc_467FD2 loc_468025: mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_468037: cmp edi, gpBufEnd jb loc_468047 add esi, 20h add edi, 20h jmp loc_46806A loc_468047: push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_468054: mov al, [esi] inc esi shl edx, 1 jnb loc_46805E xlat mov [edi], al loc_46805E: inc edi dec ecx jnz loc_468054 mov ebp, esi and ebp, 2 add esi, ebp pop edx loc_46806A: sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_468037 pop ebp jmp loc_468867 loc_468086: mov edx, 20h loc_46808B: cmp edi, gpBufEnd jb loc_46809B add esi, 20h add edi, 20h jmp loc_4680B6 loc_46809B: push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_4680A8: mov al, [esi] inc esi shl edx, 1 jnb loc_4680B1 mov [edi], al loc_4680B1: inc edi dec ecx jnz loc_4680A8 pop edx loc_4680B6: sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_46808B jmp loc_468867 loc_4680D1: mov ecx, 20h loc_4680D6: push ecx mov eax, gpDrawMask mov eax, [eax] mov gdwCurrentMask, eax mov edx, 20h loc_4680E8: xor eax, eax mov al, [esi] inc esi test al, al js loc_468124 sub edx, eax cmp edi, gpBufEnd jb loc_468101 add esi, eax add edi, eax jmp loc_46811E loc_468101: mov ecx, eax push edx mov edx, gdwCurrentMask loc_46810A: mov al, [esi] inc esi shl edx, 1 jnb loc_468113 mov [edi], al loc_468113: inc edi dec ecx jnz loc_46810A mov gdwCurrentMask, edx pop edx loc_46811E: test edx, edx jz loc_468141 jmp loc_4680E8 loc_468124: neg al add edi, eax mov ecx, eax and ecx, 1Fh jz loc_46813D mov ebx, gdwCurrentMask shl ebx, cl mov gdwCurrentMask, ebx loc_46813D: sub edx, eax jnz loc_4680E8 loc_468141: pop ecx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec ecx jnz loc_4680D6 jmp loc_468867 loc_468161: mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_4681A8 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_46819A mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_4681A8 loc_46819A: sub edi, 3000h add esi, 120h jmp loc_4681DF loc_4681A8: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_4681C7 mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_4681D4 loc_4681C7: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_4681C7 loc_4681D4: sub edi, 320h sub edx, 2 jge loc_4681A8 loc_4681DF: mov edx, 2 mov eax, edi sub eax, gpBufEnd jb loc_468229 add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_468218 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add edx, ecx jmp loc_468229 loc_468218: sub edi, 2D00h add esi, 100h jmp loc_468867 loc_468229: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_468248 mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_468255 loc_468248: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_468248 loc_468255: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_468229 jmp loc_468867 loc_468268: push ebp mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_4682B0 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_4682A2 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_4682B0 loc_4682A2: sub edi, 3000h add esi, 120h jmp loc_4682E9 loc_4682B0: mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_4682CB loc_4682BE: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_4682BE loc_4682CB: and ebp, 2 jz loc_4682DC mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_4682DC: sub edi, 320h add edi, edx sub edx, 2 jge loc_4682B0 loc_4682E9: mov edx, 2 mov eax, edi sub eax, gpBufEnd jb loc_468330 add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_468322 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add edx, ecx jmp loc_468330 loc_468322: sub edi, 2D00h add esi, 100h jmp loc_46836C loc_468330: mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_46834B loc_46833E: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_46833E loc_46834B: and ebp, 2 jz loc_46835C mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_46835C: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_468330 loc_46836C: pop ebp jmp loc_468867 loc_468372: mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_4683B9 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_4683AB mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_4683B9 loc_4683AB: sub edi, 3000h add esi, 120h jmp loc_4683F0 loc_4683B9: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_4683D8 mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_4683E5 loc_4683D8: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_4683D8 loc_4683E5: sub edi, 320h sub edx, 2 jge loc_4683B9 loc_4683F0: mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_468402: cmp edi, gpBufEnd jb loc_468412 add esi, 20h add edi, 20h jmp loc_46842D loc_468412: push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_46841F: mov al, [esi] inc esi shl edx, 1 jnb loc_468428 mov [edi], al loc_468428: inc edi dec ecx jnz loc_46841F pop edx loc_46842D: sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_468402 jmp loc_468867 loc_468448: push ebp mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_468490 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_468482 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_468490 loc_468482: sub edi, 3000h add esi, 120h jmp loc_4684C9 loc_468490: mov ecx, 20h sub ecx, edx mov ebp, ecx shr ecx, 2 jz loc_4684AB loc_46849E: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_46849E loc_4684AB: and ebp, 2 jz loc_4684BC mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_4684BC: sub edi, 320h add edi, edx sub edx, 2 jge loc_468490 loc_4684C9: mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_4684DB: cmp edi, gpBufEnd jb loc_4684EB add esi, 20h add edi, 20h jmp loc_46850D loc_4684EB: push edx mov eax, gpDrawMask mov edx, [eax] mov ecx, 20h loc_4684F8: mov al, [esi] inc esi shl edx, 1 jnb loc_468501 mov [edi], al loc_468501: inc edi dec ecx jnz loc_4684F8 mov ebp, esi and ebp, 2 add esi, ebp pop edx loc_46850D: sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_4684DB pop ebp jmp loc_468867 loc_468529: mov edx, 20h loc_46852E: cmp edi, gpBufEnd jb loc_46853E add esi, 20h add edi, 20h jmp loc_468558 loc_46853E: push edx mov eax, gpDrawMask mov edx, [eax] xor eax, eax mov ecx, 20h loc_46854D: shl edx, 1 jnb loc_468553 mov [edi], al loc_468553: inc edi dec ecx jnz loc_46854D pop edx loc_468558: sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_46852E jmp loc_468867 loc_468573: mov ecx, 20h loc_468578: push ecx mov eax, gpDrawMask mov eax, [eax] mov gdwCurrentMask, eax mov edx, 20h loc_46858A: xor eax, eax mov al, [esi] inc esi test al, al js loc_4685C7 sub edx, eax cmp edi, gpBufEnd jb loc_4685A3 add esi, eax add edi, eax jmp loc_4685C1 loc_4685A3: mov ecx, eax add esi, ecx push edx mov edx, gdwCurrentMask xor eax, eax loc_4685B0: shl edx, 1 jnb loc_4685B6 mov [edi], al loc_4685B6: inc edi dec ecx jnz loc_4685B0 mov gdwCurrentMask, edx pop edx loc_4685C1: test edx, edx jz loc_4685E4 jmp loc_46858A loc_4685C7: neg al add edi, eax mov ecx, eax and ecx, 1Fh jz loc_4685E0 mov ebx, gdwCurrentMask shl ebx, cl mov gdwCurrentMask, ebx loc_4685E0: sub edx, eax jnz loc_46858A loc_4685E4: pop ecx sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec ecx jnz loc_468578 jmp loc_468867 loc_468604: mov edx, 1Eh xor eax, eax loc_46860B: cmp edi, gpBufEnd jb loc_46861D add esi, 20h sub esi, edx add edi, 20h jmp loc_46863D loc_46861D: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_468635 mov [edi], ax add edi, 2 test ecx, ecx jz loc_46863D loc_468635: mov [edi], eax add edi, 4 dec ecx jnz loc_468635 loc_46863D: sub edi, 320h test edx, edx jz loc_46864C sub edx, 2 jmp loc_46860B loc_46864C: mov edx, 2 loc_468651: cmp edi, gpBufEnd jb loc_468663 add esi, 20h sub esi, edx add edi, 20h jmp loc_468683 loc_468663: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_46867B mov [edi], ax add edi, 2 test ecx, ecx jz loc_468683 loc_46867B: mov [edi], eax add edi, 4 dec ecx jnz loc_46867B loc_468683: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_468651 jmp loc_468867 loc_468696: mov edx, 1Eh xor eax, eax loc_46869D: cmp edi, gpBufEnd jb loc_4686B1 add esi, 20h sub esi, edx add edi, 20h sub edi, edx jmp loc_4686CF loc_4686B1: mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_4686C7 mov [edi], ax add edi, 2 test ecx, ecx jz loc_4686CF loc_4686C7: mov [edi], eax add edi, 4 dec ecx jnz loc_4686C7 loc_4686CF: sub edi, 320h test edx, edx jz loc_4686E0 add edi, edx sub edx, 2 jmp loc_46869D loc_4686E0: mov edx, 2 loc_4686E5: cmp edi, gpBufEnd jb loc_4686F9 add esi, 20h sub esi, edx add edi, 20h sub edi, edx jmp loc_468717 loc_4686F9: mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_46870F mov [edi], ax add edi, 2 test ecx, ecx jz loc_468717 loc_46870F: mov [edi], eax add edi, 4 dec ecx jnz loc_46870F loc_468717: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_4686E5 jmp loc_468867 loc_46872C: mov edx, 1Eh xor eax, eax loc_468733: cmp edi, gpBufEnd jb loc_468745 add esi, 20h sub esi, edx add edi, 20h jmp loc_468765 loc_468745: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_46875D mov [edi], ax add edi, 2 test ecx, ecx jz loc_468765 loc_46875D: mov [edi], eax add edi, 4 dec ecx jnz loc_46875D loc_468765: sub edi, 320h test edx, edx jz loc_468774 sub edx, 2 jmp loc_468733 loc_468774: mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_468786: cmp edi, gpBufEnd jb loc_468796 add esi, 20h add edi, 20h jmp loc_4687B0 loc_468796: push edx mov eax, gpDrawMask mov edx, [eax] xor eax, eax mov ecx, 20h loc_4687A5: shl edx, 1 jnb loc_4687AB mov [edi], al loc_4687AB: inc edi dec ecx jnz loc_4687A5 pop edx loc_4687B0: sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_468786 jmp loc_468867 loc_4687CB: mov edx, 1Eh xor eax, eax loc_4687D2: cmp edi, gpBufEnd jb loc_4687E6 add esi, 20h sub esi, edx add edi, 20h sub edi, edx jmp loc_468804 loc_4687E6: mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_4687FC mov [edi], ax add edi, 2 test ecx, ecx jz loc_468804 loc_4687FC: mov [edi], eax add edi, 4 dec ecx jnz loc_4687FC loc_468804: sub edi, 320h test edx, edx jz loc_468815 add edi, edx sub edx, 2 jmp loc_4687D2 loc_468815: mov eax, gpDrawMask sub eax, 40h mov gpDrawMask, eax mov edx, 10h loc_468827: cmp edi, gpBufEnd jb loc_468837 add esi, 20h add edi, 20h jmp loc_468851 loc_468837: push edx mov eax, gpDrawMask mov edx, [eax] xor eax, eax mov ecx, 20h loc_468846: shl edx, 1 jnb loc_46884C mov [edi], al loc_46884C: inc edi dec ecx jnz loc_468846 pop edx loc_468851: sub edi, 320h mov eax, gpDrawMask sub eax, 4 mov gpDrawMask, eax dec edx jnz loc_468827 loc_468867: pop esi pop edi pop ebx retn } } __declspec(naked) void drawLowerScreen(BYTE *pBuff) { __asm { push ebx push edx push edi push esi mov edx, cel_transparency_active test edx, edx jz loc_468918 mov dl, arch_draw_type cmp dl, 0 jnz loc_468892 call drawTopArchesLowerScreen jmp loc_4696B9 loc_468892: cmp dl, 1 jnz loc_4688D5 mov ebx, level_piece_id mov al, block_lvid[ebx] cmp al, 1 jz loc_4688AD cmp al, 3 jz loc_4688AD jmp loc_4688D5 loc_4688AD: mov edx, offset LeftMask add edx, 7Ch call drawBottomArchesLowerScreen jmp loc_4696B9 cmp al, 4 jnz loc_4688D5 mov edx, offset RightMask add edx, 7Ch call drawBottomArchesLowerScreen jmp loc_4696B9 loc_4688D5: cmp dl, 2 jnz loc_468918 mov ebx, level_piece_id mov al, block_lvid[ebx] cmp al, 2 jz loc_4688F0 cmp al, 3 jz loc_4688F0 jmp loc_468918 loc_4688F0: mov edx, offset RightMask add edx, 7Ch call drawBottomArchesLowerScreen jmp loc_4696B9 cmp al, 4 jnz loc_468918 mov edx, offset LeftMask add edx, 7Ch call drawBottomArchesLowerScreen jmp loc_4696B9 loc_468918: mov edi, offset SpeedFrameTbl mov gpCelFrame, edi mov edi, ecx mov eax, light_table_index test al, al jz loc_468A1A cmp al, lightmax jz loc_468A78 mov eax, level_cel_block and eax, 8000h jnz loc_4689B0 mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov ebx, light_table_index shl ebx, 8 add ebx, pLightTbl mov eax, level_cel_block shr eax, 0Ch and eax, 0Fh jz loc_468B03 cmp ax, 1 jz loc_468B5B cmp ax, 2 jz loc_468C06 cmp ax, 3 jz loc_468CEC cmp ax, 4 jz loc_468DD2 jmp loc_468EE2 loc_4689B0: mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 4 add eax, light_table_index shl eax, 2 add esi, eax mov eax, [esi] mov esi, pSpeedCels add esi, eax mov eax, level_cel_block shr eax, 0Ch and eax, 0Fh loc_4689E3: cmp ax, 8 jz loc_468FF2 cmp ax, 9 jz loc_469027 cmp ax, 0Ah jz loc_469099 cmp ax, 0Bh jz loc_46919D cmp ax, 0Ch jz loc_4692A5 jmp loc_469358 loc_468A1A: mov eax, level_cel_block and eax, 8000h jz loc_468A4C mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_468A4C: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block shr eax, 0Ch and eax, 7 add eax, 8 jmp loc_4689E3 loc_468A78: mov eax, level_cel_block and eax, 8000h jz loc_468AAA mov esi, gpCelFrame mov eax, level_cel_block and eax, 0FFFh shl eax, 6 add esi, eax mov eax, level_cel_block and eax, 0F000h add eax, [esi] mov level_cel_block, eax loc_468AAA: mov ebx, pDungeonCels mov esi, ebx mov eax, level_cel_block and eax, 0FFFh shl eax, 2 add ebx, eax add esi, [ebx] mov eax, level_cel_block mov al, ah shr eax, 4 and eax, 7 jz loc_46940D cmp ax, 1 jz loc_46943F cmp ax, 2 jz loc_4694A7 cmp ax, 3 jz loc_469539 cmp ax, 4 jz loc_4695CF jmp loc_469644 loc_468B03: mov edx, 20h push ebp loc_468B09: push edx cmp edi, gpBufEnd jb loc_468B1A add esi, 20h add edi, 20h jmp loc_468B4B loc_468B1A: xor edx, edx mov ebp, 8 loc_468B21: mov eax, [esi] add esi, 4 ror eax, 10h mov dl, al mov cl, [ebx+edx] mov dl, ah mov ch, [ebx+edx] ror eax, 10h shl ecx, 10h mov dl, al mov cl, [ebx+edx] mov dl, ah mov ch, [ebx+edx] mov [edi], ecx add edi, 4 dec ebp jnz loc_468B21 loc_468B4B: sub edi, 320h pop edx dec edx jnz loc_468B09 pop ebp jmp loc_4696B9 loc_468B5B: push ebp mov ecx, 20h loc_468B61: push ecx mov ebp, 20h loc_468B67: xor eax, eax mov al, [esi] inc esi test al, al jns loc_468B78 neg al add edi, eax sub ebp, eax jmp loc_468BEA loc_468B78: sub ebp, eax cmp edi, gpBufEnd jb loc_468B88 add esi, eax add edi, eax jmp loc_468BEA loc_468B88: mov ecx, eax cmp cl, 4 jl loc_468BC1 loc_468B8F: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_468B8F loc_468BC1: cmp cl, 2 jl loc_468BDC mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 loc_468BDC: and cl, 1 jz loc_468BEA mov dl, [esi] inc esi mov dl, [ebx+edx] mov [edi], dl inc edi loc_468BEA: test ebp, ebp jnz loc_468B67 pop ecx sub edi, 320h dec ecx jnz loc_468B61 pop ebp jmp loc_4696B9 loc_468C06: push ebp mov ebp, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_468C4E add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_468C40 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub ebp, ecx jmp loc_468C4E loc_468C40: sub edi, 3000h add esi, 120h jmp loc_468C75 loc_468C4E: add edi, ebp mov ecx, 20h sub ecx, ebp mov edx, ecx and edx, 2 add esi, edx loc_468C5E: mov dl, [esi] inc esi mov dl, [ebx+edx] mov [edi], dl inc edi dec ecx jnz loc_468C5E sub edi, 320h sub ebp, 2 jge loc_468C4E loc_468C75: mov ebp, 2 mov eax, edi sub eax, gpBufEnd jb loc_468CBC add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_468CAE mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add ebp, ecx jmp loc_468CBC loc_468CAE: sub edi, 2D00h add esi, 100h jmp loc_468CE6 loc_468CBC: add edi, ebp mov ecx, 20h sub ecx, ebp mov edx, ecx and edx, 2 add esi, edx loc_468CCC: mov dl, [esi] inc esi mov dl, [ebx+edx] mov [edi], dl inc edi dec ecx jnz loc_468CCC add ebp, 2 sub edi, 320h cmp ebp, 20h jnz loc_468CBC loc_468CE6: pop ebp jmp loc_4696B9 loc_468CEC: push ebp mov ebp, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_468D34 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_468D26 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub ebp, ecx jmp loc_468D34 loc_468D26: sub edi, 3000h add esi, 120h jmp loc_468D5B loc_468D34: mov ecx, 20h sub ecx, ebp loc_468D3B: mov dl, [esi] inc esi mov dl, [ebx+edx] mov [edi], dl inc edi dec ecx jnz loc_468D3B mov edx, esi and edx, 2 add esi, edx sub edi, 320h add edi, ebp sub ebp, 2 jge loc_468D34 loc_468D5B: mov ebp, 2 mov eax, edi sub eax, gpBufEnd jb loc_468DA2 add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_468D94 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add ebp, ecx jmp loc_468DA2 loc_468D94: sub edi, 2D00h add esi, 100h jmp loc_468DCC loc_468DA2: mov ecx, 20h sub ecx, ebp loc_468DA9: mov dl, [esi] inc esi mov dl, [ebx+edx] mov [edi], dl inc edi dec ecx jnz loc_468DA9 mov edx, esi and edx, 2 add esi, edx sub edi, 320h add edi, ebp add ebp, 2 cmp ebp, 20h jnz loc_468DA2 loc_468DCC: pop ebp jmp loc_4696B9 loc_468DD2: push ebp mov ebp, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_468E1A add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_468E0C mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub ebp, ecx jmp loc_468E1A loc_468E0C: sub edi, 3000h add esi, 120h jmp loc_468E87 loc_468E1A: add edi, ebp mov ecx, 20h sub ecx, ebp mov edx, ecx and edx, 2 add esi, edx cmp cl, 4 jl loc_468E61 loc_468E2F: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_468E2F loc_468E61: cmp cl, 2 jl loc_468E7C mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 loc_468E7C: sub edi, 320h sub ebp, 2 jge loc_468E1A loc_468E87: mov ebp, 10h loc_468E8C: cmp edi, gpBufEnd jb loc_468E9C add esi, 20h add edi, 20h jmp loc_468ED3 loc_468E9C: mov ecx, 20h loc_468EA1: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_468EA1 loc_468ED3: sub edi, 320h dec ebp jnz loc_468E8C pop ebp jmp loc_4696B9 loc_468EE2: push ebp mov ebp, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_468F2A add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_468F1C mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub ebp, ecx jmp loc_468F2A loc_468F1C: sub edi, 3000h add esi, 120h jmp loc_468F97 loc_468F2A: mov ecx, 20h sub ecx, ebp cmp cl, 4 jl loc_468F68 loc_468F36: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_468F36 loc_468F68: cmp cl, 2 jl loc_468F83 mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 loc_468F83: mov edx, esi and edx, 2 add esi, edx sub edi, 320h add edi, ebp sub ebp, 2 jge loc_468F2A loc_468F97: mov ebp, 10h loc_468F9C: cmp edi, gpBufEnd jb loc_468FAC add esi, 20h add edi, 20h jmp loc_468FE3 loc_468FAC: mov ecx, 20h loc_468FB1: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 sub cl, 4 cmp cl, 4 jge loc_468FB1 loc_468FE3: sub edi, 320h dec ebp jnz loc_468F9C pop ebp jmp loc_4696B9 loc_468FF2: mov edx, 20h loc_468FF7: cmp edi, gpBufEnd jb loc_469007 add esi, 20h add edi, 20h jmp loc_469019 loc_469007: mov ecx, 8 loc_46900C: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_46900C loc_469019: sub edi, 320h dec edx jnz loc_468FF7 jmp loc_4696B9 loc_469027: mov ecx, 20h loc_46902C: push ecx mov edx, 20h loc_469032: xor eax, eax mov al, [esi] inc esi test al, al js loc_469082 sub edx, eax cmp edi, gpBufEnd jb loc_46904B add esi, eax add edi, eax jmp loc_46907C loc_46904B: mov ecx, eax shr ecx, 1 jnb loc_46905B mov al, [esi] inc esi mov [edi], al inc edi test ecx, ecx jz loc_46907C loc_46905B: shr ecx, 1 jnb loc_46906F mov ax, [esi] add esi, 2 mov [edi], ax add edi, 2 test ecx, ecx jz loc_46907C loc_46906F: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_46906F loc_46907C: test edx, edx jz loc_46908A jmp loc_469032 loc_469082: neg al add edi, eax sub edx, eax jnz loc_469032 loc_46908A: pop ecx sub edi, 320h dec ecx jnz loc_46902C jmp loc_4696B9 loc_469099: mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_4690E0 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_4690D2 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_4690E0 loc_4690D2: sub edi, 3000h add esi, 120h jmp loc_469117 loc_4690E0: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_4690FF mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_46910C loc_4690FF: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_4690FF loc_46910C: sub edi, 320h sub edx, 2 jge loc_4690E0 loc_469117: mov edx, 2 mov eax, edi sub eax, gpBufEnd jb loc_46915E add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_469150 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add edx, ecx jmp loc_46915E loc_469150: sub edi, 2D00h add esi, 100h jmp loc_469198 loc_46915E: mov ecx, 20h add edi, edx sub ecx, edx shr ecx, 2 jnb loc_46917D mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_46918A loc_46917D: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_46917D loc_46918A: add edx, 2 sub edi, 320h cmp edx, 20h jl loc_46915E loc_469198: jmp loc_4696B9 loc_46919D: mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_4691E4 add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_4691D6 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_4691E4 loc_4691D6: sub edi, 3000h add esi, 120h jmp loc_46921D loc_4691E4: mov ecx, 20h sub ecx, edx mov ebx, ecx shr ecx, 2 jz loc_4691FF loc_4691F2: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_4691F2 loc_4691FF: and ebx, 2 jz loc_469210 mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_469210: add edi, edx sub edi, 320h sub edx, 2 jge loc_4691E4 loc_46921D: mov edx, 2 mov eax, edi sub eax, gpBufEnd jb loc_469264 add eax, 3FFh shr eax, 8 cmp eax, 2Ah jg loc_469256 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_2[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax add edx, ecx jmp loc_469264 loc_469256: sub edi, 2D00h add esi, 100h jmp loc_4692A0 loc_469264: mov ecx, 20h sub ecx, edx mov ebx, ecx shr ecx, 2 jz loc_46927F loc_469272: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_469272 loc_46927F: and ebx, 2 jz loc_469290 mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_469290: add edi, edx add edx, 2 sub edi, 320h cmp edx, 20h jl loc_469264 loc_4692A0: jmp loc_4696B9 loc_4692A5: mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_4692EC add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_4692DE mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_4692EC loc_4692DE: sub edi, 3000h add esi, 120h jmp loc_469323 loc_4692EC: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_46930B mov ax, [esi+2] add esi, 4 mov [edi], ax add edi, 2 test ecx, ecx jz loc_469318 loc_46930B: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_46930B loc_469318: sub edi, 320h sub edx, 2 jge loc_4692EC loc_469323: mov edx, 10h loc_469328: cmp edi, gpBufEnd jb loc_469338 add esi, 20h add edi, 20h jmp loc_46934A loc_469338: mov ecx, 8 loc_46933D: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_46933D loc_46934A: sub edi, 320h dec edx jnz loc_469328 jmp loc_4696B9 loc_469358: mov edx, 1Eh mov eax, edi sub eax, gpBufEnd jb loc_46939F add eax, 3FFh shr eax, 8 cmp eax, 2Dh jg loc_469391 mov ecx, WorldTbl3x16[eax*4] mov eax, ecx add esi, WorldTbl17_1[ecx] shl eax, 6 lea eax, [eax+eax*2] shr ecx, 1 sub edi, eax sub edx, ecx jmp loc_46939F loc_469391: sub edi, 3000h add esi, 120h jmp loc_4693D8 loc_46939F: mov ecx, 20h sub ecx, edx mov ebx, ecx shr ecx, 2 jz loc_4693BA loc_4693AD: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_4693AD loc_4693BA: and ebx, 2 jz loc_4693CB mov ax, [esi] add esi, 4 mov [edi], ax add edi, 2 loc_4693CB: sub edi, 320h add edi, edx sub edx, 2 jge loc_46939F loc_4693D8: mov edx, 10h loc_4693DD: cmp edi, gpBufEnd jb loc_4693ED add esi, 20h add edi, 20h jmp loc_4693FF loc_4693ED: mov ecx, 8 loc_4693F2: mov eax, [esi] add esi, 4 mov [edi], eax add edi, 4 dec ecx jnz loc_4693F2 loc_4693FF: sub edi, 320h dec edx jnz loc_4693DD jmp loc_4696B9 loc_46940D: mov edx, 20h xor eax, eax loc_469414: cmp edi, gpBufEnd jb loc_469424 add esi, 20h add edi, 20h jmp loc_469431 loc_469424: mov ecx, 8 loc_469429: mov [edi], eax add edi, 4 dec ecx jnz loc_469429 loc_469431: sub edi, 320h dec edx jnz loc_469414 jmp loc_4696B9 loc_46943F: mov ecx, 20h loc_469444: push ecx mov edx, 20h loc_46944A: xor eax, eax mov al, [esi] inc esi test al, al js loc_469490 sub edx, eax cmp edi, gpBufEnd jb loc_469463 add esi, eax add edi, eax jmp loc_46948A loc_469463: mov ecx, eax add esi, ecx xor eax, eax shr ecx, 1 jnb loc_469474 mov [edi], al inc edi test ecx, ecx jz loc_46948A loc_469474: shr ecx, 1 jnb loc_469482 mov [edi], ax add edi, 2 test ecx, ecx jz loc_46948A loc_469482: mov [edi], eax add edi, 4 dec ecx jnz loc_469482 loc_46948A: test edx, edx jz loc_469498 jmp loc_46944A loc_469490: neg al add edi, eax sub edx, eax jnz loc_46944A loc_469498: pop ecx sub edi, 320h dec ecx jnz loc_469444 jmp loc_4696B9 loc_4694A7: mov edx, 1Eh xor eax, eax loc_4694AE: cmp edi, gpBufEnd jb loc_4694C0 add esi, 20h sub esi, edx add edi, 20h jmp loc_4694E0 loc_4694C0: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_4694D8 mov [edi], ax add edi, 2 test ecx, ecx jz loc_4694E0 loc_4694D8: mov [edi], eax add edi, 4 dec ecx jnz loc_4694D8 loc_4694E0: sub edi, 320h test edx, edx jz loc_4694EF sub edx, 2 jmp loc_4694AE loc_4694EF: mov edx, 2 loc_4694F4: cmp edi, gpBufEnd jb loc_469506 add esi, 20h sub esi, edx add edi, 20h jmp loc_469526 loc_469506: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_46951E mov [edi], ax add edi, 2 test ecx, ecx jz loc_469526 loc_46951E: mov [edi], eax add edi, 4 dec ecx jnz loc_46951E loc_469526: sub edi, 320h add edx, 2 cmp edx, 20h jnz loc_4694F4 jmp loc_4696B9 loc_469539: mov edx, 1Eh xor eax, eax loc_469540: cmp edi, gpBufEnd jb loc_469554 add esi, 20h sub esi, edx add edi, 20h sub edi, edx jmp loc_469572 loc_469554: mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_46956A mov [edi], ax add edi, 2 test ecx, ecx jz loc_469572 loc_46956A: mov [edi], eax add edi, 4 dec ecx jnz loc_46956A loc_469572: sub edi, 320h test edx, edx jz loc_469583 add edi, edx sub edx, 2 jmp loc_469540 loc_469583: mov edx, 2 loc_469588: cmp edi, gpBufEnd jb loc_46959C add esi, 20h sub esi, edx add edi, 20h sub edi, edx jmp loc_4695BA loc_46959C: mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_4695B2 mov [edi], ax add edi, 2 test ecx, ecx jz loc_4695BA loc_4695B2: mov [edi], eax add edi, 4 dec ecx jnz loc_4695B2 loc_4695BA: sub edi, 320h add edi, edx add edx, 2 cmp edx, 20h jnz loc_469588 jmp loc_4696B9 loc_4695CF: mov edx, 1Eh xor eax, eax loc_4695D6: cmp edi, gpBufEnd jb loc_4695E8 add esi, 20h sub esi, edx add edi, 20h jmp loc_469608 loc_4695E8: add edi, edx mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_469600 mov [edi], ax add edi, 2 test ecx, ecx jz loc_469608 loc_469600: mov [edi], eax add edi, 4 dec ecx jnz loc_469600 loc_469608: sub edi, 320h test edx, edx jz loc_469617 sub edx, 2 jmp loc_4695D6 loc_469617: mov edx, 10h loc_46961C: cmp edi, gpBufEnd jb loc_46962C add esi, 20h add edi, 20h jmp loc_469639 loc_46962C: mov ecx, 8 loc_469631: mov [edi], eax add edi, 4 dec ecx jnz loc_469631 loc_469639: sub edi, 320h dec edx jnz loc_46961C jmp loc_4696B9 loc_469644: mov edx, 1Eh xor eax, eax loc_46964B: cmp edi, gpBufEnd jb loc_46965F add esi, 20h sub esi, edx add edi, 20h sub edi, edx jmp loc_46967D loc_46965F: mov ecx, 20h sub ecx, edx shr ecx, 2 jnb loc_469675 mov [edi], ax add edi, 2 test ecx, ecx jz loc_46967D loc_469675: mov [edi], eax add edi, 4 dec ecx jnz loc_469675 loc_46967D: sub edi, 320h test edx, edx jz loc_46968E add edi, edx sub edx, 2 jmp loc_46964B loc_46968E: mov edx, 10h loc_469693: cmp edi, gpBufEnd jb loc_4696A3 add esi, 20h add edi, 20h jmp loc_4696B0 loc_4696A3: mov ecx, 8 loc_4696A8: mov [edi], eax add edi, 4 dec ecx jnz loc_4696A8 loc_4696B0: sub edi, 320h dec edx jnz loc_469693 loc_4696B9: pop esi pop edi pop edx pop ebx retn } } __declspec(naked) void world_draw_black_tile(BYTE *pBuff) { __asm { push ebx push edx push edi push esi mov edi, ecx mov edx, 1Eh mov ebx, 1 xor eax, eax loc_4696D0: add edi, edx mov ecx, ebx loc_4696D4: mov [edi], eax add edi, 4 dec ecx jnz loc_4696D4 add edi, edx sub edi, 340h test edx, edx jz loc_4696EE sub edx, 2 inc ebx jmp loc_4696D0 loc_4696EE: mov edx, 2 mov ebx, 0Fh loc_4696F8: add edi, edx mov ecx, ebx loc_4696FC: mov [edi], eax add edi, 4 dec ecx jnz loc_4696FC add edi, edx sub edi, 340h dec ebx add edx, 2 cmp edx, 20h jnz loc_4696F8 pop esi pop edi pop edx pop ebx retn } } ================================================ FILE: Source/all.h ================================================ /** * @file all.h * * Include all application headers. */ #ifndef __ALL_H__ #define __ALL_H__ #include "../types.h" #ifdef __cplusplus extern "C" { #endif #include "appfat.h" #include "automap.h" #include "capture.h" #include "codec.h" #include "control.h" #include "cursor.h" #include "dead.h" #include "debug.h" #include "diablo.h" #include "doom.h" #include "drlg_l1.h" #include "drlg_l2.h" #include "drlg_l3.h" #include "drlg_l4.h" #include "dthread.h" #include "dx.h" #include "effects.h" #include "encrypt.h" #include "engine.h" #include "error.h" #include "fault.h" #include "gamemenu.h" #include "gendung.h" #include "gmenu.h" #include "help.h" #include "init.h" #include "interfac.h" #include "inv.h" #include "itemdat.h" #include "items.h" #include "lighting.h" #include "loadsave.h" #include "logging.h" #include "mainmenu.h" #include "minitext.h" #include "misdat.h" #include "missiles.h" #include "monstdat.h" #include "monster.h" #include "movie.h" #include "mpqapi.h" #include "msg.h" #include "msgcmd.h" #include "multi.h" #include "nthread.h" #include "objdat.h" #include "objects.h" #include "pack.h" #include "palette.h" #include "path.h" #include "pfile.h" #include "player.h" #include "plrmsg.h" #include "portal.h" #include "quests.h" #include "restrict.h" #include "scrollrt.h" #include "setmaps.h" #include "sha.h" #include "sound.h" #include "spelldat.h" #include "spells.h" #include "stores.h" #include "sync.h" #include "textdat.h" // check file name #include "themes.h" #include "tmsg.h" #include "town.h" #include "towners.h" #include "track.h" #include "trigs.h" #include "wave.h" #include "render.h" // linked last, likely .s/.asm #ifdef __cplusplus } #endif #endif /* __ALL_H__ */ ================================================ FILE: Source/appfat.cpp ================================================ /** * @file appfat.cpp * * Implementation of error dialogs. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" /** Buffer used by GetErrorStr for its return value */ char sz_error_buf[256]; /** Set to true when a fatal error is encountered and the application should shut down. */ BOOL terminating; /** Thread id of the last callee to FreeDlg(). */ int cleanup_thread_id; // delete overloads the delete operator. void __cdecl operator delete(void *ptr) { if (ptr != NULL) { SMemFree(ptr, "delete", -1, 0); } } #ifdef _DEBUG static LONG __stdcall BreakFilter(PEXCEPTION_POINTERS pExc) { if (pExc->ExceptionRecord == NULL) { return EXCEPTION_CONTINUE_SEARCH; } if (pExc->ExceptionRecord->ExceptionCode != EXCEPTION_BREAKPOINT) { return EXCEPTION_CONTINUE_SEARCH; } if (((BYTE *)pExc->ContextRecord->Eip)[0] == 0xCC) { // int 3 pExc->ContextRecord->Eip++; } return EXCEPTION_CONTINUE_EXECUTION; } #endif void TriggerBreak() { #ifdef _DEBUG LPTOP_LEVEL_EXCEPTION_FILTER pFilter; pFilter = SetUnhandledExceptionFilter(BreakFilter); #ifdef USE_ASM __asm { int 3 } #else __debugbreak(); #endif SetUnhandledExceptionFilter(pFilter); #endif } /** * @brief Generate a textual message for DirectDraw error codes * @param hError DirectDraw error code * @param pszBuffer Buffer for the error message * @param dwMaxChars Length of pszBuffer */ static void TraceErrorDD(HRESULT hError, char *pszBuffer, DWORD dwMaxChars) { const char *szError; switch (hError) { case DD_OK: szError = "DD_OK"; break; case DDERR_ALREADYINITIALIZED: szError = "DDERR_ALREADYINITIALIZED"; break; case DDERR_BLTFASTCANTCLIP: szError = "DDERR_BLTFASTCANTCLIP"; break; case DDERR_CANNOTATTACHSURFACE: szError = "DDERR_CANNOTATTACHSURFACE"; break; case DDERR_CANNOTDETACHSURFACE: szError = "DDERR_CANNOTDETACHSURFACE"; break; case DDERR_CANTCREATEDC: szError = "DDERR_CANTCREATEDC"; break; case DDERR_CANTDUPLICATE: szError = "DDERR_CANTDUPLICATE"; break; case DDERR_CLIPPERISUSINGHWND: szError = "DDERR_CLIPPERISUSINGHWND"; break; case DDERR_COLORKEYNOTSET: szError = "DDERR_COLORKEYNOTSET"; break; case DDERR_CURRENTLYNOTAVAIL: szError = "DDERR_CURRENTLYNOTAVAIL"; break; case DDERR_DIRECTDRAWALREADYCREATED: szError = "DDERR_DIRECTDRAWALREADYCREATED"; break; case DDERR_EXCEPTION: szError = "DDERR_EXCEPTION"; break; case DDERR_EXCLUSIVEMODEALREADYSET: szError = "DDERR_EXCLUSIVEMODEALREADYSET"; break; case DDERR_GENERIC: szError = "DDERR_GENERIC"; break; case DDERR_HEIGHTALIGN: szError = "DDERR_HEIGHTALIGN"; break; case DDERR_HWNDALREADYSET: szError = "DDERR_HWNDALREADYSET"; break; case DDERR_HWNDSUBCLASSED: szError = "DDERR_HWNDSUBCLASSED"; break; case DDERR_IMPLICITLYCREATED: szError = "DDERR_IMPLICITLYCREATED"; break; case DDERR_INCOMPATIBLEPRIMARY: szError = "DDERR_INCOMPATIBLEPRIMARY"; break; case DDERR_INVALIDCAPS: szError = "DDERR_INVALIDCAPS"; break; case DDERR_INVALIDCLIPLIST: szError = "DDERR_INVALIDCLIPLIST"; break; case DDERR_INVALIDDIRECTDRAWGUID: szError = "DDERR_INVALIDDIRECTDRAWGUID"; break; case DDERR_INVALIDMODE: szError = "DDERR_INVALIDMODE"; break; case DDERR_INVALIDOBJECT: szError = "DDERR_INVALIDOBJECT"; break; case DDERR_INVALIDPARAMS: szError = "DDERR_INVALIDPARAMS"; break; case DDERR_INVALIDPIXELFORMAT: szError = "DDERR_INVALIDPIXELFORMAT"; break; case DDERR_INVALIDPOSITION: szError = "DDERR_INVALIDPOSITION"; break; case DDERR_INVALIDRECT: szError = "DDERR_INVALIDRECT"; break; case DDERR_LOCKEDSURFACES: szError = "DDERR_LOCKEDSURFACES"; break; case DDERR_NO3D: szError = "DDERR_NO3D"; break; case DDERR_NOALPHAHW: szError = "DDERR_NOALPHAHW"; break; case DDERR_NOBLTHW: szError = "DDERR_NOBLTHW"; break; case DDERR_NOCLIPLIST: szError = "DDERR_NOCLIPLIST"; break; case DDERR_NOCLIPPERATTACHED: szError = "DDERR_NOCLIPPERATTACHED"; break; case DDERR_NOCOLORCONVHW: szError = "DDERR_NOCOLORCONVHW"; break; case DDERR_NOCOLORKEY: szError = "DDERR_NOCOLORKEY"; break; case DDERR_NOCOLORKEYHW: szError = "DDERR_NOCOLORKEYHW"; break; case DDERR_NOCOOPERATIVELEVELSET: szError = "DDERR_NOCOOPERATIVELEVELSET"; break; case DDERR_NODC: szError = "DDERR_NODC"; break; case DDERR_NODDROPSHW: szError = "DDERR_NODDROPSHW"; break; case DDERR_NODIRECTDRAWHW: szError = "DDERR_NODIRECTDRAWHW"; break; case DDERR_NOEMULATION: szError = "DDERR_NOEMULATION"; break; case DDERR_NOEXCLUSIVEMODE: szError = "DDERR_NOEXCLUSIVEMODE"; break; case DDERR_NOFLIPHW: szError = "DDERR_NOFLIPHW"; break; case DDERR_NOGDI: szError = "DDERR_NOGDI"; break; case DDERR_NOHWND: szError = "DDERR_NOHWND"; break; case DDERR_NOMIRRORHW: szError = "DDERR_NOMIRRORHW"; break; case DDERR_NOOVERLAYDEST: szError = "DDERR_NOOVERLAYDEST"; break; case DDERR_NOOVERLAYHW: szError = "DDERR_NOOVERLAYHW"; break; case DDERR_NOPALETTEATTACHED: szError = "DDERR_NOPALETTEATTACHED"; break; case DDERR_NOPALETTEHW: szError = "DDERR_NOPALETTEHW"; break; case DDERR_NORASTEROPHW: szError = "DDERR_NORASTEROPHW"; break; case DDERR_NOROTATIONHW: szError = "DDERR_NOROTATIONHW"; break; case DDERR_NOSTRETCHHW: szError = "DDERR_NOSTRETCHHW"; break; case DDERR_NOT4BITCOLOR: szError = "DDERR_NOT4BITCOLOR"; break; case DDERR_NOT4BITCOLORINDEX: szError = "DDERR_NOT4BITCOLORINDEX"; break; case DDERR_NOT8BITCOLOR: szError = "DDERR_NOT8BITCOLOR"; break; case DDERR_NOTAOVERLAYSURFACE: szError = "DDERR_NOTAOVERLAYSURFACE"; break; case DDERR_NOTEXTUREHW: szError = "DDERR_NOTEXTUREHW"; break; case DDERR_NOTFLIPPABLE: szError = "DDERR_NOTFLIPPABLE"; break; case DDERR_NOTFOUND: szError = "DDERR_NOTFOUND"; break; case DDERR_NOTLOCKED: szError = "DDERR_NOTLOCKED"; break; case DDERR_NOTPALETTIZED: szError = "DDERR_NOTPALETTIZED"; break; case DDERR_NOVSYNCHW: szError = "DDERR_NOVSYNCHW"; break; case DDERR_NOZBUFFERHW: szError = "DDERR_NOZBUFFERHW"; break; case DDERR_NOZOVERLAYHW: szError = "DDERR_NOZOVERLAYHW"; break; case DDERR_OUTOFCAPS: szError = "DDERR_OUTOFCAPS"; break; case DDERR_OUTOFMEMORY: szError = "DDERR_OUTOFMEMORY"; break; case DDERR_OUTOFVIDEOMEMORY: szError = "DDERR_OUTOFVIDEOMEMORY"; break; case DDERR_OVERLAYCANTCLIP: szError = "DDERR_OVERLAYCANTCLIP"; break; case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: szError = "DDERR_OVERLAYCOLORKEYONLYONEACTIVE"; break; case DDERR_OVERLAYNOTVISIBLE: szError = "DDERR_OVERLAYNOTVISIBLE"; break; case DDERR_PALETTEBUSY: szError = "DDERR_PALETTEBUSY"; break; case DDERR_PRIMARYSURFACEALREADYEXISTS: szError = "DDERR_PRIMARYSURFACEALREADYEXISTS"; break; case DDERR_REGIONTOOSMALL: szError = "DDERR_REGIONTOOSMALL"; break; case DDERR_SURFACEALREADYATTACHED: szError = "DDERR_SURFACEALREADYATTACHED"; break; case DDERR_SURFACEALREADYDEPENDENT: szError = "DDERR_SURFACEALREADYDEPENDENT"; break; case DDERR_SURFACEBUSY: szError = "DDERR_SURFACEBUSY"; break; case DDERR_SURFACEISOBSCURED: szError = "DDERR_SURFACEISOBSCURED"; break; case DDERR_SURFACELOST: szError = "DDERR_SURFACELOST"; break; case DDERR_SURFACENOTATTACHED: szError = "DDERR_SURFACENOTATTACHED"; break; case DDERR_TOOBIGHEIGHT: szError = "DDERR_TOOBIGHEIGHT"; break; case DDERR_TOOBIGSIZE: szError = "DDERR_TOOBIGSIZE"; break; case DDERR_TOOBIGWIDTH: szError = "DDERR_TOOBIGWIDTH"; break; case DDERR_UNSUPPORTED: szError = "DDERR_UNSUPPORTED"; break; case DDERR_UNSUPPORTEDFORMAT: szError = "DDERR_UNSUPPORTEDFORMAT"; break; case DDERR_UNSUPPORTEDMASK: szError = "DDERR_UNSUPPORTEDMASK"; break; case DDERR_VERTICALBLANKINPROGRESS: szError = "DDERR_VERTICALBLANKINPROGRESS"; break; case DDERR_WASSTILLDRAWING: szError = "DDERR_WASSTILLDRAWING"; break; case DDERR_WRONGMODE: szError = "DDERR_WRONGMODE"; break; case DDERR_XALIGN: szError = "DDERR_XALIGN"; break; case DDERR_CANTLOCKSURFACE: szError = "DDERR_CANTLOCKSURFACE"; break; case DDERR_CANTPAGELOCK: szError = "DDERR_CANTPAGELOCK"; break; case DDERR_CANTPAGEUNLOCK: szError = "DDERR_CANTPAGEUNLOCK"; break; case DDERR_DCALREADYCREATED: szError = "DDERR_DCALREADYCREATED"; break; case DDERR_INVALIDSURFACETYPE: szError = "DDERR_INVALIDSURFACETYPE"; break; case DDERR_NOMIPMAPHW: szError = "DDERR_NOMIPMAPHW"; break; case DDERR_NOTPAGELOCKED: szError = "DDERR_NOTPAGELOCKED"; break; default: { const char szUnknown[] = "DDERR unknown 0x%x"; assert(dwMaxChars >= sizeof(szUnknown) + 10); sprintf(pszBuffer, szUnknown, hError); return; } } strncpy(pszBuffer, szError, dwMaxChars); } /** * @brief Generate a textual message for DirectSound error codes * @param hError DirectSound error code * @param pszBuffer Buffer for the error message * @param dwMaxChars Length of pszBuffer */ static void TraceErrorDS(HRESULT hError, char *pszBuffer, DWORD dwMaxChars) { const char *szError; switch (hError) { case DSERR_PRIOLEVELNEEDED: szError = "DSERR_PRIOLEVELNEEDED"; break; case DSERR_BADFORMAT: szError = "DSERR_BADFORMAT"; break; case DSERR_NODRIVER: szError = "DSERR_NODRIVER"; break; case DSERR_ALREADYINITIALIZED: szError = "DSERR_ALREADYINITIALIZED"; break; case DSERR_BUFFERLOST: szError = "DSERR_BUFFERLOST"; break; case DS_OK: szError = "DS_OK"; break; case DSERR_INVALIDCALL: szError = "DSERR_INVALIDCALL"; break; case E_NOINTERFACE: szError = "E_NOINTERFACE"; break; case DSERR_NOAGGREGATION: szError = "DSERR_NOAGGREGATION"; break; case DSERR_OUTOFMEMORY: szError = "DSERR_OUTOFMEMORY"; break; case DSERR_INVALIDPARAM: szError = "DSERR_INVALIDPARAM"; break; case DSERR_ALLOCATED: szError = "DSERR_ALLOCATED"; break; case DSERR_CONTROLUNAVAIL: szError = "DSERR_CONTROLUNAVAIL"; break; default: { const char szUnknown[] = "DSERR unknown 0x%x"; assert(dwMaxChars >= sizeof(szUnknown) + 10); sprintf(pszBuffer, szUnknown, hError); return; } } strncpy(pszBuffer, szError, dwMaxChars); } /** * @brief Returns a formatted error message based on the given error code. * @param error_code DirectX error code */ const char *GetErrorStr(DWORD error_code) { int size; char *chr; if (HRESULT_FACILITY(error_code) == _FACDS) { TraceErrorDS(error_code, sz_error_buf, sizeof(sz_error_buf) / sizeof(sz_error_buf[0])); } else if (HRESULT_FACILITY(error_code) == _FACDD) { TraceErrorDD(error_code, sz_error_buf, sizeof(sz_error_buf) / sizeof(sz_error_buf[0])); } else if (!SErrGetErrorStr(error_code, sz_error_buf, sizeof(sz_error_buf) / sizeof(sz_error_buf[0])) && !FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), sz_error_buf, sizeof(sz_error_buf) / sizeof(sz_error_buf[0]), NULL)) { wsprintf(sz_error_buf, "unknown error 0x%08x", error_code); } size = strlen(sz_error_buf); chr = &sz_error_buf[size - 1]; while (size-- > 0) { chr--; if (*chr != '\r' && *chr != '\n') break; *chr = 0x00; } return sz_error_buf; } /** * @brief Returns a formatted error message of the last error. */ const char *TraceLastError() { return GetErrorStr(GetLastError()); } /** * @brief Displays an error message box based on the given format string and variable argument list. * @param pszFmt Error message format * @param va Additional parameters for message format */ static void MsgBox(const char *pszFmt, va_list va) { char Text[256]; 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); } /** * @brief Cleans up after a fatal application error. */ static void FreeDlg() { if (terminating && cleanup_thread_id != GetCurrentThreadId()) Sleep(20000); terminating = TRUE; cleanup_thread_id = GetCurrentThreadId(); dx_cleanup(); if (gbMaxPlayers > 1) { if (SNetLeaveGame(3)) Sleep(2000); } SNetDestroy(); ShowCursor(TRUE); } /** * @brief Terminates the game and displays an error message box. * @param pszFmt Optional error message. * @param ... (see printf) */ #ifdef HELLFIRE __declspec(naked) #endif void __cdecl app_fatal(const char *pszFmt, ...) { va_list va; va_start(va, pszFmt); FreeDlg(); #if defined(_DEBUG) || defined(HELLFIRE) TriggerBreak(); #endif if (pszFmt) MsgBox(pszFmt, va); va_end(va); init_cleanup(FALSE); exit(1); ExitProcess(1); } /** * @brief Displays a warning message box based on the given formatted error message. * @param pszFmt Error message format * @param ... Additional parameters for message format */ void __cdecl DrawDlg(const char *pszFmt, ...) { char text[256]; va_list arglist; va_start(arglist, pszFmt); wvsprintf(text, pszFmt, arglist); va_end(arglist); SDrawMessageBox(text, APP_NAME, MB_TASKMODAL | MB_ICONEXCLAMATION); } #ifdef _DEBUG /** * @brief Show an error and exit the application. * @param nLineNo The line number of the assertion * @param pszFile File name where the assertion is located * @param pszFail Fail message */ void assert_fail(int nLineNo, const char *pszFile, const char *pszFail) { app_fatal("assertion failed (%d:%s)\n%s", nLineNo, pszFile, pszFail); } #endif /** * @brief Terminates the game with a DirectDraw assertion message box. */ void DDErrMsg(DWORD error_code, int log_line_nr, const char *log_file_path) { const char *msg; if (error_code) { msg = GetErrorStr(error_code); app_fatal("Direct draw error (%s:%d)\n%s", log_file_path, log_line_nr, msg); } } /** * @brief Terminates the game with a DirectSound assertion message box. */ void DSErrMsg(DWORD error_code, int log_line_nr, const char *log_file_path) { const char *msg; if (error_code) { msg = GetErrorStr(error_code); app_fatal("Direct sound error (%s:%d)\n%s", log_file_path, log_line_nr, msg); } } /** * @brief Centres the given dialog box. */ void center_window(HWND hDlg) { LONG w, h; int screenW, screenH; tagRECT Rect; HDC hdc; GetWindowRect(hDlg, &Rect); w = Rect.right - Rect.left; h = Rect.bottom - Rect.top; hdc = GetDC(hDlg); screenW = GetDeviceCaps(hdc, HORZRES); screenH = GetDeviceCaps(hdc, VERTRES); ReleaseDC(hDlg, hdc); if (!SetWindowPos(hDlg, HWND_TOP, (screenW - w) / 2, (screenH - h) / 2, 0, 0, SWP_NOZORDER | SWP_NOSIZE)) { app_fatal("center_window: %s", TraceLastError()); } } /** * @brief Sets the text of the given dialog. */ static void TextDlg(HWND hDlg, const char *text) { center_window(hDlg); if (text) SetDlgItemText(hDlg, 1000, text); } /** * @brief Callback function which processes messages sent to the given dialog box. */ static BOOL CALLBACK FuncDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: TextDlg(hDlg, (char *)lParam); break; case WM_COMMAND: if (LOWORD(wParam) == IDOK) { EndDialog(hDlg, TRUE); } else if (LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, FALSE); } break; default: return FALSE; } return TRUE; } /** * @brief Terminates the game and displays an error dialog box based on the given dialog_id. */ void ErrDlg(int dialog_id, DWORD error_code, const char *log_file_path, int log_line_nr) { const char *size; LPARAM dwInitParam[128]; FreeDlg(); size = strrchr(log_file_path, '\\'); if (size) log_file_path = size + 1; wsprintf((LPSTR)dwInitParam, "%s\nat: %s line %d", GetErrorStr(error_code), log_file_path, log_line_nr); if (DialogBoxParam(ghInst, MAKEINTRESOURCE(dialog_id), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)dwInitParam) == -1) app_fatal("ErrDlg: %d", dialog_id); app_fatal(NULL); } #ifndef HELLFIRE /** * @brief Displays a warning dialog box based on the given dialog_id and error code. */ void ErrOkDlg(int dialog_id, DWORD error_code, const char *log_file_path, int log_line_nr) { const char *size; LPARAM dwInitParam[128]; size = strrchr(log_file_path, '\\'); if (size) log_file_path = size + 1; wsprintf((LPSTR)dwInitParam, "%s\nat: %s line %d", GetErrorStr(error_code), log_file_path, log_line_nr); DialogBoxParam(ghInst, MAKEINTRESOURCE(dialog_id), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)dwInitParam); } #endif /** * @brief Terminates the game with a file not found error dialog. */ void FileErrDlg(const char *error) { FreeDlg(); if (!error) error = ""; if (DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_DIALOG3), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)error) == -1) app_fatal("FileErrDlg"); app_fatal(NULL); } /** * @brief Terminates the game with an out of disk space error dialog. */ void DiskFreeDlg(const char *error) { FreeDlg(); if (DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_DIALOG7), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)error) == -1) app_fatal("DiskFreeDlg"); app_fatal(NULL); } /** * @brief Terminates the game with an insert CD error dialog. */ BOOL InsertCDDlg() { int nResult; ShowCursor(TRUE); nResult = DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_DIALOG9), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM) ""); if (nResult == -1) app_fatal("InsertCDDlg"); ShowCursor(FALSE); return nResult == IDOK; } #ifndef HELLFIRE /** * @brief Terminates the game with a read-only directory error dialog. */ void DirErrorDlg(const char *error) { FreeDlg(); if (DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_DIALOG11), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)error) == -1) app_fatal("DirErrorDlg"); app_fatal(NULL); } #endif ================================================ FILE: Source/appfat.h ================================================ /** * @file appfat.h * * Interface of error dialogs. */ #ifndef __APPFAT_H__ #define __APPFAT_H__ void TriggerBreak(); const char *TraceLastError(); void __cdecl app_fatal(const char *pszFmt, ...); void __cdecl DrawDlg(const char *pszFmt, ...); #ifdef _DEBUG void assert_fail(int nLineNo, const char *pszFile, const char *pszFail); #endif void DDErrMsg(DWORD error_code, int log_line_nr, const char *log_file_path); void DSErrMsg(DWORD error_code, int log_line_nr, const char *log_file_path); void ErrDlg(int template_id, DWORD error_code, const char *log_file_path, int log_line_nr); void ErrOkDlg(int template_id, DWORD error_code, const char *log_file_path, int log_line_nr); void FileErrDlg(const char *error); void DiskFreeDlg(const char *error); BOOL InsertCDDlg(); void DirErrorDlg(const char *error); #endif /* __APPFAT_H__ */ ================================================ FILE: Source/asm_trans_rect.inc ================================================ /* Draws a half-transparent rectangle by blacking out odd pixels on odd lines, * even pixels on even lines. * * TRANS_RECT_X = x offset of upper-left corner * TRANS_RECT_Y = y offset of upper-left corner * TRANS_RECT_WIDTH = width of rectangle * TRANS_RECT_HEIGHT = height of rectangle */ #if !defined(TRANS_RECT_X) || !defined(TRANS_RECT_Y) || !defined(TRANS_RECT_WIDTH) || !defined(TRANS_RECT_HEIGHT) #error ASM_TRANS_RECT: Parameter not set #endif #if defined(_MSC_VER) && defined(_M_IX86) __asm { mov edi, gpBuffer ; origin is at 64,160 add edi, (SCREEN_Y + TRANS_RECT_Y + TRANS_RECT_HEIGHT - 1) * BUFFER_WIDTH + 64 + TRANS_RECT_X xor eax, eax mov edx, TRANS_RECT_HEIGHT >> 1 yloop: mov ecx, TRANS_RECT_WIDTH >> 1 x0loop: stosb inc edi loop x0loop #if (TRANS_RECT_WIDTH & 1) stosb #endif sub edi, BUFFER_WIDTH + TRANS_RECT_WIDTH mov ecx, TRANS_RECT_WIDTH >> 1 x1loop: inc edi stosb loop x1loop sub edi, BUFFER_WIDTH + (TRANS_RECT_WIDTH & ~1) dec edx jnz yloop #if (TRANS_RECT_HEIGHT & 1) mov ecx, TRANS_RECT_WIDTH >> 1 x2loop: stosb inc edi loop x2loop #if (TRANS_RECT_WIDTH & 1) stosb #endif #endif } #else // _MSC_VER && _M_IX86 { int row, col; BYTE *pix = &gpBuffer[SCREENXY(TRANS_RECT_X, TRANS_RECT_Y + TRANS_RECT_HEIGHT - 1)]; for (row = TRANS_RECT_HEIGHT >> 1; row != 0; row--) { for (col = TRANS_RECT_WIDTH >> 1; col != 0; col--) { *pix++ = 0; pix++; } #if (TRANS_RECT_WIDTH & 1) *pix++ = 0; #endif pix -= BUFFER_WIDTH + TRANS_RECT_WIDTH; for (col = TRANS_RECT_WIDTH >> 1; col != 0; col--) { pix++; *pix++ = 0; } pix -= BUFFER_WIDTH + (TRANS_RECT_WIDTH & ~1); } #if (TRANS_RECT_HEIGHT & 1) for (col = TRANS_RECT_WIDTH >> 1; col != 0; col--) { *pix++ = 0; pix++; } #if (TRANS_RECT_WIDTH & 1) *pix++ = 0; #endif #endif } #endif #undef TRANS_RECT_Y #undef TRANS_RECT_X #undef TRANS_RECT_WIDTH #undef TRANS_RECT_HEIGHT ================================================ FILE: Source/automap.cpp ================================================ /** * @file automap.cpp * * Implementation of the in-game map overlay. */ #include "all.h" /** * Maps from tile_id to automap type. * BUGFIX: only the first 256 elements are ever read */ WORD automaptype[512]; static int AutoMapX; static int AutoMapY; /** Specifies whether the automap is enabled. */ BOOL automapflag; char AmShiftTab[32]; /** Tracks the explored areas of the map. */ BOOLEAN automapview[DMAXX][DMAXY]; /** Specifies the scale of the automap. */ int AutoMapScale; int AutoMapXOfs; int AutoMapYOfs; int AmLine64; int AmLine32; int AmLine16; int AmLine8; int AmLine4; /** color used to draw the player's arrow */ #define COLOR_PLAYER (PAL8_ORANGE + 1) /** color for bright map lines (doors, stairs etc.) */ #define COLOR_BRIGHT PAL8_YELLOW /** color for dim map lines/dots */ #define COLOR_DIM (PAL16_YELLOW + 8) #ifdef HELLFIRE // color for items on automap #define COLOR_ITEM (PAL8_BLUE + 1) #endif #define MAPFLAG_TYPE 0x000F /** these are in the second byte */ #define MAPFLAG_VERTDOOR 0x01 #define MAPFLAG_HORZDOOR 0x02 #define MAPFLAG_VERTARCH 0x04 #define MAPFLAG_HORZARCH 0x08 #define MAPFLAG_VERTGRATE 0x10 #define MAPFLAG_HORZGRATE 0x20 #define MAPFLAG_DIRT 0x40 #define MAPFLAG_STAIRS 0x80 /** * @brief Initializes the automap. */ void InitAutomapOnce() { automapflag = FALSE; AutoMapScale = 50; AmLine64 = 32; AmLine32 = 16; AmLine16 = 8; AmLine8 = 4; AmLine4 = 2; } /** * @brief Loads the mapping between tile IDs and automap shapes. */ void InitAutomap() { BYTE b1, b2; DWORD dwTiles; int x, y; BYTE *pAFile, *pTmp; int i, j; int d; j = 50; for (i = 0; i < 31; i++) { d = (j << 6) / 100; AmShiftTab[i] = 2 * (SCREEN_WIDTH / 2 / d) + 1; if ((SCREEN_WIDTH / 2) % d) AmShiftTab[i]++; if ((SCREEN_WIDTH / 2) % d >= (j << 5) / 100) AmShiftTab[i]++; j += 5; } memset(automaptype, 0, sizeof(automaptype)); switch (leveltype) { case DTYPE_CATHEDRAL: #ifdef HELLFIRE if (currlevel < 21) pAFile = LoadFileInMem("Levels\\L1Data\\L1.AMP", &dwTiles); else pAFile = LoadFileInMem("NLevels\\L5Data\\L5.AMP", &dwTiles); #else pAFile = LoadFileInMem("Levels\\L1Data\\L1.AMP", &dwTiles); #endif break; case DTYPE_CATACOMBS: pAFile = LoadFileInMem("Levels\\L2Data\\L2.AMP", &dwTiles); break; case DTYPE_CAVES: #ifdef HELLFIRE if (currlevel < 17) pAFile = LoadFileInMem("Levels\\L3Data\\L3.AMP", &dwTiles); else pAFile = LoadFileInMem("NLevels\\L6Data\\L6.AMP", &dwTiles); #else pAFile = LoadFileInMem("Levels\\L3Data\\L3.AMP", &dwTiles); #endif break; case DTYPE_HELL: pAFile = LoadFileInMem("Levels\\L4Data\\L4.AMP", &dwTiles); break; default: return; } dwTiles /= 2; pTmp = pAFile; for (i = 1; i <= dwTiles; i++) { b1 = *pTmp++; b2 = *pTmp++; automaptype[i] = b1 + (b2 << 8); } mem_free_dbg(pAFile); memset(automapview, 0, sizeof(automapview)); for (y = 0; y < MAXDUNY; y++) { for (x = 0; x < MAXDUNX; x++) dFlags[x][y] &= ~BFLAG_EXPLORED; } } /** * @brief Displays the automap. */ void StartAutomap() { AutoMapXOfs = 0; AutoMapYOfs = 0; automapflag = TRUE; } /** * @brief Scrolls the automap upwards. */ void AutomapUp() { AutoMapXOfs--; AutoMapYOfs--; } /** * @brief Scrolls the automap downwards. */ void AutomapDown() { AutoMapXOfs++; AutoMapYOfs++; } /** * @brief Scrolls the automap leftwards. */ void AutomapLeft() { AutoMapXOfs--; AutoMapYOfs++; } /** * @brief Scrolls the automap rightwards. */ void AutomapRight() { AutoMapXOfs++; AutoMapYOfs--; } /** * @brief Increases the zoom level of the automap. */ void AutomapZoomIn() { if (AutoMapScale < 200) { AutoMapScale += 5; AmLine64 = (AutoMapScale << 6) / 100; AmLine32 = AmLine64 >> 1; AmLine16 = AmLine32 >> 1; AmLine8 = AmLine16 >> 1; AmLine4 = AmLine8 >> 1; } } /** * @brief Decreases the zoom level of the automap. */ void AutomapZoomOut() { if (AutoMapScale > 50) { AutoMapScale -= 5; AmLine64 = (AutoMapScale << 6) / 100; AmLine32 = AmLine64 >> 1; AmLine16 = AmLine32 >> 1; AmLine8 = AmLine16 >> 1; AmLine4 = AmLine8 >> 1; } } /** * @brief Renders the given automap shape at the specified screen coordinates. */ static void DrawAutomapTile(int sx, int sy, WORD automap_type) { BOOL do_vert; BOOL do_horz; BOOL do_cave_horz; BOOL do_cave_vert; int x1, y1, x2, y2; BYTE flags = automap_type >> 8; if (flags & MAPFLAG_DIRT) { ENG_set_pixel(sx, sy, COLOR_DIM); ENG_set_pixel(sx - AmLine8, sy - AmLine4, COLOR_DIM); ENG_set_pixel(sx - AmLine8, sy + AmLine4, COLOR_DIM); ENG_set_pixel(sx + AmLine8, sy - AmLine4, COLOR_DIM); ENG_set_pixel(sx + AmLine8, sy + AmLine4, COLOR_DIM); ENG_set_pixel(sx - AmLine16, sy, COLOR_DIM); ENG_set_pixel(sx + AmLine16, sy, COLOR_DIM); ENG_set_pixel(sx, sy - AmLine8, COLOR_DIM); ENG_set_pixel(sx, sy + AmLine8, COLOR_DIM); ENG_set_pixel(sx + AmLine8 - AmLine32, sy + AmLine4, COLOR_DIM); ENG_set_pixel(sx - AmLine8 + AmLine32, sy + AmLine4, COLOR_DIM); ENG_set_pixel(sx - AmLine16, sy + AmLine8, COLOR_DIM); ENG_set_pixel(sx + AmLine16, sy + AmLine8, COLOR_DIM); ENG_set_pixel(sx - AmLine8, sy + AmLine16 - AmLine4, COLOR_DIM); ENG_set_pixel(sx + AmLine8, sy + AmLine16 - AmLine4, COLOR_DIM); ENG_set_pixel(sx, sy + AmLine16, COLOR_DIM); } if (flags & MAPFLAG_STAIRS) { DrawLine(sx - AmLine8, sy - AmLine8 - AmLine4, sx + AmLine8 + AmLine16, sy + AmLine4, COLOR_BRIGHT); DrawLine(sx - AmLine16, sy - AmLine8, sx + AmLine16, sy + AmLine8, COLOR_BRIGHT); DrawLine(sx - AmLine16 - AmLine8, sy - AmLine4, sx + AmLine8, sy + AmLine8 + AmLine4, COLOR_BRIGHT); DrawLine(sx - AmLine32, sy, sx, sy + AmLine16, COLOR_BRIGHT); } do_vert = FALSE; do_horz = FALSE; do_cave_horz = FALSE; do_cave_vert = FALSE; switch (automap_type & MAPFLAG_TYPE) { case 1: // stand-alone column or other unpassable object x1 = sx - AmLine16; y1 = sy - AmLine16; x2 = x1 + AmLine32; y2 = sy - AmLine8; DrawLine(sx, y1, x1, y2, COLOR_DIM); DrawLine(sx, y1, x2, y2, COLOR_DIM); DrawLine(sx, sy, x1, y2, COLOR_DIM); DrawLine(sx, sy, x2, y2, COLOR_DIM); break; case 2: case 5: do_vert = TRUE; break; case 3: case 6: do_horz = TRUE; break; case 4: do_vert = TRUE; do_horz = TRUE; break; case 8: do_vert = TRUE; do_cave_horz = TRUE; break; case 9: do_horz = TRUE; do_cave_vert = TRUE; break; case 10: do_cave_horz = TRUE; break; case 11: do_cave_vert = TRUE; break; case 12: do_cave_horz = TRUE; do_cave_vert = TRUE; break; } if (do_vert) { // right-facing obstacle if (flags & MAPFLAG_VERTDOOR) { // two wall segments with a door in the middle x1 = sx - AmLine32; x2 = sx - AmLine16; y1 = sy - AmLine16; y2 = sy - AmLine8; DrawLine(sx, y1, sx - AmLine8, y1 + AmLine4, COLOR_DIM); DrawLine(x1, sy, x1 + AmLine8, sy - AmLine4, COLOR_DIM); DrawLine(x2, y1, x1, y2, COLOR_BRIGHT); DrawLine(x2, y1, sx, y2, COLOR_BRIGHT); DrawLine(x2, sy, x1, y2, COLOR_BRIGHT); DrawLine(x2, sy, sx, y2, COLOR_BRIGHT); } if (flags & MAPFLAG_VERTGRATE) { // right-facing half-wall DrawLine(sx - AmLine16, sy - AmLine8, sx - AmLine32, sy, COLOR_DIM); flags |= MAPFLAG_VERTARCH; } if (flags & MAPFLAG_VERTARCH) { // window or passable column x1 = sx - AmLine16; y1 = sy - AmLine16; x2 = x1 + AmLine32; y2 = sy - AmLine8; DrawLine(sx, y1, x1, y2, COLOR_DIM); DrawLine(sx, y1, x2, y2, COLOR_DIM); DrawLine(sx, sy, x1, y2, COLOR_DIM); DrawLine(sx, sy, x2, y2, COLOR_DIM); } if ((flags & (MAPFLAG_VERTDOOR | MAPFLAG_VERTGRATE | MAPFLAG_VERTARCH)) == 0) DrawLine(sx, sy - AmLine16, sx - AmLine32, sy, COLOR_DIM); } if (do_horz) { // left-facing obstacle if (flags & MAPFLAG_HORZDOOR) { x1 = sx + AmLine16; x2 = sx + AmLine32; y1 = sy - AmLine16; y2 = sy - AmLine8; DrawLine(sx, y1, sx + AmLine8, y1 + AmLine4, COLOR_DIM); DrawLine(x2, sy, x2 - AmLine8, sy - AmLine4, COLOR_DIM); DrawLine(x1, y1, sx, y2, COLOR_BRIGHT); DrawLine(x1, y1, x2, y2, COLOR_BRIGHT); DrawLine(x1, sy, sx, y2, COLOR_BRIGHT); DrawLine(x1, sy, x2, y2, COLOR_BRIGHT); } if (flags & MAPFLAG_HORZGRATE) { DrawLine(sx + AmLine16, sy - AmLine8, sx + AmLine32, sy, COLOR_DIM); flags |= MAPFLAG_HORZARCH; } if (flags & MAPFLAG_HORZARCH) { x1 = sx - AmLine16; y1 = sy - AmLine16; x2 = x1 + AmLine32; y2 = sy - AmLine8; DrawLine(sx, y1, x1, y2, COLOR_DIM); DrawLine(sx, y1, x2, y2, COLOR_DIM); DrawLine(sx, sy, x1, y2, COLOR_DIM); DrawLine(sx, sy, x2, y2, COLOR_DIM); } if ((flags & (MAPFLAG_HORZDOOR | MAPFLAG_HORZGRATE | MAPFLAG_HORZARCH)) == 0) DrawLine(sx, sy - AmLine16, sx + AmLine32, sy, COLOR_DIM); } // for caves the horz/vert flags are switched if (do_cave_horz) { if (flags & MAPFLAG_VERTDOOR) { x1 = sx - AmLine32; x2 = sx - AmLine16; y1 = sy + AmLine16; y2 = sy + AmLine8; DrawLine(sx, y1, sx - AmLine8, y1 - AmLine4, COLOR_DIM); DrawLine(x1, sy, x1 + AmLine8, sy + AmLine4, COLOR_DIM); DrawLine(x2, y1, x1, y2, COLOR_BRIGHT); DrawLine(x2, y1, sx, y2, COLOR_BRIGHT); DrawLine(x2, sy, x1, y2, COLOR_BRIGHT); DrawLine(x2, sy, sx, y2, COLOR_BRIGHT); } else DrawLine(sx, sy + AmLine16, sx - AmLine32, sy, COLOR_DIM); } if (do_cave_vert) { if (flags & MAPFLAG_HORZDOOR) { x1 = sx + AmLine16; x2 = sx + AmLine32; y1 = sy + AmLine16; y2 = sy + AmLine8; DrawLine(sx, y1, sx + AmLine8, y1 - AmLine4, COLOR_DIM); DrawLine(x2, sy, x2 - AmLine8, sy + AmLine4, COLOR_DIM); DrawLine(x1, y1, sx, y2, COLOR_BRIGHT); DrawLine(x1, y1, x2, y2, COLOR_BRIGHT); DrawLine(x1, sy, sx, y2, COLOR_BRIGHT); DrawLine(x1, sy, x2, y2, COLOR_BRIGHT); } else DrawLine(sx, sy + AmLine16, sx + AmLine32, sy, COLOR_DIM); } } #ifdef HELLFIRE static void DrawAutomapItem(int x, int y, BYTE color) { int x1, y1, x2, y2; x1 = x - AmLine32 / 2; y1 = y - AmLine16 / 2; x2 = x1 + AmLine64 / 2; y2 = y1 + AmLine32 / 2; DrawLine(x, y1, x1, y, color); DrawLine(x, y1, x2, y, color); DrawLine(x, y2, x1, y, color); DrawLine(x, y2, x2, y, color); } void SearchAutomapItem() { int x, y; int x1, y1, x2, y2; int px, py; int i, j; if (plr[myplr]._pmode == PM_WALK3) { x = plr[myplr]._pfutx; y = plr[myplr]._pfuty; if (plr[myplr]._pdir == DIR_W) x++; else y++; } else { x = plr[myplr]._px; y = plr[myplr]._py; } x1 = x - 8; if (x1 < 0) x1 = 0; else if (x1 > MAXDUNX) x1 = MAXDUNX; y1 = y - 8; if (y1 < 0) y1 = 0; else if (y1 > MAXDUNY) y1 = MAXDUNY; x2 = x + 8; if (x2 < 0) x2 = 0; else if (x2 > MAXDUNX) x2 = MAXDUNX; y2 = y + 8; if (y2 < 0) y2 = 0; else if (y2 > MAXDUNY) y2 = MAXDUNY; for (i = x1; i < x2; i++) { for (j = y1; j < y2; j++) { if (dItem[i][j] != 0) { px = i - 2 * AutoMapXOfs - ViewX; py = j - 2 * AutoMapYOfs - ViewY; x = (ScrollInfo._sxoff * AutoMapScale / 100 >> 1) + (px - py) * AmLine16 + SCREEN_WIDTH / 2 + SCREEN_X; y = (ScrollInfo._syoff * AutoMapScale / 100 >> 1) + (px + py) * AmLine8 + (SCREEN_HEIGHT - PANEL_HEIGHT) / 2 + SCREEN_Y; if (invflag || sbookflag) x -= 160; if (chrflag || questlog) x += 160; y -= AmLine8; DrawAutomapItem(x, y, COLOR_ITEM); } } } } #endif /** * @brief Renders an arrow on the automap, centered on and facing the direction of the player. */ static void DrawAutomapPlr() { int px, py; int x, y; if (plr[myplr]._pmode == PM_WALK3) { x = plr[myplr]._pfutx; y = plr[myplr]._pfuty; if (plr[myplr]._pdir == DIR_W) x++; else y++; } else { x = plr[myplr]._px; y = plr[myplr]._py; } px = x - 2 * AutoMapXOfs - ViewX; py = y - 2 * AutoMapYOfs - ViewY; x = (plr[myplr]._pxoff * AutoMapScale / 100 >> 1) + (ScrollInfo._sxoff * AutoMapScale / 100 >> 1) + (px - py) * AmLine16 + SCREEN_WIDTH / 2 + SCREEN_X; y = (plr[myplr]._pyoff * AutoMapScale / 100 >> 1) + (ScrollInfo._syoff * AutoMapScale / 100 >> 1) + (px + py) * AmLine8 + (SCREEN_HEIGHT - PANEL_HEIGHT) / 2 + SCREEN_Y; if (invflag || sbookflag) x -= SCREEN_WIDTH / 4; if (chrflag || questlog) x += SCREEN_WIDTH / 4; y -= AmLine8; switch (plr[myplr]._pdir) { case DIR_N: DrawLine(x, y, x, y - AmLine16, COLOR_PLAYER); DrawLine(x, y - AmLine16, x - AmLine4, y - AmLine8, COLOR_PLAYER); DrawLine(x, y - AmLine16, x + AmLine4, y - AmLine8, COLOR_PLAYER); break; case DIR_NE: DrawLine(x, y, x + AmLine16, y - AmLine8, COLOR_PLAYER); DrawLine(x + AmLine16, y - AmLine8, x + AmLine8, y - AmLine8, COLOR_PLAYER); DrawLine(x + AmLine16, y - AmLine8, x + AmLine8 + AmLine4, y, COLOR_PLAYER); break; case DIR_E: DrawLine(x, y, x + AmLine16, y, COLOR_PLAYER); DrawLine(x + AmLine16, y, x + AmLine8, y - AmLine4, COLOR_PLAYER); DrawLine(x + AmLine16, y, x + AmLine8, y + AmLine4, COLOR_PLAYER); break; case DIR_SE: DrawLine(x, y, x + AmLine16, y + AmLine8, COLOR_PLAYER); DrawLine(x + AmLine16, y + AmLine8, x + AmLine8 + AmLine4, y, COLOR_PLAYER); DrawLine(x + AmLine16, y + AmLine8, x + AmLine8, y + AmLine8, COLOR_PLAYER); break; case DIR_S: DrawLine(x, y, x, y + AmLine16, COLOR_PLAYER); DrawLine(x, y + AmLine16, x + AmLine4, y + AmLine8, COLOR_PLAYER); DrawLine(x, y + AmLine16, x - AmLine4, y + AmLine8, COLOR_PLAYER); break; case DIR_SW: DrawLine(x, y, x - AmLine16, y + AmLine8, COLOR_PLAYER); DrawLine(x - AmLine16, y + AmLine8, x - AmLine4 - AmLine8, y, COLOR_PLAYER); DrawLine(x - AmLine16, y + AmLine8, x - AmLine8, y + AmLine8, COLOR_PLAYER); break; case DIR_W: DrawLine(x, y, x - AmLine16, y, COLOR_PLAYER); DrawLine(x - AmLine16, y, x - AmLine8, y - AmLine4, COLOR_PLAYER); DrawLine(x - AmLine16, y, x - AmLine8, y + AmLine4, COLOR_PLAYER); break; case DIR_NW: DrawLine(x, y, x - AmLine16, y - AmLine8, COLOR_PLAYER); DrawLine(x - AmLine16, y - AmLine8, x - AmLine8, y - AmLine8, COLOR_PLAYER); DrawLine(x - AmLine16, y - AmLine8, x - AmLine4 - AmLine8, y, COLOR_PLAYER); break; } } /** * @brief Returns the automap shape at the given coordinate. */ static WORD GetAutomapType(int x, int y, BOOL view) { WORD rv; if (view && x == -1 && y >= 0 && y < DMAXY && automapview[0][y]) { if (GetAutomapType(0, y, FALSE) & (MAPFLAG_DIRT << 8)) { return 0; } else { return MAPFLAG_DIRT << 8; } } if (view && y == -1 && x >= 0 && x < DMAXY && automapview[x][0]) { if (GetAutomapType(x, 0, FALSE) & (MAPFLAG_DIRT << 8)) { return 0; } else { return MAPFLAG_DIRT << 8; } } if (x < 0 || x >= DMAXX) { return 0; } if (y < 0 || y >= DMAXX) { return 0; } if (!automapview[x][y] && view) { return 0; } rv = automaptype[(BYTE)dungeon[x][y]]; if (rv == 7) { #ifdef HELLFIRE if ((BYTE)(GetAutomapType(x - 1, y, FALSE) >> 8) & MAPFLAG_HORZARCH) { if ((BYTE)(GetAutomapType(x, y - 1, FALSE) >> 8) & MAPFLAG_VERTARCH) { #else if ((GetAutomapType(x - 1, y, FALSE) >> 8) & MAPFLAG_HORZARCH) { if ((GetAutomapType(x, y - 1, FALSE) >> 8) & MAPFLAG_VERTARCH) { #endif rv = 1; } } } return rv; } /** * @brief Renders game info, such as the name of the current level, and in multi player the name of the game and the game password. */ static void DrawAutomapText() { char desc[256]; int nextline = 20; if (gbMaxPlayers > 1) { strcat(strcpy(desc, "game: "), szPlayerName); PrintGameStr(8, 20, desc, COL_GOLD); nextline = 35; if (szPlayerDescript[0]) { strcat(strcpy(desc, "password: "), szPlayerDescript); PrintGameStr(8, 35, desc, COL_GOLD); nextline = 50; } } if (setlevel) { PrintGameStr(8, nextline, quest_level_names[(BYTE)setlvlnum], COL_GOLD); } else if (currlevel != 0) { #ifdef HELLFIRE if (currlevel < 17 || currlevel > 20) { if (currlevel < 21 || currlevel > 24) sprintf(desc, "Level: %i", currlevel); else sprintf(desc, "Level: Crypt %i", currlevel - 20); } else { sprintf(desc, "Level: Nest %i", currlevel - 16); } #else sprintf(desc, "Level: %i", currlevel); #endif PrintGameStr(8, nextline, desc, COL_GOLD); } } /** * @brief Renders the automap on screen. */ void DrawAutomap() { int cells; int sx, sy; int i, j; int mapx, mapy; if (leveltype == DTYPE_TOWN) { DrawAutomapText(); return; } gpBufEnd = &gpBuffer[BUFFER_WIDTH * (SCREEN_Y + VIEWPORT_HEIGHT)]; AutoMapX = (ViewX - 16) >> 1; while (AutoMapX + AutoMapXOfs < 0) AutoMapXOfs++; while (AutoMapX + AutoMapXOfs >= DMAXX) AutoMapXOfs--; AutoMapX += AutoMapXOfs; AutoMapY = (ViewY - 16) >> 1; while (AutoMapY + AutoMapYOfs < 0) AutoMapYOfs++; while (AutoMapY + AutoMapYOfs >= DMAXY) AutoMapYOfs--; AutoMapY += AutoMapYOfs; cells = AmShiftTab[(AutoMapScale - 50) / 5]; if (ScrollInfo._sxoff + ScrollInfo._syoff) cells++; mapx = AutoMapX - cells; mapy = AutoMapY - 1; if (cells & 1) { sx = SCREEN_WIDTH / 2 + SCREEN_X - AmLine64 * ((cells - 1) >> 1); sy = (SCREEN_HEIGHT - PANEL_HEIGHT) / 2 + SCREEN_Y - AmLine32 * ((cells + 1) >> 1); } else { sx = SCREEN_WIDTH / 2 + SCREEN_X - AmLine64 * (cells >> 1) + AmLine32; sy = (SCREEN_HEIGHT - PANEL_HEIGHT) / 2 + SCREEN_Y - AmLine32 * (cells >> 1) - AmLine16; } if (ViewX & 1) { sx -= AmLine16; sy -= AmLine8; } if (ViewY & 1) { sx += AmLine16; sy -= AmLine8; } sx += AutoMapScale * ScrollInfo._sxoff / 100 >> 1; sy += AutoMapScale * ScrollInfo._syoff / 100 >> 1; if (invflag || sbookflag) { sx -= SCREEN_WIDTH / 4; } if (chrflag || questlog) { sx += SCREEN_WIDTH / 4; } for (i = 0; i <= cells + 1; i++) { int x = sx; int y; for (j = 0; j < cells; j++) { WORD maptype = GetAutomapType(mapx + j, mapy - j, TRUE); if (maptype != 0) DrawAutomapTile(x, sy, maptype); x += AmLine64; } mapy++; x = sx - AmLine32; y = sy + AmLine16; for (j = 0; j <= cells; j++) { WORD maptype = GetAutomapType(mapx + j, mapy - j, TRUE); if (maptype != 0) DrawAutomapTile(x, y, maptype); x += AmLine64; } mapx++; sy += AmLine32; } DrawAutomapPlr(); #ifdef HELLFIRE if (AutoMapShowItems) SearchAutomapItem(); #endif DrawAutomapText(); } /** * @brief Marks the given coordinate as within view on the automap. */ void SetAutomapView(int x, int y) { WORD maptype, solid; int xx, yy; xx = (x - 16) >> 1; yy = (y - 16) >> 1; if (xx < 0 || xx >= DMAXX || yy < 0 || yy >= DMAXY) { return; } automapview[xx][yy] = TRUE; maptype = GetAutomapType(xx, yy, FALSE); solid = maptype & 0x4000; switch (maptype & MAPFLAG_TYPE) { case 2: if (solid) { if (GetAutomapType(xx, yy + 1, FALSE) == 0x4007) automapview[xx][yy + 1] = TRUE; } else if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000) { automapview[xx - 1][yy] = TRUE; } break; case 3: if (solid) { if (GetAutomapType(xx + 1, yy, FALSE) == 0x4007) automapview[xx + 1][yy] = TRUE; } else if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000) { automapview[xx][yy - 1] = TRUE; } break; case 4: if (solid) { if (GetAutomapType(xx, yy + 1, FALSE) == 0x4007) automapview[xx][yy + 1] = TRUE; if (GetAutomapType(xx + 1, yy, FALSE) == 0x4007) automapview[xx + 1][yy] = TRUE; } else { if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000) automapview[xx - 1][yy] = TRUE; if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000) automapview[xx][yy - 1] = TRUE; if (GetAutomapType(xx - 1, yy - 1, FALSE) & 0x4000) automapview[xx - 1][yy - 1] = TRUE; } break; case 5: if (solid) { if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000) automapview[xx][yy - 1] = TRUE; if (GetAutomapType(xx, yy + 1, FALSE) == 0x4007) automapview[xx][yy + 1] = TRUE; } else if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000) { automapview[xx - 1][yy] = TRUE; } break; case 6: if (solid) { if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000) automapview[xx - 1][yy] = TRUE; if (GetAutomapType(xx + 1, yy, FALSE) == 0x4007) automapview[xx + 1][yy] = TRUE; } else if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000) { automapview[xx][yy - 1] = TRUE; } break; } } /** * @brief Resets the zoom level of the automap. */ void AutomapZoomReset() { AutoMapXOfs = 0; AutoMapYOfs = 0; AmLine64 = (AutoMapScale << 6) / 100; AmLine32 = AmLine64 >> 1; AmLine16 = AmLine32 >> 1; AmLine8 = AmLine16 >> 1; AmLine4 = AmLine8 >> 1; } ================================================ FILE: Source/automap.h ================================================ /** * @file automap.h * * Interface of the in-game map overlay. */ #ifndef __AUTOMAP_H__ #define __AUTOMAP_H__ extern BOOL automapflag; extern BOOLEAN automapview[DMAXX][DMAXY]; extern int AutoMapScale; void InitAutomapOnce(); void InitAutomap(); void StartAutomap(); void AutomapUp(); void AutomapDown(); void AutomapLeft(); void AutomapRight(); void AutomapZoomIn(); void AutomapZoomOut(); void DrawAutomap(); void SetAutomapView(int x, int y); void AutomapZoomReset(); #endif /* __AUTOMAP_H__ */ ================================================ FILE: Source/capture.cpp ================================================ /** * @file capture.cpp * * Implementation of the screenshot function. */ #include "all.h" /** * @brief Write the PCX-file header * @param hFile File handler for the PCX file. * @param width Image width * @param height Image height * @return True on success */ static BOOL CaptureHdr(HANDLE hFile, short width, short height) { DWORD lpNumBytes; PCXHEADER Buffer; memset(&Buffer, 0, sizeof(Buffer)); Buffer.Manufacturer = 10; Buffer.Version = 5; Buffer.Encoding = 1; Buffer.BitsPerPixel = 8; Buffer.Xmax = width - 1; Buffer.Ymax = height - 1; Buffer.HDpi = width; Buffer.VDpi = height; Buffer.NPlanes = 1; Buffer.BytesPerLine = width; return WriteFile(hFile, &Buffer, sizeof(Buffer), &lpNumBytes, NULL) && lpNumBytes == sizeof(Buffer); } /** * @brief Write the current ingame palette to the PCX file * @param hFile File handler for the PCX file. * @param palette Current palette * @return True if successful, else false */ static BOOL CapturePal(HANDLE hFile, PALETTEENTRY *palette) { DWORD NumberOfBytesWritten; BYTE pcx_palette[1 + 256 * 3]; int i; pcx_palette[0] = 12; for (i = 0; i < 256; i++) { pcx_palette[1 + 3 * i + 0] = palette[i].peRed; pcx_palette[1 + 3 * i + 1] = palette[i].peGreen; pcx_palette[1 + 3 * i + 2] = palette[i].peBlue; } return WriteFile(hFile, pcx_palette, sizeof(pcx_palette), &NumberOfBytesWritten, NULL) && NumberOfBytesWritten == sizeof(pcx_palette); } /** * @brief RLE compress the pixel data * @param src Raw pixel buffer * @param dst Output buffer * @param width Width of pixel buffer * @return Output buffer */ static BYTE *CaptureEnc(BYTE *src, BYTE *dst, int width) { int rleLength; do { BYTE rlePixel = *src; *src++; rleLength = 1; width--; while (rlePixel == *src) { if (rleLength >= 63) break; if (!width) break; rleLength++; width--; src++; } if (rleLength > 1 || rlePixel > 0xBF) { *dst = rleLength | 0xC0; *dst++; } *dst = rlePixel; *dst++; } while (width); return dst; } /** * @brief Write the pixel data to the PCX file * @param hFile File handler for the PCX file. * @param width Image width * @param height Image height * @param stride Buffer width * @param pixels Raw pixel buffer * @return True if successful, else false */ static BOOL CapturePix(HANDLE hFile, WORD width, WORD height, WORD stride, BYTE *pixels) { int writeSize; DWORD lpNumBytes; BYTE *pBuffer, *pBufferEnd; pBuffer = (BYTE *)DiabloAllocPtr(2 * width); while (height--) { pBufferEnd = CaptureEnc(pixels, pBuffer, width); pixels += stride; writeSize = pBufferEnd - pBuffer; if (!(WriteFile(hFile, pBuffer, writeSize, &lpNumBytes, NULL) && lpNumBytes == writeSize)) { return FALSE; } } mem_free_dbg(pBuffer); return TRUE; } static HANDLE CaptureFile(char *dst_path) { BOOLEAN num_used[100]; int free_num, hFind; struct _finddata_t finder; memset(num_used, FALSE, sizeof(num_used)); hFind = _findfirst("screen??.PCX", &finder); if (hFind != -1) { do { if (isdigit(finder.name[6]) && isdigit(finder.name[7])) { free_num = 10 * (finder.name[6] - '0'); free_num += (finder.name[7] - '0'); num_used[free_num] = TRUE; } } while (_findnext(hFind, &finder) == 0); } for (free_num = 0; free_num < 100; free_num++) { if (!num_used[free_num]) { sprintf(dst_path, "screen%02d.PCX", free_num); return CreateFile(dst_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } } return INVALID_HANDLE_VALUE; } /** * @brief Make a red version of the given palette and apply it to the screen. * @param pal The original palette */ static void RedPalette(PALETTEENTRY *pal) { PALETTEENTRY red[256]; int i; for (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); } /** * @brief Save the current screen to a screen??.PCX (00-99) in file if available, then make the screen red for 200ms. */ void CaptureScreen() { HANDLE hObject; PALETTEENTRY palette[256]; char FileName[MAX_PATH]; BOOL success; hObject = CaptureFile(FileName); if (hObject != INVALID_HANDLE_VALUE) { DrawAndBlit(); lpDDPalette->GetEntries(0, 0, 256, palette); RedPalette(palette); lock_buf(2); success = CaptureHdr(hObject, SCREEN_WIDTH, SCREEN_HEIGHT); if (success) { success = CapturePix(hObject, SCREEN_WIDTH, SCREEN_HEIGHT, BUFFER_WIDTH, &gpBuffer[SCREENXY(0, 0)]); } if (success) { success = CapturePal(hObject, palette); } unlock_buf(2); CloseHandle(hObject); if (!success) DeleteFile(FileName); Sleep(300); lpDDPalette->SetEntries(0, 0, 256, palette); } } ================================================ FILE: Source/capture.h ================================================ /** * @file capture.h * * Interface of the screenshot function. */ #ifndef __CAPTURE_H__ #define __CAPTURE_H__ void CaptureScreen(); #endif /* __CAPTURE_H__ */ ================================================ FILE: Source/codec.cpp ================================================ /** * @file codec.cpp * * Implementation of save game encryption algorithm. */ #include "all.h" typedef struct CodecSignature { DWORD checksum; BYTE error; BYTE last_chunk_size; WORD unused; } CodecSignature; #define BLOCKSIZE 64 static void codec_init_key(int unused, const char *pszPassword) { int i, ch, n; char key[136]; // last 64 bytes are the SHA1 char pw[64]; char digest[SHA1HashSize]; char *keyInit; srand(0x7058); keyInit = key; for (i = 0; i < sizeof(key); i++) { *keyInit = rand(); keyInit++; } ch = 0; for (i = 0; i < 64; i++) { if (!pszPassword[ch]) ch = 0; pw[i] = pszPassword[ch]; ch++; } SHA1Reset(0); SHA1Calculate(0, pw, digest); SHA1Clear(); for (i = 0; i < sizeof(key); i++) key[i] ^= digest[i % SHA1HashSize]; memset(pw, 0, sizeof(pw)); memset(digest, 0, sizeof(digest)); for (n = 0; n < 3; n++) { SHA1Reset(n); SHA1Calculate(n, &key[72], NULL); } memset(key, 0, sizeof(key)); } int codec_decode(BYTE *pbSrcDst, DWORD size, const char *pszPassword) { char buf[128]; char dst[SHA1HashSize]; int i; CodecSignature *sig; codec_init_key(0, pszPassword); if (size <= sizeof(CodecSignature)) return 0; size -= sizeof(CodecSignature); if (size % BLOCKSIZE != 0) return 0; for (i = size; i != 0; pbSrcDst += BLOCKSIZE, i -= BLOCKSIZE) { memcpy(buf, pbSrcDst, BLOCKSIZE); SHA1Result(0, dst); for (int j = 0; j < BLOCKSIZE; j++) { buf[j] ^= dst[j % SHA1HashSize]; } SHA1Calculate(0, buf, NULL); memset(dst, 0, sizeof(dst)); memcpy(pbSrcDst, buf, BLOCKSIZE); } memset(buf, 0, sizeof(buf)); sig = (CodecSignature *)pbSrcDst; if (sig->error > 0) { goto error; } SHA1Result(0, dst); if (sig->checksum != *(DWORD *)dst) { memset(dst, 0, sizeof(dst)); goto error; } size += sig->last_chunk_size - BLOCKSIZE; SHA1Clear(); return size; error: SHA1Clear(); return 0; } DWORD codec_get_encoded_len(DWORD dwSrcBytes) { if (dwSrcBytes % BLOCKSIZE != 0) dwSrcBytes += BLOCKSIZE - (dwSrcBytes % BLOCKSIZE); return dwSrcBytes + sizeof(CodecSignature); } void codec_encode(BYTE *pbSrcDst, DWORD size, int size_64, const char *pszPassword) { char buf[128]; char tmp[SHA1HashSize]; char dst[SHA1HashSize]; DWORD chunk; WORD last_chunk; CodecSignature *sig; if (size_64 != codec_get_encoded_len(size)) app_fatal("Invalid encode parameters"); codec_init_key(1, pszPassword); last_chunk = 0; while (size != 0) { chunk = size < BLOCKSIZE ? size : BLOCKSIZE; memcpy(buf, pbSrcDst, chunk); if (chunk < BLOCKSIZE) memset(buf + chunk, 0, BLOCKSIZE - chunk); SHA1Result(0, dst); SHA1Calculate(0, buf, NULL); for (int j = 0; j < BLOCKSIZE; j++) { buf[j] ^= dst[j % SHA1HashSize]; } memset(dst, 0, sizeof(dst)); memcpy(pbSrcDst, buf, BLOCKSIZE); last_chunk = chunk; pbSrcDst += BLOCKSIZE; size -= chunk; } memset(buf, 0, sizeof(buf)); SHA1Result(0, tmp); sig = (CodecSignature *)pbSrcDst; sig->error = 0; sig->unused = 0; sig->checksum = *(DWORD *)&tmp[0]; sig->last_chunk_size = last_chunk; SHA1Clear(); } ================================================ FILE: Source/codec.h ================================================ /** * @file codec.h * * Interface of save game encryption algorithm. */ #ifndef __CODEC_H__ #define __CODEC_H__ int codec_decode(BYTE *pbSrcDst, DWORD size, const char *pszPassword); DWORD codec_get_encoded_len(DWORD dwSrcBytes); void codec_encode(BYTE *pbSrcDst, DWORD size, int size_64, const char *pszPassword); #endif /* __CODEC_H__ */ ================================================ FILE: Source/control.cpp ================================================ /** * @file control.cpp * * Implementation of the character and main control panels */ #include "all.h" BYTE sgbNextTalkSave; BYTE sgbTalkSavePos; BYTE *pDurIcons; BYTE *pChrButtons; BOOL drawhpflag; BOOL dropGoldFlag; BOOL panbtn[8]; BOOL chrbtn[4]; BYTE *pMultiBtns; BYTE *pPanelButtons; BYTE *pChrPanel; BOOL lvlbtndown; char sgszTalkSave[8][80]; int dropGoldValue; BOOL drawmanaflag; BOOL chrbtnactive; char sgszTalkMsg[MAX_SEND_STR_LEN]; BYTE *pPanelText; /** current frame # for the pentagram caret in gold input */ int nGoldFrame; BYTE *pLifeBuff; BYTE *pBtmBuff; BYTE *pTalkBtns; BOOL pstrjust[4]; int pnumlines; BOOL pinfoflag; BOOL talkbtndown[3]; int pSpell; BYTE *pManaBuff; char infoclr; int sgbPlrTalkTbl; BYTE *pGBoxBuff; BYTE *pSBkBtnCel; char tempstr[256]; BOOLEAN whisper[MAX_PLRS]; int sbooktab; int pSplType; /** current frame # for the pentagram caret in chat input */ int frame; int initialDropGoldIndex; BOOL talkflag; BYTE *pSBkIconCels; BOOL sbookflag; BOOL chrflag; BOOL drawbtnflag; BYTE *pSpellBkCel; char infostr[256]; int numpanbtns; BYTE *pStatusPanel; char panelstr[4][64]; BOOL panelflag; BYTE SplTransTbl[256]; int initialDropGoldValue; BYTE *pSpellCels; BOOL panbtndown; BYTE *pTalkPanel; BOOL spselflag; /** Maps from font index to smaltext.cel frame number. */ const BYTE fontframe[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0 }; /** * Maps from smaltext.cel frame number to character width. Note, the * character width may be distinct from the frame width, which is 13 for every * smaltext.cel frame. */ const BYTE 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 }; /** * Line start position for info box text when displaying 1, 2, 3, 4 and 5 lines respectivly */ const int lineOffsets[5][5] = { { SCREENXY(177, 434), SCREENXY(-64, -128), SCREENXY(-64, -128), SCREENXY(-64, -128), SCREENXY(116, -128), }, { SCREENXY(177, 422), SCREENXY(177, 446), SCREENXY(-64, -128), SCREENXY(-64, -128), SCREENXY(-64, -128), }, { SCREENXY(177, 416), SCREENXY(177, 434), SCREENXY(177, 452), SCREENXY(-64, -128), SCREENXY(-64, -128), }, { SCREENXY(177, 412), SCREENXY(177, 427), SCREENXY(177, 441), SCREENXY(177, 456), SCREENXY(-64, -128), }, { SCREENXY(177, 410), SCREENXY(177, 422), SCREENXY(177, 434), SCREENXY(177, 446), SCREENXY(177, 457), } }; /** * Maps ASCII character code to font index, as used by the * small, medium and large sized fonts; which corresponds to smaltext.cel, * medtexts.cel and bigtgold.cel respectively. */ const BYTE gbFontTransTbl[256] = { // clang-format off '\0', 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ' ', '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x01, 'C', 'u', 'e', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'i', 'i', 'i', 'A', 'A', 'E', 'a', 'A', 'o', 'o', 'o', 'u', 'u', 'y', 'O', 'U', 'c', 'L', 'Y', 'P', 'f', 'a', 'i', 'o', 'u', 'n', 'N', 'a', 'o', '?', 0x01, 0x01, 0x01, 0x01, '!', '<', '>', 'o', '+', '2', '3', '\'', 'u', 'P', '.', ',', '1', '0', '>', 0x01, 0x01, 0x01, '?', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'X', '0', 'U', 'U', 'U', 'U', 'Y', 'b', 'B', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'o', 'n', 'o', 'o', 'o', 'o', 'o', '/', '0', 'u', 'u', 'u', 'u', 'y', 'b', 'y', // clang-format on }; /* data */ /** Maps from spell_id to spelicon.cel frame number. */ char SpellITbl[MAX_SPELLS] = { #ifdef HELLFIRE 27, #else 1, #endif 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, #ifdef HELLFIRE 51, 51, 50, 46, 47, 43, 45, 48, 49, 44, 35, 35, 35, 35, 35, #endif }; /** Maps from panel_button_id to the position and dimensions of a panel button. */ int PanBtnPos[8][5] = { // clang-format off { PANEL_LEFT + 9, PANEL_TOP + 9, 71, 19, TRUE }, // char button { PANEL_LEFT + 9, PANEL_TOP + 35, 71, 19, FALSE }, // quests button { PANEL_LEFT + 9, PANEL_TOP + 75, 71, 19, TRUE }, // map button { PANEL_LEFT + 9, PANEL_TOP + 101, 71, 19, FALSE }, // menu button { PANEL_LEFT + 560, PANEL_TOP + 9, 71, 19, TRUE }, // inv button { PANEL_LEFT + 560, PANEL_TOP + 35, 71, 19, FALSE }, // spells button { PANEL_LEFT + 87, PANEL_TOP + 91, 33, 32, TRUE }, // chat button { PANEL_LEFT + 527, PANEL_TOP + 91, 33, 32, TRUE }, // friendly fire button // clang-format on }; /** Maps from panel_button_id to hotkey name. */ const char *const PanBtnHotKey[8] = { "'c'", "'q'", "Tab", "Esc", "'i'", "'b'", "Enter", NULL }; /** Maps from panel_button_id to panel button description. */ const char *const PanBtnStr[8] = { "Character Information", "Quests log", "Automap", "Main Menu", "Inventory", "Spell book", "Send Message", "Player Attack" }; /** Maps from attribute_id to the rectangle on screen used for attribute increment buttons. */ RECT32 ChrBtnsRect[4] = { { 137, 138, 41, 22 }, { 137, 166, 41, 22 }, { 137, 195, 41, 22 }, { 137, 223, 41, 22 } }; /** Maps from spellbook page number and position to spell_id. */ 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 }, #ifndef HELLFIRE { -1, -1, -1, -1, -1, -1, -1 }, #else { SPL_LIGHTWALL, SPL_IMMOLAT, SPL_WARP, SPL_REFLECT, SPL_BERSERK, SPL_FIRERING, SPL_SEARCH }, #endif { -1, -1, -1, -1, -1, -1, -1 } }; #define SPLICONLENGTH 56 #define SPLROWICONLS 10 #ifdef HELLFIRE #define SPLICONLAST 52 #else #define SPLICONLAST 43 #endif /** * Draw spell cell onto the back buffer. * @param xp Back buffer coordinate * @param yp Back buffer coordinate * @param Trans Pointer to the cel buffer. * @param nCel Index of the cel frame to draw. 0 based. * @param w Width of the frame. */ void DrawSpellCel(int xp, int yp, BYTE *Trans, int nCel, int w) { BYTE *dst, *tbl, *end; assert(gpBuffer); dst = &gpBuffer[xp + PitchTbl[yp]]; tbl = &SplTransTbl[0]; #ifdef USE_ASM __asm { mov ebx, Trans mov eax, nCel shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov end, eax mov esi, Trans add esi, [ebx] mov edi, dst mov eax, end add eax, esi mov end, eax mov ebx, tbl label1: mov edx, w label2: xor eax, eax lodsb or al, al js label6 sub edx, eax mov ecx, eax shr ecx, 1 jnb label3 lodsb xlat stosb jecxz label5 label3: shr ecx, 1 jnb label4 lodsw xlat ror ax, 8 xlat ror ax, 8 stosw jecxz label5 label4: lodsd xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 xlat ror eax, 8 stosd loop label4 label5: or edx, edx jz label7 jmp label2 label6: neg al add edi, eax sub edx, eax jnz label2 label7: sub edi, BUFFER_WIDTH sub edi, w cmp esi, end jnz label1 } #else int i; BYTE width; BYTE *src; DWORD *pFrameTable; pFrameTable = (DWORD *)&Trans[4 * nCel]; src = &Trans[pFrameTable[0]]; end = &src[pFrameTable[1] - pFrameTable[0]]; for (; src != end; dst -= BUFFER_WIDTH + w) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; // asm_cel_light_edge(width, tbl, dst, src); if (width & 1) { dst[0] = tbl[src[0]]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = tbl[src[0]]; dst[1] = tbl[src[1]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = tbl[src[0]]; dst[1] = tbl[src[1]]; dst[2] = tbl[src[2]]; dst[3] = tbl[src[3]]; src += 4; dst += 4; } } else { width = -(char)width; dst += width; i -= width; } } } #endif } void SetSpellTrans(char t) { int i; if (t == RSPLTYPE_SKILL) { for (i = 0; i < 128; i++) SplTransTbl[i] = i; } for (i = 128; i < 256; i++) SplTransTbl[i] = i; SplTransTbl[255] = 0; switch (t) { case RSPLTYPE_SPELL: SplTransTbl[PAL8_YELLOW] = PAL16_BLUE + 1; SplTransTbl[PAL8_YELLOW + 1] = PAL16_BLUE + 3; SplTransTbl[PAL8_YELLOW + 2] = PAL16_BLUE + 5; for (i = PAL16_BLUE; i < PAL16_BLUE + 16; i++) { SplTransTbl[PAL16_BEIGE - PAL16_BLUE + i] = i; SplTransTbl[PAL16_YELLOW - PAL16_BLUE + i] = i; SplTransTbl[PAL16_ORANGE - PAL16_BLUE + i] = i; } break; case RSPLTYPE_SCROLL: SplTransTbl[PAL8_YELLOW] = PAL16_BEIGE + 1; SplTransTbl[PAL8_YELLOW + 1] = PAL16_BEIGE + 3; SplTransTbl[PAL8_YELLOW + 2] = PAL16_BEIGE + 5; for (i = PAL16_BEIGE; i < PAL16_BEIGE + 16; i++) { SplTransTbl[PAL16_YELLOW - PAL16_BEIGE + i] = i; SplTransTbl[PAL16_ORANGE - PAL16_BEIGE + i] = i; } break; case RSPLTYPE_CHARGES: SplTransTbl[PAL8_YELLOW] = PAL16_ORANGE + 1; SplTransTbl[PAL8_YELLOW + 1] = PAL16_ORANGE + 3; SplTransTbl[PAL8_YELLOW + 2] = PAL16_ORANGE + 5; for (i = PAL16_ORANGE; i < PAL16_ORANGE + 16; i++) { SplTransTbl[PAL16_BEIGE - PAL16_ORANGE + i] = i; SplTransTbl[PAL16_YELLOW - PAL16_ORANGE + i] = i; } break; case RSPLTYPE_INVALID: SplTransTbl[PAL8_YELLOW] = PAL16_GRAY + 1; SplTransTbl[PAL8_YELLOW + 1] = PAL16_GRAY + 3; SplTransTbl[PAL8_YELLOW + 2] = PAL16_GRAY + 5; for (i = PAL16_GRAY; i < PAL16_GRAY + 15; i++) { SplTransTbl[PAL16_BEIGE - PAL16_GRAY + i] = i; SplTransTbl[PAL16_YELLOW - PAL16_GRAY + i] = i; SplTransTbl[PAL16_ORANGE - PAL16_GRAY + i] = i; } SplTransTbl[PAL16_BEIGE + 15] = 0; SplTransTbl[PAL16_YELLOW + 15] = 0; SplTransTbl[PAL16_ORANGE + 15] = 0; break; } } /** * Sets the spell frame to draw and its position then draws it. */ void DrawSpell() { char spl, st; int tlvl; spl = plr[myplr]._pRSpell; st = plr[myplr]._pRSplType; // BUGFIX: Move the next line into the if statement to avoid OOB (SPL_INVALID is -1) tlvl = plr[myplr]._pISplLvlAdd + plr[myplr]._pSplLvl[spl]; if (st == RSPLTYPE_SPELL && spl != SPL_INVALID) { if (!CheckSpell(myplr, spl, RSPLTYPE_SPELL, TRUE)) st = RSPLTYPE_INVALID; if (tlvl <= 0) st = RSPLTYPE_INVALID; } if (currlevel == 0 && st != RSPLTYPE_INVALID && !spelldata[spl].sTownSpell) st = RSPLTYPE_INVALID; if (plr[myplr]._pRSpell < 0) st = RSPLTYPE_INVALID; SetSpellTrans(st); if (spl != SPL_INVALID) DrawSpellCel(PANEL_X + 565, PANEL_Y + 119, pSpellCels, SpellITbl[spl], SPLICONLENGTH); else DrawSpellCel(PANEL_X + 565, PANEL_Y + 119, pSpellCels, 27, SPLICONLENGTH); } void DrawSpellList() { int i, j, x, y, c, s, t, v, lx, ly, trans; unsigned __int64 mask, spl; pSpell = SPL_INVALID; infostr[0] = '\0'; x = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; y = PANEL_Y - 17; ClearPanel(); for (i = 0; i < 4; i++) { switch ((spell_type)i) { case RSPLTYPE_SKILL: SetSpellTrans(RSPLTYPE_SKILL); mask = plr[myplr]._pAblSpells; c = SPLICONLAST + 3; break; case RSPLTYPE_SPELL: mask = plr[myplr]._pMemSpells; c = SPLICONLAST + 4; break; case RSPLTYPE_SCROLL: SetSpellTrans(RSPLTYPE_SCROLL); mask = plr[myplr]._pScrlSpells; c = SPLICONLAST + 1; break; case RSPLTYPE_CHARGES: SetSpellTrans(RSPLTYPE_CHARGES); mask = plr[myplr]._pISpells; c = SPLICONLAST + 2; break; } for (spl = 1, j = 1; j < MAX_SPELLS; spl <<= 1, j++) { if (!(mask & spl)) continue; if (i == RSPLTYPE_SPELL) { s = plr[myplr]._pISplLvlAdd + plr[myplr]._pSplLvl[j]; if (s < 0) s = 0; if (s > 0) trans = RSPLTYPE_SPELL; else trans = RSPLTYPE_INVALID; SetSpellTrans(trans); } if (currlevel == 0 && !spelldata[j].sTownSpell) SetSpellTrans(RSPLTYPE_INVALID); DrawSpellCel(x, y, pSpellCels, SpellITbl[j], SPLICONLENGTH); lx = x - BORDER_LEFT; ly = y - BORDER_TOP - SPLICONLENGTH; if (MouseX >= lx && MouseX < lx + SPLICONLENGTH && MouseY >= ly && MouseY < ly + SPLICONLENGTH) { pSpell = j; pSplType = i; #ifdef HELLFIRE if (plr[myplr]._pClass == PC_MONK && j == SPL_SEARCH) pSplType = RSPLTYPE_SKILL; #endif DrawSpellCel(x, y, pSpellCels, c, SPLICONLENGTH); #ifdef HELLFIRE switch (pSplType) { #else switch (i) { #endif case RSPLTYPE_SKILL: sprintf(infostr, "%s Skill", spelldata[pSpell].sSkillText); break; case RSPLTYPE_SPELL: sprintf(infostr, "%s Spell", spelldata[pSpell].sNameText); if (pSpell == SPL_HBOLT) { sprintf(tempstr, "Damages undead only"); AddPanelString(tempstr, TRUE); } if (s == 0) sprintf(tempstr, "Spell Level 0 - Unusable"); else sprintf(tempstr, "Spell Level %i", s); AddPanelString(tempstr, TRUE); break; case RSPLTYPE_SCROLL: sprintf(infostr, "Scroll of %s", spelldata[pSpell].sNameText); v = 0; for (t = 0; t < plr[myplr]._pNumInv; t++) { if (plr[myplr].InvList[t]._itype != ITYPE_NONE && (plr[myplr].InvList[t]._iMiscId == IMISC_SCROLL || plr[myplr].InvList[t]._iMiscId == IMISC_SCROLLT) && plr[myplr].InvList[t]._iSpell == pSpell) { v++; } } for (t = 0; t < MAXBELTITEMS; t++) { if (plr[myplr].SpdList[t]._itype != ITYPE_NONE && (plr[myplr].SpdList[t]._iMiscId == IMISC_SCROLL || plr[myplr].SpdList[t]._iMiscId == IMISC_SCROLLT) && plr[myplr].SpdList[t]._iSpell == pSpell) { v++; } } if (v == 1) strcpy(tempstr, "1 Scroll"); else sprintf(tempstr, "%i Scrolls", v); AddPanelString(tempstr, TRUE); break; case RSPLTYPE_CHARGES: sprintf(infostr, "Staff of %s", spelldata[pSpell].sNameText); if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges == 1) strcpy(tempstr, "1 Charge"); else sprintf(tempstr, "%i Charges", plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges); AddPanelString(tempstr, TRUE); break; } for (t = 0; t < 4; t++) { if (plr[myplr]._pSplHotKey[t] == pSpell && plr[myplr]._pSplTHotKey[t] == pSplType) { DrawSpellCel(x, y, pSpellCels, t + SPLICONLAST + 5, SPLICONLENGTH); sprintf(tempstr, "Spell Hot Key #F%i", t + 5); AddPanelString(tempstr, TRUE); } } } x -= SPLICONLENGTH; if (x == PANEL_X + 12 - SPLICONLENGTH) { x = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; y -= SPLICONLENGTH; } } if (mask != 0 && x != PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS) x -= SPLICONLENGTH; if (x == PANEL_X + 12 - SPLICONLENGTH) { x = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; y -= SPLICONLENGTH; } } } void SetSpell() { spselflag = FALSE; if (pSpell != SPL_INVALID) { ClearPanel(); plr[myplr]._pRSpell = pSpell; plr[myplr]._pRSplType = pSplType; force_redraw = 255; } } void SetSpeedSpell(int slot) { int i; if (pSpell != SPL_INVALID) { for (i = 0; i < 4; ++i) { if (plr[myplr]._pSplHotKey[i] == pSpell && plr[myplr]._pSplTHotKey[i] == pSplType) plr[myplr]._pSplHotKey[i] = SPL_INVALID; } plr[myplr]._pSplHotKey[slot] = pSpell; plr[myplr]._pSplTHotKey[slot] = pSplType; } } void ToggleSpell(int slot) { unsigned __int64 spells; if (plr[myplr]._pSplHotKey[slot] == -1) { return; } switch (plr[myplr]._pSplTHotKey[slot]) { case RSPLTYPE_SKILL: spells = plr[myplr]._pAblSpells; break; case RSPLTYPE_SPELL: spells = plr[myplr]._pMemSpells; break; case RSPLTYPE_SCROLL: spells = plr[myplr]._pScrlSpells; break; case RSPLTYPE_CHARGES: spells = plr[myplr]._pISpells; break; } if (spells & SPELLBIT(plr[myplr]._pSplHotKey[slot])) { plr[myplr]._pRSpell = plr[myplr]._pSplHotKey[slot]; plr[myplr]._pRSplType = plr[myplr]._pSplTHotKey[slot]; force_redraw = 255; } } /** * @brief Print letter to the back buffer * @param nOffset Back buffer offset * @param nCel Number of letter in Windows-1252 * @param col text_color color value */ void PrintChar(int nOffset, int nCel, char col) { assert(gpBuffer); #ifdef USE_ASM __asm { mov ebx, pPanelText mov eax, nCel shl eax, 2 add ebx, eax mov edx, [ebx+4] sub edx, [ebx] mov esi, pPanelText add esi, [ebx] mov edi, gpBuffer add edi, nOffset mov ebx, edx add ebx, esi xor edx, edx mov dl, col cmp edx, COL_WHITE jz c0_label1 cmp edx, COL_BLUE jz c1_label1 cmp edx, COL_RED jz c2_label1 jmp d_label1 // Case 0 c0_label1: mov edx, 13 c0_label2: xor eax, eax lodsb or al, al js c0_label6 sub edx, eax mov ecx, eax shr ecx, 1 jnb c0_label3 movsb jecxz c0_label5 c0_label3: shr ecx, 1 jnb c0_label4 movsw jecxz c0_label5 c0_label4: rep movsd c0_label5: or edx, edx jz c0_label7 jmp c0_label2 c0_label6: neg al add edi, eax sub edx, eax jnz c0_label2 c0_label7: sub edi, BUFFER_WIDTH + 13 cmp ebx, esi jnz c0_label1 jmp labret // Case 1 c1_label1: mov edx, 13 c1_label2: xor eax, eax lodsb or al, al js c1_label6 sub edx, eax mov ecx, eax c1_label3: lodsb cmp al, PAL16_GRAY + 13 ja c1_label4 cmp al, PAL16_GRAY jb c1_label5 sub al, PAL16_GRAY - (PAL16_BLUE + 2) jmp c1_label5 c1_label4: mov al, PAL16_BLUE + 15 c1_label5: stosb loop c1_label3 or edx, edx jz c1_label7 jmp c1_label2 c1_label6: neg al add edi, eax sub edx, eax jnz c1_label2 c1_label7: sub edi, BUFFER_WIDTH + 13 cmp ebx, esi jnz c1_label1 jmp labret // Case 2 c2_label1: mov edx, 13 c2_label2: xor eax, eax lodsb or al, al js c2_label5 sub edx, eax mov ecx, eax c2_label3: lodsb cmp al, PAL16_GRAY jb c2_label4 sub al, PAL16_GRAY - PAL16_RED c2_label4: stosb loop c2_label3 or edx, edx jz c2_label6 jmp c2_label2 c2_label5: neg al add edi, eax sub edx, eax jnz c2_label2 c2_label6: sub edi, BUFFER_WIDTH + 13 cmp ebx, esi jnz c2_label1 jmp labret // Default d_label1: mov edx, 13 d_label2: xor eax, eax lodsb or al, al js d_label6 sub edx, eax mov ecx, eax d_label3: lodsb cmp al, PAL16_GRAY jb d_label5 cmp al, PAL16_GRAY + 14 jnb d_label4 sub al, PAL16_GRAY - (PAL16_YELLOW + 2) jmp d_label5 d_label4: mov al, PAL16_YELLOW + 15 d_label5: stosb loop d_label3 or edx, edx jz d_label7 jmp d_label2 d_label6: neg al add edi, eax sub edx, eax jnz d_label2 d_label7: sub edi, BUFFER_WIDTH + 13 cmp ebx, esi jnz d_label1 labret: } #else int i, nDataSize; BYTE width, pix; BYTE *src, *dst, *end; src = CelGetFrame(pPanelText, nCel, &nDataSize); end = &src[nDataSize]; dst = &gpBuffer[nOffset]; switch (col) { case COL_WHITE: for (; src != end; dst -= BUFFER_WIDTH + 13) { for (i = 13; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (width & 1) { dst[0] = src[0]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = src[0]; dst[1] = src[1]; src += 2; dst += 2; } width >>= 1; while (width) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; src += 4; dst += 4; width--; } } else { width = -(char)width; dst += width; i -= width; } } } break; case COL_BLUE: for (; src != end; dst -= BUFFER_WIDTH + 13) { for (i = 13; i;) { width = *src++; if (!(width & 0x80)) { i -= width; while (width) { pix = *src++; if (pix > PAL16_GRAY + 13) pix = PAL16_BLUE + 15; else if (pix >= PAL16_GRAY) pix -= PAL16_GRAY - (PAL16_BLUE + 2); *dst++ = pix; width--; } } else { width = -(char)width; dst += width; i -= width; } } } break; case COL_RED: for (; src != end; dst -= BUFFER_WIDTH + 13) { for (i = 13; i;) { width = *src++; if (!(width & 0x80)) { i -= width; while (width) { pix = *src++; if (pix >= PAL16_GRAY) pix -= PAL16_GRAY - PAL16_RED; *dst++ = pix; width--; } } else { width = -(char)width; dst += width; i -= width; } } } break; default: for (; src != end; dst -= BUFFER_WIDTH + 13) { for (i = 13; i;) { width = *src++; if (!(width & 0x80)) { i -= width; while (width) { pix = *src++; if (pix >= PAL16_GRAY) { if (pix >= PAL16_GRAY + 14) pix = PAL16_YELLOW + 15; else pix -= PAL16_GRAY - (PAL16_YELLOW + 2); } *dst++ = pix; width--; } } else { width = -(char)width; dst += width; i -= width; } } } break; } #endif } void AddPanelString(const char *str, BOOL just) { strcpy(panelstr[pnumlines], str); pstrjust[pnumlines] = just; if (pnumlines < 4) pnumlines++; } void ClearPanel() { pnumlines = 0; pinfoflag = FALSE; } void DrawPanelBox(int x, int y, int w, int h, int sx, int sy) { int nSrcOff, nDstOff; assert(gpBuffer); nSrcOff = x + PANEL_WIDTH * y; nDstOff = sx + BUFFER_WIDTH * sy; #ifdef USE_ASM __asm { mov esi, pBtmBuff add esi, nSrcOff mov edi, gpBuffer add edi, nDstOff xor ebx, ebx mov bx, word ptr w xor edx, edx mov dx, word ptr h label1: mov ecx, ebx shr ecx, 1 jnb label2 movsb jecxz label4 label2: shr ecx, 1 jnb label3 movsw jecxz label4 label3: rep movsd label4: add esi, PANEL_WIDTH sub esi, ebx add edi, BUFFER_WIDTH sub edi, ebx dec edx jnz label1 } #else int wdt, hgt; BYTE *src, *dst; src = &pBtmBuff[nSrcOff]; dst = &gpBuffer[nDstOff]; for (hgt = h; hgt; hgt--, src += PANEL_WIDTH - w, dst += BUFFER_WIDTH - w) { wdt = w; if (wdt & 1) { dst[0] = src[0]; src++; dst++; } wdt >>= 1; if (wdt & 1) { dst[0] = src[0]; dst[1] = src[1]; src += 2; dst += 2; } wdt >>= 1; while (wdt) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; src += 4; dst += 4; wdt--; } } #endif } /** * Draws a section of the empty flask cel on top of the panel to create the illusion * of the flask getting empty. This function takes a cel and draws a * horizontal stripe of height (max-min) onto the back buffer. * @param pCelBuff Buffer of the empty flask cel. * @param min Top of the flask cel section to draw. * @param max Bottom of the flask cel section to draw. * @param sx Back buffer coordinate * @param sy Back buffer coordinate */ void SetFlaskHeight(BYTE *pCelBuff, int min, int max, int sx, int sy) { int nSrcOff, nDstOff, w; assert(gpBuffer); nSrcOff = 88 * min; nDstOff = sx + BUFFER_WIDTH * sy; w = max - min; #ifdef USE_ASM __asm { mov esi, pCelBuff add esi, nSrcOff mov edi, gpBuffer add edi, nDstOff mov edx, w label1: mov ecx, 88 / 4 rep movsd add edi, BUFFER_WIDTH - 88 dec edx jnz label1 } #else BYTE *src, *dst; src = &pCelBuff[nSrcOff]; dst = &gpBuffer[nDstOff]; for (; w; w--, src += 88, dst += BUFFER_WIDTH) memcpy(dst, src, 88); #endif } /** * Draws the dome of the flask that protrudes above the panel top line. * It draws a rectangle of fixed width 59 and height 'h' from the source buffer * into the target buffer. * @param pCelBuff The flask cel buffer. * @param w Width of the cel. * @param nSrcOff Offset of the source buffer from where the bytes will start to be copied from. * @param pBuff Target buffer. * @param nDstOff Offset of the target buffer where the bytes will start to be copied to. * @param h How many lines of the source buffer that will be copied. */ void DrawFlask(BYTE *pCelBuff, int w, int nSrcOff, BYTE *pBuff, int nDstOff, int h) { #ifdef USE_ASM __asm { mov esi, pCelBuff add esi, nSrcOff mov edi, pBuff add edi, nDstOff mov edx, h label1: mov ecx, 59 label2: lodsb or al, al jz label3 mov [edi], al label3: inc edi loop label2 add esi, w sub esi, 59 add edi, BUFFER_WIDTH - 59 dec edx jnz label1 } #else int wdt, hgt; BYTE *src, *dst; src = &pCelBuff[nSrcOff]; dst = &pBuff[nDstOff]; for (hgt = h; hgt; hgt--, src += w - 59, dst += BUFFER_WIDTH - 59) { for (wdt = 59; wdt; wdt--) { if (*src) *dst = *src; src++; dst++; } } #endif } /** * Draws the top dome of the life flask (that part that protrudes out of the control panel). * First it draws the empty flask cel and then draws the filled part on top if needed. */ void DrawLifeFlask() { double p; int filled; #ifdef HELLFIRE if (plr[myplr]._pMaxHP <= 0) { p = 0.0; } else { p = (double)plr[myplr]._pHitPoints / (double)plr[myplr]._pMaxHP * 80.0; } #else p = (double)plr[myplr]._pHitPoints / (double)plr[myplr]._pMaxHP * 80.0; #endif plr[myplr]._pHPPer = p; filled = plr[myplr]._pHPPer; #ifndef HELLFIRE if (filled > 80) filled = 80; #endif filled = 80 - filled; if (filled > 11) filled = 11; filled += 2; DrawFlask(pLifeBuff, 88, 88 * 3 + 13, gpBuffer, SCREENXY(PANEL_LEFT + 109, PANEL_TOP - 13), filled); if (filled != 13) DrawFlask(pBtmBuff, PANEL_WIDTH, PANEL_WIDTH * (filled + 3) + 109, gpBuffer, SCREENXY(PANEL_LEFT + 109, PANEL_TOP - 13 + filled), 13 - filled); } /** * Controls the drawing of the area of the life flask within the control panel. * First sets the fill amount then draws the empty flask cel portion then the filled * flask portion. */ void UpdateLifeFlask() { double p; int filled; #ifdef HELLFIRE if (plr[myplr]._pMaxHP <= 0) { p = 0.0; } else { p = (double)plr[myplr]._pHitPoints / (double)plr[myplr]._pMaxHP * 80.0; } #else p = (double)plr[myplr]._pHitPoints / (double)plr[myplr]._pMaxHP * 80.0; #endif filled = p; plr[myplr]._pHPPer = filled; if (filled > 69) filled = 69; #ifndef HELLFIRE else if (filled < 0) filled = 0; #endif if (filled != 69) SetFlaskHeight(pLifeBuff, 16, 85 - filled, 96 + PANEL_X, PANEL_Y); if (filled != 0) DrawPanelBox(96, 85 - filled, 88, filled, 96 + PANEL_X, PANEL_Y + 69 - filled); } void DrawManaFlask() { int filled = plr[myplr]._pManaPer; #ifndef HELLFIRE if (filled > 80) filled = 80; #endif filled = 80 - filled; if (filled > 11) filled = 11; filled += 2; DrawFlask(pManaBuff, 88, 88 * 3 + 13, gpBuffer, SCREENXY(PANEL_LEFT + 475, PANEL_TOP - 13), filled); if (filled != 13) DrawFlask(pBtmBuff, PANEL_WIDTH, PANEL_WIDTH * (filled + 3) + 475, gpBuffer, SCREENXY(PANEL_LEFT + 475, PANEL_TOP - 13 + filled), 13 - filled); } void control_update_life_mana() { int manaPer; int maxMana = plr[myplr]._pMaxMana; int mana = plr[myplr]._pMana; if (maxMana < 0) maxMana = 0; if (mana < 0) mana = 0; if (maxMana == 0) manaPer = 0; else manaPer = (double)mana / (double)maxMana * 80.0; plr[myplr]._pManaPer = manaPer; plr[myplr]._pHPPer = (double)plr[myplr]._pHitPoints / (double)plr[myplr]._pMaxHP * 80.0; } /** * Controls the drawing of the area of the life flask within the control panel. * Also for some reason draws the current right mouse button spell. */ void UpdateManaFlask() { int filled; int maxMana = plr[myplr]._pMaxMana; int mana = plr[myplr]._pMana; if (maxMana < 0) maxMana = 0; if (mana < 0) mana = 0; if (maxMana == 0) filled = 0; else filled = (double)mana / (double)maxMana * 80.0; plr[myplr]._pManaPer = filled; if (filled > 69) filled = 69; if (filled != 69) SetFlaskHeight(pManaBuff, 16, 85 - filled, PANEL_X + 464, PANEL_Y); if (filled != 0) DrawPanelBox(464, 85 - filled, 88, filled, PANEL_X + 464, PANEL_Y + 69 - filled); DrawSpell(); } void InitControlPan() { int i; if (gbMaxPlayers == 1) { pBtmBuff = DiabloAllocPtr((PANEL_HEIGHT + 16) * PANEL_WIDTH); memset(pBtmBuff, 0, (PANEL_HEIGHT + 16) * PANEL_WIDTH); } else { pBtmBuff = DiabloAllocPtr((PANEL_HEIGHT + 16) * 2 * PANEL_WIDTH); memset(pBtmBuff, 0, (PANEL_HEIGHT + 16) * 2 * PANEL_WIDTH); } pManaBuff = DiabloAllocPtr(88 * 88); memset(pManaBuff, 0, 88 * 88); pLifeBuff = DiabloAllocPtr(88 * 88); memset(pLifeBuff, 0, 88 * 88); pPanelText = LoadFileInMem("CtrlPan\\SmalText.CEL", NULL); pChrPanel = LoadFileInMem("Data\\Char.CEL", NULL); #ifndef HELLFIRE pSpellCels = LoadFileInMem("CtrlPan\\SpelIcon.CEL", NULL); #else pSpellCels = LoadFileInMem("Data\\SpelIcon.CEL", NULL); #endif SetSpellTrans(RSPLTYPE_SKILL); pStatusPanel = LoadFileInMem("CtrlPan\\Panel8.CEL", NULL); CelBlitWidth(pBtmBuff, 0, (PANEL_HEIGHT + 16) - 1, PANEL_WIDTH, pStatusPanel, 1, PANEL_WIDTH); MemFreeDbg(pStatusPanel); pStatusPanel = LoadFileInMem("CtrlPan\\P8Bulbs.CEL", NULL); CelBlitWidth(pLifeBuff, 0, 87, 88, pStatusPanel, 1, 88); CelBlitWidth(pManaBuff, 0, 87, 88, pStatusPanel, 2, 88); MemFreeDbg(pStatusPanel); talkflag = FALSE; if (gbMaxPlayers != 1) { pTalkPanel = LoadFileInMem("CtrlPan\\TalkPanl.CEL", NULL); CelBlitWidth(pBtmBuff, 0, (PANEL_HEIGHT + 16) * 2 - 1, PANEL_WIDTH, pTalkPanel, 1, PANEL_WIDTH); MemFreeDbg(pTalkPanel); pMultiBtns = LoadFileInMem("CtrlPan\\P8But2.CEL", NULL); pTalkBtns = LoadFileInMem("CtrlPan\\TalkButt.CEL", NULL); sgbPlrTalkTbl = 0; sgszTalkMsg[0] = '\0'; for (i = 0; i < MAX_PLRS; i++) whisper[i] = TRUE; for (i = 0; i < sizeof(talkbtndown) / sizeof(talkbtndown[0]); i++) talkbtndown[i] = FALSE; } panelflag = FALSE; lvlbtndown = FALSE; pPanelButtons = LoadFileInMem("CtrlPan\\Panel8bu.CEL", NULL); for (i = 0; i < sizeof(panbtn) / sizeof(panbtn[0]); i++) panbtn[i] = FALSE; panbtndown = FALSE; if (gbMaxPlayers == 1) numpanbtns = 6; else numpanbtns = 8; pChrButtons = LoadFileInMem("Data\\CharBut.CEL", NULL); for (i = 0; i < sizeof(chrbtn) / sizeof(chrbtn[0]); i++) chrbtn[i] = FALSE; chrbtnactive = FALSE; pDurIcons = LoadFileInMem("Items\\DurIcons.CEL", NULL); strcpy(infostr, ""); ClearPanel(); drawhpflag = TRUE; drawmanaflag = TRUE; chrflag = FALSE; spselflag = FALSE; pSpellBkCel = LoadFileInMem("Data\\SpellBk.CEL", NULL); pSBkBtnCel = LoadFileInMem("Data\\SpellBkB.CEL", NULL); pSBkIconCels = LoadFileInMem("Data\\SpellI2.CEL", NULL); sbooktab = 0; sbookflag = FALSE; if (plr[myplr]._pClass == PC_WARRIOR) { SpellPages[0][0] = SPL_REPAIR; #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { SpellPages[0][0] = SPL_DISARM; } else if (plr[myplr]._pClass == PC_SORCERER) { SpellPages[0][0] = SPL_RECHARGE; #endif #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { SpellPages[0][0] = SPL_SEARCH; } else if (plr[myplr]._pClass == PC_BARD) { SpellPages[0][0] = SPL_IDENTIFY; } else if (plr[myplr]._pClass == PC_BARBARIAN) { SpellPages[0][0] = SPL_BLODBOIL; #endif } pQLogCel = LoadFileInMem("Data\\Quest.CEL", NULL); pGBoxBuff = LoadFileInMem("CtrlPan\\Golddrop.cel", NULL); dropGoldFlag = FALSE; dropGoldValue = 0; initialDropGoldValue = 0; initialDropGoldIndex = 0; nGoldFrame = 1; } void DrawCtrlPan() { DrawPanelBox(0, sgbPlrTalkTbl + 16, PANEL_WIDTH, PANEL_HEIGHT, PANEL_X, PANEL_Y); DrawInfoBox(); } /** * Draws the control panel buttons in their current state. If the button is in the default * state draw it from the panel cel(extract its sub-rect). Else draw it from the buttons cel. */ void DrawCtrlBtns() { int i; for (i = 0; i < 6; i++) { if (!panbtn[i]) DrawPanelBox(PanBtnPos[i][0] - PANEL_LEFT, PanBtnPos[i][1] - (PANEL_TOP - 16), 71, 20, PanBtnPos[i][0] + SCREEN_X, PanBtnPos[i][1] + SCREEN_Y); else CelDraw(PanBtnPos[i][0] + SCREEN_X, PanBtnPos[i][1] + SCREEN_Y + 18, pPanelButtons, i + 1, 71); } if (numpanbtns == 8) { CelDraw(87 + PANEL_X, 122 + PANEL_Y, pMultiBtns, panbtn[6] + 1, 33); if (FriendlyMode) CelDraw(527 + PANEL_X, 122 + PANEL_Y, pMultiBtns, panbtn[7] + 3, 33); else CelDraw(527 + PANEL_X, 122 + PANEL_Y, pMultiBtns, panbtn[7] + 5, 33); } } /** * Draws the "Speed Book": the rows of known spells for quick-setting a spell that * show up when you click the spell slot at the control panel. */ void DoSpeedBook() { unsigned __int64 spell, spells; int xo, yo, X, Y, i, j; spselflag = TRUE; xo = PANEL_X + 12 + SPLICONLENGTH * 10; yo = PANEL_Y - 17; X = xo - (BORDER_LEFT - SPLICONLENGTH / 2); Y = yo - (BORDER_TOP + SPLICONLENGTH / 2); if (plr[myplr]._pRSpell != SPL_INVALID) { for (i = 0; i < 4; i++) { switch (i) { case RSPLTYPE_SKILL: spells = plr[myplr]._pAblSpells; break; case RSPLTYPE_SPELL: spells = plr[myplr]._pMemSpells; break; case RSPLTYPE_SCROLL: spells = plr[myplr]._pScrlSpells; break; case RSPLTYPE_CHARGES: spells = plr[myplr]._pISpells; break; } spell = (__int64)1; for (j = 1; j < MAX_SPELLS; j++) { if (spell & spells) { if (j == plr[myplr]._pRSpell && i == plr[myplr]._pRSplType) { X = xo - (BORDER_LEFT - SPLICONLENGTH / 2); Y = yo - (BORDER_TOP + SPLICONLENGTH / 2); } xo -= SPLICONLENGTH; if (xo == PANEL_X + 12 - SPLICONLENGTH) { xo = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; yo -= SPLICONLENGTH; } } spell <<= (__int64)1; } if (spells && xo != PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS) xo -= SPLICONLENGTH; if (xo == PANEL_X + 12 - SPLICONLENGTH) { xo = PANEL_X + 12 + SPLICONLENGTH * SPLROWICONLS; yo -= SPLICONLENGTH; } } } SetCursorPos(X, Y); } /** * Checks if the mouse cursor is within any of the panel buttons and flag it if so. */ void DoPanBtn() { int i; for (i = 0; i < numpanbtns; i++) { int x = PanBtnPos[i][0] + PanBtnPos[i][2]; int y = PanBtnPos[i][1] + PanBtnPos[i][3]; if (MouseX >= PanBtnPos[i][0] && MouseX <= x) { if (MouseY >= PanBtnPos[i][1] && MouseY <= y) { panbtn[i] = TRUE; drawbtnflag = TRUE; panbtndown = TRUE; } } } if (!spselflag && MouseX >= 565 + PANEL_LEFT && MouseX < 621 + PANEL_LEFT && MouseY >= 64 + PANEL_TOP && MouseY < 120 + PANEL_TOP) { DoSpeedBook(); gamemenu_off(); } } void control_set_button_down(int btn_id) { panbtn[btn_id] = TRUE; drawbtnflag = TRUE; panbtndown = TRUE; } void control_check_btn_press() { int x, y; x = PanBtnPos[3][0] + PanBtnPos[3][2]; y = PanBtnPos[3][1] + PanBtnPos[3][3]; if (MouseX >= PanBtnPos[3][0] && MouseX <= x && MouseY >= PanBtnPos[3][1] && MouseY <= y) { control_set_button_down(3); } x = PanBtnPos[6][0] + PanBtnPos[6][2]; y = PanBtnPos[6][1] + PanBtnPos[6][3]; if (MouseX >= PanBtnPos[6][0] && MouseX <= x && MouseY >= PanBtnPos[6][1] && MouseY <= y) { control_set_button_down(6); } } void DoAutoMap() { if (currlevel != 0 || gbMaxPlayers != 1) { if (!automapflag) StartAutomap(); else automapflag = FALSE; } else { InitDiabloMsg(EMSG_NO_AUTOMAP_IN_TOWN); } } /** * Checks the mouse cursor position within the control panel and sets information * strings if needed. */ void CheckPanelInfo() { int i, c, v, s, xend, yend; panelflag = FALSE; ClearPanel(); for (i = 0; i < numpanbtns; i++) { xend = PanBtnPos[i][0] + PanBtnPos[i][2]; yend = PanBtnPos[i][1] + PanBtnPos[i][3]; if (MouseX >= PanBtnPos[i][0] && MouseX <= xend && MouseY >= PanBtnPos[i][1] && MouseY <= yend) { if (i != 7) { strcpy(infostr, PanBtnStr[i]); } else { if (FriendlyMode) strcpy(infostr, "Player friendly"); else strcpy(infostr, "Player attack"); } if (PanBtnHotKey[i] != NULL) { sprintf(tempstr, "Hotkey : %s", PanBtnHotKey[i]); AddPanelString(tempstr, TRUE); } infoclr = COL_WHITE; panelflag = TRUE; pinfoflag = TRUE; } } if (!spselflag && MouseX >= 565 + PANEL_LEFT && MouseX < 621 + PANEL_LEFT && MouseY >= 64 + PANEL_TOP && MouseY < 120 + PANEL_TOP) { strcpy(infostr, "Select current spell button"); infoclr = COL_WHITE; panelflag = TRUE; pinfoflag = TRUE; strcpy(tempstr, "Hotkey : 's'"); AddPanelString(tempstr, TRUE); v = plr[myplr]._pRSpell; if (v != SPL_INVALID) { switch (plr[myplr]._pRSplType) { case RSPLTYPE_SKILL: sprintf(tempstr, "%s Skill", spelldata[v].sSkillText); AddPanelString(tempstr, TRUE); break; case RSPLTYPE_SPELL: sprintf(tempstr, "%s Spell", spelldata[v].sNameText); AddPanelString(tempstr, TRUE); c = plr[myplr]._pISplLvlAdd + plr[myplr]._pSplLvl[v]; if (c < 0) c = 0; if (c == 0) sprintf(tempstr, "Spell Level 0 - Unusable"); else sprintf(tempstr, "Spell Level %i", c); AddPanelString(tempstr, TRUE); break; case RSPLTYPE_SCROLL: sprintf(tempstr, "Scroll of %s", spelldata[v].sNameText); AddPanelString(tempstr, TRUE); s = 0; for (i = 0; i < plr[myplr]._pNumInv; i++) { if (plr[myplr].InvList[i]._itype != ITYPE_NONE && (plr[myplr].InvList[i]._iMiscId == IMISC_SCROLL || plr[myplr].InvList[i]._iMiscId == IMISC_SCROLLT) && plr[myplr].InvList[i]._iSpell == v) { s++; } } for (i = 0; i < MAXBELTITEMS; i++) { if (plr[myplr].SpdList[i]._itype != ITYPE_NONE && (plr[myplr].SpdList[i]._iMiscId == IMISC_SCROLL || plr[myplr].SpdList[i]._iMiscId == IMISC_SCROLLT) && plr[myplr].SpdList[i]._iSpell == v) { s++; } } if (s == 1) strcpy(tempstr, "1 Scroll"); else sprintf(tempstr, "%i Scrolls", s); AddPanelString(tempstr, TRUE); break; case RSPLTYPE_CHARGES: sprintf(tempstr, "Staff of %s", spelldata[v].sNameText); AddPanelString(tempstr, TRUE); if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges == 1) strcpy(tempstr, "1 Charge"); else sprintf(tempstr, "%i Charges", plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges); AddPanelString(tempstr, TRUE); break; } } } if (MouseX > 190 + PANEL_LEFT && MouseX < 437 + PANEL_LEFT && MouseY > 4 + PANEL_TOP && MouseY < 33 + PANEL_TOP) pcursinvitem = CheckInvHLight(); } /** * Check if the mouse is within a control panel button that's flagged. * Takes apropiate action if so. */ void CheckBtnUp() { int i; BOOLEAN gamemenuOff; gamemenuOff = TRUE; drawbtnflag = TRUE; panbtndown = FALSE; for (i = 0; i < 8; i++) { if (!panbtn[i]) { continue; } panbtn[i] = FALSE; if (MouseX < PanBtnPos[i][0] || MouseX > PanBtnPos[i][0] + PanBtnPos[i][2] || MouseY < PanBtnPos[i][1] || MouseY > PanBtnPos[i][1] + PanBtnPos[i][3]) { continue; } switch (i) { case PANBTN_CHARINFO: questlog = FALSE; chrflag = !chrflag; break; case PANBTN_QLOG: chrflag = FALSE; if (!questlog) StartQuestlog(); else questlog = FALSE; break; case PANBTN_AUTOMAP: DoAutoMap(); break; case PANBTN_MAINMENU: qtextflag = FALSE; gamemenu_handle_previous(); gamemenuOff = FALSE; break; case PANBTN_INVENTORY: sbookflag = FALSE; invflag = !invflag; if (dropGoldFlag) { dropGoldFlag = FALSE; dropGoldValue = 0; } break; case PANBTN_SPELLBOOK: invflag = FALSE; if (dropGoldFlag) { dropGoldFlag = FALSE; dropGoldValue = 0; } sbookflag = !sbookflag; break; case PANBTN_SENDMSG: if (talkflag) control_reset_talk(); else control_type_message(); break; case PANBTN_FRIENDLY: FriendlyMode = !FriendlyMode; break; } } if (gamemenuOff) gamemenu_off(); } void FreeControlPan() { MemFreeDbg(pBtmBuff); MemFreeDbg(pManaBuff); MemFreeDbg(pLifeBuff); MemFreeDbg(pPanelText); MemFreeDbg(pChrPanel); MemFreeDbg(pSpellCels); MemFreeDbg(pPanelButtons); MemFreeDbg(pMultiBtns); MemFreeDbg(pTalkBtns); MemFreeDbg(pChrButtons); MemFreeDbg(pDurIcons); MemFreeDbg(pQLogCel); MemFreeDbg(pSpellBkCel); MemFreeDbg(pSBkBtnCel); MemFreeDbg(pSBkIconCels); MemFreeDbg(pGBoxBuff); } BOOL control_WriteStringToBuffer(BYTE *str) { int k; BYTE ichar; k = 0; while (*str) { ichar = gbFontTransTbl[*str]; str++; k += fontkern[fontframe[ichar]]; if (k >= 125) return FALSE; } return TRUE; } static void CPrintString(int y, const char *str, BOOL center, int lines) { BYTE c; const char *tmp; int strWidth, lineOffset, lineStart; lineOffset = 0; lineStart = lineOffsets[lines][y] + PANEL_LEFT; if (center == TRUE) { strWidth = 0; tmp = str; while (*tmp) { c = gbFontTransTbl[(BYTE)*tmp++]; strWidth += fontkern[fontframe[c]] + 2; } if (strWidth < 288) lineOffset = (288 - strWidth) >> 1; lineStart += lineOffset; } while (*str) { c = gbFontTransTbl[(BYTE)*str++]; c = fontframe[c]; lineOffset += fontkern[c] + 2; if (c) { if (lineOffset < 288) { PrintChar(lineStart, c, infoclr); } } lineStart += fontkern[c] + 2; } } static void PrintInfo() { int yo, lo, i; if (!talkflag) { yo = 0; lo = 1; if (infostr[0] != '\0') { CPrintString(0, infostr, TRUE, pnumlines); yo = 1; lo = 0; } for (i = 0; i < pnumlines; i++) { CPrintString(i + yo, panelstr[i], pstrjust[i], pnumlines - lo); } } } /** * Sets a string to be drawn in the info box and then draws it. */ void DrawInfoBox() { int nGold; DrawPanelBox(177, 62, 288, 60, PANEL_X + 177, PANEL_Y + 46); if (!panelflag && !trigflag && pcursinvitem == -1 && !spselflag) { infostr[0] = '\0'; infoclr = COL_WHITE; ClearPanel(); } if (spselflag || trigflag) { infoclr = COL_WHITE; } else if (pcurs >= CURSOR_FIRSTITEM) { if (plr[myplr].HoldItem._itype == ITYPE_GOLD) { nGold = plr[myplr].HoldItem._ivalue; sprintf(infostr, "%i gold %s", nGold, get_pieces_str(nGold)); } else if (!plr[myplr].HoldItem._iStatFlag) { ClearPanel(); AddPanelString("Requirements not met", TRUE); pinfoflag = TRUE; } else { if (plr[myplr].HoldItem._iIdentified) strcpy(infostr, plr[myplr].HoldItem._iIName); else strcpy(infostr, plr[myplr].HoldItem._iName); if (plr[myplr].HoldItem._iMagical == ITEM_QUALITY_MAGIC) infoclr = COL_BLUE; if (plr[myplr].HoldItem._iMagical == ITEM_QUALITY_UNIQUE) infoclr = COL_GOLD; } } else { if (pcursitem != -1) GetItemStr(pcursitem); if (pcursobj != -1) GetObjectStr(pcursobj); if (pcursmonst != -1) { if (leveltype != DTYPE_TOWN) { infoclr = COL_WHITE; strcpy(infostr, monster[pcursmonst].mName); ClearPanel(); if (monster[pcursmonst]._uniqtype != 0) { infoclr = COL_GOLD; PrintUniqueHistory(); } else { PrintMonstHistory(monster[pcursmonst].MType->mtype); } } else { strcpy(infostr, towner[pcursmonst]._tName); } } if (pcursplr != -1) { infoclr = COL_GOLD; strcpy(infostr, plr[pcursplr]._pName); ClearPanel(); #ifdef HELLFIRE sprintf(tempstr, "%s, Level : %i", ClassStrTbl[plr[pcursplr]._pClass], plr[pcursplr]._pLevel); #else sprintf(tempstr, "Level : %i", plr[pcursplr]._pLevel); #endif AddPanelString(tempstr, TRUE); sprintf(tempstr, "Hit Points %i of %i", plr[pcursplr]._pHitPoints >> 6, plr[pcursplr]._pMaxHP >> 6); AddPanelString(tempstr, TRUE); } } if (infostr[0] != '\0' || pnumlines != 0) PrintInfo(); } /** * @brief Identical to MY_PlrStringXY(x, y, width, pszStr, col, 1) */ static void ADD_PlrStringXY(int x, int y, int width, const char *pszStr, char col) { BYTE c; const char *tmp; int nOffset, screen_x, line, widthOffset; nOffset = x + PitchTbl[y + SCREEN_Y] + SCREEN_X; widthOffset = width - x + 1; line = 0; screen_x = 0; tmp = pszStr; while (*tmp) { c = gbFontTransTbl[(BYTE)*tmp++]; screen_x += fontkern[fontframe[c]] + 1; } if (screen_x < widthOffset) line = (widthOffset - screen_x) >> 1; nOffset += line; while (*pszStr) { c = gbFontTransTbl[(BYTE)*pszStr++]; c = fontframe[c]; line += fontkern[c] + 1; if (c) { if (line < widthOffset) PrintChar(nOffset, c, col); } nOffset += fontkern[c] + 1; } } void PrintGameStr(int x, int y, const char *str, int color) { BYTE c; int off; off = PitchTbl[y + SCREEN_Y] + x + SCREEN_X; while (*str) { c = gbFontTransTbl[(BYTE)*str++]; c = fontframe[c]; if (c) PrintChar(off, c, color); off += fontkern[c] + 1; } } /** * @brief Render text string to back buffer * @param x Screen coordinate * @param y Screen coordinate * @param endX End of line in screen coordinate * @param pszStr String to print, in Windows-1252 encoding * @param col text_color color value * @param base Letter spacing */ static void MY_PlrStringXY(int x, int y, int endX, const char *pszStr, char col, int base) { BYTE c; const char *tmp; int nOffset, screen_x, line, widthOffset; nOffset = x + PitchTbl[y + SCREEN_Y] + SCREEN_X; widthOffset = endX - x + 1; line = 0; screen_x = 0; tmp = pszStr; while (*tmp) { c = gbFontTransTbl[(BYTE)*tmp++]; screen_x += fontkern[fontframe[c]] + base; } if (screen_x < widthOffset) line = (widthOffset - screen_x) >> 1; nOffset += line; while (*pszStr) { c = gbFontTransTbl[(BYTE)*pszStr++]; c = fontframe[c]; line += fontkern[c] + base; if (c) { if (line < widthOffset) PrintChar(nOffset, c, col); } nOffset += fontkern[c] + base; } } void DrawChr() { char col; char chrstr[64]; int pc, mindam, maxdam; CelDraw(SCREEN_X, 351 + SCREEN_Y, pChrPanel, 1, 320); ADD_PlrStringXY(20, 32, 151, plr[myplr]._pName, COL_WHITE); #ifdef HELLFIRE ADD_PlrStringXY(168, 32, 299, ClassStrTbl[plr[myplr]._pClass], COL_WHITE); #else if (plr[myplr]._pClass == PC_WARRIOR) { ADD_PlrStringXY(168, 32, 299, "Warrior", COL_WHITE); #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { ADD_PlrStringXY(168, 32, 299, "Rogue", COL_WHITE); } else if (plr[myplr]._pClass == PC_SORCERER) { ADD_PlrStringXY(168, 32, 299, "Sorceror", COL_WHITE); #endif } #endif sprintf(chrstr, "%i", plr[myplr]._pLevel); ADD_PlrStringXY(66, 69, 109, chrstr, COL_WHITE); sprintf(chrstr, "%li", plr[myplr]._pExperience); ADD_PlrStringXY(216, 69, 300, chrstr, COL_WHITE); if (plr[myplr]._pLevel == MAXCHARLEVEL - 1) { strcpy(chrstr, "None"); col = COL_GOLD; } else { sprintf(chrstr, "%li", plr[myplr]._pNextExper); col = COL_WHITE; } ADD_PlrStringXY(216, 97, 300, chrstr, col); sprintf(chrstr, "%i", plr[myplr]._pGold); ADD_PlrStringXY(216, 146, 300, chrstr, COL_WHITE); col = COL_WHITE; if (plr[myplr]._pIBonusAC > 0) col = COL_BLUE; if (plr[myplr]._pIBonusAC < 0) col = COL_RED; sprintf(chrstr, "%i", plr[myplr]._pIBonusAC + plr[myplr]._pIAC + plr[myplr]._pDexterity / 5); ADD_PlrStringXY(258, 183, 301, chrstr, col); col = COL_WHITE; if (plr[myplr]._pIBonusToHit > 0) col = COL_BLUE; if (plr[myplr]._pIBonusToHit < 0) col = COL_RED; sprintf(chrstr, "%i%%", (plr[myplr]._pDexterity >> 1) + plr[myplr]._pIBonusToHit + 50); ADD_PlrStringXY(258, 211, 301, chrstr, col); col = COL_WHITE; if (plr[myplr]._pIBonusDam > 0) col = COL_BLUE; if (plr[myplr]._pIBonusDam < 0) col = COL_RED; mindam = plr[myplr]._pIMinDam; mindam += plr[myplr]._pIBonusDam * mindam / 100; mindam += plr[myplr]._pIBonusDamMod; if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_BOW) { if (plr[myplr]._pClass == PC_ROGUE) mindam += plr[myplr]._pDamageMod; else mindam += plr[myplr]._pDamageMod >> 1; } else { mindam += plr[myplr]._pDamageMod; } maxdam = plr[myplr]._pIMaxDam; maxdam += plr[myplr]._pIBonusDam * maxdam / 100; maxdam += plr[myplr]._pIBonusDamMod; if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_BOW) { if (plr[myplr]._pClass == PC_ROGUE) maxdam += plr[myplr]._pDamageMod; else maxdam += plr[myplr]._pDamageMod >> 1; } else { maxdam += plr[myplr]._pDamageMod; } sprintf(chrstr, "%i-%i", mindam, maxdam); if (mindam >= 100 || maxdam >= 100) MY_PlrStringXY(254, 239, 305, chrstr, col, -1); else MY_PlrStringXY(258, 239, 301, chrstr, col, 0); if (plr[myplr]._pMagResist == 0) col = COL_WHITE; else col = COL_BLUE; if (plr[myplr]._pMagResist < MAXRESIST) { sprintf(chrstr, "%i%%", plr[myplr]._pMagResist); } else { col = COL_GOLD; sprintf(chrstr, "MAX"); } ADD_PlrStringXY(257, 276, 300, chrstr, col); if (plr[myplr]._pFireResist == 0) col = COL_WHITE; else col = COL_BLUE; if (plr[myplr]._pFireResist < MAXRESIST) { sprintf(chrstr, "%i%%", plr[myplr]._pFireResist); } else { col = COL_GOLD; sprintf(chrstr, "MAX"); } ADD_PlrStringXY(257, 304, 300, chrstr, col); if (plr[myplr]._pLghtResist == 0) col = COL_WHITE; else col = COL_BLUE; if (plr[myplr]._pLghtResist < MAXRESIST) { sprintf(chrstr, "%i%%", plr[myplr]._pLghtResist); } else { col = COL_GOLD; sprintf(chrstr, "MAX"); } ADD_PlrStringXY(257, 332, 300, chrstr, col); col = COL_WHITE; sprintf(chrstr, "%i", plr[myplr]._pBaseStr); if (MaxStats[plr[myplr]._pClass][ATTRIB_STR] == plr[myplr]._pBaseStr) col = COL_GOLD; ADD_PlrStringXY(95, 155, 126, chrstr, col); col = COL_WHITE; sprintf(chrstr, "%i", plr[myplr]._pBaseMag); if (MaxStats[plr[myplr]._pClass][ATTRIB_MAG] == plr[myplr]._pBaseMag) col = COL_GOLD; ADD_PlrStringXY(95, 183, 126, chrstr, col); col = COL_WHITE; sprintf(chrstr, "%i", plr[myplr]._pBaseDex); if (MaxStats[plr[myplr]._pClass][ATTRIB_DEX] == plr[myplr]._pBaseDex) col = COL_GOLD; ADD_PlrStringXY(95, 211, 126, chrstr, col); col = COL_WHITE; sprintf(chrstr, "%i", plr[myplr]._pBaseVit); if (MaxStats[plr[myplr]._pClass][ATTRIB_VIT] == plr[myplr]._pBaseVit) col = COL_GOLD; ADD_PlrStringXY(95, 239, 126, chrstr, col); col = COL_WHITE; if (plr[myplr]._pStrength > plr[myplr]._pBaseStr) col = COL_BLUE; if (plr[myplr]._pStrength < plr[myplr]._pBaseStr) col = COL_RED; sprintf(chrstr, "%i", plr[myplr]._pStrength); ADD_PlrStringXY(143, 155, 173, chrstr, col); col = COL_WHITE; if (plr[myplr]._pMagic > plr[myplr]._pBaseMag) col = COL_BLUE; if (plr[myplr]._pMagic < plr[myplr]._pBaseMag) col = COL_RED; sprintf(chrstr, "%i", plr[myplr]._pMagic); ADD_PlrStringXY(143, 183, 173, chrstr, col); col = COL_WHITE; if (plr[myplr]._pDexterity > plr[myplr]._pBaseDex) col = COL_BLUE; if (plr[myplr]._pDexterity < plr[myplr]._pBaseDex) col = COL_RED; sprintf(chrstr, "%i", plr[myplr]._pDexterity); ADD_PlrStringXY(143, 211, 173, chrstr, col); col = COL_WHITE; if (plr[myplr]._pVitality > plr[myplr]._pBaseVit) col = COL_BLUE; if (plr[myplr]._pVitality < plr[myplr]._pBaseVit) col = COL_RED; sprintf(chrstr, "%i", plr[myplr]._pVitality); ADD_PlrStringXY(143, 239, 173, chrstr, col); if (plr[myplr]._pStatPts > 0) { if (CalcStatDiff(myplr) < plr[myplr]._pStatPts) { plr[myplr]._pStatPts = CalcStatDiff(myplr); } } if (plr[myplr]._pStatPts > 0) { sprintf(chrstr, "%i", plr[myplr]._pStatPts); ADD_PlrStringXY(95, 266, 126, chrstr, COL_RED); pc = plr[myplr]._pClass; if (plr[myplr]._pBaseStr < MaxStats[pc][ATTRIB_STR]) CelDraw(137 + SCREEN_X, 159 + SCREEN_Y, pChrButtons, chrbtn[ATTRIB_STR] + 2, 41); if (plr[myplr]._pBaseMag < MaxStats[pc][ATTRIB_MAG]) CelDraw(137 + SCREEN_X, 187 + SCREEN_Y, pChrButtons, chrbtn[ATTRIB_MAG] + 4, 41); if (plr[myplr]._pBaseDex < MaxStats[pc][ATTRIB_DEX]) CelDraw(137 + SCREEN_X, 216 + SCREEN_Y, pChrButtons, chrbtn[ATTRIB_DEX] + 6, 41); if (plr[myplr]._pBaseVit < MaxStats[pc][ATTRIB_VIT]) CelDraw(137 + SCREEN_X, 244 + SCREEN_Y, pChrButtons, chrbtn[ATTRIB_VIT] + 8, 41); } if (plr[myplr]._pMaxHP > plr[myplr]._pMaxHPBase) col = COL_BLUE; else col = COL_WHITE; sprintf(chrstr, "%i", plr[myplr]._pMaxHP >> 6); ADD_PlrStringXY(95, 304, 126, chrstr, col); if (plr[myplr]._pHitPoints != plr[myplr]._pMaxHP) col = COL_RED; sprintf(chrstr, "%i", plr[myplr]._pHitPoints >> 6); ADD_PlrStringXY(143, 304, 174, chrstr, col); if (plr[myplr]._pMaxMana > plr[myplr]._pMaxManaBase) col = COL_BLUE; else col = COL_WHITE; sprintf(chrstr, "%i", plr[myplr]._pMaxMana >> 6); ADD_PlrStringXY(95, 332, 126, chrstr, col); if (plr[myplr]._pMana != plr[myplr]._pMaxMana) col = COL_RED; sprintf(chrstr, "%i", plr[myplr]._pMana >> 6); ADD_PlrStringXY(143, 332, 174, chrstr, col); } void CheckLvlBtn() { if (!lvlbtndown && MouseX >= 40 + PANEL_LEFT && MouseX <= 81 + PANEL_LEFT && MouseY >= -39 + PANEL_TOP && MouseY <= -17 + PANEL_TOP) lvlbtndown = TRUE; } void ReleaseLvlBtn() { if (MouseX >= 40 + PANEL_LEFT && MouseX <= 81 + PANEL_LEFT && MouseY >= -39 + PANEL_TOP && MouseY <= -17 + PANEL_TOP) chrflag = TRUE; lvlbtndown = FALSE; } void DrawLevelUpIcon() { int nCel; if (stextflag == STORE_NONE) { nCel = lvlbtndown ? 3 : 2; ADD_PlrStringXY(PANEL_LEFT + 0, PANEL_TOP - 49, PANEL_LEFT + 120, "Level Up", COL_WHITE); CelDraw(40 + PANEL_X, -17 + PANEL_Y, pChrButtons, nCel, 41); } } void CheckChrBtns() { int pc, i, x, y; if (!chrbtnactive && plr[myplr]._pStatPts) { pc = plr[myplr]._pClass; for (i = 0; i < 4; i++) { switch (i) { case ATTRIB_STR: if (plr[myplr]._pBaseStr >= MaxStats[pc][ATTRIB_STR]) continue; break; case ATTRIB_MAG: if (plr[myplr]._pBaseMag >= MaxStats[pc][ATTRIB_MAG]) continue; break; case ATTRIB_DEX: if (plr[myplr]._pBaseDex >= MaxStats[pc][ATTRIB_DEX]) continue; break; case ATTRIB_VIT: if (plr[myplr]._pBaseVit >= MaxStats[pc][ATTRIB_VIT]) continue; break; default: continue; } x = ChrBtnsRect[i].x + ChrBtnsRect[i].w; y = ChrBtnsRect[i].y + ChrBtnsRect[i].h; if (MouseX >= ChrBtnsRect[i].x && MouseX <= x && MouseY >= ChrBtnsRect[i].y && MouseY <= y) { chrbtn[i] = TRUE; chrbtnactive = TRUE; } } } } void ReleaseChrBtns() { int i; chrbtnactive = FALSE; for (i = 0; i < 4; ++i) { if (chrbtn[i]) { chrbtn[i] = FALSE; if (MouseX >= ChrBtnsRect[i].x && MouseX <= ChrBtnsRect[i].x + ChrBtnsRect[i].w && MouseY >= ChrBtnsRect[i].y && MouseY <= ChrBtnsRect[i].y + ChrBtnsRect[i].h) { switch (i) { case 0: NetSendCmdParam1(TRUE, CMD_ADDSTR, 1); plr[myplr]._pStatPts--; break; case 1: NetSendCmdParam1(TRUE, CMD_ADDMAG, 1); plr[myplr]._pStatPts--; break; case 2: NetSendCmdParam1(TRUE, CMD_ADDDEX, 1); plr[myplr]._pStatPts--; break; case 3: NetSendCmdParam1(TRUE, CMD_ADDVIT, 1); plr[myplr]._pStatPts--; break; } } } } } static int DrawDurIcon4Item(ItemStruct *pItem, int x, int c) { if (pItem->_itype == ITYPE_NONE) return x; if (pItem->_iDurability > 5) return x; if (c == 0) { if (pItem->_iClass == ICLASS_WEAPON) { switch (pItem->_itype) { case ITYPE_SWORD: c = 2; break; case ITYPE_AXE: c = 6; break; case ITYPE_BOW: c = 7; break; case ITYPE_MACE: c = 5; break; case ITYPE_STAFF: c = 8; break; } } else { c = 1; } } if (pItem->_iDurability > 2) c += 8; CelDraw(x, -17 + PANEL_Y, pDurIcons, c, 32); return x - 32 - 8; } void DrawDurIcon() { PlayerStruct *p; int x; if ((chrflag || questlog) && (invflag || sbookflag)) return; x = PANEL_X + PANEL_WIDTH - 32 - 16; if (invflag || sbookflag) x -= SPANEL_WIDTH; p = &plr[myplr]; x = DrawDurIcon4Item(&p->InvBody[INVLOC_HEAD], x, 4); x = DrawDurIcon4Item(&p->InvBody[INVLOC_CHEST], x, 3); x = DrawDurIcon4Item(&p->InvBody[INVLOC_HAND_LEFT], x, 0); DrawDurIcon4Item(&p->InvBody[INVLOC_HAND_RIGHT], x, 0); } void RedBack() { int idx; idx = light4flag ? 1536 : 4608; assert(gpBuffer); #ifdef USE_ASM if (leveltype != DTYPE_HELL) { __asm { mov edi, gpBuffer add edi, SCREENXY(0, 0) mov ebx, pLightTbl add ebx, idx mov edx, PANEL_TOP lx_label1: mov ecx, SCREEN_WIDTH lx_label2: mov al, [edi] xlat stosb loop lx_label2 add edi, BUFFER_WIDTH - SCREEN_WIDTH dec edx jnz lx_label1 } } else { __asm { mov edi, gpBuffer add edi, SCREENXY(0, 0) mov ebx, pLightTbl add ebx, idx mov edx, PANEL_TOP l4_label1: mov ecx, SCREEN_WIDTH l4_label2: mov al, [edi] cmp al, 32 jb l4_label3 xlat l4_label3: stosb loop l4_label2 add edi, BUFFER_WIDTH - SCREEN_WIDTH dec edx jnz l4_label1 } } #else int w, h; BYTE *dst, *tbl; if (leveltype != DTYPE_HELL) { dst = &gpBuffer[SCREENXY(0, 0)]; tbl = &pLightTbl[idx]; for (h = VIEWPORT_HEIGHT; h; h--, dst += BUFFER_WIDTH - SCREEN_WIDTH) { for (w = SCREEN_WIDTH; w; w--) { *dst = tbl[*dst]; dst++; } } } else { dst = &gpBuffer[SCREENXY(0, 0)]; tbl = &pLightTbl[idx]; for (h = VIEWPORT_HEIGHT; h; h--, dst += BUFFER_WIDTH - SCREEN_WIDTH) { for (w = SCREEN_WIDTH; w; w--) { if (*dst >= 32) *dst = tbl[*dst]; dst++; } } } #endif } static void PrintSBookStr(int x, int y, BOOL cjustflag, const char *pszStr, char col) { BYTE c; const char *tmp; int screen_x, line, width; width = PitchTbl[y] + x + RIGHT_PANEL_X + SPLICONLENGTH; line = 0; if (cjustflag) { screen_x = 0; tmp = pszStr; while (*tmp) { c = gbFontTransTbl[(BYTE)*tmp++]; screen_x += fontkern[fontframe[c]] + 1; } if (screen_x < 222) line = (222 - screen_x) >> 1; width += line; } while (*pszStr) { c = gbFontTransTbl[(BYTE)*pszStr++]; c = fontframe[c]; line += fontkern[c] + 1; if (c) { if (line <= 222) PrintChar(width, c, col); } width += fontkern[c] + 1; } } char GetSBookTrans(int ii, BOOL townok) { char st; #ifdef HELLFIRE if ((plr[myplr]._pClass == PC_MONK) && (ii == SPL_SEARCH)) return RSPLTYPE_SKILL; #endif st = RSPLTYPE_SPELL; if (plr[myplr]._pISpells & SPELLBIT(ii)) { st = RSPLTYPE_CHARGES; } #ifdef HELLFIRE if (plr[myplr]._pAblSpells & SPELLBIT(ii)) { #else if (plr[myplr]._pAblSpells & 1 << (ii - 1)) { /// BUGFIX: missing (__int64) - use SPELLBIT(ii) macro #endif st = RSPLTYPE_SKILL; } if (st == RSPLTYPE_SPELL) { if (!CheckSpell(myplr, ii, RSPLTYPE_SPELL, TRUE)) { st = RSPLTYPE_INVALID; } if ((char)(plr[myplr]._pSplLvl[ii] + plr[myplr]._pISplLvlAdd) <= 0) { st = RSPLTYPE_INVALID; } } if (townok && currlevel == 0 && st != RSPLTYPE_INVALID && !spelldata[ii].sTownSpell) { st = RSPLTYPE_INVALID; } return st; } void DrawSpellBook() { int i, sn, mana, lvl, yp, min, max; char st; unsigned __int64 spl; CelDraw(RIGHT_PANEL_X, 351 + SCREEN_Y, pSpellBkCel, 1, 320); #ifdef HELLFIRE if (sbooktab < 5) CelDraw(RIGHT_PANEL_X + 61 * sbooktab + 7, 348 + SCREEN_Y, pSBkBtnCel, sbooktab + 1, 61); #else // BUGFIX: rendering of page 3 and page 4 buttons are both off-by-one pixel. // The fix would look as follows: // // int sx = RIGHT_PANEL_X + 76 * sbooktab + 7; // if (sbooktab == 2 || sbooktab == 3) { // sx++; // } // CelDraw(sx, 348 + SCREEN_Y, pSBkBtnCel, sbooktab + 1, 76); CelDraw(RIGHT_PANEL_X + 76 * sbooktab + 7, 348 + SCREEN_Y, pSBkBtnCel, sbooktab + 1, 76); #endif spl = plr[myplr]._pMemSpells | plr[myplr]._pISpells | plr[myplr]._pAblSpells; yp = 55 + SCREEN_Y; for (i = 1; i < 8; i++) { sn = SpellPages[sbooktab][i - 1]; if (sn != -1 && spl & SPELLBIT(sn)) { st = GetSBookTrans(sn, TRUE); SetSpellTrans(st); DrawSpellCel(RIGHT_PANEL_X + 11, yp, pSBkIconCels, SpellITbl[sn], 37); if (sn == plr[myplr]._pRSpell && st == plr[myplr]._pRSplType) { SetSpellTrans(RSPLTYPE_SKILL); DrawSpellCel(RIGHT_PANEL_X + 11, yp, pSBkIconCels, SPLICONLAST, 37); } PrintSBookStr(10, yp - 23, FALSE, spelldata[sn].sNameText, COL_WHITE); switch (GetSBookTrans(sn, FALSE)) { case RSPLTYPE_SKILL: strcpy(tempstr, "Skill"); break; case RSPLTYPE_CHARGES: sprintf(tempstr, "Staff (%i charges)", plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges); break; default: mana = GetManaAmount(myplr, sn) >> 6; GetDamageAmt(sn, &min, &max); if (min != -1) { sprintf(tempstr, "Mana: %i Dam: %i - %i", mana, min, max); } else { sprintf(tempstr, "Mana: %i Dam: n/a", mana); } if (sn == SPL_BONESPIRIT) { sprintf(tempstr, "Mana: %i Dam: 1/3 tgt hp", mana); } PrintSBookStr(10, yp - 1, FALSE, tempstr, COL_WHITE); lvl = plr[myplr]._pSplLvl[sn] + plr[myplr]._pISplLvlAdd; if (lvl < 0) { lvl = 0; } if (lvl == 0) { sprintf(tempstr, "Spell Level 0 - Unusable"); } else { sprintf(tempstr, "Spell Level %i", lvl); } break; } PrintSBookStr(10, yp - 12, FALSE, tempstr, COL_WHITE); } yp += 43; } } void CheckSBook() { int sn; char st; unsigned __int64 spl; if (MouseX >= RIGHT_PANEL + 11 && MouseX < RIGHT_PANEL + 48 && MouseY >= 18 && MouseY < 314) { sn = SpellPages[sbooktab][(MouseY - 18) / 43]; spl = plr[myplr]._pMemSpells | plr[myplr]._pISpells | plr[myplr]._pAblSpells; if (sn != -1 && spl & SPELLBIT(sn)) { st = RSPLTYPE_SPELL; if (plr[myplr]._pISpells & SPELLBIT(sn)) { st = RSPLTYPE_CHARGES; } if (plr[myplr]._pAblSpells & SPELLBIT(sn)) { st = RSPLTYPE_SKILL; } plr[myplr]._pRSpell = sn; plr[myplr]._pRSplType = st; force_redraw = 255; } } #ifdef HELLFIRE if (MouseX >= RIGHT_PANEL + 7 && MouseX < RIGHT_PANEL + 312 && MouseY >= 320 && MouseY < 349) { sbooktab = (MouseX - (RIGHT_PANEL + 7)) / 61; } #else if (MouseX >= RIGHT_PANEL + 7 && MouseX < RIGHT_PANEL + 313 && MouseY >= 320 && MouseY < 349) { /// BUGFIX: change `< 313` to `< 311` sbooktab = (MouseX - (RIGHT_PANEL + 7)) / 76; } #endif } const char *get_pieces_str(int nGold) { const char *result; result = "piece"; if (nGold != 1) result = "pieces"; return result; } void DrawGoldSplit(int amount) { int screen_x, i; screen_x = 0; CelDraw(351 + SCREEN_X, 178 + SCREEN_Y, pGBoxBuff, 1, 261); sprintf(tempstr, "You have %u gold", initialDropGoldValue); ADD_PlrStringXY(366, 87, 600, tempstr, COL_GOLD); sprintf(tempstr, "%s. How many do", get_pieces_str(initialDropGoldValue)); ADD_PlrStringXY(366, 103, 600, tempstr, COL_GOLD); ADD_PlrStringXY(366, 121, 600, "you want to remove?", COL_GOLD); if (amount > 0) { sprintf(tempstr, "%u", amount); PrintGameStr(388, 140, tempstr, COL_WHITE); } if (amount > 0) { // BUGFIX: loop condition should be `tempstr[i] != 0`, not `i < tempstr[i]`. for (i = 0; i < tempstr[i]; i++) { BYTE c = fontframe[gbFontTransTbl[(BYTE)tempstr[i]]]; screen_x += fontkern[c] + 1; } screen_x += 452; } else { screen_x = 450; } CelDraw(screen_x, 140 + SCREEN_Y, pSPentSpn2Cels, nGoldFrame, 12); nGoldFrame = (nGoldFrame & 7) + 1; } void control_drop_gold(char vkey) { char input[6]; if (plr[myplr]._pHitPoints >> 6 <= 0) { dropGoldFlag = FALSE; dropGoldValue = 0; return; } memset(input, 0, sizeof(input)); _itoa(dropGoldValue, input, 10); if (vkey == VK_RETURN) { if (dropGoldValue > 0) control_remove_gold(myplr, initialDropGoldIndex); dropGoldFlag = FALSE; } else if (vkey == VK_ESCAPE) { dropGoldFlag = FALSE; dropGoldValue = 0; } else if (vkey == VK_BACK) { input[strlen(input) - 1] = '\0'; dropGoldValue = atoi(input); } else if (vkey - '0' >= 0 && vkey - '0' <= 9) { if (dropGoldValue != 0 || atoi(input) <= initialDropGoldValue) { input[strlen(input)] = vkey; if (atoi(input) > initialDropGoldValue) return; if (strlen(input) > strlen(input)) return; } else { input[0] = vkey; } dropGoldValue = atoi(input); } } void control_remove_gold(int pnum, int gold_index) { int gi; if (gold_index <= INVITEM_INV_LAST) { gi = gold_index - INVITEM_INV_FIRST; plr[pnum].InvList[gi]._ivalue -= dropGoldValue; if (plr[pnum].InvList[gi]._ivalue > 0) SetGoldCurs(pnum, gi); else RemoveInvItem(pnum, gi); } else { gi = gold_index - INVITEM_BELT_FIRST; plr[pnum].SpdList[gi]._ivalue -= dropGoldValue; if (plr[pnum].SpdList[gi]._ivalue > 0) SetSpdbarGoldCurs(pnum, gi); else RemoveSpdBarItem(pnum, gi); } SetPlrHandItem(&plr[pnum].HoldItem, IDI_GOLD); GetGoldSeed(pnum, &plr[pnum].HoldItem); plr[pnum].HoldItem._ivalue = dropGoldValue; plr[pnum].HoldItem._iStatFlag = TRUE; control_set_gold_curs(pnum); plr[pnum]._pGold = CalculateGold(pnum); dropGoldValue = 0; } void control_set_gold_curs(int pnum) { if (plr[pnum].HoldItem._ivalue >= GOLD_MEDIUM_LIMIT) plr[pnum].HoldItem._iCurs = ICURS_GOLD_LARGE; else if (plr[pnum].HoldItem._ivalue <= GOLD_SMALL_LIMIT) plr[pnum].HoldItem._iCurs = ICURS_GOLD_SMALL; else plr[pnum].HoldItem._iCurs = ICURS_GOLD_MEDIUM; NewCursor(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM); } static char *control_print_talk_msg(char *msg, int x, int y, int *nOffset, int color) { BYTE c; int width; x += 200 + SCREEN_X; y += 22 + PANEL_Y; width = x; *nOffset = PitchTbl[y] + x; while (*msg) { c = gbFontTransTbl[(BYTE)*msg]; c = fontframe[c]; width += fontkern[c] + 1; if (width > 450 + PANEL_X) return msg; msg++; if (c != 0) { PrintChar(*nOffset, c, color); } *nOffset += fontkern[c] + 1; } return NULL; } void DrawTalkPan() { int i, off, talk_btn, color, nCel, x; char *msg; if (!talkflag) return; DrawPanelBox(175, sgbPlrTalkTbl + 20, 294, 5, PANEL_X + 175, PANEL_Y + 4); off = 0; for (i = 293; i > 283; off++, i--) { DrawPanelBox((off >> 1) + 175, sgbPlrTalkTbl + off + 25, i, 1, (off >> 1) + PANEL_X + 175, off + PANEL_Y + 9); } DrawPanelBox(185, sgbPlrTalkTbl + 35, 274, 30, PANEL_X + 185, PANEL_Y + 19); DrawPanelBox(180, sgbPlrTalkTbl + 65, 284, 5, PANEL_X + 180, PANEL_Y + 49); for (i = 0; i < 10; i++) { DrawPanelBox(180, sgbPlrTalkTbl + i + 70, i + 284, 1, PANEL_X + 180, i + PANEL_Y + 54); } DrawPanelBox(170, sgbPlrTalkTbl + 80, 310, 55, PANEL_X + 170, PANEL_Y + 64); msg = sgszTalkMsg; for (i = 0; i < 39; i += 13) { msg = control_print_talk_msg(msg, 0 + PANEL_LEFT, i, &x, 0); if (!msg) break; } if (msg) *msg = '\0'; CelBlitFrame(gpBuffer + x, pSPentSpn2Cels, frame, 12); frame = (frame & 7) + 1; talk_btn = 0; for (i = 0; i < MAX_PLRS; i++) { if (i == myplr) continue; if (whisper[i]) { color = COL_GOLD; if (talkbtndown[talk_btn]) { if (talk_btn != 0) nCel = 4; else nCel = 3; CelDraw(172 + PANEL_X, 84 + 18 * talk_btn + PANEL_Y, pTalkBtns, nCel, 61); } } else { color = COL_RED; if (talk_btn != 0) nCel = 2; else nCel = 1; if (talkbtndown[talk_btn]) nCel += 4; CelDraw(172 + PANEL_X, 84 + 18 * talk_btn + PANEL_Y, pTalkBtns, nCel, 61); } if (plr[i].plractive) { control_print_talk_msg(plr[i]._pName, 46 + PANEL_LEFT, 60 + talk_btn * 18, &x, color); } talk_btn++; } } BOOL control_check_talk_btn() { int i; if (!talkflag) return FALSE; if (MouseX < 172 + PANEL_LEFT) return FALSE; if (MouseY < 69 + PANEL_TOP) return FALSE; if (MouseX > 233 + PANEL_LEFT) return FALSE; if (MouseY > 123 + PANEL_TOP) return FALSE; for (i = 0; i < sizeof(talkbtndown) / sizeof(talkbtndown[0]); i++) { talkbtndown[i] = FALSE; } talkbtndown[(MouseY - (69 + PANEL_TOP)) / 18] = TRUE; return TRUE; } void control_release_talk_btn() { int i, p, off; if (talkflag) { for (i = 0; i < sizeof(talkbtndown) / sizeof(talkbtndown[0]); i++) talkbtndown[i] = FALSE; if (MouseX >= 172 + PANEL_LEFT && MouseY >= 69 + PANEL_TOP && MouseX <= 233 + PANEL_LEFT && MouseY <= 123 + PANEL_TOP) { off = (MouseY - (69 + PANEL_TOP)) / 18; for (p = 0; p < MAX_PLRS && off != -1; p++) { if (p != myplr) off--; } if (p <= MAX_PLRS) whisper[p - 1] = !whisper[p - 1]; } } } #ifndef HELLFIRE void control_reset_talk_msg(char *msg) { int i, pmask; pmask = 0; for (i = 0; i < MAX_PLRS; i++) { if (whisper[i]) pmask |= 1 << i; } if (!msgcmd_add_server_cmd_W(sgszTalkMsg)) NetSendCmdString(pmask, sgszTalkMsg); } #endif void control_type_message() { int i; if (gbMaxPlayers == 1) { return; } talkflag = TRUE; sgszTalkMsg[0] = '\0'; frame = 1; for (i = 0; i < 3; i++) { talkbtndown[i] = FALSE; } sgbPlrTalkTbl = PANEL_HEIGHT + 16; force_redraw = 255; sgbTalkSavePos = sgbNextTalkSave; } void control_reset_talk() { talkflag = FALSE; sgbPlrTalkTbl = 0; force_redraw = 255; } static void control_press_enter() { int i; BYTE talk_save; if (sgszTalkMsg[0] != 0) { #ifdef HELLFIRE int pmask; pmask = 0; for (i = 0; i < MAX_PLRS; i++) { if (whisper[i]) pmask |= 1 << i; } NetSendCmdString(pmask, sgszTalkMsg); #else control_reset_talk_msg(sgszTalkMsg); #endif for (i = 0; i < 8; i++) { if (!strcmp(sgszTalkSave[i], sgszTalkMsg)) break; } if (i >= 8) { strcpy(sgszTalkSave[sgbNextTalkSave], sgszTalkMsg); sgbNextTalkSave++; sgbNextTalkSave &= 7; } else { talk_save = sgbNextTalkSave - 1; talk_save &= 7; if (i != talk_save) { strcpy(sgszTalkSave[i], sgszTalkSave[talk_save]); strcpy(sgszTalkSave[talk_save], sgszTalkMsg); } } sgszTalkMsg[0] = '\0'; sgbTalkSavePos = sgbNextTalkSave; } control_reset_talk(); } BOOL control_talk_last_key(int vkey) { int result; if (gbMaxPlayers == 1) return FALSE; if (!talkflag) return FALSE; if ((DWORD)vkey < VK_SPACE) return FALSE; result = strlen(sgszTalkMsg); if (result < 78) { sgszTalkMsg[result] = vkey; sgszTalkMsg[result + 1] = '\0'; } return TRUE; } static void control_up_down(int v) { int i; for (i = 0; i < 8; i++) { sgbTalkSavePos = (v + sgbTalkSavePos) & 7; if (sgszTalkSave[sgbTalkSavePos][0]) { strcpy(sgszTalkMsg, sgszTalkSave[sgbTalkSavePos]); return; } } } BOOL control_presskeys(int vkey) { int len; BOOL ret; if (gbMaxPlayers != 1) { if (!talkflag) { ret = FALSE; } else { if (vkey == VK_SPACE) { } else if (vkey == VK_ESCAPE) { control_reset_talk(); } else if (vkey == VK_RETURN) { control_press_enter(); } else if (vkey == VK_BACK) { len = strlen(sgszTalkMsg); if (len > 0) sgszTalkMsg[len - 1] = '\0'; } else if (vkey == VK_DOWN) { control_up_down(1); } else if (vkey == VK_UP) { control_up_down(-1); } else { return FALSE; } ret = TRUE; } } else { ret = FALSE; } return ret; } ================================================ FILE: Source/control.h ================================================ /** * @file control.h * * Interface of the character and main control panels */ #ifndef __CONTROL_H__ #define __CONTROL_H__ extern BOOL drawhpflag; extern BOOL dropGoldFlag; extern BOOL panbtn[8]; extern BOOL chrbtn[4]; extern BOOL lvlbtndown; extern int dropGoldValue; extern BOOL drawmanaflag; extern BOOL chrbtnactive; extern BOOL pinfoflag; extern int pSpell; extern char infoclr; extern char tempstr[256]; extern BOOLEAN whisper[MAX_PLRS]; extern int pSplType; extern int frame; extern int initialDropGoldIndex; extern BOOL talkflag; extern BOOL sbookflag; extern BOOL chrflag; extern BOOL drawbtnflag; extern char infostr[256]; extern char panelstr[4][64]; extern BOOL panelflag; extern int initialDropGoldValue; extern BOOL panbtndown; extern BOOL spselflag; void DrawSpellList(); void SetSpell(); void SetSpeedSpell(int slot); void ToggleSpell(int slot); void PrintChar(int nOffset, int nCel, char col); void AddPanelString(const char *str, BOOL just); void ClearPanel(); void DrawPanelBox(int x, int y, int w, int h, int sx, int sy); void DrawLifeFlask(); void UpdateLifeFlask(); void DrawManaFlask(); void control_update_life_mana(); void UpdateManaFlask(); void InitControlPan(); void DrawCtrlPan(); void DrawCtrlBtns(); void DoSpeedBook(); void DoPanBtn(); void control_check_btn_press(); void DoAutoMap(); void CheckPanelInfo(); void CheckBtnUp(); void FreeControlPan(); BOOL control_WriteStringToBuffer(BYTE *str); void DrawInfoBox(); void PrintGameStr(int x, int y, const char *str, int color); void DrawChr(); void CheckLvlBtn(); void ReleaseLvlBtn(); void DrawLevelUpIcon(); void CheckChrBtns(); void ReleaseChrBtns(); void DrawDurIcon(); void RedBack(); void DrawSpellBook(); void CheckSBook(); const char *get_pieces_str(int nGold); void DrawGoldSplit(int amount); void control_drop_gold(char vkey); void control_remove_gold(int pnum, int gold_index); void control_set_gold_curs(int pnum); void DrawTalkPan(); BOOL control_check_talk_btn(); void control_release_talk_btn(); void control_type_message(); void control_reset_talk(); BOOL control_talk_last_key(int vkey); BOOL control_presskeys(int vkey); /* rdata */ extern const BYTE fontframe[128]; extern const BYTE fontkern[68]; extern const BYTE gbFontTransTbl[256]; #endif /* __CONTROL_H__ */ ================================================ FILE: Source/cursor.cpp ================================================ /** * @file cursor.cpp * * Implementation of cursor tracking functionality. */ #include "all.h" /** Pixel width of the current cursor image */ int cursW; /** Pixel height of the current cursor image */ int cursH; /** Current highlighted monster */ int pcursmonst; /** Width of current cursor in inventory cells */ int icursW28; /** Height of current cursor in inventory cells */ int icursH28; /** Cursor images CEL */ BYTE *pCursCels; #ifdef HELLFIRE BYTE *pCursCels2; #endif /** inv_item value */ char pcursinvitem; /** Pixel width of the current cursor image */ int icursW; /** Pixel height of the current cursor image */ int icursH; /** Current highlighted item */ char pcursitem; /** Current highlighted object */ char pcursobj; /** Current highlighted player */ char pcursplr; /** Current highlighted tile row */ int cursmx; /** Current highlighted tile column */ int cursmy; /** Previously highlighted monster */ int pcurstemp; /** Index of current cursor image */ int pcurs; /* rdata */ /** Maps from objcurs.cel frame number to frame width. */ const int InvItemWidth[] = { // clang-format off // Cursors 0, 33, 32, 32, 32, 32, 32, 32, 32, 32, 32, 23, // Items 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, #ifdef HELLFIRE 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 2 * 28, 2 * 28, 1 * 28, 1 * 28, 1 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28 #endif // clang-format on }; /** Maps from objcurs.cel frame number to frame height. */ const int InvItemHeight[] = { // clang-format off // Cursors 0, 29, 32, 32, 32, 32, 32, 32, 32, 32, 32, 35, // Items 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, #ifdef HELLFIRE 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 2 * 28, 2 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28 #endif // clang-format on }; void InitCursor() { assert(!pCursCels); pCursCels = LoadFileInMem("Data\\Inv\\Objcurs.CEL", NULL); #ifdef HELLFIRE pCursCels2 = LoadFileInMem("Data\\Inv\\Objcurs2.CEL", NULL); #endif ClearCursor(); } void FreeCursor() { MemFreeDbg(pCursCels); #ifdef HELLFIRE MemFreeDbg(pCursCels2); #endif ClearCursor(); } void SetICursor(int i) { icursW = InvItemWidth[i]; icursH = InvItemHeight[i]; icursW28 = icursW / 28; icursH28 = icursH / 28; } void SetCursor_(int i) { pcurs = i; cursW = InvItemWidth[i]; cursH = InvItemHeight[i]; SetICursor(i); } void NewCursor(int i) { SetCursor_(i); } void InitLevelCursor() { SetCursor_(CURSOR_HAND); cursmx = ViewX; cursmy = ViewY; pcurstemp = -1; pcursmonst = -1; pcursobj = -1; pcursitem = -1; pcursplr = -1; ClearCursor(); } void CheckTown() { int i, mx; for (i = 0; i < nummissiles; i++) { mx = missileactive[i]; if (missile[mx]._mitype == MIS_TOWN) { if (cursmx == missile[mx]._mix - 1 && cursmy == missile[mx]._miy || cursmx == missile[mx]._mix && cursmy == missile[mx]._miy - 1 || cursmx == missile[mx]._mix - 1 && cursmy == missile[mx]._miy - 1 || cursmx == missile[mx]._mix - 2 && cursmy == missile[mx]._miy - 1 || cursmx == missile[mx]._mix - 2 && cursmy == missile[mx]._miy - 2 || cursmx == missile[mx]._mix - 1 && cursmy == missile[mx]._miy - 2 || cursmx == missile[mx]._mix && cursmy == missile[mx]._miy) { trigflag = TRUE; ClearPanel(); strcpy(infostr, "Town Portal"); sprintf(tempstr, "from %s", plr[missile[mx]._misource]._pName); AddPanelString(tempstr, TRUE); cursmx = missile[mx]._mix; cursmy = missile[mx]._miy; } } } } void CheckRportal() { int i, mx; for (i = 0; i < nummissiles; i++) { mx = missileactive[i]; if (missile[mx]._mitype == MIS_RPORTAL) { if (cursmx == missile[mx]._mix - 1 && cursmy == missile[mx]._miy || cursmx == missile[mx]._mix && cursmy == missile[mx]._miy - 1 || cursmx == missile[mx]._mix - 1 && cursmy == missile[mx]._miy - 1 || cursmx == missile[mx]._mix - 2 && cursmy == missile[mx]._miy - 1 || cursmx == missile[mx]._mix - 2 && cursmy == missile[mx]._miy - 2 || cursmx == missile[mx]._mix - 1 && cursmy == missile[mx]._miy - 2 || cursmx == missile[mx]._mix && cursmy == missile[mx]._miy) { trigflag = TRUE; ClearPanel(); strcpy(infostr, "Portal to"); if (!setlevel) strcpy(tempstr, "The Unholy Altar"); else strcpy(tempstr, "level 15"); AddPanelString(tempstr, TRUE); cursmx = missile[mx]._mix; cursmy = missile[mx]._miy; } } } } void CheckCursMove() { int i, sx, sy, fx, fy, mx, my, tx, ty, px, py, xx, yy, mi; char bv; BOOL flipflag, flipx, flipy; sx = MouseX; sy = MouseY; if (chrflag || questlog) { if (sx >= SCREEN_WIDTH / 4) { /// BUGFIX: (sx >= SCREEN_WIDTH / 2) sx -= SCREEN_WIDTH / 4; } else { sx = 0; } } else if (invflag || sbookflag) { if (sx <= SCREEN_WIDTH / 2) { sx += SCREEN_WIDTH / 4; } else { sx = 0; } } if (sy > PANEL_TOP - 1 && track_isscrolling()) { sy = PANEL_TOP - 1; } if (!zoomflag) { sx >>= 1; sy >>= 1; } // Adjust by player offset sx -= ScrollInfo._sxoff; sy -= ScrollInfo._syoff; // Predict the next frame when walking to avoid input jitter fx = plr[myplr]._pVar6 >> 8; fy = plr[myplr]._pVar7 >> 8; fx -= (plr[myplr]._pVar6 + plr[myplr]._pxvel) >> 8; fy -= (plr[myplr]._pVar7 + plr[myplr]._pyvel) >> 8; if (ScrollInfo._sdir != SDIR_NONE) { sx -= fx; sy -= fy; } if (sx < 0) { sx = 0; } if (sx >= SCREEN_WIDTH) { sx = SCREEN_WIDTH; } if (sy < 0) { sy = 0; } if (sy >= SCREEN_HEIGHT) { sy = SCREEN_HEIGHT; } // Convert to tile grid tx = sx >> 6; // sx / TILE_WIDTH ty = sy >> 5; // sy / TILE_HEIGHT px = sx & (TILE_WIDTH - 1); py = sy & (TILE_HEIGHT - 1); // Center player tile on screen mx = ViewX + tx + ty - (zoomflag ? (SCREEN_WIDTH / TILE_WIDTH) : (SCREEN_WIDTH / 2 / TILE_WIDTH)); my = ViewY + ty - tx; // Shift position to match diamond grid aligment flipy = py < (px >> 1); if (flipy) { my--; } flipx = py >= TILE_HEIGHT - (px >> 1); if (flipx) { mx++; } if (mx < 0) { mx = 0; } if (mx >= MAXDUNX) { mx = MAXDUNX - 1; } if (my < 0) { my = 0; } if (my >= MAXDUNY) { my = MAXDUNY - 1; } flipflag = flipy && flipx || (flipy || flipx) && px < TILE_WIDTH / 2; pcurstemp = pcursmonst; pcursmonst = -1; pcursobj = -1; pcursitem = -1; if (pcursinvitem != -1) { drawsbarflag = TRUE; } pcursinvitem = -1; pcursplr = -1; uitemflag = FALSE; panelflag = FALSE; trigflag = FALSE; if (plr[myplr]._pInvincible) { return; } if (pcurs >= CURSOR_FIRSTITEM || spselflag) { cursmx = mx; cursmy = my; return; } if (MouseY > PANEL_TOP) { CheckPanelInfo(); return; } if (doomflag) { return; } if (invflag && MouseX > RIGHT_PANEL) { pcursinvitem = CheckInvHLight(); return; } if (sbookflag && MouseX > RIGHT_PANEL) { return; } if ((chrflag || questlog) && MouseX < SPANEL_WIDTH) { return; } if (leveltype != DTYPE_TOWN) { if (pcurstemp != -1) { if (!flipflag && dMonster[mx + 2][my + 1] != 0 && dFlags[mx + 2][my + 1] & BFLAG_LIT) { mi = dMonster[mx + 2][my + 1] > 0 ? dMonster[mx + 2][my + 1] - 1 : -(dMonster[mx + 2][my + 1] + 1); if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) { cursmx = mx + 1; /// BUGFIX: 'mx + 2' cursmy = my + 2; /// BUGFIX: 'my + 1' pcursmonst = mi; } } if (flipflag && dMonster[mx + 1][my + 2] != 0 && dFlags[mx + 1][my + 2] & BFLAG_LIT) { mi = dMonster[mx + 1][my + 2] > 0 ? dMonster[mx + 1][my + 2] - 1 : -(dMonster[mx + 1][my + 2] + 1); if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) { cursmx = mx + 1; cursmy = my + 2; pcursmonst = mi; } } if (dMonster[mx + 2][my + 2] != 0 && dFlags[mx + 2][my + 2] & BFLAG_LIT) { mi = dMonster[mx + 2][my + 2] > 0 ? dMonster[mx + 2][my + 2] - 1 : -(dMonster[mx + 2][my + 2] + 1); if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) { cursmx = mx + 2; cursmy = my + 2; pcursmonst = mi; } } if (!flipflag && dMonster[mx + 1][my] != 0 && dFlags[mx + 1][my] & BFLAG_LIT) { mi = dMonster[mx + 1][my] > 0 ? dMonster[mx + 1][my] - 1 : -(dMonster[mx + 1][my] + 1); if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) { cursmx = mx + 1; cursmy = my; pcursmonst = mi; } } if (flipflag && dMonster[mx][my + 1] != 0 && dFlags[mx][my + 1] & BFLAG_LIT) { mi = dMonster[mx][my + 1] > 0 ? dMonster[mx][my + 1] - 1 : -(dMonster[mx][my + 1] + 1); if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) { cursmx = mx; cursmy = my + 1; pcursmonst = mi; } } if (dMonster[mx][my] != 0 && dFlags[mx][my] & BFLAG_LIT) { mi = dMonster[mx][my] > 0 ? dMonster[mx][my] - 1 : -(dMonster[mx][my] + 1); if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 1) { cursmx = mx; cursmy = my; pcursmonst = mi; } } if (dMonster[mx + 1][my + 1] != 0 && dFlags[mx + 1][my + 1] & BFLAG_LIT) { mi = dMonster[mx + 1][my + 1] > 0 ? dMonster[mx + 1][my + 1] - 1 : -(dMonster[mx + 1][my + 1] + 1); if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) { cursmx = mx + 1; cursmy = my + 1; pcursmonst = mi; } } if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_HIDDEN) { pcursmonst = -1; cursmx = mx; cursmy = my; } #ifdef HELLFIRE if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_GOLEM && !(monster[pcursmonst]._mFlags & MFLAG_BERSERK)) { pcursmonst = -1; } #else if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_GOLEM) { pcursmonst = -1; } #endif if (pcursmonst != -1) { return; } } if (!flipflag && dMonster[mx + 2][my + 1] != 0 && dFlags[mx + 2][my + 1] & BFLAG_LIT) { mi = dMonster[mx + 2][my + 1] > 0 ? dMonster[mx + 2][my + 1] - 1 : -(dMonster[mx + 2][my + 1] + 1); if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) { cursmx = mx + 2; cursmy = my + 1; pcursmonst = mi; } } if (flipflag && dMonster[mx + 1][my + 2] != 0 && dFlags[mx + 1][my + 2] & BFLAG_LIT) { mi = dMonster[mx + 1][my + 2] > 0 ? dMonster[mx + 1][my + 2] - 1 : -(dMonster[mx + 1][my + 2] + 1); if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) { cursmx = mx + 1; cursmy = my + 2; pcursmonst = mi; } } if (dMonster[mx + 2][my + 2] != 0 && dFlags[mx + 2][my + 2] & BFLAG_LIT) { mi = dMonster[mx + 2][my + 2] > 0 ? dMonster[mx + 2][my + 2] - 1 : -(dMonster[mx + 2][my + 2] + 1); if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) { cursmx = mx + 2; cursmy = my + 2; pcursmonst = mi; } } if (!flipflag && dMonster[mx + 1][my] != 0 && dFlags[mx + 1][my] & BFLAG_LIT) { mi = dMonster[mx + 1][my] > 0 ? dMonster[mx + 1][my] - 1 : -(dMonster[mx + 1][my] + 1); if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) { cursmx = mx + 1; cursmy = my; pcursmonst = mi; } } if (flipflag && dMonster[mx][my + 1] != 0 && dFlags[mx][my + 1] & BFLAG_LIT) { mi = dMonster[mx][my + 1] > 0 ? dMonster[mx][my + 1] - 1 : -(dMonster[mx][my + 1] + 1); if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) { cursmx = mx; cursmy = my + 1; pcursmonst = mi; } } if (dMonster[mx][my] != 0 && dFlags[mx][my] & BFLAG_LIT) { mi = dMonster[mx][my] > 0 ? dMonster[mx][my] - 1 : -(dMonster[mx][my] + 1); if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 1) { cursmx = mx; cursmy = my; pcursmonst = mi; } } if (dMonster[mx + 1][my + 1] != 0 && dFlags[mx + 1][my + 1] & BFLAG_LIT) { mi = dMonster[mx + 1][my + 1] > 0 ? dMonster[mx + 1][my + 1] - 1 : -(dMonster[mx + 1][my + 1] + 1); if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) { cursmx = mx + 1; cursmy = my + 1; pcursmonst = mi; } } if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_HIDDEN) { pcursmonst = -1; cursmx = mx; cursmy = my; } #ifdef HELLFIRE if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_GOLEM && !(monster[pcursmonst]._mFlags & MFLAG_BERSERK)) { pcursmonst = -1; } #else if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_GOLEM) { pcursmonst = -1; } #endif } else { if (!flipflag && dMonster[mx + 1][my] > 0) { pcursmonst = dMonster[mx + 1][my] - 1; cursmx = mx + 1; cursmy = my; } if (flipflag && dMonster[mx][my + 1] > 0) { pcursmonst = dMonster[mx][my + 1] - 1; cursmx = mx; cursmy = my + 1; } if (dMonster[mx][my] > 0) { pcursmonst = dMonster[mx][my] - 1; cursmx = mx; cursmy = my; } if (dMonster[mx + 1][my + 1] > 0) { pcursmonst = dMonster[mx + 1][my + 1] - 1; cursmx = mx + 1; cursmy = my + 1; } if (!towner[pcursmonst]._tSelFlag) { /// BUGFIX: Add check 'pcursmonst != -1' pcursmonst = -1; } } if (pcursmonst == -1) { if (!flipflag && dPlayer[mx + 1][my] != 0) { bv = dPlayer[mx + 1][my] > 0 ? dPlayer[mx + 1][my] - 1 : -(dPlayer[mx + 1][my] + 1); if (bv != myplr && plr[bv]._pHitPoints != 0) { cursmx = mx + 1; cursmy = my; pcursplr = bv; } } if (flipflag && dPlayer[mx][my + 1] != 0) { bv = dPlayer[mx][my + 1] > 0 ? dPlayer[mx][my + 1] - 1 : -(dPlayer[mx][my + 1] + 1); if (bv != myplr && plr[bv]._pHitPoints != 0) { cursmx = mx; cursmy = my + 1; pcursplr = bv; } } if (dPlayer[mx][my] != 0) { bv = dPlayer[mx][my] > 0 ? dPlayer[mx][my] - 1 : -(dPlayer[mx][my] + 1); if (bv != myplr) { cursmx = mx; cursmy = my; pcursplr = bv; } } if (dFlags[mx][my] & BFLAG_DEAD_PLAYER) { for (i = 0; i < MAX_PLRS; i++) { if (plr[i]._px == mx && plr[i]._py == my && i != myplr) { cursmx = mx; cursmy = my; pcursplr = i; } } } if (pcurs == CURSOR_RESURRECT) { for (xx = -1; xx < 2; xx++) { for (yy = -1; yy < 2; yy++) { if (dFlags[mx + xx][my + yy] & BFLAG_DEAD_PLAYER) { for (i = 0; i < MAX_PLRS; i++) { if (plr[i]._px == mx + xx && plr[i]._py == my + yy && i != myplr) { cursmx = mx + xx; cursmy = my + yy; pcursplr = i; } } } } } } if (dPlayer[mx + 1][my + 1] != 0) { bv = dPlayer[mx + 1][my + 1] > 0 ? dPlayer[mx + 1][my + 1] - 1 : -(dPlayer[mx + 1][my + 1] + 1); if (bv != myplr && plr[bv]._pHitPoints != 0) { cursmx = mx + 1; cursmy = my + 1; pcursplr = bv; } } } if (pcursmonst == -1 && pcursplr == -1) { if (!flipflag && dObject[mx + 1][my] != 0) { bv = dObject[mx + 1][my] > 0 ? dObject[mx + 1][my] - 1 : -(dObject[mx + 1][my] + 1); if (object[bv]._oSelFlag >= 2) { cursmx = mx + 1; cursmy = my; pcursobj = bv; } } if (flipflag && dObject[mx][my + 1] != 0) { bv = dObject[mx][my + 1] > 0 ? dObject[mx][my + 1] - 1 : -(dObject[mx][my + 1] + 1); if (object[bv]._oSelFlag >= 2) { cursmx = mx; cursmy = my + 1; pcursobj = bv; } } if (dObject[mx][my] != 0) { bv = dObject[mx][my] > 0 ? dObject[mx][my] - 1 : -(dObject[mx][my] + 1); if (object[bv]._oSelFlag == 1 || object[bv]._oSelFlag == 3) { cursmx = mx; cursmy = my; pcursobj = bv; } } if (dObject[mx + 1][my + 1] != 0) { bv = dObject[mx + 1][my + 1] > 0 ? dObject[mx + 1][my + 1] - 1 : -(dObject[mx + 1][my + 1] + 1); if (object[bv]._oSelFlag >= 2) { cursmx = mx + 1; cursmy = my + 1; pcursobj = bv; } } } if (pcursplr == -1 && pcursobj == -1 && pcursmonst == -1) { if (!flipflag && dItem[mx + 1][my] > 0) { bv = dItem[mx + 1][my] - 1; if (item[bv]._iSelFlag >= 2) { cursmx = mx + 1; cursmy = my; pcursitem = bv; } } if (flipflag && dItem[mx][my + 1] > 0) { bv = dItem[mx][my + 1] - 1; if (item[bv]._iSelFlag >= 2) { cursmx = mx; cursmy = my + 1; pcursitem = bv; } } if (dItem[mx][my] > 0) { bv = dItem[mx][my] - 1; if (item[bv]._iSelFlag == 1 || item[bv]._iSelFlag == 3) { cursmx = mx; cursmy = my; pcursitem = bv; } } if (dItem[mx + 1][my + 1] > 0) { bv = dItem[mx + 1][my + 1] - 1; if (item[bv]._iSelFlag >= 2) { cursmx = mx + 1; cursmy = my + 1; pcursitem = bv; } } if (pcursitem == -1) { cursmx = mx; cursmy = my; CheckTrigForce(); CheckTown(); CheckRportal(); } } if (pcurs == CURSOR_IDENTIFY) { pcursobj = -1; pcursmonst = -1; pcursitem = -1; cursmx = mx; cursmy = my; } #ifdef HELLFIRE if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_GOLEM && !(monster[pcursmonst]._mFlags & MFLAG_BERSERK)) { pcursmonst = -1; } #else if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_GOLEM) { pcursmonst = -1; } #endif } ================================================ FILE: Source/cursor.h ================================================ /** * @file cursor.h * * Interface of cursor tracking functionality. */ #ifndef __CURSOR_H__ #define __CURSOR_H__ extern int cursW; extern int cursH; extern int pcursmonst; extern int icursW28; extern int icursH28; extern BYTE *pCursCels; #ifdef HELLFIRE extern BYTE *pCursCels2; #endif extern int icursH; extern char pcursinvitem; extern int icursW; extern char pcursitem; extern char pcursobj; extern char pcursplr; extern int cursmx; extern int cursmy; extern int pcurs; void InitCursor(); void FreeCursor(); void SetICursor(int i); void SetCursor_(int i); void NewCursor(int i); void InitLevelCursor(); void CheckCursMove(); /* rdata */ extern const int InvItemWidth[]; extern const int InvItemHeight[]; #endif /* __CURSOR_H__ */ ================================================ FILE: Source/dead.cpp ================================================ /** * @file dead.cpp * * Implementation of functions for placing dead monsters. */ #include "all.h" /** unused, this was probably for blood boil/burn */ int spurtndx; DeadStruct dead[MAXDEAD]; int stonendx; void InitDead() { int i, d, nd, mi; int mtypes[MAXMONSTERS]; for (i = 0; i < MAXMONSTERS; i++) mtypes[i] = 0; nd = 0; for (i = 0; i < nummtypes; i++) { if (mtypes[Monsters[i].mtype] == 0) { for (d = 0; d < 8; d++) dead[nd]._deadData[d] = Monsters[i].Anims[MA_DEATH].Data[d]; dead[nd]._deadFrame = Monsters[i].Anims[MA_DEATH].Frames; dead[nd]._deadWidth = Monsters[i].width; dead[nd]._deadWidth2 = Monsters[i].width2; dead[nd]._deadtrans = 0; Monsters[i].mdeadval = nd + 1; mtypes[Monsters[i].mtype] = nd + 1; nd++; } } for (d = 0; d < 8; d++) dead[nd]._deadData[d] = misfiledata[MFILE_BLODBUR].mAnimData[0]; dead[nd]._deadFrame = 8; dead[nd]._deadWidth = 128; dead[nd]._deadWidth2 = 32; dead[nd]._deadtrans = 0; spurtndx = nd + 1; nd++; for (d = 0; d < 8; d++) dead[nd]._deadData[d] = misfiledata[MFILE_SHATTER1].mAnimData[0]; dead[nd]._deadFrame = 12; dead[nd]._deadWidth = 128; dead[nd]._deadWidth2 = 32; dead[nd]._deadtrans = 0; stonendx = nd + 1; nd++; for (i = 0; i < nummonsters; i++) { mi = monstactive[i]; if (monster[mi]._uniqtype != 0) { for (d = 0; d < 8; d++) dead[nd]._deadData[d] = monster[mi].MType->Anims[MA_DEATH].Data[d]; dead[nd]._deadFrame = monster[mi].MType->Anims[MA_DEATH].Frames; dead[nd]._deadWidth = monster[mi].MType->width; dead[nd]._deadWidth2 = monster[mi].MType->width2; dead[nd]._deadtrans = monster[mi]._uniqtrans + 4; monster[mi]._udeadval = nd + 1; nd++; } } assert(nd <= MAXDEAD); } void AddDead(int dx, int dy, char dv, int ddir) { dDead[dx][dy] = (dv & 0x1F) + (ddir << 5); } void SyncUniqDead() { int i, mi; int dx, dy; for (i = 0; i < nummonsters; i++) { mi = monstactive[i]; if (monster[mi]._uniqtype != 0) { for (dx = 0; dx < MAXDUNX; dx++) { for (dy = 0; dy < MAXDUNY; dy++) { if ((dDead[dx][dy] & 0x1F) == monster[mi]._udeadval) ChangeLightXY(monster[mi].mlid, dx, dy); } } } } } ================================================ FILE: Source/dead.h ================================================ /** * @file dead.h * * Interface of functions for placing dead monsters. */ #ifndef __DEAD_H__ #define __DEAD_H__ extern DeadStruct dead[MAXDEAD]; extern int stonendx; void InitDead(); void AddDead(int dx, int dy, char dv, int ddir); void SyncUniqDead(); #endif /* __DEAD_H__ */ ================================================ FILE: Source/debug.cpp ================================================ /** * @file debug.cpp * * Implementation of debug functions. */ #include "all.h" #ifdef _DEBUG BOOL update_seed_check = FALSE; #endif #define DEBUGSEEDS 4096 int seed_index; int level_seeds[NUMLEVELS + 1]; int seed_table[DEBUGSEEDS]; BYTE *pSquareCel; char dMonsDbg[NUMLEVELS][MAXDUNX][MAXDUNY]; char dFlagDbg[NUMLEVELS][MAXDUNX][MAXDUNY]; void LoadDebugGFX() { if (visiondebug) pSquareCel = LoadFileInMem("Data\\Square.CEL", NULL); } void FreeDebugGFX() { MemFreeDbg(pSquareCel); } #ifdef _DEBUG void init_seed_desync() { int i; for (i = 0; i < DEBUGSEEDS; i++) { seed_table[i] = -1; } seed_index = 0; for (i = 0; i < NUMLEVELS; i++) { level_seeds[i] = 0; } } void seed_desync_index_get() { if (currlevel == 0) { return; } update_seed_check = TRUE; seed_index = level_seeds[currlevel]; } void seed_desync_index_set() { if (currlevel == 0) { return; } update_seed_check = FALSE; level_seeds[currlevel + 1] = seed_index; } void seed_desync_check(int seed) { if (!update_seed_check || seed_index == DEBUGSEEDS || currlevel == 0) { return; } if (seed_table[seed_index] == -1) { seed_table[seed_index] = seed; } else if (seed != seed_table[seed_index]) { app_fatal("Seeds desynced"); } seed_index++; } #endif void CheckDungeonClear() { int i, j; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dMonster[i][j] != 0) app_fatal("Monsters not cleared"); if (dPlayer[i][j] != 0) app_fatal("Players not cleared"); dMonsDbg[currlevel][i][j] = dFlags[i][j] & BFLAG_VISIBLE; dFlagDbg[currlevel][i][j] = dFlags[i][j] & BFLAG_POPULATED; } } } #ifdef _DEBUG void GiveGoldCheat() { int i, ni; for (i = 0; i < NUM_INV_GRID_ELEM; i++) { if (plr[myplr].InvGrid[i] == 0) { ni = plr[myplr]._pNumInv++; SetPlrHandItem(&plr[myplr].InvList[ni], IDI_GOLD); GetPlrHandSeed(&plr[myplr].InvList[ni]); plr[myplr].InvList[ni]._ivalue = GOLD_MAX_LIMIT; plr[myplr].InvList[ni]._iCurs = ICURS_GOLD_LARGE; plr[myplr]._pGold += GOLD_MAX_LIMIT; plr[myplr].InvGrid[i] = plr[myplr]._pNumInv; } } } void StoresCheat() { #ifndef HELLFIRE int i; numpremium = 0; for (i = 0; i < SMITH_PREMIUM_ITEMS; i++) premiumitem[i]._itype = ITYPE_NONE; SpawnPremium(30); for (i = 0; i < 20; i++) witchitem[i]._itype = ITYPE_NONE; SpawnWitch(30); #endif } void TakeGoldCheat() { int i; char ig; for (i = 0; i < NUM_INV_GRID_ELEM; 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 < MAXBELTITEMS; i++) { if (plr[myplr].SpdList[i]._itype == ITYPE_GOLD) plr[myplr].SpdList[i]._itype = ITYPE_NONE; } plr[myplr]._pGold = 0; } void MaxSpellsCheat() { int i; for (i = 1; i < MAX_SPELLS; i++) { if (spelldata[i].sBookLvl != -1) { plr[myplr]._pMemSpells |= SPELLBIT(i); plr[myplr]._pSplLvl[i] = 10; } } } void SetSpellLevelCheat(char spl, int spllvl) { plr[myplr]._pMemSpells |= SPELLBIT(spl); plr[myplr]._pSplLvl[spl] = spllvl; } void 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 PrintDebugPlayer(BOOL bNextPlayer) { char dstr[128]; 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]._px, plr[dbgplr]._py, 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 PrintDebugQuest() { char dstr[128]; sprintf(dstr, "Quest %i : Active = %i, Var1 = %i", dbgqst, quests[dbgqst]._qactive, quests[dbgqst]._qvar1); NetSendCmdString(1 << myplr, dstr); dbgqst++; if (dbgqst == MAXQUESTS) dbgqst = 0; } void PrintDebugMonster(int m) { BOOL bActive; int i; char dstr[128]; 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 = FALSE; for (i = 0; i < nummonsters; i++) { if (monstactive[i] == m) bActive = TRUE; } sprintf(dstr, "Active List = %i, Squelch = %i", bActive, monster[m]._msquelch); NetSendCmdString(1 << myplr, dstr); } void GetDebugMonster() { int mi1, mi2; mi1 = pcursmonst; if (mi1 == -1) { mi2 = dMonster[cursmx][cursmy]; if (mi2 != 0) { mi1 = mi2 - 1; if (mi2 <= 0) mi1 = -1 - mi2; } else { mi1 = dbgmon; } } PrintDebugMonster(mi1); } void NextDebugMonster() { char dstr[128]; dbgmon++; if (dbgmon == MAXMONSTERS) dbgmon = 0; sprintf(dstr, "Current debug monster = %i", dbgmon); NetSendCmdString(1 << myplr, dstr); } #endif ================================================ FILE: Source/debug.h ================================================ /** * @file debug.h * * Interface of debug functions. */ #ifndef __DEBUG_H__ #define __DEBUG_H__ extern BYTE *pSquareCel; void LoadDebugGFX(); void FreeDebugGFX(); #ifdef _DEBUG void init_seed_desync(); void seed_desync_index_get(); void seed_desync_index_set(); void seed_desync_check(int seed); #endif void CheckDungeonClear(); #ifdef _DEBUG void GiveGoldCheat(); void StoresCheat(); void TakeGoldCheat(); void MaxSpellsCheat(); void SetAllSpellsCheat(); void PrintDebugPlayer(BOOL bNextPlayer); void PrintDebugQuest(); void GetDebugMonster(); void NextDebugMonster(); #endif #endif /* __DEBUG_H__ */ ================================================ FILE: Source/diablo.cpp ================================================ /** * @file diablo.cpp * * Implementation of the main game initialization functions. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" #include "../DiabloUI/diabloui.h" HWND ghMainWnd; DWORD glSeedTbl[NUMLEVELS]; int gnLevelTypeTbl[NUMLEVELS]; #ifndef HELLFIRE int glEndSeed[NUMLEVELS]; int glMid1Seed[NUMLEVELS]; int glMid2Seed[NUMLEVELS]; int glMid3Seed[NUMLEVELS]; #else int glEndSeed[NUMLEVELS + 1]; int glMid1Seed[NUMLEVELS + 1]; int glMid2Seed[NUMLEVELS + 1]; int glMid3Seed[NUMLEVELS + 1]; #endif int MouseX; int MouseY; BOOL gbGameLoopStartup; BOOL gbRunGame; BOOL gbRunGameResult; BOOL zoomflag; /** Enable updating of player character, set to false once Diablo dies */ BOOL gbProcessPlayers; BOOL gbLoadGame; HINSTANCE ghInst; int DebugMonsters[10]; BOOLEAN cineflag; int force_redraw; BOOL visiondebug; /** unused */ BOOL scrollflag; BOOL light4flag; BOOL leveldebug; BOOL monstdebug; /** unused */ BOOL trigdebug; int setseed; int debugmonsttypes; int PauseMode; #ifdef HELLFIRE BOOLEAN UseTheoQuest; BOOLEAN UseCowFarmer; BOOLEAN UseNestArt; BOOLEAN UseBardTest; BOOLEAN UseBarbarianTest; BOOLEAN UseMultiTest; #endif int sgnTimeoutCurs; char sgbMouseDown; int color_cycle_timer; /* rdata */ /** * Specifies whether to give the game exclusive access to the * screen, as needed for efficient rendering in fullscreen mode. */ BOOL fullscreen = TRUE; #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 /** Specifies whether players are in non-PvP mode. */ BOOL FriendlyMode = TRUE; /** Default quick messages */ const char *const spszMsgTbl[4] = { "I need help! Come Here!", "Follow me.", "Here's something for you.", "Now you DIE!" }; /** INI files variable names for quick message keys */ const char *const spszMsgHotKeyTbl[4] = { "F9", "F10", "F11", "F12" }; static void diablo_parse_flags(char *args) { char c; #ifdef _DEBUG int i; #endif while (*args != '\0') { while (isspace(*args)) { args++; } static char de[] = "dd_emulate"; if (_strnicmp(de, args, strlen(de)) == 0) { gbEmulate = TRUE; args += strlen(de); continue; } static char db[] = "dd_backbuf"; if (_strnicmp(db, args, strlen(db)) == 0) { gbBackBuf = TRUE; args += strlen(db); continue; } static char ds[] = "ds_noduplicates"; if (_strnicmp(ds, args, strlen(ds)) == 0) { gbDupSounds = FALSE; args += strlen(ds); continue; } #ifdef HELLFIRE char tq[] = "Theoquest"; if (_strnicmp(tq, args, strlen(tq)) == 0) { UseTheoQuest = TRUE; args += strlen(tq); continue; } char cq[] = "Cowquest"; if (_strnicmp(cq, args, strlen(cq)) == 0) { UseCowFarmer = TRUE; args += strlen(cq); continue; } char na[] = "NestArt"; if (_strnicmp(na, args, strlen(na)) == 0) { UseNestArt = TRUE; args += strlen(na); continue; } char bt[] = "Bardtest"; if (_strnicmp(bt, args, strlen(bt)) == 0) { UseBardTest = TRUE; args += strlen(bt); continue; } char mt[] = "Multitest"; if (_strnicmp(mt, bt, strlen(mt)) == 0) { // BUGFIX: secound arg should be args UseMultiTest = TRUE; args += strlen(mt); continue; } char bb[] = "Barbariantest"; if (_strnicmp(bb, args, strlen(bb)) == 0) { UseBarbarianTest = TRUE; args += strlen(bb); continue; } #endif c = tolower(*args); args++; #ifdef _DEBUG switch (c) { case '^': debug_mode_key_inverted_v = TRUE; break; case '$': debug_mode_dollar_sign = TRUE; break; case 'b': /* debug_mode_key_b = TRUE; */ break; case 'd': showintrodebug = FALSE; debug_mode_key_d = TRUE; break; case 'f': EnableFrameCount(); break; case 'i': debug_mode_key_i = TRUE; break; case 'j': /* while(isspace(*args)) { args++; } i = 0; while(isdigit(*args)) { i = *args + 10 * i - '0'; args++; } debug_mode_key_J_trigger = i; */ break; case 'l': setlevel = FALSE; leveldebug = TRUE; while (isspace(*args)) { args++; } i = 0; while (isdigit(*args)) { i = *args + 10 * i - '0'; args++; } leveltype = i; while (isspace(*args)) { args++; } i = 0; while (isdigit(*args)) { i = *args + 10 * i - '0'; args++; } currlevel = i; plr[0].plrlevel = i; break; case 'm': monstdebug = TRUE; while (isspace(*args)) { args++; } i = 0; while (isdigit(*args)) { i = *args + 10 * i - '0'; args++; } DebugMonsters[debugmonsttypes++] = i; break; case 'n': showintrodebug = FALSE; break; case 'q': while (isspace(*args)) { args++; } i = 0; while (isdigit(*args)) { i = *args + 10 * i - '0'; args++; } questdebug = i; break; case 'r': while (isspace(*args)) { args++; } i = 0; while (isdigit(*args)) { i = *args + 10 * i - '0'; args++; } setseed = i; break; case 's': debug_mode_key_s = TRUE; break; case 't': leveldebug = TRUE; setlevel = TRUE; while (isspace(*args)) { args++; } i = 0; while (isdigit(*args)) { i = *args + 10 * i - '0'; args++; } setlvlnum = i; break; case 'v': visiondebug = TRUE; break; case 'w': debug_mode_key_w = TRUE; break; case 'x': fullscreen = FALSE; break; } #endif } } void FreeGameMem() { music_stop(); MemFreeDbg(pDungeonCels); MemFreeDbg(pMegaTiles); MemFreeDbg(pLevelPieces); MemFreeDbg(pSpecialCels); MemFreeDbg(pSpeedCels); FreeMissiles(); FreeMonsters(); FreeObjectGFX(); FreeMonsterSnd(); FreeTownerGFX(); } static void start_game(unsigned int uMsg) { zoomflag = TRUE; cineflag = FALSE; InitCursor(); InitLightTable(); LoadDebugGFX(); assert(ghMainWnd); music_stop(); ShowProgress(uMsg); gmenu_init_menu(); InitLevelCursor(); sgnTimeoutCurs = CURSOR_NONE; sgbMouseDown = CLICK_NONE; track_repeat_walk(FALSE); } static void free_game() { int i; FreeControlPan(); FreeInvGFX(); FreeGMenu(); FreeQuestText(); FreeStoreMem(); for (i = 0; i < MAX_PLRS; i++) FreePlayerGFX(i); FreeItemGFX(); FreeCursor(); FreeLightTable(); FreeDebugGFX(); FreeGameMem(); } static void run_game_loop(unsigned int uMsg) { BOOL bLoop; WNDPROC saveProc; MSG msg; nthread_ignore_mutex(TRUE); start_game(uMsg); assert(ghMainWnd); saveProc = SetWindowProc(GM_Game); control_update_life_mana(); run_delta_info(); gbRunGame = TRUE; gbProcessPlayers = TRUE; gbRunGameResult = TRUE; force_redraw = 255; DrawAndBlit(); PaletteFadeIn(8); force_redraw = 255; gbGameLoopStartup = TRUE; nthread_ignore_mutex(FALSE); while (gbRunGame) { 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 = FALSE; gbRunGame = FALSE; break; } TranslateMessage(&msg); DispatchMessage(&msg); } bLoop = gbRunGame && nthread_has_500ms_passed(FALSE); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); if (!bLoop) { continue; } } else if (!nthread_has_500ms_passed(FALSE)) { #ifdef SLEEPFIX Sleep(1); #endif continue; } multi_process_network_packets(); game_loop(gbGameLoopStartup); #ifndef HELLFIRE msgcmd_send_chat(); #endif gbGameLoopStartup = FALSE; DrawAndBlit(); } if (gbMaxPlayers > 1) { pfile_write_hero(); } pfile_flush_W(); PaletteFadeOut(8); SetCursor_(CURSOR_NONE); ClearScreenBuffer(); force_redraw = 255; scrollrt_draw_game_screen(TRUE); saveProc = SetWindowProc(saveProc); assert(saveProc == GM_Game); free_game(); if (cineflag) { cineflag = FALSE; DoEnding(); } } BOOL StartGame(BOOL bNewGame, BOOL bSinglePlayer) { BOOL fExitProgram; unsigned int uMsg; gbSelectProvider = TRUE; do { fExitProgram = FALSE; #ifndef HELLFIRE gbLoadGame = FALSE; #endif if (!NetInit(bSinglePlayer, &fExitProgram)) { gbRunGameResult = !fExitProgram; break; } gbSelectProvider = FALSE; if (bNewGame || !gbValidSaveFile) { InitLevels(); InitQuests(); InitPortals(); InitDungMsgs(myplr); #ifndef HELLFIRE } if (!gbValidSaveFile || !gbLoadGame) { #else if (!gbValidSaveFile && gbLoadGame) inv_diablo_to_hellfire(myplr); #endif uMsg = WM_DIABNEWGAME; } else { uMsg = WM_DIABLOADGAME; } run_game_loop(uMsg); NetClose(); #ifndef HELLFIRE pfile_create_player_description(NULL, 0); #else if (gbMaxPlayers == 1) break; #endif } while (gbRunGameResult); SNetDestroy(); return gbRunGameResult; } static void diablo_init_screen() { int i; MouseX = SCREEN_WIDTH / 2; MouseY = SCREEN_HEIGHT / 2; ScrollInfo._sdx = 0; ScrollInfo._sdy = 0; ScrollInfo._sxoff = 0; ScrollInfo._syoff = 0; ScrollInfo._sdir = SDIR_NONE; for (i = 0; i < 1024; i++) PitchTbl[i] = i * BUFFER_WIDTH; ClrDiabloMsg(); } #ifdef HELLFIRE static LONG __stdcall diablo_TopLevelExceptionFilter(PEXCEPTION_POINTERS pExc) { dx_cleanup(); init_cleanup(FALSE); if (lpTopLevelExceptionFilter) return lpTopLevelExceptionFilter(pExc); return EXCEPTION_CONTINUE_SEARCH; } #endif BOOL diablo_get_not_running() { SetLastError(0); CreateEvent(NULL, FALSE, FALSE, "DiabloEvent"); #ifdef HELLFIRE CreateEvent(NULL, FALSE, FALSE, "HellfireEvent"); #endif return GetLastError() != ERROR_ALREADY_EXISTS; } static BOOL diablo_find_window(LPCSTR lpClassName) { HWND hWnd, active; hWnd = FindWindow(lpClassName, NULL); if (hWnd == NULL) return FALSE; active = GetLastActivePopup(hWnd); if (active != NULL) hWnd = active; active = GetTopWindow(hWnd); if (!active) active = hWnd; SetForegroundWindow(hWnd); SetFocus(active); return TRUE; } static void diablo_reload_process(HINSTANCE hInstance) { DWORD dwSize, dwProcessId; BOOL bNoExist; char *s; long *plMap; HWND hWnd, hPrev; HANDLE hMap; STARTUPINFO si; SYSTEM_INFO sinf; PROCESS_INFORMATION pi; char szReload[MAX_PATH + 16]; char szFileName[MAX_PATH] = ""; GetModuleFileName(hInstance, szFileName, sizeof(szFileName)); wsprintf(szReload, "Reload-%s", szFileName); for (s = szReload; *s != '\0'; s++) { if (*s == '\\') { *s = '/'; } } GetSystemInfo(&sinf); dwSize = sinf.dwPageSize; if (dwSize < 4096) { dwSize = 4096; } hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, dwSize, szReload); bNoExist = GetLastError() != ERROR_ALREADY_EXISTS; if (hMap == NULL) { return; } plMap = (long *)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, dwSize); if (plMap == NULL) { return; } if (bNoExist) { plMap[0] = -1; plMap[1] = 0; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); CreateProcess(szFileName, NULL, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi); WaitForInputIdle(pi.hProcess, INFINITE); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); while (plMap[0] < 0) { Sleep(1000); } UnmapViewOfFile(plMap); CloseHandle(hMap); ExitProcess(0); } if (InterlockedIncrement(&plMap[0]) == 0) { plMap[1] = GetCurrentProcessId(); } else { hPrev = GetForegroundWindow(); hWnd = hPrev; while (1) { hPrev = GetWindow(hPrev, GW_HWNDPREV); if (hPrev == NULL) { break; } hWnd = hPrev; } do { GetWindowThreadProcessId(hWnd, &dwProcessId); if (dwProcessId == plMap[1]) { SetForegroundWindow(hWnd); break; } hWnd = GetWindow(hWnd, GW_HWNDNEXT); } while (hWnd != NULL); UnmapViewOfFile(plMap); CloseHandle(hMap); ExitProcess(0); } } /** * @brief Main entry point, check env, initialize systesm, play intros, start main menu, shut down * @param hInstance A handle to the current instance of the application. * @param hPrevInstance Always null * @param lpCmdLine The command line for the application * @param nCmdShow Initial window state */ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HINSTANCE hInst; int nData; char szFileName[MAX_PATH]; BOOL bNoEvent; #ifdef HELLFIRE char content[256]; FILE *file; #endif hInst = hInstance; #ifndef DEBUGGER diablo_reload_process(hInstance); #endif ghInst = hInst; #ifndef HELLFIRE if (RestrictedTest()) ErrOkDlg(IDD_DIALOG10, 0, "C:\\Src\\Diablo\\Source\\DIABLO.CPP", 877); if (ReadOnlyTest()) { if (!GetModuleFileName(ghInst, szFileName, sizeof(szFileName))) szFileName[0] = '\0'; DirErrorDlg(szFileName); } #endif ShowCursor(FALSE); srand(GetTickCount()); InitHash(); #ifdef HELLFIRE alloc_plr(); lpTopLevelExceptionFilter = SetUnhandledExceptionFilter(diablo_TopLevelExceptionFilter); #else fault_get_filter(); #endif bNoEvent = diablo_get_not_running(); #ifdef HELLFIRE if (diablo_find_window("DIABLO")) return 0; #endif if (diablo_find_window(GAME_NAME) || !bNoEvent) return 0; #ifdef _DEBUG SFileEnableDirectAccess(TRUE); #endif diablo_init_screen(); #ifdef HELLFIRE if (lpCmdLine[0] == '\0') { content[0] = '\0'; if (file = fopen("command.txt", "r")) { fgets(content, sizeof(content) / sizeof(char), file); lpCmdLine = content; fclose(file); } } #endif diablo_parse_flags(lpCmdLine); init_create_window(nCmdShow); ui_sound_init(); UiInitialize(); #ifdef SPAWN UiSetSpawned(TRUE); #endif #ifdef _DEBUG if (showintrodebug) #endif play_movie("gendata\\logo.smk", TRUE); #ifndef SPAWN { char szValueName[] = "Intro"; if (!SRegLoadValue(APP_NAME, szValueName, 0, &nData)) nData = 1; #ifndef HELLFIRE if (nData) play_movie("gendata\\diablo1.smk", TRUE); #else play_movie("gendata\\Hellfire.smk", TRUE); #endif SRegSaveValue(APP_NAME, szValueName, 0, 0); } #endif #ifdef _DEBUG if (showintrodebug) { #endif UiTitleDialog(7); BlackPalette(); #ifdef _DEBUG } #endif mainmenu_loop(); UiDestroy(); SaveGamma(); if (ghMainWnd) { Sleep(300); DestroyWindow(ghMainWnd); } return 0; } static BOOL LeftMouseCmd(BOOL bShift) { BOOL bNear; assert(MouseY < PANEL_TOP); // 352 if (leveltype == DTYPE_TOWN) { if (pcursitem != -1 && pcurs == CURSOR_HAND) NetSendCmdLocParam1(TRUE, invflag ? CMD_GOTOGETITEM : CMD_GOTOAGETITEM, cursmx, cursmy, pcursitem); if (pcursmonst != -1) NetSendCmdLocParam1(TRUE, CMD_TALKXY, cursmx, cursmy, pcursmonst); if (pcursitem == -1 && pcursmonst == -1 && pcursplr == -1) return TRUE; } else { bNear = abs(plr[myplr]._px - cursmx) < 2 && abs(plr[myplr]._py - cursmy) < 2; if (pcursitem != -1 && pcurs == CURSOR_HAND && !bShift) { NetSendCmdLocParam1(TRUE, invflag ? CMD_GOTOGETITEM : CMD_GOTOAGETITEM, cursmx, cursmy, pcursitem); } else if (pcursobj != -1 && (!bShift || bNear && object[pcursobj]._oBreak == 1)) { NetSendCmdLocParam1(TRUE, pcurs == CURSOR_DISARM ? CMD_DISARMXY : CMD_OPOBJXY, cursmx, cursmy, pcursobj); } else if (plr[myplr]._pwtype == WT_RANGED) { if (bShift) { NetSendCmdLoc(TRUE, CMD_RATTACKXY, cursmx, cursmy); } else if (pcursmonst != -1) { if (CanTalkToMonst(pcursmonst)) { NetSendCmdParam1(TRUE, CMD_ATTACKID, pcursmonst); } else { NetSendCmdParam1(TRUE, CMD_RATTACKID, pcursmonst); } } else if (pcursplr != -1 && !FriendlyMode) { NetSendCmdParam1(TRUE, CMD_RATTACKPID, pcursplr); } } else { if (bShift) { if (pcursmonst != -1) { if (CanTalkToMonst(pcursmonst)) { NetSendCmdParam1(TRUE, CMD_ATTACKID, pcursmonst); } else { NetSendCmdLoc(TRUE, CMD_SATTACKXY, cursmx, cursmy); } } else { NetSendCmdLoc(TRUE, CMD_SATTACKXY, cursmx, cursmy); } } else if (pcursmonst != -1) { NetSendCmdParam1(TRUE, CMD_ATTACKID, pcursmonst); } else if (pcursplr != -1 && !FriendlyMode) { NetSendCmdParam1(TRUE, CMD_ATTACKPID, pcursplr); } } if (!bShift && pcursitem == -1 && pcursobj == -1 && pcursmonst == -1 && pcursplr == -1) return TRUE; } return FALSE; } static BOOL TryIconCurs() { if (pcurs == CURSOR_RESURRECT) { NetSendCmdParam1(TRUE, CMD_RESURRECT, pcursplr); return TRUE; } if (pcurs == CURSOR_HEALOTHER) { NetSendCmdParam1(TRUE, CMD_HEALOTHER, pcursplr); return TRUE; } if (pcurs == CURSOR_TELEKINESIS) { DoTelekinesis(); return TRUE; } if (pcurs == CURSOR_IDENTIFY) { if (pcursinvitem != -1) CheckIdentify(myplr, pcursinvitem); else NewCursor(CURSOR_HAND); return TRUE; } if (pcurs == CURSOR_REPAIR) { if (pcursinvitem != -1) DoRepair(myplr, pcursinvitem); else NewCursor(CURSOR_HAND); return TRUE; } if (pcurs == CURSOR_RECHARGE) { if (pcursinvitem != -1) DoRecharge(myplr, pcursinvitem); else NewCursor(CURSOR_HAND); return TRUE; } #ifdef HELLFIRE if (pcurs == CURSOR_OIL) { if (pcursinvitem != -1) DoOil(myplr, pcursinvitem); else NewCursor(CURSOR_HAND); return TRUE; } #endif if (pcurs == CURSOR_TELEPORT) { if (pcursmonst != -1) NetSendCmdParam3(TRUE, CMD_TSPELLID, pcursmonst, plr[myplr]._pTSpell, GetSpellLevel(myplr, plr[myplr]._pTSpell)); else if (pcursplr != -1) NetSendCmdParam3(TRUE, CMD_TSPELLPID, pcursplr, plr[myplr]._pTSpell, GetSpellLevel(myplr, plr[myplr]._pTSpell)); else NetSendCmdLocParam2(TRUE, CMD_TSPELLXY, cursmx, cursmy, plr[myplr]._pTSpell, GetSpellLevel(myplr, plr[myplr]._pTSpell)); NewCursor(CURSOR_HAND); return TRUE; } if (pcurs == CURSOR_DISARM && pcursobj == -1) { NewCursor(CURSOR_HAND); return TRUE; } return FALSE; } static BOOL LeftMouseDown(int wParam) { if (gmenu_left_mouse(TRUE)) return FALSE; if (control_check_talk_btn()) return FALSE; if (sgnTimeoutCurs != CURSOR_NONE) return FALSE; if (deathflag) { control_check_btn_press(); return FALSE; } if (PauseMode == 2) { return FALSE; } if (doomflag) { doom_close(); return FALSE; } if (spselflag) { SetSpell(); return FALSE; } if (stextflag != STORE_NONE) { CheckStoreBtn(); return FALSE; } if (MouseY < PANEL_TOP) { if (!gmenu_is_active() && !TryIconCurs()) { if (questlog && MouseX > 32 && MouseX < 288 && MouseY > 32 && MouseY < 308) { QuestlogESC(); } else if (qtextflag) { qtextflag = FALSE; stream_stop(); } else if (chrflag && MouseX < SPANEL_WIDTH) { CheckChrBtns(); } else if (invflag && MouseX > RIGHT_PANEL) { if (!dropGoldFlag) CheckInvItem(); } else if (sbookflag && MouseX > RIGHT_PANEL) { CheckSBook(); } else if (pcurs >= CURSOR_FIRSTITEM) { if (TryInvPut()) { NetSendCmdPItem(TRUE, CMD_PUTITEM, cursmx, cursmy); NewCursor(CURSOR_HAND); } } else { if (plr[myplr]._pStatPts != 0 && !spselflag) CheckLvlBtn(); if (!lvlbtndown) return LeftMouseCmd(wParam == MK_SHIFT + MK_LBUTTON); } } } else { if (!talkflag && !dropGoldFlag && !gmenu_is_active()) CheckInvScrn(); DoPanBtn(); if (pcurs > CURSOR_HAND && pcurs < CURSOR_FIRSTITEM) NewCursor(CURSOR_HAND); } return FALSE; } static void LeftMouseUp() { gmenu_left_mouse(FALSE); control_release_talk_btn(); if (panbtndown) CheckBtnUp(); if (chrbtnactive) ReleaseChrBtns(); if (lvlbtndown) ReleaseLvlBtn(); if (stextflag != STORE_NONE) ReleaseStoreBtn(); } static void RightMouseDown() { if (!gmenu_is_active() && sgnTimeoutCurs == CURSOR_NONE && PauseMode != 2 && !plr[myplr]._pInvincible) { if (doomflag) { doom_close(); } else if (stextflag == STORE_NONE) { if (spselflag) { SetSpell(); #ifdef HELLFIRE } else if ((!sbookflag || MouseX <= RIGHT_PANEL) && (MouseY >= SPANEL_HEIGHT || (!TryIconCurs() && (pcursinvitem == -1 || !UseInvItem(myplr, pcursinvitem))))) { #else } else if (MouseY >= SPANEL_HEIGHT || (!sbookflag || MouseX <= RIGHT_PANEL) && !TryIconCurs() && (pcursinvitem == -1 || !UseInvItem(myplr, pcursinvitem))) { #endif if (pcurs == CURSOR_HAND) { if (pcursinvitem == -1 || !UseInvItem(myplr, pcursinvitem)) CheckPlrSpell(); } else if (pcurs > CURSOR_HAND && pcurs < CURSOR_FIRSTITEM) { NewCursor(CURSOR_HAND); } } } } } static void diablo_pause_game() { if (gbMaxPlayers <= 1) { if (PauseMode) { PauseMode = 0; } else { PauseMode = 2; sound_stop(); track_repeat_walk(FALSE); } force_redraw = 255; } } static void diablo_hotkey_msg(DWORD dwMsg) { char *s; char szFileName[MAX_PATH]; char szMsg[MAX_SEND_STR_LEN]; if (gbMaxPlayers == 1) { return; } if (GetModuleFileName(ghInst, szFileName, sizeof(szFileName)) == 0) { app_fatal("Can't get program name"); } s = strrchr(szFileName, '\\'); if (s != NULL) { *s = '\0'; } strcat(szFileName, "\\Diablo.ini"); assert(dwMsg < sizeof(spszMsgTbl) / sizeof(spszMsgTbl[0])); GetPrivateProfileString("NetMsg", spszMsgHotKeyTbl[dwMsg], spszMsgTbl[dwMsg], szMsg, sizeof(szMsg), szFileName); NetSendCmdString(-1, szMsg); } static BOOL PressSysKey(int wParam) { if (gmenu_is_active() || wParam != VK_F10) return FALSE; diablo_hotkey_msg(1); return TRUE; } static void ReleaseKey(int vkey) { if (vkey == VK_SNAPSHOT) CaptureScreen(); } BOOL PressEscKey() { BOOL rv = FALSE; if (doomflag) { doom_close(); rv = TRUE; } if (helpflag) { helpflag = FALSE; rv = TRUE; } if (qtextflag) { qtextflag = FALSE; stream_stop(); rv = TRUE; } else if (stextflag) { STextESC(); rv = TRUE; } if (msgflag) { msgdelay = 0; rv = TRUE; } if (talkflag) { control_reset_talk(); rv = TRUE; } if (dropGoldFlag) { control_drop_gold(VK_ESCAPE); rv = TRUE; } if (spselflag) { spselflag = FALSE; rv = TRUE; } return rv; } static void PressKey(int vkey) { if (gmenu_presskeys(vkey) || control_presskeys(vkey)) { return; } if (deathflag) { if (sgnTimeoutCurs != CURSOR_NONE) { return; } if (vkey == VK_F9) { diablo_hotkey_msg(0); } if (vkey == VK_F10) { diablo_hotkey_msg(1); } if (vkey == VK_F11) { diablo_hotkey_msg(2); } if (vkey == VK_F12) { diablo_hotkey_msg(3); } if (vkey == VK_RETURN) { control_type_message(); } if (vkey != VK_ESCAPE) { return; } } if (vkey == VK_ESCAPE) { if (!PressEscKey()) { track_repeat_walk(FALSE); gamemenu_on(); } return; } if (sgnTimeoutCurs != CURSOR_NONE || dropGoldFlag) { return; } if (vkey == VK_PAUSE) { diablo_pause_game(); return; } if (PauseMode == 2) { return; } if (vkey == VK_RETURN) { if (stextflag) { STextEnter(); } else if (questlog) { QuestlogEnter(); } else { control_type_message(); } } else if (vkey == VK_F1) { if (helpflag) { helpflag = FALSE; } else if (stextflag != STORE_NONE) { ClearPanel(); AddPanelString("No help available", TRUE); /// BUGFIX: message isn't displayed AddPanelString("while in stores", TRUE); track_repeat_walk(FALSE); } else { invflag = FALSE; chrflag = FALSE; sbookflag = FALSE; spselflag = FALSE; if (qtextflag && leveltype == DTYPE_TOWN) { qtextflag = FALSE; stream_stop(); } questlog = FALSE; automapflag = FALSE; msgdelay = 0; gamemenu_off(); DisplayHelp(); doom_close(); } } #ifdef _DEBUG else if (vkey == VK_F2) { } #endif #ifdef _DEBUG else if (vkey == 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); } #endif #ifdef _DEBUG else if (vkey == VK_F4) { PrintDebugQuest(); } #endif else if (vkey == VK_F5) { if (spselflag) { SetSpeedSpell(0); return; } ToggleSpell(0); return; } else if (vkey == VK_F6) { if (spselflag) { SetSpeedSpell(1); return; } ToggleSpell(1); return; } else if (vkey == VK_F7) { if (spselflag) { SetSpeedSpell(2); return; } ToggleSpell(2); return; } else if (vkey == VK_F8) { if (spselflag) { SetSpeedSpell(3); return; } ToggleSpell(3); return; } else if (vkey == VK_F9) { diablo_hotkey_msg(0); } else if (vkey == VK_F10) { diablo_hotkey_msg(1); } else if (vkey == VK_F11) { diablo_hotkey_msg(2); } else if (vkey == VK_F12) { diablo_hotkey_msg(3); } else if (vkey == VK_UP) { if (stextflag) { STextUp(); } else if (questlog) { QuestlogUp(); } else if (helpflag) { HelpScrollUp(); } else if (automapflag) { AutomapUp(); } } else if (vkey == VK_DOWN) { if (stextflag) { STextDown(); } else if (questlog) { QuestlogDown(); } else if (helpflag) { HelpScrollDown(); } else if (automapflag) { AutomapDown(); } } else if (vkey == VK_PRIOR) { if (stextflag) { STextPrior(); } } else if (vkey == VK_NEXT) { if (stextflag) { STextNext(); } } else if (vkey == VK_LEFT) { if (automapflag && !talkflag) { AutomapLeft(); } } else if (vkey == VK_RIGHT) { if (automapflag && !talkflag) { AutomapRight(); } } else if (vkey == VK_TAB) { DoAutoMap(); } else if (vkey == VK_SPACE) { if (!chrflag && invflag && MouseX < 480 && MouseY < PANEL_TOP) { SetCursorPos(MouseX + 160, MouseY); } if (!invflag && chrflag && MouseX > 160 && MouseY < PANEL_TOP) { SetCursorPos(MouseX - 160, MouseY); } helpflag = FALSE; invflag = FALSE; chrflag = FALSE; sbookflag = FALSE; spselflag = FALSE; if (qtextflag && leveltype == DTYPE_TOWN) { qtextflag = FALSE; stream_stop(); } questlog = FALSE; automapflag = FALSE; msgdelay = 0; gamemenu_off(); doom_close(); } } /** * @internal `return` must be used instead of `break` to be bin exact as C++ */ static void PressChar(WPARAM vkey) { if (gmenu_is_active() || control_talk_last_key(vkey) || sgnTimeoutCurs != CURSOR_NONE || deathflag) { return; } if ((char)vkey == 'p' || (char)vkey == 'P') { diablo_pause_game(); return; } if (PauseMode == 2) { return; } if (doomflag) { doom_close(); return; } if (dropGoldFlag) { control_drop_gold(vkey); return; } switch (vkey) { case 'G': case 'g': DecreaseGamma(); return; case 'F': case 'f': IncreaseGamma(); return; case 'I': case 'i': if (stextflag == STORE_NONE) { sbookflag = FALSE; invflag = !invflag; if (!invflag || chrflag) { if (MouseX < 480 && MouseY < PANEL_TOP) { SetCursorPos(MouseX + 160, MouseY); } } else { if (MouseX > 160 && MouseY < PANEL_TOP) { SetCursorPos(MouseX - 160, MouseY); } } } return; case 'C': case 'c': if (stextflag == STORE_NONE) { questlog = FALSE; chrflag = !chrflag; if (!chrflag || invflag) { if (MouseX > 160 && MouseY < PANEL_TOP) { SetCursorPos(MouseX - 160, MouseY); } } else { if (MouseX < 480 && MouseY < PANEL_TOP) { SetCursorPos(MouseX + 160, MouseY); } } } return; case 'Q': case 'q': if (stextflag == STORE_NONE) { chrflag = FALSE; if (!questlog) { StartQuestlog(); } else { questlog = FALSE; } } return; case 'Z': case 'z': zoomflag = !zoomflag; return; case 'S': case 's': if (stextflag == STORE_NONE) { invflag = FALSE; if (!spselflag) { DoSpeedBook(); } else { spselflag = FALSE; } track_repeat_walk(FALSE); } return; case 'B': case 'b': if (stextflag == STORE_NONE) { invflag = FALSE; sbookflag = !sbookflag; } return; case '+': case '=': if (automapflag) { AutomapZoomIn(); } return; case '-': case '_': if (automapflag) { AutomapZoomOut(); } return; case 'v': #ifndef HELLFIRE NetSendCmdString(1 << myplr, gszProductName); #else char *local_10[3]; char pszStr[120]; local_10[0] = "Normal"; local_10[1] = "Nightmare"; local_10[2] = "Hell"; sprintf(pszStr, "%s, mode = %s", gszProductName, local_10[gnDifficulty]); NetSendCmdString(1 << myplr, pszStr); #endif return; case 'V': NetSendCmdString(1 << myplr, gszVersionNumber); return; case '!': case '1': if (plr[myplr].SpdList[0]._itype != ITYPE_NONE && plr[myplr].SpdList[0]._itype != ITYPE_GOLD) { UseInvItem(myplr, INVITEM_BELT_FIRST); } return; case '@': case '2': if (plr[myplr].SpdList[1]._itype != ITYPE_NONE && plr[myplr].SpdList[1]._itype != ITYPE_GOLD) { UseInvItem(myplr, INVITEM_BELT_FIRST + 1); } return; case '#': case '3': if (plr[myplr].SpdList[2]._itype != ITYPE_NONE && plr[myplr].SpdList[2]._itype != ITYPE_GOLD) { UseInvItem(myplr, INVITEM_BELT_FIRST + 2); } return; case '$': case '4': if (plr[myplr].SpdList[3]._itype != ITYPE_NONE && plr[myplr].SpdList[3]._itype != ITYPE_GOLD) { UseInvItem(myplr, INVITEM_BELT_FIRST + 3); } return; case '%': case '5': if (plr[myplr].SpdList[4]._itype != ITYPE_NONE && plr[myplr].SpdList[4]._itype != ITYPE_GOLD) { UseInvItem(myplr, INVITEM_BELT_FIRST + 4); } return; case '^': case '6': if (plr[myplr].SpdList[5]._itype != ITYPE_NONE && plr[myplr].SpdList[5]._itype != ITYPE_GOLD) { UseInvItem(myplr, INVITEM_BELT_FIRST + 5); } return; case '&': case '7': if (plr[myplr].SpdList[6]._itype != ITYPE_NONE && plr[myplr].SpdList[6]._itype != ITYPE_GOLD) { UseInvItem(myplr, INVITEM_BELT_FIRST + 6); } return; case '*': case '8': #ifdef _DEBUG if (debug_mode_key_inverted_v || debug_mode_key_w) { NetSendCmd(TRUE, CMD_CHEAT_EXPERIENCE); return; } #endif if (plr[myplr].SpdList[7]._itype != ITYPE_NONE && plr[myplr].SpdList[7]._itype != ITYPE_GOLD) { UseInvItem(myplr, INVITEM_BELT_FIRST + 7); } return; #ifdef _DEBUG case ')': case '0': if (debug_mode_key_inverted_v) { if (arrowdebug > 2) { arrowdebug = 0; } if (arrowdebug == 0) { 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 == 0 && debug_mode_key_w) { SetAllSpellsCheat(); } return; case '[': if (currlevel == 0 && debug_mode_key_w) { TakeGoldCheat(); } return; case ']': if (currlevel == 0 && 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(TRUE); return; case 'd': PrintDebugPlayer(FALSE); 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]._px, plr[myplr]._py); NetSendCmdString(1 << myplr, tempstr); // BUGFIX: out-of-bounds access to dungeon; should be `dPiece[cursmx][cursmy]`, was `dungeon[cursmx][cursmy]`. sprintf(tempstr, "CX = %i CY = %i DP = %i", cursmx, cursmy, dungeon[cursmx][cursmy]); NetSendCmdString(1 << myplr, tempstr); } return; case '|': if (currlevel == 0 && debug_mode_key_w) { GiveGoldCheat(); } return; case '~': if (currlevel == 0 && debug_mode_key_w) { StoresCheat(); } return; #endif } } LRESULT CALLBACK DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_KEYDOWN: case WM_KEYUP: case WM_CHAR: case WM_SYSKEYDOWN: case WM_SYSCOMMAND: case WM_MOUSEMOVE: return 0; case WM_LBUTTONDOWN: if (sgbMouseDown != CLICK_NONE) return 0; sgbMouseDown = CLICK_LEFT; SetCapture(hWnd); return 0; case WM_LBUTTONUP: if (sgbMouseDown != CLICK_LEFT) return 0; sgbMouseDown = CLICK_NONE; ReleaseCapture(); return 0; case WM_RBUTTONDOWN: if (sgbMouseDown != CLICK_NONE) return 0; sgbMouseDown = CLICK_RIGHT; SetCapture(hWnd); return 0; case WM_RBUTTONUP: if (sgbMouseDown != CLICK_RIGHT) return 0; sgbMouseDown = CLICK_NONE; ReleaseCapture(); return 0; case WM_CAPTURECHANGED: if (hWnd == (HWND)lParam) return 0; sgbMouseDown = CLICK_NONE; return 0; } return MainWndProc(hWnd, uMsg, wParam, lParam); } LRESULT CALLBACK GM_Game(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_KEYDOWN: 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; break; case WM_SYSCOMMAND: if (wParam == SC_CLOSE) { gbRunGame = FALSE; gbRunGameResult = FALSE; return 0; } break; case WM_MOUSEMOVE: MouseX = LOWORD(lParam); // BUGFIX (short)LOWORD coords are signed MouseY = HIWORD(lParam); // BUGFIX (short)HIWORD coords are signed gmenu_on_mouse_move(); return 0; case WM_LBUTTONDOWN: MouseX = LOWORD(lParam); // BUGFIX (short)LOWORD coords are signed MouseY = HIWORD(lParam); // BUGFIX (short)HIWORD coords are signed if (sgbMouseDown == CLICK_NONE) { sgbMouseDown = CLICK_LEFT; SetCapture(hWnd); track_repeat_walk(LeftMouseDown(wParam)); } return 0; case WM_LBUTTONUP: MouseX = LOWORD(lParam); // BUGFIX (short)LOWORD coords are signed MouseY = HIWORD(lParam); // BUGFIX (short)HIWORD coords are signed if (sgbMouseDown == CLICK_LEFT) { sgbMouseDown = CLICK_NONE; LeftMouseUp(); track_repeat_walk(FALSE); ReleaseCapture(); } return 0; case WM_RBUTTONDOWN: MouseX = LOWORD(lParam); // BUGFIX (short)LOWORD coords are signed MouseY = HIWORD(lParam); // BUGFIX (short)HIWORD coords are signed if (sgbMouseDown == CLICK_NONE) { sgbMouseDown = CLICK_RIGHT; SetCapture(hWnd); RightMouseDown(); } return 0; case WM_RBUTTONUP: MouseX = LOWORD(lParam); // BUGFIX (short)LOWORD coords are signed MouseY = HIWORD(lParam); // BUGFIX (short)HIWORD coords are signed if (sgbMouseDown == CLICK_RIGHT) { sgbMouseDown = CLICK_NONE; ReleaseCapture(); } return 0; case WM_CAPTURECHANGED: if (hWnd != (HWND)lParam) { sgbMouseDown = CLICK_NONE; track_repeat_walk(FALSE); } break; case WM_DIABNEXTLVL: case WM_DIABPREVLVL: case WM_DIABRTNLVL: case WM_DIABSETLVL: case WM_DIABWARPLVL: case WM_DIABTOWNWARP: case WM_DIABTWARPUP: case WM_DIABRETOWN: if (gbMaxPlayers > 1) pfile_write_hero(); nthread_ignore_mutex(TRUE); PaletteFadeOut(8); sound_stop(); music_stop(); track_repeat_walk(FALSE); sgbMouseDown = CLICK_NONE; ReleaseCapture(); ShowProgress(uMsg); force_redraw = 255; DrawAndBlit(); if (gbRunGame) PaletteFadeIn(8); nthread_ignore_mutex(FALSE); gbGameLoopStartup = TRUE; return 0; } return MainWndProc(hWnd, uMsg, wParam, lParam); } void LoadLvlGFX() { assert(!pDungeonCels); switch (leveltype) { case DTYPE_TOWN: #ifdef HELLFIRE pDungeonCels = LoadFileInMem("NLevels\\TownData\\Town.CEL", NULL); pMegaTiles = LoadFileInMem("NLevels\\TownData\\Town.TIL", NULL); pLevelPieces = LoadFileInMem("NLevels\\TownData\\Town.MIN", NULL); #else pDungeonCels = LoadFileInMem("Levels\\TownData\\Town.CEL", NULL); pMegaTiles = LoadFileInMem("Levels\\TownData\\Town.TIL", NULL); pLevelPieces = LoadFileInMem("Levels\\TownData\\Town.MIN", NULL); #endif pSpecialCels = LoadFileInMem("Levels\\TownData\\TownS.CEL", NULL); break; case DTYPE_CATHEDRAL: #ifdef HELLFIRE if (currlevel < 21) { #endif pDungeonCels = LoadFileInMem("Levels\\L1Data\\L1.CEL", NULL); pMegaTiles = LoadFileInMem("Levels\\L1Data\\L1.TIL", NULL); pLevelPieces = LoadFileInMem("Levels\\L1Data\\L1.MIN", NULL); pSpecialCels = LoadFileInMem("Levels\\L1Data\\L1S.CEL", NULL); #ifdef HELLFIRE } else { pDungeonCels = LoadFileInMem("NLevels\\L5Data\\L5.CEL", NULL); pMegaTiles = LoadFileInMem("NLevels\\L5Data\\L5.TIL", NULL); pLevelPieces = LoadFileInMem("NLevels\\L5Data\\L5.MIN", NULL); pSpecialCels = LoadFileInMem("NLevels\\L5Data\\L5S.CEL", NULL); } #endif break; #ifndef SPAWN case DTYPE_CATACOMBS: pDungeonCels = LoadFileInMem("Levels\\L2Data\\L2.CEL", NULL); pMegaTiles = LoadFileInMem("Levels\\L2Data\\L2.TIL", NULL); pLevelPieces = LoadFileInMem("Levels\\L2Data\\L2.MIN", NULL); pSpecialCels = LoadFileInMem("Levels\\L2Data\\L2S.CEL", NULL); break; case DTYPE_CAVES: #ifdef HELLFIRE if (currlevel < 17) { #endif pDungeonCels = LoadFileInMem("Levels\\L3Data\\L3.CEL", NULL); pMegaTiles = LoadFileInMem("Levels\\L3Data\\L3.TIL", NULL); pLevelPieces = LoadFileInMem("Levels\\L3Data\\L3.MIN", NULL); #ifdef HELLFIRE } else { pDungeonCels = LoadFileInMem("NLevels\\L6Data\\L6.CEL", NULL); pMegaTiles = LoadFileInMem("NLevels\\L6Data\\L6.TIL", NULL); pLevelPieces = LoadFileInMem("NLevels\\L6Data\\L6.MIN", NULL); } #endif pSpecialCels = LoadFileInMem("Levels\\L1Data\\L1S.CEL", NULL); break; case DTYPE_HELL: pDungeonCels = LoadFileInMem("Levels\\L4Data\\L4.CEL", NULL); pMegaTiles = LoadFileInMem("Levels\\L4Data\\L4.TIL", NULL); pLevelPieces = LoadFileInMem("Levels\\L4Data\\L4.MIN", NULL); pSpecialCels = LoadFileInMem("Levels\\L2Data\\L2S.CEL", NULL); break; #endif default: app_fatal("LoadLvlGFX"); break; } } void LoadAllGFX() { assert(!pSpeedCels); pSpeedCels = DiabloAllocPtr(0x100000); IncProgress(); IncProgress(); InitObjectGFX(); IncProgress(); InitMissileGFX(); IncProgress(); } /** * @param lvldir method of entry */ void CreateLevel(int lvldir) { switch (leveltype) { case DTYPE_TOWN: CreateTown(lvldir); InitTownTriggers(); LoadRndLvlPal(0); break; case DTYPE_CATHEDRAL: CreateL5Dungeon(glSeedTbl[currlevel], lvldir); InitL1Triggers(); Freeupstairs(); #ifdef HELLFIRE if (currlevel < 21) { LoadRndLvlPal(1); } else { LoadRndLvlPal(5); } #else LoadRndLvlPal(1); #endif break; #ifndef SPAWN case DTYPE_CATACOMBS: CreateL2Dungeon(glSeedTbl[currlevel], lvldir); InitL2Triggers(); Freeupstairs(); LoadRndLvlPal(2); break; case DTYPE_CAVES: CreateL3Dungeon(glSeedTbl[currlevel], lvldir); InitL3Triggers(); Freeupstairs(); #ifdef HELLFIRE if (currlevel < 17) { LoadRndLvlPal(3); } else { LoadRndLvlPal(6); } #else LoadRndLvlPal(3); #endif break; case DTYPE_HELL: CreateL4Dungeon(glSeedTbl[currlevel], lvldir); InitL4Triggers(); Freeupstairs(); LoadRndLvlPal(4); break; #endif default: app_fatal("CreateLevel"); break; } } void LoadGameLevel(BOOL firstflag, int lvldir) { int i, j; BOOL visited; if (setseed) glSeedTbl[currlevel] = setseed; music_stop(); SetCursor_(CURSOR_HAND); SetRndSeed(glSeedTbl[currlevel]); IncProgress(); MakeLightTable(); LoadLvlGFX(); IncProgress(); if (firstflag) { InitInv(); InitItemGFX(); InitQuestText(); 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 != ENTRY_LOAD) { 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 == ENTRY_RTNLVL) GetReturnLvlPos(); if (lvldir == ENTRY_WARPLVL) GetPortalLvlPos(); IncProgress(); for (i = 0; i < MAX_PLRS; i++) { if (plr[i].plractive && currlevel == plr[i].plrlevel) { InitPlayerGFX(i); if (lvldir != ENTRY_LOAD) InitPlayer(i, firstflag); } } PlayDungMsgs(); InitMultiView(); IncProgress(); visited = FALSE; 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 == ENTRY_LOAD || !plr[myplr]._pLvlVisited[currlevel] || gbMaxPlayers != 1) { HoldThemeRooms(); glMid1Seed[currlevel] = GetRndSeed(); InitMonsters(); glMid2Seed[currlevel] = GetRndSeed(); InitObjects(); InitItems(); #ifdef HELLFIRE if (currlevel < 17) #endif CreateThemeRooms(); glMid3Seed[currlevel] = GetRndSeed(); InitMissiles(); InitDead(); glEndSeed[currlevel] = GetRndSeed(); if (gbMaxPlayers != 1) DeltaLoadLevel(); IncProgress(); SavePreLighting(); } else { InitMonsters(); InitMissiles(); InitDead(); IncProgress(); LoadLevel(); IncProgress(); } } else { for (i = 0; i < MAXDUNX; i++) { for (j = 0; j < MAXDUNY; j++) dFlags[i][j] |= BFLAG_LIT; } InitTowners(); InitItems(); InitMissiles(); IncProgress(); if (!firstflag && lvldir != ENTRY_LOAD && plr[myplr]._pLvlVisited[currlevel] && gbMaxPlayers == 1) LoadLevel(); if (gbMaxPlayers != 1) DeltaLoadLevel(); IncProgress(); } if (gbMaxPlayers == 1) ResyncQuests(); else ResyncMPQuests(); #ifndef SPAWN } else { assert(!pSpeedCels); pSpeedCels = DiabloAllocPtr(0x100000); LoadSetMap(); IncProgress(); GetLevelMTypes(); // BUGFIX: must invoke FillSolidBlockTbls prior to invoking InitMonsters, // as placement of unique monsters in set levels require initialization // of nSolidTable. In particular, InitMonsters -> PlaceQuestMonsters -> // PlaceUniqueMonst -> MonstPlace -> SolidLoc, which requires nSolidTable // to be initialized. InitMonsters(); InitMissileGFX(); InitDead(); FillSolidBlockTbls(); IncProgress(); if (lvldir == ENTRY_WARPLVL) GetPortalLvlPos(); for (i = 0; i < MAX_PLRS; i++) { if (plr[i].plractive && currlevel == plr[i].plrlevel) { InitPlayerGFX(i); if (lvldir != ENTRY_LOAD) InitPlayer(i, firstflag); } } InitMultiView(); IncProgress(); if (firstflag || lvldir == ENTRY_LOAD || !plr[myplr]._pSLvlVisited[setlvlnum]) { InitItems(); SavePreLighting(); } else { LoadLevel(); } InitMissiles(); IncProgress(); #endif } 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) { if (gbMaxPlayers == 1) dPlayer[plr[i]._px][plr[i]._py] = i + 1; else SyncInitPlrPos(i); } else { dFlags[plr[i]._px][plr[i]._py] |= BFLAG_DEAD_PLAYER; } } } if (leveltype != DTYPE_TOWN) SetDungeonMicros(); InitLightMax(); IncProgress(); IncProgress(); if (firstflag) { InitControlPan(); IncProgress(); } if (leveltype != DTYPE_TOWN) { ProcessLightList(); ProcessVisionList(); } #ifdef HELLFIRE if (currlevel >= 21) { if (currlevel == 21) { CornerstoneLoad(CornerStone.x, CornerStone.y); } if (quests[Q_NAKRUL]._qactive == QUEST_DONE && currlevel == 24) { SyncNakrulRoom(); } } #endif #ifdef HELLFIRE if (currlevel >= 17) music_start(currlevel > 20 ? TMUSIC_L5 : TMUSIC_L6); else music_start(leveltype); #else music_start(leveltype); #endif while (!IncProgress()) ; #ifndef SPAWN if (setlevel && setlvlnum == SL_SKELKING && quests[Q_SKELKING]._qactive == QUEST_ACTIVE) PlaySFX(USFX_SKING1); #endif } static void game_logic() { if (PauseMode == 2) { return; } if (PauseMode == 1) { PauseMode = 2; } if (gbMaxPlayers == 1 && gmenu_is_active()) { force_redraw |= 1; return; } if (!gmenu_is_active() && 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 && GetAsyncKeyState(VK_SHIFT) & 0x8000) { ScrollView(); } #endif sound_update(); ClearPlrMsg(); CheckTriggers(); CheckQuests(); force_redraw |= 1; pfile_update(FALSE); } static void timeout_cursor(BOOL bTimeout) { if (bTimeout) { if (sgnTimeoutCurs == CURSOR_NONE && sgbMouseDown == CLICK_NONE) { sgnTimeoutCurs = pcurs; multi_net_ping(); ClearPanel(); AddPanelString("-- Network timeout --", TRUE); AddPanelString("-- Waiting for players --", TRUE); NewCursor(CURSOR_HOURGLASS); force_redraw = 255; } scrollrt_draw_game_screen(TRUE); } else if (sgnTimeoutCurs != CURSOR_NONE) { SetCursor_(sgnTimeoutCurs); sgnTimeoutCurs = CURSOR_NONE; ClearPanel(); force_redraw = 255; } } /** * @param bStartup Process additional ticks before returning */ void game_loop(BOOL bStartup) { int i; i = bStartup ? 60 : 3; while (i--) { if (!multi_handle_delta()) { timeout_cursor(TRUE); break; } else { timeout_cursor(FALSE); game_logic(); } if (!gbRunGame || gbMaxPlayers == 1 || !nthread_has_500ms_passed(TRUE)) break; } } void diablo_color_cyc_logic() { DWORD tc; tc = GetTickCount(); if (tc - color_cycle_timer >= 50) { color_cycle_timer = tc; #ifndef HELLFIRE if (!palette_get_color_cycling()) return; #endif if (leveltype == DTYPE_HELL) { lighting_color_cycling(); #ifdef HELLFIRE } else if (currlevel >= 21) { palette_update_crypt(); } else if (currlevel >= 17) { palette_update_hive(); #endif } else if (leveltype == DTYPE_CAVES) { if (fullscreen) palette_update_caves(); } } } #ifdef HELLFIRE static PlayerStruct *get_plr_mem(PlayerStruct *p) { void *r; PlayerStruct *pPlayer; r = malloc(rand() & 0x7FFF); pPlayer = (PlayerStruct *)malloc(sizeof(PlayerStruct) * MAX_PLRS); if (r != NULL) { free(r); } if (pPlayer == NULL) { return p; } if (p != NULL) { memcpy(pPlayer, p, sizeof(PlayerStruct) * MAX_PLRS); free(p); } return pPlayer; } void alloc_plr() { plr = get_plr_mem(NULL); if (plr == NULL) { app_fatal("Unable to initialize memory"); } memset(plr, 0, sizeof(PlayerStruct) * MAX_PLRS); } #endif ================================================ FILE: Source/diablo.h ================================================ /** * @file diablo.h * * Interface of the main game initialization functions. */ #ifndef __DIABLO_H__ #define __DIABLO_H__ extern HWND ghMainWnd; extern DWORD glSeedTbl[NUMLEVELS]; extern int gnLevelTypeTbl[NUMLEVELS]; extern int MouseX; extern int MouseY; extern BOOL gbRunGame; extern BOOL gbRunGameResult; extern BOOL zoomflag; extern BOOL gbProcessPlayers; extern BOOL gbLoadGame; extern HINSTANCE ghInst; extern int DebugMonsters[10]; extern BOOLEAN cineflag; extern int force_redraw; extern BOOL visiondebug; /** unused */ extern BOOL light4flag; extern BOOL leveldebug; extern BOOL monstdebug; /** unused */ extern int debugmonsttypes; extern int PauseMode; #ifdef HELLFIRE extern BOOLEAN UseTheoQuest; extern BOOLEAN UseCowFarmer; extern BOOLEAN UseNestArt; extern BOOLEAN UseBardTest; extern BOOLEAN UseBarbarianTest; extern BOOLEAN UseMultiTest; #endif extern char sgbMouseDown; void FreeGameMem(); BOOL StartGame(BOOL bNewGame, BOOL bSinglePlayer); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); BOOL PressEscKey(); LRESULT CALLBACK DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK GM_Game(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void LoadGameLevel(BOOL firstflag, int lvldir); void game_loop(BOOL bStartup); void diablo_color_cyc_logic(); #ifdef HELLFIRE void alloc_plr(); #endif /* rdata */ extern BOOL fullscreen; #ifdef _DEBUG extern int questdebug; 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 frameflag; extern int frameend; extern int framerate; extern int framestart; #endif extern BOOL FriendlyMode; #endif /* __DIABLO_H__ */ ================================================ FILE: Source/doom.cpp ================================================ /** * @file doom.cpp * * Implementation of the map of the stars quest. */ #include "all.h" int doom_quest_time; int doom_stars_drawn; BYTE *pDoomCel; DIABOOL doomflag; int DoomQuestState; /* void doom_reset_state() { if (DoomQuestState <= 0) { DoomQuestState = 0; } } void doom_play_movie() { if (DoomQuestState < 36001) { DoomQuestState++; if (DoomQuestState == 36001) { PlayInGameMovie("gendata\\doom.smk"); DoomQuestState++; } } } */ int doom_get_frame_from_time() { if (DoomQuestState == 36001) { return 31; } return DoomQuestState / 1200; } void doom_cleanup() { #ifdef HELLFIRE if (pDoomCel != NULL) { MemFreeDbg(pDoomCel); pDoomCel = NULL; } #else MemFreeDbg(pDoomCel); #endif } #ifdef HELLFIRE static BOOLEAN doom_alloc_cel() #else static void doom_alloc_cel() #endif { #ifdef HELLFIRE doom_cleanup(); pDoomCel = DiabloAllocPtr(0x39000); return pDoomCel ? TRUE : FALSE; #else pDoomCel = DiabloAllocPtr(0x38000); #endif } #ifdef HELLFIRE static BOOLEAN doom_load_graphics() #else static void doom_load_graphics() #endif { #ifdef HELLFIRE BOOLEAN ret; ret = FALSE; strcpy(tempstr, "Items\\Map\\MapZtown.CEL"); if (LoadFileWithMem(tempstr, pDoomCel)) ret = TRUE; return ret; #else 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); #endif } void doom_init() { #ifdef HELLFIRE if (doom_alloc_cel()) { doom_quest_time = doom_get_frame_from_time() == 31 ? 31 : 0; if (doom_load_graphics()) { doomflag = TRUE; } else { doom_close(); } } #else doomflag = TRUE; doom_alloc_cel(); doom_quest_time = doom_get_frame_from_time() == 31 ? 31 : 0; doom_load_graphics(); #endif } void doom_close() { #ifndef HELLFIRE if (doomflag) { #endif doomflag = FALSE; doom_cleanup(); #ifndef HELLFIRE } #endif } void doom_draw() { if (!doomflag) { return; } #ifndef HELLFIRE 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(); } } #endif CelDraw(SCREEN_X, PANEL_Y - 1, pDoomCel, 1, 640); } ================================================ FILE: Source/doom.h ================================================ /** * @file doom.h * * Interface of the map of the stars quest. */ #ifndef __DOOM_H__ #define __DOOM_H__ extern DIABOOL doomflag; extern int DoomQuestState; void doom_init(); void doom_close(); void doom_draw(); #endif /* __DOOM_H__ */ ================================================ FILE: Source/drlg_l1.cpp ================================================ /** * @file drlg_l1.cpp * * Implementation of the cathedral level generation algorithms. */ #include "all.h" /** Represents a tile ID map of twice the size, repeating each tile of the original map in blocks of 4. */ BYTE L5dungeon[80][80]; BYTE L5dflags[DMAXX][DMAXY]; /** Specifies whether a single player quest DUN has been loaded. */ BOOL L5setloadflag; /** Specifies whether to generate a horizontal room at position 1 in the Cathedral. */ int HR1; /** Specifies whether to generate a horizontal room at position 2 in the Cathedral. */ int HR2; /** Specifies whether to generate a horizontal room at position 3 in the Cathedral. */ int HR3; #ifdef HELLFIRE int UberRow; int UberCol; int dword_577368; int IsUberRoomOpened; int UberLeverRow; int UberLeverCol; int IsUberLeverActivated; int UberDiabloMonsterIndex; #endif /** Specifies whether to generate a vertical room at position 1 in the Cathedral. */ BOOL VR1; /** Specifies whether to generate a vertical room at position 2 in the Cathedral. */ BOOL VR2; /** Specifies whether to generate a vertical room at position 3 in the Cathedral. */ BOOL VR3; /** Contains the contents of the single player quest DUN file. */ BYTE *L5pSetPiece; /** Contains shadows for 2x2 blocks of base tile IDs in the Cathedral. */ const ShadowStruct SPATS[37] = { // clang-format off // strig, s1, s2, s3, nv1, nv2, nv3 { 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 } // clang-format on }; // BUGFIX: This array should contain an additional 0 (207 elements). /** Maps tile IDs to their corresponding base tile ID. */ const BYTE 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 }; // BUGFIX: This array should contain an additional 0 (207 elements). /** Maps tile IDs to their corresponding undecorated tile ID. */ const BYTE 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 }; /** Miniset: stairs up on a corner wall. */ const BYTE STAIRSUP[] = { // clang-format off 4, 4, // width, height 13, 13, 13, 13, // search 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 0, 66, 6, 0, // replace 63, 64, 65, 0, 0, 67, 68, 0, 0, 0, 0, 0, // clang-format on }; #ifdef HELLFIRE const BYTE L5STAIRSUP[] = { // clang-format off 4, 5, // width, height 22, 22, 22, 22, // search 22, 22, 22, 22, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 0, 54, 23, 0, // replace 0, 53, 18, 0, 55, 56, 57, 0, 58, 59, 60, 0, 0, 0, 0, 0 // clang-format on }; #else /** Miniset: stairs up. */ const BYTE L5STAIRSUP[] = { // clang-format off 4, 4, // width, height 22, 22, 22, 22, // search 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 0, 66, 23, 0, // replace 63, 64, 65, 0, 0, 67, 68, 0, 0, 0, 0, 0, // clang-format on }; #endif /** Miniset: stairs down. */ const BYTE STAIRSDOWN[] = { // clang-format off 4, 3, // width, height 13, 13, 13, 13, // search 13, 13, 13, 13, 13, 13, 13, 13, 62, 57, 58, 0, // replace 61, 59, 60, 0, 0, 0, 0, 0, // clang-format on }; #ifdef HELLFIRE const BYTE L5STAIRSDOWN[] = { // clang-format off 4, 5, // width, height 13, 13, 13, 13, // search 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 0, 0, 52, 0, // replace 0, 48, 51, 0, 0, 47, 50, 0, 45, 46, 49, 0, 0, 0, 0, 0, // clang-format on }; const BYTE L5STAIRSTOWN[] = { // clang-format off 4, 5, // width, height 22, 22, 22, 22, // search 22, 22, 22, 22, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 0, 62, 23, 0, // replace 0, 61, 18, 0, 63, 64, 65, 0, 66, 67, 68, 0, 0, 0, 0, 0, // clang-format on }; #endif /** Miniset: candlestick. */ const BYTE LAMPS[] = { // clang-format off 2, 2, // width, height 13, 0, // search 13, 13, 129, 0, // replace 130, 128, // clang-format on }; /** Miniset: Poisoned Water Supply entrance. */ const BYTE PWATERIN[] = { // clang-format off 6, 6, // width, height 13, 13, 13, 13, 13, 13, // search 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, // replace 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, // clang-format on }; #ifdef HELLFIRE const BYTE byte_48A1B4[4] = { 1, 1, 11, 95 }; const BYTE byte_48A1B8[8] = { 1, 1, 12, 96 }; const BYTE byte_48A1C0[8] = { // clang-format off 1, 3, // width, height 1, // search 1, 1, 91, // replace 90, 89, // clang-format on }; const BYTE byte_48A1C8[8] = { // clang-format off 3, 1, // width, height 2, 2, 2, // search 94, 93, 92, // replace // clang-format on }; const BYTE byte_48A1D0[4] = { 1, 1, 13, 97 }; const BYTE byte_48A1D4[4] = { 1, 1, 13, 98 }; const BYTE byte_48A1D8[4] = { 1, 1, 13, 99 }; const BYTE byte_48A1DC[4] = { 1, 1, 13, 100 }; const BYTE byte_48A1E0[20] = { // clang-format off 3, 3, // width, height 13, 13, 13, // search 13, 13, 13, 13, 13, 13, 0, 0, 0, // replace 0, 101, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A1F4[4] = { 1, 1, 11, 185 }; const BYTE byte_48A1F8[4] = { 1, 1, 11, 186 }; const BYTE byte_48A1FC[4] = { 1, 1, 12, 187 }; const BYTE byte_48A200[4] = { 1, 1, 12, 188 }; const BYTE byte_48A204[4] = { 1, 1, 89, 173 }; const BYTE byte_48A208[4] = { 1, 1, 89, 174 }; const BYTE byte_48A20C[4] = { 1, 1, 90, 175 }; const BYTE byte_48A210[4] = { 1, 1, 90, 176 }; const BYTE byte_48A214[4] = { 1, 1, 91, 177 }; const BYTE byte_48A218[4] = { 1, 1, 91, 178 }; const BYTE byte_48A21C[4] = { 1, 1, 92, 179 }; const BYTE byte_48A220[4] = { 1, 1, 92, 180 }; const BYTE byte_48A224[4] = { 1, 1, 92, 181 }; const BYTE byte_48A228[4] = { 1, 1, 92, 182 }; const BYTE byte_48A22C[4] = { 1, 1, 92, 183 }; const BYTE byte_48A230[4] = { 1, 1, 92, 184 }; const BYTE byte_48A234[4] = { 1, 1, 98, 189 }; const BYTE byte_48A238[4] = { 1, 1, 98, 190 }; const BYTE byte_48A23C[4] = { 1, 1, 97, 191 }; const BYTE byte_48A240[4] = { 1, 1, 15, 192 }; const BYTE byte_48A244[4] = { 1, 1, 99, 193 }; const BYTE byte_48A248[4] = { 1, 1, 99, 194 }; const BYTE byte_48A24C[4] = { 1, 1, 100, 195 }; const BYTE byte_48A250[4] = { 1, 1, 101, 196 }; const BYTE byte_48A254[4] = { 1, 1, 101, 197 }; const BYTE byte_48A258[8] = { 1, 1, 101, 198 }; const BYTE byte_48A260[24] = { // clang-format off 3, 3, // width, height 13, 13, 13, // search 13, 13, 13, 13, 13, 13, 0, 0, 0, // replace 0, 167, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A278[24] = { // clang-format off 3, 3, // width, height 13, 13, 13, // search 13, 13, 13, 13, 13, 13, 0, 0, 0, // replace 0, 168, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A290[24] = { // clang-format off 3, 3, // width, height 13, 13, 13, // search 13, 13, 13, 13, 13, 13, 0, 0, 0, // replace 0, 169, 0, 0, 0, 0, }; const BYTE byte_48A2A8[24] = { // clang-format off 3, 3, // width, height 13, 13, 13, // search 13, 13, 13, 13, 13, 13, 0, 0, 0, // replace 0, 170, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A2C0[24] = { // clang-format off 3, 3, // width, height 13, 13, 13, // search 13, 13, 13, 13, 13, 13, 0, 0, 0, // replace 0, 171, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A2D8[20] = { // clang-format off 3, 3, // width, height 13, 13, 13, // search 13, 13, 13, 13, 13, 13, 0, 0, 0, // replace 0, 172, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A2EC[4] = { 1, 1, 13, 163 }; const BYTE byte_48A2F0[4] = { 1, 1, 13, 164 }; const BYTE byte_48A2F4[4] = { 1, 1, 13, 165 }; const BYTE byte_48A2F8[4] = { 1, 1, 13, 166 }; const BYTE byte_48A2FC[4] = { 1, 1, 1, 112 }; const BYTE byte_48A300[4] = { 1, 1, 2, 113 }; const BYTE byte_48A304[4] = { 1, 1, 3, 114 }; const BYTE byte_48A308[4] = { 1, 1, 4, 115 }; const BYTE byte_48A30C[4] = { 1, 1, 5, 116 }; const BYTE byte_48A310[4] = { 1, 1, 6, 117 }; const BYTE byte_48A314[4] = { 1, 1, 7, 118 }; const BYTE byte_48A318[4] = { 1, 1, 8, 119 }; const BYTE byte_48A31C[4] = { 1, 1, 9, 120 }; const BYTE byte_48A320[4] = { 1, 1, 10, 121 }; const BYTE byte_48A324[4] = { 1, 1, 11, 122 }; const BYTE byte_48A328[4] = { 1, 1, 12, 123 }; const BYTE byte_48A32C[4] = { 1, 1, 13, 124 }; const BYTE byte_48A330[4] = { 1, 1, 14, 125 }; const BYTE byte_48A334[4] = { 1, 1, 15, 126 }; const BYTE byte_48A338[4] = { 1, 1, 16, 127 }; const BYTE byte_48A33C[4] = { 1, 1, 17, 128 }; const BYTE byte_48A340[4] = { 1, 1, 1, 129 }; const BYTE byte_48A344[4] = { 1, 1, 2, 130 }; const BYTE byte_48A348[4] = { 1, 1, 3, 131 }; const BYTE byte_48A34C[4] = { 1, 1, 4, 132 }; const BYTE byte_48A350[4] = { 1, 1, 5, 133 }; const BYTE byte_48A354[4] = { 1, 1, 6, 134 }; const BYTE byte_48A358[4] = { 1, 1, 7, 135 }; const BYTE byte_48A35C[4] = { 1, 1, 8, 136 }; const BYTE byte_48A360[4] = { 1, 1, 9, 137 }; const BYTE byte_48A364[4] = { 1, 1, 10, 138 }; const BYTE byte_48A368[4] = { 1, 1, 11, 139 }; const BYTE byte_48A36C[4] = { 1, 1, 12, 140 }; const BYTE byte_48A370[4] = { 1, 1, 13, 141 }; const BYTE byte_48A374[4] = { 1, 1, 14, 142 }; const BYTE byte_48A378[4] = { 1, 1, 15, 143 }; const BYTE byte_48A37C[4] = { 1, 1, 16, 144 }; const BYTE byte_48A380[4] = { 1, 1, 17, 145 }; const BYTE byte_48A384[4] = { 1, 1, 1, 146 }; const BYTE byte_48A388[4] = { 1, 1, 2, 147 }; const BYTE byte_48A38C[4] = { 1, 1, 3, 148 }; const BYTE byte_48A390[4] = { 1, 1, 4, 149 }; const BYTE byte_48A394[4] = { 1, 1, 5, 150 }; const BYTE byte_48A398[4] = { 1, 1, 6, 151 }; const BYTE byte_48A39C[4] = { 1, 1, 7, 152 }; const BYTE byte_48A3A0[4] = { 1, 1, 8, 153 }; const BYTE byte_48A3A4[4] = { 1, 1, 9, 154 }; const BYTE byte_48A3A8[4] = { 1, 1, 10, 155 }; const BYTE byte_48A3AC[4] = { 1, 1, 11, 156 }; const BYTE byte_48A3B0[4] = { 1, 1, 12, 157 }; const BYTE byte_48A3B4[4] = { 1, 1, 13, 158 }; const BYTE byte_48A3B8[4] = { 1, 1, 14, 159 }; const BYTE byte_48A3BC[4] = { 1, 1, 15, 160 }; const BYTE byte_48A3C0[4] = { 1, 1, 16, 161 }; const BYTE byte_48A3C4[4] = { 1, 1, 17, 162 }; const BYTE byte_48A3C8[4] = { 1, 1, 1, 199 }; const BYTE byte_48A3CC[4] = { 1, 1, 1, 201 }; const BYTE byte_48A3D0[4] = { 1, 1, 2, 200 }; const BYTE byte_48A3D4[4] = { 1, 1, 2, 202 }; #endif /* data */ #ifdef HELLFIRE BYTE UberRoomPattern[26] = { // clang-format off 4, 6, // width, height 115, 130, 6, 13, // pattern 129, 108, 1, 13, 1, 107, 103, 13, 146, 106, 102, 13, 129, 168, 1, 13, 7, 2, 3, 13, // clang-format on }; BYTE CornerstoneRoomPattern[27] = { // clang-format off 5, 5, // width, height 4, 2, 2, 2, 6, // pattern 1, 111, 172, 0, 1, 1, 172, 0, 0, 25, 1, 0, 0, 0, 1, 7, 2, 2, 2, 3, // clang-format on }; #endif /** * A lookup table for the 16 possible patterns of a 2x2 area, * where each cell either contains a SW wall or it doesn't. */ BYTE L5ConvTbl[16] = { 22, 13, 1, 13, 2, 13, 13, 13, 4, 13, 1, 13, 2, 13, 16, 13 }; #ifdef HELLFIRE void DRLG_InitL5Vals() { int i, j, pc; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 77) { pc = 1; } else if (dPiece[i][j] == 80) { pc = 2; } else { continue; } dSpecial[i][j] = pc; } } } #endif static void DRLG_PlaceDoor(int x, int y) { if ((L5dflags[x][y] & DLRG_PROTECTED) == 0) { BYTE df = L5dflags[x][y] & 0x7F; BYTE c = dungeon[x][y]; if (df == 1) { if (y != 1 && c == 2) dungeon[x][y] = 26; if (y != 1 && c == 7) dungeon[x][y] = 31; if (y != 1 && c == 14) dungeon[x][y] = 42; if (y != 1 && c == 4) dungeon[x][y] = 43; if (x != 1 && c == 1) dungeon[x][y] = 25; if (x != 1 && c == 10) dungeon[x][y] = 40; if (x != 1 && c == 6) dungeon[x][y] = 30; } if (df == 2) { if (x != 1 && c == 1) dungeon[x][y] = 25; if (x != 1 && c == 6) dungeon[x][y] = 30; if (x != 1 && c == 10) dungeon[x][y] = 40; if (x != 1 && c == 4) dungeon[x][y] = 41; if (y != 1 && c == 2) dungeon[x][y] = 26; if (y != 1 && c == 14) dungeon[x][y] = 42; if (y != 1 && c == 7) dungeon[x][y] = 31; } if (df == 3) { if (x != 1 && y != 1 && c == 4) dungeon[x][y] = 28; if (x != 1 && c == 10) dungeon[x][y] = 40; if (y != 1 && c == 14) dungeon[x][y] = 42; if (y != 1 && c == 2) dungeon[x][y] = 26; if (x != 1 && c == 1) dungeon[x][y] = 25; if (y != 1 && c == 7) dungeon[x][y] = 31; if (x != 1 && c == 6) dungeon[x][y] = 30; } } L5dflags[x][y] = DLRG_PROTECTED; } #ifdef HELLFIRE void drlg_l1_crypt_lavafloor() { int i, j; for (j = 1; j < 40; j++) { for (i = 1; i < 40; i++) { switch (dungeon[i][j]) { case 5: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 7: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; break; case 8: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 9: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 10: if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 11: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 12: if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 14: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 15: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; break; case 17: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; break; case 95: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 96: if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 208; break; case 116: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 118: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; break; case 119: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 120: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 121: if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 122: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 211; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 212; break; case 123: if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 125: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 126: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; break; case 128: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; break; case 133: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 135: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; break; case 136: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 137: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 213; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 214; if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 138: if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 139: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 215; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 216; break; case 140: if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 217; break; case 142: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 143: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 213; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 214; break; case 145: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 213; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 214; break; case 150: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 217; break; case 152: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; break; case 153: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 154: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 155: if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 205; break; case 156: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 157: if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 217; break; case 159: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 160: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 206; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 207; break; case 162: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 209; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 210; break; case 167: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 209; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 210; break; case 187: if (dungeon[i][j - 1] == 13) dungeon[i][j - 1] = 208; break; case 185: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 186: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 203; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 204; break; case 192: if (dungeon[i - 1][j] == 13) dungeon[i - 1][j] = 209; if (dungeon[i - 1][j - 1] == 13) dungeon[i - 1][j - 1] = 210; break; } } } } #endif static void DRLG_L1Shadows() { int x, y, i; BYTE sd[2][2]; BYTE tnv3; BOOL patflag; for (y = 1; y < DMAXY; y++) { for (x = 1; x < DMAXX; x++) { sd[0][0] = BSTYPES[dungeon[x][y]]; sd[1][0] = BSTYPES[dungeon[x - 1][y]]; sd[0][1] = BSTYPES[dungeon[x][y - 1]]; sd[1][1] = BSTYPES[dungeon[x - 1][y - 1]]; for (i = 0; i < 37; i++) { if (SPATS[i].strig == sd[0][0]) { patflag = TRUE; if (SPATS[i].s1 && SPATS[i].s1 != sd[1][1]) patflag = FALSE; if (SPATS[i].s2 && SPATS[i].s2 != sd[0][1]) patflag = FALSE; if (SPATS[i].s3 && SPATS[i].s3 != sd[1][0]) patflag = FALSE; if (patflag == TRUE) { if (SPATS[i].nv1 && !L5dflags[x - 1][y - 1]) dungeon[x - 1][y - 1] = SPATS[i].nv1; if (SPATS[i].nv2 && !L5dflags[x][y - 1]) dungeon[x][y - 1] = SPATS[i].nv2; if (SPATS[i].nv3 && !L5dflags[x - 1][y]) dungeon[x - 1][y] = SPATS[i].nv3; } } } } } for (y = 1; y < DMAXY; y++) { for (x = 1; x < DMAXX; x++) { if (dungeon[x - 1][y] == 139 && !L5dflags[x - 1][y]) { tnv3 = 139; if (dungeon[x][y] == 29) tnv3 = 141; if (dungeon[x][y] == 32) tnv3 = 141; if (dungeon[x][y] == 35) tnv3 = 141; if (dungeon[x][y] == 37) tnv3 = 141; if (dungeon[x][y] == 38) tnv3 = 141; if (dungeon[x][y] == 39) tnv3 = 141; dungeon[x - 1][y] = tnv3; } if (dungeon[x - 1][y] == 149 && !L5dflags[x - 1][y]) { tnv3 = 149; if (dungeon[x][y] == 29) tnv3 = 153; if (dungeon[x][y] == 32) tnv3 = 153; if (dungeon[x][y] == 35) tnv3 = 153; if (dungeon[x][y] == 37) tnv3 = 153; if (dungeon[x][y] == 38) tnv3 = 153; if (dungeon[x][y] == 39) tnv3 = 153; dungeon[x - 1][y] = tnv3; } if (dungeon[x - 1][y] == 148 && !L5dflags[x - 1][y]) { tnv3 = 148; if (dungeon[x][y] == 29) tnv3 = 154; if (dungeon[x][y] == 32) tnv3 = 154; if (dungeon[x][y] == 35) tnv3 = 154; if (dungeon[x][y] == 37) tnv3 = 154; if (dungeon[x][y] == 38) tnv3 = 154; if (dungeon[x][y] == 39) tnv3 = 154; dungeon[x - 1][y] = tnv3; } } } } static int DRLG_PlaceMiniSet(const BYTE *miniset, int tmin, int tmax, int cx, int cy, BOOL setview, int noquad, int ldir) { int sx, sy, sw, sh, xx, yy, i, ii, numt, found, t; BOOL abort; sw = miniset[0]; sh = miniset[1]; if (tmax - tmin == 0) numt = 1; else numt = random_(0, tmax - tmin) + tmin; for (i = 0; i < numt; i++) { sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); abort = FALSE; found = 0; while (abort == FALSE) { abort = TRUE; // BUGFIX: This code has no purpose but causes the set piece to never appear in x 0-13 or y 0-13 if (cx != -1 && sx >= cx - sw && sx <= cx + 12) { sx++; abort = FALSE; } if (cy != -1 && sy >= cy - sh && sy <= cy + 12) { sy++; abort = FALSE; } switch (noquad) { case 0: if (sx < cx && sy < cy) abort = FALSE; break; case 1: if (sx > cx && sy < cy) abort = FALSE; break; case 2: if (sx < cx && sy > cy) abort = FALSE; break; case 3: if (sx > cx && sy > cy) abort = FALSE; break; } ii = 2; for (yy = 0; yy < sh && abort == TRUE; yy++) { for (xx = 0; xx < sw && abort == TRUE; xx++) { if (miniset[ii] && dungeon[xx + sx][sy + yy] != miniset[ii]) abort = FALSE; if (L5dflags[xx + sx][sy + yy]) abort = FALSE; ii++; } } if (abort == FALSE) { if (++sx == DMAXX - sw) { sx = 0; if (++sy == DMAXY - sh) sy = 0; } if (++found > 4000) return -1; } } ii = sw * sh + 2; for (yy = 0; yy < sh; yy++) { for (xx = 0; xx < sw; xx++) { if (miniset[ii]) dungeon[xx + sx][sy + yy] = miniset[ii]; ii++; } } } if (miniset == PWATERIN) { t = TransVal; TransVal = 0; DRLG_MRectTrans(sx, sy + 2, sx + 5, sy + 4); TransVal = t; quests[Q_PWATER]._qtx = 2 * sx + 21; quests[Q_PWATER]._qty = 2 * sy + 22; } if (setview == TRUE) { ViewX = 2 * sx + 19; ViewY = 2 * sy + 20; } if (ldir == 0) { LvlViewX = 2 * sx + 19; LvlViewY = 2 * sy + 20; } if (sx < cx && sy < cy) return 0; if (sx > cx && sy < cy) return 1; if (sx < cx && sy > cy) return 2; else return 3; } static void DRLG_L1Floor() { int i, j; LONG rv; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (L5dflags[i][j] == 0 && dungeon[i][j] == 13) { rv = random_(0, 3); if (rv == 1) dungeon[i][j] = 162; if (rv == 2) dungeon[i][j] = 163; } } } } static void DRLG_L1Pass3() { int i, j, xx, yy; long v1, v2, v3, v4, lv; lv = 22 - 1; #ifdef USE_ASM __asm { mov esi, pMegaTiles mov eax, lv shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax } #else v1 = *((WORD *)&pMegaTiles[lv * 8] + 0) + 1; v2 = *((WORD *)&pMegaTiles[lv * 8] + 1) + 1; v3 = *((WORD *)&pMegaTiles[lv * 8] + 2) + 1; v4 = *((WORD *)&pMegaTiles[lv * 8] + 3) + 1; #endif for (j = 0; j < MAXDUNY; j += 2) { for (i = 0; i < MAXDUNX; i += 2) { dPiece[i][j] = v1; dPiece[i + 1][j] = v2; dPiece[i][j + 1] = v3; dPiece[i + 1][j + 1] = v4; } } yy = 16; for (j = 0; j < DMAXY; j++) { xx = 16; for (i = 0; i < DMAXX; i++) { lv = dungeon[i][j] - 1; /// ASSERT: assert(lv >= 0); #ifdef USE_ASM __asm { mov esi, pMegaTiles mov eax, lv shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax } #else v1 = *((WORD *)&pMegaTiles[lv * 8] + 0) + 1; v2 = *((WORD *)&pMegaTiles[lv * 8] + 1) + 1; v3 = *((WORD *)&pMegaTiles[lv * 8] + 2) + 1; v4 = *((WORD *)&pMegaTiles[lv * 8] + 3) + 1; #endif dPiece[xx][yy] = v1; dPiece[xx + 1][yy] = v2; dPiece[xx][yy + 1] = v3; dPiece[xx + 1][yy + 1] = v4; xx += 2; } yy += 2; } } static void DRLG_LoadL1SP() { L5setloadflag = FALSE; if (QuestStatus(Q_BUTCHER)) { L5pSetPiece = LoadFileInMem("Levels\\L1Data\\rnd6.DUN", NULL); L5setloadflag = TRUE; } if (QuestStatus(Q_SKELKING) && gbMaxPlayers == 1) { L5pSetPiece = LoadFileInMem("Levels\\L1Data\\SKngDO.DUN", NULL); L5setloadflag = TRUE; } if (QuestStatus(Q_LTBANNER)) { L5pSetPiece = LoadFileInMem("Levels\\L1Data\\Banner2.DUN", NULL); L5setloadflag = TRUE; } } static void DRLG_FreeL1SP() { MemFreeDbg(L5pSetPiece); } void DRLG_Init_Globals() { char c; memset(dFlags, 0, sizeof(dFlags)); memset(dPlayer, 0, sizeof(dPlayer)); memset(dMonster, 0, sizeof(dMonster)); memset(dDead, 0, sizeof(dDead)); memset(dObject, 0, sizeof(dObject)); memset(dItem, 0, sizeof(dItem)); memset(dMissile, 0, sizeof(dMissile)); memset(dSpecial, 0, sizeof(dSpecial)); if (!lightflag) { if (light4flag) c = 3; else c = 15; } else { c = 0; } memset(dLight, c, sizeof(dLight)); } static void DRLG_InitL1Vals() { int i, j, pc; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 12) { pc = 1; } else if (dPiece[i][j] == 11) { pc = 2; } else if (dPiece[i][j] == 71) { pc = 1; } else if (dPiece[i][j] == 259) { pc = 5; } else if (dPiece[i][j] == 249) { pc = 2; } else if (dPiece[i][j] == 325) { pc = 2; } else if (dPiece[i][j] == 321) { pc = 1; } else if (dPiece[i][j] == 255) { pc = 4; } else if (dPiece[i][j] == 211) { pc = 1; } else if (dPiece[i][j] == 344) { pc = 2; } else if (dPiece[i][j] == 341) { pc = 1; } else if (dPiece[i][j] == 331) { pc = 2; } else if (dPiece[i][j] == 418) { pc = 1; } else if (dPiece[i][j] == 421) { pc = 2; } else { continue; } dSpecial[i][j] = pc; } } } #ifndef SPAWN void LoadL1Dungeon(const char *sFileName, int vx, int vy) { int i, j, rw, rh; BYTE *pLevelMap, *lm; dminx = 16; dminy = 16; dmaxx = 96; dmaxy = 96; DRLG_InitTrans(); pLevelMap = LoadFileInMem(sFileName, NULL); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { dungeon[i][j] = 22; L5dflags[i][j] = 0; } } lm = pLevelMap; rw = *lm; lm += 2; rh = *lm; lm += 2; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm != 0) { dungeon[i][j] = *lm; L5dflags[i][j] |= DLRG_PROTECTED; } else { dungeon[i][j] = 13; } lm += 2; } } DRLG_L1Floor(); ViewX = vx; ViewY = vy; DRLG_L1Pass3(); DRLG_Init_Globals(); #ifdef HELLFIRE if (currlevel < 17) #endif DRLG_InitL1Vals(); SetMapMonsters(pLevelMap, 0, 0); SetMapObjects(pLevelMap, 0, 0); mem_free_dbg(pLevelMap); } void LoadPreL1Dungeon(const char *sFileName, int vx, int vy) { int i, j, rw, rh; BYTE *pLevelMap, *lm; dminx = 16; dminy = 16; dmaxx = 96; dmaxy = 96; pLevelMap = LoadFileInMem(sFileName, NULL); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { dungeon[i][j] = 22; L5dflags[i][j] = 0; } } lm = pLevelMap; rw = *lm; lm += 2; rh = *lm; lm += 2; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm != 0) { dungeon[i][j] = *lm; L5dflags[i][j] |= DLRG_PROTECTED; } else { dungeon[i][j] = 13; } lm += 2; } } DRLG_L1Floor(); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { pdungeon[i][j] = dungeon[i][j]; } } mem_free_dbg(pLevelMap); } #endif static void InitL5Dungeon() { int i, j; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { dungeon[i][j] = 0; L5dflags[i][j] = 0; } } } static void L5ClearFlags() { int i, j; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { L5dflags[i][j] &= 0xBF; } } } static void L5drawRoom(int x, int y, int w, int h) { int i, j; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { dungeon[x + i][y + j] = 1; } } } static BOOL L5checkRoom(int x, int y, int width, int height) { int i, j; for (j = 0; j < height; j++) { for (i = 0; i < width; i++) { if (i + x < 0 || i + x >= DMAXX || j + y < 0 || j + y >= DMAXY) return FALSE; if (dungeon[i + x][j + y]) return FALSE; } } return TRUE; } static void L5roomGen(int x, int y, int w, int h, int dir) { int num, dirProb; BOOL ran, ran2; int width, height, rx, ry, ry2; int cw, ch, cx1, cy1, cx2; dirProb = random_(0, 4); switch (dir == 1 ? dirProb != 0 : dirProb == 0) { case FALSE: num = 0; do { cw = (random_(0, 5) + 2) & 0xFFFFFFFE; ch = (random_(0, 5) + 2) & 0xFFFFFFFE; cy1 = h / 2 + y - ch / 2; cx1 = x - cw; ran = L5checkRoom(cx1 - 1, cy1 - 1, ch + 2, cw + 1); /// BUGFIX: swap args 3 and 4 ("ch+2" and "cw+1") num++; } while (ran == FALSE && num < 20); if (ran == TRUE) L5drawRoom(cx1, cy1, cw, ch); cx2 = x + w; ran2 = L5checkRoom(cx2, cy1 - 1, cw + 1, ch + 2); if (ran2 == TRUE) L5drawRoom(cx2, cy1, cw, ch); if (ran == TRUE) L5roomGen(cx1, cy1, cw, ch, 1); if (ran2 == TRUE) L5roomGen(cx2, cy1, cw, ch, 1); break; case TRUE: num = 0; do { width = (random_(0, 5) + 2) & 0xFFFFFFFE; height = (random_(0, 5) + 2) & 0xFFFFFFFE; rx = w / 2 + x - width / 2; ry = y - height; ran = L5checkRoom(rx - 1, ry - 1, width + 2, height + 1); num++; } while (ran == FALSE && num < 20); if (ran == TRUE) L5drawRoom(rx, ry, width, height); ry2 = y + h; ran2 = L5checkRoom(rx - 1, ry2, width + 2, height + 1); if (ran2 == TRUE) L5drawRoom(rx, ry2, width, height); if (ran == TRUE) L5roomGen(rx, ry, width, height, 0); if (ran2 == TRUE) L5roomGen(rx, ry2, width, height, 0); break; } } static void L5firstRoom() { int ys, ye, y; int xs, xe, x; if (random_(0, 2) == 0) { ys = 1; ye = DMAXY - 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 ys = 18; if (VR2) L5drawRoom(15, 15, 10, 10); if (VR3) L5drawRoom(15, 29, 10, 10); else ye = 22; for (y = ys; y < ye; y++) { dungeon[17][y] = 1; dungeon[18][y] = 1; dungeon[19][y] = 1; dungeon[20][y] = 1; dungeon[21][y] = 1; dungeon[22][y] = 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; } else { xs = 1; xe = DMAXX - 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 xs = 18; if (HR2) L5drawRoom(15, 15, 10, 10); if (HR3) L5drawRoom(29, 15, 10, 10); else xe = 22; for (x = xs; x < xe; x++) { dungeon[x][17] = 1; dungeon[x][18] = 1; dungeon[x][19] = 1; dungeon[x][20] = 1; dungeon[x][21] = 1; dungeon[x][22] = 1; } 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; } } static int L5GetArea() { int i, j; int rv; rv = 0; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 1) rv++; } } return rv; } static void L5makeDungeon() { int i, j; int i_2, j_2; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { j_2 = j << 1; i_2 = i << 1; L5dungeon[i_2][j_2] = dungeon[i][j]; L5dungeon[i_2][j_2 + 1] = dungeon[i][j]; L5dungeon[i_2 + 1][j_2] = dungeon[i][j]; L5dungeon[i_2 + 1][j_2 + 1] = dungeon[i][j]; } } } static void L5makeDmt() { int i, j, idx, val, dmtx, dmty; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { dungeon[i][j] = 22; } } for (j = 0, dmty = 1; dmty <= 77; j++, dmty += 2) { for (i = 0, dmtx = 1; dmtx <= 77; i++, dmtx += 2) { val = 8 * L5dungeon[dmtx + 1][dmty + 1] + 4 * L5dungeon[dmtx][dmty + 1] + 2 * L5dungeon[dmtx + 1][dmty] + L5dungeon[dmtx][dmty]; idx = L5ConvTbl[val]; dungeon[i][j] = idx; } } } static int L5HWallOk(int i, int j) { int x; BOOL wallok; for (x = 1; dungeon[i + x][j] == 13; x++) { if (dungeon[i + x][j - 1] != 13 || dungeon[i + x][j + 1] != 13 || L5dflags[i + x][j]) break; } wallok = FALSE; if (dungeon[i + x][j] >= 3 && dungeon[i + x][j] <= 7) wallok = TRUE; if (dungeon[i + x][j] >= 16 && dungeon[i + x][j] <= 24) wallok = TRUE; if (dungeon[i + x][j] == 22) wallok = FALSE; if (x == 1) wallok = FALSE; if (wallok) return x; else return -1; } static int L5VWallOk(int i, int j) { int y; BOOL wallok; for (y = 1; dungeon[i][j + y] == 13; y++) { if (dungeon[i - 1][j + y] != 13 || dungeon[i + 1][j + y] != 13 || L5dflags[i][j + y]) break; } wallok = FALSE; if (dungeon[i][j + y] >= 3 && dungeon[i][j + y] <= 7) wallok = TRUE; if (dungeon[i][j + y] >= 16 && dungeon[i][j + y] <= 24) wallok = TRUE; if (dungeon[i][j + y] == 22) wallok = FALSE; if (y == 1) wallok = FALSE; if (wallok) return y; else return -1; } static void L5HorizWall(int i, int j, char p, int dx) { int xx; char wt, dt; switch (random_(0, 4)) { case 0: case 1: dt = 2; break; case 2: dt = 12; if (p == 2) p = 12; if (p == 4) p = 10; break; case 3: dt = 36; if (p == 2) p = 36; if (p == 4) p = 27; break; } if (random_(0, 6) == 5) wt = 12; else wt = 26; if (dt == 12) wt = 12; dungeon[i][j] = p; for (xx = 1; xx < dx; xx++) { dungeon[i + xx][j] = dt; } xx = random_(0, dx - 1) + 1; if (wt == 12) { dungeon[i + xx][j] = wt; } else { dungeon[i + xx][j] = 2; L5dflags[i + xx][j] |= DLRG_HDOOR; } } static void L5VertWall(int i, int j, char p, int dy) { int yy; char wt, dt; switch (random_(0, 4)) { case 0: case 1: dt = 1; break; case 2: dt = 11; if (p == 1) p = 11; if (p == 4) p = 14; break; case 3: dt = 35; if (p == 1) p = 35; if (p == 4) p = 37; break; } if (random_(0, 6) == 5) wt = 11; else wt = 25; if (dt == 11) wt = 11; dungeon[i][j] = p; for (yy = 1; yy < dy; yy++) { dungeon[i][j + yy] = dt; } yy = random_(0, dy - 1) + 1; if (wt == 11) { dungeon[i][j + yy] = wt; } else { dungeon[i][j + yy] = 1; L5dflags[i][j + yy] |= DLRG_VDOOR; } } static void L5AddWall() { int i, j, x, y; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (!L5dflags[i][j]) { if (dungeon[i][j] == 3 && random_(0, 100) < 100) { x = L5HWallOk(i, j); if (x != -1) L5HorizWall(i, j, 2, x); } if (dungeon[i][j] == 3 && random_(0, 100) < 100) { y = L5VWallOk(i, j); if (y != -1) L5VertWall(i, j, 1, y); } if (dungeon[i][j] == 6 && random_(0, 100) < 100) { x = L5HWallOk(i, j); if (x != -1) L5HorizWall(i, j, 4, x); } if (dungeon[i][j] == 7 && random_(0, 100) < 100) { y = L5VWallOk(i, j); if (y != -1) L5VertWall(i, j, 4, y); } if (dungeon[i][j] == 2 && random_(0, 100) < 100) { x = L5HWallOk(i, j); if (x != -1) L5HorizWall(i, j, 2, x); } if (dungeon[i][j] == 1 && random_(0, 100) < 100) { y = L5VWallOk(i, j); if (y != -1) L5VertWall(i, j, 1, y); } } } } } static void DRLG_L5GChamber(int sx, int sy, BOOL topflag, BOOL bottomflag, BOOL leftflag, BOOL rightflag) { int i, j; if (topflag == TRUE) { dungeon[sx + 2][sy] = 12; dungeon[sx + 3][sy] = 12; dungeon[sx + 4][sy] = 3; dungeon[sx + 7][sy] = 9; dungeon[sx + 8][sy] = 12; dungeon[sx + 9][sy] = 2; } if (bottomflag == TRUE) { sy += 11; dungeon[sx + 2][sy] = 10; dungeon[sx + 3][sy] = 12; dungeon[sx + 4][sy] = 8; dungeon[sx + 7][sy] = 5; dungeon[sx + 8][sy] = 12; if (dungeon[sx + 9][sy] != 4) { dungeon[sx + 9][sy] = 21; } sy -= 11; } if (leftflag == TRUE) { dungeon[sx][sy + 2] = 11; dungeon[sx][sy + 3] = 11; dungeon[sx][sy + 4] = 3; dungeon[sx][sy + 7] = 8; dungeon[sx][sy + 8] = 11; dungeon[sx][sy + 9] = 1; } if (rightflag == TRUE) { sx += 11; dungeon[sx][sy + 2] = 14; dungeon[sx][sy + 3] = 11; dungeon[sx][sy + 4] = 9; dungeon[sx][sy + 7] = 5; dungeon[sx][sy + 8] = 11; if (dungeon[sx][sy + 9] != 4) { dungeon[sx][sy + 9] = 21; } sx -= 11; } for (j = 1; j < 11; j++) { for (i = 1; i < 11; i++) { dungeon[i + sx][j + sy] = 13; L5dflags[i + sx][j + sy] |= DLRG_CHAMBER; } } dungeon[sx + 4][sy + 4] = 15; dungeon[sx + 7][sy + 4] = 15; dungeon[sx + 4][sy + 7] = 15; dungeon[sx + 7][sy + 7] = 15; } static void DRLG_L5GHall(int x1, int y1, int x2, int y2) { int i; if (y1 == y2) { for (i = x1; i < x2; i++) { dungeon[i][y1] = 12; dungeon[i][y1 + 3] = 12; } } else { for (i = y1; i < y2; i++) { dungeon[x1][i] = 11; dungeon[x1 + 3][i] = 11; } } } static void L5tileFix() { int i, j; // BUGFIX: Bounds checks are required in all loop bodies. // See https://github.com/diasurgical/devilutionX/pull/401 for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 22) dungeon[i + 1][j] = 23; if (dungeon[i][j] == 13 && dungeon[i + 1][j] == 22) dungeon[i + 1][j] = 18; if (dungeon[i][j] == 13 && dungeon[i + 1][j] == 2) dungeon[i + 1][j] = 7; if (dungeon[i][j] == 6 && dungeon[i + 1][j] == 22) dungeon[i + 1][j] = 24; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 22) dungeon[i][j + 1] = 24; if (dungeon[i][j] == 13 && dungeon[i][j + 1] == 1) dungeon[i][j + 1] = 6; if (dungeon[i][j] == 13 && dungeon[i][j + 1] == 22) dungeon[i][j + 1] = 19; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 13 && dungeon[i + 1][j] == 19) dungeon[i + 1][j] = 21; if (dungeon[i][j] == 13 && dungeon[i + 1][j] == 22) dungeon[i + 1][j] = 20; if (dungeon[i][j] == 7 && dungeon[i + 1][j] == 22) dungeon[i + 1][j] = 23; if (dungeon[i][j] == 13 && dungeon[i + 1][j] == 24) dungeon[i + 1][j] = 21; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 22) dungeon[i + 1][j] = 20; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 19) dungeon[i + 1][j] = 21; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 6; if (dungeon[i][j] == 7 && dungeon[i + 1][j] == 19) dungeon[i + 1][j] = 21; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 6; if (dungeon[i][j] == 3 && dungeon[i + 1][j] == 22) dungeon[i + 1][j] = 24; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 6; if (dungeon[i][j] == 7 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 6; if (dungeon[i][j] == 7 && dungeon[i + 1][j] == 24) dungeon[i + 1][j] = 21; if (dungeon[i][j] == 4 && dungeon[i + 1][j] == 16) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 7 && dungeon[i + 1][j] == 13) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 24) dungeon[i + 1][j] = 21; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 13) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 23 && dungeon[i - 1][j] == 22) dungeon[i - 1][j] = 19; if (dungeon[i][j] == 19 && dungeon[i - 1][j] == 23) dungeon[i - 1][j] = 21; if (dungeon[i][j] == 6 && dungeon[i - 1][j] == 22) dungeon[i - 1][j] = 24; if (dungeon[i][j] == 6 && dungeon[i - 1][j] == 23) dungeon[i - 1][j] = 21; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 7; if (dungeon[i][j] == 6 && dungeon[i][j + 1] == 18) dungeon[i][j + 1] = 21; if (dungeon[i][j] == 18 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 7; if (dungeon[i][j] == 6 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 7; if (dungeon[i][j] == 21 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 7; if (dungeon[i][j] == 6 && dungeon[i][j + 1] == 22) dungeon[i][j + 1] = 24; if (dungeon[i][j] == 6 && dungeon[i][j + 1] == 13) dungeon[i][j + 1] = 16; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 13) dungeon[i][j + 1] = 16; if (dungeon[i][j] == 13 && dungeon[i][j + 1] == 16) dungeon[i][j + 1] = 17; if (dungeon[i][j] == 6 && dungeon[i][j - 1] == 22) dungeon[i][j - 1] = 7; if (dungeon[i][j] == 6 && dungeon[i][j - 1] == 22) dungeon[i][j - 1] = 24; if (dungeon[i][j] == 7 && dungeon[i][j - 1] == 24) dungeon[i][j - 1] = 21; if (dungeon[i][j] == 18 && dungeon[i][j - 1] == 24) dungeon[i][j - 1] = 21; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 4 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 7; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 19) dungeon[i + 1][j] = 21; if (dungeon[i][j] == 18 && dungeon[i][j + 1] == 22) dungeon[i][j + 1] = 20; } } } #ifdef HELLFIRE void drlg_l1_crypt_rndset(const BYTE *miniset, int rndper) { int sx, sy, sw, sh, xx, yy, ii, kk; BOOL found; sw = miniset[0]; sh = miniset[1]; for (sy = 0; sy < DMAXY - sh; sy++) { for (sx = 0; sx < DMAXX - sw; sx++) { found = TRUE; ii = 2; for (yy = 0; yy < sh && found == TRUE; yy++) { for (xx = 0; xx < sw && found == TRUE; xx++) { if (miniset[ii] != 0 && dungeon[xx + sx][yy + sy] != miniset[ii]) { found = FALSE; } if (dflags[xx + sx][yy + sy] != 0) { // BUGFIX: Should be L5dflags or it will always be false found = FALSE; } ii++; } } kk = sw * sh + 2; // BUGFIX: This code is copied from Cave and should not be applied for crypt if (miniset[kk] >= 84 && miniset[kk] <= 100 && found == TRUE) { // BUGFIX: accesses to dungeon can go out of bounds // BUGFIX: Comparisons vs 100 should use same tile as comparisons vs 84. if (dungeon[sx - 1][sy] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } if (dungeon[sx + 1][sy] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } if (dungeon[sx][sy + 1] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } if (dungeon[sx][sy - 1] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } } if (found == TRUE && random_(0, 100) < rndper) { for (yy = 0; yy < sh; yy++) { for (xx = 0; xx < sw; xx++) { if (miniset[kk] != 0) { dungeon[xx + sx][yy + sy] = miniset[kk]; } kk++; } } } } } } #endif static void DRLG_L5Subs() { int x, y, rv, i; for (y = 0; y < DMAXY; y++) { for (x = 0; x < DMAXX; x++) { if (random_(0, 4) == 0) { BYTE c = L5BTYPES[dungeon[x][y]]; if (c && !L5dflags[x][y]) { rv = random_(0, 16); i = -1; while (rv >= 0) { if (++i == sizeof(L5BTYPES)) i = 0; if (c == L5BTYPES[i]) rv--; } // BUGFIX: Add `&& y > 0` to the if statement. if (i == 89) { if (L5BTYPES[dungeon[x][y - 1]] != 79 || L5dflags[x][y - 1]) i = 79; else dungeon[x][y - 1] = 90; } // BUGFIX: Add `&& x + 1 < DMAXX` to the if statement. if (i == 91) { if (L5BTYPES[dungeon[x + 1][y]] != 80 || L5dflags[x + 1][y]) i = 80; else dungeon[x + 1][y] = 92; } dungeon[x][y] = i; } } } } } static void DRLG_L5SetRoom(int rx1, int ry1) { int rw, rh, i, j; BYTE *sp; rw = *L5pSetPiece; rh = *(L5pSetPiece + 2); setpc_x = rx1; setpc_y = ry1; setpc_w = rw; setpc_h = rh; sp = L5pSetPiece + 4; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*sp) { dungeon[rx1 + i][ry1 + j] = *sp; L5dflags[rx1 + i][ry1 + j] |= DLRG_PROTECTED; } else { dungeon[rx1 + i][ry1 + j] = 13; } sp += 2; } } } static void L5FillChambers() { int c; if (HR1) DRLG_L5GChamber(0, 14, 0, 0, 0, 1); if (HR2) { if (HR1 && !HR3) DRLG_L5GChamber(14, 14, 0, 0, 1, 0); if (!HR1 && HR3) DRLG_L5GChamber(14, 14, 0, 0, 0, 1); if (HR1 && HR3) DRLG_L5GChamber(14, 14, 0, 0, 1, 1); if (!HR1 && !HR3) DRLG_L5GChamber(14, 14, 0, 0, 0, 0); } if (HR3) DRLG_L5GChamber(28, 14, 0, 0, 1, 0); if (HR1 && HR2) DRLG_L5GHall(12, 18, 14, 18); if (HR2 && HR3) DRLG_L5GHall(26, 18, 28, 18); if (HR1 && !HR2 && HR3) DRLG_L5GHall(12, 18, 28, 18); if (VR1) DRLG_L5GChamber(14, 0, 0, 1, 0, 0); if (VR2) { if (VR1 && !VR3) DRLG_L5GChamber(14, 14, 1, 0, 0, 0); if (!VR1 && VR3) DRLG_L5GChamber(14, 14, 0, 1, 0, 0); if (VR1 && VR3) DRLG_L5GChamber(14, 14, 1, 1, 0, 0); if (!VR1 && !VR3) DRLG_L5GChamber(14, 14, 0, 0, 0, 0); } if (VR3) DRLG_L5GChamber(14, 28, 1, 0, 0, 0); if (VR1 && VR2) DRLG_L5GHall(18, 12, 18, 14); if (VR2 && VR3) DRLG_L5GHall(18, 26, 18, 28); if (VR1 && !VR2 && VR3) DRLG_L5GHall(18, 12, 18, 28); #ifdef HELLFIRE if (currlevel == 24) { if (VR1 || VR2 || VR3) { c = 1; if (!VR1 && VR2 && VR3 && random_(0, 2) != 0) c = 2; if (VR1 && VR2 && !VR3 && random_(0, 2) != 0) c = 0; if (VR1 && !VR2 && VR3) { if (random_(0, 2) != 0) c = 0; else c = 2; } if (VR1 && VR2 && VR3) c = random_(0, 3); switch (c) { case 0: drlg_l1_set_crypt_room(16, 2); break; case 1: drlg_l1_set_crypt_room(16, 16); break; case 2: drlg_l1_set_crypt_room(16, 30); break; } } else { c = 1; if (!HR1 && HR2 && HR3 && random_(0, 2) != 0) c = 2; if (HR1 && HR2 && !HR3 && random_(0, 2) != 0) c = 0; if (HR1 && !HR2 && HR3) { if (random_(0, 2) != 0) c = 0; else c = 2; } if (HR1 && HR2 && HR3) c = random_(0, 3); switch (c) { case 0: drlg_l1_set_crypt_room(2, 16); break; case 1: drlg_l1_set_crypt_room(16, 16); break; case 2: drlg_l1_set_crypt_room(30, 16); break; } } } if (currlevel == 21) { if (VR1 || VR2 || VR3) { c = 1; if (!VR1 && VR2 && VR3 && random_(0, 2) != 0) c = 2; if (VR1 && VR2 && !VR3 && random_(0, 2) != 0) c = 0; if (VR1 && !VR2 && VR3) { if (random_(0, 2) != 0) c = 0; else c = 2; } if (VR1 && VR2 && VR3) c = random_(0, 3); switch (c) { case 0: drlg_l1_set_corner_room(16, 2); break; case 1: drlg_l1_set_corner_room(16, 16); break; case 2: drlg_l1_set_corner_room(16, 30); break; } } else { c = 1; if (!HR1 && HR2 && HR3 && random_(0, 2)) c = 2; if (HR1 && HR2 && !HR3 && random_(0, 2)) c = 0; if (HR1 && !HR2 && HR3) { if (random_(0, 2)) c = 0; else c = 2; } if (HR1 && HR2 && HR3) c = random_(0, 3); switch (c) { case 0: drlg_l1_set_corner_room(2, 16); break; case 1: drlg_l1_set_corner_room(16, 16); break; case 2: drlg_l1_set_corner_room(30, 16); break; } } } #endif if (L5setloadflag) { if (VR1 || VR2 || VR3) { c = 1; if (!VR1 && VR2 && VR3 && random_(0, 2) != 0) c = 2; if (VR1 && VR2 && !VR3 && random_(0, 2) != 0) c = 0; if (VR1 && !VR2 && VR3) { if (random_(0, 2) != 0) c = 0; else c = 2; } if (VR1 && VR2 && VR3) c = random_(0, 3); switch (c) { case 0: DRLG_L5SetRoom(16, 2); break; case 1: DRLG_L5SetRoom(16, 16); break; case 2: DRLG_L5SetRoom(16, 30); break; } } else { c = 1; if (!HR1 && HR2 && HR3 && random_(0, 2) != 0) c = 2; if (HR1 && HR2 && !HR3 && random_(0, 2) != 0) c = 0; if (HR1 && !HR2 && HR3) { if (random_(0, 2) != 0) c = 0; else c = 2; } if (HR1 && HR2 && HR3) c = random_(0, 3); switch (c) { case 0: DRLG_L5SetRoom(2, 16); break; case 1: DRLG_L5SetRoom(16, 16); break; case 2: DRLG_L5SetRoom(30, 16); break; } } } } #ifdef HELLFIRE void drlg_l1_set_crypt_room(int rx1, int ry1) { int rw, rh, i, j, sp; rw = UberRoomPattern[0]; rh = UberRoomPattern[1]; UberRow = 2 * rx1 + 6; UberCol = 2 * ry1 + 8; setpc_x = rx1; setpc_y = ry1; setpc_w = rw; setpc_h = rh; IsUberRoomOpened = 0; dword_577368 = 0; IsUberLeverActivated = 0; sp = 2; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (UberRoomPattern[sp]) { dungeon[rx1 + i][ry1 + j] = UberRoomPattern[sp]; L5dflags[rx1 + i][ry1 + j] |= DLRG_PROTECTED; } else { dungeon[rx1 + i][ry1 + j] = 13; } sp++; } } } void drlg_l1_set_corner_room(int rx1, int ry1) { int rw, rh, i, j, sp; rw = CornerstoneRoomPattern[0]; rh = CornerstoneRoomPattern[1]; setpc_x = rx1; setpc_y = ry1; setpc_w = rw; setpc_h = rh; sp = 2; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (CornerstoneRoomPattern[sp]) { dungeon[rx1 + i][ry1 + j] = CornerstoneRoomPattern[sp]; L5dflags[rx1 + i][ry1 + j] |= DLRG_PROTECTED; } else { dungeon[rx1 + i][ry1 + j] = 13; } sp++; } } } #endif static void DRLG_L5FTVR(int i, int j, int x, int y, int d) { if (dTransVal[x][y] || dungeon[i][j] != 13) { if (d == 1) { dTransVal[x][y] = TransVal; dTransVal[x][y + 1] = TransVal; } if (d == 2) { dTransVal[x + 1][y] = TransVal; dTransVal[x + 1][y + 1] = TransVal; } if (d == 3) { dTransVal[x][y] = TransVal; dTransVal[x + 1][y] = TransVal; } if (d == 4) { dTransVal[x][y + 1] = TransVal; dTransVal[x + 1][y + 1] = TransVal; } if (d == 5) dTransVal[x + 1][y + 1] = TransVal; if (d == 6) dTransVal[x][y + 1] = TransVal; if (d == 7) dTransVal[x + 1][y] = TransVal; if (d == 8) dTransVal[x][y] = TransVal; } else { dTransVal[x][y] = TransVal; dTransVal[x + 1][y] = TransVal; dTransVal[x][y + 1] = TransVal; dTransVal[x + 1][y + 1] = TransVal; DRLG_L5FTVR(i + 1, j, x + 2, y, 1); DRLG_L5FTVR(i - 1, j, x - 2, y, 2); DRLG_L5FTVR(i, j + 1, x, y + 2, 3); DRLG_L5FTVR(i, j - 1, x, y - 2, 4); DRLG_L5FTVR(i - 1, j - 1, x - 2, y - 2, 5); DRLG_L5FTVR(i + 1, j - 1, x + 2, y - 2, 6); DRLG_L5FTVR(i - 1, j + 1, x - 2, y + 2, 7); DRLG_L5FTVR(i + 1, j + 1, x + 2, y + 2, 8); } } static void DRLG_L5FloodTVal() { int xx, yy, i, j; yy = 16; for (j = 0; j < DMAXY; j++) { xx = 16; for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 13 && !dTransVal[xx][yy]) { DRLG_L5FTVR(i, j, xx, yy, 0); TransVal++; } xx += 2; } yy += 2; } } static void DRLG_L5TransFix() { int xx, yy, i, j; yy = 16; for (j = 0; j < DMAXY; j++) { xx = 16; for (i = 0; i < DMAXX; i++) { // BUGFIX: Should check for `j > 0` first. if (dungeon[i][j] == 23 && dungeon[i][j - 1] == 18) { dTransVal[xx + 1][yy] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } // BUGFIX: Should check for `i + 1 < DMAXY` first. if (dungeon[i][j] == 24 && dungeon[i + 1][j] == 19) { dTransVal[xx][yy + 1] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 18) { dTransVal[xx + 1][yy] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 19) { dTransVal[xx][yy + 1] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 20) { dTransVal[xx + 1][yy] = dTransVal[xx][yy]; dTransVal[xx][yy + 1] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } xx += 2; } yy += 2; } } static void DRLG_L5DirtFix() { int i, j; #ifdef HELLFIRE if (currlevel < 21) { for (j = 0; j < DMAXY - 1; j++) { for (i = 0; i < DMAXX - 1; i++) { if (dungeon[i][j] == 21 && dungeon[i + 1][j] != 19) dungeon[i][j] = 202; if (dungeon[i][j] == 19 && dungeon[i + 1][j] != 19) dungeon[i][j] = 200; if (dungeon[i][j] == 24 && dungeon[i + 1][j] != 19) dungeon[i][j] = 205; if (dungeon[i][j] == 18 && dungeon[i][j + 1] != 18) dungeon[i][j] = 199; if (dungeon[i][j] == 21 && dungeon[i][j + 1] != 18) dungeon[i][j] = 202; if (dungeon[i][j] == 23 && dungeon[i][j + 1] != 18) dungeon[i][j] = 204; } } } else { for (j = 0; j < DMAXY - 1; j++) { for (i = 0; i < DMAXX - 1; i++) { if (dungeon[i][j] == 19) dungeon[i][j] = 83; if (dungeon[i][j] == 21) dungeon[i][j] = 85; if (dungeon[i][j] == 23) dungeon[i][j] = 87; if (dungeon[i][j] == 24) dungeon[i][j] = 88; if (dungeon[i][j] == 18) dungeon[i][j] = 82; } } } #else for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 21 && dungeon[i + 1][j] != 19) dungeon[i][j] = 202; if (dungeon[i][j] == 19 && dungeon[i + 1][j] != 19) dungeon[i][j] = 200; if (dungeon[i][j] == 24 && dungeon[i + 1][j] != 19) dungeon[i][j] = 205; if (dungeon[i][j] == 18 && dungeon[i][j + 1] != 18) dungeon[i][j] = 199; if (dungeon[i][j] == 21 && dungeon[i][j + 1] != 18) dungeon[i][j] = 202; if (dungeon[i][j] == 23 && dungeon[i][j + 1] != 18) dungeon[i][j] = 204; } } #endif } static void DRLG_L5CornerFix() { int i, j; for (j = 1; j < DMAXY - 1; j++) { for (i = 1; i < DMAXX - 1; i++) { if (!(L5dflags[i][j] & DLRG_PROTECTED) && dungeon[i][j] == 17 && dungeon[i - 1][j] == 13 && dungeon[i][j - 1] == 1) { dungeon[i][j] = 16; L5dflags[i][j - 1] &= DLRG_PROTECTED; // BUGFIX: Should be |= or it will clear all flags } if (dungeon[i][j] == 202 && dungeon[i + 1][j] == 13 && dungeon[i][j + 1] == 1) { dungeon[i][j] = 8; } } } } static void DRLG_L5(int entry) { int i, j; LONG minarea; BOOL doneflag; switch (currlevel) { case 1: minarea = 533; break; case 2: minarea = 693; break; case 3: case 4: minarea = 761; break; #ifdef HELLFIRE default: minarea = 761; break; #endif } do { DRLG_InitTrans(); do { InitL5Dungeon(); L5firstRoom(); } while (L5GetArea() < minarea); L5makeDungeon(); L5makeDmt(); L5FillChambers(); L5tileFix(); L5AddWall(); L5ClearFlags(); DRLG_L5FloodTVal(); doneflag = TRUE; if (QuestStatus(Q_PWATER)) { if (entry == ENTRY_MAIN) { if (DRLG_PlaceMiniSet(PWATERIN, 1, 1, 0, 0, TRUE, -1, 0) < 0) doneflag = FALSE; } else { if (DRLG_PlaceMiniSet(PWATERIN, 1, 1, 0, 0, FALSE, -1, 0) < 0) doneflag = FALSE; ViewY--; } } if (QuestStatus(Q_LTBANNER)) { if (entry == ENTRY_MAIN) { if (DRLG_PlaceMiniSet(STAIRSUP, 1, 1, 0, 0, TRUE, -1, 0) < 0) doneflag = FALSE; } else { if (DRLG_PlaceMiniSet(STAIRSUP, 1, 1, 0, 0, FALSE, -1, 0) < 0) doneflag = FALSE; if (entry == ENTRY_PREV) { ViewX = 2 * setpc_x + 20; ViewY = 2 * setpc_y + 28; } else { ViewY--; } } #ifdef HELLFIRE } else if (entry == ENTRY_MAIN) { if (currlevel < 21) { if (DRLG_PlaceMiniSet(STAIRSUP, 1, 1, 0, 0, TRUE, -1, 0) < 0) doneflag = FALSE; if (DRLG_PlaceMiniSet(STAIRSDOWN, 1, 1, 0, 0, FALSE, -1, 1) < 0) doneflag = FALSE; } else if (currlevel == 21) { if (DRLG_PlaceMiniSet(L5STAIRSTOWN, 1, 1, 0, 0, FALSE, -1, 6) < 0) doneflag = FALSE; if (DRLG_PlaceMiniSet(L5STAIRSDOWN, 1, 1, 0, 0, FALSE, -1, 1) < 0) doneflag = FALSE; ViewY++; } else { if (DRLG_PlaceMiniSet(L5STAIRSUP, 1, 1, 0, 0, TRUE, -1, 0) < 0) doneflag = FALSE; if (currlevel != 24) { if (DRLG_PlaceMiniSet(L5STAIRSDOWN, 1, 1, 0, 0, FALSE, -1, 1) < 0) doneflag = FALSE; } ViewY++; } } else if (entry == ENTRY_PREV) { if (currlevel < 21) { if (DRLG_PlaceMiniSet(STAIRSUP, 1, 1, 0, 0, FALSE, -1, 0) < 0) doneflag = FALSE; if (DRLG_PlaceMiniSet(STAIRSDOWN, 1, 1, 0, 0, TRUE, -1, 1) < 0) doneflag = FALSE; ViewY--; } else if (currlevel == 21) { if (DRLG_PlaceMiniSet(L5STAIRSTOWN, 1, 1, 0, 0, FALSE, -1, 6) < 0) doneflag = FALSE; if (DRLG_PlaceMiniSet(L5STAIRSDOWN, 1, 1, 0, 0, TRUE, -1, 1) < 0) doneflag = FALSE; ViewY += 3; } else { if (DRLG_PlaceMiniSet(L5STAIRSUP, 1, 1, 0, 0, TRUE, -1, 0) < 0) doneflag = FALSE; if (currlevel != 24) { if (DRLG_PlaceMiniSet(L5STAIRSDOWN, 1, 1, 0, 0, TRUE, -1, 1) < 0) doneflag = FALSE; } ViewY += 3; } } else { if (currlevel < 21) { if (DRLG_PlaceMiniSet(STAIRSUP, 1, 1, 0, 0, FALSE, -1, 0) < 0) doneflag = FALSE; if (DRLG_PlaceMiniSet(STAIRSDOWN, 1, 1, 0, 0, FALSE, -1, 1) < 0) doneflag = FALSE; } else if (currlevel == 21) { if (DRLG_PlaceMiniSet(L5STAIRSTOWN, 1, 1, 0, 0, TRUE, -1, 6) < 0) doneflag = FALSE; if (DRLG_PlaceMiniSet(L5STAIRSDOWN, 1, 1, 0, 0, FALSE, -1, 1) < 0) doneflag = FALSE; } else { if (DRLG_PlaceMiniSet(L5STAIRSUP, 1, 1, 0, 0, TRUE, -1, 0) < 0) doneflag = FALSE; if (currlevel != 24) { if (DRLG_PlaceMiniSet(L5STAIRSDOWN, 1, 1, 0, 0, FALSE, -1, 1) < 0) doneflag = FALSE; } } #else } else if (entry == ENTRY_MAIN) { if (DRLG_PlaceMiniSet(L5STAIRSUP, 1, 1, 0, 0, TRUE, -1, 0) < 0) doneflag = FALSE; else if (DRLG_PlaceMiniSet(STAIRSDOWN, 1, 1, 0, 0, FALSE, -1, 1) < 0) doneflag = FALSE; } else { if (DRLG_PlaceMiniSet(L5STAIRSUP, 1, 1, 0, 0, FALSE, -1, 0) < 0) doneflag = FALSE; else if (DRLG_PlaceMiniSet(STAIRSDOWN, 1, 1, 0, 0, TRUE, -1, 1) < 0) doneflag = FALSE; ViewY--; #endif } } while (doneflag == FALSE); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 64) { int xx = 2 * i + 16; /* todo: fix loop */ int yy = 2 * j + 16; DRLG_CopyTrans(xx, yy + 1, xx, yy); DRLG_CopyTrans(xx + 1, yy + 1, xx + 1, yy); } } } DRLG_L5TransFix(); DRLG_L5DirtFix(); DRLG_L5CornerFix(); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (L5dflags[i][j] & 0x7F) DRLG_PlaceDoor(i, j); } } #ifdef HELLFIRE if (currlevel < 21) { DRLG_L5Subs(); } else { drlg_l1_crypt_pattern1(10); drlg_l1_crypt_rndset(byte_48A1B4, 95); drlg_l1_crypt_rndset(byte_48A1B8, 95); drlg_l1_crypt_rndset(byte_48A1C0, 100); drlg_l1_crypt_rndset(byte_48A1C8, 100); drlg_l1_crypt_rndset(byte_48A1E0, 60); drlg_l1_crypt_lavafloor(); switch (currlevel) { case 21: drlg_l1_crypt_pattern2(30); drlg_l1_crypt_pattern3(15); drlg_l1_crypt_pattern4(5); drlg_l1_crypt_lavafloor(); drlg_l1_crypt_pattern7(10); drlg_l1_crypt_pattern6(5); drlg_l1_crypt_pattern5(20); break; case 22: drlg_l1_crypt_pattern7(10); drlg_l1_crypt_pattern6(10); drlg_l1_crypt_pattern5(20); drlg_l1_crypt_pattern2(30); drlg_l1_crypt_pattern3(20); drlg_l1_crypt_pattern4(10); drlg_l1_crypt_lavafloor(); break; case 23: drlg_l1_crypt_pattern7(10); drlg_l1_crypt_pattern6(15); drlg_l1_crypt_pattern5(30); drlg_l1_crypt_pattern2(30); drlg_l1_crypt_pattern3(20); drlg_l1_crypt_pattern4(15); drlg_l1_crypt_lavafloor(); break; default: drlg_l1_crypt_pattern7(10); drlg_l1_crypt_pattern6(20); drlg_l1_crypt_pattern5(30); drlg_l1_crypt_pattern2(30); drlg_l1_crypt_pattern3(20); drlg_l1_crypt_pattern4(20); drlg_l1_crypt_lavafloor(); break; } } #else DRLG_L5Subs(); #endif #ifdef HELLFIRE if (currlevel < 21) #endif DRLG_L1Shadows(); #ifdef HELLFIRE if (currlevel < 21) #endif DRLG_PlaceMiniSet(LAMPS, 5, 10, 0, 0, FALSE, -1, 4); #ifdef HELLFIRE if (currlevel < 21) #endif DRLG_L1Floor(); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { pdungeon[i][j] = dungeon[i][j]; } } DRLG_Init_Globals(); DRLG_CheckQuests(setpc_x, setpc_y); } void CreateL5Dungeon(DWORD rseed, int entry) { #ifdef HELLFIRE int i, j; #endif SetRndSeed(rseed); dminx = 16; dminy = 16; dmaxx = 96; dmaxy = 96; #ifdef HELLFIRE UberRow = 0; UberCol = 0; IsUberRoomOpened = 0; dword_577368 = 0; UberLeverRow = 0; UberLeverCol = 0; IsUberLeverActivated = 0; UberDiabloMonsterIndex = 0; #endif DRLG_InitTrans(); DRLG_InitSetPC(); DRLG_LoadL1SP(); DRLG_L5(entry); DRLG_L1Pass3(); DRLG_FreeL1SP(); #ifdef HELLFIRE if (currlevel < 17) DRLG_InitL1Vals(); else DRLG_InitL5Vals(); DRLG_SetPC(); for (j = dminy; j < dmaxy; j++) { for (i = dminx; i < dmaxx; i++) { if (dPiece[i][j] == 290) { UberRow = i; UberCol = j; } if (dPiece[i][j] == 317) { CornerStone.x = i; CornerStone.y = j; } } } #else DRLG_InitL1Vals(); DRLG_SetPC(); #endif } #ifdef HELLFIRE void drlg_l1_crypt_pattern1(int rndper) { drlg_l1_crypt_rndset(byte_48A3C8, rndper); drlg_l1_crypt_rndset(byte_48A3CC, rndper); drlg_l1_crypt_rndset(byte_48A3D0, rndper); drlg_l1_crypt_rndset(byte_48A3D4, rndper); } void drlg_l1_crypt_pattern2(int rndper) { drlg_l1_crypt_rndset(byte_48A2FC, rndper); drlg_l1_crypt_rndset(byte_48A300, rndper); drlg_l1_crypt_rndset(byte_48A304, rndper); drlg_l1_crypt_rndset(byte_48A308, rndper); drlg_l1_crypt_rndset(byte_48A30C, rndper); drlg_l1_crypt_rndset(byte_48A310, rndper); drlg_l1_crypt_rndset(byte_48A314, rndper); drlg_l1_crypt_rndset(byte_48A318, rndper); drlg_l1_crypt_rndset(byte_48A31C, rndper); drlg_l1_crypt_rndset(byte_48A320, rndper); drlg_l1_crypt_rndset(byte_48A324, rndper); drlg_l1_crypt_rndset(byte_48A328, rndper); drlg_l1_crypt_rndset(byte_48A32C, rndper); drlg_l1_crypt_rndset(byte_48A330, rndper); drlg_l1_crypt_rndset(byte_48A334, rndper); drlg_l1_crypt_rndset(byte_48A338, rndper); drlg_l1_crypt_rndset(byte_48A33C, rndper); } void drlg_l1_crypt_pattern3(int rndper) { drlg_l1_crypt_rndset(byte_48A340, rndper); drlg_l1_crypt_rndset(byte_48A344, rndper); drlg_l1_crypt_rndset(byte_48A348, rndper); drlg_l1_crypt_rndset(byte_48A34C, rndper); drlg_l1_crypt_rndset(byte_48A350, rndper); drlg_l1_crypt_rndset(byte_48A354, rndper); drlg_l1_crypt_rndset(byte_48A358, rndper); drlg_l1_crypt_rndset(byte_48A35C, rndper); drlg_l1_crypt_rndset(byte_48A360, rndper); drlg_l1_crypt_rndset(byte_48A364, rndper); drlg_l1_crypt_rndset(byte_48A368, rndper); drlg_l1_crypt_rndset(byte_48A36C, rndper); drlg_l1_crypt_rndset(byte_48A370, rndper); drlg_l1_crypt_rndset(byte_48A374, rndper); drlg_l1_crypt_rndset(byte_48A378, rndper); drlg_l1_crypt_rndset(byte_48A37C, rndper); drlg_l1_crypt_rndset(byte_48A380, rndper); } void drlg_l1_crypt_pattern4(int rndper) { drlg_l1_crypt_rndset(byte_48A384, rndper); drlg_l1_crypt_rndset(byte_48A388, rndper); drlg_l1_crypt_rndset(byte_48A38C, rndper); drlg_l1_crypt_rndset(byte_48A390, rndper); drlg_l1_crypt_rndset(byte_48A394, rndper); drlg_l1_crypt_rndset(byte_48A398, rndper); drlg_l1_crypt_rndset(byte_48A39C, rndper); drlg_l1_crypt_rndset(byte_48A3A0, rndper); drlg_l1_crypt_rndset(byte_48A3A4, rndper); drlg_l1_crypt_rndset(byte_48A3A8, rndper); drlg_l1_crypt_rndset(byte_48A3AC, rndper); drlg_l1_crypt_rndset(byte_48A3B0, rndper); drlg_l1_crypt_rndset(byte_48A3B4, rndper); drlg_l1_crypt_rndset(byte_48A3B8, rndper); drlg_l1_crypt_rndset(byte_48A3BC, rndper); drlg_l1_crypt_rndset(byte_48A3C0, rndper); drlg_l1_crypt_rndset(byte_48A3C4, rndper); } void drlg_l1_crypt_pattern5(int rndper) { drlg_l1_crypt_rndset(byte_48A260, rndper); drlg_l1_crypt_rndset(byte_48A278, rndper); drlg_l1_crypt_rndset(byte_48A290, rndper); drlg_l1_crypt_rndset(byte_48A2A8, rndper); drlg_l1_crypt_rndset(byte_48A2C0, rndper); drlg_l1_crypt_rndset(byte_48A2D8, rndper); drlg_l1_crypt_rndset(byte_48A2EC, rndper); drlg_l1_crypt_rndset(byte_48A2F0, rndper); drlg_l1_crypt_rndset(byte_48A2F4, rndper); drlg_l1_crypt_rndset(byte_48A2F8, rndper); } void drlg_l1_crypt_pattern6(int rndper) { drlg_l1_crypt_rndset(byte_48A1F4, rndper); drlg_l1_crypt_rndset(byte_48A1FC, rndper); drlg_l1_crypt_rndset(byte_48A1F8, rndper); drlg_l1_crypt_rndset(byte_48A200, rndper); drlg_l1_crypt_rndset(byte_48A204, rndper); drlg_l1_crypt_rndset(byte_48A208, rndper); drlg_l1_crypt_rndset(byte_48A20C, rndper); drlg_l1_crypt_rndset(byte_48A210, rndper); drlg_l1_crypt_rndset(byte_48A214, rndper); drlg_l1_crypt_rndset(byte_48A218, rndper); drlg_l1_crypt_rndset(byte_48A21C, rndper); drlg_l1_crypt_rndset(byte_48A220, rndper); drlg_l1_crypt_rndset(byte_48A224, rndper); drlg_l1_crypt_rndset(byte_48A228, rndper); drlg_l1_crypt_rndset(byte_48A22C, rndper); drlg_l1_crypt_rndset(byte_48A230, rndper); drlg_l1_crypt_rndset(byte_48A234, rndper); drlg_l1_crypt_rndset(byte_48A238, rndper); drlg_l1_crypt_rndset(byte_48A23C, rndper); drlg_l1_crypt_rndset(byte_48A240, rndper); drlg_l1_crypt_rndset(byte_48A244, rndper); drlg_l1_crypt_rndset(byte_48A248, rndper); drlg_l1_crypt_rndset(byte_48A24C, rndper); drlg_l1_crypt_rndset(byte_48A250, rndper); drlg_l1_crypt_rndset(byte_48A254, rndper); drlg_l1_crypt_rndset(byte_48A258, rndper); } void drlg_l1_crypt_pattern7(int rndper) { drlg_l1_crypt_rndset(byte_48A1D0, rndper); drlg_l1_crypt_rndset(byte_48A1D4, rndper); drlg_l1_crypt_rndset(byte_48A1D8, rndper); drlg_l1_crypt_rndset(byte_48A1DC, rndper); } #endif ================================================ FILE: Source/drlg_l1.h ================================================ /** * @file drlg_l1.h * * Interface of the cathedral level generation algorithms. */ #ifndef __DRLG_L1_H__ #define __DRLG_L1_H__ #ifdef HELLFIRE extern int UberRow; extern int UberCol; extern int IsUberRoomOpened; extern int UberLeverRow; extern int UberLeverCol; extern int IsUberLeverActivated; extern int UberDiabloMonsterIndex; #endif void DRLG_Init_Globals(); void LoadL1Dungeon(const char *sFileName, int vx, int vy); void LoadPreL1Dungeon(const char *sFileName, int vx, int vy); void CreateL5Dungeon(DWORD rseed, int entry); #ifdef HELLFIRE void drlg_l1_set_crypt_room(int rx1, int ry1); void drlg_l1_set_corner_room(int rx1, int ry1); void drlg_l1_crypt_pattern1(int rndper); void drlg_l1_crypt_pattern2(int rndper); void drlg_l1_crypt_pattern3(int rndper); void drlg_l1_crypt_pattern4(int rndper); void drlg_l1_crypt_pattern5(int rndper); void drlg_l1_crypt_pattern6(int rndper); void drlg_l1_crypt_pattern7(int rndper); #endif #endif /* __DRLG_L1_H__ */ ================================================ FILE: Source/drlg_l2.cpp ================================================ /** * @file drlg_l2.cpp * * Implementation of the catacombs level generation algorithms. */ #ifndef SPAWN #include "all.h" int nSx1; int nSy1; int nSx2; int nSy2; int nRoomCnt; BYTE predungeon[DMAXX][DMAXY]; ROOMNODE RoomList[81]; HALLNODE *pHallList; int Area_Min = 2; int Room_Max = 10; int Room_Min = 4; int Dir_Xadd[5] = { 0, 0, 1, 0, -1 }; int Dir_Yadd[5] = { 0, -1, 0, 1, 0 }; ShadowStruct SPATSL2[2] = { { 6, 3, 0, 3, 48, 0, 50 }, { 9, 3, 0, 3, 48, 0, 50 } }; //short word_48489A = 0; BYTE 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 }; BYTE 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 }; /** Miniset: Arch vertical. */ BYTE VARCH1[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 1, 3, 4, 0, 7, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH2[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 1, 3, 4, 0, 8, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH3[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 1, 3, 4, 0, 6, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH4[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 1, 3, 4, 0, 9, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH5[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 1, 3, 4, 0, 14, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH6[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 1, 3, 4, 0, 13, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH7[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 1, 3, 4, 0, 16, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH8[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 1, 3, 4, 0, 15, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - corner. */ BYTE VARCH9[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 8, 3, 4, 0, 7, 48, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - corner. */ BYTE VARCH10[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 8, 3, 4, 0, 8, 48, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - corner. */ BYTE VARCH11[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 8, 3, 4, 0, 6, 48, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - corner. */ BYTE VARCH12[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 8, 3, 4, 0, 9, 48, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - corner. */ BYTE VARCH13[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 8, 3, 4, 0, 14, 48, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - corner. */ BYTE VARCH14[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 8, 3, 4, 0, 13, 48, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - corner. */ BYTE VARCH15[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 8, 3, 4, 0, 16, 48, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - corner. */ BYTE VARCH16[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 8, 3, 4, 0, 15, 48, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - open wall. */ BYTE VARCH17[] = { // clang-format off 2, 3, // width, height 2, 7, // search 3, 4, 0, 7, 141, 39, // replace 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - open wall. */ BYTE VARCH18[] = { // clang-format off 2, 3, // width, height 2, 7, // search 3, 4, 0, 8, 141, 39, // replace 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - open wall. */ BYTE VARCH19[] = { // clang-format off 2, 3, // width, height 2, 7, // search 3, 4, 0, 6, 141, 39, // replace 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - open wall. */ BYTE VARCH20[] = { // clang-format off 2, 3, // width, height 2, 7, // search 3, 4, 0, 9, 141, 39, // replace 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - open wall. */ BYTE VARCH21[] = { // clang-format off 2, 3, // width, height 2, 7, // search 3, 4, 0, 14, 141, 39, // replace 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - open wall. */ BYTE VARCH22[] = { // clang-format off 2, 3, // width, height 2, 7, // search 3, 4, 0, 13, 141, 39, // replace 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - open wall. */ BYTE VARCH23[] = { // clang-format off 2, 3, // width, height 2, 7, // search 3, 4, 0, 16, 141, 39, // replace 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - open wall. */ BYTE VARCH24[] = { // clang-format off 2, 3, // width, height 2, 7, // search 3, 4, 0, 15, 141, 39, // replace 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH25[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 4, 3, 1, 0, 7, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH26[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 4, 3, 1, 0, 8, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH27[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 4, 3, 1, 0, 6, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH28[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 4, 3, 1, 0, 9, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH29[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 4, 3, 1, 0, 14, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH30[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 4, 3, 1, 0, 13, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH31[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 4, 3, 1, 0, 16, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical. */ BYTE VARCH32[] = { // clang-format off 2, 4, // width, height 3, 0, // search 3, 4, 3, 1, 0, 15, 48, 0, // replace 51, 39, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - room west entrance. */ BYTE VARCH33[] = { // clang-format off 2, 4, // width, height 2, 0, // search 3, 8, 3, 4, 0, 7, 142, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - room west entrance. */ BYTE VARCH34[] = { // clang-format off 2, 4, // width, height 2, 0, // search 3, 8, 3, 4, 0, 8, 142, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - room west entrance. */ BYTE VARCH35[] = { // clang-format off 2, 4, // width, height 2, 0, // search 3, 8, 3, 4, 0, 6, 142, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - room west entrance. */ BYTE VARCH36[] = { // clang-format off 2, 4, // width, height 2, 0, // search 3, 8, 3, 4, 0, 9, 142, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - room west entrance. */ BYTE VARCH37[] = { // clang-format off 2, 4, // width, height 2, 0, // search 3, 8, 3, 4, 0, 14, 142, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - room west entrance. */ BYTE VARCH38[] = { // clang-format off 2, 4, // width, height 2, 0, // search 3, 8, 3, 4, 0, 13, 142, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - room west entrance. */ BYTE VARCH39[] = { // clang-format off 2, 4, // width, height 2, 0, // search 3, 8, 3, 4, 0, 16, 142, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch vertical - room west entrance. */ BYTE VARCH40[] = { // clang-format off 2, 4, // width, height 2, 0, // search 3, 8, 3, 4, 0, 15, 142, 0, // replace 51, 42, 47, 44, 0, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH1[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 2, 5, 9, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH2[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 2, 5, 6, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH3[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 2, 5, 8, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH4[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 2, 5, 7, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH5[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 2, 5, 15, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH6[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 2, 5, 16, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH7[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 2, 5, 13, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH8[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 2, 5, 14, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - north corner. */ BYTE HARCH9[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 8, 5, 9, 49, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - north corner. */ BYTE HARCH10[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 8, 5, 6, 49, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - north corner. */ BYTE HARCH11[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 8, 5, 8, 49, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - north corner. */ BYTE HARCH12[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 8, 5, 7, 49, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - north corner. */ BYTE HARCH13[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 8, 5, 15, 49, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - north corner. */ BYTE HARCH14[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 8, 5, 16, 49, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - north corner. */ BYTE HARCH15[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 8, 5, 13, 49, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - north corner. */ BYTE HARCH16[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 8, 5, 14, 49, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - wall. */ BYTE HARCH17[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 8, 5, 9, 140, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - wall. */ BYTE HARCH18[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 8, 5, 6, 140, 46, 0, // Replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - wall. */ BYTE HARCH19[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 8, 5, 8, 140, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - wall. */ BYTE HARCH20[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 8, 5, 7, 140, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - wall. */ BYTE HARCH21[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 8, 5, 15, 140, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - wall. */ BYTE HARCH22[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 8, 5, 16, 140, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - wall. */ BYTE HARCH23[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 8, 5, 13, 140, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - wall. */ BYTE HARCH24[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 8, 5, 14, 140, 46, 0, // replace 43, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH25[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 5, 2, 9, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH26[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 5, 2, 6, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH27[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 5, 2, 8, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH28[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 5, 2, 7, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH29[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 5, 2, 15, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH30[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 5, 2, 16, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH31[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 5, 2, 13, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal. */ BYTE HARCH32[] = { // clang-format off 3, 2, // width, height 3, 3, 0, // search 5, 2, 14, 49, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - west corner. */ BYTE HARCH33[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 9, 5, 9, 140, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - west corner. */ BYTE HARCH34[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 9, 5, 6, 140, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - west corner. */ BYTE HARCH35[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 9, 5, 8, 140, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - west corner. */ BYTE HARCH36[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 9, 5, 7, 140, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - west corner. */ BYTE HARCH37[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 9, 5, 15, 140, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - west corner. */ BYTE HARCH38[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 9, 5, 16, 140, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - west corner. */ BYTE HARCH39[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 9, 5, 13, 140, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Arch horizontal - west corner. */ BYTE HARCH40[] = { // clang-format off 3, 2, // width, height 1, 3, 0, // search 9, 5, 14, 140, 46, 0, // replace 40, 45, 0, // clang-format on }; /** Miniset: Stairs up. */ BYTE USTAIRS[] = { // clang-format off 4, 4, // width, height 3, 3, 3, 3, // search 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, // replace 0, 72, 77, 0, 0, 76, 0, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stairs down. */ BYTE DSTAIRS[] = { // clang-format off 4, 4, // width, height 3, 3, 3, 3, // search 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, // replace 0, 48, 71, 0, 0, 50, 78, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stairs to town. */ BYTE WARPSTAIRS[] = { // clang-format off 4, 4, // width, height 3, 3, 3, 3, // search 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, // replace 0, 158, 160, 0, 0, 159, 0, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Crumbled south pillar. */ BYTE CRUSHCOL[] = { // clang-format off 3, 3, // width, height 3, 1, 3, // search 2, 6, 3, 3, 3, 3, 0, 0, 0, // replace 0, 83, 0, 0, 0, 0, // clang-format on }; /** Miniset: Vertical oil spill. */ BYTE BIG1[] = { // clang-format off 2, 2, // width, height 3, 3, // search 3, 3, 113, 0, // replace 112, 0, // clang-format on }; /** Miniset: Horizontal oil spill. */ BYTE BIG2[] = { // clang-format off 2, 2, // width, height 3, 3, // search 3, 3, 114, 115, // replace 0, 0, // clang-format on }; /** Miniset: Horizontal platform. */ BYTE BIG3[] = { // clang-format off 1, 2, // width, height 1, // search 1, 117, // replace 116, // clang-format on }; /** Miniset: Vertical platform. */ BYTE BIG4[] = { // clang-format off 2, 1, // width, height 2, 2, // search 118, 119, // replace // clang-format on }; /** Miniset: Large oil spill. */ BYTE BIG5[] = { // clang-format off 2, 2, // width, height 3, 3, // search 3, 3, 120, 122, // replace 121, 123, // clang-format on }; /** Miniset: Vertical wall with debris. */ BYTE BIG6[] = { // clang-format off 1, 2, // width, height 1, // search 1, 125, // replace 124, // clang-format on }; /** Miniset: Horizontal wall with debris. */ BYTE BIG7[] = { // clang-format off 2, 1, // width, height 2, 2, // search 126, 127, // replace // clang-format on }; /** Miniset: Rock pile. */ BYTE BIG8[] = { // clang-format off 2, 2, // width, height 3, 3, // search 3, 3, 128, 130, // replace 129, 131, // clang-format on }; /** Miniset: Vertical wall collapsed. */ BYTE BIG9[] = { // clang-format off 2, 2, // width, height 1, 3, // search 1, 3, 133, 135, // replace 132, 134, // clang-format on }; /** Miniset: Horizontal wall collapsed. */ BYTE BIG10[] = { // clang-format off 2, 2, // width, height 2, 2, // search 3, 3, 136, 137, // replace 3, 3, // clang-format on }; /** Miniset: Crumbled vertical wall 1. */ BYTE RUINS1[] = { // clang-format off 1, 1, // width, height 1, // search 80, // replace // clang-format on }; /** Miniset: Crumbled vertical wall 2. */ BYTE RUINS2[] = { // clang-format off 1, 1, // width, height 1, // search 81, // replace // clang-format on }; /** Miniset: Crumbled vertical wall 3. */ BYTE RUINS3[] = { // clang-format off 1, 1, // width, height 1, // search 82, // replace // clang-format on }; /** Miniset: Crumbled horizontal wall 1. */ BYTE RUINS4[] = { // clang-format off 1, 1, // width, height 2, // search 84, // replace // clang-format on }; /** Miniset: Crumbled horizontal wall 2. */ BYTE RUINS5[] = { // clang-format off 1, 1, // width, height 2, // search 85, // replace // clang-format on }; /** Miniset: Crumbled horizontal wall 3. */ BYTE RUINS6[] = { // clang-format off 1, 1, // width, height 2, // search 86, // replace // clang-format on }; /** Miniset: Crumbled north pillar. */ BYTE RUINS7[] = { // clang-format off 1, 1, // width, height 8, // search 87, // replace // clang-format on }; /** Miniset: Bloody gib 1. */ BYTE PANCREAS1[] = { // clang-format off 5, 3, // width, height 3, 3, 3, 3, 3, // search 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // replace 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Bloody gib 2. */ BYTE PANCREAS2[] = { // clang-format off 5, 3, // width, height 3, 3, 3, 3, 3, // search 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // replace 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Move vertical doors away from west pillar 1. */ BYTE CTRDOOR1[] = { // clang-format off 3, 3, // width, height 3, 1, 3, // search 0, 4, 0, 0, 9, 0, 0, 4, 0, // replace 0, 1, 0, 0, 0, 0, // clang-format on }; /** Miniset: Move vertical doors away from west pillar 2. */ BYTE CTRDOOR2[] = { // clang-format off 3, 3, // width, height 3, 1, 3, // search 0, 4, 0, 0, 8, 0, 0, 4, 0, // replace 0, 1, 0, 0, 0, 0, // clang-format on }; /** Miniset: Move vertical doors away from west pillar 3. */ BYTE CTRDOOR3[] = { // clang-format off 3, 3, // width, height 3, 1, 3, // search 0, 4, 0, 0, 6, 0, 0, 4, 0, // replace 0, 1, 0, 0, 0, 0, // clang-format on }; /** Miniset: Move vertical doors away from west pillar 4. */ BYTE CTRDOOR4[] = { // clang-format off 3, 3, // width, height 3, 1, 3, // search 0, 4, 0, 0, 7, 0, 0, 4, 0, // replace 0, 1, 0, 0, 0, 0, // clang-format on }; /** Miniset: Move vertical doors away from west pillar 5. */ BYTE CTRDOOR5[] = { // clang-format off 3, 3, // width, height 3, 1, 3, // search 0, 4, 0, 0, 15, 0, 0, 4, 0, // replace 0, 1, 0, 0, 0, 0, // clang-format on }; /** Miniset: Move vertical doors away from west pillar 6. */ BYTE CTRDOOR6[] = { // clang-format off 3, 3, // width, height 3, 1, 3, // search 0, 4, 0, 0, 13, 0, 0, 4, 0, // replace 0, 1, 0, 0, 0, 0, // clang-format on }; /** Miniset: Move vertical doors away from west pillar 7. */ BYTE CTRDOOR7[] = { // clang-format off 3, 3, // width, height 3, 1, 3, // search 0, 4, 0, 0, 16, 0, 0, 4, 0, // replace 0, 1, 0, 0, 0, 0, // clang-format on }; /** Miniset: Move vertical doors away from west pillar 8. */ BYTE CTRDOOR8[] = { // clang-format off 3, 3, // width, height 3, 1, 3, // search 0, 4, 0, 0, 14, 0, 0, 4, 0, // replace 0, 1, 0, 0, 0, 0, // clang-format on }; 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 } }; static BOOL DRLG_L2PlaceMiniSet(BYTE *miniset, int tmin, int tmax, int cx, int cy, BOOL setview, int ldir) { int sx, sy, sw, sh, xx, yy, i, ii, numt, bailcnt; BOOL found; sw = miniset[0]; sh = miniset[1]; if (tmax - tmin == 0) { numt = 1; } else { numt = random_(0, tmax - tmin) + tmin; } for (i = 0; i < numt; i++) { sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); found = FALSE; for (bailcnt = 0; !found && bailcnt < 200; bailcnt++) { found = TRUE; if (sx >= nSx1 && sx <= nSx2 && sy >= nSy1 && sy <= nSy2) { found = FALSE; } if (cx != -1 && sx >= cx - sw && sx <= cx + 12) { sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); found = FALSE; } if (cy != -1 && sy >= cy - sh && sy <= cy + 12) { sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); found = FALSE; } ii = 2; for (yy = 0; yy < sh && found == TRUE; yy++) { for (xx = 0; xx < sw && found == TRUE; xx++) { if (miniset[ii] != 0 && dungeon[xx + sx][yy + sy] != miniset[ii]) { found = FALSE; } if (dflags[xx + sx][yy + sy] != 0) { found = FALSE; } ii++; } } if (!found) { sx++; if (sx == DMAXX - sw) { sx = 0; sy++; if (sy == DMAXY - sh) { sy = 0; } } } } if (bailcnt >= 200) { return FALSE; } ii = sw * sh + 2; for (yy = 0; yy < sh; yy++) { for (xx = 0; xx < sw; xx++) { if (miniset[ii] != 0) { dungeon[xx + sx][yy + sy] = miniset[ii]; } ii++; } } } if (setview == TRUE) { ViewX = 2 * sx + 21; ViewY = 2 * sy + 22; } if (ldir == 0) { LvlViewX = 2 * sx + 21; LvlViewY = 2 * sy + 22; } if (ldir == 6) { LvlViewX = 2 * sx + 21; LvlViewY = 2 * sy + 22; } return TRUE; } static void DRLG_L2PlaceRndSet(BYTE *miniset, int rndper) { int sx, sy, sw, sh, xx, yy, ii, kk; BOOL found; sw = miniset[0]; sh = miniset[1]; for (sy = 0; sy < DMAXY - sh; sy++) { for (sx = 0; sx < DMAXX - sw; sx++) { found = TRUE; ii = 2; if (sx >= nSx1 && sx <= nSx2 && sy >= nSy1 && sy <= nSy2) { found = FALSE; } for (yy = 0; yy < sh && found == TRUE; yy++) { for (xx = 0; xx < sw && found == TRUE; xx++) { if (miniset[ii] != 0 && dungeon[xx + sx][yy + sy] != miniset[ii]) { found = FALSE; } if (dflags[xx + sx][yy + sy] != 0) { found = FALSE; } ii++; } } kk = sw * sh + 2; if (found == TRUE) { for (yy = sy - sh; yy < sy + 2 * sh && found == TRUE; yy++) { for (xx = sx - sw; xx < sx + 2 * sw; xx++) { // BUGFIX: yy and xx can go out of bounds if (dungeon[xx][yy] == miniset[kk]) { found = FALSE; } } } } if (found == TRUE && random_(0, 100) < rndper) { for (yy = 0; yy < sh; yy++) { for (xx = 0; xx < sw; xx++) { if (miniset[kk] != 0) { dungeon[xx + sx][yy + sy] = miniset[kk]; } kk++; } } } } } } static void DRLG_L2Subs() { int x, y, i, j, k, rv; BYTE c; for (y = 0; y < DMAXY; y++) { for (x = 0; x < DMAXX; x++) { if ((x < nSx1 || x > nSx2) && (y < nSy1 || y > nSy2) && random_(0, 4) == 0) { // BUGFIX: Should be (x < nSx1 || x > nSx2 || y < nSy1 || y >= nSy2) c = BTYPESL2[dungeon[x][y]]; if (c != 0) { rv = random_(0, 16); k = -1; while (rv >= 0) { k++; if (k == sizeof(BTYPESL2)) { k = 0; } if (c == BTYPESL2[k]) { rv--; } } for (j = y - 2; j < y + 2; j++) { for (i = x - 2; i < x + 2; i++) { if (dungeon[i][j] == k) { j = y + 3; i = x + 2; } } } if (j < y + 3) { dungeon[x][y] = k; } } } } } } static void DRLG_L2Shadows() { int x, y, i; BOOL patflag; BYTE sd[2][2]; for (y = 1; y < DMAXY; y++) { for (x = 1; x < DMAXX; x++) { sd[0][0] = BSTYPESL2[dungeon[x][y]]; sd[1][0] = BSTYPESL2[dungeon[x - 1][y]]; sd[0][1] = BSTYPESL2[dungeon[x][y - 1]]; sd[1][1] = BSTYPESL2[dungeon[x - 1][y - 1]]; for (i = 0; i < 2; i++) { if (SPATSL2[i].strig == sd[0][0]) { patflag = TRUE; if (SPATSL2[i].s1 != 0 && SPATSL2[i].s1 != sd[1][1]) { patflag = FALSE; } if (SPATSL2[i].s2 != 0 && SPATSL2[i].s2 != sd[0][1]) { patflag = FALSE; } if (SPATSL2[i].s3 != 0 && SPATSL2[i].s3 != sd[1][0]) { patflag = FALSE; } if (patflag == TRUE) { if (SPATSL2[i].nv1 != 0) { dungeon[x - 1][y - 1] = SPATSL2[i].nv1; } if (SPATSL2[i].nv2 != 0) { dungeon[x][y - 1] = SPATSL2[i].nv2; } if (SPATSL2[i].nv3 != 0) { dungeon[x - 1][y] = SPATSL2[i].nv3; } } } } } } } void InitDungeon() { int i, j; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { predungeon[i][j] = 32; dflags[i][j] = 0; } } } static void DRLG_LoadL2SP() { setloadflag = FALSE; if (QuestStatus(Q_BLIND)) { pSetPiece = LoadFileInMem("Levels\\L2Data\\Blind2.DUN", NULL); setloadflag = TRUE; } else if (QuestStatus(Q_BLOOD)) { pSetPiece = LoadFileInMem("Levels\\L2Data\\Blood1.DUN", NULL); setloadflag = TRUE; } else if (QuestStatus(Q_SCHAMB)) { pSetPiece = LoadFileInMem("Levels\\L2Data\\Bonestr2.DUN", NULL); setloadflag = TRUE; } } static void DRLG_FreeL2SP() { MemFreeDbg(pSetPiece); } static void DRLG_L2SetRoom(int rx1, int ry1) { int rw, rh, i, j; BYTE *sp; rw = pSetPiece[0]; rh = pSetPiece[2]; setpc_x = rx1; setpc_y = ry1; setpc_w = rw; setpc_h = rh; sp = &pSetPiece[4]; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*sp != 0) { dungeon[i + rx1][j + ry1] = *sp; dflags[i + rx1][j + ry1] |= DLRG_PROTECTED; } else { dungeon[i + rx1][j + ry1] = 3; } sp += 2; } } } static void DefineRoom(int nX1, int nY1, int nX2, int nY2, BOOL ForceHW) { int i, j; predungeon[nX1][nY1] = 67; predungeon[nX1][nY2] = 69; predungeon[nX2][nY1] = 66; predungeon[nX2][nY2] = 65; nRoomCnt++; RoomList[nRoomCnt].nRoomx1 = nX1; RoomList[nRoomCnt].nRoomx2 = nX2; RoomList[nRoomCnt].nRoomy1 = nY1; RoomList[nRoomCnt].nRoomy2 = nY2; if (ForceHW == TRUE) { for (i = nX1; i < nX2; i++) { /// BUGFIX: Should loop j between nY1 and nY2 instead of always using nY1. while (i < nY2) { dflags[i][nY1] |= DLRG_PROTECTED; i++; } } } for (i = nX1 + 1; i <= nX2 - 1; i++) { predungeon[i][nY1] = 35; predungeon[i][nY2] = 35; } nY2--; for (j = nY1 + 1; j <= nY2; j++) { predungeon[nX1][j] = 35; predungeon[nX2][j] = 35; for (i = nX1 + 1; i < nX2; i++) { predungeon[i][j] = 46; } } } static void CreateDoorType(int nX, int nY) { BOOL fDoneflag; fDoneflag = FALSE; if (predungeon[nX - 1][nY] == 68) { fDoneflag = TRUE; } if (predungeon[nX + 1][nY] == 68) { fDoneflag = TRUE; } if (predungeon[nX][nY - 1] == 68) { fDoneflag = TRUE; } if (predungeon[nX][nY + 1] == 68) { fDoneflag = TRUE; } if (predungeon[nX][nY] == 66 || predungeon[nX][nY] == 67 || predungeon[nX][nY] == 65 || predungeon[nX][nY] == 69) { fDoneflag = TRUE; } if (!fDoneflag) { predungeon[nX][nY] = 68; } } static void PlaceHallExt(int nX, int nY) { if (predungeon[nX][nY] == 32) { predungeon[nX][nY] = 44; } } static void AddHall(int nX1, int nY1, int nX2, int nY2, int nHd) { HALLNODE *p1, *p2; if (pHallList == NULL) { pHallList = (HALLNODE *)DiabloAllocPtr(sizeof(*pHallList)); pHallList->nHallx1 = nX1; pHallList->nHally1 = nY1; pHallList->nHallx2 = nX2; pHallList->nHally2 = nY2; pHallList->nHalldir = nHd; pHallList->pNext = NULL; } else { p1 = (HALLNODE *)DiabloAllocPtr(sizeof(*pHallList)); p1->nHallx1 = nX1; p1->nHally1 = nY1; p1->nHallx2 = nX2; p1->nHally2 = nY2; p1->nHalldir = nHd; p1->pNext = NULL; p2 = pHallList; while (p2->pNext != NULL) { p2 = p2->pNext; } p2->pNext = p1; } } /** * Draws a random room rectangle, and then subdivides the rest of the passed in rectangle into 4 and recurses. * @param nX1 Lower X boundary of the area to draw into. * @param nY1 Lower Y boundary of the area to draw into. * @param nX2 Upper X boundary of the area to draw into. * @param nY2 Upper Y boundary of the area to draw into. * @param nRDest The room number of the parent room this call was invoked for. Zero for empty * @param nHDir The direction of the hall from nRDest to this room. * @param ForceHW If set, nH and nW are used for room size instead of random values. * @param nH Height of the room, if ForceHW is set. * @param nW Width of the room, if ForceHW is set. */ static void CreateRoom(int nX1, int nY1, int nX2, int nY2, int nRDest, int nHDir, BOOL ForceHW, int nH, int nW) { int nAw, nAh, nRw, nRh, nRx1, nRy1, nRx2, nRy2, nHw, nHh, nHx1, nHy1, nHx2, nHy2, nRid; if (nRoomCnt >= 80) { return; } nAw = nX2 - nX1; nAh = nY2 - nY1; if (nAw < Area_Min || nAh < Area_Min) { return; } if (nAw > Room_Max) { nRw = random_(0, Room_Max - Room_Min) + Room_Min; } else if (nAw > Room_Min) { nRw = random_(0, nAw - Room_Min) + Room_Min; } else { nRw = nAw; } if (nAh > Room_Max) { nRh = random_(0, Room_Max - Room_Min) + Room_Min; } else if (nAh > Room_Min) { nRh = random_(0, nAh - Room_Min) + Room_Min; } else { nRh = nAh; } if (ForceHW == TRUE) { nRw = nW; nRh = nH; } nRx1 = random_(0, nX2 - nX1) + nX1; nRy1 = random_(0, nY2 - nY1) + nY1; nRx2 = nRw + nRx1; nRy2 = nRh + nRy1; if (nRx2 > nX2) { nRx2 = nX2; nRx1 = nX2 - nRw; } if (nRy2 > nY2) { nRy2 = nY2; nRy1 = nY2 - nRh; } if (nRx1 >= 38) { nRx1 = 38; } if (nRy1 >= 38) { nRy1 = 38; } if (nRx1 <= 1) { nRx1 = 1; } if (nRy1 <= 1) { nRy1 = 1; } if (nRx2 >= 38) { nRx2 = 38; } if (nRy2 >= 38) { nRy2 = 38; } if (nRx2 <= 1) { nRx2 = 1; } if (nRy2 <= 1) { nRy2 = 1; } DefineRoom(nRx1, nRy1, nRx2, nRy2, ForceHW); if (ForceHW == TRUE) { nSx1 = nRx1 + 2; nSy1 = nRy1 + 2; nSx2 = nRx2; nSy2 = nRy2; } nRid = nRoomCnt; RoomList[nRid].nRoomDest = nRDest; if (nRDest != 0) { if (nHDir == 1) { nHx1 = random_(0, nRx2 - nRx1 - 2) + nRx1 + 1; nHy1 = nRy1; nHw = RoomList[nRDest].nRoomx2 - RoomList[nRDest].nRoomx1 - 2; nHx2 = random_(0, nHw) + RoomList[nRDest].nRoomx1 + 1; nHy2 = RoomList[nRDest].nRoomy2; } if (nHDir == 3) { nHx1 = random_(0, nRx2 - nRx1 - 2) + nRx1 + 1; nHy1 = nRy2; nHw = RoomList[nRDest].nRoomx2 - RoomList[nRDest].nRoomx1 - 2; nHx2 = random_(0, nHw) + RoomList[nRDest].nRoomx1 + 1; nHy2 = RoomList[nRDest].nRoomy1; } if (nHDir == 2) { nHx1 = nRx2; nHy1 = random_(0, nRy2 - nRy1 - 2) + nRy1 + 1; nHx2 = RoomList[nRDest].nRoomx1; nHh = RoomList[nRDest].nRoomy2 - RoomList[nRDest].nRoomy1 - 2; nHy2 = random_(0, nHh) + RoomList[nRDest].nRoomy1 + 1; } if (nHDir == 4) { nHx1 = nRx1; nHy1 = random_(0, nRy2 - nRy1 - 2) + nRy1 + 1; nHx2 = RoomList[nRDest].nRoomx2; nHh = RoomList[nRDest].nRoomy2 - RoomList[nRDest].nRoomy1 - 2; nHy2 = random_(0, nHh) + RoomList[nRDest].nRoomy1 + 1; } AddHall(nHx1, nHy1, nHx2, nHy2, nHDir); } if (nRh > nRw) { CreateRoom(nX1 + 2, nY1 + 2, nRx1 - 2, nRy2 - 2, nRid, 2, 0, 0, 0); CreateRoom(nRx2 + 2, nRy1 + 2, nX2 - 2, nY2 - 2, nRid, 4, 0, 0, 0); CreateRoom(nX1 + 2, nRy2 + 2, nRx2 - 2, nY2 - 2, nRid, 1, 0, 0, 0); CreateRoom(nRx1 + 2, nY1 + 2, nX2 - 2, nRy1 - 2, nRid, 3, 0, 0, 0); } else { CreateRoom(nX1 + 2, nY1 + 2, nRx2 - 2, nRy1 - 2, nRid, 3, 0, 0, 0); CreateRoom(nRx1 + 2, nRy2 + 2, nX2 - 2, nY2 - 2, nRid, 1, 0, 0, 0); CreateRoom(nX1 + 2, nRy1 + 2, nRx1 - 2, nY2 - 2, nRid, 2, 0, 0, 0); CreateRoom(nRx2 + 2, nY1 + 2, nX2 - 2, nRy2 - 2, nRid, 4, 0, 0, 0); } } static void GetHall(int *nX1, int *nY1, int *nX2, int *nY2, int *nHd) { HALLNODE *p1; p1 = pHallList->pNext; *nX1 = pHallList->nHallx1; *nY1 = pHallList->nHally1; *nX2 = pHallList->nHallx2; *nY2 = pHallList->nHally2; *nHd = pHallList->nHalldir; MemFreeDbg(pHallList); pHallList = p1; } static void ConnectHall(int nX1, int nY1, int nX2, int nY2, int nHd) { int nCurrd, nDx, nDy, nRp, nOrigX1, nOrigY1, fMinusFlag, fPlusFlag; BOOL fDoneflag, fInroom; fDoneflag = FALSE; fMinusFlag = random_(0, 100); fPlusFlag = random_(0, 100); nOrigX1 = nX1; nOrigY1 = nY1; CreateDoorType(nX1, nY1); CreateDoorType(nX2, nY2); nDx = abs(nX2 - nX1); /* unused */ nDy = abs(nY2 - nY1); /* unused */ nCurrd = nHd; nX2 -= Dir_Xadd[nCurrd]; nY2 -= Dir_Yadd[nCurrd]; predungeon[nX2][nY2] = 44; fInroom = FALSE; while (!fDoneflag) { if (nX1 >= 38 && nCurrd == 2) { nCurrd = 4; } if (nY1 >= 38 && nCurrd == 3) { nCurrd = 1; } if (nX1 <= 1 && nCurrd == 4) { nCurrd = 2; } if (nY1 <= 1 && nCurrd == 1) { nCurrd = 3; } if (predungeon[nX1][nY1] == 67 && (nCurrd == 1 || nCurrd == 4)) { nCurrd = 2; } if (predungeon[nX1][nY1] == 66 && (nCurrd == 1 || nCurrd == 2)) { nCurrd = 3; } if (predungeon[nX1][nY1] == 69 && (nCurrd == 4 || nCurrd == 3)) { nCurrd = 1; } if (predungeon[nX1][nY1] == 65 && (nCurrd == 2 || nCurrd == 3)) { nCurrd = 4; } nX1 += Dir_Xadd[nCurrd]; nY1 += Dir_Yadd[nCurrd]; if (predungeon[nX1][nY1] == 32) { if (fInroom) { CreateDoorType(nX1 - Dir_Xadd[nCurrd], nY1 - Dir_Yadd[nCurrd]); } else { if (fMinusFlag < 50) { if (nCurrd != 1 && nCurrd != 3) { PlaceHallExt(nX1, nY1 - 1); } else { PlaceHallExt(nX1 - 1, nY1); } } if (fPlusFlag < 50) { if (nCurrd != 1 && nCurrd != 3) { PlaceHallExt(nX1, nY1 + 1); } else { PlaceHallExt(nX1 + 1, nY1); } } } predungeon[nX1][nY1] = 44; fInroom = FALSE; } else { if (!fInroom && predungeon[nX1][nY1] == 35) { CreateDoorType(nX1, nY1); } if (predungeon[nX1][nY1] != 44) { fInroom = TRUE; } } nDx = abs(nX2 - nX1); nDy = abs(nY2 - nY1); if (nDx > nDy) { nRp = 2 * nDx; if (nRp > 30) { nRp = 30; } if (random_(0, 100) < nRp) { if (nX2 <= nX1 || nX1 >= DMAXX) { nCurrd = 4; } else { nCurrd = 2; } } } else { nRp = 5 * nDy; if (nRp > 80) { nRp = 80; } if (random_(0, 100) < nRp) { if (nY2 <= nY1 || nY1 >= DMAXY) { nCurrd = 1; } else { nCurrd = 3; } } } if (nDy < 10 && nX1 == nX2 && (nCurrd == 2 || nCurrd == 4)) { if (nY2 <= nY1 || nY1 >= DMAXY) { nCurrd = 1; } else { nCurrd = 3; } } if (nDx < 10 && nY1 == nY2 && (nCurrd == 1 || nCurrd == 3)) { if (nX2 <= nX1 || nX1 >= DMAXX) { nCurrd = 4; } else { nCurrd = 2; } } if (nDy == 1 && nDx > 1 && (nCurrd == 1 || nCurrd == 3)) { if (nX2 <= nX1 || nX1 >= DMAXX) { nCurrd = 4; } else { nCurrd = 2; } } if (nDx == 1 && nDy > 1 && (nCurrd == 2 || nCurrd == 4)) { if (nY2 <= nY1 || nX1 >= DMAXX) { nCurrd = 1; } else { nCurrd = 3; } } if (nDx == 0 && predungeon[nX1][nY1] != 32 && (nCurrd == 2 || nCurrd == 4)) { if (nX2 <= nOrigX1 || nX1 >= DMAXX) { nCurrd = 1; } else { nCurrd = 3; } } if (nDy == 0 && predungeon[nX1][nY1] != 32 && (nCurrd == 1 || nCurrd == 3)) { if (nY2 <= nOrigY1 || nY1 >= DMAXY) { nCurrd = 4; } else { nCurrd = 2; } } if (nX1 == nX2 && nY1 == nY2) { fDoneflag = TRUE; } } } static void DoPatternCheck(int i, int j) { int k, l, x, y, nOk; for (k = 0; Patterns[k][4] != 255; k++) { x = i - 1; y = j - 1; nOk = 254; for (l = 0; l < 9 && nOk == 254; l++) { nOk = 255; if (l == 3 || l == 6) { y++; x = i - 1; } if (x >= 0 && x < DMAXX && y >= 0 && y < DMAXY) { switch (Patterns[k][l]) { case 0: nOk = 254; break; case 1: if (predungeon[x][y] == 35) { nOk = 254; } break; case 2: if (predungeon[x][y] == 46) { nOk = 254; } break; case 4: if (predungeon[x][y] == 32) { nOk = 254; } break; case 3: if (predungeon[x][y] == 68) { nOk = 254; } break; case 5: if (predungeon[x][y] == 68 || predungeon[x][y] == 46) { nOk = 254; } break; case 6: if (predungeon[x][y] == 68 || predungeon[x][y] == 35) { nOk = 254; } break; case 7: if (predungeon[x][y] == 32 || predungeon[x][y] == 46) { nOk = 254; } break; case 8: if (predungeon[x][y] == 68 || predungeon[x][y] == 35 || predungeon[x][y] == 46) { nOk = 254; } break; } } else { nOk = 254; } x++; } if (nOk == 254) { dungeon[i][j] = Patterns[k][9]; } } } static void L2TileFix() { int i, j; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 3) { dungeon[i][j + 1] = 1; } if (dungeon[i][j] == 3 && dungeon[i][j + 1] == 1) { dungeon[i][j + 1] = 3; } if (dungeon[i][j] == 3 && dungeon[i + 1][j] == 7) { dungeon[i + 1][j] = 3; } if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 3) { dungeon[i + 1][j] = 2; } if (dungeon[i][j] == 11 && dungeon[i + 1][j] == 14) { dungeon[i + 1][j] = 16; } } } } static BOOL DL2_Cont(BOOL x1f, BOOL y1f, BOOL x2f, BOOL y2f) { if (x1f && x2f && y1f && y2f) { return FALSE; } if (x1f && x2f && (y1f || y2f)) { return TRUE; } if (y1f && y2f && (x1f || x2f)) { return TRUE; } return FALSE; } static int DL2_NumNoChar() { int t, ii, jj; t = 0; for (jj = 0; jj < DMAXY; jj++) { for (ii = 0; ii < DMAXX; ii++) { if (predungeon[ii][jj] == 32) { t++; } } } return t; } static void DL2_DrawRoom(int x1, int y1, int x2, int y2) { int ii, jj; for (jj = y1; jj <= y2; jj++) { for (ii = x1; ii <= x2; ii++) { predungeon[ii][jj] = 46; } } for (jj = y1; jj <= y2; jj++) { predungeon[x1][jj] = 35; predungeon[x2][jj] = 35; } for (ii = x1; ii <= x2; ii++) { predungeon[ii][y1] = 35; predungeon[ii][y2] = 35; } } static void DL2_KnockWalls(int x1, int y1, int x2, int y2) { int ii, jj; for (ii = x1 + 1; ii < x2; ii++) { if (predungeon[ii][y1 - 1] == 46 && predungeon[ii][y1 + 1] == 46) { predungeon[ii][y1] = 46; } if (predungeon[ii][y2 - 1] == 46 && predungeon[ii][y2 + 1] == 46) { predungeon[ii][y2] = 46; } if (predungeon[ii][y1 - 1] == 68) { predungeon[ii][y1 - 1] = 46; } if (predungeon[ii][y2 + 1] == 68) { predungeon[ii][y2 + 1] = 46; } } for (jj = y1 + 1; jj < y2; jj++) { if (predungeon[x1 - 1][jj] == 46 && predungeon[x1 + 1][jj] == 46) { predungeon[x1][jj] = 46; } if (predungeon[x2 - 1][jj] == 46 && predungeon[x2 + 1][jj] == 46) { predungeon[x2][jj] = 46; } if (predungeon[x1 - 1][jj] == 68) { predungeon[x1 - 1][jj] = 46; } if (predungeon[x2 + 1][jj] == 68) { predungeon[x2 + 1][jj] = 46; } } } static BOOL DL2_FillVoids() { int ii, jj, xx, yy, x1, x2, y1, y2; BOOL xf1, xf2, yf1, yf2; int to; to = 0; while (DL2_NumNoChar() > 700 && to < 100) { xx = random_(0, 38) + 1; yy = random_(0, 38) + 1; if (predungeon[xx][yy] != 35) { continue; } xf1 = xf2 = yf1 = yf2 = FALSE; if (predungeon[xx - 1][yy] == 32 && predungeon[xx + 1][yy] == 46) { if (predungeon[xx + 1][yy - 1] == 46 && predungeon[xx + 1][yy + 1] == 46 && predungeon[xx - 1][yy - 1] == 32 && predungeon[xx - 1][yy + 1] == 32) { xf1 = yf1 = yf2 = TRUE; } } else if (predungeon[xx + 1][yy] == 32 && predungeon[xx - 1][yy] == 46) { if (predungeon[xx - 1][yy - 1] == 46 && predungeon[xx - 1][yy + 1] == 46 && predungeon[xx + 1][yy - 1] == 32 && predungeon[xx + 1][yy + 1] == 32) { xf2 = yf1 = yf2 = TRUE; } } else if (predungeon[xx][yy - 1] == 32 && predungeon[xx][yy + 1] == 46) { if (predungeon[xx - 1][yy + 1] == 46 && predungeon[xx + 1][yy + 1] == 46 && predungeon[xx - 1][yy - 1] == 32 && predungeon[xx + 1][yy - 1] == 32) { yf1 = xf1 = xf2 = TRUE; } } else if (predungeon[xx][yy + 1] == 32 && predungeon[xx][yy - 1] == 46) { if (predungeon[xx - 1][yy - 1] == 46 && predungeon[xx + 1][yy - 1] == 46 && predungeon[xx - 1][yy + 1] == 32 && predungeon[xx + 1][yy + 1] == 32) { yf2 = xf1 = xf2 = TRUE; } } if (DL2_Cont(xf1, yf1, xf2, yf2)) { if (xf1) { x1 = xx - 1; } else { x1 = xx; } if (xf2) { x2 = xx + 1; } else { x2 = xx; } if (yf1) { y1 = yy - 1; } else { y1 = yy; } if (yf2) { y2 = yy + 1; } else { y2 = yy; } if (!xf1) { while (yf1 || yf2) { if (y1 == 0) { yf1 = FALSE; } if (y2 == DMAXY - 1) { yf2 = FALSE; } if (y2 - y1 >= 14) { yf1 = FALSE; yf2 = FALSE; } if (yf1) { y1--; } if (yf2) { y2++; } if (predungeon[x2][y1] != 32) { yf1 = FALSE; } if (predungeon[x2][y2] != 32) { yf2 = FALSE; } } y1 += 2; y2 -= 2; if (y2 - y1 > 5) { while (xf2) { if (x2 == 39) { xf2 = FALSE; } if (x2 - x1 >= 12) { xf2 = FALSE; } for (jj = y1; jj <= y2; jj++) { if (predungeon[x2][jj] != 32) { xf2 = FALSE; } } if (xf2) { x2++; } } x2 -= 2; if (x2 - x1 > 5) { DL2_DrawRoom(x1, y1, x2, y2); DL2_KnockWalls(x1, y1, x2, y2); } } } else if (!xf2) { while (yf1 || yf2) { if (y1 == 0) { yf1 = FALSE; } if (y2 == DMAXY - 1) { yf2 = FALSE; } if (y2 - y1 >= 14) { yf1 = FALSE; yf2 = FALSE; } if (yf1) { y1--; } if (yf2) { y2++; } if (predungeon[x1][y1] != 32) { yf1 = FALSE; } if (predungeon[x1][y2] != 32) { yf2 = FALSE; } } y1 += 2; y2 -= 2; if (y2 - y1 > 5) { while (xf1) { if (x1 == 0) { xf1 = FALSE; } if (x2 - x1 >= 12) { xf1 = FALSE; } for (jj = y1; jj <= y2; jj++) { if (predungeon[x1][jj] != 32) { xf1 = FALSE; } } if (xf1) { x1--; } } x1 += 2; if (x2 - x1 > 5) { DL2_DrawRoom(x1, y1, x2, y2); DL2_KnockWalls(x1, y1, x2, y2); } } } else if (!yf1) { while (xf1 || xf2) { if (x1 == 0) { xf1 = FALSE; } if (x2 == DMAXX - 1) { xf2 = FALSE; } if (x2 - x1 >= 14) { xf1 = FALSE; xf2 = FALSE; } if (xf1) { x1--; } if (xf2) { x2++; } if (predungeon[x1][y2] != 32) { xf1 = FALSE; } if (predungeon[x2][y2] != 32) { xf2 = FALSE; } } x1 += 2; x2 -= 2; if (x2 - x1 > 5) { while (yf2) { if (y2 == DMAXY - 1) { yf2 = FALSE; } if (y2 - y1 >= 12) { yf2 = FALSE; } for (ii = x1; ii <= x2; ii++) { if (predungeon[ii][y2] != 32) { yf2 = FALSE; } } if (yf2) { y2++; } } y2 -= 2; if (y2 - y1 > 5) { DL2_DrawRoom(x1, y1, x2, y2); DL2_KnockWalls(x1, y1, x2, y2); } } } else if (!yf2) { while (xf1 || xf2) { if (x1 == 0) { xf1 = FALSE; } if (x2 == DMAXX - 1) { xf2 = FALSE; } if (x2 - x1 >= 14) { xf1 = FALSE; xf2 = FALSE; } if (xf1) { x1--; } if (xf2) { x2++; } if (predungeon[x1][y1] != 32) { xf1 = FALSE; } if (predungeon[x2][y1] != 32) { xf2 = FALSE; } } x1 += 2; x2 -= 2; if (x2 - x1 > 5) { while (yf1) { if (y1 == 0) { yf1 = FALSE; } if (y2 - y1 >= 12) { yf1 = FALSE; } for (ii = x1; ii <= x2; ii++) { if (predungeon[ii][y1] != 32) { yf1 = FALSE; } } if (yf1) { y1--; } } y1 += 2; if (y2 - y1 > 5) { DL2_DrawRoom(x1, y1, x2, y2); DL2_KnockWalls(x1, y1, x2, y2); } } } } to++; } return DL2_NumNoChar() <= 700; } static BOOL CreateDungeon() { int i, j, nHx1, nHy1, nHx2, nHy2, nHd, ForceH, ForceW; BOOL ForceHW; ForceW = 0; ForceH = 0; ForceHW = FALSE; switch (currlevel) { case 5: if (quests[Q_BLOOD]._qactive != QUEST_NOTAVAIL) { ForceHW = TRUE; ForceH = 20; ForceW = 14; } break; case 6: if (quests[Q_SCHAMB]._qactive != QUEST_NOTAVAIL) { ForceHW = TRUE; ForceW = 10; ForceH = 10; } break; case 7: if (quests[Q_BLIND]._qactive != QUEST_NOTAVAIL) { ForceHW = TRUE; ForceW = 15; ForceH = 15; } break; case 8: break; } CreateRoom(2, 2, DMAXX - 1, DMAXY - 1, 0, 0, ForceHW, ForceH, ForceW); while (pHallList != NULL) { GetHall(&nHx1, &nHy1, &nHx2, &nHy2, &nHd); ConnectHall(nHx1, nHy1, nHx2, nHy2, nHd); } for (j = 0; j <= DMAXY; j++) { /// BUGFIX: change '<=' to '<' for (i = 0; i <= DMAXX; i++) { /// BUGFIX: change '<=' to '<' if (predungeon[i][j] == 67) { predungeon[i][j] = 35; } if (predungeon[i][j] == 66) { predungeon[i][j] = 35; } if (predungeon[i][j] == 69) { predungeon[i][j] = 35; } if (predungeon[i][j] == 65) { predungeon[i][j] = 35; } if (predungeon[i][j] == 44) { predungeon[i][j] = 46; if (predungeon[i - 1][j - 1] == 32) { predungeon[i - 1][j - 1] = 35; } if (predungeon[i - 1][j] == 32) { predungeon[i - 1][j] = 35; } if (predungeon[i - 1][1 + j] == 32) { predungeon[i - 1][1 + j] = 35; } if (predungeon[i + 1][j - 1] == 32) { predungeon[i + 1][j - 1] = 35; } if (predungeon[i + 1][j] == 32) { predungeon[i + 1][j] = 35; } if (predungeon[i + 1][1 + j] == 32) { predungeon[i + 1][1 + j] = 35; } if (predungeon[i][j - 1] == 32) { predungeon[i][j - 1] = 35; } if (predungeon[i][j + 1] == 32) { predungeon[i][j + 1] = 35; } } } } if (!DL2_FillVoids()) { return FALSE; } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { DoPatternCheck(i, j); } } return TRUE; } static void DRLG_L2Pass3() { int i, j, xx, yy; long v1, v2, v3, v4, lv; lv = 12 - 1; #ifdef USE_ASM __asm { mov esi, pMegaTiles mov eax, lv shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax } #else v1 = *((WORD *)&pMegaTiles[lv * 8] + 0) + 1; v2 = *((WORD *)&pMegaTiles[lv * 8] + 1) + 1; v3 = *((WORD *)&pMegaTiles[lv * 8] + 2) + 1; v4 = *((WORD *)&pMegaTiles[lv * 8] + 3) + 1; #endif for (j = 0; j < MAXDUNY; j += 2) { for (i = 0; i < MAXDUNX; i += 2) { dPiece[i][j] = v1; dPiece[i + 1][j] = v2; dPiece[i][j + 1] = v3; dPiece[i + 1][j + 1] = v4; } } yy = 16; for (j = 0; j < DMAXY; j++) { xx = 16; for (i = 0; i < DMAXX; i++) { lv = dungeon[i][j] - 1; #ifdef USE_ASM __asm { mov esi, pMegaTiles mov eax, lv shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax } #else v1 = *((WORD *)&pMegaTiles[lv * 8] + 0) + 1; v2 = *((WORD *)&pMegaTiles[lv * 8] + 1) + 1; v3 = *((WORD *)&pMegaTiles[lv * 8] + 2) + 1; v4 = *((WORD *)&pMegaTiles[lv * 8] + 3) + 1; #endif dPiece[xx][yy] = v1; dPiece[xx + 1][yy] = v2; dPiece[xx][yy + 1] = v3; dPiece[xx + 1][yy + 1] = v4; xx += 2; } yy += 2; } } static void DRLG_L2FTVR(int i, int j, int x, int y, int d) { if (dTransVal[x][y] != 0 || dungeon[i][j] != 3) { if (d == 1) { dTransVal[x][y] = TransVal; dTransVal[x][y + 1] = TransVal; } if (d == 2) { dTransVal[x + 1][y] = TransVal; dTransVal[x + 1][y + 1] = TransVal; } if (d == 3) { dTransVal[x][y] = TransVal; dTransVal[x + 1][y] = TransVal; } if (d == 4) { dTransVal[x][y + 1] = TransVal; dTransVal[x + 1][y + 1] = TransVal; } if (d == 5) { dTransVal[x + 1][y + 1] = TransVal; } if (d == 6) { dTransVal[x][y + 1] = TransVal; } if (d == 7) { dTransVal[x + 1][y] = TransVal; } if (d == 8) { dTransVal[x][y] = TransVal; } } else { dTransVal[x][y] = TransVal; dTransVal[x + 1][y] = TransVal; dTransVal[x][y + 1] = TransVal; dTransVal[x + 1][y + 1] = TransVal; DRLG_L2FTVR(i + 1, j, x + 2, y, 1); DRLG_L2FTVR(i - 1, j, x - 2, y, 2); DRLG_L2FTVR(i, j + 1, x, y + 2, 3); DRLG_L2FTVR(i, j - 1, x, y - 2, 4); DRLG_L2FTVR(i - 1, j - 1, x - 2, y - 2, 5); DRLG_L2FTVR(i + 1, j - 1, x + 2, y - 2, 6); DRLG_L2FTVR(i - 1, j + 1, x - 2, y + 2, 7); DRLG_L2FTVR(i + 1, j + 1, x + 2, y + 2, 8); } } static void DRLG_L2FloodTVal() { int i, j, xx, yy; yy = 16; for (j = 0; j < DMAXY; j++) { xx = 16; for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 3 && dTransVal[xx][yy] == 0) { DRLG_L2FTVR(i, j, xx, yy, 0); TransVal++; } xx += 2; } yy += 2; } } static void DRLG_L2TransFix() { int i, j, xx, yy; yy = 16; for (j = 0; j < DMAXY; j++) { xx = 16; for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 14 && dungeon[i][j - 1] == 10) { dTransVal[xx + 1][yy] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 11) { dTransVal[xx][yy + 1] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 10) { dTransVal[xx + 1][yy] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 11) { dTransVal[xx][yy + 1] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 16) { dTransVal[xx + 1][yy] = dTransVal[xx][yy]; dTransVal[xx][yy + 1] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } xx += 2; } yy += 2; } } static void L2DirtFix() { int i, j; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 13 && dungeon[i + 1][j] != 11) { dungeon[i][j] = 146; } if (dungeon[i][j] == 11 && dungeon[i + 1][j] != 11) { dungeon[i][j] = 144; } if (dungeon[i][j] == 15 && dungeon[i + 1][j] != 11) { dungeon[i][j] = 148; } if (dungeon[i][j] == 10 && dungeon[i][j + 1] != 10) { dungeon[i][j] = 143; } if (dungeon[i][j] == 13 && dungeon[i][j + 1] != 10) { dungeon[i][j] = 146; } if (dungeon[i][j] == 14 && dungeon[i][j + 1] != 15) { dungeon[i][j] = 147; } } } } void L2LockoutFix() { int i, j; BOOL doorok; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 4 && dungeon[i - 1][j] != 3) { dungeon[i][j] = 1; } if (dungeon[i][j] == 5 && dungeon[i][j - 1] != 3) { dungeon[i][j] = 2; } } } for (j = 1; j < DMAXY - 1; j++) { for (i = 1; i < DMAXX - 1; i++) { if (dflags[i][j] & DLRG_PROTECTED) { continue; } if ((dungeon[i][j] == 2 || dungeon[i][j] == 5) && dungeon[i][j - 1] == 3 && dungeon[i][j + 1] == 3) { doorok = FALSE; while (1) { if (dungeon[i][j] != 2 && dungeon[i][j] != 5) { break; } if (dungeon[i][j - 1] != 3 || dungeon[i][j + 1] != 3) { break; } if (dungeon[i][j] == 5) { doorok = TRUE; } i++; } if (!doorok && !(dflags[i - 1][j] & DLRG_PROTECTED)) { dungeon[i - 1][j] = 5; } } } } for (j = 1; j < DMAXX - 1; j++) { /* check: might be flipped */ for (i = 1; i < DMAXY - 1; i++) { if (dflags[j][i] & DLRG_PROTECTED) { continue; } if ((dungeon[j][i] == 1 || dungeon[j][i] == 4) && dungeon[j - 1][i] == 3 && dungeon[j + 1][i] == 3) { doorok = FALSE; while (1) { if (dungeon[j][i] != 1 && dungeon[j][i] != 4) { break; } if (dungeon[j - 1][i] != 3 || dungeon[j + 1][i] != 3) { break; } if (dungeon[j][i] == 4) { doorok = TRUE; } i++; } if (!doorok && !(dflags[j][i - 1] & DLRG_PROTECTED)) { dungeon[j][i - 1] = 4; } } } } } void L2DoorFix() { int i, j; for (j = 1; j < DMAXY; j++) { for (i = 1; i < DMAXX; i++) { if (dungeon[i][j] == 4 && dungeon[i][j - 1] == 3) { dungeon[i][j] = 7; } if (dungeon[i][j] == 5 && dungeon[i - 1][j] == 3) { dungeon[i][j] = 9; } } } } static void DRLG_L2(int entry) { int i, j; BOOL doneflag; doneflag = FALSE; while (!doneflag) { nRoomCnt = 0; InitDungeon(); DRLG_InitTrans(); if (!CreateDungeon()) { continue; } L2TileFix(); if (setloadflag) { DRLG_L2SetRoom(nSx1, nSy1); } DRLG_L2FloodTVal(); DRLG_L2TransFix(); if (entry == ENTRY_MAIN) { doneflag = DRLG_L2PlaceMiniSet(USTAIRS, 1, 1, -1, -1, TRUE, 0); if (doneflag) { doneflag = DRLG_L2PlaceMiniSet(DSTAIRS, 1, 1, -1, -1, FALSE, 1); if (doneflag && currlevel == 5) { doneflag = DRLG_L2PlaceMiniSet(WARPSTAIRS, 1, 1, -1, -1, FALSE, 6); } } ViewY -= 2; } else if (entry == ENTRY_PREV) { doneflag = DRLG_L2PlaceMiniSet(USTAIRS, 1, 1, -1, -1, FALSE, 0); if (doneflag) { doneflag = DRLG_L2PlaceMiniSet(DSTAIRS, 1, 1, -1, -1, TRUE, 1); if (doneflag && currlevel == 5) { doneflag = DRLG_L2PlaceMiniSet(WARPSTAIRS, 1, 1, -1, -1, FALSE, 6); } } ViewX--; } else { doneflag = DRLG_L2PlaceMiniSet(USTAIRS, 1, 1, -1, -1, FALSE, 0); if (doneflag) { doneflag = DRLG_L2PlaceMiniSet(DSTAIRS, 1, 1, -1, -1, FALSE, 1); if (doneflag && currlevel == 5) { doneflag = DRLG_L2PlaceMiniSet(WARPSTAIRS, 1, 1, -1, -1, TRUE, 6); } } ViewY -= 2; } } 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(); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { pdungeon[i][j] = dungeon[i][j]; } } DRLG_Init_Globals(); DRLG_CheckQuests(nSx1, nSy1); } static void DRLG_InitL2Vals() { int i, j, pc; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 541) { pc = 5; } else if (dPiece[i][j] == 178) { pc = 5; } else if (dPiece[i][j] == 551) { pc = 5; } else if (dPiece[i][j] == 542) { pc = 6; } else if (dPiece[i][j] == 553) { pc = 6; } else if (dPiece[i][j] == 13) { pc = 5; } else if (dPiece[i][j] == 17) { pc = 6; } else { continue; } dSpecial[i][j] = pc; } } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 132) { dSpecial[i][j + 1] = 2; dSpecial[i][j + 2] = 1; } else if (dPiece[i][j] == 135 || dPiece[i][j] == 139) { dSpecial[i + 1][j] = 3; dSpecial[i + 2][j] = 4; } } } } void LoadL2Dungeon(const char *sFileName, int vx, int vy) { int i, j, rw, rh, pc; BYTE *pLevelMap, *lm; InitDungeon(); DRLG_InitTrans(); pLevelMap = LoadFileInMem(sFileName, NULL); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { dungeon[i][j] = 12; dflags[i][j] = 0; } } lm = pLevelMap; rw = *lm; lm += 2; rh = *lm; lm += 2; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm != 0) { dungeon[i][j] = *lm; dflags[i][j] |= DLRG_PROTECTED; } else { dungeon[i][j] = 3; } lm += 2; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 0) { dungeon[i][j] = 12; } } } DRLG_L2Pass3(); DRLG_Init_Globals(); for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { pc = 0; if (dPiece[i][j] == 541) { pc = 5; } if (dPiece[i][j] == 178) { pc = 5; } if (dPiece[i][j] == 551) { pc = 5; } if (dPiece[i][j] == 542) { pc = 6; } if (dPiece[i][j] == 553) { pc = 6; } if (dPiece[i][j] == 13) { pc = 5; } if (dPiece[i][j] == 17) { pc = 6; } dSpecial[i][j] = pc; } } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 132) { dSpecial[i][j + 1] = 2; dSpecial[i][j + 2] = 1; } else if (dPiece[i][j] == 135 || dPiece[i][j] == 139) { dSpecial[i + 1][j] = 3; dSpecial[i + 2][j] = 4; } } } ViewX = vx; ViewY = vy; SetMapMonsters(pLevelMap, 0, 0); SetMapObjects(pLevelMap, 0, 0); mem_free_dbg(pLevelMap); } void LoadPreL2Dungeon(const char *sFileName, int vx, int vy) { int i, j, rw, rh; BYTE *pLevelMap, *lm; InitDungeon(); DRLG_InitTrans(); pLevelMap = LoadFileInMem(sFileName, NULL); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { dungeon[i][j] = 12; dflags[i][j] = 0; } } lm = pLevelMap; rw = *lm; lm += 2; rh = *lm; lm += 2; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm != 0) { dungeon[i][j] = *lm; dflags[i][j] |= DLRG_PROTECTED; } else { dungeon[i][j] = 3; } lm += 2; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 0) { dungeon[i][j] = 12; } } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { pdungeon[i][j] = dungeon[i][j]; } } mem_free_dbg(pLevelMap); } void CreateL2Dungeon(DWORD rseed, int entry) { if (gbMaxPlayers == 1) { if (currlevel == 7 && quests[Q_BLIND]._qactive == QUEST_NOTAVAIL) { currlevel = 6; CreateL2Dungeon(glSeedTbl[6], 4); currlevel = 7; } if (currlevel == 8) { if (quests[Q_BLIND]._qactive == QUEST_NOTAVAIL) { currlevel = 6; CreateL2Dungeon(glSeedTbl[6], 4); currlevel = 8; } else { currlevel = 7; CreateL2Dungeon(glSeedTbl[7], 4); currlevel = 8; } } } SetRndSeed(rseed); dminx = 16; dminy = 16; dmaxx = 96; dmaxy = 96; DRLG_InitTrans(); DRLG_InitSetPC(); DRLG_LoadL2SP(); DRLG_L2(entry); DRLG_L2Pass3(); DRLG_FreeL2SP(); DRLG_InitL2Vals(); DRLG_SetPC(); } #endif ================================================ FILE: Source/drlg_l2.h ================================================ /** * @file drlg_l2.h * * Interface of the catacombs level generation algorithms. */ #ifndef __DRLG_L2_H__ #define __DRLG_L2_H__ void LoadL2Dungeon(const char *sFileName, int vx, int vy); void LoadPreL2Dungeon(const char *sFileName, int vx, int vy); void CreateL2Dungeon(DWORD rseed, int entry); #endif /* __DRLG_L2_H__ */ ================================================ FILE: Source/drlg_l3.cpp ================================================ /** * @file drlg_l3.cpp * * Implementation of the caves level generation algorithms. */ #ifndef SPAWN #include "all.h" /** This will be true if a lava pool has been generated for the level */ BOOLEAN lavapool; /** unused */ int abyssx; int lockoutcnt; BOOLEAN lockout[DMAXX][DMAXY]; /** * A lookup table for the 16 possible patterns of a 2x2 area, * where each cell either contains a SW wall or it doesn't. */ const BYTE L3ConvTbl[16] = { 8, 11, 3, 10, 1, 9, 12, 12, 6, 13, 4, 13, 2, 14, 5, 7 }; /** Miniset: Stairs up. */ const BYTE L3UP[] = { // clang-format off 3, 3, // width, height 8, 8, 0, // search 10, 10, 0, 7, 7, 0, 51, 50, 0, // replace 48, 49, 0, 0, 0, 0, // clang-format on }; #ifdef HELLFIRE const BYTE L6UP[] = { // clang-format off 3, 3, // width, height 8, 8, 0, // search 10, 10, 0, 7, 7, 0, 20, 19, 0, // replace 17, 18, 0, 0, 0, 0, // clang-format on }; #endif /** Miniset: Stairs down. */ const BYTE L3DOWN[] = { // clang-format off 3, 3, // width, height 8, 9, 7, // search 8, 9, 7, 0, 0, 0, 0, 47, 0, // replace 0, 46, 0, 0, 0, 0, // clang-format on }; #ifdef HELLFIRE const BYTE L6DOWN[] = { // clang-format off 3, 3, // width, height 8, 9, 7, // search 8, 9, 7, 0, 0, 0, 0, 16, 0, // replace 0, 15, 0, 0, 0, 0, // clang-format on }; #endif /** Miniset: Stairs up to town. */ const BYTE L3HOLDWARP[] = { // clang-format off 3, 3, // width, height 8, 8, 0, // search 10, 10, 0, 7, 7, 0, 125, 125, 0, // replace 125, 125, 0, 0, 0, 0, // clang-format on }; #ifdef HELLFIRE const BYTE L6HOLDWARP[] = { // clang-format off 3, 3, // width, height 8, 8, 0, // search 10, 10, 0, 7, 7, 0, 24, 23, 0, // replace 21, 22, 0, 0, 0, 0, // clang-format on }; #endif /** Miniset: Stalagmite white stalactite 1. */ const BYTE L3TITE1[] = { // clang-format off 4, 4, // width, height 7, 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, // replace 0, 57, 58, 0, 0, 56, 55, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stalagmite white stalactite 2. */ const BYTE L3TITE2[] = { // clang-format off 4, 4, // width, height 7, 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, // replace 0, 61, 62, 0, 0, 60, 59, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stalagmite white stalactite 3. */ const BYTE L3TITE3[] = { // clang-format off 4, 4, // width, height 7, 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, // replace 0, 65, 66, 0, 0, 64, 63, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stalagmite white stalactite horizontal. */ const BYTE L3TITE6[] = { // clang-format off 5, 4, // width, height 7, 7, 7, 7, 7, // search 7, 7, 7, 0, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // replace 0, 77, 78, 0, 0, 0, 76, 74, 75, 0, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stalagmite white stalactite vertical. */ const BYTE L3TITE7[] = { // clang-format off 4, 5, // width, height 7, 7, 7, 7, // search 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, // replace 0, 83, 0, 0, 0, 82, 80, 0, 0, 81, 79, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stalagmite 1. */ const BYTE L3TITE8[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 0, 0, 0, // replace 0, 52, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stalagmite 2. */ const BYTE L3TITE9[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 0, 0, 0, // replace 0, 53, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stalagmite 3. */ const BYTE L3TITE10[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 0, 0, 0, // replace 0, 54, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stalagmite 4. */ const BYTE L3TITE11[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 0, 0, 0, // replace 0, 67, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stalagmite on vertical wall. */ const BYTE L3TITE12[] = { // clang-format off 2, 1, // width, height 9, 7, // search 68, 0, // replace // clang-format on }; /** Miniset: Stalagmite on horizontal wall. */ const BYTE L3TITE13[] = { // clang-format off 1, 2, // width, height 10, // search 7, 69, // replace 0, // clang-format on }; /** Miniset: Cracked vertical wall 1. */ const BYTE L3CREV1[] = { // clang-format off 2, 1, // width, height 8, 7, // search 84, 85, // replace // clang-format on }; /** Miniset: Cracked vertical wall - north corner. */ const BYTE L3CREV2[] = { // clang-format off 2, 1, // width, height 8, 11, // search 86, 87, // replace // clang-format on }; /** Miniset: Cracked horizontal wall 1. */ const BYTE L3CREV3[] = { // clang-format off 1, 2, // width, height 8, // search 10, 89, // replace 88, // clang-format on }; /** Miniset: Cracked vertical wall 2. */ const BYTE L3CREV4[] = { // clang-format off 2, 1, // width, height 8, 7, // search 90, 91, // replace // clang-format on }; /** Miniset: Cracked horizontal wall - north corner. */ const BYTE L3CREV5[] = { // clang-format off 1, 2, // width, height 8, // search 11, 92, // replace 93, // clang-format on }; /** Miniset: Cracked horizontal wall 2. */ const BYTE L3CREV6[] = { // clang-format off 1, 2, // width, height 8, // search 10, 95, // replace 94, // clang-format on }; /** Miniset: Cracked vertical wall - west corner. */ const BYTE L3CREV7[] = { // clang-format off 2, 1, // width, height 8, 7, // search 96, 101, // replace // clang-format on }; /** Miniset: Cracked horizontal wall - north. */ const BYTE L3CREV8[] = { // clang-format off 1, 2, // width, height 2, // search 8, 102, // replace 97, // clang-format on }; /** Miniset: Cracked vertical wall - east corner. */ const BYTE L3CREV9[] = { // clang-format off 2, 1, // width, height 3, 8, // search 103, 98, // replace // clang-format on }; /** Miniset: Cracked vertical wall - west. */ const BYTE L3CREV10[] = { // clang-format off 2, 1, // width, height 4, 8, // search 104, 99, // replace // clang-format on }; /** Miniset: Cracked horizontal wall - south corner. */ const BYTE L3CREV11[] = { // clang-format off 1, 2, // width, height 6, // search 8, 105, // replace 100, // clang-format on }; /** Miniset: Replace broken wall with floor 1. */ const BYTE L3ISLE1[] = { // clang-format off 2, 3, // width, height 5, 14, // search 4, 9, 13, 12, 7, 7, // replace 7, 7, 7, 7, // clang-format on }; /** Miniset: Replace small wall with floor 2. */ const BYTE L3ISLE2[] = { // clang-format off 3, 2, // width, height 5, 2, 14, // search 13, 10, 12, 7, 7, 7, // replace 7, 7, 7, // clang-format on }; /** Miniset: Replace small wall with lava 1. */ const BYTE L3ISLE3[] = { // clang-format off 2, 3, // width, height 5, 14, // search 4, 9, 13, 12, 29, 30, // replace 25, 28, 31, 32, // clang-format on }; /** Miniset: Replace small wall with lava 2. */ const BYTE L3ISLE4[] = { // clang-format off 3, 2, // width, height 5, 2, 14, // search 13, 10, 12, 29, 26, 30, // replace 31, 27, 32, // clang-format on }; /** Miniset: Replace small wall with floor 3. */ const BYTE L3ISLE5[] = { // clang-format off 2, 2, // width, height 5, 14, // search 13, 12, 7, 7, // replace 7, 7, // clang-format on }; /** Miniset: Use random floor tile 1. */ const BYTE L3XTRA1[] = { // clang-format off 1, 1, // width, height 7, // search 106, // replace // clang-format on }; /** Miniset: Use random floor tile 2. */ const BYTE L3XTRA2[] = { // clang-format off 1, 1, // width, height 7, // search 107, // replace // clang-format on }; /** Miniset: Use random floor tile 3. */ const BYTE L3XTRA3[] = { // clang-format off 1, 1, // width, height 7, // search 108, // replace // clang-format on }; /** Miniset: Use random horizontal wall tile. */ const BYTE L3XTRA4[] = { // clang-format off 1, 1, // width, height 9, // search 109, // replace // clang-format on }; /** Miniset: Use random vertical wall tile. */ const BYTE L3XTRA5[] = { // clang-format off 1, 1, // width, height 10, // search 110, // replace // clang-format on }; /** Miniset: Anvil of Fury island. */ const BYTE L3ANVIL[] = { // clang-format off 11, 11, // width, height 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // search 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, // replace 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, // clang-format on }; #ifdef HELLFIRE const BYTE byte_48A76C[] = { 1, 1, 8, 25 }; const BYTE byte_48A770[] = { 1, 1, 8, 26 }; const BYTE byte_48A774[] = { 1, 1, 8, 27 }; const BYTE byte_48A778[] = { 1, 1, 8, 28 }; const BYTE byte_48A77C[] = { 1, 1, 7, 29 }; const BYTE byte_48A780[] = { 1, 1, 7, 30 }; const BYTE byte_48A784[] = { 1, 1, 7, 31 }; const BYTE byte_48A788[] = { 1, 1, 7, 32 }; const BYTE byte_48A790[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 0, 0, 0, // replace 0, 126, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A7A8[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 0, 0, 0, // replace 0, 124, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A7BC[] = { 1, 1, 9, 33 }; const BYTE byte_48A7C0[] = { 1, 1, 9, 34 }; const BYTE byte_48A7C4[] = { 1, 1, 9, 35 }; const BYTE byte_48A7C8[] = { 1, 1, 9, 36 }; const BYTE byte_48A7CC[] = { 1, 1, 9, 37 }; const BYTE byte_48A7D0[] = { 1, 1, 11, 38 }; const BYTE byte_48A7D4[] = { 1, 1, 10, 39 }; const BYTE byte_48A7D8[] = { 1, 1, 10, 40 }; const BYTE byte_48A7DC[] = { 1, 1, 10, 41 }; const BYTE byte_48A7E0[] = { 1, 1, 10, 42 }; const BYTE byte_48A7E4[] = { 1, 1, 10, 43 }; const BYTE byte_48A7E8[] = { 1, 1, 11, 44 }; const BYTE byte_48A7EC[] = { 1, 1, 9, 45 }; const BYTE byte_48A7F0[] = { 1, 1, 9, 46 }; const BYTE byte_48A7F4[] = { 1, 1, 10, 47 }; const BYTE byte_48A7F8[] = { 1, 1, 10, 48 }; const BYTE byte_48A7FC[] = { 1, 1, 11, 49 }; const BYTE byte_48A800[] = { 1, 1, 11, 50 }; const BYTE byte_48A808[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 67, 0, 0, // replace 66, 51, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A820[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 69, 0, 0, // replace 68, 52, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A838[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 70, 0, 0, // replace 71, 53, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A850[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 73, 0, 0, // replace 72, 54, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A868[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 75, 0, 0, // replace 74, 55, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A880[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 77, 0, 0, // replace 76, 56, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A898[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 79, 0, 0, // replace 78, 57, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A8B0[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 81, 0, 0, // replace 80, 58, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A8C8[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 83, 0, 0, // replace 82, 59, 0, 0, 0, 0, // clang-format on }; const BYTE byte_48A8E0[] = { // clang-format off 3, 3, // width, height 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 84, 0, 0, // replace 85, 60, 0, 0, 0, 0, // clang-format on }; const BYTE L6ISLE1[] = { // clang-format off 2, 3, // width, height 5, 14, // search 4, 9, 13, 12, 7, 7, // replace 7, 7, 7, 7, // clang-format on }; const BYTE L6ISLE2[] = { // clang-format off 3, 2, // width, height 5, 2, 14, // search 13, 10, 12, 7, 7, 7, // replace 7, 7, 7, // clang-format on }; const BYTE L6ISLE3[] = { // clang-format off 2, 3, // width, height 5, 14, // search 4, 9, 13, 12, 107, 115, // replace 119, 122, 131, 123, // clang-format on }; const BYTE L6ISLE4[] = { // clang-format off 3, 2, // width, height 5, 2, 14, // search 13, 10, 12, 107, 120, 115, // replace 131, 121, 123, // clang-format on }; const BYTE L6ISLE5[] = { // clang-format off 2, 2, // width, height 5, 14, // search 13, 12, 7, 7, // replace 7, 7, // clang-format on }; const BYTE byte_48A948[] = { // clang-format off 4, 4, // width, height 7, 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // replace 7, 107, 115, 7, 7, 131, 123, 7, 7, 7, 7, 7, // clang-format on }; const BYTE byte_48A970[] = { // clang-format off 4, 4, // width, height 7, 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // replace 7, 7, 108, 7, 7, 109, 112, 7, 7, 7, 7, 7, // clang-format on }; const BYTE byte_48A998[] = { // clang-format off 4, 5, // width, height 7, 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // replace 7, 107, 115, 7, 7, 119, 122, 7, 7, 131, 123, 7, 7, 7, 7, 7, // clang-format on }; const BYTE byte_48A9C8[] = { // clang-format off 4, 5, // width, height 7, 7, 7, 7, // search 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // replace 7, 126, 108, 7, 7, 7, 117, 7, 7, 109, 112, 7, 7, 7, 7, 7, // clang-format on }; #endif static void InitL3Dungeon() { int i, j; memset(dungeon, 0, sizeof(dungeon)); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { dungeon[i][j] = 0; dflags[i][j] = 0; } } } static BOOL DRLG_L3FillRoom(int x1, int y1, int x2, int y2) { int i, j, v; if (x1 <= 1 || x2 >= 34 || y1 <= 1 || y2 >= 38) { return FALSE; } v = 0; for (j = y1; j <= y2; j++) { for (i = x1; i <= x2; i++) { v += dungeon[i][j]; } } if (v != 0) { return FALSE; } for (j = y1 + 1; j < y2; j++) { for (i = x1 + 1; i < x2; i++) { dungeon[i][j] = 1; } } for (j = y1; j <= y2; j++) { if (random_(0, 2) != 0) { dungeon[x1][j] = 1; } if (random_(0, 2) != 0) { dungeon[x2][j] = 1; } } for (i = x1; i <= x2; i++) { if (random_(0, 2) != 0) { dungeon[i][y1] = 1; } if (random_(0, 2) != 0) { dungeon[i][y2] = 1; } } return TRUE; } static void DRLG_L3CreateBlock(int x, int y, int obs, int dir) { int blksizex, blksizey, x1, y1, x2, y2; int contflag; blksizex = random_(0, 2) + 3; blksizey = random_(0, 2) + 3; if (dir == 0) { y2 = y - 1; y1 = y2 - blksizey; if (blksizex < obs) { x1 = random_(0, blksizex) + x; } if (blksizex == obs) { x1 = x; } if (blksizex > obs) { x1 = x - random_(0, blksizex); } x2 = blksizex + x1; } if (dir == 3) { x2 = x - 1; x1 = x2 - blksizex; if (blksizey < obs) { y1 = random_(0, blksizey) + y; } if (blksizey == obs) { y1 = y; } if (blksizey > obs) { y1 = y - random_(0, blksizey); } y2 = y1 + blksizey; } if (dir == 2) { y1 = y + 1; y2 = y1 + blksizey; if (blksizex < obs) { x1 = random_(0, blksizex) + x; } if (blksizex == obs) { x1 = x; } if (blksizex > obs) { x1 = x - random_(0, blksizex); } x2 = blksizex + x1; } if (dir == 1) { x1 = x + 1; x2 = x1 + blksizex; if (blksizey < obs) { y1 = random_(0, blksizey) + y; } if (blksizey == obs) { y1 = y; } if (blksizey > obs) { y1 = y - random_(0, blksizey); } y2 = y1 + blksizey; } if (DRLG_L3FillRoom(x1, y1, x2, y2) == TRUE) { contflag = random_(0, 4); if (contflag != 0 && dir != 2) { DRLG_L3CreateBlock(x1, y1, blksizey, 0); } if (contflag != 0 && dir != 3) { DRLG_L3CreateBlock(x2, y1, blksizex, 1); } if (contflag != 0 && dir != 0) { DRLG_L3CreateBlock(x1, y2, blksizey, 2); } if (contflag != 0 && dir != 1) { DRLG_L3CreateBlock(x1, y1, blksizex, 3); } } } static void DRLG_L3FloorArea(int x1, int y1, int x2, int y2) { int i, j; for (j = y1; j <= y2; j++) { for (i = x1; i <= x2; i++) { dungeon[i][j] = 1; } } } static void DRLG_L3FillDiags() { int i, j, v; for (j = 0; j < DMAXY - 1; j++) { for (i = 0; i < DMAXX - 1; i++) { v = dungeon[i + 1][j + 1] + 2 * dungeon[i][j + 1] + 4 * dungeon[i + 1][j] + 8 * dungeon[i][j]; if (v == 6) { if (random_(0, 2) == 0) { dungeon[i][j] = 1; } else { dungeon[i + 1][j + 1] = 1; } } if (v == 9) { if (random_(0, 2) == 0) { dungeon[i + 1][j] = 1; } else { dungeon[i][j + 1] = 1; } } } } } static void DRLG_L3FillSingles() { int i, j; for (j = 1; j < DMAXY - 1; j++) { for (i = 1; i < DMAXX - 1; i++) { if (dungeon[i][j] == 0 && dungeon[i][j - 1] + dungeon[i - 1][j - 1] + dungeon[i + 1][j - 1] == 3 && dungeon[i + 1][j] + dungeon[i - 1][j] == 2 && dungeon[i][j + 1] + dungeon[i - 1][j + 1] + dungeon[i + 1][j + 1] == 3) { dungeon[i][j] = 1; } } } } static void DRLG_L3FillStraights() { int i, j, xc, xs, yc, ys, k, rv; for (j = 0; j < DMAXY - 1; j++) { xs = 0; for (i = 0; i < 37; i++) { if (dungeon[i][j] == 0 && dungeon[i][j + 1] == 1) { if (xs == 0) { xc = i; } xs++; } else { if (xs > 3 && random_(0, 2) != 0) { for (k = xc; k < i; k++) { rv = random_(0, 2); dungeon[k][j] = rv; } } xs = 0; } } } for (j = 0; j < DMAXY - 1; j++) { xs = 0; for (i = 0; i < 37; i++) { if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 0) { if (xs == 0) { xc = i; } xs++; } else { if (xs > 3 && random_(0, 2) != 0) { for (k = xc; k < i; k++) { rv = random_(0, 2); dungeon[k][j + 1] = rv; } } xs = 0; } } } for (i = 0; i < DMAXX - 1; i++) { ys = 0; for (j = 0; j < 37; j++) { if (dungeon[i][j] == 0 && dungeon[i + 1][j] == 1) { if (ys == 0) { yc = j; } ys++; } else { if (ys > 3 && random_(0, 2) != 0) { for (k = yc; k < j; k++) { rv = random_(0, 2); dungeon[i][k] = rv; } } ys = 0; } } } for (i = 0; i < DMAXX - 1; i++) { ys = 0; for (j = 0; j < 37; j++) { if (dungeon[i][j] == 1 && dungeon[i + 1][j] == 0) { if (ys == 0) { yc = j; } ys++; } else { if (ys > 3 && random_(0, 2) != 0) { for (k = yc; k < j; k++) { rv = random_(0, 2); dungeon[i + 1][k] = rv; } } ys = 0; } } } } static void DRLG_L3Edges() { int i, j; for (j = 0; j < DMAXY; j++) { dungeon[DMAXX - 1][j] = 0; } for (i = 0; i < DMAXX; i++) { dungeon[i][DMAXY - 1] = 0; } } static int DRLG_L3GetFloorArea() { int i, j, gfa; gfa = 0; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { gfa += dungeon[i][j]; } } return gfa; } static void DRLG_L3MakeMegas() { int i, j, v, rv; for (j = 0; j < DMAXY - 1; j++) { for (i = 0; i < DMAXX - 1; i++) { v = dungeon[i + 1][j + 1] + 2 * dungeon[i][j + 1] + 4 * dungeon[i + 1][j] + 8 * dungeon[i][j]; if (v == 6) { rv = random_(0, 2); if (rv == 0) { v = 12; } else { v = 5; } } if (v == 9) { rv = random_(0, 2); if (rv == 0) { v = 13; } else { v = 14; } } dungeon[i][j] = L3ConvTbl[v]; } dungeon[DMAXX - 1][j] = 8; } for (i = 0; i < DMAXX; i++) { dungeon[i][DMAXY - 1] = 8; } } static void DRLG_L3River() { int rx, ry, px, py, dir, pdir, nodir, nodir2, dircheck; int river[3][100]; int rivercnt, riveramt; int i, trys, found, bridge, lpcnt; BOOL bail; rivercnt = 0; bail = FALSE; trys = 0; /// BUGFIX: pdir is uninitialized, add code `pdir = -1;` while (trys < 200 && rivercnt < 4) { bail = FALSE; while (!bail && trys < 200) { trys++; rx = 0; ry = 0; i = 0; // BUGFIX: Replace with `(ry >= DMAXY || dungeon[rx][ry] < 25 || dungeon[rx][ry] > 28) && i < 100` while ((dungeon[rx][ry] < 25 || dungeon[rx][ry] > 28) && i < 100) { rx = random_(0, DMAXX); ry = random_(0, DMAXY); i++; // BUGFIX: Move `ry < DMAXY` check before dungeon checks while ((dungeon[rx][ry] < 25 || dungeon[rx][ry] > 28) && ry < DMAXY) { rx++; if (rx >= DMAXX) { rx = 0; ry++; } } } // BUGFIX: Continue if `ry >= DMAXY` if (i >= 100) { return; } switch (dungeon[rx][ry]) { case 25: dir = 3; nodir = 2; river[2][0] = 40; break; case 26: dir = 0; nodir = 1; river[2][0] = 38; break; case 27: dir = 1; nodir = 0; river[2][0] = 41; break; case 28: dir = 2; nodir = 3; river[2][0] = 39; break; } river[0][0] = rx; river[1][0] = ry; riveramt = 1; nodir2 = 4; dircheck = 0; while (dircheck < 4 && riveramt < 100) { px = rx; py = ry; if (dircheck == 0) { dir = random_(0, 4); } else { dir = (dir + 1) & 3; } dircheck++; while (dir == nodir || dir == nodir2) { dir = (dir + 1) & 3; dircheck++; } if (dir == 0 && ry > 0) { ry--; } if (dir == 1 && ry < DMAXY) { ry++; } if (dir == 2 && rx < DMAXX) { rx++; } if (dir == 3 && rx > 0) { rx--; } if (dungeon[rx][ry] == 7) { dircheck = 0; if (dir < 2) { river[2][riveramt] = (BYTE)random_(0, 2) + 17; } if (dir > 1) { river[2][riveramt] = (BYTE)random_(0, 2) + 15; } river[0][riveramt] = rx; river[1][riveramt] = ry; riveramt++; if (dir == 0 && pdir == 2 || dir == 3 && pdir == 1) { if (riveramt > 2) { river[2][riveramt - 2] = 22; } if (dir == 0) { nodir2 = 1; } else { nodir2 = 2; } } if (dir == 0 && pdir == 3 || dir == 2 && pdir == 1) { if (riveramt > 2) { river[2][riveramt - 2] = 21; } if (dir == 0) { nodir2 = 1; } else { nodir2 = 3; } } if (dir == 1 && pdir == 2 || dir == 3 && pdir == 0) { if (riveramt > 2) { river[2][riveramt - 2] = 20; } if (dir == 1) { nodir2 = 0; } else { nodir2 = 2; } } if (dir == 1 && pdir == 3 || dir == 2 && pdir == 0) { if (riveramt > 2) { river[2][riveramt - 2] = 19; } if (dir == 1) { nodir2 = 0; } else { nodir2 = 3; } } pdir = dir; } else { rx = px; ry = py; } } // BUGFIX: Check `ry >= 2` if (dir == 0 && dungeon[rx][ry - 1] == 10 && dungeon[rx][ry - 2] == 8) { river[0][riveramt] = rx; river[1][riveramt] = ry - 1; river[2][riveramt] = 24; if (pdir == 2) { river[2][riveramt - 1] = 22; } if (pdir == 3) { river[2][riveramt - 1] = 21; } bail = TRUE; } // BUGFIX: Check `ry + 2 < DMAXY` if (dir == 1 && dungeon[rx][ry + 1] == 2 && dungeon[rx][ry + 2] == 8) { river[0][riveramt] = rx; river[1][riveramt] = ry + 1; river[2][riveramt] = 42; if (pdir == 2) { river[2][riveramt - 1] = 20; } if (pdir == 3) { river[2][riveramt - 1] = 19; } bail = TRUE; } // BUGFIX: Check `rx + 2 < DMAXX` if (dir == 2 && dungeon[rx + 1][ry] == 4 && dungeon[rx + 2][ry] == 8) { river[0][riveramt] = rx + 1; river[1][riveramt] = ry; river[2][riveramt] = 43; if (pdir == 0) { river[2][riveramt - 1] = 19; } if (pdir == 1) { river[2][riveramt - 1] = 21; } bail = TRUE; } // BUGFIX: Check `rx >= 2` if (dir == 3 && dungeon[rx - 1][ry] == 9 && dungeon[rx - 2][ry] == 8) { river[0][riveramt] = rx - 1; river[1][riveramt] = ry; river[2][riveramt] = 23; if (pdir == 0) { river[2][riveramt - 1] = 20; } if (pdir == 1) { river[2][riveramt - 1] = 22; } bail = TRUE; } } if (bail == TRUE && riveramt < 7) { bail = FALSE; } if (bail == TRUE) { found = 0; lpcnt = 0; while (found == 0 && lpcnt < 30) { lpcnt++; bridge = random_(0, riveramt); if ((river[2][bridge] == 15 || river[2][bridge] == 16) && dungeon[river[0][bridge]][river[1][bridge] - 1] == 7 && dungeon[river[0][bridge]][river[1][bridge] + 1] == 7) { found = 1; } if ((river[2][bridge] == 17 || river[2][bridge] == 18) && dungeon[river[0][bridge] - 1][river[1][bridge]] == 7 && dungeon[river[0][bridge] + 1][river[1][bridge]] == 7) { found = 2; } for (i = 0; i < riveramt && found != 0; i++) { if (found == 1 && (river[1][bridge] - 1 == river[1][i] || river[1][bridge] + 1 == river[1][i]) && river[0][bridge] == river[0][i]) { found = 0; } if (found == 2 && (river[0][bridge] - 1 == river[0][i] || river[0][bridge] + 1 == river[0][i]) && river[1][bridge] == river[1][i]) { found = 0; } } } if (found != 0) { if (found == 1) { river[2][bridge] = 44; } else { river[2][bridge] = 45; } rivercnt++; for (bridge = 0; bridge <= riveramt; bridge++) { dungeon[river[0][bridge]][river[1][bridge]] = river[2][bridge]; } } else { bail = FALSE; } } } } static BOOL DRLG_L3Spawn(int x, int y, int *totarea); static BOOL DRLG_L3SpawnEdge(int x, int y, int *totarea) { BYTE i; static BYTE spawntable[15] = { 0x00, 0x0A, 0x43, 0x05, 0x2c, 0x06, 0x09, 0x00, 0x00, 0x1c, 0x83, 0x06, 0x09, 0x0A, 0x05 }; if (*totarea > 40) { return TRUE; } if (x < 0 || y < 0 || x >= DMAXX || y >= DMAXY) { return TRUE; } if (dungeon[x][y] & 0x80) { return FALSE; } if (dungeon[x][y] > 15) { return TRUE; } i = dungeon[x][y]; dungeon[x][y] |= 0x80; *totarea += 1; if (spawntable[i] & 8 && DRLG_L3SpawnEdge(x, y - 1, totarea) == TRUE) { return TRUE; } if (spawntable[i] & 4 && DRLG_L3SpawnEdge(x, y + 1, totarea) == TRUE) { return TRUE; } if (spawntable[i] & 2 && DRLG_L3SpawnEdge(x + 1, y, totarea) == TRUE) { return TRUE; } if (spawntable[i] & 1 && DRLG_L3SpawnEdge(x - 1, y, totarea) == TRUE) { return TRUE; } if (spawntable[i] & 0x80 && DRLG_L3Spawn(x, y - 1, totarea) == TRUE) { return TRUE; } if (spawntable[i] & 0x40 && DRLG_L3Spawn(x, y + 1, totarea) == TRUE) { return TRUE; } if (spawntable[i] & 0x20 && DRLG_L3Spawn(x + 1, y, totarea) == TRUE) { return TRUE; } if (spawntable[i] & 0x10 && DRLG_L3Spawn(x - 1, y, totarea) == TRUE) { return TRUE; } return FALSE; } static BOOL DRLG_L3Spawn(int x, int y, int *totarea) { BYTE i; static BYTE spawntable[15] = { 0x00, 0x0A, 0x03, 0x05, 0x0C, 0x06, 0x09, 0x00, 0x00, 0x0C, 0x03, 0x06, 0x09, 0x0A, 0x05 }; if (*totarea > 40) { return TRUE; } if (x < 0 || y < 0 || x >= DMAXX || y >= DMAXY) { return TRUE; } if (dungeon[x][y] & 0x80) { return FALSE; } if (dungeon[x][y] > 15) { return TRUE; } i = dungeon[x][y]; dungeon[x][y] |= 0x80; *totarea += 1; if (i != 8) { if (spawntable[i] & 8 && DRLG_L3SpawnEdge(x, y - 1, totarea) == TRUE) { return TRUE; } if (spawntable[i] & 4 && DRLG_L3SpawnEdge(x, y + 1, totarea) == TRUE) { return TRUE; } if (spawntable[i] & 2 && DRLG_L3SpawnEdge(x + 1, y, totarea) == TRUE) { return TRUE; } if (spawntable[i] & 1 && DRLG_L3SpawnEdge(x - 1, y, totarea) == TRUE) { return TRUE; } } else { if (DRLG_L3Spawn(x + 1, y, totarea) == TRUE) { return TRUE; } if (DRLG_L3Spawn(x - 1, y, totarea) == TRUE) { return TRUE; } if (DRLG_L3Spawn(x, y + 1, totarea) == TRUE) { return TRUE; } if (DRLG_L3Spawn(x, y - 1, totarea) == TRUE) { return TRUE; } } return FALSE; } /** * Flood fills dirt and wall tiles looking for * an area of at most 40 tiles and disconnected from the map edge. * If it finds one, converts it to lava tiles and sets lavapool to TRUE. */ static void DRLG_L3Pool() { int i, j, dunx, duny, totarea, poolchance; BOOL found; BYTE k; static BYTE poolsub[15] = { 0, 35, 26, 36, 25, 29, 34, 7, 33, 28, 27, 37, 32, 31, 30 }; for (duny = 0; duny < DMAXY; duny++) { for (dunx = 0; dunx < DMAXY; dunx++) { if (dungeon[dunx][duny] != 8) { continue; } dungeon[dunx][duny] |= 0x80; totarea = 1; if (dunx + 1 < DMAXX) { found = DRLG_L3Spawn(dunx + 1, duny, &totarea); } else { found = TRUE; } if (dunx - 1 > 0 && !found) { found = DRLG_L3Spawn(dunx - 1, duny, &totarea); } else { found = TRUE; } if (duny + 1 < DMAXY && !found) { found = DRLG_L3Spawn(dunx, duny + 1, &totarea); } else { found = TRUE; } if (duny - 1 > 0 && !found) { found = DRLG_L3Spawn(dunx, duny - 1, &totarea); } else { found = TRUE; } poolchance = random_(0, 100); for (j = duny - totarea; j < duny + totarea; j++) { for (i = dunx - totarea; i < dunx + totarea; i++) { // BUGFIX: In the following swap the order to first do the // index checks and only then access dungeon[i][j] if (dungeon[i][j] & 0x80 && j >= 0 && j < DMAXY && i >= 0 && i < DMAXX) { dungeon[i][j] &= ~0x80; if (totarea > 4 && poolchance < 25 && !found) { k = poolsub[dungeon[i][j]]; if (k != 0 && k <= 37) { dungeon[i][j] = k; } lavapool = TRUE; } } } } } } } static void DRLG_L3PoolFix() { int dunx, duny; for (duny = 0; duny < DMAXY; duny++) { // BUGFIX: Change '0' to '1' and 'DMAXY' to 'DMAXY - 1' for (dunx = 0; dunx < DMAXX; dunx++) { // BUGFIX: Change '0' to '1' and 'DMAXX' to 'DMAXX - 1' if (dungeon[dunx][duny] == 8) { if (dungeon[dunx - 1][duny - 1] >= 25 && dungeon[dunx - 1][duny - 1] <= 41 && dungeon[dunx - 1][duny] >= 25 && dungeon[dunx - 1][duny] <= 41 && dungeon[dunx - 1][duny + 1] >= 25 && dungeon[dunx - 1][duny + 1] <= 41 && dungeon[dunx][duny - 1] >= 25 && dungeon[dunx][duny - 1] <= 41 && dungeon[dunx][duny + 1] >= 25 && dungeon[dunx][duny + 1] <= 41 && dungeon[dunx + 1][duny - 1] >= 25 && dungeon[dunx + 1][duny - 1] <= 41 && dungeon[dunx + 1][duny] >= 25 && dungeon[dunx + 1][duny] <= 41 && dungeon[dunx + 1][duny + 1] >= 25 && dungeon[dunx + 1][duny + 1] <= 41) { dungeon[dunx][duny] = 33; } } } } } static BOOL DRLG_L3PlaceMiniSet(const BYTE *miniset, int tmin, int tmax, int cx, int cy, BOOL setview, int ldir) { int sx, sy, sw, sh, xx, yy, i, ii, numt, trys; BOOL found; sw = miniset[0]; sh = miniset[1]; if (tmax - tmin == 0) { numt = 1; } else { numt = random_(0, tmax - tmin) + tmin; } for (i = 0; i < numt; i++) { sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); found = FALSE; trys = 0; while (!found && trys < 200) { trys++; found = TRUE; if (cx != -1 && sx >= cx - sw && sx <= cx + 12) { sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); found = FALSE; } if (cy != -1 && sy >= cy - sh && sy <= cy + 12) { sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); found = FALSE; } ii = 2; for (yy = 0; yy < sh && found == TRUE; yy++) { for (xx = 0; xx < sw && found == TRUE; xx++) { if (miniset[ii] != 0 && dungeon[xx + sx][yy + sy] != miniset[ii]) { found = FALSE; } if (dflags[xx + sx][yy + sy] != 0) { found = FALSE; } ii++; } } if (!found) { sx++; if (sx == DMAXX - sw) { sx = 0; sy++; if (sy == DMAXY - sh) { sy = 0; } } } } if (trys >= 200) { return TRUE; } ii = sw * sh + 2; for (yy = 0; yy < sh; yy++) { for (xx = 0; xx < sw; xx++) { if (miniset[ii] != 0) { dungeon[xx + sx][yy + sy] = miniset[ii]; } ii++; } } } if (setview == TRUE) { ViewX = 2 * sx + 17; ViewY = 2 * sy + 19; } if (ldir == 0) { LvlViewX = 2 * sx + 17; LvlViewY = 2 * sy + 19; } return FALSE; } static void DRLG_L3PlaceRndSet(const BYTE *miniset, int rndper) { int sx, sy, sw, sh, xx, yy, ii, kk; BOOL found; sw = miniset[0]; sh = miniset[1]; for (sy = 0; sy < DMAXX - sh; sy++) { for (sx = 0; sx < DMAXY - sw; sx++) { found = TRUE; ii = 2; for (yy = 0; yy < sh && found == TRUE; yy++) { for (xx = 0; xx < sw && found == TRUE; xx++) { if (miniset[ii] != 0 && dungeon[xx + sx][yy + sy] != miniset[ii]) { found = FALSE; } if (dflags[xx + sx][yy + sy] != 0) { found = FALSE; } ii++; } } kk = sw * sh + 2; // BUGFIX: This should not be applied to Nest levels if (miniset[kk] >= 84 && miniset[kk] <= 100 && found == TRUE) { // BUGFIX: accesses to dungeon can go out of bounds // BUGFIX: Comparisons vs 100 should use same tile as comparisons vs 84. if (dungeon[sx - 1][sy] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } if (dungeon[sx + 1][sy] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } if (dungeon[sx][sy + 1] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } if (dungeon[sx][sy - 1] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } } if (found == TRUE && random_(0, 100) < rndper) { for (yy = 0; yy < sh; yy++) { for (xx = 0; xx < sw; xx++) { if (miniset[kk] != 0) { dungeon[xx + sx][yy + sy] = miniset[kk]; } kk++; } } } } } } #ifdef HELLFIRE BOOLEAN drlg_l3_hive_rnd_piece(const BYTE *miniset, int rndper) { int sx, sy, sw, sh, xx, yy, ii, kk; BOOL found; BOOLEAN placed; placed = FALSE; sw = miniset[0]; sh = miniset[1]; for (sy = 0; sy < DMAXX - sh; sy++) { for (sx = 0; sx < DMAXY - sw; sx++) { found = TRUE; ii = 2; for (yy = 0; yy < sh && found == TRUE; yy++) { for (xx = 0; xx < sw && found == TRUE; xx++) { if (miniset[ii] != 0 && dungeon[xx + sx][yy + sy] != miniset[ii]) { found = FALSE; } if (dflags[xx + sx][yy + sy] != 0) { found = FALSE; } ii++; } } kk = sw * sh + 2; if (miniset[kk] >= 84 && miniset[kk] <= 100 && found == TRUE) { // BUGFIX: accesses to dungeon can go out of bounds // BUGFIX: Comparisons vs 100 should use same tile as comparisons vs 84. if (dungeon[sx - 1][sy] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } if (dungeon[sx + 1][sy] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } if (dungeon[sx][sy + 1] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } if (dungeon[sx][sy - 1] >= 84 && dungeon[sx - 1][sy] <= 100) { found = FALSE; } } if (found == TRUE && random_(0, 100) < rndper) { placed = TRUE; for (yy = 0; yy < sh; yy++) { for (xx = 0; xx < sw; xx++) { if (miniset[kk] != 0) { dungeon[xx + sx][yy + sy] = miniset[kk]; } kk++; } } } } } return placed; } #endif static BOOL WoodVertU(int i, int y) { if ((dungeon[i + 1][y] > 152 || dungeon[i + 1][y] < 130) && (dungeon[i - 1][y] > 152 || dungeon[i - 1][y] < 130)) { if (dungeon[i][y] == 7) { return TRUE; } if (dungeon[i][y] == 10) { return TRUE; } if (dungeon[i][y] == 126) { return TRUE; } if (dungeon[i][y] == 129) { return TRUE; } if (dungeon[i][y] == 134) { return TRUE; } if (dungeon[i][y] == 136) { return TRUE; } } return FALSE; } static BOOL WoodVertD(int i, int y) { if ((dungeon[i + 1][y] > 152 || dungeon[i + 1][y] < 130) && (dungeon[i - 1][y] > 152 || dungeon[i - 1][y] < 130)) { if (dungeon[i][y] == 7) { return TRUE; } if (dungeon[i][y] == 2) { return TRUE; } if (dungeon[i][y] == 134) { return TRUE; } if (dungeon[i][y] == 136) { return TRUE; } } return FALSE; } static BOOL WoodHorizL(int x, int j) { if ((dungeon[x][j + 1] > 152 || dungeon[x][j + 1] < 130) && (dungeon[x][j - 1] > 152 || dungeon[x][j - 1] < 130)) { if (dungeon[x][j] == 7) { return TRUE; } if (dungeon[x][j] == 9) { return TRUE; } if (dungeon[x][j] == 121) { return TRUE; } if (dungeon[x][j] == 124) { return TRUE; } if (dungeon[x][j] == 135) { return TRUE; } if (dungeon[x][j] == 137) { return TRUE; } } return FALSE; } static BOOL WoodHorizR(int x, int j) { if ((dungeon[x][j + 1] > 152 || dungeon[x][j + 1] < 130) && (dungeon[x][j - 1] > 152 || dungeon[x][j - 1] < 130)) { if (dungeon[x][j] == 7) { return TRUE; } if (dungeon[x][j] == 4) { return TRUE; } if (dungeon[x][j] == 135) { return TRUE; } if (dungeon[x][j] == 137) { return TRUE; } } return FALSE; } void AddFenceDoors() { int i, j; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 7) { if (dungeon[i - 1][j] <= 152 && dungeon[i - 1][j] >= 130 && dungeon[i + 1][j] <= 152 && dungeon[i + 1][j] >= 130) { dungeon[i][j] = 146; continue; } } if (dungeon[i][j] == 7) { if (dungeon[i][j - 1] <= 152 && dungeon[i][j - 1] >= 130 && dungeon[i][j + 1] <= 152 && dungeon[i][j + 1] >= 130) { dungeon[i][j] = 147; continue; } } } } } void FenceDoorFix() { int i, j; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 146) { if (dungeon[i + 1][j] > 152 || dungeon[i + 1][j] < 130 || dungeon[i - 1][j] > 152 || dungeon[i - 1][j] < 130) { dungeon[i][j] = 7; continue; } } if (dungeon[i][j] == 146) { if (dungeon[i + 1][j] != 130 && dungeon[i - 1][j] != 130 && dungeon[i + 1][j] != 132 && dungeon[i - 1][j] != 132 && dungeon[i + 1][j] != 133 && dungeon[i - 1][j] != 133 && dungeon[i + 1][j] != 134 && dungeon[i - 1][j] != 134 && dungeon[i + 1][j] != 136 && dungeon[i - 1][j] != 136 && dungeon[i + 1][j] != 138 && dungeon[i - 1][j] != 138 && dungeon[i + 1][j] != 140 && dungeon[i - 1][j] != 140) { dungeon[i][j] = 7; continue; } } if (dungeon[i][j] == 147) { if (dungeon[i][j + 1] > 152 || dungeon[i][j + 1] < 130 || dungeon[i][j - 1] > 152 || dungeon[i][j - 1] < 130) { dungeon[i][j] = 7; continue; } } if (dungeon[i][j] == 147) { if (dungeon[i][j + 1] != 131 && dungeon[i][j - 1] != 131 && dungeon[i][j + 1] != 132 && dungeon[i][j - 1] != 132 && dungeon[i][j + 1] != 133 && dungeon[i][j - 1] != 133 && dungeon[i][j + 1] != 135 && dungeon[i][j - 1] != 135 && dungeon[i][j + 1] != 137 && dungeon[i][j - 1] != 137 && dungeon[i][j + 1] != 138 && dungeon[i][j - 1] != 138 && dungeon[i][j + 1] != 139 && dungeon[i][j - 1] != 139) { dungeon[i][j] = 7; continue; } } } } } static void DRLG_L3Wood() { int i, j, x, y, xx, yy, rt, rp, x1, y1, x2, y2; BOOL skip; for (j = 0; j < DMAXY - 1; j++) { // BUGFIX: Change '0' to '1' for (i = 0; i < DMAXX - 1; i++) { // BUGFIX: Change '0' to '1' if (dungeon[i][j] == 10 && random_(0, 2) != 0) { x = i; while (dungeon[x][j] == 10) { x++; } x--; if (x - i > 0) { dungeon[i][j] = 127; for (xx = i + 1; xx < x; xx++) { if (random_(0, 2) != 0) { dungeon[xx][j] = 126; } else { dungeon[xx][j] = 129; } } dungeon[x][j] = 128; } } if (dungeon[i][j] == 9 && random_(0, 2) != 0) { y = j; while (dungeon[i][y] == 9) { y++; } y--; if (y - j > 0) { dungeon[i][j] = 123; for (yy = j + 1; yy < y; yy++) { if (random_(0, 2) != 0) { dungeon[i][yy] = 121; } else { dungeon[i][yy] = 124; } } dungeon[i][y] = 122; } } if (dungeon[i][j] == 11 && dungeon[i + 1][j] == 10 && dungeon[i][j + 1] == 9 && random_(0, 2) != 0) { dungeon[i][j] = 125; x = i + 1; while (dungeon[x][j] == 10) { x++; } x--; for (xx = i + 1; xx < x; xx++) { if (random_(0, 2) != 0) { dungeon[xx][j] = 126; } else { dungeon[xx][j] = 129; } } dungeon[x][j] = 128; y = j + 1; while (dungeon[i][y] == 9) { y++; } y--; for (yy = j + 1; yy < y; yy++) { if (random_(0, 2) != 0) { dungeon[i][yy] = 121; } else { dungeon[i][yy] = 124; } } dungeon[i][y] = 122; } } } for (j = 0; j < DMAXY; j++) { // BUGFIX: Change '0' to '1' for (i = 0; i < DMAXX; i++) { // BUGFIX: Change '0' to '1' if (dungeon[i][j] == 7 && random_(0, 1) == 0 && SkipThemeRoom(i, j)) { rt = random_(0, 2); if (rt == 0) { y1 = j; // BUGFIX: Check `y1 >= 0` first while (WoodVertU(i, y1)) { y1--; } y1++; y2 = j; // BUGFIX: Check `y2 < DMAXY` first while (WoodVertD(i, y2)) { y2++; } y2--; skip = TRUE; if (dungeon[i][y1] == 7) { skip = FALSE; } if (dungeon[i][y2] == 7) { skip = FALSE; } if (y2 - y1 > 1 && skip) { rp = random_(0, y2 - y1 - 1) + y1 + 1; for (y = y1; y <= y2; y++) { if (y == rp) { continue; } if (dungeon[i][y] == 7) { if (random_(0, 2) != 0) { dungeon[i][y] = 135; } else { dungeon[i][y] = 137; } } if (dungeon[i][y] == 10) { dungeon[i][y] = 131; } if (dungeon[i][y] == 126) { dungeon[i][y] = 133; } if (dungeon[i][y] == 129) { dungeon[i][y] = 133; } if (dungeon[i][y] == 2) { dungeon[i][y] = 139; } if (dungeon[i][y] == 134) { dungeon[i][y] = 138; } if (dungeon[i][y] == 136) { dungeon[i][y] = 138; } } } } if (rt == 1) { x1 = i; // BUGFIX: Check `x1 >= 0` first (fixed) while (WoodHorizL(x1, j)) { x1--; } x1++; x2 = i; // BUGFIX: Check `x2 < DMAXX` first (fixed) while (WoodHorizR(x2, j)) { x2++; } x2--; skip = TRUE; if (dungeon[x1][j] == 7) { skip = FALSE; } if (dungeon[x2][j] == 7) { skip = FALSE; } if (x2 - x1 > 1 && skip) { rp = random_(0, x2 - x1 - 1) + x1 + 1; for (x = x1; x <= x2; x++) { if (x == rp) { continue; } if (dungeon[x][j] == 7) { if (random_(0, 2) != 0) { dungeon[x][j] = 134; } else { dungeon[x][j] = 136; } } if (dungeon[x][j] == 9) { dungeon[x][j] = 130; } if (dungeon[x][j] == 121) { dungeon[x][j] = 132; } if (dungeon[x][j] == 124) { dungeon[x][j] = 132; } if (dungeon[x][j] == 4) { dungeon[x][j] = 140; } if (dungeon[x][j] == 135) { dungeon[x][j] = 138; } if (dungeon[x][j] == 137) { dungeon[x][j] = 138; } } } } } } } AddFenceDoors(); FenceDoorFix(); } BOOL DRLG_L3Anvil() { int sx, sy, sw, sh, xx, yy, ii, trys; BOOL found; sw = L3ANVIL[0]; sh = L3ANVIL[1]; sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); found = FALSE; trys = 0; while (!found && trys < 200) { trys++; found = TRUE; ii = 2; for (yy = 0; yy < sh && found == TRUE; yy++) { for (xx = 0; xx < sw && found == TRUE; xx++) { if (L3ANVIL[ii] != 0 && dungeon[xx + sx][yy + sy] != L3ANVIL[ii]) { found = FALSE; } if (dflags[xx + sx][yy + sy] != 0) { found = FALSE; } ii++; } } if (!found) { sx++; if (sx == DMAXX - sw) { sx = 0; sy++; if (sy == DMAXY - sh) { sy = 0; } } } } if (trys >= 200) { return TRUE; } ii = sw * sh + 2; for (yy = 0; yy < sh; yy++) { for (xx = 0; xx < sw; xx++) { if (L3ANVIL[ii] != 0) { dungeon[xx + sx][yy + sy] = L3ANVIL[ii]; } dflags[xx + sx][yy + sy] |= DLRG_PROTECTED; ii++; } } setpc_x = sx; setpc_y = sy; setpc_w = sw; setpc_h = sh; return FALSE; } void FixL3Warp() { int i, j; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 125 && dungeon[i + 1][j] == 125 && dungeon[i][j + 1] == 125 && dungeon[i + 1][j + 1] == 125) { dungeon[i][j] = 156; dungeon[i + 1][j] = 155; dungeon[i][j + 1] = 153; dungeon[i + 1][j + 1] = 154; return; } if (dungeon[i][j] == 5 && dungeon[i + 1][j + 1] == 7) { dungeon[i][j] = 7; } } } } void FixL3HallofHeroes() { int i, j; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 5 && dungeon[i + 1][j + 1] == 7) { dungeon[i][j] = 7; } } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 5 && dungeon[i + 1][j + 1] == 12 && dungeon[i + 1][j] == 7) { dungeon[i][j] = 7; dungeon[i][j + 1] = 7; dungeon[i + 1][j + 1] = 7; } if (dungeon[i][j] == 5 && dungeon[i + 1][j + 1] == 12 && dungeon[i][j + 1] == 7) { dungeon[i][j] = 7; dungeon[i + 1][j] = 7; dungeon[i + 1][j + 1] = 7; } } } } void DRLG_L3LockRec(int x, int y) { if (!lockout[x][y]) { return; } lockout[x][y] = FALSE; lockoutcnt++; DRLG_L3LockRec(x, y - 1); DRLG_L3LockRec(x, y + 1); DRLG_L3LockRec(x - 1, y); DRLG_L3LockRec(x + 1, y); } BOOL DRLG_L3Lockout() { int i, j, t, fx, fy; t = 0; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] != 0) { lockout[i][j] = TRUE; fx = i; fy = j; t++; } else { lockout[i][j] = FALSE; } } } lockoutcnt = 0; DRLG_L3LockRec(fx, fy); return t == lockoutcnt; } static void DRLG_L3(int entry) { int x1, y1, x2, y2, i, j; BOOL found, genok; lavapool = FALSE; do { do { do { InitL3Dungeon(); x1 = random_(0, 20) + 10; y1 = random_(0, 20) + 10; x2 = x1 + 2; y2 = y1 + 2; DRLG_L3FillRoom(x1, y1, x2, y2); DRLG_L3CreateBlock(x1, y1, 2, 0); DRLG_L3CreateBlock(x2, y1, 2, 1); DRLG_L3CreateBlock(x1, y2, 2, 2); DRLG_L3CreateBlock(x1, y1, 2, 3); if (QuestStatus(Q_ANVIL)) { x1 = random_(0, 10) + 10; y1 = random_(0, 10) + 10; x2 = x1 + 12; y2 = y1 + 12; DRLG_L3FloorArea(x1, y1, x2, y2); } DRLG_L3FillDiags(); DRLG_L3FillSingles(); DRLG_L3FillStraights(); DRLG_L3FillDiags(); DRLG_L3Edges(); if (DRLG_L3GetFloorArea() >= 600) { found = DRLG_L3Lockout(); } else { found = FALSE; } } while (!found); DRLG_L3MakeMegas(); if (entry == ENTRY_MAIN) { #ifdef HELLFIRE if (currlevel < 17) { #endif genok = DRLG_L3PlaceMiniSet(L3UP, 1, 1, -1, -1, TRUE, 0); #ifdef HELLFIRE } else { if (currlevel != 17) genok = DRLG_L3PlaceMiniSet(L6UP, 1, 1, -1, -1, TRUE, 0); else genok = DRLG_L3PlaceMiniSet(L6HOLDWARP, 1, 1, -1, -1, TRUE, 6); } #endif if (!genok) { #ifdef HELLFIRE if (currlevel < 17) { #endif genok = DRLG_L3PlaceMiniSet(L3DOWN, 1, 1, -1, -1, FALSE, 1); #ifdef HELLFIRE } else { if (currlevel != 20) genok = DRLG_L3PlaceMiniSet(L6DOWN, 1, 1, -1, -1, FALSE, 1); } #endif if (!genok && currlevel == 9) { genok = DRLG_L3PlaceMiniSet(L3HOLDWARP, 1, 1, -1, -1, FALSE, 6); } } } else if (entry == ENTRY_PREV) { #ifdef HELLFIRE if (currlevel < 17) { #endif genok = DRLG_L3PlaceMiniSet(L3UP, 1, 1, -1, -1, FALSE, 0); #ifdef HELLFIRE } else { if (currlevel != 17) genok = DRLG_L3PlaceMiniSet(L6UP, 1, 1, -1, -1, FALSE, 0); else genok = DRLG_L3PlaceMiniSet(L6HOLDWARP, 1, 1, -1, -1, FALSE, 6); } #endif if (!genok) { #ifdef HELLFIRE if (currlevel < 17) { #endif genok = DRLG_L3PlaceMiniSet(L3DOWN, 1, 1, -1, -1, TRUE, 1); ViewX += 2; ViewY -= 2; #ifdef HELLFIRE } else { if (currlevel != 20) { genok = DRLG_L3PlaceMiniSet(L6DOWN, 1, 1, -1, -1, TRUE, 1); ViewX += 2; ViewY -= 2; } } #endif if (!genok && currlevel == 9) { genok = DRLG_L3PlaceMiniSet(L3HOLDWARP, 1, 1, -1, -1, FALSE, 6); } } } else { #ifdef HELLFIRE if (currlevel < 17) { #endif genok = DRLG_L3PlaceMiniSet(L3UP, 1, 1, -1, -1, FALSE, 0); #ifdef HELLFIRE } else { if (currlevel != 17) genok = DRLG_L3PlaceMiniSet(L6UP, 1, 1, -1, -1, FALSE, 0); else genok = DRLG_L3PlaceMiniSet(L6HOLDWARP, 1, 1, -1, -1, TRUE, 6); } #endif if (!genok) { #ifdef HELLFIRE if (currlevel < 17) { #endif genok = DRLG_L3PlaceMiniSet(L3DOWN, 1, 1, -1, -1, FALSE, 1); #ifdef HELLFIRE } else { if (currlevel != 20) genok = DRLG_L3PlaceMiniSet(L6DOWN, 1, 1, -1, -1, FALSE, 1); } #endif if (!genok && currlevel == 9) { genok = DRLG_L3PlaceMiniSet(L3HOLDWARP, 1, 1, -1, -1, TRUE, 6); } } } if (!genok && QuestStatus(Q_ANVIL)) { genok = DRLG_L3Anvil(); } } while (genok == TRUE); #ifdef HELLFIRE if (currlevel < 17) { #endif DRLG_L3Pool(); #ifdef HELLFIRE } else { lavapool += drlg_l3_hive_rnd_piece(byte_48A998, 30); lavapool += drlg_l3_hive_rnd_piece(byte_48A9C8, 40); lavapool += drlg_l3_hive_rnd_piece(byte_48A948, 50); lavapool += drlg_l3_hive_rnd_piece(byte_48A970, 60); if (lavapool < 3) lavapool = FALSE; } #endif } while (!lavapool); #ifdef HELLFIRE if (currlevel < 17) #endif DRLG_L3PoolFix(); #ifdef HELLFIRE if (currlevel < 17) #endif FixL3Warp(); #ifdef HELLFIRE if (currlevel < 17) { #endif 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); #ifdef HELLFIRE } else { DRLG_L3PlaceRndSet(L6ISLE1, 70); DRLG_L3PlaceRndSet(L6ISLE2, 70); DRLG_L3PlaceRndSet(L6ISLE3, 30); DRLG_L3PlaceRndSet(L6ISLE4, 30); DRLG_L3PlaceRndSet(L6ISLE1, 100); DRLG_L3PlaceRndSet(L6ISLE2, 100); DRLG_L3PlaceRndSet(L6ISLE5, 90); } #endif #ifdef HELLFIRE if (currlevel < 17) #endif FixL3HallofHeroes(); #ifdef HELLFIRE if (currlevel < 17) #endif DRLG_L3River(); if (QuestStatus(Q_ANVIL)) { 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; } } #ifdef HELLFIRE if (currlevel < 17) #endif DRLG_PlaceThemeRooms(5, 10, 7, 0, 0); #ifdef HELLFIRE if (currlevel < 17) { #endif 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); #ifdef HELLFIRE } else { DRLG_L3PlaceRndSet(byte_48A76C, 20); DRLG_L3PlaceRndSet(byte_48A770, 20); DRLG_L3PlaceRndSet(byte_48A774, 20); DRLG_L3PlaceRndSet(byte_48A778, 20); DRLG_L3PlaceRndSet(byte_48A808, 10); DRLG_L3PlaceRndSet(byte_48A820, 15); DRLG_L3PlaceRndSet(byte_48A838, 20); DRLG_L3PlaceRndSet(byte_48A850, 25); DRLG_L3PlaceRndSet(byte_48A868, 30); DRLG_L3PlaceRndSet(byte_48A880, 35); DRLG_L3PlaceRndSet(byte_48A898, 40); DRLG_L3PlaceRndSet(byte_48A8B0, 45); DRLG_L3PlaceRndSet(byte_48A8C8, 50); DRLG_L3PlaceRndSet(byte_48A8E0, 55); DRLG_L3PlaceRndSet(byte_48A8E0, 10); DRLG_L3PlaceRndSet(byte_48A8C8, 15); DRLG_L3PlaceRndSet(byte_48A8B0, 20); DRLG_L3PlaceRndSet(byte_48A898, 25); DRLG_L3PlaceRndSet(byte_48A880, 30); DRLG_L3PlaceRndSet(byte_48A868, 35); DRLG_L3PlaceRndSet(byte_48A850, 40); DRLG_L3PlaceRndSet(byte_48A838, 45); DRLG_L3PlaceRndSet(byte_48A820, 50); DRLG_L3PlaceRndSet(byte_48A808, 55); DRLG_L3PlaceRndSet(byte_48A790, 40); DRLG_L3PlaceRndSet(byte_48A7A8, 45); DRLG_L3PlaceRndSet(byte_48A77C, 25); DRLG_L3PlaceRndSet(byte_48A780, 25); DRLG_L3PlaceRndSet(byte_48A784, 25); DRLG_L3PlaceRndSet(byte_48A788, 25); DRLG_L3PlaceRndSet(byte_48A7BC, 25); DRLG_L3PlaceRndSet(byte_48A7C0, 25); DRLG_L3PlaceRndSet(byte_48A7C4, 25); DRLG_L3PlaceRndSet(byte_48A7C8, 25); DRLG_L3PlaceRndSet(byte_48A7CC, 25); DRLG_L3PlaceRndSet(byte_48A7D4, 25); DRLG_L3PlaceRndSet(byte_48A7D8, 25); DRLG_L3PlaceRndSet(byte_48A7DC, 25); DRLG_L3PlaceRndSet(byte_48A7E0, 25); DRLG_L3PlaceRndSet(byte_48A7E4, 25); DRLG_L3PlaceRndSet(byte_48A7EC, 25); DRLG_L3PlaceRndSet(byte_48A7F0, 25); DRLG_L3PlaceRndSet(byte_48A7F4, 25); DRLG_L3PlaceRndSet(byte_48A7F8, 25); DRLG_L3PlaceRndSet(byte_48A7D0, 25); DRLG_L3PlaceRndSet(byte_48A7E8, 25); DRLG_L3PlaceRndSet(byte_48A7FC, 25); DRLG_L3PlaceRndSet(byte_48A800, 25); } #endif for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { pdungeon[i][j] = dungeon[i][j]; } } DRLG_Init_Globals(); } static void DRLG_L3Pass3() { int i, j, xx, yy; long v1, v2, v3, v4, lv; lv = 8 - 1; #ifdef USE_ASM __asm { mov esi, pMegaTiles mov eax, lv shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax } #else v1 = *((WORD *)&pMegaTiles[lv * 8] + 0) + 1; v2 = *((WORD *)&pMegaTiles[lv * 8] + 1) + 1; v3 = *((WORD *)&pMegaTiles[lv * 8] + 2) + 1; v4 = *((WORD *)&pMegaTiles[lv * 8] + 3) + 1; #endif for (j = 0; j < MAXDUNY; j += 2) { for (i = 0; i < MAXDUNX; i += 2) { dPiece[i][j] = v1; dPiece[i + 1][j] = v2; dPiece[i][j + 1] = v3; dPiece[i + 1][j + 1] = v4; } } yy = 16; for (j = 0; j < DMAXY; j++) { xx = 16; for (i = 0; i < DMAXX; i++) { lv = dungeon[i][j] - 1; #ifdef USE_ASM if (lv >= 0) { __asm { mov esi, pMegaTiles mov eax, lv shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax } } else { v1 = 0; v2 = 0; v3 = 0; v4 = 0; } #else if (lv >= 0) { v1 = *((WORD *)&pMegaTiles[lv * 8] + 0) + 1; v2 = *((WORD *)&pMegaTiles[lv * 8] + 1) + 1; v3 = *((WORD *)&pMegaTiles[lv * 8] + 2) + 1; v4 = *((WORD *)&pMegaTiles[lv * 8] + 3) + 1; } else { v1 = 0; v2 = 0; v3 = 0; v4 = 0; } #endif dPiece[xx][yy] = v1; dPiece[xx + 1][yy] = v2; dPiece[xx][yy + 1] = v3; dPiece[xx + 1][yy + 1] = v4; xx += 2; } yy += 2; } } void CreateL3Dungeon(DWORD rseed, int entry) { int i, j; SetRndSeed(rseed); dminx = 16; dminy = 16; dmaxx = 96; dmaxy = 96; DRLG_InitTrans(); DRLG_InitSetPC(); DRLG_L3(entry); DRLG_L3Pass3(); #ifdef HELLFIRE if (currlevel < 17) { #endif for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] >= 56 && dPiece[i][j] <= 147) { DoLighting(i, j, 7, -1); } else if (dPiece[i][j] >= 154 && dPiece[i][j] <= 161) { DoLighting(i, j, 7, -1); } else if (dPiece[i][j] == 150) { DoLighting(i, j, 7, -1); } else if (dPiece[i][j] == 152) { DoLighting(i, j, 7, -1); } } } #ifdef HELLFIRE } else { for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] >= 382 && dPiece[i][j] <= 457) { DoLighting(i, j, 9, -1); } } } } #endif DRLG_SetPC(); } void LoadL3Dungeon(const char *sFileName, int vx, int vy) { int i, j, rw, rh; BYTE *pLevelMap, *lm; InitL3Dungeon(); dminx = 16; dminy = 16; dmaxx = 96; dmaxy = 96; DRLG_InitTrans(); pLevelMap = LoadFileInMem(sFileName, NULL); lm = pLevelMap; rw = *lm; lm += 2; rh = *lm; lm += 2; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm != 0) { dungeon[i][j] = *lm; } else { dungeon[i][j] = 7; } lm += 2; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 0) { dungeon[i][j] = 8; } } } abyssx = MAXDUNX; // Unused DRLG_L3Pass3(); DRLG_Init_Globals(); ViewX = 31; ViewY = 83; SetMapMonsters(pLevelMap, 0, 0); SetMapObjects(pLevelMap, 0, 0); for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] >= 56 && dPiece[i][j] <= 147) { DoLighting(i, j, 7, -1); } else if (dPiece[i][j] >= 154 && dPiece[i][j] <= 161) { DoLighting(i, j, 7, -1); } else if (dPiece[i][j] == 150) { DoLighting(i, j, 7, -1); } else if (dPiece[i][j] == 152) { DoLighting(i, j, 7, -1); } } } mem_free_dbg(pLevelMap); } void LoadPreL3Dungeon(const char *sFileName, int vx, int vy) { int i, j, rw, rh; BYTE *pLevelMap, *lm; InitL3Dungeon(); DRLG_InitTrans(); pLevelMap = LoadFileInMem(sFileName, NULL); lm = pLevelMap; rw = *lm; lm += 2; rh = *lm; lm += 2; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm != 0) { dungeon[i][j] = *lm; } else { dungeon[i][j] = 7; } lm += 2; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 0) { dungeon[i][j] = 8; } } } memcpy(pdungeon, dungeon, sizeof(pdungeon)); mem_free_dbg(pLevelMap); } #endif ================================================ FILE: Source/drlg_l3.h ================================================ /** * @file drlg_l3.h * * Interface of the caves level generation algorithms. */ #ifndef __DRLG_L3_H__ #define __DRLG_L3_H__ void CreateL3Dungeon(DWORD rseed, int entry); void LoadL3Dungeon(const char *sFileName, int vx, int vy); void LoadPreL3Dungeon(const char *sFileName, int vx, int vy); #endif /* __DRLG_L3_H__ */ ================================================ FILE: Source/drlg_l4.cpp ================================================ /** * @file drlg_l4.cpp * * Implementation of the hell level generation algorithms. */ #include "all.h" int diabquad1x; int diabquad1y; int diabquad2x; int diabquad2y; int diabquad3x; int diabquad3y; int diabquad4x; int diabquad4y; #ifndef SPAWN BOOL hallok[20]; int l4holdx; int l4holdy; int SP4x1; int SP4y1; int SP4x2; int SP4y2; BYTE L4dungeon[80][80]; BYTE dung[20][20]; //int dword_52A4DC; /** * A lookup table for the 16 possible patterns of a 2x2 area, * where each cell either contains a SW wall or it doesn't. */ const BYTE L4ConvTbl[16] = { 30, 6, 1, 6, 2, 6, 6, 6, 9, 6, 1, 6, 2, 6, 3, 6 }; /** Miniset: Stairs up. */ const BYTE L4USTAIRS[] = { // clang-format off 4, 5, // width, height 6, 6, 6, 6, // search 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, // replace 36, 38, 35, 0, 37, 34, 33, 32, 0, 0, 31, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stairs up to town. */ const BYTE L4TWARP[] = { // clang-format off 4, 5, // width, height 6, 6, 6, 6, // search 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, // replace 134, 136, 133, 0, 135, 132, 131, 130, 0, 0, 129, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Stairs down. */ const BYTE L4DSTAIRS[] = { // clang-format off 5, 5, // width, height 6, 6, 6, 6, 6, // search 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, // replace 0, 0, 45, 41, 0, 0, 44, 43, 40, 0, 0, 46, 42, 39, 0, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Pentagram. */ const BYTE L4PENTA[] = { // clang-format off 5, 5, // width, height 6, 6, 6, 6, 6, // search 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, // replace 0, 98, 100, 103, 0, 0, 99, 102, 105, 0, 0, 101, 104, 106, 0, 0, 0, 0, 0, 0, // clang-format on }; /** Miniset: Pentagram portal. */ const BYTE L4PENTA2[] = { // clang-format off 5, 5, // width, height 6, 6, 6, 6, 6, // search 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, // replace 0, 107, 109, 112, 0, 0, 108, 111, 114, 0, 0, 110, 113, 115, 0, 0, 0, 0, 0, 0, // clang-format on }; /** Maps tile IDs to their corresponding undecorated tile ID. */ const BYTE 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 }; static void DRLG_L4Shadows() { int x, y; BOOL okflag; for (y = 1; y < DMAXY; y++) { for (x = 1; x < DMAXY; x++) { okflag = FALSE; if (dungeon[x][y] == 3) { okflag = TRUE; } if (dungeon[x][y] == 4) { okflag = TRUE; } if (dungeon[x][y] == 8) { okflag = TRUE; } if (dungeon[x][y] == 15) { okflag = TRUE; } if (!okflag) { continue; } if (dungeon[x - 1][y] == 6) { dungeon[x - 1][y] = 47; } if (dungeon[x - 1][y - 1] == 6) { dungeon[x - 1][y - 1] = 48; } } } } static void InitL4Dungeon() { int i, j; memset(dung, 0, sizeof(dung)); memset(L4dungeon, 0, sizeof(L4dungeon)); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { dungeon[i][j] = 30; dflags[i][j] = 0; } } } void DRLG_LoadL4SP() { setloadflag = FALSE; if (QuestStatus(Q_WARLORD)) { pSetPiece = LoadFileInMem("Levels\\L4Data\\Warlord.DUN", NULL); setloadflag = TRUE; } if (currlevel == 15 && gbMaxPlayers != 1) { pSetPiece = LoadFileInMem("Levels\\L4Data\\Vile1.DUN", NULL); setloadflag = TRUE; } } void DRLG_FreeL4SP() { MemFreeDbg(pSetPiece); } void DRLG_L4SetSPRoom(int rx1, int ry1) { int rw, rh, i, j; BYTE *sp; rw = pSetPiece[0]; rh = pSetPiece[2]; setpc_x = rx1; setpc_y = ry1; setpc_w = rw; setpc_h = rh; sp = &pSetPiece[4]; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*sp != 0) { dungeon[i + rx1][j + ry1] = *sp; dflags[i + rx1][j + ry1] |= DLRG_PROTECTED; } else { dungeon[i + rx1][j + ry1] = 6; } sp += 2; } } } static void L4makeDmt() { int i, j, idx, val, dmtx, dmty; for (j = 0, dmty = 1; dmty <= 77; j++, dmty += 2) { for (i = 0, dmtx = 1; dmtx <= 77; i++, dmtx += 2) { val = 8 * L4dungeon[dmtx + 1][dmty + 1] + 4 * L4dungeon[dmtx][dmty + 1] + 2 * L4dungeon[dmtx + 1][dmty] + L4dungeon[dmtx][dmty]; idx = L4ConvTbl[val]; dungeon[i][j] = idx; } } } static int L4HWallOk(int i, int j) { int x; BOOL wallok; for (x = 1; dungeon[i + x][j] == 6; x++) { if (dflags[i + x][j] != 0) { break; } if (dungeon[i + x][j - 1] != 6) { break; } if (dungeon[i + x][j + 1] != 6) { break; } } wallok = FALSE; if (dungeon[i + x][j] == 10) { wallok = TRUE; } if (dungeon[i + x][j] == 12) { wallok = TRUE; } if (dungeon[i + x][j] == 13) { wallok = TRUE; } if (dungeon[i + x][j] == 15) { wallok = TRUE; } if (dungeon[i + x][j] == 16) { wallok = TRUE; } if (dungeon[i + x][j] == 21) { wallok = TRUE; } if (dungeon[i + x][j] == 22) { wallok = TRUE; } if (x <= 3) { wallok = FALSE; } if (wallok) { return x; } else { return -1; } } static int L4VWallOk(int i, int j) { int y; BOOL wallok; for (y = 1; dungeon[i][j + y] == 6; y++) { if (dflags[i][j + y] != 0) { break; } if (dungeon[i - 1][j + y] != 6) { break; } if (dungeon[i + 1][j + y] != 6) { break; } } wallok = FALSE; if (dungeon[i][j + y] == 8) { wallok = TRUE; } if (dungeon[i][j + y] == 9) { wallok = TRUE; } if (dungeon[i][j + y] == 11) { wallok = TRUE; } if (dungeon[i][j + y] == 14) { wallok = TRUE; } if (dungeon[i][j + y] == 15) { wallok = TRUE; } if (dungeon[i][j + y] == 16) { wallok = TRUE; } if (dungeon[i][j + y] == 21) { wallok = TRUE; } if (dungeon[i][j + y] == 23) { wallok = TRUE; } if (y <= 3) { wallok = FALSE; } if (wallok) { return y; } else { return -1; } } static void L4HorizWall(int i, int j, int dx) { int xx; if (dungeon[i][j] == 13) { dungeon[i][j] = 17; } if (dungeon[i][j] == 16) { dungeon[i][j] = 11; } if (dungeon[i][j] == 12) { dungeon[i][j] = 14; } for (xx = 1; xx < dx; xx++) { dungeon[i + xx][j] = 2; } if (dungeon[i + dx][j] == 15) { dungeon[i + dx][j] = 14; } if (dungeon[i + dx][j] == 10) { dungeon[i + dx][j] = 17; } if (dungeon[i + dx][j] == 21) { dungeon[i + dx][j] = 23; } if (dungeon[i + dx][j] == 22) { dungeon[i + dx][j] = 29; } xx = random_(0, dx - 3) + 1; dungeon[i + xx][j] = 57; dungeon[i + xx + 2][j] = 56; dungeon[i + xx + 1][j] = 60; if (dungeon[i + xx][j - 1] == 6) { dungeon[i + xx][j - 1] = 58; } if (dungeon[i + xx + 1][j - 1] == 6) { dungeon[i + xx + 1][j - 1] = 59; } } static void L4VertWall(int i, int j, int dy) { int yy; if (dungeon[i][j] == 14) { dungeon[i][j] = 17; } if (dungeon[i][j] == 8) { dungeon[i][j] = 9; } if (dungeon[i][j] == 15) { dungeon[i][j] = 10; } for (yy = 1; yy < dy; yy++) { dungeon[i][j + yy] = 1; } if (dungeon[i][j + dy] == 11) { dungeon[i][j + dy] = 17; } if (dungeon[i][j + dy] == 9) { dungeon[i][j + dy] = 10; } if (dungeon[i][j + dy] == 16) { dungeon[i][j + dy] = 13; } if (dungeon[i][j + dy] == 21) { dungeon[i][j + dy] = 22; } if (dungeon[i][j + dy] == 23) { dungeon[i][j + dy] = 29; } yy = random_(0, dy - 3) + 1; dungeon[i][j + yy] = 53; dungeon[i][j + yy + 2] = 52; dungeon[i][j + yy + 1] = 6; if (dungeon[i - 1][j + yy] == 6) { dungeon[i - 1][j + yy] = 54; } if (dungeon[i - 1][j + yy - 1] == 6) { dungeon[i - 1][j + yy - 1] = 55; } } static void L4AddWall() { int i, j, x, y; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dflags[i][j] != 0) { continue; } if (dungeon[i][j] == 10 && random_(0, 100) < 100) { x = L4HWallOk(i, j); if (x != -1) { L4HorizWall(i, j, x); } } if (dungeon[i][j] == 12 && random_(0, 100) < 100) { x = L4HWallOk(i, j); if (x != -1) { L4HorizWall(i, j, x); } } if (dungeon[i][j] == 13 && random_(0, 100) < 100) { x = L4HWallOk(i, j); if (x != -1) { L4HorizWall(i, j, x); } } if (dungeon[i][j] == 15 && random_(0, 100) < 100) { x = L4HWallOk(i, j); if (x != -1) { L4HorizWall(i, j, x); } } if (dungeon[i][j] == 16 && random_(0, 100) < 100) { x = L4HWallOk(i, j); if (x != -1) { L4HorizWall(i, j, x); } } if (dungeon[i][j] == 21 && random_(0, 100) < 100) { x = L4HWallOk(i, j); if (x != -1) { L4HorizWall(i, j, x); } } if (dungeon[i][j] == 22 && random_(0, 100) < 100) { x = L4HWallOk(i, j); if (x != -1) { L4HorizWall(i, j, x); } } if (dungeon[i][j] == 8 && random_(0, 100) < 100) { y = L4VWallOk(i, j); if (y != -1) { L4VertWall(i, j, y); } } if (dungeon[i][j] == 9 && random_(0, 100) < 100) { y = L4VWallOk(i, j); if (y != -1) { L4VertWall(i, j, y); } } if (dungeon[i][j] == 11 && random_(0, 100) < 100) { y = L4VWallOk(i, j); if (y != -1) { L4VertWall(i, j, y); } } if (dungeon[i][j] == 14 && random_(0, 100) < 100) { y = L4VWallOk(i, j); if (y != -1) { L4VertWall(i, j, y); } } if (dungeon[i][j] == 15 && random_(0, 100) < 100) { y = L4VWallOk(i, j); if (y != -1) { L4VertWall(i, j, y); } } if (dungeon[i][j] == 16 && random_(0, 100) < 100) { y = L4VWallOk(i, j); if (y != -1) { L4VertWall(i, j, y); } } if (dungeon[i][j] == 21 && random_(0, 100) < 100) { y = L4VWallOk(i, j); if (y != -1) { L4VertWall(i, j, y); } } if (dungeon[i][j] == 23 && random_(0, 100) < 100) { y = L4VWallOk(i, j); if (y != -1) { L4VertWall(i, j, y); } } } } } static void L4tileFix() { int i, j; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 6) dungeon[i + 1][j] = 5; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 13; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 14; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 6) dungeon[i + 1][j] = 2; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 9) dungeon[i + 1][j] = 11; if (dungeon[i][j] == 9 && dungeon[i + 1][j] == 6) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 14 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 13; if (dungeon[i][j] == 6 && dungeon[i + 1][j] == 14) dungeon[i + 1][j] = 15; if (dungeon[i][j] == 6 && dungeon[i][j + 1] == 13) dungeon[i][j + 1] = 16; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 9) dungeon[i][j + 1] = 10; if (dungeon[i][j] == 6 && dungeon[i][j - 1] == 1) dungeon[i][j - 1] = 1; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 13 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 27; if (dungeon[i][j] == 27 && dungeon[i + 1][j] == 30) dungeon[i + 1][j] = 19; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 27; if (dungeon[i][j] == 27 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 16; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 27) dungeon[i + 1][j] = 26; if (dungeon[i][j] == 27 && dungeon[i + 1][j] == 30) dungeon[i + 1][j] = 19; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 15) dungeon[i + 1][j] = 14; if (dungeon[i][j] == 14 && dungeon[i + 1][j] == 15) dungeon[i + 1][j] = 14; if (dungeon[i][j] == 22 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 16; if (dungeon[i][j] == 27 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 16; if (dungeon[i][j] == 6 && dungeon[i + 1][j] == 27 && dungeon[i + 1][j + 1] != 0) /* check */ dungeon[i + 1][j] = 22; if (dungeon[i][j] == 22 && dungeon[i + 1][j] == 30) dungeon[i + 1][j] = 19; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 1 && dungeon[i + 1][j - 1] == 1) dungeon[i + 1][j] = 13; if (dungeon[i][j] == 14 && dungeon[i + 1][j] == 30 && dungeon[i][j + 1] == 6) dungeon[i + 1][j] = 28; if (dungeon[i][j] == 16 && dungeon[i + 1][j] == 6 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 27; if (dungeon[i][j] == 16 && dungeon[i][j + 1] == 30 && dungeon[i + 1][j + 1] == 30) dungeon[i][j + 1] = 27; if (dungeon[i][j] == 6 && dungeon[i + 1][j] == 30 && dungeon[i + 1][j - 1] == 6) dungeon[i + 1][j] = 21; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 27 && dungeon[i + 1][j + 1] == 9) dungeon[i + 1][j] = 29; if (dungeon[i][j] == 9 && dungeon[i + 1][j] == 15) dungeon[i + 1][j] = 14; if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 27 && dungeon[i + 1][j + 1] == 2) dungeon[i + 1][j] = 29; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 18) dungeon[i + 1][j] = 24; if (dungeon[i][j] == 9 && dungeon[i + 1][j] == 15) dungeon[i + 1][j] = 14; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 19 && dungeon[i + 1][j - 1] == 30) dungeon[i + 1][j] = 24; if (dungeon[i][j] == 24 && dungeon[i][j - 1] == 30 && dungeon[i][j - 2] == 6) dungeon[i][j - 1] = 21; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 30) dungeon[i + 1][j] = 28; if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 30) dungeon[i + 1][j] = 28; if (dungeon[i][j] == 28 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 18; if (dungeon[i][j] == 28 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 19 && dungeon[i + 2][j] == 2 && dungeon[i + 1][j - 1] == 18 && dungeon[i + 1][j + 1] == 1) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 19 && dungeon[i + 2][j] == 2 && dungeon[i + 1][j - 1] == 22 && dungeon[i + 1][j + 1] == 1) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 19 && dungeon[i + 2][j] == 2 && dungeon[i + 1][j - 1] == 18 && dungeon[i + 1][j + 1] == 13) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 21 && dungeon[i + 2][j] == 2 && dungeon[i + 1][j - 1] == 18 && dungeon[i + 1][j + 1] == 1) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 21 && dungeon[i + 1][j + 1] == 1 && dungeon[i + 1][j - 1] == 22 && dungeon[i + 2][j] == 3) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 28 && dungeon[i + 2][j] == 30 && dungeon[i + 1][j - 1] == 6) dungeon[i + 1][j] = 23; if (dungeon[i][j] == 14 && dungeon[i + 1][j] == 28 && dungeon[i + 2][j] == 1) dungeon[i + 1][j] = 23; if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 27 && dungeon[i + 1][j + 1] == 30) dungeon[i + 1][j] = 29; if (dungeon[i][j] == 28 && dungeon[i][j + 1] == 9) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 21 && dungeon[i + 1][j - 1] == 21) dungeon[i + 1][j] = 24; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 27 && dungeon[i + 1][j + 1] == 30) dungeon[i + 1][j] = 29; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 18) dungeon[i + 1][j] = 25; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 9 && dungeon[i + 2][j] == 2) dungeon[i + 1][j] = 11; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 10) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 15 && dungeon[i][j + 1] == 3) dungeon[i][j + 1] = 4; if (dungeon[i][j] == 22 && dungeon[i][j + 1] == 9) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 18 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 18; if (dungeon[i][j] == 24 && dungeon[i - 1][j] == 30) dungeon[i - 1][j] = 19; if (dungeon[i][j] == 21 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 21 && dungeon[i][j + 1] == 9) dungeon[i][j + 1] = 10; if (dungeon[i][j] == 22 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 18; if (dungeon[i][j] == 21 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 18; if (dungeon[i][j] == 16 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 13 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 22 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 18 && dungeon[i + 2][j] == 30) dungeon[i + 1][j] = 24; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 9 && dungeon[i + 1][j + 1] == 1) dungeon[i + 1][j] = 16; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 27 && dungeon[i + 1][j + 1] == 2) dungeon[i + 1][j] = 29; if (dungeon[i][j] == 23 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 23 && dungeon[i][j + 1] == 9) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 25 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 22 && dungeon[i + 1][j] == 9) dungeon[i + 1][j] = 11; if (dungeon[i][j] == 23 && dungeon[i + 1][j] == 9) dungeon[i + 1][j] = 11; if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 16; if (dungeon[i][j] == 11 && dungeon[i + 1][j] == 15) dungeon[i + 1][j] = 14; if (dungeon[i][j] == 23 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 16; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 27) dungeon[i + 1][j] = 26; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 18) dungeon[i + 1][j] = 24; if (dungeon[i][j] == 26 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 16; if (dungeon[i][j] == 29 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 16; if (dungeon[i][j] == 29 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 1 && dungeon[i][j - 1] == 15) dungeon[i][j - 1] = 10; if (dungeon[i][j] == 18 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 23 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 18; if (dungeon[i][j] == 18 && dungeon[i][j + 1] == 9) dungeon[i][j + 1] = 10; if (dungeon[i][j] == 14 && dungeon[i + 1][j] == 30 && dungeon[i + 1][j + 1] == 30) dungeon[i + 1][j] = 23; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 28 && dungeon[i + 1][j - 1] == 6) dungeon[i + 1][j] = 23; if (dungeon[i][j] == 23 && dungeon[i + 1][j] == 18 && dungeon[i][j - 1] == 6) dungeon[i + 1][j] = 24; if (dungeon[i][j] == 14 && dungeon[i + 1][j] == 23 && dungeon[i + 2][j] == 30) dungeon[i + 1][j] = 28; if (dungeon[i][j] == 14 && dungeon[i + 1][j] == 28 && dungeon[i + 2][j] == 30 && dungeon[i + 1][j - 1] == 6) dungeon[i + 1][j] = 23; if (dungeon[i][j] == 23 && dungeon[i + 1][j] == 30) dungeon[i + 1][j] = 19; if (dungeon[i][j] == 29 && dungeon[i + 1][j] == 30) dungeon[i + 1][j] = 19; if (dungeon[i][j] == 29 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 18; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 30) dungeon[i + 1][j] = 19; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 30) dungeon[i + 1][j] = 19; if (dungeon[i][j] == 26 && dungeon[i + 1][j] == 30) dungeon[i + 1][j] = 19; if (dungeon[i][j] == 16 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 18; if (dungeon[i][j] == 13 && dungeon[i][j + 1] == 9) dungeon[i][j + 1] = 10; if (dungeon[i][j] == 25 && dungeon[i][j + 1] == 30) dungeon[i][j + 1] = 18; if (dungeon[i][j] == 18 && dungeon[i][j + 1] == 2) dungeon[i][j + 1] = 15; if (dungeon[i][j] == 11 && dungeon[i + 1][j] == 3) dungeon[i + 1][j] = 5; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 9) dungeon[i + 1][j] = 11; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 13; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 13 && dungeon[i + 1][j - 1] == 6) dungeon[i + 1][j] = 16; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 21 && dungeon[i][j + 1] == 24 && dungeon[i][j + 2] == 1) dungeon[i][j + 1] = 17; if (dungeon[i][j] == 15 && dungeon[i + 1][j + 1] == 9 && dungeon[i + 1][j - 1] == 1 && dungeon[i + 2][j] == 16) dungeon[i + 1][j] = 29; if (dungeon[i][j] == 2 && dungeon[i - 1][j] == 6) dungeon[i - 1][j] = 8; if (dungeon[i][j] == 1 && dungeon[i][j - 1] == 6) dungeon[i][j - 1] = 7; if (dungeon[i][j] == 6 && dungeon[i + 1][j] == 15 && dungeon[i + 1][j + 1] == 4) dungeon[i + 1][j] = 10; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 3) dungeon[i][j + 1] = 4; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 6) dungeon[i][j + 1] = 4; if (dungeon[i][j] == 9 && dungeon[i][j + 1] == 3) dungeon[i][j + 1] = 4; if (dungeon[i][j] == 10 && dungeon[i][j + 1] == 3) dungeon[i][j + 1] = 4; if (dungeon[i][j] == 13 && dungeon[i][j + 1] == 3) dungeon[i][j + 1] = 4; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 5) dungeon[i][j + 1] = 12; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 16) dungeon[i][j + 1] = 13; if (dungeon[i][j] == 6 && dungeon[i][j + 1] == 13) dungeon[i][j + 1] = 16; if (dungeon[i][j] == 25 && dungeon[i][j + 1] == 9) dungeon[i][j + 1] = 10; if (dungeon[i][j] == 13 && dungeon[i][j + 1] == 5) dungeon[i][j + 1] = 12; if (dungeon[i][j] == 28 && dungeon[i][j - 1] == 6 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 23; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 10) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 9) dungeon[i + 1][j] = 11; if (dungeon[i][j] == 11 && dungeon[i + 1][j] == 3) dungeon[i + 1][j] = 5; if (dungeon[i][j] == 10 && dungeon[i + 1][j] == 4) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 14 && dungeon[i + 1][j] == 4) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 27 && dungeon[i + 1][j] == 9) dungeon[i + 1][j] = 11; if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 4) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 1) dungeon[i + 1][j] = 16; if (dungeon[i][j] == 11 && dungeon[i + 1][j] == 4) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 3) dungeon[i + 1][j] = 5; if (dungeon[i][j] == 9 && dungeon[i + 1][j] == 3) dungeon[i + 1][j] = 5; if (dungeon[i][j] == 14 && dungeon[i + 1][j] == 3) dungeon[i + 1][j] = 5; if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 3) dungeon[i + 1][j] = 5; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 5 && dungeon[i + 1][j - 1] == 16) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 2 && dungeon[i + 1][j] == 4) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 9 && dungeon[i + 1][j] == 4) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 1 && dungeon[i][j - 1] == 8) dungeon[i][j - 1] = 9; if (dungeon[i][j] == 28 && dungeon[i + 1][j] == 23 && dungeon[i + 1][j + 1] == 3) dungeon[i + 1][j] = 16; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 10) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 17 && dungeon[i + 1][j] == 4) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 10 && dungeon[i + 1][j] == 4) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 17 && dungeon[i][j + 1] == 5) dungeon[i][j + 1] = 12; if (dungeon[i][j] == 29 && dungeon[i][j + 1] == 9) dungeon[i][j + 1] = 10; if (dungeon[i][j] == 13 && dungeon[i][j + 1] == 5) dungeon[i][j + 1] = 12; if (dungeon[i][j] == 9 && dungeon[i][j + 1] == 16) dungeon[i][j + 1] = 13; if (dungeon[i][j] == 10 && dungeon[i][j + 1] == 16) dungeon[i][j + 1] = 13; if (dungeon[i][j] == 16 && dungeon[i][j + 1] == 3) dungeon[i][j + 1] = 4; if (dungeon[i][j] == 11 && dungeon[i][j + 1] == 5) dungeon[i][j + 1] = 12; if (dungeon[i][j] == 10 && dungeon[i + 1][j] == 3 && dungeon[i + 1][j - 1] == 16) dungeon[i + 1][j] = 12; if (dungeon[i][j] == 16 && dungeon[i][j + 1] == 5) dungeon[i][j + 1] = 12; if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 6) dungeon[i][j + 1] = 4; if (dungeon[i][j] == 21 && dungeon[i + 1][j] == 13 && dungeon[i][j + 1] == 10) dungeon[i + 1][j + 1] = 12; if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 10) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 22 && dungeon[i][j + 1] == 11) dungeon[i][j + 1] = 17; if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 28 && dungeon[i + 2][j] == 16) dungeon[i + 1][j] = 23; if (dungeon[i][j] == 28 && dungeon[i + 1][j] == 23 && dungeon[i + 1][j + 1] == 1 && dungeon[i + 2][j] == 6) dungeon[i + 1][j] = 16; } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 15 && dungeon[i + 1][j] == 28 && dungeon[i + 2][j] == 16) dungeon[i + 1][j] = 23; if (dungeon[i][j] == 21 && dungeon[i + 1][j - 1] == 21 && dungeon[i + 1][j + 1] == 13 && dungeon[i + 2][j] == 2) dungeon[i + 1][j] = 17; if (dungeon[i][j] == 19 && dungeon[i + 1][j] == 15 && dungeon[i + 1][j + 1] == 12) dungeon[i + 1][j] = 17; } } } static void DRLG_L4Subs() { int x, y, i, rv; BYTE c; for (y = 0; y < DMAXY; y++) { for (x = 0; x < DMAXX; x++) { rv = random_(0, 3); if (rv == 0) { c = dungeon[x][y]; c = L4BTYPES[c]; if (c != 0 && dflags[x][y] == 0) { rv = random_(0, 16); i = -1; while (rv >= 0) { i++; if (i == sizeof(L4BTYPES)) { i = 0; } if (c == L4BTYPES[i]) { rv--; } } dungeon[x][y] = i; } } } } for (y = 0; y < DMAXY; y++) { for (x = 0; x < DMAXX; x++) { rv = random_(0, 10); if (rv == 0) { c = dungeon[x][y]; if (L4BTYPES[c] == 6 && dflags[x][y] == 0) { dungeon[x][y] = random_(0, 3) + 95; } } } } } static void L4makeDungeon() { int i, j, k, l; for (j = 0; j < 20; j++) { for (i = 0; i < 20; i++) { k = i << 1; l = j << 1; L4dungeon[k][l] = dung[i][j]; L4dungeon[k][l + 1] = dung[i][j]; L4dungeon[k + 1][l] = dung[i][j]; L4dungeon[k + 1][l + 1] = dung[i][j]; } } for (j = 0; j < 20; j++) { for (i = 0; i < 20; i++) { k = i << 1; l = j << 1; L4dungeon[k][l + 40] = dung[i][19 - j]; L4dungeon[k][l + 41] = dung[i][19 - j]; L4dungeon[k + 1][l + 40] = dung[i][19 - j]; L4dungeon[k + 1][l + 41] = dung[i][19 - j]; } } for (j = 0; j < 20; j++) { for (i = 0; i < 20; i++) { k = i << 1; l = j << 1; L4dungeon[k + 40][l] = dung[19 - i][j]; L4dungeon[k + 40][l + 1] = dung[19 - i][j]; L4dungeon[k + 41][l] = dung[19 - i][j]; L4dungeon[k + 41][l + 1] = dung[19 - i][j]; } } for (j = 0; j < 20; j++) { for (i = 0; i < 20; i++) { k = i << 1; l = j << 1; L4dungeon[k + 40][l + 40] = dung[19 - i][19 - j]; L4dungeon[k + 40][l + 41] = dung[19 - i][19 - j]; L4dungeon[k + 41][l + 40] = dung[19 - i][19 - j]; L4dungeon[k + 41][l + 41] = dung[19 - i][19 - j]; } } } static void uShape() { int j, i, rv; for (j = 19; j >= 0; j--) { for (i = 19; i >= 0; i--) { if (dung[i][j] != 1) { hallok[j] = FALSE; } if (dung[i][j] == 1) { // BUGFIX: check that i + 1 < 20 and j + 1 < 20 if (dung[i][j + 1] == 1 && dung[i + 1][j + 1] == 0) { hallok[j] = TRUE; } else { hallok[j] = FALSE; } i = 0; } } } rv = random_(0, 19) + 1; do { if (hallok[rv]) { for (i = 19; i >= 0; i--) { if (dung[i][rv] == 1) { i = -1; rv = 0; } else { dung[i][rv] = 1; dung[i][rv + 1] = 1; } } } else { rv++; if (rv == 20) { rv = 1; } } } while (rv != 0); for (i = 19; i >= 0; i--) { for (j = 19; j >= 0; j--) { if (dung[i][j] != 1) { hallok[i] = FALSE; } if (dung[i][j] == 1) { // BUGFIX: check that i + 1 < 20 and j + 1 < 20 if (dung[i + 1][j] == 1 && dung[i + 1][j + 1] == 0) { hallok[i] = TRUE; } else { hallok[i] = FALSE; } j = 0; } } } rv = random_(0, 19) + 1; do { if (hallok[rv]) { for (j = 19; j >= 0; j--) { if (dung[rv][j] == 1) { j = -1; rv = 0; } else { dung[rv][j] = 1; dung[rv + 1][j] = 1; } } } else { rv++; if (rv == 20) { rv = 1; } } } while (rv != 0); } static long GetArea() { int i, j; long rv; rv = 0; for (j = 0; j < 20; j++) { for (i = 0; i < 20; i++) { if (dung[i][j] == 1) { rv++; } } } return rv; } static void L4drawRoom(int x, int y, int width, int height) { int i, j; for (j = 0; j < height; j++) { for (i = 0; i < width; i++) { dung[i + x][j + y] = 1; } } } static BOOL L4checkRoom(int x, int y, int width, int height) { int i, j; if (x <= 0 || y <= 0) { return FALSE; } for (j = 0; j < height; j++) { for (i = 0; i < width; i++) { if (i + x < 0 || i + x >= 20 || j + y < 0 || j + y >= 20) { return FALSE; } if (dung[i + x][j + y] != 0) { return FALSE; } } } return TRUE; } static void L4roomGen(int x, int y, int w, int h, int dir) { int num; BOOL ran, ran2; int width, height, rx, ry, ry2; int cw, ch, cx1, cy1, cx2; int dirProb = random_(0, 4); switch (dir == 1 ? dirProb != 0 : dirProb == 0) { case FALSE: num = 0; do { cw = (random_(0, 5) + 2) & ~1; ch = (random_(0, 5) + 2) & ~1; cy1 = h / 2 + y - ch / 2; cx1 = x - cw; ran = L4checkRoom(cx1 - 1, cy1 - 1, ch + 2, cw + 1); /// BUGFIX: swap args 3 and 4 ("ch+2" and "cw+1") num++; } while (ran == FALSE && num < 20); if (ran == TRUE) L4drawRoom(cx1, cy1, cw, ch); cx2 = x + w; ran2 = L4checkRoom(cx2, cy1 - 1, cw + 1, ch + 2); if (ran2 == TRUE) L4drawRoom(cx2, cy1, cw, ch); if (ran == TRUE) L4roomGen(cx1, cy1, cw, ch, 1); if (ran2 == TRUE) L4roomGen(cx2, cy1, cw, ch, 1); break; case TRUE: num = 0; do { width = (random_(0, 5) + 2) & ~1; height = (random_(0, 5) + 2) & ~1; rx = w / 2 + x - width / 2; ry = y - height; ran = L4checkRoom(rx - 1, ry - 1, width + 2, height + 1); num++; } while (ran == FALSE && num < 20); if (ran == TRUE) L4drawRoom(rx, ry, width, height); ry2 = y + h; ran2 = L4checkRoom(rx - 1, ry2, width + 2, height + 1); if (ran2 == TRUE) L4drawRoom(rx, ry2, width, height); if (ran == TRUE) L4roomGen(rx, ry, width, height, 0); if (ran2 == TRUE) L4roomGen(rx, ry2, width, height, 0); break; } } static void L4firstRoom() { int x, y, w, h, rndx, rndy, xmin, xmax, ymin, ymax, tx, ty; if (currlevel != 16) { if (currlevel == quests[Q_WARLORD]._qlevel && quests[Q_WARLORD]._qactive != QUEST_NOTAVAIL) { /// ASSERT: assert(gbMaxPlayers == 1); w = 11; h = 11; } else if (currlevel == quests[Q_BETRAYER]._qlevel && gbMaxPlayers != 1) { w = 11; h = 11; } else { w = random_(0, 5) + 2; h = random_(0, 5) + 2; } } else { w = 14; h = 14; } xmin = (20 - w) >> 1; xmax = 19 - w; rndx = random_(0, xmax - xmin + 1) + xmin; if (rndx + w > 19) { tx = w + rndx - 19; x = rndx - tx + 1; } else { x = rndx; } ymin = (20 - h) >> 1; ymax = 19 - h; rndy = random_(0, ymax - ymin + 1) + ymin; if (rndy + h > 19) { ty = h + rndy - 19; y = rndy - ty + 1; } else { y = rndy; } if (currlevel == 16) { l4holdx = x; l4holdy = y; } if (QuestStatus(Q_WARLORD) || currlevel == quests[Q_BETRAYER]._qlevel && gbMaxPlayers != 1) { SP4x1 = x + 1; SP4y1 = y + 1; SP4x2 = SP4x1 + w; SP4y2 = SP4y1 + h; } else { SP4x1 = 0; SP4y1 = 0; SP4x2 = 0; SP4y2 = 0; } L4drawRoom(x, y, w, h); L4roomGen(x, y, w, h, random_(0, 2)); } void L4SaveQuads() { int i, j, x, y; x = l4holdx; y = l4holdy; for (j = 0; j < 14; j++) { for (i = 0; i < 14; i++) { dflags[i + x][j + y] = 1; dflags[DMAXX - 1 - i - x][j + y] = 1; dflags[i + x][DMAXY - 1 - j - y] = 1; dflags[DMAXX - 1 - i - x][DMAXY - 1 - j - y] = 1; } } } void DRLG_L4SetRoom(BYTE *pSetPiece, int rx1, int ry1) { int rw, rh, i, j; BYTE *sp; rw = pSetPiece[0]; rh = pSetPiece[2]; sp = &pSetPiece[4]; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*sp != 0) { dungeon[i + rx1][j + ry1] = *sp; dflags[i + rx1][j + ry1] |= DLRG_PROTECTED; } else { dungeon[i + rx1][j + ry1] = 6; } sp += 2; } } } void DRLG_LoadDiabQuads(BOOL preflag) { BYTE *lpSetPiece; lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab1.DUN", NULL); diabquad1x = 4 + l4holdx; diabquad1y = 4 + l4holdy; DRLG_L4SetRoom(lpSetPiece, diabquad1x, diabquad1y); mem_free_dbg(lpSetPiece); if (preflag) { lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab2b.DUN", NULL); } else { lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab2a.DUN", NULL); } diabquad2x = 27 - l4holdx; diabquad2y = 1 + l4holdy; DRLG_L4SetRoom(lpSetPiece, diabquad2x, diabquad2y); mem_free_dbg(lpSetPiece); if (preflag) { lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab3b.DUN", NULL); } else { lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab3a.DUN", NULL); } diabquad3x = 1 + l4holdx; diabquad3y = 27 - l4holdy; DRLG_L4SetRoom(lpSetPiece, diabquad3x, diabquad3y); mem_free_dbg(lpSetPiece); if (preflag) { lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab4b.DUN", NULL); } else { lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab4a.DUN", NULL); } diabquad4x = 28 - l4holdx; diabquad4y = 28 - l4holdy; DRLG_L4SetRoom(lpSetPiece, diabquad4x, diabquad4y); mem_free_dbg(lpSetPiece); } static BOOL DRLG_L4PlaceMiniSet(const BYTE *miniset, int tmin, int tmax, int cx, int cy, BOOL setview, int ldir) { int sx, sy, sw, sh, xx, yy, i, ii, numt, bailcnt; BOOL found; sw = miniset[0]; sh = miniset[1]; if (tmax - tmin == 0) { numt = 1; } else { numt = random_(0, tmax - tmin) + tmin; } for (i = 0; i < numt; i++) { sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); found = FALSE; for (bailcnt = 0; !found && bailcnt < 200; bailcnt++) { found = TRUE; if (sx >= SP4x1 && sx <= SP4x2 && sy >= SP4y1 && sy <= SP4y2) { found = FALSE; } if (cx != -1 && sx >= cx - sw && sx <= cx + 12) { sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); found = FALSE; } if (cy != -1 && sy >= cy - sh && sy <= cy + 12) { sx = random_(0, DMAXX - sw); sy = random_(0, DMAXY - sh); found = FALSE; } ii = 2; for (yy = 0; yy < sh && found == TRUE; yy++) { for (xx = 0; xx < sw && found == TRUE; xx++) { if (miniset[ii] != 0 && dungeon[xx + sx][yy + sy] != miniset[ii]) { found = FALSE; } if (dflags[xx + sx][yy + sy] != 0) { found = FALSE; } ii++; } } if (!found) { sx++; if (sx == DMAXX - sw) { sx = 0; sy++; if (sy == DMAXY - sh) { sy = 0; } } } } if (bailcnt >= 200) { return FALSE; } ii = sw * sh + 2; for (yy = 0; yy < sh; yy++) { for (xx = 0; xx < sw; xx++) { if (miniset[ii] != 0) { dungeon[xx + sx][yy + sy] = miniset[ii]; dflags[xx + sx][yy + sy] |= 8; } ii++; } } } if (currlevel == 15) { quests[Q_BETRAYER]._qtx = sx + 1; quests[Q_BETRAYER]._qty = sy + 1; } if (setview == TRUE) { ViewX = 2 * sx + 21; ViewY = 2 * sy + 22; } if (ldir == 0) { LvlViewX = 2 * sx + 21; LvlViewY = 2 * sy + 22; } return TRUE; } static void DRLG_L4FTVR(int i, int j, int x, int y, int d) { if (dTransVal[x][y] != 0 || dungeon[i][j] != 6) { if (d == 1) { dTransVal[x][y] = TransVal; dTransVal[x][y + 1] = TransVal; } if (d == 2) { dTransVal[x + 1][y] = TransVal; dTransVal[x + 1][y + 1] = TransVal; } if (d == 3) { dTransVal[x][y] = TransVal; dTransVal[x + 1][y] = TransVal; } if (d == 4) { dTransVal[x][y + 1] = TransVal; dTransVal[x + 1][y + 1] = TransVal; } if (d == 5) { dTransVal[x + 1][y + 1] = TransVal; } if (d == 6) { dTransVal[x][y + 1] = TransVal; } if (d == 7) { dTransVal[x + 1][y] = TransVal; } if (d == 8) { dTransVal[x][y] = TransVal; } } else { dTransVal[x][y] = TransVal; dTransVal[x + 1][y] = TransVal; dTransVal[x][y + 1] = TransVal; dTransVal[x + 1][y + 1] = TransVal; DRLG_L4FTVR(i + 1, j, x + 2, y, 1); DRLG_L4FTVR(i - 1, j, x - 2, y, 2); DRLG_L4FTVR(i, j + 1, x, y + 2, 3); DRLG_L4FTVR(i, j - 1, x, y - 2, 4); DRLG_L4FTVR(i - 1, j - 1, x - 2, y - 2, 5); DRLG_L4FTVR(i + 1, j - 1, x + 2, y - 2, 6); DRLG_L4FTVR(i - 1, j + 1, x - 2, y + 2, 7); DRLG_L4FTVR(i + 1, j + 1, x + 2, y + 2, 8); } } static void DRLG_L4FloodTVal() { int i, j, xx, yy; yy = 16; for (j = 0; j < DMAXY; j++) { xx = 16; for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 6 && dTransVal[xx][yy] == 0) { DRLG_L4FTVR(i, j, xx, yy, 0); TransVal++; } xx += 2; } yy += 2; } } BOOL IsDURWall(char d) { if (d == 25) { return TRUE; } if (d == 28) { return TRUE; } if (d == 23) { return TRUE; } return FALSE; } BOOL IsDLLWall(char dd) { if (dd == 27) { return TRUE; } if (dd == 26) { return TRUE; } if (dd == 22) { return TRUE; } return FALSE; } static void DRLG_L4TransFix() { int i, j, xx, yy; yy = 16; for (j = 0; j < DMAXY; j++) { xx = 16; for (i = 0; i < DMAXX; i++) { if (IsDURWall(dungeon[i][j]) && dungeon[i][j - 1] == 18) { dTransVal[xx + 1][yy] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (IsDLLWall(dungeon[i][j]) && dungeon[i + 1][j] == 19) { dTransVal[xx][yy + 1] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 18) { dTransVal[xx + 1][yy] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 19) { dTransVal[xx][yy + 1] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 24) { dTransVal[xx + 1][yy] = dTransVal[xx][yy]; dTransVal[xx][yy + 1] = dTransVal[xx][yy]; dTransVal[xx + 1][yy + 1] = dTransVal[xx][yy]; } if (dungeon[i][j] == 57) { dTransVal[xx - 1][yy] = dTransVal[xx][yy + 1]; dTransVal[xx][yy] = dTransVal[xx][yy + 1]; } if (dungeon[i][j] == 53) { dTransVal[xx][yy - 1] = dTransVal[xx + 1][yy]; dTransVal[xx][yy] = dTransVal[xx + 1][yy]; } xx += 2; } yy += 2; } } static void DRLG_L4Corners() { int i, j; for (j = 1; j < DMAXY - 1; j++) { for (i = 1; i < DMAXX - 1; i++) { if (dungeon[i][j] >= 18 && dungeon[i][j] <= 30) { if (dungeon[i + 1][j] < 18) { dungeon[i][j] += 98; } else if (dungeon[i][j + 1] < 18) { dungeon[i][j] += 98; } } } } } void L4FixRim() { int i, j; for (i = 0; i < 20; i++) { dung[i][0] = 0; } for (j = 0; j < 20; j++) { dung[0][j] = 0; } } void DRLG_L4GeneralFix() { int i, j; for (j = 0; j < DMAXY - 1; j++) { for (i = 0; i < DMAXX - 1; i++) { if ((dungeon[i][j] == 24 || dungeon[i][j] == 122) && dungeon[i + 1][j] == 2 && dungeon[i][j + 1] == 5) { dungeon[i][j] = 17; } } } } static void DRLG_L4(int entry) { int i, j, spi, spj, ar; BOOL doneflag; do { DRLG_InitTrans(); do { InitL4Dungeon(); L4firstRoom(); L4FixRim(); ar = GetArea(); if (ar >= 173) { uShape(); } } while (ar < 173); L4makeDungeon(); L4makeDmt(); L4tileFix(); if (currlevel == 16) { L4SaveQuads(); } if (QuestStatus(Q_WARLORD) || currlevel == quests[Q_BETRAYER]._qlevel && gbMaxPlayers != 1) { for (spi = SP4x1; spi < SP4x2; spi++) { for (spj = SP4y1; spj < SP4y2; spj++) { dflags[spi][spj] = 1; } } } L4AddWall(); DRLG_L4FloodTVal(); DRLG_L4TransFix(); if (setloadflag) { DRLG_L4SetSPRoom(SP4x1, SP4y1); } if (currlevel == 16) { DRLG_LoadDiabQuads(TRUE); } if (QuestStatus(Q_WARLORD)) { if (entry == ENTRY_MAIN) { doneflag = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, TRUE, 0); if (doneflag && currlevel == 13) { doneflag = DRLG_L4PlaceMiniSet(L4TWARP, 1, 1, -1, -1, FALSE, 6); } ViewX++; } else if (entry == ENTRY_PREV) { doneflag = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, FALSE, 0); if (doneflag && currlevel == 13) { doneflag = DRLG_L4PlaceMiniSet(L4TWARP, 1, 1, -1, -1, FALSE, 6); } ViewX = 2 * setpc_x + 22; ViewY = 2 * setpc_y + 22; } else { doneflag = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, FALSE, 0); if (doneflag && currlevel == 13) { doneflag = DRLG_L4PlaceMiniSet(L4TWARP, 1, 1, -1, -1, TRUE, 6); } ViewX++; } } else if (currlevel != 15) { if (entry == ENTRY_MAIN) { doneflag = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, TRUE, 0); if (doneflag && currlevel != 16) { doneflag = DRLG_L4PlaceMiniSet(L4DSTAIRS, 1, 1, -1, -1, FALSE, 1); } if (doneflag && currlevel == 13) { doneflag = DRLG_L4PlaceMiniSet(L4TWARP, 1, 1, -1, -1, FALSE, 6); } ViewX++; } else if (entry == ENTRY_PREV) { doneflag = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, FALSE, 0); if (doneflag && currlevel != 16) { doneflag = DRLG_L4PlaceMiniSet(L4DSTAIRS, 1, 1, -1, -1, TRUE, 1); } if (doneflag && currlevel == 13) { doneflag = DRLG_L4PlaceMiniSet(L4TWARP, 1, 1, -1, -1, FALSE, 6); } ViewY++; } else { doneflag = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, FALSE, 0); if (doneflag && currlevel != 16) { doneflag = DRLG_L4PlaceMiniSet(L4DSTAIRS, 1, 1, -1, -1, FALSE, 1); } if (doneflag && currlevel == 13) { doneflag = DRLG_L4PlaceMiniSet(L4TWARP, 1, 1, -1, -1, TRUE, 6); } ViewX++; } } else { if (entry == ENTRY_MAIN) { doneflag = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, TRUE, 0); if (doneflag) { if (gbMaxPlayers == 1 && quests[Q_DIABLO]._qactive != QUEST_ACTIVE) { doneflag = DRLG_L4PlaceMiniSet(L4PENTA, 1, 1, -1, -1, FALSE, 1); } else { doneflag = DRLG_L4PlaceMiniSet(L4PENTA2, 1, 1, -1, -1, FALSE, 1); } } ViewX++; } else { doneflag = DRLG_L4PlaceMiniSet(L4USTAIRS, 1, 1, -1, -1, FALSE, 0); if (doneflag) { if (gbMaxPlayers == 1 && quests[Q_DIABLO]._qactive != QUEST_ACTIVE) { doneflag = DRLG_L4PlaceMiniSet(L4PENTA, 1, 1, -1, -1, TRUE, 1); } else { doneflag = DRLG_L4PlaceMiniSet(L4PENTA2, 1, 1, -1, -1, TRUE, 1); } } ViewY++; } } } while (!doneflag); DRLG_L4GeneralFix(); if (currlevel != 16) { DRLG_PlaceThemeRooms(7, 10, 6, 8, 1); } DRLG_L4Shadows(); DRLG_L4Corners(); DRLG_L4Subs(); DRLG_Init_Globals(); if (QuestStatus(Q_WARLORD)) { for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { pdungeon[i][j] = dungeon[i][j]; } } } DRLG_CheckQuests(SP4x1, SP4y1); if (currlevel == 15) { for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == 98) { Make_SetPC(i - 1, j - 1, 5, 5); } if (dungeon[i][j] == 107) { Make_SetPC(i - 1, j - 1, 5, 5); } } } } if (currlevel == 16) { for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { pdungeon[i][j] = dungeon[i][j]; } } DRLG_LoadDiabQuads(FALSE); } } static void DRLG_L4Pass3() { int i, j, xx, yy; long v1, v2, v3, v4, lv; lv = 30 - 1; #ifdef USE_ASM __asm { mov esi, pMegaTiles mov eax, lv shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax } #else v1 = *((WORD *)&pMegaTiles[lv * 8] + 0) + 1; v2 = *((WORD *)&pMegaTiles[lv * 8] + 1) + 1; v3 = *((WORD *)&pMegaTiles[lv * 8] + 2) + 1; v4 = *((WORD *)&pMegaTiles[lv * 8] + 3) + 1; #endif for (j = 0; j < MAXDUNY; j += 2) { for (i = 0; i < MAXDUNX; i += 2) { dPiece[i][j] = v1; dPiece[i + 1][j] = v2; dPiece[i][j + 1] = v3; dPiece[i + 1][j + 1] = v4; } } yy = 16; for (j = 0; j < DMAXY; j++) { xx = 16; for (i = 0; i < DMAXX; i++) { lv = dungeon[i][j] - 1; #ifdef USE_ASM if (lv >= 0) { __asm { mov esi, pMegaTiles mov eax, lv shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax } } else { v1 = 0; v2 = 0; v3 = 0; v4 = 0; } #else if (lv >= 0) { v1 = *((WORD *)&pMegaTiles[lv * 8] + 0) + 1; v2 = *((WORD *)&pMegaTiles[lv * 8] + 1) + 1; v3 = *((WORD *)&pMegaTiles[lv * 8] + 2) + 1; v4 = *((WORD *)&pMegaTiles[lv * 8] + 3) + 1; } else { v1 = 0; v2 = 0; v3 = 0; v4 = 0; } #endif dPiece[xx][yy] = v1; dPiece[xx + 1][yy] = v2; dPiece[xx][yy + 1] = v3; dPiece[xx + 1][yy + 1] = v4; xx += 2; } yy += 2; } } void CreateL4Dungeon(DWORD rseed, int entry) { SetRndSeed(rseed); dminx = 16; dminy = 16; dmaxx = 96; dmaxy = 96; ViewX = 40; ViewY = 40; DRLG_InitSetPC(); DRLG_LoadL4SP(); DRLG_L4(entry); DRLG_L4Pass3(); DRLG_FreeL4SP(); DRLG_SetPC(); } #endif ================================================ FILE: Source/drlg_l4.h ================================================ /** * @file drlg_l4.h * * Interface of the hell level generation algorithms. */ #ifndef __DRLG_L4_H__ #define __DRLG_L4_H__ extern int diabquad1x; extern int diabquad1y; extern int diabquad2x; extern int diabquad2y; extern int diabquad3x; extern int diabquad3y; extern int diabquad4x; extern int diabquad4y; void CreateL4Dungeon(DWORD rseed, int entry); #endif /* __DRLG_L4_H__ */ ================================================ FILE: Source/dthread.cpp ================================================ /** * @file dthread.cpp * * Implementation of functions for updating game state from network commands. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" static CCritSect sgMemCrit; unsigned int glpDThreadId; TMegaPkt *sgpInfoHead; /* may not be right struct */ BOOLEAN dthread_running; HANDLE sghWorkToDoEvent; /* rdata */ static HANDLE sghThread = INVALID_HANDLE_VALUE; static unsigned int __stdcall dthread_handler(void *data) { const char *error_buf; TMegaPkt *pkt; DWORD dwMilliseconds; while (dthread_running) { if (!sgpInfoHead && WaitForSingleObject(sghWorkToDoEvent, INFINITE) == WAIT_FAILED) { error_buf = TraceLastError(); app_fatal("dthread4:\n%s", error_buf); } sgMemCrit.Enter(); pkt = sgpInfoHead; if (sgpInfoHead) sgpInfoHead = sgpInfoHead->pNext; else ResetEvent(sghWorkToDoEvent); sgMemCrit.Leave(); if (pkt) { if (pkt->dwSpaceLeft != MAX_PLRS) multi_send_zero_packet(pkt->dwSpaceLeft, pkt->data[0], &pkt->data[8], *(DWORD *)&pkt->data[4]); dwMilliseconds = 1000 * *(DWORD *)&pkt->data[4] / gdwDeltaBytesSec; if (dwMilliseconds >= 1) dwMilliseconds = 1; mem_free_dbg(pkt); if (dwMilliseconds) Sleep(dwMilliseconds); } } return 0; } void dthread_remove_player(int pnum) { TMegaPkt *pkt; sgMemCrit.Enter(); for (pkt = sgpInfoHead; pkt; pkt = pkt->pNext) { if (pkt->dwSpaceLeft == pnum) pkt->dwSpaceLeft = MAX_PLRS; } sgMemCrit.Leave(); } void dthread_send_delta(int pnum, char cmd, void *pbSrc, int dwLen) { TMegaPkt *pkt; TMegaPkt *p; if (gbMaxPlayers == 1) { return; } pkt = (TMegaPkt *)DiabloAllocPtr(dwLen + 20); pkt->pNext = NULL; pkt->dwSpaceLeft = pnum; pkt->data[0] = cmd; *(DWORD *)&pkt->data[4] = dwLen; memcpy(&pkt->data[8], pbSrc, dwLen); sgMemCrit.Enter(); p = (TMegaPkt *)&sgpInfoHead; while (p->pNext) { p = p->pNext; } p->pNext = pkt; SetEvent(sghWorkToDoEvent); sgMemCrit.Leave(); } void dthread_start() { const char *error_buf; if (gbMaxPlayers == 1) { return; } sghWorkToDoEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (sghWorkToDoEvent == NULL) { error_buf = TraceLastError(); app_fatal("dthread:1\n%s", error_buf); } dthread_running = TRUE; sghThread = (HANDLE)_beginthreadex(NULL, 0, dthread_handler, NULL, 0, &glpDThreadId); if (sghThread == INVALID_HANDLE_VALUE) { error_buf = TraceLastError(); app_fatal("dthread2:\n%s", error_buf); } } void dthread_cleanup() { const char *error_buf; TMegaPkt *tmp; if (sghWorkToDoEvent == NULL) { return; } dthread_running = FALSE; SetEvent(sghWorkToDoEvent); if (sghThread != INVALID_HANDLE_VALUE && glpDThreadId != GetCurrentThreadId()) { if (WaitForSingleObject(sghThread, INFINITE) == WAIT_FAILED) { error_buf = TraceLastError(); app_fatal("dthread3:\n(%s)", error_buf); } CloseHandle(sghThread); sghThread = INVALID_HANDLE_VALUE; } CloseHandle(sghWorkToDoEvent); sghWorkToDoEvent = NULL; while (sgpInfoHead) { tmp = sgpInfoHead->pNext; MemFreeDbg(sgpInfoHead); sgpInfoHead = tmp; } } ================================================ FILE: Source/dthread.h ================================================ /** * @file dthread.h * * Interface of functions for updating game state from network commands. */ #ifndef __DTHREAD_H__ #define __DTHREAD_H__ void dthread_remove_player(int pnum); void dthread_send_delta(int pnum, char cmd, void *pbSrc, int dwLen); void dthread_start(); void dthread_cleanup(); /* data */ #endif /* __DTHREAD_H__ */ ================================================ FILE: Source/dx.cpp ================================================ /** * @file dx.cpp * * Implementation of functions setting up the graphics pipeline. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" BYTE *sgpBackBuf; LPDIRECTDRAW lpDDInterface; IDirectDrawPalette *lpDDPalette; int sgdwLockCount; BYTE *gpBuffer; IDirectDrawSurface *lpDDSBackBuf; IDirectDrawSurface *lpDDSPrimary; #ifdef _DEBUG int locktbl[256]; #endif static CCritSect sgMemCrit; char gbBackBuf; char gbEmulate; HMODULE ghDiabMod; static void dx_create_back_buffer() { DDSCAPS caps; HRESULT error_code; DDSURFACEDESC ddsd; error_code = lpDDSPrimary->GetCaps(&caps); if (error_code != DD_OK) DDErrMsg(error_code, 59, "C:\\Src\\Diablo\\Source\\dx.cpp"); if (!gbBackBuf) { ddsd.dwSize = sizeof(ddsd); error_code = lpDDSPrimary->Lock(NULL, &ddsd, DDLOCK_WRITEONLY | DDLOCK_WAIT, NULL); if (error_code == DD_OK) { lpDDSPrimary->Unlock(NULL); sgpBackBuf = (BYTE *)DiabloAllocPtr(BUFFER_HEIGHT * BUFFER_WIDTH); return; } if (error_code != DDERR_CANTLOCKSURFACE) ErrDlg(IDD_DIALOG1, error_code, "C:\\Src\\Diablo\\Source\\dx.cpp", 81); } memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; ddsd.dwHeight = BUFFER_HEIGHT; ddsd.dwWidth = BUFFER_WIDTH; ddsd.lPitch = BUFFER_WIDTH; ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat); error_code = lpDDSPrimary->GetPixelFormat(&ddsd.ddpfPixelFormat); if (error_code != DD_OK) ErrDlg(IDD_DIALOG1, error_code, "C:\\Src\\Diablo\\Source\\dx.cpp", 94); error_code = lpDDInterface->CreateSurface(&ddsd, &lpDDSBackBuf, NULL); if (error_code != DD_OK) ErrDlg(IDD_DIALOG1, error_code, "C:\\Src\\Diablo\\Source\\dx.cpp", 96); } static void dx_create_primary_surface() { DDSURFACEDESC ddsd; HRESULT error_code; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; error_code = lpDDInterface->CreateSurface(&ddsd, &lpDDSPrimary, NULL); if (error_code != DD_OK) ErrDlg(IDD_DIALOG1, error_code, "C:\\Src\\Diablo\\Source\\dx.cpp", 109); } static HRESULT dx_DirectDrawCreate(LPGUID guid, LPDIRECTDRAW *lplpDD, LPUNKNOWN pUnkOuter) { HRESULT(WINAPI * DirectDrawCreate) (LPGUID lpGuid, LPDIRECTDRAW * lplpDD, LPUNKNOWN pUnkOuter); if (ghDiabMod == NULL) { ghDiabMod = LoadLibrary("ddraw.dll"); } if (ghDiabMod == NULL) { ErrDlg(IDD_DIALOG4, GetLastError(), "C:\\Src\\Diablo\\Source\\dx.cpp", 122); } DirectDrawCreate = (HRESULT(WINAPI *)(LPGUID, LPDIRECTDRAW *, LPUNKNOWN))GetProcAddress(ghDiabMod, "DirectDrawCreate"); if (DirectDrawCreate == NULL) { ErrDlg(IDD_DIALOG4, GetLastError(), "C:\\Src\\Diablo\\Source\\dx.cpp", 127); } return DirectDrawCreate(guid, lplpDD, pUnkOuter); } void dx_init(HWND hWnd) { HRESULT hDDVal; int winw, winh; BOOL bSuccess; GUID *lpGUID; assert(!gpBuffer); assert(!sgdwLockCount); assert(!sgpBackBuf); SetFocus(hWnd); ShowWindow(hWnd, SW_SHOWNORMAL); lpGUID = NULL; if (gbEmulate) { lpGUID = (GUID *)DDCREATE_EMULATIONONLY; } hDDVal = dx_DirectDrawCreate(lpGUID, &lpDDInterface, NULL); if (hDDVal != DD_OK) { ErrDlg(IDD_DIALOG1, hDDVal, "C:\\Src\\Diablo\\Source\\dx.cpp", 149); } #ifdef COLORFIX #ifdef __DDRAWI_INCLUDED__ ((LPDDRAWI_DIRECTDRAW_INT)lpDDInterface)->lpLcl->dwAppHackFlags |= 0x800; #else ((DWORD **)lpDDInterface)[1][18] |= 0x800; #endif #endif #ifndef _DEBUG fullscreen = TRUE; #endif if (!fullscreen) { hDDVal = lpDDInterface->SetCooperativeLevel(hWnd, DDSCL_NORMAL | DDSCL_ALLOWREBOOT); if (hDDVal == DDERR_EXCLUSIVEMODEALREADYSET) { TriggerBreak(); } else if (hDDVal != DD_OK) { ErrDlg(IDD_DIALOG1, hDDVal, "C:\\Diablo\\Direct\\dx.cpp", 155); } SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } else { hDDVal = lpDDInterface->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT | DDSCL_FULLSCREEN); if (hDDVal == DDERR_EXCLUSIVEMODEALREADYSET) { TriggerBreak(); } else if (hDDVal != DD_OK) { ErrDlg(IDD_DIALOG1, hDDVal, "C:\\Src\\Diablo\\Source\\dx.cpp", 170); } hDDVal = lpDDInterface->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP); if (hDDVal != DD_OK) { winw = GetSystemMetrics(SM_CXSCREEN); winh = GetSystemMetrics(SM_CYSCREEN); hDDVal = lpDDInterface->SetDisplayMode(winw, winh, SCREEN_BPP); } if (hDDVal != DD_OK) { ErrDlg(IDD_DIALOG1, hDDVal, "C:\\Src\\Diablo\\Source\\dx.cpp", 183); } } dx_create_primary_surface(); palette_init(); GdiSetBatchLimit(1); dx_create_back_buffer(); bSuccess = SDrawManualInitialize(hWnd, lpDDInterface, lpDDSPrimary, NULL, NULL, lpDDSBackBuf, lpDDPalette, NULL); assert(bSuccess); } static void lock_buf_priv() { DDSURFACEDESC ddsd; HRESULT error_code; sgMemCrit.Enter(); if (sgpBackBuf != NULL) { gpBuffer = sgpBackBuf; sgdwLockCount++; return; } if (lpDDSBackBuf == NULL) { Sleep(20000); app_fatal("lock_buf_priv"); sgdwLockCount++; return; } if (sgdwLockCount != 0) { sgdwLockCount++; return; } ddsd.dwSize = sizeof(ddsd); error_code = lpDDSBackBuf->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); if (error_code != DD_OK) DDErrMsg(error_code, 235, "C:\\Src\\Diablo\\Source\\dx.cpp"); gpBuffer = (BYTE *)ddsd.lpSurface; gpBufEnd += (size_t)ddsd.lpSurface; sgdwLockCount++; } void lock_buf(BYTE idx) { #ifdef _DEBUG ++locktbl[idx]; #endif lock_buf_priv(); } static void unlock_buf_priv() { HRESULT error_code; if (sgdwLockCount == 0) app_fatal("draw main unlock error"); if (gpBuffer == NULL) app_fatal("draw consistency error"); sgdwLockCount--; if (sgdwLockCount == 0) { gpBufEnd -= (size_t)gpBuffer; gpBuffer = NULL; if (sgpBackBuf == NULL) { error_code = lpDDSBackBuf->Unlock(NULL); if (error_code != DD_OK) DDErrMsg(error_code, 273, "C:\\Src\\Diablo\\Source\\dx.cpp"); } } sgMemCrit.Leave(); } void unlock_buf(BYTE idx) { #ifdef _DEBUG if (!locktbl[idx]) app_fatal("Draw lock underflow: 0x%x", idx); --locktbl[idx]; #endif unlock_buf_priv(); } void dx_cleanup() { if (ghMainWnd) ShowWindow(ghMainWnd, SW_HIDE); SDrawDestroy(); sgMemCrit.Enter(); if (sgpBackBuf != NULL) { MemFreeDbg(sgpBackBuf); } else if (lpDDSBackBuf != NULL) { lpDDSBackBuf->Release(); lpDDSBackBuf = NULL; } sgdwLockCount = 0; gpBuffer = NULL; sgMemCrit.Leave(); if (lpDDSPrimary) { lpDDSPrimary->Release(); lpDDSPrimary = NULL; } if (lpDDPalette) { lpDDPalette->Release(); lpDDPalette = NULL; } if (lpDDInterface) { lpDDInterface->Release(); lpDDInterface = NULL; } } void dx_reinit() { int lockCount; sgMemCrit.Enter(); ClearCursor(); lockCount = sgdwLockCount; while (sgdwLockCount != 0) unlock_buf_priv(); dx_cleanup(); force_redraw = 255; dx_init(ghMainWnd); while (lockCount-- != 0) { lock_buf_priv(); } sgMemCrit.Leave(); } /* check extern remove stub */ void j_dx_reinit() { dx_reinit(); } ================================================ FILE: Source/dx.h ================================================ /** * @file dx.h * * Interface of functions setting up the graphics pipeline. */ #ifndef __DX_H__ #define __DX_H__ extern IDirectDraw *lpDDInterface; extern IDirectDrawPalette *lpDDPalette; extern BYTE *gpBuffer; extern IDirectDrawSurface *lpDDSBackBuf; extern IDirectDrawSurface *lpDDSPrimary; extern char gbBackBuf; extern char gbEmulate; void dx_init(HWND hWnd); void lock_buf(BYTE idx); void unlock_buf(BYTE idx); void dx_cleanup(); void dx_reinit(); void j_dx_reinit(); #endif /* __DX_H__ */ ================================================ FILE: Source/effects.cpp ================================================ /** * @file effects.cpp * * Implementation of functions for loading and playing sounds. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" int sfxdelay; int sfxdnum; /** A handle to the current sound effect playing. */ HANDLE sghStream; /** Specifies the sound file and the playback state of the current sound effect. */ TSFX *sgpStreamSFX; /** * Monster sound type prefix * a: Attack * h: Hit * d: Death * s: Special */ const char MonstSndChar[] = { 'a', 'h', 'd', 's' }; /* data */ /** List of all sounds, except monsters and music */ TSFX sgSFX[] = { // clang-format off // bFlags, pszName, pSnd { sfx_MISC, "Sfx\\Misc\\Walk1.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Walk2.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Walk3.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Walk4.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\BFire.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Fmag.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Tmag.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Lghit.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Lghit1.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Swing.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Swing2.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Dead.wav", NULL }, #ifdef HELLFIRE { sfx_MISC, "Sfx\\Misc\\Sting1.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\FBallBow.wav", NULL }, #endif { sfx_STREAM, "Sfx\\Misc\\Questdon.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Armrfkd.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Barlfire.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Barrel.wav", NULL }, #ifdef HELLFIRE { sfx_MISC, "Sfx\\Items\\PodPop8.wav", NULL }, { sfx_MISC, "Sfx\\Items\\PodPop5.wav", NULL }, { sfx_MISC, "Sfx\\Items\\UrnPop3.wav", NULL }, { sfx_MISC, "Sfx\\Items\\UrnPop2.wav", NULL }, #endif { sfx_MISC, "Sfx\\Items\\Bhit.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Bhit1.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Chest.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Doorclos.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Dooropen.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipanvl.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipaxe.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipblst.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipbody.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipbook.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipbow.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipcap.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipharm.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Fliplarm.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipmag.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipmag1.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipmush.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flippot.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipring.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Fliprock.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipscrl.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipshld.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipsign.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipstaf.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Flipswor.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Gold.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Hlmtfkd.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invanvl.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invaxe.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invblst.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invbody.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invbook.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invbow.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invcap.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invgrab.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invharm.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invlarm.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invmush.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invpot.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invring.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invrock.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invscrol.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invshiel.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invsign.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invstaf.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Invsword.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Lever.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Magic.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Magic1.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Readbook.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Sarc.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Shielfkd.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Swrdfkd.wav", NULL }, { sfx_UI, "Sfx\\Items\\Titlemov.wav", NULL }, { sfx_UI, "Sfx\\Items\\Titlslct.wav", NULL }, { sfx_UI, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Trap.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast1.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast10.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast12.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast2.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast3.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast4.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast5.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast6.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast7.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast8.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cast9.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Healing.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Repair.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Acids1.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Acids2.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Apoc.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Arrowall.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Bldboil.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Blodstar.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Blsimpt.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Bonesp.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Bsimpct.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Caldron.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Cbolt.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Chltning.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\DSerp.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Elecimp1.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Elementl.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Ethereal.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Fball.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Fbolt1.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Fbolt2.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Firimp1.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Firimp2.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Flamwave.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Flash.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Fountain.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Golum.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Golumded.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Gshrine.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Guard.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Grdlanch.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Holybolt.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Hyper.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Infravis.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Invisibl.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Invpot.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Lning1.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Ltning.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Mshield.wav", NULL }, #ifdef HELLFIRE { sfx_MISC, "Sfx\\Misc\\NestXpld.wav", NULL }, #endif { sfx_MISC, "Sfx\\Misc\\Nova.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Portal.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Puddle.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Resur.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Scurse.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Scurimp.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Sentinel.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Shatter.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Soulfire.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Spoutlop.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Spoutstr.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Storm.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Trapdis.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Teleport.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Vtheft.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Wallloop.wav", NULL }, { sfx_MISC, "Sfx\\Misc\\Wallstrt.wav", NULL }, #ifdef HELLFIRE { sfx_MISC, "Sfx\\Misc\\LMag.wav", NULL }, #endif #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Bmaid01.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid02.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid03.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid04.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid05.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid06.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid07.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid08.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid09.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid10.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid11.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid12.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid13.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid14.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid15.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid16.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid17.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid18.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid19.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid20.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid21.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid22.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid23.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid24.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid25.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid26.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid27.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid28.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid29.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid30.wav", NULL }, #endif { sfx_STREAM, "Sfx\\Towners\\Bmaid31.wav", NULL }, #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Bmaid32.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid33.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid34.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid35.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid36.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid37.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid38.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid39.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bmaid40.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith01.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith02.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith03.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith04.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith05.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith06.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith07.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith08.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith09.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith10.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith11.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith12.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith13.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith14.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith15.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith16.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith17.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith18.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith19.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith20.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith21.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith22.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith23.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith24.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith25.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith26.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith27.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith28.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith29.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith30.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith31.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith32.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith33.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith34.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith35.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith36.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith37.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith38.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith39.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith40.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith41.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith42.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith43.wav", NULL }, #endif { sfx_STREAM, "Sfx\\Towners\\Bsmith44.wav", NULL }, #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Bsmith45.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith46.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith47.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith48.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith49.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith50.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith51.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith52.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith53.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith54.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith55.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Bsmith56.wav", NULL }, #endif { 0, "Sfx\\Towners\\Cow1.wav", NULL }, { 0, "Sfx\\Towners\\Cow2.wav", NULL }, #ifdef HELLFIRE { 0, "Sfx\\Towners\\Cow7.wav", NULL }, { 0, "Sfx\\Towners\\Cow8.wav", NULL }, #endif #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Deadguy2.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk01.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk02.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk03.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk04.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk05.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk06.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk07.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk08.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk09.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk10.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk11.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk12.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk13.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk14.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk15.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk16.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk17.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk18.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk19.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk20.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk21.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk22.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk23.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk24.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk25.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk26.wav", NULL }, #endif { sfx_STREAM, "Sfx\\Towners\\Drunk27.wav", NULL }, #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Drunk28.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk29.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk30.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk31.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk32.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk33.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk34.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Drunk35.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer01.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer02.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer03.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer04.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer05.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer06.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer07.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer08.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer09.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer10.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer11.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer12.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer13.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer14.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer15.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer16.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer17.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer18.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer19.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer20.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer21.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer22.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer23.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer24.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer25.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer26.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer27.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer28.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer29.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer30.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer31.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer32.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer33.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer34.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer35.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer36.wav", NULL }, #endif { sfx_STREAM, "Sfx\\Towners\\Healer37.wav", NULL }, #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Healer38.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer39.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer40.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer41.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer42.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer43.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer44.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer45.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer46.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Healer47.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy01.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy02.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy03.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy04.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy05.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy06.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy07.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy08.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy09.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy10.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy11.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy12.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy13.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy14.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy15.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy16.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy17.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy18.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy19.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy20.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy21.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy22.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy23.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy24.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy25.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy26.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy27.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy28.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy29.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy30.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy31.wav", NULL }, #endif { sfx_STREAM, "Sfx\\Towners\\Pegboy32.wav", NULL }, #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Pegboy33.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy34.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy35.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy36.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy37.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy38.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy39.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy40.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy41.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy42.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Pegboy43.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Priest00.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Priest01.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Priest02.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Priest03.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Priest04.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Priest05.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Priest06.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Priest07.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt00.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt01.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt02.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt03.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt04.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt05.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt06.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt07.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt08.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt09.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt10.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt11.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt12.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt13.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt14.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt15.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt16.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt17.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt18.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt19.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt20.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt21.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt22.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt23.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt24.wav", NULL }, #endif { sfx_STREAM, "Sfx\\Towners\\Storyt25.wav", NULL }, #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Storyt26.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt27.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt28.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt29.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt30.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt31.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt32.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt33.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt34.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt35.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt36.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt37.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Storyt38.wav", NULL }, #endif { sfx_STREAM, "Sfx\\Towners\\Tavown00.wav", NULL }, #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Tavown01.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown02.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown03.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown04.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown05.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown06.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown07.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown08.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown09.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown10.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown11.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown12.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown13.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown14.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown15.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown16.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown17.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown18.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown19.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown20.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown21.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown22.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown23.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown24.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown25.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown26.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown27.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown28.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown29.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown30.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown31.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown32.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown33.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown34.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown35.wav", NULL }, #endif { sfx_STREAM, "Sfx\\Towners\\Tavown36.wav", NULL }, #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Tavown37.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown38.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown39.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown40.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown41.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown42.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown43.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown44.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Tavown45.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch01.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch02.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch03.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch04.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch05.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch06.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch07.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch08.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch09.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch10.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch11.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch12.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch13.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch14.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch15.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch16.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch17.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch18.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch19.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch20.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch21.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch22.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch23.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch24.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch25.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch26.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch27.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch28.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch29.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch30.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch31.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch32.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch33.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch34.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch35.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch36.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch37.wav", NULL }, #endif { sfx_STREAM, "Sfx\\Towners\\Witch38.wav", NULL }, #ifndef SPAWN { sfx_STREAM, "Sfx\\Towners\\Witch39.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch40.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch41.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch42.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch43.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch44.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch45.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch46.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch47.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch48.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch49.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Witch50.wav", NULL }, { sfx_STREAM, "Sfx\\Towners\\Wound01.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage01.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage02.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage03.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage04.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage05.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage06.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage07.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage08.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage09.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage10.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage11.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage12.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage13.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage14.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage15.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage16.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage17.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage18.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage19.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage20.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage21.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage22.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage23.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage24.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage25.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage26.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage27.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage28.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage29.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage30.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage31.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage32.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage33.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage34.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage35.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage36.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage37.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage38.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage39.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage40.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage41.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage42.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage43.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage44.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage45.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage46.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage47.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage48.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage49.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage50.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage51.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage52.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage53.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage54.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage55.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage56.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage57.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage58.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage59.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage60.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage61.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage62.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage63.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage64.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage65.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage66.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage67.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage68.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage69.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage69b.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage70.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage71.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage72.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage73.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage74.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage75.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage76.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage77.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage78.wav", NULL }, { sfx_SORCEROR, "Sfx\\Sorceror\\Mage79.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage80.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage81.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage82.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage83.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage84.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage85.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage86.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage87.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage88.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage89.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage90.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage91.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage92.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage93.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage94.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage95.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage96.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage97.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage98.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage99.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage100.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage101.wav", NULL }, { sfx_STREAM | sfx_SORCEROR, "Sfx\\Sorceror\\Mage102.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue01.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue02.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue03.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue04.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue05.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue06.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue07.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue08.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue09.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue10.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue11.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue12.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue13.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue14.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue15.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue16.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue17.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue18.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue19.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue20.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue21.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue22.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue23.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue24.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue25.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue26.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue27.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue28.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue29.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue30.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue31.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue32.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue33.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue34.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue35.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue36.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue37.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue38.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue39.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue40.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue41.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue42.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue43.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue44.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue45.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue46.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue47.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue48.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue49.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue50.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue51.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue52.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue53.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue54.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue55.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue56.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue57.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue58.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue59.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue60.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue61.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue62.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue63.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue64.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue65.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue66.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue67.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue68.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue69.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue69b.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue70.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue71.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue72.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue73.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue74.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue75.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue76.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue77.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue78.wav", NULL }, { sfx_ROGUE, "Sfx\\Rogue\\Rogue79.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue80.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue81.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue82.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue83.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue84.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue85.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue86.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue87.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue88.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue89.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue90.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue91.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue92.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue93.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue94.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue95.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue96.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue97.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue98.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue99.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue100.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue101.wav", NULL }, { sfx_STREAM | sfx_ROGUE, "Sfx\\Rogue\\Rogue102.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior01.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior02.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior03.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior04.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior05.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior06.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior07.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior08.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior09.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior10.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior11.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior12.wav", NULL }, #endif { sfx_WARRIOR, "Sfx\\Warrior\\Warior13.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior14.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Wario14b.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Wario14c.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior15.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Wario15b.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Wario15c.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior16.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Wario16b.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Wario16c.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior17.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior18.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior19.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior20.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior21.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior22.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior23.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior24.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior25.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior26.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior27.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior28.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior29.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior30.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior31.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior32.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior33.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior34.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior35.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior36.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior37.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior38.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior39.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior40.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior41.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior42.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior43.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior44.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior45.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior46.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior47.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior48.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior49.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior50.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior51.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior52.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior53.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior54.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior55.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior56.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior57.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior58.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior59.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior60.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior61.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior62.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior63.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior64.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior65.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior66.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior67.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior68.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior69.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Wario69b.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior70.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior71.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior72.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior73.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior74.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior75.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior76.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior77.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior78.wav", NULL }, { sfx_WARRIOR, "Sfx\\Warrior\\Warior79.wav", NULL }, #ifndef SPAWN { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior80.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior81.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior82.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior83.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior84.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior85.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior86.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior87.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior88.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior89.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior90.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior91.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior92.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior93.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior94.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior95.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario95b.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario95c.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario95d.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario95e.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario95f.wav", NULL }, #endif { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario96b.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario97.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario98.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Warior99.wav", NULL }, #ifndef SPAWN { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario100.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario101.wav", NULL }, { sfx_STREAM | sfx_WARRIOR, "Sfx\\Warrior\\Wario102.wav", NULL }, #endif #ifdef HELLFIRE { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk01.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk08.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk09.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk10.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk11.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk12.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk13.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk14.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk15.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk16.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk24.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk27.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk29.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk34.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk35.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk43.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk46.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk49.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk50.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk52.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk54.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk55.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk56.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk61.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk62.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk68.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk69.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk69b.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk70.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk71.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_MONK, "Sfx\\Monk\\Monk79.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk80.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk82.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk83.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk87.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk88.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk89.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk91.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk92.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk94.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk95.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk96.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk97.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk98.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Monk\\Monk99.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, { sfx_STREAM | sfx_MONK, "Sfx\\Misc\\blank.wav", NULL }, #endif #ifndef SPAWN { sfx_STREAM, "Sfx\\Narrator\\Nar01.wav", NULL }, { sfx_STREAM, "Sfx\\Narrator\\Nar02.wav", NULL }, { sfx_STREAM, "Sfx\\Narrator\\Nar03.wav", NULL }, { sfx_STREAM, "Sfx\\Narrator\\Nar04.wav", NULL }, { sfx_STREAM, "Sfx\\Narrator\\Nar05.wav", NULL }, { sfx_STREAM, "Sfx\\Narrator\\Nar06.wav", NULL }, { sfx_STREAM, "Sfx\\Narrator\\Nar07.wav", NULL }, { sfx_STREAM, "Sfx\\Narrator\\Nar08.wav", NULL }, { sfx_STREAM, "Sfx\\Narrator\\Nar09.wav", NULL }, { sfx_STREAM, "Sfx\\Misc\\Lvl16int.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Butcher.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Garbud01.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Garbud02.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Garbud03.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Garbud04.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Izual01.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Lach01.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Lach02.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Lach03.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Laz01.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Laz02.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Sking01.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Snot01.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Snot02.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Snot03.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Warlrd01.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Wlock01.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Zhar01.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\Zhar02.wav", NULL }, { sfx_STREAM, "Sfx\\Monsters\\DiabloD.wav", NULL }, #endif #ifdef HELLFIRE { sfx_STREAM, "Sfx\\Hellfire\\Farmer1.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Farmer2.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Farmer2A.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Farmer3.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Farmer4.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Farmer5.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Farmer6.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Farmer7.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Farmer8.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Farmer9.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\TEDDYBR1.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\TEDDYBR2.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\TEDDYBR3.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\TEDDYBR4.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\DEFILER1.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\DEFILER2.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\DEFILER3.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\DEFILER4.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\DEFILER8.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\DEFILER6.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\DEFILER7.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\NAKRUL1.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\NAKRUL2.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\NAKRUL3.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\NAKRUL4.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\NAKRUL5.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\NAKRUL6.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\NARATR3.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT1.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT2.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT3.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT4.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT4A.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT5.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT6.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT7.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT8.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT9.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT10.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT11.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\COWSUT12.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Skljrn1.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Naratr6.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Naratr7.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Naratr8.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Naratr5.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Naratr9.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\Naratr4.wav", NULL }, { sfx_STREAM, "Sfx\\Hellfire\\TRADER1.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Cropen.wav", NULL }, { sfx_MISC, "Sfx\\Items\\Crclos.wav", NULL }, #endif // clang-format on }; #ifdef HELLFIRE #define PLRSFXS (sfx_WARRIOR | sfx_ROGUE | sfx_SORCEROR | sfx_MONK) #else #define PLRSFXS (sfx_WARRIOR | sfx_ROGUE | sfx_SORCEROR) #endif BOOL effect_is_playing(int nSFX) { TSFX *sfx = &sgSFX[nSFX]; if (sfx->pSnd) return snd_playing(sfx->pSnd); if (sfx->bFlags & sfx_STREAM) return sfx == sgpStreamSFX; return FALSE; } void stream_stop() { if (sghStream) { SFileDdaEnd(sghStream); SFileCloseFile(sghStream); sghStream = NULL; sgpStreamSFX = NULL; } } static void stream_play(TSFX *pSFX, int lVolume, int lPan) { BOOL success; assert(pSFX); assert(pSFX->bFlags & sfx_STREAM); stream_stop(); lVolume += sound_get_or_set_sound_volume(1); if (lVolume >= VOLUME_MIN) { if (lVolume > VOLUME_MAX) lVolume = VOLUME_MAX; #ifdef _DEBUG SFileEnableDirectAccess(FALSE); #endif success = SFileOpenFile(pSFX->pszName, &sghStream); #ifdef _DEBUG SFileEnableDirectAccess(TRUE); #endif if (!success) { sghStream = NULL; } else { if (!SFileDdaBeginEx(sghStream, 0x40000, 0, 0, lVolume, lPan, 0)) stream_stop(); else sgpStreamSFX = pSFX; } } } static void stream_update() { DWORD current, end; if (sghStream != NULL && SFileDdaGetPos(sghStream, ¤t, &end) && current >= end) { stream_stop(); } } static void sfx_stop() { int i; TSFX *snd; snd = &sgSFX[0]; for (i = 0; i < sizeof(sgSFX) / sizeof(TSFX); i++) { if (snd->pSnd) snd_stop_snd(snd->pSnd); snd++; } } void InitMonsterSND(int monst) { TSnd *pSnd; char name[MAX_PATH]; char *path; int mtype, i, j; if (!gbSndInited) { return; } mtype = Monsters[monst].mtype; for (i = 0; i < 4; i++) { if (MonstSndChar[i] != 's' || monsterdata[mtype].snd_special) { for (j = 0; j < 2; j++) { sprintf(name, monsterdata[mtype].sndfile, MonstSndChar[i], j + 1); path = (char *)DiabloAllocPtr(strlen(name) + 1); strcpy(path, name); pSnd = sound_file_load(path); Monsters[monst].Snds[i][j] = pSnd; if (!pSnd) mem_free_dbg(path); } } } } void FreeMonsterSnd() { int mtype, i, j, k; const char *file; TSnd *pSnd; for (i = 0; i < nummtypes; i++) { mtype = Monsters[i].mtype; for (j = 0; j < 4; ++j) { for (k = 0; k < 2; ++k) { pSnd = Monsters[i].Snds[j][k]; if (pSnd) { Monsters[i].Snds[j][k] = NULL; file = pSnd->sound_path; pSnd->sound_path = NULL; sound_file_cleanup(pSnd); // pSnd->sound_path is malloc'd (but only for monsters). mem_free_dbg(const_cast(file)); } } } } } static BOOL calc_snd_position(int x, int y, int *plVolume, int *plPan) { int pan, volume; x -= plr[myplr]._px; y -= plr[myplr]._py; pan = (x - y) * 256; *plPan = pan; if (abs(pan) > 6400) return FALSE; volume = abs(x) > abs(y) ? abs(x) : abs(y); volume *= 64; *plVolume = volume; if (volume >= 6400) return FALSE; *plVolume = -volume; return TRUE; } static void PlaySFX_priv(TSFX *pSFX, BOOL loc, int x, int y) { int lPan, lVolume; if (plr[myplr].pLvlLoad && gbMaxPlayers != 1) { return; } if (!gbSndInited || !gbSoundOn || gbBufferMsgs) { return; } if (!(pSFX->bFlags & (sfx_STREAM | sfx_MISC)) && pSFX->pSnd != 0 && snd_playing(pSFX->pSnd)) { return; } lPan = 0; lVolume = 0; if (loc && !calc_snd_position(x, y, &lVolume, &lPan)) { return; } if (pSFX->bFlags & sfx_STREAM) { stream_play(pSFX, lVolume, lPan); return; } if (!pSFX->pSnd) pSFX->pSnd = sound_file_load(pSFX->pszName); if (pSFX->pSnd) snd_play_snd(pSFX->pSnd, lVolume, lPan); } void PlayEffect(int i, int mode) { int sndIdx, mi, lVolume, lPan; TSnd *snd; if (plr[myplr].pLvlLoad) { return; } sndIdx = random_(164, 2); if (!gbSndInited || !gbSoundOn || gbBufferMsgs) { return; } mi = monster[i]._mMTidx; snd = Monsters[mi].Snds[mode][sndIdx]; if (!snd || snd_playing(snd)) { return; } if (!calc_snd_position(monster[i]._mx, monster[i]._my, &lVolume, &lPan)) return; snd_play_snd(snd, lVolume, lPan); } static int RndSFX(int psfx) { int nRand; if (psfx == PS_WARR69) nRand = 2; else if (psfx == PS_WARR14) nRand = 3; else if (psfx == PS_WARR15) nRand = 3; else if (psfx == PS_WARR16) nRand = 3; #ifndef SPAWN else if (psfx == PS_MAGE69) nRand = 2; else if (psfx == PS_ROGUE69) nRand = 2; #endif #ifdef HELLFIRE else if (psfx == PS_MONK69) nRand = 2; #endif else if (psfx == PS_SWING) nRand = 2; else if (psfx == LS_ACID) nRand = 2; else if (psfx == IS_FMAG) nRand = 2; else if (psfx == IS_MAGIC) nRand = 2; else if (psfx == IS_BHIT) nRand = 2; #ifndef SPAWN else if (psfx == PS_WARR2) nRand = 3; #endif else return psfx; return psfx + random_(165, nRand); } void PlaySFX(int psfx) { psfx = RndSFX(psfx); PlaySFX_priv(&sgSFX[psfx], FALSE, 0, 0); } void PlaySfxLoc(int psfx, int x, int y) { TSnd *pSnd; psfx = RndSFX(psfx); if (psfx >= 0 && psfx <= 3) { pSnd = sgSFX[psfx].pSnd; if (pSnd) pSnd->start_tc = 0; } PlaySFX_priv(&sgSFX[psfx], TRUE, x, y); } void sound_stop() { int i, j, k; snd_update(TRUE); stream_stop(); sfx_stop(); for (i = 0; i < nummtypes; i++) { for (j = 0; j < 4; j++) { for (k = 0; k < 2; k++) { snd_stop_snd(Monsters[i].Snds[j][k]); } } } } void sound_update() { if (!gbSndInited) { return; } snd_update(FALSE); stream_update(); } void effects_cleanup_sfx() { DWORD i; sound_stop(); for (i = 0; i < sizeof(sgSFX) / sizeof(TSFX); i++) { if (sgSFX[i].pSnd) { sound_file_cleanup(sgSFX[i].pSnd); sgSFX[i].pSnd = NULL; } } } static void priv_sound_init(BYTE bLoadMask) { BYTE pc; DWORD i; if (!gbSndInited) { return; } pc = bLoadMask & PLRSFXS; bLoadMask ^= pc; for (i = 0; i < sizeof(sgSFX) / sizeof(TSFX); i++) { if (sgSFX[i].pSnd) { continue; } if (sgSFX[i].bFlags & sfx_STREAM) { continue; } if (bLoadMask && !(sgSFX[i].bFlags & bLoadMask)) { continue; } if (sgSFX[i].bFlags & PLRSFXS && !(sgSFX[i].bFlags & pc)) { continue; } sgSFX[i].pSnd = sound_file_load(sgSFX[i].pszName); } } void sound_init() { BYTE mask = 0; if (gbMaxPlayers > 1) { mask = PLRSFXS; } else if (plr[myplr]._pClass == PC_WARRIOR) { mask = sfx_WARRIOR; } else if (plr[myplr]._pClass == PC_ROGUE) { mask = sfx_ROGUE; } else if (plr[myplr]._pClass == PC_SORCERER) { mask = sfx_SORCEROR; #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { mask = sfx_MONK; } else if (plr[myplr]._pClass == PC_BARD) { mask = sfx_ROGUE; } else if (plr[myplr]._pClass == PC_BARBARIAN) { mask = sfx_WARRIOR; #endif } else { app_fatal("effects:1"); } priv_sound_init(mask); } void ui_sound_init() { priv_sound_init(sfx_UI); } void __stdcall effects_play_sound(const char *snd_file) { DWORD i; if (!gbSndInited || !gbSoundOn) { return; } for (i = 0; i < sizeof(sgSFX) / sizeof(TSFX); i++) { if (!_strcmpi(sgSFX[i].pszName, snd_file) && sgSFX[i].pSnd) { if (!snd_playing(sgSFX[i].pSnd)) snd_play_snd(sgSFX[i].pSnd, 0, 0); return; } } } ================================================ FILE: Source/effects.h ================================================ /** * @file effects.h * * Interface of functions for loading and playing sounds. */ #ifndef __EFFECTS_H__ #define __EFFECTS_H__ extern int sfxdelay; extern int sfxdnum; BOOL effect_is_playing(int nSFX); void stream_stop(); void InitMonsterSND(int monst); void FreeMonsterSnd(); void PlayEffect(int i, int mode); void PlaySFX(int psfx); void PlaySfxLoc(int psfx, int x, int y); void sound_stop(); void sound_update(); void effects_cleanup_sfx(); void sound_init(); void ui_sound_init(); void __stdcall effects_play_sound(const char *snd_file); #endif /* __EFFECTS_H__ */ ================================================ FILE: Source/encrypt.cpp ================================================ /** * @file encrypt.cpp * * Implementation of functions for compression and decompressing MPQ data. */ #include "all.h" #include "../3rdParty/PKWare/pkware.h" DWORD hashtable[5][256]; void Decrypt(DWORD *castBlock, DWORD size, DWORD key) { DWORD seed, i; seed = 0xEEEEEEEE; i = size >> 2; while (i--) { seed += hashtable[4][(key & 0xFF)]; *castBlock ^= seed + key; seed += *castBlock + (seed << 5) + 3; castBlock++; key = (((key << 0x15) ^ 0xFFE00000) + 0x11111111) | (key >> 0x0B); } } void Encrypt(DWORD *castBlock, DWORD size, DWORD key) { DWORD seed, i, ch; seed = 0xEEEEEEEE; i = size >> 2; while (i--) { ch = *castBlock; seed += hashtable[4][(key & 0xFF)]; *castBlock ^= seed + key; castBlock++; seed += ch + (seed << 5) + 3; key = ((key << 0x15) ^ 0xFFE00000) + 0x11111111 | (key >> 0x0B); } } DWORD Hash(const char *s, int type) { char ch; DWORD seed1, seed2; seed1 = 0x7FED7FED; seed2 = 0xEEEEEEEE; while (s != NULL && *s) { ch = *s++; ch = toupper(ch); seed1 = hashtable[type][ch] ^ (seed1 + seed2); seed2 += ch + seed1 + (seed2 << 5) + 3; } return seed1; } void InitHash() { DWORD seed, ch; int i, j; seed = 0x00100001; for (i = 0; i < 256; i++) { for (j = 0; j < 5; j++) { seed = (125 * seed + 3) % 0x2AAAAB; ch = (seed & 0xFFFF); seed = (125 * seed + 3) % 0x2AAAAB; hashtable[j][i] = ch << 16 | (seed & 0xFFFF); } } } static unsigned int __cdecl PkwareBufferRead(char *buf, unsigned int *size, void *param) { TDataInfo *pInfo; DWORD sSize; pInfo = (TDataInfo *)param; if (*size >= pInfo->size - pInfo->srcOffset) { sSize = pInfo->size - pInfo->srcOffset; } else { sSize = *size; } memcpy(buf, pInfo->srcData + pInfo->srcOffset, sSize); pInfo->srcOffset += sSize; return sSize; } static void __cdecl PkwareBufferWrite(char *buf, unsigned int *size, void *param) { TDataInfo *pInfo; pInfo = (TDataInfo *)param; memcpy(pInfo->destData + pInfo->destOffset, buf, *size); pInfo->destOffset += *size; } int PkwareCompress(BYTE *srcData, int size) { BYTE *destData; char *ptr; unsigned int destSize, type, dsize; TDataInfo param; ptr = (char *)DiabloAllocPtr(CMP_BUFFER_SIZE); destSize = 2 * size; if (destSize < 2 * 4096) destSize = 2 * 4096; destData = (BYTE *)DiabloAllocPtr(destSize); param.srcData = srcData; param.srcOffset = 0; param.destData = destData; param.destOffset = 0; param.size = size; type = 0; dsize = 4096; implode(PkwareBufferRead, PkwareBufferWrite, ptr, ¶m, &type, &dsize); if (param.destOffset < size) { memcpy(srcData, destData, param.destOffset); size = param.destOffset; } mem_free_dbg(ptr); mem_free_dbg(destData); return size; } void PkwareDecompress(BYTE *pbInBuff, int recv_size, int dwMaxBytes) { char *ptr; BYTE *pbOutBuff; TDataInfo info; ptr = (char *)DiabloAllocPtr(CMP_BUFFER_SIZE); pbOutBuff = DiabloAllocPtr(dwMaxBytes); info.srcData = pbInBuff; info.srcOffset = 0; info.destData = pbOutBuff; info.destOffset = 0; info.size = recv_size; explode(PkwareBufferRead, PkwareBufferWrite, ptr, &info); memcpy(pbInBuff, pbOutBuff, info.destOffset); mem_free_dbg(ptr); mem_free_dbg(pbOutBuff); } ================================================ FILE: Source/encrypt.h ================================================ /** * @file encrypt.h * * Interface of functions for compression and decompressing MPQ data. */ #ifndef __ENCRYPT_H__ #define __ENCRYPT_H__ void Decrypt(DWORD *castBlock, DWORD size, DWORD key); void Encrypt(DWORD *castBlock, DWORD size, DWORD key); DWORD Hash(const char *s, int type); void InitHash(); int PkwareCompress(BYTE *srcData, int size); void PkwareDecompress(BYTE *pbInBuff, int recv_size, int dwMaxBytes); #endif /* __ENCRYPT_H__ */ ================================================ FILE: Source/engine.cpp ================================================ /** * @file engine.cpp * * Implementation of basic engine helper functions: * - Sprite blitting * - Drawing * - Angle calculation * - RNG * - Memory allocation * - File loading * - Video playback */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" #ifdef USE_ASM #pragma warning(disable : 4731) // frame pointer register 'ebp' modified by inline assembly code #endif /** automap pixel color 8-bit (palette entry) */ char gbPixelCol; /** flip - if y < x */ BOOL gbRotateMap; /** Seed value before the most recent call to SetRndSeed() */ int orgseed; /** Width of sprite being blitted */ int sgnWidth; /** Current game seed */ int sglGameSeed; static CCritSect sgMemCrit; /** Number of times the current seed has been fetched */ int SeedCount; /** valid - if x/y are in bounds */ BOOL gbNotInView; /** * Specifies the increment used in the Borland C/C++ pseudo-random. */ const int RndInc = 1; /** * Specifies the multiplier used in the Borland C/C++ pseudo-random number generator algorithm. */ const int RndMult = 0x015A4E35; /** * @brief Find the start of a CEL frame * @param pCelBuff Cel data * @param nCel CEL frame number * @param nDataSize Will be set to frame size */ __FINLINE BYTE *CelGetFrame(BYTE *pCelBuff, int nCel, int *nDataSize) { DWORD *pFrameTable; DWORD nCellStart; pFrameTable = (DWORD *)pCelBuff; nCellStart = SwapLE32(pFrameTable[nCel]); *nDataSize = SwapLE32(pFrameTable[nCel + 1]) - nCellStart; return pCelBuff + nCellStart; } /** * @brief Calculate the size of a CEL frame * @param pCelBuff Cel data * @param nCel CEL frame number * @return Size of CEL in bytes */ __FINLINE int CelGetFrameSize(BYTE *pCelBuff, int nCel) { DWORD *pFrameTable; pFrameTable = (DWORD *)pCelBuff; return SwapLE32(pFrameTable[nCel + 1]) - SwapLE32(pFrameTable[nCel]); } /** * @brief Blit CEL sprite to the given buffer * @param pDecodeTo The output buffer * @param pRLEBytes CEL pixel stream (run-length encoded) * @param nDataSize Size of CEL in bytes * @param nWidth Width of sprite */ void CelBlit(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; assert(pDecodeTo != NULL); if (pDecodeTo == NULL) return; assert(pRLEBytes != NULL); if (pRLEBytes == NULL) return; #ifdef USE_ASM __asm { mov esi, pRLEBytes mov edi, pDecodeTo mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label6 sub edx, eax mov ecx, eax shr ecx, 1 jnb label3 movsb jecxz label5 label3: shr ecx, 1 jnb label4 movsw jecxz label5 label4: rep movsd label5: or edx, edx jz label7 jmp label2 label6: neg al add edi, eax sub edx, eax jnz label2 label7: sub edi, w cmp ebx, esi jnz label1 } #else int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (width & 1) { dst[0] = src[0]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = src[0]; dst[1] = src[1]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; src += 4; dst += 4; } } else { width = -(char)width; dst += width; i -= width; } } } #endif } /** * @brief Blit CEL sprite to the back buffer at the given coordinates * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of sprite */ void CelDraw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth) { int nDataSize; BYTE *pRLEBytes; assert(gpBuffer); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; pRLEBytes = CelGetFrame(pCelBuff, nCel, &nDataSize); CelBlit(&gpBuffer[sx + PitchTbl[sy]], pRLEBytes, nDataSize, nWidth); } /** * @brief Blit a given CEL frame to the given buffer * @param pBuff Target buffer * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of sprite */ void CelBlitFrame(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth) { int nDataSize; BYTE *pRLEBytes; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(pBuff != NULL); if (pBuff == NULL) return; pRLEBytes = CelGetFrame(pCelBuff, nCel, &nDataSize); CelBlit(pBuff, pRLEBytes, nDataSize, nWidth); } /** * @brief Same as CelDraw but with the option to skip parts of the top and bottom of the sprite * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelClippedDraw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize, nDataCap; assert(gpBuffer); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; CelBlit( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize, nWidth); } /** * @brief Same as CelBlit but with the option to skip parts of the top and bottom of the sprite * @param pBuff Target buffer * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelClippedBlit(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize, nDataCap; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(pBuff != NULL); if (pBuff == NULL) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; CelBlit(pBuff, pRLEBytes + nDataStart, nDataSize, nWidth); } /** * @brief Blit CEL sprite, and apply lighting, to the given buffer * @param pDecodeTo The output buffer * @param pRLEBytes CEL pixel stream (run-length encoded) * @param nDataSize Size of CEL in bytes * @param nWidth Width of sprite */ void CelBlitLight(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; BYTE *tbl; assert(pDecodeTo != NULL); if (pDecodeTo == NULL) return; assert(pRLEBytes != NULL); if (pRLEBytes == NULL) return; #ifdef USE_ASM __asm { mov eax, light_table_index shl eax, 8 add eax, pLightTbl mov tbl, eax mov esi, pRLEBytes mov edi, pDecodeTo mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label3 push ebx mov ebx, tbl sub edx, eax mov ecx, eax push edx call CelBlitLightEntry pop edx pop ebx or edx, edx jnz label2 jmp label4 label3: neg al add edi, eax sub edx, eax jnz label2 label4: sub edi, w cmp ebx, esi jnz label1 jmp labexit } /* Assembly Macro */ // clang-format off __asm { CelBlitLightEntry: shr cl, 1 jnb label5 mov dl, [esi] mov dl, [ebx+edx] mov [edi], dl add esi, 1 add edi, 1 label5: shr cl, 1 jnb label6 mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 label6: test cl, cl jz labret label7: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 dec cl jnz label7 labret: retn } // clang-format on __asm { labexit: } #else int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; tbl = &pLightTbl[light_table_index * 256]; w = nWidth; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (width & 1) { dst[0] = tbl[src[0]]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = tbl[src[0]]; dst[1] = tbl[src[1]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = tbl[src[0]]; dst[1] = tbl[src[1]]; dst[2] = tbl[src[2]]; dst[3] = tbl[src[3]]; src += 4; dst += 4; } } else { width = -(char)width; dst += width; i -= width; } } } #endif } /** * @brief Blit CEL sprite, and apply lighting, to the given buffer, with transparancy applied * @param pDecodeTo The output buffer * @param pRLEBytes CEL pixel stream (run-length encoded) * @param nDataSize Size of CEL in bytes * @param nWidth Width of sprite */ void CelBlitLightTrans(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; BOOL shift; BYTE *tbl; assert(pDecodeTo != NULL); if (pDecodeTo == NULL) return; assert(pRLEBytes != NULL); if (pRLEBytes == NULL) return; #ifdef USE_ASM __asm { mov eax, light_table_index shl eax, 8 add eax, pLightTbl mov tbl, eax mov esi, pRLEBytes mov edi, pDecodeTo mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi mov eax, edi and eax, 1 mov shift, eax label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label9 push ebx mov ebx, tbl sub edx, eax mov ecx, eax mov eax, edi and eax, 1 cmp eax, shift jnz label5 shr ecx, 1 jnb label3 inc esi inc edi jecxz label8 jmp label6 label3: shr ecx, 1 jnb label4 inc esi inc edi lodsb xlat stosb jecxz label8 label4: lodsd inc edi ror eax, 8 xlat stosb ror eax, 10h inc edi xlat stosb loop label4 jmp label8 label5: shr ecx, 1 jnb label6 lodsb xlat stosb jecxz label8 jmp label3 label6: shr ecx, 1 jnb label7 lodsb xlat stosb inc esi inc edi jecxz label8 label7: lodsd xlat stosb inc edi ror eax, 10h xlat stosb inc edi loop label7 label8: pop ebx or edx, edx jz label10 jmp label2 label9: neg al add edi, eax sub edx, eax jnz label2 label10: sub edi, w mov eax, shift inc eax and eax, 1 mov shift, eax cmp ebx, esi jnz label1 } #else int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; tbl = &pLightTbl[light_table_index * 256]; w = nWidth; shift = (BYTE)dst & 1; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w, shift = (shift + 1) & 1) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (((BYTE)dst & 1) == shift) { if (!(width & 1)) { goto L_ODD; } else { src++; dst++; L_EVEN: width >>= 1; if (width & 1) { dst[0] = tbl[src[0]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = tbl[src[0]]; dst[2] = tbl[src[2]]; src += 4; dst += 4; } } } else { if (!(width & 1)) { goto L_EVEN; } else { dst[0] = tbl[src[0]]; src++; dst++; L_ODD: width >>= 1; if (width & 1) { dst[1] = tbl[src[1]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[1] = tbl[src[1]]; dst[3] = tbl[src[3]]; src += 4; dst += 4; } } } } else { width = -(char)width; dst += width; i -= width; } } } #endif } /** * @brief Blit CEL sprite, and apply lighting, to the back buffer at the given coordinates * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of sprite */ void CelDrawLight(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth) { int nDataSize; BYTE *pDecodeTo, *pRLEBytes; assert(gpBuffer); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; pRLEBytes = CelGetFrame(pCelBuff, nCel, &nDataSize); pDecodeTo = &gpBuffer[sx + PitchTbl[sy]]; if (light_table_index) CelBlitLight(pDecodeTo, pRLEBytes, nDataSize, nWidth); else CelBlit(pDecodeTo, pRLEBytes, nDataSize, nWidth); } /** * @brief Same as CelDrawLight but with the option to skip parts of the top and bottom of the sprite * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelClippedDrawLight(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; assert(gpBuffer); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; if (light_table_index) CelBlitLight(pDecodeTo, pRLEBytes, nDataSize, nWidth); else CelBlit(pDecodeTo, pRLEBytes, nDataSize, nWidth); } /** * @brief Same as CelBlitLightTrans but with the option to skip parts of the top and bottom of the sprite * @param pBuff Target buffer * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelClippedBlitLightTrans(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes; DWORD *pFrameTable; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(pBuff != NULL); if (pBuff == NULL) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; if (cel_transparency_active) CelBlitLightTrans(pBuff, pRLEBytes, nDataSize, nWidth); else if (light_table_index) CelBlitLight(pBuff, pRLEBytes, nDataSize, nWidth); else CelBlit(pBuff, pRLEBytes, nDataSize, nWidth); } /** * @brief Blit CEL sprite, and apply lighting, to the back buffer at the given coordinates, translated to a red hue * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 * @param light Light shade to use */ void CelDrawLightRed(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light) { int nDataStart, nDataSize, nDataCap, w, idx; BYTE *pRLEBytes, *dst, *tbl; DWORD *pFrameTable; assert(gpBuffer); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; idx = light4flag ? 1024 : 4096; if (light == 2) idx += 256; // gray colors if (light >= 4) idx += (light - 1) << 8; #ifdef USE_ASM __asm { mov eax, pLightTbl add eax, idx mov tbl, eax mov esi, pRLEBytes mov edi, dst mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax /* use C for w? w = BUFFER_WIDTH + nWidth */ mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax mov al, [esi] inc esi test al, al js label4 push ebx mov ebx, tbl sub edx, eax mov ecx, eax label3: mov al, [esi] inc esi mov al, [ebx+eax] mov [edi], al dec ecx lea edi, [edi+1] jnz label3 pop ebx test edx, edx jz label5 jmp label2 label4: neg al add edi, eax sub edx, eax jnz label2 label5: sub edi, w cmp ebx, esi jnz label1 } #else BYTE width; BYTE *end; tbl = &pLightTbl[idx]; end = &pRLEBytes[nDataSize]; for (; pRLEBytes != end; dst -= BUFFER_WIDTH + nWidth) { for (w = nWidth; w;) { width = *pRLEBytes++; if (!(width & 0x80)) { w -= width; while (width) { *dst = tbl[*pRLEBytes]; pRLEBytes++; dst++; width--; } } else { width = -(char)width; dst += width; w -= width; } } } #endif } /** * @brief Same as CelBlit but checks for drawing outside the buffer * @param pDecodeTo The output buffer * @param pRLEBytes CEL pixel stream (run-length encoded) * @param nDataSize Size of CEL in bytes * @param nWidth Width of sprite */ void CelBlitSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; assert(pDecodeTo != NULL); if (pDecodeTo == NULL) return; assert(pRLEBytes != NULL); if (pRLEBytes == NULL) return; assert(gpBuffer); if (gpBuffer == NULL) return; #ifdef USE_ASM __asm { mov esi, pRLEBytes mov edi, pDecodeTo mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label7 sub edx, eax cmp edi, gpBufEnd jb label3 add esi, eax add edi, eax jmp label6 label3: mov ecx, eax shr ecx, 1 jnb label4 movsb jecxz label6 label4: shr ecx, 1 jnb label5 movsw jecxz label6 label5: rep movsd label6: or edx, edx jz label8 jmp label2 label7: neg al add edi, eax sub edx, eax jnz label2 label8: sub edi, w cmp ebx, esi jnz label1 } #else int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (dst < gpBufEnd) { if (width & 1) { dst[0] = src[0]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = src[0]; dst[1] = src[1]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; src += 4; dst += 4; } } else { src += width; dst += width; } } else { width = -(char)width; dst += width; i -= width; } } } #endif } /** * @brief Same as CelClippedDraw but checks for drawing outside the buffer * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelClippedDrawSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize, nDataCap; assert(gpBuffer); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; CelBlitSafe( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize, nWidth); } /** * @brief Same as CelClippedBlit but checks for drawing outside the buffer * @param pBuff Target buffer * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelClippedBlitSafe(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize, nDataCap; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(pBuff != NULL); if (pBuff == NULL) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; CelBlitSafe(pBuff, pRLEBytes + nDataStart, nDataSize, nWidth); } /** * @brief Same as CelBlitLight but checks for drawing outside the buffer * @param pDecodeTo The output buffer * @param pRLEBytes CEL pixel stream (run-length encoded) * @param nDataSize Size of CEL in bytes * @param nWidth Width of sprite */ void CelBlitLightSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; BYTE *tbl; assert(pDecodeTo != NULL); if (pDecodeTo == NULL) return; assert(pRLEBytes != NULL); if (pRLEBytes == NULL) return; assert(gpBuffer); if (gpBuffer == NULL) return; #ifdef USE_ASM __asm { mov eax, light_table_index shl eax, 8 add eax, pLightTbl mov tbl, eax mov esi, pRLEBytes mov edi, pDecodeTo mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label5 push ebx mov ebx, tbl sub edx, eax cmp edi, gpBufEnd jb label3 add esi, eax add edi, eax jmp label4 label3: mov ecx, eax push edx call Cel2DecDatLightEntry pop edx label4: pop ebx or edx, edx jz label6 jmp label2 label5: neg al add edi, eax sub edx, eax jnz label2 label6: sub edi, w cmp ebx, esi jnz label1 jmp labexit } /* Assembly Macro */ // clang-format off __asm { Cel2DecDatLightEntry: shr cl, 1 jnb label7 mov dl, [esi] mov dl, [ebx+edx] mov [edi], dl add esi, 1 add edi, 1 label7: shr cl, 1 jnb label8 mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 label8: test cl, cl jz labret label9: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 dec cl jnz label9 labret: retn } // clang-format on __asm { labexit: } #else int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; tbl = &pLightTbl[light_table_index * 256]; w = nWidth; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (dst < gpBufEnd) { if (width & 1) { dst[0] = tbl[src[0]]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = tbl[src[0]]; dst[1] = tbl[src[1]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = tbl[src[0]]; dst[1] = tbl[src[1]]; dst[2] = tbl[src[2]]; dst[3] = tbl[src[3]]; src += 4; dst += 4; } } else { src += width; dst += width; } } else { width = -(char)width; dst += width; i -= width; } } } #endif } /** * @brief Same as CelBlitLightTrans but checks for drawing outside the buffer * @param pDecodeTo The output buffer * @param pRLEBytes CEL pixel stream (run-length encoded) * @param nDataSize Size of CEL in bytes * @param nWidth Width of sprite */ void CelBlitLightTransSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; BOOL shift; BYTE *tbl; assert(pDecodeTo != NULL); if (pDecodeTo == NULL) return; assert(pRLEBytes != NULL); if (pRLEBytes == NULL) return; assert(gpBuffer); if (gpBuffer == NULL) return; #ifdef USE_ASM __asm { mov eax, light_table_index shl eax, 8 add eax, pLightTbl mov tbl, eax mov esi, pRLEBytes mov edi, pDecodeTo mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi mov eax, edi and eax, 1 mov shift, eax label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label10 push ebx mov ebx, tbl sub edx, eax cmp edi, gpBufEnd jb label3 add esi, eax add edi, eax jmp label9 label3: mov ecx, eax mov eax, edi and eax, 1 cmp eax, shift jnz label6 shr ecx, 1 jnb label4 inc esi inc edi jecxz label9 jmp label7 label4: shr ecx, 1 jnb label5 inc esi inc edi lodsb xlat stosb jecxz label9 label5: lodsd inc edi ror eax, 8 xlat stosb ror eax, 10h inc edi xlat stosb loop label5 jmp label9 label6: shr ecx, 1 jnb label7 lodsb xlat stosb jecxz label9 jmp label4 label7: shr ecx, 1 jnb label8 lodsb xlat stosb inc esi inc edi jecxz label9 label8: lodsd xlat stosb inc edi ror eax, 10h xlat stosb inc edi loop label8 label9: pop ebx or edx, edx jz label11 jmp label2 label10: neg al add edi, eax sub edx, eax jnz label2 label11: sub edi, w mov eax, shift inc eax and eax, 1 mov shift, eax cmp ebx, esi jnz label1 } #else int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; tbl = &pLightTbl[light_table_index * 256]; w = nWidth; shift = (BYTE)dst & 1; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w, shift = (shift + 1) & 1) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (dst < gpBufEnd) { if (((BYTE)dst & 1) == shift) { if (!(width & 1)) { goto L_ODD; } else { src++; dst++; L_EVEN: width >>= 1; if (width & 1) { dst[0] = tbl[src[0]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = tbl[src[0]]; dst[2] = tbl[src[2]]; src += 4; dst += 4; } } } else { if (!(width & 1)) { goto L_EVEN; } else { dst[0] = tbl[src[0]]; src++; dst++; L_ODD: width >>= 1; if (width & 1) { dst[1] = tbl[src[1]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[1] = tbl[src[1]]; dst[3] = tbl[src[3]]; src += 4; dst += 4; } } } } else { src += width; dst += width; } } else { width = -(char)width; dst += width; i -= width; } } } #endif } /** * @brief Same as CelDrawLight but checks for drawing outside the buffer * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of cel * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelDrawLightSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; assert(gpBuffer); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; if (light_table_index) CelBlitLightSafe(pDecodeTo, pRLEBytes, nDataSize, nWidth); else CelBlitSafe(pDecodeTo, pRLEBytes, nDataSize, nWidth); } /** * @brief Same as CelClippedBlitLightTrans but checks for drawing outside the buffer * @param pBuff Target buffer * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of cel * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelClippedBlitLightTransSafe(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes; DWORD *pFrameTable; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; if (cel_transparency_active) CelBlitLightTransSafe(pBuff, pRLEBytes, nDataSize, nWidth); else if (light_table_index) CelBlitLightSafe(pBuff, pRLEBytes, nDataSize, nWidth); else CelBlitSafe(pBuff, pRLEBytes, nDataSize, nWidth); } /** * @brief Same as CelDrawLightRed but checks for drawing outside the buffer * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of cel * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 * @param light Light shade to use */ void CelDrawLightRedSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light) { int nDataStart, nDataSize, nDataCap, w, idx; BYTE *pRLEBytes, *dst, *tbl; DWORD *pFrameTable; assert(gpBuffer); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; idx = light4flag ? 1024 : 4096; if (light == 2) idx += 256; // gray colors if (light >= 4) idx += (light - 1) << 8; tbl = &pLightTbl[idx]; #ifdef USE_ASM w = BUFFER_WIDTH + nWidth; __asm { mov esi, pRLEBytes mov edi, dst mov ecx, nDataSize add ecx, esi label1: push ecx mov edx, nWidth xor ecx, ecx label2: xor eax, eax mov al, [esi] inc esi test al, al js label5 mov ebx, tbl sub edx, eax cmp edi, gpBufEnd jb label3 add esi, eax add edi, eax jmp label4 label3: mov cl, [esi] inc esi mov cl, [ebx+ecx] mov [edi], cl dec eax lea edi, [edi+1] jnz label3 label4: test edx, edx jz label6 jmp label2 label5: neg al add edi, eax sub edx, eax jnz label2 label6: pop ecx sub edi, w cmp ecx, esi jnz label1 } #else BYTE width; BYTE *end; end = &pRLEBytes[nDataSize]; for (; pRLEBytes != end; dst -= BUFFER_WIDTH + nWidth) { for (w = nWidth; w;) { width = *pRLEBytes++; if (!(width & 0x80)) { w -= width; if (dst < gpBufEnd) { while (width) { *dst = tbl[*pRLEBytes]; pRLEBytes++; dst++; width--; } } else { pRLEBytes += width; dst += width; } } else { width = -(char)width; dst += width; w -= width; } } } #endif } /** * @brief Blit to a buffer at given coordinates * @param pBuff Target buffer * @param x Cordinate in pBuff buffer * @param y Cordinate in pBuff buffer * @param wdt Width of pBuff * @param pCelBuff Cel data * @param nCel CEL frame number * @param nWidth Width of cel */ void CelBlitWidth(BYTE *pBuff, int x, int y, int wdt, BYTE *pCelBuff, int nCel, int nWidth) { BYTE *pRLEBytes, *dst, *end; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(pBuff != NULL); if (pBuff == NULL) return; #ifdef USE_ASM __asm { mov ebx, pCelBuff mov eax, nCel shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov end, eax mov eax, pCelBuff add eax, [ebx] mov pRLEBytes, eax } dst = &pBuff[y * wdt + x]; __asm { mov esi, pRLEBytes mov edi, dst mov eax, wdt add eax, nWidth mov wdt, eax mov ebx, end add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label6 sub edx, eax mov ecx, eax shr ecx, 1 jnb label3 movsb jecxz label5 label3: shr ecx, 1 jnb label4 movsw jecxz label5 label4: rep movsd label5: or edx, edx jz label7 jmp label2 label6: neg al add edi, eax sub edx, eax jnz label2 label7: sub edi, wdt cmp ebx, esi jnz label1 } #else int i, nDataSize; BYTE width; pRLEBytes = CelGetFrame(pCelBuff, nCel, &nDataSize); end = &pRLEBytes[nDataSize]; dst = &pBuff[y * wdt + x]; for (; pRLEBytes != end; dst -= wdt + nWidth) { for (i = nWidth; i;) { width = *pRLEBytes++; if (!(width & 0x80)) { i -= width; if (width & 1) { dst[0] = pRLEBytes[0]; pRLEBytes++; dst++; } width >>= 1; if (width & 1) { dst[0] = pRLEBytes[0]; dst[1] = pRLEBytes[1]; pRLEBytes += 2; dst += 2; } width >>= 1; while (width) { dst[0] = pRLEBytes[0]; dst[1] = pRLEBytes[1]; dst[2] = pRLEBytes[2]; dst[3] = pRLEBytes[3]; pRLEBytes += 4; dst += 4; width--; } } else { width = -(char)width; dst += width; i -= width; } } } #endif } /** * @brief Blit a solid colder shape one pixel larger then the given sprite shape, to the back buffer at the given coordianates * @param col Color index from current palette * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff CEL buffer * @param nCel CEL frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelBlitOutline(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap, w; BYTE *pRLEBytes, *dst; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(gpBuffer); if (gpBuffer == NULL) return; #ifdef USE_ASM __asm { mov ebx, pCelBuff mov eax, nCel shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov nDataSize, eax mov edx, pCelBuff add edx, [ebx] mov pRLEBytes, edx add edx, CelSkip xor eax, eax mov ax, [edx] mov nDataStart, eax mov edx, pRLEBytes add edx, CelCap mov ax, [edx] mov nDataCap, eax } if (nDataStart == 0) return; if (CelCap == 8) nDataCap = 0; if (nDataCap != 0) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; __asm { mov esi, pRLEBytes mov edi, dst mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label5 sub edx, eax mov ecx, eax mov ah, col label3: lodsb or al, al jz label4 mov [edi-BUFFER_WIDTH], ah mov [edi-1], ah mov [edi+1], ah mov [edi+BUFFER_WIDTH], ah label4: inc edi loop label3 or edx, edx jz label6 jmp label2 label5: neg al add edi, eax sub edx, eax jnz label2 label6: sub edi, w cmp ebx, esi jnz label1 } #else BYTE width; BYTE *end, *src; DWORD *pFrameTable; pFrameTable = (DWORD *)&pCelBuff[4 * nCel]; pRLEBytes = &pCelBuff[pFrameTable[0]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize = pFrameTable[1] - pFrameTable[0] - nDataStart; src = pRLEBytes + nDataStart; end = &src[nDataSize]; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; for (; src != end; dst -= BUFFER_WIDTH + nWidth) { for (w = nWidth; w;) { width = *src++; if (!(width & 0x80)) { w -= width; while (width) { if (*src++) { dst[-BUFFER_WIDTH] = col; dst[-1] = col; dst[1] = col; dst[BUFFER_WIDTH] = col; } dst++; width--; } } else { width = -(char)width; dst += width; w -= width; } } } #endif } /** * @brief Same as CelBlitOutline but checks for drawing outside the buffer * @param col Color index from current palette * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff CEL buffer * @param nCel CEL frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelBlitOutlineSafe(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap, w; BYTE *pRLEBytes, *dst; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(gpBuffer); if (gpBuffer == NULL) return; #ifdef USE_ASM __asm { mov ebx, pCelBuff mov eax, nCel shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov nDataSize, eax mov edx, pCelBuff add edx, [ebx] mov pRLEBytes, edx add edx, CelSkip xor eax, eax mov ax, [edx] mov nDataStart, eax mov edx, pRLEBytes add edx, CelCap mov ax, [edx] mov nDataCap, eax } if (nDataStart == 0) return; if (CelCap == 8) nDataCap = 0; if (nDataCap != 0) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; __asm { mov esi, pRLEBytes mov edi, dst mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label10 sub edx, eax mov ecx, gpBufEnd cmp edi, ecx jb label3 add esi, eax add edi, eax jmp label9 label3: sub ecx, BUFFER_WIDTH cmp edi, ecx jnb label6 mov ecx, eax mov ah, col label4: lodsb or al, al jz label5 mov [edi-BUFFER_WIDTH], ah mov [edi-1], ah mov [edi+1], ah mov [edi+BUFFER_WIDTH], ah label5: inc edi loop label4 jmp label9 label6: mov ecx, eax mov ah, col label7: lodsb or al, al jz label8 mov [edi-BUFFER_WIDTH], ah mov [edi-1], ah mov [edi+1], ah label8: inc edi loop label7 label9: or edx, edx jz label11 jmp label2 label10: neg al add edi, eax sub edx, eax jnz label2 label11: sub edi, w cmp ebx, esi jnz label1 } #else BYTE width; BYTE *end, *src; DWORD *pFrameTable; pFrameTable = (DWORD *)&pCelBuff[4 * nCel]; pRLEBytes = &pCelBuff[pFrameTable[0]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize = pFrameTable[1] - pFrameTable[0] - nDataStart; src = pRLEBytes + nDataStart; end = &src[nDataSize]; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; for (; src != end; dst -= BUFFER_WIDTH + nWidth) { for (w = nWidth; w;) { width = *src++; if (!(width & 0x80)) { w -= width; if (dst < gpBufEnd) { if (dst >= gpBufEnd - BUFFER_WIDTH) { while (width) { if (*src++) { dst[-BUFFER_WIDTH] = col; dst[-1] = col; dst[1] = col; } dst++; width--; } } else { while (width) { if (*src++) { dst[-BUFFER_WIDTH] = col; dst[-1] = col; dst[1] = col; dst[BUFFER_WIDTH] = col; } dst++; width--; } } } else { src += width; dst += width; } } else { width = -(char)width; dst += width; w -= width; } } } #endif } /** * @brief Set the value of a single pixel in the back buffer, checks bounds * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param col Color index from current palette */ void ENG_set_pixel(int sx, int sy, BYTE col) { BYTE *dst; assert(gpBuffer); if (sy < 0 || sy >= SCREEN_HEIGHT + SCREEN_Y || sx < SCREEN_X || sx >= SCREEN_WIDTH + SCREEN_X) return; dst = &gpBuffer[sx + PitchTbl[sy]]; #ifdef USE_ASM __asm { mov edi, dst cmp edi, gpBufEnd jnb label1 mov al, col mov [edi], al label1: } #else if (dst < gpBufEnd) *dst = col; #endif } /** * @brief Set the value of a single pixel in the back buffer to that of gbPixelCol, checks bounds * @param sx Back buffer coordinate * @param sy Back buffer coordinate */ void engine_draw_pixel(int sx, int sy) { BYTE *dst; assert(gpBuffer); if (gbRotateMap) { if (gbNotInView && (sx < 0 || sx >= SCREEN_HEIGHT + SCREEN_Y || sy < SCREEN_X || sy >= SCREEN_WIDTH + SCREEN_X)) return; dst = &gpBuffer[sy + PitchTbl[sx]]; } else { if (gbNotInView && (sy < 0 || sy >= SCREEN_HEIGHT + SCREEN_Y || sx < SCREEN_X || sx >= SCREEN_WIDTH + SCREEN_X)) return; dst = &gpBuffer[sx + PitchTbl[sy]]; } #ifdef USE_ASM __asm { mov edi, dst cmp edi, gpBufEnd jnb label1 mov al, gbPixelCol mov [edi], al label1: } #else if (dst < gpBufEnd) *dst = gbPixelCol; #endif } /** Macro used in DrawLine() */ #define GG_SWAP(A, B) \ { \ (A) ^= (B); \ (B) ^= (A); \ (A) ^= (B); \ } /** Macro used in DrawLine() */ #define GG_ABSOLUTE(I, J, K) (((I) - (J)) * ((K) = (((I) - (J)) < 0 ? -1 : 1))) /** * Symmetric Double Step Line Algorithm * by Brian Wyvill * from "Graphics Gems", Academic Press, 1990 * * Exact copy from https://github.com/erich666/GraphicsGems/blob/dad26f941e12c8bf1f96ea21c1c04cd2206ae7c9/gems/DoubleLine.c * Except: * - not in view checks * - global variable instead of reverse flag * - condition for pixels_left < 0 removed * * @brief Draw a line on the back buffer * @param x0 Back buffer coordinate * @param y0 Back buffer coordinate * @param x1 Back buffer coordinate * @param y1 Back buffer coordinate * @param col Color index from current palette */ void DrawLine(int x0, int y0, int x1, int y1, BYTE col) { int dx, dy, incr1, incr2, D, x, y, xend, c, pixels_left; int sign_x, sign_y, step, i; int x1_, y1_; gbPixelCol = col; gbNotInView = FALSE; if (x0 < 0 + SCREEN_X || x0 >= SCREEN_WIDTH + SCREEN_X) { gbNotInView = TRUE; } if (x1 < 0 + SCREEN_X || x1 >= SCREEN_WIDTH + SCREEN_X) { gbNotInView = TRUE; } if (y0 < 0 + SCREEN_Y || y0 >= PANEL_Y) { gbNotInView = TRUE; } if (y1 < 0 + SCREEN_Y || y1 >= PANEL_Y) { gbNotInView = TRUE; } dx = GG_ABSOLUTE(x1, x0, sign_x); dy = GG_ABSOLUTE(y1, y0, sign_y); /* decide increment sign by the slope sign */ if (sign_x == sign_y) step = 1; else step = -1; if (dy > dx) { /* chooses axis of greatest movement (make * dx) */ GG_SWAP(x0, y0); GG_SWAP(x1, y1); GG_SWAP(dx, dy); gbRotateMap = TRUE; } else gbRotateMap = FALSE; /* note error check for dx==0 should be included here */ if (x0 > x1) { /* start from the smaller coordinate */ x = x1; y = y1; x1_ = x0; y1_ = y0; } else { x = x0; y = y0; x1_ = x1; y1_ = y1; } /* Note dx=n implies 0 - n or (dx+1) pixels to be set */ /* Go round loop dx/4 times then plot last 0,1,2 or 3 pixels */ /* In fact (dx-1)/4 as 2 pixels are already plotted */ xend = (dx - 1) / 4; pixels_left = (dx - 1) % 4; /* number of pixels left over at the end */ engine_draw_pixel(x, y); engine_draw_pixel(x1_, y1_); /* plot first two points */ incr2 = 4 * dy - 2 * dx; if (incr2 < 0) { /* slope less than 1/2 */ c = 2 * dy; incr1 = 2 * c; D = incr1 - dx; for (i = 0; i < xend; i++) { /* plotting loop */ ++x; --x1_; if (D < 0) { /* pattern 1 forwards */ engine_draw_pixel(x, y); engine_draw_pixel(++x, y); /* pattern 1 backwards */ engine_draw_pixel(x1_, y1_); engine_draw_pixel(--x1_, y1_); D += incr1; } else { if (D < c) { /* pattern 2 forwards */ engine_draw_pixel(x, y); engine_draw_pixel(++x, y += step); /* pattern 2 backwards */ engine_draw_pixel(x1_, y1_); engine_draw_pixel(--x1_, y1_ -= step); } else { /* pattern 3 forwards */ engine_draw_pixel(x, y += step); engine_draw_pixel(++x, y); /* pattern 3 backwards */ engine_draw_pixel(x1_, y1_ -= step); engine_draw_pixel(--x1_, y1_); } D += incr2; } } /* end for */ /* plot last pattern */ if (pixels_left) { if (D < 0) { engine_draw_pixel(++x, y); /* pattern 1 */ if (pixels_left > 1) engine_draw_pixel(++x, y); if (pixels_left > 2) engine_draw_pixel(--x1_, y1_); } else { if (D < c) { engine_draw_pixel(++x, y); /* pattern 2 */ if (pixels_left > 1) engine_draw_pixel(++x, y += step); if (pixels_left > 2) engine_draw_pixel(--x1_, y1_); } else { /* pattern 3 */ engine_draw_pixel(++x, y += step); if (pixels_left > 1) engine_draw_pixel(++x, y); if (pixels_left > 2) engine_draw_pixel(--x1_, y1_ -= step); } } } /* end if pixels_left */ } /* end slope < 1/2 */ else { /* slope greater than 1/2 */ c = 2 * (dy - dx); incr1 = 2 * c; D = incr1 + dx; for (i = 0; i < xend; i++) { ++x; --x1_; if (D > 0) { /* pattern 4 forwards */ engine_draw_pixel(x, y += step); engine_draw_pixel(++x, y += step); /* pattern 4 backwards */ engine_draw_pixel(x1_, y1_ -= step); engine_draw_pixel(--x1_, y1_ -= step); D += incr1; } else { if (D < c) { /* pattern 2 forwards */ engine_draw_pixel(x, y); engine_draw_pixel(++x, y += step); /* pattern 2 backwards */ engine_draw_pixel(x1_, y1_); engine_draw_pixel(--x1_, y1_ -= step); } else { /* pattern 3 forwards */ engine_draw_pixel(x, y += step); engine_draw_pixel(++x, y); /* pattern 3 backwards */ engine_draw_pixel(x1_, y1_ -= step); engine_draw_pixel(--x1_, y1_); } D += incr2; } } /* end for */ /* plot last pattern */ if (pixels_left) { if (D > 0) { engine_draw_pixel(++x, y += step); /* pattern 4 */ if (pixels_left > 1) engine_draw_pixel(++x, y += step); if (pixels_left > 2) engine_draw_pixel(--x1_, y1_ -= step); } else { if (D < c) { engine_draw_pixel(++x, y); /* pattern 2 */ if (pixels_left > 1) engine_draw_pixel(++x, y += step); if (pixels_left > 2) engine_draw_pixel(--x1_, y1_); } else { /* pattern 3 */ engine_draw_pixel(++x, y += step); if (pixels_left > 1) engine_draw_pixel(++x, y); if (pixels_left > 2) { if (D > c) /* step 3 */ engine_draw_pixel(--x1_, y1_ -= step); else /* step 2 */ engine_draw_pixel(--x1_, y1_); } } } } } } /** * @brief Calculate the best fit direction between two points * @param x1 Tile coordinate * @param y1 Tile coordinate * @param x2 Tile coordinate * @param y2 Tile coordinate * @return A value from the direction enum */ int GetDirection(int x1, int y1, int x2, int y2) { int mx, my; int md, ny; mx = x2 - x1; my = y2 - y1; if (mx >= 0) { if (my >= 0) { md = DIR_S; if (2 * mx < my) md = DIR_SW; } else { my = -my; md = DIR_E; if (2 * mx < my) md = DIR_NE; } if (2 * my < mx) return DIR_SE; } else { if (my >= 0) { ny = -mx; md = DIR_W; if (2 * ny < my) md = DIR_SW; } else { ny = -mx; my = -my; md = DIR_N; if (2 * ny < my) md = DIR_NE; } if (2 * my < ny) return DIR_NW; } return md; } /** * @brief Set the RNG seed * @param s RNG seed */ void SetRndSeed(int s) { SeedCount = 0; sglGameSeed = s; orgseed = s; } /** * @brief Get the current RNG seed * @return RNG seed */ int GetRndSeed() { SeedCount++; sglGameSeed = RndMult * sglGameSeed + RndInc; return abs(sglGameSeed); } /** * @brief Main RNG function * @param idx Unused * @param v The upper limit for the return value * @return A random number from 0 to (v-1) */ int random_(BYTE idx, int v) { if (v <= 0) return 0; if (v < 0xFFFF) return (GetRndSeed() >> 16) % v; return GetRndSeed() % v; } /** * @brief Unallocate all remaining pointers * @param show_cursor unused */ void engine_debug_trap(BOOL show_cursor) { /* TMemBlock *pCurr; sgMemCrit.Enter(); while(sgpMemBlock != NULL) { pCurr = sgpMemBlock->pNext; SMemFree(sgpMemBlock, "C:\\Diablo\\Direct\\ENGINE.CPP", 1970); sgpMemBlock = pCurr; } sgMemCrit.Leave(); */ } /** * @brief Multithreaded safe malloc * @param dwBytes Byte size to allocate */ BYTE *DiabloAllocPtr(DWORD dwBytes) { BYTE *buf; sgMemCrit.Enter(); buf = (BYTE *)SMemAlloc(dwBytes, "C:\\Src\\Diablo\\Source\\ENGINE.CPP", 2236, 0); sgMemCrit.Leave(); if (buf == NULL) { ErrDlg(IDD_DIALOG2, GetLastError(), "C:\\Src\\Diablo\\Source\\ENGINE.CPP", 2269); } return buf; } /** * @brief Multithreaded safe memfree * @param p Memory pointer to free */ void mem_free_dbg(void *p) { if (p) { sgMemCrit.Enter(); SMemFree(p, "C:\\Src\\Diablo\\Source\\ENGINE.CPP", 2317, 0); sgMemCrit.Leave(); } } /** * @brief Load a file into a buffer * @param pszName Path of file * @param pdwFileLen Will be set to file size if non-NULL * @return Buffer with content of file */ BYTE *LoadFileInMem(const char *pszName, DWORD *pdwFileLen) { HANDLE file; BYTE *buf; int fileLen; WOpenFile(pszName, &file, FALSE); fileLen = WGetFileSize(file, NULL); if (pdwFileLen) *pdwFileLen = fileLen; if (!fileLen) app_fatal("Zero length SFILE:\n%s", pszName); buf = (BYTE *)DiabloAllocPtr(fileLen); WReadFile(file, buf, fileLen); WCloseFile(file); return buf; } /** * @brief Load a file into the given buffer * @param pszName Path of file * @param p Target buffer * @return Size of file */ DWORD LoadFileWithMem(const char *pszName, BYTE *p) { DWORD dwFileLen; HANDLE hsFile; assert(pszName); if (p == NULL) { app_fatal("LoadFileWithMem(NULL):\n%s", pszName); } WOpenFile(pszName, &hsFile, FALSE); dwFileLen = WGetFileSize(hsFile, NULL); if (dwFileLen == 0) { app_fatal("Zero length SFILE:\n%s", pszName); } WReadFile(hsFile, p, dwFileLen); WCloseFile(hsFile); return dwFileLen; } /** * @brief Apply the color swaps to a CL2 sprite * @param p CL2 buffer * @param ttbl Palette translation table * @param nCel Frame number in CL2 file */ void Cl2ApplyTrans(BYTE *p, BYTE *ttbl, int nCel) { int i, nDataSize; char width; BYTE *dst; DWORD *pFrameTable; assert(p != NULL); assert(ttbl != NULL); for (i = 1; i <= nCel; i++) { pFrameTable = (DWORD *)p; dst = &p[SwapLE32(pFrameTable[i]) + 10]; nDataSize = SwapLE32(pFrameTable[i + 1]) - SwapLE32(pFrameTable[i]) - 10; while (nDataSize) { width = *dst++; nDataSize--; assert(nDataSize >= 0); if (width < 0) { width = -width; if (width > 65) { nDataSize--; assert(nDataSize >= 0); *dst = ttbl[*dst]; dst++; } else { nDataSize -= width; assert(nDataSize >= 0); while (width--) { *dst = ttbl[*dst]; dst++; } } } } } } /** * @brief Blit CL2 sprite to the given buffer * @param pDecodeTo The output buffer * @param pRLEBytes CL2 pixel stream (run-length encoded) * @param nDataSize Size of CL2 in bytes * @param nWidth Width of sprite */ static void Cl2Blit(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' xor eax, eax mov ebx, nWidth mov ecx, nDataSize label1: mov al, [esi] inc esi dec ecx test al, al jns label6 neg al cmp al, 41h jle label3 sub al, 41h dec ecx mov dl, [esi] inc esi sub ebx, eax label2: mov [edi], dl dec eax lea edi, [edi+1] jnz label2 jmp label5 label3: sub ecx, eax sub ebx, eax label4: mov dl, [esi] inc esi mov [edi], dl dec eax lea edi, [edi+1] jnz label4 label5: test ebx, ebx jnz label10 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label10 label6: cmp eax, ebx jle label7 mov edx, ebx add edi, ebx sub eax, ebx jmp label8 label7: mov edx, eax add edi, eax xor eax, eax label8: sub ebx, edx jnz label9 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx label9: test eax, eax jnz label6 label10: test ecx, ecx jnz label1 pop edi pop esi pop ebx } #else int w; char width; BYTE fill; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; fill = *src++; w -= width; while (width) { *dst = fill; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } else { nDataSize -= width; w -= width; while (width) { *dst = *src; src++; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } } } #endif } /** * @brief Blit a solid colder shape one pixel larger then the given sprite shape, to the given buffer * @param pDecodeTo The output buffer * @param pRLEBytes CL2 pixel stream (run-length encoded) * @param nDataSize Size of CL2 in bytes * @param nWidth Width of sprite * @param col Color index from current palette */ static void Cl2BlitOutline(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, char col) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' xor eax, eax mov ebx, nWidth xor edx, edx mov ecx, nDataSize mov dl, col label1: mov al, [esi] inc esi dec ecx test al, al jns label7 neg al cmp al, 41h jle label3 sub al, 41h dec ecx mov dh, [esi] inc esi test dh, dh jz label7 mov [edi-1], dl sub ebx, eax mov [edi+eax], dl label2: mov [edi-BUFFER_WIDTH], dl mov [edi+BUFFER_WIDTH], dl dec eax lea edi, [edi+1] jnz label2 jmp label6 label3: sub ecx, eax sub ebx, eax label4: mov dh, [esi] inc esi test dh, dh jz label5 mov [edi-1], dl mov [edi+1], dl mov [edi-BUFFER_WIDTH], dl mov [edi+BUFFER_WIDTH], dl label5: dec eax lea edi, [edi+1] jnz label4 label6: test ebx, ebx jnz label11 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label11 label7: cmp eax, ebx jle label8 mov edx, ebx add edi, ebx sub eax, ebx jmp label9 label8: mov edx, eax add edi, eax xor eax, eax label9: sub ebx, edx jnz label10 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx label10: test eax, eax jnz label7 mov dl, col label11: test ecx, ecx jnz label1 pop edi pop esi pop ebx } #else int w; char width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; if (*src++) { w -= width; dst[-1] = col; dst[width] = col; while (width) { dst[-BUFFER_WIDTH] = col; dst[BUFFER_WIDTH] = col; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } } else { nDataSize -= width; w -= width; while (width) { if (*src++) { dst[-1] = col; dst[1] = col; dst[-BUFFER_WIDTH] = col; dst[BUFFER_WIDTH] = col; } dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } } } #endif } /** * @brief Blit CL2 sprite, and apply lighting, to the given buffer * @param pDecodeTo The output buffer * @param pRLEBytes CL2 pixel stream (run-length encoded) * @param nDataSize Size of CL2 in bytes * @param nWidth Width of sprite * @param pTable Light color table */ static void Cl2BlitLight(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, BYTE *pTable) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' mov ebx, nWidth mov ecx, nDataSize mov edx, pTable push ebp mov sgnWidth, ebx mov ebp, edx xor eax, eax xor edx, edx label1: mov al, [esi] inc esi dec ecx test al, al jns label6 neg al cmp al, 41h jle label3 sub al, 41h dec ecx sub ebx, eax mov dl, [esi] inc esi mov dl, [ebp+edx] label2: mov [edi], dl dec eax lea edi, [edi+1] jnz label2 jmp label5 label3: sub ecx, eax sub ebx, eax label4: mov dl, [esi] inc esi mov dl, [ebp+edx] mov [edi], dl dec eax lea edi, [edi+1] jnz label4 label5: test ebx, ebx jnz label10 mov ebx, sgnWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label10 label6: cmp eax, ebx jle label7 mov edx, ebx add edi, ebx sub eax, ebx jmp label8 label7: mov edx, eax add edi, eax xor eax, eax label8: sub ebx, edx jnz label9 mov ebx, sgnWidth sub edi, BUFFER_WIDTH sub edi, ebx label9: test eax, eax jnz label6 label10: test ecx, ecx jnz label1 pop ebp pop edi pop esi pop ebx } #else int w; char width; BYTE fill; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; sgnWidth = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; fill = pTable[*src++]; w -= width; while (width) { *dst = fill; dst++; width--; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } continue; } else { nDataSize -= width; w -= width; while (width) { *dst = pTable[*src]; src++; dst++; width--; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } continue; } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } } } #endif } /** * @brief Same as Cl2Blit but checks for drawing outside the buffer * @param pDecodeTo The output buffer * @param pRLEBytes CL2 pixel stream (run-length encoded) * @param nDataSize Size of CL2 in bytes * @param nWidth Width of sprite */ static void Cl2BlitSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' xor eax, eax mov ebx, nWidth mov ecx, nDataSize label1: mov al, [esi] inc esi dec ecx test al, al jns label7 neg al cmp al, 41h jle label3 sub al, 41h dec ecx mov dl, [esi] inc esi cmp edi, gpBufEnd jge label7 sub ebx, eax label2: mov [edi], dl dec eax lea edi, [edi+1] jnz label2 jmp label6 label3: sub ecx, eax cmp edi, gpBufEnd jl label4 add esi, eax jmp label7 label4: sub ebx, eax label5: mov dl, [esi] inc esi mov [edi], dl dec eax lea edi, [edi+1] jnz label5 label6: test ebx, ebx jnz label11 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label11 label7: cmp eax, ebx jle label8 mov edx, ebx add edi, ebx sub eax, ebx jmp label9 label8: mov edx, eax add edi, eax xor eax, eax label9: sub ebx, edx jnz label10 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx label10: test eax, eax jnz label7 label11: test ecx, ecx jnz label1 pop edi pop esi pop ebx } #else int w; char width; BYTE fill; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; fill = *src++; if (dst < gpBufEnd) { w -= width; while (width) { *dst = fill; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } } else { nDataSize -= width; if (dst < gpBufEnd) { w -= width; while (width) { *dst = *src; src++; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } else { src += width; } } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } } } #endif } /** * @brief Same as Cl2BlitOutline but checks for drawing outside the buffer * @param pDecodeTo The output buffer * @param pRLEBytes CL2 pixel stream (run-length encoded) * @param nDataSize Size of CL2 in bytes * @param nWidth Width of sprite * @param col Color index from current palette */ static void Cl2BlitOutlineSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, char col) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' xor eax, eax mov ebx, nWidth xor edx, edx mov ecx, nDataSize mov dl, col label1: mov al, [esi] inc esi dec ecx test al, al jns label9 neg al cmp al, 41h jle label3 sub al, 41h dec ecx mov dh, [esi] inc esi test dh, dh jz label9 cmp edi, gpBufEnd jge label9 mov [edi-1], dl sub ebx, eax mov [edi+eax], dl label2: mov [edi-BUFFER_WIDTH], dl mov [edi+BUFFER_WIDTH], dl dec eax lea edi, [edi+1] jnz label2 jmp label7 label3: sub ecx, eax cmp edi, gpBufEnd jl label4 add esi, eax jmp label9 label4: sub ebx, eax label5: mov dh, [esi] inc esi test dh, dh jz label6 mov [edi-1], dl mov [edi+1], dl mov [edi-BUFFER_WIDTH], dl mov [edi+BUFFER_WIDTH], dl label6: dec eax lea edi, [edi+1] jnz label5 label7: test ebx, ebx jnz label13 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label13 label9: cmp eax, ebx jle label10 mov edx, ebx add edi, ebx sub eax, ebx jmp label11 label10: mov edx, eax add edi, eax xor eax, eax label11: sub ebx, edx jnz label12 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx label12: test eax, eax jnz label9 mov dl, col label13: test ecx, ecx jnz label1 pop edi pop esi pop ebx } #else int w; char width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; if (*src++ && dst < gpBufEnd) { w -= width; dst[-1] = col; dst[width] = col; while (width) { dst[-BUFFER_WIDTH] = col; dst[BUFFER_WIDTH] = col; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } } else { nDataSize -= width; if (dst < gpBufEnd) { w -= width; while (width) { if (*src++) { dst[-1] = col; dst[1] = col; dst[-BUFFER_WIDTH] = col; // BUGFIX: only set `if (dst+BUFFER_WIDTH < gpBufEnd)` dst[BUFFER_WIDTH] = col; } dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } else { src += width; } } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } } } #endif } /** * @brief Same as Cl2BlitLight but checks for drawing outside the buffer * @param pDecodeTo The output buffer * @param pRLEBytes CL2 pixel stream (run-length encoded) * @param nDataSize Size of CL2 in bytes * @param nWidth With of CL2 sprite * @param pTable Light color table */ static void Cl2BlitLightSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, BYTE *pTable) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' mov ebx, nWidth mov ecx, nDataSize mov edx, pTable push ebp mov sgnWidth, ebx mov ebp, edx xor eax, eax xor edx, edx label1: mov al, [esi] inc esi dec ecx test al, al jns label7 neg al cmp al, 41h jle label3 sub al, 41h dec ecx mov dl, [esi] inc esi mov dl, [ebp+edx] cmp edi, gpBufEnd jge label7 sub ebx, eax label2: mov [edi], dl dec eax lea edi, [edi+1] jnz label2 jmp label6 label3: sub ecx, eax cmp edi, gpBufEnd jl label4 add esi, eax jmp label7 label4: sub ebx, eax label5: mov dl, [esi] inc esi mov dl, [ebp+edx] mov [edi], dl dec eax lea edi, [edi+1] jnz label5 label6: test ebx, ebx jnz label11 mov ebx, sgnWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label11 label7: cmp eax, ebx jle label8 mov edx, ebx add edi, ebx sub eax, ebx jmp label9 label8: mov edx, eax add edi, eax xor eax, eax label9: sub ebx, edx jnz label10 mov ebx, sgnWidth sub edi, BUFFER_WIDTH sub edi, ebx label10: test eax, eax jnz label7 label11: test ecx, ecx jnz label1 pop ebp pop edi pop esi pop ebx } #else int w; char width; BYTE fill; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; sgnWidth = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; fill = pTable[*src++]; if (dst < gpBufEnd) { w -= width; while (width) { *dst = fill; dst++; width--; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } continue; } } else { nDataSize -= width; if (dst < gpBufEnd) { w -= width; while (width) { *dst = pTable[*src]; src++; dst++; width--; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } continue; } else { src += width; } } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } } } #endif } /** * @brief Blit CL2 sprite, to the back buffer at the given coordianates * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff CL2 buffer * @param nCel CL2 frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2Draw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize; assert(gpBuffer != NULL); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; assert(nCel <= (int)pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; Cl2Blit( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth); } /** * @brief Blit a solid colder shape one pixel larger then the given sprite shape, to the back buffer at the given coordianates * @param col Color index from current palette * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff CL2 buffer * @param nCel CL2 frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DrawOutline(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize; BYTE *pRLEBytes; DWORD *pFrameTable; assert(gpBuffer != NULL); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; assert(nCel <= (int)pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; Cl2BlitOutline( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth, col); } /** * @brief Blit CL2 sprite, and apply a given lighting, to the back buffer at the given coordianates * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff CL2 buffer * @param nCel CL2 frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 * @param light Light shade to use */ void Cl2DrawLightTbl(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light) { int nDataStart, nDataSize, idx, nSize; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; assert(gpBuffer != NULL); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; assert(nCel <= (int)pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nSize = nDataSize - nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; idx = light4flag ? 1024 : 4096; if (light == 2) idx += 256; // gray colors if (light >= 4) idx += (light - 1) << 8; Cl2BlitLight( pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[idx]); } /** * @brief Blit CL2 sprite, and apply lighting, to the back buffer at the given coordinates * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff CL2 buffer * @param nCel CL2 frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DrawLight(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nSize; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; assert(gpBuffer != NULL); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; assert(nCel <= (int)pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nSize = nDataSize - nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; if (light_table_index) Cl2BlitLight(pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[light_table_index * 256]); else Cl2Blit(pDecodeTo, pRLEBytes, nSize, nWidth); } /** * @brief Same as Cl2Draw but checks for drawing outside the buffer * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff CL2 buffer * @param nCel CL2 frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DrawSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize; assert(gpBuffer != NULL); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; assert(nCel <= (int)pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; Cl2BlitSafe( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth); } /** * @brief Same as Cl2DrawOutline but checks for drawing outside the buffer * @param col Color index from current palette * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff CL2 buffer * @param nCel CL2 frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DrawOutlineSafe(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize; BYTE *pRLEBytes; DWORD *pFrameTable; assert(gpBuffer != NULL); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; assert(nCel <= (int)pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; gpBufEnd -= BUFFER_WIDTH; Cl2BlitOutlineSafe( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth, col); gpBufEnd += BUFFER_WIDTH; } /** * @brief Same as Cl2DrawLightTbl but checks for drawing outside the buffer * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff CL2 buffer * @param nCel CL2 frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 * @param light light shade to use */ void Cl2DrawLightTblSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light) { int nDataStart, nDataSize, idx, nSize; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; assert(gpBuffer != NULL); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; assert(nCel <= (int)pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nSize = nDataSize - nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; idx = light4flag ? 1024 : 4096; if (light == 2) idx += 256; // gray colors if (light >= 4) idx += (light - 1) << 8; Cl2BlitLightSafe( pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[idx]); } /** * @brief Same as Cl2DrawLight but checks for drawing outside the buffer * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff CL2 buffer * @param nCel CL2 frame number * @param nWidth Width of sprite * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DrawLightSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nSize; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; assert(gpBuffer != NULL); if (gpBuffer == NULL) return; assert(pCelBuff != NULL); if (pCelBuff == NULL) return; assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; assert(nCel <= (int)pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nSize = nDataSize - nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; if (light_table_index) Cl2BlitLightSafe(pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[light_table_index * 256]); else Cl2BlitSafe(pDecodeTo, pRLEBytes, nSize, nWidth); } /** * @brief Fade to black and play a video * @param pszMovie file path of movie */ void PlayInGameMovie(const char *pszMovie) { PaletteFadeOut(8); play_movie(pszMovie, FALSE); ClearScreenBuffer(); force_redraw = 255; scrollrt_draw_game_screen(TRUE); PaletteFadeIn(8); force_redraw = 255; } ================================================ FILE: Source/engine.h ================================================ /** * @file engine.h * * of basic engine helper functions: * - Sprite blitting * - Drawing * - Angle calculation * - RNG * - Memory allocation * - File loading * - Video playback */ #ifndef __ENGINE_H__ #define __ENGINE_H__ __FINLINE BYTE *CelGetFrame(BYTE *pCelBuff, int nCel, int *nDataSize); void CelBlit(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth); void CelDraw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth); void CelBlitFrame(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth); void CelClippedDraw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void CelClippedBlit(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void CelBlitLight(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth); void CelBlitLightTrans(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth); void CelDrawLight(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth); void CelClippedDrawLight(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void CelClippedBlitLightTrans(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void CelDrawLightRed(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light); void CelBlitSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth); void CelClippedDrawSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void CelClippedBlitSafe(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void CelBlitLightSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth); void CelBlitLightTransSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth); void CelDrawLightSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void CelClippedBlitLightTransSafe(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void CelDrawLightRedSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light); void CelBlitWidth(BYTE *pBuff, int x, int y, int wdt, BYTE *pCelBuff, int nCel, int nWidth); void CelBlitOutline(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void CelBlitOutlineSafe(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void ENG_set_pixel(int sx, int sy, BYTE col); void engine_draw_pixel(int sx, int sy); void DrawLine(int x0, int y0, int x1, int y1, BYTE col); int GetDirection(int x1, int y1, int x2, int y2); void SetRndSeed(int s); int GetRndSeed(); int random_(BYTE idx, int v); void engine_debug_trap(BOOL show_cursor); BYTE *DiabloAllocPtr(DWORD dwBytes); void mem_free_dbg(void *p); BYTE *LoadFileInMem(const char *pszName, DWORD *pdwFileLen); DWORD LoadFileWithMem(const char *pszName, BYTE *p); void Cl2ApplyTrans(BYTE *p, BYTE *ttbl, int nCel); void Cl2Draw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void Cl2DrawOutline(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void Cl2DrawLightTbl(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light); void Cl2DrawLight(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void Cl2DrawSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void Cl2DrawOutlineSafe(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void Cl2DrawLightTblSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light); void Cl2DrawLightSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap); void PlayInGameMovie(const char *pszMovie); #endif /* __ENGINE_H__ */ ================================================ FILE: Source/error.cpp ================================================ /** * @file error.cpp * * Implementation of in-game message functions. */ #include "all.h" char msgtable[MAX_SEND_STR_LEN]; char msgdelay; char msgflag; char msgcnt; /** Maps from error_id to error message. */ const char *const MsgStrings[] = { "", "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!", #ifdef HELLFIRE "That which does not kill you...", "Knowledge is power.", "Give and you shall receive.", "Some experience is gained by touch.", "There's no place like home.", "Spirtual energy is restored.", "You feel more agile.", "You feel stronger.", "You feel wiser.", "You feel refreshed.", "That which can break will.", #endif }; void InitDiabloMsg(char e) { int i; for (i = 0; i < msgcnt; i++) { if (msgtable[i] == e) return; } msgtable[msgcnt] = e; // BUGFIX: missing out-of-bounds check if (msgcnt < (BYTE)sizeof(msgtable)) msgcnt++; msgflag = msgtable[0]; msgdelay = 70; } void ClrDiabloMsg() { int i; for (i = 0; i < sizeof(msgtable); i++) msgtable[i] = 0; msgflag = 0; msgcnt = 0; } void DrawDiabloMsg() { int i, len, off, width, sx, sy; BYTE c; CelDraw(PANEL_X + 101, DIALOG_Y, pSTextSlidCels, 1, 12); CelDraw(PANEL_X + 527, DIALOG_Y, pSTextSlidCels, 4, 12); CelDraw(PANEL_X + 101, DIALOG_Y + 48, pSTextSlidCels, 2, 12); CelDraw(PANEL_X + 527, DIALOG_Y + 48, pSTextSlidCels, 3, 12); sx = PANEL_X + 109; for (i = 0; i < 35; i++) { CelDraw(sx, DIALOG_Y, pSTextSlidCels, 5, 12); CelDraw(sx, DIALOG_Y + 48, pSTextSlidCels, 7, 12); sx += 12; } sy = DIALOG_Y + 12; for (i = 0; i < 3; i++) { CelDraw(PANEL_X + 101, sy, pSTextSlidCels, 6, 12); CelDraw(PANEL_X + 527, sy, pSTextSlidCels, 8, 12); sy += 12; } assert(gpBuffer); #define TRANS_RECT_X (PANEL_LEFT + 104) #define TRANS_RECT_Y (DIALOG_TOP - 8) #define TRANS_RECT_WIDTH 432 #define TRANS_RECT_HEIGHT 54 #include "asm_trans_rect.inc" strcpy(tempstr, MsgStrings[msgflag]); off = PANEL_X + 101 + PitchTbl[DIALOG_Y + 24]; len = strlen(tempstr); width = 0; for (i = 0; i < len; i++) { width += fontkern[fontframe[gbFontTransTbl[(BYTE)tempstr[i]]]] + 1; } if (width < 442) { off += (442 - width) >> 1; } for (i = 0; i < len; i++) { c = fontframe[gbFontTransTbl[(BYTE)tempstr[i]]]; if (c != '\0') { PrintChar(off, c, COL_GOLD); } off += fontkern[c] + 1; } if (msgdelay > 0) { msgdelay--; } if (msgdelay == 0) { msgcnt--; msgdelay = 70; if (msgcnt == 0) { msgflag = 0; } else { msgflag = msgtable[msgcnt]; } } } ================================================ FILE: Source/error.h ================================================ /** * @file error.h * * Interface of in-game message functions. */ #ifndef __ERROR_H__ #define __ERROR_H__ extern char msgdelay; extern char msgflag; void InitDiabloMsg(char e); void ClrDiabloMsg(); void DrawDiabloMsg(); #endif /* __ERROR_H__ */ ================================================ FILE: Source/fault.cpp ================================================ /** * @file fault.cpp * * Implementation of exception logging functionality. */ #include "all.h" typedef struct STACK_FRAME { struct STACK_FRAME *pNext; void *pCallRet; } STACK_FRAME; LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter; int fault_unused; static void *fault_set_filter(void *unused) { lpTopLevelExceptionFilter = SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)TopLevelExceptionFilter); return unused; } static LPTOP_LEVEL_EXCEPTION_FILTER fault_reset_filter(void *unused) { return SetUnhandledExceptionFilter(lpTopLevelExceptionFilter); } static LPTOP_LEVEL_EXCEPTION_FILTER __cdecl fault_cleanup_filter() { return fault_reset_filter(&fault_unused); } static void fault_init_filter() { fault_set_filter(&fault_unused); } static void fault_cleanup_filter_atexit() { atexit((void(__cdecl *)(void))fault_cleanup_filter); } #ifndef _MSC_VER __attribute__((constructor)) #endif static void fault_c_init(void) { fault_init_filter(); fault_cleanup_filter_atexit(); } SEG_ALLOCATE(SEGMENT_C_INIT) _PVFV exception_c_init_funcs[] = { &fault_c_init }; static void fault_hex_format(BYTE *ptr, DWORD numBytes) { DWORD i, bytesRead; const char *fmt; BYTE c; while (numBytes > 0) { if (numBytes < 16) bytesRead = numBytes; else bytesRead = 16; if (IsBadReadPtr(ptr, bytesRead)) break; log_printf("0x%08x: ", ptr); for (i = 0; i < 16; ++i) { fmt = "%02x "; if (i >= bytesRead) fmt = " "; log_printf(fmt, ptr[i]); if (i % 4 == 3) log_printf(" "); } for (i = 0; i < bytesRead; i++) { 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"); } static void fault_unknown_module(LPCVOID lpAddress, LPSTR lpModuleName, int iMaxLength, int *sectionNum, int *sectionOffset) { MEMORY_BASIC_INFORMATION memInfo; PIMAGE_DOS_HEADER dosHeader; LONG ntOffset; PIMAGE_NT_HEADERS ntHeader; PIMAGE_SECTION_HEADER section; DWORD numSections, moduleOffset, sectionSize, sectionAddress; int i; lstrcpyn(lpModuleName, "*unknown*", iMaxLength); *sectionNum = 0; *sectionOffset = 0; if (!VirtualQuery(lpAddress, &memInfo, sizeof(memInfo))) return; 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) { ntOffset = dosHeader->e_lfanew; if (ntOffset) { ntHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader + ntOffset); if (ntHeader->Signature == IMAGE_NT_SIGNATURE) { section = IMAGE_FIRST_SECTION(ntHeader); numSections = ntHeader->FileHeader.NumberOfSections; moduleOffset = (BYTE *)lpAddress - (BYTE *)dosHeader; for (i = 0; i < numSections; i++, section++) { sectionSize = section->SizeOfRawData; 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; } } } } } } static void fault_call_stack(void *instr, STACK_FRAME *stackFrame) { STACK_FRAME *oldStackFrame; char szModuleName[MAX_PATH]; int sectionNumber, sectionOffset; log_printf("Call stack:\r\nAddress Frame Logical addr Module\r\n"); do { fault_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, 8)) break; instr = stackFrame->pCallRet; oldStackFrame = stackFrame; stackFrame = stackFrame->pNext; if ((DWORD)stackFrame % 4 != 0) break; } while (stackFrame > oldStackFrame && !IsBadWritePtr(stackFrame, 8)); log_printf("\r\n"); } static char *fault_get_error_type(DWORD dwMessageId, LPSTR lpString1, DWORD nSize) { const char *s; switch (dwMessageId) { case EXCEPTION_STACK_OVERFLOW: s = "STACK_OVERFLOW"; break; case EXCEPTION_FLT_DIVIDE_BY_ZERO: s = "FLT_DIVIDE_BY_ZERO"; break; case EXCEPTION_FLT_INEXACT_RESULT: s = "FLT_INEXACT_RESULT"; break; case EXCEPTION_FLT_INVALID_OPERATION: s = "FLT_INVALID_OPERATION"; break; case EXCEPTION_FLT_OVERFLOW: s = "FLT_OVERFLOW"; break; case EXCEPTION_FLT_STACK_CHECK: s = "FLT_STACK_CHECK"; break; case EXCEPTION_FLT_UNDERFLOW: s = "FLT_UNDERFLOW"; break; case EXCEPTION_INT_DIVIDE_BY_ZERO: s = "INT_DIVIDE_BY_ZERO"; break; case EXCEPTION_INT_OVERFLOW: s = "INT_OVERFLOW"; break; case EXCEPTION_PRIV_INSTRUCTION: s = "PRIV_INSTRUCTION"; break; case EXCEPTION_FLT_DENORMAL_OPERAND: s = "FLT_DENORMAL_OPERAND"; break; case EXCEPTION_INVALID_HANDLE: s = "INVALID_HANDLE"; break; case EXCEPTION_ILLEGAL_INSTRUCTION: s = "ILLEGAL_INSTRUCTION"; break; case EXCEPTION_NONCONTINUABLE_EXCEPTION: s = "NONCONTINUABLE_EXCEPTION"; break; case EXCEPTION_INVALID_DISPOSITION: s = "INVALID_DISPOSITION"; break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: s = "ARRAY_BOUNDS_EXCEEDED"; break; case EXCEPTION_IN_PAGE_ERROR: s = "IN_PAGE_ERROR"; break; case EXCEPTION_GUARD_PAGE: s = "GUARD_PAGE"; break; case EXCEPTION_DATATYPE_MISALIGNMENT: s = "DATATYPE_MISALIGNMENT"; break; case EXCEPTION_BREAKPOINT: s = "BREAKPOINT"; break; case EXCEPTION_SINGLE_STEP: s = "SINGLE_STEP"; break; case EXCEPTION_ACCESS_VIOLATION: s = "ACCESS_VIOLATION"; break; default: if (FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, (LPCVOID)GetModuleHandle("NTDLL.DLL"), dwMessageId, 0, lpString1, nSize, NULL)) { return lpString1; } s = "*unknown*"; break; } lstrcpyn(lpString1, s, nSize); return lpString1; } LONG __stdcall TopLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) { PEXCEPTION_RECORD xcpt; char szExceptionNameBuf[MAX_PATH]; char szModuleName[MAX_PATH]; char *pszExceptionName; int sectionNumber, sectionOffset; PCONTEXT ctx; log_dump_computer_info(); xcpt = ExceptionInfo->ExceptionRecord; pszExceptionName = fault_get_error_type(ExceptionInfo->ExceptionRecord->ExceptionCode, szExceptionNameBuf, sizeof(szExceptionNameBuf)); log_printf("Exception code: %08X %s\r\n", xcpt->ExceptionCode, pszExceptionName); fault_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); 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); fault_call_stack((void *)ctx->Eip, (STACK_FRAME *)ctx->Ebp); log_printf("Stack bytes:\r\n"); fault_hex_format((BYTE *)ctx->Esp, 768); log_printf("Code bytes:\r\n"); fault_hex_format((BYTE *)ctx->Eip, 16); log_printf("\r\n"); log_flush(TRUE); if (lpTopLevelExceptionFilter) return lpTopLevelExceptionFilter(ExceptionInfo); return EXCEPTION_CONTINUE_SEARCH; } LPTOP_LEVEL_EXCEPTION_FILTER fault_get_filter() { return lpTopLevelExceptionFilter; } ================================================ FILE: Source/fault.h ================================================ /** * @file fault.h * * Interface of exception logging functionality. */ #ifndef __FAULT_H__ #define __FAULT_H__ extern LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter; LONG __stdcall TopLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo); LPTOP_LEVEL_EXCEPTION_FILTER fault_get_filter(); #endif /* __FAULT_H__ */ ================================================ FILE: Source/gamemenu.cpp ================================================ /** * @file gamemenu.cpp * * Implementation of the in-game menu functions. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" #ifdef HELLFIRE BOOL jogging_opt = TRUE; #endif /** Contains the game menu items of the single player menu. */ TMenuItem sgSingleMenu[] = { // clang-format off // dwFlags, pszStr, fnMenu { GMENU_ENABLED, "Save Game", &gamemenu_save_game }, { GMENU_ENABLED, "Options", &gamemenu_options }, { GMENU_ENABLED, "New Game", &gamemenu_new_game }, { GMENU_ENABLED, "Load Game", &gamemenu_load_game }, #ifndef HELLFIRE { GMENU_ENABLED, "Quit Diablo", &gamemenu_quit_game }, #else { GMENU_ENABLED, "Quit Hellfire", &gamemenu_quit_game }, #endif { GMENU_ENABLED, NULL, NULL } // clang-format on }; /** Contains the game menu items of the multi player menu. */ TMenuItem sgMultiMenu[] = { // clang-format off // dwFlags, pszStr, fnMenu { GMENU_ENABLED, "Options", &gamemenu_options }, { GMENU_ENABLED, "New Game", &gamemenu_new_game }, { GMENU_ENABLED, "Restart In Town", &gamemenu_restart_town }, #ifndef HELLFIRE { GMENU_ENABLED, "Quit Diablo", &gamemenu_quit_game }, #else { GMENU_ENABLED, "Quit Hellfire", &gamemenu_quit_game }, #endif { GMENU_ENABLED, NULL, NULL }, // clang-format on }; TMenuItem sgOptionsMenu[] = { // clang-format off // dwFlags, pszStr, fnMenu { GMENU_ENABLED | GMENU_SLIDER, NULL, &gamemenu_music_volume }, { GMENU_ENABLED | GMENU_SLIDER, NULL, &gamemenu_sound_volume }, { GMENU_ENABLED | GMENU_SLIDER, "Gamma", &gamemenu_gamma }, #ifndef HELLFIRE { GMENU_ENABLED , NULL, &gamemenu_color_cycling }, #else { GMENU_ENABLED | GMENU_SLIDER, NULL, &gamemenu_loadjog }, #endif { GMENU_ENABLED , "Previous Menu", &gamemenu_previous }, { GMENU_ENABLED , NULL, NULL }, // clang-format on }; /** Specifies the menu names for music enabled and disabled. */ const char *const music_toggle_names[] = { "Music", "Music Disabled", }; /** Specifies the menu names for sound enabled and disabled. */ const char *const sound_toggle_names[] = { "Sound", "Sound Disabled", }; #ifdef HELLFIRE char *jogging_toggle_names[] = { "Jog", "Walk", }; char *jogging_title = "Fast Walk"; #endif #ifndef HELLFIRE /** Specifies the menu names for colour cycling disabled and enabled. */ const char *const color_cycling_toggle_names[] = { "Color Cycling Off", "Color Cycling On" }; #endif static void gamemenu_update_single(TMenuItem *pMenuItems) { BOOL enable; gmenu_enable(&sgSingleMenu[3], gbValidSaveFile); enable = FALSE; if (plr[myplr]._pmode != PM_DEATH && !deathflag) enable = TRUE; gmenu_enable(&sgSingleMenu[0], enable); } static void gamemenu_update_multi(TMenuItem *pMenuItems) { gmenu_enable(&sgMultiMenu[2], deathflag); } void gamemenu_on() { if (gbMaxPlayers == 1) { gmenu_set_items(sgSingleMenu, gamemenu_update_single); } else { gmenu_set_items(sgMultiMenu, gamemenu_update_multi); } PressEscKey(); } void gamemenu_off() { gmenu_set_items(NULL, NULL); } void gamemenu_handle_previous() { if (gmenu_is_active()) gamemenu_off(); else gamemenu_on(); } void gamemenu_previous(BOOL bActivate) { gamemenu_on(); } void gamemenu_new_game(BOOL bActivate) { int i; for (i = 0; i < MAX_PLRS; i++) { plr[i]._pmode = PM_QUIT; plr[i]._pInvincible = TRUE; } deathflag = FALSE; force_redraw = 255; scrollrt_draw_game_screen(TRUE); #ifdef HELLFIRE CornerStone.activated = FALSE; #endif gbRunGame = FALSE; gamemenu_off(); } void gamemenu_quit_game(BOOL bActivate) { gamemenu_new_game(bActivate); gbRunGameResult = FALSE; } void gamemenu_load_game(BOOL bActivate) { WNDPROC saveProc = SetWindowProc(DisableInputWndProc); gamemenu_off(); SetCursor_(CURSOR_NONE); InitDiabloMsg(EMSG_LOADING); force_redraw = 255; DrawAndBlit(); LoadGame(FALSE); ClrDiabloMsg(); #ifdef HELLFIRE CornerStone.activated = FALSE; #endif PaletteFadeOut(8); deathflag = FALSE; force_redraw = 255; DrawAndBlit(); PaletteFadeIn(8); SetCursor_(CURSOR_HAND); interface_msg_pump(); SetWindowProc(saveProc); } void gamemenu_save_game(BOOL bActivate) { if (pcurs != CURSOR_HAND) { return; } if (plr[myplr]._pmode == PM_DEATH || deathflag) { gamemenu_off(); return; } WNDPROC saveProc = SetWindowProc(DisableInputWndProc); SetCursor_(CURSOR_NONE); gamemenu_off(); InitDiabloMsg(EMSG_SAVING); force_redraw = 255; DrawAndBlit(); SaveGame(); ClrDiabloMsg(); force_redraw = 255; SetCursor_(CURSOR_HAND); #ifdef HELLFIRE if (CornerStone.activated) { CornerstoneSave(); } #endif interface_msg_pump(); SetWindowProc(saveProc); } void gamemenu_restart_town(BOOL bActivate) { NetSendCmd(TRUE, CMD_RETOWN); } static void gamemenu_sound_music_toggle(const char *const *names, TMenuItem *menu_item, int volume) { if (gbSndInited) { menu_item->dwFlags |= GMENU_ENABLED | GMENU_SLIDER; menu_item->pszStr = *names; gmenu_slider_steps(menu_item, 17); gmenu_slider_set(menu_item, VOLUME_MIN, VOLUME_MAX, volume); return; } menu_item->dwFlags &= ~(GMENU_ENABLED | GMENU_SLIDER); menu_item->pszStr = names[1]; } static int gamemenu_slider_music_sound(TMenuItem *menu_item) { return gmenu_slider_get(menu_item, VOLUME_MIN, VOLUME_MAX); } static void gamemenu_get_music() { gamemenu_sound_music_toggle(music_toggle_names, sgOptionsMenu, sound_get_or_set_music_volume(1)); } static void gamemenu_get_sound() { gamemenu_sound_music_toggle(sound_toggle_names, &sgOptionsMenu[1], sound_get_or_set_sound_volume(1)); } #ifdef HELLFIRE static void gamemenu_jogging() { gmenu_slider_steps(&sgOptionsMenu[3], 2); gmenu_slider_set(&sgOptionsMenu[3], 0, 1, jogging_opt); sgOptionsMenu[3].pszStr = jogging_toggle_names[!jogging_opt ? 1 : 0]; } #endif static void gamemenu_get_gamma() { gmenu_slider_steps(&sgOptionsMenu[2], 15); gmenu_slider_set(&sgOptionsMenu[2], 30, 100, UpdateGamma(0)); } #ifndef HELLFIRE static void gamemenu_get_color_cycling() { sgOptionsMenu[3].pszStr = color_cycling_toggle_names[palette_get_color_cycling() & 1]; } #endif static int gamemenu_slider_gamma() { return gmenu_slider_get(&sgOptionsMenu[2], 30, 100); } void gamemenu_options(BOOL bActivate) { gamemenu_get_music(); gamemenu_get_sound(); #ifdef HELLFIRE gamemenu_jogging(); #endif gamemenu_get_gamma(); #ifndef HELLFIRE gamemenu_get_color_cycling(); #endif gmenu_set_items(sgOptionsMenu, NULL); } void gamemenu_music_volume(BOOL bActivate) { int volume; if (bActivate) { if (gbMusicOn) { gbMusicOn = FALSE; music_stop(); sound_get_or_set_music_volume(VOLUME_MIN); } else { gbMusicOn = TRUE; sound_get_or_set_music_volume(VOLUME_MAX); #ifdef HELLFIRE int lt; if (currlevel >= 17) { if (currlevel > 20) lt = DTYPE_NEST; else lt = DTYPE_CRYPT; } else lt = leveltype; music_start(lt); #else music_start(leveltype); #endif } } else { volume = gamemenu_slider_music_sound(&sgOptionsMenu[0]); sound_get_or_set_music_volume(volume); if (volume == VOLUME_MIN) { if (gbMusicOn) { gbMusicOn = FALSE; music_stop(); } } else if (!gbMusicOn) { gbMusicOn = TRUE; #ifdef HELLFIRE int lt; if (currlevel >= 17) { if (currlevel > 20) lt = DTYPE_NEST; else lt = DTYPE_CRYPT; } else lt = leveltype; music_start(lt); #else music_start(leveltype); #endif } } gamemenu_get_music(); } void gamemenu_sound_volume(BOOL bActivate) { int volume; if (bActivate) { if (gbSoundOn) { gbSoundOn = FALSE; sound_stop(); sound_get_or_set_sound_volume(VOLUME_MIN); } else { gbSoundOn = TRUE; sound_get_or_set_sound_volume(VOLUME_MAX); } } else { volume = gamemenu_slider_music_sound(&sgOptionsMenu[1]); sound_get_or_set_sound_volume(volume); if (volume == VOLUME_MIN) { if (gbSoundOn) { gbSoundOn = FALSE; sound_stop(); } } else if (!gbSoundOn) { gbSoundOn = TRUE; } } PlaySFX(IS_TITLEMOV); gamemenu_get_sound(); } #ifdef HELLFIRE void gamemenu_loadjog(BOOL bActivate) { if (gbMaxPlayers == 1) { jogging_opt = !jogging_opt; SRegSaveValue(APP_NAME, jogging_title, FALSE, jogging_opt); PlaySFX(IS_TITLEMOV); gamemenu_jogging(); } } #endif void gamemenu_gamma(BOOL bActivate) { int gamma; if (bActivate) { gamma = UpdateGamma(0); if (gamma == 30) gamma = 100; else gamma = 30; } else { gamma = gamemenu_slider_gamma(); } UpdateGamma(gamma); gamemenu_get_gamma(); } #ifndef HELLFIRE void gamemenu_color_cycling(BOOL bActivate) { BOOL color_cycling; color_cycling = palette_set_color_cycling(palette_get_color_cycling() == 0); sgOptionsMenu[3].pszStr = color_cycling_toggle_names[color_cycling & 1]; } #endif ================================================ FILE: Source/gamemenu.h ================================================ /** * @file gamemenu.h * * Interface of the in-game menu functions. */ #ifndef __GAMEMENU_H__ #define __GAMEMENU_H__ #ifdef HELLFIRE extern char *jogging_title; extern BOOL jogging_opt; #endif void gamemenu_on(); void gamemenu_off(); void gamemenu_handle_previous(); void gamemenu_previous(BOOL bActivate); void gamemenu_new_game(BOOL bActivate); void gamemenu_quit_game(BOOL bActivate); void gamemenu_load_game(BOOL bActivate); void gamemenu_save_game(BOOL bActivate); void gamemenu_restart_town(BOOL bActivate); void gamemenu_options(BOOL bActivate); void gamemenu_music_volume(BOOL bActivate); void gamemenu_sound_volume(BOOL bActivate); #ifdef HELLFIRE void gamemenu_loadjog(BOOL bActivate); #endif void gamemenu_gamma(BOOL bActivate); #ifndef HELLFIRE void gamemenu_color_cycling(BOOL bActivate); #endif #endif /* __GAMEMENU_H__ */ ================================================ FILE: Source/gendung.cpp ================================================ /** * @file gendung.cpp * * Implementation of general dungeon generation code. */ #include "all.h" /** Contains the tile IDs of the map. */ BYTE dungeon[DMAXX][DMAXY]; /** Contains a backup of the tile IDs of the map. */ BYTE pdungeon[DMAXX][DMAXY]; char dflags[DMAXX][DMAXY]; /** Specifies the active set level X-coordinate of the map. */ int setpc_x; /** Specifies the active set level Y-coordinate of the map. */ int setpc_y; /** Specifies the width of the active set level of the map. */ int setpc_w; /** Specifies the height of the active set level of the map. */ int setpc_h; /** Contains the contents of the single player quest DUN file. */ BYTE *pSetPiece; /** Specifies whether a single player quest DUN has been loaded. */ BOOL setloadflag; BYTE *pSpecialCels; /** Specifies the tile definitions of the active dungeon type; (e.g. levels/l1data/l1.til). */ BYTE *pMegaTiles; BYTE *pLevelPieces; BYTE *pDungeonCels; BYTE *pSpeedCels; /** * Returns the frame number of the speed CEL, an in memory decoding * of level CEL frames, based on original frame number and light index. * Note, given light index 0, the original frame number is returned. */ int SpeedFrameTbl[128][16]; /** * List of transparancy masks to use for dPieces */ char block_lvid[MAXTILES + 1]; /** Specifies the CEL frame occurrence for each frame of the level CEL (e.g. "levels/l1data/l1.cel"). */ int level_frame_count[MAXTILES]; int tile_defs[MAXTILES]; /** * Secifies the CEL frame decoder type for each frame of the * level CEL (e.g. "levels/l1data/l1.cel"), Indexed by frame numbers starting at 1. * The decoder type may be one of the following. * 0x0000 - cel.decodeType0 * 0x1000 - cel.decodeType1 * 0x2000 - cel.decodeType2 * 0x3000 - cel.decodeType3 * 0x4000 - cel.decodeType4 * 0x5000 - cel.decodeType5 * 0x6000 - cel.decodeType6 */ WORD level_frame_types[MAXTILES]; /** * Specifies the size of each frame of the level cel (e.g. * "levels/l1data/l1.cel"). Indexed by frame numbers starting at 1. */ int level_frame_sizes[MAXTILES]; /** Specifies the number of frames in the level cel (e.g. "levels/l1data/l1.cel"). */ int nlevel_frames; /** * List of light blocking dPieces */ BOOLEAN nBlockTable[MAXTILES + 1]; /** * List of path blocking dPieces */ BOOLEAN nSolidTable[MAXTILES + 1]; /** * List of transparent dPieces */ BOOLEAN nTransTable[MAXTILES + 1]; /** * List of missile blocking dPieces */ BOOLEAN nMissileTable[MAXTILES + 1]; BOOLEAN nTrapTable[MAXTILES + 1]; /** Specifies the minimum X-coordinate of the map. */ int dminx; /** Specifies the minimum Y-coordinate of the map. */ int dminy; /** Specifies the maximum X-coordinate of the map. */ int dmaxx; /** Specifies the maximum Y-coordinate of the map. */ int dmaxy; int gnDifficulty; /** Specifies the active dungeon type of the current game. */ BYTE leveltype; /** Specifies the active dungeon level of the current game. */ BYTE currlevel; BOOLEAN setlevel; /** Specifies the active quest level of the current game. */ BYTE setlvlnum; char setlvltype; /** Specifies the player viewpoint X-coordinate of the map. */ int ViewX; /** Specifies the player viewpoint Y-coordinate of the map. */ int ViewY; int ViewBX; int ViewBY; int ViewDX; int ViewDY; ScrollStruct ScrollInfo; /** Specifies the level viewpoint X-coordinate of the map. */ int LvlViewX; /** Specifies the level viewpoint Y-coordinate of the map. */ int LvlViewY; int MicroTileLen; char TransVal; /** Specifies the active transparency indices. */ BOOLEAN TransList[256]; /** Contains the piece IDs of each tile on the map. */ int dPiece[MAXDUNX][MAXDUNY]; /** Specifies the dungeon piece information for a given coordinate and block number. */ MICROS dpiece_defs_map_2[MAXDUNX][MAXDUNY]; /** Specifies the dungeon piece information for a given coordinate and block number, optimized for diagonal access. */ MICROS dpiece_defs_map_1[MAXDUNX * MAXDUNY]; /** Specifies the transparency at each coordinate of the map. */ char dTransVal[MAXDUNX][MAXDUNY]; char dLight[MAXDUNX][MAXDUNY]; char dPreLight[MAXDUNX][MAXDUNY]; char dFlags[MAXDUNX][MAXDUNY]; /** Contains the player numbers (players array indices) of the map. */ char dPlayer[MAXDUNX][MAXDUNY]; /** * Contains the NPC numbers of the map. The NPC number represents a * towner number (towners array index) in Tristram and a monster number * (monsters array index) in the dungeon. */ int dMonster[MAXDUNX][MAXDUNY]; /** * Contains the dead numbers (deads array indices) and dead direction of * the map, encoded as specified by the pseudo-code below. * dDead[x][y] & 0x1F - index of dead * dDead[x][y] >> 0x5 - direction */ char dDead[MAXDUNX][MAXDUNY]; /** Contains the object numbers (objects array indices) of the map. */ char dObject[MAXDUNX][MAXDUNY]; /** Contains the item numbers (items array indices) of the map. */ char dItem[MAXDUNX][MAXDUNY]; /** Contains the missile numbers (missiles array indices) of the map. */ char dMissile[MAXDUNX][MAXDUNY]; /** * Contains the arch frame numbers of the map from the special tileset * (e.g. "levels/l1data/l1s.cel"). Note, the special tileset of Tristram (i.e. * "levels/towndata/towns.cel") contains trees rather than arches. */ char dSpecial[MAXDUNX][MAXDUNY]; int themeCount; THEME_LOC themeLoc[MAXTHEMES]; void FillSolidBlockTbls() { BYTE bv; DWORD dwTiles; BYTE *pSBFile, *pTmp; int i; memset(nBlockTable, 0, sizeof(nBlockTable)); memset(nSolidTable, 0, sizeof(nSolidTable)); memset(nTransTable, 0, sizeof(nTransTable)); memset(nMissileTable, 0, sizeof(nMissileTable)); memset(nTrapTable, 0, sizeof(nTrapTable)); switch (leveltype) { case DTYPE_TOWN: #ifdef HELLFIRE pSBFile = LoadFileInMem("NLevels\\TownData\\Town.SOL", &dwTiles); #else pSBFile = LoadFileInMem("Levels\\TownData\\Town.SOL", &dwTiles); #endif break; case DTYPE_CATHEDRAL: #ifdef HELLFIRE if (currlevel < 17) pSBFile = LoadFileInMem("Levels\\L1Data\\L1.SOL", &dwTiles); else pSBFile = LoadFileInMem("NLevels\\L5Data\\L5.SOL", &dwTiles); #else pSBFile = LoadFileInMem("Levels\\L1Data\\L1.SOL", &dwTiles); #endif break; case DTYPE_CATACOMBS: pSBFile = LoadFileInMem("Levels\\L2Data\\L2.SOL", &dwTiles); break; case DTYPE_CAVES: #ifdef HELLFIRE if (currlevel < 17) pSBFile = LoadFileInMem("Levels\\L3Data\\L3.SOL", &dwTiles); else pSBFile = LoadFileInMem("NLevels\\L6Data\\L6.SOL", &dwTiles); #else pSBFile = LoadFileInMem("Levels\\L3Data\\L3.SOL", &dwTiles); #endif break; case DTYPE_HELL: pSBFile = LoadFileInMem("Levels\\L4Data\\L4.SOL", &dwTiles); break; default: app_fatal("FillSolidBlockTbls"); } pTmp = pSBFile; for (i = 1; i <= dwTiles; i++) { bv = *pTmp++; if (bv & 1) nSolidTable[i] = TRUE; if (bv & 2) nBlockTable[i] = TRUE; if (bv & 4) nMissileTable[i] = TRUE; if (bv & 8) nTransTable[i] = TRUE; if (bv & 0x80) nTrapTable[i] = TRUE; block_lvid[i] = (bv & 0x70) >> 4; /* beta: (bv >> 4) & 7 */ } mem_free_dbg(pSBFile); } static void SwapTile(int f1, int f2) { int swap; swap = level_frame_count[f1]; level_frame_count[f1] = level_frame_count[f2]; level_frame_count[f2] = swap; swap = tile_defs[f1]; tile_defs[f1] = tile_defs[f2]; tile_defs[f2] = swap; swap = level_frame_types[f1]; level_frame_types[f1] = level_frame_types[f2]; level_frame_types[f2] = swap; swap = level_frame_sizes[f1]; level_frame_sizes[f1] = level_frame_sizes[f2]; level_frame_sizes[f2] = swap; } static void SortTiles(int frames) { int i; BOOL doneflag; doneflag = FALSE; while (frames > 0 && !doneflag) { doneflag = TRUE; for (i = 0; i < frames; i++) { if (level_frame_count[i] < level_frame_count[i + 1]) { SwapTile(i, i + 1); doneflag = FALSE; } } frames--; } } void MakeSpeedCels() { int i, j, x, y, mt, t, z; int total_frames, blocks, total_size, frameidx, blk_cnt, nDataSize; WORD m; BOOL blood_flag; DWORD *pFrameTable; MICROS *pMap; #ifndef USE_ASM int l, k; BYTE width, pix; BYTE *src, *dst, *tbl; #endif for (i = 0; i < MAXTILES; i++) { tile_defs[i] = i; level_frame_count[i] = 0; level_frame_types[i] = 0; } if (leveltype != DTYPE_HELL) blocks = 10; else blocks = 12; for (y = 0; y < MAXDUNY; y++) { for (x = 0; x < MAXDUNX; x++) { pMap = &dpiece_defs_map_2[x][y]; for (j = 0; j < blocks; j++) { mt = pMap->mt[j]; if (mt) { level_frame_count[pMap->mt[j] & 0xFFF]++; level_frame_types[pMap->mt[j] & 0xFFF] = mt & 0x7000; } } } } #if defined HELLFIRE && defined USE_ASM __asm { mov ebx, pDungeonCels mov eax, [ebx] mov nDataSize, eax } #else pFrameTable = (DWORD *)pDungeonCels; nDataSize = pFrameTable[0]; #endif nlevel_frames = nDataSize & 0xFFFF; #ifdef HELLFIRE for (i = 0; i < nlevel_frames; i++) { #else for (i = 1; i < nlevel_frames; i++) { #endif z = i; #ifdef USE_ASM __asm { mov ebx, pDungeonCels mov eax, z shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov nDataSize, eax } #else nDataSize = pFrameTable[i + 1] - pFrameTable[i]; #endif level_frame_sizes[i] = nDataSize & 0xFFFF; } level_frame_sizes[0] = 0; if (leveltype == DTYPE_HELL) { for (i = 0; i < nlevel_frames; i++) { #ifndef HELLFIRE if (i == 0) level_frame_count[0] = 0; #endif z = i; blood_flag = TRUE; if (level_frame_count[i] != 0) { if (level_frame_types[i] != 0x1000) { #ifdef USE_ASM t = level_frame_sizes[i]; __asm { mov ebx, pDungeonCels mov eax, z shl eax, 2 add ebx, eax mov esi, pDungeonCels add esi, [ebx] xor ebx, ebx mov ecx, t jecxz l1_label3 l1_label1: lodsb cmp al, 0 jz l1_label2 cmp al, 32 jnb l1_label2 mov blood_flag, ebx l1_label2: loop l1_label1 l1_label3: nop } #else src = &pDungeonCels[pFrameTable[i]]; for (j = level_frame_sizes[i]; j; j--) { pix = *src++; if (pix && pix < 32) blood_flag = FALSE; } #endif } else { #ifdef USE_ASM __asm { mov ebx, pDungeonCels mov eax, z shl eax, 2 add ebx, eax mov esi, pDungeonCels add esi, [ebx] xor ebx, ebx mov ecx, 32 l2_label1: push ecx mov edx, 32 l2_label2: xor eax, eax lodsb or al, al js l2_label5 sub edx, eax mov ecx, eax l2_label3: lodsb cmp al, 0 jz l2_label4 cmp al, 32 jnb l2_label4 mov blood_flag, ebx l2_label4: loop l2_label3 or edx, edx jz l2_label6 jmp l2_label2 l2_label5: neg al sub edx, eax jnz l2_label2 l2_label6: pop ecx loop l2_label1 } #else src = &pDungeonCels[pFrameTable[i]]; for (k = 32; k; k--) { for (l = 32; l;) { width = *src++; if (!(width & 0x80)) { l -= width; while (width) { pix = *src++; if (pix && pix < 32) blood_flag = FALSE; width--; } } else { width = -(char)width; l -= width; } } } #endif } if (!blood_flag) level_frame_count[i] = 0; } } } SortTiles(MAXTILES - 1); total_size = 0; total_frames = 0; if (light4flag) { while (total_size < 0x100000) { total_size += level_frame_sizes[total_frames] << 1; total_frames++; } } else { while (total_size < 0x100000) { total_size += (level_frame_sizes[total_frames] << 4) - (level_frame_sizes[total_frames] << 1); total_frames++; } } total_frames--; if (total_frames > 128) total_frames = 128; frameidx = 0; if (light4flag) blk_cnt = 3; else blk_cnt = 15; for (i = 0; i < total_frames; i++) { z = tile_defs[i]; SpeedFrameTbl[i][0] = z; if (level_frame_types[i] != 0x1000) { t = level_frame_sizes[i]; for (j = 1; j < blk_cnt; j++) { SpeedFrameTbl[i][j] = frameidx; #ifdef USE_ASM __asm { mov ebx, pDungeonCels mov eax, z shl eax, 2 add ebx, eax mov esi, pDungeonCels add esi, [ebx] mov edi, pSpeedCels add edi, frameidx mov ebx, j shl ebx, 8 add ebx, pLightTbl mov ecx, t jecxz l3_label2 l3_label1: lodsb xlat stosb loop l3_label1 l3_label2: nop } #else src = &pDungeonCels[pFrameTable[z]]; dst = &pSpeedCels[frameidx]; tbl = &pLightTbl[256 * j]; for (k = t; k; k--) { *dst++ = tbl[*src++]; } #endif frameidx += t; } } else { for (j = 1; j < blk_cnt; j++) { SpeedFrameTbl[i][j] = frameidx; #ifdef USE_ASM __asm { mov ebx, pDungeonCels mov eax, z shl eax, 2 add ebx, eax mov esi, pDungeonCels add esi, [ebx] mov edi, pSpeedCels add edi, frameidx mov ebx, j shl ebx, 8 add ebx, pLightTbl mov ecx, 32 l4_label1: push ecx mov edx, 32 l4_label2: xor eax, eax lodsb stosb or al, al js l4_label4 sub edx, eax mov ecx, eax l4_label3: lodsb xlat stosb loop l4_label3 or edx, edx jz l4_label5 jmp l4_label2 l4_label4: neg al sub edx, eax jnz l4_label2 l4_label5: pop ecx loop l4_label1 } #else src = &pDungeonCels[pFrameTable[z]]; dst = &pSpeedCels[frameidx]; tbl = &pLightTbl[256 * j]; for (k = 32; k; k--) { for (l = 32; l;) { width = *src++; *dst++ = width; if (!(width & 0x80)) { l -= width; while (width) { *dst++ = tbl[*src++]; width--; } } else { width = -(char)width; l -= width; } } } #endif frameidx += level_frame_sizes[i]; } } } for (y = 0; y < MAXDUNY; y++) { for (x = 0; x < MAXDUNX; x++) { if (dPiece[x][y] != 0) { pMap = &dpiece_defs_map_2[x][y]; for (i = 0; i < blocks; i++) { if (pMap->mt[i]) { for (m = 0; m < total_frames; m++) { if ((pMap->mt[i] & 0xFFF) == tile_defs[m]) { pMap->mt[i] = m + level_frame_types[m] + 0x8000; m = total_frames; } } } } } } } } int IsometricCoord(int x, int y) { if (x < MAXDUNY - y) return (y + y * y + x * (x + 2 * y + 3)) / 2; x = MAXDUNX - x - 1; y = MAXDUNY - y - 1; return MAXDUNX * MAXDUNY - ((y + y * y + x * (x + 2 * y + 3)) / 2) - 1; } void SetSpeedCels() { int x, y; for (x = 0; x < MAXDUNX; x++) { for (y = 0; y < MAXDUNY; y++) { dpiece_defs_map_1[IsometricCoord(x, y)] = dpiece_defs_map_2[x][y]; } } } void SetDungeonMicros() { int i, x, y, lv, blocks; WORD *pPiece; MICROS *pMap; if (leveltype != DTYPE_HELL) { MicroTileLen = 10; blocks = 10; } else { MicroTileLen = 12; blocks = 16; } for (y = 0; y < MAXDUNY; y++) { for (x = 0; x < MAXDUNX; x++) { lv = dPiece[x][y]; pMap = &dpiece_defs_map_2[x][y]; if (lv != 0) { lv--; if (leveltype != DTYPE_HELL) pPiece = (WORD *)&pLevelPieces[20 * lv]; else pPiece = (WORD *)&pLevelPieces[32 * lv]; for (i = 0; i < blocks; i++) pMap->mt[i] = pPiece[(i & 1) + blocks - 2 - (i & 0xE)]; } else { for (i = 0; i < blocks; i++) pMap->mt[i] = 0; } } } MakeSpeedCels(); SetSpeedCels(); if (zoomflag) { ViewDX = SCREEN_WIDTH; ViewDY = VIEWPORT_HEIGHT; ViewBX = SCREEN_WIDTH / TILE_WIDTH; ViewBY = VIEWPORT_HEIGHT / TILE_HEIGHT; } else { ViewDX = ZOOM_WIDTH; ViewDY = ZOOM_HEIGHT; ViewBX = ZOOM_WIDTH / TILE_WIDTH; ViewBY = ZOOM_HEIGHT / TILE_HEIGHT; } } void DRLG_InitTrans() { memset(dTransVal, 0, sizeof(dTransVal)); memset(TransList, 0, sizeof(TransList)); TransVal = 1; } void DRLG_MRectTrans(int x1, int y1, int x2, int y2) { int i, j; x1 = 2 * x1 + 17; y1 = 2 * y1 + 17; x2 = 2 * x2 + 16; y2 = 2 * y2 + 16; for (j = y1; j <= y2; j++) { for (i = x1; i <= x2; i++) { dTransVal[i][j] = TransVal; } } TransVal++; } void DRLG_RectTrans(int x1, int y1, int x2, int y2) { int i, j; for (j = y1; j <= y2; j++) { for (i = x1; i <= x2; i++) { dTransVal[i][j] = TransVal; } } TransVal++; } void DRLG_CopyTrans(int sx, int sy, int dx, int dy) { dTransVal[dx][dy] = dTransVal[sx][sy]; } #ifndef SPAWN void DRLG_ListTrans(int num, BYTE *List) { int i; BYTE x1, y1, x2, y2; for (i = 0; i < num; i++) { x1 = *List++; y1 = *List++; x2 = *List++; y2 = *List++; DRLG_RectTrans(x1, y1, x2, y2); } } void DRLG_AreaTrans(int num, BYTE *List) { int i; BYTE x1, y1, x2, y2; for (i = 0; i < num; i++) { x1 = *List++; y1 = *List++; x2 = *List++; y2 = *List++; DRLG_RectTrans(x1, y1, x2, y2); TransVal--; } TransVal++; } #endif void DRLG_InitSetPC() { setpc_x = 0; setpc_y = 0; setpc_w = 0; setpc_h = 0; } void DRLG_SetPC() { int i, j, x, y, w, h; w = 2 * setpc_w; h = 2 * setpc_h; x = 2 * setpc_x + 16; y = 2 * setpc_y + 16; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { dFlags[i + x][j + y] |= BFLAG_POPULATED; } } } #ifndef SPAWN void Make_SetPC(int x, int y, int w, int h) { int i, j, dx, dy, dh, dw; dw = 2 * w; dh = 2 * h; dx = 2 * x + 16; dy = 2 * y + 16; for (j = 0; j < dh; j++) { for (i = 0; i < dw; i++) { dFlags[i + dx][j + dy] |= BFLAG_POPULATED; } } } BOOL DRLG_WillThemeRoomFit(int floor, int x, int y, int minSize, int maxSize, int *width, int *height) { int ii, xx, yy; int xSmallest, ySmallest; int xArray[20], yArray[20]; int xCount, yCount; BOOL yFlag, xFlag; yFlag = TRUE; xFlag = TRUE; xCount = 0; yCount = 0; // BUGFIX: incorrect out-of-bounds check, should check that `dungeon[xx][y + ii]` is not out-of-bounds in loop. if (x > DMAXX - maxSize && y > DMAXY - maxSize) { return FALSE; } if (!SkipThemeRoom(x, y)) { return FALSE; } memset(xArray, 0, sizeof(xArray)); memset(yArray, 0, sizeof(yArray)); for (ii = 0; ii < maxSize; ii++) { if (xFlag) { for (xx = x; xx < x + maxSize; xx++) { if (dungeon[xx][y + ii] != floor) { if (xx >= minSize) { // BUGFIX: This is comparing absolute to relative, should be `xx - x >= minSize` break; } xFlag = FALSE; } else { xCount++; } } if (xFlag) { xArray[ii] = xCount; xCount = 0; } } if (yFlag) { for (yy = y; yy < y + maxSize; yy++) { if (dungeon[x + ii][yy] != floor) { if (yy >= minSize) { // BUGFIX: This is comparing absolute to relative, should be `yy - y >= minSize` break; } yFlag = FALSE; } else { yCount++; } } if (yFlag) { yArray[ii] = yCount; yCount = 0; } } } for (ii = 0; ii < minSize; ii++) { if (xArray[ii] < minSize || yArray[ii] < minSize) { return FALSE; } } xSmallest = xArray[0]; ySmallest = yArray[0]; for (ii = 0; ii < maxSize; ii++) { if (xArray[ii] < minSize || yArray[ii] < minSize) { break; } if (xArray[ii] < xSmallest) { xSmallest = xArray[ii]; } if (yArray[ii] < ySmallest) { ySmallest = yArray[ii]; } } *width = xSmallest - 2; *height = ySmallest - 2; return TRUE; } void DRLG_CreateThemeRoom(int themeIndex) { int xx, yy; for (yy = themeLoc[themeIndex].y; yy < themeLoc[themeIndex].y + themeLoc[themeIndex].height; yy++) { for (xx = themeLoc[themeIndex].x; xx < themeLoc[themeIndex].x + themeLoc[themeIndex].width; xx++) { if (leveltype == DTYPE_CATACOMBS) { if (yy == themeLoc[themeIndex].y && xx >= themeLoc[themeIndex].x && xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width || yy == themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1 && xx >= themeLoc[themeIndex].x && xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width) { dungeon[xx][yy] = 2; } else if (xx == themeLoc[themeIndex].x && yy >= themeLoc[themeIndex].y && yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height || xx == themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1 && yy >= themeLoc[themeIndex].y && yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height) { dungeon[xx][yy] = 1; } else { dungeon[xx][yy] = 3; } } if (leveltype == DTYPE_CAVES) { if (yy == themeLoc[themeIndex].y && xx >= themeLoc[themeIndex].x && xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width || yy == themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1 && xx >= themeLoc[themeIndex].x && xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width) { dungeon[xx][yy] = 134; } else if (xx == themeLoc[themeIndex].x && yy >= themeLoc[themeIndex].y && yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height || xx == themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1 && yy >= themeLoc[themeIndex].y && yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height) { dungeon[xx][yy] = 137; } else { dungeon[xx][yy] = 7; } } if (leveltype == DTYPE_HELL) { if (yy == themeLoc[themeIndex].y && xx >= themeLoc[themeIndex].x && xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width || yy == themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1 && xx >= themeLoc[themeIndex].x && xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width) { dungeon[xx][yy] = 2; } else if (xx == themeLoc[themeIndex].x && yy >= themeLoc[themeIndex].y && yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height || xx == themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1 && yy >= themeLoc[themeIndex].y && yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height) { dungeon[xx][yy] = 1; } else { dungeon[xx][yy] = 6; } } } } if (leveltype == DTYPE_CATACOMBS) { dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y] = 8; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y] = 7; dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 9; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 6; } if (leveltype == DTYPE_CAVES) { dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y] = 150; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y] = 151; dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 152; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 138; } if (leveltype == DTYPE_HELL) { dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y] = 9; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y] = 16; dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 15; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 12; } if (leveltype == DTYPE_CATACOMBS) { switch (random_(0, 2)) { case 0: dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height / 2] = 4; break; case 1: dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width / 2][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 5; break; } } if (leveltype == DTYPE_CAVES) { switch (random_(0, 2)) { case 0: dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height / 2] = 147; break; case 1: dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width / 2][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 146; break; } } if (leveltype == DTYPE_HELL) { switch (random_(0, 2)) { case 0: dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height / 2 - 1] = 53; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height / 2] = 6; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height / 2 + 1] = 52; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width - 2][themeLoc[themeIndex].y + themeLoc[themeIndex].height / 2 - 1] = 54; break; case 1: dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width / 2 - 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 57; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width / 2][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 6; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width / 2 + 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 1] = 56; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width / 2][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 2] = 59; dungeon[themeLoc[themeIndex].x + themeLoc[themeIndex].width / 2 - 1][themeLoc[themeIndex].y + themeLoc[themeIndex].height - 2] = 58; break; } } } void DRLG_PlaceThemeRooms(int minSize, int maxSize, int floor, int freq, int rndSize) { int i, j; int themeW, themeH; int rv2, min, max; themeCount = 0; memset(themeLoc, 0, sizeof(*themeLoc)); for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dungeon[i][j] == floor && !random_(0, freq) && DRLG_WillThemeRoomFit(floor, i, j, minSize, maxSize, &themeW, &themeH)) { if (rndSize) { min = minSize - 2; max = maxSize - 2; rv2 = min + random_(0, random_(0, themeW - min + 1)); if (rv2 >= min && rv2 <= max) themeW = rv2; else themeW = min; rv2 = min + random_(0, random_(0, themeH - min + 1)); if (rv2 >= min && rv2 <= max) themeH = rv2; else themeH = min; } themeLoc[themeCount].x = i + 1; themeLoc[themeCount].y = j + 1; themeLoc[themeCount].width = themeW; themeLoc[themeCount].height = themeH; if (leveltype == DTYPE_CAVES) DRLG_RectTrans(2 * i + 20, 2 * j + 20, 2 * (i + themeW) + 15, 2 * (j + themeH) + 15); else DRLG_MRectTrans(i + 1, j + 1, i + themeW, j + themeH); themeLoc[themeCount].ttval = TransVal - 1; DRLG_CreateThemeRoom(themeCount); themeCount++; } } } } #endif void DRLG_HoldThemeRooms() { int i, x, y, xx, yy; for (i = 0; i < themeCount; i++) { for (y = themeLoc[i].y; y < themeLoc[i].y + themeLoc[i].height - 1; y++) { for (x = themeLoc[i].x; x < themeLoc[i].x + themeLoc[i].width - 1; x++) { xx = 2 * x + 16; yy = 2 * y + 16; dFlags[xx][yy] |= BFLAG_POPULATED; dFlags[xx + 1][yy] |= BFLAG_POPULATED; dFlags[xx][yy + 1] |= BFLAG_POPULATED; dFlags[xx + 1][yy + 1] |= BFLAG_POPULATED; } } } } BOOL SkipThemeRoom(int x, int y) { int i; for (i = 0; i < themeCount; i++) { if (x >= themeLoc[i].x - 2 && x <= themeLoc[i].x + themeLoc[i].width + 2 && y >= themeLoc[i].y - 2 && y <= themeLoc[i].y + themeLoc[i].height + 2) return FALSE; } return TRUE; } void InitLevels() { if (!leveldebug) { currlevel = 0; leveltype = DTYPE_TOWN; setlevel = FALSE; } } ================================================ FILE: Source/gendung.h ================================================ /** * @file gendung.h * * Interface of general dungeon generation code. */ #ifndef __GENDUNG_H__ #define __GENDUNG_H__ extern BYTE dungeon[DMAXX][DMAXY]; extern BYTE pdungeon[DMAXX][DMAXY]; extern char dflags[DMAXX][DMAXY]; extern int setpc_x; extern int setpc_y; extern int setpc_w; extern int setpc_h; extern BYTE *pSetPiece; extern BOOL setloadflag; extern BYTE *pSpecialCels; extern BYTE *pMegaTiles; extern BYTE *pLevelPieces; extern BYTE *pDungeonCels; extern BYTE *pSpeedCels; extern int SpeedFrameTbl[128][16]; extern char block_lvid[MAXTILES + 1]; extern BOOLEAN nBlockTable[MAXTILES + 1]; extern BOOLEAN nSolidTable[MAXTILES + 1]; extern BOOLEAN nTransTable[MAXTILES + 1]; extern BOOLEAN nMissileTable[MAXTILES + 1]; extern BOOLEAN nTrapTable[MAXTILES + 1]; extern int dminx; extern int dminy; extern int dmaxx; extern int dmaxy; extern int gnDifficulty; extern BYTE leveltype; extern BYTE currlevel; extern BOOLEAN setlevel; extern BYTE setlvlnum; extern char setlvltype; extern int ViewX; extern int ViewY; extern int ViewBX; extern int ViewBY; extern int ViewDX; extern int ViewDY; extern ScrollStruct ScrollInfo; extern int LvlViewX; extern int LvlViewY; extern int MicroTileLen; extern char TransVal; extern BOOLEAN TransList[256]; extern int dPiece[MAXDUNX][MAXDUNY]; extern MICROS dpiece_defs_map_2[MAXDUNX][MAXDUNY]; extern MICROS dpiece_defs_map_1[MAXDUNX * MAXDUNY]; extern char dTransVal[MAXDUNX][MAXDUNY]; extern char dLight[MAXDUNX][MAXDUNY]; extern char dPreLight[MAXDUNX][MAXDUNY]; extern char dFlags[MAXDUNX][MAXDUNY]; extern char dPlayer[MAXDUNX][MAXDUNY]; extern int dMonster[MAXDUNX][MAXDUNY]; extern char dDead[MAXDUNX][MAXDUNY]; extern char dObject[MAXDUNX][MAXDUNY]; extern char dItem[MAXDUNX][MAXDUNY]; extern char dMissile[MAXDUNX][MAXDUNY]; extern char dSpecial[MAXDUNX][MAXDUNY]; extern int themeCount; extern THEME_LOC themeLoc[MAXTHEMES]; void FillSolidBlockTbls(); int IsometricCoord(int x, int y); void SetDungeonMicros(); void DRLG_InitTrans(); void DRLG_MRectTrans(int x1, int y1, int x2, int y2); void DRLG_RectTrans(int x1, int y1, int x2, int y2); void DRLG_CopyTrans(int sx, int sy, int dx, int dy); void DRLG_ListTrans(int num, BYTE *List); void DRLG_AreaTrans(int num, BYTE *List); void DRLG_InitSetPC(); void DRLG_SetPC(); void Make_SetPC(int x, int y, int w, int h); void DRLG_PlaceThemeRooms(int minSize, int maxSize, int floor, int freq, int rndSize); void DRLG_HoldThemeRooms(); BOOL SkipThemeRoom(int x, int y); void InitLevels(); #endif /* __GENDUNG_H__ */ ================================================ FILE: Source/gmenu.cpp ================================================ /** * @file gmenu.cpp * * Implementation of the in-game navigation and interaction. */ #include "all.h" BYTE *optbar_cel; BOOLEAN mouseNavigation; BYTE *PentSpin_cel; TMenuItem *sgpCurrItem; BYTE *BigTGold_cel; #ifdef HELLFIRE int LogoAnim_tick; BYTE LogoAnim_frame; #endif int PentSpin_tick; BYTE PentSpin_frame; void (*gmenu_current_option)(TMenuItem *); TMenuItem *sgpCurrentMenu; BYTE *option_cel; BYTE *sgpLogo; int sgCurrentMenuIdx; /** Maps from font index to bigtgold.cel frame number. */ const BYTE lfontframe[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0 }; /** Maps from bigtgold.cel frame number to character width. */ const BYTE lfontkern[] = { 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 }; static void gmenu_print_text(int x, int y, const char *pszStr) { BYTE c; while (*pszStr) { c = gbFontTransTbl[(BYTE)*pszStr++]; c = lfontframe[c]; if (c != 0) CelDrawLight(x, y, BigTGold_cel, c, 46); x += lfontkern[c] + 2; } } void gmenu_draw_pause() { if (currlevel != 0) RedBack(); if (!sgpCurrentMenu) { light_table_index = 0; gmenu_print_text(316 + PANEL_LEFT, 336, "Pause"); } } void FreeGMenu() { MemFreeDbg(sgpLogo); MemFreeDbg(BigTGold_cel); MemFreeDbg(PentSpin_cel); MemFreeDbg(option_cel); MemFreeDbg(optbar_cel); } void gmenu_init_menu() { PentSpin_frame = 1; #ifdef HELLFIRE LogoAnim_frame = 1; #endif sgpCurrentMenu = NULL; sgpCurrItem = NULL; gmenu_current_option = NULL; sgCurrentMenuIdx = 0; mouseNavigation = FALSE; #ifdef HELLFIRE sgpLogo = LoadFileInMem("Data\\hf_logo3.CEL", NULL); #else sgpLogo = LoadFileInMem("Data\\Diabsmal.CEL", NULL); #endif BigTGold_cel = LoadFileInMem("Data\\BigTGold.CEL", NULL); PentSpin_cel = LoadFileInMem("Data\\PentSpin.CEL", NULL); option_cel = LoadFileInMem("Data\\option.CEL", NULL); optbar_cel = LoadFileInMem("Data\\optbar.CEL", NULL); } BOOL gmenu_is_active() { return sgpCurrentMenu != NULL; } static void gmenu_up_down(BOOL isDown) { int i; if (!sgpCurrItem) { return; } mouseNavigation = FALSE; i = sgCurrentMenuIdx; if (sgCurrentMenuIdx) { while (i) { i--; if (isDown) { sgpCurrItem++; if (!sgpCurrItem->fnMenu) sgpCurrItem = &sgpCurrentMenu[0]; } else { if (sgpCurrItem == sgpCurrentMenu) sgpCurrItem = &sgpCurrentMenu[sgCurrentMenuIdx]; sgpCurrItem--; } if ((sgpCurrItem->dwFlags & GMENU_ENABLED) != 0) { if (i) PlaySFX(IS_TITLEMOV); return; } } } } void gmenu_set_items(TMenuItem *pItem, void (*gmFunc)(TMenuItem *)) { int i; PauseMode = 0; mouseNavigation = FALSE; sgpCurrentMenu = pItem; gmenu_current_option = gmFunc; if (gmFunc) { gmenu_current_option(sgpCurrentMenu); pItem = sgpCurrentMenu; } sgCurrentMenuIdx = 0; if (sgpCurrentMenu) { for (i = 0; sgpCurrentMenu[i].fnMenu; i++) { sgCurrentMenuIdx++; } } // BUGFIX: OOB access when sgCurrentMenuIdx is 0; should be set to NULL instead. sgpCurrItem = &sgpCurrentMenu[sgCurrentMenuIdx - 1]; gmenu_up_down(TRUE); } static void gmenu_clear_buffer(int x, int y, int width, int height) { BYTE *i; i = gpBuffer + PitchTbl[y] + x; while (height--) { memset(i, 205, width); i -= BUFFER_WIDTH; } } static int gmenu_get_lfont(TMenuItem *pItem) { const char *text; int i; BYTE c; if (pItem->dwFlags & GMENU_SLIDER) return 490; text = pItem->pszStr; i = 0; while (*text) { c = gbFontTransTbl[(BYTE)*text++]; i += lfontkern[lfontframe[c]] + 2; } return i - 2; } static void gmenu_draw_menu_item(TMenuItem *pItem, int y) { DWORD w, x, nSteps, step, pos, t; #ifndef HELLFIRE t = y - 2; #endif w = gmenu_get_lfont(pItem); if (pItem->dwFlags & GMENU_SLIDER) { x = 16 + w / 2 + SCREEN_X; #ifdef HELLFIRE CelDraw(x + PANEL_LEFT, y - 10, optbar_cel, 1, 287); #else CelDraw(x + PANEL_LEFT, t - 8, optbar_cel, 1, 287); #endif step = pItem->dwFlags & 0xFFF; nSteps = (pItem->dwFlags & 0xFFF000) >> 12; if (nSteps < 2) nSteps = 2; pos = step * 256 / nSteps; #ifdef HELLFIRE gmenu_clear_buffer(x + 2 + PANEL_LEFT, y - 12, pos + 13, 28); #else gmenu_clear_buffer(x + 2 + PANEL_LEFT, t - 10, pos + 13, 28); #endif CelDraw(x + 2 + pos + PANEL_LEFT, y - 12, option_cel, 1, 27); } x = SCREEN_WIDTH / 2 - w / 2 + SCREEN_X; light_table_index = (pItem->dwFlags & GMENU_ENABLED) ? 0 : 15; gmenu_print_text(x, y, pItem->pszStr); if (pItem == sgpCurrItem) { CelDraw(x - 54, y + 1, PentSpin_cel, PentSpin_frame, 48); CelDraw(x + 4 + w, y + 1, PentSpin_cel, PentSpin_frame, 48); } } void gmenu_draw() { int y; TMenuItem *i; DWORD ticks; if (sgpCurrentMenu) { if (gmenu_current_option) gmenu_current_option(sgpCurrentMenu); #ifdef HELLFIRE ticks = GetTickCount(); if ((int)(ticks - LogoAnim_tick) > 25) { LogoAnim_frame++; if (LogoAnim_frame > 16) LogoAnim_frame = 1; LogoAnim_tick = ticks; } CelDraw((SCREEN_WIDTH - 430) / 2 + SCREEN_X, 102 + SCREEN_Y, sgpLogo, LogoAnim_frame, 430); #else CelDraw((SCREEN_WIDTH - 296) / 2 + SCREEN_X, 102 + SCREEN_Y, sgpLogo, 1, 296); #endif y = 160 + SCREEN_Y; i = sgpCurrentMenu; if (sgpCurrentMenu->fnMenu) { while (i->fnMenu) { gmenu_draw_menu_item(i, y); i++; y += 45; } } #ifndef HELLFIRE ticks = GetTickCount(); #endif if ((int)(ticks - PentSpin_tick) > 25) { // BUGFIX: thould be 50ms PentSpin_frame++; if (PentSpin_frame == 9) PentSpin_frame = 1; PentSpin_tick = ticks; } } } static void gmenu_left_right(BOOL isRight) { int step, steps; if (!(sgpCurrItem->dwFlags & GMENU_SLIDER)) return; step = sgpCurrItem->dwFlags & 0xFFF; steps = (int)(sgpCurrItem->dwFlags & 0xFFF000) >> 12; if (isRight) { if (step == steps) return; step++; } else { if (step == 0) return; step--; } sgpCurrItem->dwFlags &= 0xFFFFF000; sgpCurrItem->dwFlags |= step; sgpCurrItem->fnMenu(FALSE); } BOOL gmenu_presskeys(int vkey) { if (!sgpCurrentMenu) return FALSE; switch (vkey) { case VK_RETURN: if ((sgpCurrItem->dwFlags & GMENU_ENABLED) != 0) { PlaySFX(IS_TITLEMOV); sgpCurrItem->fnMenu(TRUE); } break; case VK_ESCAPE: PlaySFX(IS_TITLEMOV); gmenu_set_items(NULL, NULL); break; case VK_SPACE: return FALSE; case VK_LEFT: gmenu_left_right(FALSE); break; case VK_RIGHT: gmenu_left_right(TRUE); break; case VK_UP: gmenu_up_down(FALSE); break; case VK_DOWN: gmenu_up_down(TRUE); break; } return TRUE; } static BOOLEAN gmenu_get_mouse_slider(int *plOffset) { *plOffset = 282; if (MouseX < 282 + PANEL_LEFT) { *plOffset = 0; return FALSE; } if (MouseX > 538 + PANEL_LEFT) { *plOffset = 256; return FALSE; } *plOffset = MouseX - 282 - PANEL_LEFT; return TRUE; } BOOL gmenu_on_mouse_move() { int step, nSteps; if (!mouseNavigation) return FALSE; gmenu_get_mouse_slider(&step); nSteps = (int)(sgpCurrItem->dwFlags & 0xFFF000) >> 12; step *= nSteps; step /= 256; sgpCurrItem->dwFlags &= 0xFFFFF000; sgpCurrItem->dwFlags |= step; sgpCurrItem->fnMenu(FALSE); return TRUE; } BOOL gmenu_left_mouse(BOOL isDown) { TMenuItem *pItem; DWORD i, w; int dummy; if (!isDown) { if (mouseNavigation) { mouseNavigation = FALSE; return TRUE; } else { return FALSE; } } if (!sgpCurrentMenu) { return FALSE; } if (MouseY >= PANEL_TOP) { return FALSE; } if (MouseY - 117 < 0) { return TRUE; } i = (MouseY - 117) / 45; if (i >= sgCurrentMenuIdx) { return TRUE; } pItem = &sgpCurrentMenu[i]; if (!(sgpCurrentMenu[i].dwFlags & GMENU_ENABLED)) { return TRUE; } w = gmenu_get_lfont(pItem); if (MouseX < SCREEN_WIDTH / 2 - w / 2) { return TRUE; } if (MouseX > SCREEN_WIDTH / 2 + w / 2) { return TRUE; } sgpCurrItem = pItem; PlaySFX(IS_TITLEMOV); if (pItem->dwFlags & GMENU_SLIDER) { mouseNavigation = gmenu_get_mouse_slider(&dummy); gmenu_on_mouse_move(); } else { sgpCurrItem->fnMenu(TRUE); } return TRUE; } void gmenu_enable(TMenuItem *pMenuItem, BOOL enable) { if (enable) pMenuItem->dwFlags |= GMENU_ENABLED; else pMenuItem->dwFlags &= ~GMENU_ENABLED; } /** * @brief Set the TMenuItem slider position based on the given value */ void gmenu_slider_set(TMenuItem *pItem, int min, int max, int value) { int nSteps; assert(pItem); nSteps = (int)(pItem->dwFlags & 0xFFF000) >> 12; if (nSteps < 2) nSteps = 2; pItem->dwFlags &= 0xFFFFF000; pItem->dwFlags |= ((max - min - 1) / 2 + (value - min) * nSteps) / (max - min); } /** * @brief Get the current value for the slider */ int gmenu_slider_get(TMenuItem *pItem, int min, int max) { int nSteps, step; step = pItem->dwFlags & 0xFFF; nSteps = (int)(pItem->dwFlags & 0xFFF000) >> 12; if (nSteps < 2) nSteps = 2; return min + (step * (max - min) + (nSteps - 1) / 2) / nSteps; } /** * @brief Set the number of steps for the slider */ void gmenu_slider_steps(TMenuItem *pItem, int steps) { pItem->dwFlags &= 0xFF000FFF; pItem->dwFlags |= (steps << 12) & 0xFFF000; } ================================================ FILE: Source/gmenu.h ================================================ /** * @file gmenu.h * * Interface of the in-game navigation and interaction. */ #ifndef __GMENU_H__ #define __GMENU_H__ void gmenu_draw_pause(); void FreeGMenu(); void gmenu_init_menu(); BOOL gmenu_is_active(); void gmenu_set_items(TMenuItem *pItem, void (*gmFunc)(TMenuItem *)); void gmenu_draw(); BOOL gmenu_presskeys(int vkey); BOOL gmenu_on_mouse_move(); BOOL gmenu_left_mouse(BOOL isDown); void gmenu_enable(TMenuItem *pMenuItem, BOOL enable); void gmenu_slider_set(TMenuItem *pItem, int min, int max, int gamma); int gmenu_slider_get(TMenuItem *pItem, int min, int max); void gmenu_slider_steps(TMenuItem *pItem, int dwTicks); #endif /* __GMENU_H__ */ ================================================ FILE: Source/help.cpp ================================================ /** * @file help.cpp * * Implementation of the in-game help text. */ #include "all.h" int help_select_line; int unused_help; BOOL helpflag; int displayinghelp[22]; /* check, does nothing? */ int HelpTop; const char gszHelpText[] = { #ifdef SPAWN "Shareware Diablo Help|" "|" "$Keyboard Shortcuts:|" "Diablo can be played exclusively by using the mouse controls. " "There are times, however, when you may want to use shortcuts to some " "commands by using the keyboard. These shortcuts are listed below:|" "|" "F1: Open the Help Screen|" "Esc: Displays the main menu|" "Tab: Displays the Auto-map|" "Space: Removes any pop-up menus or maps from the play area|" "S: Open Speedbook|" "B: Open Spellbook|" "I: Opens the Inventory screen|" "C: Opens the Character screen|" "Z: Zooms the game screen in and out|" "F: Reduces the brightness of the screen|" "G: Increases the brightness of the screen|" "Q: Opens the Quest log (non-functional in the Shareware version)|" "1 - 8: Use that item from your Belt|" "F5, F6, F7, F8: Sets a hot key for a selected skill or spell|" "Shift + Left Click: Use any weapon without moving|" "|" "|" "$Movement:|" "Movement is controlled by the mouse. The gauntlet on the screen is " "your cursor. Use this to indicate the destination of your character " "and then left-click to move to that area. " "If you hold the mouse button down while moving, the character " "will continue to move in that direction.|" "|" "$Selecting Items:|" "What you can interact with within the game is easily identifiable. " "Move the cursor over any object or creature. If the object can be " "picked up, attacked, activated or used in any way, it will be " "immediately outlined. A description of the highlighted object appears " "in the text area on the control panel.|" "|" "Example: If you select a door and then left-click the character will " "walk to the door and open it. If you left-click on a highlighted " "weapon, the character will walk over to it and put it in his " "inventory. If you left-click on a highlighted creature...|" "|" "$Combat:|" "Combat is initiated by left-clicking on a creature that has been " "highlighted. If your character is equipped with a melee weapon " "(Sword, Mace, Ax, etc.) your character will move to range and attack. " "If your character is equipped with a bow, left-clicking will fire an " "arrow at the highlighted creature. " "Holding down the shift key and then left-clicking allows the " "character to attack without moving.|" "|" "$Picking up Objects:|" "If you left-click on an item - such as a weapon, shield, armor or " "book - your character will move to that item and add it to his " "inventory automatically.|" "|" "Useable items that are small in size - such as a potion or " "scroll - 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 " "right-clicking on the item or pressing the corresponding number on " "the keyboard.|" "|" "If you do not have enough room in your inventory or belt for an item " "that you try to pick up, it will fall from your grasp. Open your " "inventory screen and try re-arranging or removing items to carry " "what you really want or need.|" "|" "$Inventory:|" "You can toggle the Inventory screen on and off by clicking the " "INV> button on the control panel. Items may be moved around in " "your inventory by selecting them and then left-clicking to pick " "them up. When you pick up an item while in the inventory screen, " "your cursor changes into the item. You can then place this item into " "empty spaces in your inventory, swap them with other items in your " "inventory or equip them.|" "|" "If you have an item that you no longer wish to carry, simply " "grab the item from your inventory and then left-click in the " "play area to drop it.|" "|" "$Equipping Items:|" "To equip an item, open the inventory screen and pick up the desired " "item, either from play or from your inventory, placing it in the " "appropriate box on the figure in the inventory screen. Weapons and " "shields go into the large spaces to the right or left of the figure. " "Two-handed weapons such as bows and axes preclude the use of a " "shield and will take up both of these large spaces.|" "|" "Cloaks, robes, capes and all other armor must go in the central " "torso slot of the figure. |" "|" "Helmets and caps go in the box over the head of the character.|" "|" "Rings go into the small boxes at the hands of the figure.|" "|" "Amulets go into the small box at the next to the neck of the figure.|" "|" "To change items that your character has equipped, pick up a new " "item and place it on top of the item you wish to remove. Your " "character will automatically swap the items and the cursor will " "now change into the item that was in that box.|" "|" "$Usable Items:|" "Potions, elixirs and books are classified as usable items. These " "items can be used by right-clicking on them in the inventory screen. " "Books are too large to be placed in the belt, but any potions or " "scrolls that are put there can also be used by pressing the " "corresponding number on the keyboard.|" "|" "$Gold:|" "You can select a specific amount of gold to drop by right " "clicking on a pile of gold in your inventory. " "A dialog will appear that allows you to select a specific amount of " "gold to take. When you have entered that number, your cursor will " "change into that amount of gold.|" "|" "$Item Information:|" "Many items in Diablo share certain common attributes. These are " "damage, durability, charges and minimum requirements..|" "|" "Damage: This is represented by a range that indicates the minimum " "and maximum damage that item can inflict. A short sword has a (2-6) " "after its name, meaning it inflicts a minimum of two damage and a " "maximum of six when it hits. Damage can be modified by the quality " "of the weapon, the character's strength and magical effects.|" "|" "Durability: This is the amount of damage that an item can take " "before it is rendered useless. Durability is represented by a " "ratio of current durability to maximum durability. A shield that " "has a durability of 15/20 would still have 15 points of damage it " "could take from use before it was rendered useless. Maximum " "durability can be affected by the quality of the item, enchantments " "or repairs made upon the item. The minimum durability can be raised " "by repairing an item.|" "|" "Charges: Some items have charges associated with them. Charges " "indicate how many times that item can be used to cast the spell or " "affect indicated in its description. Charges are represented by " "a ratio of charges left to maximum charges. A staff that has charges " "listed as 2/5 could be used to cast 2 more spells before it was " "rendered powerless. It could still be used to attack with as a " "physical weapon, however. Maximum charges can be affected by the " "magic or recharges cast upon the item. Minimum charges can be " "raised by recharging the item.|" "|" "Minimum Requirements: These are the minimum requirements that a " "character must meet to wield the item. The more powerful an item is, " "the higher the minimum requirements will be. If a character " "does not meet these requirements, he will be unable to equip the " "item and its name and information will be displayed in red. " "The item artwork will also have a red tint in the Inventory screen.|" "|" "$Items Classes:|" "There are three classes of items in Diablo - Mundane, " "Magic and Unique:|" "|" "Mundane items have no special attributes. Their information is " "displayed in white text.|" "|" "Magic Items are represented by blue names and text descriptions. " "Use the Identify spell or speak to Cain in town to determine their " "exact properties and attributes.|" "|" "Unique items are represented by gold names and text descriptions. " "Use the Identify spell or speak to Cain in town to determine their " "exact properties and attributes.|" "|" "$Skills & Spells:|" "You can access your list of skills and spells by left-clicking on " "the SPELLS button in the interface bar. This 'Spellbook' contains all " "of the skills and spells that your character knows. Spells " "available through staffs are also listed here. Left-clicking on " "the Icon of the spell you wish to ready will place it in the " "'select current spell' icon/area and set it as the current " "readied spell. A readied spell " "may be cast by simply right-clicking in the play area.|" "|" "Left-clicking on the 'select current spell' button will also " "open a 'Speedbook' menu that also allows you to ready a skill " "or spell for use. To use a readied skill or spell, simply " "right-click in the main play area.|" "|" "Skills are the innate abilities of your character. These skills " "are different depending on what class you choose and require no " "mana to use.|" "|" "Warrior:|" "The Warrior has the skill of Repair Items. This allows him to fix " "an item that has been worn by use or is damaged in combat. " "To accomplish this, select the Repair Skill through the " "Spellbook or Speedbook and right-click the mouse as if you were " "casting a spell. Your cursor will change into a Hammer Icon " "that you will use to select the item to be repaired. " "Although Repairing an item in this way will decrease the " "maximum durability of that item, it can be done without leaving " "the labyrinth.|" "|" "The Blacksmith can also repair items for a price. When the " "Blacksmith performs this service, it does decrease the maximum " "durability of the item.|" "|" "Rogue:|" "The Rogue has the skill of Disarm Traps. This allows her to not only " "remove traps, but also acts as a 'sixth sense' that warns her of " "where these trapped items are located. To accomplish this, select " "the Disarm Trap skill through the Spellbook or Speedbook and " "right-click the mouse as if you were casting a spell. " "Your cursor will change into a Targeting Cursor that you will " "use to select the item to be disarmed. The success of this " "attempt is based on the level of the Rogue and the expertise of " "whomever set the trap.|" "|" "Sorcerer:|" "The Sorcerer has the skill of Recharge Staffs. This allows him to " "focus his mana into an staff that has been drained of its magical " "energies. To accomplish this, select the Recharge Staffs skill " "through the Spellbook or Speedbook and right-click the mouse as " "if you were casting a spell. Your cursor will change into a " "Staff Icon that you will use to select the item to be recharged. " "Although Recharging a staff in this way will decrease its maximum " "charges, it can be done without leaving the labyrinth.|" "|" "The Witch can also recharge staffs for a price. When the Witch " "performs this service, it does decrease the maximum charges of the " "item.|" "|" "Spells are magical effects that can be cast from a scroll, " "a staff or memorized from a book. Spells may or may not require " "mana to use and are available to all classes.|" "|" "Spells cast from a scroll cost no mana to use, but are limited " "to only one charge. Casting a spell from a scroll is accomplished " "by either right clicking on the scroll or, if it is located in " "our belt, pressing the corresponding number on the keyboard. " "Scrolls can also be readied in the Speedbook and are represented " "by a red icon/button in the 'select current spell' area.|" "|" "Spells cast from staffs cost no mana to use, but are limited by " "the number of charges available. To cast spells from a staff, " "it must first be equipped. The 'select current spell' icon/button " "will change to indicate that the spell on the staff is currently " "ready to cast. Scrolls can also be readied in the Spellbook or " "Speedbook and are represented by an orange icon/button in the " "'select current spell' area.|" "|" "Spells that are memorized cost mana to cast, but they can be used " "as long as the character has mana to power them. The Warrior " "and Rogue start the game with no memorized spells while " "the sorcerer begins with Firebolt. If the character finds a book " "in the labyrinth, he can memorize the spell written in that book " "by opening the Inventory screen and right-clicking on the book. " "This will make that spell always available to the character for " "casting. Memorized spells can be readied through either the " "Spellbook or Speedbook and are represented by a blue icon/button " "in the 'select current spell' area.|" "|" "$Important note on books:|" "Reading more than one book increases your knowledge of that spell " "and gives you the spell at a higher level. The higher the level " "of a spell the more effective it is.|" "|" "While some spells affect the caster, other spells require a target. " "These targeted spells are cast in the direction that you indicate " "with your cursor on the play area. If you highlight a creature, " "you will cast that spell at that creature. Not all items within " "the labyrinth can be targeted.|" "|" "Example: A fireball spell will travel at the creature or to the " "location you right-click on. A Healing spell will simply add " "health to your character while diminishing his available mana " "and requires no targeting.|" "|" "You can also set a spell or scroll as a Hot Key position for " "instant selection. Start by opening the pop-up menu as described " "in the skill section above. Assign Hot Keys by hitting the " "F5, F6, F7 or F8 keys on your keyboard after scrolling through " "the available spells and highlighting the one you wish to assign. |" "|" "$Health and Mana:|" "The two orbs in the Information Bar display your life and mana. " "The red sphere of fluid on the left side of the control panel " "represents the overall health of your character. When the fluid " "is gone - your character is dead.|" "|" "The blue fluid on the right side of the control panel represents " "your character's available mana. Mana is the magical force used by " "your character to cast spells. When the liquid in the sphere is " "low or depleted, you may be unable to cast some (or all) of your " "spells.|" "|" "$Information Bar:|" "The Information Bar is where you receive detailed information in " "Diablo and interact with much of your surroundings. Here is a " "quick run-down of the control panel areas and their use:|" "|" "CHAR: This button is used to access your Character Statistics screen|" "INV: This button is used to access your Inventory screen|" "Quest: This button displays your Quest Log (inactive in " "Shareware version)|" "Automap: This button activates the mapping overlay|" "Menu: This button activates the game menu screen|" "Spells: This button is used to access your Spellbook|" "Current Spell: This is the spell that has been readied for " "immediate casting|" "Life Orb: This is the amount of health your character currently has|" "Mana Orb: This is the amount of mana your character currently has|" "Multiplayer Message: This activates the Message Area|" "Description Area: This is where any important information about " "creatures or items you can interact with is displayed. " "This is also where you will enter the text you wish to send when " "sending multiplayer messages.|" "|" "$Character Info:|" "Toggle the Character Statistics Screen on and off by clicking the " "= 577) { c--; while (tempstr[c] != ' ') { s--; c--; } } if (*s == '|') { s++; } } for (i = 7; i < 22; i++) { c = 0; w = 0; while (*s == '\0') { s++; } if (*s == '$') { s++; col = COL_RED; } else { col = COL_WHITE; } if (*s == '&') { HelpTop = help_select_line; continue; } while (*s != '|' && w < 577) { while (*s == '\0') { s++; } tempstr[c] = *s; BYTE tc = gbFontTransTbl[(BYTE)tempstr[c]]; w += fontkern[fontframe[tc]] + 1; c++; s++; } if (w >= 577) { c--; while (tempstr[c] != ' ') { s--; c--; } } if (c != 0) { tempstr[c] = '\0'; DrawHelpLine(0, i, tempstr, col); } if (*s == '|') { s++; } } PrintSString(0, 23, TRUE, "Press ESC to end or the arrow keys to scroll.", COL_GOLD, 0); } void DisplayHelp() { help_select_line = 0; helpflag = TRUE; HelpTop = 5000; } void HelpScrollUp() { if (help_select_line > 0) help_select_line--; } void HelpScrollDown() { if (help_select_line < HelpTop) help_select_line++; } ================================================ FILE: Source/help.h ================================================ /** * @file help.h * * Interface of the in-game help text. */ #ifndef __HELP_H__ #define __HELP_H__ extern BOOL helpflag; void InitHelp(); void DrawHelp(); void DisplayHelp(); void HelpScrollUp(); void HelpScrollDown(); #endif /* __HELP_H__ */ ================================================ FILE: Source/init.cpp ================================================ /** * @file init.cpp * * Implementation of routines for initializing the environment, disable screen saver, load MPQ. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" #include "../DiabloUI/diabloui.h" _SNETVERSIONDATA fileinfo; /** True if the game is the current active window */ int gbActive; /** Specifies the path to diablo.exe. */ char diablo_exe_path[MAX_PATH]; /** A handle to an unused MPQ archive. */ HANDLE hellfire_mpq; /** Specifies the path to patch_rt.mpq. */ char patch_rt_mpq_path[MAX_PATH]; /** The current input handler function */ WNDPROC CurrentProc; /** A handle to the diabdat.mpq archive. */ HANDLE diabdat_mpq; /** Specifies the path to diabdat.mpq. */ char diabdat_mpq_path[MAX_PATH]; /** A handle to the patch_rt.mpq archive. */ HANDLE patch_rt_mpq; /** Specifies whether the MS Office Shortcut Bar was killed. */ BOOL killed_mom_parent; /** Stores the previous state of the screensaver. */ BOOLEAN screensaver_enabled_prev; #ifdef HELLFIRE char hellfire_mpq_path[MAX_PATH]; char hfmonk_mpq_path[MAX_PATH]; char hfbard_mpq_path[MAX_PATH]; char hfbarb_mpq_path[MAX_PATH]; char hfmusic_mpq_path[MAX_PATH]; char hfvoice_mpq_path[MAX_PATH]; char hfopt1_mpq_path[MAX_PATH]; char hfopt2_mpq_path[MAX_PATH]; HANDLE hfmonk_mpq; HANDLE hfbard_mpq; HANDLE hfbarb_mpq; HANDLE hfmusic_mpq; HANDLE hfvoice_mpq; HANDLE hfopt1_mpq; HANDLE hfopt2_mpq; #endif /* data */ char gszVersionNumber[MAX_PATH] = "internal version unknown"; char gszProductName[MAX_PATH] = "Diablo v1.09"; static void init_run_office(char *dir) { HANDLE hSearch; WIN32_FIND_DATA find; char szFirst[MAX_PATH]; strcpy(szFirst, dir); if (szFirst[0] != '\0' && szFirst[strlen(szFirst) - 1] == '\\') { strcat(szFirst, "*"); } else { strcat(szFirst, "\\*"); } hSearch = FindFirstFile(szFirst, &find); if (hSearch == INVALID_HANDLE_VALUE) { return; } while (1) { if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (strcmp(find.cFileName, ".") != 0 && strcmp(find.cFileName, "..") != 0) { char szNext[MAX_PATH] = ""; if (dir[0] != '\0' && dir[strlen(dir) - 1] == '\\') { sprintf(szNext, "%s%s\\", dir, find.cFileName); } else { sprintf(szNext, "%s\\%s\\", dir, find.cFileName); } init_run_office(szNext); } } else if (_strcmpi(find.cFileName, "Microsoft Office Shortcut Bar.lnk") == 0) { ShellExecute(GetDesktopWindow(), "open", find.cFileName, "", dir, SW_SHOWNORMAL); } if (!FindNextFile(hSearch, &find)) { break; } } FindClose(hSearch); } static HWND init_find_mom_parent() { HWND i, handle; char ClassName[256]; for (i = GetForegroundWindow();; i = GetWindow(handle, GW_HWNDNEXT)) { handle = i; if (!i) break; GetClassName(i, ClassName, 255); if (!_strcmpi(ClassName, "MOM Parent")) break; } return handle; } static void init_kill_mom_parent() { HWND handle; handle = init_find_mom_parent(); if (handle != NULL) { PostMessage(handle, WM_CLOSE, 0, 0); killed_mom_parent = TRUE; } } static void init_await_mom_parent_exit() { DWORD tick; tick = GetTickCount(); if (!init_find_mom_parent()) { return; } do { Sleep(250); } while (GetTickCount() - tick <= 4000 && init_find_mom_parent() != NULL); } static void init_run_office_from_start_menu() { LPITEMIDLIST idl; if (!killed_mom_parent) { return; } killed_mom_parent = FALSE; char szPath[256] = ""; /// BUGFIX: size should be at least 'MAX_PATH' idl = NULL; if (SHGetSpecialFolderLocation(GetDesktopWindow(), CSIDL_STARTMENU, &idl) == NOERROR) { SHGetPathFromIDList(idl, szPath); init_run_office(szPath); } } static void init_disable_screensaver(BOOLEAN disable) { BOOLEAN enabled; char Data[16]; DWORD Type, cbData; HKEY phkResult; LRESULT success; // BUGFIX: this is probably the worst possible way to do this. Alternatives: ExtEscape() with SETPOWERMANAGEMENT, // SystemParametersInfo() with SPI_SETSCREENSAVEACTIVE/SPI_SETPOWEROFFACTIVE/SPI_SETLOWPOWERACTIVE success = RegOpenKeyEx(HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, KEY_READ | KEY_WRITE, (PHKEY)&phkResult); if (success != ERROR_SUCCESS) { return; } if (disable) { cbData = 16; success = RegQueryValueEx(phkResult, "ScreenSaveActive", NULL, &Type, (LPBYTE)Data, &cbData); if (success == ERROR_SUCCESS) screensaver_enabled_prev = Data[0] != '0'; enabled = FALSE; } else { enabled = screensaver_enabled_prev; } Data[0] = enabled ? '1' : '0'; Data[1] = 0; RegSetValueEx(phkResult, "ScreenSaveActive", NULL, REG_SZ, (const BYTE *)Data, 2); RegCloseKey(phkResult); } void init_cleanup(BOOL show_cursor) { pfile_flush_W(); init_disable_screensaver(FALSE); init_run_office_from_start_menu(); if (diabdat_mpq) { SFileCloseArchive(diabdat_mpq); diabdat_mpq = NULL; } if (patch_rt_mpq) { SFileCloseArchive(patch_rt_mpq); patch_rt_mpq = NULL; } if (hellfire_mpq) { SFileCloseArchive(hellfire_mpq); hellfire_mpq = NULL; } #ifdef HELLFIRE if (hfmonk_mpq) { SFileCloseArchive(hfmonk_mpq); hfmonk_mpq = NULL; } if (hfbard_mpq) { SFileCloseArchive(hfbard_mpq); hfbard_mpq = NULL; } if (hfbarb_mpq) { SFileCloseArchive(hfbarb_mpq); hfbarb_mpq = NULL; } if (hfmusic_mpq) { SFileCloseArchive(hfmusic_mpq); hfmusic_mpq = NULL; } if (hfvoice_mpq) { SFileCloseArchive(hfvoice_mpq); hfvoice_mpq = NULL; } if (hfopt1_mpq) { SFileCloseArchive(hfopt1_mpq); hfopt1_mpq = NULL; } if (hfopt2_mpq) { SFileCloseArchive(hfopt2_mpq); hfopt2_mpq = NULL; } #endif UiDestroy(); effects_cleanup_sfx(); sound_cleanup(); NetClose(); dx_cleanup(); engine_debug_trap(show_cursor); StormDestroy(); if (show_cursor) ShowCursor(TRUE); } static void init_strip_trailing_slash(char *path) { char *result; result = strrchr(path, '\\'); if (result) { if (!result[1]) *result = 0; } } static BOOL init_read_test_file(char *pszPath, const char *pszArchive, int dwPriority, HANDLE *phArchive) { DWORD dwSize; char *pszDrive, *pszRoot; char szDrive[MAX_PATH]; dwSize = GetLogicalDriveStrings(sizeof(szDrive), szDrive); if (dwSize == 0 || dwSize > sizeof(szDrive)) { return FALSE; } while (*pszArchive == '\\') { pszArchive++; } pszDrive = szDrive; if (*pszDrive == '\0') { return FALSE; } while (1) { pszRoot = pszDrive; while (*pszDrive++ != '\0') ; if (GetDriveType(pszRoot) == DRIVE_CDROM) { strcpy(pszPath, pszRoot); strcat(pszPath, pszArchive); if (SFileOpenArchive(pszPath, dwPriority, FS_CD, phArchive)) { break; } } if (*pszDrive == '\0') { return FALSE; } } return TRUE; } static HANDLE init_test_access(char *mpq_path, const char *mpq_name, const char *reg_loc, int dwPriority, int fs) { char *last_slash_pos; char Filename[MAX_PATH]; char Buffer[MAX_PATH]; char archive_path[MAX_PATH]; HANDLE archive; if (!GetCurrentDirectory(sizeof(Buffer), Buffer)) app_fatal("Can't get program path"); init_strip_trailing_slash(Buffer); if (!SFileSetBasePath(Buffer)) app_fatal("SFileSetBasePath"); if (!GetModuleFileName(ghInst, Filename, sizeof(Filename))) app_fatal("Can't get program name"); last_slash_pos = strrchr(Filename, '\\'); if (last_slash_pos) *last_slash_pos = '\0'; init_strip_trailing_slash(Filename); strcpy(mpq_path, Buffer); strcat(mpq_path, mpq_name); if (SFileOpenArchive(mpq_path, dwPriority, fs, &archive)) return archive; if (strcmp(Filename, Buffer)) { strcpy(mpq_path, Filename); strcat(mpq_path, mpq_name); if (SFileOpenArchive(mpq_path, dwPriority, fs, &archive)) return archive; } archive_path[0] = '\0'; if (reg_loc) { if (SRegLoadString("Archives", reg_loc, 0, archive_path, sizeof(archive_path))) { init_strip_trailing_slash(archive_path); strcpy(mpq_path, archive_path); strcat(mpq_path, mpq_name); if (SFileOpenArchive(mpq_path, dwPriority, fs, &archive)) return archive; } } if (fs != FS_PC && init_read_test_file(archive_path, mpq_name, dwPriority, &archive)) { strcpy(mpq_path, archive_path); return archive; } return NULL; } static void init_get_file_info() { DWORD dwLen; void *pBlock; unsigned int uBytes; DWORD dwHandle; VS_FIXEDFILEINFO *lpBuffer; if (GetModuleFileName(ghInst, diablo_exe_path, sizeof(diablo_exe_path))) { dwLen = GetFileVersionInfoSize(diablo_exe_path, &dwHandle); if (dwLen) { pBlock = DiabloAllocPtr(dwLen); if (GetFileVersionInfo(diablo_exe_path, 0, dwLen, pBlock)) { if (VerQueryValue(pBlock, "\\", (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(pBlock); } } } static void init_archives() { HANDLE fh; #ifdef COPYPROT int result; #endif memset(&fileinfo, 0, sizeof(fileinfo)); fileinfo.size = sizeof(fileinfo); 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 #ifdef SPAWN diabdat_mpq = init_test_access(diabdat_mpq_path, "\\spawn.mpq", "DiabloSpawn", 1000, FS_PC); #else #ifdef COPYPROT diabdat_mpq = init_test_access(diabdat_mpq_path, "\\diabdat.mpq", "DiabloCD", 1000, FS_CD); #else diabdat_mpq = init_test_access(diabdat_mpq_path, "\\diabdat.mpq", "DiabloCD", 1000, FS_PC); #endif #endif #ifdef COPYPROT if (diabdat_mpq != NULL) break; UiCopyProtError(&result); if (result == COPYPROT_CANCEL) FileErrDlg("diabdat.mpq"); } #endif if (!WOpenFile("ui_art\\title.pcx", &fh, TRUE)) #ifdef SPAWN FileErrDlg("Main program archive: spawn.mpq"); #else FileErrDlg("Main program archive: diabdat.mpq"); #endif WCloseFile(fh); #ifdef SPAWN patch_rt_mpq = init_test_access(patch_rt_mpq_path, "\\patch_sh.mpq", "DiabloSpawn", 2000, FS_PC); #else patch_rt_mpq = init_test_access(patch_rt_mpq_path, "\\patch_rt.mpq", "DiabloInstall", 2000, FS_PC); #endif #ifdef HELLFIRE hellfire_mpq = init_test_access(hellfire_mpq_path, "\\hellfire.mpq", "DiabloInstall", 8000, FS_PC); hfmonk_mpq = init_test_access(hfmonk_mpq_path, "\\hfmonk.mpq", "DiabloInstall", 8100, FS_PC); hfbard_mpq = init_test_access(hfbard_mpq_path, "\\hfbard.mpq", "DiabloInstall", 8110, FS_PC); hfbarb_mpq = init_test_access(hfbarb_mpq_path, "\\hfbarb.mpq", "DiabloInstall", 8120, FS_PC); hfmusic_mpq = init_test_access(hfmusic_mpq_path, "\\hfmusic.mpq", "DiabloInstall", 8200, FS_PC); hfvoice_mpq = init_test_access(hfvoice_mpq_path, "\\hfvoice.mpq", "DiabloInstall", 8500, FS_PC); hfopt1_mpq = init_test_access(hfopt1_mpq_path, "\\hfopt1.mpq", "DiabloInstall", 8600, FS_PC); hfopt2_mpq = init_test_access(hfopt2_mpq_path, "\\hfopt2.mpq", "DiabloInstall", 8610, FS_PC); #endif } void init_create_window(int nCmdShow) { int nWidth, nHeight; HWND hWnd; WNDCLASSEXA wcex; 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(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wcex.lpszMenuName = GAME_NAME; wcex.lpszClassName = "DIABLO"; wcex.hIconSm = (HICON)LoadImage(ghInst, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); if (!RegisterClassEx(&wcex)) app_fatal("Unable to register window class"); if (GetSystemMetrics(SM_CXSCREEN) < SCREEN_WIDTH) nWidth = SCREEN_WIDTH; else nWidth = GetSystemMetrics(SM_CXSCREEN); if (GetSystemMetrics(SM_CYSCREEN) < SCREEN_HEIGHT) nHeight = SCREEN_HEIGHT; else nHeight = GetSystemMetrics(SM_CYSCREEN); hWnd = CreateWindowEx(0, "DIABLO", GAME_NAME, WS_POPUP, 0, 0, nWidth, nHeight, NULL, NULL, ghInst, NULL); if (!hWnd) app_fatal("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(TRUE); } static void init_activate_window(HWND hWnd, BOOL bActive) { LONG dwNewLong; 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) { force_redraw = 255; ResetPal(); } } LRESULT __stdcall MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch (Msg) { case WM_ERASEBKGND: return 0; case WM_CREATE: ghMainWnd = hWnd; break; case WM_DESTROY: init_cleanup(TRUE); ghMainWnd = NULL; PostQuitMessage(0); break; case WM_PAINT: force_redraw = 255; break; case WM_CLOSE: return 0; case WM_ACTIVATEAPP: init_activate_window(hWnd, wParam); break; #ifdef _DEBUG case WM_SYSKEYUP: if (wParam == VK_RETURN) { fullscreen = !fullscreen; dx_reinit(); return 0; } break; #endif case WM_QUERYNEWPALETTE: SDrawRealizePalette(); return 1; case WM_PALETTECHANGED: if ((HWND)wParam != hWnd) SDrawRealizePalette(); break; } return DefWindowProc(hWnd, Msg, wParam, lParam); } LRESULT __stdcall WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { if (CurrentProc) return CurrentProc(hWnd, Msg, wParam, lParam); return MainWndProc(hWnd, Msg, wParam, lParam); } WNDPROC SetWindowProc(WNDPROC NewProc) { WNDPROC OldProc; OldProc = CurrentProc; CurrentProc = NewProc; return OldProc; } ================================================ FILE: Source/init.h ================================================ /** * @file init.h * * Interface of routines for initializing the environment, disable screen saver, load MPQ. */ #ifndef __INIT_H__ #define __INIT_H__ extern _SNETVERSIONDATA fileinfo; extern int gbActive; extern WNDPROC CurrentProc; extern HANDLE diabdat_mpq; #ifdef HELLFIRE extern HANDLE hfbard_mpq; extern HANDLE hfbarb_mpq; #endif void init_cleanup(BOOL show_cursor); void init_create_window(int nCmdShow); LRESULT __stdcall MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); LRESULT __stdcall WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); WNDPROC SetWindowProc(WNDPROC NewProc); /* data */ extern char gszVersionNumber[MAX_PATH]; extern char gszProductName[MAX_PATH]; #endif /* __INIT_H__ */ ================================================ FILE: Source/interfac.cpp ================================================ /** * @file interfac.cpp * * Implementation of load screens. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" BYTE *sgpBackCel; int sgdwProgress; int progress_id; /** The colour used for the progress bar as an index into the palette. */ const BYTE BarColor[3] = { 138, 43, 254 }; /** The screen position of the top left corner of the progress bar. */ const int BarPos[3][2] = { { 53, 37 }, { 53, 421 }, { 53, 37 } }; static void FreeInterface() { MemFreeDbg(sgpBackCel); } static void InitCutscene(unsigned int uMsg) { assert(!sgpBackCel); switch (uMsg) { case WM_DIABNEXTLVL: switch (gnLevelTypeTbl[currlevel]) { case DTYPE_TOWN: sgpBackCel = LoadFileInMem("Gendata\\Cuttt.CEL", NULL); LoadPalette("Gendata\\Cuttt.pal"); progress_id = 1; break; case DTYPE_CATHEDRAL: #ifdef HELLFIRE if (currlevel < 17) { #endif sgpBackCel = LoadFileInMem("Gendata\\Cutl1d.CEL", NULL); LoadPalette("Gendata\\Cutl1d.pal"); progress_id = 0; #ifdef HELLFIRE } else { sgpBackCel = LoadFileInMem("Nlevels\\cutl5.CEL", NULL); LoadPalette("Nlevels\\cutl5.pal"); progress_id = 1; } #endif break; case DTYPE_CATACOMBS: sgpBackCel = LoadFileInMem("Gendata\\Cut2.CEL", NULL); LoadPalette("Gendata\\Cut2.pal"); progress_id = 2; break; case DTYPE_CAVES: #ifdef HELLFIRE if (currlevel < 17) { #endif sgpBackCel = LoadFileInMem("Gendata\\Cut3.CEL", NULL); LoadPalette("Gendata\\Cut3.pal"); progress_id = 1; #ifdef HELLFIRE } else { sgpBackCel = LoadFileInMem("Nlevels\\cutl6.CEL", NULL); LoadPalette("Nlevels\\cutl6.pal"); progress_id = 1; } #endif break; case DTYPE_HELL: if (currlevel < 15) { sgpBackCel = LoadFileInMem("Gendata\\Cut4.CEL", NULL); LoadPalette("Gendata\\Cut4.pal"); progress_id = 1; } else { sgpBackCel = LoadFileInMem("Gendata\\Cutgate.CEL", NULL); LoadPalette("Gendata\\Cutgate.pal"); progress_id = 1; } break; default: sgpBackCel = LoadFileInMem("Gendata\\Cutl1d.CEL", NULL); LoadPalette("Gendata\\Cutl1d.pal"); progress_id = 0; break; } break; case WM_DIABPREVLVL: if (gnLevelTypeTbl[currlevel - 1] == 0) { sgpBackCel = LoadFileInMem("Gendata\\Cuttt.CEL", NULL); LoadPalette("Gendata\\Cuttt.pal"); progress_id = 1; } else { switch (gnLevelTypeTbl[currlevel]) { case DTYPE_TOWN: sgpBackCel = LoadFileInMem("Gendata\\Cuttt.CEL", NULL); LoadPalette("Gendata\\Cuttt.pal"); progress_id = 1; break; case DTYPE_CATHEDRAL: #ifdef HELLFIRE if (currlevel < 17) { #endif sgpBackCel = LoadFileInMem("Gendata\\Cutl1d.CEL", NULL); LoadPalette("Gendata\\Cutl1d.pal"); progress_id = 0; #ifdef HELLFIRE } else { sgpBackCel = LoadFileInMem("Nlevels\\cutl5.CEL", NULL); LoadPalette("Nlevels\\cutl5.pal"); progress_id = 1; } #endif break; case DTYPE_CATACOMBS: sgpBackCel = LoadFileInMem("Gendata\\Cut2.CEL", NULL); LoadPalette("Gendata\\Cut2.pal"); progress_id = 2; break; case DTYPE_CAVES: #ifdef HELLFIRE if (currlevel < 17) { #endif sgpBackCel = LoadFileInMem("Gendata\\Cut3.CEL", NULL); LoadPalette("Gendata\\Cut3.pal"); progress_id = 1; #ifdef HELLFIRE } else { sgpBackCel = LoadFileInMem("Nlevels\\cutl6.CEL", NULL); LoadPalette("Nlevels\\cutl6.pal"); progress_id = 1; } #endif break; case DTYPE_HELL: sgpBackCel = LoadFileInMem("Gendata\\Cut4.CEL", NULL); LoadPalette("Gendata\\Cut4.pal"); progress_id = 1; break; default: sgpBackCel = LoadFileInMem("Gendata\\Cutl1d.CEL", NULL); LoadPalette("Gendata\\Cutl1d.pal"); progress_id = 0; break; } } break; case WM_DIABSETLVL: if (setlvlnum == SL_BONECHAMB) { sgpBackCel = LoadFileInMem("Gendata\\Cut2.CEL", NULL); LoadPalette("Gendata\\Cut2.pal"); progress_id = 2; } else if (setlvlnum == SL_VILEBETRAYER) { sgpBackCel = LoadFileInMem("Gendata\\Cutportr.CEL", NULL); LoadPalette("Gendata\\Cutportr.pal"); progress_id = 1; } else { sgpBackCel = LoadFileInMem("Gendata\\Cutl1d.CEL", NULL); LoadPalette("Gendata\\Cutl1d.pal"); progress_id = 0; } break; case WM_DIABRTNLVL: if (setlvlnum == SL_BONECHAMB) { sgpBackCel = LoadFileInMem("Gendata\\Cut2.CEL", NULL); LoadPalette("Gendata\\Cut2.pal"); progress_id = 2; } else if (setlvlnum == SL_VILEBETRAYER) { sgpBackCel = LoadFileInMem("Gendata\\Cutportr.CEL", NULL); LoadPalette("Gendata\\Cutportr.pal"); progress_id = 1; } else { sgpBackCel = LoadFileInMem("Gendata\\Cutl1d.CEL", NULL); LoadPalette("Gendata\\Cutl1d.pal"); progress_id = 0; } break; case WM_DIABWARPLVL: sgpBackCel = LoadFileInMem("Gendata\\Cutportl.CEL", NULL); LoadPalette("Gendata\\Cutportl.pal"); progress_id = 1; break; case WM_DIABLOADGAME: sgpBackCel = LoadFileInMem("Gendata\\Cutstart.CEL", NULL); LoadPalette("Gendata\\Cutstart.pal"); progress_id = 1; break; case WM_DIABNEWGAME: sgpBackCel = LoadFileInMem("Gendata\\Cutstart.CEL", NULL); LoadPalette("Gendata\\Cutstart.pal"); progress_id = 1; break; case WM_DIABTOWNWARP: case WM_DIABTWARPUP: switch (gnLevelTypeTbl[plr[myplr].plrlevel]) { case DTYPE_TOWN: sgpBackCel = LoadFileInMem("Gendata\\Cuttt.CEL", NULL); LoadPalette("Gendata\\Cuttt.pal"); progress_id = 1; break; #ifdef HELLFIRE case DTYPE_CATHEDRAL: if (plr[myplr].plrlevel < 17) { sgpBackCel = LoadFileInMem("Gendata\\Cutl1d.CEL", NULL); LoadPalette("Gendata\\Cutl1d.pal"); progress_id = 0; } else { sgpBackCel = LoadFileInMem("Nlevels\\Cutl5.CEL", NULL); LoadPalette("Nlevels\\Cutl5.pal"); progress_id = 1; } break; #endif case DTYPE_CATACOMBS: sgpBackCel = LoadFileInMem("Gendata\\Cut2.CEL", NULL); LoadPalette("Gendata\\Cut2.pal"); progress_id = 2; break; case DTYPE_CAVES: #ifdef HELLFIRE if (plr[myplr].plrlevel < 17) { #endif sgpBackCel = LoadFileInMem("Gendata\\Cut3.CEL", NULL); LoadPalette("Gendata\\Cut3.pal"); progress_id = 1; #ifdef HELLFIRE } else { sgpBackCel = LoadFileInMem("Nlevels\\Cutl6.CEL", NULL); LoadPalette("Nlevels\\Cutl6.pal"); progress_id = 1; } #endif break; case DTYPE_HELL: sgpBackCel = LoadFileInMem("Gendata\\Cut4.CEL", NULL); LoadPalette("Gendata\\Cut4.pal"); progress_id = 1; break; } break; case WM_DIABRETOWN: sgpBackCel = LoadFileInMem("Gendata\\Cuttt.CEL", NULL); LoadPalette("Gendata\\Cuttt.pal"); progress_id = 1; break; default: app_fatal("Unknown progress mode"); break; } sgdwProgress = 0; } static void DrawProgress(int screen_x, int screen_y, int progress_id) { BYTE *dst; int i; dst = &gpBuffer[screen_x + PitchTbl[screen_y]]; for (i = 0; i < 22; i++) { *dst = BarColor[progress_id]; dst += BUFFER_WIDTH; } } static void DrawCutscene() { DWORD i; lock_buf(1); CelDraw(PANEL_X, 480 + SCREEN_Y - 1, sgpBackCel, 1, 640); for (i = 0; i < sgdwProgress; i++) { DrawProgress( BarPos[progress_id][0] + i + PANEL_X, BarPos[progress_id][1] + SCREEN_Y, progress_id); } unlock_buf(1); force_redraw = 255; scrollrt_draw_game_screen(FALSE); } void interface_msg_pump() { MSG Msg; while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) { if (Msg.message != WM_QUIT) { TranslateMessage(&Msg); DispatchMessage(&Msg); } } } BOOL IncProgress() { interface_msg_pump(); sgdwProgress += 15; if ((DWORD)sgdwProgress > 534) sgdwProgress = 534; if (sgpBackCel) DrawCutscene(); return (DWORD)sgdwProgress >= 534; } void ShowProgress(unsigned int uMsg) { WNDPROC saveProc; gbSomebodyWonGameKludge = FALSE; plrmsg_delay(TRUE); assert(ghMainWnd); saveProc = SetWindowProc(DisableInputWndProc); interface_msg_pump(); ClearScreenBuffer(); scrollrt_draw_game_screen(TRUE); InitCutscene(uMsg); BlackPalette(); DrawCutscene(); PaletteFadeIn(8); IncProgress(); sound_init(); IncProgress(); switch (uMsg) { case WM_DIABLOADGAME: IncProgress(); LoadGame(TRUE); IncProgress(); break; case WM_DIABNEWGAME: IncProgress(); FreeGameMem(); IncProgress(); pfile_remove_temp_files(); LoadGameLevel(TRUE, ENTRY_MAIN); IncProgress(); break; case WM_DIABNEXTLVL: IncProgress(); if (gbMaxPlayers == 1) { SaveLevel(); } else { DeltaSaveLevel(); } FreeGameMem(); currlevel++; leveltype = gnLevelTypeTbl[currlevel]; assert(plr[myplr].plrlevel == currlevel); IncProgress(); LoadGameLevel(FALSE, ENTRY_MAIN); IncProgress(); break; case WM_DIABPREVLVL: IncProgress(); if (gbMaxPlayers == 1) { SaveLevel(); } else { DeltaSaveLevel(); } IncProgress(); FreeGameMem(); currlevel--; leveltype = gnLevelTypeTbl[currlevel]; assert(plr[myplr].plrlevel == currlevel); IncProgress(); LoadGameLevel(FALSE, ENTRY_PREV); IncProgress(); break; case WM_DIABSETLVL: SetReturnLvlPos(); if (gbMaxPlayers == 1) { SaveLevel(); } else { DeltaSaveLevel(); } setlevel = TRUE; leveltype = setlvltype; FreeGameMem(); IncProgress(); LoadGameLevel(FALSE, ENTRY_SETLVL); IncProgress(); break; case WM_DIABRTNLVL: if (gbMaxPlayers == 1) { SaveLevel(); } else { DeltaSaveLevel(); } setlevel = FALSE; FreeGameMem(); IncProgress(); GetReturnLvlPos(); LoadGameLevel(FALSE, ENTRY_RTNLVL); IncProgress(); break; case WM_DIABWARPLVL: IncProgress(); if (gbMaxPlayers == 1) { SaveLevel(); } else { DeltaSaveLevel(); } FreeGameMem(); GetPortalLevel(); IncProgress(); LoadGameLevel(FALSE, ENTRY_WARPLVL); IncProgress(); break; case WM_DIABTOWNWARP: IncProgress(); if (gbMaxPlayers == 1) { SaveLevel(); } else { DeltaSaveLevel(); } FreeGameMem(); currlevel = plr[myplr].plrlevel; leveltype = gnLevelTypeTbl[currlevel]; assert(plr[myplr].plrlevel == currlevel); IncProgress(); LoadGameLevel(FALSE, ENTRY_TWARPDN); IncProgress(); break; case WM_DIABTWARPUP: IncProgress(); if (gbMaxPlayers == 1) { SaveLevel(); } else { DeltaSaveLevel(); } FreeGameMem(); currlevel = plr[myplr].plrlevel; leveltype = gnLevelTypeTbl[currlevel]; assert(plr[myplr].plrlevel == currlevel); IncProgress(); LoadGameLevel(FALSE, ENTRY_TWARPUP); IncProgress(); break; case WM_DIABRETOWN: IncProgress(); if (gbMaxPlayers == 1) { SaveLevel(); } else { DeltaSaveLevel(); } FreeGameMem(); currlevel = plr[myplr].plrlevel; leveltype = gnLevelTypeTbl[currlevel]; assert(plr[myplr].plrlevel == currlevel); IncProgress(); LoadGameLevel(FALSE, ENTRY_MAIN); IncProgress(); break; } assert(ghMainWnd); PaletteFadeOut(8); FreeInterface(); saveProc = SetWindowProc(saveProc); assert(saveProc == DisableInputWndProc); NetSendCmdLocParam1(TRUE, CMD_PLAYER_JOINLEVEL, plr[myplr]._px, plr[myplr]._py, plr[myplr].plrlevel); plrmsg_delay(FALSE); ResetPal(); if (gbSomebodyWonGameKludge && plr[myplr].plrlevel == 16) { PrepDoEnding(); } gbSomebodyWonGameKludge = FALSE; } ================================================ FILE: Source/interfac.h ================================================ /** * @file interfac.h * * Interface of load screens. */ #ifndef __INTERFAC_H__ #define __INTERFAC_H__ void interface_msg_pump(); BOOL IncProgress(); void ShowProgress(unsigned int uMsg); #endif /* __INTERFAC_H__ */ ================================================ FILE: Source/inv.cpp ================================================ /** * @file inv.cpp * * Implementation of player inventory. */ #include "all.h" BOOL invflag; BYTE *pInvCels; BOOL drawsbarflag; int sgdwLastTime; // check name /** * Maps from inventory slot to screen position. The inventory slots are * arranged as follows: * 00 01 * 02 03 06 * 07 08 19 20 13 14 * 09 10 21 22 15 16 * 11 12 23 24 17 18 * 04 05 * 25 26 27 28 29 30 31 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 * @see graphics/inv/inventory.png */ const InvXY InvRect[] = { // clang-format off // X, Y { RIGHT_PANEL + 132, 31 }, // helmet { RIGHT_PANEL + 160, 31 }, // helmet { RIGHT_PANEL + 132, 59 }, // helmet { RIGHT_PANEL + 160, 59 }, // helmet { RIGHT_PANEL + 45, 205 }, // left ring { RIGHT_PANEL + 247, 205 }, // right ring { RIGHT_PANEL + 204, 59 }, // amulet { RIGHT_PANEL + 17, 104 }, // left hand { RIGHT_PANEL + 46, 104 }, // left hand { RIGHT_PANEL + 17, 132 }, // left hand { RIGHT_PANEL + 46, 132 }, // left hand { RIGHT_PANEL + 17, 160 }, // left hand { RIGHT_PANEL + 46, 160 }, // left hand { RIGHT_PANEL + 247, 104 }, // right hand { RIGHT_PANEL + 276, 104 }, // right hand { RIGHT_PANEL + 247, 132 }, // right hand { RIGHT_PANEL + 276, 132 }, // right hand { RIGHT_PANEL + 247, 160 }, // right hand { RIGHT_PANEL + 276, 160 }, // right hand { RIGHT_PANEL + 132, 104 }, // chest { RIGHT_PANEL + 160, 104 }, // chest { RIGHT_PANEL + 132, 132 }, // chest { RIGHT_PANEL + 160, 132 }, // chest { RIGHT_PANEL + 132, 160 }, // chest { RIGHT_PANEL + 160, 160 }, // chest { RIGHT_PANEL + 17, 250 }, // inv row 1 { RIGHT_PANEL + 46, 250 }, // inv row 1 { RIGHT_PANEL + 74, 250 }, // inv row 1 { RIGHT_PANEL + 103, 250 }, // inv row 1 { RIGHT_PANEL + 131, 250 }, // inv row 1 { RIGHT_PANEL + 160, 250 }, // inv row 1 { RIGHT_PANEL + 189, 250 }, // inv row 1 { RIGHT_PANEL + 218, 250 }, // inv row 1 { RIGHT_PANEL + 247, 250 }, // inv row 1 { RIGHT_PANEL + 276, 250 }, // inv row 1 { RIGHT_PANEL + 17, 279 }, // inv row 2 { RIGHT_PANEL + 46, 279 }, // inv row 2 { RIGHT_PANEL + 74, 279 }, // inv row 2 { RIGHT_PANEL + 103, 279 }, // inv row 2 { RIGHT_PANEL + 131, 279 }, // inv row 2 { RIGHT_PANEL + 160, 279 }, // inv row 2 { RIGHT_PANEL + 189, 279 }, // inv row 2 { RIGHT_PANEL + 218, 279 }, // inv row 2 { RIGHT_PANEL + 247, 279 }, // inv row 2 { RIGHT_PANEL + 276, 279 }, // inv row 2 { RIGHT_PANEL + 17, 308 }, // inv row 3 { RIGHT_PANEL + 46, 308 }, // inv row 3 { RIGHT_PANEL + 74, 308 }, // inv row 3 { RIGHT_PANEL + 103, 308 }, // inv row 3 { RIGHT_PANEL + 131, 308 }, // inv row 3 { RIGHT_PANEL + 160, 308 }, // inv row 3 { RIGHT_PANEL + 189, 308 }, // inv row 3 { RIGHT_PANEL + 218, 308 }, // inv row 3 { RIGHT_PANEL + 247, 308 }, // inv row 3 { RIGHT_PANEL + 276, 308 }, // inv row 3 { RIGHT_PANEL + 17, 336 }, // inv row 4 { RIGHT_PANEL + 46, 336 }, // inv row 4 { RIGHT_PANEL + 74, 336 }, // inv row 4 { RIGHT_PANEL + 103, 336 }, // inv row 4 { RIGHT_PANEL + 131, 336 }, // inv row 4 { RIGHT_PANEL + 160, 336 }, // inv row 4 { RIGHT_PANEL + 189, 336 }, // inv row 4 { RIGHT_PANEL + 218, 336 }, // inv row 4 { RIGHT_PANEL + 247, 336 }, // inv row 4 { RIGHT_PANEL + 276, 336 }, // inv row 4 { PANEL_LEFT + 205, PANEL_TOP + 33 }, // belt { PANEL_LEFT + 234, PANEL_TOP + 33 }, // belt { PANEL_LEFT + 263, PANEL_TOP + 33 }, // belt { PANEL_LEFT + 292, PANEL_TOP + 33 }, // belt { PANEL_LEFT + 321, PANEL_TOP + 33 }, // belt { PANEL_LEFT + 350, PANEL_TOP + 33 }, // belt { PANEL_LEFT + 379, PANEL_TOP + 33 }, // belt { PANEL_LEFT + 408, PANEL_TOP + 33 } // belt // clang-format on }; /* data */ /** Specifies the starting inventory slots for placement of 2x2 items. */ int AP2x2Tbl[10] = { 8, 28, 6, 26, 4, 24, 2, 22, 0, 20 }; void FreeInvGFX() { MemFreeDbg(pInvCels); } void InitInv() { if (plr[myplr]._pClass == PC_WARRIOR) { pInvCels = LoadFileInMem("Data\\Inv\\Inv.CEL", NULL); #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { pInvCels = LoadFileInMem("Data\\Inv\\Inv_rog.CEL", NULL); } else if (plr[myplr]._pClass == PC_SORCERER) { pInvCels = LoadFileInMem("Data\\Inv\\Inv_Sor.CEL", NULL); #endif #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { #ifndef SPAWN pInvCels = LoadFileInMem("Data\\Inv\\Inv_Sor.CEL", NULL); #else pInvCels = LoadFileInMem("Data\\Inv\\Inv.CEL", NULL); #endif } else if (plr[myplr]._pClass == PC_BARD) { pInvCels = LoadFileInMem("Data\\Inv\\Inv_rog.CEL", NULL); } else if (plr[myplr]._pClass == PC_BARBARIAN) { pInvCels = LoadFileInMem("Data\\Inv\\Inv.CEL", NULL); #endif } invflag = FALSE; drawsbarflag = FALSE; } void InvDrawSlotBack(int X, int Y, int W, int H) { BYTE *dst; assert(gpBuffer); dst = &gpBuffer[X + PitchTbl[Y]]; #ifdef USE_ASM __asm { mov edi, dst xor edx, edx xor ebx, ebx mov dx, word ptr H mov bx, word ptr W label1: mov ecx, ebx label2: mov al, [edi] cmp al, PAL16_BLUE jb label5 cmp al, PAL16_BLUE + 15 ja label3 sub al, PAL16_BLUE - PAL16_BEIGE jmp label4 label3: cmp al, PAL16_GRAY jb label5 sub al, PAL16_GRAY - PAL16_BEIGE label4: mov [edi], al label5: inc edi loop label2 sub edi, BUFFER_WIDTH sub edi, ebx dec edx jnz label1 } #else int wdt, hgt; BYTE pix; for (hgt = H; hgt; hgt--, dst -= BUFFER_WIDTH + W) { for (wdt = W; wdt; wdt--) { pix = *dst; if (pix >= PAL16_BLUE) { if (pix <= PAL16_BLUE + 15) pix -= PAL16_BLUE - PAL16_BEIGE; else if (pix >= PAL16_GRAY) pix -= PAL16_GRAY - PAL16_BEIGE; } *dst++ = pix; } } #endif } /** * @brief Render the inventory panel to the back buffer */ void DrawInv() { BOOL invtest[NUM_INV_GRID_ELEM]; int frame, frame_width, color, screen_x, screen_y, i, j, ii; BYTE *pBuff; CelDraw(RIGHT_PANEL_X, 351 + SCREEN_Y, pInvCels, 1, 320); if (plr[myplr].InvBody[INVLOC_HEAD]._itype != ITYPE_NONE) { InvDrawSlotBack(RIGHT_PANEL_X + 133, 59 + SCREEN_Y, 2 * INV_SLOT_SIZE_PX, 2 * INV_SLOT_SIZE_PX); frame = plr[myplr].InvBody[INVLOC_HEAD]._iCurs + CURSOR_FIRSTITEM; frame_width = InvItemWidth[frame]; if (pcursinvitem == INVITEM_HEAD) { color = ICOL_WHITE; if (plr[myplr].InvBody[INVLOC_HEAD]._iMagical != ITEM_QUALITY_NORMAL) { color = ICOL_BLUE; } if (!plr[myplr].InvBody[INVLOC_HEAD]._iStatFlag) { color = ICOL_RED; } #ifdef HELLFIRE if (frame <= 179) { #endif CelBlitOutline(color, RIGHT_PANEL_X + 133, 59 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelBlitOutline(color, RIGHT_PANEL_X + 133, 59 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } if (plr[myplr].InvBody[INVLOC_HEAD]._iStatFlag) { #ifdef HELLFIRE if (frame <= 179) { #endif CelClippedDraw(RIGHT_PANEL_X + 133, 59 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelClippedDraw(RIGHT_PANEL_X + 133, 59 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } else { #ifdef HELLFIRE if (frame <= 179) { #endif CelDrawLightRed(RIGHT_PANEL_X + 133, 59 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8, 1); #ifdef HELLFIRE } else { CelDrawLightRed(RIGHT_PANEL_X + 133, 59 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8, 1); } #endif } } if (plr[myplr].InvBody[INVLOC_RING_LEFT]._itype != ITYPE_NONE) { InvDrawSlotBack(RIGHT_PANEL_X + 48, 205 + SCREEN_Y, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX); frame = plr[myplr].InvBody[INVLOC_RING_LEFT]._iCurs + CURSOR_FIRSTITEM; frame_width = InvItemWidth[frame]; if (pcursinvitem == INVITEM_RING_LEFT) { color = ICOL_WHITE; if (plr[myplr].InvBody[INVLOC_RING_LEFT]._iMagical != ITEM_QUALITY_NORMAL) { color = ICOL_BLUE; } if (!plr[myplr].InvBody[INVLOC_RING_LEFT]._iStatFlag) { color = ICOL_RED; } #ifdef HELLFIRE if (frame <= 179) { #endif CelBlitOutline(color, RIGHT_PANEL_X + 48, 205 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelBlitOutline(color, RIGHT_PANEL_X + 48, 205 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } if (plr[myplr].InvBody[INVLOC_RING_LEFT]._iStatFlag) { #ifdef HELLFIRE if (frame <= 179) { #endif CelClippedDraw(RIGHT_PANEL_X + 48, 205 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelClippedDraw(RIGHT_PANEL_X + 48, 205 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } else { #ifdef HELLFIRE if (frame <= 179) { #endif CelDrawLightRed(RIGHT_PANEL_X + 48, 205 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8, 1); #ifdef HELLFIRE } else { CelDrawLightRed(RIGHT_PANEL_X + 48, 205 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8, 1); } #endif } } if (plr[myplr].InvBody[INVLOC_RING_RIGHT]._itype != ITYPE_NONE) { InvDrawSlotBack(RIGHT_PANEL_X + 249, 205 + SCREEN_Y, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX); frame = plr[myplr].InvBody[INVLOC_RING_RIGHT]._iCurs + CURSOR_FIRSTITEM; frame_width = InvItemWidth[frame]; if (pcursinvitem == INVITEM_RING_RIGHT) { color = ICOL_WHITE; if (plr[myplr].InvBody[INVLOC_RING_RIGHT]._iMagical != ITEM_QUALITY_NORMAL) { color = ICOL_BLUE; } if (!plr[myplr].InvBody[INVLOC_RING_RIGHT]._iStatFlag) { color = ICOL_RED; } #ifdef HELLFIRE if (frame <= 179) { #endif CelBlitOutline(color, RIGHT_PANEL_X + 249, 205 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelBlitOutline(color, RIGHT_PANEL_X + 249, 205 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } if (plr[myplr].InvBody[INVLOC_RING_RIGHT]._iStatFlag) { #ifdef HELLFIRE if (frame <= 179) { #endif CelClippedDraw(RIGHT_PANEL_X + 249, 205 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelClippedDraw(RIGHT_PANEL_X + 249, 205 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } else { #ifdef HELLFIRE if (frame <= 179) { #endif CelDrawLightRed(RIGHT_PANEL_X + 249, 205 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8, 1); #ifdef HELLFIRE } else { CelDrawLightRed(RIGHT_PANEL_X + 249, 205 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8, 1); } #endif } } if (plr[myplr].InvBody[INVLOC_AMULET]._itype != ITYPE_NONE) { InvDrawSlotBack(RIGHT_PANEL_X + 205, 60 + SCREEN_Y, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX); frame = plr[myplr].InvBody[INVLOC_AMULET]._iCurs + CURSOR_FIRSTITEM; frame_width = InvItemWidth[frame]; if (pcursinvitem == INVITEM_AMULET) { color = ICOL_WHITE; if (plr[myplr].InvBody[INVLOC_AMULET]._iMagical != ITEM_QUALITY_NORMAL) { color = ICOL_BLUE; } if (!plr[myplr].InvBody[INVLOC_AMULET]._iStatFlag) { color = ICOL_RED; } #ifdef HELLFIRE if (frame <= 179) { #endif CelBlitOutline(color, RIGHT_PANEL_X + 205, 60 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelBlitOutline(color, RIGHT_PANEL_X + 205, 60 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } if (plr[myplr].InvBody[INVLOC_AMULET]._iStatFlag) { #ifdef HELLFIRE if (frame <= 179) { #endif CelClippedDraw(RIGHT_PANEL_X + 205, 60 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelClippedDraw(RIGHT_PANEL_X + 205, 60 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } else { #ifdef HELLFIRE if (frame <= 179) { #endif CelDrawLightRed(RIGHT_PANEL_X + 205, 60 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8, 1); #ifdef HELLFIRE } else { CelDrawLightRed(RIGHT_PANEL_X + 205, 60 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8, 1); } #endif } } if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE) { InvDrawSlotBack(RIGHT_PANEL_X + 17, 160 + SCREEN_Y, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX); frame = plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCurs + CURSOR_FIRSTITEM; frame_width = InvItemWidth[frame]; // calc item offsets for weapons smaller than 2x3 slots screen_x = frame_width == INV_SLOT_SIZE_PX ? (RIGHT_PANEL_X + 31) : (RIGHT_PANEL_X + 17); screen_y = InvItemHeight[frame] == (3 * INV_SLOT_SIZE_PX) ? (160 + SCREEN_Y) : (146 + SCREEN_Y); if (pcursinvitem == INVITEM_HAND_LEFT) { color = ICOL_WHITE; if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMagical != ITEM_QUALITY_NORMAL) { color = ICOL_BLUE; } if (!plr[myplr].InvBody[INVLOC_HAND_LEFT]._iStatFlag) { color = ICOL_RED; } #ifdef HELLFIRE if (frame <= 179) { #endif CelBlitOutline(color, screen_x, screen_y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelBlitOutline(color, screen_x, screen_y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._iStatFlag) { #ifdef HELLFIRE if (frame <= 179) { #endif CelClippedDraw(screen_x, screen_y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelClippedDraw(screen_x, screen_y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } else { #ifdef HELLFIRE if (frame <= 179) { #endif CelDrawLightRed(screen_x, screen_y, pCursCels, frame, frame_width, 0, 8, 1); #ifdef HELLFIRE } else { CelDrawLightRed(screen_x, screen_y, pCursCels2, frame - 179, frame_width, 0, 8, 1); } #endif } if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._iLoc == ILOC_TWOHAND) { #ifdef HELLFIRE if (plr[myplr]._pClass != PC_BARBARIAN || plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_SWORD && plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_MACE) { #endif InvDrawSlotBack(RIGHT_PANEL_X + 247, 160 + SCREEN_Y, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX); light_table_index = 0; cel_transparency_active = TRUE; pBuff = frame_width == INV_SLOT_SIZE_PX ? &gpBuffer[SCREENXY(RIGHT_PANEL_X + 197, SCREEN_Y)] : &gpBuffer[SCREENXY(RIGHT_PANEL_X + 183, SCREEN_Y)]; #ifdef HELLFIRE if (frame <= 179) { #endif CelClippedBlitLightTrans(pBuff, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelClippedBlitLightTrans(pBuff, pCursCels2, frame - 179, frame_width, 0, 8); } #endif cel_transparency_active = FALSE; #ifdef HELLFIRE } #endif } } if (plr[myplr].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE) { InvDrawSlotBack(RIGHT_PANEL_X + 247, 160 + SCREEN_Y, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX); frame = plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iCurs + CURSOR_FIRSTITEM; frame_width = InvItemWidth[frame]; // calc item offsets for weapons smaller than 2x3 slots screen_x = frame_width == INV_SLOT_SIZE_PX ? (RIGHT_PANEL_X + 261) : (RIGHT_PANEL_X + 249); screen_y = InvItemHeight[frame] == 3 * INV_SLOT_SIZE_PX ? (160 + SCREEN_Y) : (146 + SCREEN_Y); if (pcursinvitem == INVITEM_HAND_RIGHT) { color = ICOL_WHITE; if (plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iMagical != ITEM_QUALITY_NORMAL) { color = ICOL_BLUE; } if (!plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) { color = ICOL_RED; } #ifdef HELLFIRE if (frame <= 179) { #endif CelBlitOutline(color, screen_x, screen_y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelBlitOutline(color, screen_x, screen_y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } if (plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) { #ifdef HELLFIRE if (frame <= 179) { #endif CelClippedDraw(screen_x, screen_y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelClippedDraw(screen_x, screen_y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } else { #ifdef HELLFIRE if (frame <= 179) { #endif CelDrawLightRed(screen_x, screen_y, pCursCels, frame, frame_width, 0, 8, 1); #ifdef HELLFIRE } else { CelDrawLightRed(screen_x, screen_y, pCursCels2, frame - 179, frame_width, 0, 8, 1); } #endif } } if (plr[myplr].InvBody[INVLOC_CHEST]._itype != ITYPE_NONE) { InvDrawSlotBack(RIGHT_PANEL_X + 133, 160 + SCREEN_Y, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX); frame = plr[myplr].InvBody[INVLOC_CHEST]._iCurs + CURSOR_FIRSTITEM; frame_width = InvItemWidth[frame]; if (pcursinvitem == INVITEM_CHEST) { color = ICOL_WHITE; if (plr[myplr].InvBody[INVLOC_CHEST]._iMagical != ITEM_QUALITY_NORMAL) { color = ICOL_BLUE; } if (!plr[myplr].InvBody[INVLOC_CHEST]._iStatFlag) { color = ICOL_RED; } #ifdef HELLFIRE if (frame <= 179) { #endif CelBlitOutline(color, RIGHT_PANEL_X + 133, 160 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelBlitOutline(color, RIGHT_PANEL_X + 133, 160 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } if (plr[myplr].InvBody[INVLOC_CHEST]._iStatFlag) { #ifdef HELLFIRE if (frame <= 179) { #endif CelClippedDraw(RIGHT_PANEL_X + 133, 160 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelClippedDraw(RIGHT_PANEL_X + 133, 160 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } else { #ifdef HELLFIRE if (frame <= 179) { #endif CelDrawLightRed(RIGHT_PANEL_X + 133, 160 + SCREEN_Y, pCursCels, frame, frame_width, 0, 8, 1); #ifdef HELLFIRE } else { CelDrawLightRed(RIGHT_PANEL_X + 133, 160 + SCREEN_Y, pCursCels2, frame - 179, frame_width, 0, 8, 1); } #endif } } for (i = 0; i < NUM_INV_GRID_ELEM; i++) { invtest[i] = FALSE; if (plr[myplr].InvGrid[i] != 0) { InvDrawSlotBack( InvRect[i + SLOTXY_INV_FIRST].X + SCREEN_X, InvRect[i + SLOTXY_INV_FIRST].Y + SCREEN_Y - 1, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX); } } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[myplr].InvGrid[j] > 0) // first slot of an item { ii = plr[myplr].InvGrid[j] - 1; invtest[j] = TRUE; frame = plr[myplr].InvList[ii]._iCurs + CURSOR_FIRSTITEM; frame_width = InvItemWidth[frame]; if (pcursinvitem == ii + INVITEM_INV_FIRST) { color = ICOL_WHITE; if (plr[myplr].InvList[ii]._iMagical != ITEM_QUALITY_NORMAL) { color = ICOL_BLUE; } if (!plr[myplr].InvList[ii]._iStatFlag) { color = ICOL_RED; } #ifdef HELLFIRE if (frame <= 179) { #endif CelBlitOutline( color, InvRect[j + SLOTXY_INV_FIRST].X + SCREEN_X, InvRect[j + SLOTXY_INV_FIRST].Y + SCREEN_Y - 1, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelBlitOutline( color, InvRect[j + SLOTXY_INV_FIRST].X + SCREEN_X, InvRect[j + SLOTXY_INV_FIRST].Y + SCREEN_Y - 1, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } if (plr[myplr].InvList[ii]._iStatFlag) { #ifdef HELLFIRE if (frame <= 179) { #endif CelClippedDraw( InvRect[j + SLOTXY_INV_FIRST].X + SCREEN_X, InvRect[j + SLOTXY_INV_FIRST].Y + SCREEN_Y - 1, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE } else { CelClippedDraw( InvRect[j + SLOTXY_INV_FIRST].X + SCREEN_X, InvRect[j + SLOTXY_INV_FIRST].Y + SCREEN_Y - 1, pCursCels2, frame - 179, frame_width, 0, 8); } #endif } else { #ifdef HELLFIRE if (frame <= 179) { #endif CelDrawLightRed( InvRect[j + SLOTXY_INV_FIRST].X + SCREEN_X, InvRect[j + SLOTXY_INV_FIRST].Y + SCREEN_Y - 1, pCursCels, frame, frame_width, 0, 8, 1); #ifdef HELLFIRE } else { CelDrawLightRed( InvRect[j + SLOTXY_INV_FIRST].X + SCREEN_X, InvRect[j + SLOTXY_INV_FIRST].Y + SCREEN_Y - 1, pCursCels2, frame - 179, frame_width, 0, 8, 1); } #endif } } } } void DrawInvBelt() { int i, frame, frame_width, color; BYTE fi, ff; if (talkflag) { return; } DrawPanelBox(205, 21, 232, 28, PANEL_X + 205, PANEL_Y + 5); for (i = 0; i < MAXBELTITEMS; i++) { if (plr[myplr].SpdList[i]._itype == ITYPE_NONE) { continue; } InvDrawSlotBack(InvRect[i + SLOTXY_BELT_FIRST].X + SCREEN_X, InvRect[i + SLOTXY_BELT_FIRST].Y + SCREEN_Y - 1, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX); frame = plr[myplr].SpdList[i]._iCurs + CURSOR_FIRSTITEM; frame_width = InvItemWidth[frame]; if (pcursinvitem == i + INVITEM_BELT_FIRST) { color = ICOL_WHITE; if (plr[myplr].SpdList[i]._iMagical) color = ICOL_BLUE; if (!plr[myplr].SpdList[i]._iStatFlag) color = ICOL_RED; #ifdef HELLFIRE if (frame <= 179) #endif CelBlitOutline(color, InvRect[i + SLOTXY_BELT_FIRST].X + SCREEN_X, InvRect[i + SLOTXY_BELT_FIRST].Y + SCREEN_Y - 1, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE else CelBlitOutline(color, InvRect[i + SLOTXY_BELT_FIRST].X + SCREEN_X, InvRect[i + SLOTXY_BELT_FIRST].Y + SCREEN_Y - 1, pCursCels2, frame - 179, frame_width, 0, 8); #endif } if (plr[myplr].SpdList[i]._iStatFlag) { #ifdef HELLFIRE if (frame <= 179) #endif CelClippedDraw(InvRect[i + SLOTXY_BELT_FIRST].X + SCREEN_X, InvRect[i + SLOTXY_BELT_FIRST].Y + SCREEN_Y - 1, pCursCels, frame, frame_width, 0, 8); #ifdef HELLFIRE else CelClippedDraw(InvRect[i + SLOTXY_BELT_FIRST].X + SCREEN_X, InvRect[i + SLOTXY_BELT_FIRST].Y + SCREEN_Y - 1, pCursCels2, frame - 179, frame_width, 0, 8); #endif } else { #ifdef HELLFIRE if (frame <= 179) #endif CelDrawLightRed(InvRect[i + SLOTXY_BELT_FIRST].X + SCREEN_X, InvRect[i + SLOTXY_BELT_FIRST].Y + SCREEN_Y - 1, pCursCels, frame, frame_width, 0, 8, 1); #ifdef HELLFIRE else CelDrawLightRed(InvRect[i + SLOTXY_BELT_FIRST].X + SCREEN_X, InvRect[i + SLOTXY_BELT_FIRST].Y + SCREEN_Y - 1, pCursCels2, frame - 179, frame_width, 0, 8, 1); #endif } if (AllItemsList[plr[myplr].SpdList[i].IDidx].iUsable && plr[myplr].SpdList[i]._iStatFlag && plr[myplr].SpdList[i]._itype != ITYPE_GOLD) { fi = i + 49; ff = fontframe[gbFontTransTbl[fi]]; PrintChar(InvRect[i + SLOTXY_BELT_FIRST].X + SCREEN_X + PitchTbl[InvRect[i + SLOTXY_BELT_FIRST].Y + SCREEN_Y - 1] - fontkern[ff] + INV_SLOT_SIZE_PX, ff, 0); } } } BOOL AutoPlace(int pnum, int ii, int sx, int sy, BOOL saveflag) { int i, j, xx, yy; BOOL done; done = TRUE; yy = 10 * (ii / 10); if (yy < 0) { yy = 0; } for (j = 0; j < sy && done; j++) { if (yy >= NUM_INV_GRID_ELEM) { done = FALSE; } xx = ii % 10; if (xx < 0) { xx = 0; } for (i = 0; i < sx && done; i++) { if (xx >= 10) { done = FALSE; } else { done = plr[pnum].InvGrid[xx + yy] == 0; } xx++; } yy += 10; } if (done && saveflag) { plr[pnum].InvList[plr[pnum]._pNumInv] = plr[pnum].HoldItem; plr[pnum]._pNumInv++; yy = 10 * (ii / 10); if (yy < 0) { yy = 0; } for (j = 0; j < sy; j++) { xx = ii % 10; if (xx < 0) { xx = 0; } for (i = 0; i < sx; i++) { if (i != 0 || j != sy - 1) { plr[pnum].InvGrid[xx + yy] = -plr[pnum]._pNumInv; } else { plr[pnum].InvGrid[xx + yy] = plr[pnum]._pNumInv; } xx++; } yy += 10; } CalcPlrScrolls(pnum); } return done; } BOOL SpecialAutoPlace(int pnum, int ii, int sx, int sy, BOOL saveflag) { int i, j, xx, yy; BOOL done; done = TRUE; yy = 10 * (ii / 10); if (yy < 0) { yy = 0; } for (j = 0; j < sy && done; j++) { if (yy >= NUM_INV_GRID_ELEM) { done = FALSE; } xx = ii % 10; if (xx < 0) { xx = 0; } for (i = 0; i < sx && done; i++) { if (xx >= 10) { done = FALSE; } else { done = plr[pnum].InvGrid[xx + yy] == 0; } xx++; } yy += 10; } if (!done) { if (sx > 1 || sy > 1) { done = FALSE; } else { for (i = 0; i < MAXBELTITEMS; i++) { if (plr[pnum].SpdList[i]._itype == ITYPE_NONE) { done = TRUE; break; } } } } if (done && saveflag) { plr[pnum].InvList[plr[pnum]._pNumInv] = plr[pnum].HoldItem; plr[pnum]._pNumInv++; yy = 10 * (ii / 10); if (yy < 0) { yy = 0; } for (j = 0; j < sy; j++) { xx = ii % 10; if (xx < 0) { xx = 0; } for (i = 0; i < sx; i++) { if (i != 0 || j != sy - 1) { plr[pnum].InvGrid[xx + yy] = -plr[pnum]._pNumInv; } else { plr[pnum].InvGrid[xx + yy] = plr[pnum]._pNumInv; } xx++; } yy += 10; } CalcPlrScrolls(pnum); } return done; } BOOL GoldAutoPlace(int pnum) { int ii; int xx, yy; BOOL done; done = FALSE; for (int i = 0; i < plr[pnum]._pNumInv && !done; i++) { if (plr[pnum].InvList[i]._itype == ITYPE_GOLD) { int gold = plr[pnum].InvList[i]._ivalue + plr[pnum].HoldItem._ivalue; #ifdef HELLFIRE if (gold <= MaxGold) { #else if (plr[pnum].HoldItem._ivalue + plr[pnum].InvList[i]._ivalue <= GOLD_MAX_LIMIT) { #endif plr[pnum].InvList[i]._ivalue = gold; if (gold >= GOLD_MEDIUM_LIMIT) plr[pnum].InvList[i]._iCurs = ICURS_GOLD_LARGE; else if (gold <= GOLD_SMALL_LIMIT) plr[pnum].InvList[i]._iCurs = ICURS_GOLD_SMALL; else plr[pnum].InvList[i]._iCurs = ICURS_GOLD_MEDIUM; plr[pnum]._pGold = CalculateGold(pnum); done = TRUE; #ifdef HELLFIRE plr[pnum].HoldItem._ivalue = 0; } else { int max_gold = MaxGold; if (plr[pnum].InvList[i]._ivalue < max_gold) { int gold = max_gold - plr[pnum].InvList[i]._ivalue; plr[pnum].InvList[i]._ivalue = max_gold; plr[pnum].InvList[i]._iCurs = ICURS_GOLD_LARGE; plr[pnum].HoldItem._ivalue -= gold; if (plr[pnum].HoldItem._ivalue < 0) { plr[pnum].HoldItem._ivalue = 0; done = TRUE; } GetPlrHandSeed(&plr[pnum].HoldItem); control_set_gold_curs(pnum); plr[pnum]._pGold = CalculateGold(pnum); } #endif } } } #ifndef HELLFIRE if (!done) for (int i = 0; i < plr[pnum]._pNumInv && !done; i++) { if (plr[pnum].InvList[i]._itype == ITYPE_GOLD && plr[pnum].InvList[i]._ivalue < GOLD_MAX_LIMIT) { if (plr[pnum].HoldItem._ivalue + plr[pnum].InvList[i]._ivalue <= GOLD_MAX_LIMIT) { plr[pnum].InvList[i]._ivalue = plr[pnum].HoldItem._ivalue + plr[pnum].InvList[i]._ivalue; if (plr[pnum].InvList[i]._ivalue >= GOLD_MEDIUM_LIMIT) plr[pnum].InvList[i]._iCurs = ICURS_GOLD_LARGE; else if (plr[pnum].InvList[i]._ivalue <= GOLD_SMALL_LIMIT) plr[pnum].InvList[i]._iCurs = ICURS_GOLD_SMALL; else plr[pnum].InvList[i]._iCurs = ICURS_GOLD_MEDIUM; plr[pnum]._pGold = CalculateGold(pnum); done = TRUE; } } } #endif if (!done) for (int i = 39; i >= 0 && !done; i--) { yy = 10 * (i / 10); xx = i % 10; if (plr[pnum].InvGrid[xx + yy] == 0) { ii = plr[pnum]._pNumInv; plr[pnum].InvList[ii] = plr[pnum].HoldItem; plr[pnum]._pNumInv = plr[pnum]._pNumInv + 1; plr[pnum].InvGrid[xx + yy] = plr[pnum]._pNumInv; if (plr[pnum].HoldItem._ivalue >= GOLD_MEDIUM_LIMIT) plr[pnum].InvList[ii]._iCurs = ICURS_GOLD_LARGE; else if (plr[pnum].HoldItem._ivalue <= GOLD_SMALL_LIMIT) plr[pnum].InvList[ii]._iCurs = ICURS_GOLD_SMALL; else plr[pnum].InvList[ii]._iCurs = ICURS_GOLD_MEDIUM; #ifdef HELLFIRE int gold = plr[pnum].HoldItem._ivalue; if (gold > MaxGold) { gold -= MaxGold; plr[pnum].HoldItem._ivalue = gold; GetPlrHandSeed(&plr[pnum].HoldItem); plr[pnum].InvList[ii]._ivalue = MaxGold; } else { plr[pnum].HoldItem._ivalue = 0; done = TRUE; plr[pnum]._pGold = CalculateGold(pnum); SetCursor_(CURSOR_HAND); } #else plr[pnum]._pGold = CalculateGold(pnum); done = TRUE; #endif } } return done; } BOOL WeaponAutoPlace(int pnum) { #ifdef HELLFIRE if (plr[pnum]._pClass == PC_MONK) return FALSE; #endif if (plr[pnum].HoldItem._iLoc != ILOC_TWOHAND #ifdef HELLFIRE || (plr[pnum]._pClass == PC_BARBARIAN && (plr[pnum].HoldItem._itype == ITYPE_SWORD || plr[pnum].HoldItem._itype == ITYPE_MACE)) #endif ) { #ifdef HELLFIRE if (plr[pnum]._pClass != PC_BARD) #endif { if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON) return FALSE; if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON) return FALSE; } if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_NONE) { NetSendCmdChItem(TRUE, INVLOC_HAND_LEFT); plr[pnum].InvBody[INVLOC_HAND_LEFT] = plr[pnum].HoldItem; return TRUE; } if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iLoc != ILOC_TWOHAND) { NetSendCmdChItem(TRUE, INVLOC_HAND_RIGHT); plr[pnum].InvBody[INVLOC_HAND_RIGHT] = plr[pnum].HoldItem; return TRUE; } } else if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_NONE) { NetSendCmdChItem(TRUE, INVLOC_HAND_LEFT); plr[pnum].InvBody[INVLOC_HAND_LEFT] = plr[pnum].HoldItem; return TRUE; } return FALSE; } int SwapItem(ItemStruct *a, ItemStruct *b) { ItemStruct h; h = *a; *a = *b; *b = h; return h._iCurs + CURSOR_FIRSTITEM; } void CheckInvPaste(int pnum, int mx, int my) { int r, sx, sy; int i, j, xx, yy, ii; BOOL done, done2h; int il, cn, it, iv, ig, gt; ItemStruct tempitem; SetICursor(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM); i = mx + (icursW >> 1); j = my + (icursH >> 1); sx = icursW28; sy = icursH28; done = FALSE; for (r = 0; (DWORD)r < NUM_XY_SLOTS && !done; r++) { if (i >= InvRect[r].X && i < InvRect[r].X + INV_SLOT_SIZE_PX) { if (j >= InvRect[r].Y - INV_SLOT_SIZE_PX - 1 && j < InvRect[r].Y) { done = TRUE; r--; } } if (r == SLOTXY_CHEST_LAST) { if ((sx & 1) == 0) i -= 14; if ((sy & 1) == 0) j -= 14; } if (r == SLOTXY_INV_LAST && (sy & 1) == 0) j += 14; } if (!done) return; il = ILOC_UNEQUIPABLE; if (r >= SLOTXY_HEAD_FIRST && r <= SLOTXY_HEAD_LAST) il = ILOC_HELM; if (r >= SLOTXY_RING_LEFT && r <= SLOTXY_RING_RIGHT) il = ILOC_RING; if (r == SLOTXY_AMULET) il = ILOC_AMULET; if (r >= SLOTXY_HAND_LEFT_FIRST && r <= SLOTXY_HAND_RIGHT_LAST) il = ILOC_ONEHAND; if (r >= SLOTXY_CHEST_FIRST && r <= SLOTXY_CHEST_LAST) il = ILOC_ARMOR; if (r >= SLOTXY_BELT_FIRST && r <= SLOTXY_BELT_LAST) il = ILOC_BELT; done = FALSE; if (plr[pnum].HoldItem._iLoc == il) done = TRUE; if (il == ILOC_ONEHAND && plr[pnum].HoldItem._iLoc == ILOC_TWOHAND) { #ifdef HELLFIRE if (plr[pnum]._pClass == PC_BARBARIAN && (plr[pnum].HoldItem._itype == ITYPE_SWORD || plr[pnum].HoldItem._itype == ITYPE_MACE)) il = ILOC_ONEHAND; else #endif il = ILOC_TWOHAND; done = TRUE; } if (plr[pnum].HoldItem._iLoc == ILOC_UNEQUIPABLE && il == ILOC_BELT) { if (sx == 1 && sy == 1) { done = TRUE; if (!AllItemsList[plr[pnum].HoldItem.IDidx].iUsable) done = FALSE; if (!plr[pnum].HoldItem._iStatFlag) done = FALSE; if (plr[pnum].HoldItem._itype == ITYPE_GOLD) done = FALSE; } } if (il == ILOC_UNEQUIPABLE) { done = TRUE; it = 0; ii = r - SLOTXY_INV_FIRST; if (plr[pnum].HoldItem._itype == ITYPE_GOLD) { yy = 10 * (ii / 10); xx = ii % 10; if (plr[pnum].InvGrid[xx + yy] != 0) { iv = plr[pnum].InvGrid[xx + yy]; if (iv > 0) { if (plr[pnum].InvList[iv - 1]._itype != ITYPE_GOLD) { it = iv; } } else { it = -iv; } } } else { yy = 10 * ((ii / 10) - ((sy - 1) >> 1)); if (yy < 0) yy = 0; for (j = 0; j < sy && done; j++) { if (yy >= NUM_INV_GRID_ELEM) done = FALSE; xx = (ii % 10) - ((sx - 1) >> 1); if (xx < 0) xx = 0; for (i = 0; i < sx && done; i++) { if (xx >= 10) { done = FALSE; } else { if (plr[pnum].InvGrid[xx + yy] != 0) { iv = plr[pnum].InvGrid[xx + yy]; if (iv < 0) iv = -iv; if (it != 0) { if (it != iv) done = FALSE; } else it = iv; } } xx++; } yy += 10; } } } if (!done) return; if (il != ILOC_UNEQUIPABLE && il != ILOC_BELT && !plr[pnum].HoldItem._iStatFlag) { done = FALSE; if (plr[pnum]._pClass == PC_WARRIOR) PlaySFX(PS_WARR13); #ifndef SPAWN else if (plr[pnum]._pClass == PC_ROGUE) PlaySFX(PS_ROGUE13); else if (plr[pnum]._pClass == PC_SORCERER) PlaySFX(PS_MAGE13); #endif #ifdef HELLFIRE else if (plr[pnum]._pClass == PC_MONK) PlaySFX(PS_MONK13); #ifndef SPAWN else if (plr[pnum]._pClass == PC_BARD) PlaySFX(PS_ROGUE13); #endif else if (plr[pnum]._pClass == PC_BARBARIAN) PlaySFX(PS_MAGE13); #endif } if (!done) return; if (pnum == myplr) PlaySFX(ItemInvSnds[ItemCAnimTbl[plr[pnum].HoldItem._iCurs]]); cn = CURSOR_HAND; switch (il) { case ILOC_HELM: NetSendCmdChItem(FALSE, INVLOC_HEAD); if (plr[pnum].InvBody[INVLOC_HEAD]._itype == ITYPE_NONE) plr[pnum].InvBody[INVLOC_HEAD] = plr[pnum].HoldItem; else cn = SwapItem(&plr[pnum].InvBody[INVLOC_HEAD], &plr[pnum].HoldItem); break; case ILOC_RING: if (r == SLOTXY_RING_LEFT) { NetSendCmdChItem(FALSE, INVLOC_RING_LEFT); if (plr[pnum].InvBody[INVLOC_RING_LEFT]._itype == ITYPE_NONE) plr[pnum].InvBody[INVLOC_RING_LEFT] = plr[pnum].HoldItem; else cn = SwapItem(&plr[pnum].InvBody[INVLOC_RING_LEFT], &plr[pnum].HoldItem); } else { NetSendCmdChItem(FALSE, INVLOC_RING_RIGHT); if (plr[pnum].InvBody[INVLOC_RING_RIGHT]._itype == ITYPE_NONE) plr[pnum].InvBody[INVLOC_RING_RIGHT] = plr[pnum].HoldItem; else cn = SwapItem(&plr[pnum].InvBody[INVLOC_RING_RIGHT], &plr[pnum].HoldItem); } break; case ILOC_AMULET: NetSendCmdChItem(FALSE, INVLOC_AMULET); if (plr[pnum].InvBody[INVLOC_AMULET]._itype == ITYPE_NONE) plr[pnum].InvBody[INVLOC_AMULET] = plr[pnum].HoldItem; else cn = SwapItem(&plr[pnum].InvBody[INVLOC_AMULET], &plr[pnum].HoldItem); break; case ILOC_ONEHAND: if (r <= SLOTXY_HAND_LEFT_LAST) { if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_NONE) { if ((plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_NONE || plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass != plr[pnum].HoldItem._iClass) #ifdef HELLFIRE || (plr[pnum]._pClass == PC_BARD && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON && plr[pnum].HoldItem._iClass == ICLASS_WEAPON) #endif ) { NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT); plr[pnum].InvBody[INVLOC_HAND_LEFT] = plr[pnum].HoldItem; } else { NetSendCmdChItem(FALSE, INVLOC_HAND_RIGHT); cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_RIGHT], &plr[pnum].HoldItem); } break; } if ((plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_NONE || plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass != plr[pnum].HoldItem._iClass) #ifdef HELLFIRE || (plr[pnum]._pClass == PC_BARD && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON && plr[pnum].HoldItem._iClass == ICLASS_WEAPON) #endif ) { NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT); cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_LEFT], &plr[pnum].HoldItem); break; } NetSendCmdChItem(FALSE, INVLOC_HAND_RIGHT); cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_RIGHT], &plr[pnum].HoldItem); break; } if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_NONE) { if ((plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_NONE || plr[pnum].InvBody[INVLOC_HAND_LEFT]._iLoc != ILOC_TWOHAND) #ifdef HELLFIRE || (plr[pnum]._pClass == PC_BARBARIAN && (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD || plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_MACE)) #endif ) { if ((plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_NONE || plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass != plr[pnum].HoldItem._iClass) #ifdef HELLFIRE || (plr[pnum]._pClass == PC_BARD && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON && plr[pnum].HoldItem._iClass == ICLASS_WEAPON) #endif ) { NetSendCmdChItem(FALSE, INVLOC_HAND_RIGHT); plr[pnum].InvBody[INVLOC_HAND_RIGHT] = plr[pnum].HoldItem; break; } NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT); cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_LEFT], &plr[pnum].HoldItem); break; } #ifdef HELLFIRE NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT); #else NetSendCmdDelItem(FALSE, INVLOC_HAND_LEFT); NetSendCmdChItem(FALSE, INVLOC_HAND_RIGHT); #endif SwapItem(&plr[pnum].InvBody[INVLOC_HAND_RIGHT], &plr[pnum].InvBody[INVLOC_HAND_LEFT]); cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_RIGHT], &plr[pnum].HoldItem); break; } if ((plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass == plr[pnum].HoldItem._iClass) #ifdef HELLFIRE && !(plr[pnum]._pClass == PC_BARD && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON && plr[pnum].HoldItem._iClass == ICLASS_WEAPON) #endif ) { NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT); cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_LEFT], &plr[pnum].HoldItem); break; } NetSendCmdChItem(FALSE, INVLOC_HAND_RIGHT); cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_RIGHT], &plr[pnum].HoldItem); break; case ILOC_TWOHAND: NetSendCmdDelItem(FALSE, INVLOC_HAND_RIGHT); if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE) { tempitem = plr[pnum].HoldItem; if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD) plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_HAND_RIGHT]; else plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_HAND_LEFT]; if (pnum == myplr) SetCursor_(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM); else SetICursor(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM); done2h = FALSE; for (i = 0; i < NUM_INV_GRID_ELEM && !done2h; i++) done2h = AutoPlace(pnum, i, icursW28, icursH28, TRUE); plr[pnum].HoldItem = tempitem; if (pnum == myplr) SetCursor_(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM); else SetICursor(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM); if (!done2h) return; if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD) plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype = ITYPE_NONE; else plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype = ITYPE_NONE; } if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE || plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE) { NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT); if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_NONE) SwapItem(&plr[pnum].InvBody[INVLOC_HAND_LEFT], &plr[pnum].InvBody[INVLOC_HAND_RIGHT]); cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_LEFT], &plr[pnum].HoldItem); } else { NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT); plr[pnum].InvBody[INVLOC_HAND_LEFT] = plr[pnum].HoldItem; } if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_STAFF && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iSpell != SPL_NULL && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iCharges > 0) { plr[pnum]._pRSpell = plr[pnum].InvBody[INVLOC_HAND_LEFT]._iSpell; plr[pnum]._pRSplType = RSPLTYPE_CHARGES; force_redraw = 255; } break; case ILOC_ARMOR: NetSendCmdChItem(FALSE, INVLOC_CHEST); if (plr[pnum].InvBody[INVLOC_CHEST]._itype == ITYPE_NONE) plr[pnum].InvBody[INVLOC_CHEST] = plr[pnum].HoldItem; else cn = SwapItem(&plr[pnum].InvBody[INVLOC_CHEST], &plr[pnum].HoldItem); break; case ILOC_UNEQUIPABLE: if (plr[pnum].HoldItem._itype == ITYPE_GOLD && it == 0) { ii = r - SLOTXY_INV_FIRST; yy = 10 * (ii / 10); xx = ii % 10; if (plr[pnum].InvGrid[yy + xx] > 0) { il = plr[pnum].InvGrid[yy + xx]; il--; gt = plr[pnum].InvList[il]._ivalue; ig = plr[pnum].HoldItem._ivalue + gt; if (ig <= GOLD_MAX_LIMIT) { plr[pnum].InvList[il]._ivalue = ig; plr[pnum]._pGold += plr[pnum].HoldItem._ivalue; if (ig >= GOLD_MEDIUM_LIMIT) plr[pnum].InvList[il]._iCurs = ICURS_GOLD_LARGE; else if (ig <= GOLD_SMALL_LIMIT) plr[pnum].InvList[il]._iCurs = ICURS_GOLD_SMALL; else plr[pnum].InvList[il]._iCurs = ICURS_GOLD_MEDIUM; } else { ig = GOLD_MAX_LIMIT - gt; plr[pnum]._pGold += ig; plr[pnum].HoldItem._ivalue -= ig; plr[pnum].InvList[il]._ivalue = GOLD_MAX_LIMIT; plr[pnum].InvList[il]._iCurs = ICURS_GOLD_LARGE; // BUGFIX: incorrect values here are leftover from beta if (plr[pnum].HoldItem._ivalue >= GOLD_MEDIUM_LIMIT) cn = ICURS_GOLD_LARGE + CURSOR_FIRSTITEM; else if (plr[pnum].HoldItem._ivalue <= GOLD_SMALL_LIMIT) cn = ICURS_GOLD_SMALL + CURSOR_FIRSTITEM; else cn = ICURS_GOLD_MEDIUM + CURSOR_FIRSTITEM; } } else { il = plr[pnum]._pNumInv; plr[pnum].InvList[il] = plr[pnum].HoldItem; plr[pnum]._pNumInv++; plr[pnum].InvGrid[yy + xx] = plr[pnum]._pNumInv; plr[pnum]._pGold += plr[pnum].HoldItem._ivalue; if (plr[pnum].HoldItem._ivalue <= GOLD_MAX_LIMIT) { if (plr[pnum].HoldItem._ivalue >= GOLD_MEDIUM_LIMIT) plr[pnum].InvList[il]._iCurs = ICURS_GOLD_LARGE; else if (plr[pnum].HoldItem._ivalue <= GOLD_SMALL_LIMIT) plr[pnum].InvList[il]._iCurs = ICURS_GOLD_SMALL; else plr[pnum].InvList[il]._iCurs = ICURS_GOLD_MEDIUM; #ifdef HELLFIRE } else { plr[pnum].InvList[ii]._iCurs = ICURS_GOLD_LARGE; #endif } } } else { if (it == 0) { plr[pnum].InvList[plr[pnum]._pNumInv] = plr[pnum].HoldItem; plr[pnum]._pNumInv++; it = plr[pnum]._pNumInv; } else { il = it - 1; if (plr[pnum].HoldItem._itype == ITYPE_GOLD) plr[pnum]._pGold += plr[pnum].HoldItem._ivalue; cn = SwapItem(&plr[pnum].InvList[il], &plr[pnum].HoldItem); if (plr[pnum].HoldItem._itype == ITYPE_GOLD) plr[pnum]._pGold = CalculateGold(pnum); for (i = 0; i < NUM_INV_GRID_ELEM; i++) { if (plr[pnum].InvGrid[i] == it) plr[pnum].InvGrid[i] = 0; if (plr[pnum].InvGrid[i] == -it) plr[pnum].InvGrid[i] = 0; } } ii = r - SLOTXY_INV_FIRST; yy = 10 * (ii / 10 - ((sy - 1) >> 1)); if (yy < 0) yy = 0; for (j = 0; j < sy; j++) { xx = (ii % 10 - ((sx - 1) >> 1)); if (xx < 0) xx = 0; for (i = 0; i < sx; i++) { if (i != 0 || j != sy - 1) plr[pnum].InvGrid[xx + yy] = -it; else plr[pnum].InvGrid[xx + yy] = it; xx++; } yy += 10; } } break; case ILOC_BELT: ii = r - SLOTXY_BELT_FIRST; if (plr[pnum].HoldItem._itype == ITYPE_GOLD) { if (plr[pnum].SpdList[ii]._itype != ITYPE_NONE) { if (plr[pnum].SpdList[ii]._itype == ITYPE_GOLD) { i = plr[pnum].HoldItem._ivalue + plr[pnum].SpdList[ii]._ivalue; if (i <= GOLD_MAX_LIMIT) { plr[pnum].SpdList[ii]._ivalue += plr[pnum].HoldItem._ivalue; plr[pnum]._pGold += plr[pnum].HoldItem._ivalue; if (i >= GOLD_MEDIUM_LIMIT) plr[pnum].SpdList[ii]._iCurs = ICURS_GOLD_LARGE; else if (i <= GOLD_SMALL_LIMIT) plr[pnum].SpdList[ii]._iCurs = ICURS_GOLD_SMALL; else plr[pnum].SpdList[ii]._iCurs = ICURS_GOLD_MEDIUM; } else { i = GOLD_MAX_LIMIT - plr[pnum].SpdList[ii]._ivalue; plr[pnum]._pGold += i; plr[pnum].HoldItem._ivalue -= i; plr[pnum].SpdList[ii]._ivalue = GOLD_MAX_LIMIT; plr[pnum].SpdList[ii]._iCurs = ICURS_GOLD_LARGE; // BUGFIX: incorrect values here are leftover from beta if (plr[pnum].HoldItem._ivalue >= GOLD_MEDIUM_LIMIT) cn = ICURS_GOLD_LARGE + CURSOR_FIRSTITEM; else if (plr[pnum].HoldItem._ivalue <= GOLD_SMALL_LIMIT) cn = ICURS_GOLD_SMALL + CURSOR_FIRSTITEM; else cn = ICURS_GOLD_MEDIUM + CURSOR_FIRSTITEM; } } else { plr[pnum]._pGold += plr[pnum].HoldItem._ivalue; cn = SwapItem(&plr[pnum].SpdList[ii], &plr[pnum].HoldItem); } } else { plr[pnum].SpdList[ii] = plr[pnum].HoldItem; plr[pnum]._pGold += plr[pnum].HoldItem._ivalue; } } else if (plr[pnum].SpdList[ii]._itype == ITYPE_NONE) { plr[pnum].SpdList[ii] = plr[pnum].HoldItem; } else { cn = SwapItem(&plr[pnum].SpdList[ii], &plr[pnum].HoldItem); if (plr[pnum].HoldItem._itype == ITYPE_GOLD) plr[pnum]._pGold = CalculateGold(pnum); } drawsbarflag = TRUE; break; } CalcPlrInv(pnum, TRUE); if (pnum == myplr) { if (cn == CURSOR_HAND) SetCursorPos(MouseX + (cursW >> 1), MouseY + (cursH >> 1)); SetCursor_(cn); } } void CheckInvSwap(int pnum, BYTE bLoc, int idx, WORD wCI, int seed, BOOL bId) { PlayerStruct *p; RecreateItem(MAXITEMS, idx, wCI, seed, 0); 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 CheckInvCut(int pnum, int mx, int my) { int r; BOOL done; char ii; int iv, i, j, offs, ig; if (plr[pnum]._pmode > PM_WALK3) { return; } if (dropGoldFlag) { dropGoldFlag = FALSE; dropGoldValue = 0; } done = FALSE; 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) { ig = r - SLOTXY_INV_FIRST; ii = plr[pnum].InvGrid[ig]; if (ii != 0) { iv = ii; if (ii <= 0) { iv = -ii; } for (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 (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) { 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 = TRUE; } } 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); // BUGFIX: should be `my - (cursH >> 1)`, was `MouseY - (cursH >> 1)`. SetCursorPos(mx - (cursW >> 1), MouseY - (cursH >> 1)); } } } void inv_update_rem_item(int pnum, BYTE iv) { if (iv < NUM_INVLOC) { plr[pnum].InvBody[iv]._itype = ITYPE_NONE; } if (plr[pnum]._pmode != PM_DEATH) { CalcPlrInv(pnum, TRUE); } else { CalcPlrInv(pnum, FALSE); } } void RemoveInvItem(int pnum, int iv) { int i, j; iv++; for (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 (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 `unsigned __int64` to make that bitshift 64bit // this causes the last 4 skills to not reset correctly after use // replace with SPELLBIT(plr[pnum]._pRSpell) if (!( plr[pnum]._pScrlSpells & (1 << (plr[pnum]._pRSpell - 1)))) { plr[pnum]._pRSpell = SPL_INVALID; } force_redraw = 255; } } } #ifdef HELLFIRE /** * @brief This destroyes all items except gold */ BOOL inv_diablo_to_hellfire(int pnum) { ItemStruct tmp; ItemStruct *item; int i, old_item_cnt, new_item_index; if (plr[pnum]._pgfxnum != 0) { plr[pnum]._pgfxnum = 0; plr[pnum]._pGFXLoad = 0; SetPlrAnims(pnum); } for (i = 0, item = plr[pnum].InvBody; i < NUM_INVLOC; i++, item++) { item->_itype = ITYPE_NONE; } old_item_cnt = plr[pnum]._pNumInv; memset(plr[pnum].InvGrid, 0, sizeof(plr[pnum].InvGrid)); plr[pnum]._pNumInv = 0; for (i = 0; i < old_item_cnt; i++) { item = &plr[pnum].InvList[i]; if (item->_itype == ITYPE_GOLD) { new_item_index = plr[pnum]._pNumInv; // BUGFIX: new_item_index may be greater or equal to NUM_INV_GRID_ELEM tmp = *item; item->_itype = ITYPE_NONE; plr[pnum].InvList[new_item_index] = tmp; plr[pnum]._pNumInv++; plr[pnum].InvGrid[i] = plr[pnum]._pNumInv; } else { item->_itype = ITYPE_NONE; } }; for (i = 0, item = plr[pnum].SpdList; i < MAXBELTITEMS; i++, item++) { item->_itype = ITYPE_NONE; } CalcPlrItemVals(pnum, FALSE); return FALSE; } #endif void 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 `unsigned __int64` to make that bitshift 64bit // this causes the last 4 skills to not reset correctly after use // replace with SPELLBIT(plr[pnum]._pRSpell) if (!( plr[pnum]._pScrlSpells & (1 << (plr[pnum]._pRSpell - 1)))) { plr[pnum]._pRSpell = SPL_INVALID; } } } force_redraw = 255; } void CheckInvItem() { if (pcurs >= CURSOR_FIRSTITEM) { CheckInvPaste(myplr, MouseX, MouseY); } else { CheckInvCut(myplr, MouseX, MouseY); } } /** * Check for interactions with belt */ void CheckInvScrn() { if (MouseX > 190 + PANEL_LEFT && MouseX < 437 + PANEL_LEFT && MouseY > PANEL_TOP && MouseY < 33 + PANEL_TOP) { CheckInvItem(); } } void 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 CheckBookLevel(int pnum) { int slvl; if (plr[pnum].HoldItem._iMiscId == IMISC_BOOK) { plr[pnum].HoldItem._iMinMag = spelldata[plr[pnum].HoldItem._iSpell].sMinInt; slvl = plr[pnum]._pSplLvl[plr[pnum].HoldItem._iSpell]; while (slvl != 0) { plr[pnum].HoldItem._iMinMag += 20 * plr[pnum].HoldItem._iMinMag / 100; slvl--; if (plr[pnum].HoldItem._iMinMag + 20 * plr[pnum].HoldItem._iMinMag / 100 > 255) { plr[pnum].HoldItem._iMinMag = -1; slvl = 0; } } } } void CheckQuestItem(int pnum) { if (plr[pnum].HoldItem.IDidx == IDI_OPTAMULET) quests[Q_BLIND]._qactive = QUEST_DONE; if (plr[pnum].HoldItem.IDidx == IDI_MUSHROOM && quests[Q_MUSHROOM]._qactive == QUEST_ACTIVE && quests[Q_MUSHROOM]._qvar1 == QS_MUSHSPAWNED) { #ifndef SPAWN sfxdelay = 10; if (plr[pnum]._pClass == PC_WARRIOR) { // BUGFIX: Voice for this quest might be wrong in MP sfxdnum = PS_WARR95; } else if (plr[pnum]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE95; } else if (plr[pnum]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE95; } #ifdef HELLFIRE else if (plr[pnum]._pClass == PC_MONK) { sfxdnum = PS_MONK95; } else if (plr[pnum]._pClass == PC_BARD) { sfxdnum = PS_ROGUE95; } else if (plr[pnum]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR95; } #endif #endif quests[Q_MUSHROOM]._qvar1 = QS_MUSHPICKED; } if (plr[pnum].HoldItem.IDidx == IDI_ANVIL) { if (quests[Q_ANVIL]._qactive == QUEST_INIT) { quests[Q_ANVIL]._qactive = QUEST_ACTIVE; quests[Q_ANVIL]._qvar1 = 1; } #ifndef SPAWN if (quests[Q_ANVIL]._qlog == TRUE) { sfxdelay = 10; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR89; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE89; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE89; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK89; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE89; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR89; } #endif } #endif } #ifndef SPAWN if (plr[pnum].HoldItem.IDidx == IDI_GLDNELIX) { sfxdelay = 30; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR88; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE88; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE88; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK88; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE88; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR88; } #endif } #endif if (plr[pnum].HoldItem.IDidx == IDI_ROCK) { if (quests[Q_ROCK]._qactive == QUEST_INIT) { quests[Q_ROCK]._qactive = QUEST_ACTIVE; quests[Q_ROCK]._qvar1 = 1; } #ifndef SPAWN if (quests[Q_ROCK]._qlog == TRUE) { sfxdelay = 10; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR87; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE87; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE87; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK87; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE87; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR87; } #endif } #endif } if (plr[pnum].HoldItem.IDidx == IDI_ARMOFVAL) { quests[Q_BLOOD]._qactive = QUEST_DONE; #ifndef SPAWN sfxdelay = 20; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR91; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE91; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE91; #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK91; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE91; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR91; #endif } #endif } #ifdef HELLFIRE if (plr[pnum].HoldItem.IDidx == IDI_MAPOFDOOM) { quests[Q_GRAVE]._qlog = FALSE; quests[Q_GRAVE]._qactive = QUEST_ACTIVE; quests[Q_GRAVE]._qvar1 = 1; sfxdelay = 10; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR79; #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE79; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE79; #endif } else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK79; #ifndef SPAWN } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE79; #endif } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR79; } } if (plr[pnum].HoldItem.IDidx == IDI_NOTE1 || plr[pnum].HoldItem.IDidx == IDI_NOTE2 || plr[pnum].HoldItem.IDidx == IDI_NOTE3) { int mask, idx, item_num; int n1, n2, n3; ItemStruct tmp; mask = 0; idx = plr[pnum].HoldItem.IDidx; if (PlrHasItem(pnum, IDI_NOTE1, n1) || idx == IDI_NOTE1) mask = 1; if (PlrHasItem(pnum, IDI_NOTE2, n2) || idx == IDI_NOTE2) mask |= 2; if (PlrHasItem(pnum, IDI_NOTE3, n3) || idx == IDI_NOTE3) mask |= 4; if (mask == 7) { sfxdelay = 10; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR46; #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE46; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE46; #endif } else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK46; #ifndef SPAWN } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE46; #endif } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR46; } switch (idx) { case IDI_NOTE1: PlrHasItem(pnum, IDI_NOTE2, n2); RemoveInvItem(pnum, n2); PlrHasItem(pnum, IDI_NOTE3, n3); RemoveInvItem(pnum, n3); break; case IDI_NOTE2: PlrHasItem(pnum, IDI_NOTE1, n1); RemoveInvItem(pnum, n1); PlrHasItem(pnum, IDI_NOTE3, n3); RemoveInvItem(pnum, n3); break; case IDI_NOTE3: PlrHasItem(pnum, IDI_NOTE1, n1); RemoveInvItem(pnum, n1); PlrHasItem(pnum, IDI_NOTE2, n2); RemoveInvItem(pnum, n2); break; } item_num = itemactive[0]; tmp = item[item_num]; GetItemAttrs(item_num, IDI_FULLNOTE, 16); SetupItem(item_num); plr[pnum].HoldItem = item[item_num]; item[item_num] = tmp; } } #endif } void InvGetItem(int pnum, int ii) { int i; #ifdef HELLFIRE BOOL cursor_updated; #endif if (dropGoldFlag) { dropGoldFlag = FALSE; dropGoldValue = 0; } if (dItem[item[ii]._ix][item[ii]._iy] != 0) { if (myplr == pnum && pcurs >= CURSOR_FIRSTITEM) NetSendCmdPItem(TRUE, CMD_SYNCPUTITEM, plr[myplr]._px, plr[myplr]._py); #ifdef HELLFIRE if (item[ii]._iUid != 0) #endif item[ii]._iCreateInfo &= ~CF_PREGEN; plr[pnum].HoldItem = item[ii]; CheckQuestItem(pnum); CheckBookLevel(pnum); CheckItemStats(pnum); #ifdef HELLFIRE cursor_updated = FALSE; if (plr[pnum].HoldItem._itype == ITYPE_GOLD && GoldAutoPlace(pnum)) cursor_updated = TRUE; #endif dItem[item[ii]._ix][item[ii]._iy] = 0; #ifdef HELLFIRE if (currlevel == 21 && item[ii]._ix == CornerStone.x && item[ii]._iy == CornerStone.y) { CornerStone.item.IDidx = -1; CornerStone.item._itype = ITYPE_MISC; // BUGFIX should be ITYPE_NONE CornerStone.item._iSelFlag = FALSE; CornerStone.item._ix = 0; CornerStone.item._iy = 0; CornerStone.item._iAnimFlag = FALSE; CornerStone.item._iIdentified = FALSE; CornerStone.item._iPostDraw = FALSE; } #endif i = 0; while (i < numitems) { if (itemactive[i] == ii) { DeleteItem(itemactive[i], i); i = 0; } else { i++; } } pcursitem = -1; #ifdef HELLFIRE if (!cursor_updated) #endif SetCursor_(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM); } } void AutoGetItem(int pnum, int ii) { int i, idx; int w, h; BOOL done; if (dropGoldFlag) { dropGoldFlag = FALSE; dropGoldValue = 0; } if (ii != MAXITEMS) { if (dItem[item[ii]._ix][item[ii]._iy] == 0) return; } #ifdef HELLFIRE if (item[ii]._iUid != 0) #endif item[ii]._iCreateInfo &= ~CF_PREGEN; plr[pnum].HoldItem = item[ii]; /// BUGFIX: overwrites cursor item, allowing for belt dupe bug CheckQuestItem(pnum); CheckBookLevel(pnum); CheckItemStats(pnum); SetICursor(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM); if (plr[pnum].HoldItem._itype == ITYPE_GOLD) { done = GoldAutoPlace(pnum); #ifdef HELLFIRE if (!done) item[ii]._ivalue = plr[pnum].HoldItem._ivalue; #endif } else { done = FALSE; if (((plr[pnum]._pgfxnum & 0xF) == ANIM_ID_UNARMED || (plr[pnum]._pgfxnum & 0xF) == ANIM_ID_UNARMED_SHIELD #ifdef HELLFIRE || plr[pnum]._pClass == PC_BARD && ((plr[pnum]._pgfxnum & 0xF) == ANIM_ID_MACE || (plr[pnum]._pgfxnum & 0xF) == ANIM_ID_SWORD) #endif ) && plr[pnum]._pmode <= PM_WALK3) { if (plr[pnum].HoldItem._iStatFlag) { if (plr[pnum].HoldItem._iClass == ICLASS_WEAPON) { done = WeaponAutoPlace(pnum); if (done) CalcPlrInv(pnum, TRUE); } } } if (!done) { w = icursW28; h = icursH28; if (w == 1 && h == 1) { idx = plr[pnum].HoldItem.IDidx; if (plr[pnum].HoldItem._iStatFlag && AllItemsList[idx].iUsable) { for (i = 0; i < MAXBELTITEMS && !done; i++) { if (plr[pnum].SpdList[i]._itype == ITYPE_NONE) { plr[pnum].SpdList[i] = plr[pnum].HoldItem; CalcPlrScrolls(pnum); drawsbarflag = TRUE; done = TRUE; } } } for (i = 30; i <= 39 && !done; i++) { done = AutoPlace(pnum, i, w, h, TRUE); } for (i = 20; i <= 29 && !done; i++) { done = AutoPlace(pnum, i, w, h, TRUE); } for (i = 10; i <= 19 && !done; i++) { done = AutoPlace(pnum, i, w, h, TRUE); } for (i = 0; i <= 9 && !done; i++) { done = AutoPlace(pnum, i, w, h, TRUE); } } if (w == 1 && h == 2) { for (i = 29; i >= 20 && !done; i--) { done = AutoPlace(pnum, i, w, h, TRUE); } for (i = 9; i >= 0 && !done; i--) { done = AutoPlace(pnum, i, w, h, TRUE); } for (i = 19; i >= 10 && !done; i--) { done = AutoPlace(pnum, i, w, h, TRUE); } } if (w == 1 && h == 3) { for (i = 0; i < 20 && !done; i++) { done = AutoPlace(pnum, i, w, h, TRUE); } } if (w == 2 && h == 2) { for (i = 0; i < 10 && !done; i++) { done = AutoPlace(pnum, AP2x2Tbl[i], w, h, TRUE); } for (i = 21; i < 29 && !done; i += 2) { done = AutoPlace(pnum, i, w, h, TRUE); } for (i = 1; i < 9 && !done; i += 2) { done = AutoPlace(pnum, i, w, h, TRUE); } for (i = 10; i < 19 && !done; i++) { done = AutoPlace(pnum, i, w, h, TRUE); } } if (w == 2 && h == 3) { for (i = 0; i < 9 && !done; i++) { done = AutoPlace(pnum, i, w, h, TRUE); } for (i = 10; i < 19 && !done; i++) { done = AutoPlace(pnum, i, w, h, TRUE); } } } } if (done) { dItem[item[ii]._ix][item[ii]._iy] = 0; #ifdef HELLFIRE if (currlevel == 21 && item[ii]._ix == CornerStone.x && item[ii]._iy == CornerStone.y) { CornerStone.item.IDidx = -1; CornerStone.item._itype = ITYPE_MISC; CornerStone.item._iSelFlag = FALSE; CornerStone.item._ix = 0; CornerStone.item._iy = 0; CornerStone.item._iAnimFlag = FALSE; CornerStone.item._iIdentified = FALSE; CornerStone.item._iPostDraw = FALSE; } #endif i = 0; while (i < numitems) { if (itemactive[i] == ii) { DeleteItem(itemactive[i], i); i = 0; } else { i++; } } } else { if (pnum == myplr) { if (plr[pnum]._pClass == PC_WARRIOR) { PlaySFX(random_(0, 3) + PS_WARR14); #ifndef SPAWN } else if (plr[pnum]._pClass == PC_ROGUE) { PlaySFX(random_(0, 3) + PS_ROGUE14); } else if (plr[pnum]._pClass == PC_SORCERER) { PlaySFX(random_(0, 3) + PS_MAGE14); #endif #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK) { PlaySFX(random_(0, 3) + PS_MONK14); #ifndef SPAWN } else if (plr[pnum]._pClass == PC_BARD) { PlaySFX(random_(0, 3) + PS_ROGUE14); #endif } else if (plr[pnum]._pClass == PC_BARBARIAN) { PlaySFX(random_(0, 3) + PS_WARR14); #endif } } plr[pnum].HoldItem = item[ii]; RespawnItem(ii, TRUE); NetSendCmdPItem(TRUE, CMD_RESPAWNITEM, item[ii]._ix, item[ii]._iy); plr[pnum].HoldItem._itype = ITYPE_NONE; #ifdef HELLFIRE NewCursor(CURSOR_HAND); #endif } } int FindGetItem(int idx, WORD ci, int iseed) { int i, ii; i = 0; if (numitems <= 0) return -1; while (1) { ii = itemactive[i]; if (item[ii].IDidx == idx && item[ii]._iSeed == iseed && item[ii]._iCreateInfo == ci) break; i++; if (i >= numitems) return -1; } return ii; } void SyncGetItem(int x, int y, int idx, WORD ci, int iseed) { int i, ii; if (dItem[x][y]) { ii = dItem[x][y] - 1; if (item[ii].IDidx == idx && item[ii]._iSeed == iseed && item[ii]._iCreateInfo == ci) { FindGetItem(idx, ci, iseed); } else { ii = FindGetItem(idx, ci, iseed); } } else { ii = FindGetItem(idx, ci, iseed); } if (ii != -1) { dItem[item[ii]._ix][item[ii]._iy] = 0; #ifdef HELLFIRE if (currlevel == 21 && item[ii]._ix == CornerStone.x && item[ii]._iy == CornerStone.y) { CornerStone.item.IDidx = -1; CornerStone.item._itype = ITYPE_MISC; CornerStone.item._iSelFlag = FALSE; CornerStone.item._ix = 0; CornerStone.item._iy = 0; CornerStone.item._iAnimFlag = FALSE; CornerStone.item._iIdentified = FALSE; CornerStone.item._iPostDraw = FALSE; } #endif i = 0; while (i < numitems) { if (itemactive[i] == ii) { DeleteItem(itemactive[i], i); FindGetItem(idx, ci, iseed); #ifndef HELLFIRE /// ASSERT: assert(FindGetItem(idx,ci,iseed) == -1); FindGetItem(idx, ci, iseed); /* todo: replace with above */ #endif i = 0; } else { i++; } } /// ASSERT: assert(FindGetItem(idx, ci, iseed) == -1); FindGetItem(idx, ci, iseed); /* todo: replace with above */ } } BOOL CanPut(int x, int y) { char oi, oi2; if (dItem[x][y]) return FALSE; if (nSolidTable[dPiece[x][y]]) return FALSE; if (dObject[x][y] != 0) { if (object[dObject[x][y] > 0 ? dObject[x][y] - 1 : -1 - dObject[x][y]]._oSolidFlag) return FALSE; } oi = dObject[x + 1][y + 1]; if (oi > 0 && object[oi - 1]._oSelFlag != 0) { return FALSE; } if (oi < 0 && object[-(oi + 1)]._oSelFlag != 0) { return FALSE; } oi = dObject[x + 1][y]; if (oi > 0) { oi2 = dObject[x][y + 1]; if (oi2 > 0 && object[oi - 1]._oSelFlag != 0 && object[oi2 - 1]._oSelFlag != 0) return FALSE; } if (currlevel == 0 && dMonster[x][y] != 0) return FALSE; if (currlevel == 0 && dMonster[x + 1][y + 1] != 0) return FALSE; return TRUE; } BOOL TryInvPut() { int dir; if (numitems >= MAXITEMS) return FALSE; dir = GetDirection(plr[myplr]._px, plr[myplr]._py, cursmx, cursmy); if (CanPut(plr[myplr]._px + offset_x[dir], plr[myplr]._py + offset_y[dir])) { return TRUE; } dir = (dir - 1) & 7; if (CanPut(plr[myplr]._px + offset_x[dir], plr[myplr]._py + offset_y[dir])) { return TRUE; } dir = (dir + 2) & 7; if (CanPut(plr[myplr]._px + offset_x[dir], plr[myplr]._py + offset_y[dir])) { return TRUE; } return CanPut(plr[myplr]._px, plr[myplr]._py); } void DrawInvMsg(const char *msg) { DWORD dwTicks; dwTicks = GetTickCount(); if (dwTicks - sgdwLastTime >= 5000) { sgdwLastTime = dwTicks; ErrorPlrMsg(msg); } } int InvPutItem(int pnum, int x, int y) { BOOL done; int d, ii; int i, j, l; int xx, yy; int xp, yp; if (numitems >= MAXITEMS) return -1; if (FindGetItem(plr[pnum].HoldItem.IDidx, plr[pnum].HoldItem._iCreateInfo, plr[pnum].HoldItem._iSeed) != -1) { DrawInvMsg("A duplicate item has been detected. Destroying duplicate..."); SyncGetItem(x, y, plr[pnum].HoldItem.IDidx, plr[pnum].HoldItem._iCreateInfo, plr[pnum].HoldItem._iSeed); } d = GetDirection(plr[pnum]._px, plr[pnum]._py, x, y); xx = x - plr[pnum]._px; yy = y - plr[pnum]._py; if (abs(xx) > 1 || abs(yy) > 1) { x = plr[pnum]._px + offset_x[d]; y = plr[pnum]._py + offset_y[d]; } if (!CanPut(x, y)) { d = (d - 1) & 7; x = plr[pnum]._px + offset_x[d]; y = plr[pnum]._py + offset_y[d]; if (!CanPut(x, y)) { d = (d + 2) & 7; x = plr[pnum]._px + offset_x[d]; y = plr[pnum]._py + offset_y[d]; if (!CanPut(x, y)) { done = FALSE; for (l = 1; l < 50 && !done; l++) { for (j = -l; j <= l && !done; j++) { yp = j + plr[pnum]._py; for (i = -l; i <= l && !done; i++) { xp = i + plr[pnum]._px; if (CanPut(xp, yp)) { done = TRUE; x = xp; y = yp; } } } } if (!done) return -1; } } } #ifdef HELLFIRE if (currlevel == 0) { yp = cursmy; xp = cursmx; if (plr[pnum].HoldItem._iCurs == ICURS_RUNE_BOMB && xp >= 79 && xp <= 82 && yp >= 61 && yp <= 64) { NetSendCmdLocParam2(0, CMD_OPENHIVE, plr[pnum]._px, plr[pnum]._py, xx, yy); quests[Q_FARMER]._qactive = QUEST_DONE; if (gbMaxPlayers != 1) { NetSendCmdQuest(TRUE, Q_FARMER); return -1; } return -1; } if (plr[pnum].HoldItem.IDidx == IDI_MAPOFDOOM && xp >= 35 && xp <= 38 && yp >= 20 && yp <= 24) { NetSendCmd(FALSE, CMD_OPENCRYPT); quests[Q_GRAVE]._qactive = QUEST_DONE; if (gbMaxPlayers != 1) { NetSendCmdQuest(TRUE, Q_GRAVE); } return -1; } } #endif CanPut(x, y); //if (!CanPut(x, y)) { // assertion_failed(1524, "C:\\Diablo\\Direct\\inv.cpp", "CanPut(x,y)"); //} ii = itemavail[0]; dItem[x][y] = ii + 1; itemavail[0] = itemavail[MAXITEMS - (numitems + 1)]; itemactive[numitems] = ii; item[ii] = plr[pnum].HoldItem; item[ii]._ix = x; item[ii]._iy = y; RespawnItem(ii, TRUE); numitems++; #ifdef HELLFIRE if (currlevel == 21 && x == CornerStone.x && y == CornerStone.y) { CornerStone.item = item[ii]; InitQTextMsg(296); quests[Q_CORNSTN]._qlog = FALSE; quests[Q_CORNSTN]._qactive = QUEST_DONE; } #endif NewCursor(CURSOR_HAND); return ii; } int SyncPutItem(int pnum, int x, int y, int idx, WORD icreateinfo, int iseed, int Id, int dur, int mdur, int ch, int mch, int ivalue, DWORD ibuff #ifdef HELLFIRE , int to_hit, int max_dam, int min_str, int min_mag, int min_dex, int ac #endif ) { BOOL done; int d, ii; int i, j, l; int xx, yy; int xp, yp; if (numitems >= MAXITEMS) return -1; if (FindGetItem(idx, icreateinfo, iseed) != -1) { DrawInvMsg("A duplicate item has been detected from another player."); SyncGetItem(x, y, idx, icreateinfo, iseed); } d = GetDirection(plr[pnum]._px, plr[pnum]._py, x, y); xx = x - plr[pnum]._px; yy = y - plr[pnum]._py; if (abs(xx) > 1 || abs(yy) > 1) { x = plr[pnum]._px + offset_x[d]; y = plr[pnum]._py + offset_y[d]; } if (!CanPut(x, y)) { d = (d - 1) & 7; x = plr[pnum]._px + offset_x[d]; y = plr[pnum]._py + offset_y[d]; if (!CanPut(x, y)) { d = (d + 2) & 7; x = plr[pnum]._px + offset_x[d]; y = plr[pnum]._py + offset_y[d]; if (!CanPut(x, y)) { done = FALSE; for (l = 1; l < 50 && !done; l++) { for (j = -l; j <= l && !done; j++) { yp = j + plr[pnum]._py; for (i = -l; i <= l && !done; i++) { xp = i + plr[pnum]._px; if (CanPut(xp, yp)) { done = TRUE; x = xp; y = yp; } } } } if (!done) return -1; } } } CanPut(x, y); ii = itemavail[0]; dItem[x][y] = ii + 1; itemavail[0] = itemavail[MAXITEMS - (numitems + 1)]; itemactive[numitems] = ii; if (idx == IDI_EAR) { RecreateEar(ii, icreateinfo, iseed, Id, dur, mdur, ch, mch, ivalue, ibuff); } else { RecreateItem(ii, idx, icreateinfo, iseed, ivalue); if (Id) item[ii]._iIdentified = TRUE; item[ii]._iDurability = dur; item[ii]._iMaxDur = mdur; item[ii]._iCharges = ch; item[ii]._iMaxCharges = mch; #ifdef HELLFIRE item[ii]._iPLToHit = to_hit; item[ii]._iMaxDam = max_dam; item[ii]._iMinStr = min_str; item[ii]._iMinMag = min_mag; item[ii]._iMinDex = min_dex; item[ii]._iAC = ac; #endif } item[ii]._ix = x; item[ii]._iy = y; RespawnItem(ii, TRUE); numitems++; #ifdef HELLFIRE if (currlevel == 21 && x == CornerStone.x && y == CornerStone.y) { CornerStone.item = item[ii]; InitQTextMsg(296); quests[Q_CORNSTN]._qlog = FALSE; quests[Q_CORNSTN]._qactive = QUEST_DONE; } #endif return ii; } char CheckInvHLight() { int r, ii, nGold; ItemStruct *pi; PlayerStruct *p; char rv; for (r = 0; (DWORD)r < NUM_XY_SLOTS; r++) { if (MouseX >= InvRect[r].X && MouseX < InvRect[r].X + (INV_SLOT_SIZE_PX + 1) && MouseY >= InvRect[r].Y - (INV_SLOT_SIZE_PX + 1) && MouseY < InvRect[r].Y) { break; } } if ((DWORD)r >= NUM_XY_SLOTS) return -1; rv = -1; infoclr = COL_WHITE; pi = NULL; p = &plr[myplr]; ClearPanel(); if (r >= SLOTXY_HEAD_FIRST && r <= SLOTXY_HEAD_LAST) { rv = INVLOC_HEAD; pi = &p->InvBody[rv]; } else if (r == SLOTXY_RING_LEFT) { rv = INVLOC_RING_LEFT; pi = &p->InvBody[rv]; } else if (r == SLOTXY_RING_RIGHT) { rv = INVLOC_RING_RIGHT; pi = &p->InvBody[rv]; } else if (r == SLOTXY_AMULET) { rv = INVLOC_AMULET; pi = &p->InvBody[rv]; } else if (r >= SLOTXY_HAND_LEFT_FIRST && r <= SLOTXY_HAND_LEFT_LAST) { rv = INVLOC_HAND_LEFT; pi = &p->InvBody[rv]; } else if (r >= SLOTXY_HAND_RIGHT_FIRST && r <= SLOTXY_HAND_RIGHT_LAST) { pi = &p->InvBody[INVLOC_HAND_LEFT]; #ifdef HELLFIRE if (pi->_itype == ITYPE_NONE || pi->_iLoc != ILOC_TWOHAND || (p->_pClass == PC_BARBARIAN && (p->InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD || p->InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_MACE))) { #else if (pi->_itype == ITYPE_NONE || pi->_iLoc != ILOC_TWOHAND) { #endif rv = INVLOC_HAND_RIGHT; pi = &p->InvBody[rv]; } else { rv = INVLOC_HAND_LEFT; } } else if (r >= SLOTXY_CHEST_FIRST && r <= SLOTXY_CHEST_LAST) { rv = INVLOC_CHEST; pi = &p->InvBody[rv]; } else if (r >= SLOTXY_INV_FIRST && r <= SLOTXY_INV_LAST) { r = abs(p->InvGrid[r - SLOTXY_INV_FIRST]); if (r == 0) return -1; ii = r - 1; rv = ii + INVITEM_INV_FIRST; pi = &p->InvList[ii]; } else if (r >= SLOTXY_BELT_FIRST) { r -= SLOTXY_BELT_FIRST; drawsbarflag = TRUE; pi = &p->SpdList[r]; if (pi->_itype == ITYPE_NONE) return -1; rv = r + INVITEM_BELT_FIRST; } if (pi->_itype == ITYPE_NONE) return -1; if (pi->_itype == ITYPE_GOLD) { nGold = pi->_ivalue; sprintf(infostr, "%i gold %s", nGold, get_pieces_str(nGold)); } else { if (pi->_iMagical == ITEM_QUALITY_MAGIC) { infoclr = COL_BLUE; } else if (pi->_iMagical == ITEM_QUALITY_UNIQUE) { infoclr = COL_GOLD; } strcpy(infostr, pi->_iName); if (pi->_iIdentified) { strcpy(infostr, pi->_iIName); PrintItemDetails(pi); } else { PrintItemDur(pi); } } return rv; } void RemoveScroll(int pnum) { int i; for (i = 0; i < plr[pnum]._pNumInv; i++) { if (plr[pnum].InvList[i]._itype != ITYPE_NONE && (plr[pnum].InvList[i]._iMiscId == IMISC_SCROLL || plr[pnum].InvList[i]._iMiscId == IMISC_SCROLLT) #ifndef HELLFIRE && plr[pnum].InvList[i]._iSpell == plr[pnum]._pRSpell) { #else && plr[pnum].InvList[i]._iSpell == plr[pnum]._pSpell) { #endif RemoveInvItem(pnum, i); CalcPlrScrolls(pnum); return; } } for (i = 0; i < MAXBELTITEMS; i++) { if (plr[pnum].SpdList[i]._itype != ITYPE_NONE && (plr[pnum].SpdList[i]._iMiscId == IMISC_SCROLL || plr[pnum].SpdList[i]._iMiscId == IMISC_SCROLLT) #ifndef HELLFIRE && plr[pnum].SpdList[i]._iSpell == plr[pnum]._pRSpell) { #else && plr[pnum].SpdList[i]._iSpell == plr[pnum]._pSpell) { #endif RemoveSpdBarItem(pnum, i); CalcPlrScrolls(pnum); return; } } } BOOL UseScroll() { int i; if (pcurs != CURSOR_HAND) return FALSE; if (leveltype == DTYPE_TOWN && !spelldata[plr[myplr]._pRSpell].sTownSpell) return FALSE; for (i = 0; i < plr[myplr]._pNumInv; i++) { if (plr[myplr].InvList[i]._itype != ITYPE_NONE && (plr[myplr].InvList[i]._iMiscId == IMISC_SCROLL || plr[myplr].InvList[i]._iMiscId == IMISC_SCROLLT) && plr[myplr].InvList[i]._iSpell == plr[myplr]._pRSpell) { return TRUE; } } for (i = 0; i < MAXBELTITEMS; i++) { if (plr[myplr].SpdList[i]._itype != ITYPE_NONE && (plr[myplr].SpdList[i]._iMiscId == IMISC_SCROLL || plr[myplr].SpdList[i]._iMiscId == IMISC_SCROLLT) && plr[myplr].SpdList[i]._iSpell == plr[myplr]._pRSpell) { return TRUE; } } return FALSE; } void UseStaffCharge(int pnum) { if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE && (plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_STAFF #ifdef HELLFIRE || plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_UNIQUE // BUGFIX: myplr->pnum #endif ) && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iSpell == plr[pnum]._pRSpell && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iCharges > 0) { plr[pnum].InvBody[INVLOC_HAND_LEFT]._iCharges--; CalcPlrStaff(pnum); } } BOOL UseStaff() { if (pcurs == CURSOR_HAND) { if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE #ifdef HELLFIRE && (plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_STAFF || plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_UNIQUE) #else && plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_STAFF #endif && plr[myplr].InvBody[INVLOC_HAND_LEFT]._iSpell == plr[myplr]._pRSpell && plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges > 0) { return TRUE; } } return FALSE; } void StartGoldDrop() { initialDropGoldIndex = pcursinvitem; if (pcursinvitem <= INVITEM_INV_LAST) initialDropGoldValue = plr[myplr].InvList[pcursinvitem - INVITEM_INV_FIRST]._ivalue; else initialDropGoldValue = plr[myplr].SpdList[pcursinvitem - INVITEM_BELT_FIRST]._ivalue; dropGoldFlag = TRUE; dropGoldValue = 0; if (talkflag) control_reset_talk(); } BOOL UseInvItem(int pnum, int cii) { int c, idata; ItemStruct *Item; BOOL speedlist; if (plr[pnum]._pInvincible && plr[pnum]._pHitPoints == 0 && pnum == myplr) return TRUE; if (pcurs != CURSOR_HAND) return TRUE; if (stextflag != STORE_NONE) return TRUE; if (cii <= INVITEM_HAND_RIGHT) // BUGFIX: should be `cii < INVITEM_INV_FIRST`, was `cii <= INVITEM_HAND_RIGHT`. return FALSE; if (cii <= INVITEM_INV_LAST) { c = cii - INVITEM_INV_FIRST; Item = &plr[pnum].InvList[c]; speedlist = FALSE; } else { if (talkflag) return TRUE; c = cii - INVITEM_BELT_FIRST; Item = &plr[pnum].SpdList[c]; speedlist = TRUE; } switch (Item->IDidx) { case IDI_MUSHROOM: sfxdelay = 10; #ifndef SPAWN if (plr[pnum]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR95; } else if (plr[pnum]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE95; } else if (plr[pnum]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE95; } #ifdef HELLFIRE else if (plr[pnum]._pClass == PC_MONK) { sfxdnum = PS_MONK95; } else if (plr[pnum]._pClass == PC_BARD) { sfxdnum = PS_ROGUE95; } else if (plr[pnum]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR95; } #endif #endif return TRUE; case IDI_FUNGALTM: PlaySFX(IS_IBOOK); sfxdelay = 10; if (plr[pnum]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR29; #ifndef SPAWN } else if (plr[pnum]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE29; } else if (plr[pnum]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE29; #endif #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK) { sfxdnum = PS_MONK29; #ifndef SPAWN } else if (plr[pnum]._pClass == PC_BARD) { sfxdnum = PS_ROGUE29; #endif } else if (plr[pnum]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR29; #endif } return TRUE; } if (!AllItemsList[Item->IDidx].iUsable) return FALSE; if (!Item->_iStatFlag) { if (plr[pnum]._pClass == PC_WARRIOR) { PlaySFX(PS_WARR13); #ifndef SPAWN } else if (plr[pnum]._pClass == PC_ROGUE) { PlaySFX(PS_ROGUE13); } else if (plr[pnum]._pClass == PC_SORCERER) { PlaySFX(PS_MAGE13); #endif #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK) { PlaySFX(PS_MONK13); #ifndef SPAWN } else if (plr[pnum]._pClass == PC_BARD) { PlaySFX(PS_ROGUE13); #endif } else if (plr[pnum]._pClass == PC_BARBARIAN) { PlaySFX(PS_WARR13); #endif } return TRUE; } if (Item->_iMiscId == IMISC_NONE && Item->_itype == ITYPE_GOLD) { StartGoldDrop(); return TRUE; } if (dropGoldFlag) { dropGoldFlag = FALSE; dropGoldValue = 0; } if (Item->_iMiscId == IMISC_SCROLL && currlevel == 0 && !spelldata[Item->_iSpell].sTownSpell) { return TRUE; } if (Item->_iMiscId == IMISC_SCROLLT && currlevel == 0 && !spelldata[Item->_iSpell].sTownSpell) { return TRUE; } #ifdef HELLFIRE if (Item->_iMiscId > IMISC_RUNEFIRST && Item->_iMiscId < IMISC_RUNELAST && currlevel == 0) { return TRUE; } #endif idata = ItemCAnimTbl[Item->_iCurs]; if (Item->_iMiscId == IMISC_BOOK) PlaySFX(IS_RBOOK); else if (pnum == myplr) PlaySFX(ItemInvSnds[idata]); UseItem(pnum, Item->_iMiscId, Item->_iSpell); if (speedlist) { #ifdef HELLFIRE if (plr[pnum].SpdList[c]._iMiscId == IMISC_NOTE) { InitQTextMsg(322); invflag = FALSE; return TRUE; } #endif RemoveSpdBarItem(pnum, c); return TRUE; } else { if (plr[pnum].InvList[c]._iMiscId == IMISC_MAPOFDOOM) return TRUE; #ifdef HELLFIRE if (plr[pnum].InvList[c]._iMiscId == IMISC_NOTE) { InitQTextMsg(322); invflag = FALSE; return TRUE; } #endif RemoveInvItem(pnum, c); } return TRUE; } void DoTelekinesis() { if (pcursobj != -1) NetSendCmdParam1(TRUE, CMD_OPOBJT, pcursobj); if (pcursitem != -1) NetSendCmdGItem(TRUE, CMD_REQUESTAGITEM, myplr, myplr, pcursitem); if (pcursmonst != -1 && !M_Talker(pcursmonst) && monster[pcursmonst].mtalkmsg == 0) NetSendCmdParam1(TRUE, CMD_KNOCKBACK, pcursmonst); NewCursor(CURSOR_HAND); } int CalculateGold(int pnum) { int i, gold; gold = 0; for (i = 0; i < MAXBELTITEMS; i++) { if (plr[pnum].SpdList[i]._itype == ITYPE_GOLD) { gold += plr[pnum].SpdList[i]._ivalue; force_redraw = 255; } } for (i = 0; i < plr[pnum]._pNumInv; i++) { if (plr[pnum].InvList[i]._itype == ITYPE_GOLD) gold += plr[pnum].InvList[i]._ivalue; } return gold; } BOOL DropItemBeforeTrig() { if (TryInvPut()) { NetSendCmdPItem(TRUE, CMD_PUTITEM, cursmx, cursmy); NewCursor(CURSOR_HAND); return TRUE; } return FALSE; } ================================================ FILE: Source/inv.h ================================================ /** * @file inv.h * * Interface of player inventory. */ #ifndef __INV_H__ #define __INV_H__ extern BOOL invflag; extern BOOL drawsbarflag; void FreeInvGFX(); void InitInv(); void DrawInv(); void DrawInvBelt(); BOOL AutoPlace(int pnum, int ii, int sx, int sy, BOOL saveflag); BOOL SpecialAutoPlace(int pnum, int ii, int sx, int sy, BOOL saveflag); BOOL GoldAutoPlace(int pnum); int SwapItem(ItemStruct *a, ItemStruct *b); void CheckInvSwap(int pnum, BYTE bLoc, int idx, WORD wCI, int seed, BOOL bId); void inv_update_rem_item(int pnum, BYTE iv); void RemoveInvItem(int pnum, int iv); #ifdef HELLFIRE BOOL inv_diablo_to_hellfire(int pnum); #endif void RemoveSpdBarItem(int pnum, int iv); void CheckInvItem(); void CheckInvScrn(); void CheckItemStats(int pnum); void InvGetItem(int pnum, int ii); void AutoGetItem(int pnum, int ii); int FindGetItem(int idx, WORD ci, int iseed); void SyncGetItem(int x, int y, int idx, WORD ci, int iseed); BOOL CanPut(int x, int y); BOOL TryInvPut(); void DrawInvMsg(const char *msg); int InvPutItem(int pnum, int x, int y); int SyncPutItem(int pnum, int x, int y, int idx, WORD icreateinfo, int iseed, int Id, int dur, int mdur, int ch, int mch, int ivalue, DWORD ibuff #ifdef HELLFIRE , int to_hit, int max_dam, int min_str, int min_mag, int min_dex, int ac #endif ); char CheckInvHLight(); void RemoveScroll(int pnum); BOOL UseScroll(); void UseStaffCharge(int pnum); BOOL UseStaff(); BOOL UseInvItem(int pnum, int cii); void DoTelekinesis(); int CalculateGold(int pnum); BOOL DropItemBeforeTrig(); /* data */ extern int AP2x2Tbl[10]; #endif /* __INV_H__ */ ================================================ FILE: Source/itemdat.cpp ================================================ /** * @file itemdat.cpp * * Implementation of all item data. */ #include "all.h" /** Contains the data related to each item ID. */ ItemDataStruct AllItemsList[] = { // clang-format off //_item_indexes iRnd, iClass, iLoc, iCurs, itype, iItemId, iName, iSName, iMinMLvl, iDurability, iMinDam, iMaxDam, iMinAC, iMaxAC, iMinStr, iMinMag, iMinDex, iFlags, iMiscId, iSpell, iUsable, iValue, iMaxValue /*IDI_GOLD */ { IDROP_REGULAR, ICLASS_GOLD, ILOC_UNEQUIPABLE, ICURS_GOLD, ITYPE_GOLD, UITYPE_NONE, "Gold", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, TRUE, 0, 0 }, /*IDI_WARRIOR */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_SHORT_SWORD, ITYPE_SWORD, UITYPE_NONE, "Short Sword", NULL, 2, 20, 2, 6, 0, 0, 18, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 50, 50 }, /*IDI_WARRSHLD */ { IDROP_NEVER, ICLASS_ARMOR, ILOC_ONEHAND, ICURS_BUCKLER, ITYPE_SHIELD, UITYPE_NONE, "Buckler", NULL, 2, 10, 0, 0, 3, 3, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 50, 50 }, /*IDI_WARRCLUB */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_CLUB, ITYPE_MACE, UITYPE_SPIKCLUB, "Club", NULL, 1, 20, 1, 6, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 20, 20 }, /*IDI_ROGUE */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_BOW, ITYPE_BOW, UITYPE_NONE, "Short Bow", NULL, 1, 30, 1, 4, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 100, 100 }, #ifndef HELLFIRE /*IDI_SORCEROR */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_STAFF, ITYPE_STAFF, UITYPE_NONE, "Short Staff of Charged Bolt", NULL, 1, 25, 2, 4, 0, 0, 0, 20, 0, ISPL_NONE, IMISC_STAFF, SPL_CBOLT, FALSE, 520, 520 }, #else /*IDI_SORCEROR */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_STAFF, ITYPE_STAFF, UITYPE_NONE, "Short Staff of Mana", NULL, 1, 25, 2, 4, 0, 0, 0, 20, 0, ISPL_NONE, IMISC_STAFF, SPL_MANA, FALSE, 520, 520 }, #endif /*IDI_CLEAVER */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_CLEAVER, ITYPE_AXE, UITYPE_CLEAVER, "Cleaver", NULL, 10, 10, 4, 24, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 2000, 2000 }, /*IDI_SKCROWN */ { IDROP_NEVER, ICLASS_ARMOR, ILOC_HELM, ICURS_THE_UNDEAD_CROWN, ITYPE_HELM, UITYPE_SKCROWN, "The Undead Crown", NULL, 0, 50, 0, 0, 15, 15, 0, 0, 0, ISPL_RNDSTEALLIFE, IMISC_UNIQUE, SPL_NULL, FALSE, 10000, 10000 }, /*IDI_INFRARING */ { IDROP_NEVER, ICLASS_MISC, ILOC_RING, ICURS_EMPYREAN_BAND, ITYPE_RING, UITYPE_INFRARING, "Empyrean Band", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 8000, 8000 }, /*IDI_ROCK */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_MAGIC_ROCK, ITYPE_MISC, UITYPE_NONE, "Magic Rock", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_OPTAMULET */ { IDROP_NEVER, ICLASS_MISC, ILOC_AMULET, ICURS_OPTIC_AMULET, ITYPE_AMULET, UITYPE_OPTAMULET, "Optic Amulet", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 5000, 5000 }, /*IDI_TRING */ { IDROP_NEVER, ICLASS_MISC, ILOC_RING, ICURS_RING_OF_TRUTH, ITYPE_RING, UITYPE_TRING, "Ring of Truth", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 1000, 1000 }, /*IDI_BANNER */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_TAVERN_SIGN, ITYPE_MISC, UITYPE_NONE, "Tavern Sign", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_HARCREST */ { IDROP_NEVER, ICLASS_ARMOR, ILOC_HELM, ICURS_HARLEQUIN_CREST, ITYPE_HELM, UITYPE_HARCREST, "Harlequin Crest", NULL, 0, 15, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 15, 20 }, /*IDI_STEELVEIL */ { IDROP_NEVER, ICLASS_ARMOR, ILOC_HELM, ICURS_VIEL_OF_STEEL, ITYPE_HELM, UITYPE_STEELVEIL, "Veil of Steel", NULL, 0, 60, 0, 0, 18, 18, 0, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 0, 0 }, /*IDI_GLDNELIX */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_GOLDEN_ELIXIR, ITYPE_MISC, UITYPE_ELIXIR, "Golden Elixir", NULL, 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_ANVIL */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_ANVIL_OF_FURY, ITYPE_MISC, UITYPE_NONE, "Anvil of Fury", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_MUSHROOM */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_BLACK_MUSHROOM, ITYPE_MISC, UITYPE_NONE, "Black Mushroom", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_BRAIN */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_BRAIN, ITYPE_MISC, UITYPE_NONE, "Brain", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_FUNGALTM */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_FUNGAL_TOME, ITYPE_MISC, UITYPE_NONE, "Fungal Tome", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_SPECELIX */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SPECTRAL_ELIXIR, ITYPE_MISC, UITYPE_ELIXIR, "Spectral Elixir", NULL, 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SPECELIX, SPL_NULL, FALSE, 0, 0 }, /*IDI_BLDSTONE */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_BLOOD_STONE, ITYPE_MISC, UITYPE_NONE, "Blood Stone", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, #ifndef HELLFIRE /*IDI_MAPOFDOOM */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_MAP_OF_THE_STARS, ITYPE_MISC, UITYPE_MAPOFDOOM, "Map of the Stars", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_MAPOFDOOM, SPL_NULL, TRUE, 0, 0 }, #else /*IDI_MAPOFDOOM */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_MAP_OF_THE_STARS, ITYPE_MISC, UITYPE_MAPOFDOOM, "Cathedral Map", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_MAPOFDOOM, SPL_NULL, TRUE, 0, 0 }, #endif /*IDI_EAR */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_EAR_SORCEROR, ITYPE_MISC, UITYPE_NONE, "Heart", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_EAR, SPL_NULL, FALSE, 0, 0 }, /*IDI_HEAL */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_HEALING, ITYPE_MISC, UITYPE_NONE, "Potion of Healing", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_HEAL, SPL_NULL, TRUE, 50, 50 }, /*IDI_MANA */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_MANA, ITYPE_MISC, UITYPE_NONE, "Potion of Mana", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_MANA, SPL_NULL, TRUE, 50, 50 }, /*IDI_IDENTIFY */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Identify", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLL, SPL_IDENTIFY, TRUE, 200, 200 }, /*IDI_PORTAL */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Town Portal", NULL, 4, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLL, SPL_TOWN, TRUE, 200, 200 }, /*IDI_ARMOFVAL */ { IDROP_NEVER, ICLASS_ARMOR, ILOC_ARMOR, ICURS_ARKAINES_VALOR, ITYPE_MARMOR, UITYPE_ARMOFVAL, "Arkaine's Valor", NULL, 0, 40, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 0, 0 }, /*IDI_FULLHEAL */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_FULL_HEALING, ITYPE_MISC, UITYPE_NONE, "Potion of Full Healing", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_FULLHEAL, SPL_NULL, TRUE, 150, 150 }, /*IDI_FULLMANA */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, "Potion of Full Mana", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_FULLMANA, SPL_NULL, TRUE, 150, 150 }, /*IDI_GRISWOLD */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_BROAD_SWORD, ITYPE_SWORD, UITYPE_GRISWOLD, "Griswold's Edge", NULL, 8, 50, 4, 12, 0, 0, 40, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 750, 750 }, #ifndef HELLFIRE /*IDI_LGTFORGE */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_MACE, ITYPE_MACE, UITYPE_LGTFORGE, "Lightforge", NULL, 2, 32, 1, 8, 0, 0, 16, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 200, 200 }, #else /*IDI_LGTFORGE */ { IDROP_NEVER, ICLASS_ARMOR, ILOC_ARMOR, ICURS_BOVINE, ITYPE_HARMOR, UITYPE_BOVINE, "Bovine Plate", NULL, 0, 40, 0, 0, 0, 0, 50, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 0, 0 }, #endif /*IDI_LAZSTAFF */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_STAFF_OF_LAZARUS, ITYPE_MISC, UITYPE_LAZSTAFF, "Staff of Lazarus", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_RESURRECT */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Resurrect", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLLT, SPL_RESURRECT, TRUE, 250, 250 }, #ifndef HELLFIRE /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, #else /*IDI_OIL */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_OIL, ITYPE_MISC, UITYPE_NONE, "Blacksmith Oil", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_OILBSMTH, SPL_NULL, TRUE, 100, 100 }, /*IDI_SHORTSTAFF */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_STAFF, ITYPE_STAFF, UITYPE_NONE, "Short Staff", NULL, 1, 25, 2, 4, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 20, 20 }, /*IDI_BARDSWORD */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_SHORT_SWORD, ITYPE_SWORD, UITYPE_NONE, "Sword", NULL, 2, 8, 1, 5, 0, 0, 15, 0, 20, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 20, 20 }, /*IDI_BARDDAGGER */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_DAGGER, ITYPE_SWORD, UITYPE_NONE, "Dagger", NULL, 1, 16, 1, 4, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 20, 20 }, /*IDI_RUNEBOMB */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_RUNE_BOMB, ITYPE_MISC, UITYPE_NONE, "Rune Bomb", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_THEODORE */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_THEODORE, ITYPE_MISC, UITYPE_NONE, "Theodore", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_AURIC */ { IDROP_NEVER, ICLASS_MISC, ILOC_AMULET, ICURS_AURIC_AMULET, ITYPE_MISC, UITYPE_NONE, "Auric Amulet", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_AURIC, SPL_NULL, FALSE, 100, 100 }, /*IDI_NOTE1 */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_TORN_NOTE_1, ITYPE_MISC, UITYPE_NONE, "Torn Note 1", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_NOTE2 */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_TORN_NOTE_2, ITYPE_MISC, UITYPE_NONE, "Torn Note 2", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_NOTE3 */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_TORN_NOTE_3, ITYPE_MISC, UITYPE_NONE, "Torn Note 3", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_FULLNOTE */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_RECONSTRUCTED_NOTE, ITYPE_MISC, UITYPE_NONE, "Reconstructed Note", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NOTE, SPL_NULL, TRUE, 0, 0 }, /*IDI_BROWNSUIT */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_BROWN_SUIT, ITYPE_MISC, UITYPE_NONE, "Brown Suit", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_GREYSUIT */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_GREY_SUIT, ITYPE_MISC, UITYPE_NONE, "Grey Suit", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, #endif /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, ICURS_CAP, ITYPE_HELM, UITYPE_NONE, "Cap", "Cap", 1, 15, 0, 0, 1, 3, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 15, 20 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, ICURS_SKULL_CAP, ITYPE_HELM, UITYPE_SKULLCAP, "Skull Cap", "Cap", 4, 20, 0, 0, 2, 4, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 25, 30 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, ICURS_HELM, ITYPE_HELM, UITYPE_HELM, "Helm", "Helm", 8, 30, 0, 0, 4, 6, 25, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 40, 70 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, ICURS_FULL_HELM, ITYPE_HELM, UITYPE_NONE, "Full Helm", "Helm", 12, 35, 0, 0, 6, 8, 35, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 90, 130 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, ICURS_CROWN, ITYPE_HELM, UITYPE_CROWN, "Crown", "Crown", 16, 40, 0, 0, 8, 12, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 200, 300 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, ICURS_GREAT_HELM, ITYPE_HELM, UITYPE_GREATHELM, "Great Helm", "Helm", 20, 60, 0, 0, 10, 15, 50, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 400, 500 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_CAPE, ITYPE_LARMOR, UITYPE_CAPE, "Cape", "Cape", 1, 12, 0, 0, 1, 5, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 10, 50 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_RAGS, ITYPE_LARMOR, UITYPE_RAGS, "Rags", "Rags", 1, 6, 0, 0, 2, 6, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 5, 25 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_CLOAK, ITYPE_LARMOR, UITYPE_CLOAK, "Cloak", "Cloak", 2, 18, 0, 0, 3, 7, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 40, 70 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_ROBE, ITYPE_LARMOR, UITYPE_ROBE, "Robe", "Robe", 3, 24, 0, 0, 4, 7, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 75, 125 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_QUILTED_ARMOR, ITYPE_LARMOR, UITYPE_NONE, "Quilted Armor", "Armor", 4, 30, 0, 0, 7, 10, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 200, 300 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_LEATHER_ARMOR, ITYPE_LARMOR, UITYPE_LEATHARMOR, "Leather Armor", "Armor", 6, 35, 0, 0, 10, 13, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 300, 400 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_HARD_LEATHER_ARMOR, ITYPE_LARMOR, UITYPE_NONE, "Hard Leather Armor", "Armor", 7, 40, 0, 0, 11, 14, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 450, 550 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_STUDDED_LEATHER_ARMOR, ITYPE_LARMOR, UITYPE_STUDARMOR, "Studded Leather Armor", "Armor", 9, 45, 0, 0, 15, 17, 20, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 700, 800 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_RING_MAIL, ITYPE_MARMOR, UITYPE_NONE, "Ring Mail", "Mail", 11, 50, 0, 0, 17, 20, 25, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 900, 1100 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_CHAIN_MAIL, ITYPE_MARMOR, UITYPE_CHAINMAIL, "Chain Mail", "Mail", 13, 55, 0, 0, 18, 22, 30, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 1250, 1750 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_SCALE_MAIL, ITYPE_MARMOR, UITYPE_NONE, "Scale Mail", "Mail", 15, 60, 0, 0, 23, 28, 35, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 2300, 2800 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_BREAST_PLATE, ITYPE_HARMOR, UITYPE_BREASTPLATE, "Breast Plate", "Plate", 16, 80, 0, 0, 20, 24, 40, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 2800, 3200 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_SPLINT_MAIL, ITYPE_MARMOR, UITYPE_NONE, "Splint Mail", "Mail", 17, 65, 0, 0, 30, 35, 40, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 3250, 3750 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_FIELD_PLATE, ITYPE_HARMOR, UITYPE_PLATEMAIL, "Plate Mail", "Plate", 19, 75, 0, 0, 42, 50, 60, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 4600, 5400 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_FIELD_PLATE, ITYPE_HARMOR, UITYPE_NONE, "Field Plate", "Plate", 21, 80, 0, 0, 40, 45, 65, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 5800, 6200 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_GOTHIC_PLATE, ITYPE_HARMOR, UITYPE_NONE, "Gothic Plate", "Plate", 23, 100, 0, 0, 50, 60, 80, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 8000, 10000 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ARMOR, ICURS_FULL_PLATE_MAIL, ITYPE_HARMOR, UITYPE_FULLPLATE, "Full Plate Mail", "Plate", 25, 90, 0, 0, 60, 75, 90, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 6500, 8000 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, ICURS_BUCKLER, ITYPE_SHIELD, UITYPE_BUCKLER, "Buckler", "Shield", 1, 16, 0, 0, 1, 5, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 30, 70 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, ICURS_SMALL_SHIELD, ITYPE_SHIELD, UITYPE_SMALLSHIELD, "Small Shield", "Shield", 5, 24, 0, 0, 3, 8, 25, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 90, 130 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, ICURS_LARGE_SHIELD, ITYPE_SHIELD, UITYPE_LARGESHIELD, "Large Shield", "Shield", 9, 32, 0, 0, 5, 10, 40, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 200, 300 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, ICURS_KITE_SHIELD, ITYPE_SHIELD, UITYPE_KITESHIELD, "Kite Shield", "Shield", 14, 40, 0, 0, 8, 15, 50, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 400, 700 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, ICURS_TOWER_SHIELD, ITYPE_SHIELD, UITYPE_GOTHSHIELD, "Tower Shield", "Shield", 20, 50, 0, 0, 12, 20, 60, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 850, 1200 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_ONEHAND, ICURS_GOTHIC_SHIELD, ITYPE_SHIELD, UITYPE_GOTHSHIELD, "Gothic Shield", "Shield", 23, 60, 0, 0, 14, 18, 80, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 2300, 2700 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_HEALING, ITYPE_MISC, UITYPE_NONE, "Potion of Healing", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_HEAL, SPL_NULL, TRUE, 50, 50 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_FULL_HEALING, ITYPE_MISC, UITYPE_NONE, "Potion of Full Healing", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_FULLHEAL, SPL_NULL, TRUE, 150, 150 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_MANA, ITYPE_MISC, UITYPE_NONE, "Potion of Mana", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_MANA, SPL_NULL, TRUE, 50, 50 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, "Potion of Full Mana", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_FULLMANA, SPL_NULL, TRUE, 150, 150 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_REJUVENATION, ITYPE_MISC, UITYPE_NONE, "Potion of Rejuvenation", NULL, 3, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_REJUV, SPL_NULL, TRUE, 120, 120 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_FULL_REJUVENATION, ITYPE_MISC, UITYPE_NONE, "Potion of Full Rejuvenation", NULL, 7, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_FULLREJUV, SPL_NULL, TRUE, 600, 600 }, #ifdef HELLFIRE /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_OIL, ITYPE_MISC, UITYPE_NONE, "Blacksmith Oil", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_OILBSMTH, SPL_NULL, TRUE, 100, 100 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_OIL, ITYPE_MISC, UITYPE_NONE, "Oil of Accuracy", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_OILACC, SPL_NULL, TRUE, 500, 500 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_OIL, ITYPE_MISC, UITYPE_NONE, "Oil of Sharpness", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_OILSHARP, SPL_NULL, TRUE, 500, 500 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_OIL, ITYPE_MISC, UITYPE_NONE, "Oil", NULL, 10, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_OILOF, SPL_NULL, TRUE, 0, 0 }, #endif /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_ELIXIR_OF_STRENGTH, ITYPE_MISC, UITYPE_NONE, "Elixir of Strength", NULL, 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_ELIXSTR, SPL_NULL, TRUE, 5000, 5000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_ELIXIR_OF_MAGIC, ITYPE_MISC, UITYPE_NONE, "Elixir of Magic", NULL, 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_ELIXMAG, SPL_NULL, TRUE, 5000, 5000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_ELIXIR_OF_DEXTERITY, ITYPE_MISC, UITYPE_NONE, "Elixir of Dexterity", NULL, 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_ELIXDEX, SPL_NULL, TRUE, 5000, 5000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_ELIXIR_OF_VITALITY, ITYPE_MISC, UITYPE_NONE, "Elixir of Vitality", NULL, 20, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_ELIXVIT, SPL_NULL, TRUE, 5000, 5000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Healing", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLL, SPL_HEAL, TRUE, 50, 50 }, #ifdef HELLFIRE /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Search", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLL, SPL_SEARCH, TRUE, 50, 50 }, #endif /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Lightning", NULL, 4, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLLT, SPL_LIGHTNING, TRUE, 150, 150 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Identify", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLL, SPL_IDENTIFY, TRUE, 100, 100 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Resurrect", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLLT, SPL_RESURRECT, TRUE, 250, 250 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Fire Wall", NULL, 4, 0, 0, 0, 0, 0, 0, 17, 0, ISPL_NONE, IMISC_SCROLLT, SPL_FIREWALL, TRUE, 400, 400 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Inferno", NULL, 1, 0, 0, 0, 0, 0, 0, 19, 0, ISPL_NONE, IMISC_SCROLLT, SPL_FLAME, TRUE, 100, 100 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Town Portal", NULL, 4, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLL, SPL_TOWN, TRUE, 200, 200 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Flash", NULL, 6, 0, 0, 0, 0, 0, 0, 21, 0, ISPL_NONE, IMISC_SCROLLT, SPL_FLASH, TRUE, 500, 500 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Infravision", NULL, 8, 0, 0, 0, 0, 0, 0, 23, 0, ISPL_NONE, IMISC_SCROLL, SPL_INFRA, TRUE, 600, 600 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Phasing", NULL, 6, 0, 0, 0, 0, 0, 0, 25, 0, ISPL_NONE, IMISC_SCROLL, SPL_RNDTELEPORT, TRUE, 200, 200 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Mana Shield", NULL, 8, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLL, SPL_MANASHIELD, TRUE, 1200, 1200 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Flame Wave", NULL, 10, 0, 0, 0, 0, 0, 0, 29, 0, ISPL_NONE, IMISC_SCROLLT, SPL_WAVE, TRUE, 650, 650 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Fireball", NULL, 8, 0, 0, 0, 0, 0, 0, 31, 0, ISPL_NONE, IMISC_SCROLLT, SPL_FIREBALL, TRUE, 300, 300 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Stone Curse", NULL, 6, 0, 0, 0, 0, 0, 0, 33, 0, ISPL_NONE, IMISC_SCROLLT, SPL_STONE, TRUE, 800, 800 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Chain Lightning", NULL, 10, 0, 0, 0, 0, 0, 0, 35, 0, ISPL_NONE, IMISC_SCROLLT, SPL_CHAIN, TRUE, 750, 750 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Guardian", NULL, 12, 0, 0, 0, 0, 0, 0, 47, 0, ISPL_NONE, IMISC_SCROLLT, SPL_GUARDIAN, TRUE, 950, 950 }, /* */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Non Item", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Nova", NULL, 14, 0, 0, 0, 0, 0, 0, 57, 0, ISPL_NONE, IMISC_SCROLL, SPL_NOVA, TRUE, 1300, 1300 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Golem", NULL, 10, 0, 0, 0, 0, 0, 0, 51, 0, ISPL_NONE, IMISC_SCROLLT, SPL_GOLEM, TRUE, 1100, 1100 }, /* */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of None", NULL, 99, 0, 0, 0, 0, 0, 0, 61, 0, ISPL_NONE, IMISC_SCROLLT, SPL_NULL, TRUE, 1000, 1000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Teleport", NULL, 14, 0, 0, 0, 0, 0, 0, 81, 0, ISPL_NONE, IMISC_SCROLL, SPL_TELEPORT, TRUE, 3000, 3000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Apocalypse", NULL, 22, 0, 0, 0, 0, 0, 0, 117, 0, ISPL_NONE, IMISC_SCROLL, SPL_APOCA, TRUE, 2000, 2000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_BOOK_BLUE, ITYPE_MISC, UITYPE_NONE, "Book of ", NULL, 2, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_BOOK, SPL_NULL, TRUE, 0, 0 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_BOOK_BLUE, ITYPE_MISC, UITYPE_NONE, "Book of ", NULL, 8, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_BOOK, SPL_NULL, TRUE, 0, 0 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_BOOK_BLUE, ITYPE_MISC, UITYPE_NONE, "Book of ", NULL, 14, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_BOOK, SPL_NULL, TRUE, 0, 0 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_BOOK_BLUE, ITYPE_MISC, UITYPE_NONE, "Book of ", NULL, 20, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_BOOK, SPL_NULL, TRUE, 0, 0 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_DAGGER, ITYPE_SWORD, UITYPE_DAGGER, "Dagger", "Dagger", 1, 16, 1, 4, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 60, 60 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_SHORT_SWORD, ITYPE_SWORD, UITYPE_NONE, "Short Sword", "Sword", 1, 24, 2, 6, 0, 0, 18, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 120, 120 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_FALCHION, ITYPE_SWORD, UITYPE_FALCHION, "Falchion", "Sword", 2, 20, 4, 8, 0, 0, 30, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 250, 250 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_SCIMITAR, ITYPE_SWORD, UITYPE_SCIMITAR, "Scimitar", "Sword", 4, 28, 3, 7, 0, 0, 23, 0, 23, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 200, 200 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_CLAYMORE, ITYPE_SWORD, UITYPE_CLAYMORE, "Claymore", "Sword", 5, 36, 1, 12, 0, 0, 35, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 450, 450 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_BLADE, ITYPE_SWORD, UITYPE_NONE, "Blade", "Blade", 4, 30, 3, 8, 0, 0, 25, 0, 30, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 280, 280 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_SABRE, ITYPE_SWORD, UITYPE_SABRE, "Sabre", "Sabre", 1, 45, 1, 8, 0, 0, 17, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 170, 170 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_LONG_SWORD, ITYPE_SWORD, UITYPE_LONGSWR, "Long Sword", "Sword", 6, 40, 2, 10, 0, 0, 30, 0, 30, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 350, 350 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_BROAD_SWORD, ITYPE_SWORD, UITYPE_BROADSWR, "Broad Sword", "Sword", 8, 50, 4, 12, 0, 0, 40, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 750, 750 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_BASTARD_SWORD, ITYPE_SWORD, UITYPE_BASTARDSWR, "Bastard Sword", "Sword", 10, 60, 6, 15, 0, 0, 50, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 1000, 1000 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_TWO_HANDED_SWORD, ITYPE_SWORD, UITYPE_TWOHANDSWR, "Two-Handed Sword", "Sword", 14, 75, 8, 16, 0, 0, 65, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 1800, 1800 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_GREAT_SWORD, ITYPE_SWORD, UITYPE_GREATSWR, "Great Sword", "Sword", 17, 100, 10, 20, 0, 0, 75, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 3000, 3000 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SMALL_AXE, ITYPE_AXE, UITYPE_SMALLAXE, "Small Axe", "Axe", 2, 24, 2, 10, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 150, 150 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_AXE, ITYPE_AXE, UITYPE_NONE, "Axe", "Axe", 4, 32, 4, 12, 0, 0, 22, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 450, 450 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_LARGE_AXE, ITYPE_AXE, UITYPE_LARGEAXE, "Large Axe", "Axe", 6, 40, 6, 16, 0, 0, 30, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 750, 750 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_BROAD_AXE, ITYPE_AXE, UITYPE_BROADAXE, "Broad Axe", "Axe", 8, 50, 8, 20, 0, 0, 50, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 1000, 1000 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_BATTLE_AXE, ITYPE_AXE, UITYPE_BATTLEAXE, "Battle Axe", "Axe", 10, 60, 10, 25, 0, 0, 65, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 1500, 1500 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_GREAT_AXE, ITYPE_AXE, UITYPE_GREATAXE, "Great Axe", "Axe", 12, 75, 12, 30, 0, 0, 80, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 2500, 2500 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_MACE, ITYPE_MACE, UITYPE_MACE, "Mace", "Mace", 2, 32, 1, 8, 0, 0, 16, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 200, 200 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_MORNING_STAR, ITYPE_MACE, UITYPE_MORNSTAR, "Morning Star", "Mace", 3, 40, 1, 10, 0, 0, 26, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 300, 300 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_WAR_HAMMER, ITYPE_MACE, UITYPE_WARHAMMER, "War Hammer", "Hammer", 5, 50, 5, 9, 0, 0, 40, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 600, 600 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_SPIKED_CLUB, ITYPE_MACE, UITYPE_SPIKCLUB, "Spiked Club", "Club", 4, 20, 3, 6, 0, 0, 18, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 225, 225 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_CLUB, ITYPE_MACE, UITYPE_SPIKCLUB, "Club", "Club", 1, 20, 1, 6, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 20, 20 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_FLAIL, ITYPE_MACE, UITYPE_FLAIL, "Flail", "Flail", 7, 36, 2, 12, 0, 0, 30, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 500, 500 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_MAUL, ITYPE_MACE, UITYPE_MAUL, "Maul", "Maul", 10, 50, 6, 20, 0, 0, 55, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 900, 900 }, /* */ { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_BOW, ITYPE_BOW, UITYPE_SHORTBOW, "Short Bow", "Bow", 1, 30, 1, 4, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 100, 100 }, /* */ { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_HUNTERS_BOW, ITYPE_BOW, UITYPE_HUNTBOW, "Hunter's Bow", "Bow", 3, 40, 2, 5, 0, 0, 20, 0, 35, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 350, 350 }, /* */ { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_HUNTERS_BOW, ITYPE_BOW, UITYPE_LONGBOW, "Long Bow", "Bow", 5, 35, 1, 6, 0, 0, 25, 0, 30, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 250, 250 }, /* */ { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_COMPOSITE_BOW, ITYPE_BOW, UITYPE_COMPBOW, "Composite Bow", "Bow", 7, 45, 3, 6, 0, 0, 25, 0, 40, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 600, 600 }, /* */ { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_BATTLE_BOW, ITYPE_BOW, UITYPE_NONE, "Short Battle Bow", "Bow", 9, 45, 3, 7, 0, 0, 30, 0, 50, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 750, 750 }, /* */ { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_LONG_WAR_BOW, ITYPE_BOW, UITYPE_BATTLEBOW, "Long Battle Bow", "Bow", 11, 50, 1, 10, 0, 0, 30, 0, 60, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 1000, 1000 }, /* */ { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_WAR_BOW, ITYPE_BOW, UITYPE_NONE, "Short War Bow", "Bow", 15, 55, 4, 8, 0, 0, 35, 0, 70, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 1500, 1500 }, /* */ { IDROP_DOUBLE, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_LONG_WAR_BOW, ITYPE_BOW, UITYPE_WARBOW, "Long War Bow", "Bow", 19, 60, 1, 14, 0, 0, 45, 0, 80, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 2000, 2000 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_STAFF, ITYPE_STAFF, UITYPE_SHORTSTAFF, "Short Staff", "Staff", 1, 25, 2, 4, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_STAFF, SPL_NULL, FALSE, 30, 30 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_LONG_STAFF, ITYPE_STAFF, UITYPE_LONGSTAFF, "Long Staff", "Staff", 4, 35, 4, 8, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_STAFF, SPL_NULL, FALSE, 100, 100 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_COMPOSITE_STAFF, ITYPE_STAFF, UITYPE_COMPSTAFF, "Composite Staff", "Staff", 6, 45, 5, 10, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_STAFF, SPL_NULL, FALSE, 500, 500 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_STAFF, ITYPE_STAFF, UITYPE_QUARSTAFF, "Quarter Staff", "Staff", 9, 55, 6, 12, 0, 0, 20, 0, 0, ISPL_NONE, IMISC_STAFF, SPL_NULL, FALSE, 1000, 1000 }, /* */ { IDROP_REGULAR, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_WAR_STAFF, ITYPE_STAFF, UITYPE_WARSTAFF, "War Staff", "Staff", 12, 75, 8, 16, 0, 0, 30, 0, 0, ISPL_NONE, IMISC_STAFF, SPL_NULL, FALSE, 1500, 1500 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_RING, ICURS_RING, ITYPE_RING, UITYPE_RING, "Ring", "Ring", 5, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_RING, SPL_NULL, FALSE, 1000, 1000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_RING, ICURS_RING, ITYPE_RING, UITYPE_RING, "Ring", "Ring", 10, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_RING, SPL_NULL, FALSE, 1000, 1000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_RING, ICURS_RING, ITYPE_RING, UITYPE_RING, "Ring", "Ring", 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_RING, SPL_NULL, FALSE, 1000, 1000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_AMULET, ICURS_AMULET, ITYPE_AMULET, UITYPE_AMULET, "Amulet", "Amulet", 8, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_AMULET, SPL_NULL, FALSE, 1200, 1200 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_AMULET, ICURS_AMULET, ITYPE_AMULET, UITYPE_AMULET, "Amulet", "Amulet", 16, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_AMULET, SPL_NULL, FALSE, 1200, 1200 }, #ifdef HELLFIRE /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_RUNE_OF_FIRE, ITYPE_MISC, UITYPE_NONE, "Rune of Fire", "Rune", 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_RUNEF, SPL_NULL, TRUE, 100, 100 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_RUNE_OF_LIGHTNING, ITYPE_MISC, UITYPE_NONE, "Rune of Lightning", "Rune", 3, 0, 0, 0, 0, 0, 0, 13, 0, ISPL_NONE, IMISC_RUNEL, SPL_NULL, TRUE, 200, 200 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_GREATER_RUNE_OF_FIRE, ITYPE_MISC, UITYPE_NONE, "Greater Rune of Fire", "Rune", 7, 0, 0, 0, 0, 0, 0, 42, 0, ISPL_NONE, IMISC_GR_RUNEF, SPL_NULL, TRUE, 400, 400 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_GREATER_RUNE_OF_LIGHTNING, ITYPE_MISC, UITYPE_NONE, "Greater Rune of Lightning", "Rune", 7, 0, 0, 0, 0, 0, 0, 42, 0, ISPL_NONE, IMISC_GR_RUNEL, SPL_NULL, TRUE, 500, 500 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_RUNE_OF_STONE, ITYPE_MISC, UITYPE_NONE, "Rune of Stone", "Rune", 7, 0, 0, 0, 0, 0, 0, 25, 0, ISPL_NONE, IMISC_RUNES, SPL_NULL, TRUE, 300, 300 }, #endif /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_INVALID, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, // clang-format on }; /** Contains the data related to each item prefix. */ const PLStruct PL_Prefix[] = { // clang-format off // PLName, PLPower, PLParam1, PLParam2, PLMinLvl, PLIType, PLGOE, PLDouble, PLOk, PLMinVal, PLMaxVal, PLMultVal { "Tin", IPL_TOHIT_CURSE, 6, 10, 3, PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, TRUE, FALSE, 0, 0, -3 }, { "Brass", IPL_TOHIT_CURSE, 1, 5, 1, PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, TRUE, FALSE, 0, 0, -2 }, { "Bronze", IPL_TOHIT, 1, 5, 1, PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, TRUE, TRUE, 100, 500, 2 }, { "Iron", IPL_TOHIT, 6, 10, 4, PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, TRUE, TRUE, 600, 1000, 3 }, { "Steel", IPL_TOHIT, 11, 15, 6, PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, TRUE, TRUE, 1100, 1500, 5 }, { "Silver", IPL_TOHIT, 16, 20, 9, PLT_WEAP | PLT_BOW | PLT_MISC, GOE_GOOD, TRUE, TRUE, 1600, 2000, 7 }, { "Gold", IPL_TOHIT, 21, 30, 12, PLT_WEAP | PLT_BOW | PLT_MISC, GOE_GOOD, TRUE, TRUE, 2100, 3000, 9 }, { "Platinum", IPL_TOHIT, 31, 40, 16, PLT_WEAP | PLT_BOW , GOE_GOOD, TRUE, TRUE, 3100, 4000, 11 }, { "Mithril", IPL_TOHIT, 41, 60, 20, PLT_WEAP | PLT_BOW , GOE_GOOD, TRUE, TRUE, 4100, 6000, 13 }, { "Meteoric", IPL_TOHIT, 61, 80, 23, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 6100, 10000, 15 }, { "Weird", IPL_TOHIT, 81, 100, 35, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 10100, 14000, 17 }, { "Strange", IPL_TOHIT, 101, 150, 60, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 14100, 20000, 20 }, #ifdef HELLFIRE { "Useless", IPL_DAMP_CURSE, 100, 100, 5, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, FALSE, 0, 0, -8 }, { "Bent", IPL_DAMP_CURSE, 50, 75, 3, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, FALSE, 0, 0, -4 }, { "Weak", IPL_DAMP_CURSE, 25, 45, 1, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, FALSE, 0, 0, -3 }, { "Jagged", IPL_DAMP, 20, 35, 4, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, TRUE, 250, 450, 3 }, { "Deadly", IPL_DAMP, 36, 50, 6, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, TRUE, 500, 700, 4 }, { "Heavy", IPL_DAMP, 51, 65, 9, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, TRUE, 750, 950, 5 }, { "Vicious", IPL_DAMP, 66, 80, 12, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_EVIL, TRUE, TRUE, 1000, 1450, 8 }, { "Brutal", IPL_DAMP, 81, 95, 16, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, TRUE, 1500, 1950, 10 }, { "Massive", IPL_DAMP, 96, 110, 20, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, TRUE, 2000, 2450, 13 }, #else { "Useless", IPL_DAMP_CURSE, 100, 100, 5, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, FALSE, 0, 0, -8 }, { "Bent", IPL_DAMP_CURSE, 50, 75, 3, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, FALSE, 0, 0, -4 }, { "Weak", IPL_DAMP_CURSE, 25, 45, 1, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, FALSE, 0, 0, -3 }, { "Jagged", IPL_DAMP, 20, 35, 4, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 250, 450, 3 }, { "Deadly", IPL_DAMP, 36, 50, 6, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 500, 700, 4 }, { "Heavy", IPL_DAMP, 51, 65, 9, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 750, 950, 5 }, { "Vicious", IPL_DAMP, 66, 80, 12, PLT_WEAP | PLT_BOW , GOE_EVIL, TRUE, TRUE, 1000, 1450, 8 }, { "Brutal", IPL_DAMP, 81, 95, 16, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 1500, 1950, 10 }, { "Massive", IPL_DAMP, 96, 110, 20, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 2000, 2450, 13 }, #endif { "Savage", IPL_DAMP, 111, 125, 23, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 2500, 3000, 15 }, { "Ruthless", IPL_DAMP, 126, 150, 35, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 10100, 15000, 17 }, { "Merciless", IPL_DAMP, 151, 175, 60, PLT_WEAP | PLT_BOW , GOE_ANY, TRUE, TRUE, 15000, 20000, 20 }, { "Clumsy", IPL_TOHIT_DAMP_CURSE, 50, 75, 5, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, FALSE, 0, 0, -7 }, { "Dull", IPL_TOHIT_DAMP_CURSE, 25, 45, 1, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, FALSE, 0, 0, -5 }, { "Sharp", IPL_TOHIT_DAMP, 20, 35, 1, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, FALSE, 350, 950, 5 }, { "Fine", IPL_TOHIT_DAMP, 36, 50, 6, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, TRUE, 1100, 1700, 7 }, { "Warrior's", IPL_TOHIT_DAMP, 51, 65, 10, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, TRUE, TRUE, 1850, 2450, 13 }, { "Soldier's", IPL_TOHIT_DAMP, 66, 80, 15, PLT_WEAP | PLT_STAFF , GOE_ANY, TRUE, TRUE, 2600, 3950, 17 }, { "Lord's", IPL_TOHIT_DAMP, 81, 95, 19, PLT_WEAP | PLT_STAFF , GOE_ANY, TRUE, TRUE, 4100, 5950, 21 }, { "Knight's", IPL_TOHIT_DAMP, 96, 110, 23, PLT_WEAP | PLT_STAFF , GOE_ANY, TRUE, TRUE, 6100, 8450, 26 }, { "Master's", IPL_TOHIT_DAMP, 111, 125, 28, PLT_WEAP | PLT_STAFF , GOE_ANY, TRUE, TRUE, 8600, 13000, 30 }, { "Champion's", IPL_TOHIT_DAMP, 126, 150, 40, PLT_WEAP | PLT_STAFF , GOE_ANY, TRUE, TRUE, 15200, 24000, 33 }, { "King's", IPL_TOHIT_DAMP, 151, 175, 28, PLT_WEAP | PLT_STAFF , GOE_ANY, TRUE, TRUE, 24100, 35000, 38 }, { "Vulnerable", IPL_ACP_CURSE, 51, 100, 3, PLT_ARMO | PLT_SHLD , GOE_ANY, TRUE, FALSE, 0, 0, -3 }, { "Rusted", IPL_ACP_CURSE, 25, 50, 1, PLT_ARMO | PLT_SHLD , GOE_ANY, TRUE, FALSE, 0, 0, -2 }, { "Fine", IPL_ACP, 20, 30, 1, PLT_ARMO | PLT_SHLD , GOE_ANY, TRUE, TRUE, 20, 100, 2 }, { "Strong", IPL_ACP, 31, 40, 3, PLT_ARMO | PLT_SHLD , GOE_ANY, TRUE, TRUE, 120, 200, 3 }, { "Grand", IPL_ACP, 41, 55, 6, PLT_ARMO | PLT_SHLD , GOE_ANY, TRUE, TRUE, 220, 300, 5 }, { "Valiant", IPL_ACP, 56, 70, 10, PLT_ARMO | PLT_SHLD , GOE_ANY, TRUE, TRUE, 320, 400, 7 }, { "Glorious", IPL_ACP, 71, 90, 14, PLT_ARMO | PLT_SHLD , GOE_GOOD, TRUE, TRUE, 420, 600, 9 }, { "Blessed", IPL_ACP, 91, 110, 19, PLT_ARMO | PLT_SHLD , GOE_GOOD, TRUE, TRUE, 620, 800, 11 }, { "Saintly", IPL_ACP, 111, 130, 24, PLT_ARMO | PLT_SHLD , GOE_GOOD, TRUE, TRUE, 820, 1200, 13 }, { "Awesome", IPL_ACP, 131, 150, 28, PLT_ARMO | PLT_SHLD , GOE_GOOD, TRUE, TRUE, 1220, 2000, 15 }, { "Holy", IPL_ACP, 151, 170, 35, PLT_ARMO | PLT_SHLD , GOE_GOOD, TRUE, TRUE, 5200, 6000, 17 }, { "Godly", IPL_ACP, 171, 200, 60, PLT_ARMO | PLT_SHLD , GOE_GOOD, TRUE, TRUE, 6200, 7000, 20 }, { "Red", IPL_FIRERES, 10, 20, 4, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 500, 1500, 2 }, { "Crimson", IPL_FIRERES, 21, 30, 10, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 2100, 3000, 2 }, { "Crimson", IPL_FIRERES, 31, 40, 16, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 3100, 4000, 2 }, { "Garnet", IPL_FIRERES, 41, 50, 20, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 8200, 12000, 3 }, { "Ruby", IPL_FIRERES, 51, 60, 26, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 17100, 20000, 5 }, { "Blue", IPL_LIGHTRES, 10, 20, 4, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 500, 1500, 2 }, { "Azure", IPL_LIGHTRES, 21, 30, 10, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 2100, 3000, 2 }, { "Lapis", IPL_LIGHTRES, 31, 40, 16, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 3100, 4000, 2 }, { "Cobalt", IPL_LIGHTRES, 41, 50, 20, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 8200, 12000, 3 }, { "Sapphire", IPL_LIGHTRES, 51, 60, 26, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 17100, 20000, 5 }, { "White", IPL_MAGICRES, 10, 20, 4, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 500, 1500, 2 }, { "Pearl", IPL_MAGICRES, 21, 30, 10, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 2100, 3000, 2 }, { "Ivory", IPL_MAGICRES, 31, 40, 16, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 3100, 4000, 2 }, { "Crystal", IPL_MAGICRES, 41, 50, 20, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 8200, 12000, 3 }, { "Diamond", IPL_MAGICRES, 51, 60, 26, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 17100, 20000, 5 }, { "Topaz", IPL_ALLRES, 10, 15, 8, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 2000, 5000, 3 }, { "Amber", IPL_ALLRES, 16, 20, 12, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 7400, 10000, 3 }, { "Jade", IPL_ALLRES, 21, 30, 18, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 11000, 15000, 3 }, { "Obsidian", IPL_ALLRES, 31, 40, 24, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 24000, 40000, 4 }, { "Emerald", IPL_ALLRES, 41, 50, 31, PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, FALSE, TRUE, 61000, 75000, 7 }, { "Hyena's", IPL_MANA_CURSE, 11, 25, 4, PLT_STAFF | PLT_MISC, GOE_ANY, FALSE, FALSE, 100, 1000, -2 }, { "Frog's", IPL_MANA_CURSE, 1, 10, 1, PLT_STAFF | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "Spider's", IPL_MANA, 10, 15, 1, PLT_STAFF | PLT_MISC, GOE_EVIL, FALSE, TRUE, 500, 1000, 2 }, { "Raven's", IPL_MANA, 15, 20, 5, PLT_STAFF | PLT_MISC, GOE_ANY, FALSE, TRUE, 1100, 2000, 3 }, { "Snake's", IPL_MANA, 21, 30, 9, PLT_STAFF | PLT_MISC, GOE_ANY, FALSE, TRUE, 2100, 4000, 5 }, { "Serpent's", IPL_MANA, 30, 40, 15, PLT_STAFF | PLT_MISC, GOE_ANY, FALSE, TRUE, 4100, 6000, 7 }, { "Drake's", IPL_MANA, 41, 50, 21, PLT_STAFF | PLT_MISC, GOE_ANY, FALSE, TRUE, 6100, 10000, 9 }, { "Dragon's", IPL_MANA, 51, 60, 27, PLT_STAFF | PLT_MISC, GOE_ANY, FALSE, TRUE, 10100, 15000, 11 }, { "Wyrm's", IPL_MANA, 61, 80, 35, PLT_STAFF , GOE_ANY, FALSE, TRUE, 15100, 19000, 12 }, { "Hydra's", IPL_MANA, 81, 100, 60, PLT_STAFF , GOE_ANY, FALSE, TRUE, 19100, 30000, 13 }, { "Angel's", IPL_SPLLVLADD, 1, 1, 15, PLT_STAFF , GOE_GOOD, FALSE, TRUE, 25000, 25000, 2 }, { "Arch-Angel's", IPL_SPLLVLADD, 2, 2, 25, PLT_STAFF , GOE_GOOD, FALSE, TRUE, 50000, 50000, 3 }, { "Plentiful", IPL_CHARGES, 2, 2, 4, PLT_STAFF , GOE_ANY, FALSE, TRUE, 2000, 2000, 2 }, { "Bountiful", IPL_CHARGES, 3, 3, 9, PLT_STAFF , GOE_ANY, FALSE, TRUE, 3000, 3000, 3 }, { "Flaming", IPL_FIREDAM, 1, 10, 7, PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 5000, 5000, 2 }, { "Lightning", IPL_LIGHTDAM, 2, 20, 18, PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 10000, 10000, 2 }, #ifdef HELLFIRE { "Jester's", IPL_JESTERS, 1, 1, 7, PLT_WEAP , GOE_ANY, FALSE, TRUE, 1200, 1200, 3 }, { "Crystalline", IPL_CRYSTALLINE, 30, 70, 5, PLT_WEAP , GOE_ANY, FALSE, TRUE, 1000, 3000, 3 }, { "Doppelganger's", IPL_DOPPELGANGER, 81, 95, 11, PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 2000, 2400, 10 }, #endif { "", IPL_INVALID, 0, 0, 0, 0 , GOE_ANY, FALSE, FALSE, 0, 0, 0 }, // clang-format on }; /** Contains the data related to each item suffix. */ const PLStruct PL_Suffix[] = { // clang-format off // PLName, PLPower, PLParam1, PLParam2, PLMinLvl, PLIType, PLGOE, PLDouble, PLOk, PLMinVal, PLMaxVal, PLMultVal #ifdef HELLFIRE { "quality", IPL_DAMMOD, 1, 2, 2, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, FALSE, TRUE, 100, 200, 2 }, { "maiming", IPL_DAMMOD, 3, 5, 7, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, FALSE, TRUE, 1300, 1500, 3 }, #else { "quality", IPL_DAMMOD, 1, 2, 2, PLT_WEAP | PLT_BOW , GOE_ANY, FALSE, TRUE, 100, 200, 2 }, { "maiming", IPL_DAMMOD, 3, 5, 7, PLT_WEAP | PLT_BOW , GOE_ANY, FALSE, TRUE, 1300, 1500, 3 }, #endif { "slaying", IPL_DAMMOD, 6, 8, 15, PLT_WEAP , GOE_ANY, FALSE, TRUE, 2600, 3000, 5 }, { "gore", IPL_DAMMOD, 9, 12, 25, PLT_WEAP , GOE_ANY, FALSE, TRUE, 4100, 5000, 8 }, { "carnage", IPL_DAMMOD, 13, 16, 35, PLT_WEAP , GOE_ANY, FALSE, TRUE, 5100, 10000, 10 }, { "slaughter", IPL_DAMMOD, 17, 20, 60, PLT_WEAP , GOE_ANY, FALSE, TRUE, 10100, 15000, 13 }, { "pain", IPL_GETHIT_CURSE, 2, 4, 4, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -4 }, { "tears", IPL_GETHIT_CURSE, 1, 1, 2, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "health", IPL_GETHIT, 1, 1, 2, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_GOOD, FALSE, TRUE, 200, 200, 2 }, { "protection", IPL_GETHIT, 2, 2, 6, PLT_ARMO | PLT_SHLD , GOE_GOOD, FALSE, TRUE, 400, 800, 4 }, { "absorption", IPL_GETHIT, 3, 3, 12, PLT_ARMO | PLT_SHLD , GOE_GOOD, FALSE, TRUE, 1001, 2500, 10 }, { "deflection", IPL_GETHIT, 4, 4, 20, PLT_ARMO , GOE_GOOD, FALSE, TRUE, 2500, 6500, 15 }, { "osmosis", IPL_GETHIT, 5, 6, 50, PLT_ARMO , GOE_GOOD, FALSE, TRUE, 7500, 10000, 20 }, { "frailty", IPL_STR_CURSE, 6, 10, 3, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -3 }, #ifdef HELLFIRE { "weakness", IPL_STR_CURSE, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "strength", IPL_STR, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 200, 1000, 2 }, #else { "weakness", IPL_STR_CURSE, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "strength", IPL_STR, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 200, 1000, 2 }, #endif { "might", IPL_STR, 6, 10, 5, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 1200, 2000, 3 }, { "power", IPL_STR, 11, 15, 11, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 2200, 3000, 4 }, { "giants", IPL_STR, 16, 20, 17, PLT_ARMO | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 3200, 5000, 7 }, { "titans", IPL_STR, 21, 30, 23, PLT_WEAP | PLT_MISC, GOE_ANY, FALSE, TRUE, 5200, 10000, 10 }, { "paralysis", IPL_DEX_CURSE, 6, 10, 3, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -3 }, #ifdef HELLFIRE { "atrophy", IPL_DEX_CURSE, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "dexterity", IPL_DEX, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 200, 1000, 2 }, #else { "atrophy", IPL_DEX_CURSE, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "dexterity", IPL_DEX, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 200, 1000, 2 }, #endif { "skill", IPL_DEX, 6, 10, 5, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 1200, 2000, 3 }, { "accuracy", IPL_DEX, 11, 15, 11, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 2200, 3000, 4 }, { "precision", IPL_DEX, 16, 20, 17, PLT_ARMO | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 3200, 5000, 7 }, { "perfection", IPL_DEX, 21, 30, 23, PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 5200, 10000, 10 }, { "the fool", IPL_MAG_CURSE, 6, 10, 3, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -3 }, { "dyslexia", IPL_MAG_CURSE, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "magic", IPL_MAG, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 200, 1000, 2 }, { "the mind", IPL_MAG, 6, 10, 5, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 1200, 2000, 3 }, { "brilliance", IPL_MAG, 11, 15, 11, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 2200, 3000, 4 }, { "sorcery", IPL_MAG, 16, 20, 17, PLT_ARMO | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 3200, 5000, 7 }, { "wizardry", IPL_MAG, 21, 30, 23, PLT_STAFF | PLT_MISC, GOE_ANY, FALSE, TRUE, 5200, 10000, 10 }, #ifdef HELLFIRE { "illness", IPL_VIT_CURSE, 6, 10, 3, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -3 }, { "disease", IPL_VIT_CURSE, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "vitality", IPL_VIT, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_GOOD, FALSE, TRUE, 200, 1000, 2 }, #else { "illness", IPL_VIT_CURSE, 6, 10, 3, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -3 }, { "disease", IPL_VIT_CURSE, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "vitality", IPL_VIT, 1, 5, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_GOOD, FALSE, TRUE, 200, 1000, 2 }, #endif { "zest", IPL_VIT, 6, 10, 5, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_GOOD, FALSE, TRUE, 1200, 2000, 3 }, { "vim", IPL_VIT, 11, 15, 11, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_GOOD, FALSE, TRUE, 2200, 3000, 4 }, { "vigor", IPL_VIT, 16, 20, 17, PLT_ARMO | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_GOOD, FALSE, TRUE, 3200, 5000, 7 }, { "life", IPL_VIT, 21, 30, 23, PLT_MISC, GOE_GOOD, FALSE, TRUE, 5200, 10000, 10 }, #ifdef HELLFIRE { "trouble", IPL_ATTRIBS_CURSE, 6, 10, 12, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -10 }, { "the pit", IPL_ATTRIBS_CURSE, 1, 5, 5, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -5 }, { "the sky", IPL_ATTRIBS, 1, 3, 5, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 800, 4000, 5 }, { "the moon", IPL_ATTRIBS, 4, 7, 11, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 4800, 8000, 10 }, #else { "trouble", IPL_ATTRIBS_CURSE, 6, 10, 12, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -10 }, { "the pit", IPL_ATTRIBS_CURSE, 1, 5, 5, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -5 }, { "the sky", IPL_ATTRIBS, 1, 3, 5, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 800, 4000, 5 }, { "the moon", IPL_ATTRIBS, 4, 7, 11, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 4800, 8000, 10 }, #endif { "the stars", IPL_ATTRIBS, 8, 11, 17, PLT_ARMO | PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 8800, 12000, 15 }, { "the heavens", IPL_ATTRIBS, 12, 15, 25, PLT_WEAP | PLT_BOW | PLT_MISC, GOE_ANY, FALSE, TRUE, 12800, 20000, 20 }, { "the zodiac", IPL_ATTRIBS, 16, 20, 30, PLT_MISC, GOE_ANY, FALSE, TRUE, 20800, 40000, 30 }, { "the vulture", IPL_LIFE_CURSE, 11, 25, 4, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -4 }, { "the jackal", IPL_LIFE_CURSE, 1, 10, 1, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "the fox", IPL_LIFE, 10, 15, 1, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_ANY, FALSE, TRUE, 100, 1000, 2 }, { "the jaguar", IPL_LIFE, 16, 20, 5, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_ANY, FALSE, TRUE, 1100, 2000, 3 }, { "the eagle", IPL_LIFE, 21, 30, 9, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_ANY, FALSE, TRUE, 2100, 4000, 5 }, { "the wolf", IPL_LIFE, 30, 40, 15, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_ANY, FALSE, TRUE, 4100, 6000, 7 }, { "the tiger", IPL_LIFE, 41, 50, 21, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_ANY, FALSE, TRUE, 6100, 10000, 9 }, { "the lion", IPL_LIFE, 51, 60, 27, PLT_ARMO | PLT_MISC, GOE_ANY, FALSE, TRUE, 10100, 15000, 11 }, { "the mammoth", IPL_LIFE, 61, 80, 35, PLT_ARMO , GOE_ANY, FALSE, TRUE, 15100, 19000, 12 }, { "the whale", IPL_LIFE, 81, 100, 60, PLT_ARMO , GOE_ANY, FALSE, TRUE, 19100, 30000, 13 }, { "fragility", IPL_DUR_CURSE, 100, 100, 3, PLT_ARMO | PLT_SHLD | PLT_WEAP , GOE_EVIL, FALSE, FALSE, 0, 0, -4 }, { "brittleness", IPL_DUR_CURSE, 26, 75, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP , GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, #ifdef HELLFIRE { "sturdiness", IPL_DUR, 26, 75, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 100, 100, 2 }, { "craftsmanship", IPL_DUR, 51, 100, 6, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 200, 200, 2 }, { "structure", IPL_DUR, 101, 200, 12, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 300, 300, 2 }, { "the ages", IPL_INDESTRUCTIBLE, 0, 0, 25, PLT_ARMO | PLT_SHLD | PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 600, 600, 5 }, #else { "sturdiness", IPL_DUR, 26, 75, 1, PLT_ARMO | PLT_SHLD | PLT_WEAP , GOE_ANY, FALSE, TRUE, 100, 100, 2 }, { "craftsmanship", IPL_DUR, 51, 100, 6, PLT_ARMO | PLT_SHLD | PLT_WEAP , GOE_ANY, FALSE, TRUE, 200, 200, 2 }, { "structure", IPL_DUR, 101, 200, 12, PLT_ARMO | PLT_SHLD | PLT_WEAP , GOE_ANY, FALSE, TRUE, 300, 300, 2 }, { "the ages", IPL_INDESTRUCTIBLE, 0, 0, 25, PLT_ARMO | PLT_SHLD | PLT_WEAP , GOE_ANY, FALSE, TRUE, 600, 600, 5 }, #endif { "the dark", IPL_LIGHT_CURSE, 4, 4, 6, PLT_ARMO | PLT_WEAP | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -3 }, { "the night", IPL_LIGHT_CURSE, 2, 2, 3, PLT_ARMO | PLT_WEAP | PLT_MISC, GOE_EVIL, FALSE, FALSE, 0, 0, -2 }, { "light", IPL_LIGHT, 2, 2, 4, PLT_ARMO | PLT_WEAP | PLT_MISC, GOE_GOOD, FALSE, TRUE, 750, 750, 2 }, { "radiance", IPL_LIGHT, 4, 4, 8, PLT_ARMO | PLT_WEAP | PLT_MISC, GOE_GOOD, FALSE, TRUE, 1500, 1500, 3 }, { "flame", IPL_FIRE_ARROWS, 1, 3, 1, PLT_BOW , GOE_ANY, FALSE, TRUE, 2000, 2000, 2 }, { "fire", IPL_FIRE_ARROWS, 1, 6, 11, PLT_BOW , GOE_ANY, FALSE, TRUE, 4000, 4000, 4 }, { "burning", IPL_FIRE_ARROWS, 1, 16, 35, PLT_BOW , GOE_ANY, FALSE, TRUE, 6000, 6000, 6 }, { "shock", IPL_LIGHT_ARROWS, 1, 6, 13, PLT_BOW , GOE_ANY, FALSE, TRUE, 6000, 6000, 2 }, { "lightning", IPL_LIGHT_ARROWS, 1, 10, 21, PLT_BOW , GOE_ANY, FALSE, TRUE, 8000, 8000, 4 }, { "thunder", IPL_LIGHT_ARROWS, 1, 20, 60, PLT_BOW , GOE_ANY, FALSE, TRUE, 12000, 12000, 6 }, { "many", IPL_DUR, 100, 100, 3, PLT_BOW , GOE_ANY, FALSE, TRUE, 750, 750, 2 }, { "plenty", IPL_DUR, 200, 200, 7, PLT_BOW , GOE_ANY, FALSE, TRUE, 1500, 1500, 3 }, { "thorns", IPL_THORNS, 1, 3, 1, PLT_ARMO | PLT_SHLD , GOE_ANY, FALSE, TRUE, 500, 500, 2 }, { "corruption", IPL_NOMANA, 0, 0, 5, PLT_ARMO | PLT_SHLD | PLT_WEAP , GOE_EVIL, FALSE, FALSE, -1000, -1000, 2 }, { "thieves", IPL_ABSHALFTRAP, 0, 0, 11, PLT_ARMO | PLT_SHLD | PLT_MISC, GOE_ANY, FALSE, TRUE, 1500, 1500, 2 }, { "the bear", IPL_KNOCKBACK, 0, 0, 5, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_EVIL, FALSE, TRUE, 750, 750, 2 }, { "the bat", IPL_STEALMANA, 3, 3, 8, PLT_WEAP , GOE_ANY, FALSE, TRUE, 7500, 7500, 3 }, { "vampires", IPL_STEALMANA, 5, 5, 19, PLT_WEAP , GOE_ANY, FALSE, TRUE, 15000, 15000, 3 }, { "the leech", IPL_STEALLIFE, 3, 3, 8, PLT_WEAP , GOE_ANY, FALSE, TRUE, 7500, 7500, 3 }, { "blood", IPL_STEALLIFE, 5, 5, 19, PLT_WEAP , GOE_ANY, FALSE, TRUE, 15000, 15000, 3 }, #ifdef HELLFIRE { "piercing", IPL_TARGAC, 1, 1, 1, PLT_WEAP | PLT_BOW , GOE_ANY, FALSE, TRUE, 1000, 1000, 3 }, { "puncturing", IPL_TARGAC, 2, 2, 9, PLT_WEAP | PLT_BOW , GOE_ANY, FALSE, TRUE, 2000, 2000, 6 }, { "bashing", IPL_TARGAC, 3, 3, 17, PLT_WEAP , GOE_ANY, FALSE, TRUE, 4000, 4000, 12 }, #else { "piercing", IPL_TARGAC, 2, 6, 1, PLT_WEAP | PLT_BOW , GOE_ANY, FALSE, TRUE, 1000, 1000, 3 }, { "puncturing", IPL_TARGAC, 4, 12, 9, PLT_WEAP | PLT_BOW , GOE_ANY, FALSE, TRUE, 2000, 2000, 6 }, { "bashing", IPL_TARGAC, 8, 24, 17, PLT_WEAP , GOE_ANY, FALSE, TRUE, 4000, 4000, 12 }, #endif { "readiness", IPL_FASTATTACK, 1, 1, 1, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, FALSE, TRUE, 2000, 2000, 2 }, { "swiftness", IPL_FASTATTACK, 2, 2, 10, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, FALSE, TRUE, 4000, 4000, 4 }, { "speed", IPL_FASTATTACK, 3, 3, 19, PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 8000, 8000, 8 }, { "haste", IPL_FASTATTACK, 4, 4, 27, PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 16000, 16000, 16 }, { "balance", IPL_FASTRECOVER, 1, 1, 1, PLT_ARMO | PLT_MISC, GOE_ANY, FALSE, TRUE, 2000, 2000, 2 }, { "stability", IPL_FASTRECOVER, 2, 2, 10, PLT_ARMO | PLT_MISC, GOE_ANY, FALSE, TRUE, 4000, 4000, 4 }, { "harmony", IPL_FASTRECOVER, 3, 3, 20, PLT_ARMO | PLT_MISC, GOE_ANY, FALSE, TRUE, 8000, 8000, 8 }, { "blocking", IPL_FASTBLOCK, 1, 1, 5, PLT_SHLD , GOE_ANY, FALSE, TRUE, 4000, 4000, 4 }, #ifdef HELLFIRE { "devastation", IPL_DEVASTATION, 1, 1, 1, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, FALSE, TRUE, 1200, 1200, 3 }, { "decay", IPL_DECAY, 150, 250, 1, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, FALSE, TRUE, 200, 200, 2 }, { "peril", IPL_PERIL, 1, 1, 5, PLT_WEAP | PLT_STAFF | PLT_BOW , GOE_ANY, FALSE, TRUE, 500, 500, 1 }, #endif { "", IPL_INVALID, 0, 0, 0, 0 , GOE_ANY, FALSE, FALSE, 0, 0, 0 }, // clang-format on }; /** Contains the data related to each unique item ID. */ const UItemStruct UniqueItemList[] = { // clang-format off // UIName, UIItemId, UIMinLvl, UINumPL, UIValue, UIPower1, UIParam1, UIParam2, UIPower2, UIParam3, UIParam4, UIPower3, UIParam5, UIParam6, UIPower4, UIParam7, UIParam8, UIPower5, UIParam9, UIParam10, UIPower6, UIParam11, UIParam12 { "The Butcher's Cleaver", UITYPE_CLEAVER, 1, 3, 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, 1, 3, 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, 1, 4, 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, 1, 5, 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, 1, 4, 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, 1, 6, 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, 1, 6, 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, 1, 4, 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, 1, 6, 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 }, #ifdef HELLFIRE { "Bovine Plate", UITYPE_BOVINE, 1, 6, 400, IPL_SETAC, 150, 150, IPL_INDESTRUCTIBLE, 0, 0, IPL_LIGHT, 5, 5, IPL_ALLRES, 30, 30, IPL_MANA_CURSE, 50, 50, IPL_SPLLVLADD, -2, -2 }, #else { "Lightforge", UITYPE_MACE, 1, 6, 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 }, #endif { "The Rift Bow", UITYPE_SHORTBOW, 1, 3, 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, 2, 4, 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, 2, 4, 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, 3, 4, 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, 5, 6, 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, 5, 4, 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, 10, 4, 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, 13, 4, 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, 17, 4, 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, 26, 5, 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, 1, 5, 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, 1, 3, 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, 1, 4, 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, 1, 4, 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, 2, 4, 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, 3, 3, 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, 3, 5, 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, 6, 6, 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, 8, 4, 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, 11, 5, 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, 13, 4, 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, 15, 5, 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, 17, 4, 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, 19, 5, 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, 23, 6, 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, 27, 6, 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, 2, 5, 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, 2, 4, 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, 3, 5, 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, 4, 4, 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, 5, 6, 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, 7, 5, 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, 12, 3, 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, 15, 5, 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, 25, 6, 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, 1, 5, 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, 1, 4, 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, 1, 3, 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, 2, 5, 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, 5, 6, 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, 9, 6, 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, 12, 6, 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, 16, 6, 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, 26, 5, 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, 2, 5, 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, 4, 4, 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, 8, 4, 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, 8, 4, 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, 14, 5, 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, 16, 6, 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, 18, 5, 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, 20, 4, 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, 22, 3, 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, 1, 2, 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, 6, 5, 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, 7, 6, 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, 12, 5, 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, 21, 6, 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, 27, 5, 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, 2, 5, 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, 6, 4, 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, 2, 6, 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, 4, 5, 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, 5, 6, 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, 9, 2, 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, 13, 4, 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, 16, 6, 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, 19, 6, 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, 25, 5, 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, 1, 5, 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, 1, 6, 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, 2, 6, 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, 4, 6, 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, 10, 6, 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, 24, 6, 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, 1, 4, 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, 1, 6, 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, 2, 4, 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, 5, 3, 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, 11, 5, 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 }, #ifdef HELLFIRE { "Giant's Knuckle", UITYPE_RING, 8, 3, 8000, IPL_STR, 60, 60, IPL_DEX_CURSE, 30, 30, IPL_INVCURS, 179, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Mercurial Ring", UITYPE_RING, 8, 3, 8000, IPL_DEX, 60, 60, IPL_STR_CURSE, 30, 30, IPL_INVCURS, 176, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Xorine's Ring", UITYPE_RING, 8, 3, 8000, IPL_MAG, 60, 60, IPL_STR_CURSE, 30, 30, IPL_INVCURS, 168, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Karik's Ring", UITYPE_RING, 8, 3, 8000, IPL_VIT, 60, 60, IPL_MAG_CURSE, 30, 30, IPL_INVCURS, 173, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Ring of Magma", UITYPE_RING, 8, 4, 8000, IPL_FIRERES, 60, 60, IPL_LIGHTRES_CURSE, 30, 30, IPL_MAGICRES_CURSE, 30, 30, IPL_INVCURS, 184, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Ring of the Mystics", UITYPE_RING, 8, 4, 8000, IPL_MAGICRES, 60, 60, IPL_FIRERES_CURSE, 30, 30, IPL_LIGHTRES_CURSE, 30, 30, IPL_INVCURS, 181, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Ring of Thunder", UITYPE_RING, 8, 4, 8000, IPL_LIGHTRES, 60, 60, IPL_FIRERES_CURSE, 30, 30, IPL_MAGICRES_CURSE, 30, 30, IPL_INVCURS, 177, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Amulet of Warding", UITYPE_AMULET, 12, 3, 30000, IPL_ALLRES, 40, 40, IPL_LIFE_CURSE, 100, 100, IPL_INVCURS, 170, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Gnat Sting", UITYPE_HUNTBOW, 15, 5, 30000, IPL_MULT_ARROWS, 3, 3, IPL_SETDAM, 1, 2, IPL_FASTATTACK, 1, 1, IPL_INDESTRUCTIBLE, 0, 0, IPL_INVCURS, 210, 0, IPL_TOHIT, 0, 0 }, { "Flambeau", UITYPE_COMPBOW, 11, 4, 30000, IPL_FIREBALL, 15, 20, IPL_SETDAM, 0, 0, IPL_INDESTRUCTIBLE, 0, 0, IPL_INVCURS, 209, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Armor of Gloom", UITYPE_FULLPLATE, 25, 5, 200000, IPL_NOMINSTR, 0, 0, IPL_SETAC, 225, 225, IPL_ALLRESZERO, 0, 0, IPL_LIGHT_CURSE, 2, 2, IPL_INVCURS, 203, 0, IPL_TOHIT, 0, 0 }, { "Blitzen", UITYPE_COMPBOW, 13, 4, 30000, IPL_ADDACLIFE, 10, 15, IPL_SETDAM, 0, 0, IPL_INDESTRUCTIBLE, 0, 0, IPL_INVCURS, 219, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Thunderclap", UITYPE_WARHAMMER, 13, 6, 30000, IPL_ADDMANAAC, 3, 6, IPL_STR, 20, 20, IPL_LIGHTRES, 30, 30, IPL_LIGHT, 2, 2, IPL_INDESTRUCTIBLE, 0, 0, IPL_INVCURS, 205, 0 }, { "Shirotachi", UITYPE_GREATSWR, 21, 4, 36000, IPL_ONEHAND, 0, 0, IPL_FASTATTACK, 4, 4, IPL_TARGAC, 2, 2, IPL_LIGHTDAM, 6, 6, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Eater of Souls", UITYPE_TWOHANDSWR, 23, 6, 42000, IPL_INDESTRUCTIBLE, 0, 0, IPL_LIFE, 50, 50, IPL_STEALLIFE, 5, 5, IPL_STEALMANA, 5, 5, IPL_DRAINLIFE, 0, 0, IPL_INVCURS, 200, 0 }, { "Diamondedge", UITYPE_LONGSWR, 17, 6, 42000, IPL_SETDUR, 10, 10, IPL_TOHIT, 50, 50, IPL_DAMP, 100, 100, IPL_LIGHTRES, 50, 50, IPL_SETAC, 10, 10, IPL_INVCURS, 206, 0 }, { "Bone Chain Armor", UITYPE_CHAINMAIL, 13, 3, 36000, IPL_SETAC, 40, 40, IPL_ACUNDEAD, 0, 0, IPL_INVCURS, 204, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Demon Plate Armor", UITYPE_FULLPLATE, 25, 3, 80000, IPL_SETAC, 80, 80, IPL_ACDEMON, 0, 0, IPL_INVCURS, 225, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Acolyte's Amulet", UITYPE_AMULET, 10, 2, 10000, IPL_MANATOLIFE, 50, 50, IPL_INVCURS, 183, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Gladiator's Ring", UITYPE_RING, 10, 2, 10000, IPL_LIFETOMANA, 40, 40, IPL_INVCURS, 186, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, #endif { "", UITYPE_INVALID, 0, 0, 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 }, // clang-format on }; ================================================ FILE: Source/itemdat.h ================================================ /** * @file itemdat.h * * Interface of all item data. */ #ifndef __ITEMDAT_H__ #define __ITEMDAT_H__ extern ItemDataStruct AllItemsList[]; extern const PLStruct PL_Prefix[]; extern const PLStruct PL_Suffix[]; extern const UItemStruct UniqueItemList[]; #endif /* __ITEMDAT_H__ */ ================================================ FILE: Source/items.cpp ================================================ /** * @file items.cpp * * Implementation of item functionality. */ #include "all.h" #ifdef HELLFIRE #include "../3rdParty/Storm/Source/storm.h" #endif int itemactive[MAXITEMS]; BOOL uitemflag; int itemavail[MAXITEMS]; ItemStruct curruitem; ItemGetRecordStruct itemrecord[MAXITEMS]; /** Contains the items on ground in the current game. */ ItemStruct item[MAXITEMS + 1]; BOOL itemhold[3][3]; #ifdef HELLFIRE CornerStoneStruct CornerStone; #endif BYTE *itemanims[ITEMTYPES]; BOOL UniqueItemFlag[128]; #ifdef HELLFIRE int auricGold = GOLD_MAX_LIMIT * 2; #endif int numitems; int gnNumGetRecords; /* data */ #ifdef HELLFIRE int OilLevels[] = { 1, 10, 1, 10, 4, 1, 5, 17, 1, 10 }; int OilValues[] = { 500, 2500, 500, 2500, 1500, 100, 2500, 15000, 500, 2500 }; int OilMagic[] = { IMISC_OILACC, IMISC_OILMAST, IMISC_OILSHARP, IMISC_OILDEATH, IMISC_OILSKILL, IMISC_OILBSMTH, IMISC_OILFORT, IMISC_OILPERM, IMISC_OILHARD, IMISC_OILIMP, }; char OilNames[10][25] = { "Oil of Accuracy", "Oil of Mastery", "Oil of Sharpness", "Oil of Death", "Oil of Skill", "Blacksmith Oil", "Oil of Fortitude", "Oil of Permanence", "Oil of Hardening", "Oil of Imperviousness" }; int MaxGold = GOLD_MAX_LIMIT; #endif /** Maps from item_cursor_graphic to in-memory item type. */ BYTE ItemCAnimTbl[] = { #ifndef HELLFIRE 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 #else 20, 16, 16, 16, 4, 4, 4, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 25, 12, 28, 28, 28, 38, 38, 38, 32, 38, 38, 38, 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, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 35, 39, 36, 36, 36, 37, 38, 38, 38, 38, 38, 41, 42, 8, 8, 8, 17, 0, 6, 8, 11, 11, 3, 3, 1, 6, 6, 6, 1, 8, 6, 11, 3, 6, 8, 1, 6, 6, 17, 40, 0, 0 #endif }; /** Map of item type .cel file names. */ const char *const ItemDropNames[] = { "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", #ifdef HELLFIRE "bombs1", "halfps1", "wholeps1", "runes1", "teddys1", "cows1", "donkys1", "mooses1", #endif }; /** Maps of item drop animation length. */ BYTE ItemAnimLs[] = { 15, 13, 16, 13, 10, 13, 13, 13, 13, 10, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 16, 16, 16, 16, 16, 16, 16, 16, 13, 12, 12, 13, 13, 13, 8, #ifdef HELLFIRE 10, 16, 16, 10, 10, 15, 15, 15, #endif }; /** Maps of drop sounds effect of dropping the item on ground. */ int ItemDropSnds[] = { 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, #ifdef HELLFIRE IS_FROCK, IS_FSCRL, IS_FSCRL, IS_FROCK, IS_FMUSH, IS_FHARM, IS_FLARM, IS_FLARM, #endif }; /** Maps of drop sounds effect of placing the item in the inventory. */ int ItemInvSnds[] = { 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, #ifdef HELLFIRE IS_IROCK, IS_ISCROL, IS_ISCROL, IS_IROCK, IS_IMUSH, IS_IHARM, IS_ILARM, IS_ILARM, #endif }; #ifdef HELLFIRE char *CornerStoneRegKey = "SItem"; #endif /** Specifies the current Y-coordinate used for validation of items on ground. */ int idoppely = 16; /** Maps from Griswold premium item number to a quality level delta as added to the base quality level. */ int premiumlvladd[SMITH_PREMIUM_ITEMS] = { // clang-format off -1, -1, #ifdef HELLFIRE -1, #endif 0, 0, #ifdef HELLFIRE 0, 0, 1, 1, 1, #endif 1, 2, #ifdef HELLFIRE 2, 3, 3, #endif // clang-format on }; #ifdef HELLFIRE int get_ring_max_value(int i) { int j, res; res = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[i].InvBody[j]._iClass != ITYPE_NONE && plr[i].InvBody[j]._itype == ITYPE_RING && res < plr[i].InvBody[j]._iIvalue) res = plr[i].InvBody[j]._iIvalue; } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[i].InvList[j]._iClass != ITYPE_NONE && plr[i].InvList[j]._itype == ITYPE_RING && res < plr[i].InvList[j]._iIvalue) res = plr[i].InvList[j]._iIvalue; } return res; } int get_bow_max_value(int i) { int j, res; res = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[i].InvBody[j]._iClass != ITYPE_NONE && plr[i].InvBody[j]._itype == ITYPE_BOW && res < plr[i].InvBody[j]._iIvalue) res = plr[i].InvBody[j]._iIvalue; } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[i].InvList[j]._iClass != ITYPE_NONE && plr[i].InvList[j]._itype == ITYPE_BOW && res < plr[i].InvList[j]._iIvalue) res = plr[i].InvList[j]._iIvalue; } return res; } int get_staff_max_value(int i) { int j, res; res = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[i].InvBody[j]._iClass != ITYPE_NONE && plr[i].InvBody[j]._itype == ITYPE_STAFF && res < plr[i].InvBody[j]._iIvalue) res = plr[i].InvBody[j]._iIvalue; } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[i].InvList[j]._iClass != ITYPE_NONE && plr[i].InvList[j]._itype == ITYPE_STAFF && res < plr[i].InvList[j]._iIvalue) res = plr[i].InvList[j]._iIvalue; } return res; } int get_sword_max_value(int i) { int j, res; res = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[i].InvBody[j]._iClass != ITYPE_NONE && plr[i].InvBody[j]._itype == ITYPE_SWORD && res < plr[i].InvBody[j]._iIvalue) res = plr[i].InvBody[j]._iIvalue; } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[i].InvList[j]._iClass != ITYPE_NONE && plr[i].InvList[j]._itype == ITYPE_SWORD && res < plr[i].InvList[j]._iIvalue) res = plr[i].InvList[j]._iIvalue; } return res; } int get_helm_max_value(int i) { int j, res; res = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[i].InvBody[j]._iClass != ITYPE_NONE && plr[i].InvBody[j]._itype == ITYPE_HELM && res < plr[i].InvBody[j]._iIvalue) res = plr[i].InvBody[j]._iIvalue; } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[i].InvList[j]._iClass != ITYPE_NONE && plr[i].InvList[j]._itype == ITYPE_HELM && res < plr[i].InvList[j]._iIvalue) res = plr[i].InvList[j]._iIvalue; } return res; } int get_shield_max_value(int i) { int j, res; res = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[i].InvBody[j]._iClass != ITYPE_NONE && plr[i].InvBody[j]._itype == ITYPE_SHIELD && res < plr[i].InvBody[j]._iIvalue) res = plr[i].InvBody[j]._iIvalue; } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[i].InvList[j]._iClass != ITYPE_NONE && plr[i].InvList[j]._itype == ITYPE_SHIELD && res < plr[i].InvList[j]._iIvalue) res = plr[i].InvList[j]._iIvalue; } return res; } int get_armor_max_value(int i) { int j, res; res = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[i].InvBody[j]._iClass != ITYPE_NONE && (plr[i].InvBody[j]._itype == ITYPE_LARMOR || plr[i].InvBody[j]._itype == ITYPE_MARMOR || plr[i].InvBody[j]._itype == ITYPE_HARMOR) && res < plr[i].InvBody[j]._iIvalue) res = plr[i].InvBody[j]._iIvalue; } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[i].InvList[j]._iClass != ITYPE_NONE && (plr[i].InvList[j]._itype == ITYPE_LARMOR || plr[i].InvList[j]._itype == ITYPE_MARMOR || plr[i].InvList[j]._itype == ITYPE_HARMOR) && res < plr[i].InvList[j]._iIvalue) res = plr[i].InvList[j]._iIvalue; } return res; } int get_mace_max_value(int i) { int j, res; res = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[i].InvBody[j]._iClass != ITYPE_NONE && plr[i].InvBody[j]._itype == ITYPE_MACE && res < plr[i].InvBody[j]._iIvalue) res = plr[i].InvBody[j]._iIvalue; } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[i].InvList[j]._iClass != ITYPE_NONE && plr[i].InvList[j]._itype == ITYPE_MACE && res < plr[i].InvList[j]._iIvalue) res = plr[i].InvList[j]._iIvalue; } return res; } int get_amulet_max_value(int i) { int j, res; res = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[i].InvBody[j]._iClass != ITYPE_NONE && plr[i].InvBody[j]._itype == ITYPE_AMULET && res < plr[i].InvBody[j]._iIvalue) res = plr[i].InvBody[j]._iIvalue; } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[i].InvList[j]._iClass != ITYPE_NONE && plr[i].InvList[j]._itype == ITYPE_AMULET && res < plr[i].InvList[j]._iIvalue) res = plr[i].InvList[j]._iIvalue; } return res; } int get_axe_max_value(int i) { int j, res; res = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[i].InvBody[j]._iClass != ITYPE_NONE && plr[i].InvBody[j]._itype == ITYPE_AXE && res < plr[i].InvBody[j]._iIvalue) res = plr[i].InvBody[j]._iIvalue; } for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[i].InvList[j]._iClass != ITYPE_NONE && plr[i].InvList[j]._itype == ITYPE_AXE && res < plr[i].InvList[j]._iIvalue) res = plr[i].InvList[j]._iIvalue; } return res; } int items_get_currlevel() { int lvl; lvl = currlevel; if (currlevel >= 17 && currlevel <= 20) lvl = currlevel - 8; if (currlevel >= 21 && currlevel <= 24) lvl = currlevel - 7; return lvl; } #endif void InitItemGFX() { #ifdef HELLFIRE DWORD i; #else int i; #endif char arglist[64]; for (i = 0; i < ITEMTYPES; i++) { sprintf(arglist, "Items\\%s.CEL", ItemDropNames[i]); itemanims[i] = LoadFileInMem(arglist, NULL); } memset(UniqueItemFlag, 0, sizeof(UniqueItemFlag)); } BOOL ItemPlace(int xp, int yp) { if (dMonster[xp][yp] != 0) return FALSE; if (dPlayer[xp][yp] != 0) return FALSE; if (dItem[xp][yp] != 0) return FALSE; if (dObject[xp][yp] != 0) return FALSE; if (dFlags[xp][yp] & BFLAG_POPULATED) return FALSE; if (nSolidTable[dPiece[xp][yp]]) return FALSE; return TRUE; } void AddInitItems() { int x, y, i, j, rnd; #ifdef HELLFIRE int curlv = items_get_currlevel(); #endif rnd = random_(11, 3) + 3; for (j = 0; j < rnd; j++) { i = itemavail[0]; itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = i; x = random_(12, 80) + 16; y = random_(12, 80) + 16; while (!ItemPlace(x, y)) { x = random_(12, 80) + 16; y = random_(12, 80) + 16; } item[i]._ix = x; item[i]._iy = y; dItem[x][y] = i + 1; item[i]._iSeed = GetRndSeed(); SetRndSeed(item[i]._iSeed); #ifdef HELLFIRE if (random_(12, 2) != 0) GetItemAttrs(i, IDI_HEAL, curlv); else GetItemAttrs(i, IDI_MANA, curlv); item[i]._iCreateInfo = curlv + CF_PREGEN; #else if (random_(12, 2) != 0) GetItemAttrs(i, IDI_HEAL, currlevel); else GetItemAttrs(i, IDI_MANA, currlevel); item[i]._iCreateInfo = currlevel + CF_PREGEN; #endif SetupItem(i); item[i]._iAnimFrame = item[i]._iAnimLen; item[i]._iAnimFlag = FALSE; item[i]._iSelFlag = 1; DeltaAddItem(i); numitems++; } } #ifdef HELLFIRE static void SpawnNote() { int x, y, id; x = random_(12, 80) + 16; y = random_(12, 80) + 16; while (!ItemPlace(x, y)) { x = random_(12, 80) + 16; y = random_(12, 80) + 16; } switch (currlevel) { case 22: id = IDI_NOTE2; break; case 23: id = IDI_NOTE3; break; default: id = IDI_NOTE1; break; } SpawnQuestItem(id, x, y, 0, 1); } #endif void InitItems() { int i; long s; GetItemAttrs(0, IDI_GOLD, 1); golditem = item[0]; golditem._iStatFlag = TRUE; numitems = 0; for (i = 0; i < MAXITEMS; i++) { item[i]._itype = ITYPE_MISC; // BUGFIX Should be ITYPE_NONE item[i]._ix = 0; item[i]._iy = 0; item[i]._iAnimFlag = FALSE; item[i]._iSelFlag = 0; item[i]._iIdentified = FALSE; item[i]._iPostDraw = FALSE; } for (i = 0; i < MAXITEMS; i++) { itemavail[i] = i; itemactive[i] = 0; } if (!setlevel) { s = GetRndSeed(); /* unused */ if (QuestStatus(Q_ROCK)) SpawnRock(); if (QuestStatus(Q_ANVIL)) SpawnQuestItem(IDI_ANVIL, 2 * setpc_x + 27, 2 * setpc_y + 27, 0, 1); #ifdef HELLFIRE if (UseCowFarmer && currlevel == 20) SpawnQuestItem(IDI_BROWNSUIT, 25, 25, 3, 1); if (UseCowFarmer && currlevel == 19) SpawnQuestItem(IDI_GREYSUIT, 25, 25, 3, 1); #endif if (currlevel > 0 && currlevel < 16) AddInitItems(); #ifdef HELLFIRE if (currlevel >= 21 && currlevel <= 23) SpawnNote(); #endif } uitemflag = FALSE; // BUGFIX: item get records not reset when resetting items. } void CalcPlrItemVals(int p, BOOL Loadgfx) { int pvid, d; 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 = ISPL_NONE; // item_special_effect flags #ifdef HELLFIRE int pDamAcFlags = 0; #endif int sadd = 0; // added strength int madd = 0; // added magic int dadd = 0; // added dexterity int vadd = 0; // added vitality unsigned __int64 spl = 0; // bitarray for all enabled/active spells int fr = 0; // fire resistance int lr = 0; // lightning resistance int mr = 0; // magic resistance int dmod = 0; // bonus damage mod? int ghit = 0; // increased damage from enemies 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 for (i = 0; i < NUM_INVLOC; i++) { ItemStruct *itm = &plr[p].InvBody[i]; if (itm->_itype != ITYPE_NONE && itm->_iStatFlag) { mind += itm->_iMinDam; maxd += itm->_iMaxDam; tac += itm->_iAC; if (itm->_iSpell != SPL_NULL) { spl |= SPELLBIT(itm->_iSpell); } if (itm->_iMagical == ITEM_QUALITY_NORMAL || itm->_iIdentified) { bdam += itm->_iPLDam; btohit += itm->_iPLToHit; if (itm->_iPLAC) { int tmpac = itm->_iAC; tmpac *= itm->_iPLAC; tmpac /= 100; if (tmpac == 0) tmpac = 1; bac += tmpac; } iflgs |= itm->_iFlags; #ifdef HELLFIRE pDamAcFlags |= itm->_iDamAcFlags; #endif sadd += itm->_iPLStr; madd += itm->_iPLMag; dadd += itm->_iPLDex; vadd += itm->_iPLVit; fr += itm->_iPLFR; lr += itm->_iPLLR; mr += itm->_iPLMR; dmod += itm->_iPLDamMod; 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[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) { maxd = 3; } if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) { maxd = 3; } #ifdef HELLFIRE if (plr[p]._pClass == PC_MONK) { mind = max(mind, plr[p]._pLevel >> 1); maxd = max(maxd, plr[p]._pLevel); } #endif } #ifdef HELLFIRE if ((plr[p]._pSpellFlags & 2) == 2) { sadd += 2 * plr[p]._pLevel; dadd += plr[p]._pLevel + plr[p]._pLevel / 2; vadd += 2 * plr[p]._pLevel; } if ((plr[p]._pSpellFlags & 4) == 4) { sadd -= 2 * plr[p]._pLevel; dadd -= plr[p]._pLevel + plr[p]._pLevel / 2; vadd -= 2 * plr[p]._pLevel; } #endif plr[p]._pIMinDam = mind; plr[p]._pIMaxDam = maxd; plr[p]._pIAC = tac; plr[p]._pIBonusDam = bdam; plr[p]._pIBonusToHit = btohit; plr[p]._pIBonusAC = bac; plr[p]._pIFlags = iflgs; #ifdef HELLFIRE plr[p].pDamAcFlags = pDamAcFlags; #endif plr[p]._pIBonusDamMod = dmod; plr[p]._pIGetHit = ghit; if (lrad < 2) { lrad = 2; } if (lrad > 15) { lrad = 15; } if (plr[p]._pLightRad != lrad && p == myplr) { ChangeLightRadius(plr[p]._plid, lrad); if (lrad < 10) { ChangeVisionRadius(plr[p]._pvid, 10); } else { ChangeVisionRadius(plr[p]._pvid, lrad); } 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; } #ifdef HELLFIRE else if (plr[p]._pClass == PC_MONK) { if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_STAFF) { if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_STAFF && (plr[p].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE)) { plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 300; } else { plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 150; } } else { plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 150; } } else if (plr[p]._pClass == PC_BARD) { if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SWORD) plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 150; else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_BOW || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_BOW) { plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 250; } else { plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 100; } } else if (plr[p]._pClass == PC_BARBARIAN) { if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_AXE || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_AXE) { plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 75; } else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_MACE || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_MACE) { plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 75; } else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_BOW || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_BOW) { plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 300; } else { plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 100; } if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD) { if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD) plr[p]._pIAC -= plr[p].InvBody[INVLOC_HAND_LEFT]._iAC / 2; else if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD) plr[p]._pIAC -= plr[p].InvBody[INVLOC_HAND_RIGHT]._iAC / 2; } else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_STAFF && plr[p].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_STAFF && plr[p].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_BOW && plr[p].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_BOW) { plr[p]._pDamageMod += plr[p]._pLevel * plr[p]._pVitality / 100; } plr[p]._pIAC += plr[p]._pLevel / 4; } #endif else { plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 100; } plr[p]._pISpells = spl; // check if the current RSplType is a valid/allowed spell if (plr[p]._pRSplType == RSPLTYPE_CHARGES && !(plr[p]._pISpells & SPELLBIT(plr[p]._pRSpell))) { plr[p]._pRSpell = SPL_INVALID; plr[p]._pRSplType = RSPLTYPE_INVALID; force_redraw = 255; } plr[p]._pISplLvlAdd = spllvladd; plr[p]._pIEnAc = enac; #ifdef HELLFIRE if (plr[p]._pClass == PC_BARBARIAN) { mr += plr[p]._pLevel; fr += plr[p]._pLevel; lr += plr[p]._pLevel; } if ((plr[p]._pSpellFlags & 4) == 4) { mr -= plr[p]._pLevel; fr -= plr[p]._pLevel; lr -= plr[p]._pLevel; } #endif if (iflgs & ISPL_ALLRESZERO) { // reset resistances to zero if the respective special effect is active mr = 0; fr = 0; lr = 0; } if (mr > MAXRESIST) mr = MAXRESIST; #ifdef HELLFIRE else if (mr < 0) mr = 0; #endif plr[p]._pMagResist = mr; if (fr > MAXRESIST) fr = MAXRESIST; #ifdef HELLFIRE else if (fr < 0) fr = 0; #endif plr[p]._pFireResist = fr; if (lr > MAXRESIST) lr = MAXRESIST; #ifdef HELLFIRE else if (lr < 0) lr = 0; #endif plr[p]._pLghtResist = lr; if (plr[p]._pClass == PC_WARRIOR) { vadd <<= 1; } #ifdef HELLFIRE else if (plr[p]._pClass == PC_BARBARIAN) { vadd += vadd; vadd += (vadd >> 2); } else if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK || plr[p]._pClass == PC_BARD) { #else if (plr[p]._pClass == PC_ROGUE) { #endif vadd += vadd >> 1; } ihp += (vadd << 6); if (plr[p]._pClass == PC_SORCERER) { madd <<= 1; } #ifdef HELLFIRE if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK) { #else if (plr[p]._pClass == PC_ROGUE) { #endif madd += madd >> 1; } #ifdef HELLFIRE else if (plr[p]._pClass == PC_BARD) { madd += (madd >> 2) + (madd >> 1); } #endif imana += (madd << 6); plr[p]._pHitPoints = ihp + plr[p]._pHPBase; plr[p]._pMaxHP = ihp + plr[p]._pMaxHPBase; #ifdef HELLFIRE if (plr[p]._pHitPoints > plr[p]._pMaxHP) plr[p]._pHitPoints = plr[p]._pMaxHP; #endif 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; #ifdef HELLFIRE if (plr[p]._pMana > plr[p]._pMaxMana) plr[p]._pMana = plr[p]._pMaxMana; #endif plr[p]._pIFMinDam = fmin; plr[p]._pIFMaxDam = fmax; plr[p]._pILMinDam = lmin; plr[p]._pILMaxDam = lmax; if (iflgs & ISPL_INFRAVISION) { plr[p]._pInfraFlag = TRUE; } else { plr[p]._pInfraFlag = FALSE; } plr[p]._pBlockFlag = FALSE; #ifdef HELLFIRE if (plr[p]._pClass == PC_MONK) { if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_STAFF && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) { plr[p]._pBlockFlag = TRUE; plr[p]._pIFlags |= ISPL_FASTBLOCK; } if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_STAFF && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) { plr[p]._pBlockFlag = TRUE; plr[p]._pIFlags |= ISPL_FASTBLOCK; } if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_NONE && plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_NONE) plr[p]._pBlockFlag = TRUE; if (plr[p].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON && plr[p].InvBody[INVLOC_HAND_LEFT]._iLoc != ILOC_TWOHAND && plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_NONE) plr[p]._pBlockFlag = TRUE; if (plr[p].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON && plr[p].InvBody[INVLOC_HAND_RIGHT]._iLoc != ILOC_TWOHAND && plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_NONE) plr[p]._pBlockFlag = TRUE; } #endif plr[p]._pwtype = WT_MELEE; g = 0; if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE && plr[p].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) { g = plr[p].InvBody[INVLOC_HAND_LEFT]._itype; } if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE && plr[p].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) { g = plr[p].InvBody[INVLOC_HAND_RIGHT]._itype; } switch (g) { case ITYPE_SWORD: g = ANIM_ID_SWORD; break; case ITYPE_AXE: g = ANIM_ID_AXE; break; case ITYPE_BOW: plr[p]._pwtype = WT_RANGED; g = ANIM_ID_BOW; break; case ITYPE_MACE: g = ANIM_ID_MACE; break; case ITYPE_STAFF: g = ANIM_ID_STAFF; break; } if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) { plr[p]._pBlockFlag = TRUE; g++; } if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) { plr[p]._pBlockFlag = TRUE; g++; } #ifndef SPAWN #ifdef HELLFIRE if (plr[p].InvBody[INVLOC_CHEST]._itype == ITYPE_HARMOR && plr[p].InvBody[INVLOC_CHEST]._iStatFlag) { if (plr[p]._pClass == PC_MONK && plr[p].InvBody[INVLOC_CHEST]._iMagical == ITEM_QUALITY_UNIQUE) plr[p]._pIAC += plr[p]._pLevel >> 1; g += ANIM_ID_HEAVY_ARMOR; } else if (plr[p].InvBody[INVLOC_CHEST]._itype == ITYPE_MARMOR && plr[p].InvBody[INVLOC_CHEST]._iStatFlag) { if (plr[p]._pClass == PC_MONK) { if (plr[p].InvBody[INVLOC_CHEST]._iMagical == ITEM_QUALITY_UNIQUE) plr[p]._pIAC += plr[p]._pLevel << 1; else plr[p]._pIAC += plr[p]._pLevel >> 1; } g += ANIM_ID_MEDIUM_ARMOR; } else if (plr[p]._pClass == PC_MONK) { plr[p]._pIAC += plr[p]._pLevel << 1; } #else if (plr[p].InvBody[INVLOC_CHEST]._itype == ITYPE_MARMOR && plr[p].InvBody[INVLOC_CHEST]._iStatFlag) { g += ANIM_ID_MEDIUM_ARMOR; } if (plr[p].InvBody[INVLOC_CHEST]._itype == ITYPE_HARMOR && plr[p].InvBody[INVLOC_CHEST]._iStatFlag) { g += ANIM_ID_HEAVY_ARMOR; } #endif #endif if (plr[p]._pgfxnum != g && Loadgfx) { plr[p]._pgfxnum = g; plr[p]._pGFXLoad = 0; LoadPlrGFX(p, PFILE_STAND); SetPlrAnims(p); d = plr[p]._pdir; assert(plr[p]._pNAnim[d]); 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 == MIS_MANASHIELD && missile[mi]._misource == p) { missile[mi]._miVar1 = plr[p]._pHitPoints; missile[mi]._miVar2 = plr[p]._pHPBase; #ifdef HELLFIRE break; #endif } } #ifdef HELLFIRE if (plr[p].InvBody[INVLOC_AMULET]._itype == ITYPE_NONE || plr[p].InvBody[INVLOC_AMULET].IDidx != IDI_AURIC) { int half = MaxGold; MaxGold = auricGold / 2; if (half != MaxGold) StripTopGold(p); } else { MaxGold = auricGold; } #endif drawmanaflag = TRUE; drawhpflag = TRUE; } void CalcPlrScrolls(int p) { int i, j; plr[p]._pScrlSpells = 0; for (i = 0; i < plr[p]._pNumInv; i++) { if (plr[p].InvList[i]._itype != ITYPE_NONE && (plr[p].InvList[i]._iMiscId == IMISC_SCROLL || plr[p].InvList[i]._iMiscId == IMISC_SCROLLT)) { if (plr[p].InvList[i]._iStatFlag) plr[p]._pScrlSpells |= SPELLBIT(plr[p].InvList[i]._iSpell); } } for (j = 0; j < MAXBELTITEMS; j++) { if (plr[p].SpdList[j]._itype != ITYPE_NONE && (plr[p].SpdList[j]._iMiscId == IMISC_SCROLL || plr[p].SpdList[j]._iMiscId == IMISC_SCROLLT)) { if (plr[p].SpdList[j]._iStatFlag) plr[p]._pScrlSpells |= SPELLBIT(plr[p].SpdList[j]._iSpell); } } if (plr[p]._pRSplType == RSPLTYPE_SCROLL) { if (!(plr[p]._pScrlSpells & 1 << (plr[p]._pRSpell - 1))) { // BUGFIX: apply SPELLBIT macro plr[p]._pRSpell = SPL_INVALID; plr[p]._pRSplType = RSPLTYPE_INVALID; force_redraw = 255; } } } void CalcPlrStaff(int p) { plr[p]._pISpells = 0; if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag && plr[p].InvBody[INVLOC_HAND_LEFT]._iCharges > 0) { plr[p]._pISpells |= SPELLBIT(plr[p].InvBody[INVLOC_HAND_LEFT]._iSpell); } } void CalcSelfItems(int pnum) { int i; PlayerStruct *p; ItemStruct *pi; BOOL sf, changeflag; int sa, ma, da; p = &plr[pnum]; sa = 0; ma = 0; da = 0; pi = p->InvBody; for (i = 0; i < NUM_INVLOC; i++, pi++) { if (pi->_itype != ITYPE_NONE) { pi->_iStatFlag = TRUE; if (pi->_iIdentified) { sa += pi->_iPLStr; ma += pi->_iPLMag; da += pi->_iPLDex; } } } do { changeflag = FALSE; pi = p->InvBody; for (i = 0; i < NUM_INVLOC; i++, pi++) { if (pi->_itype != ITYPE_NONE && pi->_iStatFlag) { sf = TRUE; if (sa + p->_pBaseStr < pi->_iMinStr) sf = FALSE; if (ma + p->_pBaseMag < pi->_iMinMag) sf = FALSE; if (da + p->_pBaseDex < pi->_iMinDex) sf = FALSE; if (!sf) { changeflag = TRUE; pi->_iStatFlag = FALSE; if (pi->_iIdentified) { sa -= pi->_iPLStr; ma -= pi->_iPLMag; da -= pi->_iPLDex; } } } } } while (changeflag); } static BOOL ItemMinStats(PlayerStruct *p, ItemStruct *x) { if (p->_pMagic < x->_iMinMag) return FALSE; if (p->_pStrength < x->_iMinStr) return FALSE; if (p->_pDexterity < x->_iMinDex) return FALSE; return TRUE; } void CalcPlrItemMin(int pnum) { PlayerStruct *p; ItemStruct *pi; int i; p = &plr[pnum]; pi = p->InvList; i = p->_pNumInv; while (i--) { pi->_iStatFlag = ItemMinStats(p, pi); pi++; } pi = p->SpdList; for (i = MAXBELTITEMS; i != 0; i--) { if (pi->_itype != ITYPE_NONE) { pi->_iStatFlag = ItemMinStats(p, pi); } pi++; } } void CalcPlrBookVals(int p) { int i, slvl; if (currlevel == 0) { for (i = 1; witchitem[i]._itype != ITYPE_NONE; i++) { WitchBookLevel(i); #ifndef HELLFIRE witchitem[i]._iStatFlag = StoreStatOk(&witchitem[i]); #endif } } for (i = 0; i < plr[p]._pNumInv; i++) { if (plr[p].InvList[i]._itype == ITYPE_MISC && plr[p].InvList[i]._iMiscId == IMISC_BOOK) { plr[p].InvList[i]._iMinMag = spelldata[plr[p].InvList[i]._iSpell].sMinInt; slvl = plr[p]._pSplLvl[plr[p].InvList[i]._iSpell]; while (slvl != 0) { plr[p].InvList[i]._iMinMag += 20 * plr[p].InvList[i]._iMinMag / 100; slvl--; if (plr[p].InvList[i]._iMinMag + 20 * plr[p].InvList[i]._iMinMag / 100 > 255) { plr[p].InvList[i]._iMinMag = 255; slvl = 0; } } plr[p].InvList[i]._iStatFlag = ItemMinStats(&plr[p], &plr[p].InvList[i]); } } } void 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 == 0) RecalcStoreStats(); } } void 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) { #ifdef HELLFIRE h->_iCharges = 18; #else h->_iCharges = 40; #endif } 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 = ITEM_QUALITY_NORMAL; h->IDidx = idata; } void GetPlrHandSeed(ItemStruct *h) { h->_iSeed = GetRndSeed(); } void GetGoldSeed(int pnum, ItemStruct *h) { int i, ii, s; BOOL doneflag; do { doneflag = TRUE; s = GetRndSeed(); for (i = 0; i < numitems; i++) { ii = itemactive[i]; if (item[ii]._iSeed == s) doneflag = FALSE; } if (pnum == myplr) { for (i = 0; i < plr[pnum]._pNumInv; i++) { if (plr[pnum].InvList[i]._iSeed == s) doneflag = FALSE; } } } while (!doneflag); h->_iSeed = s; } void SetPlrHandSeed(ItemStruct *h, int iseed) { h->_iSeed = iseed; } void SetPlrHandGoldCurs(ItemStruct *h) { if (h->_ivalue >= GOLD_MEDIUM_LIMIT) h->_iCurs = ICURS_GOLD_LARGE; else if (h->_ivalue <= GOLD_SMALL_LIMIT) h->_iCurs = ICURS_GOLD_SMALL; else h->_iCurs = ICURS_GOLD_MEDIUM; } void CreatePlrItems(int p) { int i; ItemStruct *pi = plr[p].InvBody; for (i = NUM_INVLOC; i != 0; i--) { pi->_itype = ITYPE_NONE; pi++; } // 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 = NUM_INV_GRID_ELEM; i != 0; i--) { pi->_itype = ITYPE_NONE; pi++; } plr[p]._pNumInv = 0; pi = &plr[p].SpdList[0]; for (i = MAXBELTITEMS; i != 0; i--) { pi->_itype = ITYPE_NONE; pi++; } 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]); #ifdef _DEBUG if (!debug_mode_key_w) { #endif SetPlrHandItem(&plr[p].HoldItem, IDI_WARRCLUB); GetPlrHandSeed(&plr[p].HoldItem); AutoPlace(p, 0, 1, 3, TRUE); #ifdef _DEBUG } #endif 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; #ifndef SPAWN 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]); #ifdef HELLFIRE SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL); GetPlrHandSeed(&plr[p].SpdList[0]); SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL); GetPlrHandSeed(&plr[p].SpdList[1]); #else SetPlrHandItem(&plr[p].SpdList[0], IDI_MANA); GetPlrHandSeed(&plr[p].SpdList[0]); SetPlrHandItem(&plr[p].SpdList[1], IDI_MANA); GetPlrHandSeed(&plr[p].SpdList[1]); #endif break; #endif #ifdef HELLFIRE case PC_MONK: SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_SHORTSTAFF); 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_BARD: SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_BARDSWORD); GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]); SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_RIGHT], IDI_BARDDAGGER); GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_RIGHT]); 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_BARBARIAN: SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], 139); // TODO: add more enums to items GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]); SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_RIGHT], IDI_WARRSHLD); GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_RIGHT]); 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; #endif } SetPlrHandItem(&plr[p].HoldItem, IDI_GOLD); GetPlrHandSeed(&plr[p].HoldItem); #ifdef _DEBUG if (!debug_mode_key_w) { #endif plr[p].HoldItem._ivalue = 100; plr[p].HoldItem._iCurs = ICURS_GOLD_SMALL; plr[p]._pGold = plr[p].HoldItem._ivalue; plr[p].InvList[plr[p]._pNumInv++] = plr[p].HoldItem; plr[p].InvGrid[30] = plr[p]._pNumInv; #ifdef _DEBUG } else { plr[p].HoldItem._ivalue = GOLD_MAX_LIMIT; plr[p].HoldItem._iCurs = ICURS_GOLD_LARGE; plr[p]._pGold = plr[p].HoldItem._ivalue * 40; for (i = 0; i < NUM_INV_GRID_ELEM; i++) { GetPlrHandSeed(&plr[p].HoldItem); plr[p].InvList[plr[p]._pNumInv++] = plr[p].HoldItem; plr[p].InvGrid[i] = plr[p]._pNumInv; } } #endif CalcPlrItemVals(p, FALSE); } BOOL ItemSpaceOk(int i, int j) { int oi; if (i < 0 || i >= MAXDUNX || j < 0 || j >= MAXDUNY) return FALSE; if (dMonster[i][j] != 0) return FALSE; if (dPlayer[i][j] != 0) return FALSE; if (dItem[i][j] != 0) return FALSE; if (dObject[i][j] != 0) { oi = dObject[i][j] > 0 ? dObject[i][j] - 1 : -(dObject[i][j] + 1); if (object[oi]._oSolidFlag) return FALSE; } if (dObject[i + 1][j + 1] > 0 && object[dObject[i + 1][j + 1] - 1]._oSelFlag != 0) /// BUGFIX: check for dObject OOB return FALSE; if (dObject[i + 1][j + 1] < 0 && object[-(dObject[i + 1][j + 1] + 1)]._oSelFlag != 0) /// BUGFIX: check for dObject OOB return FALSE; if (dObject[i + 1][j] > 0 /// BUGFIX: check for dObject OOB && dObject[i][j + 1] > 0 /// BUGFIX: check for dObject OOB && object[dObject[i + 1][j] - 1]._oSelFlag != 0 && object[dObject[i][j + 1] - 1]._oSelFlag != 0) { return FALSE; } return !nSolidTable[dPiece[i][j]]; } BOOL GetItemSpace(int x, int y, char inum) { int i, j, rs; int xx, yy; BOOL savail; yy = 0; for (j = y - 1; j <= y + 1; j++) { xx = 0; for (i = x - 1; i <= x + 1; i++) { itemhold[xx][yy] = ItemSpaceOk(i, j); xx++; } yy++; } savail = FALSE; for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) { if (itemhold[i][j]) savail = TRUE; } } rs = random_(13, 15) + 1; if (!savail) return FALSE; xx = 0; yy = 0; while (rs > 0) { if (itemhold[xx][yy]) rs--; if (rs > 0) { xx++; if (xx == 3) { xx = 0; yy++; if (yy == 3) yy = 0; } } } xx += x - 1; yy += y - 1; item[inum]._ix = xx; item[inum]._iy = yy; dItem[xx][yy] = inum + 1; return TRUE; } void GetSuperItemSpace(int x, int y, char inum) { int xx, yy; int i, j, k; if (!GetItemSpace(x, y, inum)) { for (k = 2; k < 50; k++) { for (j = -k; j <= k; j++) { yy = y + j; for (i = -k; i <= k; i++) { xx = i + x; if (ItemSpaceOk(xx, yy)) { item[inum]._ix = xx; item[inum]._iy = yy; dItem[xx][yy] = inum + 1; return; } } } } } } void GetSuperItemLoc(int x, int y, int &xx, int &yy) { int i, j, k; for (k = 1; k < 50; k++) { for (j = -k; j <= k; j++) { yy = y + j; for (i = -k; i <= k; i++) { xx = i + x; if (ItemSpaceOk(xx, yy)) { return; } } } } } void CalcItemValue(int i) { int v; v = item[i]._iVMult1 + item[i]._iVMult2; if (v > 0) { v *= item[i]._ivalue; } if (v < 0) { v = item[i]._ivalue / v; } v = item[i]._iVAdd1 + item[i]._iVAdd2 + v; if (v <= 0) { v = 1; } item[i]._iIvalue = v; } void GetBookSpell(int i, int lvl) { int rv, s, bs; if (lvl == 0) lvl = 1; rv = random_(14, MAX_SPELLS) + 1; #ifdef SPAWN if (lvl > 5) lvl = 5; #endif s = SPL_FIREBOLT; #ifdef HELLFIRE bs = SPL_FIREBOLT; #endif while (rv > 0) { if (spelldata[s].sBookLvl != -1 && lvl >= spelldata[s].sBookLvl) { rv--; bs = s; } s++; if (gbMaxPlayers == 1) { if (s == SPL_RESURRECT) s = SPL_TELEKINESIS; } if (gbMaxPlayers == 1) { if (s == SPL_HEALOTHER) s = SPL_FLARE; } if (s == MAX_SPELLS) s = 1; } strcat(item[i]._iName, spelldata[bs].sNameText); strcat(item[i]._iIName, spelldata[bs].sNameText); item[i]._iSpell = bs; item[i]._iMinMag = spelldata[bs].sMinInt; item[i]._ivalue += spelldata[bs].sBookCost; item[i]._iIvalue += spelldata[bs].sBookCost; if (spelldata[bs].sType == STYPE_FIRE) item[i]._iCurs = ICURS_BOOK_RED; #ifdef HELLFIRE else #endif if (spelldata[bs].sType == STYPE_LIGHTNING) item[i]._iCurs = ICURS_BOOK_BLUE; #ifdef HELLFIRE else #endif if (spelldata[bs].sType == STYPE_MAGIC) item[i]._iCurs = ICURS_BOOK_GREY; } void GetStaffPower(int i, int lvl, int bs, BOOL onlygood) { int l[256]; char istr[128]; int nl, j, preidx; BOOL addok; int tmp; tmp = random_(15, 10); preidx = -1; if (tmp == 0 || onlygood) { nl = 0; for (j = 0; PL_Prefix[j].PLPower != IPL_INVALID; j++) { if (PL_Prefix[j].PLIType & PLT_STAFF && PL_Prefix[j].PLMinLvl <= lvl) { addok = TRUE; if (onlygood && !PL_Prefix[j].PLOk) addok = FALSE; if (addok) { l[nl] = j; nl++; if (PL_Prefix[j].PLDouble) { l[nl] = j; nl++; } } } } if (nl != 0) { preidx = l[random_(16, nl)]; sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, item[i]._iIName); strcpy(item[i]._iIName, istr); item[i]._iMagical = ITEM_QUALITY_MAGIC; 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); item[i]._iPrePower = PL_Prefix[preidx].PLPower; } } if (!control_WriteStringToBuffer((BYTE *)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); } sprintf(istr, "%s of %s", item[i]._iIName, spelldata[bs].sNameText); strcpy(item[i]._iIName, istr); if (item[i]._iMagical == ITEM_QUALITY_NORMAL) strcpy(item[i]._iName, item[i]._iIName); } CalcItemValue(i); } void GetStaffSpell(int i, int lvl, BOOL onlygood) { int l, rv, s, minc, maxc, v, bs; char istr[64]; #ifndef HELLFIRE if (random_(17, 4) == 0) { GetItemPower(i, lvl >> 1, lvl, PLT_STAFF, onlygood); } else #endif { l = lvl >> 1; if (l == 0) l = 1; rv = random_(18, MAX_SPELLS) + 1; #ifdef SPAWN if (lvl > 10) lvl = 10; #endif s = SPL_FIREBOLT; while (rv > 0) { if (spelldata[s].sStaffLvl != -1 && l >= spelldata[s].sStaffLvl) { rv--; bs = s; } s++; if (gbMaxPlayers == 1 && s == SPL_RESURRECT) s = SPL_TELEKINESIS; if (gbMaxPlayers == 1 && s == SPL_HEALOTHER) s = SPL_FLARE; if (s == MAX_SPELLS) s = SPL_FIREBOLT; } sprintf(istr, "%s of %s", item[i]._iName, spelldata[bs].sNameText); if (!control_WriteStringToBuffer((BYTE *)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; item[i]._iCharges = minc + random_(19, maxc); item[i]._iMaxCharges = item[i]._iCharges; item[i]._iMinMag = spelldata[bs].sMinInt; v = item[i]._iCharges * spelldata[bs].sStaffCost / 5; item[i]._ivalue += v; item[i]._iIvalue += v; GetStaffPower(i, lvl, bs, onlygood); } } #ifdef HELLFIRE void GetOilType(int i, int max_lvl) { int cnt, t, j, r; char rnd[32]; if (gbMaxPlayers == 1) { if (max_lvl == 0) max_lvl = 1; cnt = 0; for (j = 0; j < (int)(sizeof(OilLevels) / sizeof(OilLevels[0])); j++) { if (OilLevels[j] <= max_lvl) { rnd[cnt] = j; cnt++; } } r = random_(165, cnt); t = rnd[r]; } else { r = random_(165, 2); t = (r != 0 ? 6 : 5); } strcpy(item[i]._iName, OilNames[t]); strcpy(item[i]._iIName, OilNames[t]); item[i]._iMiscId = OilMagic[t]; item[i]._ivalue = OilValues[t]; item[i]._iIvalue = OilValues[t]; } #endif void GetItemAttrs(int i, int idata, int lvl) { int rndv; #ifdef HELLFIRE int itemlevel; #endif 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]._iAC = AllItemsList[idata].iMinAC + random_(20, AllItemsList[idata].iMaxAC - AllItemsList[idata].iMinAC + 1); #ifndef HELLFIRE item[i]._iFlags = AllItemsList[idata].iFlags; #endif item[i]._iMiscId = AllItemsList[idata].iMiscId; item[i]._iSpell = AllItemsList[idata].iSpell; item[i]._iMagical = ITEM_QUALITY_NORMAL; item[i]._ivalue = AllItemsList[idata].iValue; item[i]._iIvalue = AllItemsList[idata].iValue; item[i]._iVAdd1 = 0; 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]._iDurability = AllItemsList[idata].iDurability; item[i]._iMaxDur = AllItemsList[idata].iDurability; item[i]._iMinStr = AllItemsList[idata].iMinStr; item[i]._iMinMag = AllItemsList[idata].iMinMag; item[i]._iMinDex = AllItemsList[idata].iMinDex; 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]._iRequest = FALSE; 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; item[i]._iPrePower = -1; item[i]._iSufPower = -1; #ifndef HELLFIRE if (item[i]._iMiscId == IMISC_BOOK) GetBookSpell(i, lvl); if (item[i]._itype == ITYPE_GOLD) { if (gnDifficulty == DIFF_NORMAL) 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)); #else item[i]._iFlags = 0; item[i]._iDamAcFlags = 0; if (item[i]._iMiscId == IMISC_BOOK) GetBookSpell(i, lvl); if (item[i]._iMiscId == IMISC_OILOF) GetOilType(i, lvl); itemlevel = items_get_currlevel(); if (item[i]._itype == ITYPE_GOLD) { if (gnDifficulty == DIFF_NORMAL) rndv = 5 * itemlevel + random_(21, 10 * itemlevel); else if (gnDifficulty == DIFF_NIGHTMARE) rndv = 5 * (itemlevel + 16) + random_(21, 10 * (itemlevel + 16)); else if (gnDifficulty == DIFF_HELL) rndv = 5 * (itemlevel + 32) + random_(21, 10 * (itemlevel + 32)); #endif if (leveltype == DTYPE_HELL) rndv += rndv >> 3; if (rndv > GOLD_MAX_LIMIT) rndv = GOLD_MAX_LIMIT; item[i]._ivalue = rndv; if (rndv >= GOLD_MEDIUM_LIMIT) item[i]._iCurs = ICURS_GOLD_LARGE; else item[i]._iCurs = (rndv > GOLD_SMALL_LIMIT) + 4; } } int RndPL(int param1, int param2) { return param1 + random_(22, param2 - param1 + 1); } int 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 SaveItemPower(int i, int power, int param1, int param2, int minval, int maxval, int multval) { int r, r2; r = RndPL(param1, param2); switch (power) { case IPL_TOHIT: item[i]._iPLToHit += r; break; case IPL_TOHIT_CURSE: item[i]._iPLToHit -= r; break; case IPL_DAMP: item[i]._iPLDam += r; break; case IPL_DAMP_CURSE: item[i]._iPLDam -= r; break; #ifdef HELLFIRE case IPL_DOPPELGANGER: item[i]._iDamAcFlags |= ISPLHF_DOPPELGANGER; // no break #endif case IPL_TOHIT_DAMP: r = RndPL(param1, param2); item[i]._iPLDam += r; if (param1 == 20) r2 = RndPL(1, 5); if (param1 == 36) r2 = RndPL(6, 10); if (param1 == 51) r2 = RndPL(11, 15); if (param1 == 66) r2 = RndPL(16, 20); if (param1 == 81) r2 = RndPL(21, 30); if (param1 == 96) r2 = RndPL(31, 40); if (param1 == 111) r2 = RndPL(41, 50); if (param1 == 126) r2 = RndPL(51, 75); if (param1 == 151) r2 = RndPL(76, 100); item[i]._iPLToHit += r2; break; case IPL_TOHIT_DAMP_CURSE: item[i]._iPLDam -= r; if (param1 == 25) r2 = RndPL(1, 5); if (param1 == 50) r2 = RndPL(6, 10); item[i]._iPLToHit -= r2; break; case IPL_ACP: item[i]._iPLAC += r; break; case IPL_ACP_CURSE: item[i]._iPLAC -= r; break; case IPL_SETAC: item[i]._iAC = r; break; case IPL_AC_CURSE: item[i]._iAC -= r; break; case IPL_FIRERES: item[i]._iPLFR += r; break; case IPL_LIGHTRES: item[i]._iPLLR += r; break; case IPL_MAGICRES: item[i]._iPLMR += r; break; case IPL_ALLRES: item[i]._iPLFR += r; item[i]._iPLLR += r; item[i]._iPLMR += r; if (item[i]._iPLFR < 0) item[i]._iPLFR = 0; if (item[i]._iPLLR < 0) item[i]._iPLLR = 0; if (item[i]._iPLMR < 0) item[i]._iPLMR = 0; break; case IPL_SPLLVLADD: item[i]._iSplLvlAdd = r; break; case IPL_CHARGES: item[i]._iCharges *= param1; item[i]._iMaxCharges = item[i]._iCharges; break; case IPL_SPELL: item[i]._iSpell = param1; #ifdef HELLFIRE item[i]._iCharges = param2; #else item[i]._iCharges = param1; // BUGFIX: should be param2. This code was correct in v1.04, and the bug was introduced between 1.04 and 1.09b. #endif item[i]._iMaxCharges = param2; break; case IPL_FIREDAM: item[i]._iFlags |= ISPL_FIREDAM; #ifdef HELLFIRE item[i]._iFlags &= ~ISPL_LIGHTDAM; #endif item[i]._iFMinDam = param1; item[i]._iFMaxDam = param2; #ifdef HELLFIRE item[i]._iLMinDam = 0; item[i]._iLMaxDam = 0; #endif break; case IPL_LIGHTDAM: item[i]._iFlags |= ISPL_LIGHTDAM; #ifdef HELLFIRE item[i]._iFlags &= ~ISPL_FIREDAM; #endif item[i]._iLMinDam = param1; item[i]._iLMaxDam = param2; #ifdef HELLFIRE item[i]._iFMinDam = 0; item[i]._iFMaxDam = 0; #endif break; case IPL_STR: item[i]._iPLStr += r; break; case IPL_STR_CURSE: item[i]._iPLStr -= r; break; case IPL_MAG: item[i]._iPLMag += r; break; case IPL_MAG_CURSE: item[i]._iPLMag -= r; break; case IPL_DEX: item[i]._iPLDex += r; break; case IPL_DEX_CURSE: item[i]._iPLDex -= r; break; case IPL_VIT: item[i]._iPLVit += r; break; case IPL_VIT_CURSE: item[i]._iPLVit -= r; break; case IPL_ATTRIBS: item[i]._iPLStr += r; item[i]._iPLMag += r; item[i]._iPLDex += r; item[i]._iPLVit += r; break; case IPL_ATTRIBS_CURSE: item[i]._iPLStr -= r; item[i]._iPLMag -= r; item[i]._iPLDex -= r; item[i]._iPLVit -= r; break; case IPL_GETHIT_CURSE: item[i]._iPLGetHit += r; break; case IPL_GETHIT: item[i]._iPLGetHit -= r; break; case IPL_LIFE: item[i]._iPLHP += r << 6; break; case IPL_LIFE_CURSE: item[i]._iPLHP -= r << 6; break; case IPL_MANA: item[i]._iPLMana += r << 6; drawmanaflag = TRUE; break; case IPL_MANA_CURSE: item[i]._iPLMana -= r << 6; drawmanaflag = TRUE; break; case IPL_DUR: r2 = r * item[i]._iMaxDur / 100; item[i]._iMaxDur += r2; item[i]._iDurability += r2; break; #ifdef HELLFIRE case IPL_CRYSTALLINE: item[i]._iPLDam += 140 + r * 2; // no break #endif case IPL_DUR_CURSE: item[i]._iMaxDur -= r * item[i]._iMaxDur / 100; if (item[i]._iMaxDur < 1) item[i]._iMaxDur = 1; item[i]._iDurability = item[i]._iMaxDur; break; case IPL_INDESTRUCTIBLE: item[i]._iDurability = DUR_INDESTRUCTIBLE; item[i]._iMaxDur = DUR_INDESTRUCTIBLE; break; case IPL_LIGHT: item[i]._iPLLight += param1; break; case IPL_LIGHT_CURSE: item[i]._iPLLight -= param1; break; #ifdef HELLFIRE case IPL_MULT_ARROWS: item[i]._iFlags |= ISPL_MULT_ARROWS; break; #endif case IPL_FIRE_ARROWS: item[i]._iFlags |= ISPL_FIRE_ARROWS; #ifdef HELLFIRE item[i]._iFlags &= ~ISPL_LIGHT_ARROWS; #endif item[i]._iFMinDam = param1; item[i]._iFMaxDam = param2; #ifdef HELLFIRE item[i]._iLMinDam = 0; item[i]._iLMaxDam = 0; #endif break; case IPL_LIGHT_ARROWS: item[i]._iFlags |= ISPL_LIGHT_ARROWS; #ifdef HELLFIRE item[i]._iFlags &= ~ISPL_FIRE_ARROWS; #endif item[i]._iLMinDam = param1; item[i]._iLMaxDam = param2; #ifdef HELLFIRE item[i]._iFMinDam = 0; item[i]._iFMaxDam = 0; #endif break; #ifdef HELLFIRE case IPL_FIREBALL: item[i]._iFlags |= (ISPL_LIGHT_ARROWS | ISPL_FIRE_ARROWS); item[i]._iFMinDam = param1; item[i]._iFMaxDam = param2; item[i]._iLMinDam = 0; item[i]._iLMaxDam = 0; break; #endif case IPL_THORNS: item[i]._iFlags |= ISPL_THORNS; break; case IPL_NOMANA: item[i]._iFlags |= ISPL_NOMANA; drawmanaflag = TRUE; break; case IPL_NOHEALPLR: item[i]._iFlags |= ISPL_NOHEALPLR; break; case IPL_ABSHALFTRAP: item[i]._iFlags |= ISPL_ABSHALFTRAP; break; case IPL_KNOCKBACK: item[i]._iFlags |= ISPL_KNOCKBACK; break; case IPL_3XDAMVDEM: item[i]._iFlags |= ISPL_3XDAMVDEM; break; case IPL_ALLRESZERO: item[i]._iFlags |= ISPL_ALLRESZERO; break; case IPL_NOHEALMON: item[i]._iFlags |= ISPL_NOHEALMON; break; case IPL_STEALMANA: if (param1 == 3) item[i]._iFlags |= ISPL_STEALMANA_3; if (param1 == 5) item[i]._iFlags |= ISPL_STEALMANA_5; drawmanaflag = TRUE; break; case IPL_STEALLIFE: if (param1 == 3) item[i]._iFlags |= ISPL_STEALLIFE_3; if (param1 == 5) item[i]._iFlags |= ISPL_STEALLIFE_5; drawhpflag = TRUE; break; case IPL_TARGAC: #ifdef HELLFIRE item[i]._iPLEnAc = param1; #else item[i]._iPLEnAc += r; #endif break; case IPL_FASTATTACK: if (param1 == 1) item[i]._iFlags |= ISPL_QUICKATTACK; if (param1 == 2) item[i]._iFlags |= ISPL_FASTATTACK; if (param1 == 3) item[i]._iFlags |= ISPL_FASTERATTACK; if (param1 == 4) item[i]._iFlags |= ISPL_FASTESTATTACK; break; case IPL_FASTRECOVER: if (param1 == 1) item[i]._iFlags |= ISPL_FASTRECOVER; if (param1 == 2) item[i]._iFlags |= ISPL_FASTERRECOVER; if (param1 == 3) item[i]._iFlags |= ISPL_FASTESTRECOVER; break; case IPL_FASTBLOCK: item[i]._iFlags |= ISPL_FASTBLOCK; break; case IPL_DAMMOD: item[i]._iPLDamMod += r; break; case IPL_RNDARROWVEL: item[i]._iFlags |= ISPL_RNDARROWVEL; break; case IPL_SETDAM: item[i]._iMinDam = param1; item[i]._iMaxDam = param2; break; case IPL_SETDUR: item[i]._iDurability = param1; item[i]._iMaxDur = param1; break; case IPL_FASTSWING: item[i]._iFlags |= ISPL_FASTERATTACK; break; case IPL_ONEHAND: item[i]._iLoc = ILOC_ONEHAND; break; case IPL_DRAINLIFE: item[i]._iFlags |= ISPL_DRAINLIFE; break; case IPL_RNDSTEALLIFE: item[i]._iFlags |= ISPL_RNDSTEALLIFE; break; case IPL_INFRAVISION: item[i]._iFlags |= ISPL_INFRAVISION; break; case IPL_NOMINSTR: item[i]._iMinStr = 0; break; case IPL_INVCURS: item[i]._iCurs = param1; break; case IPL_ADDACLIFE: #ifdef HELLFIRE item[i]._iFlags |= (ISPL_LIGHT_ARROWS | ISPL_FIRE_ARROWS); item[i]._iFMinDam = param1; item[i]._iFMaxDam = param2; item[i]._iLMinDam = 1; item[i]._iLMaxDam = 0; #else item[i]._iPLHP = (plr[myplr]._pIBonusAC + plr[myplr]._pIAC + plr[myplr]._pDexterity / 5) << 6; #endif break; case IPL_ADDMANAAC: #ifdef HELLFIRE item[i]._iFlags |= (ISPL_LIGHTDAM | ISPL_FIREDAM); item[i]._iFMinDam = param1; item[i]._iFMaxDam = param2; item[i]._iLMinDam = 2; item[i]._iLMaxDam = 0; #else item[i]._iAC += (plr[myplr]._pMaxManaBase >> 6) / 10; #endif break; case IPL_FIRERESCLVL: item[i]._iPLFR = 30 - plr[myplr]._pLevel; if (item[i]._iPLFR < 0) item[i]._iPLFR = 0; break; #ifdef HELLFIRE case IPL_FIRERES_CURSE: item[i]._iPLFR -= r; break; case IPL_LIGHTRES_CURSE: item[i]._iPLLR -= r; break; case IPL_MAGICRES_CURSE: item[i]._iPLMR -= r; break; case IPL_ALLRES_CURSE: item[i]._iPLFR -= r; item[i]._iPLLR -= r; item[i]._iPLMR -= r; break; case IPL_DEVASTATION: item[i]._iDamAcFlags |= ISPLHF_DEVASTATION; break; case IPL_DECAY: item[i]._iDamAcFlags |= ISPLHF_DECAY; item[i]._iPLDam += r; break; case IPL_PERIL: item[i]._iDamAcFlags |= ISPLHF_PERIL; break; case IPL_JESTERS: item[i]._iDamAcFlags |= ISPLHF_JESTERS; break; case IPL_ACDEMON: item[i]._iDamAcFlags |= ISPLHF_ACDEMON; break; case IPL_ACUNDEAD: item[i]._iDamAcFlags |= ISPLHF_ACUNDEAD; break; case IPL_MANATOLIFE: r2 = ((plr[myplr]._pMaxManaBase >> 6) * 50 / 100); item[i]._iPLMana -= (r2 << 6); item[i]._iPLHP += (r2 << 6); break; case IPL_LIFETOMANA: r2 = ((plr[myplr]._pMaxHPBase >> 6) * 40 / 100); item[i]._iPLHP -= (r2 << 6); item[i]._iPLMana += (r2 << 6); break; #endif } if (item[i]._iVAdd1 || item[i]._iVMult1) { item[i]._iVAdd2 = PLVal(r, param1, param2, minval, maxval); item[i]._iVMult2 = multval; } else { item[i]._iVAdd1 = PLVal(r, param1, param2, minval, maxval); item[i]._iVMult1 = multval; } } void GetItemPower(int i, int minlvl, int maxlvl, int flgs, BOOL onlygood) { int pre, post, nt, nl, j, preidx, sufidx; int l[256]; char istr[128]; BYTE goe; pre = random_(23, 4); post = random_(23, 3); if (pre != 0 && post == 0) { if (random_(23, 2) != 0) post = 1; else pre = 0; } preidx = -1; sufidx = -1; goe = GOE_ANY; if (!onlygood && random_(0, 3) != 0) onlygood = TRUE; if (pre == 0) { nt = 0; for (j = 0; PL_Prefix[j].PLPower != IPL_INVALID; j++) { if (flgs & PL_Prefix[j].PLIType) { if (PL_Prefix[j].PLMinLvl >= minlvl && PL_Prefix[j].PLMinLvl <= maxlvl && (!onlygood || PL_Prefix[j].PLOk) && (flgs != PLT_STAFF || PL_Prefix[j].PLPower != IPL_CHARGES)) { l[nt] = j; nt++; if (PL_Prefix[j].PLDouble) { l[nt] = j; nt++; } } } } if (nt != 0) { preidx = l[random_(23, nt)]; sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, item[i]._iIName); strcpy(item[i]._iIName, istr); item[i]._iMagical = ITEM_QUALITY_MAGIC; 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); item[i]._iPrePower = PL_Prefix[preidx].PLPower; goe = PL_Prefix[preidx].PLGOE; } } if (post != 0) { nl = 0; for (j = 0; PL_Suffix[j].PLPower != IPL_INVALID; j++) { if (PL_Suffix[j].PLIType & flgs && PL_Suffix[j].PLMinLvl >= minlvl && PL_Suffix[j].PLMinLvl <= maxlvl && (goe | PL_Suffix[j].PLGOE) != (GOE_GOOD | GOE_EVIL) && (!onlygood || PL_Suffix[j].PLOk)) { l[nl] = j; nl++; } } if (nl != 0) { sufidx = l[random_(23, nl)]; sprintf(istr, "%s of %s", item[i]._iIName, PL_Suffix[sufidx].PLName); strcpy(item[i]._iIName, istr); item[i]._iMagical = ITEM_QUALITY_MAGIC; 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((BYTE *)item[i]._iIName)) { #ifdef HELLFIRE int aii = item[i].IDidx; if (AllItemsList[aii].iSName) strcpy(item[i]._iIName, AllItemsList[aii].iSName); else item[i]._iName[0] = 0; #else strcpy(item[i]._iIName, AllItemsList[item[i].IDidx].iSName); #endif 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); } #ifdef HELLFIRE void GetItemBonus(int i, int idata, int minlvl, int maxlvl, BOOL onlygood, BOOLEAN allowspells) #else void GetItemBonus(int i, int idata, int minlvl, int maxlvl, BOOL onlygood) #endif { 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, PLT_WEAP, onlygood); break; case ITYPE_BOW: GetItemPower(i, minlvl, maxlvl, PLT_BOW, onlygood); break; case ITYPE_SHIELD: GetItemPower(i, minlvl, maxlvl, PLT_SHLD, onlygood); break; case ITYPE_LARMOR: case ITYPE_HELM: case ITYPE_MARMOR: case ITYPE_HARMOR: GetItemPower(i, minlvl, maxlvl, PLT_ARMO, onlygood); break; case ITYPE_STAFF: #ifdef HELLFIRE if (allowspells) #endif GetStaffSpell(i, maxlvl, onlygood); #ifdef HELLFIRE else GetItemPower(i, minlvl, maxlvl, PLT_STAFF, onlygood); #endif break; case ITYPE_RING: case ITYPE_AMULET: GetItemPower(i, minlvl, maxlvl, PLT_MISC, onlygood); break; } } } void SetupItem(int i) { int it; it = ItemCAnimTbl[item[i]._iCurs]; item[i]._iAnimData = itemanims[it]; item[i]._iAnimLen = ItemAnimLs[it]; item[i]._iAnimWidth = 96; item[i]._iAnimWidth2 = 16; item[i]._iIdentified = FALSE; item[i]._iPostDraw = FALSE; if (!plr[myplr].pLvlLoad) { item[i]._iAnimFrame = 1; item[i]._iAnimFlag = TRUE; item[i]._iSelFlag = 0; } else { item[i]._iAnimFrame = item[i]._iAnimLen; item[i]._iAnimFlag = FALSE; item[i]._iSelFlag = 1; } } int RndItem(int m) { int i, ri, r; int ril[512]; 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 IDI_GOLD + 1; ri = 0; for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) { if (AllItemsList[i].iRnd == IDROP_DOUBLE && monster[m].mLevel >= AllItemsList[i].iMinMLvl #ifdef HELLFIRE && ri < 512 #endif ) { ril[ri] = i; ri++; } if (AllItemsList[i].iRnd != IDROP_NEVER && monster[m].mLevel >= AllItemsList[i].iMinMLvl #ifdef HELLFIRE && ri < 512 #endif ) { ril[ri] = i; ri++; } // BUGFIX: ri decremented even for IDROP_NEVER, thus Scroll of Resurrect // (IDI_RESURRECT) decrements ri, unintentionally removing gold drop in // Single Player (gold drop is still valid in Multi Player). if (AllItemsList[i].iSpell == SPL_RESURRECT && gbMaxPlayers == 1) ri--; if (AllItemsList[i].iSpell == SPL_HEALOTHER && gbMaxPlayers == 1) ri--; } r = random_(24, ri); return ril[r] + 1; } int RndUItem(int m) { int i, ri; int ril[512]; BOOL okflag; if (m != -1 && (monster[m].MData->mTreasure & 0x8000) != 0 && gbMaxPlayers == 1) return -1 - (monster[m].MData->mTreasure & 0xFFF); #ifdef HELLFIRE int curlv = items_get_currlevel(); #endif ri = 0; for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) { okflag = TRUE; if (AllItemsList[i].iRnd == IDROP_NEVER) okflag = FALSE; if (m != -1) { if (monster[m].mLevel < AllItemsList[i].iMinMLvl) okflag = FALSE; } else { #ifdef HELLFIRE if (2 * curlv < AllItemsList[i].iMinMLvl) #else if (2 * currlevel < AllItemsList[i].iMinMLvl) #endif okflag = FALSE; } if (AllItemsList[i].itype == ITYPE_MISC) okflag = FALSE; if (AllItemsList[i].itype == ITYPE_GOLD) okflag = FALSE; if (AllItemsList[i].itype == ITYPE_FOOD) okflag = FALSE; if (AllItemsList[i].iMiscId == IMISC_BOOK) okflag = TRUE; if (AllItemsList[i].iSpell == SPL_RESURRECT && gbMaxPlayers == 1) okflag = FALSE; if (AllItemsList[i].iSpell == SPL_HEALOTHER && gbMaxPlayers == 1) okflag = FALSE; #ifdef HELLFIRE if (okflag && ri < 512) { #else if (okflag) { #endif ril[ri] = i; ri++; } } return ril[random_(25, ri)]; } int RndAllItems() { int i, ri; int ril[512]; if (random_(26, 100) > 25) return 0; #ifdef HELLFIRE int curlv = items_get_currlevel(); #endif ri = 0; for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) { #ifdef HELLFIRE if (AllItemsList[i].iRnd != IDROP_NEVER && 2 * curlv >= AllItemsList[i].iMinMLvl && ri < 512) { #else if (AllItemsList[i].iRnd != IDROP_NEVER && 2 * currlevel >= AllItemsList[i].iMinMLvl) { #endif ril[ri] = i; ri++; } if (AllItemsList[i].iSpell == SPL_RESURRECT && gbMaxPlayers == 1) ri--; if (AllItemsList[i].iSpell == SPL_HEALOTHER && gbMaxPlayers == 1) ri--; } return ril[random_(26, ri)]; } #ifdef HELLFIRE int RndTypeItems(int itype, int imid, int lvl) #else int RndTypeItems(int itype, int imid) #endif { int i, ri; BOOL okflag; int ril[512]; ri = 0; for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) { okflag = TRUE; if (AllItemsList[i].iRnd == IDROP_NEVER) okflag = FALSE; #ifdef HELLFIRE if (lvl << 1 < AllItemsList[i].iMinMLvl) #else if (currlevel << 1 < AllItemsList[i].iMinMLvl) #endif okflag = FALSE; if (AllItemsList[i].itype != itype) okflag = FALSE; if (imid != -1 && AllItemsList[i].iMiscId != imid) okflag = FALSE; #ifdef HELLFIRE if (okflag && ri < 512) { #else if (okflag) { #endif ril[ri] = i; ri++; } } return ril[random_(27, ri)]; } int CheckUnique(int i, int lvl, int uper, BOOL recreate) { int j, idata, numu; BOOLEAN uok[128]; if (random_(28, 100) > uper) return UITYPE_INVALID; numu = 0; memset(uok, 0, sizeof(uok)); for (j = 0; UniqueItemList[j].UIItemId != UITYPE_INVALID; j++) { if (UniqueItemList[j].UIItemId == AllItemsList[item[i].IDidx].iItemId && lvl >= UniqueItemList[j].UIMinLvl && (recreate || !UniqueItemFlag[j] || gbMaxPlayers != 1)) { uok[j] = TRUE; numu++; } } if (numu == 0) return UITYPE_INVALID; random_(29, 10); /// BUGFIX: unused, last unique in array always gets chosen idata = 0; while (numu > 0) { if (uok[idata]) numu--; if (numu > 0) { idata++; if (idata == 128) idata = 0; } } return idata; } void GetUniqueItem(int i, int uid) { UniqueItemFlag[uid] = TRUE; 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]._iUid = uid; item[i]._iMagical = ITEM_QUALITY_UNIQUE; item[i]._iCreateInfo |= CF_UNIQUE; } void SpawnUnique(int uid, int x, int y) { int ii, itype; #ifdef HELLFIRE int curlv = items_get_currlevel(); #endif if (numitems >= MAXITEMS) return; ii = itemavail[0]; GetSuperItemSpace(x, y, ii); itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; itype = 0; while (AllItemsList[itype].iItemId != UniqueItemList[uid].UIItemId) { itype++; } #ifdef HELLFIRE GetItemAttrs(ii, itype, curlv); #else GetItemAttrs(ii, itype, currlevel); #endif GetUniqueItem(ii, uid); SetupItem(ii); numitems++; } void ItemRndDur(int ii) { if (item[ii]._iDurability && item[ii]._iDurability != DUR_INDESTRUCTIBLE) item[ii]._iDurability = random_(0, item[ii]._iMaxDur >> 1) + (item[ii]._iMaxDur >> 2) + 1; } void SetupAllItems(int ii, int idx, int iseed, int lvl, int uper, BOOL onlygood, BOOL recreate, BOOL pregen) { int iblvl, uid; item[ii]._iSeed = iseed; SetRndSeed(iseed); GetItemAttrs(ii, idx, lvl >> 1); item[ii]._iCreateInfo = lvl; if (pregen) item[ii]._iCreateInfo = lvl | CF_PREGEN; if (onlygood) item[ii]._iCreateInfo |= CF_ONLYGOOD; if (uper == 15) item[ii]._iCreateInfo |= CF_UPER15; else if (uper == 1) item[ii]._iCreateInfo |= CF_UPER1; if (item[ii]._iMiscId != IMISC_UNIQUE) { iblvl = -1; if (random_(32, 100) <= 10 || random_(33, 100) <= lvl) { iblvl = lvl; } if (iblvl == -1 && item[ii]._iMiscId == IMISC_STAFF) { iblvl = lvl; } if (iblvl == -1 && item[ii]._iMiscId == IMISC_RING) { iblvl = lvl; } if (iblvl == -1 && 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 == UITYPE_INVALID) { #ifdef HELLFIRE GetItemBonus(ii, idx, iblvl >> 1, iblvl, onlygood, TRUE); #else GetItemBonus(ii, idx, iblvl >> 1, iblvl, onlygood); #endif } else { GetUniqueItem(ii, uid); item[ii]._iCreateInfo |= CF_UNIQUE; } } if (item[ii]._iMagical != ITEM_QUALITY_UNIQUE) ItemRndDur(ii); } else { if (item[ii]._iLoc != ILOC_UNEQUIPABLE) { //uid = CheckUnique(ii, iblvl, uper, recreate); //if (uid != UITYPE_INVALID) { // GetUniqueItem(ii, uid); //} GetUniqueItem(ii, iseed); // BUG: the second argument to GetUniqueItem should be uid. } } SetupItem(ii); } void SpawnItem(int m, int x, int y, BOOL sendmsg) { int ii, idx; // BUGFIX: onlygood may be used uninitialized in call to SetupAllItems. BOOL onlygood; if (monster[m]._uniqtype || ((monster[m].MData->mTreasure & 0x8000) && gbMaxPlayers != 1)) { idx = RndUItem(m); if (idx < 0) { SpawnUnique(-(idx + 1), x, y); return; } onlygood = TRUE; } else if (quests[Q_MUSHROOM]._qactive != QUEST_ACTIVE || quests[Q_MUSHROOM]._qvar1 != QS_MUSHGIVEN) { idx = RndItem(m); if (!idx) return; if (idx > 0) { idx--; onlygood = FALSE; } else { SpawnUnique(-(idx + 1), x, y); return; } } else { idx = IDI_BRAIN; quests[Q_MUSHROOM]._qvar1 = QS_BRAINSPAWNED; } if (numitems < MAXITEMS) { ii = itemavail[0]; GetSuperItemSpace(x, y, ii); itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; if (monster[m]._uniqtype) { SetupAllItems(ii, idx, GetRndSeed(), monster[m].MData->mLevel, 15, onlygood, FALSE, FALSE); } else { SetupAllItems(ii, idx, GetRndSeed(), monster[m].MData->mLevel, 1, onlygood, FALSE, FALSE); } numitems++; if (sendmsg) NetSendCmdDItem(FALSE, ii); } } void CreateItem(int uid, int x, int y) { int ii, idx; #ifdef HELLFIRE int curlv = items_get_currlevel(); #endif if (numitems < MAXITEMS) { ii = itemavail[0]; GetSuperItemSpace(x, y, ii); idx = 0; itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; while (AllItemsList[idx].iItemId != UniqueItemList[uid].UIItemId) { idx++; } #ifdef HELLFIRE GetItemAttrs(ii, idx, curlv); #else GetItemAttrs(ii, idx, currlevel); #endif GetUniqueItem(ii, uid); SetupItem(ii); item[ii]._iMagical = ITEM_QUALITY_UNIQUE; numitems++; } } void CreateRndItem(int x, int y, BOOL onlygood, BOOL sendmsg, BOOL delta) { int idx, ii; #ifdef HELLFIRE int curlv = items_get_currlevel(); #endif if (onlygood) idx = RndUItem(-1); else idx = RndAllItems(); if (numitems < MAXITEMS) { ii = itemavail[0]; GetSuperItemSpace(x, y, ii); itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; #ifdef HELLFIRE SetupAllItems(ii, idx, GetRndSeed(), 2 * curlv, 1, onlygood, FALSE, delta); #else SetupAllItems(ii, idx, GetRndSeed(), 2 * currlevel, 1, onlygood, FALSE, delta); #endif if (sendmsg) NetSendCmdDItem(FALSE, ii); if (delta) DeltaAddItem(ii); numitems++; } } void SetupAllUseful(int ii, int iseed, int lvl) { int idx; item[ii]._iSeed = iseed; SetRndSeed(iseed); #ifdef HELLFIRE idx = random_(34, 7); switch (idx) { case 0: idx = IDI_PORTAL; if ((lvl <= 1)) idx = IDI_HEAL; break; case 1: case 2: idx = IDI_HEAL; break; case 3: idx = IDI_PORTAL; if ((lvl <= 1)) idx = IDI_MANA; break; case 4: case 5: idx = IDI_MANA; break; case 6: idx = IDI_OIL; break; default: idx = IDI_OIL; break; } #else if (random_(34, 2) != 0) idx = IDI_HEAL; else idx = IDI_MANA; if (lvl > 1 && random_(34, 3) == 0) idx = IDI_PORTAL; #endif GetItemAttrs(ii, idx, lvl); item[ii]._iCreateInfo = lvl + CF_USEFUL; SetupItem(ii); } void CreateRndUseful(int pnum, int x, int y, BOOL sendmsg) { int ii; #ifdef HELLFIRE int curlv = items_get_currlevel(); #endif if (numitems < MAXITEMS) { ii = itemavail[0]; GetSuperItemSpace(x, y, ii); itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; #ifdef HELLFIRE SetupAllUseful(ii, GetRndSeed(), curlv); #else SetupAllUseful(ii, GetRndSeed(), currlevel); #endif if (sendmsg) { NetSendCmdDItem(FALSE, ii); } numitems++; } } void CreateTypeItem(int x, int y, BOOL onlygood, int itype, int imisc, BOOL sendmsg, BOOL delta) { int idx, ii; #ifdef HELLFIRE int curlv = items_get_currlevel(); if (itype != ITYPE_GOLD) idx = RndTypeItems(itype, imisc, curlv); #else if (itype != ITYPE_GOLD) idx = RndTypeItems(itype, imisc); #endif else idx = IDI_GOLD; if (numitems < MAXITEMS) { ii = itemavail[0]; GetSuperItemSpace(x, y, ii); itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; #ifdef HELLFIRE SetupAllItems(ii, idx, GetRndSeed(), 2 * curlv, 1, onlygood, FALSE, delta); #else SetupAllItems(ii, idx, GetRndSeed(), 2 * currlevel, 1, onlygood, FALSE, delta); #endif if (sendmsg) NetSendCmdDItem(FALSE, ii); if (delta) DeltaAddItem(ii); numitems++; } } void RecreateItem(int ii, int idx, WORD icreateinfo, int iseed, int ivalue) { int uper; BOOL onlygood, recreate, pregen; if (!idx) { SetPlrHandItem(&item[ii], IDI_GOLD); item[ii]._iSeed = iseed; item[ii]._iCreateInfo = icreateinfo; item[ii]._ivalue = ivalue; if (ivalue >= GOLD_MEDIUM_LIMIT) item[ii]._iCurs = ICURS_GOLD_LARGE; else if (ivalue <= GOLD_SMALL_LIMIT) item[ii]._iCurs = ICURS_GOLD_SMALL; else item[ii]._iCurs = ICURS_GOLD_MEDIUM; } else { if (!icreateinfo) { SetPlrHandItem(&item[ii], idx); SetPlrHandSeed(&item[ii], iseed); } else { if (icreateinfo & CF_TOWN) { RecreateTownItem(ii, idx, icreateinfo, iseed, ivalue); } else if ((icreateinfo & CF_USEFUL) == CF_USEFUL) { SetupAllUseful(ii, iseed, icreateinfo & CF_LEVEL); } else { uper = 0; onlygood = FALSE; recreate = FALSE; pregen = FALSE; if (icreateinfo & CF_UPER1) uper = 1; if (icreateinfo & CF_UPER15) uper = 15; if (icreateinfo & CF_ONLYGOOD) onlygood = TRUE; if (icreateinfo & CF_UNIQUE) recreate = TRUE; if (icreateinfo & CF_PREGEN) pregen = TRUE; SetupAllItems(ii, idx, iseed, icreateinfo & CF_LEVEL, uper, onlygood, recreate, pregen); } } } } void RecreateEar(int ii, WORD ic, int iseed, int 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) + ICURS_EAR_SORCEROR; item[ii]._ivalue = ivalue & 0x3F; item[ii]._iCreateInfo = ic; item[ii]._iSeed = iseed; } #ifdef HELLFIRE void CornerstoneSave() { PkItemStruct id; if (CornerStone.activated) { if (CornerStone.item.IDidx >= 0) { PackItem(&id, &CornerStone.item); SRegSaveData(APP_NAME, CornerStoneRegKey, 0, (BYTE *)&id, 19); } else { SRegSaveData(APP_NAME, CornerStoneRegKey, 0, (BYTE *)"", 1); } } } void CornerstoneLoad(int x, int y) { int i, ii; DWORD dwSize; PkItemStruct PkSItem; if (CornerStone.activated || x == 0 || y == 0) { return; } CornerStone.item.IDidx = 0; CornerStone.activated = TRUE; if (dItem[x][y]) { ii = dItem[x][y] - 1; for (i = 0; i < numitems; i++) { if (itemactive[i] == ii) { DeleteItem(ii, i); break; } } dItem[x][y] = 0; } dwSize = 0; if (SRegLoadData(APP_NAME, CornerStoneRegKey, 0, (BYTE *)&PkSItem, sizeof(PkSItem), &dwSize)) { if (dwSize == sizeof(PkSItem)) { ii = itemavail[0]; dItem[x][y] = ii + 1; itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; UnPackItem(&PkSItem, &item[ii]); item[ii]._ix = x; item[ii]._iy = y; RespawnItem(ii, FALSE); CornerStone.item = item[ii]; numitems++; } } } #endif void SpawnQuestItem(int itemid, int x, int y, int randarea, int selflag) { BOOL failed; int i, j, tries; #ifdef HELLFIRE int curlv = items_get_currlevel(); #endif if (randarea) { tries = 0; while (1) { tries++; if (tries > 1000 && randarea > 1) randarea--; x = random_(0, MAXDUNX); y = random_(0, MAXDUNY); failed = FALSE; for (i = 0; i < randarea && !failed; i++) { for (j = 0; j < randarea && !failed; j++) { failed = !ItemSpaceOk(i + x, j + y); } } if (!failed) break; } } if (numitems < MAXITEMS) { i = itemavail[0]; itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = i; item[i]._ix = x; item[i]._iy = y; dItem[x][y] = i + 1; #ifdef HELLFIRE GetItemAttrs(i, itemid, curlv); #else GetItemAttrs(i, itemid, currlevel); #endif SetupItem(i); item[i]._iPostDraw = TRUE; if (selflag) { item[i]._iSelFlag = selflag; item[i]._iAnimFrame = item[i]._iAnimLen; item[i]._iAnimFlag = FALSE; } numitems++; } } void SpawnRock() { int i, ii; int xx, yy; int ostand; ostand = FALSE; for (i = 0; i < nobjects && !ostand; i++) { ii = objectactive[i]; ostand = object[ii]._otype == OBJ_STAND; } #ifdef HELLFIRE int curlv = items_get_currlevel(); #endif if (ostand) { i = itemavail[0]; itemavail[0] = itemavail[127 - numitems - 1]; itemactive[numitems] = i; xx = object[ii]._ox; yy = object[ii]._oy; item[i]._ix = xx; item[i]._iy = yy; dItem[xx][item[i]._iy] = i + 1; #ifdef HELLFIRE GetItemAttrs(i, IDI_ROCK, curlv); #else GetItemAttrs(i, IDI_ROCK, currlevel); #endif SetupItem(i); item[i]._iSelFlag = 2; item[i]._iPostDraw = TRUE; item[i]._iAnimFrame = 11; numitems++; } } #ifdef HELLFIRE void SpawnRewardItem(int itemid, int xx, int yy) { int i; i = itemavail[0]; int curlv = items_get_currlevel(); itemavail[0] = itemavail[127 - numitems - 1]; itemactive[numitems] = i; item[i]._ix = xx; item[i]._iy = yy; dItem[xx][yy] = i + 1; GetItemAttrs(i, itemid, curlv); SetupItem(i); item[i]._iSelFlag = 2; item[i]._iPostDraw = TRUE; item[i]._iAnimFrame = 1; item[i]._iAnimFlag = TRUE; item[i]._iIdentified = TRUE; numitems++; } void SpawnMapOfDoom(int xx, int yy) { SpawnRewardItem(IDI_MAPOFDOOM, xx, yy); } void SpawnRuneBomb(int xx, int yy) { SpawnRewardItem(IDI_RUNEBOMB, xx, yy); } void SpawnTheodore(int xx, int yy) { SpawnRewardItem(IDI_THEODORE, xx, yy); } #endif void RespawnItem(int i, BOOL FlipFlag) { int it; it = ItemCAnimTbl[item[i]._iCurs]; item[i]._iAnimData = itemanims[it]; item[i]._iAnimLen = ItemAnimLs[it]; item[i]._iAnimWidth = 96; item[i]._iAnimWidth2 = 16; item[i]._iPostDraw = FALSE; item[i]._iRequest = FALSE; if (FlipFlag) { item[i]._iAnimFrame = 1; item[i]._iAnimFlag = TRUE; item[i]._iSelFlag = 0; } else { item[i]._iAnimFrame = item[i]._iAnimLen; item[i]._iAnimFlag = FALSE; item[i]._iSelFlag = 1; } if (item[i]._iCurs == ICURS_MAGIC_ROCK) { item[i]._iSelFlag = 1; PlaySfxLoc(ItemDropSnds[it], item[i]._ix, item[i]._iy); } if (item[i]._iCurs == ICURS_TAVERN_SIGN) item[i]._iSelFlag = 1; if (item[i]._iCurs == ICURS_ANVIL_OF_FURY) item[i]._iSelFlag = 1; } void DeleteItem(int ii, int i) { itemavail[MAXITEMS - numitems] = ii; numitems--; if (numitems > 0 && i != numitems) itemactive[i] = itemactive[numitems]; } void ItemDoppel() { int idoppelx; ItemStruct *i; 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; } } idoppely++; if (idoppely == 96) idoppely = 16; } } void ProcessItems() { int i, ii; for (i = 0; i < numitems; i++) { ii = itemactive[i]; if (item[ii]._iAnimFlag) { item[ii]._iAnimFrame++; if (item[ii]._iCurs == ICURS_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]._iAnimFrame = item[ii]._iAnimLen; item[ii]._iAnimFlag = FALSE; item[ii]._iSelFlag = 1; } } } } ItemDoppel(); } void FreeItemGFX() { #ifdef HELLFIRE DWORD i; #else int i; #endif for (i = 0; i < ITEMTYPES; i++) { MemFreeDbg(itemanims[i]); } } void GetItemFrm(int i) { item[i]._iAnimData = itemanims[ItemCAnimTbl[item[i]._iCurs]]; } void GetItemStr(int i) { int nGold; if (item[i]._itype != ITYPE_GOLD) { if (item[i]._iIdentified) strcpy(infostr, item[i]._iIName); else strcpy(infostr, item[i]._iName); if (item[i]._iMagical == ITEM_QUALITY_MAGIC) infoclr = COL_BLUE; if (item[i]._iMagical == ITEM_QUALITY_UNIQUE) infoclr = COL_GOLD; } else { nGold = item[i]._ivalue; sprintf(infostr, "%i gold %s", nGold, get_pieces_str(nGold)); } } void CheckIdentify(int pnum, int cii) { ItemStruct *pi; if (cii >= NUM_INVLOC) pi = &plr[pnum].InvList[cii - NUM_INVLOC]; else pi = &plr[pnum].InvBody[cii]; pi->_iIdentified = TRUE; CalcPlrInv(pnum, TRUE); if (pnum == myplr) SetCursor_(CURSOR_HAND); } static void RepairItem(ItemStruct *i, int lvl) { int rep, d; if (i->_iDurability == i->_iMaxDur) { return; } if (i->_iMaxDur <= 0) { i->_itype = ITYPE_NONE; return; } rep = 0; do { rep += lvl + random_(37, lvl); d = i->_iMaxDur / (lvl + 9); if (d < 1) d = 1; i->_iMaxDur = i->_iMaxDur - d; if (!i->_iMaxDur) { i->_itype = ITYPE_NONE; return; } } while (rep + i->_iDurability < i->_iMaxDur); i->_iDurability += rep; if (i->_iDurability > i->_iMaxDur) i->_iDurability = i->_iMaxDur; } void DoRepair(int pnum, int cii) { PlayerStruct *p; ItemStruct *pi; p = &plr[pnum]; PlaySfxLoc(IS_REPAIR, p->_px, p->_py); if (cii >= NUM_INVLOC) { pi = &p->InvList[cii - NUM_INVLOC]; } else { pi = &p->InvBody[cii]; } RepairItem(pi, p->_pLevel); CalcPlrInv(pnum, TRUE); if (pnum == myplr) SetCursor_(CURSOR_HAND); } static void RechargeItem(ItemStruct *i, int r) { if (i->_iCharges != i->_iMaxCharges) { do { i->_iMaxCharges--; if (i->_iMaxCharges == 0) { return; } i->_iCharges += r; } while (i->_iCharges < i->_iMaxCharges); if (i->_iCharges > i->_iMaxCharges) i->_iCharges = i->_iMaxCharges; } } void DoRecharge(int pnum, int cii) { PlayerStruct *p; ItemStruct *pi; int r; p = &plr[pnum]; if (cii >= NUM_INVLOC) { pi = &p->InvList[cii - NUM_INVLOC]; } else { pi = &p->InvBody[cii]; } if (pi->_itype == ITYPE_STAFF && pi->_iSpell != SPL_NULL) { r = spelldata[pi->_iSpell].sBookLvl; r = random_(38, p->_pLevel / r) + 1; RechargeItem(pi, r); CalcPlrInv(pnum, TRUE); } if (pnum == myplr) SetCursor_(CURSOR_HAND); } #ifdef HELLFIRE static BOOL OilItem(ItemStruct *x, PlayerStruct *p) { int dur, r; if (x->_iClass == ICLASS_MISC) { return FALSE; } if (x->_iClass == ICLASS_GOLD) { return FALSE; } if (x->_iClass == ICLASS_QUEST) { return FALSE; } switch (p->_pOilType) { case IMISC_OILACC: case IMISC_OILMAST: case IMISC_OILSHARP: if (x->_iClass == ICLASS_ARMOR) { return FALSE; } break; case IMISC_OILDEATH: if (x->_iClass == ICLASS_ARMOR) { return FALSE; } if (x->_itype == ITYPE_BOW) { return FALSE; } break; case IMISC_OILHARD: case IMISC_OILIMP: if (x->_iClass == ICLASS_WEAPON) { return FALSE; } break; } switch (p->_pOilType) { case IMISC_OILACC: if (x->_iPLToHit < 50) { x->_iPLToHit += random_(68, 2) + 1; } break; case IMISC_OILMAST: if (x->_iPLToHit < 100) { x->_iPLToHit += random_(68, 3) + 3; } break; case IMISC_OILSHARP: if (x->_iMaxDam - x->_iMinDam < 30) { x->_iMaxDam = x->_iMaxDam + 1; } break; case IMISC_OILDEATH: if (x->_iMaxDam - x->_iMinDam < 30) { x->_iMinDam = x->_iMinDam + 1; x->_iMaxDam = x->_iMaxDam + 2; } break; case IMISC_OILSKILL: r = random_(68, 6) + 5; if (x->_iMinStr > r) { x->_iMinStr = x->_iMinStr - r; } else { x->_iMinStr = 0; } if (x->_iMinMag > r) { x->_iMinMag = x->_iMinMag - r; } else { x->_iMinMag = 0; } if (x->_iMinDex > r) { x->_iMinDex = x->_iMinDex - r; } else { x->_iMinDex = 0; } break; case IMISC_OILBSMTH: if (x->_iMaxDur != 255) { if (x->_iDurability < x->_iMaxDur) { dur = (x->_iMaxDur + 4) / 5 + x->_iDurability; if (dur > x->_iMaxDur) { dur = x->_iMaxDur; } } else { if (x->_iMaxDur >= 100) { return TRUE; } dur = x->_iMaxDur + 1; x->_iMaxDur = dur; } x->_iDurability = dur; } break; case IMISC_OILFORT: if (x->_iMaxDur != 255 && x->_iMaxDur < 200) { r = random_(68, 41) + 10; x->_iMaxDur += r; x->_iDurability += r; } break; case IMISC_OILPERM: x->_iDurability = 255; x->_iMaxDur = 255; break; case IMISC_OILHARD: if (x->_iAC < 60) { x->_iAC += random_(68, 2) + 1; } break; case IMISC_OILIMP: if (x->_iAC < 120) { x->_iAC += random_(68, 3) + 3; } break; } return TRUE; } void DoOil(int pnum, int cii) { PlayerStruct *p = &plr[pnum]; if (cii >= NUM_INVLOC || cii == INVLOC_HEAD || (cii > INVLOC_AMULET && cii <= INVLOC_CHEST)) { if (OilItem(&p->InvBody[cii], p)) { CalcPlrInv(pnum, TRUE); if (pnum == myplr) { SetCursor_(CURSOR_HAND); } } } } #endif void PrintItemOil(char IDidx) { switch (IDidx) { #ifdef HELLFIRE case IMISC_OILACC: strcpy(tempstr, "increases a weapon's"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "chance to hit"); AddPanelString(tempstr, TRUE); break; case IMISC_OILMAST: strcpy(tempstr, "greatly increases a"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "weapon's chance to hit"); AddPanelString(tempstr, TRUE); break; case IMISC_OILSHARP: strcpy(tempstr, "increases a weapon's"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "damage potential"); AddPanelString(tempstr, TRUE); break; case IMISC_OILDEATH: strcpy(tempstr, "greatly increases a weapon's"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "damage potential - not bows"); AddPanelString(tempstr, TRUE); break; case IMISC_OILSKILL: strcpy(tempstr, "reduces attributes needed"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "to use armor or weapons"); AddPanelString(tempstr, TRUE); break; case IMISC_OILBSMTH: strcpy(tempstr, "restores 20% of an"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "item's durability"); AddPanelString(tempstr, TRUE); break; case IMISC_OILFORT: strcpy(tempstr, "increases an item's"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "current and max durability"); AddPanelString(tempstr, TRUE); break; case IMISC_OILPERM: strcpy(tempstr, "makes an item indestructible"); AddPanelString(tempstr, TRUE); break; case IMISC_OILHARD: strcpy(tempstr, "increases the armor class"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "of armor and shields"); AddPanelString(tempstr, TRUE); break; case IMISC_OILIMP: strcpy(tempstr, "greatly increases the armor"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "class of armor and shields"); AddPanelString(tempstr, TRUE); break; case IMISC_RUNEF: strcpy(tempstr, "sets fire trap"); AddPanelString(tempstr, TRUE); break; case IMISC_RUNEL: strcpy(tempstr, "sets lightning trap"); AddPanelString(tempstr, TRUE); break; case IMISC_GR_RUNEL: strcpy(tempstr, "sets lightning trap"); AddPanelString(tempstr, TRUE); break; case IMISC_GR_RUNEF: strcpy(tempstr, "sets fire trap"); AddPanelString(tempstr, TRUE); break; case IMISC_RUNES: strcpy(tempstr, "sets petrification trap"); AddPanelString(tempstr, TRUE); break; #endif case IMISC_FULLHEAL: strcpy(tempstr, "fully recover life"); AddPanelString(tempstr, TRUE); break; case IMISC_HEAL: strcpy(tempstr, "recover partial life"); AddPanelString(tempstr, TRUE); break; case IMISC_OLDHEAL: strcpy(tempstr, "recover life"); AddPanelString(tempstr, TRUE); break; case IMISC_DEADHEAL: strcpy(tempstr, "deadly heal"); AddPanelString(tempstr, TRUE); break; case IMISC_MANA: strcpy(tempstr, "recover mana"); AddPanelString(tempstr, TRUE); break; case IMISC_FULLMANA: strcpy(tempstr, "fully recover mana"); AddPanelString(tempstr, TRUE); break; case IMISC_ELIXSTR: strcpy(tempstr, "increase strength"); AddPanelString(tempstr, TRUE); break; case IMISC_ELIXMAG: strcpy(tempstr, "increase magic"); AddPanelString(tempstr, TRUE); break; case IMISC_ELIXDEX: strcpy(tempstr, "increase dexterity"); AddPanelString(tempstr, TRUE); break; case IMISC_ELIXVIT: strcpy(tempstr, "increase vitality"); AddPanelString(tempstr, TRUE); break; case IMISC_ELIXWEAK: strcpy(tempstr, "decrease strength"); AddPanelString(tempstr, TRUE); break; case IMISC_ELIXDIS: strcpy(tempstr, "decrease strength"); AddPanelString(tempstr, TRUE); break; case IMISC_ELIXCLUM: strcpy(tempstr, "decrease dexterity"); AddPanelString(tempstr, TRUE); break; case IMISC_ELIXSICK: strcpy(tempstr, "decrease vitality"); AddPanelString(tempstr, TRUE); break; case IMISC_REJUV: strcpy(tempstr, "recover life and mana"); AddPanelString(tempstr, TRUE); break; case IMISC_FULLREJUV: strcpy(tempstr, "fully recover life and mana"); AddPanelString(tempstr, TRUE); break; } } void PrintItemPower(char plidx, ItemStruct *x) { switch (plidx) { case IPL_TOHIT: case IPL_TOHIT_CURSE: sprintf(tempstr, "chance to hit : %+i%%", x->_iPLToHit); break; case IPL_DAMP: case IPL_DAMP_CURSE: sprintf(tempstr, "%+i%% damage", x->_iPLDam); break; case IPL_TOHIT_DAMP: case IPL_TOHIT_DAMP_CURSE: sprintf(tempstr, "to hit: %+i%%, %+i%% damage", x->_iPLToHit, x->_iPLDam); break; case IPL_ACP: case IPL_ACP_CURSE: sprintf(tempstr, "%+i%% armor", x->_iPLAC); break; case IPL_SETAC: sprintf(tempstr, "armor class: %i", x->_iAC); break; case IPL_AC_CURSE: sprintf(tempstr, "armor class: %i", x->_iAC); break; case IPL_FIRERES: #ifdef HELLFIRE case IPL_FIRERES_CURSE: #endif if (x->_iPLFR < 75) sprintf(tempstr, "Resist Fire : %+i%%", x->_iPLFR); #ifdef HELLFIRE else #else if (x->_iPLFR >= 75) #endif sprintf(tempstr, "Resist Fire : 75%% MAX"); break; case IPL_LIGHTRES: #ifdef HELLFIRE case IPL_LIGHTRES_CURSE: #endif if (x->_iPLLR < 75) sprintf(tempstr, "Resist Lightning : %+i%%", x->_iPLLR); #ifdef HELLFIRE else #else if (x->_iPLLR >= 75) #endif sprintf(tempstr, "Resist Lightning : 75%% MAX"); break; case IPL_MAGICRES: #ifdef HELLFIRE case IPL_MAGICRES_CURSE: #endif if (x->_iPLMR < 75) sprintf(tempstr, "Resist Magic : %+i%%", x->_iPLMR); #ifdef HELLFIRE else #else if (x->_iPLMR >= 75) #endif sprintf(tempstr, "Resist Magic : 75%% MAX"); break; case IPL_ALLRES: #ifdef HELLFIRE case IPL_ALLRES_CURSE: #endif if (x->_iPLFR < 75) sprintf(tempstr, "Resist All : %+i%%", x->_iPLFR); if (x->_iPLFR >= 75) sprintf(tempstr, "Resist All : 75%% MAX"); break; case IPL_SPLLVLADD: if (x->_iSplLvlAdd == 1) strcpy(tempstr, "spells are increased 1 level"); #ifdef HELLFIRE else if (x->_iSplLvlAdd > 1) sprintf(tempstr, "spells are increased %i levels", x->_iSplLvlAdd); else if (x->_iSplLvlAdd == -1) #else if (x->_iSplLvlAdd == 2) strcpy(tempstr, "spells are increased 2 levels"); if (x->_iSplLvlAdd < 1) // BUGFIX: should be `x->_iSplLvlAdd == -1`, not `x->_iSplLvlAdd < 1`. #endif strcpy(tempstr, "spells are decreased 1 level"); #ifdef HELLFIRE else if (x->_iSplLvlAdd < -1) sprintf(tempstr, "spells are decreased %i levels", -x->_iSplLvlAdd); else if (x->_iSplLvlAdd == 0) strcpy(tempstr, "spell levels unchanged (?)"); #endif break; case IPL_CHARGES: strcpy(tempstr, "Extra charges"); break; case IPL_SPELL: sprintf(tempstr, "%i %s charges", x->_iMaxCharges, spelldata[x->_iSpell].sNameText); break; case IPL_FIREDAM: #ifdef HELLFIRE if (x->_iFMinDam == x->_iFMaxDam) sprintf(tempstr, "Fire hit damage: %i", x->_iFMinDam); else #endif sprintf(tempstr, "Fire hit damage: %i-%i", x->_iFMinDam, x->_iFMaxDam); break; case IPL_LIGHTDAM: #ifdef HELLFIRE if (x->_iLMinDam == x->_iLMaxDam) sprintf(tempstr, "Lightning hit damage: %i", x->_iLMinDam); else #endif sprintf(tempstr, "Lightning hit damage: %i-%i", x->_iLMinDam, x->_iLMaxDam); break; case IPL_STR: case IPL_STR_CURSE: sprintf(tempstr, "%+i to strength", x->_iPLStr); break; case IPL_MAG: case IPL_MAG_CURSE: sprintf(tempstr, "%+i to magic", x->_iPLMag); break; case IPL_DEX: case IPL_DEX_CURSE: sprintf(tempstr, "%+i to dexterity", x->_iPLDex); break; case IPL_VIT: case IPL_VIT_CURSE: sprintf(tempstr, "%+i to vitality", x->_iPLVit); break; case IPL_ATTRIBS: case IPL_ATTRIBS_CURSE: sprintf(tempstr, "%+i to all attributes", x->_iPLStr); break; case IPL_GETHIT_CURSE: case IPL_GETHIT: sprintf(tempstr, "%+i damage from enemies", x->_iPLGetHit); break; case IPL_LIFE: case IPL_LIFE_CURSE: sprintf(tempstr, "Hit Points : %+i", x->_iPLHP >> 6); break; case IPL_MANA: case IPL_MANA_CURSE: sprintf(tempstr, "Mana : %+i", x->_iPLMana >> 6); break; case IPL_DUR: strcpy(tempstr, "high durability"); break; case IPL_DUR_CURSE: strcpy(tempstr, "decreased durability"); break; case IPL_INDESTRUCTIBLE: strcpy(tempstr, "indestructible"); break; case IPL_LIGHT: sprintf(tempstr, "+%i%% light radius", 10 * x->_iPLLight); break; case IPL_LIGHT_CURSE: sprintf(tempstr, "-%i%% light radius", -10 * x->_iPLLight); break; #ifdef HELLFIRE case IPL_MULT_ARROWS: sprintf(tempstr, "multiple arrows per shot"); break; #endif case IPL_FIRE_ARROWS: #ifdef HELLFIRE if (x->_iFMinDam == x->_iFMaxDam) sprintf(tempstr, "fire arrows damage: %i", x->_iFMinDam); else #endif sprintf(tempstr, "fire arrows damage: %i-%i", x->_iFMinDam, x->_iFMaxDam); break; case IPL_LIGHT_ARROWS: #ifdef HELLFIRE if (x->_iLMinDam == x->_iLMaxDam) sprintf(tempstr, "lightning arrows damage %i", x->_iLMinDam); else #endif sprintf(tempstr, "lightning arrows damage %i-%i", x->_iLMinDam, x->_iLMaxDam); break; #ifdef HELLFIRE case IPL_FIREBALL: if (x->_iFMinDam == x->_iFMaxDam) sprintf(tempstr, "fireball damage: %i", x->_iFMinDam); else sprintf(tempstr, "fireball damage: %i-%i", x->_iFMinDam, x->_iFMaxDam); break; #endif case IPL_THORNS: strcpy(tempstr, "attacker takes 1-3 damage"); break; case IPL_NOMANA: strcpy(tempstr, "user loses all mana"); break; case IPL_NOHEALPLR: strcpy(tempstr, "you can't heal"); break; case IPL_ABSHALFTRAP: strcpy(tempstr, "absorbs half of trap damage"); break; case IPL_KNOCKBACK: strcpy(tempstr, "knocks target back"); break; case IPL_3XDAMVDEM: strcpy(tempstr, "+200% damage vs. demons"); break; case IPL_ALLRESZERO: strcpy(tempstr, "All Resistance equals 0"); break; case IPL_NOHEALMON: strcpy(tempstr, "hit monster doesn't heal"); break; case IPL_STEALMANA: if (x->_iFlags & ISPL_STEALMANA_3) strcpy(tempstr, "hit steals 3% mana"); if (x->_iFlags & ISPL_STEALMANA_5) strcpy(tempstr, "hit steals 5% mana"); break; case IPL_STEALLIFE: if (x->_iFlags & ISPL_STEALLIFE_3) strcpy(tempstr, "hit steals 3% life"); if (x->_iFlags & ISPL_STEALLIFE_5) strcpy(tempstr, "hit steals 5% life"); break; case IPL_TARGAC: #ifdef HELLFIRE strcpy(tempstr, "penetrates target's armor"); #else strcpy(tempstr, "damages target's armor"); #endif break; case IPL_FASTATTACK: if (x->_iFlags & ISPL_QUICKATTACK) strcpy(tempstr, "quick attack"); if (x->_iFlags & ISPL_FASTATTACK) strcpy(tempstr, "fast attack"); if (x->_iFlags & ISPL_FASTERATTACK) strcpy(tempstr, "faster attack"); if (x->_iFlags & ISPL_FASTESTATTACK) strcpy(tempstr, "fastest attack"); break; case IPL_FASTRECOVER: if (x->_iFlags & ISPL_FASTRECOVER) strcpy(tempstr, "fast hit recovery"); if (x->_iFlags & ISPL_FASTERRECOVER) strcpy(tempstr, "faster hit recovery"); if (x->_iFlags & ISPL_FASTESTRECOVER) strcpy(tempstr, "fastest hit recovery"); break; case IPL_FASTBLOCK: strcpy(tempstr, "fast block"); break; case IPL_DAMMOD: sprintf(tempstr, "adds %i points to damage", x->_iPLDamMod); break; case IPL_RNDARROWVEL: strcpy(tempstr, "fires random speed arrows"); break; case IPL_SETDAM: sprintf(tempstr, "unusual item damage"); break; case IPL_SETDUR: strcpy(tempstr, "altered durability"); break; case IPL_FASTSWING: strcpy(tempstr, "Faster attack swing"); break; case IPL_ONEHAND: strcpy(tempstr, "one handed sword"); break; case IPL_DRAINLIFE: strcpy(tempstr, "constantly lose hit points"); break; case IPL_RNDSTEALLIFE: strcpy(tempstr, "life stealing"); break; case IPL_NOMINSTR: strcpy(tempstr, "no strength requirement"); break; case IPL_INFRAVISION: strcpy(tempstr, "see with infravision"); break; case IPL_INVCURS: strcpy(tempstr, " "); break; case IPL_ADDACLIFE: #ifdef HELLFIRE if (x->_iFMinDam == x->_iFMaxDam) sprintf(tempstr, "lightning damage: %i", x->_iFMinDam); else sprintf(tempstr, "lightning damage: %i-%i", x->_iFMinDam, x->_iFMaxDam); #else strcpy(tempstr, "Armor class added to life"); #endif break; case IPL_ADDMANAAC: #ifdef HELLFIRE strcpy(tempstr, "charged bolts on hits"); #else strcpy(tempstr, "10% of mana added to armor"); #endif break; case IPL_FIRERESCLVL: if (x->_iPLFR <= 0) sprintf(tempstr, " "); else if (x->_iPLFR >= 1) sprintf(tempstr, "Resist Fire : %+i%%", x->_iPLFR); break; #ifdef HELLFIRE case IPL_DEVASTATION: strcpy(tempstr, "occasional triple damage"); break; case IPL_DECAY: sprintf(tempstr, "decaying %+i%% damage", x->_iPLDam); break; case IPL_PERIL: strcpy(tempstr, "2x dmg to monst, 1x to you"); break; case IPL_JESTERS: strcpy(tempstr, "Random 0 - 500% damage"); break; case IPL_CRYSTALLINE: sprintf(tempstr, "low dur, %+i%% damage", x->_iPLDam); break; case IPL_DOPPELGANGER: sprintf(tempstr, "to hit: %+i%%, %+i%% damage", x->_iPLToHit, x->_iPLDam); break; case IPL_ACDEMON: sprintf(tempstr, "extra AC vs demons"); break; case IPL_ACUNDEAD: sprintf(tempstr, "extra AC vs undead"); break; case IPL_MANATOLIFE: sprintf(tempstr, "50%% Mana moved to Health"); break; case IPL_LIFETOMANA: sprintf(tempstr, "40%% Health moved to Mana"); break; #endif default: strcpy(tempstr, "Another ability (NW)"); break; } } void DrawUTextBack() { CelDraw(PANEL_X + 24, SCREEN_Y + 327, pSTextBoxCels, 1, 271); #define TRANS_RECT_X (PANEL_LEFT + 27) #define TRANS_RECT_Y 28 #define TRANS_RECT_WIDTH 265 #define TRANS_RECT_HEIGHT 297 #include "asm_trans_rect.inc" } void PrintUString(int x, int y, BOOL cjustflag, const char *str, int col) { int len, width, off, i, k; BYTE c; off = x + PitchTbl[SStringY[y] + 44 + SCREEN_Y] + 32 + SCREEN_X; len = strlen(str); k = 0; if (cjustflag) { width = 0; for (i = 0; i < len; i++) width += fontkern[fontframe[gbFontTransTbl[(BYTE)str[i]]]] + 1; if (width < 257) k = (257 - width) >> 1; off += k; } for (i = 0; i < len; i++) { c = fontframe[gbFontTransTbl[(BYTE)str[i]]]; k += fontkern[c] + 1; if (c && k <= 257) { PrintChar(off, c, col); } off += fontkern[c] + 1; } } void DrawULine(int y) { assert(gpBuffer); #ifdef USE_ASM int yy; yy = PitchTbl[SStringY[y] + 198] + 26 + PANEL_X; __asm { mov esi, gpBuffer mov edi, esi add esi, SCREENXY(PANEL_LEFT + 26, 25) add edi, yy mov ebx, BUFFER_WIDTH - 266 mov edx, 3 copyline: mov ecx, 266 / 4 rep movsd movsw add esi, ebx add edi, ebx dec edx jnz copyline } #else int i; BYTE *src, *dst; src = &gpBuffer[SCREENXY(PANEL_LEFT + 26, 25)]; dst = &gpBuffer[PitchTbl[SStringY[y] + 38 + SCREEN_Y] + 26 + PANEL_X]; for (i = 0; i < 3; i++, src += BUFFER_WIDTH, dst += BUFFER_WIDTH) memcpy(dst, src, 266); // BUGFIX: should be 267 #endif } void DrawUniqueInfo() { int uid, y; if (!chrflag && !questlog) { uid = curruitem._iUid; DrawUTextBack(); PrintUString(PANEL_LEFT + 0, 2, TRUE, UniqueItemList[uid].UIName, 3); DrawULine(5); PrintItemPower(UniqueItemList[uid].UIPower1, &curruitem); y = 6 - UniqueItemList[uid].UINumPL + 8; PrintUString(PANEL_LEFT + 0, y, TRUE, tempstr, 0); if (UniqueItemList[uid].UINumPL > 1) { PrintItemPower(UniqueItemList[uid].UIPower2, &curruitem); PrintUString(PANEL_LEFT + 0, y + 2, TRUE, tempstr, 0); } if (UniqueItemList[uid].UINumPL > 2) { PrintItemPower(UniqueItemList[uid].UIPower3, &curruitem); PrintUString(PANEL_LEFT + 0, y + 4, TRUE, tempstr, 0); } if (UniqueItemList[uid].UINumPL > 3) { PrintItemPower(UniqueItemList[uid].UIPower4, &curruitem); PrintUString(PANEL_LEFT + 0, y + 6, TRUE, tempstr, 0); } if (UniqueItemList[uid].UINumPL > 4) { PrintItemPower(UniqueItemList[uid].UIPower5, &curruitem); PrintUString(PANEL_LEFT + 0, y + 8, TRUE, tempstr, 0); } if (UniqueItemList[uid].UINumPL > 5) { PrintItemPower(UniqueItemList[uid].UIPower6, &curruitem); PrintUString(PANEL_LEFT + 0, y + 10, TRUE, tempstr, 0); } } } void PrintItemMisc(ItemStruct *x) { if (x->_iMiscId == IMISC_SCROLL) { strcpy(tempstr, "Right-click to read"); AddPanelString(tempstr, TRUE); } if (x->_iMiscId == IMISC_SCROLLT) { strcpy(tempstr, "Right-click to read, then"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "left-click to target"); AddPanelString(tempstr, TRUE); } if (x->_iMiscId >= IMISC_USEFIRST && x->_iMiscId <= IMISC_USELAST) { PrintItemOil(x->_iMiscId); strcpy(tempstr, "Right click to use"); AddPanelString(tempstr, TRUE); } #ifdef HELLFIRE if (x->_iMiscId > IMISC_OILFIRST && x->_iMiscId < IMISC_OILLAST) { PrintItemOil(x->_iMiscId); strcpy(tempstr, "Right click to use"); AddPanelString(tempstr, TRUE); } if (x->_iMiscId > IMISC_RUNEFIRST && x->_iMiscId < IMISC_RUNELAST) { PrintItemOil(x->_iMiscId); strcpy(tempstr, "Right click to use"); AddPanelString(tempstr, TRUE); } #endif if (x->_iMiscId == IMISC_BOOK) { strcpy(tempstr, "Right click to read"); AddPanelString(tempstr, TRUE); } #ifdef HELLFIRE if (x->_iMiscId == IMISC_NOTE) { strcpy(tempstr, "Right click to read"); AddPanelString(tempstr, TRUE); } #endif if (x->_iMiscId == IMISC_MAPOFDOOM) { strcpy(tempstr, "Right click to view"); AddPanelString(tempstr, TRUE); } if (x->_iMiscId == IMISC_EAR) { sprintf(tempstr, "Level : %i", x->_ivalue); AddPanelString(tempstr, TRUE); } #ifdef HELLFIRE if (x->_iMiscId == IMISC_AURIC) { sprintf(tempstr, "Doubles gold capacity"); AddPanelString(tempstr, TRUE); } #endif } void PrintItemDetails(ItemStruct *x) { char str, dex; BYTE mag; if (x->_iClass == ICLASS_WEAPON) { #ifdef HELLFIRE if (x->_iMinDam == x->_iMaxDam) { if (x->_iMaxDur == DUR_INDESTRUCTIBLE) sprintf(tempstr, "damage: %i Indestructible", x->_iMinDam); else sprintf(tempstr, "damage: %i Dur: %i/%i", x->_iMinDam, x->_iDurability, x->_iMaxDur); } else #endif if (x->_iMaxDur == DUR_INDESTRUCTIBLE) 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, TRUE); } if (x->_iClass == ICLASS_ARMOR) { if (x->_iMaxDur == DUR_INDESTRUCTIBLE) sprintf(tempstr, "armor: %i Indestructible", x->_iAC); else sprintf(tempstr, "armor: %i Dur: %i/%i", x->_iAC, x->_iDurability, x->_iMaxDur); AddPanelString(tempstr, TRUE); } if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) { #ifdef HELLFIRE if (x->_iMinDam == x->_iMaxDam) sprintf(tempstr, "dam: %i Dur: %i/%i", x->_iMinDam, x->_iDurability, x->_iMaxDur); else #endif sprintf(tempstr, "dam: %i-%i Dur: %i/%i", x->_iMinDam, x->_iMaxDam, x->_iDurability, x->_iMaxDur); sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges); AddPanelString(tempstr, TRUE); } if (x->_iPrePower != -1) { PrintItemPower(x->_iPrePower, x); AddPanelString(tempstr, TRUE); } if (x->_iSufPower != -1) { PrintItemPower(x->_iSufPower, x); AddPanelString(tempstr, TRUE); } if (x->_iMagical == ITEM_QUALITY_UNIQUE) { AddPanelString("unique item", TRUE); uitemflag = TRUE; curruitem = *x; } PrintItemMisc(x); mag = x->_iMinMag; dex = x->_iMinDex; str = x->_iMinStr; if (mag + dex + str) { strcpy(tempstr, "Required:"); if (x->_iMinStr) sprintf(tempstr, "%s %i Str", tempstr, x->_iMinStr); if (x->_iMinMag) sprintf(tempstr, "%s %i Mag", tempstr, x->_iMinMag); if (x->_iMinDex) sprintf(tempstr, "%s %i Dex", tempstr, x->_iMinDex); AddPanelString(tempstr, TRUE); } pinfoflag = TRUE; } void PrintItemDur(ItemStruct *x) { char str, dex; BYTE mag; if (x->_iClass == ICLASS_WEAPON) { #ifdef HELLFIRE if (x->_iMinDam == x->_iMaxDam) { if (x->_iMaxDur == DUR_INDESTRUCTIBLE) sprintf(tempstr, "damage: %i Indestructible", x->_iMinDam); else sprintf(tempstr, "damage: %i Dur: %i/%i", x->_iMinDam, x->_iDurability, x->_iMaxDur); } else #endif if (x->_iMaxDur == DUR_INDESTRUCTIBLE) 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, TRUE); if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) { sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges); AddPanelString(tempstr, TRUE); } if (x->_iMagical != ITEM_QUALITY_NORMAL) AddPanelString("Not Identified", TRUE); } if (x->_iClass == ICLASS_ARMOR) { if (x->_iMaxDur == DUR_INDESTRUCTIBLE) sprintf(tempstr, "armor: %i Indestructible", x->_iAC); else sprintf(tempstr, "armor: %i Dur: %i/%i", x->_iAC, x->_iDurability, x->_iMaxDur); AddPanelString(tempstr, TRUE); if (x->_iMagical != ITEM_QUALITY_NORMAL) AddPanelString("Not Identified", TRUE); if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) { sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges); AddPanelString(tempstr, TRUE); } } if (x->_itype == ITYPE_RING || x->_itype == ITYPE_AMULET) AddPanelString("Not Identified", TRUE); PrintItemMisc(x); str = x->_iMinStr; mag = x->_iMinMag; dex = x->_iMinDex; if (str + mag + dex) { strcpy(tempstr, "Required:"); if (x->_iMinStr) sprintf(tempstr, "%s %i Str", tempstr, x->_iMinStr); if (x->_iMinMag) sprintf(tempstr, "%s %i Mag", tempstr, x->_iMinMag); if (x->_iMinDex) sprintf(tempstr, "%s %i Dex", tempstr, x->_iMinDex); AddPanelString(tempstr, TRUE); } pinfoflag = TRUE; } void UseItem(int p, int Mid, int spl) { int l, j; switch (Mid) { case IMISC_HEAL: case IMISC_FOOD: j = plr[p]._pMaxHP >> 8; l = ((j >> 1) + random_(39, j)) << 6; #ifdef HELLFIRE if (plr[p]._pClass == PC_WARRIOR || plr[p]._pClass == PC_BARBARIAN) #else if (plr[p]._pClass == PC_WARRIOR) #endif l <<= 1; #ifdef HELLFIRE if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK || plr[p]._pClass == PC_BARD) #else if (plr[p]._pClass == PC_ROGUE) #endif l += l >> 1; plr[p]._pHitPoints += l; if (plr[p]._pHitPoints > plr[p]._pMaxHP) plr[p]._pHitPoints = plr[p]._pMaxHP; plr[p]._pHPBase += l; if (plr[p]._pHPBase > plr[p]._pMaxHPBase) plr[p]._pHPBase = plr[p]._pMaxHPBase; drawhpflag = TRUE; break; case IMISC_FULLHEAL: plr[p]._pHitPoints = plr[p]._pMaxHP; plr[p]._pHPBase = plr[p]._pMaxHPBase; drawhpflag = TRUE; break; case IMISC_MANA: j = plr[p]._pMaxMana >> 8; l = ((j >> 1) + random_(40, j)) << 6; if (plr[p]._pClass == PC_SORCERER) l <<= 1; #ifdef HELLFIRE if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK || plr[p]._pClass == PC_BARD) #else if (plr[p]._pClass == PC_ROGUE) #endif l += l >> 1; if (!(plr[p]._pIFlags & ISPL_NOMANA)) { plr[p]._pMana += l; if (plr[p]._pMana > plr[p]._pMaxMana) plr[p]._pMana = plr[p]._pMaxMana; plr[p]._pManaBase += l; if (plr[p]._pManaBase > plr[p]._pMaxManaBase) plr[p]._pManaBase = plr[p]._pMaxManaBase; drawmanaflag = TRUE; } break; case IMISC_FULLMANA: if (!(plr[p]._pIFlags & ISPL_NOMANA)) { plr[p]._pMana = plr[p]._pMaxMana; plr[p]._pManaBase = plr[p]._pMaxManaBase; drawmanaflag = TRUE; } break; case IMISC_ELIXSTR: ModifyPlrStr(p, 1); break; case IMISC_ELIXMAG: ModifyPlrMag(p, 1); #ifdef HELLFIRE plr[p]._pMana = plr[p]._pMaxMana; plr[p]._pManaBase = plr[p]._pMaxManaBase; drawmanaflag = TRUE; #endif break; case IMISC_ELIXDEX: ModifyPlrDex(p, 1); break; case IMISC_ELIXVIT: ModifyPlrVit(p, 1); #ifdef HELLFIRE plr[p]._pHitPoints = plr[p]._pMaxHP; plr[p]._pHPBase = plr[p]._pMaxHPBase; drawhpflag = TRUE; #endif break; case IMISC_REJUV: j = plr[p]._pMaxHP >> 8; l = ((j >> 1) + random_(39, j)) << 6; #ifdef HELLFIRE if (plr[p]._pClass == PC_WARRIOR || plr[p]._pClass == PC_BARBARIAN) #else if (plr[p]._pClass == PC_WARRIOR) #endif l <<= 1; if (plr[p]._pClass == PC_ROGUE) l += l >> 1; plr[p]._pHitPoints += l; if (plr[p]._pHitPoints > plr[p]._pMaxHP) plr[p]._pHitPoints = plr[p]._pMaxHP; plr[p]._pHPBase += l; if (plr[p]._pHPBase > plr[p]._pMaxHPBase) plr[p]._pHPBase = plr[p]._pMaxHPBase; drawhpflag = TRUE; j = plr[p]._pMaxMana >> 8; l = ((j >> 1) + random_(40, j)) << 6; if (plr[p]._pClass == PC_SORCERER) l <<= 1; if (plr[p]._pClass == PC_ROGUE) l += l >> 1; if (!(plr[p]._pIFlags & ISPL_NOMANA)) { plr[p]._pMana += l; if (plr[p]._pMana > plr[p]._pMaxMana) plr[p]._pMana = plr[p]._pMaxMana; plr[p]._pManaBase += l; if (plr[p]._pManaBase > plr[p]._pMaxManaBase) plr[p]._pManaBase = plr[p]._pMaxManaBase; drawmanaflag = TRUE; } break; case IMISC_FULLREJUV: plr[p]._pHitPoints = plr[p]._pMaxHP; plr[p]._pHPBase = plr[p]._pMaxHPBase; drawhpflag = TRUE; if (!(plr[p]._pIFlags & ISPL_NOMANA)) { plr[p]._pMana = plr[p]._pMaxMana; plr[p]._pManaBase = plr[p]._pMaxManaBase; drawmanaflag = TRUE; } break; case IMISC_SCROLL: if (spelldata[spl].sTargeted) { plr[p]._pTSpell = spl; plr[p]._pTSplType = RSPLTYPE_INVALID; if (p == myplr) NewCursor(CURSOR_TELEPORT); } else { ClrPlrPath(p); plr[p]._pSpell = spl; plr[p]._pSplType = RSPLTYPE_INVALID; plr[p]._pSplFrom = 3; plr[p].destAction = ACTION_SPELL; plr[p].destParam1 = cursmx; plr[p].destParam2 = cursmy; #ifndef HELLFIRE if (p == myplr && spl == SPL_NOVA) NetSendCmdLoc(TRUE, CMD_NOVA, cursmx, cursmy); #endif } break; case IMISC_SCROLLT: if (spelldata[spl].sTargeted) { plr[p]._pTSpell = spl; plr[p]._pTSplType = RSPLTYPE_INVALID; if (p == myplr) NewCursor(CURSOR_TELEPORT); } else { ClrPlrPath(p); plr[p]._pSpell = spl; plr[p]._pSplType = RSPLTYPE_INVALID; plr[p]._pSplFrom = 3; plr[p].destAction = ACTION_SPELL; plr[p].destParam1 = cursmx; plr[p].destParam2 = cursmy; } break; case IMISC_BOOK: plr[p]._pMemSpells |= SPELLBIT(spl); if (plr[p]._pSplLvl[spl] < MAX_SPELL_LEVEL) plr[p]._pSplLvl[spl]++; plr[p]._pMana += spelldata[spl].sManaCost << 6; if (plr[p]._pMana > plr[p]._pMaxMana) plr[p]._pMana = plr[p]._pMaxMana; plr[p]._pManaBase += spelldata[spl].sManaCost << 6; if (plr[p]._pManaBase > plr[p]._pMaxManaBase) plr[p]._pManaBase = plr[p]._pMaxManaBase; if (p == myplr) CalcPlrBookVals(p); drawmanaflag = TRUE; break; case IMISC_MAPOFDOOM: doom_init(); break; #ifdef HELLFIRE case IMISC_OILACC: case IMISC_OILMAST: case IMISC_OILSHARP: case IMISC_OILDEATH: case IMISC_OILSKILL: case IMISC_OILBSMTH: case IMISC_OILFORT: case IMISC_OILPERM: case IMISC_OILHARD: case IMISC_OILIMP: plr[p]._pOilType = Mid; if (p != myplr) { return; } if (sbookflag) { sbookflag = FALSE; } if (!invflag) { invflag = TRUE; } NewCursor(CURSOR_OIL); break; #endif case IMISC_SPECELIX: ModifyPlrStr(p, 3); ModifyPlrMag(p, 3); ModifyPlrDex(p, 3); ModifyPlrVit(p, 3); break; #ifdef HELLFIRE case IMISC_RUNEF: plr[p]._pTSpell = SPL_RUNEFIRE; plr[p]._pTSplType = RSPLTYPE_INVALID; if (p == myplr) NewCursor(CURSOR_TELEPORT); break; case IMISC_RUNEL: plr[p]._pTSpell = SPL_RUNELIGHT; plr[p]._pTSplType = RSPLTYPE_INVALID; if (p == myplr) NewCursor(CURSOR_TELEPORT); break; case IMISC_GR_RUNEL: plr[p]._pTSpell = SPL_RUNENOVA; plr[p]._pTSplType = RSPLTYPE_INVALID; if (p == myplr) NewCursor(CURSOR_TELEPORT); break; case IMISC_GR_RUNEF: plr[p]._pTSpell = SPL_RUNEIMMOLAT; plr[p]._pTSplType = RSPLTYPE_INVALID; if (p == myplr) NewCursor(CURSOR_TELEPORT); break; case IMISC_RUNES: plr[p]._pTSpell = SPL_RUNESTONE; plr[p]._pTSplType = RSPLTYPE_INVALID; if (p == myplr) NewCursor(CURSOR_TELEPORT); break; #endif } } BOOL StoreStatOk(ItemStruct *h) { BOOL sf; sf = TRUE; if (plr[myplr]._pStrength < h->_iMinStr) sf = FALSE; if (plr[myplr]._pMagic < h->_iMinMag) sf = FALSE; if (plr[myplr]._pDexterity < h->_iMinDex) sf = FALSE; return sf; } BOOL SmithItemOk(int i) { BOOL rv; rv = TRUE; if (AllItemsList[i].itype == ITYPE_MISC) rv = FALSE; if (AllItemsList[i].itype == ITYPE_GOLD) rv = FALSE; if (AllItemsList[i].itype == ITYPE_FOOD) rv = FALSE; #ifdef HELLFIRE if (AllItemsList[i].itype == ITYPE_STAFF && AllItemsList[i].iSpell) #else if (AllItemsList[i].itype == ITYPE_STAFF) #endif rv = FALSE; if (AllItemsList[i].itype == ITYPE_RING) rv = FALSE; if (AllItemsList[i].itype == ITYPE_AMULET) rv = FALSE; return rv; } int RndSmithItem(int lvl) { int i, ri; int ril[512]; ri = 0; for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) { if (AllItemsList[i].iRnd != IDROP_NEVER && SmithItemOk(i) && lvl >= AllItemsList[i].iMinMLvl #ifdef HELLFIRE && ri < 512 #endif ) { ril[ri] = i; ri++; if (AllItemsList[i].iRnd == IDROP_DOUBLE #ifdef HELLFIRE && ri < 512 #endif ) { ril[ri] = i; ri++; } } } return ril[random_(50, ri)] + 1; } void BubbleSwapItem(ItemStruct *a, ItemStruct *b) { ItemStruct h; h = *a; *a = *b; *b = h; } void SortSmith() { int j, k; BOOL sorted; j = 0; while (smithitem[j + 1]._itype != ITYPE_NONE) { j++; } sorted = FALSE; while (j > 0 && !sorted) { sorted = TRUE; for (k = 0; k < j; k++) { if (smithitem[k].IDidx > smithitem[k + 1].IDidx) { BubbleSwapItem(&smithitem[k], &smithitem[k + 1]); sorted = FALSE; } } j--; } } void SpawnSmith(int lvl) { int i, iCnt, idata; #ifdef HELLFIRE ItemStruct holditem; holditem = item[0]; #endif iCnt = random_(50, SMITH_ITEMS - 10) + 10; for (i = 0; i < iCnt; i++) { do { item[0]._iSeed = GetRndSeed(); SetRndSeed(item[0]._iSeed); idata = RndSmithItem(lvl) - 1; GetItemAttrs(0, idata, lvl); } while (item[0]._iIvalue > SMITH_MAX_VALUE); smithitem[i] = item[0]; smithitem[i]._iCreateInfo = lvl | CF_SMITH; smithitem[i]._iIdentified = TRUE; smithitem[i]._iStatFlag = StoreStatOk(&smithitem[i]); } for (i = iCnt; i < SMITH_ITEMS; i++) smithitem[i]._itype = ITYPE_NONE; SortSmith(); #ifdef HELLFIRE item[0] = holditem; #endif } BOOL PremiumItemOk(int i) { BOOL rv; rv = TRUE; #ifdef HELLFIRE if (AllItemsList[i].itype == ITYPE_MISC || AllItemsList[i].itype == ITYPE_GOLD || AllItemsList[i].itype == ITYPE_FOOD) rv = FALSE; if (gbMaxPlayers != 1) { if (AllItemsList[i].iMiscId == IMISC_OILOF || AllItemsList[i].itype == ITYPE_RING || AllItemsList[i].itype == ITYPE_AMULET) rv = FALSE; } #else if (AllItemsList[i].itype == ITYPE_MISC) rv = FALSE; if (AllItemsList[i].itype == ITYPE_GOLD) rv = FALSE; if (AllItemsList[i].itype == ITYPE_FOOD) rv = FALSE; if (AllItemsList[i].itype == ITYPE_STAFF) rv = FALSE; if (gbMaxPlayers != 1) { if (AllItemsList[i].itype == ITYPE_RING) rv = FALSE; if (AllItemsList[i].itype == ITYPE_AMULET) rv = FALSE; } #endif return rv; } int RndPremiumItem(int minlvl, int maxlvl) { int i, ri; int ril[512]; ri = 0; for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) { if (AllItemsList[i].iRnd != IDROP_NEVER) { if (PremiumItemOk(i)) { #ifdef HELLFIRE if (AllItemsList[i].iMinMLvl >= minlvl && AllItemsList[i].iMinMLvl <= maxlvl && ri < 512) { #else if (AllItemsList[i].iMinMLvl >= minlvl && AllItemsList[i].iMinMLvl <= maxlvl) { #endif ril[ri] = i; ri++; } } } } return ril[random_(50, ri)] + 1; } #ifdef HELLFIRE static void SpawnOnePremium(int i, int plvl, int myplr, bool noSpells) #else static void SpawnOnePremium(int i, int plvl) #endif { int itype; ItemStruct holditem; holditem = item[0]; #ifdef HELLFIRE int ivalue; int count = 0; int strength = get_max_strength(plr[myplr]._pClass); int dexterity = get_max_dexterity(plr[myplr]._pClass); int magic = get_max_magic(plr[myplr]._pClass); if (strength < plr[myplr]._pStrength) { strength = plr[myplr]._pStrength; } strength *= 1.2; if (dexterity < plr[myplr]._pDexterity) { dexterity = plr[myplr]._pDexterity; } dexterity *= 1.2; if (magic < plr[myplr]._pMagic) { magic = plr[myplr]._pMagic; } magic *= 1.2; #endif 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); #ifdef HELLFIRE GetItemBonus(0, itype, plvl >> 1, plvl, TRUE, noSpells); #else GetItemBonus(0, itype, plvl >> 1, plvl, TRUE); #endif #ifdef HELLFIRE ivalue = 0; switch (item[0]._itype) { case ITYPE_LARMOR: case ITYPE_MARMOR: case ITYPE_HARMOR: ivalue = get_armor_max_value(myplr); break; case ITYPE_SHIELD: ivalue = get_shield_max_value(myplr); break; case ITYPE_AXE: ivalue = get_axe_max_value(myplr); break; case ITYPE_BOW: ivalue = get_bow_max_value(myplr); break; case ITYPE_MACE: ivalue = get_mace_max_value(myplr); break; case ITYPE_SWORD: ivalue = get_sword_max_value(myplr); break; case ITYPE_HELM: ivalue = get_helm_max_value(myplr); break; case ITYPE_STAFF: ivalue = get_staff_max_value(myplr); break; case ITYPE_RING: ivalue = get_ring_max_value(myplr); break; case ITYPE_AMULET: ivalue = get_amulet_max_value(myplr); break; } ivalue *= 0.8; count++; } while ((item[0]._iIvalue > SMITH_MAX_PREMIUM_VALUE || item[0]._iMinStr > strength || item[0]._iMinMag > magic || item[0]._iMinDex > dexterity || item[0]._iIvalue < ivalue) && count < 150); #else } while (item[0]._iIvalue > SMITH_MAX_PREMIUM_VALUE); #endif premiumitem[i] = item[0]; premiumitem[i]._iCreateInfo = plvl | CF_SMITHPREMIUM; premiumitem[i]._iIdentified = TRUE; premiumitem[i]._iStatFlag = StoreStatOk(&premiumitem[i]); item[0] = holditem; } #ifdef HELLFIRE void SpawnPremium(int pnum) #else void SpawnPremium(int lvl) #endif { int i; #ifdef HELLFIRE int lvl = plr[pnum]._pLevel; #endif if (numpremium < SMITH_PREMIUM_ITEMS) { for (i = 0; i < SMITH_PREMIUM_ITEMS; i++) { if (premiumitem[i]._itype == ITYPE_NONE) #ifdef HELLFIRE SpawnOnePremium(i, premiumlevel + premiumlvladd[i], pnum, FALSE); #else SpawnOnePremium(i, premiumlevel + premiumlvladd[i]); #endif } numpremium = SMITH_PREMIUM_ITEMS; } while (premiumlevel < lvl) { premiumlevel++; #ifdef HELLFIRE premiumitem[0] = premiumitem[3]; premiumitem[1] = premiumitem[4]; premiumitem[2] = premiumitem[5]; premiumitem[3] = premiumitem[6]; premiumitem[4] = premiumitem[7]; premiumitem[5] = premiumitem[8]; premiumitem[6] = premiumitem[9]; premiumitem[7] = premiumitem[10]; premiumitem[8] = premiumitem[11]; premiumitem[9] = premiumitem[12]; SpawnOnePremium(10, premiumlevel + premiumlvladd[10], pnum, FALSE); premiumitem[11] = premiumitem[13]; SpawnOnePremium(12, premiumlevel + premiumlvladd[12], pnum, FALSE); premiumitem[13] = premiumitem[14]; SpawnOnePremium(14, premiumlevel + premiumlvladd[14], pnum, FALSE); #else premiumitem[0] = premiumitem[2]; premiumitem[1] = premiumitem[3]; premiumitem[2] = premiumitem[4]; SpawnOnePremium(3, premiumlevel + premiumlvladd[3]); premiumitem[4] = premiumitem[5]; SpawnOnePremium(5, premiumlevel + premiumlvladd[5]); #endif } } BOOL WitchItemOk(int i) { BOOL rv; rv = FALSE; #ifdef HELLFIRE if (AllItemsList[i].itype == ITYPE_MISC || AllItemsList[i].itype == ITYPE_STAFF) rv = TRUE; if (AllItemsList[i].iMiscId == IMISC_MANA || AllItemsList[i].iMiscId == IMISC_FULLMANA) rv = FALSE; if (AllItemsList[i].iSpell == SPL_TOWN) rv = FALSE; if (AllItemsList[i].iMiscId == IMISC_FULLHEAL || AllItemsList[i].iMiscId == IMISC_HEAL) rv = FALSE; if (AllItemsList[i].iMiscId > IMISC_OILFIRST && AllItemsList[i].iMiscId < IMISC_OILLAST) rv = FALSE; if ((AllItemsList[i].iSpell == SPL_RESURRECT && gbMaxPlayers == 1) || (AllItemsList[i].iSpell == SPL_HEALOTHER && gbMaxPlayers == 1)) rv = FALSE; #else if (AllItemsList[i].itype == ITYPE_MISC) rv = TRUE; if (AllItemsList[i].itype == ITYPE_STAFF) rv = TRUE; if (AllItemsList[i].iMiscId == IMISC_MANA) rv = FALSE; if (AllItemsList[i].iMiscId == IMISC_FULLMANA) rv = FALSE; if (AllItemsList[i].iSpell == SPL_TOWN) rv = FALSE; if (AllItemsList[i].iMiscId == IMISC_FULLHEAL) rv = FALSE; if (AllItemsList[i].iMiscId == IMISC_HEAL) rv = FALSE; if (AllItemsList[i].iSpell == SPL_RESURRECT && gbMaxPlayers == 1) rv = FALSE; if (AllItemsList[i].iSpell == SPL_HEALOTHER && gbMaxPlayers == 1) rv = FALSE; #endif return rv; } int RndWitchItem(int lvl) { int i, ri; int ril[512]; ri = 0; for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) { if (AllItemsList[i].iRnd != IDROP_NEVER && WitchItemOk(i) && lvl >= AllItemsList[i].iMinMLvl #ifdef HELLFIRE && ri < 512 #endif ) { ril[ri] = i; ri++; } } return ril[random_(51, ri)] + 1; } void SortWitch() { int j, k; BOOL sorted; j = 3; while (witchitem[j + 1]._itype != ITYPE_NONE) { j++; } sorted = FALSE; while (j > 3 && !sorted) { sorted = TRUE; for (k = 3; k < j; k++) { if (witchitem[k].IDidx > witchitem[k + 1].IDidx) { BubbleSwapItem(&witchitem[k], &witchitem[k + 1]); sorted = FALSE; } } j--; } } void WitchBookLevel(int ii) { int slvl; if (witchitem[ii]._iMiscId == IMISC_BOOK) { witchitem[ii]._iMinMag = spelldata[witchitem[ii]._iSpell].sMinInt; slvl = plr[myplr]._pSplLvl[witchitem[ii]._iSpell]; while (slvl) { witchitem[ii]._iMinMag += 20 * witchitem[ii]._iMinMag / 100; slvl--; if (witchitem[ii]._iMinMag + 20 * witchitem[ii]._iMinMag / 100 > 255) { witchitem[ii]._iMinMag = 255; slvl = 0; } } } } void SpawnWitch(int lvl) { int i, j, iCnt; int idata, maxlvl; j = 3; #ifdef HELLFIRE iCnt = random_(51, WITCH_ITEMS - 10) + 10; int books = random_(3, 4); #endif GetItemAttrs(0, IDI_MANA, 1); witchitem[0] = item[0]; witchitem[0]._iCreateInfo = lvl; witchitem[0]._iStatFlag = TRUE; GetItemAttrs(0, IDI_FULLMANA, 1); witchitem[1] = item[0]; witchitem[1]._iCreateInfo = lvl; witchitem[1]._iStatFlag = TRUE; GetItemAttrs(0, IDI_PORTAL, 1); witchitem[2] = item[0]; witchitem[2]._iCreateInfo = lvl; witchitem[2]._iStatFlag = TRUE; #ifdef HELLFIRE int bCnt; for (i = 114, bCnt = 0; i <= 117 && bCnt < books; ++i) { if (WitchItemOk(i) && lvl >= AllItemsList[i].iMinMLvl) { item[0]._iSeed = GetRndSeed(); SetRndSeed(item[0]._iSeed); volatile int junk = random_(0, 1); GetItemAttrs(0, i, lvl); witchitem[j] = item[0]; witchitem[j]._iCreateInfo = lvl | CF_WITCH; witchitem[j]._iIdentified = TRUE; WitchBookLevel(j); witchitem[j]._iStatFlag = StoreStatOk(&witchitem[j]); j++; bCnt++; } } #else iCnt = random_(51, 8) + 10; #endif for (i = j; i < iCnt; i++) { do { item[0]._iSeed = GetRndSeed(); SetRndSeed(item[0]._iSeed); idata = RndWitchItem(lvl) - 1; GetItemAttrs(0, idata, lvl); maxlvl = -1; if (random_(51, 100) <= 5) maxlvl = 2 * lvl; if (maxlvl == -1 && item[0]._iMiscId == IMISC_STAFF) maxlvl = 2 * lvl; if (maxlvl != -1) #ifdef HELLFIRE GetItemBonus(0, idata, maxlvl >> 1, maxlvl, TRUE, TRUE); #else GetItemBonus(0, idata, maxlvl >> 1, maxlvl, TRUE); #endif } while (item[0]._iIvalue > WITCH_MAX_VALUE); witchitem[i] = item[0]; witchitem[i]._iCreateInfo = lvl | CF_WITCH; witchitem[i]._iIdentified = TRUE; WitchBookLevel(i); witchitem[i]._iStatFlag = StoreStatOk(&witchitem[i]); } for (i = iCnt; i < WITCH_ITEMS; i++) witchitem[i]._itype = ITYPE_NONE; SortWitch(); } int RndBoyItem(int lvl) { int i, ri; int ril[512]; ri = 0; for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) { if (AllItemsList[i].iRnd != IDROP_NEVER && PremiumItemOk(i) && lvl >= AllItemsList[i].iMinMLvl #ifdef HELLFIRE && ri < 512 #endif ) { ril[ri] = i; ri++; } } return ril[random_(49, ri)] + 1; } void SpawnBoy(int lvl) { int itype; #ifdef HELLFIRE int ivalue; int count = 0; int strength = get_max_strength(plr[myplr]._pClass); int dexterity = get_max_dexterity(plr[myplr]._pClass); int magic = get_max_magic(plr[myplr]._pClass); int pc = plr[myplr]._pClass; if (strength < plr[myplr]._pStrength) { strength = plr[myplr]._pStrength; } strength *= 1.2; if (dexterity < plr[myplr]._pDexterity) { dexterity = plr[myplr]._pDexterity; } dexterity *= 1.2; if (magic < plr[myplr]._pMagic) { magic = plr[myplr]._pMagic; } magic *= 1.2; #endif if (boylevel < (lvl >> 1) || boyitem._itype == ITYPE_NONE) { do { item[0]._iSeed = GetRndSeed(); SetRndSeed(item[0]._iSeed); itype = RndBoyItem(lvl) - 1; GetItemAttrs(0, itype, lvl); #ifdef HELLFIRE GetItemBonus(0, itype, lvl, 2 * lvl, TRUE, TRUE); ivalue = 0; int itemType = item[0]._itype; switch (itemType) { case ITYPE_LARMOR: case ITYPE_MARMOR: case ITYPE_HARMOR: ivalue = get_armor_max_value(myplr); break; case ITYPE_SHIELD: ivalue = get_shield_max_value(myplr); break; case ITYPE_AXE: ivalue = get_axe_max_value(myplr); break; case ITYPE_BOW: ivalue = get_bow_max_value(myplr); break; case ITYPE_MACE: ivalue = get_mace_max_value(myplr); break; case ITYPE_SWORD: ivalue = get_sword_max_value(myplr); break; case ITYPE_HELM: ivalue = get_helm_max_value(myplr); break; case ITYPE_STAFF: ivalue = get_staff_max_value(myplr); break; case ITYPE_RING: ivalue = get_ring_max_value(myplr); break; case ITYPE_AMULET: ivalue = get_amulet_max_value(myplr); break; } ivalue *= 0.8; count++; if (count < 200) { switch (pc) { case PC_WARRIOR: if (itemType == ITYPE_BOW || itemType == ITYPE_STAFF) ivalue = INT_MAX; break; case PC_ROGUE: if (itemType == ITYPE_SWORD || itemType == ITYPE_STAFF || itemType == ITYPE_AXE || itemType == ITYPE_MACE || itemType == ITYPE_SHIELD) ivalue = INT_MAX; break; case PC_SORCERER: if (itemType == ITYPE_STAFF || itemType == ITYPE_AXE || itemType == ITYPE_BOW || itemType == ITYPE_MACE) ivalue = INT_MAX; break; case PC_MONK: if (itemType == ITYPE_BOW || itemType == ITYPE_MARMOR || itemType == ITYPE_SHIELD || itemType == ITYPE_MACE) ivalue = INT_MAX; break; case PC_BARD: if (itemType == ITYPE_AXE || itemType == ITYPE_MACE || itemType == ITYPE_STAFF) ivalue = INT_MAX; break; case PC_BARBARIAN: if (itemType == ITYPE_BOW || itemType == ITYPE_STAFF) ivalue = INT_MAX; break; } } } while ((item[0]._iIvalue > BOY_MAX_VALUE || item[0]._iMinStr > strength || item[0]._iMinMag > magic || item[0]._iMinDex > dexterity || item[0]._iIvalue < ivalue) && count < 250); #else GetItemBonus(0, itype, lvl, 2 * lvl, TRUE); } while (item[0]._iIvalue > BOY_MAX_VALUE); #endif boyitem = item[0]; boyitem._iCreateInfo = lvl | CF_BOY; boyitem._iIdentified = TRUE; boyitem._iStatFlag = StoreStatOk(&boyitem); boylevel = lvl >> 1; } } BOOL HealerItemOk(int i) { BOOL result; result = FALSE; if (AllItemsList[i].itype != ITYPE_MISC) return FALSE; if (AllItemsList[i].iMiscId == IMISC_SCROLL && AllItemsList[i].iSpell == SPL_HEAL) result = TRUE; if (AllItemsList[i].iMiscId == IMISC_SCROLLT && AllItemsList[i].iSpell == SPL_RESURRECT && gbMaxPlayers != 1) result = FALSE; if (AllItemsList[i].iMiscId == IMISC_SCROLLT && AllItemsList[i].iSpell == SPL_HEALOTHER && gbMaxPlayers != 1) result = TRUE; if (gbMaxPlayers == 1) { #ifdef HELLFIRE if (AllItemsList[i].iMiscId == IMISC_ELIXSTR && plr[myplr]._pBaseStr < MaxStats[plr[myplr]._pClass][ATTRIB_STR]) result = TRUE; else if (AllItemsList[i].iMiscId == IMISC_ELIXMAG && plr[myplr]._pBaseMag < MaxStats[plr[myplr]._pClass][ATTRIB_MAG]) result = TRUE; else if (AllItemsList[i].iMiscId == IMISC_ELIXDEX && plr[myplr]._pBaseDex < MaxStats[plr[myplr]._pClass][ATTRIB_DEX]) result = TRUE; else if (AllItemsList[i].iMiscId == IMISC_ELIXVIT && plr[myplr]._pBaseVit < MaxStats[plr[myplr]._pClass][ATTRIB_VIT]) result = TRUE; } if (AllItemsList[i].iMiscId == IMISC_FULLHEAL) // BUGFIX this is a duplicate with the wrong case result = TRUE; else if (AllItemsList[i].iMiscId == IMISC_REJUV) result = TRUE; else if (AllItemsList[i].iMiscId == IMISC_FULLREJUV) result = TRUE; else if (AllItemsList[i].iMiscId == IMISC_HEAL) result = FALSE; else if (AllItemsList[i].iMiscId == IMISC_FULLHEAL) result = FALSE; else if (AllItemsList[i].iMiscId == IMISC_MANA) result = FALSE; else if (AllItemsList[i].iMiscId == IMISC_FULLMANA) result = FALSE; #else if (AllItemsList[i].iMiscId == IMISC_ELIXSTR) result = TRUE; if (AllItemsList[i].iMiscId == IMISC_ELIXMAG) result = TRUE; if (AllItemsList[i].iMiscId == IMISC_ELIXDEX) result = TRUE; if (AllItemsList[i].iMiscId == IMISC_ELIXVIT) result = TRUE; } if (AllItemsList[i].iMiscId == IMISC_FULLHEAL) // BUGFIX this is a duplicate with the wrong case result = TRUE; if (AllItemsList[i].iMiscId == IMISC_REJUV) result = TRUE; if (AllItemsList[i].iMiscId == IMISC_FULLREJUV) result = TRUE; if (AllItemsList[i].iMiscId == IMISC_HEAL) result = FALSE; if (AllItemsList[i].iMiscId == IMISC_FULLHEAL) result = FALSE; if (AllItemsList[i].iMiscId == IMISC_MANA) result = FALSE; if (AllItemsList[i].iMiscId == IMISC_FULLMANA) result = FALSE; #endif return result; } int RndHealerItem(int lvl) { int i, ri; int ril[512]; ri = 0; for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) { if (AllItemsList[i].iRnd != IDROP_NEVER && HealerItemOk(i) && lvl >= AllItemsList[i].iMinMLvl #ifdef HELLFIRE && ri < 512 #endif ) { ril[ri] = i; ri++; } } return ril[random_(50, ri)] + 1; } void SortHealer() { int j, k; BOOL sorted; j = 2; while (healitem[j + 1]._itype != ITYPE_NONE) { j++; } sorted = FALSE; while (j > 2 && !sorted) { sorted = TRUE; for (k = 2; k < j; k++) { if (healitem[k].IDidx > healitem[k + 1].IDidx) { BubbleSwapItem(&healitem[k], &healitem[k + 1]); sorted = FALSE; } } j--; } } void SpawnHealer(int lvl) { int i, nsi, srnd, itype; GetItemAttrs(0, IDI_HEAL, 1); healitem[0] = item[0]; healitem[0]._iCreateInfo = lvl; healitem[0]._iStatFlag = TRUE; GetItemAttrs(0, IDI_FULLHEAL, 1); healitem[1] = item[0]; healitem[1]._iCreateInfo = lvl; healitem[1]._iStatFlag = TRUE; if (gbMaxPlayers != 1) { GetItemAttrs(0, IDI_RESURRECT, 1); healitem[2] = item[0]; healitem[2]._iCreateInfo = lvl; healitem[2]._iStatFlag = TRUE; srnd = 3; } else { srnd = 2; } #ifdef HELLFIRE nsi = random_(50, 10) + 10; #else nsi = random_(50, 8) + 10; #endif for (i = srnd; i < nsi; i++) { item[0]._iSeed = GetRndSeed(); SetRndSeed(item[0]._iSeed); itype = RndHealerItem(lvl) - 1; GetItemAttrs(0, itype, lvl); healitem[i] = item[0]; healitem[i]._iCreateInfo = lvl | CF_HEALER; healitem[i]._iIdentified = TRUE; healitem[i]._iStatFlag = StoreStatOk(&healitem[i]); } for (i = nsi; i < 20; i++) { healitem[i]._itype = ITYPE_NONE; } SortHealer(); } void SpawnStoreGold() { GetItemAttrs(0, IDI_GOLD, 1); golditem = item[0]; golditem._iStatFlag = TRUE; } void RecreateSmithItem(int ii, int idx, int lvl, int iseed) { int itype; SetRndSeed(iseed); itype = RndSmithItem(lvl) - 1; GetItemAttrs(ii, itype, lvl); item[ii]._iSeed = iseed; item[ii]._iCreateInfo = lvl | CF_SMITH; item[ii]._iIdentified = TRUE; } void RecreatePremiumItem(int ii, int idx, int plvl, int iseed) { int itype; SetRndSeed(iseed); itype = RndPremiumItem(plvl >> 2, plvl) - 1; GetItemAttrs(ii, itype, plvl); #ifdef HELLFIRE GetItemBonus(ii, itype, plvl >> 1, plvl, TRUE, FALSE); #else GetItemBonus(ii, itype, plvl >> 1, plvl, TRUE); #endif item[ii]._iSeed = iseed; item[ii]._iCreateInfo = plvl | CF_SMITHPREMIUM; item[ii]._iIdentified = TRUE; } void RecreateBoyItem(int ii, int idx, int lvl, int iseed) { int itype; SetRndSeed(iseed); itype = RndBoyItem(lvl) - 1; GetItemAttrs(ii, itype, lvl); #ifdef HELLFIRE GetItemBonus(ii, itype, lvl, 2 * lvl, TRUE, TRUE); #else GetItemBonus(ii, itype, lvl, 2 * lvl, TRUE); #endif item[ii]._iSeed = iseed; item[ii]._iCreateInfo = lvl | CF_BOY; item[ii]._iIdentified = TRUE; } void RecreateWitchItem(int ii, int idx, int lvl, int iseed) { int iblvl, itype; if (idx == IDI_MANA || idx == IDI_FULLMANA || idx == IDI_PORTAL) { GetItemAttrs(ii, idx, lvl); } else { #ifdef HELLFIRE if (idx >= 114 && idx <= 117) { SetRndSeed(iseed); volatile int hi_predelnik = random_(0, 1); iblvl = lvl; GetItemAttrs(ii, idx, iblvl); } else { #endif SetRndSeed(iseed); itype = RndWitchItem(lvl) - 1; GetItemAttrs(ii, itype, lvl); iblvl = -1; if (random_(51, 100) <= 5) iblvl = 2 * lvl; if (iblvl == -1 && item[ii]._iMiscId == IMISC_STAFF) iblvl = 2 * lvl; if (iblvl != -1) #ifdef HELLFIRE GetItemBonus(ii, itype, iblvl >> 1, iblvl, TRUE, TRUE); } #else GetItemBonus(ii, itype, iblvl >> 1, iblvl, TRUE); #endif } item[ii]._iSeed = iseed; item[ii]._iCreateInfo = lvl | CF_WITCH; item[ii]._iIdentified = TRUE; } void RecreateHealerItem(int ii, int idx, int lvl, int iseed) { int itype; if (idx == IDI_HEAL || idx == IDI_FULLHEAL || idx == IDI_RESURRECT) { GetItemAttrs(ii, idx, lvl); } else { SetRndSeed(iseed); itype = RndHealerItem(lvl) - 1; GetItemAttrs(ii, itype, lvl); } item[ii]._iSeed = iseed; item[ii]._iCreateInfo = lvl | CF_HEALER; item[ii]._iIdentified = TRUE; } void RecreateTownItem(int ii, int idx, WORD icreateinfo, int iseed, int ivalue) { if (icreateinfo & CF_SMITH) RecreateSmithItem(ii, idx, icreateinfo & CF_LEVEL, iseed); else if (icreateinfo & CF_SMITHPREMIUM) RecreatePremiumItem(ii, idx, icreateinfo & CF_LEVEL, iseed); else if (icreateinfo & CF_BOY) RecreateBoyItem(ii, idx, icreateinfo & CF_LEVEL, iseed); else if (icreateinfo & CF_WITCH) RecreateWitchItem(ii, idx, icreateinfo & CF_LEVEL, iseed); else if (icreateinfo & CF_HEALER) RecreateHealerItem(ii, idx, icreateinfo & CF_LEVEL, iseed); } void RecalcStoreStats() { int i; for (i = 0; i < SMITH_ITEMS; i++) { if (smithitem[i]._itype != ITYPE_NONE) { smithitem[i]._iStatFlag = StoreStatOk(&smithitem[i]); } } for (i = 0; i < SMITH_PREMIUM_ITEMS; i++) { if (premiumitem[i]._itype != ITYPE_NONE) { premiumitem[i]._iStatFlag = StoreStatOk(&premiumitem[i]); } } for (i = 0; i < 20; i++) { if (witchitem[i]._itype != ITYPE_NONE) { witchitem[i]._iStatFlag = StoreStatOk(&witchitem[i]); } } for (i = 0; i < 20; i++) { if (healitem[i]._itype != ITYPE_NONE) { healitem[i]._iStatFlag = StoreStatOk(&healitem[i]); } } boyitem._iStatFlag = StoreStatOk(&boyitem); } int ItemNoFlippy() { int r; r = itemactive[numitems - 1]; item[r]._iAnimFrame = item[r]._iAnimLen; item[r]._iAnimFlag = FALSE; item[r]._iSelFlag = 1; return r; } void CreateSpellBook(int x, int y, int ispell, BOOL sendmsg, BOOL delta) { int ii, idx; BOOL done; done = FALSE; #ifdef HELLFIRE int lvl = spelldata[ispell].sBookLvl + 1; if (lvl < 1) { return; } idx = RndTypeItems(ITYPE_MISC, IMISC_BOOK, lvl); #else idx = RndTypeItems(ITYPE_MISC, IMISC_BOOK); #endif if (numitems < MAXITEMS) { ii = itemavail[0]; GetSuperItemSpace(x, y, ii); itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; while (!done) { #ifdef HELLFIRE SetupAllItems(ii, idx, GetRndSeed(), 2 * lvl, 1, TRUE, FALSE, delta); #else SetupAllItems(ii, idx, GetRndSeed(), 2 * currlevel, 1, TRUE, FALSE, delta); #endif if (item[ii]._iMiscId == IMISC_BOOK && item[ii]._iSpell == ispell) done = TRUE; } if (sendmsg) NetSendCmdDItem(FALSE, ii); if (delta) DeltaAddItem(ii); numitems++; } } void CreateMagicArmor(int x, int y, int imisc, int icurs, BOOL sendmsg, BOOL delta) { int ii, idx; BOOL done; done = FALSE; #ifdef HELLFIRE int curlv = items_get_currlevel(); #endif if (numitems < MAXITEMS) { ii = itemavail[0]; GetSuperItemSpace(x, y, ii); itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; #ifdef HELLFIRE idx = RndTypeItems(imisc, IMISC_NONE, curlv); #else idx = RndTypeItems(imisc, IMISC_NONE); #endif while (!done) { #ifdef HELLFIRE SetupAllItems(ii, idx, GetRndSeed(), 2 * curlv, 1, TRUE, FALSE, delta); #else SetupAllItems(ii, idx, GetRndSeed(), 2 * currlevel, 1, TRUE, FALSE, delta); #endif if (item[ii]._iCurs == icurs) done = TRUE; else #ifdef HELLFIRE idx = RndTypeItems(imisc, IMISC_NONE, curlv); #else idx = RndTypeItems(imisc, IMISC_NONE); #endif } if (sendmsg) NetSendCmdDItem(FALSE, ii); if (delta) DeltaAddItem(ii); numitems++; } } #ifdef HELLFIRE void CreateAmulet(int x, int y, int curlv, BOOL sendmsg, BOOL delta) { int ii, idx; BOOLEAN done; done = FALSE; if (numitems < MAXITEMS) { ii = itemavail[0]; GetSuperItemSpace(x, y, ii); itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; idx = RndTypeItems(ITYPE_AMULET, IMISC_AMULET, curlv); while (!done) { SetupAllItems(ii, idx, GetRndSeed(), 2 * curlv, 1, TRUE, FALSE, delta); if (item[ii]._iCurs == ICURS_AMULET) { done = TRUE; } else { idx = RndTypeItems(ITYPE_AMULET, IMISC_AMULET, curlv); } } if (sendmsg) NetSendCmdDItem(FALSE, ii); if (delta) DeltaAddItem(ii); numitems++; } } #endif void CreateMagicWeapon(int x, int y, int imisc, int icurs, BOOL sendmsg, BOOL delta) { int ii, idx; BOOL done; done = FALSE; #ifdef HELLFIRE int imid; if (imisc == ITYPE_STAFF) imid = IMISC_STAFF; else imid = IMISC_NONE; int curlv = items_get_currlevel(); #endif if (numitems < MAXITEMS) { ii = itemavail[0]; GetSuperItemSpace(x, y, ii); itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; #ifdef HELLFIRE idx = RndTypeItems(imisc, imid, curlv); #else idx = RndTypeItems(imisc, IMISC_NONE); #endif while (!done) { #ifdef HELLFIRE SetupAllItems(ii, idx, GetRndSeed(), 2 * curlv, 1, TRUE, FALSE, delta); #else SetupAllItems(ii, idx, GetRndSeed(), 2 * currlevel, 1, TRUE, FALSE, delta); #endif if (item[ii]._iCurs == icurs) done = TRUE; else #ifdef HELLFIRE idx = RndTypeItems(imisc, imid, curlv); #else idx = RndTypeItems(imisc, IMISC_NONE); #endif } if (sendmsg) NetSendCmdDItem(FALSE, ii); if (delta) DeltaAddItem(ii); numitems++; } } static void NextItemRecord(int i) { gnNumGetRecords--; if (gnNumGetRecords == 0) { return; } itemrecord[i].dwTimestamp = itemrecord[gnNumGetRecords].dwTimestamp; itemrecord[i].nSeed = itemrecord[gnNumGetRecords].nSeed; itemrecord[i].wCI = itemrecord[gnNumGetRecords].wCI; itemrecord[i].nIndex = itemrecord[gnNumGetRecords].nIndex; } BOOL GetItemRecord(int nSeed, WORD wCI, int nIndex) { int i; DWORD dwTicks; dwTicks = GetTickCount(); for (i = 0; i < gnNumGetRecords; i++) { if (dwTicks - itemrecord[i].dwTimestamp > 6000) { // BUGFIX: loot actions for multiple quest items with same seed (e.g. blood stone) performed within less then 6 seconds will be ignored. NextItemRecord(i); i--; } else if (nSeed == itemrecord[i].nSeed && wCI == itemrecord[i].wCI && nIndex == itemrecord[i].nIndex) { return FALSE; } } return TRUE; } void SetItemRecord(int nSeed, WORD wCI, int nIndex) { DWORD dwTicks; dwTicks = GetTickCount(); if (gnNumGetRecords == MAXITEMS) { return; } itemrecord[gnNumGetRecords].dwTimestamp = dwTicks; itemrecord[gnNumGetRecords].nSeed = nSeed; itemrecord[gnNumGetRecords].wCI = wCI; itemrecord[gnNumGetRecords].nIndex = nIndex; gnNumGetRecords++; } void PutItemRecord(int nSeed, WORD wCI, int nIndex) { int i; DWORD dwTicks; dwTicks = GetTickCount(); for (i = 0; i < gnNumGetRecords; i++) { if (dwTicks - itemrecord[i].dwTimestamp > 6000) { NextItemRecord(i); i--; } else if (nSeed == itemrecord[i].nSeed && wCI == itemrecord[i].wCI && nIndex == itemrecord[i].nIndex) { NextItemRecord(i); break; } } } ================================================ FILE: Source/items.h ================================================ /** * @file items.h * * Interface of item functionality. */ #ifndef __ITEMS_H__ #define __ITEMS_H__ extern int itemactive[MAXITEMS]; extern BOOL uitemflag; extern int itemavail[MAXITEMS]; extern ItemGetRecordStruct itemrecord[MAXITEMS]; extern ItemStruct item[MAXITEMS + 1]; #ifdef HELLFIRE extern CornerStoneStruct CornerStone; #endif extern BOOL UniqueItemFlag[128]; #ifdef HELLFIRE extern int auricGold; #endif extern int numitems; #ifdef HELLFIRE int get_ring_max_value(int i); int get_bow_max_value(int i); int get_staff_max_value(int i); int get_sword_max_value(int i); int get_helm_max_value(int i); int get_shield_max_value(int i); int get_armor_max_value(int i); int get_mace_max_value(int i); int get_amulet_max_value(int i); int get_axe_max_value(int i); #endif void InitItemGFX(); void InitItems(); void CalcPlrItemVals(int p, BOOL Loadgfx); void CalcPlrScrolls(int p); void CalcPlrStaff(int p); void CalcPlrInv(int p, BOOL Loadgfx); void SetPlrHandItem(ItemStruct *h, int idata); void GetPlrHandSeed(ItemStruct *h); void GetGoldSeed(int pnum, ItemStruct *h); void SetPlrHandGoldCurs(ItemStruct *h); void CreatePlrItems(int p); BOOL ItemSpaceOk(int i, int j); void GetSuperItemLoc(int x, int y, int &xx, int &yy); void GetItemAttrs(int i, int idata, int lvl); void SaveItemPower(int i, int power, int param1, int param2, int minval, int maxval, int multval); void GetItemPower(int i, int minlvl, int maxlvl, int flgs, BOOL onlygood); void SetupItem(int i); int RndItem(int m); void SpawnUnique(int uid, int x, int y); void SpawnItem(int m, int x, int y, BOOL sendmsg); void CreateItem(int uid, int x, int y); void CreateRndItem(int x, int y, BOOL onlygood, BOOL sendmsg, BOOL delta); void CreateRndUseful(int pnum, int x, int y, BOOL sendmsg); void CreateTypeItem(int x, int y, BOOL onlygood, int itype, int imisc, BOOL sendmsg, BOOL delta); void RecreateItem(int ii, int idx, WORD icreateinfo, int iseed, int ivalue); void RecreateEar(int ii, WORD ic, int iseed, int Id, int dur, int mdur, int ch, int mch, int ivalue, int ibuff); #ifdef HELLFIRE void CornerstoneSave(); void CornerstoneLoad(int x, int y); #endif void SpawnQuestItem(int itemid, int x, int y, int randarea, int selflag); void SpawnRock(); #ifdef HELLFIRE void SpawnRewardItem(int itemid, int xx, int yy); void SpawnMapOfDoom(int xx, int yy); void SpawnRuneBomb(int xx, int yy); void SpawnTheodore(int xx, int yy); #endif void RespawnItem(int i, BOOL FlipFlag); void DeleteItem(int ii, int i); void ProcessItems(); void FreeItemGFX(); void GetItemFrm(int i); void GetItemStr(int i); void CheckIdentify(int pnum, int cii); void DoRepair(int pnum, int cii); void DoRecharge(int pnum, int cii); #ifdef HELLFIRE void DoOil(int pnum, int cii); #endif void PrintItemPower(char plidx, ItemStruct *x); void DrawUniqueInfo(); void PrintItemDetails(ItemStruct *x); void PrintItemDur(ItemStruct *x); void UseItem(int p, int Mid, int spl); BOOL StoreStatOk(ItemStruct *h); void SpawnSmith(int lvl); #ifdef HELLFIRE void SpawnPremium(int pnum); #else void SpawnPremium(int lvl); #endif void WitchBookLevel(int ii); void SpawnWitch(int lvl); void SpawnBoy(int lvl); void SpawnHealer(int lvl); void SpawnStoreGold(); void RecreateTownItem(int ii, int idx, WORD icreateinfo, int iseed, int ivalue); void RecalcStoreStats(); int ItemNoFlippy(); void CreateSpellBook(int x, int y, int ispell, BOOL sendmsg, BOOL delta); void CreateMagicArmor(int x, int y, int imisc, int icurs, BOOL sendmsg, BOOL delta); #ifdef HELLFIRE void CreateAmulet(int x, int y, int curlv, BOOL sendmsg, BOOL delta); #endif void CreateMagicWeapon(int x, int y, int imisc, int icurs, BOOL sendmsg, BOOL delta); BOOL GetItemRecord(int nSeed, WORD wCI, int nIndex); void SetItemRecord(int nSeed, WORD wCI, int nIndex); void PutItemRecord(int nSeed, WORD wCI, int nIndex); /* data */ #ifdef HELLFIRE extern int MaxGold; #endif extern BYTE ItemCAnimTbl[]; extern int ItemInvSnds[]; #endif /* __ITEMS_H__ */ ================================================ FILE: Source/lighting.cpp ================================================ /** * @file lighting.cpp * * Implementation of light and vision. */ #include "all.h" LightListStruct VisionList[MAXVISION]; BYTE lightactive[MAXLIGHTS]; LightListStruct LightList[MAXLIGHTS]; int numlights; BYTE lightradius[16][128]; BOOL dovision; int numvision; char lightmax; BOOL dolighting; BYTE lightblock[64][16][16]; int visionid; BYTE *pLightTbl; BOOL lightflag; /** * CrawlTable specifies X- and Y-coordinate deltas from a missile target coordinate. * * n=4 * * y * ^ * | 1 * | 3#4 * | 2 * +-----> x * * n=16 * * y * ^ * | 314 * | B7 8C * | F # G * | D9 AE * | 526 * +-------> x */ 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 }; /** pCrawlTable maps from circle radius to the X- and Y-coordinate deltas from the center of a circle. */ char *pCrawlTable[19] = { 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 }; /** vCrawlTable specifies the X- Y-coordinate offsets of lighting visions. */ BYTE 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 } }; /** unused */ BYTE byte_49463C[18][18] = { { 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 } }; /** RadiusAdj maps from vCrawlTable index to lighting vision radius adjustment. */ BYTE 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 RotateRadius(int *x, int *y, int *dx, int *dy, int *lx, int *ly, int *bx, int *by) { int swap; *bx = 0; *by = 0; swap = *dx; *dx = 7 - *dy; *dy = swap; swap = *lx; *lx = 7 - *ly; *ly = swap; *x = *dx - *lx; *y = *dy - *ly; if (*x < 0) { *x += 8; *bx = 1; } if (*y < 0) { *y += 8; *by = 1; } } void DoLighting(int nXPos, int nYPos, int nRadius, int Lnum) { int x, y, v, xoff, yoff, mult, radius_block; int min_x, max_x, min_y, max_y; int dist_x, dist_y, light_x, light_y, block_x, block_y, temp_x, temp_y; xoff = 0; yoff = 0; light_x = 0; light_y = 0; block_x = 0; block_y = 0; if (Lnum >= 0) { xoff = LightList[Lnum]._xoff; yoff = LightList[Lnum]._yoff; if (xoff < 0) { xoff += 8; nXPos--; } if (yoff < 0) { yoff += 8; nYPos--; } } dist_x = xoff; dist_y = yoff; if (nXPos - 15 < 0) { min_x = nXPos + 1; } else { min_x = 15; } if (nXPos + 15 > MAXDUNX) { max_x = MAXDUNX - nXPos; } else { max_x = 15; } if (nYPos - 15 < 0) { min_y = nYPos + 1; } else { min_y = 15; } if (nYPos + 15 > MAXDUNY) { max_y = MAXDUNY - nYPos; } else { max_y = 15; } #ifdef HELLFIRE if (currlevel < 17) { #else if (nXPos >= 0 && nXPos < MAXDUNX && nYPos >= 0 && nYPos < MAXDUNY) { #endif dLight[nXPos][nYPos] = 0; #ifdef HELLFIRE } else if (dLight[nXPos][nYPos] > lightradius[nRadius][0]) { dLight[nXPos][nYPos] = lightradius[nRadius][0]; #endif } mult = xoff + 8 * yoff; for (y = 0; y < min_y; y++) { for (x = 1; x < max_x; x++) { radius_block = lightblock[mult][y][x]; if (radius_block < 128) { temp_x = nXPos + x; temp_y = nYPos + y; v = lightradius[nRadius][radius_block]; #ifndef HELLFIRE if (temp_x >= 0 && temp_x < MAXDUNX && temp_y >= 0 && temp_y < MAXDUNY) #endif if (v < dLight[temp_x][temp_y]) dLight[temp_x][temp_y] = v; } } } RotateRadius(&xoff, &yoff, &dist_x, &dist_y, &light_x, &light_y, &block_x, &block_y); mult = xoff + 8 * yoff; for (y = 0; y < max_y; y++) { for (x = 1; x < max_x; x++) { radius_block = lightblock[mult][y + block_y][x + block_x]; if (radius_block < 128) { temp_x = nXPos + y; temp_y = nYPos - x; v = lightradius[nRadius][radius_block]; #ifndef HELLFIRE if (temp_x >= 0 && temp_x < MAXDUNX && temp_y >= 0 && temp_y < MAXDUNY) #endif if (v < dLight[temp_x][temp_y]) dLight[temp_x][temp_y] = v; } } } RotateRadius(&xoff, &yoff, &dist_x, &dist_y, &light_x, &light_y, &block_x, &block_y); mult = xoff + 8 * yoff; for (y = 0; y < max_y; y++) { for (x = 1; x < min_x; x++) { radius_block = lightblock[mult][y + block_y][x + block_x]; if (radius_block < 128) { temp_x = nXPos - x; temp_y = nYPos - y; v = lightradius[nRadius][radius_block]; #ifndef HELLFIRE if (temp_x >= 0 && temp_x < MAXDUNX && temp_y >= 0 && temp_y < MAXDUNY) #endif if (v < dLight[temp_x][temp_y]) dLight[temp_x][temp_y] = v; } } } RotateRadius(&xoff, &yoff, &dist_x, &dist_y, &light_x, &light_y, &block_x, &block_y); mult = xoff + 8 * yoff; for (y = 0; y < min_y; y++) { for (x = 1; x < min_x; x++) { radius_block = lightblock[mult][y + block_y][x + block_x]; if (radius_block < 128) { temp_x = nXPos - y; temp_y = nYPos + x; v = lightradius[nRadius][radius_block]; #ifndef HELLFIRE if (temp_x >= 0 && temp_x < MAXDUNX && temp_y >= 0 && temp_y < MAXDUNY) #endif if (v < dLight[temp_x][temp_y]) dLight[temp_x][temp_y] = v; } } } } void DoUnLight(int nXPos, int nYPos, int nRadius) { int x, y, min_x, min_y, max_x, max_y; nRadius++; min_y = nYPos - nRadius; max_y = nYPos + nRadius; min_x = nXPos - nRadius; max_x = nXPos + nRadius; if (min_y < 0) { min_y = 0; } if (max_y > MAXDUNY) { max_y = MAXDUNY; } if (min_x < 0) { min_x = 0; } if (max_x > MAXDUNX) { max_x = MAXDUNX; } for (y = min_y; y < max_y; y++) { for (x = min_x; x < max_x; x++) { #ifndef HELLFIRE if (x >= 0 && x < MAXDUNX && y >= 0 && y < MAXDUNY) #endif dLight[x][y] = dPreLight[x][y]; } } } void DoUnVision(int nXPos, int nYPos, int nRadius) { int i, j, x1, y1, x2, y2; nRadius++; y1 = nYPos - nRadius; y2 = nYPos + nRadius; x1 = nXPos - nRadius; x2 = nXPos + nRadius; if (y1 < 0) { y1 = 0; } if (y2 > MAXDUNY) { y2 = MAXDUNY; } if (x1 < 0) { x1 = 0; } if (x2 > MAXDUNX) { x2 = MAXDUNX; } for (i = x1; i < x2; i++) { for (j = y1; j < y2; j++) { dFlags[i][j] &= ~(BFLAG_VISIBLE | BFLAG_LIT); } } } void DoVision(int nXPos, int nYPos, int nRadius, BOOL doautomap, BOOL visible) { BOOL nBlockerFlag; int nCrawlX, nCrawlY, nLineLen, nTrans; int j, k, v, x1adj, x2adj, y1adj, y2adj; if (nXPos >= 0 && nXPos <= MAXDUNX && nYPos >= 0 && nYPos <= MAXDUNY) { // BUGFIX < MAXDUNX/MAXDUNY or OOB if (doautomap) { if (dFlags[nXPos][nYPos] >= 0) { SetAutomapView(nXPos, nXPos); // BUGFIX - second argument should be nYPos } dFlags[nXPos][nYPos] |= BFLAG_EXPLORED; } if (visible) { dFlags[nXPos][nYPos] |= BFLAG_LIT; } dFlags[nXPos][nYPos] |= BFLAG_VISIBLE; } for (v = 0; v < 4; v++) { for (j = 0; j < 23; j++) { nBlockerFlag = FALSE; nLineLen = 2 * (nRadius - RadiusAdj[j]); for (k = 0; k < nLineLen && !nBlockerFlag; k += 2) { x1adj = 0; x2adj = 0; y1adj = 0; y2adj = 0; switch (v) { case 0: nCrawlX = nXPos + vCrawlTable[j][k]; nCrawlY = nYPos + vCrawlTable[j][k + 1]; if (vCrawlTable[j][k] > 0 && vCrawlTable[j][k + 1] > 0) { x1adj = -1; y2adj = -1; } break; case 1: nCrawlX = nXPos - vCrawlTable[j][k]; nCrawlY = nYPos - vCrawlTable[j][k + 1]; if (vCrawlTable[j][k] > 0 && vCrawlTable[j][k + 1] > 0) { y1adj = 1; x2adj = 1; } break; case 2: nCrawlX = nXPos + vCrawlTable[j][k]; nCrawlY = nYPos - vCrawlTable[j][k + 1]; if (vCrawlTable[j][k] > 0 && vCrawlTable[j][k + 1] > 0) { x1adj = -1; y2adj = 1; } break; case 3: nCrawlX = nXPos - vCrawlTable[j][k]; nCrawlY = nYPos + vCrawlTable[j][k + 1]; if (vCrawlTable[j][k] > 0 && vCrawlTable[j][k + 1] > 0) { y1adj = -1; x2adj = 1; } break; } if (nCrawlX >= 0 && nCrawlX <= MAXDUNX && nCrawlY >= 0 && nCrawlY <= MAXDUNY) { nBlockerFlag = nBlockTable[dPiece[nCrawlX][nCrawlY]]; if (!nBlockTable[dPiece[x1adj + nCrawlX][y1adj + nCrawlY]] || !nBlockTable[dPiece[x2adj + nCrawlX][y2adj + nCrawlY]]) { if (doautomap) { if (dFlags[nCrawlX][nCrawlY] >= 0) { SetAutomapView(nCrawlX, nCrawlY); } dFlags[nCrawlX][nCrawlY] |= BFLAG_EXPLORED; } if (visible) { dFlags[nCrawlX][nCrawlY] |= BFLAG_LIT; } dFlags[nCrawlX][nCrawlY] |= BFLAG_VISIBLE; if (!nBlockerFlag) { nTrans = dTransVal[nCrawlX][nCrawlY]; if (nTrans != 0) { TransList[nTrans] = TRUE; } } } } } } } } void FreeLightTable() { MemFreeDbg(pLightTbl); } void InitLightTable() { assert(!pLightTbl); pLightTbl = DiabloAllocPtr(LIGHTSIZE); } void MakeLightTable() { int i, j, k, l, lights, shade, l1, l2, cnt, rem, div; double fs, fa; BYTE col, max; BYTE *tbl, *trn; BYTE blood[16]; tbl = pLightTbl; shade = 0; if (light4flag) { lights = 3; } else { lights = 15; } for (i = 0; i < lights; i++) { *tbl++ = 0; for (j = 0; j < 8; j++) { col = 16 * j + shade; max = 16 * j + 15; for (k = 0; k < 16; k++) { if (k != 0 || j != 0) { *tbl++ = col; } if (col < max) { col++; } else { max = 0; col = 0; } } } for (j = 16; j < 20; j++) { col = 8 * j + (shade >> 1); max = 8 * j + 7; for (k = 0; k < 8; k++) { *tbl++ = col; if (col < max) { col++; } else { max = 0; col = 0; } } } for (j = 10; j < 16; j++) { col = 16 * j + shade; max = 16 * j + 15; for (k = 0; k < 16; k++) { *tbl++ = col; if (col < max) { col++; } else { max = 0; col = 0; } if (col == 255) { max = 0; col = 0; } } } if (light4flag) { shade += 5; } else { shade++; } } for (i = 0; i < 256; i++) { *tbl++ = 0; } if (leveltype == DTYPE_HELL) { tbl = pLightTbl; for (i = 0; i < lights; i++) { l1 = lights - i; l2 = l1; div = lights / l1; rem = lights % l1; cnt = 0; blood[0] = 0; col = 1; for (j = 1; j < 16; j++) { blood[j] = col; l2 += rem; if (l2 > l1 && j < 15) { j++; blood[j] = col; l2 -= l1; } cnt++; if (cnt == div) { col++; cnt = 0; } } *tbl++ = 0; for (j = 1; j <= 15; j++) { *tbl++ = blood[j]; } for (j = 15; j > 0; j--) { *tbl++ = blood[j]; } *tbl++ = 1; tbl += 224; } *tbl++ = 0; for (j = 0; j < 31; j++) { *tbl++ = 1; } tbl += 224; } #ifdef HELLFIRE if (currlevel >= 17) { tbl = pLightTbl; for (i = 0; i < lights; i++) { *tbl++ = 0; for (j = 1; j < 16; j++) *tbl++ = j; tbl += 240; } *tbl++ = 0; for (j = 1; j < 16; j++) *tbl++ = 1; tbl += 240; } #endif trn = LoadFileInMem("PlrGFX\\Infra.TRN", NULL); for (i = 0; i < 256; i++) { *tbl++ = trn[i]; } mem_free_dbg(trn); trn = LoadFileInMem("PlrGFX\\Stone.TRN", NULL); for (i = 0; i < 256; i++) { *tbl++ = trn[i]; } mem_free_dbg(trn); for (i = 0; i < 8; i++) { for (col = 226; col < 239; col++) { if (i != 0 || col != 226) { *tbl++ = col; } else { *tbl++ = 0; } } *tbl++ = 0; *tbl++ = 0; *tbl++ = 0; } for (i = 0; i < 4; i++) { col = 224; for (j = 224; j < 239; j += 2) { *tbl++ = col; col += 2; } } for (i = 0; i < 6; i++) { for (col = 224; col < 239; col++) { *tbl++ = col; } *tbl++ = 0; } for (j = 0; j < 16; j++) { for (i = 0; i < 128; i++) { if (i > (j + 1) * 8) { lightradius[j][i] = 15; } else { fs = (double)15 * i / ((double)8 * (j + 1)); lightradius[j][i] = (BYTE)(fs + 0.5); } } } #ifdef HELLFIRE if (currlevel >= 17) { for (j = 0; j < 16; j++) { fa = (sqrt((double)(16 - j))) / 128; fa *= fa; for (i = 0; i < 128; i++) { lightradius[15 - j][i] = 15 - (BYTE)(fa * (double)((128 - i) * (128 - i))); if (lightradius[15 - j][i] > 15) lightradius[15 - j][i] = 0; lightradius[15 - j][i] = lightradius[15 - j][i] - (BYTE)((15 - j) / 2); if (lightradius[15 - j][i] > 15) lightradius[15 - j][i] = 0; } } } #endif for (j = 0; j < 8; j++) { for (i = 0; i < 8; i++) { for (k = 0; k < 16; k++) { for (l = 0; l < 16; l++) { fs = (BYTE)sqrt((8 * l - j) * (8 * l - j) + (8 * k - i) * (8 * k - i)); fs += fs < 0 ? -0.5 : 0.5; // BUGFIX: This error causes a "jittery" effect when a light source moves. // Swap the addition and multiplication operators to fix the lookup table. // lightblock[j + 8 * i][k][l] = fs; lightblock[j * 8 + i][k][l] = fs; } } } } } #ifdef _DEBUG void ToggleLighting_2() { int i; if (lightflag) { memset(dLight, 0, sizeof(dLight)); } else { memset(dLight, lightmax, sizeof(dLight)); for (i = 0; i < MAX_PLRS; i++) { if (plr[i].plractive && plr[i].plrlevel == currlevel) { DoLighting(plr[i]._px, plr[i]._py, plr[i]._pLightRad, -1); } } } } void ToggleLighting() { int i; lightflag ^= TRUE; if (lightflag) { memset(dLight, 0, sizeof(dLight)); } else { memcpy(dLight, dPreLight, sizeof(dLight)); for (i = 0; i < MAX_PLRS; i++) { if (plr[i].plractive && plr[i].plrlevel == currlevel) { DoLighting(plr[i]._px, plr[i]._py, plr[i]._pLightRad, -1); } } } } #endif void InitLightMax() { if (light4flag) { lightmax = 3; } else { lightmax = 15; } } void InitLighting() { int i; numlights = 0; dolighting = FALSE; lightflag = FALSE; for (i = 0; i < MAXLIGHTS; i++) { lightactive[i] = i; } } int AddLight(int x, int y, int r) { int lid; if (lightflag) { return -1; } lid = -1; if (numlights < MAXLIGHTS) { lid = lightactive[numlights++]; LightList[lid]._lx = x; LightList[lid]._ly = y; LightList[lid]._lradius = r; LightList[lid]._xoff = 0; LightList[lid]._yoff = 0; LightList[lid]._ldel = FALSE; LightList[lid]._lunflag = FALSE; dolighting = TRUE; } return lid; } void AddUnLight(int i) { if (lightflag || i == -1) { return; } LightList[i]._ldel = TRUE; dolighting = TRUE; } void ChangeLightRadius(int i, int r) { if (lightflag || i == -1) { return; } LightList[i]._lunflag = TRUE; LightList[i]._lunx = LightList[i]._lx; LightList[i]._luny = LightList[i]._ly; LightList[i]._lunr = LightList[i]._lradius; LightList[i]._lradius = r; dolighting = TRUE; } void ChangeLightXY(int i, int x, int y) { if (lightflag || i == -1) { return; } LightList[i]._lunflag = TRUE; LightList[i]._lunx = LightList[i]._lx; LightList[i]._luny = LightList[i]._ly; LightList[i]._lunr = LightList[i]._lradius; LightList[i]._lx = x; LightList[i]._ly = y; dolighting = TRUE; } void ChangeLightOff(int i, int x, int y) { if (lightflag || i == -1) { return; } LightList[i]._lunflag = TRUE; LightList[i]._lunx = LightList[i]._lx; LightList[i]._luny = LightList[i]._ly; LightList[i]._lunr = LightList[i]._lradius; LightList[i]._xoff = x; LightList[i]._yoff = y; dolighting = TRUE; } void ChangeLight(int i, int x, int y, int r) { if (lightflag || i == -1) { return; } LightList[i]._lunflag = TRUE; LightList[i]._lunx = LightList[i]._lx; LightList[i]._luny = LightList[i]._ly; LightList[i]._lunr = LightList[i]._lradius; LightList[i]._lx = x; LightList[i]._ly = y; LightList[i]._lradius = r; dolighting = TRUE; } void ProcessLightList() { int i, j; BYTE temp; if (lightflag) { return; } if (dolighting) { for (i = 0; i < numlights; i++) { j = lightactive[i]; if (LightList[j]._ldel) { DoUnLight(LightList[j]._lx, LightList[j]._ly, LightList[j]._lradius); } if (LightList[j]._lunflag) { DoUnLight(LightList[j]._lunx, LightList[j]._luny, LightList[j]._lunr); LightList[j]._lunflag = FALSE; } } for (i = 0; i < numlights; i++) { j = lightactive[i]; if (!LightList[j]._ldel) { DoLighting(LightList[j]._lx, LightList[j]._ly, LightList[j]._lradius, j); } } i = 0; while (i < numlights) { if (LightList[lightactive[i]]._ldel) { numlights--; temp = lightactive[numlights]; lightactive[numlights] = lightactive[i]; lightactive[i] = temp; } else { i++; } } } dolighting = FALSE; } void SavePreLighting() { memcpy(dPreLight, dLight, sizeof(dPreLight)); } void InitVision() { int i; numvision = 0; dovision = FALSE; visionid = 1; for (i = 0; i < TransVal; i++) { TransList[i] = FALSE; } } int AddVision(int x, int y, int r, BOOL mine) { int vid; // BUGFIX: if numvision >= MAXVISION behavior is undefined if (numvision < MAXVISION) { VisionList[numvision]._lx = x; VisionList[numvision]._ly = y; VisionList[numvision]._lradius = r; vid = visionid++; VisionList[numvision]._lid = vid; VisionList[numvision]._ldel = FALSE; VisionList[numvision]._lunflag = FALSE; VisionList[numvision]._lflags = mine != 0; numvision++; dovision = TRUE; } return vid; } void ChangeVisionRadius(int id, int r) { int i; for (i = 0; i < numvision; i++) { if (VisionList[i]._lid == id) { VisionList[i]._lunflag = TRUE; VisionList[i]._lunx = VisionList[i]._lx; VisionList[i]._luny = VisionList[i]._ly; VisionList[i]._lunr = VisionList[i]._lradius; VisionList[i]._lradius = r; dovision = TRUE; } } } void ChangeVisionXY(int id, int x, int y) { int i; for (i = 0; i < numvision; i++) { if (VisionList[i]._lid == id) { VisionList[i]._lunflag = TRUE; 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 = TRUE; } } } void ProcessVisionList() { int i; BOOL delflag; 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 = FALSE; } } for (i = 0; i < TransVal; i++) { TransList[i] = FALSE; } 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 = FALSE; for (i = 0; i < numvision; i++) { if (VisionList[i]._ldel) { numvision--; if (numvision > 0 && i != numvision) { VisionList[i] = VisionList[numvision]; } delflag = TRUE; } } } while (delflag); } dovision = FALSE; } void lighting_color_cycling() { int i, j, l; BYTE col; BYTE *tbl; l = light4flag ? 4 : 16; if (leveltype != DTYPE_HELL) { return; } tbl = pLightTbl; for (j = 0; j < l; j++) { tbl++; col = *tbl; for (i = 0; i < 30; i++) { tbl[0] = tbl[1]; tbl++; } *tbl = col; tbl += 225; } } ================================================ FILE: Source/lighting.h ================================================ /** * @file lighting.h * * Interface of light and vision. */ #ifndef __LIGHTING_H__ #define __LIGHTING_H__ extern LightListStruct VisionList[MAXVISION]; extern BYTE lightactive[MAXLIGHTS]; extern LightListStruct LightList[MAXLIGHTS]; extern int numlights; extern BYTE lightradius[16][128]; extern BOOL dovision; extern int numvision; extern char lightmax; extern BOOL dolighting; extern int visionid; extern BYTE *pLightTbl; extern BOOL lightflag; void DoLighting(int nXPos, int nYPos, int nRadius, int Lnum); void DoUnVision(int nXPos, int nYPos, int nRadius); void DoVision(int nXPos, int nYPos, int nRadius, BOOL doautomap, BOOL visible); void FreeLightTable(); void InitLightTable(); void MakeLightTable(); #ifdef _DEBUG void ToggleLighting_2(); void ToggleLighting(); #endif void InitLightMax(); void InitLighting(); int AddLight(int x, int y, int r); void AddUnLight(int i); void ChangeLightRadius(int i, int r); void ChangeLightXY(int i, int x, int y); void ChangeLightOff(int i, int x, int y); void ChangeLight(int i, int x, int y, int r); void ProcessLightList(); void SavePreLighting(); void InitVision(); int AddVision(int x, int y, int r, BOOL mine); void ChangeVisionRadius(int id, int r); void ChangeVisionXY(int id, int x, int y); void ProcessVisionList(); void lighting_color_cycling(); /* rdata */ extern char CrawlTable[2749]; extern BYTE vCrawlTable[23][30]; #endif /* __LIGHTING_H__ */ ================================================ FILE: Source/list.h ================================================ /** * @file list.h * Intrusive double-linked list implementation, * based on https://github.com/webcoyote/coho/blob/master/Base/List.h */ #include "../3rdParty/Storm/Source/storm.h" #define OBJECT_NAME(obj) (((const char *)&typeid(obj)) + 8) /****************************************************************************** * * List definition macros * ***/ /** Define a field within a structure that will be used to link it into a list */ #define LIST_LINK(T) TLink template class TLink; /****************************************************************************** * * TList * ***/ //============================================================================= template class TList { public: TList(); ~TList(); void UnlinkAll(); void DeleteAll(); T *Head(); enum InsertPos { NONE = 0, AFTER, BEFORE }; void Insert(T *node, InsertPos pos, T *ref); T *Remove(T *node); T *Create(InsertPos pos = BEFORE, size_t extra = 0, int memflags = 0); private: size_t m_offset; TLink m_link; TLink *GetLinkFromNode(T *node) const; // Hide copy-constructor and assignment operator TList(const TList &); TList &operator=(const TList &); static __forceinline void SDelete(T *node) { SMemFree(node, (char *)OBJECT_NAME(T), SLOG_OBJECT, 0); } }; //============================================================================= template TList::~TList() { // BUGFIX: Unlinking does not free memory, should use DeleteAll() UnlinkAll(); } //============================================================================= template TList::TList() { size_t offset = offsetof(T, m_Link); // Mark this node as the end of the list, with the link offset set m_link.m_prevLink = &m_link; m_offset = offset; m_link.m_nextNode = (T *)~((size_t)&m_link - offset); } //============================================================================= template void TList::DeleteAll() { while (T *node = m_link.Next()) { node->Delete(0x0); SDelete(node); } } //============================================================================= template __forceinline T *TList::Head() { return m_link.Next(); } //============================================================================= template __forceinline TLink *TList::GetLinkFromNode(T *node) const { // assert(m_offset != (size_t) -1); // return (TLink *) ((size_t) node + m_offset); return &node->m_Link; } template T *TList::Remove(T *node) { TLink *link = node ? &node->m_Link : &m_link; T *next = link->Next(); node->Delete(0x0); SDelete(node); return next; } template T *TList::Create(InsertPos pos, size_t extra, int memflags) { T *node = new (extra, memflags) T; if (pos != NONE) Insert(node, pos, NULL); return node; } template void TList::Insert(T *node, InsertPos pos, T *ref) { TLink *reflink; TLink *i = node ? GetLinkFromNode(node) : &m_link; if (i->IsLinked()) i->Unlink(); reflink = ref ? GetLinkFromNode(ref) : &m_link; switch (pos) { case AFTER: i->InsertAfter(node, reflink, m_offset); break; case BEFORE: i->InsertBefore(node, reflink); break; } } //============================================================================= template void TList::UnlinkAll() { for (;;) { T *node = m_link.Next(); if ((int)node <= 0) break; node->m_Link.Unlink(); } } /****************************************************************************** * * TLink * ***/ //============================================================================= template class TLink { public: TLink() : m_prevLink(NULL) , m_nextNode(NULL) { } ~TLink() { Unlink(); } bool IsLinked() const { return m_prevLink != NULL; } void Unlink(); T *Next() { if ((ptrdiff_t)m_nextNode <= 0) return NULL; return m_nextNode; } TLink *NextLink(size_t offset = -1) { if ((ptrdiff_t)m_nextNode <= 0) return (TLink *)~((size_t)m_nextNode); if ((int)offset < 0) { // Calculate the offset from a node pointer to a link structure offset = (size_t)this - (size_t)m_prevLink->m_nextNode; } // Get the link field for the next node return (TLink *)((size_t)m_nextNode + offset); } void InsertBefore(T *node, TLink *nextLink) { TLink *p = nextLink->m_prevLink; m_prevLink = p; m_nextNode = p->m_nextNode; p->m_nextNode = node; nextLink->m_prevLink = this; } __forceinline void InsertAfter(T *node, TLink *prevLink, const size_t &offset) { m_prevLink = prevLink; m_nextNode = prevLink->m_nextNode; prevLink->NextLink(offset)->m_prevLink = this; prevLink->m_nextNode = node; } private: TLink *m_prevLink; // pointer to the previous >link field< T *m_nextNode; // pointer to the next >object< // Hide copy-constructor and assignment operator TLink(const TLink &); TLink &operator=(const TLink &); friend class TList; }; //============================================================================= template void TLink::Unlink() { if (IsLinked()) { NextLink()->m_prevLink = m_prevLink; m_prevLink->m_nextNode = m_nextNode; m_prevLink = NULL; m_nextNode = NULL; } } ================================================ FILE: Source/loadsave.cpp ================================================ /** * @file loadsave.cpp * * Implementation of save game functionality. */ #include "all.h" BYTE *tbuff; static char BLoad() { return *tbuff++; } static int WLoad() { int rv = *tbuff++ << 24; rv |= *tbuff++ << 16; rv |= *tbuff++ << 8; rv |= *tbuff++; return rv; } static int ILoad() { int rv = *tbuff++ << 24; rv |= *tbuff++ << 16; rv |= *tbuff++ << 8; rv |= *tbuff++; return rv; } static BOOL OLoad() { if (*tbuff++ == TRUE) return TRUE; else return FALSE; } static void LoadPlayer(int i) { memcpy(&plr[i], tbuff, sizeof(*plr) - (10 * sizeof(void *))); tbuff += sizeof(*plr) - (10 * sizeof(void *)); // omit last 10 pointers } static void LoadMonster(int i) { memcpy(&monster[i], tbuff, sizeof(*monster) - (3 * sizeof(void *))); tbuff += sizeof(*monster) - (3 * sizeof(void *)); // omit last 3 pointers SyncMonsterAnim(i); } static void LoadMissile(int i) { memcpy(&missile[i], tbuff, sizeof(*missile)); tbuff += sizeof(*missile); } static void LoadObject(int i) { memcpy(&object[i], tbuff, sizeof(*object)); tbuff += sizeof(*object); } static void LoadItem(int i) { memcpy(&item[i], tbuff, sizeof(*item)); tbuff += sizeof(*item); GetItemFrm(i); } static void LoadPremium(int i) { memcpy(&premiumitem[i], tbuff, sizeof(*premiumitem)); tbuff += sizeof(*premiumitem); } static void LoadQuest(int i) { memcpy(&quests[i], tbuff, sizeof(*quests)); tbuff += sizeof(*quests); ReturnLvlX = WLoad(); ReturnLvlY = WLoad(); ReturnLvl = WLoad(); ReturnLvlT = WLoad(); DoomQuestState = WLoad(); } static void LoadLighting(int i) { memcpy(&LightList[i], tbuff, sizeof(*LightList)); tbuff += sizeof(*LightList); } static void LoadVision(int i) { memcpy(&VisionList[i], tbuff, sizeof(*VisionList)); tbuff += sizeof(*VisionList); } static void LoadPortal(int i) { memcpy(&portal[i], tbuff, sizeof(*portal)); tbuff += sizeof(*portal); } /** * @brief Load game state * @param firstflag Can be set to false if we are simply reloading the current game */ void LoadGame(BOOL firstflag) { int i, j; DWORD dwLen; char szName[MAX_PATH]; BYTE *LoadBuff; int _ViewX, _ViewY, _nummonsters, _numitems, _nummissiles, _nobjects; FreeGameMem(); pfile_remove_temp_files(); pfile_get_game_name(szName); LoadBuff = pfile_read(szName, &dwLen); tbuff = LoadBuff; #ifdef HELLFIRE if (ILoad() != 'HELF') #elif defined(SPAWN) if (ILoad() != 'SHAR') #else if (ILoad() != 'RETL') #endif app_fatal("Invalid save file"); setlevel = OLoad(); setlvlnum = WLoad(); currlevel = WLoad(); leveltype = WLoad(); _ViewX = WLoad(); _ViewY = WLoad(); invflag = OLoad(); chrflag = OLoad(); _nummonsters = WLoad(); _numitems = WLoad(); _nummissiles = WLoad(); _nobjects = WLoad(); for (i = 0; i < NUMLEVELS; i++) { glSeedTbl[i] = ILoad(); gnLevelTypeTbl[i] = WLoad(); } LoadPlayer(myplr); #ifdef HELLFIRE gnDifficulty = plr[myplr].pDifficulty; if (gnDifficulty < DIFF_NORMAL || gnDifficulty > DIFF_HELL) gnDifficulty = DIFF_NORMAL; #endif for (i = 0; i < MAXQUESTS; i++) LoadQuest(i); for (i = 0; i < MAXPORTAL; i++) LoadPortal(i); LoadGameLevel(firstflag, ENTRY_LOAD); SyncInitPlr(myplr); SyncPlrAnim(myplr); ViewX = _ViewX; ViewY = _ViewY; nummonsters = _nummonsters; numitems = _numitems; nummissiles = _nummissiles; nobjects = _nobjects; for (i = 0; i < MAXMONSTERS; i++) monstkills[i] = ILoad(); if (leveltype != DTYPE_TOWN) { for (i = 0; i < MAXMONSTERS; i++) monstactive[i] = WLoad(); for (i = 0; i < nummonsters; i++) LoadMonster(monstactive[i]); for (i = 0; i < MAXMISSILES; i++) missileactive[i] = BLoad(); for (i = 0; i < MAXMISSILES; i++) missileavail[i] = BLoad(); for (i = 0; i < nummissiles; i++) LoadMissile(missileactive[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]); numlights = WLoad(); for (i = 0; i < MAXLIGHTS; i++) lightactive[i] = BLoad(); for (i = 0; i < numlights; i++) LoadLighting(lightactive[i]); visionid = WLoad(); numvision = WLoad(); for (i = 0; i < numvision; i++) LoadVision(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 < 128; i++) UniqueItemFlag[i] = OLoad(); for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dLight[i][j] = BLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dFlags[i][j] = BLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dPlayer[i][j] = BLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dItem[i][j] = BLoad(); } if (leveltype != DTYPE_TOWN) { for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dMonster[i][j] = WLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dDead[i][j] = BLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dObject[i][j] = BLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dLight[i][j] = BLoad(); // BUGFIX: dLight got loaded already } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dPreLight[i][j] = BLoad(); } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) automapview[i][j] = OLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dMissile[i][j] = BLoad(); } } numpremium = WLoad(); premiumlevel = WLoad(); for (i = 0; i < SMITH_PREMIUM_ITEMS; i++) LoadPremium(i); automapflag = OLoad(); AutoMapScale = WLoad(); mem_free_dbg(LoadBuff); AutomapZoomReset(); ResyncQuests(); if (leveltype != DTYPE_TOWN) ProcessLightList(); RedoPlayerVision(); ProcessVisionList(); missiles_process_charge(); ResetPal(); SetCursor_(CURSOR_HAND); gbProcessPlayers = TRUE; } static void BSave(char v) { *tbuff++ = v; } static void WSave(int v) { *tbuff++ = v >> 24; *tbuff++ = v >> 16; *tbuff++ = v >> 8; *tbuff++ = v; } static void ISave(int v) { *tbuff++ = v >> 24; *tbuff++ = v >> 16; *tbuff++ = v >> 8; *tbuff++ = v; } static void OSave(BOOL v) { if (v != FALSE) *tbuff++ = TRUE; else *tbuff++ = FALSE; } static void SavePlayer(int i) { memcpy(tbuff, &plr[i], sizeof(*plr) - (10 * sizeof(void *))); tbuff += sizeof(*plr) - (10 * sizeof(void *)); // omit last 10 pointers } static void SaveMonster(int i) { memcpy(tbuff, &monster[i], sizeof(*monster) - (3 * sizeof(void *))); tbuff += sizeof(*monster) - (3 * sizeof(void *)); // omit last 3 pointers } static void SaveMissile(int i) { memcpy(tbuff, &missile[i], sizeof(*missile)); tbuff += sizeof(*missile); } static void SaveObject(int i) { memcpy(tbuff, &object[i], sizeof(*object)); tbuff += sizeof(*object); } static void SaveItem(int i) { memcpy(tbuff, &item[i], sizeof(*item)); tbuff += sizeof(*item); } static void SavePremium(int i) { memcpy(tbuff, &premiumitem[i], sizeof(*premiumitem)); tbuff += sizeof(*premiumitem); } static void SaveQuest(int i) { memcpy(tbuff, &quests[i], sizeof(*quests)); tbuff += sizeof(*quests); WSave(ReturnLvlX); WSave(ReturnLvlY); WSave(ReturnLvl); WSave(ReturnLvlT); WSave(DoomQuestState); } static void SaveLighting(int i) { memcpy(tbuff, &LightList[i], sizeof(*LightList)); tbuff += sizeof(*LightList); } static void SaveVision(int i) { memcpy(tbuff, &VisionList[i], sizeof(*VisionList)); tbuff += sizeof(*VisionList); } static void SavePortal(int i) { memcpy(tbuff, &portal[i], sizeof(*portal)); tbuff += sizeof(*portal); } void SaveGame() { int i, j; char szName[MAX_PATH]; DWORD dwLen = codec_get_encoded_len(FILEBUFF); BYTE *SaveBuff = DiabloAllocPtr(dwLen); tbuff = SaveBuff; #ifdef HELLFIRE ISave('HELF'); #elif defined(SPAWN) ISave('SHAR'); #else ISave('RETL'); #endif OSave(setlevel); WSave(setlvlnum); WSave(currlevel); WSave(leveltype); WSave(ViewX); WSave(ViewY); OSave(invflag); OSave(chrflag); WSave(nummonsters); WSave(numitems); WSave(nummissiles); WSave(nobjects); for (i = 0; i < NUMLEVELS; i++) { ISave(glSeedTbl[i]); WSave(gnLevelTypeTbl[i]); } #ifdef HELLFIRE plr[myplr].pDifficulty = gnDifficulty; #endif SavePlayer(myplr); for (i = 0; i < MAXQUESTS; i++) SaveQuest(i); for (i = 0; i < MAXPORTAL; i++) SavePortal(i); for (i = 0; i < MAXMONSTERS; i++) ISave(monstkills[i]); if (leveltype != DTYPE_TOWN) { for (i = 0; i < MAXMONSTERS; i++) WSave(monstactive[i]); for (i = 0; i < nummonsters; i++) SaveMonster(monstactive[i]); for (i = 0; i < MAXMISSILES; i++) BSave(missileactive[i]); for (i = 0; i < MAXMISSILES; i++) BSave(missileavail[i]); for (i = 0; i < nummissiles; i++) SaveMissile(missileactive[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]); WSave(numlights); for (i = 0; i < MAXLIGHTS; i++) BSave(lightactive[i]); for (i = 0; i < numlights; i++) SaveLighting(lightactive[i]); WSave(visionid); WSave(numvision); for (i = 0; i < numvision; i++) SaveVision(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 < 128; i++) OSave(UniqueItemFlag[i]); for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dLight[i][j]); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dFlags[i][j] & ~(BFLAG_MISSILE | BFLAG_VISIBLE | BFLAG_DEAD_PLAYER)); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dPlayer[i][j]); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dItem[i][j]); } if (leveltype != DTYPE_TOWN) { for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) WSave(dMonster[i][j]); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dDead[i][j]); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dObject[i][j]); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dLight[i][j]); // BUGFIX: dLight got saved already } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dPreLight[i][j]); } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) OSave(automapview[i][j]); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dMissile[i][j]); } } WSave(numpremium); WSave(premiumlevel); for (i = 0; i < SMITH_PREMIUM_ITEMS; i++) SavePremium(i); OSave(automapflag); WSave(AutoMapScale); pfile_get_game_name(szName); dwLen = codec_get_encoded_len(tbuff - SaveBuff); pfile_write_save_file(szName, SaveBuff, tbuff - SaveBuff, dwLen); mem_free_dbg(SaveBuff); gbValidSaveFile = TRUE; pfile_rename_temp_to_perm(); pfile_write_hero(); } void SaveLevel() { int i, j; char szName[MAX_PATH]; int dwLen; BYTE *SaveBuff; if (currlevel == 0) glSeedTbl[0] = GetRndSeed(); dwLen = codec_get_encoded_len(FILEBUFF); SaveBuff = DiabloAllocPtr(dwLen); tbuff = SaveBuff; if (leveltype != DTYPE_TOWN) { for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dDead[i][j]); } } WSave(nummonsters); WSave(numitems); WSave(nobjects); if (leveltype != DTYPE_TOWN) { for (i = 0; i < MAXMONSTERS; i++) WSave(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 (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dFlags[i][j] & ~(BFLAG_MISSILE | BFLAG_VISIBLE | BFLAG_DEAD_PLAYER)); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dItem[i][j]); } if (leveltype != DTYPE_TOWN) { for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) WSave(dMonster[i][j]); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dObject[i][j]); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dLight[i][j]); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dPreLight[i][j]); } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) OSave(automapview[i][j]); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) BSave(dMissile[i][j]); } } GetTempLevelNames(szName); dwLen = codec_get_encoded_len(tbuff - SaveBuff); pfile_write_save_file(szName, SaveBuff, tbuff - SaveBuff, dwLen); mem_free_dbg(SaveBuff); if (!setlevel) plr[myplr]._pLvlVisited[currlevel] = TRUE; else plr[myplr]._pSLvlVisited[setlvlnum] = TRUE; } void LoadLevel() { int i, j; DWORD dwLen; char szName[MAX_PATH]; BYTE *LoadBuff; GetPermLevelNames(szName); LoadBuff = pfile_read(szName, &dwLen); tbuff = LoadBuff; if (leveltype != DTYPE_TOWN) { for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dDead[i][j] = BLoad(); } SyncUniqDead(); } nummonsters = WLoad(); numitems = WLoad(); nobjects = WLoad(); if (leveltype != DTYPE_TOWN) { for (i = 0; i < MAXMONSTERS; i++) monstactive[i] = WLoad(); 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 (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dFlags[i][j] = BLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dItem[i][j] = BLoad(); } if (leveltype != DTYPE_TOWN) { for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dMonster[i][j] = WLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dObject[i][j] = BLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dLight[i][j] = BLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dPreLight[i][j] = BLoad(); } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) automapview[i][j] = OLoad(); } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) dMissile[i][j] = 0; /// BUGFIX: supposed to load saved missiles with "BLoad()"? } } AutomapZoomReset(); ResyncQuests(); SyncPortals(); dolighting = TRUE; for (i = 0; i < MAX_PLRS; i++) { if (plr[i].plractive && currlevel == plr[i].plrlevel) LightList[plr[i]._plid]._lunflag = TRUE; } mem_free_dbg(LoadBuff); } ================================================ FILE: Source/loadsave.h ================================================ /** * @file loadsave.h * * Interface of save game functionality. */ #ifndef __LOADSAVE_H__ #define __LOADSAVE_H__ void LoadGame(BOOL firstflag); void SaveGame(); void SaveLevel(); void LoadLevel(); #endif /* __LOADSAVE_H__ */ ================================================ FILE: Source/logging.cpp ================================================ /** * @file logging.cpp * * Implementation of logging functionality. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" static CCritSect sgMemCrit; CHAR FileName[MAX_PATH]; char log_buffer[388]; LPCVOID lpAddress; DWORD nNumberOfBytesToWrite; /* data */ /** Has the log file not yet been created. */ BOOL log_not_created = TRUE; /** Handle to the log file. */ HANDLE log_file = INVALID_HANDLE_VALUE; static void log_get_version(VS_FIXEDFILEINFO *file_info) { DWORD size, len, dwHandle; unsigned int puLen; void *version; char Filename[MAX_PATH]; LPVOID lpBuffer; memset(file_info, 0, sizeof(*file_info)); if (GetModuleFileName(0, Filename, sizeof(Filename))) { size = GetFileVersionInfoSize(Filename, &dwHandle); if (size) { version = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); if (GetFileVersionInfo(Filename, 0, size, version) && VerQueryValue(version, "\\", &lpBuffer, &puLen)) { len = puLen; if (puLen >= 52) len = 52; memcpy(file_info, lpBuffer, len); } VirtualFree(version, 0, MEM_RELEASE); } } } static HANDLE log_create() { char *last_slash_pos; HANDLE fh; VS_FIXEDFILEINFO file_info; DWORD i; char buf[32]; if (log_not_created) { char filename_tmp[MAX_PATH]; if (GetModuleFileName(NULL, filename_tmp, sizeof filename_tmp) == 0) filename_tmp[0] = '\0'; else { last_slash_pos = strrchr(filename_tmp, '\\'); if (last_slash_pos == NULL) filename_tmp[0] = '\0'; else *(last_slash_pos + 1) = '\0'; } i = 32; if (!GetUserName(buf, &i)) buf[0] = '\0'; log_get_version(&file_info); _snprintf( FileName, sizeof(filename_tmp), "%s%s%02u%02u%02u.ERR", filename_tmp, buf, file_info.dwProductVersionMS & 0xFFFF, file_info.dwProductVersionLS >> 16, file_info.dwProductVersionLS & 0xFFFF); } fh = INVALID_HANDLE_VALUE; for (i = log_not_created ? 0 : 1; (int)i < 2; i++) { fh = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fh != INVALID_HANDLE_VALUE) { if (GetFileSize(fh, NULL) > 0x10000) SetEndOfFile(fh); break; } last_slash_pos = strrchr(FileName, '\\'); if (!last_slash_pos) last_slash_pos = FileName; char filename_tmp[MAX_PATH] = "c:\\"; strcat(filename_tmp, last_slash_pos); strcpy(FileName, filename_tmp); } log_not_created = FALSE; return fh; } void __cdecl log_flush(BOOL force_close) { DWORD NumberOfBytesWritten; sgMemCrit.Enter(); if (nNumberOfBytesToWrite) { if (log_file == INVALID_HANDLE_VALUE) { log_file = log_create(); if (log_file == INVALID_HANDLE_VALUE) { nNumberOfBytesToWrite = 0; return; } SetFilePointer(log_file, 0, NULL, FILE_END); } WriteFile(log_file, lpAddress, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0); nNumberOfBytesToWrite = 0; } if (force_close && log_file != INVALID_HANDLE_VALUE) { CloseHandle(log_file); log_file = INVALID_HANDLE_VALUE; } sgMemCrit.Leave(); } void __cdecl log_printf(const char *pszFmt, ...) { #ifdef HELLFIRE CHAR Buffer[1024]; DWORD NumberOfBytesWritten, nNumberOfBytesToWrite; va_list va; va_start(va, pszFmt); nNumberOfBytesToWrite = wvsprintf(Buffer, va_arg(va, const CHAR *), va); WriteFile((HANDLE)pszFmt, Buffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0); va_end(va); #else size_t size; char *pBuffer; char msg[512]; va_list va; sgMemCrit.Enter(); va_start(va, pszFmt); _vsnprintf(msg, 0x200, pszFmt, va); va_end(va); msg[511] = 0; size = strlen(msg); if (size + nNumberOfBytesToWrite > 0x1000) { log_flush(FALSE); } if (lpAddress == NULL) { lpAddress = (char *)VirtualAlloc((LPVOID)lpAddress, 0x1000, MEM_COMMIT, PAGE_READWRITE); pBuffer = (char *)lpAddress; nNumberOfBytesToWrite = 0; } if (lpAddress != NULL) { pBuffer = (char *)lpAddress; memcpy(&pBuffer[nNumberOfBytesToWrite], msg, size); nNumberOfBytesToWrite += size; } sgMemCrit.Leave(); #endif } void log_dump_computer_info() { char Buffer[64]; VS_FIXEDFILEINFO file_info; SYSTEMTIME SystemTime; DWORD pcbBuffer; 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, file_info.dwProductVersionMS & 0xFFFF, file_info.dwProductVersionLS >> 16, file_info.dwProductVersionLS & 0xFFFF, Buffer, SystemTime.wMonth, SystemTime.wDay, SystemTime.wYear % 100, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, log_buffer); } ================================================ FILE: Source/logging.h ================================================ /** * @file logging.h * * Interface of logging functionality. */ #ifndef __LOGGING_H__ #define __LOGGING_H__ extern CHAR FileName[MAX_PATH]; extern LPCVOID lpAddress; extern DWORD nNumberOfBytesToWrite; void __cdecl log_flush(BOOL force_close); void __cdecl log_printf(const char *pszFmt, ...); // LogMessage void log_dump_computer_info(); /* data */ extern HANDLE log_file; #endif /* __LOGGING_H__ */ ================================================ FILE: Source/mainmenu.cpp ================================================ /** * @file mainmenu.cpp * * Implementation of functions for interacting with the main menu. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" #include "../DiabloUI/diabloui.h" char gszHero[16]; /* data */ /** The active music track id for the main menu. */ int menu_music_track_id = TMUSIC_INTRO; void mainmenu_refresh_music() { music_start(menu_music_track_id); #ifndef SPAWN do { menu_music_track_id++; if (menu_music_track_id == NUM_MUSIC) menu_music_track_id = TMUSIC_TOWN; } while (menu_music_track_id == TMUSIC_TOWN || menu_music_track_id == TMUSIC_L1); #endif } static BOOL mainmenu_init_menu(int type) { BOOL success; if (type == SELHERO_PREVIOUS) return TRUE; music_stop(); success = StartGame(type != SELHERO_CONTINUE, type != SELHERO_CONNECT); if (success) mainmenu_refresh_music(); return success; } static BOOL mainmenu_single_player() { #ifdef HELLFIRE int dlgresult; while (TRUE) { gbMaxPlayers = 1; dlgresult = 0; if (!SRegLoadValue(APP_NAME, jogging_title, 0, &jogging_opt)) { jogging_opt = TRUE; } if (!UiSelHeroSingDialog( pfile_ui_set_hero_infos, pfile_ui_save_create, pfile_delete_save, pfile_ui_set_class_stats, &dlgresult, gszHero, &gnDifficulty //,UseBardTest, //UseBarbarianTest )) { app_fatal("Unable to display SelHeroSing"); } if (dlgresult == SELHERO_PREVIOUS) return TRUE; if (!mainmenu_init_menu(dlgresult)) return FALSE; } #else gbMaxPlayers = 1; return mainmenu_init_menu(SELHERO_NEW_DUNGEON); #endif } static BOOL mainmenu_multi_player() { #ifdef HELLFIRE int dlgresult; BOOL hero_is_created = TRUE; while (TRUE) { gbMaxPlayers = MAX_PLRS; dlgresult = 0; jogging_opt = FALSE; if (!UiSelHeroMultDialog( pfile_ui_set_hero_infos, pfile_ui_save_create, pfile_delete_save, pfile_ui_set_class_stats, &dlgresult, &hero_is_created, // Not in hellfire gszHero //,UseBardTest, //UseBarbarianTest )) { app_fatal("Can't load multiplayer dialog"); } if (dlgresult == SELHERO_PREVIOUS) return TRUE; if (!mainmenu_init_menu(dlgresult)) return FALSE; } #else gbMaxPlayers = MAX_PLRS; return mainmenu_init_menu(SELHERO_CONNECT); #endif } #ifndef SPAWN static void mainmenu_play_intro() { music_stop(); #ifdef HELLFIRE play_movie("gendata\\Hellfire.smk", TRUE); #else play_movie("gendata\\diablo1.smk", TRUE); #endif mainmenu_refresh_music(); } #endif void __stdcall mainmenu_change_name(int arg1, int arg2, int arg3, int arg4, char *name_1, char *name_2) { if (UiValidPlayerName(name_2)) pfile_rename_hero(name_1, name_2); } BOOL __stdcall mainmenu_select_hero_dialog( const _SNETPROGRAMDATA *client_info, const _SNETPLAYERDATA *user_info, const _SNETUIDATA *ui_info, const _SNETVERSIONDATA *fileinfo, DWORD mode, char *cname, DWORD clen, char *cdesc, DWORD cdlen, BOOL *multi) { BOOL hero_is_created = TRUE; int dlgresult = 0; if (gbMaxPlayers == 1) { if (!UiSelHeroSingDialog( pfile_ui_set_hero_infos, pfile_ui_save_create, pfile_delete_save, pfile_ui_set_class_stats, &dlgresult, gszHero, &gnDifficulty)) app_fatal("Unable to display SelHeroSing"); if (dlgresult == SELHERO_CONTINUE) gbLoadGame = TRUE; else gbLoadGame = FALSE; } else if (!UiSelHeroMultDialog( pfile_ui_set_hero_infos, pfile_ui_save_create, pfile_delete_save, pfile_ui_set_class_stats, &dlgresult, &hero_is_created, gszHero)) { app_fatal("Can't load multiplayer dialog"); } if (dlgresult == SELHERO_PREVIOUS) { SErrSetLastError(1223); return FALSE; } pfile_create_player_description(cdesc, cdlen); if (multi) { #ifndef HELLFIRE if (mode == 'BNET') *multi = hero_is_created || !plr[myplr].pBattleNet; else *multi = hero_is_created; #endif } if (cname && clen) SStrCopy(cname, gszHero, clen); return TRUE; } void mainmenu_loop() { BOOL done; int menu; mainmenu_refresh_music(); done = FALSE; do { menu = 0; #ifdef HELLFIRE //if (!UiMainMenuDialog(gszProductName, &menu, UseMultiTest, effects_play_sound, 30)) if (!UiMainMenuDialog(gszProductName, &menu, effects_play_sound, 30)) #else if (!UiMainMenuDialog(gszProductName, &menu, effects_play_sound, 30)) #endif app_fatal("Unable to display mainmenu"); switch (menu) { case MAINMENU_SINGLE_PLAYER: if (!mainmenu_single_player()) done = TRUE; break; case MAINMENU_MULTIPLAYER: if (!mainmenu_multi_player()) done = TRUE; break; case MAINMENU_ATTRACT_MODE: #ifdef HELLFIRE break; #endif case MAINMENU_REPLAY_INTRO: #ifdef SPAWN #ifndef HELLFIRE done = FALSE; #endif #else if (gbActive) mainmenu_play_intro(); #endif break; case MAINMENU_SHOW_CREDITS: UiCreditsDialog(16); break; #ifdef HELLFIRE case MAINMENU_SHOW_SUPPORT: //UiSupportDialog(16); UiCreditsDialog(16); break; #endif case MAINMENU_EXIT_DIABLO: done = TRUE; break; } } while (!done); music_stop(); } ================================================ FILE: Source/mainmenu.h ================================================ /** * @file mainmenu.h * * Interface of functions for interacting with the main menu. */ #ifndef __MAINMENU_H__ #define __MAINMENU_H__ extern char gszHero[16]; void __stdcall mainmenu_change_name(int arg1, int arg2, int arg3, int arg4, char *name_1, char *name_2); BOOL __stdcall mainmenu_select_hero_dialog( const _SNETPROGRAMDATA *client_info, const _SNETPLAYERDATA *user_info, const _SNETUIDATA *ui_info, const _SNETVERSIONDATA *fileinfo, DWORD mode, // 4 chars, e.g. 'IPXN', 'BNET' etc. */ char *cname, DWORD clen, // character name will be copied here char *cdesc, DWORD cdlen, // character "description" will be copied here (used to advertise games) BOOL *multi); // new character? - unsure about this void mainmenu_loop(); #endif /* __MAINMENU_H__ */ ================================================ FILE: Source/minitext.cpp ================================================ /** * @file minitext.cpp * * Implementation of scrolling dialog text. */ #include "all.h" /** Current y position of text in px */ int qtexty; /** Pointer to the current text being displayed */ const char *qtextptr; /** Time of last rendering of the text */ int sgLastScroll; /** Specify if the quest dialog window is being shown */ BOOLEAN qtextflag; /** Duplicate of qtextSpd */ int qtextDelay; /** Vertical speed of the scrolling text, see qscroll_spd_tbl */ int qtextSpd; /** Graphics for the medium size font */ BYTE *pMedTextCels; /** Graphics for the window border */ BYTE *pTextBoxCels; /** Maps from font index to medtexts.cel frame number. */ const BYTE mfontframe[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0 }; /** * Maps from medtexts.cel frame number to character width. Note, the * character width may be distinct from the frame width, which is 22 for every * medtexts.cel frame. */ const BYTE 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 */ /** * Text scroll speeds. Positive numbers will delay scrolling 1 out of n frames, * negative numbers will scroll 1+(-n) pixels. */ int qscroll_spd_tbl[9] = { 2, 4, 6, 8, 0, -1, -2, -3, -4 }; /** * @brief Free the resouces used by the quest dialog window */ void FreeQuestText() { MemFreeDbg(pMedTextCels); MemFreeDbg(pTextBoxCels); } /** * @brief Load the resouces used by the quest dialog window, and initialize it's state */ void InitQuestText() { pMedTextCels = LoadFileInMem("Data\\MedTextS.CEL", NULL); pTextBoxCels = LoadFileInMem("Data\\TextBox.CEL", NULL); qtextflag = FALSE; } /** * @brief Start the given naration * @param m Index of narration from the alltext table */ void InitQTextMsg(int m) { if (alltext[m].scrlltxt) { questlog = FALSE; qtextptr = alltext[m].txtstr; qtextflag = TRUE; qtexty = 340 + SCREEN_Y; qtextSpd = qscroll_spd_tbl[alltext[m].txtspd - 1]; qtextDelay = qtextSpd; sgLastScroll = GetTickCount(); } PlaySFX(alltext[m].sfxnr); } /** * @brief Draw the quest dialog window decoration and background */ void DrawQTextBack() { CelDraw(PANEL_X + 24, SCREEN_Y + 327, pTextBoxCels, 1, 591); #define TRANS_RECT_X (PANEL_LEFT + 27) #define TRANS_RECT_Y 28 #define TRANS_RECT_WIDTH 585 #define TRANS_RECT_HEIGHT 297 #include "asm_trans_rect.inc" } /** * @brief Print a character * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param pCelBuff Cel data * @param nCel CEL frame number */ void PrintQTextChr(int sx, int sy, BYTE *pCelBuff, int nCel) { BYTE *dst, *pStart, *pEnd, *end; /// ASSERT: assert(gpBuffer); dst = &gpBuffer[sx + PitchTbl[sy]]; pStart = &gpBuffer[PitchTbl[209]]; pEnd = &gpBuffer[PitchTbl[469]]; #ifdef USE_ASM __asm { mov ebx, pCelBuff mov eax, nCel shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov end, eax mov esi, pCelBuff add esi, [ebx] mov edi, dst mov ebx, end add ebx, esi label1: mov edx, 22 label2: xor eax, eax lodsb or al, al js label7 sub edx, eax cmp edi, pStart jb label5 cmp edi, pEnd ja label5 mov ecx, eax shr ecx, 1 jnb label3 movsb jecxz label6 label3: shr ecx, 1 jnb label4 movsw jecxz label6 label4: rep movsd jmp label6 label5: add esi, eax add edi, eax label6: or edx, edx jz label8 jmp label2 label7: neg al add edi, eax sub edx, eax jnz label2 label8: sub edi, BUFFER_WIDTH + 22 cmp ebx, esi jnz label1 } #else int i; BYTE width; BYTE *src; DWORD *pFrameTable; pFrameTable = (DWORD *)&pCelBuff[4 * nCel]; src = &pCelBuff[pFrameTable[0]]; end = &src[pFrameTable[1] - pFrameTable[0]]; for (; src != end; dst -= BUFFER_WIDTH + 22) { for (i = 22; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (dst >= pStart && dst <= pEnd) { if (width & 1) { dst[0] = src[0]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = src[0]; dst[1] = src[1]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; src += 4; dst += 4; } } else { src += width; dst += width; } } else { width = -(char)width; dst += width; i -= width; } } } #endif } /** * @brief Draw the quest dialog window decoration and background */ void DrawQText() { int i, l, w, tx, ty; BYTE c; const char *p, *pnl, *s; char tempstr[128]; BOOL doneflag; DWORD currTime; DrawQTextBack(); p = qtextptr; pnl = NULL; tx = 48 + PANEL_X; ty = qtexty; doneflag = FALSE; while (!doneflag) { w = 0; s = p; l = 0; while (*s != '\n' && *s != '|' && w < 543) { c = gbFontTransTbl[(BYTE)*s]; s++; if (c != '\0') { tempstr[l] = c; w += mfontkern[mfontframe[c]] + 2; } else { l--; } l++; } tempstr[l] = '\0'; if (*s == '|') { tempstr[l] = '\0'; doneflag = TRUE; } else if (*s != '\n') { while (tempstr[l] != ' ' && l > 0) { tempstr[l] = '\0'; l--; } } for (i = 0; tempstr[i]; i++) { p++; c = mfontframe[gbFontTransTbl[(BYTE)tempstr[i]]]; if (*p == '\n') { p++; } if (c != 0) { PrintQTextChr(tx, ty, pMedTextCels, c); } tx += mfontkern[c] + 2; } if (pnl == NULL) { pnl = p; } tx = 48 + PANEL_X; ty += 38; if (ty > 341 + SCREEN_Y) { doneflag = TRUE; } } currTime = GetTickCount(); while (1) { if (qtextSpd <= 0) { qtexty--; qtexty += qtextSpd; } else { qtextDelay--; if (qtextDelay != 0) { qtexty--; } } if (qtextDelay == 0) { qtextDelay = qtextSpd; } if (qtexty <= 49 + SCREEN_Y) { qtexty += 38; qtextptr = pnl; if (*pnl == '|') { qtextflag = FALSE; } break; } sgLastScroll += 50; if (currTime - sgLastScroll >= 0x7FFFFFFF) { break; } } } ================================================ FILE: Source/minitext.h ================================================ /** * @file minitext.h * * Interface of scrolling dialog text. */ #ifndef __MINITEXT_H__ #define __MINITEXT_H__ extern BOOLEAN qtextflag; void FreeQuestText(); void InitQuestText(); void InitQTextMsg(int m); void DrawQTextBack(); void DrawQText(); #endif /* __MINITEXT_H__ */ ================================================ FILE: Source/misdat.cpp ================================================ /** * @file misdat.cpp * * Implementation of data related to missiles. */ #include "all.h" /** Data related to each missile ID. */ MissileData missiledata[] = { // clang-format off // mName, mAddProc, mProc, mDraw, mType, mResist, mFileNum, mlSFX, miSFX; { MIS_ARROW, &AddArrow, &MI_Arrow, TRUE, 0, MISR_NONE, MFILE_ARROWS, -1, -1 }, { MIS_FIREBOLT, &AddFirebolt, &MI_Firebolt, TRUE, 1, MISR_FIRE, MFILE_FIREBA, LS_FBOLT1, LS_FIRIMP2 }, { MIS_GUARDIAN, &AddGuardian, &MI_Guardian, TRUE, 1, MISR_NONE, MFILE_GUARD, LS_GUARD, LS_GUARDLAN }, { MIS_RNDTELEPORT, &AddRndTeleport, &MI_Teleport, FALSE, 1, MISR_NONE, MFILE_NONE, LS_TELEPORT, -1 }, { MIS_LIGHTBALL, &AddLightball, &MI_Lightball, TRUE, 1, MISR_LIGHTNING, MFILE_LGHNING, -1, -1 }, { MIS_FIREWALL, &AddFirewall, &MI_Firewall, TRUE, 1, MISR_FIRE, MFILE_FIREWAL, LS_WALLLOOP, LS_FIRIMP2 }, { MIS_FIREBALL, &AddFireball, &MI_Fireball, TRUE, 1, MISR_FIRE, MFILE_FIREBA, LS_FBOLT1, LS_FIRIMP2 }, { MIS_LIGHTCTRL, &AddLightctrl, &MI_Lightctrl, FALSE, 1, MISR_LIGHTNING, MFILE_LGHNING, -1, -1 }, { MIS_LIGHTNING, &AddLightning, &MI_Lightning, TRUE, 1, MISR_LIGHTNING, MFILE_LGHNING, LS_LNING1, LS_ELECIMP1 }, { MIS_MISEXP, &AddMisexp, &MI_Misexp, TRUE, 2, MISR_NONE, MFILE_MAGBLOS, -1, -1 }, { MIS_TOWN, &AddTown, &MI_Town, TRUE, 1, MISR_MAGIC, MFILE_PORTAL, LS_SENTINEL, LS_ELEMENTL }, { MIS_FLASH, &AddFlash, &MI_Flash, TRUE, 1, MISR_MAGIC, MFILE_BLUEXFR, LS_NOVA, LS_ELECIMP1 }, { MIS_FLASH2, &AddFlash2, &MI_Flash2, TRUE, 1, MISR_MAGIC, MFILE_BLUEXBK, -1, -1 }, #ifdef HELLFIRE { MIS_MANASHIELD, &AddManashield, &MI_SetManashield, TRUE, 1, MISR_MAGIC, MFILE_MANASHLD, LS_MSHIELD, -1 }, #else { MIS_MANASHIELD, &AddManashield, &MI_SetManashield, FALSE, 1, MISR_MAGIC, MFILE_MANASHLD, LS_MSHIELD, -1 }, #endif { MIS_FIREMOVE, &AddFiremove, &MI_Firemove, TRUE, 1, MISR_FIRE, MFILE_FIREWAL, -1, -1 }, { MIS_CHAIN, &AddChain, &MI_Chain, TRUE, 1, MISR_LIGHTNING, MFILE_LGHNING, LS_LNING1, LS_ELECIMP1 }, { MIS_SENTINAL, NULL, NULL, TRUE, 1, MISR_LIGHTNING, MFILE_LGHNING, -1, -1 }, { MIS_BLODSTAR, &miss_null_11, &mi_null_11, TRUE, 2, MISR_NONE, MFILE_BLOOD, LS_BLODSTAR, LS_BLSIMPT }, { MIS_BONE, &miss_null_12, &mi_null_11, TRUE, 2, MISR_NONE, MFILE_BONE, -1, -1 }, { MIS_METLHIT, &miss_null_13, &mi_null_11, TRUE, 2, MISR_NONE, MFILE_METLHIT, -1, -1 }, { MIS_RHINO, &AddRhino, &MI_Rhino, TRUE, 2, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_MAGMABALL, &AddMagmaball, &MI_Firebolt, TRUE, 1, MISR_FIRE, MFILE_MAGBALL, -1, -1 }, { MIS_LIGHTCTRL2, &AddLightctrl, &MI_Lightctrl, FALSE, 1, MISR_LIGHTNING, MFILE_THINLGHT, -1, -1 }, { MIS_LIGHTNING2, &AddLightning, &MI_Lightning, TRUE, 1, MISR_LIGHTNING, MFILE_THINLGHT, -1, -1 }, { MIS_FLARE, &AddFlare, &MI_Firebolt, TRUE, 1, MISR_MAGIC, MFILE_FLARE, -1, -1 }, { MIS_MISEXP2, &AddMisexp, &MI_Misexp, TRUE, 2, MISR_MAGIC, MFILE_FLAREEXP, -1, -1 }, { MIS_TELEPORT, &AddTeleport, &MI_Teleport, FALSE, 1, MISR_NONE, MFILE_NONE, LS_ELEMENTL, -1 }, { MIS_FARROW, &AddLArrow, &MI_LArrow, TRUE, 0, MISR_FIRE, MFILE_FARROW, -1, -1 }, { MIS_DOOMSERP, NULL, NULL, FALSE, 1, MISR_MAGIC, MFILE_DOOM, LS_DSERP, -1 }, { MIS_FIREWALLA, &miss_null_1D, &MI_Firewall, TRUE, 2, MISR_FIRE, MFILE_FIREWAL, -1, -1 }, { MIS_STONE, &AddStone, &MI_Stone, FALSE, 1, MISR_MAGIC, MFILE_NONE, LS_SCURIMP, -1 }, { MIS_NULL_1F, &miss_null_1F, &MI_Dummy, TRUE, 1, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_INVISIBL, NULL, NULL, FALSE, 1, MISR_NONE, MFILE_NONE, LS_INVISIBL, -1 }, { MIS_GOLEM, &AddGolem, &MI_Golem, FALSE, 1, MISR_NONE, MFILE_NONE, LS_GOLUM, -1 }, { MIS_ETHEREALIZE, &AddEtherealize, &MI_Etherealize, TRUE, 1, MISR_NONE, MFILE_ETHRSHLD, LS_ETHEREAL, -1 }, { MIS_BLODBUR, &miss_null_23, &mi_null_11, TRUE, 2, MISR_NONE, MFILE_BLODBUR, -1, -1 }, { MIS_BOOM, &AddBoom, &MI_Boom, TRUE, 2, MISR_NONE, MFILE_NEWEXP, -1, -1 }, { MIS_HEAL, &AddHeal, &MI_Dummy, FALSE, 1, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_FIREWALLC, &AddFirewallC, &MI_FirewallC, FALSE, 1, MISR_FIRE, MFILE_FIREWAL, -1, -1 }, { MIS_INFRA, &AddInfra, &MI_Infra, FALSE, 1, MISR_NONE, MFILE_NONE, LS_INFRAVIS, -1 }, { MIS_IDENTIFY, &AddIdentify, &MI_Dummy, FALSE, 1, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_WAVE, &AddWave, &MI_Wave, TRUE, 1, MISR_FIRE, MFILE_FIREWAL, LS_FLAMWAVE, -1 }, { MIS_NOVA, &AddNova, &MI_Nova, TRUE, 1, MISR_LIGHTNING, MFILE_LGHNING, LS_NOVA, -1 }, #ifdef HELLFIRE { MIS_BLODBOIL, &miss_null_1F, &MI_Blodboil, FALSE, 1, MISR_NONE, MFILE_NONE, -1, -1 }, #else { MIS_BLODBOIL, &AddBlodboil, &MI_Blodboil, TRUE, 1, MISR_NONE, MFILE_NONE, -1, LS_BLODBOIL }, #endif { MIS_APOCA, &AddApoca, &MI_Apoca, TRUE, 1, MISR_MAGIC, MFILE_NEWEXP, LS_APOC, -1 }, { MIS_REPAIR, &AddRepair, &MI_Dummy, FALSE, 2, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_RECHARGE, &AddRecharge, &MI_Dummy, FALSE, 2, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_DISARM, &AddDisarm, &MI_Dummy, FALSE, 2, MISR_NONE, MFILE_NONE, LS_TRAPDIS, -1 }, { MIS_FLAME, &AddFlame, &MI_Flame, TRUE, 1, MISR_FIRE, MFILE_INFERNO, LS_SPOUTSTR, -1 }, { MIS_FLAMEC, &AddFlamec, &MI_Flamec, FALSE, 1, MISR_FIRE, MFILE_NONE, -1, -1 }, { MIS_FIREMAN, &miss_null_32, &mi_null_32, TRUE, 2, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_KRULL, &miss_null_33, &mi_null_33, TRUE, 0, MISR_FIRE, MFILE_KRULL, -1, -1 }, { MIS_CBOLT, &AddCbolt, &MI_Cbolt, TRUE, 1, MISR_LIGHTNING, MFILE_MINILTNG, LS_CBOLT, -1 }, { MIS_HBOLT, &AddHbolt, &MI_Hbolt, TRUE, 1, MISR_NONE, MFILE_HOLY, LS_HOLYBOLT, LS_ELECIMP1 }, { MIS_RESURRECT, &AddResurrect, &MI_Dummy, FALSE, 1, MISR_MAGIC, MFILE_NONE, -1, LS_RESUR }, { MIS_TELEKINESIS, &AddTelekinesis, &MI_Dummy, FALSE, 1, MISR_NONE, MFILE_NONE, LS_ETHEREAL, -1 }, { MIS_LARROW, &AddLArrow, &MI_LArrow, TRUE, 0, MISR_LIGHTNING, MFILE_LARROW, -1, -1 }, { MIS_ACID, &AddAcid, &MI_Firebolt, TRUE, 1, MISR_ACID, MFILE_ACIDBF, LS_ACID, -1 }, { MIS_MISEXP3, &AddMisexp, &MI_Acidsplat, TRUE, 2, MISR_ACID, MFILE_ACIDSPLA, -1, -1 }, { MIS_ACIDPUD, &AddAcidpud, &MI_Acidpud, TRUE, 2, MISR_ACID, MFILE_ACIDPUD, LS_PUDDLE, -1 }, { MIS_HEALOTHER, &AddHealOther, &MI_Dummy, FALSE, 1, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_ELEMENT, &AddElement, &MI_Element, TRUE, 1, MISR_FIRE, MFILE_FIRERUN, LS_ELEMENTL, -1 }, { MIS_RESURRECTBEAM, &AddResurrectBeam, &MI_ResurrectBeam, TRUE, 1, MISR_NONE, MFILE_RESSUR1, -1, -1 }, { MIS_BONESPIRIT, &AddBoneSpirit, &MI_Bonespirit, TRUE, 1, MISR_MAGIC, MFILE_SKLBALL, LS_BONESP, LS_BSIMPCT }, { MIS_WEAPEXP, &AddWeapexp, &MI_Weapexp, TRUE, 2, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_RPORTAL, &AddRportal, &MI_Rportal, TRUE, 2, MISR_NONE, MFILE_RPORTAL, LS_SENTINEL, LS_ELEMENTL }, { MIS_BOOM2, &AddBoom, &MI_Boom, TRUE, 2, MISR_NONE, MFILE_FIREPLAR, -1, -1 }, { MIS_DIABAPOCA, &AddDiabApoca, &MI_Dummy, FALSE, 2, MISR_NONE, MFILE_NONE, -1, -1 }, #ifdef HELLFIRE { MIS_MANA, &missiles_rech_mana, &MI_Dummy, FALSE, 1, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_MAGI, &missiles_magi, &MI_Dummy, FALSE, 1, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_LIGHTWALL, &missiles_light_wall, &mi_light_wall, TRUE, 1, MISR_LIGHTNING, MFILE_LGHNING, LS_LMAG, LS_ELECIMP1 }, { MIS_LIGHTNINGWALL, &AddFirewallC, &mi_lightning_wall, FALSE, 1, MISR_LIGHTNING, MFILE_LGHNING, -1, -1 }, { MIS_IMMOLATION, &AddNova, &mi_fire_nova, TRUE, 1, MISR_FIRE, MFILE_FIREBA, LS_FBOLT1, LS_FIRIMP2 }, { MIS_SPECARROW, &missiles_spec_arrow, &mi_spec_arrow, TRUE, 0, MISR_NONE, MFILE_ARROWS, -1, -1 }, { MIS_FIRENOVA, &missiles_immo_2, &MI_Fireball, TRUE, 1, MISR_FIRE, MFILE_FIREBA, IS_FBALLBOW, LS_FIRIMP2 }, { MIS_LIGHTARROW, &missiles_larrow, &mi_light_arrow, FALSE, 1, MISR_LIGHTNING, MFILE_LGHNING, IS_FBALLBOW, -1 }, { MIS_CBOLTARROW, &missiles_cbolt_arrow, &MI_Cbolt, TRUE, 1, MISR_LIGHTNING, MFILE_MINILTNG, LS_CBOLT, -1 }, { MIS_HBOLTARROW, &missiles_hbolt_arrow, &MI_Hbolt, TRUE, 1, MISR_NONE, MFILE_HOLY, LS_HOLYBOLT, LS_ELECIMP1 }, { MIS_WARP, &missiles_warp, &MI_Teleport, FALSE, 1, MISR_NONE, MFILE_NONE, LS_ETHEREAL, -1 }, { MIS_REFLECT, &missiles_reflection, &mi_reflect, TRUE, 1, MISR_NONE, MFILE_REFLECT, LS_MSHIELD, -1 }, { MIS_BERSERK, &missiles_berserk, &MI_Dummy, FALSE, 1, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_FIRERING, &missiles_ring, &mi_fire_ring, FALSE, 1, MISR_FIRE, MFILE_FIREWAL, -1, -1 }, { MIS_STEALPOTS, &missiles_steal_pots, &MI_Dummy, FALSE, 1, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_MANATRAP, &missiles_mana_trap, &MI_Dummy, FALSE, 1, MISR_NONE, MFILE_NONE, IS_CAST7, -1 }, { MIS_LIGHTRING, &missiles_ring, &mi_light_ring, FALSE, 1, MISR_LIGHTNING, MFILE_LGHNING, -1, -1 }, { MIS_SEARCH, &missiles_search, &mi_search, FALSE, 1, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_FLASHFR, &missiles_43303D, &mi_flashfr, TRUE, 1, MISR_MAGIC, MFILE_BLUEXFR, -1, LS_ELECIMP1 }, { MIS_FLASHBK, &missiles_433040, &mi_flashbk, TRUE, 1, MISR_MAGIC, MFILE_BLUEXBK, -1, -1 }, { MIS_IMMOLATION2, &missiles_immo_1, &mi_immolation, TRUE, 1, MISR_FIRE, MFILE_FIREBA, LS_FBOLT1, LS_FIRIMP2 }, { MIS_RUNEFIRE, &missiles_fire_rune, &MI_Rune, TRUE, 1, MISR_NONE, MFILE_RUNE, -1, -1 }, { MIS_RUNELIGHT, &missiles_light_rune, &MI_Rune, TRUE, 1, MISR_NONE, MFILE_RUNE, -1, -1 }, { MIS_RUNENOVA, &missiles_great_light_rune, &MI_Rune, TRUE, 1, MISR_NONE, MFILE_RUNE, -1, -1 }, { MIS_RUNEIMMOLAT, &missiles_immolation_rune, &MI_Rune, TRUE, 1, MISR_NONE, MFILE_RUNE, -1, -1 }, { MIS_RUNESTONE, &missiles_stone_rune, &MI_Rune, TRUE, 1, MISR_NONE, MFILE_RUNE, -1, -1 }, { MIS_HIVEEXP, &missiles_rune_explosion, &mi_hive_explode, TRUE, 1, MISR_FIRE, MFILE_BIGEXP, LS_NESTXPLD, LS_NESTXPLD }, { MIS_HORKDMN, &missiles_hork_spawn, &mi_hork_spawn, TRUE, 2, MISR_NONE, MFILE_NULL, -1, -1 }, { MIS_JESTER, &missiles_jester, &MI_Dummy, FALSE, 2, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_HIVEEXP2, &missiles_hive_explosion, &MI_Dummy, FALSE, 2, MISR_NONE, MFILE_NONE, -1, -1 }, { MIS_LICH, &AddFlare, &MI_Firebolt, TRUE, 1, MISR_MAGIC, MFILE_LICH, -1, -1 }, { MIS_PSYCHORB, &AddFlare, &MI_Firebolt, TRUE, 1, MISR_MAGIC, MFILE_BONEDEMON, -1, -1 }, { MIS_NECROMORB, &AddFlare, &MI_Firebolt, TRUE, 1, MISR_MAGIC, MFILE_NECROMORB, -1, -1 }, { MIS_ARCHLICH, &AddFlare, &MI_Firebolt, TRUE, 1, MISR_MAGIC, MFILE_ARCHLICH, -1, -1 }, { MIS_BONEDEMON, &AddFlare, &MI_Firebolt, TRUE, 1, MISR_MAGIC, MFILE_BONEDEMON, -1, -1 }, { MIS_EXYEL2, &AddMisexp, &MI_Misexp, TRUE, 2, MISR_NONE, MFILE_EXYEL2, LS_FIRIMP2, -1 }, { MIS_EXRED3, &AddMisexp, &MI_Misexp, TRUE, 2, MISR_NONE, MFILE_EXRED3, LS_FIRIMP2, -1 }, { MIS_EXBL2, &AddMisexp, &MI_Misexp, TRUE, 2, MISR_NONE, MFILE_EXBL2, LS_FIRIMP2, -1 }, { MIS_EXBL3, &AddMisexp, &MI_Misexp, TRUE, 2, MISR_NONE, MFILE_EXBL3, LS_FIRIMP2, -1 }, { MIS_EXORA1, &AddMisexp, &MI_Misexp, TRUE, 2, MISR_NONE, MFILE_EXORA1, LS_FIRIMP2, -1 }, #endif // clang-format on }; /** Data related to each missile graphic ID. */ MisFileData misfiledata[] = { // clang-format off // mAnimName, mAnimFAmt, mName, mFlags, mAnimData[16], mAnimDelay[16], mAnimLen[16], mAnimWidth[16], mAnimWidth2[16] { 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 } }, #ifdef HELLFIRE { MFILE_SPAWNS, 8, "spawns", 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, 9, 9, 9, 9, 9, 9, 9, 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_REFLECT, 1, "reflect", 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 }, { 160, 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 } }, { MFILE_LICH, 16, "ms_ora", 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 }, { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, { 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 }, { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 } }, { MFILE_MSBLA, 16, "ms_bla", 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 }, { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, { 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 }, { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 } }, { MFILE_NECROMORB, 16, "ms_reb", 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 }, { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, { 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 }, { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 } }, { MFILE_ARCHLICH, 16, "ms_yeb", 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 }, { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, { 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 }, { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 } }, { MFILE_RUNE, 1, "rglows1", 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 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 }, { 96, 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 } }, { MFILE_EXYEL2, 1, "ex_yel2", 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 }, { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, { MFILE_EXBL2, 1, "ex_blu2", 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 }, { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, { MFILE_EXRED3, 1, "ex_red3", 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 }, { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 292, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, { MFILE_BONEDEMON, 16, "ms_blb", 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 }, { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, { 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 }, { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 } }, { MFILE_EXORA1, 1, "ex_ora1", 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 }, { 13, 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 }, { -12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, { MFILE_EXBL3, 1, "ex_blu3", 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 }, { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 292, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, #endif { MFILE_NONE, 0, "", 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, // clang-format on }; ================================================ FILE: Source/misdat.h ================================================ /** * @file misdat.h * * Interface of data related to missiles. */ #ifndef __MISDAT_H__ #define __MISDAT_H__ extern MissileData missiledata[]; extern MisFileData misfiledata[]; #endif /* __MISDAT_H__ */ ================================================ FILE: Source/missiles.cpp ================================================ /** * @file missiles.cpp * * Implementation of missile functionality. */ #include "all.h" int missileactive[MAXMISSILES]; int missileavail[MAXMISSILES]; MissileStruct missile[MAXMISSILES]; int nummissiles; BOOL ManashieldFlag; ChainStruct chain[MAXMISSILES]; BOOL MissilePreFlag; int numchains; /** Maps from direction to X-offset. */ int XDirAdd[8] = { 1, 0, -1, -1, -1, 0, 1, 1 }; /** Maps from direction to Y-offset. */ int YDirAdd[8] = { 1, 1, 1, 0, -1, -1, -1, 0 }; #ifdef HELLFIRE int CrawlNum[19] = { 0, 3, 12, 45, 94, 159, 240, 337, 450, 579, 724, 885, 1062, 1255, 1464, 1689, 1930, 2187, 2460 }; #endif void GetDamageAmt(int i, int *mind, int *maxd) { int k, sl; assert((DWORD)myplr < MAX_PLRS); assert((DWORD)i < 64); sl = plr[myplr]._pSplLvl[i] + plr[myplr]._pISplLvlAdd; switch (i) { case SPL_FIREBOLT: *mind = (plr[myplr]._pMagic >> 3) + sl + 1; *maxd = (plr[myplr]._pMagic >> 3) + sl + 10; break; case SPL_HEAL: /// BUGFIX: healing calculation is unused *mind = plr[myplr]._pLevel + sl + 1; #ifdef HELLFIRE if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_MONK || plr[myplr]._pClass == PC_BARBARIAN) { #else if (plr[myplr]._pClass == PC_WARRIOR) { #endif *mind <<= 1; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_ROGUE || plr[myplr]._pClass == PC_BARD) { #else if (plr[myplr]._pClass == PC_ROGUE) { #endif *mind += *mind >> 1; } *maxd = 10; for (k = 0; k < plr[myplr]._pLevel; k++) { *maxd += 4; } for (k = 0; k < sl; k++) { *maxd += 6; } #ifdef HELLFIRE if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_MONK || plr[myplr]._pClass == PC_BARBARIAN) { #else if (plr[myplr]._pClass == PC_WARRIOR) { #endif *maxd <<= 1; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_ROGUE || plr[myplr]._pClass == PC_BARD) { #else if (plr[myplr]._pClass == PC_ROGUE) { #endif *maxd += *maxd >> 1; } *mind = -1; *maxd = -1; break; #ifdef HELLFIRE case SPL_RUNELIGHT: #endif case SPL_LIGHTNING: *mind = 2; *maxd = plr[myplr]._pLevel + 2; break; case SPL_FLASH: *mind = plr[myplr]._pLevel; for (k = 0; k < sl; k++) { *mind += *mind >> 3; } *mind += *mind >> 1; *maxd = *mind * 2; break; 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: #ifdef HELLFIRE case SPL_WARP: case SPL_REFLECT: case SPL_BERSERK: case SPL_SEARCH: case SPL_RUNESTONE: #endif *mind = -1; *maxd = -1; break; case SPL_FIREWALL: *mind = (4 * plr[myplr]._pLevel + 8) >> 1; *maxd = (4 * plr[myplr]._pLevel + 80) >> 1; break; case SPL_FIREBALL: *mind = 2 * plr[myplr]._pLevel + 4; for (k = 0; k < sl; k++) { *mind += *mind >> 3; } *maxd = 2 * plr[myplr]._pLevel + 40; for (k = 0; k < sl; k++) { *maxd += *maxd >> 3; } break; case SPL_GUARDIAN: *mind = (plr[myplr]._pLevel >> 1) + 1; for (k = 0; k < sl; k++) { *mind += *mind >> 3; } *maxd = (plr[myplr]._pLevel >> 1) + 10; for (k = 0; k < sl; k++) { *maxd += *maxd >> 3; } break; case SPL_CHAIN: *mind = 4; *maxd = 2 * plr[myplr]._pLevel + 4; break; case SPL_WAVE: *mind = 6 * (plr[myplr]._pLevel + 1); *maxd = 6 * (plr[myplr]._pLevel + 10); break; case SPL_NOVA: *mind = (plr[myplr]._pLevel + 5) >> 1; for (k = 0; k < sl; k++) { *mind += *mind >> 3; } *mind *= 5; *maxd = (plr[myplr]._pLevel + 30) >> 1; for (k = 0; k < sl; k++) { *maxd += *maxd >> 3; } *maxd *= 5; break; case SPL_FLAME: *mind = 3; *maxd = plr[myplr]._pLevel + 4; *maxd += *maxd >> 1; break; case SPL_GOLEM: *mind = 11; *maxd = 17; break; case SPL_APOCA: *mind = 0; for (k = 0; k < plr[myplr]._pLevel; k++) { *mind += 1; } *maxd = 0; for (k = 0; k < plr[myplr]._pLevel; k++) { *maxd += 6; } break; case SPL_ELEMENT: *mind = 2 * plr[myplr]._pLevel + 4; for (k = 0; k < sl; k++) { *mind += *mind >> 3; } /// BUGFIX: add here '*mind >>= 1;' *maxd = 2 * plr[myplr]._pLevel + 40; for (k = 0; k < sl; k++) { *maxd += *maxd >> 3; } /// BUGFIX: add here '*maxd >>= 1;' break; case SPL_CBOLT: *mind = 1; *maxd = (plr[myplr]._pMagic >> 2) + 1; break; case SPL_HBOLT: *mind = plr[myplr]._pLevel + 9; *maxd = plr[myplr]._pLevel + 18; break; case SPL_HEALOTHER: /// BUGFIX: healing calculation is unused *mind = plr[myplr]._pLevel + sl + 1; #ifdef HELLFIRE if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_MONK || plr[myplr]._pClass == PC_BARBARIAN) { #else if (plr[myplr]._pClass == PC_WARRIOR) { #endif *mind <<= 1; } #ifdef HELLFIRE if (plr[myplr]._pClass == PC_ROGUE || plr[myplr]._pClass == PC_BARD) { #else if (plr[myplr]._pClass == PC_ROGUE) { #endif *mind += *mind >> 1; } *maxd = 10; for (k = 0; k < plr[myplr]._pLevel; k++) { *maxd += 4; } for (k = 0; k < sl; k++) { *maxd += 6; } #ifdef HELLFIRE if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_MONK || plr[myplr]._pClass == PC_BARBARIAN) { #else if (plr[myplr]._pClass == PC_WARRIOR) { #endif *maxd <<= 1; } #ifdef HELLFIRE if (plr[myplr]._pClass == PC_ROGUE || plr[myplr]._pClass == PC_BARD) { #else if (plr[myplr]._pClass == PC_ROGUE) { #endif *maxd += *maxd >> 1; } *mind = -1; *maxd = -1; break; case SPL_FLARE: *mind = (plr[myplr]._pMagic >> 1) + 3 * sl - (plr[myplr]._pMagic >> 3); *maxd = *mind; break; } } BOOL CheckBlock(int fx, int fy, int tx, int ty) { int pn; BOOL coll; coll = FALSE; while (fx != tx || fy != ty) { pn = GetDirection(fx, fy, tx, ty); fx += XDirAdd[pn]; fy += YDirAdd[pn]; if (nSolidTable[dPiece[fx][fy]]) coll = TRUE; } return coll; } int FindClosest(int sx, int sy, int rad) { int j, i, mid, tx, ty, cr; #ifndef HELLFIRE int CrawlNum[19] = { 0, 3, 12, 45, 94, 159, 240, 337, 450, 579, 724, 885, 1062, 1255, 1464, 1689, 1930, 2187, 2460 }; #endif if (rad > 19) rad = 19; for (i = 1; i < rad; i++) { cr = CrawlNum[i] + 2; #ifdef HELLFIRE for (j = CrawlTable[CrawlNum[i]]; j > 0; j--) { // BUGFIX: should cast to BYTE or CrawlTable header will be wrong #else for (j = (BYTE)CrawlTable[CrawlNum[i]]; j > 0; j--) { #endif tx = sx + CrawlTable[cr - 1]; ty = sy + CrawlTable[cr]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { mid = dMonster[tx][ty]; if (mid > 0 && !CheckBlock(sx, sy, tx, ty)) return mid - 1; } cr += 2; } } return -1; } int GetSpellLevel(int id, int sn) { int result; if (id == myplr) result = plr[id]._pISplLvlAdd + plr[id]._pSplLvl[sn]; else result = 1; if (result < 0) result = 0; return result; } int GetDirection8(int x1, int y1, int x2, int y2) { BYTE Dirs[16][16] = { { 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 2, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, { 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, { 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, { 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; int mx, my, md; ALIGN_BY_1 BYTE urtoll[] = { 3, 4, 5 }, ultolr[] = { 3, 2, 1 }, lrtoul[] = { 7, 6, 5 }, lltour[] = { 7, 0, 1 }; mx = abs(x2 - x1); if (mx > 15) mx = 15; my = abs(y2 - y1); if (my > 15) my = 15; md = Dirs[my][mx]; if (x1 > x2) { if (y1 > y2) md = urtoll[md]; else md = ultolr[md]; } else if (y1 > y2) md = lrtoul[md]; else md = lltour[md]; return md; } int GetDirection16(int x1, int y1, int x2, int y2) { BYTE Dirs[16][16] = { { 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 4, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 4, 3, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, { 4, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, { 4, 4, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // BUGFIX: should be `{ 4, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },` { 4, 4, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 4, 4, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1 }, // BUGFIX: should be `{ 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1 },` { 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1 }, { 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1 }, { 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1 }, { 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1 }, { 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1 }, { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }, { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }, { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2 }, { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2 } }; // The correct quadrant of direction indices is presented below: /* { 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 4, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 4, 3, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, { 4, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, { 4, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 4, 4, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1 }, { 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1 }, { 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1 }, { 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1 }, { 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1 }, { 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1 }, { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }, { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }, { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2 }, { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2 } */ BYTE urtoll[5] = { 6, 7, 8, 9, 10 }; BYTE ultolr[5] = { 6, 5, 4, 3, 2 }; BYTE lltour[5] = { 14, 13, 12, 11, 10 }; BYTE lrtoul[5] = { 14, 15, 0, 1, 2 }; int mx, my, md; mx = abs(x2 - x1); if (mx > 15) mx = 15; my = abs(y2 - y1); if (my > 15) my = 15; md = Dirs[my][mx]; // BUGFIX, md can be 99, leading to an OOB read if (x1 > x2) { if (y1 > y2) md = urtoll[md]; else md = ultolr[md]; } else if (y1 > y2) { md = lltour[md]; } else { md = lrtoul[md]; } return md; } void DeleteMissile(int mi, int i) { #ifndef HELLFIRE int src; if (missile[mi]._mitype == MIS_MANASHIELD) { src = missile[mi]._misource; if (src == myplr) NetSendCmd(TRUE, CMD_REMSHIELD); plr[src].pManaShield = FALSE; } #endif missileavail[MAXMISSILES - nummissiles] = mi; nummissiles--; if (nummissiles > 0 && i != nummissiles) missileactive[i] = missileactive[nummissiles]; } void GetMissileVel(int i, int sx, int sy, int dx, int dy, int v) { double dxp, dyp, dr; #ifndef HELLFIRE if (dx != sx || dy != sy) { #endif dxp = (dx + sy - sx - dy) << 21; dyp = (dy + dx - sx - sy) << 21; dr = sqrt(dxp * dxp + dyp * dyp); missile[i]._mixvel = (dxp * (v << 16)) / dr; missile[i]._miyvel = (dyp * (v << 15)) / dr; #ifndef HELLFIRE } else { missile[i]._mixvel = 0; missile[i]._miyvel = 0; } #endif } void PutMissile(int i) { int x, y; x = missile[i]._mix; y = missile[i]._miy; // BUGFIX: should be `x < 0 || y < 0`, was `x <= 0 || y <= 0`. if (x <= 0 || y <= 0 || x >= MAXDUNX || y >= MAXDUNY) missile[i]._miDelFlag = TRUE; if (!missile[i]._miDelFlag) { dFlags[x][y] |= BFLAG_MISSILE; if (dMissile[x][y] == 0) dMissile[x][y] = i + 1; else dMissile[x][y] = -1; if (missile[i]._miPreFlag) MissilePreFlag = TRUE; } } void GetMissilePos(int i) { int mx, my, dx, dy, lx, ly; mx = missile[i]._mitxoff >> 16; my = missile[i]._mityoff >> 16; dx = mx + 2 * my; dy = 2 * my - mx; if (dx < 0) { lx = -(-dx >> 3); dx = -(-dx >> 6); } else { lx = dx >> 3; dx = dx >> 6; } if (dy < 0) { ly = -(-dy >> 3); dy = -(-dy >> 6); } else { ly = dy >> 3; dy = dy >> 6; } missile[i]._mix = dx + missile[i]._misx; missile[i]._miy = dy + missile[i]._misy; missile[i]._mixoff = mx + (dy << 5) - (dx << 5); missile[i]._miyoff = my - (dx << 4) - (dy << 4); ChangeLightOff(missile[i]._mlid, lx - (dx << 3), ly - (dy << 3)); } void MoveMissilePos(int i) { int dx, dy, x, y; switch (missile[i]._mimfnum) { case DIR_S: dx = 1; dy = 1; break; case DIR_SW: dx = 1; dy = 1; break; case DIR_W: dx = 0; dy = 1; break; case DIR_NW: dx = 0; dy = 0; break; case DIR_N: dx = 0; dy = 0; break; case DIR_NE: dx = 0; dy = 0; break; case DIR_E: dx = 1; dy = 0; break; case DIR_SE: dx = 1; dy = 1; break; } x = missile[i]._mix + dx; y = missile[i]._miy + dy; if (PosOkMonst(missile[i]._misource, x, y)) { missile[i]._mix += dx; missile[i]._miy += dy; missile[i]._mixoff += (dy << 5) - (dx << 5); missile[i]._miyoff -= (dy << 4) + (dx << 4); } } BOOL MonsterTrapHit(int m, int mindam, int maxdam, int dist, int t, BOOLEAN shift) { int hit, hper, dam, mor, mir; BOOL resist, ret; resist = FALSE; if (monster[m].mtalkmsg) { return FALSE; } if (monster[m]._mhitpoints >> 6 <= 0) { return FALSE; } if (monster[m].MType->mtype == MT_ILLWEAV && monster[m]._mgoal == MGOAL_RETREAT) return FALSE; if (monster[m]._mmode == MM_CHARGE) return FALSE; mir = missiledata[t].mResist; mor = monster[m].mMagicRes; if (mor & IMMUNE_MAGIC && mir == MISR_MAGIC || mor & IMMUNE_FIRE && mir == MISR_FIRE || mor & IMMUNE_LIGHTNING && mir == MISR_LIGHTNING) { return FALSE; } if ((mor & RESIST_MAGIC && mir == MISR_MAGIC) || (mor & RESIST_FIRE && mir == MISR_FIRE) || (mor & RESIST_LIGHTNING && mir == MISR_LIGHTNING)) { resist = TRUE; } hit = random_(68, 100); #ifdef HELLFIRE hper = 90 - (char)monster[m].mArmorClass - dist; #else hper = 90 - (BYTE)monster[m].mArmorClass - dist; #endif if (hper < 5) hper = 5; if (hper > 95) hper = 95; if (CheckMonsterHit(m, ret)) { return ret; } #ifdef _DEBUG else if (hit < hper || debug_mode_dollar_sign || debug_mode_key_inverted_v || monster[m]._mmode == MM_STONE) { #else else if (hit < hper || monster[m]._mmode == MM_STONE) { #endif dam = mindam + random_(68, maxdam - mindam + 1); if (!shift) dam <<= 6; if (resist) monster[m]._mhitpoints -= dam >> 2; else monster[m]._mhitpoints -= dam; #ifdef _DEBUG if (debug_mode_dollar_sign || debug_mode_key_inverted_v) monster[m]._mhitpoints = 0; #endif if (monster[m]._mhitpoints >> 6 <= 0) { if (monster[m]._mmode == MM_STONE) { M_StartKill(m, -1); monster[m]._mmode = MM_STONE; } else { M_StartKill(m, -1); } } else { if (resist) { PlayEffect(m, 1); } else if (monster[m]._mmode == MM_STONE) { if (m > MAX_PLRS - 1) M_StartHit(m, -1, dam); monster[m]._mmode = MM_STONE; } else { if (m > MAX_PLRS - 1) M_StartHit(m, -1, dam); } } return TRUE; } else { return FALSE; } } BOOL MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, BOOLEAN shift) { int hit, hper, dam, mor, mir; BOOL resist, ret; resist = FALSE; if (monster[m].mtalkmsg || monster[m]._mhitpoints >> 6 <= 0 || t == MIS_HBOLT && monster[m].MType->mtype != MT_DIABLO && monster[m].MData->mMonstClass != MC_UNDEAD) { return FALSE; } if (monster[m].MType->mtype == MT_ILLWEAV && monster[m]._mgoal == MGOAL_RETREAT) return FALSE; if (monster[m]._mmode == MM_CHARGE) return FALSE; mor = monster[m].mMagicRes; mir = missiledata[t].mResist; if (mor & IMMUNE_MAGIC && mir == MISR_MAGIC || mor & IMMUNE_FIRE && mir == MISR_FIRE || mor & IMMUNE_LIGHTNING && mir == MISR_LIGHTNING || (mor & IMMUNE_ACID) && mir == MISR_ACID) return FALSE; if (mor & RESIST_MAGIC && mir == MISR_MAGIC || mor & RESIST_FIRE && mir == MISR_FIRE || mor & RESIST_LIGHTNING && mir == MISR_LIGHTNING) resist = TRUE; #ifdef HELLFIRE if (t == MIS_HBOLT && (monster[m].MType->mtype == MT_DIABLO || monster[m].MType->mtype == MT_BONEDEMN)) resist = TRUE; #endif hit = random_(69, 100); #ifdef HELLFIRE if (pnum != -1) { #endif if (missiledata[t].mType == 0) { hper = plr[pnum]._pDexterity; hper += plr[pnum]._pIBonusToHit; hper += plr[pnum]._pLevel; hper -= monster[m].mArmorClass; hper -= (dist * dist) >> 1; #ifdef HELLFIRE hper -= plr[pnum]._pIEnAc; // BUGFIX: armor piercing DECREASES hit chance here, probably a 1.04 bug that got fixed in 1.09, go with += #endif #ifndef HELLFIRE hper += plr[pnum]._pIEnAc; #endif hper += 50; if (plr[pnum]._pClass == PC_ROGUE) hper += 20; #ifdef HELLFIRE if (plr[pnum]._pClass == PC_WARRIOR || plr[pnum]._pClass == PC_BARD) hper += 10; #endif #ifndef HELLFIRE if (plr[pnum]._pClass == PC_WARRIOR) hper += 10; #endif } else { hper = plr[pnum]._pMagic - (monster[m].mLevel << 1) - dist + 50; if (plr[pnum]._pClass == PC_SORCERER) hper += 20; #ifdef HELLFIRE else if (plr[pnum]._pClass == PC_BARD) hper += 10; #endif } #ifdef HELLFIRE } else { hper = random_(71, 75) - monster[m].mLevel * 2; } #endif if (hper < 5) hper = 5; if (hper > 95) hper = 95; if (monster[m]._mmode == MM_STONE) hit = 0; if (CheckMonsterHit(m, ret)) return ret; #ifdef _DEBUG if (hit < hper || debug_mode_key_inverted_v || debug_mode_dollar_sign) { #else if (hit < hper) { #endif if (t == MIS_BONESPIRIT) { dam = monster[m]._mhitpoints / 3 >> 6; } else { dam = mindam + random_(70, maxdam - mindam + 1); } if (missiledata[t].mType == 0) { dam = plr[pnum]._pIBonusDamMod + dam * plr[pnum]._pIBonusDam / 100 + dam; if (plr[pnum]._pClass == PC_ROGUE) dam += plr[pnum]._pDamageMod; else dam += (plr[pnum]._pDamageMod >> 1); } if (!shift) dam <<= 6; if (resist) dam >>= 2; if (pnum == myplr) monster[m]._mhitpoints -= dam; #ifdef HELLFIRE if (plr[pnum]._pIFlags & ISPL_NOHEALMON) #else if (plr[pnum]._pIFlags & ISPL_FIRE_ARROWS) #endif monster[m]._mFlags |= MFLAG_NOHEAL; if (monster[m]._mhitpoints >> 6 <= 0) { if (monster[m]._mmode == MM_STONE) { M_StartKill(m, pnum); monster[m]._mmode = MM_STONE; } else { M_StartKill(m, pnum); } } else { if (resist) { PlayEffect(m, 1); } else if (monster[m]._mmode == MM_STONE) { if (m > MAX_PLRS - 1) M_StartHit(m, pnum, dam); monster[m]._mmode = MM_STONE; } else { if (missiledata[t].mType == 0 && plr[pnum]._pIFlags & ISPL_KNOCKBACK) { M_GetKnockback(m); } if (m > MAX_PLRS - 1) M_StartHit(m, pnum, dam); } } if (monster[m]._msquelch == 0) { monster[m]._msquelch = UCHAR_MAX; monster[m]._lastx = plr[pnum]._px; monster[m]._lasty = plr[pnum]._py; } return TRUE; } return FALSE; } BOOL PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, BOOLEAN shift, int earflag #ifdef HELLFIRE , BOOLEAN *blocked #endif ) { int hit, hper, tac, dam, blk, blkper, resper; #ifdef HELLFIRE *blocked = false; #endif if (plr[pnum]._pHitPoints >> 6 <= 0) { return FALSE; } if (plr[pnum]._pInvincible) { return FALSE; } if (plr[pnum]._pSpellFlags & 1 && missiledata[mtype].mType == 0) { return FALSE; } hit = random_(72, 100); #ifdef _DEBUG if (debug_mode_dollar_sign || debug_mode_key_inverted_v) hit = 1000; #endif if (missiledata[mtype].mType == 0) { tac = plr[pnum]._pIAC + plr[pnum]._pIBonusAC + plr[pnum]._pDexterity / 5; if (m != -1) { hper = monster[m].mHit + ((monster[m].mLevel - plr[pnum]._pLevel) << 1) + 30 - (dist << 1) - tac; } else { hper = 100 - (tac >> 1) - (dist << 1); } } else { if (m != -1) { hper = +40 - (plr[pnum]._pLevel << 1) - (dist << 1) + (monster[m].mLevel << 1); } else { hper = 40; } } if (hper < 10) hper = 10; if (currlevel == 14 && hper < 20) { hper = 20; } if (currlevel == 15 && hper < 25) { hper = 25; } if (currlevel == 16 && hper < 30) { hper = 30; } if ((plr[pnum]._pmode == PM_STAND || plr[pnum]._pmode == PM_ATTACK) && plr[pnum]._pBlockFlag) { blk = random_(73, 100); } else { blk = 100; } if (shift == TRUE) blk = 100; if (mtype == MIS_ACIDPUD) blk = 100; if (m != -1) blkper = plr[pnum]._pBaseToBlk + plr[pnum]._pDexterity - ((monster[m].mLevel - plr[pnum]._pLevel) << 1); else blkper = plr[pnum]._pBaseToBlk + plr[pnum]._pDexterity; if (blkper < 0) blkper = 0; if (blkper > 100) blkper = 100; switch (missiledata[mtype].mResist) { case MISR_FIRE: resper = plr[pnum]._pFireResist; break; case MISR_LIGHTNING: resper = plr[pnum]._pLghtResist; break; case MISR_MAGIC: case MISR_ACID: resper = plr[pnum]._pMagResist; break; default: resper = 0; break; } if (hit < hper) { if (mtype == MIS_BONESPIRIT) { dam = plr[pnum]._pHitPoints / 3; } else { if (shift == FALSE) { dam = (mind << 6) + random_(75, (maxd - mind + 1) << 6); #ifndef HELLFIRE if (m == -1) #endif if (plr[pnum]._pIFlags & ISPL_ABSHALFTRAP) dam >>= 1; dam += (plr[pnum]._pIGetHit << 6); } else { dam = mind + random_(75, maxd - mind + 1); #ifndef HELLFIRE if (m == -1) #endif if (plr[pnum]._pIFlags & ISPL_ABSHALFTRAP) dam >>= 1; dam += plr[pnum]._pIGetHit; } if (dam < 64) dam = 64; } #ifdef HELLFIRE if (blk < blkper) { if (m != -1) { tac = GetDirection(plr[pnum]._px, plr[pnum]._py, monster[m]._mx, monster[m]._my); } else { tac = plr[pnum]._pdir; } *blocked = true; StartPlrBlock(pnum, tac); return TRUE; } #endif if (resper > 0) { dam = dam - dam * resper / 100; if (pnum == myplr) { plr[pnum]._pHitPoints -= dam; plr[pnum]._pHPBase -= dam; } if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) { plr[pnum]._pHitPoints = plr[pnum]._pMaxHP; plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase; } if (plr[pnum]._pHitPoints >> 6 <= 0) { SyncPlrKill(pnum, earflag); } else { if (plr[pnum]._pClass == PC_WARRIOR) { PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py); #ifndef SPAWN } else if (plr[pnum]._pClass == PC_ROGUE) { PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py); } else if (plr[pnum]._pClass == PC_SORCERER) { PlaySfxLoc(PS_MAGE69, plr[pnum]._px, plr[pnum]._py); #endif #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK) { PlaySfxLoc(PS_MONK69, plr[pnum]._px, plr[pnum]._py); } else if (plr[pnum]._pClass == PC_BARD) { PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py); } else if (plr[pnum]._pClass == PC_BARBARIAN) { PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py); #endif } drawhpflag = TRUE; } return TRUE; } else { #ifndef HELLFIRE if (blk < blkper) { if (m != -1) { tac = GetDirection(plr[pnum]._px, plr[pnum]._py, monster[m]._mx, monster[m]._my); } else { tac = plr[pnum]._pdir; } StartPlrBlock(pnum, tac); } else #endif { if (pnum == myplr) { plr[pnum]._pHitPoints -= dam; plr[pnum]._pHPBase -= dam; } if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) { plr[pnum]._pHitPoints = plr[pnum]._pMaxHP; plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase; } if (plr[pnum]._pHitPoints >> 6 <= 0) { SyncPlrKill(pnum, earflag); } else { StartPlrHit(pnum, dam, FALSE); } } return TRUE; } } return FALSE; } BOOL Plr2PlrMHit(int pnum, int p, int mindam, int maxdam, int dist, int mtype, BOOLEAN shift #ifdef HELLFIRE , BOOLEAN *blocked #endif ) { int dam, blk, blkper, hper, hit, resper; #ifdef HELLFIRE *blocked = false; #endif if (plr[p]._pInvincible) { return FALSE; } if (mtype == MIS_HBOLT) { return FALSE; } if (plr[p]._pSpellFlags & 1 && missiledata[mtype].mType == 0) { return FALSE; } switch (missiledata[mtype].mResist) { case MISR_FIRE: resper = plr[p]._pFireResist; break; case MISR_LIGHTNING: resper = plr[p]._pLghtResist; break; case MISR_MAGIC: case MISR_ACID: resper = plr[p]._pMagResist; break; default: resper = 0; break; } hper = random_(69, 100); if (missiledata[mtype].mType == 0) { hit = plr[pnum]._pIBonusToHit + plr[pnum]._pLevel - (dist * dist >> 1) - plr[p]._pDexterity / 5 - plr[p]._pIBonusAC - plr[p]._pIAC + plr[pnum]._pDexterity + 50; if (plr[pnum]._pClass == PC_ROGUE) hit += 20; #ifdef HELLFIRE if (plr[pnum]._pClass == PC_WARRIOR || plr[pnum]._pClass == PC_BARD) #else if (plr[pnum]._pClass == PC_WARRIOR) #endif hit += 10; } else { hit = plr[pnum]._pMagic - (plr[p]._pLevel << 1) - dist + 50; if (plr[pnum]._pClass == PC_SORCERER) hit += 20; #ifdef HELLFIRE else if (plr[pnum]._pClass == PC_BARD) hit += 10; #endif } if (hit < 5) hit = 5; if (hit > 95) hit = 95; if (hper < hit) { if ((plr[p]._pmode == PM_STAND || plr[p]._pmode == PM_ATTACK) && plr[p]._pBlockFlag) { blkper = random_(73, 100); } else { blkper = 100; } if (shift == TRUE) blkper = 100; blk = plr[p]._pDexterity + plr[p]._pBaseToBlk + (plr[p]._pLevel << 1) - (plr[pnum]._pLevel << 1); if (blk < 0) { blk = 0; } if (blk > 100) { blk = 100; } if (mtype == MIS_BONESPIRIT) { dam = plr[p]._pHitPoints / 3; } else { dam = mindam + random_(70, maxdam - mindam + 1); if (missiledata[mtype].mType == 0) dam += plr[pnum]._pIBonusDamMod + plr[pnum]._pDamageMod + dam * plr[pnum]._pIBonusDam / 100; if (!shift) dam <<= 6; } if (missiledata[mtype].mType != 0) dam >>= 1; if (resper > 0) { dam -= (dam * resper) / 100; if (pnum == myplr) NetSendCmdDamage(TRUE, p, dam); if (plr[pnum]._pClass == PC_WARRIOR) {// BUGFIX: should use p instead of pnum PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum #ifndef SPAWN } else if (plr[pnum]._pClass == PC_ROGUE) {// BUGFIX: should use p instead of pnum PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum } else if (plr[pnum]._pClass == PC_SORCERER) {// BUGFIX: should use p instead of pnum PlaySfxLoc(PS_MAGE69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum #endif #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK) {// BUGFIX: should use p instead of pnum PlaySfxLoc(PS_MONK69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum } else if (plr[pnum]._pClass == PC_BARD) {// BUGFIX: should use p instead of pnum PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum } else if (plr[pnum]._pClass == PC_BARBARIAN) {// BUGFIX: should use p instead of pnum PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum #endif } return TRUE; } else { if (blkper < blk) { StartPlrBlock(p, GetDirection(plr[p]._px, plr[p]._py, plr[pnum]._px, plr[pnum]._py)); #ifdef HELLFIRE *blocked = true; #endif } else { if (pnum == myplr) NetSendCmdDamage(TRUE, p, dam); StartPlrHit(p, dam, FALSE); } return TRUE; } } return FALSE; } void CheckMissileCol(int i, int mindam, int maxdam, BOOL shift, int mx, int my, BOOLEAN nodel) { int oi; #ifdef HELLFIRE int dir, mAnimFAmt; BOOLEAN blocked; if (i >= MAXMISSILES || i < 0) return; if (mx >= MAXDUNX || mx < 0) return; if (my >= MAXDUNY || my < 0) return; if (missile[i]._micaster != TARGET_BOTH && missile[i]._misource != -1) { #else if (missile[i]._miAnimType != MFILE_FIREWAL && missile[i]._misource != -1) { #endif if (missile[i]._micaster == TARGET_MONSTERS) { if (dMonster[mx][my] > 0) { if (MonsterMHit( missile[i]._misource, dMonster[mx][my] - 1, mindam, maxdam, missile[i]._midist, missile[i]._mitype, shift)) { if (!nodel) missile[i]._mirange = 0; missile[i]._miHitFlag = TRUE; } } else { if (dMonster[mx][my] < 0 && monster[-(dMonster[mx][my] + 1)]._mmode == MM_STONE && MonsterMHit( missile[i]._misource, -(dMonster[mx][my] + 1), mindam, maxdam, missile[i]._midist, missile[i]._mitype, shift)) { if (!nodel) missile[i]._mirange = 0; missile[i]._miHitFlag = TRUE; } } if (dPlayer[mx][my] > 0 && dPlayer[mx][my] - 1 != missile[i]._misource && Plr2PlrMHit( missile[i]._misource, dPlayer[mx][my] - 1, mindam, maxdam, missile[i]._midist, missile[i]._mitype, shift #ifdef HELLFIRE , &blocked #endif )) { #ifdef HELLFIRE if (blocked) { dir = missile[i]._mimfnum + (random_(10, 2) ? 1 : -1); mAnimFAmt = misfiledata[missile[i]._miAnimType].mAnimFAmt; if (dir < 0) dir = mAnimFAmt - 1; else if (dir > mAnimFAmt) dir = 0; SetMissDir(i, dir); } else #endif { if (!nodel) missile[i]._mirange = 0; } missile[i]._miHitFlag = TRUE; } } else { if (monster[missile[i]._misource]._mFlags & MFLAG_TARGETS_MONSTER && dMonster[mx][my] > 0 && monster[dMonster[mx][my] - 1]._mFlags & MFLAG_GOLEM && MonsterTrapHit(dMonster[mx][my] - 1, mindam, maxdam, missile[i]._midist, missile[i]._mitype, shift)) { if (!nodel) missile[i]._mirange = 0; missile[i]._miHitFlag = TRUE; } if (dPlayer[mx][my] > 0 && PlayerMHit( dPlayer[mx][my] - 1, missile[i]._misource, missile[i]._midist, mindam, maxdam, missile[i]._mitype, shift, 0 #ifdef HELLFIRE , &blocked #endif )) { #ifdef HELLFIRE if (blocked) { dir = missile[i]._mimfnum + (random_(10, 2) ? 1 : -1); mAnimFAmt = misfiledata[missile[i]._miAnimType].mAnimFAmt; if (dir < 0) dir = mAnimFAmt - 1; else if (dir > mAnimFAmt) dir = 0; SetMissDir(i, dir); } else #endif { if (!nodel) missile[i]._mirange = 0; } missile[i]._miHitFlag = TRUE; } } } else { if (dMonster[mx][my] > 0) { #ifdef HELLFIRE if (missile[i]._micaster == TARGET_BOTH) { #else if (missile[i]._miAnimType == MFILE_FIREWAL) { #endif if (MonsterMHit( missile[i]._misource, dMonster[mx][my] - 1, mindam, maxdam, missile[i]._midist, missile[i]._mitype, shift)) { if (!nodel) missile[i]._mirange = 0; missile[i]._miHitFlag = TRUE; } } else if (MonsterTrapHit(dMonster[mx][my] - 1, mindam, maxdam, missile[i]._midist, missile[i]._mitype, shift)) { if (!nodel) missile[i]._mirange = 0; missile[i]._miHitFlag = TRUE; } } if (dPlayer[mx][my] > 0 && PlayerMHit(dPlayer[mx][my] - 1, -1, missile[i]._midist, mindam, maxdam, missile[i]._mitype, shift, missile[i]._miAnimType == MFILE_FIREWAL #ifdef HELLFIRE || missile[i]._miAnimType == MFILE_LGHNING, &blocked #endif )) { #ifdef HELLFIRE if (blocked) { dir = missile[i]._mimfnum + (random_(10, 2) ? 1 : -1); mAnimFAmt = misfiledata[missile[i]._miAnimType].mAnimFAmt; if (dir < 0) dir = mAnimFAmt - 1; else if (dir > mAnimFAmt) dir = 0; SetMissDir(i, dir); } else #endif { if (!nodel) missile[i]._mirange = 0; } missile[i]._miHitFlag = TRUE; } } if (dObject[mx][my] != 0) { oi = dObject[mx][my] > 0 ? dObject[mx][my] - 1 : -(dObject[mx][my] + 1); if (!object[oi]._oMissFlag) { if (object[oi]._oBreak == 1) BreakObject(-1, oi); if (!nodel) missile[i]._mirange = 0; missile[i]._miHitFlag = FALSE; } } if (nMissileTable[dPiece[mx][my]]) { if (!nodel) missile[i]._mirange = 0; missile[i]._miHitFlag = FALSE; } if (missile[i]._mirange == 0 && missiledata[missile[i]._mitype].miSFX != -1) PlaySfxLoc(missiledata[missile[i]._mitype].miSFX, missile[i]._mix, missile[i]._miy); } void SetMissAnim(int mi, int animtype) { int dir = missile[mi]._mimfnum; missile[mi]._miAnimType = animtype; missile[mi]._miAnimFlags = misfiledata[animtype].mFlags; // BUGFIX: buffer overflow for MFILE_NONE (255). missile[mi]._miAnimData = misfiledata[animtype].mAnimData[dir]; // BUGFIX: buffer overflow for MFILE_NONE (255). missile[mi]._miAnimDelay = misfiledata[animtype].mAnimDelay[dir]; // BUGFIX: buffer overflow for MFILE_NONE (255). missile[mi]._miAnimLen = misfiledata[animtype].mAnimLen[dir]; // BUGFIX: buffer overflow for MFILE_NONE (255). missile[mi]._miAnimWidth = misfiledata[animtype].mAnimWidth[dir]; // BUGFIX: buffer overflow for MFILE_NONE (255). missile[mi]._miAnimWidth2 = misfiledata[animtype].mAnimWidth2[dir]; // BUGFIX: buffer overflow for MFILE_NONE (255). missile[mi]._miAnimCnt = 0; missile[mi]._miAnimFrame = 1; } void SetMissDir(int mi, int dir) { missile[mi]._mimfnum = dir; SetMissAnim(mi, missile[mi]._miAnimType); } void LoadMissileGFX(BYTE mi) { char pszName[256]; int i; BYTE *file; MisFileData *mfd; mfd = &misfiledata[mi]; if (mfd->mFlags & MFLAG_ALLOW_SPECIAL) { sprintf(pszName, "Missiles\\%s.CL2", mfd->mName); file = LoadFileInMem(pszName, NULL); for (i = 0; i < mfd->mAnimFAmt; i++) mfd->mAnimData[i] = &file[((int *)file)[i]]; } else if (mfd->mAnimFAmt == 1) { sprintf(pszName, "Missiles\\%s.CL2", mfd->mName); if (!mfd->mAnimData[0]) mfd->mAnimData[0] = LoadFileInMem(pszName, NULL); } else { for (i = 0; i < mfd->mAnimFAmt; i++) { sprintf(pszName, "Missiles\\%s%i.CL2", mfd->mName, i + 1); if (!mfd->mAnimData[i]) { file = LoadFileInMem(pszName, NULL); mfd->mAnimData[i] = file; } } } } void InitMissileGFX() { int mi; for (mi = 0; misfiledata[mi].mAnimFAmt; mi++) { if (!(misfiledata[mi].mFlags & MFLAG_HIDDEN)) LoadMissileGFX(mi); } } void FreeMissileGFX(int mi) { int i; DWORD *p; if (misfiledata[mi].mFlags & MFLAG_ALLOW_SPECIAL) { if (misfiledata[mi].mAnimData[0]) { p = (DWORD *)misfiledata[mi].mAnimData[0]; p -= misfiledata[mi].mAnimFAmt; MemFreeDbg(p); misfiledata[mi].mAnimData[0] = NULL; } return; } for (i = 0; i < misfiledata[mi].mAnimFAmt; i++) { if (misfiledata[mi].mAnimData[i]) { MemFreeDbg(misfiledata[mi].mAnimData[i]); } } } void FreeMissiles() { int mi; for (mi = 0; misfiledata[mi].mAnimFAmt; mi++) { if (!(misfiledata[mi].mFlags & MFLAG_HIDDEN)) FreeMissileGFX(mi); } } void FreeMissiles2() { int mi; for (mi = 0; misfiledata[mi].mAnimFAmt; mi++) { if (misfiledata[mi].mFlags & MFLAG_HIDDEN) FreeMissileGFX(mi); } } void InitMissiles() { int mi, src, i, j; #ifdef HELLFIRE AutoMapShowItems = FALSE; #endif plr[myplr]._pSpellFlags &= ~0x1; if (plr[myplr]._pInfraFlag == TRUE) { for (i = 0; i < nummissiles; ++i) { mi = missileactive[i]; if (missile[mi]._mitype == MIS_INFRA) { src = missile[mi]._misource; if (src == myplr) CalcPlrItemVals(src, TRUE); } } } #ifdef HELLFIRE if ((plr[myplr]._pSpellFlags & 2) == 2 || (plr[myplr]._pSpellFlags & 4) == 4) { plr[myplr]._pSpellFlags &= ~0x2; plr[myplr]._pSpellFlags &= ~0x4; for (i = 0; i < nummissiles; ++i) { mi = missileactive[i]; if (missile[mi]._mitype == MIS_BLODBOIL) { if (missile[mi]._misource == myplr) { int missingHP = plr[myplr]._pMaxHP - plr[myplr]._pHitPoints; CalcPlrItemVals(myplr, TRUE); plr[myplr]._pHitPoints -= missingHP + missile[mi]._miVar2; if (plr[myplr]._pHitPoints < 64) { plr[myplr]._pHitPoints = 64; } } } } } #endif nummissiles = 0; for (i = 0; i < MAXMISSILES; i++) { missileavail[i] = i; missileactive[i] = 0; } numchains = 0; for (i = 0; i < MAXMISSILES; i++) { chain[i].idx = -1; chain[i]._mitype = 0; chain[i]._mirange = 0; } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { dFlags[i][j] &= ~BFLAG_MISSILE; } } #ifdef HELLFIRE plr[myplr].wReflections = 0; #endif } #ifdef HELLFIRE void missiles_hive_explosion(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { AddMissile(80, 62, 80, 62, midir, MIS_HIVEEXP, mienemy, id, dam, 0); AddMissile(80, 63, 80, 62, midir, MIS_HIVEEXP, mienemy, id, dam, 0); AddMissile(81, 62, 80, 62, midir, MIS_HIVEEXP, mienemy, id, dam, 0); AddMissile(81, 63, 80, 62, midir, MIS_HIVEEXP, mienemy, id, dam, 0); missile[mi]._miDelFlag = TRUE; } static BOOLEAN missiles_found_target(int mi, int *x, int *y, int rad) { BOOLEAN found; int i, j, k, tx, ty, dp; found = FALSE; if (rad > 19) rad = 19; for (j = 0; j < rad; j++) { if (found) { break; } k = CrawlNum[j] + 2; for (i = CrawlTable[CrawlNum[j]]; i > 0; i--, k += 2) { tx = *x + CrawlTable[k - 1]; ty = *y + CrawlTable[k]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { dp = dPiece[tx][ty]; if (!nSolidTable[dp] && dObject[tx][ty] == 0 && dMissile[tx][ty] == 0) { missile[mi]._mix = tx; missile[mi]._miy = ty; *x = tx; *y = ty; found = TRUE; break; } } } } return found; } void missiles_fire_rune(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (LineClear(sx, sy, dx, dy)) { if (id >= 0) UseMana(id, SPL_RUNEFIRE); if (missiles_found_target(mi, &dx, &dy, 10)) { missile[mi]._miVar1 = MIS_HIVEEXP; missile[mi]._miDelFlag = FALSE; missile[mi]._mlid = AddLight(dx, dy, 8); } else { missile[mi]._miDelFlag = TRUE; } } else { missile[mi]._miDelFlag = TRUE; } } void missiles_light_rune(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (LineClear(sx, sy, dx, dy)) { if (id >= 0) UseMana(id, SPL_RUNELIGHT); if (missiles_found_target(mi, &dx, &dy, 10)) { missile[mi]._miVar1 = MIS_LIGHTBALL; missile[mi]._miDelFlag = FALSE; missile[mi]._mlid = AddLight(dx, dy, 8); } else { missile[mi]._miDelFlag = TRUE; } } else { missile[mi]._miDelFlag = TRUE; } } void missiles_great_light_rune(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (LineClear(sx, sy, dx, dy)) { if (id >= 0) UseMana(id, SPL_RUNENOVA); if (missiles_found_target(mi, &dx, &dy, 10)) { missile[mi]._miVar1 = MIS_NOVA; missile[mi]._miDelFlag = FALSE; missile[mi]._mlid = AddLight(dx, dy, 8); } else { missile[mi]._miDelFlag = TRUE; } } else { missile[mi]._miDelFlag = TRUE; } } void missiles_immolation_rune(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (LineClear(sx, sy, dx, dy)) { if (id >= 0) UseMana(id, SPL_RUNEIMMOLAT); if (missiles_found_target(mi, &dx, &dy, 10)) { missile[mi]._miVar1 = MIS_IMMOLATION; missile[mi]._miDelFlag = FALSE; missile[mi]._mlid = AddLight(dx, dy, 8); } else { missile[mi]._miDelFlag = TRUE; } } else { missile[mi]._miDelFlag = TRUE; } } void missiles_stone_rune(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (LineClear(sx, sy, dx, dy)) { if (id >= 0) UseMana(id, SPL_RUNESTONE); if (missiles_found_target(mi, &dx, &dy, 10)) { missile[mi]._miVar1 = MIS_STONE; missile[mi]._miDelFlag = FALSE; missile[mi]._mlid = AddLight(dx, dy, 8); } else { missile[mi]._miDelFlag = TRUE; } } else { missile[mi]._miDelFlag = TRUE; } } void missiles_reflection(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int lvl; if (id >= 0) { if (missile[mi]._mispllvl) lvl = missile[mi]._mispllvl; else lvl = 2; plr[id].wReflections += lvl * plr[id]._pLevel; UseMana(id, SPL_REFLECT); } missile[mi]._mirange = 0; missile[mi]._miDelFlag = 0; } void missiles_berserk(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i, j, k, tx, ty, dm, r; if (id >= 0) { missile[mi]._misource = id; for (j = 0; j < 6; j++) { k = CrawlNum[j] + 2; for (i = CrawlTable[CrawlNum[j]]; i > 0; i--, k += 2) { tx = dx + CrawlTable[k - 1]; ty = dy + CrawlTable[k]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { dm = dMonster[tx][ty]; dm = dm > 0 ? dm - 1 : -(dm + 1); if (dm > 3) { if (!monster[dm]._uniqtype && monster[dm]._mAi != AI_DIABLO) { if (monster[dm]._mmode != MM_FADEIN && monster[dm]._mmode != MM_FADEOUT) { if (!(monster[dm].mMagicRes & IMMUNE_MAGIC)) { if ((!(monster[dm].mMagicRes & RESIST_MAGIC) || (monster[dm].mMagicRes & RESIST_MAGIC) == 1 && !random_(99, 2)) && monster[dm]._mmode != MM_CHARGE) { j = 6; double slvl = (double)GetSpellLevel(id, SPL_BERSERK); monster[dm]._mFlags |= MFLAG_BERSERK | MFLAG_GOLEM; monster[dm].mMinDamage = ((double)(random_(145, 10) + 20) / 100 - -1) * (double)monster[dm].mMinDamage + slvl; monster[dm].mMaxDamage = ((double)(random_(145, 10) + 20) / 100 - -1) * (double)monster[dm].mMaxDamage + slvl; monster[dm].mMinDamage2 = ((double)(random_(145, 10) + 20) / 100 - -1) * (double)monster[dm].mMinDamage2 + slvl; monster[dm].mMaxDamage2 = ((double)(random_(145, 10) + 20) / 100 - -1) * (double)monster[dm].mMaxDamage2 + slvl; if (currlevel < 17 || currlevel > 20) r = 3; else r = 9; monster[dm].mlid = AddLight(monster[dm]._mx, monster[dm]._my, r); UseMana(id, SPL_BERSERK); break; } } } } } } } } } missile[mi]._mirange = 0; missile[mi]._miDelFlag = TRUE; } void missiles_hork_spawn(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { GetMissileVel(mi, sx, sy, dx, dy, 8); missile[mi]._mirange = 9; missile[mi]._miVar1 = midir; PutMissile(mi); } void missiles_jester(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int spell; spell = MIS_FIREBOLT; switch (random_(255, 10)) { case 0: case 1: spell = MIS_FIREBOLT; break; case 2: spell = MIS_FIREBALL; break; case 3: spell = MIS_FIREWALLC; break; case 4: spell = MIS_GUARDIAN; break; case 5: spell = MIS_CHAIN; break; case 6: spell = MIS_TOWN; UseMana(id, SPL_TOWN); break; case 7: spell = MIS_TELEPORT; break; case 8: spell = MIS_APOCA; break; case 9: spell = MIS_STONE; break; } AddMissile(sx, sy, dx, dy, midir, spell, missile[mi]._micaster, missile[mi]._misource, 0, missile[mi]._mispllvl); missile[mi]._miDelFlag = TRUE; missile[mi]._mirange = 0; } void missiles_steal_pots(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i, l, k, j, tx, ty, si, ii, pnum; BOOL hasPlayedSFX; missile[mi]._misource = id; for (i = 0; i < 3; i++) { k = CrawlNum[i]; l = k + 2; for (j = CrawlTable[k]; j > 0; j--, l += 2) { tx = sx + CrawlTable[l - 1]; ty = sy + CrawlTable[l]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { pnum = dPlayer[tx][ty]; if (pnum) { pnum = pnum > 0 ? pnum - 1 : -(pnum + 1); hasPlayedSFX = FALSE; for (si = 0; si < MAXBELTITEMS; si++) { ii = -1; if (plr[pnum].SpdList[si]._itype == ITYPE_MISC) { if (random_(205, 2) == 0) continue; switch (plr[pnum].SpdList[si]._iMiscId) { case IMISC_FULLHEAL: ii = ItemMiscIdIdx(IMISC_HEAL); break; case IMISC_HEAL: case IMISC_MANA: RemoveSpdBarItem(pnum, si); continue; case IMISC_FULLMANA: ii = ItemMiscIdIdx(IMISC_MANA); break; case IMISC_REJUV: if (random_(205, 2) != 0) { ii = ItemMiscIdIdx(IMISC_MANA); } else { ii = ItemMiscIdIdx(IMISC_HEAL); } ii = ItemMiscIdIdx(IMISC_HEAL); break; case IMISC_FULLREJUV: switch (random_(205, 3)) { case 0: ii = ItemMiscIdIdx(IMISC_FULLMANA); break; case 1: ii = ItemMiscIdIdx(IMISC_FULLHEAL); break; default: ii = ItemMiscIdIdx(IMISC_REJUV); break; } break; default: continue; } } if (ii != -1) { SetPlrHandItem(&plr[pnum].HoldItem, ii); GetPlrHandSeed(&plr[pnum].HoldItem); plr[pnum].HoldItem._iStatFlag = TRUE; plr[pnum].SpdList[si] = plr[pnum].HoldItem; } if (!hasPlayedSFX) { PlaySfxLoc(IS_POPPOP2, tx, ty); hasPlayedSFX = TRUE; } } force_redraw = 255; } } } } missile[mi]._mirange = 0; missile[mi]._miDelFlag = TRUE; } void missiles_mana_trap(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i, pn, k, j, tx, ty, pid; missile[mi]._misource = id; for (i = 0; i < 3; i++) { k = CrawlNum[i]; pn = k + 2; for (j = CrawlTable[k]; j > 0; j--) { tx = sx + CrawlTable[pn - 1]; ty = sy + CrawlTable[pn]; if (0 < tx && tx < MAXDUNX && 0 < ty && ty < MAXDUNY) { pid = dPlayer[tx][ty]; if (pid != 0) { if (pid > 0) pid = pid - 1; else pid = -(pid + 1); plr[pid]._pMana = 0; plr[pid]._pManaBase = plr[pid]._pMana + plr[pid]._pMaxManaBase - plr[pid]._pMaxMana; CalcPlrInv(pid, FALSE); drawmanaflag = TRUE; PlaySfxLoc(TSFX_COW7, tx, ty); } } pn += 2; } } missile[mi]._mirange = 0; missile[mi]._miDelFlag = TRUE; } void missiles_spec_arrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int av; av = 0; if (mienemy == TARGET_MONSTERS) { if (plr[id]._pClass == PC_ROGUE) av += (plr[id]._pLevel - 1) >> 2; else if (plr[id]._pClass == PC_WARRIOR || plr[id]._pClass == PC_BARD) av += (plr[id]._pLevel - 1) >> 3; if (plr[id]._pIFlags & ISPL_QUICKATTACK) av++; if (plr[id]._pIFlags & ISPL_FASTATTACK) av += 2; if (plr[id]._pIFlags & ISPL_FASTERATTACK) av += 4; if (plr[id]._pIFlags & ISPL_FASTESTATTACK) av += 8; } missile[mi]._mirange = 1; missile[mi]._miVar1 = dx; missile[mi]._miVar2 = dy; missile[mi]._miVar3 = av; } void missiles_warp(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int tx, ty, fx, fy, i, dist; TriggerStruct *trg; dist = INT_MAX; if (id >= 0) { sx = plr[id]._px; sy = plr[id]._py; } tx = sx; ty = sy; for (i = 0; i < numtrigs && i < MAXTRIGGERS; i++) { trg = &trigs[i]; if (trg->_tmsg == WM_DIABTWARPUP || trg->_tmsg == WM_DIABPREVLVL || trg->_tmsg == WM_DIABNEXTLVL || trg->_tmsg == WM_DIABRTNLVL) { if ((leveltype == DTYPE_CATHEDRAL || leveltype == DTYPE_CATACOMBS) && (trg->_tmsg == WM_DIABNEXTLVL || trg->_tmsg == WM_DIABPREVLVL || trg->_tmsg == WM_DIABRTNLVL)) { fx = trg->_tx; fy = trg->_ty + 1; } else { fx = trg->_tx + 1; fy = trg->_ty; } int dify = (sy - fy); int difx = (sx - fx); int dif = dify * dify + difx * difx; if (dif < dist) { dist = dif; tx = fx; ty = fy; } } } missile[mi]._mirange = 2; missile[mi]._miVar1 = 0; missile[mi]._mix = tx; missile[mi]._miy = ty; if (mienemy == TARGET_MONSTERS) UseMana(id, SPL_WARP); } void missiles_light_wall(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { GetMissileVel(mi, sx, sy, dx, dy, 16); missile[mi]._midam = dam; missile[mi]._miAnimFrame = random_(63, 8) + 1; missile[mi]._mirange = 255 * (missile[mi]._mispllvl + 1); if (id < 0) { missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; } else { missile[mi]._miVar1 = plr[id]._px; missile[mi]._miVar2 = plr[id]._py; } } void missiles_rune_explosion(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i, dmg; if (mienemy == TARGET_MONSTERS || mienemy == TARGET_BOTH) { missile[mi]._midam = 2 * (plr[id]._pLevel + random_(60, 10) + random_(60, 10)) + 4; for (i = missile[mi]._mispllvl; i > 0; i--) { missile[mi]._midam += missile[mi]._midam >> 3; } dmg = missile[mi]._midam; CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix - 1, missile[mi]._miy - 1, 1); CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix, missile[mi]._miy - 1, 1); CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix + 1, missile[mi]._miy - 1, 1); CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix - 1, missile[mi]._miy, 1); CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix, missile[mi]._miy, 1); CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix + 1, missile[mi]._miy, 1); CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix - 1, missile[mi]._miy + 1, 1); CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix, missile[mi]._miy + 1, 1); CheckMissileCol(mi, dmg, dmg, 0, missile[mi]._mix + 1, missile[mi]._miy + 1, 1); } missile[mi]._mlid = AddLight(sx, sy, 8); SetMissDir(mi, 0); missile[mi]._miDelFlag = 0; missile[mi]._mirange = missile[mi]._miAnimLen - 1; } void missiles_immo_1(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } if (mienemy == TARGET_MONSTERS) { missile[mi]._midam = 2 * (plr[id]._pLevel + random_(60, 10) + random_(60, 10)) + 4; for (i = missile[mi]._mispllvl; i > 0; i--) { missile[mi]._midam += missile[mi]._midam >> 3; } i = 2 * missile[mi]._mispllvl + 16; if (i > 50) i = 50; UseMana(id, SPL_FIREBALL); } else { i = 16; } GetMissileVel(mi, sx, sy, dx, dy, i); SetMissDir(mi, GetDirection16(sx, sy, dx, dy)); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._miVar3 = 0; missile[mi]._miVar4 = sx; missile[mi]._miVar5 = sy; missile[mi]._miVar6 = 2; missile[mi]._miVar7 = 2; missile[mi]._mlid = AddLight(sx, sy, 8); } void missiles_immo_2(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } if (mienemy == TARGET_MONSTERS) { i = missile[mi]._mispllvl + 16; if (i > 50) { i = 50; } } else { i = 16; } GetMissileVel(mi, sx, sy, dx, dy, i); SetMissDir(mi, GetDirection16(sx, sy, dx, dy)); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._miVar3 = 0; missile[mi]._miVar4 = sx; missile[mi]._miVar5 = sy; missile[mi]._mlid = AddLight(sx, sy, 8); } void missiles_larrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } GetMissileVel(mi, sx, sy, dx, dy, 32); missile[mi]._miAnimFrame = random_(52, 8) + 1; missile[mi]._mirange = 255; if (id < 0) { missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; } else { missile[mi]._miVar1 = plr[id]._px; missile[mi]._miVar2 = plr[id]._py; } missile[mi]._midam <<= 6; } void missiles_43303D(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { } void missiles_433040(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int lvl; if (mienemy == TARGET_MONSTERS && id != -1) { missile[mi]._midam = 0; if (2 * (id > 0)) // BUGFIX, wrong order of operation, this should be `2 * lvl` after the else. lvl = plr[id]._pLevel; else lvl = 1; missile[mi]._mirange = lvl + 10 * missile[mi]._mispllvl + 245; } } void missiles_rech_mana(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i, ManaAmount; ManaAmount = (random_(57, 10) + 1) << 6; for (i = 0; i < plr[id]._pLevel; i++) { ManaAmount += (random_(57, 4) + 1) << 6; } for (i = 0; i < missile[mi]._mispllvl; i++) { ManaAmount += (random_(57, 6) + 1) << 6; } if (plr[id]._pClass == PC_SORCERER) ManaAmount <<= 1; if (plr[id]._pClass == PC_ROGUE || plr[id]._pClass == PC_BARD) ManaAmount += ManaAmount >> 1; plr[id]._pMana += ManaAmount; if (plr[id]._pMana > plr[id]._pMaxMana) plr[id]._pMana = plr[id]._pMaxMana; plr[id]._pManaBase += ManaAmount; if (plr[id]._pManaBase > plr[id]._pMaxManaBase) plr[id]._pManaBase = plr[id]._pMaxManaBase; UseMana(id, SPL_MANA); missile[mi]._miDelFlag = TRUE; drawmanaflag = TRUE; } void missiles_magi(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { plr[id]._pMana = plr[id]._pMaxMana; plr[id]._pManaBase = plr[id]._pMaxManaBase; UseMana(id, SPL_MAGI); missile[mi]._miDelFlag = TRUE; drawmanaflag = TRUE; } void missiles_ring(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._miDelFlag = TRUE; if (mienemy == TARGET_MONSTERS) UseMana(id, SPL_FIRERING); missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._miDelFlag = FALSE; missile[mi]._miVar3 = 0; missile[mi]._miVar4 = 0; missile[mi]._miVar5 = 0; missile[mi]._miVar6 = 0; missile[mi]._miVar7 = 0; missile[mi]._miVar8 = 0; missile[mi]._mirange = 7; } void missiles_search(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int lvl, i, mx, r1, r2; MissileStruct *mis; missile[mi]._miDelFlag = FALSE; missile[mi]._miVar1 = id; missile[mi]._miVar2 = 0; missile[mi]._miVar3 = 0; missile[mi]._miVar4 = 0; missile[mi]._miVar5 = 0; missile[mi]._miVar6 = 0; missile[mi]._miVar7 = 0; missile[mi]._miVar8 = 0; AutoMapShowItems = TRUE; if (2 * (id > 0)) // BUGFIX, wrong order of operation, this should be `2 * lvl` after the else. lvl = plr[id]._pLevel; else lvl = 1; missile[mi]._mirange = lvl + 10 * missile[mi]._mispllvl + 245; if (mienemy == TARGET_MONSTERS) UseMana(id, SPL_SEARCH); for (i = 0; i < nummissiles; i++) { mx = missileactive[i]; if (mx != mi) { mis = &missile[mx]; if (mis->_miVar1 == id && mis->_mitype == 85) { r1 = missile[mi]._mirange; r2 = mis->_mirange; if (r2 < INT_MAX - r1) mis->_mirange = r1 + r2; missile[mi]._miDelFlag = TRUE; break; } } } } void missiles_cbolt_arrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (mienemy == TARGET_MONSTERS) { if (id == myplr) { missile[mi]._mirnd = random_(63, 15) + 1; } else { missile[mi]._mirnd = random_(63, 15) + 1; } } else { missile[mi]._mirnd = random_(63, 15) + 1; missile[mi]._midam = 15; } if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } missile[mi]._miAnimFrame = random_(63, 8) + 1; missile[mi]._mlid = AddLight(sx, sy, 5); GetMissileVel(mi, sx, sy, dx, dy, 8); missile[mi]._miVar1 = 5; missile[mi]._miVar2 = midir; missile[mi]._miVar3 = 0; missile[mi]._mirange = 256; } void missiles_hbolt_arrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } if (id != -1) { i = 2 * missile[mi]._mispllvl + 16; if (i >= 63) { i = 63; } } else { i = 16; } GetMissileVel(mi, sx, sy, dx, dy, i); SetMissDir(mi, GetDirection16(sx, sy, dx, dy)); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._mlid = AddLight(sx, sy, 8); } #endif void AddLArrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } if (mienemy == TARGET_MONSTERS) { #ifdef HELLFIRE int av = 32; if (plr[id]._pClass == PC_ROGUE) av += (plr[id]._pLevel) >> 2; else if (plr[id]._pClass == PC_WARRIOR || plr[id]._pClass == PC_BARD) av += (plr[id]._pLevel) >> 3; if (plr[id]._pIFlags & ISPL_QUICKATTACK) av++; if (plr[id]._pIFlags & ISPL_FASTATTACK) av += 2; if (plr[id]._pIFlags & ISPL_FASTERATTACK) av += 4; if (plr[id]._pIFlags & ISPL_FASTESTATTACK) av += 8; GetMissileVel(mi, sx, sy, dx, dy, av); #else if (plr[id]._pClass == PC_ROGUE) GetMissileVel(mi, sx, sy, dx, dy, (plr[id]._pLevel >> 2) + 31); else if (plr[id]._pClass == PC_WARRIOR) GetMissileVel(mi, sx, sy, dx, dy, (plr[id]._pLevel >> 3) + 31); else GetMissileVel(mi, sx, sy, dx, dy, 32); #endif } else GetMissileVel(mi, sx, sy, dx, dy, 32); SetMissDir(mi, GetDirection16(sx, sy, dx, dy)); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._mlid = AddLight(sx, sy, 5); } void AddArrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int av; if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } if (mienemy == TARGET_MONSTERS) { av = 32; if (plr[id]._pIFlags & ISPL_RNDARROWVEL) { av = random_(64, 32) + 16; } #ifdef HELLFIRE if (plr[id]._pClass == PC_ROGUE) av += (plr[id]._pLevel - 1) >> 2; else if (plr[id]._pClass == PC_WARRIOR || plr[id]._pClass == PC_BARD) av += (plr[id]._pLevel - 1) >> 3; if (plr[id]._pIFlags & ISPL_QUICKATTACK) av++; if (plr[id]._pIFlags & ISPL_FASTATTACK) av += 2; if (plr[id]._pIFlags & ISPL_FASTERATTACK) av += 4; if (plr[id]._pIFlags & ISPL_FASTESTATTACK) av += 8; #else if (plr[id]._pClass == PC_ROGUE) av += (plr[id]._pLevel - 1) >> 2; if (plr[id]._pClass == PC_WARRIOR) av += (plr[id]._pLevel - 1) >> 3; #endif GetMissileVel(mi, sx, sy, dx, dy, av); } else { GetMissileVel(mi, sx, sy, dx, dy, 32); } missile[mi]._miAnimFrame = GetDirection16(sx, sy, dx, dy) + 1; missile[mi]._mirange = 256; } void GetVileMissPos(int mi, int dx, int dy) { int xx, yy, k, j, i; for (k = 1; k < 50; k++) { for (j = -k; j <= k; j++) { yy = j + dy; for (i = -k; i <= k; i++) { xx = i + dx; if (PosOkPlayer(myplr, xx, yy)) { missile[mi]._mix = xx; missile[mi]._miy = yy; return; } } } } missile[mi]._mix = dx; missile[mi]._miy = dy; } void AddRndTeleport(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int pn, r1, r2, nTries; nTries = 0; do { nTries++; if (nTries > 500) { r1 = 0; r2 = 0; break; //BUGFIX: warps player to 0/0 in hellfire, change to return or use 1.09's version of the code } r1 = random_(58, 3) + 4; r2 = random_(58, 3) + 4; if (random_(58, 2) == 1) r1 = -r1; if (random_(58, 2) == 1) r2 = -r2; #ifdef HELLFIRE r1 += sx; r2 += sy; if (r1 <= MAXDUNX && r1 >= 0 && r2 <= MAXDUNY && r2 >= 0) { ///BUGFIX: < MAXDUNX / < MAXDUNY pn = dPiece[r1][r2]; } } while (nSolidTable[pn] || dObject[r1][r2] != 0 || dMonster[r1][r2] != 0); #else pn = dPiece[r1 + sx][sy + r2]; } while (nSolidTable[pn] || dObject[r1 + sx][sy + r2] != 0 || dMonster[r1 + sx][sy + r2] != 0); #endif missile[mi]._mirange = 2; missile[mi]._miVar1 = 0; if (!setlevel || setlvlnum != SL_VILEBETRAYER) { #ifdef HELLFIRE missile[mi]._mix = r1; missile[mi]._miy = r2; #else missile[mi]._mix = sx + r1; missile[mi]._miy = sy + r2; #endif if (mienemy == TARGET_MONSTERS) UseMana(id, SPL_RNDTELEPORT); } else { pn = dObject[dx][dy] - 1; // BUGFIX: should only run magic circle check if dObject[dx][dy] is non-zero. if (object[pn]._otype == OBJ_MCIRCLE1 || object[pn]._otype == OBJ_MCIRCLE2) { missile[mi]._mix = dx; missile[mi]._miy = dy; if (!PosOkPlayer(myplr, dx, dy)) GetVileMissPos(mi, dx, dy); } } } void AddFirebolt(int mi, int sx, int sy, int dx, int dy, int midir, char micaster, int id, int dam) { int i, mx, sp; if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } if (!micaster) { for (i = 0; i < nummissiles; i++) { mx = missileactive[i]; if (missile[mx]._mitype == MIS_GUARDIAN && missile[mx]._misource == id && missile[mx]._miVar3 == mi) break; } if (i == nummissiles) UseMana(id, SPL_FIREBOLT); if (id != -1) { sp = 2 * missile[mi]._mispllvl + 16; if (sp >= 63) sp = 63; } else { sp = 16; } } else { sp = 26; } GetMissileVel(mi, sx, sy, dx, dy, sp); SetMissDir(mi, GetDirection16(sx, sy, dx, dy)); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._mlid = AddLight(sx, sy, 8); } void AddMagmaball(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { GetMissileVel(mi, sx, sy, dx, dy, 16); missile[mi]._mitxoff += 3 * missile[mi]._mixvel; missile[mi]._mityoff += 3 * missile[mi]._miyvel; GetMissilePos(mi); #ifdef HELLFIRE if (missile[mi]._mixvel & 0xFFFF0000 || missile[mi]._miyvel & 0xFFFF0000) missile[mi]._mirange = 256; else missile[mi]._mirange = 1; #else missile[mi]._mirange = 256; #endif missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._mlid = AddLight(sx, sy, 8); } void miss_null_33(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { GetMissileVel(mi, sx, sy, dx, dy, 16); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; PutMissile(mi); } void AddTeleport(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i, pn, k, j, tx, ty; #ifndef HELLFIRE int CrawlNum[6] = { 0, 3, 12, 45, 94, 159 }; #endif missile[mi]._miDelFlag = TRUE; for (i = 0; i < 6; i++) { k = CrawlNum[i]; pn = k + 2; #ifdef HELLFIRE for (j = CrawlTable[k]; j > 0; j--) { // BUGFIX: should cast to BYTE or CrawlTable header will be wrong #else for (j = (BYTE)CrawlTable[k]; j > 0; j--) { #endif tx = dx + CrawlTable[pn - 1]; ty = dy + CrawlTable[pn]; if (0 < tx && tx < MAXDUNX && 0 < ty && ty < MAXDUNY) { if ((nSolidTable[dPiece[tx][ty]] | dMonster[tx][ty] | dObject[tx][ty] | dPlayer[tx][ty]) == 0) { missile[mi]._mix = tx; missile[mi]._miy = ty; missile[mi]._misx = tx; missile[mi]._misy = ty; missile[mi]._miDelFlag = FALSE; i = 6; break; } } pn += 2; } } if (!missile[mi]._miDelFlag) { UseMana(id, SPL_TELEPORT); missile[mi]._mirange = 2; } } void AddLightball(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { GetMissileVel(mi, sx, sy, dx, dy, 16); missile[mi]._midam = dam; missile[mi]._miAnimFrame = random_(63, 8) + 1; missile[mi]._mirange = 255; if (id < 0) { missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; } else { missile[mi]._miVar1 = plr[id]._px; missile[mi]._miVar2 = plr[id]._py; } } void AddFirewall(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; #ifdef HELLFIRE missile[mi]._midam = (random_(53, 10) + random_(53, 10) + 2 + (id > 0) ? plr[id]._pLevel : currlevel); // BUGFIX: missing parenthesis around ternary #else missile[mi]._midam = (random_(53, 10) + random_(53, 10) + 2 + plr[id]._pLevel); #endif missile[mi]._midam <<= 4; missile[mi]._midam >>= 1; GetMissileVel(mi, sx, sy, dx, dy, 16); i = missile[mi]._mispllvl; missile[mi]._mirange = 10; #ifndef HELLFIRE if (i > 0) #endif missile[mi]._mirange *= i + 1; #ifdef HELLFIRE if (mienemy != TARGET_MONSTERS || id < 0) missile[mi]._mirange += currlevel; else #endif missile[mi]._mirange += (plr[id]._pISplDur * missile[mi]._mirange) >> 7; missile[mi]._mirange <<= 4; missile[mi]._miVar1 = missile[mi]._mirange - missile[mi]._miAnimLen; missile[mi]._miVar2 = 0; } void AddFireball(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } if (mienemy == TARGET_MONSTERS) { missile[mi]._midam = 2 * (plr[id]._pLevel + random_(60, 10) + random_(60, 10)) + 4; for (i = missile[mi]._mispllvl; i > 0; i--) { missile[mi]._midam += missile[mi]._midam >> 3; } i = 2 * missile[mi]._mispllvl + 16; if (i > 50) i = 50; UseMana(id, SPL_FIREBALL); } else { i = 16; } GetMissileVel(mi, sx, sy, dx, dy, i); SetMissDir(mi, GetDirection16(sx, sy, dx, dy)); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._miVar3 = 0; missile[mi]._miVar4 = sx; missile[mi]._miVar5 = sy; missile[mi]._mlid = AddLight(sx, sy, 8); } void AddLightctrl(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (!dam && mienemy == TARGET_MONSTERS) UseMana(id, SPL_LIGHTNING); missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; GetMissileVel(mi, sx, sy, dx, dy, 32); missile[mi]._miAnimFrame = random_(52, 8) + 1; missile[mi]._mirange = 256; } void AddLightning(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._misx = dx; missile[mi]._misy = dy; if (midir >= 0) { missile[mi]._mixoff = missile[midir]._mixoff; missile[mi]._miyoff = missile[midir]._miyoff; missile[mi]._mitxoff = missile[midir]._mitxoff; missile[mi]._mityoff = missile[midir]._mityoff; } missile[mi]._miAnimFrame = random_(52, 8) + 1; if (midir < 0 || mienemy == TARGET_PLAYERS || id == -1) { if (midir < 0 || id == -1) missile[mi]._mirange = 8; else missile[mi]._mirange = 10; } else { missile[mi]._mirange = (missile[mi]._mispllvl >> 1) + 6; } missile[mi]._mlid = AddLight(missile[mi]._mix, missile[mi]._miy, 4); } void AddMisexp(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { CMonster *mon; if (mienemy && id > 0) { mon = monster[id].MType; #ifndef HELLFIRE if (mon->mtype == MT_SUCCUBUS) SetMissAnim(mi, MFILE_FLAREEXP); if (mon->mtype == MT_SNOWWICH) SetMissAnim(mi, MFILE_SCBSEXPB); if (mon->mtype == MT_HLSPWN) SetMissAnim(mi, MFILE_SCBSEXPD); if (mon->mtype == MT_SOLBRNR) SetMissAnim(mi, MFILE_SCBSEXPC); #else switch (mon->mtype) { case MT_SUCCUBUS: SetMissAnim(mi, MFILE_FLAREEXP); break; case MT_SNOWWICH: SetMissAnim(mi, MFILE_SCBSEXPB); break; case MT_HLSPWN: SetMissAnim(mi, MFILE_SCBSEXPD); break; case MT_SOLBRNR: SetMissAnim(mi, MFILE_SCBSEXPC); break; } #endif } missile[mi]._mix = missile[dx]._mix; missile[mi]._miy = missile[dx]._miy; missile[mi]._misx = missile[dx]._misx; missile[mi]._misy = missile[dx]._misy; missile[mi]._mixoff = missile[dx]._mixoff; missile[mi]._miyoff = missile[dx]._miyoff; missile[mi]._mitxoff = missile[dx]._mitxoff; missile[mi]._mityoff = missile[dx]._mityoff; missile[mi]._mixvel = 0; missile[mi]._miyvel = 0; missile[mi]._mirange = missile[mi]._miAnimLen; missile[mi]._miVar1 = 0; } void AddWeapexp(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._mix = sx; missile[mi]._miy = sy; missile[mi]._misx = sx; missile[mi]._misy = sy; missile[mi]._mixvel = 0; missile[mi]._miyvel = 0; missile[mi]._miVar1 = 0; missile[mi]._miVar2 = dx; missile[mi]._mimfnum = 0; if (dx == 1) SetMissAnim(mi, MFILE_MAGBLOS); else SetMissAnim(mi, MFILE_MINILTNG); missile[mi]._mirange = missile[mi]._miAnimLen - 1; } BOOL CheckIfTrig(int x, int y) { int i; for (i = 0; i < numtrigs; i++) { if ((x == trigs[i]._tx && y == trigs[i]._ty) || (abs(trigs[i]._tx - x) < 2 && abs(trigs[i]._ty - y) < 2)) return TRUE; } return FALSE; } void AddTown(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i, j, k, mx, tx, ty, dp; #ifndef HELLFIRE int CrawlNum[6] = { 0, 3, 12, 45, 94, 159 }; #endif if (currlevel != 0) { missile[mi]._miDelFlag = TRUE; for (j = 0; j < 6; j++) { k = CrawlNum[j] + 2; #ifdef HELLFIRE for (i = CrawlTable[CrawlNum[j]]; i > 0; i--) { // BUGFIX: should cast to BYTE or CrawlTable header will be wrong #else for (i = (BYTE)CrawlTable[CrawlNum[j]]; i > 0; i--) { #endif tx = dx + CrawlTable[k - 1]; ty = dy + CrawlTable[k]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { dp = dPiece[tx][ty]; if ((dMissile[tx][ty] | nSolidTable[dp] | nMissileTable[dp] | dObject[tx][ty] | dPlayer[tx][ty]) == 0) { if (!CheckIfTrig(tx, ty)) { missile[mi]._mix = tx; missile[mi]._miy = ty; missile[mi]._misx = tx; missile[mi]._misy = ty; missile[mi]._miDelFlag = FALSE; j = 6; break; } } } k += 2; } } } else { tx = dx; ty = dy; missile[mi]._mix = tx; missile[mi]._miy = ty; missile[mi]._misx = tx; missile[mi]._misy = ty; missile[mi]._miDelFlag = FALSE; } missile[mi]._mirange = 100; missile[mi]._miVar1 = missile[mi]._mirange - missile[mi]._miAnimLen; missile[mi]._miVar2 = 0; for (i = 0; i < nummissiles; i++) { mx = missileactive[i]; if (missile[mx]._mitype == MIS_TOWN && mx != mi && missile[mx]._misource == id) missile[mx]._mirange = 0; } PutMissile(mi); if (id == myplr && !missile[mi]._miDelFlag && currlevel != 0) { if (!setlevel) { NetSendCmdLocParam3(TRUE, CMD_ACTIVATEPORTAL, tx, ty, currlevel, leveltype, 0); } else { NetSendCmdLocParam3(TRUE, CMD_ACTIVATEPORTAL, tx, ty, setlvlnum, leveltype, 1); } } } void AddFlash(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; if (mienemy == TARGET_MONSTERS) { if (id != -1) { missile[mi]._midam = 0; for (i = 0; i <= plr[id]._pLevel; i++) { missile[mi]._midam += random_(55, 20) + 1; } for (i = missile[mi]._mispllvl; i > 0; i--) { missile[mi]._midam += missile[mi]._midam >> 3; } missile[mi]._midam += missile[mi]._midam >> 1; UseMana(id, SPL_FLASH); } else { missile[mi]._midam = currlevel >> 1; } } else { missile[mi]._midam = monster[id].mLevel << 1; } missile[mi]._mirange = 19; } void AddFlash2(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; if (mienemy == TARGET_MONSTERS) { if (id != -1) { missile[mi]._midam = 0; for (i = 0; i <= plr[id]._pLevel; i++) { missile[mi]._midam += random_(56, 2) + 1; } for (i = missile[mi]._mispllvl; i > 0; i--) { missile[mi]._midam += missile[mi]._midam >> 3; } missile[mi]._midam += missile[mi]._midam >> 1; } else { missile[mi]._midam = currlevel >> 1; } } missile[mi]._miPreFlag = TRUE; missile[mi]._mirange = 19; } void AddManashield(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._mirange = 48 * plr[id]._pLevel; missile[mi]._miVar1 = plr[id]._pHitPoints; missile[mi]._miVar2 = plr[id]._pHPBase; missile[mi]._miVar8 = -1; if (mienemy == TARGET_MONSTERS) UseMana(id, SPL_MANASHIELD); #ifndef HELLFIRE if (id == myplr) NetSendCmd(TRUE, CMD_SETSHIELD); plr[id].pManaShield = TRUE; #endif } void AddFiremove(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._midam = random_(59, 10) + plr[id]._pLevel + 1; GetMissileVel(mi, sx, sy, dx, dy, 16); missile[mi]._mirange = 255; missile[mi]._miVar1 = 0; missile[mi]._miVar2 = 0; missile[mi]._mix++; missile[mi]._miy++; missile[mi]._miyoff -= 32; } void AddGuardian(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i, pn, k, j, tx, ty; #ifndef HELLFIRE int CrawlNum[6] = { 0, 3, 12, 45, 94, 159 }; #endif missile[mi]._midam = random_(62, 10) + (plr[id]._pLevel >> 1) + 1; for (i = missile[mi]._mispllvl; i > 0; i--) { missile[mi]._midam += missile[mi]._midam >> 3; } missile[mi]._miDelFlag = TRUE; for (i = 0; i < 6; i++) { pn = CrawlNum[i]; k = pn + 2; #ifdef HELLFIRE for (j = CrawlTable[pn]; j > 0; j--) { // BUGFIX: should cast to BYTE or CrawlTable header will be wrong #else for (j = (BYTE)CrawlTable[pn]; j > 0; j--) { #endif tx = dx + CrawlTable[k - 1]; ty = dy + CrawlTable[k]; pn = dPiece[tx][ty]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { if (LineClear(sx, sy, tx, ty)) { if ((dMonster[tx][ty] | nSolidTable[pn] | nMissileTable[pn] | dObject[tx][ty] | dMissile[tx][ty]) == 0) { missile[mi]._mix = tx; missile[mi]._miy = ty; missile[mi]._misx = tx; missile[mi]._misy = ty; missile[mi]._miDelFlag = FALSE; UseMana(id, SPL_GUARDIAN); i = 6; break; } } } k += 2; } } if (missile[mi]._miDelFlag != TRUE) { missile[mi]._misource = id; missile[mi]._mlid = AddLight(missile[mi]._mix, missile[mi]._miy, 1); missile[mi]._mirange = missile[mi]._mispllvl + (plr[id]._pLevel >> 1); missile[mi]._mirange += (missile[mi]._mirange * plr[id]._pISplDur) >> 7; if (missile[mi]._mirange > 30) missile[mi]._mirange = 30; missile[mi]._mirange <<= 4; if (missile[mi]._mirange < 30) missile[mi]._mirange = 30; missile[mi]._miVar1 = missile[mi]._mirange - missile[mi]._miAnimLen; missile[mi]._miVar2 = 0; missile[mi]._miVar3 = 1; } } void AddChain(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._miVar1 = dx; missile[mi]._miVar2 = dy; missile[mi]._mirange = 1; UseMana(id, SPL_CHAIN); } void miss_null_11(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { SetMissDir(mi, dx); missile[mi]._midam = 0; missile[mi]._miLightFlag = TRUE; missile[mi]._mirange = 250; } void miss_null_12(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (dx > 3) dx = 2; SetMissDir(mi, dx); missile[mi]._midam = 0; missile[mi]._miLightFlag = TRUE; missile[mi]._mirange = 250; } void miss_null_13(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (dx > 3) dx = 2; SetMissDir(mi, dx); missile[mi]._midam = 0; missile[mi]._miLightFlag = TRUE; missile[mi]._mirange = missile[mi]._miAnimLen; } void AddRhino(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { AnimStruct *anim; if (monster[id].MType->mtype < MT_HORNED || monster[id].MType->mtype > MT_OBLORD) { if (monster[id].MType->mtype < MT_NSNAKE || monster[id].MType->mtype > MT_GSNAKE) { anim = &monster[id].MType->Anims[MA_WALK]; } else { anim = &monster[id].MType->Anims[MA_ATTACK]; } } else { anim = &monster[id].MType->Anims[MA_SPECIAL]; } GetMissileVel(mi, sx, sy, dx, dy, 18); missile[mi]._mimfnum = midir; missile[mi]._miAnimFlags = 0; missile[mi]._miAnimData = anim->Data[midir]; missile[mi]._miAnimDelay = anim->Rate; missile[mi]._miAnimLen = anim->Frames; missile[mi]._miAnimWidth = monster[id].MType->width; missile[mi]._miAnimWidth2 = monster[id].MType->width2; missile[mi]._miAnimAdd = 1; if (monster[id].MType->mtype >= MT_NSNAKE && monster[id].MType->mtype <= MT_GSNAKE) missile[mi]._miAnimFrame = 7; missile[mi]._miVar1 = 0; missile[mi]._miVar2 = 0; missile[mi]._miLightFlag = TRUE; if (monster[id]._uniqtype != 0) { missile[mi]._miUniqTrans = monster[id]._uniqtrans + 1; missile[mi]._mlid = monster[id].mlid; } missile[mi]._mirange = 256; PutMissile(mi); } void miss_null_32(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { AnimStruct *anim; MonsterStruct *mon; anim = &monster[id].MType->Anims[MA_WALK]; GetMissileVel(mi, sx, sy, dx, dy, 16); missile[mi]._mimfnum = midir; missile[mi]._miAnimFlags = 0; missile[mi]._miAnimData = anim->Data[midir]; missile[mi]._miAnimDelay = anim->Rate; missile[mi]._miAnimLen = anim->Frames; missile[mi]._miAnimWidth = monster[id].MType->width; missile[mi]._miAnimWidth2 = monster[id].MType->width2; missile[mi]._miAnimAdd = 1; missile[mi]._miVar1 = 0; missile[mi]._miVar2 = 0; missile[mi]._miLightFlag = TRUE; if (monster[id]._uniqtype != 0) missile[mi]._miUniqTrans = monster[id]._uniqtrans + 1; mon = &monster[id]; dMonster[mon->_mx][mon->_my] = 0; missile[mi]._mirange = 256; PutMissile(mi); } void AddFlare(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } GetMissileVel(mi, sx, sy, dx, dy, 16); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._mlid = AddLight(sx, sy, 8); if (mienemy == TARGET_MONSTERS) { UseMana(id, SPL_FLARE); plr[id]._pHitPoints -= 320; plr[id]._pHPBase -= 320; drawhpflag = TRUE; if (plr[id]._pHitPoints <= 0) SyncPlrKill(id, 0); } else { if (id > 0) { if (monster[id].MType->mtype == MT_SUCCUBUS) SetMissAnim(mi, MFILE_FLARE); if (monster[id].MType->mtype == MT_SNOWWICH) SetMissAnim(mi, MFILE_SCUBMISB); if (monster[id].MType->mtype == MT_HLSPWN) SetMissAnim(mi, MFILE_SCUBMISD); if (monster[id].MType->mtype == MT_SOLBRNR) SetMissAnim(mi, MFILE_SCUBMISC); } } #ifdef HELLFIRE if (misfiledata[missile[mi]._miAnimType].mAnimFAmt == 16) { SetMissDir(mi, GetDirection16(sx, sy, dx, dy)); } #endif } void AddAcid(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { GetMissileVel(mi, sx, sy, dx, dy, 16); SetMissDir(mi, GetDirection16(sx, sy, dx, dy)); #ifdef HELLFIRE if (missile[mi]._mixvel & 0xFFFF0000 || missile[mi]._miyvel & 0xFFFF0000) missile[mi]._mirange = 5 * (monster[id]._mint + 4); else missile[mi]._mirange = 1; #else missile[mi]._mirange = 5 * (monster[id]._mint + 4); #endif missile[mi]._mlid = -1; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; PutMissile(mi); } void miss_null_1D(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._midam = dam; missile[mi]._mixvel = 0; missile[mi]._miyvel = 0; missile[mi]._mirange = 50; missile[mi]._miVar1 = missile[mi]._mirange - missile[mi]._miAnimLen; missile[mi]._miVar2 = 0; } void AddAcidpud(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int monst; missile[mi]._mixvel = 0; missile[mi]._miyvel = 0; missile[mi]._mixoff = 0; missile[mi]._miyoff = 0; missile[mi]._miLightFlag = TRUE; monst = missile[mi]._misource; missile[mi]._mirange = random_(50, 15) + 40 * (monster[monst]._mint + 1); missile[mi]._miPreFlag = TRUE; } void AddStone(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i, j, k, l, tx, ty, mid; #ifndef HELLFIRE int CrawlNum[6] = { 0, 3, 12, 45, 94, 159 }; #endif missile[mi]._misource = id; for (i = 0; i < 6; i++) { k = CrawlNum[i]; l = k + 2; #ifdef HELLFIRE for (j = CrawlTable[k]; j > 0; j--) { // BUGFIX: should cast to BYTE or CrawlTable header will be wrong #else for (j = (BYTE)CrawlTable[k]; j > 0; j--) { #endif tx = dx + CrawlTable[l - 1]; ty = dy + CrawlTable[l]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { mid = dMonster[tx][ty]; mid = mid > 0 ? mid - 1 : -1 - mid; #ifdef HELLFIRE if (mid > MAX_PLRS - 1 && monster[mid]._mAi != AI_DIABLO && monster[mid].MType->mtype != MT_NAKRUL) { #else if (mid > MAX_PLRS - 1 && monster[mid]._mAi != AI_DIABLO) { #endif if (monster[mid]._mmode != MM_FADEIN && monster[mid]._mmode != MM_FADEOUT && monster[mid]._mmode != MM_CHARGE) { j = -99; i = 6; missile[mi]._miVar1 = monster[mid]._mmode; missile[mi]._miVar2 = mid; monster[mid]._mmode = MM_STONE; break; } } } l += 2; } } if (j != -99) { missile[mi]._miDelFlag = TRUE; } else { missile[mi]._mix = tx; missile[mi]._miy = ty; missile[mi]._misx = missile[mi]._mix; missile[mi]._misy = missile[mi]._miy; missile[mi]._mirange = missile[mi]._mispllvl + 6; missile[mi]._mirange += (missile[mi]._mirange * plr[id]._pISplDur) >> 7; if (missile[mi]._mirange > 15) missile[mi]._mirange = 15; missile[mi]._mirange <<= 4; UseMana(id, SPL_STONE); } } void AddGolem(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; int mx; missile[mi]._miDelFlag = FALSE; for (i = 0; i < nummissiles; i++) { mx = missileactive[i]; if (missile[mx]._mitype == MIS_GOLEM) { if (mx != mi && missile[mx]._misource == id) { missile[mi]._miDelFlag = TRUE; return; } } } missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._miVar4 = dx; missile[mi]._miVar5 = dy; if ((monster[id]._mx != 1 || monster[id]._my != 0) && id == myplr) M_StartKill(id, id); UseMana(id, SPL_GOLEM); } void AddEtherealize(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; missile[mi]._mirange = 16 * plr[id]._pLevel >> 1; for (i = missile[mi]._mispllvl; i > 0; i--) { missile[mi]._mirange += missile[mi]._mirange >> 3; } missile[mi]._mirange += missile[mi]._mirange * plr[id]._pISplDur >> 7; missile[mi]._miVar1 = plr[id]._pHitPoints; missile[mi]._miVar2 = plr[id]._pHPBase; if (mienemy == TARGET_MONSTERS) UseMana(id, SPL_ETHEREALIZE); } void miss_null_1F(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._miDelFlag = TRUE; } void miss_null_23(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._midam = dam; missile[mi]._mix = sx; missile[mi]._miy = sy; missile[mi]._misx = sx; missile[mi]._misy = sy; missile[mi]._misource = id; if (dam == 1) SetMissDir(mi, 0); else SetMissDir(mi, 1); missile[mi]._miLightFlag = TRUE; missile[mi]._mirange = missile[mi]._miAnimLen; } void AddBoom(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._mix = dx; missile[mi]._miy = dy; missile[mi]._misx = dx; missile[mi]._misy = dy; missile[mi]._mixvel = 0; missile[mi]._miyvel = 0; missile[mi]._midam = dam; missile[mi]._mirange = missile[mi]._miAnimLen; missile[mi]._miVar1 = 0; } void AddHeal(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; int HealAmount; HealAmount = (random_(57, 10) + 1) << 6; for (i = 0; i < plr[id]._pLevel; i++) { HealAmount += (random_(57, 4) + 1) << 6; } for (i = 0; i < missile[mi]._mispllvl; i++) { HealAmount += (random_(57, 6) + 1) << 6; } if (plr[id]._pClass == PC_WARRIOR) HealAmount <<= 1; #ifdef HELLFIRE else if (plr[id]._pClass == PC_BARBARIAN || plr[id]._pClass == PC_MONK) HealAmount <<= 1; #endif if (plr[id]._pClass == PC_ROGUE) HealAmount += HealAmount >> 1; #ifdef HELLFIRE else if (plr[id]._pClass == PC_BARD) HealAmount += HealAmount >> 1; #endif plr[id]._pHitPoints += HealAmount; if (plr[id]._pHitPoints > plr[id]._pMaxHP) plr[id]._pHitPoints = plr[id]._pMaxHP; plr[id]._pHPBase += HealAmount; if (plr[id]._pHPBase > plr[id]._pMaxHPBase) plr[id]._pHPBase = plr[id]._pMaxHPBase; UseMana(id, SPL_HEAL); missile[mi]._miDelFlag = TRUE; drawhpflag = TRUE; } void AddHealOther(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._miDelFlag = TRUE; UseMana(id, SPL_HEALOTHER); if (id == myplr) SetCursor_(CURSOR_HEALOTHER); } void AddElement(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } missile[mi]._midam = 2 * (plr[id]._pLevel + random_(60, 10) + random_(60, 10)) + 4; for (i = missile[mi]._mispllvl; i > 0; i--) { missile[mi]._midam += missile[mi]._midam >> 3; } missile[mi]._midam >>= 1; GetMissileVel(mi, sx, sy, dx, dy, 16); SetMissDir(mi, GetDirection8(sx, sy, dx, dy)); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._miVar3 = 0; missile[mi]._miVar4 = dx; missile[mi]._miVar5 = dy; missile[mi]._mlid = AddLight(sx, sy, 8); UseMana(id, SPL_ELEMENT); } void AddIdentify(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._miDelFlag = TRUE; UseMana(id, SPL_IDENTIFY); if (id == myplr) { if (sbookflag) sbookflag = FALSE; if (!invflag) invflag = TRUE; SetCursor_(CURSOR_IDENTIFY); } } void AddFirewallC(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i, j, k, tx, ty, pn; #ifndef HELLFIRE int CrawlNum[6] = { 0, 3, 12, 45, 94, 159 }; #endif missile[mi]._miDelFlag = TRUE; for (i = 0; i < 6; i++) { k = CrawlNum[i]; pn = k + 2; #ifdef HELLFIRE for (j = CrawlTable[k]; j > 0; j--) { // BUGFIX: should cast to BYTE or CrawlTable header will be wrong #else for (j = (BYTE)CrawlTable[k]; j > 0; j--) { #endif tx = dx + CrawlTable[pn - 1]; ty = dy + CrawlTable[pn]; if (0 < tx && tx < MAXDUNX && 0 < ty && ty < MAXDUNY) { k = dPiece[tx][ty]; if (LineClear(sx, sy, tx, ty)) { if ((sx != tx || sy != ty) && (nSolidTable[k] | dObject[tx][ty]) == 0) { missile[mi]._miVar1 = tx; missile[mi]._miVar2 = ty; missile[mi]._miVar5 = tx; missile[mi]._miVar6 = ty; missile[mi]._miDelFlag = FALSE; i = 6; break; } } } pn += 2; } } if (missile[mi]._miDelFlag != TRUE) { missile[mi]._miVar7 = 0; missile[mi]._miVar8 = 0; missile[mi]._miVar3 = (midir - 2) & 7; missile[mi]._miVar4 = (midir + 2) & 7; missile[mi]._mirange = 7; UseMana(id, SPL_FIREWALL); } } void AddInfra(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; missile[mi]._mirange = 1584; for (i = missile[mi]._mispllvl; i > 0; i--) { missile[mi]._mirange += missile[mi]._mirange >> 3; } missile[mi]._mirange += missile[mi]._mirange * plr[id]._pISplDur >> 7; if (mienemy == TARGET_MONSTERS) UseMana(id, SPL_INFRA); } void AddWave(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._miVar1 = dx; missile[mi]._miVar2 = dy; missile[mi]._miVar3 = 0; missile[mi]._miVar4 = 0; missile[mi]._mirange = 1; missile[mi]._miAnimFrame = 4; UseMana(id, SPL_WAVE); } void AddNova(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int k; missile[mi]._miVar1 = dx; missile[mi]._miVar2 = dy; if (id != -1) { missile[mi]._midam = (random_(66, 6) + random_(66, 6) + random_(66, 6) + random_(66, 6) + random_(66, 6)); missile[mi]._midam += plr[id]._pLevel + 5; missile[mi]._midam >>= 1; for (k = missile[mi]._mispllvl; k > 0; k--) { missile[mi]._midam += missile[mi]._midam >> 3; } if (mienemy == TARGET_MONSTERS) UseMana(id, SPL_NOVA); } else { missile[mi]._midam = ((DWORD)currlevel >> 1) + random_(66, 3) + random_(66, 3) + random_(66, 3); } missile[mi]._mirange = 1; } void AddBlodboil(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { #ifdef HELLFIRE int lvl; if (id == -1 || plr[id]._pSpellFlags & 6 || plr[id]._pHitPoints <= plr[id]._pLevel << 6) { missile[mi]._miDelFlag = TRUE; } else { int blodboilSFX[NUM_CLASSES] = { PS_WARR70, #ifndef SPAWN PS_ROGUE70, PS_MAGE70, PS_MAGE70, // BUGFIX: PS_MONK70? PS_ROGUE70, #else 0, 0, 0, 0, #endif PS_WARR70 }; UseMana(id, 22); missile[mi]._miVar1 = id; int tmp = 3 * plr[id]._pLevel; tmp <<= 7; plr[id]._pSpellFlags |= 2u; missile[mi]._miVar2 = tmp; if (2 * (id > 0)) // BUGFIX, wrong order of operation, this should be `2 * lvl` after the else. lvl = plr[id]._pLevel; else lvl = 1; missile[mi]._mirange = lvl + 10 * missile[mi]._mispllvl + 245; CalcPlrItemVals(id, TRUE); force_redraw = 255; PlaySfxLoc(blodboilSFX[plr[id]._pClass], plr[id]._px, plr[id]._py); } #else missile[mi]._miDelFlag = 1; #endif } void AddRepair(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._miDelFlag = TRUE; UseMana(id, SPL_REPAIR); if (id == myplr) { if (sbookflag) sbookflag = FALSE; if (!invflag) invflag = TRUE; SetCursor_(CURSOR_REPAIR); } } void AddRecharge(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._miDelFlag = TRUE; UseMana(id, SPL_RECHARGE); if (id == myplr) { if (sbookflag) sbookflag = FALSE; if (!invflag) invflag = TRUE; SetCursor_(CURSOR_RECHARGE); } } void AddDisarm(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._miDelFlag = TRUE; UseMana(id, SPL_DISARM); if (id == myplr) SetCursor_(CURSOR_DISARM); } void AddApoca(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; missile[mi]._miVar1 = 8; missile[mi]._miVar2 = sy - missile[mi]._miVar1; missile[mi]._miVar3 = missile[mi]._miVar1 + sy; missile[mi]._miVar4 = sx - missile[mi]._miVar1; missile[mi]._miVar5 = missile[mi]._miVar1 + sx; missile[mi]._miVar6 = missile[mi]._miVar4; if (missile[mi]._miVar2 <= 0) missile[mi]._miVar2 = 1; if (missile[mi]._miVar3 >= MAXDUNY) missile[mi]._miVar3 = MAXDUNY - 1; if (missile[mi]._miVar4 <= 0) missile[mi]._miVar4 = 1; if (missile[mi]._miVar5 >= MAXDUNX) missile[mi]._miVar5 = MAXDUNX - 1; for (i = 0; i < plr[id]._pLevel; i++) { missile[mi]._midam += random_(67, 6) + 1; } missile[mi]._mirange = 255; missile[mi]._miDelFlag = FALSE; UseMana(id, SPL_APOCA); } void AddFlame(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int i; missile[mi]._miVar2 = 0; for (i = dam; i > 0; i--) { missile[mi]._miVar2 += 5; } missile[mi]._misx = dx; missile[mi]._misy = dy; missile[mi]._mixoff = missile[midir]._mixoff; missile[mi]._miyoff = missile[midir]._miyoff; missile[mi]._mitxoff = missile[midir]._mitxoff; missile[mi]._mityoff = missile[midir]._mityoff; missile[mi]._mirange = missile[mi]._miVar2 + 20; missile[mi]._mlid = AddLight(sx, sy, 1); if (mienemy == TARGET_MONSTERS) { i = random_(79, plr[id]._pLevel) + random_(79, 2); missile[mi]._midam = 8 * i + 16 + ((8 * i + 16) >> 1); } else { missile[mi]._midam = monster[id].mMinDamage + random_(77, monster[id].mMaxDamage - monster[id].mMinDamage + 1); } } void AddFlamec(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } GetMissileVel(mi, sx, sy, dx, dy, 32); if (mienemy == TARGET_MONSTERS) UseMana(id, SPL_FLAME); missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._miVar3 = 0; missile[mi]._mirange = 256; } void AddCbolt(int mi, int sx, int sy, int dx, int dy, int midir, char micaster, int id, int dam) { /// ASSERT: assert((DWORD)mi < MAXMISSILES); if (micaster == 0) { if (id == myplr) { missile[mi]._mirnd = random_(63, 15) + 1; missile[mi]._midam = random_(68, plr[id]._pMagic >> 2) + 1; } else { missile[mi]._mirnd = random_(63, 15) + 1; missile[mi]._midam = random_(68, plr[id]._pMagic >> 2) + 1; } } else { missile[mi]._mirnd = random_(63, 15) + 1; missile[mi]._midam = 15; } if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } missile[mi]._miAnimFrame = random_(63, 8) + 1; missile[mi]._mlid = AddLight(sx, sy, 5); GetMissileVel(mi, sx, sy, dx, dy, 8); missile[mi]._miVar1 = 5; missile[mi]._miVar2 = midir; missile[mi]._miVar3 = 0; missile[mi]._mirange = 256; } void AddHbolt(int mi, int sx, int sy, int dx, int dy, int midir, char micaster, int id, int dam) { int sp; if (sx == dx && sy == dy) { dx += XDirAdd[midir]; dy += YDirAdd[midir]; } if (id != -1) { sp = 2 * missile[mi]._mispllvl + 16; if (sp >= 63) { sp = 63; } } else { sp = 16; } GetMissileVel(mi, sx, sy, dx, dy, sp); SetMissDir(mi, GetDirection16(sx, sy, dx, dy)); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._mlid = AddLight(sx, sy, 8); missile[mi]._midam = random_(69, 10) + plr[id]._pLevel + 9; UseMana(id, SPL_HBOLT); } void AddResurrect(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { UseMana(id, SPL_RESURRECT); if (id == myplr) SetCursor_(CURSOR_RESURRECT); missile[mi]._miDelFlag = TRUE; } void AddResurrectBeam(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._mix = dx; missile[mi]._miy = dy; missile[mi]._misx = missile[mi]._mix; missile[mi]._misy = missile[mi]._miy; missile[mi]._mixvel = 0; missile[mi]._miyvel = 0; missile[mi]._mirange = misfiledata[MFILE_RESSUR1].mAnimLen[0]; } void AddTelekinesis(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._miDelFlag = TRUE; UseMana(id, SPL_TELEKINESIS); if (id == myplr) SetCursor_(CURSOR_TELEKINESIS); } void AddBoneSpirit(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { if (sx == dx && sy == dy) { dx = XDirAdd[midir] + dx; dy = YDirAdd[midir] + dy; } missile[mi]._midam = 0; GetMissileVel(mi, sx, sy, dx, dy, 16); SetMissDir(mi, GetDirection8(sx, sy, dx, dy)); missile[mi]._mirange = 256; missile[mi]._miVar1 = sx; missile[mi]._miVar2 = sy; missile[mi]._miVar3 = 0; missile[mi]._miVar4 = dx; missile[mi]._miVar5 = dy; missile[mi]._mlid = AddLight(sx, sy, 8); if (mienemy == TARGET_MONSTERS) { UseMana(id, SPL_BONESPIRIT); plr[id]._pHitPoints -= 384; plr[id]._pHPBase -= 384; drawhpflag = TRUE; if (plr[id]._pHitPoints <= 0) SyncPlrKill(id, 0); } } void AddRportal(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { missile[mi]._mix = sx; missile[mi]._miy = sy; missile[mi]._misx = sx; missile[mi]._misy = sy; missile[mi]._mirange = 100; missile[mi]._miVar1 = 100 - missile[mi]._miAnimLen; missile[mi]._miVar2 = 0; PutMissile(mi); } void AddDiabApoca(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam) { int pnum; for (pnum = 0; pnum < gbMaxPlayers; pnum++) { if (plr[pnum].plractive) { if (LineClear(sx, sy, plr[pnum]._pfutx, plr[pnum]._pfuty)) { AddMissile(0, 0, plr[pnum]._pfutx, plr[pnum]._pfuty, 0, MIS_BOOM2, mienemy, id, dam, 0); } } } missile[mi]._miDelFlag = TRUE; } int AddMissile(int sx, int sy, int dx, int dy, int midir, int mitype, char micaster, int id, int midam, int spllvl) { int i, mi; #ifdef HELLFIRE if (nummissiles >= MAXMISSILES - 1) #else if (nummissiles >= MAXMISSILES) #endif return -1; #ifndef HELLFIRE if (mitype == MIS_MANASHIELD && plr[id].pManaShield == TRUE) { if (currlevel != plr[id].plrlevel) return -1; for (i = 0; i < nummissiles; i++) { mi = missileactive[i]; if (missile[mi]._mitype == MIS_MANASHIELD && missile[mi]._misource == id) return -1; } } #endif mi = missileavail[0]; missileavail[0] = missileavail[MAXMISSILES - nummissiles - 1]; missileactive[nummissiles] = mi; nummissiles++; #ifdef HELLFIRE memset(&missile[mi], 0, sizeof(*missile)); #endif missile[mi]._mitype = mitype; missile[mi]._micaster = micaster; missile[mi]._misource = id; missile[mi]._miAnimType = missiledata[mitype].mFileNum; missile[mi]._miDrawFlag = missiledata[mitype].mDraw; missile[mi]._mispllvl = spllvl; missile[mi]._mimfnum = midir; if (missile[mi]._miAnimType == MFILE_NONE || misfiledata[missile[mi]._miAnimType].mAnimFAmt < 8) SetMissDir(mi, 0); else SetMissDir(mi, midir); missile[mi]._mix = sx; missile[mi]._miy = sy; missile[mi]._mixoff = 0; missile[mi]._miyoff = 0; missile[mi]._misx = sx; missile[mi]._misy = sy; missile[mi]._mitxoff = 0; missile[mi]._mityoff = 0; missile[mi]._miDelFlag = FALSE; missile[mi]._miAnimAdd = 1; missile[mi]._miLightFlag = FALSE; missile[mi]._miPreFlag = FALSE; missile[mi]._miUniqTrans = 0; missile[mi]._midam = midam; missile[mi]._miHitFlag = FALSE; missile[mi]._midist = 0; missile[mi]._mlid = -1; missile[mi]._mirnd = 0; if (missiledata[mitype].mlSFX != -1) { PlaySfxLoc(missiledata[mitype].mlSFX, missile[mi]._misx, missile[mi]._misy); } missiledata[mitype].mAddProc(mi, sx, sy, dx, dy, midir, micaster, id, midam); return mi; } int Sentfire(int i, int sx, int sy) { int ex, dir; ex = 0; if (LineClear(missile[i]._mix, missile[i]._miy, sx, sy)) { if (dMonster[sx][sy] > 0 && monster[dMonster[sx][sy] - 1]._mhitpoints >> 6 > 0 && dMonster[sx][sy] - 1 > MAX_PLRS - 1) { dir = GetDirection(missile[i]._mix, missile[i]._miy, sx, sy); missile[i]._miVar3 = missileavail[0]; AddMissile(missile[i]._mix, missile[i]._miy, sx, sy, dir, MIS_FIREBOLT, TARGET_MONSTERS, missile[i]._misource, missile[i]._midam, GetSpellLevel(missile[i]._misource, SPL_FIREBOLT)); ex = -1; } } if (ex == -1) { SetMissDir(i, 2); missile[i]._miVar2 = 3; } return ex; } void MI_Dummy(int i) { return; } void MI_Golem(int i) { #ifndef HELLFIRE int CrawlNum[6] = { 0, 3, 12, 45, 94, 159 }; #endif int tx, ty, dp, l, m, src, k, tid; char *ct; src = missile[i]._misource; if (monster[src]._mx == 1 && monster[src]._my == 0) { for (l = 0; l < 6; l++) { k = CrawlNum[l]; tid = k + 2; #ifdef HELLFIRE for (m = CrawlTable[k]; m > 0; m--) { // BUGFIX: should cast to BYTE or CrawlTable header will be wrong #else for (m = (BYTE)CrawlTable[k]; m > 0; m--) { #endif ct = &CrawlTable[tid]; tx = missile[i]._miVar4 + *(ct - 1); ty = missile[i]._miVar5 + *ct; if (0 < tx && tx < MAXDUNX && 0 < ty && ty < MAXDUNY) { dp = dPiece[tx][ty]; if (LineClear(missile[i]._miVar1, missile[i]._miVar2, tx, ty)) { if ((dMonster[tx][ty] | nSolidTable[dp] | dObject[tx][ty]) == 0) { l = 6; SpawnGolum(src, tx, ty, i); break; } } } tid += 2; } } } missile[i]._miDelFlag = TRUE; } void MI_SetManashield(int i) { ManashieldFlag = TRUE; } void MI_LArrow(int i) { int p, mind, maxd, rst; missile[i]._mirange--; p = missile[i]._misource; if (missile[i]._miAnimType == MFILE_MINILTNG || missile[i]._miAnimType == MFILE_MAGBLOS) { ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, missile[i]._miAnimFrame + 5); rst = missiledata[missile[i]._mitype].mResist; if (missile[i]._mitype == MIS_LARROW) { if (p != -1) { // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[p]._pILMinDam; maxd = plr[p]._pILMaxDam; } else { mind = random_(68, 10) + 1 + currlevel; maxd = random_(68, 10) + 1 + currlevel * 2; } missiledata[MIS_LARROW].mResist = MISR_LIGHTNING; CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, TRUE); } if (missile[i]._mitype == MIS_FARROW) { if (p != -1) { // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[p]._pIFMinDam; maxd = plr[p]._pIFMaxDam; } else { mind = random_(68, 10) + 1 + currlevel; maxd = random_(68, 10) + 1 + currlevel * 2; } missiledata[MIS_FARROW].mResist = MISR_FIRE; CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, TRUE); } missiledata[missile[i]._mitype].mResist = rst; } else { missile[i]._midist++; missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); if (p != -1) { if (missile[i]._micaster == TARGET_MONSTERS) { // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[p]._pIMinDam; maxd = plr[p]._pIMaxDam; } else { // BUGFIX: damage of missile should be encoded in missile struct; monster can be dead before missile arrives. mind = monster[p].mMinDamage; maxd = monster[p].mMaxDamage; } } else { mind = random_(68, 10) + 1 + currlevel; maxd = random_(68, 10) + 1 + currlevel * 2; } if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) { rst = missiledata[missile[i]._mitype].mResist; missiledata[missile[i]._mitype].mResist = 0; CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, FALSE); missiledata[missile[i]._mitype].mResist = rst; } if (missile[i]._mirange == 0) { missile[i]._mimfnum = 0; missile[i]._mitxoff -= missile[i]._mixvel; missile[i]._mityoff -= missile[i]._miyvel; GetMissilePos(i); if (missile[i]._mitype == MIS_LARROW) SetMissAnim(i, MFILE_MINILTNG); else SetMissAnim(i, MFILE_MAGBLOS); missile[i]._mirange = missile[i]._miAnimLen - 1; } else { if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) { missile[i]._miVar1 = missile[i]._mix; missile[i]._miVar2 = missile[i]._miy; ChangeLight(missile[i]._mlid, missile[i]._miVar1, missile[i]._miVar2, 5); } } } if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } PutMissile(i); } void MI_Arrow(int i) { int p, mind, maxd; missile[i]._mirange--; missile[i]._midist++; missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); p = missile[i]._misource; if (p != -1) { if (missile[i]._micaster == TARGET_MONSTERS) { // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[p]._pIMinDam; maxd = plr[p]._pIMaxDam; } else { // BUGFIX: damage of missile should be encoded in missile struct; monster can be dead before missile arrives. mind = monster[p].mMinDamage; maxd = monster[p].mMaxDamage; } } else { mind = currlevel; maxd = 2 * currlevel; } if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; PutMissile(i); } void MI_Firebolt(int i) { int omx, omy; int d, p; missile[i]._mirange--; if (missile[i]._mitype != MIS_BONESPIRIT || missile[i]._mimfnum != 8) { omx = missile[i]._mitxoff; omy = missile[i]._mityoff; missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); p = missile[i]._misource; if (p != -1) { if (missile[i]._micaster == TARGET_MONSTERS) { switch (missile[i]._mitype) { case MIS_FIREBOLT: // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. d = random_(75, 10) + (plr[p]._pMagic >> 3) + missile[i]._mispllvl + 1; break; case MIS_FLARE: // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. d = 3 * missile[i]._mispllvl - (plr[p]._pMagic >> 3) + (plr[p]._pMagic >> 1); break; case MIS_BONESPIRIT: d = 0; break; } } else { // BUGFIX: damage of missile should be encoded in missile struct; monster can be dead before missile arrives. d = monster[p].mMinDamage + random_(77, monster[p].mMaxDamage - monster[p].mMinDamage + 1); } } else { d = currlevel + random_(78, 2 * currlevel); } if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) { CheckMissileCol(i, d, d, FALSE, missile[i]._mix, missile[i]._miy, FALSE); } if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; missile[i]._mitxoff = omx; missile[i]._mityoff = omy; GetMissilePos(i); switch (missile[i]._mitype) { case MIS_FIREBOLT: case MIS_MAGMABALL: AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_MISEXP, missile[i]._micaster, missile[i]._misource, 0, 0); break; case MIS_FLARE: AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_MISEXP2, missile[i]._micaster, missile[i]._misource, 0, 0); break; case MIS_ACID: AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_MISEXP3, missile[i]._micaster, missile[i]._misource, 0, 0); break; case MIS_BONESPIRIT: SetMissDir(i, 8); missile[i]._mirange = 7; missile[i]._miDelFlag = FALSE; PutMissile(i); return; #ifdef HELLFIRE case MIS_LICH: AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_EXORA1, missile[i]._micaster, missile[i]._misource, 0, 0); break; case MIS_PSYCHORB: AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_EXBL2, missile[i]._micaster, missile[i]._misource, 0, 0); break; case MIS_NECROMORB: AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_EXRED3, missile[i]._micaster, missile[i]._misource, 0, 0); break; case MIS_ARCHLICH: AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_EXYEL2, missile[i]._micaster, missile[i]._misource, 0, 0); break; case MIS_BONEDEMON: AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_EXBL3, missile[i]._micaster, missile[i]._misource, 0, 0); break; #endif } if (missile[i]._mlid >= 0) AddUnLight(missile[i]._mlid); PutMissile(i); } else { if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) { missile[i]._miVar1 = missile[i]._mix; missile[i]._miVar2 = missile[i]._miy; if (missile[i]._mlid >= 0) ChangeLight(missile[i]._mlid, missile[i]._miVar1, missile[i]._miVar2, 8); } PutMissile(i); } } else if (missile[i]._mirange == 0) { if (missile[i]._mlid >= 0) AddUnLight(missile[i]._mlid); missile[i]._miDelFlag = TRUE; PlaySfxLoc(LS_BSIMPCT, missile[i]._mix, missile[i]._miy); PutMissile(i); } else PutMissile(i); } void MI_Lightball(int i) { int tx, ty, j, oi; char obj; tx = missile[i]._miVar1; ty = missile[i]._miVar2; missile[i]._mirange--; missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); j = missile[i]._mirange; CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._miHitFlag == TRUE) missile[i]._mirange = j; obj = dObject[tx][ty]; if (obj && tx == missile[i]._mix && ty == missile[i]._miy) { if (obj > 0) { oi = obj - 1; } else { oi = -1 - obj; } if (object[oi]._otype == OBJ_SHRINEL || object[oi]._otype == OBJ_SHRINER) missile[i]._mirange = j; } if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; PutMissile(i); } void mi_null_33(int i) { missile[i]._mirange--; missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; PutMissile(i); } void MI_Acidpud(int i) { int range; missile[i]._mirange--; range = missile[i]._mirange; CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, FALSE); missile[i]._mirange = range; if (range == 0) { if (missile[i]._mimfnum != 0) { missile[i]._miDelFlag = TRUE; } else { SetMissDir(i, 1); missile[i]._mirange = missile[i]._miAnimLen; } } PutMissile(i); } void MI_Firewall(int i) { int ExpLight[14] = { 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 12 }; missile[i]._mirange--; if (missile[i]._mirange == missile[i]._miVar1) { SetMissDir(i, 1); missile[i]._miAnimFrame = random_(83, 11) + 1; } if (missile[i]._mirange == missile[i]._miAnimLen - 1) { SetMissDir(i, 0); missile[i]._miAnimFrame = 13; missile[i]._miAnimAdd = -1; } CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, TRUE); if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } if (missile[i]._mimfnum != 0 && missile[i]._mirange != 0 && missile[i]._miAnimAdd != -1 && missile[i]._miVar2 < 12) { if (missile[i]._miVar2 == 0) missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, ExpLight[0]); ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar2]); missile[i]._miVar2++; } PutMissile(i); } void MI_Fireball(int i) { int dam, id, px, py, mx, my; id = missile[i]._misource; dam = missile[i]._midam; missile[i]._mirange--; if (missile[i]._micaster == TARGET_MONSTERS) { px = plr[id]._px; py = plr[id]._py; } else { px = monster[id]._mx; py = monster[id]._my; } if (missile[i]._miAnimType == MFILE_BIGEXP) { if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } } else { missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) CheckMissileCol(i, dam, dam, 0, missile[i]._mix, missile[i]._miy, 0); if (missile[i]._mirange == 0) { mx = missile[i]._mix; my = missile[i]._miy; ChangeLight(missile[i]._mlid, missile[i]._mix, my, missile[i]._miAnimFrame); if (!CheckBlock(px, py, mx, my)) CheckMissileCol(i, dam, dam, 0, mx, my, 1); if (!CheckBlock(px, py, mx, my + 1)) CheckMissileCol(i, dam, dam, 0, mx, my + 1, 1); if (!CheckBlock(px, py, mx, my - 1)) CheckMissileCol(i, dam, dam, 0, mx, my - 1, 1); if (!CheckBlock(px, py, mx + 1, my)) CheckMissileCol(i, dam, dam, 0, mx + 1, my, 1); if (!CheckBlock(px, py, mx + 1, my - 1)) CheckMissileCol(i, dam, dam, 0, mx + 1, my - 1, 1); if (!CheckBlock(px, py, mx + 1, my + 1)) CheckMissileCol(i, dam, dam, 0, mx + 1, my + 1, 1); if (!CheckBlock(px, py, mx - 1, my)) CheckMissileCol(i, dam, dam, 0, mx - 1, my, 1); if (!CheckBlock(px, py, mx - 1, my + 1)) CheckMissileCol(i, dam, dam, 0, mx - 1, my + 1, 1); if (!CheckBlock(px, py, mx - 1, my - 1)) CheckMissileCol(i, dam, dam, 0, mx - 1, my - 1, 1); if (!TransList[dTransVal[mx][my]] || (missile[i]._mixvel < 0 && ((TransList[dTransVal[mx][my + 1]] && nSolidTable[dPiece[mx][my + 1]]) || (TransList[dTransVal[mx][my - 1]] && nSolidTable[dPiece[mx][my - 1]])))) { missile[i]._mix++; missile[i]._miy++; missile[i]._miyoff -= 32; } if (missile[i]._miyvel > 0 && (TransList[dTransVal[mx + 1][my]] && nSolidTable[dPiece[mx + 1][my]] || TransList[dTransVal[mx - 1][my]] && nSolidTable[dPiece[mx - 1][my]])) { missile[i]._miyoff -= 32; } if (missile[i]._mixvel > 0 && (TransList[dTransVal[mx][my + 1]] && nSolidTable[dPiece[mx][my + 1]] || TransList[dTransVal[mx][my - 1]] && nSolidTable[dPiece[mx][my - 1]])) { missile[i]._mixoff -= 32; } missile[i]._mimfnum = 0; SetMissAnim(i, MFILE_BIGEXP); missile[i]._mirange = missile[i]._miAnimLen - 1; } else if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) { missile[i]._miVar1 = missile[i]._mix; missile[i]._miVar2 = missile[i]._miy; ChangeLight(missile[i]._mlid, missile[i]._miVar1, missile[i]._miVar2, 8); } } PutMissile(i); } #ifdef HELLFIRE void mi_hork_spawn(int i) { int t, j, k, tx, ty, dp; missile[i]._mirange--; CheckMissileCol(i, 0, 0, 0, missile[i]._mix, missile[i]._miy, 0); if (missile[i]._mirange <= 0) { missile[i]._miDelFlag = TRUE; for (j = 0; j < 2; j++) { k = CrawlNum[j] + 2; for (t = CrawlTable[CrawlNum[j]]; t > 0; t--, k += 2) { tx = missile[i]._mix + CrawlTable[k - 1]; ty = missile[i]._miy + CrawlTable[k]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { dp = dPiece[tx][ty]; if (!nSolidTable[dp] && dMonster[tx][ty] == 0 && dPlayer[tx][ty] == 0 && dObject[tx][ty] == 0) { j = 6; int mon = AddMonster(tx, ty, missile[i]._miVar1, 1, TRUE); M_StartStand(mon, missile[i]._miVar1); break; } } } } } else { missile[i]._midist++; missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); } PutMissile(i); } void MI_Rune(int i) { int mid, pid, dir, mx, my; mx = missile[i]._mix; my = missile[i]._miy; mid = dMonster[mx][my]; pid = dPlayer[mx][my]; if (mid != 0 || pid != 0) { if (mid != 0) { if (mid > 0) mid = mid - 1; else mid = -(mid + 1); dir = GetDirection(missile[i]._mix, missile[i]._miy, monster[mid]._mx, monster[mid]._my); } else { if (pid > 0) pid = pid - 1; else pid = -(pid + 1); dir = GetDirection(missile[i]._mix, missile[i]._miy, plr[pid]._px, plr[pid]._py); } missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); AddMissile(mx, my, mx, my, dir, missile[i]._miVar1, TARGET_BOTH, missile[i]._misource, missile[i]._midam, missile[i]._mispllvl); } PutMissile(i); } void mi_light_wall(int i) { int range; missile[i]._mirange--; range = missile[i]._mirange; CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix, missile[i]._miy, 0); if (missile[i]._miHitFlag == TRUE) missile[i]._mirange = range; if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; PutMissile(i); } void mi_hive_explode(int i) { missile[i]._mirange--; if (missile[i]._mirange <= 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } PutMissile(i); } void mi_immolation(int i) { int dam, id, px, py, mx, my, xof, yof; id = missile[i]._misource; dam = missile[i]._midam; if (missile[i]._miVar7 < 0) { int v = 2 * missile[i]._miVar6; missile[i]._miVar6 = v; missile[i]._miVar7 = v; missile[i]._mimfnum--; if (missile[i]._mimfnum < 0) missile[i]._mimfnum = 7; } else { missile[i]._miVar7--; } switch (missile[i]._mimfnum) { case DIR_S: xof = missile[i]._mixvel; yof = 0; break; case DIR_SW: xof = missile[i]._mixvel; yof = missile[i]._miyvel; break; case DIR_W: xof = 0; yof = missile[i]._miyvel; break; case DIR_NW: xof = missile[i]._mixvel; yof = missile[i]._miyvel; break; case DIR_N: xof = missile[i]._mixvel; yof = 0; break; case DIR_NE: xof = missile[i]._mixvel; yof = missile[i]._miyvel; break; case DIR_E: xof = 0; yof = missile[i]._miyvel; break; case DIR_SE: xof = missile[i]._mixvel; yof = missile[i]._miyvel; break; } missile[i]._mirange--; if (missile[i]._micaster == TARGET_MONSTERS) { px = plr[id]._px; py = plr[id]._py; } else { px = monster[id]._mx; py = monster[id]._my; } if (missile[i]._miAnimType == MFILE_BIGEXP) { if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } } else { missile[i]._mitxoff += xof; missile[i]._mityoff += yof; GetMissilePos(i); if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) CheckMissileCol(i, dam, dam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._mirange == 0) { mx = missile[i]._mix; my = missile[i]._miy; ChangeLight(missile[i]._mlid, missile[i]._mix, my, missile[i]._miAnimFrame); if (!CheckBlock(px, py, mx, my)) CheckMissileCol(i, dam, dam, FALSE, mx, my, TRUE); if (!CheckBlock(px, py, mx, my + 1)) CheckMissileCol(i, dam, dam, FALSE, mx, my + 1, TRUE); if (!CheckBlock(px, py, mx, my - 1)) CheckMissileCol(i, dam, dam, FALSE, mx, my - 1, TRUE); if (!CheckBlock(px, py, mx + 1, my)) CheckMissileCol(i, dam, dam, FALSE, mx + 1, my, TRUE); if (!CheckBlock(px, py, mx + 1, my - 1)) CheckMissileCol(i, dam, dam, FALSE, mx + 1, my - 1, TRUE); if (!CheckBlock(px, py, mx + 1, my + 1)) CheckMissileCol(i, dam, dam, FALSE, mx + 1, my + 1, TRUE); if (!CheckBlock(px, py, mx - 1, my)) CheckMissileCol(i, dam, dam, FALSE, mx - 1, my, TRUE); if (!CheckBlock(px, py, mx - 1, my + 1)) CheckMissileCol(i, dam, dam, FALSE, mx - 1, my + 1, TRUE); if (!CheckBlock(px, py, mx - 1, my - 1)) CheckMissileCol(i, dam, dam, FALSE, mx - 1, my - 1, TRUE); if (!TransList[dTransVal[mx][my]] || (missile[i]._mixvel < 0 && ((TransList[dTransVal[mx][my + 1]] && nSolidTable[dPiece[mx][my + 1]]) || (TransList[dTransVal[mx][my - 1]] && nSolidTable[dPiece[mx][my - 1]])))) { missile[i]._mix++; missile[i]._miy++; missile[i]._miyoff -= 32; } if (missile[i]._miyvel > 0 && (TransList[dTransVal[mx + 1][my]] && nSolidTable[dPiece[mx + 1][my]] || TransList[dTransVal[mx - 1][my]] && nSolidTable[dPiece[mx - 1][my]])) { missile[i]._miyoff -= 32; } if (missile[i]._mixvel > 0 && (TransList[dTransVal[mx][my + 1]] && nSolidTable[dPiece[mx][my + 1]] || TransList[dTransVal[mx][my - 1]] && nSolidTable[dPiece[mx][my - 1]])) { missile[i]._mixoff -= 32; } missile[i]._mimfnum = 0; SetMissAnim(i, MFILE_BIGEXP); missile[i]._mirange = missile[i]._miAnimLen - 1; } else if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) { missile[i]._miVar1 = missile[i]._mix; missile[i]._miVar2 = missile[i]._miy; ChangeLight(missile[i]._mlid, missile[i]._miVar1, missile[i]._miVar2, 8); } missile[i]._miDelFlag = TRUE; } PutMissile(i); } void mi_light_arrow(int i) { int pn, dam, mx, my; missile[i]._mirange--; missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); mx = missile[i]._mix; my = missile[i]._miy; /// ASSERT: assert((DWORD)mx < MAXDUNX); /// ASSERT: assert((DWORD)my < MAXDUNY); pn = dPiece[mx][my]; /// ASSERT: assert((DWORD)pn <= MAXTILES); if (missile[i]._misource == -1) { if ((mx != missile[i]._misx || my != missile[i]._misy) && nMissileTable[pn]) { missile[i]._mirange = 0; } } else if (nMissileTable[pn]) { missile[i]._mirange = 0; } if (!nMissileTable[pn]) { if ((mx != missile[i]._miVar1 || my != missile[i]._miVar2) && mx > 0 && my > 0 && mx < MAXDUNX && my < MAXDUNY) { if (missile[i]._misource != -1) { if (missile[i]._micaster == TARGET_PLAYERS && monster[missile[i]._misource].MType->mtype >= MT_STORM && monster[missile[i]._misource].MType->mtype <= MT_MAEL) { AddMissile( missile[i]._mix, missile[i]._miy, missile[i]._misx, missile[i]._misy, i, MIS_LIGHTNING2, missile[i]._micaster, missile[i]._misource, missile[i]._midam, missile[i]._mispllvl); } else { AddMissile( missile[i]._mix, missile[i]._miy, missile[i]._misx, missile[i]._misy, i, MIS_LIGHTNING, missile[i]._micaster, missile[i]._misource, missile[i]._midam, missile[i]._mispllvl); } } else { AddMissile( missile[i]._mix, missile[i]._miy, missile[i]._misx, missile[i]._misy, i, MIS_LIGHTNING, missile[i]._micaster, missile[i]._misource, missile[i]._midam, missile[i]._mispllvl); } missile[i]._miVar1 = missile[i]._mix; missile[i]._miVar2 = missile[i]._miy; } } if (missile[i]._mirange == 0 || mx <= 0 || my <= 0 || mx >= MAXDUNX || my > MAXDUNY) { // BUGFIX my >= MAXDUNY missile[i]._miDelFlag = TRUE; } } void mi_flashfr(int i) { int src; src = missile[i]._misource; if (missile[i]._micaster == TARGET_MONSTERS && src != -1) { missile[i]._mix = plr[src]._px; missile[i]._miy = plr[src]._py; missile[i]._mitxoff = plr[src]._pxoff << 16; missile[i]._mityoff = plr[src]._pyoff << 16; } missile[i]._mirange--; if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; if (missile[i]._micaster == TARGET_MONSTERS) { src = missile[i]._misource; if (src != -1) plr[src]._pBaseToBlk -= 50; } } PutMissile(i); } void mi_flashbk(int i) { if (missile[i]._micaster == TARGET_MONSTERS) { if (missile[i]._misource != -1) { missile[i]._mix = plr[missile[i]._misource]._pfutx; missile[i]._miy = plr[missile[i]._misource]._pfuty; } } missile[i]._mirange--; if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; PutMissile(i); } void mi_reflect(int i) { int src; src = missile[i]._misource; missile[i]._mitxoff = plr[src]._pxoff << 16; missile[i]._mityoff = plr[src]._pyoff << 16; if (plr[src]._pmode == PM_WALK3) { missile[i]._misx = plr[src]._pfutx + 2; missile[i]._misy = plr[src]._pfuty - 1; } else { missile[i]._misx = plr[src]._px + 2; missile[i]._misy = plr[src]._py - 1; } GetMissilePos(i); if (plr[src]._pmode == PM_WALK3) { if (plr[src]._pdir == DIR_W) missile[i]._mix++; else missile[i]._miy++; } if (src != myplr && currlevel != plr[src].plrlevel) missile[i]._miDelFlag = TRUE; if (plr[src].wReflections <= 0) { missile[i]._miDelFlag = TRUE; NetSendCmd(TRUE, CMD_REFLECT); } PutMissile(i); } void mi_fire_ring(int i) { int src, tx, ty, dmg, k, j, dp, b; BYTE lvl; b = CrawlNum[3]; missile[i]._miDelFlag = 1; src = missile[i]._micaster; k = CrawlNum[3] + 1; if (src > 0) lvl = plr[src]._pLevel; else lvl = currlevel; dmg = 16 * (random_(53, 10) + random_(53, 10) + lvl + 2) >> 1; for (j = CrawlTable[b]; j > 0; j--, k += 2) { tx = missile[i]._miVar1 + CrawlTable[k]; ty = missile[i]._miVar2 + CrawlTable[k + 1]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { dp = dPiece[tx][ty]; if (!nSolidTable[dp] && dObject[tx][ty] == 0) { if (LineClear(missile[i]._mix, missile[i]._miy, tx, ty)) { if (nMissileTable[dp] || missile[i]._miVar8) missile[i]._miVar8 = 1; else AddMissile(tx, ty, tx, ty, 0, MIS_FIREWALL, TARGET_BOTH, src, dmg, missile[i]._mispllvl); } } } } } void mi_light_ring(int i) { int src, tx, ty, dmg, k, j, dp, b; BYTE lvl; b = CrawlNum[3]; missile[i]._miDelFlag = 1; src = missile[i]._micaster; k = CrawlNum[3] + 1; if (src > 0) lvl = plr[src]._pLevel; else lvl = currlevel; dmg = 16 * (random_(53, 10) + random_(53, 10) + lvl + 2) >> 1; for (j = CrawlTable[b]; j > 0; j--, k += 2) { tx = missile[i]._miVar1 + CrawlTable[k]; ty = missile[i]._miVar2 + CrawlTable[k + 1]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { dp = dPiece[tx][ty]; if (!nSolidTable[dp] && dObject[tx][ty] == 0) { if (LineClear(missile[i]._mix, missile[i]._miy, tx, ty)) { if (nMissileTable[dp] || missile[i]._miVar8) missile[i]._miVar8 = 1; else AddMissile(tx, ty, tx, ty, 0, MIS_LIGHTWALL, TARGET_BOTH, src, dmg, missile[i]._mispllvl); } } } } } void mi_search(int i) { missile[i]._mirange--; if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; PlaySfxLoc(IS_CAST7, plr[missile[i]._miVar1]._px, plr[missile[i]._miVar1]._py); AutoMapShowItems = FALSE; } } void mi_lightning_wall(int i) { int src, lvl, dmg, tx, ty, dp; missile[i]._mirange--; src = missile[i]._misource; if (src > 0) lvl = plr[src]._pLevel; else lvl = 0; dmg = 16 * (random_(53, 10) + random_(53, 10) + lvl + 2); if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; } else { dp = dPiece[missile[i]._miVar1][missile[i]._miVar2]; if (dp || 1) { tx = missile[i]._miVar1 + XDirAdd[missile[i]._miVar3]; ty = missile[i]._miVar2 + YDirAdd[missile[i]._miVar3]; if (!nMissileTable[dp] && !missile[i]._miVar8 && tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { AddMissile(missile[i]._miVar1, missile[i]._miVar2, missile[i]._miVar1, missile[i]._miVar2, plr[src]._pdir, MIS_LIGHTWALL, TARGET_BOTH, src, dmg, missile[i]._mispllvl); missile[i]._miVar1 = tx; missile[i]._miVar2 = ty; } else { missile[i]._miVar8 = 1; } } else { missile[i]._miVar8 = 1; } dp = dPiece[missile[i]._miVar5][missile[i]._miVar6]; if (dp || 1) { tx = missile[i]._miVar5 + XDirAdd[missile[i]._miVar4]; ty = missile[i]._miVar6 + YDirAdd[missile[i]._miVar4]; if (!nMissileTable[dp] && !missile[i]._miVar7 && tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { AddMissile(missile[i]._miVar5, missile[i]._miVar6, missile[i]._miVar5, missile[i]._miVar6, plr[src]._pdir, MIS_LIGHTWALL, TARGET_BOTH, src, dmg, missile[i]._mispllvl); missile[i]._miVar5 = tx; missile[i]._miVar6 = ty; } else { missile[i]._miVar7 = 1; } } else { missile[i]._miVar7 = 1; } } } void mi_fire_nova(int i) { int k, id, sx, sy, dir, en, sx1, sy1, dam; sx1 = 0; sy1 = 0; id = missile[i]._misource; dam = missile[i]._midam; sx = missile[i]._mix; sy = missile[i]._miy; if (id != -1) { dir = plr[id]._pdir; en = TARGET_MONSTERS; } else { dir = 0; en = TARGET_PLAYERS; } for (k = 0; k < 23; k++) { if (sx1 != vCrawlTable[k][6] || sy1 != vCrawlTable[k][7]) { AddMissile(sx, sy, sx + vCrawlTable[k][6], sy + vCrawlTable[k][7], dir, MIS_FIRENOVA, en, id, dam, missile[i]._mispllvl); AddMissile(sx, sy, sx - vCrawlTable[k][6], sy - vCrawlTable[k][7], dir, MIS_FIRENOVA, en, id, dam, missile[i]._mispllvl); AddMissile(sx, sy, sx - vCrawlTable[k][6], sy + vCrawlTable[k][7], dir, MIS_FIRENOVA, en, id, dam, missile[i]._mispllvl); AddMissile(sx, sy, sx + vCrawlTable[k][6], sy - vCrawlTable[k][7], dir, MIS_FIRENOVA, en, id, dam, missile[i]._mispllvl); sx1 = vCrawlTable[k][6]; sy1 = vCrawlTable[k][7]; } } missile[i]._mirange--; if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; } void mi_spec_arrow(int i) { int dir, src, dam, sx, sy, dx, dy, spllvl, mitype, micaster; src = missile[i]._misource; dam = missile[i]._midam; sx = missile[i]._mix; sy = missile[i]._miy; dx = missile[i]._miVar1; dy = missile[i]._miVar2; spllvl = missile[i]._miVar3; mitype = 0; if (src != -1) { dir = plr[src]._pdir; micaster = TARGET_MONSTERS; switch (plr[src]._pILMinDam) { case 0: mitype = MIS_FIRENOVA; break; case 1: mitype = MIS_LIGHTARROW; break; case 2: mitype = MIS_CBOLTARROW; break; case 3: mitype = MIS_HBOLTARROW; break; } } else { dir = 0; micaster = TARGET_PLAYERS; } AddMissile(sx, sy, dx, dy, dir, mitype, micaster, src, dam, spllvl); if (mitype == MIS_CBOLTARROW) { AddMissile(sx, sy, dx, dy, dir, mitype, micaster, src, dam, spllvl); AddMissile(sx, sy, dx, dy, dir, mitype, micaster, src, dam, spllvl); } missile[i]._mirange--; if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; } #endif void MI_Lightctrl(int i) { int pn, dam, p, mx, my; /// ASSERT: assert((DWORD)i < MAXMISSILES); missile[i]._mirange--; p = missile[i]._misource; if (p != -1) { if (missile[i]._micaster == TARGET_MONSTERS) { // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. dam = (random_(79, 2) + random_(79, plr[p]._pLevel) + 2) << 6; } else { // BUGFIX: damage of missile should be encoded in missile struct; monster can be dead before missile arrives. dam = 2 * (monster[p].mMinDamage + random_(80, monster[p].mMaxDamage - monster[p].mMinDamage + 1)); } } else { dam = random_(81, currlevel) + 2 * currlevel; } missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); mx = missile[i]._mix; my = missile[i]._miy; /// ASSERT: assert((DWORD)mx < MAXDUNX); /// ASSERT: assert((DWORD)my < MAXDUNY); pn = dPiece[mx][my]; /// ASSERT: assert((DWORD)pn <= MAXTILES); if (missile[i]._misource == -1) { if ((mx != missile[i]._misx || my != missile[i]._misy) && nMissileTable[pn]) { missile[i]._mirange = 0; } } else if (nMissileTable[pn]) { missile[i]._mirange = 0; } if (!nMissileTable[pn]) { if ((mx != missile[i]._miVar1 || my != missile[i]._miVar2) && mx > 0 && my > 0 && mx < MAXDUNX && my < MAXDUNY) { if (missile[i]._misource != -1) { if (missile[i]._micaster == TARGET_PLAYERS && monster[missile[i]._misource].MType->mtype >= MT_STORM && monster[missile[i]._misource].MType->mtype <= MT_MAEL) { AddMissile( missile[i]._mix, missile[i]._miy, missile[i]._misx, missile[i]._misy, i, MIS_LIGHTNING2, missile[i]._micaster, missile[i]._misource, dam, missile[i]._mispllvl); } else { AddMissile( missile[i]._mix, missile[i]._miy, missile[i]._misx, missile[i]._misy, i, MIS_LIGHTNING, missile[i]._micaster, missile[i]._misource, dam, missile[i]._mispllvl); } } else { AddMissile( missile[i]._mix, missile[i]._miy, missile[i]._misx, missile[i]._misy, i, MIS_LIGHTNING, missile[i]._micaster, missile[i]._misource, dam, missile[i]._mispllvl); } missile[i]._miVar1 = missile[i]._mix; missile[i]._miVar2 = missile[i]._miy; } } if (missile[i]._mirange == 0 || mx <= 0 || my <= 0 || mx >= MAXDUNX || my > MAXDUNY) { missile[i]._miDelFlag = TRUE; } } void MI_Lightning(int i) { int j; missile[i]._mirange--; j = missile[i]._mirange; if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._miHitFlag == TRUE) missile[i]._mirange = j; if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } PutMissile(i); } void MI_Town(int i) { int ExpLight[17] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15 }; int p; if (missile[i]._mirange > 1) missile[i]._mirange--; if (missile[i]._mirange == missile[i]._miVar1) SetMissDir(i, 1); if (currlevel != 0 && missile[i]._mimfnum != 1 && missile[i]._mirange != 0) { if (missile[i]._miVar2 == 0) missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, 1); ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar2]); missile[i]._miVar2++; } for (p = 0; p < MAX_PLRS; p++) { if (plr[p].plractive && currlevel == plr[p].plrlevel && !plr[p]._pLvlChanging && plr[p]._pmode == PM_STAND && plr[p]._px == missile[i]._mix && plr[p]._py == missile[i]._miy) { ClrPlrPath(p); if (p == myplr) { NetSendCmdParam1(TRUE, CMD_WARP, missile[i]._misource); plr[p]._pmode = PM_NEWLVL; } } } if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } PutMissile(i); } void MI_Flash(int i) { if (missile[i]._micaster == TARGET_MONSTERS) { if (missile[i]._misource != -1) plr[missile[i]._misource]._pInvincible = TRUE; } missile[i]._mirange--; CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix - 1, missile[i]._miy, TRUE); CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, TRUE); CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix + 1, missile[i]._miy, TRUE); CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix - 1, missile[i]._miy + 1, TRUE); CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy + 1, TRUE); CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix + 1, missile[i]._miy + 1, TRUE); if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; if (missile[i]._micaster == TARGET_MONSTERS) { if (missile[i]._misource != -1) plr[missile[i]._misource]._pInvincible = FALSE; } } PutMissile(i); } void MI_Flash2(int i) { if (missile[i]._micaster == TARGET_MONSTERS) { if (missile[i]._misource != -1) plr[missile[i]._misource]._pInvincible = TRUE; } missile[i]._mirange--; CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix - 1, missile[i]._miy - 1, TRUE); CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy - 1, TRUE); CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix + 1, missile[i]._miy - 1, TRUE); if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; if (missile[i]._micaster == TARGET_MONSTERS) { if (missile[i]._misource != -1) plr[missile[i]._misource]._pInvincible = FALSE; } } PutMissile(i); } void MI_Manashield(int i) { int id, diff; id = missile[i]._misource; missile[i]._mix = plr[id]._px; missile[i]._miy = plr[id]._py; missile[i]._mitxoff = plr[id]._pxoff << 16; missile[i]._mityoff = plr[id]._pyoff << 16; if (plr[id]._pmode == PM_WALK3) { missile[i]._misx = plr[id]._pfutx; missile[i]._misy = plr[id]._pfuty; } else { missile[i]._misx = plr[id]._px; missile[i]._misy = plr[id]._py; } GetMissilePos(i); if (plr[id]._pmode == PM_WALK3) { if (plr[id]._pdir == DIR_W) missile[i]._mix++; else missile[i]._miy++; } if (id != myplr) { if (currlevel != plr[id].plrlevel) missile[i]._miDelFlag = TRUE; } else { if (plr[id]._pMana <= 0 || !plr[id].plractive) missile[i]._mirange = 0; if (plr[id]._pHitPoints < missile[i]._miVar1) { diff = missile[i]._miVar1 - plr[id]._pHitPoints; #ifdef HELLFIRE int div = 0; for (int m = 0; m < missile[i]._mispllvl && m < 7; m++) { div += 3; } if (div > 0) diff -= diff / div; #else if (missile[i]._mispllvl > 0) { diff += diff / -3; } #endif if (diff < 0) diff = 0; drawmanaflag = TRUE; drawhpflag = TRUE; if (plr[id]._pMana >= diff) { plr[id]._pHitPoints = missile[i]._miVar1; plr[id]._pHPBase = missile[i]._miVar2; plr[id]._pMana -= diff; plr[id]._pManaBase -= diff; } else { #ifdef HELLFIRE plr[id]._pHitPoints += plr[id]._pMana - diff; plr[id]._pHPBase += plr[id]._pMana - diff; #else plr[id]._pHitPoints = plr[id]._pMana + missile[i]._miVar1 - diff; plr[id]._pHPBase = plr[id]._pMana + missile[i]._miVar2 - diff; #endif plr[id]._pMana = 0; plr[id]._pManaBase = plr[id]._pMaxManaBase - plr[id]._pMaxMana; missile[i]._mirange = 0; missile[i]._miDelFlag = TRUE; if (plr[id]._pHitPoints < 0) SetPlayerHitPoints(id, 0); if ((plr[id]._pHitPoints >> 6) == 0 && id == myplr) { SyncPlrKill(id, missile[i]._miVar8); } } } #ifndef HELLFIRE if (id == myplr && plr[id]._pHitPoints == 0 && missile[i]._miVar1 == 0 && plr[id]._pmode != PM_DEATH) { missile[i]._mirange = 0; missile[i]._miDelFlag = TRUE; SyncPlrKill(id, -1); } #endif missile[i]._miVar1 = plr[id]._pHitPoints; missile[i]._miVar2 = plr[id]._pHPBase; if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; NetSendCmd(TRUE, CMD_ENDSHIELD); } } PutMissile(i); } void MI_Etherealize(int i) { int src; missile[i]._mirange--; src = missile[i]._misource; missile[i]._mix = plr[src]._px; missile[i]._miy = plr[src]._py; missile[i]._mitxoff = plr[src]._pxoff << 16; missile[i]._mityoff = plr[src]._pyoff << 16; if (plr[src]._pmode == PM_WALK3) { missile[i]._misx = plr[src]._pfutx; missile[i]._misy = plr[src]._pfuty; } else { missile[i]._misx = plr[src]._px; missile[i]._misy = plr[src]._py; } GetMissilePos(i); if (plr[src]._pmode == PM_WALK3) { if (plr[src]._pdir == DIR_W) missile[i]._mix++; else missile[i]._miy++; } plr[src]._pSpellFlags |= 1; if (missile[i]._mirange == 0 || plr[src]._pHitPoints <= 0) { missile[i]._miDelFlag = TRUE; plr[src]._pSpellFlags &= ~0x1; } PutMissile(i); } void MI_Firemove(int i) { int j; int ExpLight[14] = { 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 12 }; missile[i]._mix--; missile[i]._miy--; missile[i]._miyoff += 32; missile[i]._miVar1++; if (missile[i]._miVar1 == missile[i]._miAnimLen) { SetMissDir(i, 1); missile[i]._miAnimFrame = random_(82, 11) + 1; } missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); j = missile[i]._mirange; CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._miHitFlag == TRUE) missile[i]._mirange = j; if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } if (missile[i]._mimfnum != 0 || missile[i]._mirange == 0) { if (missile[i]._mix != missile[i]._miVar3 || missile[i]._miy != missile[i]._miVar4) { missile[i]._miVar3 = missile[i]._mix; missile[i]._miVar4 = missile[i]._miy; // BUGFIX: Flame wave gets darker after reaching full height. // ChangeLightXY(missile[i]._mlid, missile[i]._miVar3, missile[i]._miVar4); ChangeLight(missile[i]._mlid, missile[i]._miVar3, missile[i]._miVar4, 8); } } else { if (missile[i]._miVar2 == 0) missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, ExpLight[0]); ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar2]); missile[i]._miVar2++; } missile[i]._mix++; missile[i]._miy++; missile[i]._miyoff -= 32; PutMissile(i); } void MI_Guardian(int i) { int j, k, sx, sy, sx1, sy1, ex; /// ASSERT: assert((DWORD)i < MAXMISSILES); #ifndef HELLFIRE sx1 = 0; sy1 = 0; #endif missile[i]._mirange--; if (missile[i]._miVar2 > 0) { missile[i]._miVar2--; } if (missile[i]._mirange == missile[i]._miVar1 || missile[i]._mimfnum == MFILE_GUARD && missile[i]._miVar2 == 0) { SetMissDir(i, 1); } if (!(missile[i]._mirange % 16)) { ex = 0; for (j = 0; j < 23 && ex != -1; j++) { for (k = 10; k >= 0 && ex != -1 && (vCrawlTable[j][k] != 0 || vCrawlTable[j][k + 1] != 0); k -= 2) { if (sx1 == vCrawlTable[j][k] && sy1 == vCrawlTable[j][k + 1]) { continue; } sx = missile[i]._mix + vCrawlTable[j][k]; sy = missile[i]._miy + vCrawlTable[j][k + 1]; ex = Sentfire(i, sx, sy); if (ex == -1) { break; } sx = missile[i]._mix - vCrawlTable[j][k]; sy = missile[i]._miy - vCrawlTable[j][k + 1]; ex = Sentfire(i, sx, sy); if (ex == -1) { break; } sx = missile[i]._mix + vCrawlTable[j][k]; sy = missile[i]._miy - vCrawlTable[j][k + 1]; ex = Sentfire(i, sx, sy); if (ex == -1) { break; } sx = missile[i]._mix - vCrawlTable[j][k]; sy = missile[i]._miy + vCrawlTable[j][k + 1]; ex = Sentfire(i, sx, sy); if (ex == -1) { break; } sx1 = vCrawlTable[j][k]; sy1 = vCrawlTable[j][k + 1]; } } } if (missile[i]._mirange == 14) { SetMissDir(i, 0); missile[i]._miAnimFrame = 15; missile[i]._miAnimAdd = -1; } missile[i]._miVar3 += missile[i]._miAnimAdd; if (missile[i]._miVar3 > 15) { missile[i]._miVar3 = 15; } else if (missile[i]._miVar3 > 0) { ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, missile[i]._miVar3); } if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } PutMissile(i); } void MI_Chain(int i) { int sx, sy, id, l, n, m, k, rad, tx, ty, dir; #ifndef HELLFIRE int CrawlNum[19] = { 0, 3, 12, 45, 94, 159, 240, 337, 450, 579, 724, 885, 1062, 1255, 1464, 1689, 1930, 2187, 2460 }; #endif id = missile[i]._misource; sx = missile[i]._mix; sy = missile[i]._miy; dir = GetDirection(sx, sy, missile[i]._miVar1, missile[i]._miVar2); AddMissile(sx, sy, missile[i]._miVar1, missile[i]._miVar2, dir, MIS_LIGHTCTRL, TARGET_MONSTERS, id, 1, missile[i]._mispllvl); rad = missile[i]._mispllvl + 3; if (rad > 19) rad = 19; for (m = 1; m < rad; m++) { k = CrawlNum[m]; l = k + 2; #ifdef HELLFIRE for (n = CrawlTable[k]; n > 0; n--) { // BUGFIX: should cast to BYTE or CrawlTable header will be wrong #else for (n = (BYTE)CrawlTable[k]; n > 0; n--) { #endif tx = sx + CrawlTable[l - 1]; ty = sy + CrawlTable[l]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY && dMonster[tx][ty] > 0) { dir = GetDirection(sx, sy, tx, ty); AddMissile(sx, sy, tx, ty, dir, MIS_LIGHTCTRL, TARGET_MONSTERS, id, 1, missile[i]._mispllvl); } l += 2; } } missile[i]._mirange--; if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; } void mi_null_11(int i) { missile[i]._mirange--; if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; if (missile[i]._miAnimFrame == missile[i]._miAnimLen) missile[i]._miPreFlag = TRUE; PutMissile(i); } void MI_Weapexp(int i) { int id, mind, maxd; int ExpLight[10] = { 9, 10, 11, 12, 11, 10, 8, 6, 4, 2 }; missile[i]._mirange--; id = missile[i]._misource; if (missile[i]._miVar2 == 1) { // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[id]._pIFMinDam; maxd = plr[id]._pIFMaxDam; missiledata[missile[i]._mitype].mResist = MISR_FIRE; } else { // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[id]._pILMinDam; maxd = plr[id]._pILMaxDam; missiledata[missile[i]._mitype].mResist = MISR_LIGHTNING; } CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._miVar1 == 0) { missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, 9); } else { if (missile[i]._mirange != 0) ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar1]); } missile[i]._miVar1++; if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } else { PutMissile(i); } } void MI_Misexp(int i) { #ifdef HELLFIRE int ExpLight[] = { 9, 10, 11, 12, 11, 10, 8, 6, 4, 2, 1, 0, 0, 0, 0 }; #else int ExpLight[10] = { 9, 10, 11, 12, 11, 10, 8, 6, 4, 2 }; #endif missile[i]._mirange--; if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } else { if (missile[i]._miVar1 == 0) missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, 9); else ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar1]); missile[i]._miVar1++; PutMissile(i); } } void MI_Acidsplat(int i) { int monst, dam; if (missile[i]._mirange == missile[i]._miAnimLen) { missile[i]._mix++; missile[i]._miy++; missile[i]._miyoff -= 32; } missile[i]._mirange--; if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; monst = missile[i]._misource; dam = (monster[monst].MData->mLevel >= 2 ? 2 : 1); AddMissile(missile[i]._mix, missile[i]._miy, i, 0, missile[i]._mimfnum, MIS_ACIDPUD, TARGET_PLAYERS, monst, dam, missile[i]._mispllvl); } else { PutMissile(i); } } void MI_Teleport(int i) { int id; id = missile[i]._misource; missile[i]._mirange--; if (missile[i]._mirange <= 0) { missile[i]._miDelFlag = TRUE; } else { dPlayer[plr[id]._px][plr[id]._py] = 0; PlrClrTrans(plr[id]._px, plr[id]._py); plr[id]._px = missile[i]._mix; plr[id]._py = missile[i]._miy; plr[id]._pfutx = plr[id]._px; plr[id]._pfuty = plr[id]._py; plr[id]._poldx = plr[id]._px; plr[id]._poldy = plr[id]._py; PlrDoTrans(plr[id]._px, plr[id]._py); missile[i]._miVar1 = 1; dPlayer[plr[id]._px][plr[id]._py] = id + 1; if (leveltype != DTYPE_TOWN) { ChangeLightXY(plr[id]._plid, plr[id]._px, plr[id]._py); ChangeVisionXY(plr[id]._pvid, plr[id]._px, plr[id]._py); } if (id == myplr) { ViewX = plr[id]._px - ScrollInfo._sdx; ViewY = plr[id]._py - ScrollInfo._sdy; } } } void MI_Stone(int i) { int m; missile[i]._mirange--; m = missile[i]._miVar2; if (monster[m]._mhitpoints == 0 && missile[i]._miAnimType != MFILE_SHATTER1) { #ifndef HELLFIRE missile[i]._mimfnum = 0; missile[i]._miDrawFlag = TRUE; #endif SetMissAnim(i, MFILE_SHATTER1); missile[i]._mirange = 11; } if (monster[m]._mmode != MM_STONE) { missile[i]._miDelFlag = TRUE; return; } if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; if (monster[m]._mhitpoints > 0) monster[m]._mmode = missile[i]._miVar1; else AddDead(monster[m]._mx, monster[m]._my, stonendx, (direction)monster[m]._mdir); } if (missile[i]._miAnimType == MFILE_SHATTER1) PutMissile(i); } void MI_Boom(int i) { missile[i]._mirange--; if (missile[i]._miVar1 == 0) CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, TRUE); if (missile[i]._miHitFlag == TRUE) missile[i]._miVar1 = 1; if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; PutMissile(i); } void MI_Rhino(int i) { int mix, miy, mix2, miy2, omx, omy, monst; monst = missile[i]._misource; if (monster[monst]._mmode != MM_CHARGE) { missile[i]._miDelFlag = TRUE; return; } GetMissilePos(i); mix = missile[i]._mix; miy = missile[i]._miy; dMonster[mix][miy] = 0; if (monster[monst]._mAi == AI_SNAKE) { missile[i]._mitxoff += 2 * missile[i]._mixvel; missile[i]._mityoff += 2 * missile[i]._miyvel; GetMissilePos(i); mix2 = missile[i]._mix; miy2 = missile[i]._miy; missile[i]._mitxoff -= missile[i]._mixvel; missile[i]._mityoff -= missile[i]._miyvel; } else { missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; } GetMissilePos(i); omx = missile[i]._mix; omy = missile[i]._miy; if (!PosOkMonst(monst, missile[i]._mix, missile[i]._miy) || (monster[monst]._mAi == AI_SNAKE && !PosOkMonst(monst, mix2, miy2))) { MissToMonst(i, mix, miy); missile[i]._miDelFlag = TRUE; return; } monster[monst]._mfutx = omx; monster[monst]._moldx = omx; dMonster[omx][omy] = -1 - monst; monster[monst]._mx = omx; monster[monst]._mfuty = omy; monster[monst]._moldy = omy; monster[monst]._my = omy; if (monster[monst]._uniqtype != 0) ChangeLightXY(missile[i]._mlid, omx, omy); MoveMissilePos(i); PutMissile(i); } void mi_null_32(int i) { int src, enemy, ax, ay, bx, by, cx, cy, j; GetMissilePos(i); ax = missile[i]._mix; ay = missile[i]._miy; missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); src = missile[i]._misource; bx = missile[i]._mix; by = missile[i]._miy; enemy = monster[src]._menemy; if (!(monster[src]._mFlags & MFLAG_TARGETS_MONSTER)) { cx = plr[enemy]._px; cy = plr[enemy]._py; } else { cx = monster[enemy]._mx; cy = monster[enemy]._my; } if ((bx != ax || by != ay) && (missile[i]._miVar1 & 1 && (abs(ax - cx) >= 4 || abs(ay - cy) >= 4) || missile[i]._miVar2 > 1) && PosOkMonst(missile[i]._misource, ax, ay)) { MissToMonst(i, ax, ay); missile[i]._miDelFlag = TRUE; } else if (!(monster[src]._mFlags & MFLAG_TARGETS_MONSTER)) { j = dPlayer[bx][by]; } else { j = dMonster[bx][by]; } if (!PosOkMissile(bx, by) || j > 0 && !(missile[i]._miVar1 & 1)) { missile[i]._mixvel *= -1; missile[i]._miyvel *= -1; missile[i]._mimfnum = opposite[missile[i]._mimfnum]; missile[i]._miAnimData = monster[src].MType->Anims[MA_WALK].Data[missile[i]._mimfnum]; missile[i]._miVar2++; if (j > 0) missile[i]._miVar1 |= 1; } MoveMissilePos(i); PutMissile(i); } void MI_FirewallC(int i) { int tx, ty, id, dp, micaster; missile[i]._mirange--; id = missile[i]._misource; if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; } else { #ifdef HELLFIRE micaster = TARGET_BOTH; #else micaster = TARGET_MONSTERS; #endif dp = dPiece[missile[i]._miVar1][missile[i]._miVar2]; assert(dp <= MAXTILES && dp >= 0); tx = missile[i]._miVar1 + XDirAdd[missile[i]._miVar3]; ty = missile[i]._miVar2 + YDirAdd[missile[i]._miVar3]; if (!nMissileTable[dp] && missile[i]._miVar8 == 0 && tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { AddMissile(missile[i]._miVar1, missile[i]._miVar2, missile[i]._miVar1, missile[i]._miVar2, plr[id]._pdir, MIS_FIREWALL, micaster, id, 0, missile[i]._mispllvl); missile[i]._miVar1 = tx; missile[i]._miVar2 = ty; } else { missile[i]._miVar8 = 1; } dp = dPiece[missile[i]._miVar5][missile[i]._miVar6]; assert(dp <= MAXTILES && dp >= 0); tx = missile[i]._miVar5 + XDirAdd[missile[i]._miVar4]; ty = missile[i]._miVar6 + YDirAdd[missile[i]._miVar4]; if (!nMissileTable[dp] && missile[i]._miVar7 == 0 && tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { AddMissile(missile[i]._miVar5, missile[i]._miVar6, missile[i]._miVar5, missile[i]._miVar6, plr[id]._pdir, MIS_FIREWALL, micaster, id, 0, missile[i]._mispllvl); missile[i]._miVar5 = tx; missile[i]._miVar6 = ty; } else { missile[i]._miVar7 = 1; } } } void MI_Infra(int i) { missile[i]._mirange--; plr[missile[i]._misource]._pInfraFlag = TRUE; if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; CalcPlrItemVals(missile[i]._misource, TRUE); } } void MI_Apoca(int i) { int j, k, id; BOOL exit; id = missile[i]._misource; exit = FALSE; for (j = missile[i]._miVar2; j < missile[i]._miVar3 && !exit; j++) { for (k = missile[i]._miVar4; k < missile[i]._miVar5 && !exit; k++) { // BUGFIX: was `dMonster[k][j] > MAX_PLRS-1`, should be `dMonster[k][j]-1 >= MAX_PLRS`. if (dMonster[k][j] > MAX_PLRS - 1 && !nSolidTable[dPiece[k][j]]) { #ifdef HELLFIRE if (LineClear(missile[i]._mix, missile[i]._miy, k, j)) { AddMissile(k, j, k, j, plr[id]._pdir, MIS_BOOM, TARGET_MONSTERS, id, missile[i]._midam, 0); exit = TRUE; } #else AddMissile(k, j, k, j, plr[id]._pdir, MIS_BOOM, TARGET_MONSTERS, id, missile[i]._midam, 0); exit = TRUE; #endif } } if (!exit) { missile[i]._miVar4 = missile[i]._miVar6; } } if (exit == TRUE) { missile[i]._miVar2 = j - 1; missile[i]._miVar4 = k; } else { missile[i]._miDelFlag = TRUE; } } void MI_Wave(int i) { int sx, sy, sd, nxa, nxb, nya, nyb, dira, dirb; int j, id, pn; BOOL f1, f2; int v1, v2; f1 = FALSE; f2 = FALSE; /// ASSERT: assert((DWORD)i < MAXMISSILES); id = missile[i]._misource; sx = missile[i]._mix; sy = missile[i]._miy; v1 = missile[i]._miVar1; v2 = missile[i]._miVar2; sd = GetDirection(sx, sy, v1, v2); dira = (sd - 2) & 7; dirb = (sd + 2) & 7; nxa = sx + XDirAdd[sd]; nya = sy + YDirAdd[sd]; pn = dPiece[nxa][nya]; /// ASSERT: assert((DWORD)pn <= MAXTILES); if (!nMissileTable[pn]) { AddMissile(nxa, nya, nxa + XDirAdd[sd], nya + YDirAdd[sd], plr[id]._pdir, MIS_FIREMOVE, TARGET_MONSTERS, id, 0, missile[i]._mispllvl); nxa += XDirAdd[dira]; nya += YDirAdd[dira]; nxb = sx + XDirAdd[sd] + XDirAdd[dirb]; nyb = sy + YDirAdd[sd] + YDirAdd[dirb]; for (j = 0; j < (missile[i]._mispllvl >> 1) + 2; j++) { pn = dPiece[nxa][nya]; // BUGFIX: dPiece is accessed before check against dungeon size and 0 /// ASSERT: assert((DWORD)pn <= MAXTILES); if (nMissileTable[pn] || f1 || nxa <= 0 || nxa >= MAXDUNX || nya <= 0 || nya >= MAXDUNY) { f1 = TRUE; } else { AddMissile(nxa, nya, nxa + XDirAdd[sd], nya + YDirAdd[sd], plr[id]._pdir, MIS_FIREMOVE, TARGET_MONSTERS, id, 0, missile[i]._mispllvl); nxa += XDirAdd[dira]; nya += YDirAdd[dira]; } pn = dPiece[nxb][nyb]; // BUGFIX: dPiece is accessed before check against dungeon size and 0 /// ASSERT: assert((DWORD)pn <= MAXTILES); if (nMissileTable[pn] || f2 || nxb <= 0 || nxb >= MAXDUNX || nyb <= 0 || nyb >= MAXDUNY) { f2 = TRUE; } else { AddMissile(nxb, nyb, nxb + XDirAdd[sd], nyb + YDirAdd[sd], plr[id]._pdir, MIS_FIREMOVE, TARGET_MONSTERS, id, 0, missile[i]._mispllvl); nxb += XDirAdd[dirb]; nyb += YDirAdd[dirb]; } } } missile[i]._mirange--; if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; } void MI_Nova(int i) { int k, id, sx, sy, dir, en, sx1, sy1, dam; sx1 = 0; sy1 = 0; id = missile[i]._misource; dam = missile[i]._midam; sx = missile[i]._mix; sy = missile[i]._miy; if (id != -1) { dir = plr[id]._pdir; en = TARGET_MONSTERS; } else { dir = 0; en = TARGET_PLAYERS; } for (k = 0; k < 23; k++) { if (sx1 != vCrawlTable[k][6] || sy1 != vCrawlTable[k][7]) { AddMissile(sx, sy, sx + vCrawlTable[k][6], sy + vCrawlTable[k][7], dir, MIS_LIGHTBALL, en, id, dam, missile[i]._mispllvl); AddMissile(sx, sy, sx - vCrawlTable[k][6], sy - vCrawlTable[k][7], dir, MIS_LIGHTBALL, en, id, dam, missile[i]._mispllvl); AddMissile(sx, sy, sx - vCrawlTable[k][6], sy + vCrawlTable[k][7], dir, MIS_LIGHTBALL, en, id, dam, missile[i]._mispllvl); AddMissile(sx, sy, sx + vCrawlTable[k][6], sy - vCrawlTable[k][7], dir, MIS_LIGHTBALL, en, id, dam, missile[i]._mispllvl); sx1 = vCrawlTable[k][6]; sy1 = vCrawlTable[k][7]; } } missile[i]._mirange--; if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; } #ifdef HELLFIRE void MI_Blodboil(int i) { int lvl, id, hpdif; missile[i]._mirange--; if (missile[i]._mirange == 0) { id = missile[i]._miVar1; if ((plr[id]._pSpellFlags & 2) == 2) { int blodboilSFX[NUM_CLASSES] = { PS_WARR72, #ifndef SPAWN PS_ROGUE72, PS_MAGE72, PS_MAGE72, PS_ROGUE72, #else 0, 0, 0, 0, #endif PS_WARR72 }; plr[id]._pSpellFlags &= ~0x2; plr[id]._pSpellFlags |= 4; if (2 * (id > 0)) // BUGFIX, wrong order of operation, this should be `2 * lvl` after the else. lvl = plr[id]._pLevel; else lvl = 1; missile[i]._mirange = lvl + 10 * missile[i]._mispllvl + 245; hpdif = plr[id]._pMaxHP - plr[id]._pHitPoints; CalcPlrItemVals(id, TRUE); plr[id]._pHitPoints -= hpdif; if (plr[id]._pHitPoints < 64) plr[id]._pHitPoints = 64; force_redraw = 255; PlaySfxLoc(blodboilSFX[plr[id]._pClass], plr[id]._px, plr[id]._py); } else { int blodboilSFX[NUM_CLASSES] = { PS_WARR72, #ifndef SPAWN PS_ROGUE72, PS_MAGE72, PS_MAGE72, PS_ROGUE72, #else 0, 0, 0, 0, #endif PS_WARR72 }; missile[i]._miDelFlag = TRUE; plr[id]._pSpellFlags &= ~0x4; hpdif = plr[id]._pMaxHP - plr[id]._pHitPoints; CalcPlrItemVals(id, TRUE); plr[id]._pHitPoints -= hpdif + missile[i]._miVar2; if (plr[id]._pHitPoints < 64) plr[id]._pHitPoints = 64; force_redraw = 255; PlaySfxLoc(blodboilSFX[plr[id]._pClass], plr[id]._px, plr[id]._py); } } } #else void MI_Blodboil(int i) { missile[i]._miDelFlag = TRUE; } #endif void MI_Flame(int i) { int k; missile[i]._mirange--; missile[i]._miVar2--; k = missile[i]._mirange; CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._mirange == 0 && missile[i]._miHitFlag == TRUE) missile[i]._mirange = k; if (missile[i]._miVar2 == 0) missile[i]._miAnimFrame = 20; if (missile[i]._miVar2 <= 0) { k = missile[i]._miAnimFrame; if (k > 11) k = 24 - k; ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, k); } if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } if (missile[i]._miVar2 <= 0) PutMissile(i); } void MI_Flamec(int i) { int id, src; missile[i]._mirange--; src = missile[i]._misource; missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) { id = dPiece[missile[i]._mix][missile[i]._miy]; if (!nMissileTable[id]) { AddMissile( missile[i]._mix, missile[i]._miy, missile[i]._misx, missile[i]._misy, i, MIS_FLAME, missile[i]._micaster, src, missile[i]._miVar3, missile[i]._mispllvl); } else { missile[i]._mirange = 0; } missile[i]._miVar1 = missile[i]._mix; missile[i]._miVar2 = missile[i]._miy; missile[i]._miVar3++; } if (missile[i]._mirange == 0 || missile[i]._miVar3 == 3) missile[i]._miDelFlag = TRUE; } void MI_Cbolt(int i) { int md; int bpath[16] = { -1, 0, 1, -1, 0, 1, -1, -1, 0, 0, 1, 1, 0, 1, -1, 0 }; missile[i]._mirange--; if (missile[i]._miAnimType != MFILE_LGHNING) { if (missile[i]._miVar3 == 0) { md = (missile[i]._miVar2 + bpath[missile[i]._mirnd]) & 7; missile[i]._mirnd = (missile[i]._mirnd + 1) & 0xF; GetMissileVel(i, missile[i]._mix, missile[i]._miy, missile[i]._mix + XDirAdd[md], missile[i]._miy + YDirAdd[md], 8); missile[i]._miVar3 = 16; } else { missile[i]._miVar3--; } missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._miHitFlag == TRUE) { missile[i]._miVar1 = 8; missile[i]._mimfnum = 0; missile[i]._mixoff = 0; missile[i]._miyoff = 0; SetMissAnim(i, MFILE_LGHNING); missile[i]._mirange = missile[i]._miAnimLen; GetMissilePos(i); } ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, missile[i]._miVar1); } if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } PutMissile(i); } void MI_Hbolt(int i) { int dam; missile[i]._mirange--; if (missile[i]._miAnimType != MFILE_HOLYEXPL) { missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); dam = missile[i]._midam; if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) { CheckMissileCol(i, dam, dam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); } if (missile[i]._mirange == 0) { missile[i]._mitxoff -= missile[i]._mixvel; missile[i]._mityoff -= missile[i]._miyvel; GetMissilePos(i); missile[i]._mimfnum = 0; SetMissAnim(i, MFILE_HOLYEXPL); missile[i]._mirange = missile[i]._miAnimLen - 1; } else { if (missile[i]._mix != missile[i]._miVar1 || missile[i]._miy != missile[i]._miVar2) { missile[i]._miVar1 = missile[i]._mix; missile[i]._miVar2 = missile[i]._miy; ChangeLight(missile[i]._mlid, missile[i]._miVar1, missile[i]._miVar2, 8); } } } else { ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, missile[i]._miAnimFrame + 7); if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } } PutMissile(i); } void MI_Element(int i) { int mid, sd, dam, cx, cy, px, py, id; missile[i]._mirange--; dam = missile[i]._midam; id = missile[i]._misource; if (missile[i]._miAnimType == MFILE_BIGEXP) { cx = missile[i]._mix; cy = missile[i]._miy; px = plr[id]._px; py = plr[id]._py; ChangeLight(missile[i]._mlid, cx, cy, missile[i]._miAnimFrame); if (!CheckBlock(px, py, cx, cy)) CheckMissileCol(i, dam, dam, TRUE, cx, cy, TRUE); if (!CheckBlock(px, py, cx, cy + 1)) CheckMissileCol(i, dam, dam, TRUE, cx, cy + 1, TRUE); if (!CheckBlock(px, py, cx, cy - 1)) CheckMissileCol(i, dam, dam, TRUE, cx, cy - 1, TRUE); if (!CheckBlock(px, py, cx + 1, cy)) CheckMissileCol(i, dam, dam, TRUE, cx + 1, cy, TRUE); /* check x/y */ if (!CheckBlock(px, py, cx + 1, cy - 1)) CheckMissileCol(i, dam, dam, TRUE, cx + 1, cy - 1, TRUE); if (!CheckBlock(px, py, cx + 1, cy + 1)) CheckMissileCol(i, dam, dam, TRUE, cx + 1, cy + 1, TRUE); if (!CheckBlock(px, py, cx - 1, cy)) CheckMissileCol(i, dam, dam, TRUE, cx - 1, cy, TRUE); if (!CheckBlock(px, py, cx - 1, cy + 1)) CheckMissileCol(i, dam, dam, TRUE, cx - 1, cy + 1, TRUE); if (!CheckBlock(px, py, cx - 1, cy - 1)) CheckMissileCol(i, dam, dam, TRUE, cx - 1, cy - 1, TRUE); if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } } else { missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); cx = missile[i]._mix; cy = missile[i]._miy; CheckMissileCol(i, dam, dam, FALSE, cx, cy, FALSE); if (missile[i]._miVar3 == 0 && cx == missile[i]._miVar4 && cy == missile[i]._miVar5) missile[i]._miVar3 = 1; if (missile[i]._miVar3 == 1) { missile[i]._miVar3 = 2; missile[i]._mirange = 255; // BUGFIX: should be `mid >= 0`, was `mid > 0`; FindClosest returns -1 if no monster is found. mid = FindClosest(cx, cy, 19); if (mid > 0) { sd = GetDirection8(cx, cy, monster[mid]._mx, monster[mid]._my); SetMissDir(i, sd); GetMissileVel(i, cx, cy, monster[mid]._mx, monster[mid]._my, 16); } else { sd = plr[id]._pdir; SetMissDir(i, sd); GetMissileVel(i, cx, cy, cx + XDirAdd[sd], cy + YDirAdd[sd], 16); } } if (cx != missile[i]._miVar1 || cy != missile[i]._miVar2) { missile[i]._miVar1 = cx; missile[i]._miVar2 = cy; ChangeLight(missile[i]._mlid, cx, cy, 8); } if (missile[i]._mirange == 0) { missile[i]._mimfnum = 0; SetMissAnim(i, MFILE_BIGEXP); missile[i]._mirange = missile[i]._miAnimLen - 1; } } PutMissile(i); } void MI_Bonespirit(int i) { int id, mid, sd, dam; int cx, cy; missile[i]._mirange--; dam = missile[i]._midam; id = missile[i]._misource; if (missile[i]._mimfnum == 8) { ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, missile[i]._miAnimFrame); if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } PutMissile(i); } else { missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); cx = missile[i]._mix; cy = missile[i]._miy; CheckMissileCol(i, dam, dam, FALSE, cx, cy, FALSE); if (missile[i]._miVar3 == 0 && cx == missile[i]._miVar4 && cy == missile[i]._miVar5) missile[i]._miVar3 = 1; if (missile[i]._miVar3 == 1) { missile[i]._miVar3 = 2; missile[i]._mirange = 255; // BUGFIX: should be `mid >= 0`, was `mid > 0`; FindClosest returns -1 if no monster is found. mid = FindClosest(cx, cy, 19); if (mid > 0) { missile[i]._midam = monster[mid]._mhitpoints >> 7; SetMissDir(i, GetDirection8(cx, cy, monster[mid]._mx, monster[mid]._my)); GetMissileVel(i, cx, cy, monster[mid]._mx, monster[mid]._my, 16); } else { sd = plr[id]._pdir; SetMissDir(i, sd); GetMissileVel(i, cx, cy, cx + XDirAdd[sd], cy + YDirAdd[sd], 16); } } if (cx != missile[i]._miVar1 || cy != missile[i]._miVar2) { missile[i]._miVar1 = cx; missile[i]._miVar2 = cy; ChangeLight(missile[i]._mlid, cx, cy, 8); } if (missile[i]._mirange == 0) { SetMissDir(i, 8); missile[i]._mirange = 7; } PutMissile(i); } } void MI_ResurrectBeam(int i) { missile[i]._mirange--; if (missile[i]._mirange == 0) missile[i]._miDelFlag = TRUE; PutMissile(i); } void MI_Rportal(int i) { int ExpLight[17] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15 }; if (missile[i]._mirange > 1) missile[i]._mirange--; if (missile[i]._mirange == missile[i]._miVar1) SetMissDir(i, 1); if (currlevel != 0 && missile[i]._mimfnum != 1 && missile[i]._mirange != 0) { if (missile[i]._miVar2 == 0) missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, 1); ChangeLight(missile[i]._mlid, missile[i]._mix, missile[i]._miy, ExpLight[missile[i]._miVar2]); missile[i]._miVar2++; } if (missile[i]._mirange == 0) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); } PutMissile(i); } void ProcessMissiles() { int i, mi; for (i = 0; i < nummissiles; i++) { dFlags[missile[missileactive[i]]._mix][missile[missileactive[i]]._miy] &= ~BFLAG_MISSILE; dMissile[missile[missileactive[i]]._mix][missile[missileactive[i]]._miy] = 0; #ifdef HELLFIRE if (missile[missileactive[i]]._mix < 0 || missile[missileactive[i]]._mix >= MAXDUNX - 1 || missile[missileactive[i]]._miy < 0 || missile[missileactive[i]]._miy >= MAXDUNY - 1) missile[missileactive[i]]._miDelFlag = TRUE; #endif } i = 0; while (i < nummissiles) { if (missile[missileactive[i]]._miDelFlag) { DeleteMissile(missileactive[i], i); i = 0; } else { i++; } } MissilePreFlag = FALSE; ManashieldFlag = FALSE; for (i = 0; i < nummissiles; i++) { mi = missileactive[i]; missiledata[missile[mi]._mitype].mProc(missileactive[i]); if (!(missile[mi]._miAnimFlags & MFLAG_LOCK_ANIMATION)) { missile[mi]._miAnimCnt++; if (missile[mi]._miAnimCnt >= missile[mi]._miAnimDelay) { missile[mi]._miAnimCnt = 0; missile[mi]._miAnimFrame += missile[mi]._miAnimAdd; if (missile[mi]._miAnimFrame > missile[mi]._miAnimLen) missile[mi]._miAnimFrame = 1; if (missile[mi]._miAnimFrame < 1) missile[mi]._miAnimFrame = missile[mi]._miAnimLen; } } } if (ManashieldFlag) { for (i = 0; i < nummissiles; i++) { if (missile[missileactive[i]]._mitype == MIS_MANASHIELD) { MI_Manashield(missileactive[i]); } } } i = 0; while (i < nummissiles) { #ifdef HELLFIRE if (missile[missileactive[i]]._miDelFlag == TRUE) { #else if (missile[missileactive[i]]._miDelFlag) { #endif DeleteMissile(missileactive[i], i); i = 0; } else { i++; } } } void missiles_process_charge() { CMonster *mon; AnimStruct *anim; MissileStruct *mis; int i, mi; for (i = 0; i < nummissiles; i++) { mi = missileactive[i]; mis = &missile[mi]; mis->_miAnimData = misfiledata[mis->_miAnimType].mAnimData[mis->_mimfnum]; if (mis->_mitype == MIS_RHINO) { mon = monster[mis->_misource].MType; if (mon->mtype >= MT_HORNED && mon->mtype <= MT_OBLORD) { anim = &mon->Anims[MA_SPECIAL]; } else { if (mon->mtype >= MT_NSNAKE && mon->mtype <= MT_GSNAKE) anim = &mon->Anims[MA_ATTACK]; else anim = &mon->Anims[MA_WALK]; } missile[mi]._miAnimData = anim->Data[mis->_mimfnum]; } } } void ClearMissileSpot(int mi) { dFlags[missile[mi]._mix][missile[mi]._miy] &= ~BFLAG_MISSILE; dMissile[missile[mi]._mix][missile[mi]._miy] = 0; } ================================================ FILE: Source/missiles.h ================================================ /** * @file missiles.h * * Interface of missile functionality. */ #ifndef __MISSILES_H__ #define __MISSILES_H__ extern int missileactive[MAXMISSILES]; extern int missileavail[MAXMISSILES]; extern MissileStruct missile[MAXMISSILES]; extern int nummissiles; extern BOOL MissilePreFlag; void GetDamageAmt(int i, int *mind, int *maxd); int GetSpellLevel(int id, int sn); void DeleteMissile(int mi, int i); BOOL MonsterTrapHit(int m, int mindam, int maxdam, int dist, int t, BOOLEAN shift); BOOL PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, BOOLEAN shift, int earflag #ifdef HELLFIRE , BOOLEAN *blocked #endif ); void SetMissAnim(int mi, int animtype); void SetMissDir(int mi, int dir); void LoadMissileGFX(BYTE mi); void InitMissileGFX(); void FreeMissiles(); void FreeMissiles2(); void InitMissiles(); #ifdef HELLFIRE void missiles_hive_explosion(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_fire_rune(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_light_rune(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_great_light_rune(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_immolation_rune(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_stone_rune(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_reflection(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_berserk(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_hork_spawn(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_jester(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_steal_pots(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_mana_trap(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_spec_arrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_warp(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_light_wall(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_rune_explosion(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_immo_1(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_immo_2(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_larrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_43303D(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_433040(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_rech_mana(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_magi(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_ring(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_search(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_cbolt_arrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void missiles_hbolt_arrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddBlodboil(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); #endif void AddLArrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddArrow(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddRndTeleport(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddFirebolt(int mi, int sx, int sy, int dx, int dy, int midir, char micaster, int id, int dam); void AddMagmaball(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void miss_null_33(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddTeleport(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddLightball(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddFirewall(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddFireball(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddLightctrl(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddLightning(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddMisexp(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddWeapexp(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddTown(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddFlash(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddFlash2(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddManashield(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddFiremove(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddGuardian(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddChain(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void miss_null_11(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void miss_null_12(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void miss_null_13(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddRhino(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void miss_null_32(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddFlare(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddAcid(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void miss_null_1D(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddAcidpud(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddStone(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddGolem(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddEtherealize(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void miss_null_1F(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void miss_null_23(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddBoom(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddHeal(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddHealOther(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddElement(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddIdentify(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddFirewallC(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddInfra(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddWave(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddNova(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddBlodboil(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddRepair(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddRecharge(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddDisarm(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddApoca(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddFlame(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddFlamec(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddCbolt(int mi, int sx, int sy, int dx, int dy, int midir, char micaster, int id, int dam); void AddHbolt(int mi, int sx, int sy, int dx, int dy, int midir, char micaster, int id, int dam); void AddResurrect(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddResurrectBeam(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddTelekinesis(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddBoneSpirit(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddRportal(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); void AddDiabApoca(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, int id, int dam); int AddMissile(int sx, int sy, int dx, int dy, int midir, int mitype, char micaster, int id, int midam, int spllvl); void MI_Dummy(int i); void MI_Golem(int i); void MI_SetManashield(int i); void MI_LArrow(int i); void MI_Arrow(int i); void MI_Firebolt(int i); void MI_Lightball(int i); void mi_null_33(int i); void MI_Acidpud(int i); void MI_Firewall(int i); void MI_Fireball(int i); #ifdef HELLFIRE void mi_hork_spawn(int i); void MI_Rune(int i); void mi_light_wall(int i); void mi_hive_explode(int i); void mi_immolation(int i); void mi_light_arrow(int i); void mi_flashfr(int i); void mi_flashbk(int i); void mi_reflect(int i); void mi_fire_ring(int i); void mi_light_ring(int i); void mi_search(int i); void mi_lightning_wall(int i); void mi_fire_nova(int i); void mi_spec_arrow(int i); #endif void MI_Lightctrl(int i); void MI_Lightning(int i); void MI_Town(int i); void MI_Flash(int i); void MI_Flash2(int i); void MI_Etherealize(int i); void MI_Firemove(int i); void MI_Guardian(int i); void MI_Chain(int i); void mi_null_11(int i); void MI_Weapexp(int i); void MI_Misexp(int i); void MI_Acidsplat(int i); void MI_Teleport(int i); void MI_Stone(int i); void MI_Boom(int i); void MI_Rhino(int i); void mi_null_32(int i); void MI_FirewallC(int i); void MI_Infra(int i); void MI_Apoca(int i); void MI_Wave(int i); void MI_Nova(int i); void MI_Blodboil(int i); void MI_Flame(int i); void MI_Flamec(int i); void MI_Cbolt(int i); void MI_Hbolt(int i); void MI_Element(int i); void MI_Bonespirit(int i); void MI_ResurrectBeam(int i); void MI_Rportal(int i); void ProcessMissiles(); void missiles_process_charge(); void ClearMissileSpot(int mi); #endif /* __MISSILES_H__ */ ================================================ FILE: Source/monstdat.cpp ================================================ /** * @file monstdat.cpp * * Implementation of all monster data. */ #include "all.h" /** Contains the data related to each monster ID. */ MonsterData monsterdata[] = { // clang-format off // width, mImage, GraphicType, has_special, sndfile, snd_special, has_trans, TransFile, Frames[6], Rate[6], mName, mMinDLvl, mMaxDLvl, mLevel, mMinHP, mMaxHP, mAi, mFlags , mInt, mHit, mAFNum, mMinDamage, mMaxDamage, mHit2, mAFNum2, mMinDamage2, mMaxDamage2, mArmorClass, mMonstClass, mMagicRes , mMagicRes2 , mTreasure, mSelFlag, mExp { 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", FALSE, "Monsters\\Zombie\\Zombie%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 54 }, { 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", FALSE, "Monsters\\Zombie\\Zombie%c%i.WAV", FALSE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 58 }, { 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", FALSE, "Monsters\\Zombie\\Zombie%c%i.WAV", FALSE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, 0, 3, 136 }, { 128, 799, "Monsters\\Zombie\\Zombie%c.CL2", FALSE, "Monsters\\Zombie\\Zombie%c%i.WAV", FALSE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 240 }, { 128, 543, "Monsters\\FalSpear\\Phall%c.CL2", TRUE, "Monsters\\FalSpear\\Phall%c%i.WAV", TRUE, TRUE, "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", TRUE, "Monsters\\FalSpear\\Phall%c%i.WAV", TRUE, TRUE, "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", TRUE, "Monsters\\FalSpear\\Phall%c%i.WAV", TRUE, FALSE, 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 , RESIST_FIRE , 0, 3, 155 }, { 128, 543, "Monsters\\FalSpear\\Phall%c.CL2", TRUE, "Monsters\\FalSpear\\Phall%c%i.WAV", TRUE, TRUE, "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, IMMUNE_NULL_40, RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 255 }, { 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", TRUE, "Monsters\\SkelAxe\\SklAx%c%i.WAV", FALSE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 64 }, { 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", TRUE, "Monsters\\SkelAxe\\SklAx%c%i.WAV", FALSE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 68 }, { 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", TRUE, "Monsters\\SkelAxe\\SklAx%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, 0, 3, 154 }, { 128, 553, "Monsters\\SkelAxe\\SklAx%c.CL2", TRUE, "Monsters\\SkelAxe\\SklAx%c%i.WAV", FALSE, TRUE, "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, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 264 }, { 128, 623, "Monsters\\FalSword\\Fall%c.CL2", TRUE, "Monsters\\FalSword\\Fall%c%i.WAV", TRUE, TRUE, "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", TRUE, "Monsters\\FalSword\\Fall%c%i.WAV", TRUE, TRUE, "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", TRUE, "Monsters\\FalSword\\Fall%c%i.WAV", TRUE, FALSE, 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 , RESIST_FIRE , 0, 3, 180 }, { 128, 623, "Monsters\\FalSword\\Fall%c.CL2", TRUE, "Monsters\\FalSword\\Fall%c%i.WAV", TRUE, TRUE, "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, IMMUNE_NULL_40, RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 280 }, { 128, 410, "Monsters\\Scav\\Scav%c.CL2", TRUE, "Monsters\\Scav\\Scav%c%i.WAV", FALSE, FALSE, 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 , RESIST_FIRE , 0, 3, 80 }, { 128, 410, "Monsters\\Scav\\Scav%c.CL2", TRUE, "Monsters\\Scav\\Scav%c%i.WAV", FALSE, TRUE, "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 , RESIST_LIGHTNING , 0, 3, 188 }, { 128, 410, "Monsters\\Scav\\Scav%c.CL2", TRUE, "Monsters\\Scav\\Scav%c%i.WAV", FALSE, TRUE, "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, IMMUNE_NULL_40, RESIST_FIRE | IMMUNE_NULL_40, 0, 3, 375 }, { 128, 410, "Monsters\\Scav\\Scav%c.CL2", TRUE, "Monsters\\Scav\\Scav%c%i.WAV", FALSE, TRUE, "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, RESIST_MAGIC | IMMUNE_NULL_40, RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 552 }, { 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", TRUE, "Monsters\\SkelBow\\SklBw%c%i.WAV", FALSE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 110 }, { 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", TRUE, "Monsters\\SkelBow\\SklBw%c%i.WAV", FALSE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 210 }, { 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", TRUE, "Monsters\\SkelBow\\SklBw%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, 0, 3, 364 }, { 128, 567, "Monsters\\SkelBow\\SklBw%c.CL2", TRUE, "Monsters\\SkelBow\\SklBw%c%i.WAV", FALSE, TRUE, "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, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 594 }, { 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", TRUE, "Monsters\\SkelSd\\SklSr%c%i.WAV", TRUE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 90 }, { 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", TRUE, "Monsters\\SkelSd\\SklSr%c%i.WAV", FALSE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 200 }, { 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", TRUE, "Monsters\\SkelSd\\SklSr%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, 0, 3, 393 }, { 128, 575, "Monsters\\SkelSd\\SklSr%c.CL2", TRUE, "Monsters\\SkelSd\\SklSr%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH , 3, 40, 8, 5, 14, 0, 0, 0, 0, 30, MC_UNDEAD, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 604 }, #ifdef HELLFIRE { 128, 800, "Monsters\\TSneak\\TSneak%c.CL2", FALSE, "Monsters\\TSneak\\Sneakl%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 15, 11, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Invisible Lord", 36, 39, 14, 278, 278, AI_SKELSD, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 65, 8, 16, 30, 0, 0, 0, 0, 60, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 2000 }, #else { 128, 2000, "Monsters\\TSneak\\TSneak%c.CL2", FALSE, "Monsters\\TSneak\\Sneakl%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 15, 11, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Invisible Lord", 14, 14, 14, 278, 278, AI_SKELSD, MFLAG_SEARCH , 3, 65, 8, 16, 30, 0, 0, 0, 0, 60, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 2000 }, #endif { 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", TRUE, "Monsters\\Sneak\\Sneak%c%i.WAV", FALSE, FALSE, NULL, { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Hidden", 3, 8, 5, 8, 24, AI_SNEAK, MFLAG_HIDDEN , 0, 35, 8, 3, 6, 0, 0, 0, 0, 25, MC_DEMON, 0 , IMMUNE_NULL_40, 0, 3, 278 }, { 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", TRUE, "Monsters\\Sneak\\Sneak%c%i.WAV", FALSE, TRUE, "Monsters\\Sneak\\Sneakv2.TRN", { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Stalker", 8, 12, 9, 30, 45, AI_SNEAK, MFLAG_HIDDEN | MFLAG_SEARCH , 1, 40, 8, 8, 16, 0, 0, 0, 0, 30, MC_DEMON, 0 , IMMUNE_NULL_40, 0, 3, 630 }, { 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", TRUE, "Monsters\\Sneak\\Sneak%c%i.WAV", FALSE, TRUE, "Monsters\\Sneak\\Sneakv3.TRN", { 16, 8, 12, 8, 24, 15 }, { 2, 0, 0, 0, 0, 0 }, "Unseen", 10, 14, 11, 35, 50, AI_SNEAK, MFLAG_HIDDEN | MFLAG_SEARCH , 2, 45, 8, 12, 20, 0, 0, 0, 0, 30, MC_DEMON, RESIST_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 935 }, { 128, 992, "Monsters\\Sneak\\Sneak%c.CL2", TRUE, "Monsters\\Sneak\\Sneak%c%i.WAV", FALSE, TRUE, "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, MFLAG_HIDDEN | MFLAG_SEARCH , 3, 60, 8, 16, 24, 0, 0, 0, 0, 30, MC_DEMON, RESIST_MAGIC | RESIST_FIRE , IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, 0, 3, 1500 }, #ifdef HELLFIRE { 160, 800, "Monsters\\GoatLord\\GoatL%c.CL2", FALSE, "Monsters\\newsfx\\Satyr%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 14, 9, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Satyr Lord", 40, 43, 28, 160, 200, AI_SKELSD, MFLAG_SEARCH , 3, 90, 8, 20, 30, 0, 0, 0, 0, 70, MC_ANIMAL, RESIST_FIRE | RESIST_LIGHTNING , RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING , 0, 3, 2800 }, #else { 160, 2000, "Monsters\\GoatLord\\GoatL%c.CL2", FALSE, "Monsters\\GoatLord\\Goatl%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 14, 9, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Lord Sayter", 13, 13, 12, 351, 351, AI_SKELSD, MFLAG_SEARCH , 3, 80, 8, 14, 24, 0, 0, 0, 0, 60, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, RESIST_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, 0, 3, 1500 }, #endif { 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", TRUE, "Monsters\\GoatMace\\Goat%c%i.WAV", FALSE, FALSE, NULL, { 12, 8, 12, 6, 20, 12 }, { 2, 0, 0, 0, 1, 0 }, "Flesh Clan", 6, 10, 8, 30, 45, AI_GOATMC, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 0, 50, 8, 4, 10, 0, 0, 0, 0, 40, MC_DEMON, 0 , 0 , 0, 3, 460 }, { 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", TRUE, "Monsters\\GoatMace\\Goat%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 1, 60, 8, 6, 12, 0, 0, 0, 0, 40, MC_DEMON, RESIST_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 685 }, { 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", TRUE, "Monsters\\GoatMace\\Goat%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 70, 8, 8, 16, 0, 0, 0, 0, 45, MC_DEMON, RESIST_FIRE , IMMUNE_FIRE , 0, 3, 906 }, { 128, 1030, "Monsters\\GoatMace\\Goat%c.CL2", TRUE, "Monsters\\GoatMace\\Goat%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 80, 8, 10, 20, 15, 0, 30, 30, 50, MC_DEMON, RESIST_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 1190 }, { 96, 364, "Monsters\\Bat\\Bat%c.CL2", FALSE, "Monsters\\Bat\\Bat%c%i.WAV", FALSE, TRUE, "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 , 0x4000, 6, 102 }, { 96, 364, "Monsters\\Bat\\Bat%c.CL2", FALSE, "Monsters\\Bat\\Bat%c%i.WAV", FALSE, FALSE, 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 , 0x4000, 6, 340 }, { 96, 364, "Monsters\\Bat\\Bat%c.CL2", FALSE, "Monsters\\Bat\\Bat%c%i.WAV", FALSE, TRUE, "Monsters\\Bat\\grey.trn", { 9, 13, 10, 9, 13, 0 }, { 0, 0, 0, 0, 0, 0 }, "Gloom", 7, 11, 9, 28, 36, AI_BAT, MFLAG_SEARCH , 2, 70, 5, 4, 12, 0, 0, 0, 0, 35, MC_ANIMAL, RESIST_MAGIC , RESIST_MAGIC | IMMUNE_NULL_40, 0x4000, 6, 509 }, { 96, 364, "Monsters\\Bat\\Bat%c.CL2", FALSE, "Monsters\\Bat\\Bat%c%i.WAV", FALSE, TRUE, "Monsters\\Bat\\orange.trn", { 9, 13, 10, 9, 13, 0 }, { 0, 0, 0, 0, 0, 0 }, "Familiar", 11, 15, 13, 20, 35, AI_BAT, MFLAG_SEARCH , 3, 50, 5, 4, 16, 0, 0, 0, 0, 35, MC_DEMON, RESIST_MAGIC | IMMUNE_LIGHTNING , RESIST_MAGIC | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0x4000, 6, 448 }, { 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", FALSE, "Monsters\\GoatBow\\GoatB%c%i.WAV", FALSE, FALSE, NULL, { 12, 8, 16, 6, 20, 0 }, { 3, 0, 0, 0, 0, 0 }, "Flesh Clan", 6, 10, 8, 20, 35, AI_GOATBOW, MFLAG_CAN_OPEN_DOOR, 0, 35, 13, 1, 7, 0, 0, 0, 0, 35, MC_DEMON, 0 , 0 , 0, 3, 448 }, { 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", FALSE, "Monsters\\GoatBow\\GoatB%c%i.WAV", FALSE, TRUE, "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, MFLAG_CAN_OPEN_DOOR, 1, 40, 13, 2, 9, 0, 0, 0, 0, 35, MC_DEMON, RESIST_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 645 }, { 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", FALSE, "Monsters\\GoatBow\\GoatB%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 45, 13, 3, 11, 0, 0, 0, 0, 35, MC_DEMON, RESIST_FIRE , IMMUNE_FIRE , 0, 3, 822 }, { 128, 1040, "Monsters\\GoatBow\\GoatB%c.CL2", FALSE, "Monsters\\GoatBow\\GoatB%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 50, 13, 4, 13, 15, 0, 0, 0, 40, MC_DEMON, RESIST_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 3, 1092 }, { 128, 716, "Monsters\\Acid\\Acid%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", TRUE, FALSE, 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, IMMUNE_ACID , IMMUNE_MAGIC | IMMUNE_ACID , 0, 3, 846 }, { 128, 716, "Monsters\\Acid\\Acid%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", TRUE, TRUE, "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, IMMUNE_ACID , IMMUNE_MAGIC | IMMUNE_ACID , 0, 3, 1248 }, { 128, 716, "Monsters\\Acid\\Acid%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", TRUE, TRUE, "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, RESIST_MAGIC | IMMUNE_ACID , IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_ACID , 0, 3, 2060 }, { 128, 716, "Monsters\\Acid\\Acid%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", TRUE, TRUE, "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, RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_ACID , IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_ACID , 0, 3, 2940 }, { 160, 1010, "Monsters\\SKing\\SKing%c.CL2", TRUE, "Monsters\\SKing\\SKing%c%i.WAV", TRUE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 60, 8, 6, 16, 0, 0, 0, 0, 70, MC_UNDEAD, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0x8001, 7, 570 }, { 128, 980, "Monsters\\FatC\\FatC%c.CL2", FALSE, "Monsters\\FatC\\FatC%c%i.WAV", FALSE, FALSE, 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, RESIST_FIRE | RESIST_LIGHTNING , RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING , 0x8000, 3, 710 }, { 128, 1130, "Monsters\\Fat\\Fat%c.CL2", TRUE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, FALSE, 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 , RESIST_FIRE , 0, 3, 635 }, { 128, 1130, "Monsters\\Fat\\Fat%c.CL2", TRUE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH , 1, 60, 8, 8, 16, 0, 0, 0, 0, 60, MC_DEMON, 0 , IMMUNE_LIGHTNING , 0, 3, 1165 }, { 128, 1130, "Monsters\\Fat\\Fat%c.CL2", TRUE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH , 2, 70, 8, 8, 16, 40, 0, 8, 20, 65, MC_DEMON, IMMUNE_MAGIC , IMMUNE_MAGIC | RESIST_LIGHTNING , 0, 3, 1380 }, { 128, 1130, "Monsters\\Fat\\Fat%c.CL2", TRUE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH , 3, 85, 8, 10, 20, 0, 0, 0, 0, 70, MC_DEMON, RESIST_MAGIC | IMMUNE_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 3, 2058 }, { 160, 2420, "Monsters\\Worm\\Worm%c.CL2", FALSE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, FALSE, 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, RESIST_MAGIC , RESIST_MAGIC , 0, 3, 660 }, { 160, 2420, "Monsters\\Worm\\Worm%c.CL2", FALSE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, FALSE, 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, RESIST_MAGIC , RESIST_MAGIC , 0, 3, 994 }, { 160, 2420, "Monsters\\Worm\\Worm%c.CL2", FALSE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, FALSE, 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, RESIST_MAGIC | RESIST_FIRE , RESIST_MAGIC | RESIST_FIRE , 0, 3, 1320 }, { 160, 2420, "Monsters\\Worm\\Worm%c.CL2", FALSE, "Monsters\\Fat\\Fat%c%i.WAV", FALSE, FALSE, 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, RESIST_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, RESIST_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, 0, 3, 1827 }, { 128, 1680, "Monsters\\Magma\\Magma%c.CL2", TRUE, "Monsters\\Magma\\Magma%c%i.WAV", TRUE, FALSE, NULL, { 8, 10, 14, 7, 18, 18 }, { 2, 0, 0, 0, 1, 0 }, "Magma Demon", 14, 17, 13, 50, 70, AI_MAGMA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 0, 45, 4, 2, 10, 50, 13, 0, 0, 45, MC_DEMON, IMMUNE_MAGIC | RESIST_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 7, 1076 }, { 128, 1680, "Monsters\\Magma\\Magma%c.CL2", TRUE, "Monsters\\Magma\\Magma%c%i.WAV", TRUE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 1, 50, 4, 2, 12, 50, 14, 0, 0, 45, MC_DEMON, IMMUNE_MAGIC | IMMUNE_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 7, 1309 }, { 128, 1680, "Monsters\\Magma\\Magma%c.CL2", TRUE, "Monsters\\Magma\\Magma%c%i.WAV", TRUE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 60, 4, 2, 20, 60, 14, 0, 0, 50, MC_DEMON, IMMUNE_MAGIC | IMMUNE_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 7, 1680 }, { 128, 1680, "Monsters\\Magma\\Magma%c.CL2", TRUE, "Monsters\\Magma\\Magma%c%i.WAV", TRUE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 75, 4, 4, 24, 60, 14, 0, 0, 60, MC_DEMON, IMMUNE_MAGIC | IMMUNE_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 7, 2124 }, { 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", TRUE, "Monsters\\Rhino\\Rhino%c%i.WAV", TRUE, FALSE, NULL, { 8, 8, 14, 6, 16, 6 }, { 2, 0, 0, 0, 0, 0 }, "Horned Demon", 12, 16, 13, 40, 80, AI_RHINO, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 0, 60, 7, 2, 16, 100, 0, 5, 32, 40, MC_ANIMAL, 0 , RESIST_FIRE , 0, 7, 1172 }, { 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", TRUE, "Monsters\\Rhino\\Rhino%c%i.WAV", TRUE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 1, 70, 7, 6, 18, 100, 0, 12, 36, 45, MC_ANIMAL, 0 , RESIST_FIRE , 0, 7, 1404 }, { 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", TRUE, "Monsters\\Rhino\\Rhino%c%i.WAV", TRUE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 80, 7, 8, 20, 100, 0, 20, 40, 50, MC_ANIMAL, IMMUNE_MAGIC | RESIST_LIGHTNING , IMMUNE_MAGIC | RESIST_LIGHTNING , 0, 7, 1720 }, { 160, 1630, "Monsters\\Rhino\\Rhino%c.CL2", TRUE, "Monsters\\Rhino\\Rhino%c%i.WAV", TRUE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 90, 7, 10, 22, 100, 0, 20, 50, 55, MC_ANIMAL, IMMUNE_MAGIC | RESIST_LIGHTNING , IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING , 0, 7, 1809 }, #ifdef HELLFIRE { 128, 1740, "Monsters\\Demskel\\Demskl%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, FALSE, "Monsters\\Thin\\Thinv3.TRN", { 10, 8, 20, 6, 24, 16 }, { 3, 0, 0, 0, 0, 0 }, "oldboned", 46, 47, 12, 70, 70, AI_STORM, 0 , 0, 60, 8, 6, 14, 12, 0, 0, 0, 50, MC_DEMON, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 7, 1344 }, #else { 128, 1740, "Monsters\\Demskel\\Demskl%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, FALSE, "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, IMMUNE_MAGIC | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 7, 1344 }, #endif { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 7, 2168 }, { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "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, IMMUNE_MAGIC | IMMUNE_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 7, 2736 }, { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "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, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 7, 3575 }, #ifdef HELLFIRE { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Incinerator", 40, 43, 16, 30, 45, AI_FIREMAN, 0 , 0, 75, 8, 8, 16, 0, 0, 0, 0, 25, MC_DEMON, IMMUNE_MAGIC | IMMUNE_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 3, 1888 }, { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Flame Lord", 42, 45, 18, 40, 55, AI_FIREMAN, 0 , 1, 75, 8, 10, 20, 0, 0, 0, 0, 25, MC_DEMON, IMMUNE_MAGIC | IMMUNE_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 3, 2250 }, { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Doom Fire", 44, 47, 20, 50, 65, AI_FIREMAN, 0 , 2, 80, 8, 12, 24, 0, 0, 0, 0, 30, MC_DEMON, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 0, 3, 2740 }, { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 14, 19, 20, 8, 14, 23 }, { 0, 0, 0, 0, 0, 0 }, "Hell Burner", 46, 47, 22, 60, 80, AI_FIREMAN, 0 , 3, 85, 8, 15, 30, 0, 0, 0, 0, 30, MC_DEMON, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 0, 3, 3355 }, #else { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | IMMUNE_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 3, 1888 }, { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | IMMUNE_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 3, 2250 }, { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 0, 3, 2740 }, { 128, 1460, "Monsters\\Fireman\\FireM%c.CL2", TRUE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 0, 3, 3355 }, #endif { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 0, 80, 5, 8, 18, 75, 8, 4, 16, 30, MC_DEMON, IMMUNE_MAGIC | RESIST_LIGHTNING , IMMUNE_MAGIC | IMMUNE_LIGHTNING , 0, 7, 2160 }, { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, FALSE, NULL, { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Storm Rider", 19, 23, 20, 60, 120, AI_STORM, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 1, 80, 5, 8, 18, 80, 8, 4, 16, 30, MC_DEMON, RESIST_MAGIC | IMMUNE_LIGHTNING , IMMUNE_MAGIC | IMMUNE_LIGHTNING , 0, 7, 2391 }, { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 85, 5, 12, 24, 75, 8, 4, 16, 35, MC_DEMON, RESIST_MAGIC | IMMUNE_LIGHTNING , IMMUNE_MAGIC | IMMUNE_LIGHTNING , 0, 7, 2775 }, { 160, 1740, "Monsters\\Thin\\Thin%c.CL2", TRUE, "Monsters\\Thin\\Thin%c%i.WAV", TRUE, TRUE, "Monsters\\Thin\\Thinv1.TRN", { 8, 8, 18, 4, 17, 14 }, { 3, 0, 0, 0, 0, 0 }, "Maelstorm", 23, 27, 24, 90, 150, AI_STORM, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 90, 5, 12, 28, 75, 8, 4, 16, 40, MC_DEMON, RESIST_MAGIC | IMMUNE_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 7, 3177 }, #ifdef HELLFIRE { 128, 800, "Monsters\\BigFall\\Fallg%c.CL2", TRUE, "Monsters\\newsfx\\KBrute%c%i.WAV", FALSE, FALSE, NULL, { 10, 8, 11, 8, 17, 0 }, { 0, 0, 0, 0, 2, 2 }, "Devil Kin Brute", 40, 43, 27, 120, 160, AI_SKELSD, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 100, 6, 18, 24, 0, 0, 0, 0, 70, MC_ANIMAL, RESIST_FIRE | RESIST_LIGHTNING , RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 0, 3, 2400 }, #else { 128, 1650, "Monsters\\BigFall\\Fallg%c.CL2", TRUE, "Monsters\\BigFall\\Bfal%c%i.WAV", FALSE, FALSE, NULL, { 10, 8, 11, 8, 17, 0 }, { 0, 0, 0, 0, 2, 2 }, "Devil Kin Brute", 20, 20, 24, 160, 220, AI_SKELSD, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 100, 6, 18, 24, 0, 0, 0, 0, 75, MC_ANIMAL, 0 , 0 , 0, 6, 2000 }, #endif { 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", TRUE, "Monsters\\Gargoyle\\Gargo%c%i.WAV", FALSE, FALSE, NULL, { 14, 14, 14, 10, 18, 14 }, { 0, 0, 0, 0, 0, 2 }, "Winged-Demon", 8, 12, 9, 45, 60, AI_GARG, MFLAG_CAN_OPEN_DOOR, 0, 50, 7, 10, 16, 0, 0, 0, 0, 45, MC_DEMON, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, 0, 6, 662 }, { 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", TRUE, "Monsters\\Gargoyle\\Gargo%c%i.WAV", FALSE, TRUE, "Monsters\\Gargoyle\\GarE.TRN", { 14, 14, 14, 10, 18, 14 }, { 0, 0, 0, 0, 0, 2 }, "Gargoyle", 12, 16, 13, 60, 90, AI_GARG, MFLAG_CAN_OPEN_DOOR, 1, 65, 7, 10, 16, 0, 0, 0, 0, 45, MC_DEMON, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 6, 1205 }, { 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", TRUE, "Monsters\\Gargoyle\\Gargo%c%i.WAV", FALSE, TRUE, "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, MFLAG_CAN_OPEN_DOOR, 2, 80, 7, 14, 22, 0, 0, 0, 0, 50, MC_DEMON, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 6, 1873 }, { 160, 1650, "Monsters\\Gargoyle\\Gargo%c.CL2", TRUE, "Monsters\\Gargoyle\\Gargo%c%i.WAV", FALSE, TRUE, "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, MFLAG_CAN_OPEN_DOOR, 3, 95, 7, 16, 28, 0, 0, 0, 0, 60, MC_DEMON, IMMUNE_MAGIC | IMMUNE_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 6, 2278 }, { 160, 2220, "Monsters\\Mega\\Mega%c.CL2", TRUE, "Monsters\\Mega\\Mega%c%i.WAV", TRUE, FALSE, NULL, { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Slayer", 19, 23, 20, 120, 140, AI_MEGA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 0, 100, 8, 12, 20, 0, 3, 0, 0, 60, MC_DEMON, RESIST_MAGIC | IMMUNE_FIRE , RESIST_MAGIC | IMMUNE_FIRE , 0, 7, 2300 }, { 160, 2220, "Monsters\\Mega\\Mega%c.CL2", TRUE, "Monsters\\Mega\\Mega%c%i.WAV", TRUE, TRUE, "Monsters\\Mega\\Guard.TRN", { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Guardian", 21, 25, 22, 140, 160, AI_MEGA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 1, 110, 8, 14, 22, 0, 3, 0, 0, 65, MC_DEMON, RESIST_MAGIC | IMMUNE_FIRE , RESIST_MAGIC | IMMUNE_FIRE , 0, 7, 2714 }, { 160, 2220, "Monsters\\Mega\\Mega%c.CL2", TRUE, "Monsters\\Mega\\Mega%c%i.WAV", TRUE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 120, 8, 18, 24, 0, 3, 0, 0, 70, MC_DEMON, RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, RESIST_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 7, 3252 }, { 160, 2220, "Monsters\\Mega\\Mega%c.CL2", TRUE, "Monsters\\Mega\\Mega%c%i.WAV", TRUE, TRUE, "Monsters\\Mega\\Balr.TRN", { 6, 7, 14, 1, 24, 5 }, { 3, 0, 0, 0, 2, 0 }, "Balrog", 25, 29, 26, 180, 200, AI_MEGA, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 130, 8, 22, 30, 0, 3, 0, 0, 75, MC_DEMON, RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, RESIST_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 7, 3643 }, { 160, 1270, "Monsters\\Snake\\Snake%c.CL2", FALSE, "Monsters\\Snake\\Snake%c%i.WAV", FALSE, FALSE, NULL, { 12, 11, 13, 5, 18, 0 }, { 2, 0, 0, 0, 1, 0 }, "Cave Viper", 20, 24, 21, 100, 150, AI_SNAKE, MFLAG_SEARCH , 0, 90, 8, 8, 20, 0, 0, 0, 0, 60, MC_DEMON, IMMUNE_MAGIC , IMMUNE_MAGIC , 0, 7, 2725 }, { 160, 1270, "Monsters\\Snake\\Snake%c.CL2", FALSE, "Monsters\\Snake\\Snake%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH , 1, 105, 8, 12, 24, 0, 0, 0, 0, 65, MC_DEMON, IMMUNE_MAGIC | RESIST_FIRE , IMMUNE_MAGIC | IMMUNE_FIRE , 0, 7, 3139 }, { 160, 1270, "Monsters\\Snake\\Snake%c.CL2", FALSE, "Monsters\\Snake\\Snake%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH , 2, 120, 8, 15, 26, 0, 0, 0, 0, 70, MC_DEMON, IMMUNE_MAGIC | RESIST_LIGHTNING , IMMUNE_MAGIC | RESIST_LIGHTNING , 0, 7, 3540 }, { 160, 1270, "Monsters\\Snake\\Snake%c.CL2", FALSE, "Monsters\\Snake\\Snake%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH , 3, 130, 8, 18, 30, 0, 0, 0, 0, 75, MC_DEMON, RESIST_FIRE | RESIST_LIGHTNING , IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING , 0, 7, 3791 }, { 160, 2120, "Monsters\\Black\\Black%c.CL2", FALSE, "Monsters\\Black\\Black%c%i.WAV", FALSE, FALSE, NULL, { 8, 8, 16, 4, 24, 0 }, { 2, 0, 0, 0, 0, 0 }, "Black Knight", 23, 27, 24, 150, 150, AI_SKELSD, MFLAG_SEARCH , 0, 110, 8, 15, 20, 0, 0, 0, 0, 75, MC_DEMON, RESIST_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, RESIST_MAGIC | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 7, 3360 }, { 160, 2120, "Monsters\\Black\\Black%c.CL2", FALSE, "Monsters\\Black\\Black%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH , 0, 130, 8, 18, 25, 0, 0, 0, 0, 75, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, 0, 7, 3650 }, { 160, 2120, "Monsters\\Black\\Black%c.CL2", FALSE, "Monsters\\Black\\Black%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH , 1, 120, 8, 20, 30, 0, 0, 0, 0, 80, MC_DEMON, RESIST_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 7, 4252 }, { 160, 2120, "Monsters\\Black\\Black%c.CL2", FALSE, "Monsters\\Black\\Black%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH , 1, 130, 8, 25, 35, 0, 0, 0, 0, 85, MC_DEMON, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 7, 5130 }, #ifdef HELLFIRE { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\newsfx\\Shred%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "The Shredded", 32, 35, 23, 70, 90, AI_SKELSD, 0 , 0, 75, 7, 4, 12, 0, 0, 0, 0, 65, MC_UNDEAD, RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 900 }, { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Hollow One", 34, 37, 27, 135, 240, AI_SKELSD, 0 , 1, 75, 7, 12, 24, 0, 0, 0, 0, 75, MC_UNDEAD, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 4374 }, { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Pain Master", 36, 39, 29, 110, 200, AI_SKELSD, 0 , 2, 80, 7, 16, 30, 0, 0, 0, 0, 80, MC_UNDEAD, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 5147 }, { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 12, 5, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Reality Weaver", 38, 39, 30, 135, 240, AI_SKELSD, 0 , 3, 85, 7, 20, 35, 0, 0, 0, 0, 85, MC_UNDEAD, RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 3, 5925 }, #else { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 3, 3812 }, { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 4374 }, { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, 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, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 5147 }, { 96, 484, "Monsters\\Unrav\\Unrav%c.CL2", FALSE, "Monsters\\Acid\\Acid%c%i.WAV", FALSE, FALSE, 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, RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 3, 5925 }, #endif { 128, 980, "Monsters\\Succ\\Scbs%c.CL2", FALSE, "Monsters\\Succ\\Scbs%c%i.WAV", FALSE, FALSE, NULL, { 14, 8, 16, 7, 24, 0 }, { 0, 0, 0, 0, 0, 0 }, "Succubus", 22, 26, 24, 120, 150, AI_SUCC, MFLAG_CAN_OPEN_DOOR, 0, 100, 10, 1, 20, 0, 0, 0, 0, 60, MC_DEMON, RESIST_MAGIC , IMMUNE_MAGIC | RESIST_FIRE , 0, 3, 3696 }, { 128, 980, "Monsters\\Succ\\Scbs%c.CL2", FALSE, "Monsters\\Succ\\Scbs%c%i.WAV", FALSE, TRUE, "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, MFLAG_CAN_OPEN_DOOR, 1, 110, 10, 1, 24, 0, 0, 0, 0, 65, MC_DEMON, RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 4084 }, #ifdef HELLFIRE { 128, 980, "Monsters\\Succ\\Scbs%c.CL2", FALSE, "Monsters\\Succ\\Scbs%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 115, 10, 1, 30, 0, 0, 0, 0, 75, MC_ANIMAL, RESIST_MAGIC | IMMUNE_LIGHTNING , IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 0, 3, 4480 }, #else { 128, 980, "Monsters\\Succ\\Scbs%c.CL2", FALSE, "Monsters\\Succ\\Scbs%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 2, 115, 10, 1, 30, 0, 0, 0, 0, 75, MC_DEMON, RESIST_MAGIC | IMMUNE_LIGHTNING , IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 0, 3, 4480 }, #endif { 128, 980, "Monsters\\Succ\\Scbs%c.CL2", FALSE, "Monsters\\Succ\\Scbs%c%i.WAV", FALSE, TRUE, "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, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 120, 10, 1, 35, 0, 0, 0, 0, 85, MC_DEMON, RESIST_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING , 0, 3, 4644 }, { 128, 2000, "Monsters\\Mage\\Mage%c.CL2", TRUE, "Monsters\\Mage\\Mage%c%i.WAV", FALSE, FALSE, NULL, { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Counselor", 24, 26, 25, 70, 70, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 0, 90, 8, 8, 20, 0, 0, 0, 0, 0, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 0, 7, 4070 }, { 128, 2000, "Monsters\\Mage\\Mage%c.CL2", TRUE, "Monsters\\Mage\\Mage%c%i.WAV", FALSE, TRUE, "Monsters\\Mage\\Cnselg.TRN", { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Magistrate", 26, 28, 27, 85, 85, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 1, 100, 8, 10, 24, 0, 0, 0, 0, 0, MC_DEMON, RESIST_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 7, 4478 }, { 128, 2000, "Monsters\\Mage\\Mage%c.CL2", TRUE, "Monsters\\Mage\\Mage%c%i.WAV", FALSE, TRUE, "Monsters\\Mage\\Cnselgd.TRN", { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Cabalist", 28, 30, 29, 120, 120, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 2, 110, 8, 14, 30, 0, 0, 0, 0, 0, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 7, 4929 }, { 128, 2000, "Monsters\\Mage\\Mage%c.CL2", TRUE, "Monsters\\Mage\\Mage%c%i.WAV", FALSE, TRUE, "Monsters\\Mage\\Cnselbk.TRN", { 12, 1, 20, 8, 28, 20 }, { 0, 0, 0, 0, 0, 0 }, "Advocate", 30, 30, 30, 145, 145, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 3, 120, 8, 15, 25, 0, 0, 0, 0, 0, MC_DEMON, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 7, 4968 }, { 96, 386, "Monsters\\Golem\\Golem%c.CL2", TRUE, "Monsters\\Golem\\Golm%c%i.WAV", FALSE, FALSE, NULL, { 0, 16, 12, 0, 12, 20 }, { 0, 0, 0, 0, 0, 0 }, "Golem", 0, 0, 12, 1, 1, AI_GOLUM, MFLAG_CAN_OPEN_DOOR, 0, 0, 7, 1, 1, 0, 0, 0, 0, 1, MC_DEMON, 0 , 0 , 0, 0, 0 }, #ifdef HELLFIRE { 160, 2000, "Monsters\\Diablo\\Diablo%c.CL2", TRUE, "Monsters\\Diablo\\Diablo%c%i.WAV", TRUE, FALSE, NULL, { 16, 6, 16, 2, 16, 16 }, { 0, 0, 0, 0, 0, 0 }, "The Dark Lord", 50, 50, 45, 3333, 3333, AI_DIABLO, MFLAG_KNOCKBACK | MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 220, 4, 30, 60, 0, 11, 0, 0, 90, MC_DEMON, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 7, 31666 }, { 128, 1060, "Monsters\\DarkMage\\Dmage%c.CL2", TRUE, "Monsters\\DarkMage\\Dmag%c%i.WAV", FALSE, FALSE, NULL, { 6, 1, 21, 6, 23, 18 }, { 0, 0, 0, 0, 0, 0 }, "The Arch-Litch Malignus", 40, 41, 30, 160, 160, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 3, 120, 8, 20, 40, 0, 0, 0, 0, 70, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 7, 4968 }, { 188, 800, "Monsters\\Fork\\Fork%c.CL2", FALSE, "Monsters\\newsfx\\HBoar%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 15, 6, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Hellboar", 32, 35, 23, 80, 100, AI_SKELSD, MFLAG_KNOCKBACK | MFLAG_SEARCH , 2, 70, 7, 16, 24, 0, 0, 0, 0, 60, MC_DEMON, 0 , RESIST_FIRE | RESIST_LIGHTNING , 0, 3, 750 }, { 64, 305, "Monsters\\Scorp\\Scorp%c.CL2", FALSE, "Monsters\\newsfx\\Stingr%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 12, 6, 15, 0 }, { 2, 0, 0, 0, 0, 0 }, "Stinger", 32, 35, 22, 30, 40, AI_SKELSD, 0 , 3, 85, 8, 1, 20, 0, 0, 0, 0, 50, MC_ANIMAL, 0 , RESIST_LIGHTNING , 0, 1, 500 }, { 156, 800, "Monsters\\Eye\\Eye%c.CL2", FALSE, "Monsters\\newsfx\\psyco%c%i.WAV", FALSE, FALSE, NULL, { 12, 13, 13, 7, 21, 0 }, { 2, 0, 0, 0, 0, 0 }, "Psychorb", 32, 35, 22, 20, 30, AI_PSYCHORB, 0 , 3, 80, 8, 10, 10, 0, 0, 0, 0, 40, MC_ANIMAL, 0 , RESIST_FIRE , 0, 6, 450 }, { 148, 800, "Monsters\\Spider\\Spider%c.CL2", FALSE, "Monsters\\newsfx\\SLord%c%i.WAV", FALSE, FALSE, NULL, { 12, 10, 15, 6, 20, 0 }, { 2, 0, 0, 0, 0, 0 }, "Arachnon", 32, 35, 22, 60, 80, AI_SKELSD, MFLAG_SEARCH , 3, 50, 8, 5, 15, 0, 0, 0, 0, 50, MC_ANIMAL, 0 , RESIST_LIGHTNING , 0, 7, 500 }, { 128, 800, "Monsters\\TSneak\\TSneak%c.CL2", FALSE, "Monsters\\newsfx\\FTwin%c%i.WAV", FALSE, FALSE, NULL, { 13, 13, 15, 11, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Felltwin", 32, 35, 22, 50, 70, AI_SKELSD, MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 70, 8, 10, 18, 0, 0, 0, 0, 50, MC_DEMON, IMMUNE_NULL_40, RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 3, 600 }, { 164, 520, "Monsters\\Spawn\\Spawn%c.CL2", FALSE, "Monsters\\newsfx\\HSpawn%c%i.WAV", TRUE, FALSE, NULL, { 15, 12, 14, 11, 14, 0 }, { 0, 0, 0, 0, 0, 0 }, "Hork Spawn", 34, 37, 22, 30, 30, AI_SKELSD, 0 , 3, 60, 8, 10, 25, 0, 0, 0, 0, 25, MC_DEMON, RESIST_MAGIC , RESIST_MAGIC , 0, 3, 250 }, { 86, 305, "Monsters\\WScorp\\WScorp%c.CL2", FALSE, "Monsters\\newsfx\\Stingr%c%i.WAV", FALSE, FALSE, NULL, { 10, 10, 12, 6, 15, 0 }, { 2, 0, 0, 0, 0, 0 }, "Venomtail", 36, 39, 24, 40, 50, AI_SKELSD, 0 , 3, 85, 8, 1, 30, 0, 0, 0, 0, 60, MC_ANIMAL, RESIST_LIGHTNING , IMMUNE_LIGHTNING , 0, 1, 1000 }, { 140, 800, "Monsters\\Eye2\\Eye2%c.CL2", FALSE, "Monsters\\newsfx\\Psyco%c%i.WAV", FALSE, FALSE, NULL, { 12, 13, 13, 7, 21, 0 }, { 2, 0, 0, 0, 0, 0 }, "Necromorb", 36, 39, 24, 30, 40, AI_NECROMORB, 0 , 3, 80, 8, 20, 20, 0, 0, 0, 0, 50, MC_ANIMAL, RESIST_FIRE , IMMUNE_FIRE | RESIST_LIGHTNING , 0, 6, 1100 }, { 148, 800, "Monsters\\bSpidr\\bSpidr%c.CL2", TRUE, "Monsters\\newsfx\\SLord%c%i.WAV", TRUE, FALSE, NULL, { 12, 10, 15, 6, 20, 10 }, { 2, 0, 0, 0, 0, 0 }, "Spider Lord", 36, 39, 24, 80, 100, AI_ACID, MFLAG_SEARCH , 3, 60, 8, 8, 20, 75, 8, 10, 10, 60, MC_ANIMAL, RESIST_LIGHTNING , RESIST_FIRE | IMMUNE_LIGHTNING , 0, 7, 1250 }, { 176, 800, "Monsters\\Clasp\\Clasp%c.CL2", FALSE, "Monsters\\newsfx\\Lworm%c%i.WAV", FALSE, FALSE, NULL, { 10, 12, 15, 6, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Lashworm", 36, 39, 20, 30, 30, AI_SKELSD, 0 , 3, 90, 8, 12, 20, 0, 0, 0, 0, 50, MC_ANIMAL, 0 , RESIST_FIRE , 0, 3, 600 }, { 192, 800, "Monsters\\AntWorm\\Worm%c.CL2", FALSE, "Monsters\\newsfx\\TchAnt%c%i.WAV", FALSE, FALSE, NULL, { 14, 12, 12, 6, 20, 0 }, { 2, 0, 0, 0, 0, 0 }, "Torchant", 36, 39, 22, 60, 80, AI_TORCHANT, 0 , 3, 75, 8, 20, 30, 0, 0, 0, 0, 70, MC_ANIMAL, IMMUNE_FIRE , RESIST_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 0, 7, 1250 }, { 138, 800, "Monsters\\HorkD\\HorkD%c.CL2", TRUE, "Monsters\\newsfx\\HDemon%c%i.WAV", TRUE, FALSE, NULL, { 15, 8, 16, 6, 16, 9 }, { 2, 0, 0, 0, 0, 2 }, "Hork Demon", 36, 37, 27, 120, 160, AI_SKELSD, 0 , 3, 60, 8, 20, 35, 80, 8, 0, 0, 80, MC_DEMON, RESIST_LIGHTNING , RESIST_MAGIC | IMMUNE_LIGHTNING , 0, 7, 2000 }, { 198, 800, "Monsters\\Hellbug\\Hellbg%c.CL2", TRUE, "Monsters\\newsfx\\Defile%c%i.WAV", TRUE, FALSE, NULL, { 8, 8, 14, 6, 14, 12 }, { 0, 0, 0, 0, 0, 0 }, "Hell Bug", 38, 39, 30, 240, 240, AI_SKELSD, MFLAG_SEARCH , 3, 110, 8, 20, 30, 90, 8, 50, 60, 80, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING , RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING , 0, 7, 5000 }, { 124, 800, "Monsters\\Gravdg\\Gravdg%c.CL2", TRUE, "Monsters\\newsfx\\GDiggr%c%i.WAV", TRUE, FALSE, NULL, { 24, 24, 12, 6, 16, 16 }, { 2, 0, 0, 0, 0, 0 }, "Gravedigger", 40, 41, 26, 120, 240, AI_SCAV, MFLAG_CAN_OPEN_DOOR, 3, 80, 6, 2, 12, 0, 0, 0, 0, 20, MC_UNDEAD, IMMUNE_LIGHTNING | IMMUNE_NULL_40, RESIST_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 3, 2000 }, { 104, 550, "Monsters\\Rat\\Rat%c.CL2", FALSE, "Monsters\\newsfx\\TmbRat%c%i.WAV", FALSE, FALSE, NULL, { 11, 8, 12, 6, 20, 0 }, { 2, 0, 0, 0, 0, 0 }, "Tomb Rat", 40, 43, 24, 80, 120, AI_SKELSD, 0 , 3, 120, 8, 12, 25, 0, 0, 0, 0, 30, MC_ANIMAL, 0 , RESIST_FIRE | RESIST_LIGHTNING , 0, 3, 1800 }, { 96, 550, "Monsters\\Hellbat\\Helbat%c.CL2", FALSE, "Monsters\\newsfx\\HelBat%c%i.WAV", FALSE, FALSE, NULL, { 18, 16, 14, 6, 18, 11 }, { 2, 0, 0, 0, 0, 0 }, "Firebat", 40, 43, 24, 60, 80, AI_FIREBAT, 0 , 3, 100, 8, 15, 20, 0, 0, 0, 0, 70, MC_ANIMAL, IMMUNE_FIRE , RESIST_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 0, 7, 2400 }, { 128, 1740, "Monsters\\Demskel\\Demskl%c.CL2", TRUE, "Monsters\\newsfx\\SWing%c%i.WAV", FALSE, FALSE, "Monsters\\Thin\\Thinv3.TRN", { 10, 8, 20, 6, 24, 16 }, { 3, 0, 0, 0, 0, 0 }, "Skullwing", 40, 43, 27, 70, 70, AI_SKELSD, 0 , 0, 75, 7, 15, 20, 75, 9, 15, 20, 80, MC_UNDEAD, RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 7, 3000 }, { 96, 800, "Monsters\\Lich\\Lich%c.CL2", FALSE, "Monsters\\newsfx\\Lich%c%i.WAV", TRUE, FALSE, NULL, { 12, 10, 10, 7, 21, 0 }, { 2, 0, 0, 0, 2, 0 }, "Lich", 40, 43, 25, 80, 100, AI_LICH, 0 , 3, 100, 8, 15, 20, 0, 0, 0, 0, 60, MC_UNDEAD, RESIST_LIGHTNING | IMMUNE_NULL_40, RESIST_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 3, 3000 }, { 154, 800, "Monsters\\Bubba\\Bubba%c.CL2", FALSE, "Monsters\\newsfx\\Crypt%c%i.WAV", TRUE, FALSE, NULL, { 8, 18, 12, 8, 21, 0 }, { 3, 0, 0, 0, 0, 0 }, "Crypt Demon", 42, 45, 28, 200, 240, AI_SKELSD, 0 , 3, 100, 8, 20, 40, 0, 0, 0, 0, 85, MC_DEMON, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 0, 3, 3200 }, { 96, 550, "Monsters\\Hellbat2\\bhelbt%c.CL2", TRUE, "Monsters\\newsfx\\HelBat%c%i.WAV", FALSE, FALSE, NULL, { 18, 16, 14, 6, 18, 11 }, { 2, 0, 0, 0, 0, 0 }, "Hellbat", 44, 47, 29, 100, 140, AI_TORCHANT, 0 , 3, 110, 8, 30, 30, 0, 0, 0, 0, 80, MC_DEMON, RESIST_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , RESIST_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING , 0, 7, 3600 }, { 128, 1740, "Monsters\\Demskel\\Demskl%c.CL2", TRUE, "Monsters\\newsfx\\SWing%c%i.WAV", TRUE, FALSE, "Monsters\\Thin\\Thinv3.TRN", { 10, 8, 20, 6, 24, 16 }, { 3, 0, 0, 0, 0, 0 }, "Bone Demon", 44, 47, 30, 240, 280, AI_BONEDEMON, 0 , 0, 100, 8, 40, 50, 160, 12, 50, 50, 50, MC_UNDEAD, IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 7, 5000 }, { 136, 800, "Monsters\\Lich2\\Lich2%c.CL2", FALSE, "Monsters\\newsfx\\Lich%c%i.WAV", TRUE, FALSE, NULL, { 12, 10, 10, 7, 21, 0 }, { 2, 0, 0, 0, 2, 0 }, "Arch Lich", 44, 47, 30, 180, 200, AI_ARCHLICH, 0 , 3, 120, 8, 30, 30, 0, 0, 0, 0, 75, MC_UNDEAD, RESIST_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 3, 4000 }, { 180, 800, "Monsters\\Byclps\\Byclps%c.CL2", FALSE, "Monsters\\newsfx\\Biclop%c%i.WAV", FALSE, FALSE, NULL, { 10, 11, 16, 6, 16, 0 }, { 2, 0, 0, 0, 2, 0 }, "Biclops", 44, 47, 30, 200, 240, AI_SKELSD, MFLAG_KNOCKBACK | MFLAG_CAN_OPEN_DOOR, 3, 90, 8, 40, 50, 0, 0, 0, 0, 80, MC_DEMON, RESIST_LIGHTNING , RESIST_FIRE | RESIST_LIGHTNING , 0, 3, 4000 }, { 164, 800, "Monsters\\Flesh\\Flesh%c.CL2", FALSE, "Monsters\\newsfx\\FleshT%c%i.WAV", TRUE, FALSE, NULL, { 15, 24, 15, 6, 16, 0 }, { 0, 0, 0, 0, 0, 0 }, "Flesh Thing", 44, 47, 28, 300, 400, AI_SKELSD, 0 , 3, 150, 8, 12, 18, 0, 0, 0, 0, 70, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 0, 3, 4000 }, { 180, 800, "Monsters\\Reaper\\Reap%c.CL2", FALSE, "Monsters\\newsfx\\Reaper%c%i.WAV", FALSE, FALSE, NULL, { 12, 10, 14, 6, 16, 0 }, { 2, 0, 0, 0, 0, 0 }, "Reaper", 44, 47, 30, 260, 300, AI_SKELSD, 0 , 3, 120, 8, 30, 35, 0, 0, 0, 0, 90, MC_DEMON, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING , 0, 3, 6000 }, { 226, 1200, "Monsters\\Nkr\\Nkr%c.CL2", TRUE, "Monsters\\newsfx\\Nakrul%c%i.WAV", TRUE, FALSE, NULL, { 2, 6, 16, 3, 16, 16 }, { 0, 0, 0, 0, 0, 0 }, "Na-Krul", 60, 60, 40, 1332, 1332, AI_SKELSD, MFLAG_KNOCKBACK | MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 150, 7, 40, 50, 150, 10, 40, 50, 125, MC_DEMON, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 7, 13333 }, #else { 160, 2000, "Monsters\\Diablo\\Diablo%c.CL2", TRUE, "Monsters\\Diablo\\Diablo%c%i.WAV", TRUE, FALSE, NULL, { 16, 6, 16, 6, 16, 16 }, { 0, 0, 0, 0, 0, 0 }, "The Dark Lord", 50, 50, 30, 1666, 1666, AI_DIABLO, MFLAG_KNOCKBACK | MFLAG_SEARCH | MFLAG_CAN_OPEN_DOOR, 3, 220, 4, 30, 60, 0, 11, 0, 0, 90, MC_DEMON, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 7, 31666 }, { 128, 1060, "Monsters\\DarkMage\\Dmage%c.CL2", TRUE, "Monsters\\DarkMage\\Dmag%c%i.WAV", FALSE, FALSE, NULL, { 6, 1, 21, 6, 23, 18 }, { 0, 0, 0, 0, 0, 0 }, "The Arch-Litch Malignus", 30, 30, 30, 160, 160, AI_COUNSLR, MFLAG_CAN_OPEN_DOOR, 3, 120, 8, 20, 40, 0, 0, 0, 0, 70, MC_DEMON, RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 7, 4968 }, #endif // clang-format on }; /** * Map between .DUN file value and monster type enum */ #ifdef HELLFIRE int MonstConvTbl[] = { #else char MonstConvTbl[] = { #endif MT_NZOMBIE, MT_BZOMBIE, MT_GZOMBIE, MT_YZOMBIE, MT_RFALLSP, MT_DFALLSP, MT_YFALLSP, MT_BFALLSP, MT_WSKELAX, MT_TSKELAX, MT_RSKELAX, MT_XSKELAX, MT_RFALLSD, MT_DFALLSD, MT_YFALLSD, MT_BFALLSD, MT_NSCAV, MT_BSCAV, MT_WSCAV, MT_YSCAV, MT_WSKELBW, MT_TSKELBW, MT_RSKELBW, MT_XSKELBW, MT_WSKELSD, MT_TSKELSD, MT_RSKELSD, MT_XSKELSD, MT_SNEAK, MT_STALKER, MT_UNSEEN, MT_ILLWEAV, MT_NGOATMC, MT_BGOATMC, MT_RGOATMC, MT_GGOATMC, MT_FIEND, MT_GLOOM, MT_BLINK, MT_FAMILIAR, MT_NGOATBW, MT_BGOATBW, MT_RGOATBW, MT_GGOATBW, MT_NACID, MT_RACID, MT_BACID, MT_XACID, MT_SKING, MT_FAT, MT_MUDMAN, MT_TOAD, MT_FLAYED, MT_WYRM, MT_CAVSLUG, MT_DEVOUR, MT_DVLWYRM, MT_NMAGMA, MT_YMAGMA, MT_BMAGMA, MT_WMAGMA, MT_HORNED, MT_MUDRUN, MT_FROSTC, MT_OBLORD, MT_BONEDMN, MT_REDDTH, MT_LTCHDMN, MT_UDEDBLRG, 0, 0, 0, 0, MT_INCIN, MT_FLAMLRD, MT_DOOMFIRE, MT_HELLBURN, 0, 0, 0, 0, MT_RSTORM, MT_STORM, MT_STORML, MT_MAEL, MT_WINGED, MT_GARGOYLE, MT_BLOODCLW, MT_DEATHW, MT_MEGA, MT_GUARD, MT_VTEXLRD, MT_BALROG, MT_NSNAKE, MT_RSNAKE, MT_GSNAKE, MT_BSNAKE, MT_NBLACK, MT_RTBLACK, MT_BTBLACK, MT_RBLACK, MT_UNRAV, MT_HOLOWONE, MT_PAINMSTR, MT_REALWEAV, MT_SUCCUBUS, MT_SNOWWICH, MT_HLSPWN, MT_SOLBRNR, MT_COUNSLR, MT_MAGISTR, MT_CABALIST, MT_ADVOCATE, 0, MT_DIABLO, 0, MT_GOLEM, 0, 0, 0, // Monster from blood1.dun and blood2.dun 0, 0, 0, 0, // Snotspill from banner2.dun 0, 0, MT_BIGFALL, MT_DARKMAGE, #ifdef HELLFIRE MT_HELLBOAR, MT_STINGER, MT_PSYCHORB, MT_ARACHNON, MT_FELLTWIN, MT_HORKSPWN, MT_STINGER, MT_PSYCHORB, MT_ARACHNON, MT_LASHWORM, MT_TORCHANT, MT_HORKDMN, MT_DEFILER, MT_GRAVEDIG, MT_TOMBRAT, MT_FIREBAT, MT_SKLWING, MT_LICH, MT_CRYPTDMN, MT_FIREBAT, MT_SKLWING, MT_LICH, MT_BICLOPS, MT_FLESTHNG, MT_REAPER, MT_NAKRUL, #endif }; #define MAT_NEVER 0 #define MAT_ALWAYS 1 #define MAT_RETAIL 2 /** * Define what version a monster type is available in */ #ifdef HELLFIRE int MonstAvailTbl[] = { #else char MonstAvailTbl[] = { #endif MAT_ALWAYS, // Zombie MAT_ALWAYS, // Ghoul MAT_ALWAYS, // Rotting Carcass MAT_ALWAYS, // Black Death MAT_ALWAYS, // Fallen One MAT_ALWAYS, // Carver MAT_ALWAYS, // Devil Kin MAT_ALWAYS, // Dark One MAT_ALWAYS, // Skeleton MAT_ALWAYS, // Corpse Axe MAT_ALWAYS, // Burning Dead MAT_ALWAYS, // Horror MAT_ALWAYS, // Fallen One MAT_ALWAYS, // Carver MAT_ALWAYS, // Devil Kin MAT_ALWAYS, // Dark One MAT_ALWAYS, // Scavenger MAT_ALWAYS, // Plague Eater MAT_ALWAYS, // Shadow Beast MAT_ALWAYS, // Bone Gasher MAT_ALWAYS, // Skeleton MAT_ALWAYS, // Corpse Bow MAT_ALWAYS, // Burning Dead MAT_ALWAYS, // Horror MAT_ALWAYS, // Skeleton Captain MAT_ALWAYS, // Corpse Captain MAT_ALWAYS, // Burning Dead Captain MAT_ALWAYS, // Horror Captain MAT_NEVER, // Invisible Lord MAT_RETAIL, // Hidden MAT_RETAIL, // Stalker MAT_RETAIL, // Unseen MAT_RETAIL, // Illusion Weaver #ifdef HELLFIRE MAT_RETAIL, // Satyr Lord #else MAT_NEVER, // Lord Sayter #endif MAT_RETAIL, // Flesh Clan MAT_RETAIL, // Stone Clan MAT_RETAIL, // Fire Clan MAT_RETAIL, // Night Clan MAT_ALWAYS, // Fiend MAT_ALWAYS, // Blink MAT_ALWAYS, // Gloom MAT_ALWAYS, // Familiar MAT_RETAIL, // Flesh Clan MAT_RETAIL, // Stone Clan MAT_RETAIL, // Fire Clan MAT_RETAIL, // Night Clan MAT_RETAIL, // Acid Beast MAT_RETAIL, // Poison Spitter MAT_RETAIL, // Pit Beast MAT_RETAIL, // Lava Maw MAT_NEVER, // Skeleton King MAT_NEVER, // The Butcher MAT_RETAIL, // Overlord MAT_RETAIL, // Mud Man MAT_RETAIL, // Toad Demon MAT_RETAIL, // Flayed One MAT_NEVER, // Wyrm MAT_NEVER, // Cave Slug MAT_NEVER, // Devil Wyrm MAT_NEVER, // Devourer MAT_RETAIL, // Magma Demon MAT_RETAIL, // Blood Stone MAT_RETAIL, // Hell Stone MAT_RETAIL, // Lava Lord MAT_RETAIL, // Horned Demon MAT_RETAIL, // Mud Runner MAT_RETAIL, // Frost Charger MAT_RETAIL, // Obsidian Lord MAT_NEVER, // Bone Demon (oldboned in Hellfire) MAT_NEVER, // Red Death MAT_NEVER, // Litch Demon MAT_NEVER, // Undead Balrog MAT_NEVER, // Incinerator MAT_NEVER, // Flame Lord MAT_NEVER, // Doom Fire MAT_NEVER, // Hell Burner MAT_RETAIL, // Red Storm MAT_RETAIL, // Storm Rider MAT_RETAIL, // Storm Lord MAT_RETAIL, // Maelstorm #ifdef HELLFIRE MAT_RETAIL, // Devil Kin Brute #else MAT_NEVER, // Devil Kin Brute #endif MAT_RETAIL, // Winged-Demon MAT_RETAIL, // Gargoyle MAT_RETAIL, // Blood Claw MAT_RETAIL, // Death Wing MAT_RETAIL, // Slayer MAT_RETAIL, // Guardian MAT_RETAIL, // Vortex Lord MAT_RETAIL, // Balrog MAT_RETAIL, // Cave Viper MAT_RETAIL, // Fire Drake MAT_RETAIL, // Gold Viper MAT_RETAIL, // Azure Drake MAT_RETAIL, // Black Knight MAT_RETAIL, // Doom Guard MAT_RETAIL, // Steel Lord MAT_RETAIL, // Blood Knight #ifdef HELLFIRE MAT_RETAIL, // The Shredded #else MAT_NEVER, // Unraveler #endif MAT_NEVER, // Hollow One MAT_NEVER, // Pain Master MAT_NEVER, // Reality Weaver MAT_RETAIL, // Succubus MAT_RETAIL, // Snow Witch MAT_RETAIL, // Hell Spawn MAT_RETAIL, // Soul Burner MAT_RETAIL, // Counselor MAT_RETAIL, // Magistrate MAT_RETAIL, // Cabalist MAT_RETAIL, // Advocate MAT_NEVER, // Golem MAT_NEVER, // The Dark Lord MAT_NEVER, // The Arch-Litch Malignus #ifdef HELLFIRE MAT_RETAIL, // Hellboar MAT_RETAIL, // Stinger MAT_RETAIL, // Psychorb MAT_RETAIL, // Arachnon MAT_RETAIL, // Felltwin MAT_RETAIL, // Hork Spawn MAT_RETAIL, // Venomtail MAT_RETAIL, // Necromorb MAT_RETAIL, // Spider Lord MAT_RETAIL, // Lashworm MAT_RETAIL, // Torchant MAT_NEVER, // Hork Demon MAT_NEVER, // Hell Bug MAT_RETAIL, // Gravedigger MAT_RETAIL, // Tomb Rat MAT_RETAIL, // Firebat MAT_RETAIL, // Skullwing MAT_RETAIL, // Lich MAT_RETAIL, // Crypt Demon MAT_RETAIL, // Hellbat MAT_RETAIL, // Bone Demon MAT_RETAIL, // Arch Lich MAT_RETAIL, // Biclops MAT_RETAIL, // Flesh Thing MAT_RETAIL, // Reaper MAT_NEVER, // Na-Krul #endif }; /** Contains the data related to each unique monster ID. */ UniqMonstStruct UniqMonst[] = { // clang-format off // mtype, mName, mTrnName, mlevel, mmaxhp, mAi, mint, mMinDamage, mMaxDamage, mMagicRes, mUnqAttr, mUnqVar1, mUnqVar2, mtalkmsg { MT_NGOATMC, "Gharbad the Weak", "BSDB", 4, 120, AI_GARBUD, 3, 8, 16, IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 0, 0, TEXT_GARBUD1 }, { MT_SKING, "Skeleton King", "GENRL", 0, 240, AI_SKELKING, 3, 6, 16, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 1, 0, 0, 0 }, { MT_COUNSLR, "Zhar the Mad", "GENERAL", 8, 360, AI_ZHAR, 3, 16, 40, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 0, 0, 0, TEXT_ZHAR1 }, { MT_BFALLSP, "Snotspill", "BNG", 4, 220, AI_SNOTSPIL, 3, 10, 18, RESIST_LIGHTNING , 0, 0, 0, TEXT_BANNER10 }, { MT_ADVOCATE, "Arch-Bishop Lazarus", "GENERAL", 0, 600, AI_LAZURUS, 3, 30, 50, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 0, 0, TEXT_VILE13 }, { MT_HLSPWN, "Red Vex", "REDV", 0, 400, AI_LAZHELP, 3, 30, 50, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, 0, 0, 0, TEXT_VILE13 }, { MT_HLSPWN, "BlackJade", "BLKJD", 0, 400, AI_LAZHELP, 3, 30, 50, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 0, 0, TEXT_VILE13 }, { MT_RBLACK, "Lachdanan", "BHKA", 14, 500, AI_LACHDAN, 3, 0, 0, 0 , 0, 0, 0, TEXT_VEIL9 }, { MT_BTBLACK, "Warlord of Blood", "GENERAL", 13, 850, AI_WARLORD, 3, 35, 50, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 0, 0, TEXT_WARLRD9 }, { MT_CLEAVER, "The Butcher", "GENRL", 0, 220, AI_CLEAVER, 3, 6, 12, RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 0, 0, 0 }, #ifdef HELLFIRE { MT_HORKDMN, "Hork Demon", "GENRL", 19, 300, AI_HORKDMN, 3, 20, 35, RESIST_LIGHTNING , 0, 0, 0, 0 }, { MT_DEFILER, "The Defiler", "GENRL", 20, 480, AI_SKELSD, 3, 30, 40, RESIST_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING , 0, 0, 0, 0 }, { MT_NAKRUL, "Na-Krul", "GENRL", 0, 1332, AI_SKELSD, 3, 40, 50, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, #endif { MT_TSKELAX, "Bonehead Keenaxe", "BHKA", 2, 91, AI_SKELSD, 2, 4, 10, IMMUNE_MAGIC | IMMUNE_NULL_40, 7, 100, 0, 0 }, { MT_RFALLSD, "Bladeskin the Slasher", "BSTS", 2, 51, AI_FALLEN, 0, 6, 18, RESIST_FIRE , 11, 45, 0, 0 }, { MT_NZOMBIE, "Soulpus", "GENERAL", 2, 133, AI_ZOMBIE, 0, 4, 8, RESIST_FIRE | RESIST_LIGHTNING , 0, 0, 0, 0 }, { MT_RFALLSP, "Pukerat the Unclean", "PTU", 2, 77, AI_FALLEN, 3, 1, 5, RESIST_FIRE , 0, 0, 0, 0 }, { MT_WSKELAX, "Boneripper", "BR", 2, 54, AI_BAT, 0, 6, 15, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_NZOMBIE, "Rotfeast the Hungry", "ETH", 2, 85, AI_SKELSD, 3, 4, 12, IMMUNE_MAGIC | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_DFALLSD, "Gutshank the Quick", "GTQ", 3, 66, AI_BAT, 2, 6, 16, RESIST_FIRE , 3, 0, 0, 0 }, { MT_TSKELSD, "Brokenhead Bangshield", "BHBS", 3, 108, AI_SKELSD, 3, 12, 20, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, 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, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, 11, 45, 0, 0 }, { MT_NSCAV, "Shadowbite", "SHBT", 2, 60, AI_SKELSD, 3, 3, 20, IMMUNE_FIRE , 3, 0, 0, 0 }, { MT_WSKELBW, "Deadeye", "DE", 2, 49, AI_GOATBOW, 0, 6, 9, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, 0, 0, 0, 0 }, { MT_RSKELAX, "Madeye the Dead", "MTD", 4, 75, AI_BAT, 0, 9, 21, IMMUNE_MAGIC | IMMUNE_FIRE , 11, 30, 0, 0 }, { MT_BSCAV, "El Chupacabras", "GENERAL", 3, 120, AI_GOATMC, 0, 10, 18, RESIST_FIRE , 3, 30, 0, 0 }, { MT_TSKELBW, "Skullfire", "SKFR", 3, 125, AI_GOATBOW, 1, 6, 10, IMMUNE_FIRE , 0, 100, 0, 0 }, { MT_SNEAK, "Warpskull", "TSPO", 3, 117, AI_SNEAK, 2, 6, 18, RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_GZOMBIE, "Goretongue", "PMR", 3, 156, AI_SKELSD, 1, 15, 30, IMMUNE_MAGIC | IMMUNE_NULL_40, 0, 0, 0, 0 }, { MT_WSCAV, "Pulsecrawler", "BHKA", 4, 150, AI_SCAV, 0, 16, 20, IMMUNE_FIRE | RESIST_LIGHTNING , 11, 45, 0, 0 }, { MT_BLINK, "Moonbender", "GENERAL", 4, 135, AI_BAT, 0, 9, 27, IMMUNE_FIRE , 3, 0, 0, 0 }, { MT_BLINK, "Wrathraven", "GENERAL", 5, 135, AI_BAT, 2, 9, 22, IMMUNE_FIRE , 3, 0, 0, 0 }, { MT_YSCAV, "Spineeater", "GENERAL", 4, 180, AI_SCAV, 1, 18, 25, IMMUNE_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_RSKELBW, "Blackash the Burning", "BASHTB", 4, 120, AI_GOATBOW, 0, 6, 16, IMMUNE_MAGIC | IMMUNE_FIRE , 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, IMMUNE_MAGIC | RESIST_LIGHTNING , 7, 70, 0, 0 }, { MT_FAT, "Bilefroth the Pit Master", "BFTP", 6, 210, AI_BAT, 1, 16, 23, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_NGOATBW, "Bloodskin Darkbow", "BSDB", 5, 207, AI_GOATBOW, 0, 3, 16, RESIST_FIRE | RESIST_LIGHTNING , 11, 55, 0, 0 }, { MT_GLOOM, "Foulwing", "DB", 5, 246, AI_RHINO, 3, 12, 28, RESIST_FIRE , 3, 0, 0, 0 }, { MT_XSKELSD, "Shadowdrinker", "SHDR", 5, 300, AI_SNEAK, 1, 18, 26, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 8, 45, 0, 0 }, { MT_UNSEEN, "Hazeshifter", "BHKA", 5, 285, AI_SNEAK, 3, 18, 30, IMMUNE_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_NACID, "Deathspit", "BFDS", 6, 303, AI_ACIDUNIQ, 0, 12, 32, RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_RGOATMC, "Bloodgutter", "BGBL", 6, 315, AI_BAT, 1, 24, 34, IMMUNE_FIRE , 3, 0, 0, 0 }, { MT_BGOATMC, "Deathshade Fleshmaul", "DSFM", 6, 276, AI_RHINO, 0, 12, 24, IMMUNE_MAGIC | RESIST_FIRE , 8, 65, 0, 0 }, { MT_WYRM, "Warmaggot the Mad", "GENERAL", 6, 246, AI_BAT, 3, 15, 30, RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_STORM, "Glasskull the Jagged", "BHKA", 7, 354, AI_STORM, 0, 18, 30, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_RGOATBW, "Blightfire", "BLF", 7, 321, AI_SUCC, 2, 13, 21, IMMUNE_FIRE , 3, 0, 0, 0 }, { MT_GARGOYLE, "Nightwing the Cold", "GENERAL", 7, 342, AI_BAT, 1, 18, 26, IMMUNE_MAGIC | RESIST_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_GGOATBW, "Gorestone", "GENERAL", 7, 303, AI_GOATBOW, 1, 15, 28, RESIST_LIGHTNING | IMMUNE_NULL_40, 7, 70, 0, 0 }, { MT_BMAGMA, "Bronzefist Firestone", "GENERAL", 8, 360, AI_MAGMA, 0, 30, 36, IMMUNE_MAGIC | RESIST_FIRE , 3, 0, 0, 0 }, { MT_INCIN, "Wrathfire the Doomed", "WFTD", 8, 270, AI_SKELSD, 2, 20, 30, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_NMAGMA, "Firewound the Grim", "BHKA", 8, 303, AI_MAGMA, 0, 18, 22, IMMUNE_MAGIC | RESIST_FIRE , 3, 0, 0, 0 }, { MT_MUDMAN, "Baron Sludge", "BSM", 8, 315, AI_SNEAK, 3, 25, 34, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 11, 75, 0, 0 }, { MT_GGOATMC, "Blighthorn Steelmace", "BHSM", 7, 250, AI_RHINO, 0, 20, 28, RESIST_LIGHTNING , 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, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_FLAMLRD, "Madburner", "GENERAL", 9, 270, AI_STORM, 0, 20, 40, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING , 3, 0, 0, 0 }, { MT_LTCHDMN, "Bonesaw the Litch", "GENERAL", 9, 495, AI_STORM, 2, 30, 55, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_MUDRUN, "Breakspine", "GENERAL", 9, 351, AI_RHINO, 0, 25, 34, RESIST_FIRE , 3, 0, 0, 0 }, { MT_REDDTH, "Devilskull Sharpbone", "GENERAL", 9, 444, AI_STORM, 1, 25, 40, IMMUNE_FIRE , 3, 0, 0, 0 }, { MT_STORM, "Brokenstorm", "GENERAL", 9, 411, AI_STORM, 2, 25, 36, IMMUNE_LIGHTNING , 3, 0, 0, 0 }, { MT_RSTORM, "Stormbane", "GENERAL", 9, 555, AI_STORM, 3, 30, 30, IMMUNE_LIGHTNING , 3, 0, 0, 0 }, { MT_TOAD, "Oozedrool", "GENERAL", 9, 483, AI_FAT, 3, 25, 30, RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_BLOODCLW, "Goldblight of the Flame", "GENERAL", 10, 405, AI_GARG, 0, 15, 35, IMMUNE_MAGIC | IMMUNE_FIRE , 11, 80, 0, 0 }, { MT_OBLORD, "Blackstorm", "GENERAL", 10, 525, AI_RHINO, 3, 20, 40, IMMUNE_MAGIC | IMMUNE_LIGHTNING , 11, 90, 0, 0 }, { MT_RACID, "Plaguewrath", "GENERAL", 10, 450, AI_ACIDUNIQ, 2, 20, 30, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_RSTORM, "The Flayer", "GENERAL", 10, 501, AI_STORM, 1, 20, 35, RESIST_MAGIC | RESIST_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_FROSTC, "Bluehorn", "GENERAL", 11, 477, AI_RHINO, 1, 25, 30, IMMUNE_MAGIC | RESIST_FIRE , 11, 90, 0, 0 }, { MT_HELLBURN, "Warpfire Hellspawn", "GENERAL", 11, 525, AI_FIREMAN, 3, 10, 40, RESIST_MAGIC | IMMUNE_FIRE , 3, 0, 0, 0 }, { MT_NSNAKE, "Fangspeir", "GENERAL", 11, 444, AI_SKELSD, 1, 15, 32, IMMUNE_FIRE | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_UDEDBLRG, "Festerskull", "GENERAL", 11, 600, AI_STORM, 2, 15, 30, IMMUNE_MAGIC | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_NBLACK, "Lionskull the Bent", "GENERAL", 12, 525, AI_SKELSD, 2, 25, 25, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_COUNSLR, "Blacktongue", "GENERAL", 12, 360, AI_COUNSLR, 3, 15, 30, RESIST_FIRE | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_DEATHW, "Viletouch", "GENERAL", 12, 525, AI_GARG, 3, 20, 40, IMMUNE_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_RSNAKE, "Viperflame", "GENERAL", 12, 570, AI_SKELSD, 1, 25, 35, IMMUNE_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_BSNAKE, "Fangskin", "BHKA", 14, 681, AI_SKELSD, 2, 15, 50, IMMUNE_MAGIC | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_SUCCUBUS, "Witchfire the Unholy", "GENERAL", 12, 444, AI_SUCC, 3, 10, 20, IMMUNE_MAGIC | IMMUNE_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_BALROG, "Blackskull", "BHKA", 13, 750, AI_SKELSD, 3, 25, 40, IMMUNE_MAGIC | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_UNRAV, "Soulslash", "GENERAL", 12, 450, AI_SKELSD, 0, 25, 25, IMMUNE_MAGIC | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_VTEXLRD, "Windspawn", "GENERAL", 12, 711, AI_SKELSD, 1, 35, 40, IMMUNE_MAGIC | IMMUNE_FIRE , 3, 0, 0, 0 }, { MT_GSNAKE, "Lord of the Pit", "GENERAL", 13, 762, AI_SKELSD, 2, 25, 42, RESIST_FIRE | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_RTBLACK, "Rustweaver", "GENERAL", 13, 400, AI_SKELSD, 3, 1, 60, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 0, 0, 0 }, { MT_HOLOWONE, "Howlingire the Shade", "GENERAL", 13, 450, AI_SKELSD, 2, 40, 75, RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_MAEL, "Doomcloud", "GENERAL", 13, 612, AI_STORM, 1, 1, 60, RESIST_FIRE | IMMUNE_LIGHTNING , 0, 0, 0, 0 }, { MT_PAINMSTR, "Bloodmoon Soulfire", "GENERAL", 13, 684, AI_SKELSD, 1, 15, 40, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_SNOWWICH, "Witchmoon", "GENERAL", 13, 310, AI_SUCC, 3, 30, 40, RESIST_LIGHTNING , 0, 0, 0, 0 }, { MT_VTEXLRD, "Gorefeast", "GENERAL", 13, 771, AI_SKELSD, 3, 20, 55, RESIST_FIRE | IMMUNE_NULL_40, 0, 0, 0, 0 }, { MT_RTBLACK, "Graywar the Slayer", "GENERAL", 14, 672, AI_SKELSD, 1, 30, 50, RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 0, 0, 0 }, { MT_MAGISTR, "Dreadjudge", "GENERAL", 14, 540, AI_COUNSLR, 1, 30, 40, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING , 3, 0, 0, 0 }, { MT_HLSPWN, "Stareye the Witch", "GENERAL", 14, 726, AI_SUCC, 2, 30, 50, IMMUNE_FIRE , 0, 0, 0, 0 }, { MT_BTBLACK, "Steelskull the Hunter", "GENERAL", 14, 831, AI_SKELSD, 3, 40, 50, RESIST_LIGHTNING | IMMUNE_NULL_40, 0, 0, 0, 0 }, { MT_RBLACK, "Sir Gorash", "GENERAL", 16, 1050, AI_SKELSD, 1, 20, 60, IMMUNE_NULL_40, 0, 0, 0, 0 }, { MT_CABALIST, "The Vizier", "GENERAL", 15, 850, AI_COUNSLR, 2, 25, 40, IMMUNE_FIRE , 3, 0, 0, 0 }, { MT_REALWEAV, "Zamphir", "GENERAL", 15, 891, AI_SKELSD, 2, 30, 50, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_HLSPWN, "Bloodlust", "GENERAL", 15, 825, AI_SUCC, 1, 20, 55, IMMUNE_MAGIC | IMMUNE_LIGHTNING | IMMUNE_NULL_40, 0, 0, 0, 0 }, { MT_HLSPWN, "Webwidow", "GENERAL", 16, 774, AI_SUCC, 1, 20, 50, IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_NULL_40, 0, 0, 0, 0 }, { MT_SOLBRNR, "Fleshdancer", "GENERAL", 16, 999, AI_SUCC, 3, 30, 50, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, 0, 0, 0, 0 }, { MT_OBLORD, "Grimspike", "GENERAL", 19, 534, AI_SNEAK, 1, 25, 40, IMMUNE_MAGIC | RESIST_FIRE | IMMUNE_NULL_40, 3, 0, 0, 0 }, { MT_STORML, "Doomlock", "GENERAL", 28, 534, AI_SNEAK, 1, 35, 55, IMMUNE_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_NULL_40, 3, 0, 0, 0 }, { -1, NULL, NULL, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0 }, // clang-format on }; ================================================ FILE: Source/monstdat.h ================================================ /** * @file monstdat.h * * Interface of all monster data. */ #ifndef __MONSTDAT_H__ #define __MONSTDAT_H__ extern MonsterData monsterdata[]; #ifdef HELLFIRE extern int MonstConvTbl[]; extern int MonstAvailTbl[]; #else extern char MonstConvTbl[]; extern char MonstAvailTbl[]; #endif extern UniqMonstStruct UniqMonst[]; #endif /* __MONSTDAT_H__ */ ================================================ FILE: Source/monster.cpp ================================================ /** * @file monster.cpp * * Implementation of monster functionality, AI, actions, spawning, loading, etc. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" /** Tracks which missile files are already loaded */ int MissileFileFlag; // BUGFIX: replace monstkills[MAXMONSTERS] with monstkills[NUM_MTYPES]. /** Tracks the total number of monsters killed per monster_id. */ int monstkills[MAXMONSTERS]; int monstactive[MAXMONSTERS]; int nummonsters; BOOLEAN sgbSaveSoundOn; MonsterStruct monster[MAXMONSTERS]; int totalmonsters; CMonster Monsters[MAX_LVLMTYPES]; #ifdef HELLFIRE int GraphicTable[NUMLEVELS][MAX_LVLMTYPES]; #else BYTE GraphicTable[NUMLEVELS][MAX_LVLMTYPES]; #endif int monstimgtot; int uniquetrans; int nummtypes; /** Maps from walking path step to facing direction. */ const char plr2monst[9] = { 0, 5, 3, 7, 1, 4, 6, 0, 2 }; /** Maps from monster intelligence factor to missile type. */ const BYTE counsmiss[4] = { MIS_FIREBOLT, MIS_CBOLT, MIS_LIGHTCTRL, MIS_FIREBALL }; /* data */ // BUGFIX: MWVel velocity values are not rounded consistently. The correct // formula for monster walk velocity is calculated as follows (for 16, 32 and 64 // pixel distances, respectively): // // vel16 = (16 << monsterWalkShift) / nframes // vel32 = (32 << monsterWalkShift) / nframes // vel64 = (64 << monsterWalkShift) / nframes // // The correct monster walk velocity table is as follows: // // int MWVel[24][3] = { // { 256, 512, 1024 }, // { 128, 256, 512 }, // { 85, 171, 341 }, // { 64, 128, 256 }, // { 51, 102, 205 }, // { 43, 85, 171 }, // { 37, 73, 146 }, // { 32, 64, 128 }, // { 28, 57, 114 }, // { 26, 51, 102 }, // { 23, 47, 93 }, // { 21, 43, 85 }, // { 20, 39, 79 }, // { 18, 37, 73 }, // { 17, 34, 68 }, // { 16, 32, 64 }, // { 15, 30, 60 }, // { 14, 28, 57 }, // { 13, 27, 54 }, // { 13, 26, 51 }, // { 12, 24, 49 }, // { 12, 23, 47 }, // { 11, 22, 45 }, // { 11, 21, 43 } // }; /** Maps from monster walk animation frame num to monster velocity. */ 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 } }; /** Maps from monster action to monster animation letter. */ char animletter[7] = "nwahds"; /** Maps from direction to a left turn from the direction. */ int left[8] = { 7, 0, 1, 2, 3, 4, 5, 6 }; /** Maps from direction to a right turn from the direction. */ int right[8] = { 1, 2, 3, 4, 5, 6, 7, 0 }; /** Maps from direction to the opposite direction. */ int opposite[8] = { 4, 5, 6, 7, 0, 1, 2, 3 }; /** Maps from direction to delta X-offset. */ int offset_x[8] = { 1, 0, -1, -1, -1, 0, 1, 1 }; /** Maps from direction to delta Y-offset. */ int offset_y[8] = { 1, 1, 1, 0, -1, -1, -1, 0 }; #ifdef HELLFIRE int HorkXAdd[8] = { 1, 0, -1, -1, -1, 0, 1, 1 }; // CODEFIX: same values as offset_x, remove it and use offset_x instead int HorkYAdd[8] = { 1, 1, 1, 0, -1, -1, -1, 0 }; // CODEFIX: same values as offset_y, remove it and use offset_y instead #endif /** 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 }; /** Maps from monster AI ID to monster AI function. */ void (*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, #ifdef HELLFIRE &MAI_Firebat, &MAI_Torchant, &MAI_HorkDemon, &MAI_Lich, &MAI_ArchLich, &MAI_Psychorb, &MAI_Necromorb, &MAI_BoneDemon #endif }; void InitMonsterTRN(int monst, BOOL special) { BYTE *f; int i, n, j; f = Monsters[monst].trans_file; for (i = 0; i < 256; i++) { if (*f == 255) { *f = 0; } f++; } n = special ? 6 : 5; for (i = 0; i < n; i++) { if (i != 1 || Monsters[monst].mtype < MT_COUNSLR || Monsters[monst].mtype > MT_ADVOCATE) { for (j = 0; j < 8; j++) { Cl2ApplyTrans( Monsters[monst].Anims[i].Data[j], Monsters[monst].trans_file, Monsters[monst].Anims[i].Frames); } } } } void 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 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].mImage; InitMonsterGFX(i); InitMonsterSND(i); } Monsters[i].mPlaceFlags |= placeflag; return i; } void 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; const int numskeltypes = 19; int nt; // number of types #ifdef SPAWN mamask = 1; // monster availability mask #else mamask = 3; // monster availability mask #endif AddMonsterType(MT_GOLEM, PLACE_SPECIAL); if (currlevel == 16) { AddMonsterType(MT_ADVOCATE, PLACE_SCATTER); AddMonsterType(MT_RBLACK, PLACE_SCATTER); AddMonsterType(MT_DIABLO, PLACE_SPECIAL); return; } #ifdef HELLFIRE if (currlevel == 18) AddMonsterType(MT_HORKSPWN, PLACE_SCATTER); if (currlevel == 19) { AddMonsterType(MT_HORKSPWN, PLACE_SCATTER); AddMonsterType(MT_HORKDMN, PLACE_UNIQUE); } if (currlevel == 20) AddMonsterType(MT_DEFILER, PLACE_UNIQUE); if (currlevel == 24) { AddMonsterType(MT_ARCHLICH, PLACE_SCATTER); AddMonsterType(MT_NAKRUL, PLACE_SPECIAL); } #endif if (!setlevel) { if (QuestStatus(Q_BUTCHER)) AddMonsterType(MT_CLEAVER, PLACE_SPECIAL); if (QuestStatus(Q_GARBUD)) AddMonsterType(UniqMonst[UMT_GARBUD].mtype, PLACE_UNIQUE); if (QuestStatus(Q_ZHAR)) AddMonsterType(UniqMonst[UMT_ZHAR].mtype, PLACE_UNIQUE); if (QuestStatus(Q_LTBANNER)) AddMonsterType(UniqMonst[UMT_SNOTSPIL].mtype, PLACE_UNIQUE); if (QuestStatus(Q_VEIL)) AddMonsterType(UniqMonst[UMT_LACHDAN].mtype, PLACE_UNIQUE); if (QuestStatus(Q_WARLORD)) AddMonsterType(UniqMonst[UMT_WARLORD].mtype, PLACE_UNIQUE); if (gbMaxPlayers != 1 && currlevel == quests[Q_SKELKING]._qlevel) { AddMonsterType(MT_SKING, PLACE_UNIQUE); 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)], PLACE_SCATTER); } nt = 0; for (i = 0; i < NUM_MTYPES; 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], PLACE_SCATTER); } else { while (nt > 0 && nummtypes < MAX_LVLMTYPES && monstimgtot < 4000) { for (i = 0; i < nt;) { if (monsterdata[typelist[i]].mImage > 4000 - monstimgtot) { typelist[i] = typelist[--nt]; continue; } i++; } if (nt != 0) { i = random_(88, nt); AddMonsterType(typelist[i], PLACE_SCATTER); typelist[i] = typelist[--nt]; } } } } else { if (setlvlnum == SL_SKELKING) { AddMonsterType(MT_SKING, PLACE_UNIQUE); } } } void InitMonsterGFX(int monst) { int mtype, anim, i; char strBuff[256]; BYTE *celBuf; mtype = Monsters[monst].mtype; for (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]); celBuf = LoadFileInMem(strBuff, NULL); Monsters[monst].Anims[anim].CMem = celBuf; if (Monsters[monst].mtype != MT_GOLEM || (animletter[anim] != 's' && animletter[anim] != 'd')) { for (i = 0; i < 8; i++) { Monsters[monst].Anims[anim].Data[i] = &celBuf[((int *)celBuf)[i]]; } } else { for (i = 0; i < 8; i++) { Monsters[monst].Anims[anim].Data[i] = celBuf; } } } // TODO: either the AnimStruct members have wrong naming or the MonsterData ones it seems Monsters[monst].Anims[anim].Frames = monsterdata[mtype].Frames[anim]; Monsters[monst].Anims[anim].Rate = monsterdata[mtype].Rate[anim]; } Monsters[monst].width = monsterdata[mtype].width; Monsters[monst].width2 = (monsterdata[mtype].width - 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); MemFreeDbg(Monsters[monst].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 && !(MissileFileFlag & 4)) { MissileFileFlag |= 4; #ifndef HELLFIRE LoadMissileGFX(MFILE_FLARE); LoadMissileGFX(MFILE_FLAREEXP); #endif } #ifdef HELLFIRE if (mtype >= MT_INCIN && mtype <= MT_HELLBURN && !(MissileFileFlag & 8)) { MissileFileFlag |= 8; LoadMissileGFX(MFILE_KRULL); } if ((mtype >= MT_NACID && mtype <= MT_XACID || mtype == MT_SPIDLORD) && !(MissileFileFlag & 0x10)) { MissileFileFlag |= 0x10; LoadMissileGFX(MFILE_ACIDBF); LoadMissileGFX(MFILE_ACIDSPLA); LoadMissileGFX(MFILE_ACIDPUD); } #endif if (mtype == MT_SNOWWICH && !(MissileFileFlag & 0x20)) { MissileFileFlag |= 0x20; LoadMissileGFX(MFILE_SCUBMISB); LoadMissileGFX(MFILE_SCBSEXPB); } if (mtype == MT_HLSPWN && !(MissileFileFlag & 0x40)) { MissileFileFlag |= 0x40; LoadMissileGFX(MFILE_SCUBMISD); LoadMissileGFX(MFILE_SCBSEXPD); } if (mtype == MT_SOLBRNR && !(MissileFileFlag & 0x80)) { MissileFileFlag |= 0x80; LoadMissileGFX(MFILE_SCUBMISC); LoadMissileGFX(MFILE_SCBSEXPC); } #ifndef HELLFIRE 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); } #else if (mtype == MT_LICH && !(MissileFileFlag & 0x100)) { MissileFileFlag |= 0x100u; LoadMissileGFX(MFILE_LICH); LoadMissileGFX(MFILE_EXORA1); } if (mtype == MT_ARCHLICH && !(MissileFileFlag & 0x200)) { MissileFileFlag |= 0x200u; LoadMissileGFX(MFILE_ARCHLICH); LoadMissileGFX(MFILE_EXYEL2); } if ((mtype == MT_PSYCHORB || mtype == MT_BONEDEMN) && !(MissileFileFlag & 0x400)) { MissileFileFlag |= 0x400u; LoadMissileGFX(MFILE_BONEDEMON); } if (mtype == MT_NECRMORB && !(MissileFileFlag & 0x800)) { MissileFileFlag |= 0x800u; LoadMissileGFX(MFILE_NECROMORB); LoadMissileGFX(MFILE_EXRED3); } if (mtype == MT_PSYCHORB && !(MissileFileFlag & 0x1000)) { MissileFileFlag |= 0x1000u; LoadMissileGFX(MFILE_EXBL2); } if (mtype == MT_BONEDEMN && !(MissileFileFlag & 0x2000)) { MissileFileFlag |= 0x2000u; LoadMissileGFX(MFILE_EXBL3); } #endif if (mtype == MT_DIABLO) { LoadMissileGFX(MFILE_FIREPLAR); } } void 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 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]._mMTidx = mtype; monster[i]._mmode = MM_STAND; monster[i].mName = monst->MData->mName; monster[i].MType = monst; monster[i].MData = monst->MData; monster[i]._mAnimData = monst->Anims[MA_STAND].Data[rd]; monster[i]._mAnimDelay = monst->Anims[MA_STAND].Rate; monster[i]._mAnimCnt = random_(88, monster[i]._mAnimDelay - 1); monster[i]._mAnimLen = monst->Anims[MA_STAND].Frames; monster[i]._mAnimFrame = random_(88, monster[i]._mAnimLen - 1) + 1; if (monst->mtype == MT_DIABLO) { #ifdef HELLFIRE monster[i]._mmaxhp = (random_(88, 1) + 3333) << 6; #else monster[i]._mmaxhp = (random_(88, 1) + 1666) << 6; #endif } 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 = MGOAL_NORMAL; monster[i]._mgoalvar1 = 0; monster[i]._mgoalvar2 = 0; monster[i]._mgoalvar3 = 0; monster[i].field_18 = 0; monster[i]._pathcount = 0; monster[i]._mDelFlag = FALSE; monster[i]._uniqtype = 0; monster[i]._msquelch = 0; #ifdef HELLFIRE monster[i].mlid = 0; #endif 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[MA_SPECIAL].Data[rd]; monster[i]._mAnimFrame = 1; monster[i]._mFlags |= MFLAG_ALLOW_SPECIAL; monster[i]._mmode = MM_SATTACK; } if (gnDifficulty == DIFF_NIGHTMARE) { #ifdef HELLFIRE monster[i]._mmaxhp = 3 * monster[i]._mmaxhp + ((gbMaxPlayers != 1 ? 100 : 50) << 6); #else monster[i]._mmaxhp = 3 * monster[i]._mmaxhp + 64; #endif monster[i]._mhitpoints = monster[i]._mmaxhp; monster[i].mLevel += 15; monster[i].mExp = 2 * (monster[i].mExp + 1000); monster[i].mHit += 85; monster[i].mMinDamage = 2 * (monster[i].mMinDamage + 2); monster[i].mMaxDamage = 2 * (monster[i].mMaxDamage + 2); monster[i].mHit2 += 85; monster[i].mMinDamage2 = 2 * (monster[i].mMinDamage2 + 2); monster[i].mMaxDamage2 = 2 * (monster[i].mMaxDamage2 + 2); monster[i].mArmorClass += 50; } #ifdef HELLFIRE else #endif if (gnDifficulty == DIFF_HELL) { #ifdef HELLFIRE monster[i]._mmaxhp = 4 * monster[i]._mmaxhp + ((gbMaxPlayers != 1 ? 200 : 100) << 6); #else monster[i]._mmaxhp = 4 * monster[i]._mmaxhp + 192; #endif monster[i]._mhitpoints = monster[i]._mmaxhp; monster[i].mLevel += 30; monster[i].mExp = 4 * (monster[i].mExp + 1000); monster[i].mHit += 120; monster[i].mMinDamage = 4 * monster[i].mMinDamage + 6; monster[i].mMaxDamage = 4 * monster[i].mMaxDamage + 6; monster[i].mHit2 += 120; 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 ClrAllMonsters() { int i; MonsterStruct *Monst; for (i = 0; i < MAXMONSTERS; 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 = FALSE; Monst->_menemy = random_(89, gbActivePlayers); // BUGFIX: `Monst->_menemy` may be referencing a player who already left the game, thus reading garbage data from `plr[Monst->_menemy]._pfutx`. Monst->_menemyx = plr[Monst->_menemy]._pfutx; Monst->_menemyy = plr[Monst->_menemy]._pfuty; } } BOOL MonstPlace(int xp, int yp) { char f; if (xp < 0 || xp >= MAXDUNX || yp < 0 || yp >= MAXDUNY || dMonster[xp][yp] != 0 || dPlayer[xp][yp] != 0) { return FALSE; } f = dFlags[xp][yp]; if (f & BFLAG_VISIBLE) { return FALSE; } if (f & BFLAG_POPULATED) { return FALSE; } return !SolidLoc(xp, yp); } #ifdef HELLFIRE void monster_some_crypt() { MonsterStruct *mon; int hp; if (currlevel == 24 && UberDiabloMonsterIndex >= 0 && UberDiabloMonsterIndex < nummonsters) { mon = &monster[UberDiabloMonsterIndex]; PlayEffect(UberDiabloMonsterIndex, 2); quests[Q_NAKRUL]._qlog = FALSE; mon->mArmorClass -= 50; hp = mon->_mmaxhp / 2; mon->mMagicRes = 0; mon->_mhitpoints = hp; mon->_mmaxhp = hp; } } #endif void PlaceMonster(int i, int mtype, int x, int y) { int rd; #ifdef HELLFIRE if (Monsters[mtype].mtype == MT_NAKRUL) { for (int j = 0; j < nummonsters; j++) { if (monster[j]._mMTidx == mtype) { return; } if (monster[j].MType->mtype == MT_NAKRUL) { return; } } } #endif dMonster[x][y] = i + 1; rd = random_(90, 8); InitMonster(i, rd, mtype, x, y); } #ifndef SPAWN void PlaceUniqueMonst(int uniqindex, int miniontype, int bosspacksize) { int xp, yp, x, y, i; int uniqtype; int count2; char filestr[64]; BOOL zharflag, done; UniqMonstStruct *Uniq; MonsterStruct *Monst; int count; Monst = &monster[nummonsters]; count = 0; Uniq = &UniqMonst[uniqindex]; if ((uniquetrans + 19) << 8 >= LIGHTSIZE) { return; } for (uniqtype = 0; uniqtype < nummtypes; uniqtype++) { if (Monsters[uniqtype].mtype == UniqMonst[uniqindex].mtype) { break; } } while (1) { xp = random_(91, 80) + 16; yp = random_(91, 80) + 16; count2 = 0; for (x = xp - 3; x < xp + 3; x++) { for (y = yp - 3; y < yp + 3; y++) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX && MonstPlace(x, y)) { count2++; } } } if (count2 < 9) { count++; if (count < 1000) { continue; } } if (MonstPlace(xp, yp)) { break; } } if (uniqindex == UMT_SNOTSPIL) { xp = 2 * setpc_x + 24; yp = 2 * setpc_y + 28; } if (uniqindex == UMT_WARLORD) { xp = 2 * setpc_x + 22; yp = 2 * setpc_y + 23; } if (uniqindex == UMT_ZHAR) { zharflag = TRUE; for (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 == UMT_LAZURUS) { xp = 32; yp = 46; } if (uniqindex == UMT_RED_VEX) { xp = 40; yp = 45; } if (uniqindex == UMT_BLACKJADE) { xp = 38; yp = 49; } if (uniqindex == UMT_SKELKING) { xp = 35; yp = 47; } } else { if (uniqindex == UMT_LAZURUS) { xp = 2 * setpc_x + 19; yp = 2 * setpc_y + 22; } if (uniqindex == UMT_RED_VEX) { xp = 2 * setpc_x + 21; yp = 2 * setpc_y + 19; } if (uniqindex == UMT_BLACKJADE) { xp = 2 * setpc_x + 21; yp = 2 * setpc_y + 25; } } if (uniqindex == UMT_BUTCHER) { done = FALSE; for (yp = 0; yp < MAXDUNY && !done; yp++) { for (xp = 0; xp < MAXDUNX && !done; xp++) { done = dPiece[xp][yp] == 367; } } } #ifdef HELLFIRE if (uniqindex == UMT_NAKRUL) { if (UberRow == 0 || UberCol == 0) { UberDiabloMonsterIndex = -1; return; } xp = UberRow - 2; yp = UberCol; UberDiabloMonsterIndex = nummonsters; } #endif 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; #ifdef HELLFIRE if (uniqindex == UMT_HORKDMN) Monst->mlid = 0; else #endif Monst->mlid = AddLight(Monst->_mx, Monst->_my, 3); if (gbMaxPlayers != 1) { if (Monst->_mAi == AI_LAZHELP) Monst->mtalkmsg = 0; #ifndef HELLFIRE if (Monst->_mAi != AI_LAZURUS || quests[Q_BETRAYER]._qvar1 <= 3) { if (Monst->mtalkmsg) { Monst->_mgoal = MGOAL_INQUIRING; } } else { Monst->_mgoal = MGOAL_NORMAL; } #endif } #ifdef HELLFIRE if (Monst->mtalkmsg) #else else if (Monst->mtalkmsg) #endif Monst->_mgoal = MGOAL_INQUIRING; if (gnDifficulty == DIFF_NIGHTMARE) { #ifdef HELLFIRE Monst->_mmaxhp = 3 * Monst->_mmaxhp + ((gbMaxPlayers != 1 ? 100 : 50) << 6); #else Monst->_mmaxhp = 3 * Monst->_mmaxhp + 64; #endif Monst->mLevel += 15; 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); } #ifdef HELLFIRE else if (gnDifficulty == DIFF_HELL) { #else if (gnDifficulty == DIFF_HELL) { #endif #ifdef HELLFIRE Monst->_mmaxhp = 4 * Monst->_mmaxhp + ((gbMaxPlayers != 1 ? 200 : 100) << 6); #else Monst->_mmaxhp = 4 * Monst->_mmaxhp + 192; #endif Monst->mLevel += 30; 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->mTrnName); 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, bosspacksize, Uniq->mUnqAttr, nummonsters - 1); } if (Monst->_mAi != AI_GARG) { Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[Monst->_mdir]; Monst->_mAnimFrame = random_(88, Monst->_mAnimLen - 1) + 1; Monst->_mFlags &= ~MFLAG_ALLOW_SPECIAL; Monst->_mmode = MM_STAND; } } static void PlaceUniques() { int u, mt; BOOL done; for (u = 0; UniqMonst[u].mtype != -1; u++) { if (UniqMonst[u].mlevel != currlevel) continue; done = FALSE; for (mt = 0; mt < nummtypes; mt++) { if (done) break; done = (Monsters[mt].mtype == UniqMonst[u].mtype); } mt--; if (u == UMT_GARBUD && quests[Q_GARBUD]._qactive == QUEST_NOTAVAIL) done = FALSE; if (u == UMT_ZHAR && quests[Q_ZHAR]._qactive == QUEST_NOTAVAIL) done = FALSE; if (u == UMT_SNOTSPIL && quests[Q_LTBANNER]._qactive == QUEST_NOTAVAIL) done = FALSE; if (u == UMT_LACHDAN && quests[Q_VEIL]._qactive == QUEST_NOTAVAIL) done = FALSE; if (u == UMT_WARLORD && quests[Q_WARLORD]._qactive == QUEST_NOTAVAIL) done = FALSE; if (done) PlaceUniqueMonst(u, mt, 8); } } void PlaceQuestMonsters() { int skeltype; BYTE *setp; if (!setlevel) { if (QuestStatus(Q_BUTCHER)) { PlaceUniqueMonst(UMT_BUTCHER, 0, 0); } if (currlevel == quests[Q_SKELKING]._qlevel && gbMaxPlayers != 1) { skeltype = 0; for (skeltype = 0; skeltype < nummtypes; skeltype++) { if (IsSkel(Monsters[skeltype].mtype)) { break; } } PlaceUniqueMonst(UMT_SKELKING, skeltype, 30); } if (QuestStatus(Q_LTBANNER)) { setp = LoadFileInMem("Levels\\L1Data\\Banner1.DUN", NULL); SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y); mem_free_dbg(setp); } if (QuestStatus(Q_BLOOD)) { setp = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", NULL); SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y); mem_free_dbg(setp); } if (QuestStatus(Q_BLIND)) { setp = LoadFileInMem("Levels\\L2Data\\Blind2.DUN", NULL); SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y); mem_free_dbg(setp); } if (QuestStatus(Q_ANVIL)) { setp = LoadFileInMem("Levels\\L3Data\\Anvil.DUN", NULL); SetMapMonsters(setp, 2 * setpc_x + 2, 2 * setpc_y + 2); mem_free_dbg(setp); } if (QuestStatus(Q_WARLORD)) { setp = LoadFileInMem("Levels\\L4Data\\Warlord.DUN", NULL); SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y); mem_free_dbg(setp); AddMonsterType(UniqMonst[UMT_WARLORD].mtype, PLACE_SCATTER); } if (QuestStatus(Q_VEIL)) { AddMonsterType(UniqMonst[UMT_LACHDAN].mtype, PLACE_SCATTER); } if (QuestStatus(Q_ZHAR) && zharlib == -1) { quests[Q_ZHAR]._qactive = QUEST_NOTAVAIL; } if (currlevel == quests[Q_BETRAYER]._qlevel && gbMaxPlayers != 1) { AddMonsterType(UniqMonst[UMT_LAZURUS].mtype, PLACE_UNIQUE); AddMonsterType(UniqMonst[UMT_RED_VEX].mtype, PLACE_UNIQUE); PlaceUniqueMonst(UMT_LAZURUS, 0, 0); PlaceUniqueMonst(UMT_RED_VEX, 0, 0); PlaceUniqueMonst(UMT_BLACKJADE, 0, 0); setp = LoadFileInMem("Levels\\L4Data\\Vile1.DUN", NULL); SetMapMonsters(setp, 2 * setpc_x, 2 * setpc_y); mem_free_dbg(setp); } #ifdef HELLFIRE if (currlevel == 24) { UberDiabloMonsterIndex = -1; int i1; for (i1 = 0; i1 < nummtypes; i1++) { if (Monsters[i1].mtype == UniqMonst[UMT_NAKRUL].mtype) break; } if (i1 < nummtypes) { for (int i2 = 0; i2 < nummonsters; i2++) { if (monster[i2]._uniqtype != 0 || monster[i2]._mMTidx == i1) { UberDiabloMonsterIndex = i2; break; } } } if (UberDiabloMonsterIndex == -1) PlaceUniqueMonst(UMT_NAKRUL, 0, 0); } #endif } else if (setlvlnum == SL_SKELKING) { PlaceUniqueMonst(UMT_SKELKING, 0, 0); } } #endif void PlaceGroup(int mtype, int num, int leaderf, int leader) { int placed, try1, try2, j; int xp, yp, x1, y1; placed = 0; for (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); x1 = xp = monster[leader]._mx + offset_x[offset]; y1 = yp = monster[leader]._my + offset_y[offset]; } else { do { x1 = xp = random_(93, 80) + 16; y1 = yp = random_(93, 80) + 16; } while (!MonstPlace(xp, yp)); } if (num + nummonsters > totalmonsters) { num = totalmonsters - nummonsters; } j = 0; for (try2 = 0; j < num && try2 < 100; xp += offset_x[random_(94, 8)], yp += offset_x[random_(94, 8)]) { /// BUGFIX: `yp += offset_y` if (!MonstPlace(xp, yp) || (dTransVal[xp][yp] != dTransVal[x1][y1]) || (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[MA_STAND].Data[monster[nummonsters]._mdir]; monster[nummonsters]._mAnimFrame = random_(88, monster[nummonsters]._mAnimLen - 1) + 1; monster[nummonsters]._mFlags &= ~MFLAG_ALLOW_SPECIAL; monster[nummonsters]._mmode = MM_STAND; } } nummonsters++; placed++; j++; } if (placed >= num) { break; } } if (leaderf & 2) { monster[leader].packsize = placed; } } #ifndef SPAWN void LoadDiabMonsts() { BYTE *lpSetPiece; lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab1.DUN", NULL); SetMapMonsters(lpSetPiece, 2 * diabquad1x, 2 * diabquad1y); mem_free_dbg(lpSetPiece); lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab2a.DUN", NULL); SetMapMonsters(lpSetPiece, 2 * diabquad2x, 2 * diabquad2y); mem_free_dbg(lpSetPiece); lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab3a.DUN", NULL); SetMapMonsters(lpSetPiece, 2 * diabquad3x, 2 * diabquad3y); mem_free_dbg(lpSetPiece); lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab4a.DUN", NULL); SetMapMonsters(lpSetPiece, 2 * diabquad4x, 2 * diabquad4y); mem_free_dbg(lpSetPiece); } #endif void InitMonsters() { int na, nt; int i, s, t; int numplacemonsters; int mtype; int numscattypes; int scattertypes[NUM_MTYPES]; numscattypes = 0; if (gbMaxPlayers != 1) CheckDungeonClear(); if (!setlevel) { AddMonster(1, 0, 0, 0, FALSE); AddMonster(1, 0, 0, 0, FALSE); AddMonster(1, 0, 0, 0, FALSE); AddMonster(1, 0, 0, 0, FALSE); } #ifndef SPAWN if (!setlevel && currlevel == 16) LoadDiabMonsts(); #endif nt = numtrigs; if (currlevel == 15) nt = 1; for (i = 0; i < nt; i++) { for (s = -2; s < 2; s++) { for (t = -2; t < 2; t++) DoVision(s + trigs[i]._tx, t + trigs[i]._ty, 15, FALSE, FALSE); } } #ifndef SPAWN PlaceQuestMonsters(); #endif if (!setlevel) { #ifndef SPAWN PlaceUniques(); #endif na = 0; for (s = 16; s < 96; s++) for (t = 16; t < 96; t++) if (!SolidLoc(s, t)) na++; numplacemonsters = na / 30; if (gbMaxPlayers != 1) numplacemonsters += numplacemonsters >> 1; if (nummonsters + numplacemonsters > MAXMONSTERS - 10) numplacemonsters = MAXMONSTERS - 10 - nummonsters; totalmonsters = nummonsters + numplacemonsters; for (i = 0; i < nummtypes; i++) { if (Monsters[i].mPlaceFlags & PLACE_SCATTER) { scattertypes[numscattypes] = i; numscattypes++; } } while (nummonsters < totalmonsters) { mtype = scattertypes[random_(95, numscattypes)]; if (currlevel == 1 || random_(95, 2) == 0) na = 1; #ifdef HELLFIRE else if (currlevel == 2 || currlevel >= 21 && currlevel <= 24) #else else if (currlevel == 2) #endif na = random_(95, 2) + 2; else na = random_(95, 3) + 3; PlaceGroup(mtype, na, 0, 0); } } for (i = 0; i < nt; i++) { for (s = -2; s < 2; s++) { for (t = -2; t < 2; t++) DoUnVision(s + trigs[i]._tx, t + trigs[i]._ty, 15); } } } #ifndef SPAWN void SetMapMonsters(BYTE *pMap, int startx, int starty) { WORD rw, rh; WORD *lm; int i, j; int mtype; AddMonsterType(MT_GOLEM, PLACE_SPECIAL); // See https://github.com/diasurgical/devilutionX/pull/2822 AddMonster(1, 0, 0, 0, FALSE); // BUGFIX: add only if setlevel is true AddMonster(1, 0, 0, 0, FALSE); // BUGFIX: add only if setlevel is true AddMonster(1, 0, 0, 0, FALSE); // BUGFIX: add only if setlevel is true AddMonster(1, 0, 0, 0, FALSE); // BUGFIX: add only if setlevel is true if (setlevel && setlvlnum == SL_VILEBETRAYER) { AddMonsterType(UniqMonst[UMT_LAZURUS].mtype, PLACE_UNIQUE); AddMonsterType(UniqMonst[UMT_RED_VEX].mtype, PLACE_UNIQUE); AddMonsterType(UniqMonst[UMT_BLACKJADE].mtype, PLACE_UNIQUE); PlaceUniqueMonst(UMT_LAZURUS, 0, 0); PlaceUniqueMonst(UMT_RED_VEX, 0, 0); PlaceUniqueMonst(UMT_BLACKJADE, 0, 0); } lm = (WORD *)pMap; rw = *lm++; rh = *lm++; lm += rw * rh; rw = rw << 1; rh = rh << 1; lm += rw * rh; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm != 0) { mtype = AddMonsterType(MonstConvTbl[(*lm) - 1], PLACE_SPECIAL); PlaceMonster(nummonsters++, mtype, i + startx + 16, j + starty + 16); } lm++; } } } #endif void DeleteMonster(int i) { int temp; nummonsters--; temp = monstactive[nummonsters]; monstactive[nummonsters] = monstactive[i]; monstactive[i] = temp; } int AddMonster(int x, int y, int dir, int mtype, BOOL InMap) { if (nummonsters < MAXMONSTERS) { int i = monstactive[nummonsters++]; if (InMap) dMonster[x][y] = i + 1; InitMonster(i, dir, mtype, x, y); return i; } return -1; } #ifdef HELLFIRE void AddDoppelganger(int i) { int x, y, d, j, oi, dir, mx, my; if (monster[i].MType) { mx = monster[i]._mx; my = monster[i]._my; dir = monster[i]._mdir; for (d = 0; d < 8; d++) { x = mx + offset_x[d]; y = my + offset_y[d]; if (!SolidLoc(x, y)) { if (dPlayer[x][y] == 0 && dMonster[x][y] == 0) { if (dObject[x][y] == 0) break; oi = dObject[x][y] > 0 ? dObject[x][y] - 1 : -(dObject[x][y] + 1); if (!object[oi]._oSolidFlag) break; } } } if (d < 8) { for (j = 0; j < MAX_LVLMTYPES; j++) { if (Monsters[j].mtype == monster[i].MType->mtype) break; } if (j < MAX_LVLMTYPES) AddMonster(x, y, dir, j, TRUE); } } } #endif void NewMonsterAnim(int i, AnimStruct &anim, int md) { MonsterStruct *Monst = &monster[i]; Monst->_mAnimData = anim.Data[md]; Monst->_mAnimLen = anim.Frames; Monst->_mAnimCnt = 0; Monst->_mAnimFrame = 1; Monst->_mAnimDelay = anim.Rate; Monst->_mFlags &= ~(MFLAG_LOCK_ANIMATION | MFLAG_ALLOW_SPECIAL); Monst->_mdir = md; } BOOL M_Ranged(int i) { char ai = monster[i]._mAi; return ai == AI_SKELBOW || ai == AI_GOATBOW || ai == AI_SUCC || ai == AI_LAZHELP; } BOOL M_Talker(int i) { char ai = monster[i]._mAi; return ai == AI_LAZURUS || ai == AI_WARLORD || ai == AI_GARBUD || ai == AI_ZHAR || ai == AI_SNOTSPIL || ai == AI_LACHDAN || ai == AI_LAZHELP; } void M_Enemy(int i) { int j; int mi, pnum; int dist, best_dist; int _menemy; DIABOOL sameroom, bestsameroom; MonsterStruct *Monst; BYTE enemyx, enemyy; _menemy = -1; best_dist = -1; bestsameroom = 0; Monst = &monster[i]; if ( #ifdef HELLFIRE Monst->_mFlags & MFLAG_BERSERK || #endif !(Monst->_mFlags & MFLAG_GOLEM)) { for (pnum = 0; pnum < MAX_PLRS; pnum++) { if (!plr[pnum].plractive || currlevel != plr[pnum].plrlevel || plr[pnum]._pLvlChanging #ifdef HELLFIRE || ((plr[pnum]._pHitPoints >> 6) == 0) #else || (plr[pnum]._pHitPoints == 0 && gbMaxPlayers != 1) #endif ) continue; #ifdef HELLFIRE sameroom = (dTransVal[Monst->_mx][Monst->_my] == dTransVal[plr[pnum]._px][plr[pnum]._py]); #else if (dTransVal[Monst->_mx][Monst->_my] == dTransVal[plr[pnum]._px][plr[pnum]._py]) sameroom = TRUE; else sameroom = FALSE; #endif if (abs(Monst->_mx - plr[pnum]._px) > abs(Monst->_my - plr[pnum]._py)) dist = Monst->_mx - plr[pnum]._px; else dist = Monst->_my - plr[pnum]._py; dist = abs(dist); if ((sameroom && !bestsameroom) || ((sameroom || !bestsameroom) && dist < best_dist) || (_menemy == -1)) { Monst->_mFlags &= ~MFLAG_TARGETS_MONSTER; _menemy = pnum; enemyx = plr[pnum]._pfutx; enemyy = plr[pnum]._pfuty; best_dist = dist; bestsameroom = sameroom; } } } for (j = 0; j < nummonsters; j++) { mi = monstactive[j]; if (mi == i) continue; #ifdef HELLFIRE if (!((monster[mi]._mhitpoints >> 6) > 0)) continue; #endif if (monster[mi]._mx == 1 && monster[mi]._my == 0) continue; if (M_Talker(mi) && monster[mi].mtalkmsg) continue; if ((!(Monst->_mFlags & MFLAG_GOLEM) #ifdef HELLFIRE && !(Monst->_mFlags & MFLAG_BERSERK) #endif && (abs(monster[mi]._mx - Monst->_mx) >= 2 || abs(monster[mi]._my - Monst->_my) >= 2) && !M_Ranged(i)) || (!(Monst->_mFlags & MFLAG_GOLEM) #ifdef HELLFIRE && !(Monst->_mFlags & MFLAG_BERSERK) #endif && !(monster[mi]._mFlags & MFLAG_GOLEM))) { continue; } sameroom = dTransVal[Monst->_mx][Monst->_my] == dTransVal[monster[mi]._mx][monster[mi]._my]; if (abs(Monst->_mx - monster[mi]._mx) > abs(Monst->_my - monster[mi]._my)) dist = Monst->_mx - monster[mi]._mx; else dist = Monst->_my - monster[mi]._my; dist = abs(dist); if ((sameroom && !bestsameroom) || ((sameroom || !bestsameroom) && dist < best_dist) || (_menemy == -1)) { Monst->_mFlags |= MFLAG_TARGETS_MONSTER; _menemy = mi; enemyx = monster[mi]._mfutx; enemyy = monster[mi]._mfuty; best_dist = dist; bestsameroom = sameroom; } } if (_menemy != -1) { Monst->_mFlags &= ~MFLAG_NO_ENEMY; Monst->_menemy = _menemy; Monst->_menemyx = enemyx; Monst->_menemyy = enemyy; } else { Monst->_mFlags |= MFLAG_NO_ENEMY; } } int M_GetDir(int i) { return GetDirection(monster[i]._mx, monster[i]._my, monster[i]._menemyx, monster[i]._menemyy); } void M_CheckEFlag(int i) { int f, j; int x, y; WORD *m; x = monster[i]._mx - 1; y = monster[i]._my + 1; f = 0; // BUGFIX check (x > 0 && y < MAXDUNY) m = dpiece_defs_map_2[x][y].mt; #ifdef HELLFIRE for (j = 2; j < 10; j++) { f |= m[j]; } #else if (m >= dpiece_defs_map_2[0][0].mt) { for (j = 2; j < 10; j++) { f |= m[j]; } } else { monster[i]._meflag = FALSE; return; } #endif if (f | dSpecial[x][y]) monster[i]._meflag = TRUE; else { monster[i]._meflag = FALSE; } } void M_StartStand(int i, int md) { ClearMVars(i); if (monster[i].MType->mtype == MT_GOLEM) NewMonsterAnim(i, monster[i].MType->Anims[MA_WALK], md); else NewMonsterAnim(i, monster[i].MType->Anims[MA_STAND], md); monster[i]._mVar1 = monster[i]._mmode; monster[i]._mVar2 = 0; monster[i]._mmode = MM_STAND; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; monster[i]._mdir = md; M_CheckEFlag(i); M_Enemy(i); } void M_StartDelay(int i, int len) { if (len <= 0) { return; } if (monster[i]._mAi != AI_LAZURUS) { monster[i]._mVar2 = len; monster[i]._mmode = MM_DELAY; } } void M_StartSpStand(int i, int md) { NewMonsterAnim(i, monster[i].MType->Anims[MA_SPECIAL], md); monster[i]._mmode = MM_SPSTAND; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; monster[i]._mdir = md; M_CheckEFlag(i); } void M_StartWalk(int i, int xvel, int yvel, int xadd, int yadd, int EndDir) { int fx = xadd + monster[i]._mx; int fy = yadd + monster[i]._my; dMonster[fx][fy] = -(i + 1); monster[i]._mmode = MM_WALK; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; monster[i]._mfutx = fx; monster[i]._mfuty = fy; monster[i]._mxvel = xvel; monster[i]._myvel = yvel; monster[i]._mVar1 = xadd; monster[i]._mVar2 = yadd; monster[i]._mVar3 = EndDir; monster[i]._mdir = EndDir; NewMonsterAnim(i, monster[i].MType->Anims[MA_WALK], EndDir); monster[i]._mVar6 = 0; monster[i]._mVar7 = 0; monster[i]._mVar8 = 0; M_CheckEFlag(i); } void M_StartWalk2(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int EndDir) { int fx = xadd + monster[i]._mx; int fy = yadd + monster[i]._my; dMonster[monster[i]._mx][monster[i]._my] = -(i + 1); monster[i]._mVar1 = monster[i]._mx; monster[i]._mVar2 = monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; monster[i]._mx = fx; monster[i]._my = fy; monster[i]._mfutx = fx; monster[i]._mfuty = fy; dMonster[fx][fy] = i + 1; #ifdef HELLFIRE if (!(monster[i]._mFlags & MFLAG_HIDDEN) && monster[i].mlid != 0) #else if (monster[i]._uniqtype != 0) #endif ChangeLightXY(monster[i].mlid, monster[i]._mx, monster[i]._my); monster[i]._mxoff = xoff; monster[i]._myoff = yoff; monster[i]._mmode = MM_WALK2; monster[i]._mxvel = xvel; monster[i]._myvel = yvel; monster[i]._mVar3 = EndDir; monster[i]._mdir = EndDir; NewMonsterAnim(i, monster[i].MType->Anims[MA_WALK], EndDir); monster[i]._mVar6 = 16 * xoff; monster[i]._mVar7 = 16 * yoff; monster[i]._mVar8 = 0; M_CheckEFlag(i); } void M_StartWalk3(int i, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int mapx, int mapy, int EndDir) { int fx = xadd + monster[i]._mx; int fy = yadd + monster[i]._my; int x = mapx + monster[i]._mx; int y = mapy + monster[i]._my; #ifdef HELLFIRE if (!(monster[i]._mFlags & MFLAG_HIDDEN) && monster[i].mlid != 0) #else if (monster[i]._uniqtype != 0) #endif ChangeLightXY(monster[i].mlid, x, y); dMonster[monster[i]._mx][monster[i]._my] = -(i + 1); dMonster[fx][fy] = -(i + 1); monster[i]._mVar4 = x; monster[i]._mVar5 = y; dFlags[x][y] |= BFLAG_MONSTLR; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; monster[i]._mfutx = fx; monster[i]._mfuty = fy; monster[i]._mxoff = xoff; monster[i]._myoff = yoff; monster[i]._mmode = MM_WALK3; monster[i]._mxvel = xvel; monster[i]._myvel = yvel; monster[i]._mVar1 = fx; monster[i]._mVar2 = fy; monster[i]._mVar3 = EndDir; monster[i]._mdir = EndDir; NewMonsterAnim(i, monster[i].MType->Anims[MA_WALK], EndDir); monster[i]._mVar6 = 16 * xoff; monster[i]._mVar7 = 16 * yoff; monster[i]._mVar8 = 0; M_CheckEFlag(i); } void M_StartAttack(int i) { int md = M_GetDir(i); NewMonsterAnim(i, monster[i].MType->Anims[MA_ATTACK], md); monster[i]._mmode = MM_ATTACK; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; monster[i]._mdir = md; M_CheckEFlag(i); } void M_StartRAttack(int i, int missile_type, int dam) { int md = M_GetDir(i); NewMonsterAnim(i, monster[i].MType->Anims[MA_ATTACK], md); monster[i]._mmode = MM_RATTACK; monster[i]._mVar1 = missile_type; monster[i]._mVar2 = dam; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; monster[i]._mdir = md; M_CheckEFlag(i); } void M_StartRSpAttack(int i, int missile_type, int dam) { int md = M_GetDir(i); NewMonsterAnim(i, monster[i].MType->Anims[MA_SPECIAL], md); monster[i]._mmode = MM_RSPATTACK; monster[i]._mVar1 = missile_type; monster[i]._mVar2 = 0; monster[i]._mVar3 = dam; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; monster[i]._mdir = md; M_CheckEFlag(i); } void M_StartSpAttack(int i) { int md = M_GetDir(i); NewMonsterAnim(i, monster[i].MType->Anims[MA_SPECIAL], md); monster[i]._mmode = MM_SATTACK; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; monster[i]._mdir = md; M_CheckEFlag(i); } void M_StartEat(int i) { NewMonsterAnim(i, monster[i].MType->Anims[MA_SPECIAL], monster[i]._mdir); monster[i]._mmode = MM_SATTACK; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; M_CheckEFlag(i); } void M_ClearSquares(int i) { int x, y, mx, my, m1, m2; mx = monster[i]._moldx; my = monster[i]._moldy; m1 = -1 - i; m2 = i + 1; #ifdef HELLFIRE for (y = my - 1; y <= my + 1; y++) { for (x = mx - 1; x <= mx + 1; x++) { if (dMonster[x][y] == m1 || dMonster[x][y] == m2) dMonster[x][y] = 0; } } dFlags[mx + 1][my] &= ~BFLAG_MONSTLR; dFlags[mx][my + 1] &= ~BFLAG_MONSTLR; #else for (y = my - 1; y <= my + 1; y++) { if (y >= 0 && y < MAXDUNY) { for (x = mx - 1; x <= mx + 1; x++) { if (x >= 0 && x < MAXDUNX && (dMonster[x][y] == m1 || dMonster[x][y] == m2)) dMonster[x][y] = 0; } } } if (mx + 1 < MAXDUNX) dFlags[mx + 1][my] &= ~BFLAG_MONSTLR; if (my + 1 < MAXDUNY) dFlags[mx][my + 1] &= ~BFLAG_MONSTLR; #endif } void M_GetKnockback(int i) { int d = (monster[i]._mdir - 4) & 7; if (DirOK(i, d)) { M_ClearSquares(i); monster[i]._moldx += offset_x[d]; monster[i]._moldy += offset_y[d]; NewMonsterAnim(i, monster[i].MType->Anims[MA_GOTHIT], monster[i]._mdir); monster[i]._mmode = MM_GOTHIT; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mx = monster[i]._moldx; monster[i]._my = monster[i]._moldy; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; monster[i]._moldx = monster[i]._mx; // CODEFIX: useless assignment monster[i]._moldy = monster[i]._my; // CODEFIX: useless assignment M_CheckEFlag(i); M_ClearSquares(i); dMonster[monster[i]._mx][monster[i]._my] = i + 1; } } void M_StartHit(int i, int pnum, int dam) { if (pnum >= 0) monster[i].mWhoHit |= 1 << pnum; if (pnum == myplr) { delta_monster_hp(i, monster[i]._mhitpoints, currlevel); #ifdef HELLFIRE NetSendCmdMonDmg(FALSE, i, dam); #else NetSendCmdParam2(FALSE, CMD_MONSTDAMAGE, i, dam); #endif } PlayEffect(i, 1); if (monster[i].MType->mtype >= MT_SNEAK && monster[i].MType->mtype <= MT_ILLWEAV || dam >> 6 >= monster[i].mLevel + 3) { if (pnum >= 0) { monster[i]._menemy = pnum; monster[i]._menemyx = plr[pnum]._pfutx; monster[i]._menemyy = plr[pnum]._pfuty; monster[i]._mFlags &= ~MFLAG_TARGETS_MONSTER; monster[i]._mdir = M_GetDir(i); } if (monster[i].MType->mtype == MT_BLINK) { M_Teleport(i); } else if ((monster[i].MType->mtype >= MT_NSCAV && monster[i].MType->mtype <= MT_YSCAV) #ifdef HELLFIRE || monster[i].MType->mtype == MT_GRAVEDIG #endif ) { monster[i]._mgoal = MGOAL_NORMAL; #ifdef HELLFIRE monster[i]._mgoalvar1 = 0; monster[i]._mgoalvar2 = 0; #endif } if (monster[i]._mmode != MM_STONE) { NewMonsterAnim(i, monster[i].MType->Anims[MA_GOTHIT], monster[i]._mdir); monster[i]._mmode = MM_GOTHIT; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mx = monster[i]._moldx; monster[i]._my = monster[i]._moldy; monster[i]._mfutx = monster[i]._moldx; monster[i]._mfuty = monster[i]._moldy; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; M_CheckEFlag(i); M_ClearSquares(i); dMonster[monster[i]._mx][monster[i]._my] = i + 1; } } } void M_DiabloDeath(int i, BOOL sendmsg) { MonsterStruct *Monst; int dist; int j, k; Monst = &monster[i]; #ifndef SPAWN PlaySFX(USFX_DIABLOD); #endif quests[Q_DIABLO]._qactive = QUEST_DONE; if (sendmsg) NetSendCmdQuest(TRUE, Q_DIABLO); sgbSaveSoundOn = gbSoundOn; gbProcessPlayers = FALSE; #ifdef HELLFIRE gbSoundOn = FALSE; #endif for (j = 0; j < nummonsters; j++) { k = monstactive[j]; if (k == i || monster[i]._msquelch == 0) continue; NewMonsterAnim(k, monster[k].MType->Anims[MA_DEATH], monster[k]._mdir); monster[k]._mmode = MM_DEATH; monster[k]._mxoff = 0; monster[k]._myoff = 0; monster[k]._mVar1 = 0; monster[k]._mx = monster[k]._moldx; monster[k]._my = monster[k]._moldy; monster[k]._mfutx = monster[k]._mx; monster[k]._mfuty = monster[k]._my; monster[k]._moldx = monster[k]._mx; // CODEFIX: useless assignment monster[k]._moldy = monster[k]._my; // CODEFIX: useless assignment M_CheckEFlag(k); M_ClearSquares(k); dMonster[monster[k]._mx][monster[k]._my] = k + 1; } AddLight(Monst->_mx, Monst->_my, 8); DoVision(Monst->_mx, Monst->_my, 8, FALSE, TRUE); if (abs(ViewX - Monst->_mx) > abs(ViewY - Monst->_my)) dist = abs(ViewX - Monst->_mx); else dist = abs(ViewY - Monst->_my); if (dist > 20) dist = 20; Monst->_mVar3 = ViewX << 16; Monst->_mVar4 = ViewY << 16; Monst->_mVar5 = (int)((Monst->_mVar3 - (Monst->_mx << 16)) / (double)dist); Monst->_mVar6 = (int)((Monst->_mVar4 - (Monst->_my << 16)) / (double)dist); } #ifdef HELLFIRE void SpawnLoot(int i, BOOL sendmsg) { int nSFX; MonsterStruct *Monst; Monst = &monster[i]; if (QuestStatus(Q_GARBUD) && Monst->mName == UniqMonst[UMT_GARBUD].mName) { CreateTypeItem(Monst->_mx + 1, Monst->_my + 1, TRUE, ITYPE_MACE, IMISC_NONE, TRUE, FALSE); } else if (Monst->mName == UniqMonst[UMT_DEFILER].mName) { if (effect_is_playing(USFX_DEFILER8)) stream_stop(); quests[Q_DEFILER]._qlog = FALSE; SpawnMapOfDoom(Monst->_mx, Monst->_my); } else if (Monst->mName == UniqMonst[UMT_HORKDMN].mName) { if (UseTheoQuest) { SpawnTheodore(Monst->_mx, Monst->_my); } else { CreateAmulet(Monst->_mx, Monst->_my, 13, FALSE, TRUE); } } else if (Monst->MType->mtype == MT_HORKSPWN) { } else if (Monst->MType->mtype == MT_NAKRUL) { nSFX = IsUberRoomOpened ? USFX_NAKRUL4 : USFX_NAKRUL5; if (UseCowFarmer) nSFX = USFX_NAKRUL6; if (effect_is_playing(nSFX)) stream_stop(); quests[Q_NAKRUL]._qlog = FALSE; UberDiabloMonsterIndex = -2; CreateMagicWeapon(Monst->_mx, Monst->_my, ITYPE_SWORD, ICURS_GREAT_SWORD, FALSE, TRUE); CreateMagicWeapon(Monst->_mx, Monst->_my, ITYPE_STAFF, ICURS_WAR_STAFF, FALSE, TRUE); CreateMagicWeapon(Monst->_mx, Monst->_my, ITYPE_BOW, ICURS_LONG_WAR_BOW, FALSE, TRUE); CreateSpellBook(Monst->_mx, Monst->_my, SPL_APOCA, FALSE, TRUE); } else if (i > MAX_PLRS - 1) { // Golems should not spawn loot SpawnItem(i, Monst->_mx, Monst->_my, sendmsg); } } #endif void M2MStartHit(int mid, int i, int dam) { if ((DWORD)mid >= MAXMONSTERS) { #ifdef HELLFIRE return; #else app_fatal("Invalid monster %d getting hit by monster", mid); #endif } if (monster[mid].MType == NULL) { #ifdef HELLFIRE return; #else app_fatal("Monster %d \"%s\" getting hit by monster: MType NULL", mid, monster[mid].mName); #endif } if (i >= 0) // BUGFIX: Missing check for golems `&& i < MAX_PLRS` monster[i].mWhoHit |= 1 << i; // BUGFIX Should be monster[mid].mWhoHit delta_monster_hp(mid, monster[mid]._mhitpoints, currlevel); #ifdef HELLFIRE NetSendCmdMonDmg(FALSE, mid, dam); #else NetSendCmdParam2(FALSE, CMD_MONSTDAMAGE, mid, dam); #endif PlayEffect(mid, 1); if (monster[mid].MType->mtype >= MT_SNEAK && monster[mid].MType->mtype <= MT_ILLWEAV || dam >> 6 >= monster[mid].mLevel + 3) { if (i >= 0) monster[mid]._mdir = (monster[i]._mdir - 4) & 7; if (monster[mid].MType->mtype == MT_BLINK) { M_Teleport(mid); } else if (monster[mid].MType->mtype >= MT_NSCAV && monster[mid].MType->mtype <= MT_YSCAV #ifdef HELLFIRE || monster[mid].MType->mtype == MT_GRAVEDIG #endif ) { monster[mid]._mgoal = MGOAL_NORMAL; #ifdef HELLFIRE monster[mid]._mgoalvar1 = 0; monster[mid]._mgoalvar2 = 0; #endif } if (monster[mid]._mmode != MM_STONE) { if (monster[mid].MType->mtype != MT_GOLEM) { NewMonsterAnim(mid, monster[mid].MType->Anims[MA_GOTHIT], monster[mid]._mdir); monster[mid]._mmode = MM_GOTHIT; } monster[mid]._mxoff = 0; monster[mid]._myoff = 0; monster[mid]._mx = monster[mid]._moldx; monster[mid]._my = monster[mid]._moldy; monster[mid]._mfutx = monster[mid]._moldx; monster[mid]._mfuty = monster[mid]._moldy; monster[mid]._moldx = monster[mid]._mx; monster[mid]._moldy = monster[mid]._my; M_CheckEFlag(mid); M_ClearSquares(mid); dMonster[monster[mid]._mx][monster[mid]._my] = mid + 1; } } } void MonstStartKill(int i, int pnum, BOOL sendmsg) { int md; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) { #ifdef HELLFIRE return; #else app_fatal("MonstStartKill: Invalid monster %d", i); #endif } if (monster[i].MType == NULL) { #ifdef HELLFIRE return; #else app_fatal("MonstStartKill: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif } Monst = &monster[i]; if (pnum >= 0) Monst->mWhoHit |= 1 << pnum; if (pnum < MAX_PLRS && i > MAX_PLRS) /// BUGFIX: i >= MAX_PLRS AddPlrMonstExper(Monst->mLevel, Monst->mExp, Monst->mWhoHit); monstkills[Monst->MType->mtype]++; Monst->_mhitpoints = 0; SetRndSeed(Monst->_mRndSeed); #ifdef HELLFIRE SpawnLoot(i, sendmsg); #else if (QuestStatus(Q_GARBUD) && Monst->mName == UniqMonst[UMT_GARBUD].mName) { CreateTypeItem(Monst->_mx + 1, Monst->_my + 1, TRUE, ITYPE_MACE, IMISC_NONE, TRUE, FALSE); } else if (i > MAX_PLRS - 1) { // Golems should not spawn items SpawnItem(i, Monst->_mx, Monst->_my, sendmsg); } #endif if (Monst->MType->mtype == MT_DIABLO) M_DiabloDeath(i, TRUE); else PlayEffect(i, 2); if (pnum >= 0) md = M_GetDir(i); else md = Monst->_mdir; Monst->_mdir = md; NewMonsterAnim(i, Monst->MType->Anims[MA_DEATH], md); Monst->_mmode = MM_DEATH; #ifdef HELLFIRE Monst->_mgoal = 0; #endif Monst->_mxoff = 0; Monst->_myoff = 0; Monst->_mVar1 = 0; Monst->_mx = Monst->_moldx; Monst->_my = Monst->_moldy; Monst->_mfutx = Monst->_moldx; Monst->_mfuty = Monst->_moldy; M_CheckEFlag(i); M_ClearSquares(i); dMonster[Monst->_mx][Monst->_my] = i + 1; CheckQuestKill(i, sendmsg); M_FallenFear(Monst->_mx, Monst->_my); #ifdef HELLFIRE if (Monst->MType->mtype >= MT_NACID && Monst->MType->mtype <= MT_XACID || Monst->MType->mtype == MT_SPIDLORD) #else if (Monst->MType->mtype >= MT_NACID && Monst->MType->mtype <= MT_XACID) #endif AddMissile(Monst->_mx, Monst->_my, 0, 0, 0, MIS_ACIDPUD, TARGET_PLAYERS, i, Monst->_mint + 1, 0); } void M2MStartKill(int i, int mid) { int md; if ((DWORD)i >= MAXMONSTERS) { #ifdef HELLFIRE return; #else app_fatal("M2MStartKill: Invalid monster (attacker) %d", i); #endif } #ifdef HELLFIRE if ((DWORD)mid >= MAXMONSTERS) { return; #else if ((DWORD)i >= MAXMONSTERS) { /// BUGFIX: should check `mid` app_fatal("M2MStartKill: Invalid monster (killed) %d", mid); #endif } if (monster[i].MType == NULL) /// BUGFIX: should check `mid` #ifdef HELLFIRE return; #else app_fatal("M2MStartKill: Monster %d \"%s\" MType NULL", mid, monster[mid].mName); #endif delta_kill_monster(mid, monster[mid]._mx, monster[mid]._my, currlevel); NetSendCmdLocParam1(FALSE, CMD_MONSTDEATH, monster[mid]._mx, monster[mid]._my, mid); // BUGFIX: missing check for attacking golems `if (0 <= i && i < MAX_PLRS)`. monster[mid].mWhoHit |= 1 << i; if (i < MAX_PLRS) { // BUGFIX: missing check for target golems `if (mid >= MAX_PLRS)`. AddPlrMonstExper(monster[mid].mLevel, monster[mid].mExp, monster[mid].mWhoHit); } monstkills[monster[mid].MType->mtype]++; monster[mid]._mhitpoints = 0; SetRndSeed(monster[mid]._mRndSeed); #ifdef HELLFIRE SpawnLoot(mid, TRUE); #else if (mid >= MAX_PLRS) // Golems should not spawn loot SpawnItem(mid, monster[mid]._mx, monster[mid]._my, TRUE); #endif if (monster[mid].MType->mtype == MT_DIABLO) M_DiabloDeath(mid, TRUE); else #ifndef HELLFIRE PlayEffect(i, 2); #endif PlayEffect(mid, 2); md = (monster[i]._mdir - 4) & 7; if (monster[mid].MType->mtype == MT_GOLEM) md = 0; monster[mid]._mdir = md; NewMonsterAnim(mid, monster[mid].MType->Anims[MA_DEATH], md); monster[mid]._mmode = MM_DEATH; monster[mid]._mxoff = 0; monster[mid]._myoff = 0; monster[mid]._mx = monster[mid]._moldx; monster[mid]._my = monster[mid]._moldy; monster[mid]._mfutx = monster[mid]._mx; monster[mid]._mfuty = monster[mid]._my; monster[mid]._moldx = monster[mid]._mx; monster[mid]._moldy = monster[mid]._my; M_CheckEFlag(mid); M_ClearSquares(mid); dMonster[monster[mid]._mx][monster[mid]._my] = mid + 1; CheckQuestKill(mid, TRUE); M_FallenFear(monster[mid]._mx, monster[mid]._my); if (monster[mid].MType->mtype >= MT_NACID && monster[mid].MType->mtype <= MT_XACID) AddMissile(monster[mid]._mx, monster[mid]._my, 0, 0, 0, MIS_ACIDPUD, TARGET_PLAYERS, mid, monster[mid]._mint + 1, 0); #ifdef HELLFIRE M_StartStand(i, monster[i]._mdir); #endif } void M_StartKill(int i, int pnum) { if ((DWORD)i >= MAXMONSTERS) { #ifdef HELLFIRE return; #else app_fatal("M_StartKill: Invalid monster %d", i); #endif } if (myplr == pnum) { delta_kill_monster(i, monster[i]._mx, monster[i]._my, currlevel); if (i != pnum) { NetSendCmdLocParam1(FALSE, CMD_MONSTDEATH, monster[i]._mx, monster[i]._my, i); } else { NetSendCmdLocParam1(FALSE, CMD_KILLGOLEM, monster[i]._mx, monster[i]._my, currlevel); } } MonstStartKill(i, pnum, TRUE); } void M_SyncStartKill(int i, int x, int y, int pnum) { if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("M_SyncStartKill: Invalid monster %d", i); #endif if (monster[i]._mhitpoints == 0 || monster[i]._mmode == MM_DEATH) { return; } if (dMonster[x][y] == 0) { M_ClearSquares(i); monster[i]._mx = x; monster[i]._my = y; monster[i]._moldx = x; monster[i]._moldy = y; } #ifdef HELLFIRE MonstStartKill(i, pnum, FALSE); #else if (monster[i]._mmode == MM_STONE) { MonstStartKill(i, pnum, FALSE); monster[i]._mmode = MM_STONE; } else { MonstStartKill(i, pnum, FALSE); } #endif } void M_StartFadein(int i, int md, BOOL backwards) { if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("M_StartFadein: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return; #else app_fatal("M_StartFadein: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif NewMonsterAnim(i, monster[i].MType->Anims[MA_SPECIAL], md); monster[i]._mmode = MM_FADEIN; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; M_CheckEFlag(i); monster[i]._mdir = md; monster[i]._mFlags &= ~MFLAG_HIDDEN; if (backwards) { monster[i]._mFlags |= MFLAG_LOCK_ANIMATION; monster[i]._mAnimFrame = monster[i]._mAnimLen; } } void M_StartFadeout(int i, int md, BOOL backwards) { if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("M_StartFadeout: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return; #else app_fatal("M_StartFadeout: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif NewMonsterAnim(i, monster[i].MType->Anims[MA_SPECIAL], md); monster[i]._mmode = MM_FADEOUT; monster[i]._mxoff = 0; monster[i]._myoff = 0; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; M_CheckEFlag(i); monster[i]._mdir = md; if (backwards) { monster[i]._mFlags |= MFLAG_LOCK_ANIMATION; monster[i]._mAnimFrame = monster[i]._mAnimLen; } } void M_StartHeal(int i) { MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("M_StartHeal: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return; #else app_fatal("M_StartHeal: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif Monst = &monster[i]; Monst->_mAnimData = Monst->MType->Anims[MA_SPECIAL].Data[Monst->_mdir]; Monst->_mAnimFrame = Monst->MType->Anims[MA_SPECIAL].Frames; Monst->_mFlags |= MFLAG_LOCK_ANIMATION; Monst->_mmode = MM_HEAL; Monst->_mVar1 = Monst->_mmaxhp / (16 * (random_(97, 5) + 4)); } void M_ChangeLightOffset(int monst) { int lx, ly, _mxoff, _myoff, sign; if ((DWORD)monst >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("M_ChangeLightOffset: Invalid monster %d", monst); #endif lx = monster[monst]._mxoff + 2 * monster[monst]._myoff; ly = 2 * monster[monst]._myoff - monster[monst]._mxoff; if (lx < 0) { sign = -1; lx = -lx; } else { sign = 1; } _mxoff = sign * (lx >> 3); if (ly < 0) { _myoff = -1; ly = -ly; } else { _myoff = 1; } _myoff *= (ly >> 3); #ifdef HELLFIRE if (monster[monst].mlid != 0) #endif ChangeLightOff(monster[monst].mlid, _mxoff, _myoff); } BOOL M_DoStand(int i) { MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoStand: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoStand: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif Monst = &monster[i]; if (Monst->MType->mtype == MT_GOLEM) Monst->_mAnimData = Monst->MType->Anims[MA_WALK].Data[Monst->_mdir]; else Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[Monst->_mdir]; if (Monst->_mAnimFrame == Monst->_mAnimLen) M_Enemy(i); Monst->_mVar2++; // BUGFIX: Should have a bound check as this will overflow if a player stays on same level for over 3 years. return FALSE; } BOOL M_DoWalk(int i) { BOOL rv; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoWalk: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoWalk: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif if (monster[i]._mVar8 == monster[i].MType->Anims[MA_WALK].Frames) { dMonster[monster[i]._mx][monster[i]._my] = 0; monster[i]._mx += monster[i]._mVar1; monster[i]._my += monster[i]._mVar2; dMonster[monster[i]._mx][monster[i]._my] = i + 1; #ifdef HELLFIRE if (!(monster[i]._mFlags & MFLAG_HIDDEN) && monster[i].mlid != 0) #else if (monster[i]._uniqtype != 0) #endif ChangeLightXY(monster[i].mlid, monster[i]._mx, monster[i]._my); M_StartStand(i, monster[i]._mdir); rv = TRUE; } else { if (monster[i]._mAnimCnt == 0) { #ifdef HELLFIRE if (monster[i]._mVar8 == 0 && monster[i].MType->mtype == MT_FLESTHNG) PlayEffect(i, 3); #endif monster[i]._mVar8++; monster[i]._mVar6 += monster[i]._mxvel; monster[i]._mVar7 += monster[i]._myvel; monster[i]._mxoff = monster[i]._mVar6 >> 4; monster[i]._myoff = monster[i]._mVar7 >> 4; } rv = FALSE; } #ifdef HELLFIRE if (!(monster[i]._mFlags & MFLAG_HIDDEN) && monster[i].mlid != 0) #else if (monster[i]._uniqtype != 0) #endif M_ChangeLightOffset(i); return rv; } BOOL M_DoWalk2(int i) { BOOL rv; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoWalk2: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoWalk2: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif if (monster[i]._mVar8 == monster[i].MType->Anims[MA_WALK].Frames) { dMonster[monster[i]._mVar1][monster[i]._mVar2] = 0; #ifdef HELLFIRE if (!(monster[i]._mFlags & MFLAG_HIDDEN) && monster[i].mlid != 0) #else if (monster[i]._uniqtype != 0) #endif ChangeLightXY(monster[i].mlid, monster[i]._mx, monster[i]._my); M_StartStand(i, monster[i]._mdir); rv = TRUE; } else { if (monster[i]._mAnimCnt == 0) { #ifdef HELLFIRE if (monster[i]._mVar8 == 0 && monster[i].MType->mtype == MT_FLESTHNG) PlayEffect(i, 3); #endif monster[i]._mVar8++; monster[i]._mVar6 += monster[i]._mxvel; monster[i]._mVar7 += monster[i]._myvel; monster[i]._mxoff = monster[i]._mVar6 >> 4; monster[i]._myoff = monster[i]._mVar7 >> 4; } rv = FALSE; } #ifdef HELLFIRE if (!(monster[i]._mFlags & MFLAG_HIDDEN) && monster[i].mlid != 0) #else if (monster[i]._uniqtype != 0) #endif M_ChangeLightOffset(i); return rv; } BOOL M_DoWalk3(int i) { BOOL rv; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoWalk3: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoWalk3: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif if (monster[i]._mVar8 == monster[i].MType->Anims[MA_WALK].Frames) { dMonster[monster[i]._mx][monster[i]._my] = 0; monster[i]._mx = monster[i]._mVar1; monster[i]._my = monster[i]._mVar2; dFlags[monster[i]._mVar4][monster[i]._mVar5] &= ~BFLAG_MONSTLR; dMonster[monster[i]._mx][monster[i]._my] = i + 1; #ifdef HELLFIRE if (!(monster[i]._mFlags & MFLAG_HIDDEN) && monster[i].mlid != 0) #else if (monster[i]._uniqtype != 0) #endif ChangeLightXY(monster[i].mlid, monster[i]._mx, monster[i]._my); M_StartStand(i, monster[i]._mdir); rv = TRUE; } else { if (monster[i]._mAnimCnt == 0) { #ifdef HELLFIRE if (monster[i]._mVar8 == 0 && monster[i].MType->mtype == MT_FLESTHNG) PlayEffect(i, 3); #endif monster[i]._mVar8++; monster[i]._mVar6 += monster[i]._mxvel; monster[i]._mVar7 += monster[i]._myvel; monster[i]._mxoff = monster[i]._mVar6 >> 4; monster[i]._myoff = monster[i]._mVar7 >> 4; } rv = FALSE; } #ifdef HELLFIRE if (monster[i]._uniqtype != 0 && !(monster[i]._mFlags & MFLAG_HIDDEN)) // BUGFIX: change uniqtype check to mlid check like it is in all other places #else if (monster[i]._uniqtype != 0) #endif M_ChangeLightOffset(i); return rv; } void M_TryM2MHit(int i, int mid, int hper, int mind, int maxd) { BOOL ret; if ((DWORD)mid >= MAXMONSTERS) { #ifdef HELLFIRE return; #else app_fatal("M_TryM2MHit: Invalid monster %d", mid); #endif } if (monster[mid].MType == NULL) #ifdef HELLFIRE return; #else app_fatal("M_TryM2MHit: Monster %d \"%s\" MType NULL", mid, monster[mid].mName); #endif if (monster[mid]._mhitpoints >> 6 > 0 && (monster[mid].MType->mtype != MT_ILLWEAV || monster[mid]._mgoal != MGOAL_RETREAT)) { int hit = random_(4, 100); if (monster[mid]._mmode == MM_STONE) hit = 0; if (!CheckMonsterHit(mid, ret) && hit < hper) { int dam = (mind + random_(5, maxd - mind + 1)) << 6; monster[mid]._mhitpoints -= dam; if (monster[mid]._mhitpoints >> 6 <= 0) { if (monster[mid]._mmode == MM_STONE) { M2MStartKill(i, mid); monster[mid]._mmode = MM_STONE; } else { M2MStartKill(i, mid); } } else { if (monster[mid]._mmode == MM_STONE) { M2MStartHit(mid, i, dam); monster[mid]._mmode = MM_STONE; } else { M2MStartHit(mid, i, dam); } } } } } void M_TryH2HHit(int i, int pnum, int Hit, int MinDam, int MaxDam) { int hit, hper; int dx, dy; int blk, blkper; int dam, mdam; int newx, newy; int j, misnum, ms_num, cur_ms_num, new_hp, dir, ac; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("M_TryH2HHit: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return; #else app_fatal("M_TryH2HHit: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif if (monster[i]._mFlags & MFLAG_TARGETS_MONSTER) { M_TryM2MHit(i, pnum, Hit, MinDam, MaxDam); return; } if (plr[pnum]._pHitPoints >> 6 <= 0 || plr[pnum]._pInvincible || plr[pnum]._pSpellFlags & 1) return; dx = abs(monster[i]._mx - plr[pnum]._px); dy = abs(monster[i]._my - plr[pnum]._py); if (dx >= 2 || dy >= 2) return; hper = random_(98, 100); #ifdef _DEBUG if (debug_mode_dollar_sign || debug_mode_key_inverted_v) hper = 1000; #endif ac = plr[pnum]._pIBonusAC + plr[pnum]._pIAC; #ifdef HELLFIRE if (plr[pnum].pDamAcFlags & ISPLHF_ACDEMON && monster[i].MData->mMonstClass == MC_DEMON) ac += 40; if (plr[pnum].pDamAcFlags & ISPLHF_ACUNDEAD && monster[i].MData->mMonstClass == MC_UNDEAD) ac += 20; #endif hit = Hit + 2 * (monster[i].mLevel - plr[pnum]._pLevel) + 30 - ac - plr[pnum]._pDexterity / 5; if (hit < 15) hit = 15; if (currlevel == 14 && hit < 20) hit = 20; if (currlevel == 15 && hit < 25) hit = 25; if (currlevel == 16 && hit < 30) hit = 30; if ((plr[pnum]._pmode == PM_STAND || plr[pnum]._pmode == PM_ATTACK) && plr[pnum]._pBlockFlag) { blkper = random_(98, 100); } else { blkper = 100; } blk = plr[pnum]._pDexterity + plr[pnum]._pBaseToBlk - (monster[i].mLevel << 1) + (plr[pnum]._pLevel << 1); if (blk < 0) blk = 0; if (blk > 100) blk = 100; if (hper >= hit) return; if (blkper < blk) { dir = GetDirection(plr[pnum]._px, plr[pnum]._py, monster[i]._mx, monster[i]._my); StartPlrBlock(pnum, dir); #ifdef HELLFIRE if (pnum == myplr && plr[pnum].wReflections > 0) { plr[pnum].wReflections--; dam = random_(99, (MaxDam - MinDam + 1) << 6) + (MinDam << 6); dam += plr[pnum]._pIGetHit << 6; if (dam < 64) dam = 64; mdam = dam * (0.01 * (random_(100, 10) + 20)); monster[i]._mhitpoints -= mdam; dam -= mdam; if (dam < 0) dam = 0; if (monster[i]._mhitpoints >> 6 <= 0) M_StartKill(i, pnum); else M_StartHit(i, pnum, mdam); } #endif return; } if (monster[i].MType->mtype == MT_YZOMBIE && pnum == myplr) { ms_num = -1; cur_ms_num = -1; for (j = 0; j < nummissiles; j++) { misnum = missileactive[j]; if (missile[misnum]._mitype != MIS_MANASHIELD) continue; if (missile[misnum]._misource == pnum) cur_ms_num = misnum; else ms_num = misnum; } if (plr[pnum]._pMaxHP > 64) { #ifndef HELLFIRE if (plr[pnum]._pMaxHPBase > 64) #endif { plr[pnum]._pMaxHP -= 64; if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) { plr[pnum]._pHitPoints = plr[pnum]._pMaxHP; if (cur_ms_num >= 0) missile[cur_ms_num]._miVar1 = plr[pnum]._pHitPoints; } plr[pnum]._pMaxHPBase -= 64; if (plr[pnum]._pHPBase > plr[pnum]._pMaxHPBase) { plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase; if (cur_ms_num >= 0) missile[cur_ms_num]._miVar2 = plr[pnum]._pHPBase; } } } } dam = (MinDam << 6) + random_(99, (MaxDam - MinDam + 1) << 6); dam += (plr[pnum]._pIGetHit << 6); if (dam < 64) dam = 64; if (pnum == myplr) { #ifdef HELLFIRE if (plr[pnum].wReflections > 0) { plr[pnum].wReflections--; mdam = dam * (0.01 * (random_(100, 10) + 20)); monster[i]._mhitpoints -= mdam; dam -= mdam; if (dam < 0) dam = 0; if (monster[i]._mhitpoints >> 6 <= 0) M_StartKill(i, pnum); else M_StartHit(i, pnum, mdam); } #endif plr[pnum]._pHitPoints -= dam; plr[pnum]._pHPBase -= dam; } if (plr[pnum]._pIFlags & ISPL_THORNS) { mdam = (random_(99, 3) + 1) << 6; monster[i]._mhitpoints -= mdam; if (monster[i]._mhitpoints >> 6 <= 0) M_StartKill(i, pnum); else M_StartHit(i, pnum, mdam); } if (!(monster[i]._mFlags & MFLAG_NOLIFESTEAL) && monster[i].MType->mtype == MT_SKING && gbMaxPlayers != 1) monster[i]._mhitpoints += dam; if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) { plr[pnum]._pHitPoints = plr[pnum]._pMaxHP; plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase; } if (plr[pnum]._pHitPoints >> 6 <= 0) { SyncPlrKill(pnum, 0); #ifdef HELLFIRE M_StartStand(i, monster[i]._mdir); #endif return; } StartPlrHit(pnum, dam, FALSE); if (monster[i]._mFlags & MFLAG_KNOCKBACK) { if (plr[pnum]._pmode != PM_GOTHIT) StartPlrHit(pnum, 0, TRUE); newx = plr[pnum]._px + offset_x[monster[i]._mdir]; newy = plr[pnum]._py + offset_y[monster[i]._mdir]; if (PosOkPlayer(pnum, newx, newy)) { plr[pnum]._px = newx; plr[pnum]._py = newy; FixPlayerLocation(pnum, plr[pnum]._pdir); FixPlrWalkTags(pnum); dPlayer[newx][newy] = pnum + 1; SetPlayerOld(pnum); } } } BOOL M_DoAttack(int i) { MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoAttack: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoAttack: Monster %d \"%s\" MType NULL", i, Monst->mName); #endif if (Monst->MType == NULL) // BUGFIX: should check MData #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoAttack: Monster %d \"%s\" MData NULL", i, Monst->mName); #endif if (monster[i]._mAnimFrame == monster[i].MData->mAFNum) { M_TryH2HHit(i, monster[i]._menemy, monster[i].mHit, monster[i].mMinDamage, monster[i].mMaxDamage); if (monster[i]._mAi != AI_SNAKE) PlayEffect(i, 0); } if (monster[i].MType->mtype >= MT_NMAGMA && monster[i].MType->mtype <= MT_WMAGMA && monster[i]._mAnimFrame == 9) { M_TryH2HHit(i, monster[i]._menemy, monster[i].mHit + 10, monster[i].mMinDamage - 2, monster[i].mMaxDamage - 2); PlayEffect(i, 0); } if (monster[i].MType->mtype >= MT_STORM && monster[i].MType->mtype <= MT_MAEL && monster[i]._mAnimFrame == 13) { M_TryH2HHit(i, monster[i]._menemy, monster[i].mHit - 20, monster[i].mMinDamage + 4, monster[i].mMaxDamage + 4); PlayEffect(i, 0); } if (monster[i]._mAi == AI_SNAKE && monster[i]._mAnimFrame == 1) PlayEffect(i, 0); if (monster[i]._mAnimFrame == monster[i]._mAnimLen) { M_StartStand(i, monster[i]._mdir); return TRUE; } return FALSE; } BOOL M_DoRAttack(int i) { int multimissiles, mi; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoRAttack: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoRAttack: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif if (monster[i].MType == NULL) // BUGFIX: should check MData #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoRAttack: Monster %d \"%s\" MData NULL", i, monster[i].mName); #endif if (monster[i]._mAnimFrame == monster[i].MData->mAFNum) { if (monster[i]._mVar1 != -1) { if (monster[i]._mVar1 == MIS_CBOLT) multimissiles = 3; else multimissiles = 1; for (mi = 0; mi < multimissiles; mi++) { AddMissile( #ifdef HELLFIRE monster[i]._mx + HorkXAdd[monster[i]._mdir], monster[i]._my + HorkYAdd[monster[i]._mdir], #else monster[i]._mx, monster[i]._my, #endif monster[i]._menemyx, monster[i]._menemyy, monster[i]._mdir, monster[i]._mVar1, TARGET_PLAYERS, i, monster[i]._mVar2, 0); } } PlayEffect(i, 0); } if (monster[i]._mAnimFrame == monster[i]._mAnimLen) { M_StartStand(i, monster[i]._mdir); return TRUE; } return FALSE; } BOOL M_DoRSpAttack(int i) { if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoRSpAttack: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoRSpAttack: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif if (monster[i].MType == NULL) // BUGFIX: should check MData #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoRSpAttack: Monster %d \"%s\" MData NULL", i, monster[i].mName); #endif if (monster[i]._mAnimFrame == monster[i].MData->mAFNum2 && monster[i]._mAnimCnt == 0) { AddMissile( #ifdef HELLFIRE monster[i]._mx + HorkXAdd[monster[i]._mdir], monster[i]._my + HorkYAdd[monster[i]._mdir], #else monster[i]._mx, monster[i]._my, #endif monster[i]._menemyx, monster[i]._menemyy, monster[i]._mdir, monster[i]._mVar1, TARGET_PLAYERS, i, monster[i]._mVar3, 0); #ifdef HELLFIRE if (Monsters[i].Snds[3][0] != 0) // BUGFIX `Monsters[i].` should be `monster[i].MType->` #endif PlayEffect(i, 3); } if (monster[i]._mAi == AI_MEGA && monster[i]._mAnimFrame == 3) { if (monster[i]._mVar2++ == 0) { monster[i]._mFlags |= MFLAG_ALLOW_SPECIAL; } else if (monster[i]._mVar2 == 15) { monster[i]._mFlags &= ~MFLAG_ALLOW_SPECIAL; } } if (monster[i]._mAnimFrame == monster[i]._mAnimLen) { M_StartStand(i, monster[i]._mdir); return TRUE; } return FALSE; } BOOL M_DoSAttack(int i) { if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoSAttack: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoSAttack: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif if (monster[i].MType == NULL) // BUGFIX: should check MData #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoSAttack: Monster %d \"%s\" MData NULL", i, monster[i].mName); #endif if (monster[i]._mAnimFrame == monster[i].MData->mAFNum2) M_TryH2HHit(i, monster[i]._menemy, monster[i].mHit2, monster[i].mMinDamage2, monster[i].mMaxDamage2); if (monster[i]._mAnimFrame == monster[i]._mAnimLen) { M_StartStand(i, monster[i]._mdir); return TRUE; } return FALSE; } BOOL M_DoFadein(int i) { if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoFadein: Invalid monster %d", i); #endif if ((!(monster[i]._mFlags & MFLAG_LOCK_ANIMATION) || monster[i]._mAnimFrame != 1) && (monster[i]._mFlags & MFLAG_LOCK_ANIMATION || monster[i]._mAnimFrame != monster[i]._mAnimLen)) { return FALSE; } M_StartStand(i, monster[i]._mdir); monster[i]._mFlags &= ~MFLAG_LOCK_ANIMATION; return TRUE; } BOOL M_DoFadeout(int i) { int mt; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoFadeout: Invalid monster %d", i); #endif if ((!(monster[i]._mFlags & MFLAG_LOCK_ANIMATION) || monster[i]._mAnimFrame != 1) && (monster[i]._mFlags & MFLAG_LOCK_ANIMATION || monster[i]._mAnimFrame != monster[i]._mAnimLen)) { return FALSE; } mt = monster[i].MType->mtype; if (mt < MT_INCIN || mt > MT_HELLBURN) { monster[i]._mFlags &= ~MFLAG_LOCK_ANIMATION; monster[i]._mFlags |= MFLAG_HIDDEN; } else { monster[i]._mFlags &= ~MFLAG_LOCK_ANIMATION; } M_StartStand(i, monster[i]._mdir); return TRUE; } BOOL M_DoHeal(int i) { MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoHeal: Invalid monster %d", i); #endif Monst = &monster[i]; if (monster[i]._mFlags & MFLAG_NOHEAL) { #ifndef HELLFIRE Monst->_mFlags &= ~MFLAG_ALLOW_SPECIAL; Monst->_mmode = MM_SATTACK; #endif return FALSE; } if (Monst->_mAnimFrame == 1) { Monst->_mFlags &= ~MFLAG_LOCK_ANIMATION; Monst->_mFlags |= MFLAG_ALLOW_SPECIAL; if (Monst->_mVar1 + Monst->_mhitpoints < Monst->_mmaxhp) { Monst->_mhitpoints = Monst->_mVar1 + Monst->_mhitpoints; } else { Monst->_mhitpoints = Monst->_mmaxhp; Monst->_mFlags &= ~MFLAG_ALLOW_SPECIAL; Monst->_mmode = MM_SATTACK; } } return FALSE; } BOOL M_DoTalk(int i) { MonsterStruct *Monst; int tren; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoTalk: Invalid monster %d", i); #endif Monst = &monster[i]; M_StartStand(i, monster[i]._mdir); Monst->_mgoal = MGOAL_TALKING; // CODEFIX: apply Monst instead of monster[i] in the rest of the function if (effect_is_playing(alltext[monster[i].mtalkmsg].sfxnr)) return FALSE; InitQTextMsg(monster[i].mtalkmsg); if (monster[i].mName == UniqMonst[UMT_GARBUD].mName) { if (monster[i].mtalkmsg == TEXT_GARBUD1) quests[Q_GARBUD]._qactive = QUEST_ACTIVE; quests[Q_GARBUD]._qlog = TRUE; // BUGFIX: (?) for other quests qactive and qlog go together, maybe this should actually go into the if above if (monster[i].mtalkmsg == TEXT_GARBUD2 && !(monster[i]._mFlags & MFLAG_QUEST_COMPLETE)) { SpawnItem(i, monster[i]._mx + 1, monster[i]._my + 1, TRUE); monster[i]._mFlags |= MFLAG_QUEST_COMPLETE; } } if (monster[i].mName == UniqMonst[UMT_ZHAR].mName && monster[i].mtalkmsg == TEXT_ZHAR1 && !(monster[i]._mFlags & MFLAG_QUEST_COMPLETE)) { quests[Q_ZHAR]._qactive = QUEST_ACTIVE; quests[Q_ZHAR]._qlog = TRUE; CreateTypeItem(monster[i]._mx + 1, monster[i]._my + 1, FALSE, ITYPE_MISC, IMISC_BOOK, TRUE, FALSE); monster[i]._mFlags |= MFLAG_QUEST_COMPLETE; } if (monster[i].mName == UniqMonst[UMT_SNOTSPIL].mName) { if (monster[i].mtalkmsg == TEXT_BANNER10 && !(monster[i]._mFlags & MFLAG_QUEST_COMPLETE)) { ObjChangeMap(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 2, (setpc_h >> 1) + setpc_y - 2); tren = TransVal; TransVal = 9; DRLG_MRectTrans(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 4, setpc_y + (setpc_h >> 1)); TransVal = tren; quests[Q_LTBANNER]._qvar1 = 2; if (quests[Q_LTBANNER]._qactive == QUEST_INIT) quests[Q_LTBANNER]._qactive = QUEST_ACTIVE; monster[i]._mFlags |= MFLAG_QUEST_COMPLETE; } if (quests[Q_LTBANNER]._qvar1 < 2) { sprintf(tempstr, "SS Talk = %i, Flags = %i", monster[i].mtalkmsg, monster[i]._mFlags); // CODEFIX: no need for tempstr, app_fatal supports v_args app_fatal(tempstr); } } if (monster[i].mName == UniqMonst[UMT_LACHDAN].mName) { if (monster[i].mtalkmsg == TEXT_VEIL9) { quests[Q_VEIL]._qactive = QUEST_ACTIVE; quests[Q_VEIL]._qlog = TRUE; } if (monster[i].mtalkmsg == TEXT_VEIL11 && !(monster[i]._mFlags & MFLAG_QUEST_COMPLETE)) { SpawnUnique(UITEM_STEELVEIL, monster[i]._mx + 1, monster[i]._my + 1); monster[i]._mFlags |= MFLAG_QUEST_COMPLETE; } } if (monster[i].mName == UniqMonst[UMT_WARLORD].mName) quests[Q_WARLORD]._qvar1 = 2; if (monster[i].mName == UniqMonst[UMT_LAZURUS].mName && gbMaxPlayers != 1) { quests[Q_BETRAYER]._qvar1 = 6; monster[i]._mgoal = MGOAL_NORMAL; monster[i]._msquelch = UCHAR_MAX; monster[i].mtalkmsg = 0; } return FALSE; } void M_Teleport(int i) { BOOL done; MonsterStruct *Monst; int k, j, x, y, _mx, _my, rx, ry; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("M_Teleport: Invalid monster %d", i); #endif done = FALSE; Monst = &monster[i]; if (Monst->_mmode == MM_STONE) return; _mx = Monst->_menemyx; _my = Monst->_menemyy; rx = 2 * random_(100, 2) - 1; ry = 2 * random_(100, 2) - 1; for (j = -1; j <= 1 && !done; j++) { for (k = -1; k < 1 && !done; k++) { if (j != 0 || k != 0) { x = _mx + rx * j; y = _my + ry * k; if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX && x != Monst->_mx && y != Monst->_my) { if (PosOkMonst(i, x, y)) done = TRUE; } } } } if (done) { M_ClearSquares(i); dMonster[Monst->_mx][Monst->_my] = 0; dMonster[x][y] = i + 1; Monst->_moldx = x; Monst->_moldy = y; Monst->_mdir = M_GetDir(i); M_CheckEFlag(i); } } BOOL M_DoGotHit(int i) { if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoGotHit: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoGotHit: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif if (monster[i]._mAnimFrame == monster[i]._mAnimLen) { M_StartStand(i, monster[i]._mdir); return TRUE; } return FALSE; } void M_UpdateLeader(int i) { int ma, j; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("M_UpdateLeader: Invalid monster %d", i); #endif for (j = 0; j < nummonsters; j++) { ma = monstactive[j]; if (monster[ma].leaderflag == 1 && monster[ma].leader == i) monster[ma].leaderflag = 0; } if (monster[i].leaderflag == 1) { monster[monster[i].leader].packsize--; } } void DoEnding() { BOOL bMusicOn; int musicVolume; if (gbMaxPlayers > 1) { SNetLeaveGame(LEAVE_ENDING); } music_stop(); if (gbMaxPlayers > 1) { Sleep(1000); } #ifndef SPAWN #ifdef HELLFIRE if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_BARBARIAN) { #else if (plr[myplr]._pClass == PC_WARRIOR) { #endif play_movie("gendata\\DiabVic2.smk", FALSE); } else if (plr[myplr]._pClass == PC_SORCERER) { play_movie("gendata\\DiabVic1.smk", FALSE); #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { play_movie("gendata\\DiabVic1.smk", FALSE); #endif } else { play_movie("gendata\\DiabVic3.smk", FALSE); } play_movie("gendata\\Diabend.smk", FALSE); bMusicOn = gbMusicOn; gbMusicOn = TRUE; musicVolume = sound_get_or_set_music_volume(1); sound_get_or_set_music_volume(0); music_start(TMUSIC_L2); loop_movie = TRUE; play_movie("gendata\\loopdend.smk", TRUE); loop_movie = FALSE; music_stop(); sound_get_or_set_music_volume(musicVolume); gbMusicOn = bMusicOn; #endif } void PrepDoEnding() { int newKillLevel, i; DWORD *killLevel; gbSoundOn = sgbSaveSoundOn; gbRunGame = FALSE; deathflag = FALSE; cineflag = TRUE; killLevel = &plr[myplr].pDiabloKillLevel; newKillLevel = gnDifficulty + 1; if (*killLevel > newKillLevel) newKillLevel = *killLevel; plr[myplr].pDiabloKillLevel = newKillLevel; for (i = 0; i < MAX_PLRS; i++) { plr[i]._pmode = PM_QUIT; plr[i]._pInvincible = TRUE; if (gbMaxPlayers > 1) { if (plr[i]._pHitPoints >> 6 == 0) plr[i]._pHitPoints = 64; if (plr[i]._pMana >> 6 == 0) plr[i]._pMana = 64; } } } BOOL M_DoDeath(int i) { int x, y; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoDeath: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoDeath: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif monster[i]._mVar1++; if (monster[i].MType->mtype == MT_DIABLO) { x = monster[i]._mx - ViewX; if (x < 0) x = -1; else x = x > 0; ViewX += x; y = monster[i]._my - ViewY; if (y < 0) { y = -1; } else { y = y > 0; } ViewY += y; if (monster[i]._mVar1 == 140) PrepDoEnding(); } else if (monster[i]._mAnimFrame == monster[i]._mAnimLen) { if (monster[i]._uniqtype == 0) AddDead(monster[i]._mx, monster[i]._my, monster[i].MType->mdeadval, (direction)monster[i]._mdir); else AddDead(monster[i]._mx, monster[i]._my, monster[i]._udeadval, (direction)monster[i]._mdir); dMonster[monster[i]._mx][monster[i]._my] = 0; monster[i]._mDelFlag = TRUE; M_UpdateLeader(i); } return FALSE; } BOOL M_DoSpStand(int i) { if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoSpStand: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoSpStand: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif if (monster[i]._mAnimFrame == monster[i].MData->mAFNum2) PlayEffect(i, 3); if (monster[i]._mAnimFrame == monster[i]._mAnimLen) { M_StartStand(i, monster[i]._mdir); return TRUE; } return FALSE; } BOOL M_DoDelay(int i) { int oFrame; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoDelay: Invalid monster %d", i); #endif if (monster[i].MType == NULL) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoDelay: Monster %d \"%s\" MType NULL", i, monster[i].mName); #endif monster[i]._mAnimData = monster[i].MType->Anims[MA_STAND].Data[M_GetDir(i)]; if (monster[i]._mAi == AI_LAZURUS) { if (monster[i]._mVar2 > 8 || monster[i]._mVar2 < 0) monster[i]._mVar2 = 8; } if (monster[i]._mVar2-- == 0) { oFrame = monster[i]._mAnimFrame; M_StartStand(i, monster[i]._mdir); monster[i]._mAnimFrame = oFrame; return TRUE; } return FALSE; } BOOL M_DoStone(int i) { if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_DoStone: Invalid monster %d", i); #endif if (monster[i]._mhitpoints == 0) { dMonster[monster[i]._mx][monster[i]._my] = 0; monster[i]._mDelFlag = TRUE; } return FALSE; } void M_WalkDir(int i, int md) { int mwi; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("M_WalkDir: Invalid monster %d", i); #endif mwi = monster[i].MType->Anims[MA_WALK].Frames - 1; switch (md) { case DIR_N: M_StartWalk(i, 0, -MWVel[mwi][1], -1, -1, DIR_N); break; case DIR_NE: M_StartWalk(i, MWVel[mwi][1], -MWVel[mwi][0], 0, -1, DIR_NE); break; case DIR_E: M_StartWalk3(i, MWVel[mwi][2], 0, -32, -16, 1, -1, 1, 0, DIR_E); break; case DIR_SE: M_StartWalk2(i, MWVel[mwi][1], MWVel[mwi][0], -32, -16, 1, 0, DIR_SE); break; case DIR_S: M_StartWalk2(i, 0, MWVel[mwi][1], 0, -32, 1, 1, DIR_S); break; case DIR_SW: M_StartWalk2(i, -MWVel[mwi][1], MWVel[mwi][0], 32, -16, 0, 1, DIR_SW); break; case DIR_W: M_StartWalk3(i, -MWVel[mwi][2], 0, 32, -16, -1, 1, 0, 1, DIR_W); break; case DIR_NW: M_StartWalk(i, -MWVel[mwi][1], -MWVel[mwi][0], -1, 0, DIR_NW); break; } } void GroupUnity(int i) { int leader, m, j; BOOL clear; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("GroupUnity: Invalid monster %d", i); #endif if (monster[i].leaderflag != 0) { leader = monster[i].leader; clear = LineClearF(CheckNoSolid, monster[i]._mx, monster[i]._my, monster[leader]._mfutx, monster[leader]._mfuty); if (clear || monster[i].leaderflag != 1) { if (clear && monster[i].leaderflag == 2 && abs(monster[i]._mx - monster[leader]._mfutx) < 4 && abs(monster[i]._my - monster[leader]._mfuty) < 4) { monster[leader].packsize++; monster[i].leaderflag = 1; } } else { monster[leader].packsize--; monster[i].leaderflag = 2; } } if (monster[i].leaderflag == 1) { if (monster[i]._msquelch > monster[leader]._msquelch) { monster[leader]._lastx = monster[i]._mx; monster[leader]._lasty = monster[i]._my; monster[leader]._msquelch = monster[i]._msquelch - 1; } if (monster[leader]._mAi == AI_GARG) { if (monster[leader]._mFlags & MFLAG_ALLOW_SPECIAL) { monster[leader]._mFlags &= ~MFLAG_ALLOW_SPECIAL; monster[leader]._mmode = MM_SATTACK; } } } else if (monster[i]._uniqtype != 0) { if (UniqMonst[monster[i]._uniqtype - 1].mUnqAttr & 2) { for (j = 0; j < nummonsters; j++) { m = monstactive[j]; if (monster[m].leaderflag == 1 && monster[m].leader == i) { if (monster[i]._msquelch > monster[m]._msquelch) { monster[m]._lastx = monster[i]._mx; monster[m]._lasty = monster[i]._my; monster[m]._msquelch = monster[i]._msquelch - 1; } if (monster[m]._mAi == AI_GARG) { if (monster[m]._mFlags & MFLAG_ALLOW_SPECIAL) { monster[m]._mFlags &= ~MFLAG_ALLOW_SPECIAL; monster[m]._mmode = MM_SATTACK; } } } } } } } BOOL M_CallWalk(int i, int md) { int mdtemp; BOOL ok; mdtemp = md; ok = DirOK(i, md); if (random_(101, 2) != 0) ok = ok || (md = left[mdtemp], DirOK(i, md)) || (md = right[mdtemp], DirOK(i, md)); else ok = ok || (md = right[mdtemp], DirOK(i, md)) || (md = left[mdtemp], DirOK(i, md)); if (random_(102, 2) != 0) ok = ok || (md = right[right[mdtemp]], DirOK(i, md)) || (md = left[left[mdtemp]], DirOK(i, md)); else ok = ok || (md = left[left[mdtemp]], DirOK(i, md)) || (md = right[right[mdtemp]], DirOK(i, md)); if (ok) M_WalkDir(i, md); return ok; } BOOL M_PathWalk(int i) { char path[MAX_PATH_LENGTH]; BOOL(*Check) (int, int, int); if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("M_PathWalk: Invalid monster %d", i); #endif Check = PosOkMonst3; if (!(monster[i]._mFlags & MFLAG_CAN_OPEN_DOOR)) Check = PosOkMonst; if (FindPath(Check, i, monster[i]._mx, monster[i]._my, monster[i]._menemyx, monster[i]._menemyy, path)) { M_CallWalk(i, plr2monst[path[0]]); /* plr2monst is local */ return TRUE; } return FALSE; } BOOL M_CallWalk2(int i, int md) { BOOL ok; int mdtemp; mdtemp = md; ok = DirOK(i, md); // Can we continue in the same direction if (random_(101, 2) != 0) { // Randomly go left or right ok = ok || (mdtemp = left[md], DirOK(i, left[md])) || (mdtemp = right[md], DirOK(i, right[md])); } else { ok = ok || (mdtemp = right[md], DirOK(i, right[md])) || (mdtemp = left[md], DirOK(i, left[md])); } if (ok) M_WalkDir(i, mdtemp); return ok; } BOOL M_DumbWalk(int i, int md) { BOOL ok; ok = DirOK(i, md); if (ok) M_WalkDir(i, md); return ok; } BOOL M_RoundWalk(int i, int md, int &dir) { int mdtemp; BOOL ok; if (dir) md = left[left[md]]; else md = right[right[md]]; mdtemp = md; ok = DirOK(i, md); if (!ok) { if (dir) { md = right[mdtemp]; ok = DirOK(i, md) || (md = right[right[mdtemp]], DirOK(i, md)); } else { md = left[mdtemp]; ok = (DirOK(i, md) || (md = left[left[mdtemp]], DirOK(i, md))); } } if (ok) { M_WalkDir(i, md); } else { dir = !dir; ok = M_CallWalk(i, opposite[mdtemp]); } return ok; } void MAI_Zombie(int i) { MonsterStruct *Monst; int mx, my; int md, v; if ((DWORD)i >= MAXMONSTERS) { #ifdef HELLFIRE return; #else app_fatal("MAI_Zombie: Invalid monster %d", i); #endif } Monst = &monster[i]; if (Monst->_mmode != MM_STAND) { return; } mx = Monst->_mx; my = Monst->_my; if (!(dFlags[mx][my] & BFLAG_VISIBLE)) { return; } mx = mx - Monst->_menemyx; my = my - Monst->_menemyy; md = Monst->_mdir; v = random_(103, 100); if (abs(mx) >= 2 || abs(my) >= 2) { if (v < 2 * Monst->_mint + 10) { if (abs(mx) >= 2 * Monst->_mint + 4 || abs(my) >= 2 * Monst->_mint + 4) { if (random_(104, 100) < 2 * Monst->_mint + 20) { md = random_(104, 8); } M_DumbWalk(i, md); } else { md = M_GetDir(i); M_CallWalk(i, md); } } } else if (v < 2 * Monst->_mint + 10) { M_StartAttack(i); } if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[Monst->_mdir]; } void MAI_SkelSd(int i) { MonsterStruct *Monst; int mx, my, x, y, md; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_SkelSd: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->_mmode != MM_STAND || Monst->_msquelch == 0) { return; } mx = Monst->_mx; my = Monst->_my; x = mx - Monst->_menemyx; y = my - Monst->_menemyy; md = GetDirection(mx, my, Monst->_lastx, Monst->_lasty); Monst->_mdir = md; if (abs(x) >= 2 || abs(y) >= 2) { if (Monst->_mVar1 == MM_DELAY || (random_(106, 100) >= 35 - 4 * Monst->_mint)) { M_CallWalk(i, md); } else { M_StartDelay(i, 15 - 2 * Monst->_mint + random_(106, 10)); } } else { if (Monst->_mVar1 == MM_DELAY || (random_(105, 100) < 2 * Monst->_mint + 20)) { M_StartAttack(i); } else { M_StartDelay(i, 2 * (5 - Monst->_mint) + random_(105, 10)); } } if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } BOOL MAI_Path(int i) { MonsterStruct *Monst; BOOL clear; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("MAI_Path: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->MType->mtype != MT_GOLEM) { if (Monst->_msquelch == 0) return FALSE; if (Monst->_mmode != MM_STAND) return FALSE; if (Monst->_mgoal != MGOAL_NORMAL && Monst->_mgoal != MGOAL_MOVE && Monst->_mgoal != MGOAL_ATTACK2) return FALSE; if (Monst->_mx == 1 && Monst->_my == 0) return FALSE; } clear = LineClearF1( PosOkMonst2, i, Monst->_mx, Monst->_my, Monst->_menemyx, Monst->_menemyy); if (!clear || Monst->_pathcount >= 5 && Monst->_pathcount < 8) { if (Monst->_mFlags & MFLAG_CAN_OPEN_DOOR) MonstCheckDoors(i); Monst->_pathcount++; if (Monst->_pathcount < 5) return FALSE; if (M_PathWalk(i)) return TRUE; } if (Monst->MType->mtype != MT_GOLEM) Monst->_pathcount = 0; return FALSE; } void MAI_Snake(int i) { MonsterStruct *Monst; int fx, fy, mx, my, md; int pnum; int tmp; if ((DWORD)i >= MAXMONSTERS) { #ifdef HELLFIRE return; #else app_fatal("MAI_Snake: Invalid monster %d", i); #endif } char pattern[6] = { 1, 1, 0, -1, -1, 0 }; Monst = &monster[i]; pnum = Monst->_menemy; if (Monst->_mmode != MM_STAND || Monst->_msquelch == 0) return; fx = Monst->_menemyx; fy = Monst->_menemyy; mx = Monst->_mx - fx; my = Monst->_my - fy; md = GetDirection(Monst->_mx, Monst->_my, Monst->_lastx, Monst->_lasty); Monst->_mdir = md; if (abs(mx) >= 2 || abs(my) >= 2) { if (abs(mx) < 3 && abs(my) < 3 && LineClearF1(PosOkMonst, i, Monst->_mx, Monst->_my, fx, fy) && Monst->_mVar1 != MM_CHARGE) { if (AddMissile(Monst->_mx, Monst->_my, fx, fy, md, MIS_RHINO, pnum, i, 0, 0) != -1) { PlayEffect(i, 0); dMonster[Monst->_mx][Monst->_my] = -(i + 1); Monst->_mmode = MM_CHARGE; } } else if (Monst->_mVar1 == MM_DELAY || random_(106, 100) >= 35 - 2 * Monst->_mint) { if (md + pattern[Monst->_mgoalvar1] < 0) { tmp = md + pattern[Monst->_mgoalvar1] + 8; } else { tmp = md + pattern[Monst->_mgoalvar1] - 8; if (md + pattern[Monst->_mgoalvar1] < 8) tmp = md + pattern[Monst->_mgoalvar1]; } Monst->_mgoalvar1++; if (Monst->_mgoalvar1 > 5) Monst->_mgoalvar1 = 0; if (tmp - Monst->_mgoalvar2 < 0) { md = tmp - Monst->_mgoalvar2 + 8; } else if (tmp - Monst->_mgoalvar2 >= 8) { md = tmp - Monst->_mgoalvar2 - 8; } else md = tmp - Monst->_mgoalvar2; if (md > 0) { if (md < 4) { if (Monst->_mgoalvar2 + 1 < 0) { md = Monst->_mgoalvar2 + 9; } else if (Monst->_mgoalvar2 + 1 >= 8) { md = Monst->_mgoalvar2 - 7; } else md = Monst->_mgoalvar2 + 1; Monst->_mgoalvar2 = md; } else if (md == 4) { Monst->_mgoalvar2 = tmp; } else { if (Monst->_mgoalvar2 - 1 < 0) { md = Monst->_mgoalvar2 + 7; } else if (Monst->_mgoalvar2 - 1 >= 8) { md = Monst->_mgoalvar2 - 9; } else md = Monst->_mgoalvar2 - 1; Monst->_mgoalvar2 = md; } } if (!M_DumbWalk(i, Monst->_mgoalvar2)) M_CallWalk2(i, Monst->_mdir); } else { M_StartDelay(i, 15 - Monst->_mint + random_(106, 10)); } } else { if (Monst->_mVar1 == MM_DELAY || Monst->_mVar1 == MM_CHARGE || (random_(105, 100) < Monst->_mint + 20)) { M_StartAttack(i); } else M_StartDelay(i, 10 - Monst->_mint + random_(105, 10)); } if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[Monst->_mdir]; } void MAI_Bat(int i) { MonsterStruct *Monst; int md, v, pnum; int fx, fy, xd, yd; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Bat: Invalid monster %d", i); #endif Monst = &monster[i]; pnum = Monst->_menemy; if (Monst->_mmode != MM_STAND || Monst->_msquelch == 0) { return; } xd = Monst->_mx - Monst->_menemyx; yd = Monst->_my - Monst->_menemyy; md = GetDirection(Monst->_mx, Monst->_my, Monst->_lastx, Monst->_lasty); Monst->_mdir = md; v = random_(107, 100); if (Monst->_mgoal == MGOAL_RETREAT) { if (!Monst->_mgoalvar1) { M_CallWalk(i, opposite[md]); Monst->_mgoalvar1++; } else { if (random_(108, 2) != 0) M_CallWalk(i, left[md]); else M_CallWalk(i, right[md]); Monst->_mgoal = MGOAL_NORMAL; } return; } fx = Monst->_menemyx; fy = Monst->_menemyy; if (Monst->MType->mtype == MT_GLOOM && (abs(xd) >= 5 || abs(yd) >= 5) && v < 4 * Monst->_mint + 33 && LineClearF1(PosOkMonst, i, Monst->_mx, Monst->_my, fx, fy)) { if (AddMissile(Monst->_mx, Monst->_my, fx, fy, md, MIS_RHINO, pnum, i, 0, 0) != -1) { dMonster[Monst->_mx][Monst->_my] = -(i + 1); Monst->_mmode = MM_CHARGE; } } else if (abs(xd) >= 2 || abs(yd) >= 2) { if (Monst->_mVar2 > 20 && v < Monst->_mint + 13 || (Monst->_mVar1 == MM_WALK || Monst->_mVar1 == MM_WALK2 || Monst->_mVar1 == MM_WALK3) && Monst->_mVar2 == 0 && v < Monst->_mint + 63) { M_CallWalk(i, md); } } else if (v < 4 * Monst->_mint + 8) { M_StartAttack(i); Monst->_mgoal = MGOAL_RETREAT; Monst->_mgoalvar1 = 0; if (Monst->MType->mtype == MT_FAMILIAR) { AddMissile(Monst->_menemyx, Monst->_menemyy, Monst->_menemyx + 1, 0, -1, MIS_LIGHTNING, TARGET_PLAYERS, i, random_(109, 10) + 1, 0); } } if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } void MAI_SkelBow(int i) { MonsterStruct *Monst; int mx, my, md, v; BOOL walking; walking = FALSE; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_SkelBow: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->_mmode != MM_STAND || Monst->_msquelch == 0) { return; } mx = Monst->_mx - Monst->_menemyx; my = Monst->_my - Monst->_menemyy; md = M_GetDir(i); Monst->_mdir = md; v = random_(110, 100); if (abs(mx) < 4 && abs(my) < 4) { if (Monst->_mVar2 > 20 && v < 2 * Monst->_mint + 13 || (Monst->_mVar1 == MM_WALK || Monst->_mVar1 == MM_WALK2 || Monst->_mVar1 == MM_WALK3) && Monst->_mVar2 == 0 && v < 2 * Monst->_mint + 63) { walking = M_DumbWalk(i, opposite[md]); } } mx = Monst->_menemyx; my = Monst->_menemyy; if (!walking) { if (random_(110, 100) < 2 * Monst->_mint + 3) { if (LineClear(Monst->_mx, Monst->_my, mx, my)) M_StartRAttack(i, MIS_ARROW, 4); } } if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } void MAI_Fat(int i) { MonsterStruct *Monst; int mx, my, md, v; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Fat: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->_mmode != MM_STAND || Monst->_msquelch == 0) { return; } mx = Monst->_mx - Monst->_menemyx; my = Monst->_my - Monst->_menemyy; md = M_GetDir(i); Monst->_mdir = md; v = random_(111, 100); if (abs(mx) >= 2 || abs(my) >= 2) { if (Monst->_mVar2 > 20 && v < 4 * Monst->_mint + 20 || (Monst->_mVar1 == MM_WALK || Monst->_mVar1 == MM_WALK2 || Monst->_mVar1 == MM_WALK3) && Monst->_mVar2 == 0 && v < 4 * Monst->_mint + 70) { M_CallWalk(i, md); } } else if (v < 4 * Monst->_mint + 15) { M_StartAttack(i); } else if (v < 4 * Monst->_mint + 20) { M_StartSpAttack(i); } if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } void MAI_Sneak(int i) { MonsterStruct *Monst; int mx, my, md; int dist, v; if ((DWORD)i >= MAXMONSTERS) { #ifdef HELLFIRE return; #else app_fatal("MAI_Sneak: Invalid monster %d", i); #endif } Monst = &monster[i]; if (Monst->_mmode == MM_STAND) { mx = Monst->_mx; my = Monst->_my; if (dLight[mx][my] != lightmax) { mx -= Monst->_menemyx; my -= Monst->_menemyy; md = M_GetDir(i); dist = 5 - Monst->_mint; if (Monst->_mVar1 == MM_GOTHIT) { Monst->_mgoal = MGOAL_RETREAT; Monst->_mgoalvar1 = 0; } else { if (abs(mx) >= dist + 3 || abs(my) >= dist + 3 || Monst->_mgoalvar1 > 8) { Monst->_mgoal = MGOAL_NORMAL; Monst->_mgoalvar1 = 0; } } #ifdef HELLFIRE if (Monst->_mgoal == MGOAL_RETREAT && !(Monst->_mFlags & MFLAG_NO_ENEMY)) { if (Monst->_mFlags & MFLAG_TARGETS_MONSTER) md = GetDirection(Monst->_mx, Monst->_my, monster[Monst->_menemy]._mx, monster[Monst->_menemy]._my); else #else if (Monst->_mgoal == MGOAL_RETREAT) { if (Monst->_mFlags & MFLAG_TARGETS_MONSTER) #endif md = GetDirection(Monst->_mx, Monst->_my, plr[Monst->_menemy]._pownerx, plr[Monst->_menemy]._pownery); md = opposite[md]; if (Monst->MType->mtype == MT_UNSEEN) { if (random_(112, 2) != 0) md = left[md]; else md = right[md]; } } Monst->_mdir = md; v = random_(112, 100); if (abs(mx) < dist && abs(my) < dist && Monst->_mFlags & MFLAG_HIDDEN) { M_StartFadein(i, md, FALSE); } else { if ((abs(mx) >= dist + 1 || abs(my) >= dist + 1) && !(Monst->_mFlags & MFLAG_HIDDEN)) { M_StartFadeout(i, md, TRUE); } else { if (Monst->_mgoal == MGOAL_RETREAT || (abs(mx) >= 2 || abs(my) >= 2) && (Monst->_mVar2 > 20 && v < 4 * Monst->_mint + 14 || (Monst->_mVar1 == MM_WALK || Monst->_mVar1 == MM_WALK2 || Monst->_mVar1 == MM_WALK3) && Monst->_mVar2 == 0 && v < 4 * Monst->_mint + 64)) { Monst->_mgoalvar1++; M_CallWalk(i, md); } } } if (Monst->_mmode == MM_STAND) { if (abs(mx) >= 2 || abs(my) >= 2 || v >= 4 * Monst->_mint + 10) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; else M_StartAttack(i); } } } } void MAI_Fireman(int i) { int xd, yd; int md, pnum; int fx, fy; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Fireman: Invalid monster %d", i); #endif Monst = &monster[i]; if (monster[i]._mmode != MM_STAND || Monst->_msquelch == 0) return; pnum = monster[i]._menemy; fx = monster[i]._menemyx; fy = monster[i]._menemyy; xd = monster[i]._mx - fx; yd = monster[i]._my - fy; md = M_GetDir(i); if (Monst->_mgoal == MGOAL_NORMAL) { if (LineClear(Monst->_mx, Monst->_my, fx, fy) && AddMissile(Monst->_mx, Monst->_my, fx, fy, md, MIS_FIREMAN, pnum, i, 0, 0) != -1) { Monst->_mmode = MM_CHARGE; Monst->_mgoal = MGOAL_ATTACK2; Monst->_mgoalvar1 = 0; } } else if (Monst->_mgoal == MGOAL_ATTACK2) { if (Monst->_mgoalvar1 == 3) { Monst->_mgoal = MGOAL_NORMAL; M_StartFadeout(i, md, TRUE); } else if (LineClear(Monst->_mx, Monst->_my, fx, fy)) { M_StartRAttack(i, MIS_KRULL, 4); Monst->_mgoalvar1++; } else { M_StartDelay(i, random_(112, 10) + 5); Monst->_mgoalvar1++; } } else if (Monst->_mgoal == MGOAL_RETREAT) { M_StartFadein(i, md, FALSE); Monst->_mgoal = MGOAL_ATTACK2; } Monst->_mdir = md; random_(112, 100); if (Monst->_mmode != MM_STAND) return; if (abs(xd) < 2 && abs(yd) < 2 && Monst->_mgoal == MGOAL_NORMAL) { M_TryH2HHit(i, monster[i]._menemy, monster[i].mHit, monster[i].mMinDamage, monster[i].mMaxDamage); Monst->_mgoal = MGOAL_RETREAT; if (!M_CallWalk(i, opposite[md])) { M_StartFadein(i, md, FALSE); Monst->_mgoal = MGOAL_ATTACK2; } } else if (!M_CallWalk(i, md) && (Monst->_mgoal == MGOAL_NORMAL || Monst->_mgoal == MGOAL_RETREAT)) { M_StartFadein(i, md, FALSE); Monst->_mgoal = MGOAL_ATTACK2; } } void MAI_Fallen(int i) { int x, y, xpos, ypos; int m, rad; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) { #ifdef HELLFIRE return; #else app_fatal("MAI_Fallen: Invalid monster %d", i); #endif } Monst = &monster[i]; if (Monst->_mgoal == MGOAL_ATTACK2) { if (Monst->_mgoalvar1 != 0) Monst->_mgoalvar1--; else Monst->_mgoal = MGOAL_NORMAL; } if (Monst->_mmode != MM_STAND || Monst->_msquelch == 0) { return; } if (Monst->_mgoal == MGOAL_RETREAT) { if (Monst->_mgoalvar1-- == 0) { Monst->_mgoal = MGOAL_NORMAL; M_StartStand(i, opposite[Monst->_mdir]); } } if (Monst->_mAnimFrame == Monst->_mAnimLen) { if (random_(113, 4) != 0) { return; } if (!(monster[i]._mFlags & MFLAG_NOHEAL)) { // CODEFIX: - change to Monst-> in devilutionx M_StartSpStand(i, Monst->_mdir); if (Monst->_mmaxhp - (2 * Monst->_mint + 2) >= Monst->_mhitpoints) Monst->_mhitpoints += 2 * Monst->_mint + 2; else Monst->_mhitpoints = Monst->_mmaxhp; } rad = 2 * Monst->_mint + 4; for (y = -rad; y <= rad; y++) { for (x = -rad; x <= rad; x++) { xpos = Monst->_mx + x; ypos = Monst->_my + y; // BUGFIX: should check `xpos` and `ypos` for out-of-bounds, was checking `x` and `y`. if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { m = dMonster[xpos][ypos]; if (m > 0) { m--; if (monster[m]._mAi == AI_FALLEN) { monster[m]._mgoal = MGOAL_ATTACK2; monster[m]._mgoalvar1 = 30 * Monst->_mint + 105; } } } } } } else if (Monst->_mgoal == MGOAL_RETREAT) { M_CallWalk(i, Monst->_mdir); } else if (Monst->_mgoal == MGOAL_ATTACK2) { xpos = Monst->_mx - Monst->_menemyx; ypos = Monst->_my - Monst->_menemyy; if (abs(xpos) < 2 && abs(ypos) < 2) M_StartAttack(i); else M_CallWalk(i, M_GetDir(i)); } else MAI_SkelSd(i); } void MAI_Cleaver(int i) { MonsterStruct *Monst; int x, y, mx, my, md; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Cleaver: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->_mmode != MM_STAND || Monst->_msquelch == 0) { return; } mx = Monst->_mx; my = Monst->_my; x = mx - Monst->_menemyx; y = my - Monst->_menemyy; md = GetDirection(mx, my, Monst->_lastx, Monst->_lasty); Monst->_mdir = md; if (abs(x) >= 2 || abs(y) >= 2) M_CallWalk(i, md); else M_StartAttack(i); if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } void MAI_Round(int i, BOOL special) { MonsterStruct *Monst; int fx, fy; int mx, my, md; int dist, v; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Round: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->_mmode == MM_STAND && Monst->_msquelch != 0) { fy = Monst->_menemyy; fx = Monst->_menemyx; mx = Monst->_mx - fx; my = Monst->_my - fy; md = GetDirection(Monst->_mx, Monst->_my, Monst->_lastx, Monst->_lasty); if (Monst->_msquelch < UCHAR_MAX) MonstCheckDoors(i); v = random_(114, 100); if ((abs(mx) >= 2 || abs(my) >= 2) && Monst->_msquelch == UCHAR_MAX && dTransVal[Monst->_mx][Monst->_my] == dTransVal[fx][fy]) { if (Monst->_mgoal == MGOAL_MOVE || (abs(mx) >= 4 || abs(my) >= 4) && random_(115, 4) == 0) { if (Monst->_mgoal != MGOAL_MOVE) { Monst->_mgoalvar1 = 0; Monst->_mgoalvar2 = random_(116, 2); } Monst->_mgoal = MGOAL_MOVE; if (abs(mx) > abs(my)) dist = abs(mx); else dist = abs(my); if (Monst->_mgoalvar1++ >= 2 * dist && DirOK(i, md) || dTransVal[Monst->_mx][Monst->_my] != dTransVal[fx][fy]) { Monst->_mgoal = MGOAL_NORMAL; } else if (!M_RoundWalk(i, md, Monst->_mgoalvar2)) { M_StartDelay(i, random_(125, 10) + 10); } } } else Monst->_mgoal = MGOAL_NORMAL; if (Monst->_mgoal == MGOAL_NORMAL) { if (abs(mx) >= 2 || abs(my) >= 2) { if (Monst->_mVar2 > 20 && v < 2 * Monst->_mint + 28 || (Monst->_mVar1 == MM_WALK || Monst->_mVar1 == MM_WALK2 || Monst->_mVar1 == MM_WALK3) && Monst->_mVar2 == 0 && v < 2 * Monst->_mint + 78) { M_CallWalk(i, md); } } else if (v < 2 * Monst->_mint + 23) { Monst->_mdir = md; if (special && Monst->_mhitpoints < (Monst->_mmaxhp >> 1) && random_(117, 2) != 0) M_StartSpAttack(i); else M_StartAttack(i); } } if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } } void MAI_GoatMc(int i) { MAI_Round(i, TRUE); } void MAI_Ranged(int i, int missile_type, BOOL special) { int md; int fx, fy, mx, my; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Ranged: Invalid monster %d", i); #endif if (monster[i]._mmode != MM_STAND) { return; } Monst = &monster[i]; if (Monst->_msquelch == UCHAR_MAX || Monst->_mFlags & MFLAG_TARGETS_MONSTER) { fx = Monst->_menemyx; fy = Monst->_menemyy; mx = Monst->_mx - fx; my = Monst->_my - fy; md = M_GetDir(i); if (Monst->_msquelch < UCHAR_MAX) MonstCheckDoors(i); Monst->_mdir = md; if (Monst->_mVar1 == MM_RATTACK) { M_StartDelay(i, random_(118, 20)); } else if (abs(mx) < 4 && abs(my) < 4) { if (random_(119, 100) < 10 * (Monst->_mint + 7)) M_CallWalk(i, opposite[md]); } if (Monst->_mmode == MM_STAND) { if (LineClear(Monst->_mx, Monst->_my, fx, fy)) { if (special) M_StartRSpAttack(i, missile_type, 4); else M_StartRAttack(i, missile_type, 4); } else { Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } } } else if (Monst->_msquelch != 0) { fx = Monst->_lastx; fy = Monst->_lasty; md = GetDirection(Monst->_mx, Monst->_my, fx, fy); M_CallWalk(i, md); } } void MAI_GoatBow(int i) { MAI_Ranged(i, MIS_ARROW, FALSE); } void MAI_Succ(int i) { MAI_Ranged(i, MIS_FLARE, FALSE); } #ifdef HELLFIRE void MAI_Lich(int i) { MAI_Ranged(i, MIS_LICH, FALSE); } void MAI_ArchLich(int i) { MAI_Ranged(i, MIS_ARCHLICH, FALSE); } void MAI_Psychorb(int i) { MAI_Ranged(i, MIS_PSYCHORB, FALSE); } void MAI_Necromorb(int i) { MAI_Ranged(i, MIS_NECROMORB, FALSE); } #endif void MAI_AcidUniq(int i) { MAI_Ranged(i, MIS_ACID, TRUE); } #ifdef HELLFIRE void MAI_Firebat(int i) { MAI_Ranged(i, MIS_FIREBOLT, FALSE); } void MAI_Torchant(int i) { MAI_Ranged(i, MIS_FIREBALL, FALSE); } #endif void MAI_Scav(int i) { BOOL done; int x, y; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Scav: Invalid monster %d", i); #endif Monst = &monster[i]; done = FALSE; if (monster[i]._mmode != MM_STAND) return; if (Monst->_mhitpoints < (Monst->_mmaxhp >> 1) && Monst->_mgoal != MGOAL_HEALING) { if (Monst->leaderflag != 0) { monster[Monst->leader].packsize--; // BUGFIX Check Monst->leaderflag == 1, to not underflow packsize Monst->leaderflag = 0; } Monst->_mgoal = MGOAL_HEALING; Monst->_mgoalvar3 = 10; } if (Monst->_mgoal == MGOAL_HEALING && Monst->_mgoalvar3 != 0) { Monst->_mgoalvar3--; if (dDead[Monst->_mx][Monst->_my] != 0) { M_StartEat(i); if (!(Monst->_mFlags & MFLAG_NOHEAL)) { #ifdef HELLFIRE int mMaxHP = Monst->MType->mMaxHP << 6; // BUGFIX use _mmaxhp or we loose health when difficulty isn't normal if (gbMaxPlayers == 1) mMaxHP >>= 1; Monst->_mhitpoints += mMaxHP >> 3; if (Monst->_mhitpoints > mMaxHP) Monst->_mhitpoints = mMaxHP; if (Monst->_mmaxhp < Monst->_mhitpoints) Monst->_mmaxhp = Monst->_mhitpoints; if (Monst->_mgoalvar3 <= 0 || Monst->_mhitpoints == mMaxHP) dDead[Monst->_mx][Monst->_my] = 0; } if (Monst->_mhitpoints == Monst->_mmaxhp) { #else Monst->_mhitpoints += 64; } if (Monst->_mhitpoints >= (Monst->_mmaxhp >> 1) + (Monst->_mmaxhp >> 2)) { #endif Monst->_mgoal = MGOAL_NORMAL; Monst->_mgoalvar1 = 0; Monst->_mgoalvar2 = 0; } } else { if (Monst->_mgoalvar1 == 0) { if (random_(120, 2) != 0) { for (y = -4; y <= 4 && !done; y++) { for (x = -4; x <= 4 && !done; x++) { // BUGFIX: incorrect check of offset against limits of the dungeon if (y < 0 || y >= MAXDUNY || x < 0 || x >= MAXDUNX) continue; done = dDead[Monst->_mx + x][Monst->_my + y] != 0 && LineClearF( CheckNoSolid, Monst->_mx, Monst->_my, Monst->_mx + x, Monst->_my + y); } } x--; y--; } else { for (y = 4; y >= -4 && !done; y--) { for (x = 4; x >= -4 && !done; x--) { // BUGFIX: incorrect check of offset against limits of the dungeon if (y < 0 || y >= MAXDUNY || x < 0 || x >= MAXDUNX) continue; done = dDead[Monst->_mx + x][Monst->_my + y] != 0 && LineClearF( CheckNoSolid, Monst->_mx, Monst->_my, Monst->_mx + x, Monst->_my + y); } } x++; y++; } if (done) { Monst->_mgoalvar1 = x + Monst->_mx + 1; Monst->_mgoalvar2 = y + Monst->_my + 1; } } if (Monst->_mgoalvar1) { x = Monst->_mgoalvar1 - 1; y = Monst->_mgoalvar2 - 1; Monst->_mdir = GetDirection(Monst->_mx, Monst->_my, x, y); M_CallWalk(i, Monst->_mdir); } } } #ifdef HELLFIRE else #else if (Monst->_mmode == MM_STAND) #endif MAI_SkelSd(i); } void MAI_Garg(int i) { MonsterStruct *Monst; int mx, my, dx, dy, md; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Garg: Invalid monster %d", i); #endif Monst = &monster[i]; dx = Monst->_mx - Monst->_lastx; dy = Monst->_my - Monst->_lasty; md = M_GetDir(i); if (Monst->_msquelch != 0 && Monst->_mFlags & MFLAG_ALLOW_SPECIAL) { M_Enemy(i); mx = Monst->_mx - Monst->_menemyx; my = Monst->_my - Monst->_menemyy; if (abs(mx) < Monst->_mint + 2 && abs(my) < Monst->_mint + 2) { Monst->_mFlags &= ~MFLAG_ALLOW_SPECIAL; } return; } if (Monst->_mmode != MM_STAND || Monst->_msquelch == 0) { return; } if (Monst->_mhitpoints < (Monst->_mmaxhp >> 1)) #ifndef HELLFIRE if (!(Monst->_mFlags & MFLAG_NOHEAL)) #endif Monst->_mgoal = MGOAL_RETREAT; if (Monst->_mgoal == MGOAL_RETREAT) { if (abs(dx) >= Monst->_mint + 2 || abs(dy) >= Monst->_mint + 2) { Monst->_mgoal = MGOAL_NORMAL; M_StartHeal(i); } else if (!M_CallWalk(i, opposite[md])) { Monst->_mgoal = MGOAL_NORMAL; } } MAI_Round(i, FALSE); } void MAI_RoundRanged(int i, int missile_type, BOOL checkdoors, int dam, int lessmissiles) { MonsterStruct *Monst; int mx, my; int fx, fy; int md, dist, v; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_RoundRanged: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->_mmode == MM_STAND && Monst->_msquelch != 0) { fx = Monst->_menemyx; fy = Monst->_menemyy; mx = Monst->_mx - fx; my = Monst->_my - fy; md = GetDirection(Monst->_mx, Monst->_my, Monst->_lastx, Monst->_lasty); if (checkdoors && Monst->_msquelch < UCHAR_MAX) MonstCheckDoors(i); v = random_(121, 10000); if ((abs(mx) >= 2 || abs(my) >= 2) && Monst->_msquelch == UCHAR_MAX && dTransVal[Monst->_mx][Monst->_my] == dTransVal[fx][fy]) { if (Monst->_mgoal == MGOAL_MOVE || ((abs(mx) >= 3 || abs(my) >= 3) && random_(122, 4 << lessmissiles) == 0)) { if (Monst->_mgoal != MGOAL_MOVE) { Monst->_mgoalvar1 = 0; Monst->_mgoalvar2 = random_(123, 2); } Monst->_mgoal = MGOAL_MOVE; if (abs(mx) > abs(my)) { dist = abs(mx); } else { dist = abs(my); } if (Monst->_mgoalvar1++ >= 2 * dist && DirOK(i, md)) { Monst->_mgoal = MGOAL_NORMAL; } else if (v < (500 * (Monst->_mint + 1) >> lessmissiles) && (LineClear(Monst->_mx, Monst->_my, fx, fy))) { M_StartRSpAttack(i, missile_type, dam); } else { M_RoundWalk(i, md, Monst->_mgoalvar2); } } } else { Monst->_mgoal = MGOAL_NORMAL; } if (Monst->_mgoal == MGOAL_NORMAL) { if (((abs(mx) >= 3 || abs(my) >= 3) && v < ((500 * (Monst->_mint + 2)) >> lessmissiles) || v < ((500 * (Monst->_mint + 1)) >> lessmissiles)) && LineClear(Monst->_mx, Monst->_my, fx, fy)) { M_StartRSpAttack(i, missile_type, dam); } else if (abs(mx) >= 2 || abs(my) >= 2) { v = random_(124, 100); if (v < 1000 * (Monst->_mint + 5) || (Monst->_mVar1 == MM_WALK || Monst->_mVar1 == MM_WALK2 || Monst->_mVar1 == MM_WALK3) && Monst->_mVar2 == 0 && v < 1000 * (Monst->_mint + 8)) { M_CallWalk(i, md); } } else if (v < 1000 * (Monst->_mint + 6)) { Monst->_mdir = md; M_StartAttack(i); } } if (Monst->_mmode == MM_STAND) { M_StartDelay(i, random_(125, 10) + 5); } } } void MAI_Magma(int i) { MAI_RoundRanged(i, MIS_MAGMABALL, TRUE, 4, 0); } void MAI_Storm(int i) { MAI_RoundRanged(i, MIS_LIGHTCTRL2, TRUE, 4, 0); } #ifdef HELLFIRE void MAI_BoneDemon(int i) { MAI_RoundRanged(i, MIS_BONEDEMON, TRUE, 4, 0); } #endif void MAI_Acid(int i) { MAI_RoundRanged(i, MIS_ACID, FALSE, 4, 1); } void MAI_Diablo(int i) { MAI_RoundRanged(i, MIS_DIABAPOCA, FALSE, 40, 0); } void MAI_RR2(int i, int mistype, int dam) { MonsterStruct *Monst; int mx, my, fx, fy; int dist, v, md; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_RR2: Invalid monster %d", i); #endif Monst = &monster[i]; mx = Monst->_mx - Monst->_menemyx; my = Monst->_my - Monst->_menemyy; if (abs(mx) >= 5 || abs(my) >= 5) { MAI_SkelSd(i); return; } if (Monst->_mmode == MM_STAND && Monst->_msquelch != 0) { fx = Monst->_menemyx; fy = Monst->_menemyy; mx = Monst->_mx - fx; my = Monst->_my - fy; md = GetDirection(Monst->_mx, Monst->_my, Monst->_lastx, Monst->_lasty); if (Monst->_msquelch < UCHAR_MAX) MonstCheckDoors(i); v = random_(121, 100); if ((abs(mx) >= 2 || abs(my) >= 2) && Monst->_msquelch == UCHAR_MAX && dTransVal[Monst->_mx][Monst->_my] == dTransVal[fx][fy]) { if (Monst->_mgoal == MGOAL_MOVE || (abs(mx) >= 3 || abs(my) >= 3)) { if (Monst->_mgoal != MGOAL_MOVE) { Monst->_mgoalvar1 = 0; Monst->_mgoalvar2 = random_(123, 2); } Monst->_mgoal = MGOAL_MOVE; Monst->_mgoalvar3 = 4; if (abs(mx) > abs(my)) { dist = abs(mx); } else { dist = abs(my); } if (Monst->_mgoalvar1++ < 2 * dist || !DirOK(i, md)) { if (v < 5 * (Monst->_mint + 16)) M_RoundWalk(i, md, Monst->_mgoalvar2); } else Monst->_mgoal = MGOAL_NORMAL; } } else Monst->_mgoal = MGOAL_NORMAL; if (Monst->_mgoal == MGOAL_NORMAL) { if (((abs(mx) >= 3 || abs(my) >= 3) && v < 5 * (Monst->_mint + 2) || v < 5 * (Monst->_mint + 1) || Monst->_mgoalvar3 == 4) && LineClear(Monst->_mx, Monst->_my, fx, fy)) { M_StartRSpAttack(i, mistype, dam); } else if (abs(mx) >= 2 || abs(my) >= 2) { v = random_(124, 100); if (v < 2 * (5 * Monst->_mint + 25) || (Monst->_mVar1 == MM_WALK || Monst->_mVar1 == MM_WALK2 || Monst->_mVar1 == MM_WALK3) && Monst->_mVar2 == 0 && v < 2 * (5 * Monst->_mint + 40)) { M_CallWalk(i, md); } } else { if (random_(124, 100) < 10 * (Monst->_mint + 4)) { Monst->_mdir = md; if (random_(124, 2) != 0) M_StartAttack(i); else M_StartRSpAttack(i, mistype, dam); } } Monst->_mgoalvar3 = 1; } if (Monst->_mmode == MM_STAND) { M_StartDelay(i, random_(125, 10) + 5); } } } void MAI_Mega(int i) { MAI_RR2(i, MIS_FLAMEC, 0); } void MAI_Golum(int i) { int mx, my, _mex, _mey; int md, j, k, _menemy; MonsterStruct *Monst; BOOL have_enemy, ok; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Golum: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->_mx == 1 && Monst->_my == 0) { return; } if (Monst->_mmode == MM_DEATH || Monst->_mmode == MM_SPSTAND || (Monst->_mmode >= MM_WALK && Monst->_mmode <= MM_WALK3)) { return; } if (!(Monst->_mFlags & MFLAG_TARGETS_MONSTER)) M_Enemy(i); have_enemy = !(monster[i]._mFlags & MFLAG_NO_ENEMY); if (Monst->_mmode == MM_ATTACK) { return; } _menemy = monster[i]._menemy; mx = monster[i]._mx; my = monster[i]._my; _mex = mx - monster[_menemy]._mfutx; _mey = my - monster[_menemy]._mfuty; md = GetDirection(mx, my, monster[_menemy]._mx, monster[_menemy]._my); monster[i]._mdir = md; if (abs(_mex) < 2 && abs(_mey) < 2 && have_enemy) { _menemy = monster[i]._menemy; monster[i]._menemyx = monster[_menemy]._mx; monster[i]._menemyy = monster[_menemy]._my; if (monster[_menemy]._msquelch == 0) { monster[_menemy]._msquelch = UCHAR_MAX; monster[monster[i]._menemy]._lastx = monster[i]._mx; monster[monster[i]._menemy]._lasty = monster[i]._my; for (j = 0; j < 5; j++) { for (k = 0; k < 5; k++) { _menemy = dMonster[monster[i]._mx + k - 2][monster[i]._my + j - 2]; // BUGFIX: Check if indexes are between 0 and 112 if (_menemy > 0) monster[_menemy]._msquelch = UCHAR_MAX; // BUGFIX: should be `monster[_menemy-1]`, not monster[_menemy]. } } } M_StartAttack(i); return; } if (have_enemy && MAI_Path(i)) return; monster[i]._pathcount++; if (monster[i]._pathcount > 8) monster[i]._pathcount = 5; ok = M_CallWalk(i, plr[i]._pdir); if (ok) return; md = (md - 1) & 7; for (j = 0; j < 8 && !ok; j++) { md = (md + 1) & 7; ok = DirOK(i, md); } if (ok) M_WalkDir(i, md); } void MAI_SkelKing(int i) { MonsterStruct *Monst; int mx, my, fx, fy, nx, ny; int dist, v, md; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_SkelKing: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->_mmode == MM_STAND && Monst->_msquelch != 0) { fx = Monst->_menemyx; fy = Monst->_menemyy; mx = Monst->_mx - fx; my = Monst->_my - fy; md = GetDirection(Monst->_mx, Monst->_my, Monst->_lastx, Monst->_lasty); if (Monst->_msquelch < UCHAR_MAX) MonstCheckDoors(i); v = random_(126, 100); if ((abs(mx) >= 2 || abs(my) >= 2) && Monst->_msquelch == UCHAR_MAX && dTransVal[Monst->_mx][Monst->_my] == dTransVal[fx][fy]) { if (Monst->_mgoal == MGOAL_MOVE || (abs(mx) >= 3 || abs(my) >= 3) && random_(127, 4) == 0) { if (Monst->_mgoal != MGOAL_MOVE) { Monst->_mgoalvar1 = 0; Monst->_mgoalvar2 = random_(128, 2); } Monst->_mgoal = MGOAL_MOVE; if (abs(mx) > abs(my)) { dist = abs(mx); } else { dist = abs(my); } if (Monst->_mgoalvar1++ >= 2 * dist && DirOK(i, md) || dTransVal[Monst->_mx][Monst->_my] != dTransVal[fx][fy]) { Monst->_mgoal = MGOAL_NORMAL; } else if (!M_RoundWalk(i, md, Monst->_mgoalvar2)) { M_StartDelay(i, random_(125, 10) + 10); } } } else Monst->_mgoal = MGOAL_NORMAL; if (Monst->_mgoal == MGOAL_NORMAL) { if (gbMaxPlayers == 1 && ((abs(mx) >= 3 || abs(my) >= 3) && v < 4 * Monst->_mint + 35 || v < 6) && LineClear(Monst->_mx, Monst->_my, fx, fy)) { nx = Monst->_mx + offset_x[md]; ny = Monst->_my + offset_y[md]; if (PosOkMonst(i, nx, ny) && nummonsters < MAXMONSTERS) { M_SpawnSkel(nx, ny, md); M_StartSpStand(i, md); } } else { if (abs(mx) >= 2 || abs(my) >= 2) { v = random_(129, 100); if (v >= Monst->_mint + 25 && (Monst->_mVar1 != MM_WALK && Monst->_mVar1 != MM_WALK2 && Monst->_mVar1 != MM_WALK3 || Monst->_mVar2 != 0 || (v >= Monst->_mint + 75))) { M_StartDelay(i, random_(130, 10) + 10); } else { M_CallWalk(i, md); } } else if (v < Monst->_mint + 20) { Monst->_mdir = md; M_StartAttack(i); } } } if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } } void MAI_Rhino(int i) { MonsterStruct *Monst; int mx, my, fx, fy; int v, dist, md; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Rhino: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->_mmode == MM_STAND && Monst->_msquelch != 0) { fx = Monst->_menemyx; fy = Monst->_menemyy; mx = Monst->_mx - fx; my = Monst->_my - fy; md = GetDirection(Monst->_mx, Monst->_my, Monst->_lastx, Monst->_lasty); if (Monst->_msquelch < UCHAR_MAX) MonstCheckDoors(i); v = random_(131, 100); if (abs(mx) >= 2 || abs(my) >= 2) { if (Monst->_mgoal == MGOAL_MOVE || (abs(mx) >= 5 || abs(my) >= 5) && random_(132, 4) != 0) { if (Monst->_mgoal != MGOAL_MOVE) { Monst->_mgoalvar1 = 0; Monst->_mgoalvar2 = random_(133, 2); } Monst->_mgoal = MGOAL_MOVE; if (abs(mx) > abs(my)) { dist = abs(mx); } else { dist = abs(my); } if (Monst->_mgoalvar1++ >= 2 * dist || dTransVal[Monst->_mx][Monst->_my] != dTransVal[fx][fy]) { Monst->_mgoal = MGOAL_NORMAL; } else if (!M_RoundWalk(i, md, Monst->_mgoalvar2)) { M_StartDelay(i, random_(125, 10) + 10); } } } else Monst->_mgoal = MGOAL_NORMAL; if (Monst->_mgoal == MGOAL_NORMAL) { if ((abs(mx) >= 5 || abs(my) >= 5) && v < 2 * Monst->_mint + 43 && LineClearF1(PosOkMonst, i, Monst->_mx, Monst->_my, fx, fy)) { if (AddMissile(Monst->_mx, Monst->_my, fx, fy, md, MIS_RHINO, Monst->_menemy, i, 0, 0) != -1) { if (Monst->MData->snd_special) PlayEffect(i, 3); dMonster[Monst->_mx][Monst->_my] = -1 - i; Monst->_mmode = MM_CHARGE; } } else { if (abs(mx) >= 2 || abs(my) >= 2) { v = random_(134, 100); if (v >= 2 * Monst->_mint + 33 && (Monst->_mVar1 != MM_WALK && Monst->_mVar1 != MM_WALK2 && Monst->_mVar1 != MM_WALK3 || Monst->_mVar2 || v >= 2 * Monst->_mint + 83)) { M_StartDelay(i, random_(135, 10) + 10); } else { M_CallWalk(i, md); } } else if (v < 2 * Monst->_mint + 28) { Monst->_mdir = md; M_StartAttack(i); } } } if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[Monst->_mdir]; } } #ifdef HELLFIRE void MAI_HorkDemon(int i) { MonsterStruct *Monst; int fx, fy, mx, my, md, v, dist; if ((DWORD)i >= MAXMONSTERS) { return; } Monst = &monster[i]; if (Monst->_mmode != MM_STAND || Monst->_msquelch == 0) { return; } fx = Monst->_menemyx; fy = Monst->_menemyy; mx = Monst->_mx - fx; my = Monst->_my - fy; md = GetDirection(Monst->_mx, Monst->_my, Monst->_lastx, Monst->_lasty); if (Monst->_msquelch < 255) { MonstCheckDoors(i); } v = random_(131, 100); if (abs(mx) < 2 && abs(my) < 2) { Monst->_mgoal = 1; } else if (Monst->_mgoal == 4 || (abs(mx) >= 5 || abs(my) >= 5) && random_(132, 4) != 0) { if (Monst->_mgoal != 4) { Monst->_mgoalvar1 = 0; Monst->_mgoalvar2 = random_(133, 2); } Monst->_mgoal = 4; if (abs(mx) > abs(my)) { dist = abs(mx); } else { dist = abs(my); } if (Monst->_mgoalvar1++ >= 2 * dist || dTransVal[Monst->_mx][Monst->_my] != dTransVal[fx][fy]) { Monst->_mgoal = 1; } else if (!M_RoundWalk(i, md, Monst->_mgoalvar2)) { M_StartDelay(i, random_(125, 10) + 10); } } if (Monst->_mgoal == 1) { if ((abs(mx) >= 3 || abs(my) >= 3) && v < 2 * Monst->_mint + 43) { if (PosOkMonst(i, Monst->_mx + HorkXAdd[Monst->_mdir], Monst->_my + HorkYAdd[Monst->_mdir]) && nummonsters < MAXMONSTERS) { M_StartRSpAttack(i, MIS_HORKDMN, 0); } } else if (abs(mx) < 2 && abs(my) < 2) { if (v < 2 * Monst->_mint + 28) { Monst->_mdir = md; M_StartAttack(i); } } else { v = random_(134, 100); if (v < 2 * Monst->_mint + 33 || (Monst->_mVar1 == 1 || Monst->_mVar1 == 2 || Monst->_mVar1 == 3) && Monst->_mVar2 == 0 && v < 2 * Monst->_mint + 83) { M_CallWalk(i, md); } else { M_StartDelay(i, random_(135, 10) + 10); } } } if (Monst->_mmode == MM_STAND) { Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[Monst->_mdir]; } } #endif void MAI_Counselor(int i) { int mx, my, fx, fy; int dist, md, v; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Counselor: Invalid monster %d", i); #endif if (monster[i]._mmode == MM_STAND && monster[i]._msquelch != 0) { Monst = &monster[i]; fx = Monst->_menemyx; fy = Monst->_menemyy; mx = Monst->_mx - fx; my = Monst->_my - fy; md = GetDirection(Monst->_mx, Monst->_my, Monst->_lastx, Monst->_lasty); if (Monst->_msquelch < UCHAR_MAX) MonstCheckDoors(i); v = random_(121, 100); if (Monst->_mgoal == MGOAL_RETREAT) { if (Monst->_mgoalvar1++ <= 3) M_CallWalk(i, opposite[md]); else { Monst->_mgoal = MGOAL_NORMAL; M_StartFadein(i, md, TRUE); } } else if (Monst->_mgoal == MGOAL_MOVE) { if (abs(mx) > abs(my)) dist = abs(mx); else dist = abs(my); if ((abs(mx) >= 2 || abs(my) >= 2) && Monst->_msquelch == UCHAR_MAX && dTransVal[Monst->_mx][Monst->_my] == dTransVal[fx][fy]) { if (Monst->_mgoalvar1++ < 2 * dist || !DirOK(i, md)) { M_RoundWalk(i, md, Monst->_mgoalvar2); } else { Monst->_mgoal = MGOAL_NORMAL; M_StartFadein(i, md, TRUE); } } else { Monst->_mgoal = MGOAL_NORMAL; M_StartFadein(i, md, TRUE); } } else if (Monst->_mgoal == MGOAL_NORMAL) { if (abs(mx) >= 2 || abs(my) >= 2) { if (v < 5 * (Monst->_mint + 10) && LineClear(Monst->_mx, Monst->_my, fx, fy)) { M_StartRAttack(i, counsmiss[Monst->_mint], Monst->mMinDamage + random_(77, Monst->mMaxDamage - Monst->mMinDamage + 1)); } else if (random_(124, 100) < 30) { Monst->_mgoal = MGOAL_MOVE; Monst->_mgoalvar1 = 0; M_StartFadeout(i, md, FALSE); } else M_StartDelay(i, random_(105, 10) + 2 * (5 - Monst->_mint)); } else { Monst->_mdir = md; if (Monst->_mhitpoints < (Monst->_mmaxhp >> 1)) { Monst->_mgoal = MGOAL_RETREAT; Monst->_mgoalvar1 = 0; M_StartFadeout(i, md, FALSE); } else if (Monst->_mVar1 == MM_DELAY || random_(105, 100) < 2 * Monst->_mint + 20) { M_StartRAttack(i, -1, 0); AddMissile(Monst->_mx, Monst->_my, 0, 0, Monst->_mdir, MIS_FLASH, TARGET_PLAYERS, i, 4, 0); AddMissile(Monst->_mx, Monst->_my, 0, 0, Monst->_mdir, MIS_FLASH2, TARGET_PLAYERS, i, 4, 0); } else M_StartDelay(i, random_(105, 10) + 2 * (5 - Monst->_mint)); } } if (Monst->_mmode == MM_STAND) { M_StartDelay(i, random_(125, 10) + 5); } } } void MAI_Garbud(int i) { int _mx, _my, md; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Garbud: Invalid monster %d", i); #endif Monst = &monster[i]; if (Monst->_mmode != MM_STAND) { return; } _mx = Monst->_mx; _my = Monst->_my; md = M_GetDir(i); if (Monst->mtalkmsg < TEXT_GARBUD4 && Monst->mtalkmsg > TEXT_DOOM10 && !(dFlags[_mx][_my] & BFLAG_VISIBLE) && Monst->_mgoal == MGOAL_TALKING) { Monst->_mgoal = MGOAL_INQUIRING; Monst->mtalkmsg++; } if (dFlags[_mx][_my] & BFLAG_VISIBLE) { #ifndef SPAWN if (Monst->mtalkmsg == TEXT_GARBUD4) { if (!effect_is_playing(USFX_GARBUD4) && Monst->_mgoal == MGOAL_TALKING) { Monst->_mgoal = MGOAL_NORMAL; Monst->_msquelch = UCHAR_MAX; Monst->mtalkmsg = 0; } } #endif } if (Monst->_mgoal == MGOAL_NORMAL || Monst->_mgoal == MGOAL_MOVE) MAI_Round(i, TRUE); monster[i]._mdir = md; if (Monst->_mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } void MAI_Zhar(int i) { int mx, my, md; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Zhar: Invalid monster %d", i); #endif Monst = &monster[i]; if (monster[i]._mmode != MM_STAND) { return; } mx = Monst->_mx; my = Monst->_my; md = M_GetDir(i); if (Monst->mtalkmsg == TEXT_ZHAR1 && !(dFlags[mx][my] & BFLAG_VISIBLE) && Monst->_mgoal == MGOAL_TALKING) { Monst->mtalkmsg = TEXT_ZHAR2; Monst->_mgoal = MGOAL_INQUIRING; } if (dFlags[mx][my] & BFLAG_VISIBLE) { mx = Monst->_mx - Monst->_menemyx; my = Monst->_my - Monst->_menemyy; if (abs(mx) > abs(my)) abs(mx); else abs(my); #ifndef SPAWN if (Monst->mtalkmsg == TEXT_ZHAR2) { if (!effect_is_playing(USFX_ZHAR2) && Monst->_mgoal == MGOAL_TALKING) { Monst->_msquelch = UCHAR_MAX; Monst->mtalkmsg = 0; Monst->_mgoal = MGOAL_NORMAL; } } #endif } if (Monst->_mgoal == MGOAL_NORMAL || Monst->_mgoal == MGOAL_RETREAT || Monst->_mgoal == MGOAL_MOVE) MAI_Counselor(i); Monst->_mdir = md; if (monster[i]._mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } void MAI_SnotSpil(int i) { int mx, my, md; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_SnotSpil: Invalid monster %d", i); #endif Monst = &monster[i]; if (monster[i]._mmode != MM_STAND) { return; } mx = Monst->_mx; my = Monst->_my; md = M_GetDir(i); if (Monst->mtalkmsg == TEXT_BANNER10 && !(dFlags[mx][my] & BFLAG_VISIBLE) && Monst->_mgoal == MGOAL_TALKING) { Monst->mtalkmsg = TEXT_BANNER11; Monst->_mgoal = MGOAL_INQUIRING; } if (Monst->mtalkmsg == TEXT_BANNER11 && quests[Q_LTBANNER]._qvar1 == 3) { Monst->mtalkmsg = 0; Monst->_mgoal = MGOAL_NORMAL; } if (dFlags[mx][my] & BFLAG_VISIBLE) { #ifndef SPAWN if (Monst->mtalkmsg == TEXT_BANNER12) { if (!effect_is_playing(USFX_SNOT3) && Monst->_mgoal == MGOAL_TALKING) { ObjChangeMap(setpc_x, setpc_y, setpc_x + setpc_w + 1, setpc_y + setpc_h + 1); quests[Q_LTBANNER]._qvar1 = 3; RedoPlayerVision(); Monst->_msquelch = UCHAR_MAX; Monst->mtalkmsg = 0; Monst->_mgoal = MGOAL_NORMAL; } } #endif if (quests[Q_LTBANNER]._qvar1 == 3) { if (Monst->_mgoal == MGOAL_NORMAL || Monst->_mgoal == MGOAL_ATTACK2) MAI_Fallen(i); } } Monst->_mdir = md; if (monster[i]._mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } void MAI_Lazurus(int i) { int mx, my, md; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Lazurus: Invalid monster %d", i); #endif Monst = &monster[i]; if (monster[i]._mmode != MM_STAND) { return; } mx = Monst->_mx; my = Monst->_my; md = M_GetDir(i); if (dFlags[mx][my] & BFLAG_VISIBLE) { if (gbMaxPlayers == 1) { if (Monst->mtalkmsg == TEXT_VILE13 && Monst->_mgoal == MGOAL_INQUIRING && plr[myplr]._px == 35 && plr[myplr]._py == 46) { PlayInGameMovie("gendata\\fprst3.smk"); Monst->_mmode = MM_TALK; quests[Q_BETRAYER]._qvar1 = 5; } #ifndef SPAWN if (Monst->mtalkmsg == TEXT_VILE13 && !effect_is_playing(USFX_LAZ1) && Monst->_mgoal == MGOAL_TALKING) { ObjChangeMapResync(1, 18, 20, 24); RedoPlayerVision(); quests[Q_BETRAYER]._qvar1 = 6; Monst->_mgoal = MGOAL_NORMAL; Monst->_msquelch = UCHAR_MAX; Monst->mtalkmsg = 0; } #endif } if (gbMaxPlayers != 1 && Monst->mtalkmsg == TEXT_VILE13 && Monst->_mgoal == MGOAL_INQUIRING && quests[Q_BETRAYER]._qvar1 <= 3) { Monst->_mmode = MM_TALK; } } if (Monst->_mgoal == MGOAL_NORMAL || Monst->_mgoal == MGOAL_RETREAT || Monst->_mgoal == MGOAL_MOVE) { #ifndef HELLFIRE Monst->mtalkmsg = 0; #endif MAI_Counselor(i); } Monst->_mdir = md; if (monster[i]._mmode == MM_STAND || monster[i]._mmode == MM_TALK) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } void MAI_Lazhelp(int i) { int _mx, _my; volatile int md; // BUGFIX: very questionable volatile MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Lazhelp: Invalid monster %d", i); #endif if (monster[i]._mmode != MM_STAND) return; Monst = &monster[i]; _mx = Monst->_mx; _my = Monst->_my; md = M_GetDir(i); if (dFlags[_mx][_my] & BFLAG_VISIBLE) { if (gbMaxPlayers == 1) { if (quests[Q_BETRAYER]._qvar1 <= 5) { Monst->_mgoal = MGOAL_INQUIRING; } else { Monst->_mgoal = MGOAL_NORMAL; Monst->mtalkmsg = 0; } } else Monst->_mgoal = MGOAL_NORMAL; } if (Monst->_mgoal == MGOAL_NORMAL) MAI_Succ(i); Monst->_mdir = md; if (monster[i]._mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } void MAI_Lachdanan(int i) { int _mx, _my, md; MonsterStruct *Monst; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Lachdanan: Invalid monster %d", i); #endif Monst = &monster[i]; if (monster[i]._mmode != MM_STAND) { return; } _mx = Monst->_mx; _my = Monst->_my; md = M_GetDir(i); #ifndef SPAWN if (Monst->mtalkmsg == TEXT_VEIL9 && !(dFlags[_mx][_my] & BFLAG_VISIBLE) && monster[i]._mgoal == MGOAL_TALKING) { Monst->mtalkmsg = TEXT_VEIL10; monster[i]._mgoal = MGOAL_INQUIRING; } if (dFlags[_mx][_my] & BFLAG_VISIBLE) { if (Monst->mtalkmsg == TEXT_VEIL11) { if (!effect_is_playing(USFX_LACH3) && Monst->_mgoal == MGOAL_TALKING) { Monst->mtalkmsg = 0; quests[Q_VEIL]._qactive = QUEST_DONE; M_StartKill(i, -1); } } } #endif Monst->_mdir = md; if (monster[i]._mmode == MM_STAND) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[md]; } void MAI_Warlord(int i) { MonsterStruct *Monst; int mx, my, md; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MAI_Warlord: Invalid monster %d", i); #endif Monst = &monster[i]; if (monster[i]._mmode != MM_STAND) { return; } mx = Monst->_mx; my = Monst->_my; md = M_GetDir(i); if (dFlags[mx][my] & BFLAG_VISIBLE) { if (Monst->mtalkmsg == TEXT_WARLRD9 && Monst->_mgoal == MGOAL_INQUIRING) Monst->_mmode = MM_TALK; #ifndef SPAWN if (Monst->mtalkmsg == TEXT_WARLRD9 && !effect_is_playing(USFX_WARLRD1) && Monst->_mgoal == MGOAL_TALKING) { Monst->_msquelch = UCHAR_MAX; Monst->mtalkmsg = 0; Monst->_mgoal = MGOAL_NORMAL; } #endif } if (Monst->_mgoal == MGOAL_NORMAL) MAI_SkelSd(i); Monst->_mdir = md; if (monster[i]._mmode == MM_STAND || monster[i]._mmode == MM_TALK) Monst->_mAnimData = Monst->MType->Anims[MA_STAND].Data[Monst->_mdir]; } void DeleteMonsterList() { int i; for (i = 0; i < MAX_PLRS; i++) { if (monster[i]._mDelFlag) { monster[i]._mx = 1; monster[i]._my = 0; monster[i]._mfutx = 0; monster[i]._mfuty = 0; monster[i]._moldx = 0; monster[i]._moldy = 0; monster[i]._mDelFlag = FALSE; } } i = MAX_PLRS; while (i < nummonsters) { if (monster[monstactive[i]]._mDelFlag) { DeleteMonster(i); i = 0; // BUGFIX: should be `i = MAX_PLRS`, was 0 (only pseudo delete golems, their monster array indices are special and should not appear in the available monster index list). } else { i++; } } } void ProcessMonsters() { int i, mi, mx, my, _menemy; BOOL raflag; MonsterStruct *Monst; DeleteMonsterList(); /// ASSERT: assert((DWORD)nummonsters <= MAXMONSTERS); for (i = 0; i < nummonsters; i++) { mi = monstactive[i]; Monst = &monster[mi]; raflag = FALSE; if (gbMaxPlayers > 1) { SetRndSeed(Monst->_mAISeed); Monst->_mAISeed = GetRndSeed(); } if (!(monster[mi]._mFlags & MFLAG_NOHEAL) && Monst->_mhitpoints < Monst->_mmaxhp && Monst->_mhitpoints >> 6 > 0) { if (Monst->mLevel > 1) { Monst->_mhitpoints += Monst->mLevel >> 1; } else { Monst->_mhitpoints += Monst->mLevel; } } mx = Monst->_mx; my = Monst->_my; #ifndef SPAWN if (dFlags[mx][my] & BFLAG_VISIBLE && Monst->_msquelch == 0) { if (Monst->MType->mtype == MT_CLEAVER) { PlaySFX(USFX_CLEAVER); } #ifdef HELLFIRE if (Monst->MType->mtype == MT_NAKRUL) { if (UseCowFarmer) { PlaySFX(USFX_NAKRUL6); } else { if (IsUberRoomOpened) PlaySFX(USFX_NAKRUL4); else PlaySFX(USFX_NAKRUL5); } } if (Monst->MType->mtype == MT_DEFILER) PlaySFX(USFX_DEFILER8); M_Enemy(mi); #endif } #endif if (Monst->_mFlags & MFLAG_TARGETS_MONSTER) { _menemy = Monst->_menemy; if ((DWORD)_menemy >= MAXMONSTERS) { #ifdef HELLFIRE return; #else app_fatal("Illegal enemy monster %d for monster \"%s\"", _menemy, Monst->mName); #endif } // BUGFIX: enemy target may be dead at time of access, thus reading garbage data from `monster[Monst->_menemy]._mfutx`. Monst->_lastx = monster[Monst->_menemy]._mfutx; Monst->_menemyx = Monst->_lastx; Monst->_lasty = monster[Monst->_menemy]._mfuty; Monst->_menemyy = Monst->_lasty; } else { _menemy = Monst->_menemy; if ((DWORD)_menemy >= MAX_PLRS) { #ifdef HELLFIRE return; #else app_fatal("Illegal enemy player %d for monster \"%s\"", _menemy, Monst->mName); #endif } Monst->_menemyx = plr[Monst->_menemy]._pfutx; Monst->_menemyy = plr[Monst->_menemy]._pfuty; if (dFlags[mx][my] & BFLAG_VISIBLE) { Monst->_msquelch = UCHAR_MAX; Monst->_lastx = plr[Monst->_menemy]._pfutx; Monst->_lasty = plr[Monst->_menemy]._pfuty; } else if (Monst->_msquelch != 0 && Monst->_mAi != MT_DIABLO) { /// BUGFIX: change '_mAi' to 'MType->mtype' Monst->_msquelch--; } } do { if (!(Monst->_mFlags & MFLAG_SEARCH)) { AiProc[Monst->_mAi](mi); } else if (!MAI_Path(mi)) { AiProc[Monst->_mAi](mi); } switch (Monst->_mmode) { case MM_STAND: raflag = M_DoStand(mi); break; case MM_WALK: raflag = M_DoWalk(mi); break; case MM_WALK2: raflag = M_DoWalk2(mi); break; case MM_WALK3: raflag = M_DoWalk3(mi); break; case MM_ATTACK: raflag = M_DoAttack(mi); break; case MM_GOTHIT: raflag = M_DoGotHit(mi); break; case MM_DEATH: raflag = M_DoDeath(mi); break; case MM_SATTACK: raflag = M_DoSAttack(mi); break; case MM_FADEIN: raflag = M_DoFadein(mi); break; case MM_FADEOUT: raflag = M_DoFadeout(mi); break; case MM_RATTACK: raflag = M_DoRAttack(mi); break; case MM_SPSTAND: raflag = M_DoSpStand(mi); break; case MM_RSPATTACK: raflag = M_DoRSpAttack(mi); break; case MM_DELAY: raflag = M_DoDelay(mi); break; case MM_CHARGE: raflag = FALSE; break; case MM_STONE: raflag = M_DoStone(mi); break; case MM_HEAL: raflag = M_DoHeal(mi); break; case MM_TALK: raflag = M_DoTalk(mi); break; } if (raflag) { GroupUnity(mi); } } while (raflag); if (Monst->_mmode != MM_STONE) { Monst->_mAnimCnt++; if (!(Monst->_mFlags & MFLAG_ALLOW_SPECIAL) && Monst->_mAnimCnt >= Monst->_mAnimDelay) { Monst->_mAnimCnt = 0; if (Monst->_mFlags & MFLAG_LOCK_ANIMATION) { Monst->_mAnimFrame--; if (Monst->_mAnimFrame == 0) { Monst->_mAnimFrame = Monst->_mAnimLen; } } else { Monst->_mAnimFrame++; if (Monst->_mAnimFrame > Monst->_mAnimLen) { Monst->_mAnimFrame = 1; } } } } } DeleteMonsterList(); } void FreeMonsters() { int mtype; int i, j; for (i = 0; i < nummtypes; i++) { mtype = Monsters[i].mtype; for (j = 0; j < 6; j++) { if (animletter[j] != 's' || monsterdata[mtype].has_special) { MemFreeDbg(Monsters[i].Anims[j].CMem); } } } FreeMissiles2(); } BOOL DirOK(int i, int mdir) { int fx, fy; int x, y; int mcount, mi; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return FALSE; #else app_fatal("DirOK: Invalid monster %d", i); #endif fx = monster[i]._mx + offset_x[mdir]; fy = monster[i]._my + offset_y[mdir]; if (fy < 0 || fy >= MAXDUNY || fx < 0 || fx >= MAXDUNX || !PosOkMonst(i, fx, fy)) return FALSE; if (mdir == DIR_E) { if (SolidLoc(fx, fy + 1) || dFlags[fx][fy + 1] & BFLAG_MONSTLR) return FALSE; } else if (mdir == DIR_W) { if (SolidLoc(fx + 1, fy) || dFlags[fx + 1][fy] & BFLAG_MONSTLR) return FALSE; } else if (mdir == DIR_N) { if (SolidLoc(fx + 1, fy) || SolidLoc(fx, fy + 1)) return FALSE; } else if (mdir == DIR_S) if (SolidLoc(fx - 1, fy) || SolidLoc(fx, fy - 1)) return FALSE; if (monster[i].leaderflag == 1) { if (abs(fx - monster[monster[i].leader]._mfutx) >= 4 || abs(fy - monster[monster[i].leader]._mfuty) >= 4) { return FALSE; } return TRUE; } if (monster[i]._uniqtype == 0 || !(UniqMonst[monster[i]._uniqtype - 1].mUnqAttr & 2)) return TRUE; mcount = 0; for (x = fx - 3; x <= fx + 3; x++) { for (y = fy - 3; y <= fy + 3; y++) { if (y < 0 || y >= MAXDUNY || x < 0 || x >= MAXDUNX) continue; mi = dMonster[x][y]; if (mi < 0) mi = -mi; if (mi != 0) mi--; // BUGFIX: should only run pack member check if mi was non-zero prior to executing the body of the above if-statement. if (monster[mi].leaderflag == 1 && monster[mi].leader == i && monster[mi]._mfutx == x && monster[mi]._mfuty == y) { mcount++; } } } return mcount == monster[i].packsize; } BOOL PosOkMissile(int x, int y) { return !nMissileTable[dPiece[x][y]] && !(dFlags[x][y] & BFLAG_MONSTLR); } BOOL CheckNoSolid(int x, int y) { return nSolidTable[dPiece[x][y]] == FALSE; } BOOL LineClearF(BOOL (*Clear)(int, int), int x1, int y1, int x2, int y2) { int xorg, yorg; int dx, dy; int d; int xincD, yincD, dincD, dincH; int tmp; BOOL done = FALSE; xorg = x1; yorg = y1; dx = x2 - x1; dy = y2 - y1; if (abs(dx) > abs(dy)) { if (dx < 0) { tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; dx = -dx; dy = -dy; } if (dy > 0) { d = 2 * dy - dx; dincD = 2 * dy; dincH = 2 * (dy - dx); yincD = 1; } else { d = 2 * dy + dx; dincD = 2 * dy; dincH = 2 * (dx + dy); yincD = -1; } while (!done && (x1 != x2 || y1 != y2)) { if ((d <= 0) ^ (yincD < 0)) { d += dincD; } else { d += dincH; y1 += yincD; } x1++; done = ((x1 != xorg || y1 != yorg) && !Clear(x1, y1)); } } else { if (dy < 0) { tmp = y1; y1 = y2; y2 = tmp; tmp = x1; x1 = x2; x2 = tmp; dy = -dy; dx = -dx; } if (dx > 0) { d = 2 * dx - dy; dincD = 2 * dx; dincH = 2 * (dx - dy); xincD = 1; } else { d = 2 * dx + dy; dincD = 2 * dx; dincH = 2 * (dy + dx); xincD = -1; } while (!done && (y1 != y2 || x1 != x2)) { if ((d <= 0) ^ (xincD < 0)) { d += dincD; } else { d += dincH; x1 += xincD; } y1++; done = ((y1 != yorg || x1 != xorg) && !Clear(x1, y1)); } } return x1 == x2 && y1 == y2; } BOOL LineClear(int x1, int y1, int x2, int y2) { return LineClearF(PosOkMissile, x1, y1, x2, y2); } BOOL LineClearF1(BOOL (*Clear)(int, int, int), int monst, int x1, int y1, int x2, int y2) { int dx, dy; int d; int xorg, yorg; int xincD, yincD, dincD, dincH; int tmp; BOOL done = FALSE; xorg = x1; yorg = y1; dx = x2 - x1; dy = y2 - y1; if (abs(dx) > abs(dy)) { if (dx < 0) { tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; dx = -dx; dy = -dy; } if (dy > 0) { d = 2 * dy - dx; dincD = 2 * dy; dincH = 2 * (dy - dx); yincD = 1; } else { d = 2 * dy + dx; dincD = 2 * dy; dincH = 2 * (dx + dy); yincD = -1; } while (!done && (x1 != x2 || y1 != y2)) { if ((d <= 0) ^ (yincD < 0)) { d += dincD; } else { d += dincH; y1 += yincD; } x1++; done = ((x1 != xorg || y1 != yorg) && !Clear(monst, x1, y1)); } } else { if (dy < 0) { tmp = y1; y1 = y2; y2 = tmp; tmp = x1; x1 = x2; x2 = tmp; dy = -dy; dx = -dx; } if (dx > 0) { d = 2 * dx - dy; dincD = 2 * dx; dincH = 2 * (dx - dy); xincD = 1; } else { d = 2 * dx + dy; dincD = 2 * dx; dincH = 2 * (dy + dx); xincD = -1; } while (!done && (y1 != y2 || x1 != x2)) { if ((d <= 0) ^ (xincD < 0)) { d += dincD; } else { d += dincH; x1 += xincD; } y1++; done = ((y1 != yorg || x1 != xorg) && !Clear(monst, x1, y1)); } } return x1 == x2 && y1 == y2; } void SyncMonsterAnim(int i) { int _mdir; #ifdef HELLFIRE if ((DWORD)i >= MAXMONSTERS || i < 0) return; #else if ((DWORD)i >= MAXMONSTERS) app_fatal("SyncMonsterAnim: Invalid monster %d", i); #endif monster[i].MType = &Monsters[monster[i]._mMTidx]; monster[i].MData = Monsters[monster[i]._mMTidx].MData; if (monster[i]._uniqtype != 0) monster[i].mName = UniqMonst[monster[i]._uniqtype - 1].mName; else monster[i].mName = monster[i].MData->mName; _mdir = monster[i]._mdir; switch (monster[i]._mmode) { case MM_STAND: monster[i]._mAnimData = monster[i].MType->Anims[MA_STAND].Data[_mdir]; break; case MM_WALK: case MM_WALK2: case MM_WALK3: monster[i]._mAnimData = monster[i].MType->Anims[MA_WALK].Data[_mdir]; break; case MM_ATTACK: case MM_RATTACK: monster[i]._mAnimData = monster[i].MType->Anims[MA_ATTACK].Data[_mdir]; break; case MM_GOTHIT: monster[i]._mAnimData = monster[i].MType->Anims[MA_GOTHIT].Data[_mdir]; break; case MM_DEATH: monster[i]._mAnimData = monster[i].MType->Anims[MA_DEATH].Data[_mdir]; break; case MM_SATTACK: case MM_FADEIN: case MM_FADEOUT: monster[i]._mAnimData = monster[i].MType->Anims[MA_SPECIAL].Data[_mdir]; break; case MM_SPSTAND: case MM_RSPATTACK: monster[i]._mAnimData = monster[i].MType->Anims[MA_SPECIAL].Data[_mdir]; break; case MM_HEAL: monster[i]._mAnimData = monster[i].MType->Anims[MA_SPECIAL].Data[_mdir]; break; case MM_DELAY: monster[i]._mAnimData = monster[i].MType->Anims[MA_STAND].Data[_mdir]; break; case MM_TALK: monster[i]._mAnimData = monster[i].MType->Anims[MA_STAND].Data[_mdir]; break; case MM_CHARGE: monster[i]._mAnimData = monster[i].MType->Anims[MA_ATTACK].Data[_mdir]; monster[i]._mAnimFrame = 1; monster[i]._mAnimLen = monster[i].MType->Anims[MA_ATTACK].Frames; break; default: monster[i]._mAnimData = monster[i].MType->Anims[MA_STAND].Data[_mdir]; monster[i]._mAnimFrame = 1; monster[i]._mAnimLen = monster[i].MType->Anims[MA_STAND].Frames; break; } } void M_FallenFear(int x, int y) { int i, mi, rundist, aitype; for (i = 0; i < nummonsters; i++) { rundist = 0; mi = monstactive[i]; switch (monster[mi].MType->mtype) { case MT_RFALLSP: case MT_RFALLSD: rundist = 7; break; case MT_DFALLSP: case MT_DFALLSD: rundist = 5; break; case MT_YFALLSP: case MT_YFALLSD: rundist = 3; break; case MT_BFALLSP: case MT_BFALLSD: rundist = 2; break; } aitype = monster[mi]._mAi; if (aitype == AI_FALLEN && rundist && abs(x - monster[mi]._mx) < 5 && abs(y - monster[mi]._my) < 5 && monster[mi]._mhitpoints >> 6 > 0) { monster[mi]._mgoal = MGOAL_RETREAT; monster[mi]._mgoalvar1 = rundist; // BUGFIX: should be `monster[mi]`, was `monster[i]`. monster[mi]._mdir = GetDirection(x, y, monster[i]._mx, monster[i]._my); } } } void PrintMonstHistory(int mt) { int minHP, maxHP, res; sprintf(tempstr, "Total kills : %i", monstkills[mt]); AddPanelString(tempstr, TRUE); if (monstkills[mt] >= 30) { minHP = monsterdata[mt].mMinHP; maxHP = monsterdata[mt].mMaxHP; if (gbMaxPlayers == 1) { minHP = monsterdata[mt].mMinHP >> 1; maxHP = monsterdata[mt].mMaxHP >> 1; } if (minHP < 1) minHP = 1; if (maxHP < 1) maxHP = 1; #ifdef HELLFIRE if (gnDifficulty == DIFF_NIGHTMARE) { minHP = 3 * minHP + (gbMaxPlayers == 1 ? 50 : 100); maxHP = 3 * maxHP + (gbMaxPlayers == 1 ? 50 : 100); } else if (gnDifficulty == DIFF_HELL) { minHP = 4 * minHP + (gbMaxPlayers == 1 ? 100 : 200); maxHP = 4 * maxHP + (gbMaxPlayers == 1 ? 100 : 200); } #else if (gnDifficulty == DIFF_NIGHTMARE) { minHP = 3 * minHP + 1; maxHP = 3 * maxHP + 1; } if (gnDifficulty == DIFF_HELL) { minHP = 4 * minHP + 3; maxHP = 4 * maxHP + 3; } #endif sprintf(tempstr, "Hit Points : %i-%i", minHP, maxHP); AddPanelString(tempstr, TRUE); } if (monstkills[mt] >= 15) { if (gnDifficulty != DIFF_HELL) res = monsterdata[mt].mMagicRes; else res = monsterdata[mt].mMagicRes2; res = res & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING); if (!res) { strcpy(tempstr, "No magic resistance"); AddPanelString(tempstr, TRUE); } else { if (res & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING)) { strcpy(tempstr, "Resists : "); if (res & RESIST_MAGIC) strcat(tempstr, "Magic "); if (res & RESIST_FIRE) strcat(tempstr, "Fire "); if (res & RESIST_LIGHTNING) strcat(tempstr, "Lightning "); tempstr[strlen(tempstr) - 1] = '\0'; AddPanelString(tempstr, TRUE); } if (res & (IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING)) { strcpy(tempstr, "Immune : "); if (res & IMMUNE_MAGIC) strcat(tempstr, "Magic "); if (res & IMMUNE_FIRE) strcat(tempstr, "Fire "); if (res & IMMUNE_LIGHTNING) strcat(tempstr, "Lightning "); tempstr[strlen(tempstr) - 1] = '\0'; AddPanelString(tempstr, TRUE); } } } pinfoflag = TRUE; } void PrintUniqueHistory() { int res; res = monster[pcursmonst].mMagicRes & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING); if (!res) { strcpy(tempstr, "No resistances"); AddPanelString(tempstr, TRUE); strcpy(tempstr, "No Immunities"); } else { if (res & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING)) strcpy(tempstr, "Some Magic Resistances"); else strcpy(tempstr, "No resistances"); AddPanelString(tempstr, TRUE); if (res & (IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING)) { strcpy(tempstr, "Some Magic Immunities"); } else { strcpy(tempstr, "No Immunities"); } } AddPanelString(tempstr, TRUE); pinfoflag = TRUE; } void MissToMonst(int i, int x, int y) { int oldx, oldy; int newx, newy; int m, pnum; MissileStruct *Miss; MonsterStruct *Monst; if ((DWORD)i >= MAXMISSILES) #ifdef HELLFIRE return; #else app_fatal("MissToMonst: Invalid missile %d", i); #endif Miss = &missile[i]; m = Miss->_misource; if ((DWORD)m >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("MissToMonst: Invalid monster %d", m); #endif Monst = &monster[m]; oldx = Miss->_mix; oldy = Miss->_miy; dMonster[x][y] = m + 1; Monst->_mdir = Miss->_mimfnum; Monst->_mx = x; Monst->_my = y; M_StartStand(m, Monst->_mdir); if (Monst->MType->mtype < MT_INCIN || Monst->MType->mtype > MT_HELLBURN) { if (!(Monst->_mFlags & MFLAG_TARGETS_MONSTER)) M_StartHit(m, -1, 0); else M2MStartHit(m, -1, 0); } else { M_StartFadein(m, Monst->_mdir, FALSE); } if (!(Monst->_mFlags & MFLAG_TARGETS_MONSTER)) { pnum = dPlayer[oldx][oldy] - 1; if (dPlayer[oldx][oldy] > 0) { if (Monst->MType->mtype != MT_GLOOM && (Monst->MType->mtype < MT_INCIN || Monst->MType->mtype > MT_HELLBURN)) { M_TryH2HHit(m, dPlayer[oldx][oldy] - 1, 500, Monst->mMinDamage2, Monst->mMaxDamage2); if (pnum == dPlayer[oldx][oldy] - 1 && (Monst->MType->mtype < MT_NSNAKE || Monst->MType->mtype > MT_GSNAKE)) { if (plr[pnum]._pmode != PM_GOTHIT && plr[pnum]._pmode != PM_DEATH) StartPlrHit(pnum, 0, TRUE); newx = oldx + offset_x[Monst->_mdir]; newy = oldy + offset_y[Monst->_mdir]; if (PosOkPlayer(pnum, newx, newy)) { plr[pnum]._px = newx; plr[pnum]._py = newy; FixPlayerLocation(pnum, plr[pnum]._pdir); FixPlrWalkTags(pnum); dPlayer[newx][newy] = pnum + 1; SetPlayerOld(pnum); } } } } } else { if (dMonster[oldx][oldy] > 0) { if (Monst->MType->mtype != MT_GLOOM && (Monst->MType->mtype < MT_INCIN || Monst->MType->mtype > MT_HELLBURN)) { M_TryM2MHit(m, dMonster[oldx][oldy] - 1, 500, Monst->mMinDamage2, Monst->mMaxDamage2); if (Monst->MType->mtype < MT_NSNAKE || Monst->MType->mtype > MT_GSNAKE) { newx = oldx + offset_x[Monst->_mdir]; newy = oldy + offset_y[Monst->_mdir]; if (PosOkMonst(dMonster[oldx][oldy] - 1, newx, newy)) { m = dMonster[oldx][oldy]; dMonster[newx][newy] = m; dMonster[oldx][oldy] = 0; m--; monster[m]._mx = newx; monster[m]._mfutx = newx; monster[m]._my = newy; monster[m]._mfuty = newy; } } } } } } BOOL PosOkMonst(int i, int x, int y) { #ifdef HELLFIRE int oi; BOOL ret; ret = !SolidLoc(x, y) && dPlayer[x][y] == 0 && dMonster[x][y] == 0; oi = dObject[x][y]; if (ret && oi != 0) { oi = oi > 0 ? oi - 1 : -(oi + 1); if (object[oi]._oSolidFlag) ret = FALSE; } if (ret) ret = monster_posok(i, x, y); #else int oi, mi, j; BOOL ret, fire; fire = FALSE; ret = !SolidLoc(x, y) && dPlayer[x][y] == 0 && dMonster[x][y] == 0; if (ret && dObject[x][y] != 0) { oi = dObject[x][y] > 0 ? dObject[x][y] - 1 : -(dObject[x][y] + 1); if (object[oi]._oSolidFlag) ret = FALSE; } if (ret && dMissile[x][y] != 0 && i >= 0) { // BUGFIX: case with multiple missiles being present on (x, y)-coordinate not handled. mi = dMissile[x][y]; if (mi > 0) { if (missile[mi]._mitype == MIS_FIREWALL) { // BUGFIX: Change 'mi' to 'mi - 1' fire = TRUE; } else { for (j = 0; j < nummissiles; j++) { if (missile[missileactive[j]]._mitype == MIS_FIREWALL) // BUGFIX: Check missile x/y fire = TRUE; } } } if (fire && (!(monster[i].mMagicRes & IMMUNE_FIRE) || monster[i].MType->mtype == MT_DIABLO)) ret = FALSE; } #endif return ret; } #ifdef HELLFIRE BOOLEAN monster_posok(int i, int x, int y) { int mi, j; BOOLEAN ret, fire, lightning; ret = TRUE; mi = dMissile[x][y]; if (mi && i >= 0) { fire = FALSE; lightning = FALSE; if (mi > 0) { if (missile[mi]._mitype == MIS_FIREWALL) { // BUGFIX: Change 'mi' to 'mi - 1' fire = TRUE; } else if (missile[mi]._mitype == MIS_LIGHTWALL) { // BUGFIX: Change 'mi' to 'mi - 1' lightning = TRUE; } } else { for (j = 0; j < nummissiles; j++) { mi = missileactive[j]; if (missile[mi]._mix == x && missile[mi]._miy == y) { if (missile[mi]._mitype == MIS_FIREWALL) { fire = TRUE; break; } if (missile[mi]._mitype == MIS_LIGHTWALL) { lightning = TRUE; break; } } } } if ((fire && !(monster[i].mMagicRes & IMMUNE_FIRE)) || (fire && monster[i].MType->mtype == MT_DIABLO)) ret = FALSE; if ((lightning && !(monster[i].mMagicRes & IMMUNE_LIGHTNING)) || (lightning && monster[i].MType->mtype == MT_DIABLO)) ret = FALSE; } return ret; } #endif BOOL PosOkMonst2(int i, int x, int y) { int oi, mi, j; #ifdef HELLFIRE BOOL ret; oi = dObject[x][y]; ret = !SolidLoc(x, y); if (ret && oi != 0) { oi = oi > 0 ? oi - 1 : -(oi + 1); if (object[oi]._oSolidFlag) ret = FALSE; } if (ret) ret = monster_posok(i, x, y); #else BOOL ret, fire; fire = FALSE; ret = !SolidLoc(x, y); if (ret && dObject[x][y] != 0) { oi = dObject[x][y] > 0 ? dObject[x][y] - 1 : -(dObject[x][y] + 1); if (object[oi]._oSolidFlag) ret = FALSE; } if (ret && dMissile[x][y] != 0 && i >= 0) { mi = dMissile[x][y]; // BUGFIX: case with multiple missiles being present on (x, y)-coordinate not handled. if (mi > 0) { if (missile[mi]._mitype == MIS_FIREWALL) { // BUGFIX: Change 'mi' to 'mi - 1' fire = TRUE; } else { for (j = 0; j < nummissiles; j++) { if (missile[missileactive[j]]._mitype == MIS_FIREWALL) // BUGFIX: Check missile x/y fire = TRUE; } } } if (fire && (!(monster[i].mMagicRes & IMMUNE_FIRE) || monster[i].MType->mtype == MT_DIABLO)) ret = FALSE; } #endif return ret; } BOOL PosOkMonst3(int i, int x, int y) { int j, oi, objtype, mi; #ifdef HELLFIRE BOOL ret; DIABOOL isdoor; ret = TRUE; isdoor = FALSE; oi = dObject[x][y]; if (ret && oi != 0) { oi = oi > 0 ? oi - 1 : -(oi + 1); objtype = object[oi]._otype; isdoor = objtype == OBJ_L1LDOOR || objtype == OBJ_L1RDOOR || objtype == OBJ_L2LDOOR || objtype == OBJ_L2RDOOR || objtype == OBJ_L3LDOOR || objtype == OBJ_L3RDOOR; if (object[oi]._oSolidFlag && !isdoor) { ret = FALSE; } } if (ret) { ret = (!SolidLoc(x, y) || isdoor) && dPlayer[x][y] == 0 && dMonster[x][y] == 0; } if (ret) ret = monster_posok(i, x, y); #else BOOL ret, fire, isdoor; fire = FALSE; ret = TRUE; isdoor = FALSE; if (ret && dObject[x][y] != 0) { oi = dObject[x][y] > 0 ? dObject[x][y] - 1 : -(dObject[x][y] + 1); objtype = object[oi]._otype; isdoor = objtype == OBJ_L1LDOOR || objtype == OBJ_L1RDOOR || objtype == OBJ_L2LDOOR || objtype == OBJ_L2RDOOR || objtype == OBJ_L3LDOOR || objtype == OBJ_L3RDOOR; if (object[oi]._oSolidFlag && !isdoor) { ret = FALSE; } } if (ret) { ret = (!SolidLoc(x, y) || isdoor) && dPlayer[x][y] == 0 && dMonster[x][y] == 0; } if (ret && dMissile[x][y] != 0 && i >= 0) { mi = dMissile[x][y]; // BUGFIX: case with multiple missiles being present on (x, y)-coordinate not handled. if (mi > 0) { if (missile[mi]._mitype == MIS_FIREWALL) { // BUGFIX: Change 'mi' to 'mi - 1' fire = TRUE; } else { for (j = 0; j < nummissiles; j++) { if (missile[missileactive[j]]._mitype == MIS_FIREWALL) // BUGFIX: Check missile x/y fire = TRUE; } } } if (fire && (!(monster[i].mMagicRes & IMMUNE_FIRE) || monster[i].MType->mtype == MT_DIABLO)) ret = FALSE; } #endif return ret; } BOOL IsSkel(int mt) { return mt >= MT_WSKELAX && mt <= MT_XSKELAX || mt >= MT_WSKELBW && mt <= MT_XSKELBW || mt >= MT_WSKELSD && mt <= MT_XSKELSD; } BOOL IsGoat(int mt) { return mt >= MT_NGOATMC && mt <= MT_GGOATMC || mt >= MT_NGOATBW && mt <= MT_GGOATBW; } int M_SpawnSkel(int x, int y, int dir) { int i, j, skeltypes, skel; j = 0; for (i = 0; i < nummtypes; i++) { if (IsSkel(Monsters[i].mtype)) j++; } if (j) { skeltypes = random_(136, j); j = 0; for (i = 0; i < nummtypes && j <= skeltypes; i++) { if (IsSkel(Monsters[i].mtype)) j++; } skel = AddMonster(x, y, dir, i - 1, TRUE); if (skel != -1) M_StartSpStand(skel, dir); return skel; } return -1; } void ActivateSpawn(int i, int x, int y, int dir) { dMonster[x][y] = i + 1; monster[i]._mx = x; monster[i]._my = y; monster[i]._mfutx = x; monster[i]._mfuty = y; monster[i]._moldx = x; monster[i]._moldy = y; M_StartSpStand(i, dir); } BOOL SpawnSkeleton(int ii, int x, int y) { int dx, dy, xx, yy, dir, j, k, rs; BOOL savail; int monstok[3][3]; if (ii == -1) return FALSE; if (PosOkMonst(-1, x, y)) { dir = GetDirection(x, y, x, y); ActivateSpawn(ii, x, y, dir); return TRUE; } savail = FALSE; yy = 0; for (j = y - 1; j <= y + 1; j++) { xx = 0; for (k = x - 1; k <= x + 1; k++) { monstok[xx][yy] = PosOkMonst(-1, k, j); savail |= monstok[xx][yy]; xx++; } yy++; } if (!savail) { return FALSE; } rs = random_(137, 15) + 1; xx = 0; yy = 0; while (rs > 0) { if (monstok[xx][yy]) rs--; if (rs > 0) { xx++; if (xx == 3) { xx = 0; yy++; if (yy == 3) yy = 0; } } } dx = x - 1 + xx; dy = y - 1 + yy; dir = GetDirection(dx, dy, x, y); ActivateSpawn(ii, dx, dy, dir); return TRUE; } int PreSpawnSkeleton() { int i, j, skeltypes, skel; j = 0; for (i = 0; i < nummtypes; i++) { if (IsSkel(Monsters[i].mtype)) j++; } if (j) { skeltypes = random_(136, j); j = 0; for (i = 0; i < nummtypes && j <= skeltypes; i++) { if (IsSkel(Monsters[i].mtype)) j++; } skel = AddMonster(0, 0, 0, i - 1, FALSE); if (skel != -1) M_StartStand(skel, 0); return skel; } return -1; } void TalktoMonster(int i) { MonsterStruct *Monst; int pnum, itm; if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("TalktoMonster: Invalid monster %d", i); #endif Monst = &monster[i]; pnum = Monst->_menemy; Monst->_mmode = MM_TALK; if (Monst->_mAi == AI_SNOTSPIL || Monst->_mAi == AI_LACHDAN) { if (QuestStatus(Q_LTBANNER) && quests[Q_LTBANNER]._qvar1 == 2 && PlrHasItem(pnum, IDI_BANNER, itm)) { RemoveInvItem(pnum, itm); quests[Q_LTBANNER]._qactive = QUEST_DONE; Monst->mtalkmsg = TEXT_BANNER12; Monst->_mgoal = MGOAL_INQUIRING; } if (QuestStatus(Q_VEIL) && Monst->mtalkmsg >= TEXT_VEIL9) { if (PlrHasItem(pnum, IDI_GLDNELIX, itm)) { RemoveInvItem(pnum, itm); Monst->mtalkmsg = TEXT_VEIL11; Monst->_mgoal = MGOAL_INQUIRING; } } } } void SpawnGolum(int i, int x, int y, int mi) { if ((DWORD)i >= MAXMONSTERS) #ifdef HELLFIRE return; #else app_fatal("SpawnGolum: Invalid monster %d", i); #endif dMonster[x][y] = i + 1; 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]._pathcount = 0; monster[i]._mmaxhp = 2 * (320 * missile[mi]._mispllvl + plr[i]._pMaxMana / 3); monster[i]._mhitpoints = monster[i]._mmaxhp; monster[i].mArmorClass = 25; monster[i].mHit = 5 * (missile[mi]._mispllvl + 8) + 2 * plr[i]._pLevel; monster[i].mMinDamage = 2 * (missile[mi]._mispllvl + 4); monster[i].mMaxDamage = 2 * (missile[mi]._mispllvl + 8); monster[i]._mFlags |= MFLAG_GOLEM; M_StartSpStand(i, 0); M_Enemy(i); if (i == myplr) { NetSendCmdGolem( monster[i]._mx, monster[i]._my, monster[i]._mdir, monster[i]._menemy, monster[i]._mhitpoints, currlevel); } } BOOL CanTalkToMonst(int m) { if ((DWORD)m >= MAXMONSTERS) { #ifdef HELLFIRE return FALSE; #else app_fatal("CanTalkToMonst: Invalid monster %d", m); #endif } if (monster[m]._mgoal == MGOAL_INQUIRING) { return TRUE; } return monster[m]._mgoal == MGOAL_TALKING; } BOOL CheckMonsterHit(int m, BOOL &ret) { if ((DWORD)m >= MAXMONSTERS) { #ifdef HELLFIRE return FALSE; #else app_fatal("CheckMonsterHit: Invalid monster %d", m); #endif } if (monster[m]._mAi == AI_GARG && monster[m]._mFlags & MFLAG_ALLOW_SPECIAL) { monster[m]._mFlags &= ~MFLAG_ALLOW_SPECIAL; monster[m]._mmode = MM_SATTACK; ret = TRUE; return TRUE; } if (monster[m].MType->mtype >= MT_COUNSLR && monster[m].MType->mtype <= MT_ADVOCATE) { if (monster[m]._mgoal != MGOAL_NORMAL) { ret = FALSE; return TRUE; } } return FALSE; } int encode_enemy(int m) { if (monster[m]._mFlags & MFLAG_TARGETS_MONSTER) return monster[m]._menemy + MAX_PLRS; else return monster[m]._menemy; } void decode_enemy(int m, int enemy) { if (enemy < MAX_PLRS) { monster[m]._mFlags &= ~MFLAG_TARGETS_MONSTER; monster[m]._menemy = enemy; monster[m]._menemyx = plr[enemy]._pfutx; monster[m]._menemyy = plr[enemy]._pfuty; } else { monster[m]._mFlags |= MFLAG_TARGETS_MONSTER; enemy -= MAX_PLRS; monster[m]._menemy = enemy; monster[m]._menemyx = monster[enemy]._mfutx; monster[m]._menemyy = monster[enemy]._mfuty; } } ================================================ FILE: Source/monster.h ================================================ /** * @file monster.h * * Interface of monster functionality, AI, actions, spawning, loading, etc. */ #ifndef __MONSTER_H__ #define __MONSTER_H__ extern int monstkills[MAXMONSTERS]; extern int monstactive[MAXMONSTERS]; extern int nummonsters; extern MonsterStruct monster[MAXMONSTERS]; extern CMonster Monsters[MAX_LVLMTYPES]; extern int nummtypes; void InitLevelMonsters(); void GetLevelMTypes(); void InitMonsterGFX(int monst); void InitMonster(int i, int rd, int mtype, int x, int y); void ClrAllMonsters(); #ifdef HELLFIRE void monster_some_crypt(); #endif void PlaceGroup(int mtype, int num, int leaderf, int leader); void InitMonsters(); void SetMapMonsters(BYTE *pMap, int startx, int starty); void DeleteMonster(int i); int AddMonster(int x, int y, int dir, int mtype, BOOL InMap); #ifdef HELLFIRE void AddDoppelganger(int i); #endif BOOL M_Talker(int i); void M_StartStand(int i, int md); void M_ClearSquares(int i); void M_GetKnockback(int i); void M_StartHit(int i, int pnum, int dam); void M_StartKill(int i, int pnum); void M_SyncStartKill(int i, int x, int y, int pnum); BOOL M_DoStand(int i); BOOL M_DoWalk(int i); BOOL M_DoWalk2(int i); BOOL M_DoWalk3(int i); BOOL M_DoAttack(int i); void M_Teleport(int i); BOOL M_DoGotHit(int i); void M_UpdateLeader(int i); void DoEnding(); void PrepDoEnding(); void M_WalkDir(int i, int md); void MAI_Zombie(int i); void MAI_SkelSd(int i); void MAI_Snake(int i); void MAI_Bat(int i); void MAI_SkelBow(int i); void MAI_Fat(int i); void MAI_Sneak(int i); void MAI_Fireman(int i); void MAI_Fallen(int i); void MAI_Cleaver(int i); void MAI_Round(int i, BOOL special); void MAI_GoatMc(int i); void MAI_Ranged(int i, int missile_type, BOOL special); void MAI_GoatBow(int i); void MAI_Succ(int i); #ifdef HELLFIRE void MAI_Lich(int i); void MAI_ArchLich(int i); void MAI_Psychorb(int i); void MAI_Necromorb(int i); #endif void MAI_AcidUniq(int i); #ifdef HELLFIRE void MAI_Firebat(int i); void MAI_Torchant(int i); #endif void MAI_Scav(int i); void MAI_Garg(int i); void MAI_RoundRanged(int i, int missile_type, BOOL checkdoors, int dam, int lessmissiles); void MAI_Magma(int i); void MAI_Storm(int i); #ifdef HELLFIRE void MAI_BoneDemon(int i); #endif void MAI_Acid(int i); void MAI_Diablo(int i); void MAI_Mega(int i); void MAI_Golum(int i); void MAI_SkelKing(int i); void MAI_Rhino(int i); #ifdef HELLFIRE void MAI_HorkDemon(int i); #endif void MAI_Counselor(int i); void MAI_Garbud(int i); void MAI_Zhar(int i); void MAI_SnotSpil(int i); void MAI_Lazurus(int i); void MAI_Lazhelp(int i); void MAI_Lachdanan(int i); void MAI_Warlord(int i); void DeleteMonsterList(); void ProcessMonsters(); void FreeMonsters(); BOOL DirOK(int i, int mdir); BOOL PosOkMissile(int x, int y); BOOL CheckNoSolid(int x, int y); BOOL LineClearF(BOOL (*Clear)(int, int), int x1, int y1, int x2, int y2); BOOL LineClear(int x1, int y1, int x2, int y2); BOOL LineClearF1(BOOL (*Clear)(int, int, int), int monst, int x1, int y1, int x2, int y2); void SyncMonsterAnim(int i); void M_FallenFear(int x, int y); void PrintMonstHistory(int mt); void PrintUniqueHistory(); void MissToMonst(int i, int x, int y); BOOL PosOkMonst(int i, int x, int y); #ifdef HELLFIRE BOOLEAN monster_posok(int i, int x, int y); #endif BOOL PosOkMonst2(int i, int x, int y); BOOL PosOkMonst3(int i, int x, int y); BOOL IsSkel(int mt); BOOL IsGoat(int mt); int M_SpawnSkel(int x, int y, int dir); BOOL SpawnSkeleton(int ii, int x, int y); int PreSpawnSkeleton(); void TalktoMonster(int i); void SpawnGolum(int i, int x, int y, int mi); BOOL CanTalkToMonst(int m); BOOL CheckMonsterHit(int m, BOOL &ret); int encode_enemy(int m); void decode_enemy(int m, int enemy); /* data */ extern int opposite[8]; extern int offset_x[8]; extern int offset_y[8]; #endif /* __MONSTER_H__ */ ================================================ FILE: Source/movie.cpp ================================================ /** * @file movie.cpp * * Implementation of video playback. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" /** Should the movie continue playing. */ BYTE movie_playing; /** Should the movie play in a loop. */ BOOL loop_movie; /** * @brief Start playback of a given video. * @param pszMovie The file name of the video * @param user_can_close Set to false to make the video unskippable. */ void play_movie(const char *pszMovie, BOOL user_can_close) { WNDPROC saveProc; HANDLE video_stream; if (!gbActive) { return; } saveProc = SetWindowProc(MovieWndProc); InvalidateRect(ghMainWnd, NULL, 0); UpdateWindow(ghMainWnd); movie_playing = TRUE; sound_disable_music(TRUE); stream_stop(); effects_play_sound("Sfx\\Misc\\blank.wav"); SVidPlayBegin(pszMovie, 0, 0, 0, 0, loop_movie ? 0x100C0808 : 0x10280808, &video_stream); if (video_stream) { MSG Msg; while (video_stream) { if (!gbActive || user_can_close && !movie_playing) break; while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) { if (Msg.message != WM_QUIT) { TranslateMessage(&Msg); DispatchMessage(&Msg); } } if (!SVidPlayContinue()) break; } if (video_stream) SVidPlayEnd(video_stream); } SetWindowProc(saveProc); sound_disable_music(FALSE); } /** * @brief Input handler for use during video playback. * @see WNDPROC */ LRESULT __stdcall MovieWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch (Msg) { case WM_KEYDOWN: case WM_CHAR: case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: movie_playing = FALSE; break; case WM_SYSCOMMAND: if (wParam == SC_CLOSE) { movie_playing = FALSE; return 0; } break; } return MainWndProc(hWnd, Msg, wParam, lParam); } ================================================ FILE: Source/movie.h ================================================ /** * @file movie.h * * Interface of video playback. */ #ifndef __MOVIE_H__ #define __MOVIE_H__ extern BOOL loop_movie; void play_movie(const char *pszMovie, BOOL user_can_close); LRESULT __stdcall MovieWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); #endif /* __MOVIE_H__ */ ================================================ FILE: Source/mpqapi.cpp ================================================ /** * @file mpqapi.cpp * * Implementation of functions for creating and editing MPQ files. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" DWORD sgdwMpqOffset; BYTE mpq_buf[4096]; _HASHENTRY *sgpHashTbl; /** Has the savegame-file been modified in memory. */ BOOL save_archive_modified; _BLOCKENTRY *sgpBlockTbl; /** Is the savegame-file currently open. */ BOOLEAN save_archive_open; #define INDEX_ENTRIES 2048 #define BLOCK_TABLE_SIZE (INDEX_ENTRIES * sizeof(_BLOCKENTRY)) #define HASH_TABLE_SIZE (INDEX_ENTRIES * sizeof(_HASHENTRY)) //note: 32872 = 32768 + 104 (sizeof(_FILEHEADER)) /* data */ HANDLE sghArchive = INVALID_HANDLE_VALUE; static void mpqapi_xor_buf(char *pbData) { DWORD mask; char *pbCurrentData; int i; mask = 0xF0761AB; pbCurrentData = pbData; for (i = 0; i < 8; i++) { *pbCurrentData ^= mask; pbCurrentData++; mask = _rotl(mask, 1); } } static BOOL mpqapi_reg_load_modification_time(char *dst, int size) { char *pszDst; char *pbData; DWORD nbytes_read; pszDst = dst; memset(dst, 0, size); #ifdef SPAWN if (!SRegLoadData(APP_NAME, "Audio Playback ", 0, (BYTE *)pszDst, size, &nbytes_read)) { #else if (!SRegLoadData(APP_NAME, "Video Player ", 0, (BYTE *)pszDst, size, &nbytes_read)) { #endif return FALSE; } if (nbytes_read != size) return FALSE; for (; size >= 8u; size -= 8) { pbData = pszDst; pszDst += 8; mpqapi_xor_buf(pbData); } return TRUE; } static BOOLEAN mpqapi_reg_store_modification_time(char *pbData, DWORD dwLen) { char *pbCurrentData, *pbDataToXor; DWORD i; pbCurrentData = pbData; if (dwLen >= 8) { i = dwLen >> 3; do { pbDataToXor = pbCurrentData; pbCurrentData += 8; mpqapi_xor_buf(pbDataToXor); i--; } while (i); } #ifdef SPAWN return SRegSaveData(APP_NAME, "Audio Playback ", 0, (BYTE *)pbData, dwLen); #else return SRegSaveData(APP_NAME, "Video Player ", 0, (BYTE *)pbData, dwLen); #endif } BOOL mpqapi_set_hidden(const char *pszArchive, BOOL hidden) { DWORD dwFileAttributes; DWORD dwFileAttributesToSet; dwFileAttributes = GetFileAttributes(pszArchive); if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) return GetLastError() == ERROR_FILE_NOT_FOUND; dwFileAttributesToSet = hidden ? FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN : 0; if (dwFileAttributes == dwFileAttributesToSet) return TRUE; else return SetFileAttributes(pszArchive, dwFileAttributesToSet); } void mpqapi_store_default_time(DWORD dwChar) { /* DWORD idx; char dst[160]; if(gbMaxPlayers == 1) { return; } /// ASSERT: assert(dwChar < MAX_CHARACTERS); idx = 16 * dwChar; mpqapi_reg_load_modification_time(dst, sizeof(dst)); *(DWORD *)&dst[idx + 4] = 0x78341348; // dwHighDateTime mpqapi_reg_store_modification_time(dst, sizeof(dst)); */ } static void mpqapi_store_modified_time(const char *pszArchive, DWORD dwChar) { HANDLE handle; struct _WIN32_FIND_DATAA FindFileData; char dst[160]; if (gbMaxPlayers != 1) { mpqapi_reg_load_modification_time(dst, 160); handle = FindFirstFile(pszArchive, &FindFileData); if (handle != INVALID_HANDLE_VALUE) { FindClose(handle); *((FILETIME *)(dst) + dwChar * 2 + 1) = FindFileData.ftLastWriteTime; mpqapi_reg_store_modification_time(dst, 160); } } } void mpqapi_store_creation_time(const char *pszArchive, DWORD dwChar) { HANDLE handle; struct _WIN32_FIND_DATAA FindFileData; char dst[160]; if (gbMaxPlayers != 1) { mpqapi_reg_load_modification_time(dst, 160); handle = FindFirstFile(pszArchive, &FindFileData); if (handle != INVALID_HANDLE_VALUE) { FindClose(handle); *((FILETIME *)(dst) + dwChar * 2) = FindFileData.ftCreationTime; mpqapi_reg_store_modification_time(dst, 160); } } } static _BLOCKENTRY *mpqapi_new_block(int *block_index) { _BLOCKENTRY *blockEntry = sgpBlockTbl; for (DWORD i = 0; i < INDEX_ENTRIES; i++, blockEntry++) { if (blockEntry->offset != 0) continue; if (blockEntry->sizealloc != 0) continue; if (blockEntry->flags != 0) continue; if (blockEntry->sizefile != 0) continue; if (block_index) *block_index = i; return blockEntry; } app_fatal("Out of free block entries"); return NULL; } static void mpqapi_alloc_block(int block_offset, int block_size) { _BLOCKENTRY *block; int i; block = sgpBlockTbl; i = INDEX_ENTRIES; while (i-- != 0) { if (block->offset && !block->flags && !block->sizefile) { if (block->offset + block->sizealloc == block_offset) { block_offset = block->offset; block_size += block->sizealloc; memset(block, 0, sizeof(_BLOCKENTRY)); mpqapi_alloc_block(block_offset, block_size); return; } if (block_offset + block_size == block->offset) { block_size += block->sizealloc; memset(block, 0, sizeof(_BLOCKENTRY)); mpqapi_alloc_block(block_offset, block_size); return; } } block++; } if (block_offset + block_size > sgdwMpqOffset) { app_fatal("MPQ free list error"); } if (block_offset + block_size == sgdwMpqOffset) { sgdwMpqOffset = block_offset; } else { block = mpqapi_new_block(NULL); block->offset = block_offset; block->sizealloc = block_size; block->sizefile = 0; block->flags = 0; } } static int mpqapi_find_free_block(int size, int *block_size) { int result; _BLOCKENTRY *pBlockTbl = sgpBlockTbl; for (int i = INDEX_ENTRIES; i--; pBlockTbl++) { if (pBlockTbl->offset == 0) continue; if (pBlockTbl->flags != 0) continue; if (pBlockTbl->sizefile != 0) continue; if ((DWORD)pBlockTbl->sizealloc < size) continue; result = pBlockTbl->offset; *block_size = size; pBlockTbl->offset += size; pBlockTbl->sizealloc -= size; if (pBlockTbl->sizealloc == 0) memset(pBlockTbl, 0, sizeof(*pBlockTbl)); return result; } *block_size = size; result = sgdwMpqOffset; sgdwMpqOffset += size; return result; } static int mpqapi_get_hash_index(int index, int hash_a, int hash_b, int locale) { DWORD idx, i; i = INDEX_ENTRIES; for (idx = index & 0x7FF; sgpHashTbl[idx].block != -1; idx = (idx + 1) & 0x7FF) { if (i-- == 0) break; if (sgpHashTbl[idx].hashcheck[0] != hash_a) continue; if (sgpHashTbl[idx].hashcheck[1] != hash_b) continue; if (sgpHashTbl[idx].lcid != locale) continue; if (sgpHashTbl[idx].block == -2) continue; return idx; } return -1; } static BOOL WriteMPQHeader() { _FILEHEADER fhdr; DWORD NumberOfBytesWritten; memset(&fhdr, 0, sizeof(fhdr)); 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 = INDEX_ENTRIES; fhdr.blockcount = INDEX_ENTRIES; if (SetFilePointer(sghArchive, 0, NULL, FILE_BEGIN) == -1) return FALSE; if (!WriteFile(sghArchive, &fhdr, sizeof(fhdr), &NumberOfBytesWritten, 0)) return FALSE; return NumberOfBytesWritten == 104; } static BOOL mpqapi_write_block_table() { BOOL success; DWORD NumberOfBytesWritten; if (SetFilePointer(sghArchive, 104, NULL, FILE_BEGIN) == -1) return FALSE; Encrypt((DWORD *)sgpBlockTbl, BLOCK_TABLE_SIZE, Hash("(block table)", 3)); success = WriteFile(sghArchive, sgpBlockTbl, BLOCK_TABLE_SIZE, &NumberOfBytesWritten, 0); Decrypt((DWORD *)sgpBlockTbl, BLOCK_TABLE_SIZE, Hash("(block table)", 3)); return success && NumberOfBytesWritten == BLOCK_TABLE_SIZE; } static BOOL mpqapi_write_hash_table() { BOOL success; DWORD NumberOfBytesWritten; if (SetFilePointer(sghArchive, 32872, NULL, FILE_BEGIN) == -1) return FALSE; Encrypt((DWORD *)sgpHashTbl, HASH_TABLE_SIZE, Hash("(hash table)", 3)); success = WriteFile(sghArchive, sgpHashTbl, HASH_TABLE_SIZE, &NumberOfBytesWritten, 0); Decrypt((DWORD *)sgpHashTbl, HASH_TABLE_SIZE, Hash("(hash table)", 3)); return success && NumberOfBytesWritten == HASH_TABLE_SIZE; } static BOOL mpqapi_can_seek() { if (SetFilePointer(sghArchive, sgdwMpqOffset, NULL, FILE_BEGIN) == -1) return FALSE; return SetEndOfFile(sghArchive); } static BOOL ParseMPQHeader(_FILEHEADER *pHdr, DWORD *pdwNextFileStart) { DWORD size; DWORD NumberOfBytesRead; size = GetFileSize(sghArchive, 0); *pdwNextFileStart = size; if (size == -1 || size < sizeof(*pHdr) || !ReadFile(sghArchive, pHdr, sizeof(*pHdr), &NumberOfBytesRead, NULL) || NumberOfBytesRead != 104 || pHdr->signature != '\x1AQPM' || pHdr->headersize != 32 || pHdr->version > 0 || pHdr->sectorsizeid != 3 || pHdr->filesize != size || pHdr->hashoffset != 32872 || pHdr->blockoffset != 104 || pHdr->hashcount != INDEX_ENTRIES || pHdr->blockcount != INDEX_ENTRIES) { if (SetFilePointer(sghArchive, 0, NULL, FILE_BEGIN) == -1) return FALSE; if (!SetEndOfFile(sghArchive)) return FALSE; memset(pHdr, 0, sizeof(*pHdr)); pHdr->signature = '\x1AQPM'; pHdr->headersize = 32; pHdr->sectorsizeid = 3; pHdr->version = 0; *pdwNextFileStart = 0x10068; save_archive_modified = TRUE; save_archive_open = TRUE; } return TRUE; } static int FetchHandle(const char *pszName) { return mpqapi_get_hash_index(Hash(pszName, 0), Hash(pszName, 1), Hash(pszName, 2), 0); } void mpqapi_remove_hash_entry(const char *pszName) { _HASHENTRY *pHashTbl; _BLOCKENTRY *blockEntry; int hIdx, block_offset, block_size; hIdx = FetchHandle(pszName); if (hIdx != -1) { pHashTbl = &sgpHashTbl[hIdx]; blockEntry = &sgpBlockTbl[pHashTbl->block]; pHashTbl->block = -2; block_offset = blockEntry->offset; block_size = blockEntry->sizealloc; memset(blockEntry, 0, sizeof(*blockEntry)); mpqapi_alloc_block(block_offset, block_size); save_archive_modified = TRUE; } } void mpqapi_remove_hash_entries(BOOL(__stdcall *fnGetName)(DWORD, char *)) { DWORD dwIndex, i; char pszFileName[MAX_PATH]; dwIndex = 1; for (i = fnGetName(0, pszFileName); i; i = fnGetName(dwIndex++, pszFileName)) { mpqapi_remove_hash_entry(pszFileName); } } static _BLOCKENTRY *mpqapi_add_file(const char *pszName, _BLOCKENTRY *pBlk, int block_index) { DWORD h1, h2, h3; int i, hIdx; h1 = Hash(pszName, 0); h2 = Hash(pszName, 1); h3 = Hash(pszName, 2); if (mpqapi_get_hash_index(h1, h2, h3, 0) != -1) app_fatal("Hash collision between \"%s\" and existing file\n", pszName); hIdx = h1 & 0x7FF; i = INDEX_ENTRIES; while (i--) { if (sgpHashTbl[hIdx].block == -1 || sgpHashTbl[hIdx].block == -2) break; hIdx = (hIdx + 1) & 0x7FF; } if (i < 0) app_fatal("Out of hash space"); if (!pBlk) pBlk = mpqapi_new_block(&block_index); sgpHashTbl[hIdx].hashcheck[0] = h2; sgpHashTbl[hIdx].hashcheck[1] = h3; sgpHashTbl[hIdx].lcid = 0; sgpHashTbl[hIdx].block = block_index; return pBlk; } static BOOL mpqapi_write_file_contents(const char *pszName, const BYTE *pbData, DWORD dwLen, _BLOCKENTRY *pBlk) { DWORD *sectoroffsettable; DWORD destsize, num_bytes, block_size, nNumberOfBytesToWrite; const char *tmp; int i, j; while ((tmp = strchr(pszName, ':'))) { pszName = tmp + 1; } while ((tmp = strchr(pszName, '\\'))) { pszName = tmp + 1; } Hash(pszName, 3); num_bytes = (dwLen + 4095) >> 12; nNumberOfBytesToWrite = 4 * num_bytes + 4; pBlk->offset = mpqapi_find_free_block(dwLen + nNumberOfBytesToWrite, &pBlk->sizealloc); pBlk->sizefile = dwLen; pBlk->flags = 0x80000100; if (SetFilePointer(sghArchive, pBlk->offset, NULL, FILE_BEGIN) == (DWORD)-1) return FALSE; j = 0; destsize = 0; sectoroffsettable = NULL; while (dwLen != 0) { DWORD len; for (i = 0; i < 4096; i++) mpq_buf[i] -= 86; len = dwLen; if (dwLen >= 4096) len = 4096; memcpy(mpq_buf, pbData, len); pbData += len; len = PkwareCompress(mpq_buf, len); if (j == 0) { nNumberOfBytesToWrite = 4 * num_bytes + 4; sectoroffsettable = (DWORD *)DiabloAllocPtr(nNumberOfBytesToWrite); memset(sectoroffsettable, 0, nNumberOfBytesToWrite); if (!WriteFile(sghArchive, sectoroffsettable, nNumberOfBytesToWrite, &nNumberOfBytesToWrite, 0)) { goto on_error; } destsize += nNumberOfBytesToWrite; } sectoroffsettable[j] = destsize; if (!WriteFile(sghArchive, mpq_buf, len, &len, NULL)) { goto on_error; } j++; if (dwLen > 4096) dwLen -= 4096; else dwLen = 0; destsize += len; } sectoroffsettable[j] = destsize; if (SetFilePointer(sghArchive, -destsize, NULL, FILE_CURRENT) == (DWORD)-1) { goto on_error; } if (!WriteFile(sghArchive, sectoroffsettable, nNumberOfBytesToWrite, &nNumberOfBytesToWrite, 0)) { goto on_error; } if (SetFilePointer(sghArchive, destsize - nNumberOfBytesToWrite, NULL, FILE_CURRENT) == (DWORD)-1) { goto on_error; } mem_free_dbg(sectoroffsettable); if (destsize < pBlk->sizealloc) { block_size = pBlk->sizealloc - destsize; if (block_size >= 1024) { pBlk->sizealloc = destsize; mpqapi_alloc_block(pBlk->sizealloc + pBlk->offset, block_size); } } return TRUE; on_error: if (sectoroffsettable) mem_free_dbg(sectoroffsettable); return FALSE; } BOOL mpqapi_write_file(const char *pszName, const BYTE *pbData, DWORD dwLen) { _BLOCKENTRY *blockEntry; save_archive_modified = TRUE; mpqapi_remove_hash_entry(pszName); blockEntry = mpqapi_add_file(pszName, 0, 0); if (!mpqapi_write_file_contents(pszName, pbData, dwLen, blockEntry)) { mpqapi_remove_hash_entry(pszName); return FALSE; } return TRUE; } void mpqapi_rename(char *pszOld, char *pszNew) { int index, block; _HASHENTRY *hashEntry; _BLOCKENTRY *blockEntry; index = FetchHandle(pszOld); if (index != -1) { hashEntry = &sgpHashTbl[index]; block = hashEntry->block; blockEntry = &sgpBlockTbl[block]; hashEntry->block = -2; mpqapi_add_file(pszNew, blockEntry, block); save_archive_modified = TRUE; } } BOOL mpqapi_has_file(const char *pszName) { return FetchHandle(pszName) != -1; } static void CloseMPQ(const char *pszArchive, BOOL bFree, DWORD dwChar) { if (bFree) { MemFreeDbg(sgpBlockTbl); MemFreeDbg(sgpHashTbl); } if (sghArchive != INVALID_HANDLE_VALUE) { CloseHandle(sghArchive); sghArchive = INVALID_HANDLE_VALUE; } if (save_archive_modified) { save_archive_modified = FALSE; mpqapi_store_modified_time(pszArchive, dwChar); } if (save_archive_open) { save_archive_open = FALSE; mpqapi_store_creation_time(pszArchive, dwChar); } } BOOL OpenMPQ(const char *pszArchive, BOOL hidden, DWORD dwChar) { DWORD dwFlagsAndAttributes; DWORD key; DWORD dwTemp; _FILEHEADER fhdr; InitHash(); if (!mpqapi_set_hidden(pszArchive, hidden)) { return FALSE; } dwFlagsAndAttributes = gbMaxPlayers > 1 ? FILE_FLAG_WRITE_THROUGH : 0; save_archive_open = FALSE; sghArchive = CreateFile(pszArchive, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); if (sghArchive == INVALID_HANDLE_VALUE) { sghArchive = CreateFile(pszArchive, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, dwFlagsAndAttributes | (hidden ? FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN : 0), NULL); if (sghArchive == INVALID_HANDLE_VALUE) return FALSE; save_archive_open = TRUE; save_archive_modified = TRUE; } if (sgpBlockTbl == NULL || sgpHashTbl == NULL) { memset(&fhdr, 0, sizeof(fhdr)); if (ParseMPQHeader(&fhdr, &sgdwMpqOffset) == FALSE) { goto on_error; } sgpBlockTbl = (_BLOCKENTRY *)DiabloAllocPtr(BLOCK_TABLE_SIZE); memset(sgpBlockTbl, 0, BLOCK_TABLE_SIZE); if (fhdr.blockcount) { if (SetFilePointer(sghArchive, 104, NULL, FILE_BEGIN) == -1) goto on_error; if (!ReadFile(sghArchive, sgpBlockTbl, BLOCK_TABLE_SIZE, &dwTemp, NULL)) goto on_error; key = Hash("(block table)", 3); Decrypt((DWORD *)sgpBlockTbl, BLOCK_TABLE_SIZE, key); } sgpHashTbl = (_HASHENTRY *)DiabloAllocPtr(HASH_TABLE_SIZE); memset(sgpHashTbl, 255, HASH_TABLE_SIZE); if (fhdr.hashcount) { if (SetFilePointer(sghArchive, 32872, NULL, FILE_BEGIN) == -1) goto on_error; if (!ReadFile(sghArchive, sgpHashTbl, HASH_TABLE_SIZE, &dwTemp, NULL)) goto on_error; key = Hash("(hash table)", 3); Decrypt((DWORD *)sgpHashTbl, HASH_TABLE_SIZE, key); } return TRUE; } return TRUE; on_error: CloseMPQ(pszArchive, TRUE, dwChar); return FALSE; } BOOL mpqapi_flush_and_close(const char *pszArchive, BOOL bFree, DWORD dwChar) { BOOL ret = FALSE; if (sghArchive == INVALID_HANDLE_VALUE) ret = TRUE; else { ret = FALSE; if (!save_archive_modified) ret = TRUE; else if (mpqapi_can_seek() && WriteMPQHeader() && mpqapi_write_block_table()) { if (mpqapi_write_hash_table()) ret = TRUE; else ret = FALSE; } } CloseMPQ(pszArchive, bFree, dwChar); return ret; } ================================================ FILE: Source/mpqapi.h ================================================ /** * @file mpqapi.h * * Interface of functions for creating and editing MPQ files. */ #ifndef __MPQAPI_H__ #define __MPQAPI_H__ void mpqapi_store_default_time(DWORD dwChar); void mpqapi_remove_hash_entry(const char *pszName); void mpqapi_remove_hash_entries(BOOL(__stdcall *fnGetName)(DWORD, char *)); BOOL mpqapi_write_file(const char *pszName, const BYTE *pbData, DWORD dwLen); void mpqapi_rename(char *pszOld, char *pszNew); BOOL mpqapi_has_file(const char *pszName); BOOL OpenMPQ(const char *pszArchive, BOOL hidden, DWORD dwChar); BOOL mpqapi_flush_and_close(const char *pszArchive, BOOL bFree, DWORD dwChar); #endif /* __MPQAPI_H__ */ ================================================ FILE: Source/msg.cpp ================================================ /** * @file msg.cpp * * Implementation of function for sending and reciving network messages. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" #include "../DiabloUI/diabloui.h" static DWORD sgdwOwnerWait; static DWORD sgdwRecvOffset; static int sgnCurrMegaPlayer; static DLevel sgLevels[NUMLEVELS]; static BYTE sbLastCmd; static TMegaPkt *sgpCurrPkt; static BYTE sgRecvBuf[sizeof(DLevel) + 1]; static BYTE sgbRecvCmd; static LocalLevel sgLocals[NUMLEVELS]; static DJunk sgJunk; static TMegaPkt *sgpMegaPkt; static BOOLEAN sgbDeltaChanged; static BYTE sgbDeltaChunks; BOOL deltaload; BYTE gbBufferMsgs; int dwRecCount; static void msg_get_next_packet() { TMegaPkt *result; sgpCurrPkt = (TMegaPkt *)DiabloAllocPtr(sizeof(TMegaPkt)); sgpCurrPkt->pNext = NULL; sgpCurrPkt->dwSpaceLeft = sizeof(result->data); result = (TMegaPkt *)&sgpMegaPkt; while (result->pNext) result = result->pNext; result->pNext = sgpCurrPkt; } static void msg_free_packets() { while (sgpMegaPkt) { sgpCurrPkt = sgpMegaPkt->pNext; MemFreeDbg(sgpMegaPkt); sgpMegaPkt = sgpCurrPkt; } } static void msg_pre_packet() { int i; i = -1; for (TMegaPkt *pkt = sgpMegaPkt; pkt != NULL; pkt = pkt->pNext) { BYTE *data = pkt->data; int spaceLeft = sizeof(pkt->data); while (spaceLeft != pkt->dwSpaceLeft) { if (*data == FAKE_CMD_SETID) { TFakeCmdPlr *cmd = (TFakeCmdPlr *)data; data += sizeof(*cmd); spaceLeft -= sizeof(*cmd); i = cmd->bPlr; } else if (*data == FAKE_CMD_DROPID) { TFakeDropPlr *cmd = (TFakeDropPlr *)data; data += sizeof(*cmd); spaceLeft -= sizeof(*cmd); multi_player_left(cmd->bPlr, cmd->dwReason); } else { int pktSize = ParseCmd(i, (TCmd *)data); data += pktSize; spaceLeft -= pktSize; } } } } static void msg_send_packet(int pnum, const void *packet, DWORD dwSize) { TFakeCmdPlr cmd; if (pnum != sgnCurrMegaPlayer) { sgnCurrMegaPlayer = pnum; cmd.bCmd = FAKE_CMD_SETID; cmd.bPlr = pnum; msg_send_packet(pnum, &cmd, sizeof(cmd)); } if (sgpCurrPkt->dwSpaceLeft < dwSize) msg_get_next_packet(); memcpy(sgpCurrPkt->data + sizeof(sgpCurrPkt->data) - sgpCurrPkt->dwSpaceLeft, packet, dwSize); sgpCurrPkt->dwSpaceLeft -= dwSize; } void msg_send_drop_pkt(int pnum, int reason) { TFakeDropPlr cmd; cmd.dwReason = reason; cmd.bCmd = FAKE_CMD_DROPID; cmd.bPlr = pnum; msg_send_packet(pnum, &cmd, sizeof(cmd)); } static int msg_wait_for_turns() { BOOL received; DWORD turns; if (sgbDeltaChunks == 0) { nthread_send_and_recv_turn(0, 0); if (!SNetGetOwnerTurnsWaiting(&turns) && DERROR() == STORM_ERROR_NOT_IN_GAME) return 100; if (GetTickCount() - sgdwOwnerWait <= 2000 && turns < gdwTurnsInTransit) return 0; sgbDeltaChunks++; } multi_process_network_packets(); nthread_send_and_recv_turn(0, 0); if (nthread_has_500ms_passed(FALSE)) nthread_recv_turns(&received); if (gbGameDestroyed) return 100; if (gbDeltaSender >= MAX_PLRS) { sgbDeltaChunks = 0; sgbRecvCmd = CMD_DLEVEL_END; gbDeltaSender = myplr; nthread_set_turn_upper_bit(); } if (sgbDeltaChunks == MAX_CHUNKS - 1) { sgbDeltaChunks = MAX_CHUNKS; return 99; } return 100 * sgbDeltaChunks / MAX_CHUNKS; } BOOL msg_wait_resync() { BOOL success; msg_get_next_packet(); sgbDeltaChunks = 0; sgnCurrMegaPlayer = -1; sgbRecvCmd = CMD_DLEVEL_END; gbBufferMsgs = 1; sgdwOwnerWait = GetTickCount(); success = UiProgressDialog(ghMainWnd, "Waiting for game data...", 1, msg_wait_for_turns, 20); gbBufferMsgs = 0; if (!success) { msg_free_packets(); return FALSE; } if (gbGameDestroyed) { DrawDlg("The game ended"); msg_free_packets(); return FALSE; } if (sgbDeltaChunks != MAX_CHUNKS) { DrawDlg("Unable to get level data"); msg_free_packets(); return FALSE; } return TRUE; } void run_delta_info() { if (gbMaxPlayers == 1) return; gbBufferMsgs = 2; msg_pre_packet(); gbBufferMsgs = 0; msg_free_packets(); } static BYTE *DeltaExportItem(BYTE *dst, TCmdPItem *src) { for (int i = 0; i < MAXITEMS; i++, src++) { if (src->bCmd == 0xFF) *dst++ = 0xFF; else { #ifdef HELLFIRE *reinterpret_cast(dst) = *src; #else memcpy(dst, src, sizeof(TCmdPItem)); #endif dst += sizeof(TCmdPItem); } } return dst; } static BYTE *DeltaImportItem(BYTE *src, TCmdPItem *dst) { for (int i = 0; i < MAXITEMS; i++, dst++) { if (*src == 0xFF) { memset(dst, 0xFF, sizeof(TCmdPItem)); src++; } else { #ifdef HELLFIRE *dst = *reinterpret_cast(src); #else memcpy(dst, src, sizeof(TCmdPItem)); #endif src += sizeof(TCmdPItem); } } return src; } static BYTE *DeltaExportObject(BYTE *dst, DObjectStr *src) { memcpy(dst, src, sizeof(DObjectStr) * MAXOBJECTS); return dst + sizeof(DObjectStr) * MAXOBJECTS; } static BYTE *DeltaImportObject(BYTE *src, DObjectStr *dst) { memcpy(dst, src, sizeof(DObjectStr) * MAXOBJECTS); return src + sizeof(DObjectStr) * MAXOBJECTS; } static BYTE *DeltaExportMonster(BYTE *dst, DMonsterStr *src) { for (int i = 0; i < MAXMONSTERS; i++, src++) { if (src->_mx == 0xFF) *dst++ = 0xFF; else { #ifdef HELLFIRE *reinterpret_cast(dst) = *src; #else memcpy(dst, src, sizeof(DMonsterStr)); #endif dst += sizeof(DMonsterStr); } } return dst; } static BYTE *DeltaImportMonster(BYTE *src, DMonsterStr *dst) { for (int i = 0; i < MAXMONSTERS; i++, dst++) { if (*src == 0xFF) { memset(dst, 0xFF, sizeof(DMonsterStr)); src++; } else { #ifdef HELLFIRE *dst = *reinterpret_cast(src); #else memcpy(dst, src, sizeof(DMonsterStr)); #endif src += sizeof(DMonsterStr); } } return src; } static BYTE *DeltaExportJunk(BYTE *dst) { int i, q; for (i = 0; i < MAXPORTAL; i++) { if (sgJunk.portal[i].x == 0xFF) { *dst++ = 0xFF; } else { #ifdef HELLFIRE *reinterpret_cast(dst) = sgJunk.portal[i]; #else memcpy(dst, &sgJunk.portal[i], sizeof(DPortal)); #endif dst += sizeof(DPortal); } } for (i = 0, q = 0; i < MAXQUESTS; i++) { if (questlist[i]._qflags & QUEST_ANY) { sgJunk.quests[q].qlog = quests[i]._qlog; sgJunk.quests[q].qstate = quests[i]._qactive; sgJunk.quests[q].qvar1 = quests[i]._qvar1; #ifdef HELLFIRE *reinterpret_cast(dst) = sgJunk.quests[q]; #else memcpy(dst, &sgJunk.quests[q], sizeof(MultiQuests)); #endif dst += sizeof(MultiQuests); q++; } } return dst; } static void DeltaImportJunk(BYTE *src) { int i, q; for (i = 0; i < MAXPORTAL; i++) { if (*src == 0xFF) { memset(&sgJunk.portal[i], 0xFF, sizeof(DPortal)); src++; SetPortalStats(i, FALSE, 0, 0, 0, DTYPE_TOWN); } else { #ifdef HELLFIRE sgJunk.portal[i] = *reinterpret_cast(src); #else memcpy(&sgJunk.portal[i], src, sizeof(DPortal)); #endif src += sizeof(DPortal); SetPortalStats( i, TRUE, sgJunk.portal[i].x, sgJunk.portal[i].y, sgJunk.portal[i].level, sgJunk.portal[i].ltype); } } for (i = 0, q = 0; i < MAXQUESTS; i++) { if (questlist[i]._qflags & QUEST_ANY) { #ifdef HELLFIRE sgJunk.quests[q] = *reinterpret_cast(src); #else memcpy(&sgJunk.quests[q], src, sizeof(MultiQuests)); #endif src += sizeof(MultiQuests); quests[i]._qlog = sgJunk.quests[q].qlog; quests[i]._qactive = sgJunk.quests[q].qstate; quests[i]._qvar1 = sgJunk.quests[q].qvar1; q++; } } } static int msg_comp_level(BYTE *buffer, BYTE *end) { int size = end - buffer - 1; int pkSize = PkwareCompress(buffer + 1, size); *buffer = size != pkSize; return pkSize + 1; } // DeltaSendAllLevels void DeltaExportData(int pnum) { if (sgbDeltaChanged) { int size; BYTE *dstEnd, *dst = (BYTE *)DiabloAllocPtr(sizeof(DLevel) + 1); for (int i = 0; i < NUMLEVELS; i++) { dstEnd = dst + 1; dstEnd = DeltaExportItem(dstEnd, sgLevels[i].item); dstEnd = DeltaExportObject(dstEnd, sgLevels[i].object); dstEnd = DeltaExportMonster(dstEnd, sgLevels[i].monster); size = msg_comp_level(dst, dstEnd); dthread_send_delta(pnum, i + CMD_DLEVEL_0, dst, size); } dstEnd = dst + 1; dstEnd = DeltaExportJunk(dstEnd); size = msg_comp_level(dst, dstEnd); dthread_send_delta(pnum, CMD_DLEVEL_JUNK, dst, size); mem_free_dbg(dst); } char src = 0; dthread_send_delta(pnum, CMD_DLEVEL_END, &src, 1); } static void DeltaImportData(BYTE cmd, DWORD recv_offset) { if (sgRecvBuf[0] != 0) PkwareDecompress(&sgRecvBuf[1], recv_offset, sizeof(sgRecvBuf) - 1); BYTE *src = &sgRecvBuf[1]; if (cmd == CMD_DLEVEL_JUNK) { DeltaImportJunk(src); #ifdef HELLFIRE } else if (cmd >= CMD_DLEVEL_0 && cmd <= CMD_DLEVEL_24) { #else } else if (cmd >= CMD_DLEVEL_0 && cmd <= CMD_DLEVEL_16) { #endif BYTE i = cmd - CMD_DLEVEL_0; src = DeltaImportItem(src, sgLevels[i].item); src = DeltaImportObject(src, sgLevels[i].object); DeltaImportMonster(src, sgLevels[i].monster); } else { app_fatal("msg:1"); } sgbDeltaChunks++; sgbDeltaChanged = TRUE; } static DWORD On_DLEVEL(int pnum, TCmd *pCmd) { TCmdPlrInfoHdr *p = (TCmdPlrInfoHdr *)pCmd; if (gbDeltaSender != pnum) { if (p->bCmd == CMD_DLEVEL_END) { gbDeltaSender = pnum; sgbRecvCmd = CMD_DLEVEL_END; } else if (p->bCmd == CMD_DLEVEL_0 && p->wOffset == 0) { gbDeltaSender = pnum; sgbRecvCmd = CMD_DLEVEL_END; } else { return p->wBytes + sizeof(*p); } } if (sgbRecvCmd == CMD_DLEVEL_END) { if (p->bCmd == CMD_DLEVEL_END) { sgbDeltaChunks = MAX_CHUNKS - 1; return p->wBytes + sizeof(*p); } else if (p->bCmd == CMD_DLEVEL_0 && p->wOffset == 0) { sgdwRecvOffset = 0; sgbRecvCmd = p->bCmd; } else { return p->wBytes + sizeof(*p); } } else if (sgbRecvCmd != p->bCmd) { DeltaImportData(sgbRecvCmd, sgdwRecvOffset); if (p->bCmd == CMD_DLEVEL_END) { sgbDeltaChunks = MAX_CHUNKS - 1; sgbRecvCmd = CMD_DLEVEL_END; return p->wBytes + sizeof(*p); } else { sgdwRecvOffset = 0; sgbRecvCmd = p->bCmd; } } /// ASSERT: assert(p->wOffset == sgdwRecvOffset); memcpy(&sgRecvBuf[p->wOffset], &p[1], p->wBytes); sgdwRecvOffset += p->wBytes; return p->wBytes + sizeof(*p); } void delta_init() { sgbDeltaChanged = FALSE; memset(&sgJunk, 0xFF, sizeof(sgJunk)); memset(sgLevels, 0xFF, sizeof(sgLevels)); memset(sgLocals, 0, sizeof(sgLocals)); deltaload = FALSE; } void delta_kill_monster(int mi, BYTE x, BYTE y, BYTE bLevel) { if (gbMaxPlayers == 1) return; sgbDeltaChanged = TRUE; DMonsterStr *pD = &sgLevels[bLevel].monster[mi]; pD->_mx = x; pD->_my = y; // BUGFIX: should only sync monster direction if bLevel is same as currlevel. pD->_mdir = monster[mi]._mdir; pD->_mhitpoints = 0; } void delta_monster_hp(int mi, int hp, BYTE bLevel) { if (gbMaxPlayers == 1) return; sgbDeltaChanged = TRUE; DMonsterStr *pD = &sgLevels[bLevel].monster[mi]; if (pD->_mhitpoints > hp) pD->_mhitpoints = hp; } void delta_sync_monster(const TSyncMonster *pSync, BYTE bLevel) { if (gbMaxPlayers == 1) return; /// ASSERT: assert(pSync != NULL); /// ASSERT: assert(bLevel < NUMLEVELS); sgbDeltaChanged = TRUE; DMonsterStr *pD = &sgLevels[bLevel].monster[pSync->_mndx]; if (pD->_mhitpoints == 0) return; pD->_mx = pSync->_mx; pD->_my = pSync->_my; pD->_mactive = UCHAR_MAX; pD->_menemy = pSync->_menemy; } void delta_sync_golem(TCmdGolem *pG, int pnum, BYTE bLevel) { if (gbMaxPlayers == 1) return; sgbDeltaChanged = TRUE; DMonsterStr *pD = &sgLevels[bLevel].monster[pnum]; pD->_mx = pG->_mx; pD->_my = pG->_my; pD->_mactive = UCHAR_MAX; pD->_menemy = pG->_menemy; pD->_mdir = pG->_mdir; pD->_mhitpoints = pG->_mhitpoints; } void delta_leave_sync(BYTE bLevel) { if (gbMaxPlayers == 1) return; if (currlevel == 0) glSeedTbl[0] = GetRndSeed(); if (currlevel <= 0) return; for (int i = 0; i < nummonsters; i++) { int ma = monstactive[i]; if (monster[ma]._mhitpoints == 0) continue; sgbDeltaChanged = TRUE; DMonsterStr *pD = &sgLevels[bLevel].monster[ma]; pD->_mx = monster[ma]._mx; pD->_my = monster[ma]._my; pD->_mdir = monster[ma]._mdir; pD->_menemy = encode_enemy(ma); pD->_mhitpoints = monster[ma]._mhitpoints; pD->_mactive = monster[ma]._msquelch; } memcpy(&sgLocals[bLevel].automapsv, automapview, sizeof(automapview)); } static void delta_sync_object(int oi, BYTE bCmd, BYTE bLevel) { if (gbMaxPlayers == 1) return; sgbDeltaChanged = TRUE; sgLevels[bLevel].object[oi].bCmd = bCmd; } static BOOL delta_get_item(TCmdGItem *pI, BYTE bLevel) { int i; if (gbMaxPlayers == 1) return TRUE; TCmdPItem *pD = sgLevels[bLevel].item; for (i = 0; i < MAXITEMS; i++, pD++) { if (pD->bCmd == 0xFF || pD->wIndx != pI->wIndx || pD->wCI != pI->wCI || pD->dwSeed != pI->dwSeed) continue; if (pD->bCmd == CMD_WALKXY) { return TRUE; } if (pD->bCmd == CMD_STAND) { sgbDeltaChanged = TRUE; pD->bCmd = CMD_WALKXY; return TRUE; } if (pD->bCmd == CMD_ACK_PLRINFO) { sgbDeltaChanged = TRUE; pD->bCmd = 0xFF; return TRUE; } app_fatal("delta:1"); break; } if ((pI->wCI & CF_PREGEN) == 0) return FALSE; pD = sgLevels[bLevel].item; for (i = 0; i < MAXITEMS; i++, pD++) { if (pD->bCmd == 0xFF) { sgbDeltaChanged = TRUE; pD->bCmd = CMD_WALKXY; pD->x = pI->x; pD->y = pI->y; pD->wIndx = pI->wIndx; pD->wCI = pI->wCI; pD->dwSeed = pI->dwSeed; pD->bId = pI->bId; pD->bDur = pI->bDur; pD->bMDur = pI->bMDur; pD->bCh = pI->bCh; pD->bMCh = pI->bMCh; pD->wValue = pI->wValue; pD->dwBuff = pI->dwBuff; #ifdef HELLFIRE pD->wToHit = pI->wToHit; pD->wMaxDam = pI->wMaxDam; pD->bMinStr = pI->bMinStr; pD->bMinMag = pI->bMinMag; pD->bMinDex = pI->bMinDex; pD->bAC = pI->bAC; #endif break; } } return TRUE; } static void delta_put_item(TCmdPItem *pI, int x, int y, BYTE bLevel) { int i; if (gbMaxPlayers == 1) return; TCmdPItem *pD = sgLevels[bLevel].item; for (i = 0; i < MAXITEMS; i++, pD++) { if (pD->bCmd != CMD_WALKXY && pD->bCmd != 0xFF && pD->wIndx == pI->wIndx && pD->wCI == pI->wCI && pD->dwSeed == pI->dwSeed) { if (pD->bCmd == CMD_ACK_PLRINFO) return; app_fatal("Trying to drop a floor item?"); } } pD = sgLevels[bLevel].item; for (i = 0; i < MAXITEMS; i++, pD++) { if (pD->bCmd == 0xFF) { sgbDeltaChanged = TRUE; #ifdef HELLFIRE *pD = *pI; #else memcpy(pD, pI, sizeof(TCmdPItem)); #endif pD->bCmd = CMD_ACK_PLRINFO; pD->x = x; pD->y = y; return; } } } BOOL delta_portal_inited(int i) { return sgJunk.portal[i].x == 0xFF; } BOOL delta_quest_inited(int i) { return sgJunk.quests[i].qstate != 0xFF; } void DeltaAddItem(int ii) { int i; if (gbMaxPlayers == 1) return; TCmdPItem *pD = sgLevels[currlevel].item; for (i = 0; i < MAXITEMS; i++, pD++) { if (pD->bCmd != 0xFF && pD->wIndx == item[ii].IDidx && pD->wCI == item[ii]._iCreateInfo && pD->dwSeed == item[ii]._iSeed && (pD->bCmd == CMD_WALKXY || pD->bCmd == CMD_STAND)) { return; } } pD = sgLevels[currlevel].item; for (i = 0; i < MAXITEMS; i++, pD++) { if (pD->bCmd == 0xFF) { sgbDeltaChanged = TRUE; pD->bCmd = CMD_STAND; pD->x = item[ii]._ix; pD->y = item[ii]._iy; pD->wIndx = item[ii].IDidx; pD->wCI = item[ii]._iCreateInfo; pD->dwSeed = item[ii]._iSeed; pD->bId = item[ii]._iIdentified; pD->bDur = item[ii]._iDurability; pD->bMDur = item[ii]._iMaxDur; pD->bCh = item[ii]._iCharges; pD->bMCh = item[ii]._iMaxCharges; pD->wValue = item[ii]._ivalue; #ifdef HELLFIRE pD->wToHit = item[ii]._iPLToHit; pD->wMaxDam = item[ii]._iMaxDam; pD->bMinStr = item[ii]._iMinStr; pD->bMinMag = item[ii]._iMinMag; pD->bMinDex = item[ii]._iMinDex; pD->bAC = item[ii]._iAC; #endif return; } } } void DeltaSaveLevel() { if (gbMaxPlayers == 1) return; for (int i = 0; i < MAX_PLRS; i++) { if (i != myplr) plr[i]._pGFXLoad = 0; } plr[myplr]._pLvlVisited[currlevel] = TRUE; delta_leave_sync(currlevel); } void DeltaLoadLevel() { int ii, ot; int i, j, k, l; int x, y, xx, yy; BOOL done; if (gbMaxPlayers == 1) return; deltaload = TRUE; if (currlevel != 0) { for (i = 0; i < nummonsters; i++) { if (sgLevels[currlevel].monster[i]._mx != 0xFF) { M_ClearSquares(i); // BUGFIX: should use `monster[monstactive[i]]`, `not monster[i]`. monster[i]._mx = sgLevels[currlevel].monster[i]._mx; monster[i]._my = sgLevels[currlevel].monster[i]._my; monster[i]._moldx = monster[i]._mx; monster[i]._moldy = monster[i]._my; monster[i]._mfutx = monster[i]._mx; monster[i]._mfuty = monster[i]._my; if (sgLevels[currlevel].monster[i]._mhitpoints != -1) monster[i]._mhitpoints = sgLevels[currlevel].monster[i]._mhitpoints; if (sgLevels[currlevel].monster[i]._mhitpoints == 0) { monster[i]._moldx = sgLevels[currlevel].monster[i]._mx; // CODEFIX: useless assignment monster[i]._moldy = sgLevels[currlevel].monster[i]._my; // CODEFIX: useless assignment M_ClearSquares(i); if (monster[i]._mAi != AI_DIABLO) { if (monster[i]._uniqtype == 0) /// ASSERT: assert(monster[i].MType != NULL); AddDead(monster[i]._mx, monster[i]._my, monster[i].MType->mdeadval, (direction)monster[i]._mdir); else AddDead(monster[i]._mx, monster[i]._my, monster[i]._udeadval, (direction)monster[i]._mdir); } monster[i]._mDelFlag = TRUE; M_UpdateLeader(i); } else { decode_enemy(i, sgLevels[currlevel].monster[i]._menemy); if (monster[i]._mx && monster[i]._mx != 1 || monster[i]._my) dMonster[monster[i]._mx][monster[i]._my] = i + 1; if (i < MAX_PLRS) { MAI_Golum(i); monster[i]._mFlags |= (MFLAG_TARGETS_MONSTER | MFLAG_GOLEM); } else { M_StartStand(i, monster[i]._mdir); } monster[i]._msquelch = sgLevels[currlevel].monster[i]._mactive; } } } memcpy(automapview, &sgLocals[currlevel], sizeof(automapview)); } for (i = 0; i < MAXITEMS; i++) { if (sgLevels[currlevel].item[i].bCmd != 0xFF) { if (sgLevels[currlevel].item[i].bCmd == CMD_WALKXY) { ii = FindGetItem( sgLevels[currlevel].item[i].wIndx, sgLevels[currlevel].item[i].wCI, sgLevels[currlevel].item[i].dwSeed); if (ii != -1) { if (dItem[item[ii]._ix][item[ii]._iy] == ii + 1) dItem[item[ii]._ix][item[ii]._iy] = 0; DeleteItem(ii, i); } } if (sgLevels[currlevel].item[i].bCmd == CMD_ACK_PLRINFO) { ii = itemavail[0]; itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; if (sgLevels[currlevel].item[i].wIndx == IDI_EAR) { RecreateEar( ii, sgLevels[currlevel].item[i].wCI, sgLevels[currlevel].item[i].dwSeed, sgLevels[currlevel].item[i].bId, sgLevels[currlevel].item[i].bDur, sgLevels[currlevel].item[i].bMDur, sgLevels[currlevel].item[i].bCh, sgLevels[currlevel].item[i].bMCh, sgLevels[currlevel].item[i].wValue, sgLevels[currlevel].item[i].dwBuff); } else { RecreateItem( ii, sgLevels[currlevel].item[i].wIndx, sgLevels[currlevel].item[i].wCI, sgLevels[currlevel].item[i].dwSeed, sgLevels[currlevel].item[i].wValue); if (sgLevels[currlevel].item[i].bId) item[ii]._iIdentified = TRUE; item[ii]._iDurability = sgLevels[currlevel].item[i].bDur; item[ii]._iMaxDur = sgLevels[currlevel].item[i].bMDur; item[ii]._iCharges = sgLevels[currlevel].item[i].bCh; item[ii]._iMaxCharges = sgLevels[currlevel].item[i].bMCh; #ifdef HELLFIRE item[ii]._iPLToHit = sgLevels[currlevel].item[i].wToHit; item[ii]._iMaxDam = sgLevels[currlevel].item[i].wMaxDam; item[ii]._iMinStr = sgLevels[currlevel].item[i].bMinStr; item[ii]._iMinMag = sgLevels[currlevel].item[i].bMinMag; item[ii]._iMinDex = sgLevels[currlevel].item[i].bMinDex; item[ii]._iAC = sgLevels[currlevel].item[i].bAC; #endif } x = sgLevels[currlevel].item[i].x; y = sgLevels[currlevel].item[i].y; if (!CanPut(x, y)) { done = FALSE; for (k = 1; k < 50 && !done; k++) { for (j = -k; j <= k && !done; j++) { yy = y + j; for (l = -k; l <= k && !done; l++) { xx = x + l; if (CanPut(xx, yy)) { done = TRUE; x = xx; y = yy; } } } } } item[ii]._ix = x; item[ii]._iy = y; dItem[item[ii]._ix][item[ii]._iy] = ii + 1; RespawnItem(ii, FALSE); numitems++; } } } if (currlevel != 0) { for (i = 0; i < MAXOBJECTS; i++) { switch (sgLevels[currlevel].object[i].bCmd) { case CMD_OPENDOOR: case CMD_CLOSEDOOR: case CMD_OPERATEOBJ: case CMD_PLROPOBJ: SyncOpObject(-1, sgLevels[currlevel].object[i].bCmd, i); break; case CMD_BREAKOBJ: SyncBreakObj(-1, i); break; } } for (i = 0; i < nobjects; i++) { ot = object[objectactive[i]]._otype; if (ot == OBJ_TRAPL || ot == OBJ_TRAPR) Obj_Trap(objectactive[i]); } } deltaload = FALSE; } void NetSendCmd(BOOL bHiPri, BYTE bCmd) { TCmd cmd; cmd.bCmd = bCmd; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdGolem(BYTE mx, BYTE my, BYTE dir, BYTE menemy, int hp, BYTE cl) { TCmdGolem cmd; cmd.bCmd = CMD_AWAKEGOLEM; cmd._mx = mx; cmd._my = my; cmd._mdir = dir; cmd._menemy = menemy; cmd._mhitpoints = hp; cmd._currlevel = cl; NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdLoc(BOOL bHiPri, BYTE bCmd, BYTE x, BYTE y) { ALIGN_BY_1 TCmdLoc cmd; cmd.bCmd = bCmd; cmd.x = x; cmd.y = y; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdLocParam1(BOOL bHiPri, BYTE bCmd, BYTE x, BYTE y, WORD wParam1) { TCmdLocParam1 cmd; cmd.bCmd = bCmd; cmd.x = x; cmd.y = y; cmd.wParam1 = wParam1; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdLocParam2(BOOL bHiPri, BYTE bCmd, BYTE x, BYTE y, WORD wParam1, WORD wParam2) { TCmdLocParam2 cmd; cmd.bCmd = bCmd; cmd.x = x; cmd.y = y; cmd.wParam1 = wParam1; cmd.wParam2 = wParam2; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdLocParam3(BOOL bHiPri, BYTE bCmd, BYTE x, BYTE y, WORD wParam1, WORD wParam2, WORD wParam3) { TCmdLocParam3 cmd; cmd.bCmd = bCmd; cmd.x = x; cmd.y = y; cmd.wParam1 = wParam1; cmd.wParam2 = wParam2; cmd.wParam3 = wParam3; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdParam1(BOOL bHiPri, BYTE bCmd, WORD wParam1) { ALIGN_BY_1 TCmdParam1 cmd; cmd.bCmd = bCmd; cmd.wParam1 = wParam1; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdParam2(BOOL bHiPri, BYTE bCmd, WORD wParam1, WORD wParam2) { TCmdParam2 cmd; cmd.bCmd = bCmd; cmd.wParam1 = wParam1; cmd.wParam2 = wParam2; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdParam3(BOOL bHiPri, BYTE bCmd, WORD wParam1, WORD wParam2, WORD wParam3) { TCmdParam3 cmd; cmd.bCmd = bCmd; cmd.wParam1 = wParam1; cmd.wParam2 = wParam2; cmd.wParam3 = wParam3; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdQuest(BOOL bHiPri, BYTE q) { TCmdQuest cmd; cmd.q = q; cmd.bCmd = CMD_SYNCQUEST; cmd.qstate = quests[q]._qactive; cmd.qlog = quests[q]._qlog; cmd.qvar1 = quests[q]._qvar1; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdGItem(BOOL bHiPri, BYTE bCmd, BYTE mast, BYTE pnum, BYTE ii) { TCmdGItem cmd; cmd.bCmd = bCmd; cmd.bPnum = pnum; cmd.bMaster = mast; cmd.bLevel = currlevel; cmd.bCursitem = ii; cmd.dwTime = 0; cmd.x = item[ii]._ix; cmd.y = item[ii]._iy; cmd.wIndx = item[ii].IDidx; if (item[ii].IDidx == IDI_EAR) { cmd.wCI = item[ii]._iName[8] | (item[ii]._iName[7] << 8); cmd.dwSeed = item[ii]._iName[12] | ((item[ii]._iName[11] | ((item[ii]._iName[10] | (item[ii]._iName[9] << 8)) << 8)) << 8); cmd.bId = item[ii]._iName[13]; cmd.bDur = item[ii]._iName[14]; cmd.bMDur = item[ii]._iName[15]; cmd.bCh = item[ii]._iName[16]; cmd.bMCh = item[ii]._iName[17]; cmd.wValue = item[ii]._ivalue | (item[ii]._iName[18] << 8) | ((item[ii]._iCurs - ICURS_EAR_SORCEROR) << 6); cmd.dwBuff = item[ii]._iName[22] | ((item[ii]._iName[21] | ((item[ii]._iName[20] | (item[ii]._iName[19] << 8)) << 8)) << 8); } else { cmd.wCI = item[ii]._iCreateInfo; cmd.dwSeed = item[ii]._iSeed; cmd.bId = item[ii]._iIdentified; cmd.bDur = item[ii]._iDurability; cmd.bMDur = item[ii]._iMaxDur; cmd.bCh = item[ii]._iCharges; cmd.bMCh = item[ii]._iMaxCharges; cmd.wValue = item[ii]._ivalue; #ifdef HELLFIRE cmd.wToHit = item[ii]._iPLToHit; cmd.wMaxDam = item[ii]._iMaxDam; cmd.bMinStr = item[ii]._iMinStr; cmd.bMinMag = item[ii]._iMinMag; cmd.bMinDex = item[ii]._iMinDex; cmd.bAC = item[ii]._iAC; #endif } if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdGItem2(BOOL usonly, BYTE bCmd, BYTE mast, BYTE pnum, TCmdGItem *p) { TCmdGItem cmd; #ifdef HELLFIRE cmd = *p; #else memcpy(&cmd, p, sizeof(cmd)); #endif cmd.bPnum = pnum; cmd.bCmd = bCmd; cmd.bMaster = mast; if (!usonly) { cmd.dwTime = 0; NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); return; } int ticks = GetTickCount(); if (cmd.dwTime == 0) { cmd.dwTime = ticks; } else if (ticks - cmd.dwTime > 5000) { return; } multi_msg_add((BYTE *)&cmd.bCmd, sizeof(cmd)); } BOOL NetSendCmdReq2(BYTE bCmd, BYTE mast, BYTE pnum, TCmdGItem *p) { TCmdGItem cmd; #ifdef HELLFIRE cmd = *p; #else memcpy(&cmd, p, sizeof(cmd)); #endif cmd.bCmd = bCmd; cmd.bPnum = pnum; cmd.bMaster = mast; int ticks = GetTickCount(); if (cmd.dwTime == 0) cmd.dwTime = ticks; else if (ticks - cmd.dwTime > 5000) return FALSE; multi_msg_add((BYTE *)&cmd.bCmd, sizeof(cmd)); return TRUE; } void NetSendCmdExtra(TCmdGItem *p) { TCmdGItem cmd; #ifdef HELLFIRE cmd = *p; #else memcpy(&cmd, p, sizeof(cmd)); #endif cmd.dwTime = 0; cmd.bCmd = CMD_ITEMEXTRA; NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdPItem(BOOL bHiPri, BYTE bCmd, BYTE x, BYTE y) { TCmdPItem cmd; cmd.bCmd = bCmd; cmd.x = x; cmd.y = y; cmd.wIndx = plr[myplr].HoldItem.IDidx; if (plr[myplr].HoldItem.IDidx == IDI_EAR) { cmd.wCI = plr[myplr].HoldItem._iName[8] | (plr[myplr].HoldItem._iName[7] << 8); cmd.dwSeed = plr[myplr].HoldItem._iName[12] | ((plr[myplr].HoldItem._iName[11] | ((plr[myplr].HoldItem._iName[10] | (plr[myplr].HoldItem._iName[9] << 8)) << 8)) << 8); cmd.bId = plr[myplr].HoldItem._iName[13]; cmd.bDur = plr[myplr].HoldItem._iName[14]; cmd.bMDur = plr[myplr].HoldItem._iName[15]; cmd.bCh = plr[myplr].HoldItem._iName[16]; cmd.bMCh = plr[myplr].HoldItem._iName[17]; cmd.wValue = plr[myplr].HoldItem._ivalue | (plr[myplr].HoldItem._iName[18] << 8) | ((plr[myplr].HoldItem._iCurs - ICURS_EAR_SORCEROR) << 6); cmd.dwBuff = plr[myplr].HoldItem._iName[22] | ((plr[myplr].HoldItem._iName[21] | ((plr[myplr].HoldItem._iName[20] | (plr[myplr].HoldItem._iName[19] << 8)) << 8)) << 8); } else { cmd.wCI = plr[myplr].HoldItem._iCreateInfo; cmd.dwSeed = plr[myplr].HoldItem._iSeed; cmd.bId = plr[myplr].HoldItem._iIdentified; cmd.bDur = plr[myplr].HoldItem._iDurability; cmd.bMDur = plr[myplr].HoldItem._iMaxDur; cmd.bCh = plr[myplr].HoldItem._iCharges; cmd.bMCh = plr[myplr].HoldItem._iMaxCharges; cmd.wValue = plr[myplr].HoldItem._ivalue; #ifdef HELLFIRE cmd.wToHit = plr[myplr].HoldItem._iPLToHit; cmd.wMaxDam = plr[myplr].HoldItem._iMaxDam; cmd.bMinStr = plr[myplr].HoldItem._iMinStr; cmd.bMinMag = plr[myplr].HoldItem._iMinMag; cmd.bMinDex = plr[myplr].HoldItem._iMinDex; cmd.bAC = plr[myplr].HoldItem._iAC; #endif } if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdChItem(BOOL bHiPri, BYTE bLoc) { TCmdChItem cmd; cmd.bCmd = CMD_CHANGEPLRITEMS; cmd.bLoc = bLoc; cmd.wIndx = plr[myplr].HoldItem.IDidx; cmd.wCI = plr[myplr].HoldItem._iCreateInfo; cmd.dwSeed = plr[myplr].HoldItem._iSeed; cmd.bId = plr[myplr].HoldItem._iIdentified; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdDelItem(BOOL bHiPri, BYTE bLoc) { TCmdDelItem cmd; cmd.bLoc = bLoc; cmd.bCmd = CMD_DELPLRITEMS; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } void NetSendCmdDItem(BOOL bHiPri, int ii) { TCmdPItem cmd; cmd.bCmd = CMD_DROPITEM; cmd.x = item[ii]._ix; cmd.y = item[ii]._iy; cmd.wIndx = item[ii].IDidx; if (item[ii].IDidx == IDI_EAR) { cmd.wCI = item[ii]._iName[8] | (item[ii]._iName[7] << 8); cmd.dwSeed = item[ii]._iName[12] | ((item[ii]._iName[11] | ((item[ii]._iName[10] | (item[ii]._iName[9] << 8)) << 8)) << 8); cmd.bId = item[ii]._iName[13]; cmd.bDur = item[ii]._iName[14]; cmd.bMDur = item[ii]._iName[15]; cmd.bCh = item[ii]._iName[16]; cmd.bMCh = item[ii]._iName[17]; cmd.wValue = item[ii]._ivalue | (item[ii]._iName[18] << 8) | ((item[ii]._iCurs - ICURS_EAR_SORCEROR) << 6); cmd.dwBuff = item[ii]._iName[22] | ((item[ii]._iName[21] | ((item[ii]._iName[20] | (item[ii]._iName[19] << 8)) << 8)) << 8); } else { cmd.wCI = item[ii]._iCreateInfo; cmd.dwSeed = item[ii]._iSeed; cmd.bId = item[ii]._iIdentified; cmd.bDur = item[ii]._iDurability; cmd.bMDur = item[ii]._iMaxDur; cmd.bCh = item[ii]._iCharges; cmd.bMCh = item[ii]._iMaxCharges; cmd.wValue = item[ii]._ivalue; #ifdef HELLFIRE cmd.wToHit = item[ii]._iPLToHit; cmd.wMaxDam = item[ii]._iMaxDam; cmd.bMinStr = item[ii]._iMinStr; cmd.bMinMag = item[ii]._iMinMag; cmd.bMinDex = item[ii]._iMinDex; cmd.bAC = item[ii]._iAC; #endif } if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } static BOOL i_own_level(int nReqLevel) { int i; for (i = 0; i < MAX_PLRS; i++) { if (!plr[i].plractive) continue; if (plr[i]._pLvlChanging) continue; if (plr[i].plrlevel != nReqLevel) continue; if (i == myplr && gbBufferMsgs != 0) continue; break; } return i == myplr; } void NetSendCmdDamage(BOOL bHiPri, BYTE bPlr, DWORD dwDam) { TCmdDamage cmd; cmd.bCmd = CMD_PLRDAMAGE; cmd.bPlr = bPlr; cmd.dwDam = dwDam; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } #ifdef HELLFIRE void NetSendCmdMonDmg(BOOL bHiPri, WORD wMon, DWORD dwDam) { TCmdMonDamage cmd; cmd.bCmd = CMD_MONSTDAMAGE; cmd.wMon = wMon; cmd.dwDam = dwDam; if (bHiPri) NetSendHiPri((BYTE *)&cmd, sizeof(cmd)); else NetSendLoPri((BYTE *)&cmd, sizeof(cmd)); } #endif void NetSendCmdString(int pmask, const char *pszStr) { int dwStrLen; TCmdString cmd; dwStrLen = strlen(pszStr); cmd.bCmd = CMD_STRING; strcpy(cmd.str, pszStr); multi_send_msg_packet(pmask, (BYTE *)&cmd.bCmd, dwStrLen + 2); } static DWORD On_STRING2(int pnum, TCmd *pCmd) { TCmdString *p = (TCmdString *)pCmd; int len = strlen(p->str); if (!gbBufferMsgs) SendPlrMsg(pnum, p->str); return len + 2; // length of string + nul terminator + sizeof(p->bCmd) } static void delta_open_portal(int pnum, BYTE x, BYTE y, BYTE bLevel, BYTE bLType, BYTE bSetLvl) { sgbDeltaChanged = TRUE; sgJunk.portal[pnum].x = x; sgJunk.portal[pnum].y = y; sgJunk.portal[pnum].level = bLevel; sgJunk.portal[pnum].ltype = bLType; sgJunk.portal[pnum].setlvl = bSetLvl; } void delta_close_portal(int pnum) { memset(&sgJunk.portal[pnum], 0xFF, sizeof(sgJunk.portal[pnum])); sgbDeltaChanged = TRUE; } static void check_update_plr(int pnum) { if (gbMaxPlayers != 1 && pnum == myplr) pfile_update(TRUE); } static void __cdecl msg_errorf(const char *pszFmt, ...) { static DWORD msg_err_timer; DWORD ticks; char msg[256]; va_list va; va_start(va, pszFmt); ticks = GetTickCount(); if (ticks - msg_err_timer >= 5000) { msg_err_timer = ticks; vsprintf(msg, pszFmt, va); ErrorPlrMsg(msg); } va_end(va); } static DWORD On_SYNCDATA(TCmd *pCmd, int pnum) { return sync_update(pnum, (const BYTE *)pCmd); } static DWORD On_WALKXY(TCmd *pCmd, int pnum) { TCmdLoc *p = (TCmdLoc *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { ClrPlrPath(pnum); MakePlrPath(pnum, p->x, p->y, TRUE); plr[pnum].destAction = ACTION_NONE; } return sizeof(*p); } static DWORD On_ADDSTR(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (p->wParam1 <= 256) ModifyPlrStr(pnum, p->wParam1); return sizeof(*p); } static DWORD On_ADDMAG(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (p->wParam1 <= 256) ModifyPlrMag(pnum, p->wParam1); return sizeof(*p); } static DWORD On_ADDDEX(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (p->wParam1 <= 256) ModifyPlrDex(pnum, p->wParam1); return sizeof(*p); } static DWORD On_ADDVIT(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (p->wParam1 <= 256) ModifyPlrVit(pnum, p->wParam1); return sizeof(*p); } static DWORD On_SBSPELL(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs != 1) { int spell = p->wParam1; if (currlevel != 0 || spelldata[spell].sTownSpell) { plr[pnum]._pSpell = p->wParam1; plr[pnum]._pSplType = plr[pnum]._pSBkSplType; plr[pnum]._pSplFrom = 1; plr[pnum].destAction = ACTION_SPELL; } else msg_errorf("%s has cast an illegal spell.", plr[pnum]._pName); } return sizeof(*p); } static DWORD On_GOTOGETITEM(TCmd *pCmd, int pnum) { TCmdLocParam1 *p = (TCmdLocParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { MakePlrPath(pnum, p->x, p->y, FALSE); plr[pnum].destAction = ACTION_PICKUPITEM; plr[pnum].destParam1 = p->wParam1; } return sizeof(*p); } static DWORD On_REQUESTGITEM(TCmd *pCmd, int pnum) { TCmdGItem *p = (TCmdGItem *)pCmd; if (gbBufferMsgs != 1 && i_own_level(plr[pnum].plrlevel)) { if (GetItemRecord(p->dwSeed, p->wCI, p->wIndx)) { int ii = FindGetItem(p->wIndx, p->wCI, p->dwSeed); if (ii != -1) { NetSendCmdGItem2(FALSE, CMD_GETITEM, myplr, p->bPnum, p); if (p->bPnum != myplr) SyncGetItem(p->x, p->y, p->wIndx, p->wCI, p->dwSeed); else InvGetItem(myplr, ii); SetItemRecord(p->dwSeed, p->wCI, p->wIndx); } else if (!NetSendCmdReq2(CMD_REQUESTGITEM, myplr, p->bPnum, p)) NetSendCmdExtra(p); } } return sizeof(*p); } static DWORD On_GETITEM(TCmd *pCmd, int pnum) { TCmdGItem *p = (TCmdGItem *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { int ii = FindGetItem(p->wIndx, p->wCI, p->dwSeed); if (delta_get_item(p, p->bLevel)) { if ((currlevel == p->bLevel || p->bPnum == myplr) && p->bMaster != myplr) { if (p->bPnum == myplr) { if (currlevel != p->bLevel) { ii = SyncPutItem(myplr, plr[myplr]._px, plr[myplr]._py, p->wIndx, p->wCI, p->dwSeed, p->bId, p->bDur, p->bMDur, p->bCh, p->bMCh, p->wValue, p->dwBuff #ifdef HELLFIRE , p->wToHit, p->wMaxDam, p->bMinStr, p->bMinMag, p->bMinDex, p->bAC #endif ); if (ii != -1) InvGetItem(myplr, ii); } else InvGetItem(myplr, ii); } else SyncGetItem(p->x, p->y, p->wIndx, p->wCI, p->dwSeed); } } else NetSendCmdGItem2(TRUE, CMD_GETITEM, p->bMaster, p->bPnum, p); } return sizeof(*p); } static DWORD On_GOTOAGETITEM(TCmd *pCmd, int pnum) { TCmdLocParam1 *p = (TCmdLocParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { MakePlrPath(pnum, p->x, p->y, FALSE); plr[pnum].destAction = ACTION_PICKUPAITEM; plr[pnum].destParam1 = p->wParam1; } return sizeof(*p); } static DWORD On_REQUESTAGITEM(TCmd *pCmd, int pnum) { TCmdGItem *p = (TCmdGItem *)pCmd; if (gbBufferMsgs != 1 && i_own_level(plr[pnum].plrlevel)) { if (GetItemRecord(p->dwSeed, p->wCI, p->wIndx)) { int ii = FindGetItem(p->wIndx, p->wCI, p->dwSeed); if (ii != -1) { NetSendCmdGItem2(FALSE, CMD_AGETITEM, myplr, p->bPnum, p); if (p->bPnum != myplr) SyncGetItem(p->x, p->y, p->wIndx, p->wCI, p->dwSeed); else AutoGetItem(myplr, p->bCursitem); SetItemRecord(p->dwSeed, p->wCI, p->wIndx); } else if (!NetSendCmdReq2(CMD_REQUESTAGITEM, myplr, p->bPnum, p)) NetSendCmdExtra(p); } } return sizeof(*p); } static DWORD On_AGETITEM(TCmd *pCmd, int pnum) { TCmdGItem *p = (TCmdGItem *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { FindGetItem(p->wIndx, p->wCI, p->dwSeed); if (delta_get_item(p, p->bLevel)) { if ((currlevel == p->bLevel || p->bPnum == myplr) && p->bMaster != myplr) { if (p->bPnum == myplr) { if (currlevel != p->bLevel) { int ii = SyncPutItem(myplr, plr[myplr]._px, plr[myplr]._py, p->wIndx, p->wCI, p->dwSeed, p->bId, p->bDur, p->bMDur, p->bCh, p->bMCh, p->wValue, p->dwBuff #ifdef HELLFIRE , p->wToHit, p->wMaxDam, p->bMinStr, p->bMinMag, p->bMinDex, p->bAC #endif ); if (ii != -1) AutoGetItem(myplr, ii); } else AutoGetItem(myplr, p->bCursitem); } else SyncGetItem(p->x, p->y, p->wIndx, p->wCI, p->dwSeed); } } else NetSendCmdGItem2(TRUE, CMD_AGETITEM, p->bMaster, p->bPnum, p); } return sizeof(*p); } static DWORD On_ITEMEXTRA(TCmd *pCmd, int pnum) { TCmdGItem *p = (TCmdGItem *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { delta_get_item(p, p->bLevel); if (currlevel == plr[pnum].plrlevel) SyncGetItem(p->x, p->y, p->wIndx, p->wCI, p->dwSeed); } return sizeof(*p); } static DWORD On_PUTITEM(TCmd *pCmd, int pnum) { TCmdPItem *p = (TCmdPItem *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (currlevel == plr[pnum].plrlevel) { int ii; if (pnum == myplr) ii = InvPutItem(pnum, p->x, p->y); else ii = SyncPutItem(pnum, p->x, p->y, p->wIndx, p->wCI, p->dwSeed, p->bId, p->bDur, p->bMDur, p->bCh, p->bMCh, p->wValue, p->dwBuff #ifdef HELLFIRE , p->wToHit, p->wMaxDam, p->bMinStr, p->bMinMag, p->bMinDex, p->bAC #endif ); if (ii != -1) { PutItemRecord(p->dwSeed, p->wCI, p->wIndx); delta_put_item(p, item[ii]._ix, item[ii]._iy, plr[pnum].plrlevel); check_update_plr(pnum); } return sizeof(*p); } else { PutItemRecord(p->dwSeed, p->wCI, p->wIndx); delta_put_item(p, p->x, p->y, plr[pnum].plrlevel); check_update_plr(pnum); } return sizeof(*p); } static DWORD On_SYNCPUTITEM(TCmd *pCmd, int pnum) { TCmdPItem *p = (TCmdPItem *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (currlevel == plr[pnum].plrlevel) { int ii = SyncPutItem(pnum, p->x, p->y, p->wIndx, p->wCI, p->dwSeed, p->bId, p->bDur, p->bMDur, p->bCh, p->bMCh, p->wValue, p->dwBuff #ifdef HELLFIRE , p->wToHit, p->wMaxDam, p->bMinStr, p->bMinMag, p->bMinDex, p->bAC #endif ); if (ii != -1) { PutItemRecord(p->dwSeed, p->wCI, p->wIndx); delta_put_item(p, item[ii]._ix, item[ii]._iy, plr[pnum].plrlevel); check_update_plr(pnum); } return sizeof(*p); } else { PutItemRecord(p->dwSeed, p->wCI, p->wIndx); delta_put_item(p, p->x, p->y, plr[pnum].plrlevel); check_update_plr(pnum); } return sizeof(*p); } static DWORD On_RESPAWNITEM(TCmd *pCmd, int pnum) { TCmdPItem *p = (TCmdPItem *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { if (currlevel == plr[pnum].plrlevel && pnum != myplr) { SyncPutItem(pnum, p->x, p->y, p->wIndx, p->wCI, p->dwSeed, p->bId, p->bDur, p->bMDur, p->bCh, p->bMCh, p->wValue, p->dwBuff #ifdef HELLFIRE , p->wToHit, p->wMaxDam, p->bMinStr, p->bMinMag, p->bMinDex, p->bAC #endif ); } PutItemRecord(p->dwSeed, p->wCI, p->wIndx); delta_put_item(p, p->x, p->y, plr[pnum].plrlevel); } return sizeof(*p); } static DWORD On_ATTACKXY(TCmd *pCmd, int pnum) { TCmdLoc *p = (TCmdLoc *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { MakePlrPath(pnum, p->x, p->y, FALSE); plr[pnum].destAction = ACTION_ATTACK; plr[pnum].destParam1 = p->x; plr[pnum].destParam2 = p->y; } return sizeof(*p); } static DWORD On_SATTACKXY(TCmd *pCmd, int pnum) { TCmdLoc *p = (TCmdLoc *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_ATTACK; plr[pnum].destParam1 = p->x; plr[pnum].destParam2 = p->y; } return sizeof(*p); } static DWORD On_RATTACKXY(TCmd *pCmd, int pnum) { TCmdLoc *p = (TCmdLoc *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_RATTACK; plr[pnum].destParam1 = p->x; plr[pnum].destParam2 = p->y; } return sizeof(*p); } static DWORD On_SPELLXYD(TCmd *pCmd, int pnum) { TCmdLocParam3 *p = (TCmdLocParam3 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { int spell = p->wParam1; if (currlevel != 0 || spelldata[spell].sTownSpell) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_SPELLWALL; plr[pnum].destParam1 = p->x; plr[pnum].destParam2 = p->y; plr[pnum].destParam3 = p->wParam2; plr[pnum].destParam4 = p->wParam3; plr[pnum]._pSpell = p->wParam1; plr[pnum]._pSplType = plr[pnum]._pRSplType; plr[pnum]._pSplFrom = 0; } else msg_errorf("%s has cast an illegal spell.", plr[pnum]._pName); } return sizeof(*p); } static DWORD On_SPELLXY(TCmd *pCmd, int pnum) { TCmdLocParam2 *p = (TCmdLocParam2 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { int spell = p->wParam1; if (currlevel != 0 || spelldata[spell].sTownSpell) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_SPELL; plr[pnum].destParam1 = p->x; plr[pnum].destParam2 = p->y; plr[pnum].destParam3 = p->wParam2; plr[pnum]._pSpell = p->wParam1; plr[pnum]._pSplType = plr[pnum]._pRSplType; plr[pnum]._pSplFrom = 0; } else msg_errorf("%s has cast an illegal spell.", plr[pnum]._pName); } return sizeof(*p); } static DWORD On_TSPELLXY(TCmd *pCmd, int pnum) { TCmdLocParam2 *p = (TCmdLocParam2 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { int spell = p->wParam1; if (currlevel != 0 || spelldata[spell].sTownSpell) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_SPELL; plr[pnum].destParam1 = p->x; plr[pnum].destParam2 = p->y; plr[pnum].destParam3 = p->wParam2; plr[pnum]._pSpell = p->wParam1; plr[pnum]._pSplType = plr[pnum]._pTSplType; plr[pnum]._pSplFrom = 2; } else msg_errorf("%s has cast an illegal spell.", plr[pnum]._pName); } return sizeof(*p); } static DWORD On_OPOBJXY(TCmd *pCmd, int pnum) { TCmdLocParam1 *p = (TCmdLocParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { if (object[p->wParam1]._oSolidFlag || object[p->wParam1]._oDoorFlag) MakePlrPath(pnum, p->x, p->y, FALSE); else MakePlrPath(pnum, p->x, p->y, TRUE); plr[pnum].destAction = ACTION_OPERATE; plr[pnum].destParam1 = p->wParam1; } return sizeof(*p); } static DWORD On_DISARMXY(TCmd *pCmd, int pnum) { TCmdLocParam1 *p = (TCmdLocParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { if (object[p->wParam1]._oSolidFlag || object[p->wParam1]._oDoorFlag) MakePlrPath(pnum, p->x, p->y, FALSE); else MakePlrPath(pnum, p->x, p->y, TRUE); plr[pnum].destAction = ACTION_DISARM; plr[pnum].destParam1 = p->wParam1; } return sizeof(*p); } static DWORD On_OPOBJT(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { plr[pnum].destAction = ACTION_OPERATETK; plr[pnum].destParam1 = p->wParam1; } return sizeof(*p); } static DWORD On_ATTACKID(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { int distx = abs(plr[pnum]._px - monster[p->wParam1]._mfutx); int disty = abs(plr[pnum]._py - monster[p->wParam1]._mfuty); if (distx > 1 || disty > 1) MakePlrPath(pnum, monster[p->wParam1]._mfutx, monster[p->wParam1]._mfuty, FALSE); plr[pnum].destAction = ACTION_ATTACKMON; plr[pnum].destParam1 = p->wParam1; } return sizeof(*p); } static DWORD On_ATTACKPID(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { MakePlrPath(pnum, plr[p->wParam1]._pfutx, plr[p->wParam1]._pfuty, FALSE); plr[pnum].destAction = ACTION_ATTACKPLR; plr[pnum].destParam1 = p->wParam1; } return sizeof(*p); } static DWORD On_RATTACKID(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_RATTACKMON; plr[pnum].destParam1 = p->wParam1; } return sizeof(*p); } static DWORD On_RATTACKPID(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_RATTACKPLR; plr[pnum].destParam1 = p->wParam1; } return sizeof(*p); } static DWORD On_SPELLID(TCmd *pCmd, int pnum) { TCmdParam3 *p = (TCmdParam3 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { int spell = p->wParam2; if (currlevel != 0 || spelldata[spell].sTownSpell) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_SPELLMON; plr[pnum].destParam1 = p->wParam1; plr[pnum].destParam2 = p->wParam3; plr[pnum]._pSpell = p->wParam2; plr[pnum]._pSplType = plr[pnum]._pRSplType; plr[pnum]._pSplFrom = 0; } else msg_errorf("%s has cast an illegal spell.", plr[pnum]._pName); } return sizeof(*p); } static DWORD On_SPELLPID(TCmd *pCmd, int pnum) { TCmdParam3 *p = (TCmdParam3 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { int spell = p->wParam2; if (currlevel != 0 || spelldata[spell].sTownSpell) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_SPELLPLR; plr[pnum].destParam1 = p->wParam1; plr[pnum].destParam2 = p->wParam3; plr[pnum]._pSpell = p->wParam2; plr[pnum]._pSplType = plr[pnum]._pRSplType; plr[pnum]._pSplFrom = 0; } else msg_errorf("%s has cast an illegal spell.", plr[pnum]._pName); } return sizeof(*p); } static DWORD On_TSPELLID(TCmd *pCmd, int pnum) { TCmdParam3 *p = (TCmdParam3 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { int spell = p->wParam2; if (currlevel != 0 || spelldata[spell].sTownSpell) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_SPELLMON; plr[pnum].destParam1 = p->wParam1; plr[pnum].destParam2 = p->wParam3; plr[pnum]._pSpell = p->wParam2; plr[pnum]._pSplType = plr[pnum]._pTSplType; plr[pnum]._pSplFrom = 2; } else msg_errorf("%s has cast an illegal spell.", plr[pnum]._pName); } return sizeof(*p); } static DWORD On_TSPELLPID(TCmd *pCmd, int pnum) { TCmdParam3 *p = (TCmdParam3 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { int spell = p->wParam2; if (currlevel != 0 || spelldata[spell].sTownSpell) { ClrPlrPath(pnum); plr[pnum].destAction = ACTION_SPELLPLR; plr[pnum].destParam1 = p->wParam1; plr[pnum].destParam2 = p->wParam3; plr[pnum]._pSpell = p->wParam2; plr[pnum]._pSplType = plr[pnum]._pTSplType; plr[pnum]._pSplFrom = 2; } else msg_errorf("%s has cast an illegal spell.", plr[pnum]._pName); } return sizeof(*p); } static DWORD On_KNOCKBACK(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { M_GetKnockback(p->wParam1); M_StartHit(p->wParam1, pnum, 0); } return sizeof(*p); } static DWORD On_RESURRECT(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { DoResurrect(pnum, p->wParam1); check_update_plr(pnum); } return sizeof(*p); } static DWORD On_HEALOTHER(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) DoHealOther(pnum, p->wParam1); return sizeof(*p); } static DWORD On_TALKXY(TCmd *pCmd, int pnum) { TCmdLocParam1 *p = (TCmdLocParam1 *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel) { MakePlrPath(pnum, p->x, p->y, FALSE); plr[pnum].destAction = ACTION_TALK; plr[pnum].destParam1 = p->wParam1; } return sizeof(*p); } static DWORD On_NEWLVL(TCmd *pCmd, int pnum) { TCmdParam2 *p = (TCmdParam2 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (pnum != myplr) StartNewLvl(pnum, p->wParam1, p->wParam2); return sizeof(*p); } static DWORD On_WARP(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { StartWarpLvl(pnum, p->wParam1); if (pnum == myplr && pcurs >= CURSOR_FIRSTITEM) { item[MAXITEMS] = plr[myplr].HoldItem; AutoGetItem(myplr, MAXITEMS); } } return sizeof(*p); } static DWORD On_MONSTDEATH(TCmd *pCmd, int pnum) { TCmdLocParam1 *p = (TCmdLocParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (pnum != myplr) { if (currlevel == plr[pnum].plrlevel) M_SyncStartKill(p->wParam1, p->x, p->y, pnum); delta_kill_monster(p->wParam1, p->x, p->y, plr[pnum].plrlevel); } return sizeof(*p); } static DWORD On_KILLGOLEM(TCmd *pCmd, int pnum) { TCmdLocParam1 *p = (TCmdLocParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (pnum != myplr) { if (currlevel == p->wParam1) M_SyncStartKill(pnum, p->x, p->y, pnum); delta_kill_monster(pnum, p->x, p->y, plr[pnum].plrlevel); // BUGFIX: should be p->wParam1, plrlevel will be incorrect if golem is killed because player changed levels } return sizeof(*p); } static DWORD On_AWAKEGOLEM(TCmd *pCmd, int pnum) { TCmdGolem *p = (TCmdGolem *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (currlevel != plr[pnum].plrlevel) delta_sync_golem(p, pnum, p->_currlevel); else if (pnum != myplr) { int i; // check if this player already has an active golem BOOL addGolem = TRUE; for (i = 0; i < nummissiles; i++) { int mi = missileactive[i]; if (missile[mi]._mitype == MIS_GOLEM && missile[mi]._misource == pnum) { addGolem = FALSE; // CODEFIX: break, don't need to check the rest } } if (addGolem) AddMissile(plr[pnum]._px, plr[pnum]._py, p->_mx, p->_my, p->_mdir, MIS_GOLEM, TARGET_MONSTERS, pnum, 0, 1); } return sizeof(*p); } static DWORD On_MONSTDAMAGE(TCmd *pCmd, int pnum) { #ifdef HELLFIRE TCmdMonDamage *p = (TCmdMonDamage *)pCmd; #else TCmdParam2 *p = (TCmdParam2 *)pCmd; #endif if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(TCmdParam2)); // BUGFIX: change to sizeof(*p) or it still uses TCmdParam2 size for hellfire else if (pnum != myplr) { if (currlevel == plr[pnum].plrlevel) { #ifdef HELLFIRE monster[p->wMon].mWhoHit |= 1 << pnum; if (monster[p->wMon]._mhitpoints >= 0) { monster[p->wMon]._mhitpoints -= p->dwDam; if ((monster[p->wMon]._mhitpoints >> 6) < 1) monster[p->wMon]._mhitpoints = 1 << 6; delta_monster_hp(p->wMon, monster[p->wMon]._mhitpoints, plr[pnum].plrlevel); } #else monster[p->wParam1].mWhoHit |= 1 << pnum; if (monster[p->wParam1]._mhitpoints != 0) { monster[p->wParam1]._mhitpoints -= p->wParam2; if ((monster[p->wParam1]._mhitpoints >> 6) < 1) monster[p->wParam1]._mhitpoints = 1 << 6; delta_monster_hp(p->wParam1, monster[p->wParam1]._mhitpoints, plr[pnum].plrlevel); } #endif } } return sizeof(*p); } static DWORD On_PLRDEAD(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (pnum != myplr) StartPlayerKill(pnum, p->wParam1); else check_update_plr(pnum); return sizeof(*p); } static DWORD On_PLRDAMAGE(TCmd *pCmd, int pnum) { TCmdDamage *p = (TCmdDamage *)pCmd; if (p->bPlr == myplr && currlevel != 0 && gbBufferMsgs != 1) { if (currlevel == plr[pnum].plrlevel && p->dwDam <= 192000 && plr[myplr]._pHitPoints >> 6 > 0) { drawhpflag = TRUE; plr[myplr]._pHitPoints -= p->dwDam; plr[myplr]._pHPBase -= p->dwDam; if (plr[myplr]._pHitPoints > plr[myplr]._pMaxHP) { plr[myplr]._pHitPoints = plr[myplr]._pMaxHP; plr[myplr]._pHPBase = plr[myplr]._pMaxHPBase; } if (plr[myplr]._pHitPoints >> 6 <= 0) { SyncPlrKill(myplr, 1); } } } return sizeof(*p); } static DWORD On_OPENDOOR(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { if (currlevel == plr[pnum].plrlevel) SyncOpObject(pnum, CMD_OPENDOOR, p->wParam1); delta_sync_object(p->wParam1, CMD_OPENDOOR, plr[pnum].plrlevel); } return sizeof(*p); } static DWORD On_CLOSEDOOR(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { if (currlevel == plr[pnum].plrlevel) SyncOpObject(pnum, CMD_CLOSEDOOR, p->wParam1); delta_sync_object(p->wParam1, CMD_CLOSEDOOR, plr[pnum].plrlevel); } return sizeof(*p); } static DWORD On_OPERATEOBJ(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { if (currlevel == plr[pnum].plrlevel) SyncOpObject(pnum, CMD_OPERATEOBJ, p->wParam1); delta_sync_object(p->wParam1, CMD_OPERATEOBJ, plr[pnum].plrlevel); } return sizeof(*p); } static DWORD On_PLROPOBJ(TCmd *pCmd, int pnum) { TCmdParam2 *p = (TCmdParam2 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { if (currlevel == plr[pnum].plrlevel) SyncOpObject(p->wParam1, CMD_PLROPOBJ, p->wParam2); delta_sync_object(p->wParam2, CMD_PLROPOBJ, plr[pnum].plrlevel); } return sizeof(*p); } static DWORD On_BREAKOBJ(TCmd *pCmd, int pnum) { TCmdParam2 *p = (TCmdParam2 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { if (currlevel == plr[pnum].plrlevel) SyncBreakObj(p->wParam1, p->wParam2); delta_sync_object(p->wParam2, CMD_BREAKOBJ, plr[pnum].plrlevel); } return sizeof(*p); } static DWORD On_CHANGEPLRITEMS(TCmd *pCmd, int pnum) { TCmdChItem *p = (TCmdChItem *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (pnum != myplr) CheckInvSwap(pnum, p->bLoc, p->wIndx, p->wCI, p->dwSeed, p->bId); return sizeof(*p); } static DWORD On_DELPLRITEMS(TCmd *pCmd, int pnum) { TCmdDelItem *p = (TCmdDelItem *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (pnum != myplr) inv_update_rem_item(pnum, p->bLoc); return sizeof(*p); } static DWORD On_PLRLEVEL(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (p->wParam1 <= MAXCHARLEVEL && pnum != myplr) plr[pnum]._pLevel = p->wParam1; return sizeof(*p); } static DWORD On_DROPITEM(TCmd *pCmd, int pnum) { TCmdPItem *p = (TCmdPItem *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else delta_put_item(p, p->x, p->y, plr[pnum].plrlevel); return sizeof(*p); } static DWORD On_SEND_PLRINFO(TCmd *pCmd, int pnum) { TCmdPlrInfoHdr *p = (TCmdPlrInfoHdr *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, p->wBytes + sizeof(*p)); else recv_plrinfo(pnum, p, p->bCmd == CMD_ACK_PLRINFO); return p->wBytes + sizeof(*p); } static DWORD On_ACK_PLRINFO(TCmd *pCmd, int pnum) { return On_SEND_PLRINFO(pCmd, pnum); } static DWORD On_PLAYER_JOINLEVEL(TCmd *pCmd, int pnum) { TCmdLocParam1 *p = (TCmdLocParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { plr[pnum]._pLvlChanging = FALSE; if (plr[pnum]._pName[0] != 0 && !plr[pnum].plractive) { plr[pnum].plractive = TRUE; gbActivePlayers++; EventPlrMsg("Player '%s' (level %d) just joined the game", plr[pnum]._pName, plr[pnum]._pLevel); } if (plr[pnum].plractive && myplr != pnum) { plr[pnum]._px = p->x; plr[pnum]._py = p->y; plr[pnum].plrlevel = p->wParam1; plr[pnum]._pGFXLoad = 0; if (currlevel == plr[pnum].plrlevel) { LoadPlrGFX(pnum, PFILE_STAND); SyncInitPlr(pnum); if ((plr[pnum]._pHitPoints >> 6) > 0) StartStand(pnum, 0); else { plr[pnum]._pgfxnum = 0; LoadPlrGFX(pnum, PFILE_DEATH); plr[pnum]._pmode = PM_DEATH; NewPlrAnim(pnum, plr[pnum]._pDAnim[DIR_S], plr[pnum]._pDFrames, 1, plr[pnum]._pDWidth); plr[pnum]._pAnimFrame = plr[pnum]._pAnimLen - 1; plr[pnum]._pVar8 = plr[pnum]._pAnimLen << 1; dFlags[plr[pnum]._px][plr[pnum]._py] |= BFLAG_DEAD_PLAYER; } plr[pnum]._pvid = AddVision(plr[pnum]._px, plr[pnum]._py, plr[pnum]._pLightRad, pnum == myplr); plr[pnum]._plid = -1; } } } return sizeof(*p); } static DWORD On_ACTIVATEPORTAL(TCmd *pCmd, int pnum) { TCmdLocParam3 *p = (TCmdLocParam3 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { ActivatePortal(pnum, p->x, p->y, p->wParam1, p->wParam2, p->wParam3); if (pnum != myplr) { if (currlevel == 0) AddInTownPortal(pnum); else if (currlevel == plr[pnum].plrlevel) { BOOL addPortal = TRUE; for (int i = 0; i < nummissiles; i++) { int mi = missileactive[i]; if (missile[mi]._mitype == MIS_TOWN && missile[mi]._misource == pnum) { addPortal = FALSE; // CODEFIX: break } } if (addPortal) AddWarpMissile(pnum, p->x, p->y); } else RemovePortalMissile(pnum); } delta_open_portal(pnum, p->x, p->y, p->wParam1, p->wParam2, p->wParam3); } return sizeof(*p); } static DWORD On_DEACTIVATEPORTAL(TCmd *pCmd, int pnum) { if (gbBufferMsgs == 1) msg_send_packet(pnum, pCmd, sizeof(*pCmd)); else { if (PortalOnLevel(pnum)) RemovePortalMissile(pnum); DeactivatePortal(pnum); delta_close_portal(pnum); } return sizeof(*pCmd); } static DWORD On_RETOWN(TCmd *pCmd, int pnum) { if (gbBufferMsgs == 1) msg_send_packet(pnum, pCmd, sizeof(*pCmd)); else { if (pnum == myplr) { deathflag = FALSE; gamemenu_off(); } RestartTownLvl(pnum); } return sizeof(*pCmd); } static DWORD On_SETSTR(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (p->wParam1 <= 750 && pnum != myplr) SetPlrStr(pnum, p->wParam1); return sizeof(*p); } static DWORD On_SETDEX(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (p->wParam1 <= 750 && pnum != myplr) SetPlrDex(pnum, p->wParam1); return sizeof(*p); } static DWORD On_SETMAG(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (p->wParam1 <= 750 && pnum != myplr) SetPlrMag(pnum, p->wParam1); return sizeof(*p); } static DWORD On_SETVIT(TCmd *pCmd, int pnum) { TCmdParam1 *p = (TCmdParam1 *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else if (p->wParam1 <= 750 && pnum != myplr) SetPlrVit(pnum, p->wParam1); return sizeof(*p); } static DWORD On_STRING(TCmd *pCmd, int pnum) { return On_STRING2(pnum, pCmd); } static DWORD On_SYNCQUEST(TCmd *pCmd, int pnum) { TCmdQuest *p = (TCmdQuest *)pCmd; if (gbBufferMsgs == 1) msg_send_packet(pnum, p, sizeof(*p)); else { if (pnum != myplr) SetMultiQuest(p->q, p->qstate, p->qlog, p->qvar1); sgbDeltaChanged = TRUE; } return sizeof(*p); } #ifdef HELLFIRE static DWORD On_ENDREFLECT(TCmd *pCmd, int pnum) { if (gbBufferMsgs != 1 && pnum != myplr && currlevel == plr[pnum].plrlevel) { for (int i = 0; i < nummissiles; i++) { int mi = missileactive[i]; if (missile[mi]._mitype == MIS_REFLECT && missile[mi]._misource == pnum) { ClearMissileSpot(mi); DeleteMissile(mi, i); } } } return sizeof(*pCmd); } #endif static DWORD On_ENDSHIELD(TCmd *pCmd, int pnum) { if (gbBufferMsgs != 1 && pnum != myplr && currlevel == plr[pnum].plrlevel) { for (int i = 0; i < nummissiles; i++) { int mi = missileactive[i]; if (missile[mi]._mitype == MIS_MANASHIELD && missile[mi]._misource == pnum) { ClearMissileSpot(mi); DeleteMissile(mi, i); } } } return sizeof(*pCmd); } static DWORD On_CHEAT_EXPERIENCE(TCmd *pCmd, int pnum) { #ifdef _DEBUG if (gbBufferMsgs == 1) msg_send_packet(pnum, pCmd, sizeof(*pCmd)); else if (plr[pnum]._pLevel < MAXCHARLEVEL - 1) { plr[pnum]._pExperience = plr[pnum]._pNextExper; NextPlrLevel(pnum); } #endif return sizeof(*pCmd); } static DWORD On_CHEAT_SPELL_LEVEL(TCmd *pCmd, int pnum) { #ifdef _DEBUG if (gbBufferMsgs == 1) msg_send_packet(pnum, pCmd, sizeof(*pCmd)); else plr[pnum]._pSplLvl[plr[pnum]._pRSpell]++; #endif return sizeof(*pCmd); } static DWORD On_DEBUG(TCmd *pCmd, int pnum) { return sizeof(*pCmd); } #ifndef HELLFIRE static DWORD On_NOVA(TCmd *pCmd, int pnum) { TCmdLoc *p = (TCmdLoc *)pCmd; if (gbBufferMsgs != 1 && currlevel == plr[pnum].plrlevel && pnum != myplr) { ClrPlrPath(pnum); plr[pnum]._pSpell = SPL_NOVA; plr[pnum]._pSplType = RSPLTYPE_INVALID; plr[pnum]._pSplFrom = 3; plr[pnum].destAction = ACTION_SPELL; plr[pnum].destParam1 = p->x; plr[pnum].destParam2 = p->y; } return sizeof(*p); } static DWORD On_SETSHIELD(TCmd *pCmd, int pnum) { if (gbBufferMsgs != 1) plr[pnum].pManaShield = TRUE; return sizeof(*pCmd); } static DWORD On_REMSHIELD(TCmd *pCmd, int pnum) { if (gbBufferMsgs != 1) plr[pnum].pManaShield = FALSE; return sizeof(*pCmd); } #else static DWORD On_REFLECT(TCmd *pCmd, int pnum) { if (gbBufferMsgs != 1 && pnum != myplr && currlevel == plr[pnum].plrlevel) { for (int i = 0; i < nummissiles; i++) { int mx = missileactive[i]; if (missile[mx]._mitype == MIS_REFLECT && missile[mx]._misource == pnum) { ClearMissileSpot(mx); DeleteMissile(mx, i); } } } return sizeof(*pCmd); } static DWORD On_NAKRUL(TCmd *pCmd, int pnum) { if (gbBufferMsgs != 1) { OperateNakrulLever(); IsUberRoomOpened = 1; quests[Q_NAKRUL]._qactive = QUEST_DONE; monster_some_crypt(); } return sizeof(*pCmd); } static DWORD On_OPENHIVE(TCmd *pCmd, int pnum) { TCmdLocParam2 *p = (TCmdLocParam2 *)pCmd; if (gbBufferMsgs != 1) { AddMissile(p->x, p->y, p->wParam1, p->wParam2, 0, MIS_HIVEEXP2, TARGET_MONSTERS, pnum, 0, 0); TownOpenHive(); } return sizeof(*p); } static DWORD On_OPENCRYPT(TCmd *pCmd, int pnum) { if (gbBufferMsgs != 1) { TownOpenGrave(); InitTownTriggers(); if (currlevel == 0) PlaySFX(IS_SARC); } return sizeof(*pCmd); } #endif DWORD ParseCmd(int pnum, TCmd *pCmd) { sbLastCmd = pCmd->bCmd; if (sgwPackPlrOffsetTbl[pnum] != 0 && sbLastCmd != CMD_ACK_PLRINFO && sbLastCmd != CMD_SEND_PLRINFO) return 0; switch (pCmd->bCmd) { case CMD_SYNCDATA: return On_SYNCDATA(pCmd, pnum); case CMD_WALKXY: return On_WALKXY(pCmd, pnum); case CMD_ADDSTR: return On_ADDSTR(pCmd, pnum); case CMD_ADDDEX: return On_ADDDEX(pCmd, pnum); case CMD_ADDMAG: return On_ADDMAG(pCmd, pnum); case CMD_ADDVIT: return On_ADDVIT(pCmd, pnum); case CMD_SBSPELL: return On_SBSPELL(pCmd, pnum); case CMD_GOTOGETITEM: return On_GOTOGETITEM(pCmd, pnum); case CMD_REQUESTGITEM: return On_REQUESTGITEM(pCmd, pnum); case CMD_GETITEM: return On_GETITEM(pCmd, pnum); case CMD_GOTOAGETITEM: return On_GOTOAGETITEM(pCmd, pnum); case CMD_REQUESTAGITEM: return On_REQUESTAGITEM(pCmd, pnum); case CMD_AGETITEM: return On_AGETITEM(pCmd, pnum); case CMD_ITEMEXTRA: return On_ITEMEXTRA(pCmd, pnum); case CMD_PUTITEM: return On_PUTITEM(pCmd, pnum); case CMD_SYNCPUTITEM: return On_SYNCPUTITEM(pCmd, pnum); case CMD_RESPAWNITEM: return On_RESPAWNITEM(pCmd, pnum); case CMD_ATTACKXY: return On_ATTACKXY(pCmd, pnum); case CMD_SATTACKXY: return On_SATTACKXY(pCmd, pnum); case CMD_RATTACKXY: return On_RATTACKXY(pCmd, pnum); case CMD_SPELLXYD: return On_SPELLXYD(pCmd, pnum); case CMD_SPELLXY: return On_SPELLXY(pCmd, pnum); case CMD_TSPELLXY: return On_TSPELLXY(pCmd, pnum); case CMD_OPOBJXY: return On_OPOBJXY(pCmd, pnum); case CMD_DISARMXY: return On_DISARMXY(pCmd, pnum); case CMD_OPOBJT: return On_OPOBJT(pCmd, pnum); case CMD_ATTACKID: return On_ATTACKID(pCmd, pnum); case CMD_ATTACKPID: return On_ATTACKPID(pCmd, pnum); case CMD_RATTACKID: return On_RATTACKID(pCmd, pnum); case CMD_RATTACKPID: return On_RATTACKPID(pCmd, pnum); case CMD_SPELLID: return On_SPELLID(pCmd, pnum); case CMD_SPELLPID: return On_SPELLPID(pCmd, pnum); case CMD_TSPELLID: return On_TSPELLID(pCmd, pnum); case CMD_TSPELLPID: return On_TSPELLPID(pCmd, pnum); case CMD_KNOCKBACK: return On_KNOCKBACK(pCmd, pnum); case CMD_RESURRECT: return On_RESURRECT(pCmd, pnum); case CMD_HEALOTHER: return On_HEALOTHER(pCmd, pnum); case CMD_TALKXY: return On_TALKXY(pCmd, pnum); case CMD_DEBUG: return On_DEBUG(pCmd, pnum); case CMD_NEWLVL: return On_NEWLVL(pCmd, pnum); case CMD_WARP: return On_WARP(pCmd, pnum); case CMD_MONSTDEATH: return On_MONSTDEATH(pCmd, pnum); case CMD_KILLGOLEM: return On_KILLGOLEM(pCmd, pnum); case CMD_AWAKEGOLEM: return On_AWAKEGOLEM(pCmd, pnum); case CMD_MONSTDAMAGE: return On_MONSTDAMAGE(pCmd, pnum); case CMD_PLRDEAD: return On_PLRDEAD(pCmd, pnum); case CMD_PLRDAMAGE: return On_PLRDAMAGE(pCmd, pnum); case CMD_OPENDOOR: return On_OPENDOOR(pCmd, pnum); case CMD_CLOSEDOOR: return On_CLOSEDOOR(pCmd, pnum); case CMD_OPERATEOBJ: return On_OPERATEOBJ(pCmd, pnum); case CMD_PLROPOBJ: return On_PLROPOBJ(pCmd, pnum); case CMD_BREAKOBJ: return On_BREAKOBJ(pCmd, pnum); case CMD_CHANGEPLRITEMS: return On_CHANGEPLRITEMS(pCmd, pnum); case CMD_DELPLRITEMS: return On_DELPLRITEMS(pCmd, pnum); case CMD_PLRLEVEL: return On_PLRLEVEL(pCmd, pnum); case CMD_DROPITEM: return On_DROPITEM(pCmd, pnum); case CMD_ACK_PLRINFO: return On_ACK_PLRINFO(pCmd, pnum); case CMD_SEND_PLRINFO: return On_SEND_PLRINFO(pCmd, pnum); case CMD_PLAYER_JOINLEVEL: return On_PLAYER_JOINLEVEL(pCmd, pnum); case CMD_ACTIVATEPORTAL: return On_ACTIVATEPORTAL(pCmd, pnum); case CMD_DEACTIVATEPORTAL: return On_DEACTIVATEPORTAL(pCmd, pnum); case CMD_RETOWN: return On_RETOWN(pCmd, pnum); case CMD_SETSTR: return On_SETSTR(pCmd, pnum); case CMD_SETMAG: return On_SETMAG(pCmd, pnum); case CMD_SETDEX: return On_SETDEX(pCmd, pnum); case CMD_SETVIT: return On_SETVIT(pCmd, pnum); case CMD_STRING: return On_STRING(pCmd, pnum); case CMD_SYNCQUEST: return On_SYNCQUEST(pCmd, pnum); case CMD_ENDSHIELD: return On_ENDSHIELD(pCmd, pnum); case CMD_CHEAT_EXPERIENCE: return On_CHEAT_EXPERIENCE(pCmd, pnum); case CMD_CHEAT_SPELL_LEVEL: return On_CHEAT_SPELL_LEVEL(pCmd, pnum); #ifndef HELLFIRE case CMD_NOVA: return On_NOVA(pCmd, pnum); case CMD_SETSHIELD: return On_SETSHIELD(pCmd, pnum); case CMD_REMSHIELD: return On_REMSHIELD(pCmd, pnum); #else case CMD_REFLECT: return On_REFLECT(pCmd, pnum); case CMD_NAKRUL: return On_NAKRUL(pCmd, pnum); case CMD_OPENHIVE: return On_OPENHIVE(pCmd, pnum); case CMD_OPENCRYPT: return On_OPENCRYPT(pCmd, pnum); #endif } if (pCmd->bCmd < CMD_DLEVEL_0 || pCmd->bCmd > CMD_DLEVEL_END) { SNetDropPlayer(pnum, LEAVE_DROP); return 0; } return On_DLEVEL(pnum, pCmd); } ================================================ FILE: Source/msg.h ================================================ /** * @file msg.h * * Interface of function for sending and reciving network messages. */ #ifndef __MSG_H__ #define __MSG_H__ extern BOOL deltaload; extern BYTE gbBufferMsgs; extern int dwRecCount; void msg_send_drop_pkt(int pnum, int reason); BOOL msg_wait_resync(); void run_delta_info(); void DeltaExportData(int pnum); void delta_init(); void delta_kill_monster(int mi, BYTE x, BYTE y, BYTE bLevel); void delta_monster_hp(int mi, int hp, BYTE bLevel); void delta_sync_monster(const TSyncMonster *pSync, BYTE bLevel); BOOL delta_portal_inited(int i); BOOL delta_quest_inited(int i); void DeltaAddItem(int ii); void DeltaSaveLevel(); void DeltaLoadLevel(); void NetSendCmd(BOOL bHiPri, BYTE bCmd); void NetSendCmdGolem(BYTE mx, BYTE my, BYTE dir, BYTE menemy, int hp, BYTE cl); void NetSendCmdLoc(BOOL bHiPri, BYTE bCmd, BYTE x, BYTE y); void NetSendCmdLocParam1(BOOL bHiPri, BYTE bCmd, BYTE x, BYTE y, WORD wParam1); void NetSendCmdLocParam2(BOOL bHiPri, BYTE bCmd, BYTE x, BYTE y, WORD wParam1, WORD wParam2); void NetSendCmdLocParam3(BOOL bHiPri, BYTE bCmd, BYTE x, BYTE y, WORD wParam1, WORD wParam2, WORD wParam3); void NetSendCmdParam1(BOOL bHiPri, BYTE bCmd, WORD wParam1); void NetSendCmdParam2(BOOL bHiPri, BYTE bCmd, WORD wParam1, WORD wParam2); void NetSendCmdParam3(BOOL bHiPri, BYTE bCmd, WORD wParam1, WORD wParam2, WORD wParam3); void NetSendCmdQuest(BOOL bHiPri, BYTE q); void NetSendCmdGItem(BOOL bHiPri, BYTE bCmd, BYTE mast, BYTE pnum, BYTE ii); void NetSendCmdPItem(BOOL bHiPri, BYTE bCmd, BYTE x, BYTE y); void NetSendCmdChItem(BOOL bHiPri, BYTE bLoc); void NetSendCmdDelItem(BOOL bHiPri, BYTE bLoc); void NetSendCmdDItem(BOOL bHiPri, int ii); void NetSendCmdDamage(BOOL bHiPri, BYTE bPlr, DWORD dwDam); #ifdef HELLFIRE void NetSendCmdMonDmg(BOOL bHiPri, WORD bMon, DWORD dwDam); #endif void NetSendCmdString(int pmask, const char *pszStr); void delta_close_portal(int pnum); DWORD ParseCmd(int pnum, TCmd *pCmd); #endif /* __MSG_H__ */ ================================================ FILE: Source/msgcmd.cpp ================================================ /** * @file msgcmd.cpp * * Functions for sending commands to Battle.net. * * See http://classic.battle.net/info/commands.shtml for a list of commands. */ #ifndef HELLFIRE #include // for placement new #include // for offsetof #include // for typeid #include "all.h" #include "list.h" #define COMMAND_LEN 128 // static float msgcmd_init_cpp_value = 0x7F800000; struct EXTERNMESSAGE { LIST_LINK(EXTERNMESSAGE) m_Link; char command[COMMAND_LEN]; void *operator new(size_t n, DWORD extralen, int flags) { return SMemAlloc(n + extralen, (char *)OBJECT_NAME(EXTERNMESSAGE), SLOG_OBJECT, flags | (1 << 3)); } void operator delete(void *address, DWORD extralen, int flags) { } void operator delete(void *address) { } void *Delete(DWORD flags); }; void *EXTERNMESSAGE::Delete(DWORD flags) { // BUGFIX: this is already called by m_Link's destructor m_Link.Unlink(); this->~EXTERNMESSAGE(); if ((flags & 0x1) && this) { SMemFree(this, "delete", SLOG_FUNCTION, 0); } return this; } static TList sgChat_Cmd; void msgcmd_cmd_cleanup() { sgChat_Cmd.DeleteAll(); } void msgcmd_send_chat() { DWORD tick; struct EXTERNMESSAGE *msg = sgChat_Cmd.Head(); if (msg) { static DWORD sgdwMsgCmdTimer; tick = GetTickCount(); if (tick - sgdwMsgCmdTimer >= 2000) { sgdwMsgCmdTimer = tick; SNetSendServerChatCommand(msg->command); sgChat_Cmd.Remove(msg); } } } BOOL msgcmd_add_server_cmd_W(const char *chat_message) { if (chat_message[0] != '/') return FALSE; msgcmd_add_server_cmd(chat_message); return TRUE; } void msgcmd_add_server_cmd(const char *command) { size_t len = strlen(command); if (len && ++len <= COMMAND_LEN) { struct EXTERNMESSAGE *msg = sgChat_Cmd.Create(); memcpy(msg->command, command, len); } } #endif ================================================ FILE: Source/msgcmd.h ================================================ /** * @file msgcmd.h * * Interface for sending commands to Battle.net. * * See http://classic.battle.net/info/commands.shtml for a list of commands. */ #ifndef __MSGCMD_H__ #define __MSGCMD_H__ void msgcmd_cmd_cleanup(); void msgcmd_send_chat(); BOOL msgcmd_add_server_cmd_W(const char *chat_message); void msgcmd_add_server_cmd(const char *command); #endif /* __MSGCMD_H__ */ ================================================ FILE: Source/multi.cpp ================================================ /** * @file multi.cpp * * Implementation of functions for keeping multiplaye games in sync. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" #include "../DiabloUI/diabloui.h" BOOLEAN gbSomebodyWonGameKludge; #ifdef _DEBUG DWORD gdwHistTicks; #endif TBuffer sgHiPriBuf; char szPlayerDescript[128]; WORD sgwPackPlrOffsetTbl[MAX_PLRS]; PkPlayerStruct netplr[MAX_PLRS]; BOOLEAN sgbPlayerTurnBitTbl[MAX_PLRS]; BOOLEAN sgbPlayerLeftGameTbl[MAX_PLRS]; int sgbSentThisCycle; BOOL gbShouldValidatePackage; BYTE gbActivePlayers; BOOLEAN gbGameDestroyed; BOOLEAN sgbSendDeltaTbl[MAX_PLRS]; _gamedata sgGameInitInfo; BOOLEAN gbSelectProvider; int sglTimeoutStart; int sgdwPlayerLeftReasonTbl[MAX_PLRS]; TBuffer sgLoPriBuf; DWORD sgdwGameLoops; /** * Specifies the maximum number of players in a game, where 1 * represents a single player game and 4 represents a multi player game. */ BYTE gbMaxPlayers; BOOLEAN sgbTimeout; char szPlayerName[128]; BYTE gbDeltaSender; BOOL sgbNetInited; int player_state[MAX_PLRS]; /** * Contains the set of supported event types supported by the multiplayer * event handler. */ const int event_types[3] = { EVENT_TYPE_PLAYER_LEAVE_GAME, EVENT_TYPE_PLAYER_CREATE_GAME, EVENT_TYPE_PLAYER_MESSAGE }; #ifdef _DEBUG void __cdecl dumphist(const char *pszFmt, ...) { static FILE *sgpHistFile = NULL; DWORD dwTicks; va_list va; va_start(va, pszFmt); if (sgpHistFile == NULL) { sgpHistFile = fopen("c:\\dumphist.txt", "wb"); if (sgpHistFile == NULL) { return; } } dwTicks = GetTickCount(); fprintf(sgpHistFile, "%4u.%02u ", (dwTicks - gdwHistTicks) / 1000, (dwTicks - gdwHistTicks) % 1000 / 10); vfprintf(sgpHistFile, pszFmt, va); fprintf( sgpHistFile, "\r\n (%d,%d)(%d,%d)(%d,%d)(%d,%d)\r\n", plr[0].plractive, player_state[0], plr[1].plractive, player_state[1], plr[2].plractive, player_state[2], plr[3].plractive, player_state[3]); fflush(sgpHistFile); } #endif static void buffer_init(TBuffer *pBuf) { pBuf->dwNextWriteOffset = 0; pBuf->bData[0] = 0; } // Microsoft VisualC 2-11/net runtime static int multi_check_pkt_valid(TBuffer *pBuf) { return pBuf->dwNextWriteOffset == 0; } static void multi_copy_packet(TBuffer *buf, void *packet, BYTE size) { BYTE *p; if (buf->dwNextWriteOffset + size + 2 > 0x1000) { return; } p = &buf->bData[buf->dwNextWriteOffset]; buf->dwNextWriteOffset += size + 1; *p = size; p++; memcpy(p, packet, size); p[size] = 0; } static BYTE *multi_recv_packet(TBuffer *pBuf, BYTE *body, int *size) { BYTE *src_ptr; size_t chunk_size; if (pBuf->dwNextWriteOffset != 0) { src_ptr = pBuf->bData; while (TRUE) { if (*src_ptr == 0) break; chunk_size = *src_ptr; if (chunk_size > *size) break; src_ptr++; memcpy(body, src_ptr, chunk_size); body += chunk_size; src_ptr += chunk_size; *size -= chunk_size; } memcpy(pBuf->bData, src_ptr, (pBuf->bData - src_ptr) + pBuf->dwNextWriteOffset + 1); pBuf->dwNextWriteOffset += (pBuf->bData - src_ptr); return body; } return body; } static void NetRecvPlrData(TPkt *pkt) { pkt->hdr.wCheck = 'ip'; pkt->hdr.px = plr[myplr]._px; pkt->hdr.py = plr[myplr]._py; 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 multi_msg_add(BYTE *pbMsg, BYTE bLen) { if (pbMsg && bLen) { tmsg_add(pbMsg, bLen); } } static void multi_send_packet(void *packet, BYTE dwSize) { TPkt pkt; NetRecvPlrData(&pkt); pkt.hdr.wLen = dwSize + sizeof(pkt.hdr); memcpy(pkt.body, packet, dwSize); if (!SNetSendMessage(myplr, &pkt.hdr, pkt.hdr.wLen)) nthread_terminate_game("SNetSendMessage0"); } void NetSendLoPri(BYTE *pbMsg, BYTE bLen) { if (pbMsg && bLen) { multi_copy_packet(&sgLoPriBuf, pbMsg, bLen); multi_send_packet(pbMsg, bLen); } } void NetSendHiPri(BYTE *pbMsg, BYTE bLen) { BYTE *hipri_body; BYTE *lowpri_body; DWORD len; TPkt pkt; int size; if (pbMsg && bLen) { multi_copy_packet(&sgHiPriBuf, pbMsg, bLen); multi_send_packet(pbMsg, bLen); } if (!gbShouldValidatePackage) { gbShouldValidatePackage = TRUE; NetRecvPlrData(&pkt); size = gdwNormalMsgSize - sizeof(TPktHdr); hipri_body = multi_recv_packet(&sgHiPriBuf, pkt.body, &size); lowpri_body = multi_recv_packet(&sgLoPriBuf, hipri_body, &size); size = sync_all_monsters(lowpri_body, size); len = gdwNormalMsgSize - size; pkt.hdr.wLen = len; if (!SNetSendMessage(-2, &pkt.hdr, len)) nthread_terminate_game("SNetSendMessage"); } } void multi_send_msg_packet(int pmask, BYTE *src, BYTE len) { DWORD v, p, t; TPkt pkt; NetRecvPlrData(&pkt); t = len + sizeof(pkt.hdr); pkt.hdr.wLen = t; memcpy(pkt.body, src, len); for (v = 1, p = 0; p < MAX_PLRS; p++, v <<= 1) { if (v & pmask) { if (!SNetSendMessage(p, &pkt.hdr, t) && DERROR() != STORM_ERROR_INVALID_PLAYER) { nthread_terminate_game("SNetSendMessage"); return; } } } } static void multi_mon_seeds() { int i; DWORD l; sgdwGameLoops++; l = _rotr(sgdwGameLoops, 8); // BUGFIX: the monster AI seed is updated each logic tick for all monsters, even dead or non-existent ones. for (i = 0; i < MAXMONSTERS; i++) monster[i]._mAISeed = l + i; } static void multi_handle_turn_upper_bit(int pnum) { int i; for (i = 0; i < MAX_PLRS; i++) { if (player_state[i] & PS_CONNECTED && i != pnum) break; } if (myplr == i) { sgbSendDeltaTbl[pnum] = TRUE; } else if (myplr == pnum) { gbDeltaSender = i; } } static void multi_parse_turn(int pnum, int turn) { DWORD absTurns; if (turn >> 31) multi_handle_turn_upper_bit(pnum); absTurns = turn & 0x7FFFFFFF; if (sgbSentThisCycle < gdwTurnsInTransit + absTurns) { if (absTurns >= 0x7FFFFFFF) absTurns &= 0xFFFF; sgbSentThisCycle = absTurns + gdwTurnsInTransit; sgdwGameLoops = 4 * absTurns * sgbNetUpdateRate; } } void multi_msg_countdown() { int i; for (i = 0; i < MAX_PLRS; i++) { if (player_state[i] & PS_TURN_ARRIVED) { if (gdwMsgLenTbl[i] == 4) multi_parse_turn(i, *(DWORD *)glpMsgTbl[i]); } } } static void multi_player_left_msg(int pnum, int left) { const char *pszFmt; if (plr[pnum].plractive) { RemovePlrFromMap(pnum); RemovePortalMissile(pnum); DeactivatePortal(pnum); delta_close_portal(pnum); RemovePlrMissiles(pnum); if (left) { pszFmt = "Player '%s' just left the game"; switch (sgdwPlayerLeftReasonTbl[pnum]) { case LEAVE_ENDING: pszFmt = "Player '%s' killed Diablo and left the game!"; gbSomebodyWonGameKludge = TRUE; break; case LEAVE_DROP: pszFmt = "Player '%s' dropped due to timeout"; break; } EventPlrMsg(pszFmt, plr[pnum]._pName); } plr[pnum].plractive = FALSE; plr[pnum]._pName[0] = '\0'; gbActivePlayers--; } } static void multi_clear_left_tbl() { int i; for (i = 0; i < MAX_PLRS; i++) { if (sgbPlayerLeftGameTbl[i]) { if (gbBufferMsgs == 1) msg_send_drop_pkt(i, sgdwPlayerLeftReasonTbl[i]); else multi_player_left_msg(i, 1); sgbPlayerLeftGameTbl[i] = FALSE; sgdwPlayerLeftReasonTbl[i] = 0; } } } void multi_player_left(int pnum, int reason) { sgbPlayerLeftGameTbl[pnum] = TRUE; sgdwPlayerLeftReasonTbl[pnum] = reason; multi_clear_left_tbl(); } void multi_net_ping() { sgbTimeout = TRUE; sglTimeoutStart = GetTickCount(); } static void multi_check_drop_player() { int i; for (i = 0; i < MAX_PLRS; i++) { if (!(player_state[i] & PS_ACTIVE) && player_state[i] & PS_CONNECTED) { SNetDropPlayer(i, LEAVE_DROP); } } } static void multi_begin_timeout() { int i, nTicks, nState, nLowestActive, nLowestPlayer; BYTE bGroupPlayers, bGroupCount; if (!sgbTimeout) { return; } #ifdef _DEBUG if (debug_mode_key_i) { return; } #endif nTicks = GetTickCount() - sglTimeoutStart; if (nTicks > 20000) { gbRunGame = FALSE; return; } if (nTicks < 10000) { return; } nLowestActive = -1; nLowestPlayer = -1; bGroupPlayers = 0; bGroupCount = 0; for (i = 0; i < MAX_PLRS; i++) { nState = player_state[i]; if (nState & PS_CONNECTED) { if (nLowestPlayer == -1) { nLowestPlayer = i; } if (nState & PS_ACTIVE) { bGroupPlayers++; if (nLowestActive == -1) { nLowestActive = i; } } else { bGroupCount++; } } } /// ASSERT: assert(bGroupPlayers); /// ASSERT: assert(nLowestActive != -1); /// ASSERT: assert(nLowestPlayer != -1); #ifdef _DEBUG dumphist( "(%d) grp:%d ngrp:%d lowp:%d lowa:%d", myplr, bGroupPlayers, bGroupCount, nLowestPlayer, nLowestActive); #endif if (bGroupPlayers < bGroupCount) { gbGameDestroyed = TRUE; } else if (bGroupPlayers == bGroupCount) { if (nLowestPlayer != nLowestActive) { gbGameDestroyed = TRUE; } else if (nLowestActive == myplr) { multi_check_drop_player(); } } else if (nLowestActive == myplr) { multi_check_drop_player(); } } /** * @return Always true for singleplayer */ int multi_handle_delta() { int i; BOOL received; if (gbGameDestroyed) { gbRunGame = FALSE; return FALSE; } for (i = 0; i < MAX_PLRS; i++) { if (sgbSendDeltaTbl[i]) { sgbSendDeltaTbl[i] = FALSE; DeltaExportData(i); } } sgbSentThisCycle = nthread_send_and_recv_turn(sgbSentThisCycle, 1); if (!nthread_recv_turns(&received)) { multi_begin_timeout(); return FALSE; } sgbTimeout = FALSE; if (received) { if (!gbShouldValidatePackage) { NetSendHiPri(0, 0); gbShouldValidatePackage = FALSE; } else { gbShouldValidatePackage = FALSE; if (!multi_check_pkt_valid(&sgHiPriBuf)) NetSendHiPri(0, 0); } } multi_mon_seeds(); return TRUE; } static void multi_handle_all_packets(int pnum, BYTE *pData, int nSize) { int nLen; while (nSize != 0) { nLen = ParseCmd(pnum, (TCmd *)pData); if (nLen == 0) { break; } pData += nLen; nSize -= nLen; } } static void multi_process_tmsgs() { int cnt; TPkt pkt; while (cnt = tmsg_get((BYTE *)&pkt, 512)) { multi_handle_all_packets(myplr, (BYTE *)&pkt, cnt); } } void multi_process_network_packets() { int dx, dy; TPktHdr *pkt; DWORD dwMsgSize; DWORD dwID; BOOL cond; char *data; multi_clear_left_tbl(); multi_process_tmsgs(); while (SNetReceiveMessage((int *)&dwID, &data, (int *)&dwMsgSize)) { dwRecCount++; multi_clear_left_tbl(); pkt = (TPktHdr *)data; if (dwMsgSize < sizeof(TPktHdr)) continue; if (dwID >= MAX_PLRS) continue; if (pkt->wCheck != 'ip') continue; if (pkt->wLen != dwMsgSize) continue; plr[dwID]._pownerx = pkt->px; plr[dwID]._pownery = pkt->py; if (dwID != myplr) { // ASSERT: gbBufferMsgs != BUFFER_PROCESS (2) plr[dwID]._pHitPoints = pkt->php; plr[dwID]._pMaxHP = pkt->pmhp; cond = gbBufferMsgs == 1; plr[dwID]._pBaseStr = pkt->bstr; plr[dwID]._pBaseMag = pkt->bmag; plr[dwID]._pBaseDex = pkt->bdex; if (!cond && plr[dwID].plractive && plr[dwID]._pHitPoints != 0) { if (currlevel == plr[dwID].plrlevel && !plr[dwID]._pLvlChanging) { dx = abs(plr[dwID]._px - pkt->px); dy = abs(plr[dwID]._py - pkt->py); if ((dx > 3 || dy > 3) && dPlayer[pkt->px][pkt->py] == 0) { FixPlrWalkTags(dwID); plr[dwID]._poldx = plr[dwID]._px; plr[dwID]._poldy = plr[dwID]._py; FixPlrWalkTags(dwID); plr[dwID]._px = pkt->px; plr[dwID]._py = pkt->py; plr[dwID]._pfutx = pkt->px; plr[dwID]._pfuty = pkt->py; dPlayer[plr[dwID]._px][plr[dwID]._py] = dwID + 1; } dx = abs(plr[dwID]._pfutx - plr[dwID]._px); dy = abs(plr[dwID]._pfuty - plr[dwID]._py); if (dx > 1 || dy > 1) { plr[dwID]._pfutx = plr[dwID]._px; plr[dwID]._pfuty = plr[dwID]._py; } MakePlrPath(dwID, pkt->targx, pkt->targy, TRUE); } else { plr[dwID]._px = pkt->px; plr[dwID]._py = pkt->py; plr[dwID]._pfutx = pkt->px; plr[dwID]._pfuty = pkt->py; plr[dwID]._ptargx = pkt->targx; plr[dwID]._ptargy = pkt->targy; } } } multi_handle_all_packets(dwID, (BYTE *)(pkt + 1), dwMsgSize - sizeof(TPktHdr)); } if (DERROR() != STORM_ERROR_NO_MESSAGES_WAITING) nthread_terminate_game("SNetReceiveMsg"); } void multi_send_zero_packet(int pnum, BYTE bCmd, BYTE *pbSrc, DWORD dwLen) { DWORD dwOffset, dwBody, dwMsg; TPkt pkt; TCmdPlrInfoHdr *p; /// ASSERT: assert(pnum != myplr); /// ASSERT: assert(pbSrc); /// ASSERT: assert(dwLen <= 0x0ffff); dwOffset = 0; while (dwLen != 0) { pkt.hdr.wCheck = 'ip'; 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; p = (TCmdPlrInfoHdr *)pkt.body; p->bCmd = bCmd; p->wOffset = dwOffset; dwBody = gdwLargestMsgSize - sizeof(pkt.hdr) - sizeof(*p); if (dwLen < dwBody) { dwBody = dwLen; } /// ASSERT: assert(dwBody <= 0x0ffff); p->wBytes = dwBody; memcpy(&pkt.body[sizeof(*p)], pbSrc, p->wBytes); dwMsg = sizeof(pkt.hdr); dwMsg += sizeof(*p); dwMsg += p->wBytes; pkt.hdr.wLen = dwMsg; if (!SNetSendMessage(pnum, &pkt, dwMsg)) { nthread_terminate_game("SNetSendMessage2"); return; } #if 0 if((DWORD)pnum >= MAX_PLRS) { if(myplr != 0) { debug_plr_tbl[0]++; } if(myplr != 1) { debug_plr_tbl[1]++; } if(myplr != 2) { debug_plr_tbl[2]++; } if(myplr != 3) { debug_plr_tbl[3]++; } } else { debug_plr_tbl[pnum]++; } #endif pbSrc += p->wBytes; dwLen -= p->wBytes; dwOffset += p->wBytes; } } static void multi_send_pinfo(int pnum, char cmd) { PkPlayerStruct pkplr; #ifdef HELLFIRE PackPlayer(&pkplr, myplr); #else PackPlayer(&pkplr, myplr, TRUE); #endif dthread_send_delta(pnum, cmd, &pkplr, sizeof(pkplr)); } static int InitLevelType(int l) { if (l == 0) return DTYPE_TOWN; if (l >= 1 && l <= 4) return DTYPE_CATHEDRAL; if (l >= 5 && l <= 8) return DTYPE_CATACOMBS; if (l >= 9 && l <= 12) return DTYPE_CAVES; #ifdef HELLFIRE if (l >= 13 && l <= 16) return DTYPE_HELL; if (l >= 21 && l <= 24) return DTYPE_CATHEDRAL; // Crypt if (l >= 17 && l <= 20) return DTYPE_CAVES; // Hive return DTYPE_CATHEDRAL; #else return DTYPE_HELL; #endif } static void SetupLocalCoords() { int x, y; if (!leveldebug || gbMaxPlayers > 1) { currlevel = 0; leveltype = DTYPE_TOWN; setlevel = FALSE; } 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]._px = x; plr[myplr]._py = y; plr[myplr]._pfutx = x; plr[myplr]._pfuty = y; plr[myplr]._ptargx = x; plr[myplr]._ptargy = y; plr[myplr].plrlevel = currlevel; plr[myplr]._pLvlChanging = TRUE; plr[myplr].pLvlLoad = 0; plr[myplr]._pmode = PM_NEWLVL; plr[myplr].destAction = ACTION_NONE; } static BOOL multi_upgrade(BOOL *pfExitProgram) { BOOL result; int status; SNetPerformUpgrade((LPDWORD)&status); result = TRUE; if (status && status != 1) { if (status != 2) { if (status == -1) { DrawDlg("Network upgrade failed"); } } else { *pfExitProgram = 1; } result = FALSE; } return result; } static void __stdcall multi_handle_events(_SNETEVENT *pEvt) { DWORD LeftReason; _gamedata *gameData; switch (pEvt->eventid) { case EVENT_TYPE_PLAYER_CREATE_GAME: gameData = (_gamedata *)pEvt->data; sgGameInitInfo.dwSeed = gameData->dwSeed; sgGameInitInfo.bDiff = gameData->bDiff; sgbPlayerTurnBitTbl[pEvt->playerid] = TRUE; break; case EVENT_TYPE_PLAYER_LEAVE_GAME: sgbPlayerLeftGameTbl[pEvt->playerid] = TRUE; sgbPlayerTurnBitTbl[pEvt->playerid] = FALSE; LeftReason = 0; if (pEvt->data && pEvt->databytes >= sizeof(DWORD)) LeftReason = *(DWORD *)pEvt->data; sgdwPlayerLeftReasonTbl[pEvt->playerid] = LeftReason; if (LeftReason == LEAVE_ENDING) gbSomebodyWonGameKludge = TRUE; sgbSendDeltaTbl[pEvt->playerid] = FALSE; dthread_remove_player(pEvt->playerid); if (gbDeltaSender == pEvt->playerid) gbDeltaSender = MAX_PLRS; break; case EVENT_TYPE_PLAYER_MESSAGE: ErrorPlrMsg((char *)pEvt->data); break; } } static void multi_event_handler(BOOL add) { DWORD i; BOOL(STORMAPI * fn) (int, SEVTHANDLER); if (add) fn = SNetRegisterEventHandler; else fn = SNetUnregisterEventHandler; for (i = 0; i < 3; i++) { if (!fn(event_types[i], multi_handle_events) && add) { app_fatal("SNetRegisterEventHandler:\n%s", TraceLastError()); } } } void NetClose() { if (!sgbNetInited) { return; } sgbNetInited = FALSE; nthread_cleanup(); dthread_cleanup(); tmsg_cleanup(); multi_event_handler(FALSE); SNetLeaveGame(3); #ifndef HELLFIRE msgcmd_cmd_cleanup(); #endif if (gbMaxPlayers > 1) Sleep(2000); } BOOL NetInit(BOOL bSinglePlayer, BOOL *pfExitProgram) { int i; _SNETPROGRAMDATA ProgramData; _SNETUIDATA UiData; _SNETPLAYERDATA plrdata; unsigned int len; while (1) { *pfExitProgram = FALSE; #ifdef HELLFIRE pfile_create_player_description(NULL, 0); #endif SetRndSeed(0); sgGameInitInfo.dwSeed = time(NULL); sgGameInitInfo.bDiff = gnDifficulty; memset(&ProgramData, 0, sizeof(ProgramData)); ProgramData.size = sizeof(ProgramData); #ifdef SPAWN ProgramData.programname = "Diablo Shareware"; #else ProgramData.programname = PROGRAM_NAME; #endif ProgramData.programdescription = gszVersionNumber; ProgramData.programid = GAME_ID; ProgramData.versionid = GAME_VERSION; ProgramData.maxplayers = MAX_PLRS; ProgramData.initdata = &sgGameInitInfo; ProgramData.initdatabytes = sizeof(sgGameInitInfo); ProgramData.optcategorybits = 15; #ifndef HELLFIRE ProgramData.lcid = 1033; /* LANG_ENGLISH */ #endif memset(&plrdata, 0, sizeof(plrdata)); plrdata.size = sizeof(plrdata); memset(&UiData, 0, sizeof(UiData)); UiData.size = sizeof(UiData); UiData.parentwindow = SDrawGetFrameWindow(NULL); UiData.artcallback = (void (*)())UiArtCallback; UiData.createcallback = (void (*)())UiCreateGameCallback; UiData.drawdesccallback = (void (*)())UiDrawDescCallback; UiData.messageboxcallback = (void (*)())UiMessageBoxCallback; UiData.soundcallback = (void (*)())UiSoundCallback; UiData.authcallback = (void (*)())UiAuthCallback; UiData.getdatacallback = (void (*)())UiGetDataCallback; UiData.categorycallback = (void (*)())UiCategoryCallback; UiData.selectnamecallback = mainmenu_select_hero_dialog; UiData.changenamecallback = (void (*)())mainmenu_change_name; UiData.profilebitmapcallback = (void (*)())UiProfileDraw; UiData.profilecallback = (void (*)())UiProfileCallback; UiData.profilefields = UiProfileGetString(); memset(sgbPlayerTurnBitTbl, 0, sizeof(sgbPlayerTurnBitTbl)); gbGameDestroyed = FALSE; memset(sgbPlayerLeftGameTbl, 0, sizeof(sgbPlayerLeftGameTbl)); memset(sgdwPlayerLeftReasonTbl, 0, sizeof(sgdwPlayerLeftReasonTbl)); memset(sgbSendDeltaTbl, 0, sizeof(sgbSendDeltaTbl)); memset(plr, 0, sizeof(plr)); memset(sgwPackPlrOffsetTbl, 0, sizeof(sgwPackPlrOffsetTbl)); SNetSetBasePlayer(0); if (bSinglePlayer) { if (!multi_init_single(&ProgramData, &plrdata, &UiData)) return FALSE; } else { if (!multi_init_multi(&ProgramData, &plrdata, &UiData, pfExitProgram)) return FALSE; } #ifdef _DEBUG gdwHistTicks = GetTickCount(); dumphist("(%d) new game started", myplr); #endif sgbNetInited = TRUE; sgbTimeout = FALSE; delta_init(); InitPlrMsg(); buffer_init(&sgHiPriBuf); buffer_init(&sgLoPriBuf); gbShouldValidatePackage = FALSE; sync_init(); nthread_start(sgbPlayerTurnBitTbl[myplr]); dthread_start(); tmsg_start(); sgdwGameLoops = 0; sgbSentThisCycle = 0; gbDeltaSender = myplr; gbSomebodyWonGameKludge = FALSE; nthread_send_and_recv_turn(0, 0); SetupLocalCoords(); multi_send_pinfo(-2, CMD_SEND_PLRINFO); plr[myplr].plractive = TRUE; gbActivePlayers = 1; if (sgbPlayerTurnBitTbl[myplr] == FALSE || msg_wait_resync()) break; NetClose(); gbSelectProvider = FALSE; } gnDifficulty = sgGameInitInfo.bDiff; SetRndSeed(sgGameInitInfo.dwSeed); for (i = 0; i < NUMLEVELS; i++) { glSeedTbl[i] = GetRndSeed(); gnLevelTypeTbl[i] = InitLevelType(i); } if (!SNetGetGameInfo(GAMEINFO_NAME, szPlayerName, 128, &len)) nthread_terminate_game("SNetGetGameInfo1"); if (!SNetGetGameInfo(GAMEINFO_PASSWORD, szPlayerDescript, 128, &len)) nthread_terminate_game("SNetGetGameInfo2"); return TRUE; } BOOL multi_init_single(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info) { int unused; if (!SNetInitializeProvider(0, client_info, user_info, ui_info, &fileinfo)) { DERROR(); return FALSE; } unused = 0; if (!SNetCreateGame("local", "local", "local", 0, (char *)&sgGameInitInfo, sizeof(sgGameInitInfo), 1, "local", "local", &unused)) { app_fatal("SNetCreateGame1:\n%s", TraceLastError()); } myplr = 0; gbMaxPlayers = 1; return TRUE; } BOOL multi_init_multi(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, BOOL *pfExitProgram) { BOOL first; int playerId; int type; for (first = TRUE;; first = FALSE) { type = 0x00; if (gbSelectProvider) { if (!UiSelectProvider(0, client_info, user_info, ui_info, &fileinfo, &type) && (!first || DERROR() != STORM_ERROR_REQUIRES_UPGRADE || !multi_upgrade(pfExitProgram))) { return FALSE; } #ifndef HELLFIRE if (type == 'BNET') plr[0].pBattleNet = 1; #endif } multi_event_handler(TRUE); if (UiSelectGame(1, client_info, user_info, ui_info, &fileinfo, &playerId)) break; gbSelectProvider = TRUE; } if ((DWORD)playerId >= MAX_PLRS) { return FALSE; } else { myplr = playerId; gbMaxPlayers = MAX_PLRS; pfile_read_player_from_save(); #ifndef HELLFIRE if (type == 'BNET') plr[myplr].pBattleNet = 1; #endif return TRUE; } } void recv_plrinfo(int pnum, TCmdPlrInfoHdr *p, BOOL recv) { const char *szEvent; if (myplr == pnum) { return; } /// ASSERT: assert((DWORD)pnum < MAX_PLRS); if (sgwPackPlrOffsetTbl[pnum] != p->wOffset) { sgwPackPlrOffsetTbl[pnum] = 0; if (p->wOffset != 0) { return; } } if (!recv && sgwPackPlrOffsetTbl[pnum] == 0) { multi_send_pinfo(pnum, CMD_ACK_PLRINFO); } memcpy((char *)&netplr[pnum] + p->wOffset, &p[1], p->wBytes); /* todo: cast? */ sgwPackPlrOffsetTbl[pnum] += p->wBytes; if (sgwPackPlrOffsetTbl[pnum] != sizeof(*netplr)) { return; } sgwPackPlrOffsetTbl[pnum] = 0; multi_player_left_msg(pnum, 0); plr[pnum]._pGFXLoad = 0; UnPackPlayer(&netplr[pnum], pnum, TRUE); if (!recv) { #ifdef _DEBUG dumphist("(%d) received all %d plrinfo", myplr, pnum); #endif return; } plr[pnum].plractive = TRUE; gbActivePlayers++; if (sgbPlayerTurnBitTbl[pnum] != FALSE) { szEvent = "Player '%s' (level %d) just joined the game"; } else { szEvent = "Player '%s' (level %d) is already in the game"; } EventPlrMsg(szEvent, plr[pnum]._pName, plr[pnum]._pLevel); LoadPlrGFX(pnum, PFILE_STAND); SyncInitPlr(pnum); if (plr[pnum].plrlevel == currlevel) { if (plr[pnum]._pHitPoints >> 6 > 0) { StartStand(pnum, 0); } else { plr[pnum]._pgfxnum = 0; LoadPlrGFX(pnum, PFILE_DEATH); plr[pnum]._pmode = PM_DEATH; NewPlrAnim(pnum, plr[pnum]._pDAnim[DIR_S], plr[pnum]._pDFrames, 1, plr[pnum]._pDWidth); plr[pnum]._pAnimFrame = plr[pnum]._pAnimLen - 1; plr[pnum]._pVar8 = 2 * plr[pnum]._pAnimLen; dFlags[plr[pnum]._px][plr[pnum]._py] |= BFLAG_DEAD_PLAYER; } } #ifdef _DEBUG dumphist("(%d) making %d active -- recv_plrinfo", myplr, pnum); #endif } ================================================ FILE: Source/multi.h ================================================ /** * @file multi.h * * Interface of functions for keeping multiplayer games in sync. */ #ifndef __MULTI_H__ #define __MULTI_H__ extern BOOLEAN gbSomebodyWonGameKludge; extern char szPlayerDescript[128]; extern WORD sgwPackPlrOffsetTbl[MAX_PLRS]; extern BYTE gbActivePlayers; extern BOOLEAN gbGameDestroyed; extern BOOLEAN gbSelectProvider; extern BYTE gbMaxPlayers; extern char szPlayerName[128]; extern BYTE gbDeltaSender; extern int player_state[MAX_PLRS]; void multi_msg_add(BYTE *pbMsg, BYTE bLen); void NetSendLoPri(BYTE *pbMsg, BYTE bLen); void NetSendHiPri(BYTE *pbMsg, BYTE bLen); void multi_send_msg_packet(int pmask, BYTE *src, BYTE len); void multi_msg_countdown(); void multi_player_left(int pnum, int reason); void multi_net_ping(); int multi_handle_delta(); void multi_process_network_packets(); void multi_send_zero_packet(int pnum, BYTE bCmd, BYTE *pbSrc, DWORD dwLen); void NetClose(); BOOL NetInit(BOOL bSinglePlayer, BOOL *pfExitProgram); BOOL multi_init_single(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info); BOOL multi_init_multi(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, BOOL *pfExitProgram); void recv_plrinfo(int pnum, TCmdPlrInfoHdr *p, BOOL recv); #endif /* __MULTI_H__ */ ================================================ FILE: Source/nthread.cpp ================================================ /** * @file nthread.cpp * * Implementation of functions for managing game ticks. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" BYTE sgbNetUpdateRate; DWORD gdwMsgLenTbl[MAX_PLRS]; static CCritSect sgMemCrit; DWORD gdwDeltaBytesSec; BOOLEAN nthread_should_run; DWORD gdwTurnsInTransit; int glpMsgTbl[MAX_PLRS]; unsigned int glpNThreadId; char sgbSyncCountdown; int turn_upper_bit; BOOLEAN sgbTicsOutOfSync; char sgbPacketCountdown; BOOLEAN sgbThreadIsRunning; DWORD gdwLargestMsgSize; DWORD gdwNormalMsgSize; int last_tick; /* data */ static HANDLE sghThread = INVALID_HANDLE_VALUE; void nthread_terminate_game(const char *pszFcn) { DWORD sErr; sErr = DERROR(); if (sErr == STORM_ERROR_INVALID_PLAYER) { return; } else if (sErr == STORM_ERROR_GAME_TERMINATED) { gbGameDestroyed = TRUE; } else if (sErr == STORM_ERROR_NOT_IN_GAME) { gbGameDestroyed = TRUE; } else { app_fatal("%s:\n%s", pszFcn, TraceLastError()); } } DWORD nthread_send_and_recv_turn(DWORD cur_turn, int turn_delta) { DWORD new_cur_turn; int turn, turn_tmp; int curTurnsInTransit; new_cur_turn = cur_turn; if (!SNetGetTurnsInTransit(&curTurnsInTransit)) { nthread_terminate_game("SNetGetTurnsInTransit"); return 0; } while (curTurnsInTransit++ < gdwTurnsInTransit) { turn_tmp = turn_upper_bit | new_cur_turn & 0x7FFFFFFF; turn_upper_bit = 0; turn = turn_tmp; if (!SNetSendTurn((char *)&turn, sizeof(turn))) { nthread_terminate_game("SNetSendTurn"); return 0; } new_cur_turn += turn_delta; if (new_cur_turn >= 0x7FFFFFFF) new_cur_turn &= 0xFFFF; } return new_cur_turn; } BOOL nthread_recv_turns(BOOL *pfSendAsync) { *pfSendAsync = FALSE; sgbPacketCountdown--; if (sgbPacketCountdown) { last_tick += 50; return TRUE; } sgbSyncCountdown--; sgbPacketCountdown = sgbNetUpdateRate; if (sgbSyncCountdown != 0) { *pfSendAsync = TRUE; last_tick += 50; return TRUE; } if (!SNetReceiveTurns(0, MAX_PLRS, (char **)glpMsgTbl, gdwMsgLenTbl, (LPDWORD)player_state)) { if (DERROR() != STORM_ERROR_NO_MESSAGES_WAITING) nthread_terminate_game("SNetReceiveTurns"); sgbTicsOutOfSync = FALSE; sgbSyncCountdown = 1; sgbPacketCountdown = 1; return FALSE; } else { if (!sgbTicsOutOfSync) { sgbTicsOutOfSync = TRUE; last_tick = GetTickCount(); } sgbSyncCountdown = 4; multi_msg_countdown(); *pfSendAsync = TRUE; last_tick += 50; return TRUE; } } static unsigned int __stdcall nthread_handler(void *data) { int delta; BOOL received; if (nthread_should_run) { while (1) { sgMemCrit.Enter(); if (!nthread_should_run) break; nthread_send_and_recv_turn(0, 0); if (nthread_recv_turns(&received)) delta = last_tick - GetTickCount(); else delta = 50; sgMemCrit.Leave(); if (delta > 0) Sleep(delta); if (!nthread_should_run) return 0; } sgMemCrit.Leave(); } return 0; } void nthread_set_turn_upper_bit() { turn_upper_bit = 0x80000000; } void nthread_start(BOOL set_turn_upper_bit) { const char *err, *err2; DWORD largestMsgSize; _SNETCAPS caps; last_tick = GetTickCount(); sgbPacketCountdown = 1; sgbSyncCountdown = 1; sgbTicsOutOfSync = TRUE; if (set_turn_upper_bit) nthread_set_turn_upper_bit(); else turn_upper_bit = 0; caps.size = 36; if (!SNetGetProviderCaps(&caps)) { err = TraceLastError(); app_fatal("SNetGetProviderCaps:\n%s", err); } gdwTurnsInTransit = caps.defaultturnsintransit; if (!caps.defaultturnsintransit) gdwTurnsInTransit = 1; if (caps.defaultturnssec <= 20 && caps.defaultturnssec) sgbNetUpdateRate = 20 / caps.defaultturnssec; else sgbNetUpdateRate = 1; largestMsgSize = 512; if (caps.maxmessagesize < 0x200) largestMsgSize = caps.maxmessagesize; gdwDeltaBytesSec = caps.bytessec >> 2; gdwLargestMsgSize = largestMsgSize; gdwNormalMsgSize = caps.bytessec * sgbNetUpdateRate / 20; gdwNormalMsgSize *= 3; gdwNormalMsgSize >>= 2; if (caps.maxplayers > MAX_PLRS) caps.maxplayers = MAX_PLRS; gdwNormalMsgSize /= caps.maxplayers; while (gdwNormalMsgSize < 0x80) { gdwNormalMsgSize *= 2; sgbNetUpdateRate *= 2; } if (gdwNormalMsgSize > largestMsgSize) gdwNormalMsgSize = largestMsgSize; if (gbMaxPlayers > 1) { sgbThreadIsRunning = FALSE; sgMemCrit.Enter(); nthread_should_run = TRUE; sghThread = (HANDLE)_beginthreadex(NULL, 0, nthread_handler, NULL, 0, &glpNThreadId); if (sghThread == INVALID_HANDLE_VALUE) { err2 = TraceLastError(); app_fatal("nthread2:\n%s", err2); } SetThreadPriority(sghThread, THREAD_PRIORITY_HIGHEST); } } void nthread_cleanup() { nthread_should_run = FALSE; gdwTurnsInTransit = 0; gdwNormalMsgSize = 0; gdwLargestMsgSize = 0; if (sghThread != INVALID_HANDLE_VALUE && glpNThreadId != GetCurrentThreadId()) { if (!sgbThreadIsRunning) sgMemCrit.Leave(); if (WaitForSingleObject(sghThread, INFINITE) == -1) { app_fatal("nthread3:\n(%s)", TraceLastError()); } CloseHandle(sghThread); sghThread = INVALID_HANDLE_VALUE; } } void nthread_ignore_mutex(BOOL bStart) { if (sghThread != INVALID_HANDLE_VALUE) { if (bStart) sgMemCrit.Leave(); else sgMemCrit.Enter(); sgbThreadIsRunning = bStart; } } /** * @brief Checks if it's time for the logic to advance * @param unused * @return True if the engine should tick */ BOOL nthread_has_500ms_passed(BOOL unused) { DWORD currentTickCount; int ticksElapsed; currentTickCount = GetTickCount(); ticksElapsed = currentTickCount - last_tick; if (gbMaxPlayers == 1 && ticksElapsed > 500) { last_tick = currentTickCount; ticksElapsed = 0; } return ticksElapsed >= 0; } ================================================ FILE: Source/nthread.h ================================================ /** * @file nthread.h * * Interface of functions for managing game ticks. */ #ifndef __NTHREAD_H__ #define __NTHREAD_H__ extern BYTE sgbNetUpdateRate; extern DWORD gdwMsgLenTbl[MAX_PLRS]; extern DWORD gdwDeltaBytesSec; extern DWORD gdwTurnsInTransit; extern int glpMsgTbl[MAX_PLRS]; extern int turn_upper_bit; extern DWORD gdwLargestMsgSize; extern DWORD gdwNormalMsgSize; void nthread_terminate_game(const char *pszFcn); DWORD nthread_send_and_recv_turn(DWORD cur_turn, int turn_delta); BOOL nthread_recv_turns(BOOL *pfSendAsync); void nthread_set_turn_upper_bit(); void nthread_start(BOOL set_turn_upper_bit); void nthread_cleanup(); void nthread_ignore_mutex(BOOL bStart); BOOL nthread_has_500ms_passed(BOOL unused); #endif /* __NTHREAD_H__ */ ================================================ FILE: Source/objdat.cpp ================================================ /** * @file objdat.cpp * * Implementation of all object data. */ #include "all.h" /** Maps from dun_object_id to object_id. */ int ObjTypeConv[] = { 0, OBJ_LEVER, OBJ_CRUX1, OBJ_CRUX2, OBJ_CRUX3, OBJ_ANGEL, OBJ_BANNERL, OBJ_BANNERM, OBJ_BANNERR, 0, 0, 0, 0, 0, OBJ_BOOK2L, OBJ_BOOK2R, OBJ_BCROSS, 0, OBJ_CANDLE1, OBJ_CANDLE2, OBJ_CANDLEO, OBJ_CAULDRON, 0, 0, 0, 0, 0, 0, 0, 0, OBJ_FLAMEHOLE, 0, 0, 0, 0, 0, OBJ_MCIRCLE1, OBJ_MCIRCLE2, OBJ_SKFIRE, OBJ_SKPILE, OBJ_SKSTICK1, OBJ_SKSTICK2, OBJ_SKSTICK3, OBJ_SKSTICK4, OBJ_SKSTICK5, 0, 0, 0, 0, 0, 0, OBJ_SWITCHSKL, 0, OBJ_TRAPL, OBJ_TRAPR, OBJ_TORTURE1, OBJ_TORTURE2, OBJ_TORTURE3, OBJ_TORTURE4, OBJ_TORTURE5, 0, 0, 0, 0, 0, OBJ_NUDEW2R, 0, 0, 0, 0, OBJ_TNUDEM1, OBJ_TNUDEM2, OBJ_TNUDEM3, OBJ_TNUDEM4, OBJ_TNUDEW1, OBJ_TNUDEW2, OBJ_TNUDEW3, OBJ_CHEST1, OBJ_CHEST1, OBJ_CHEST1, OBJ_CHEST2, OBJ_CHEST2, OBJ_CHEST2, OBJ_CHEST3, OBJ_CHEST3, OBJ_CHEST3, 0, 0, 0, 0, 0, OBJ_PEDISTAL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OBJ_ALTBOY, 0, 0, OBJ_WARARMOR, OBJ_WARWEAP, OBJ_TORCHR2, OBJ_TORCHL2, OBJ_MUSHPATCH, }; /** Contains the data related to each object ID. */ ObjDataStruct AllObjects[] = { // clang-format off // oload, ofindex, ominlvl, omaxlvl, olvltype, otheme, oquest, oAnimFlag, oAnimDelay, oAnimLen, oAnimWidth, oSolidFlag, oMissFlag, oLightFlag, oBreak, oSelFlag, oTrapFlag { 1, OFILE_L1BRAZ, 1, 4, DTYPE_CATHEDRAL, THEME_NONE, -1, 1, 1, 26, 64, TRUE, TRUE, FALSE, 0, 0, FALSE }, { 1, OFILE_L1DOORS, 1, 4, DTYPE_CATHEDRAL, THEME_NONE, -1, 0, 1, 0, 64, FALSE, FALSE, TRUE, 0, 3, TRUE }, { 1, OFILE_L1DOORS, 1, 4, DTYPE_CATHEDRAL, THEME_NONE, -1, 0, 2, 0, 64, FALSE, FALSE, TRUE, 0, 3, TRUE }, { 3, OFILE_SKULFIRE, 0, 0, 0, THEME_SKELROOM, -1, 1, 2, 11, 96, TRUE, TRUE, FALSE, 0, 0, FALSE }, { 1, OFILE_LEVER, 1, 4, DTYPE_CATHEDRAL, THEME_NONE, -1, 0, 1, 1, 96, TRUE, TRUE, TRUE, 0, 1, TRUE }, { 1, OFILE_CHEST1, 1, 16, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 1, TRUE }, { 1, OFILE_CHEST2, 1, 16, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 1, TRUE }, { 1, OFILE_CHEST3, 1, 16, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 1, TRUE }, { 2, OFILE_L1BRAZ, 0, 0, 0, THEME_NONE, -1, 0, 0, 0, 0, FALSE, FALSE, FALSE, 0, 0, FALSE }, { 3, OFILE_CANDLE2, 0, 0, 0, THEME_SHRINE, -1, 1, 2, 4, 96, TRUE, TRUE, TRUE, 0, 0, FALSE }, { 2, OFILE_L1BRAZ, 0, 0, 0, THEME_NONE, -1, 0, 0, 0, 0, FALSE, FALSE, FALSE, 0, 0, FALSE }, { 3, OFILE_BANNER, 0, 0, 0, THEME_SKELROOM, -1, 0, 2, 0, 96, TRUE, TRUE, TRUE, 0, 0, FALSE }, { 3, OFILE_BANNER, 0, 0, 0, THEME_SKELROOM, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 0, FALSE }, { 3, OFILE_BANNER, 0, 0, 0, THEME_SKELROOM, -1, 0, 3, 0, 96, TRUE, TRUE, TRUE, 0, 0, FALSE }, { 2, OFILE_SKULPILE, 1, 4, 0, THEME_NONE, -1, 0, 0, 1, 96, TRUE, TRUE, TRUE, 0, 0, FALSE }, { 2, OFILE_L1BRAZ, 0, 0, 0, THEME_NONE, -1, 0, 0, 0, 0, FALSE, FALSE, FALSE, 0, 0, FALSE }, { 2, OFILE_L1BRAZ, 0, 0, 0, THEME_NONE, -1, 0, 0, 0, 0, FALSE, FALSE, FALSE, 0, 0, FALSE }, { 2, OFILE_L1BRAZ, 0, 0, 0, THEME_NONE, -1, 0, 0, 0, 0, FALSE, FALSE, FALSE, 0, 0, FALSE }, { 2, OFILE_L1BRAZ, 0, 0, 0, THEME_NONE, -1, 0, 0, 0, 0, FALSE, FALSE, FALSE, 0, 0, FALSE }, { 2, OFILE_L1BRAZ, 0, 0, 0, THEME_NONE, -1, 0, 0, 0, 0, FALSE, FALSE, FALSE, 0, 0, FALSE }, { 2, OFILE_CRUXSK1, 0, 0, 0, THEME_NONE, -1, 0, 1, 15, 96, TRUE, FALSE, TRUE, 1, 3, FALSE }, { 2, OFILE_CRUXSK2, 0, 0, 0, THEME_NONE, -1, 0, 1, 15, 96, TRUE, FALSE, TRUE, 1, 3, FALSE }, { 2, OFILE_CRUXSK3, 0, 0, 0, THEME_NONE, -1, 0, 1, 15, 96, TRUE, FALSE, TRUE, 1, 3, FALSE }, { 1, OFILE_ROCKSTAN, 5, 5, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 0, FALSE }, { 2, OFILE_ANGEL, 0, 0, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 2, OFILE_BOOK2, 0, 0, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 2, OFILE_BURNCROS, 0, 0, 0, THEME_NONE, -1, 1, 0, 10, 160, TRUE, FALSE, FALSE, 0, 0, FALSE }, { 2, OFILE_NUDE2, 0, 0, 0, THEME_NONE, -1, 1, 3, 6, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_SWITCH4, 16, 16, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 1, TRUE }, { 1, OFILE_TNUDEM, 13, 16, 0, THEME_NONE, Q_BUTCHER, 0, 1, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TNUDEM, 13, 16, 0, THEME_TORTURE, Q_BUTCHER, 0, 2, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TNUDEM, 13, 16, 0, THEME_TORTURE, Q_BUTCHER, 0, 3, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TNUDEM, 13, 16, 0, THEME_TORTURE, Q_BUTCHER, 0, 4, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TNUDEW, 13, 16, 0, THEME_TORTURE, Q_BUTCHER, 0, 1, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TNUDEW, 13, 16, 0, THEME_TORTURE, Q_BUTCHER, 0, 2, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TNUDEW, 13, 16, 0, THEME_TORTURE, Q_BUTCHER, 0, 3, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TSOUL, 13, 16, 0, THEME_NONE, Q_BUTCHER, 0, 1, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TSOUL, 13, 16, 0, THEME_NONE, Q_BUTCHER, 0, 2, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TSOUL, 13, 16, 0, THEME_NONE, Q_BUTCHER, 0, 3, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TSOUL, 13, 16, 0, THEME_NONE, Q_BUTCHER, 0, 4, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_TSOUL, 13, 16, 0, THEME_NONE, Q_BUTCHER, 0, 5, 0, 128, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_BOOK2, 6, 6, 0, THEME_NONE, -1, 0, 4, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 1, OFILE_L2DOORS, 5, 8, DTYPE_CATACOMBS, THEME_NONE, -1, 0, 1, 0, 64, FALSE, FALSE, TRUE, 0, 3, TRUE }, { 1, OFILE_L2DOORS, 5, 8, DTYPE_CATACOMBS, THEME_NONE, -1, 0, 2, 0, 64, FALSE, FALSE, TRUE, 0, 3, TRUE }, { 1, OFILE_WTORCH4, 5, 8, DTYPE_CATACOMBS, THEME_NONE, -1, 1, 1, 9, 96, FALSE, TRUE, FALSE, 0, 0, FALSE }, { 1, OFILE_WTORCH3, 5, 8, DTYPE_CATACOMBS, THEME_NONE, -1, 1, 1, 9, 96, FALSE, TRUE, FALSE, 0, 0, FALSE }, { 1, OFILE_WTORCH1, 5, 8, DTYPE_CATACOMBS, THEME_NONE, -1, 1, 1, 9, 96, FALSE, TRUE, FALSE, 0, 0, FALSE }, { 1, OFILE_WTORCH2, 5, 8, DTYPE_CATACOMBS, THEME_NONE, -1, 1, 1, 9, 96, FALSE, TRUE, FALSE, 0, 0, FALSE }, { 1, OFILE_SARC, 1, 4, DTYPE_CATHEDRAL, THEME_NONE, -1, 0, 1, 5, 128, TRUE, TRUE, TRUE, 0, 3, TRUE }, { 2, OFILE_FLAME1, 1, 4, DTYPE_CATHEDRAL, THEME_NONE, -1, 0, 1, 20, 96, FALSE, TRUE, TRUE, 0, 0, FALSE }, { 2, OFILE_LEVER, 1, 4, DTYPE_CATHEDRAL, THEME_NONE, -1, 0, 1, 2, 96, TRUE, TRUE, TRUE, 0, 1, TRUE }, { 2, OFILE_MINIWATR, 1, 4, DTYPE_CATHEDRAL, THEME_NONE, -1, 1, 1, 10, 64, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_BOOK1, 3, 4, DTYPE_CATHEDRAL, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 1, OFILE_TRAPHOLE, 1, 16, 0, THEME_NONE, -1, 0, 1, 0, 64, FALSE, TRUE, TRUE, 0, 0, FALSE }, { 1, OFILE_TRAPHOLE, 1, 16, 0, THEME_NONE, -1, 0, 2, 0, 64, FALSE, TRUE, TRUE, 0, 0, FALSE }, { 2, OFILE_BCASE, 0, 0, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 2, OFILE_WEAPSTND, 0, 0, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 1, OFILE_BARREL, 1, 16, 0, THEME_NONE, -1, 0, 1, 9, 96, TRUE, TRUE, TRUE, 1, 3, FALSE }, { 1, OFILE_BARRELEX, 1, 16, 0, THEME_NONE, -1, 0, 1, 10, 96, TRUE, TRUE, TRUE, 1, 3, FALSE }, { 3, OFILE_LSHRINEG, 0, 0, 0, THEME_SHRINE, -1, 0, 1, 11, 128, FALSE, FALSE, TRUE, 0, 3, FALSE }, { 3, OFILE_RSHRINEG, 0, 0, 0, THEME_SHRINE, -1, 0, 1, 11, 128, FALSE, FALSE, TRUE, 0, 3, FALSE }, { 3, OFILE_BOOK2, 0, 0, 0, THEME_SKELROOM, -1, 0, 4, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 3, OFILE_BCASE, 0, 0, 0, THEME_LIBRARY, -1, 0, 3, 0, 96, FALSE, FALSE, TRUE, 0, 3, FALSE }, { 3, OFILE_BCASE, 0, 0, 0, THEME_LIBRARY, -1, 0, 4, 0, 96, FALSE, FALSE, TRUE, 0, 3, FALSE }, { 3, OFILE_BOOK2, 0, 0, 0, THEME_LIBRARY, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 3, OFILE_CANDLE2, 0, 0, 0, THEME_LIBRARY, -1, 1, 2, 4, 96, TRUE, TRUE, TRUE, 0, 0, FALSE }, { 3, OFILE_BLOODFNT, 0, 0, 0, THEME_BLOODFOUNTAIN, -1, 1, 2, 10, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 1, OFILE_DECAP, 13, 16, 0, THEME_DECAPITATED, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 1, FALSE }, { 1, OFILE_CHEST1, 1, 16, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 1, TRUE }, { 1, OFILE_CHEST2, 1, 16, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 1, TRUE }, { 1, OFILE_CHEST3, 1, 16, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 1, TRUE }, { 1, OFILE_BOOK1, 7, 7, DTYPE_CATACOMBS, THEME_NONE, Q_BLIND, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 1, OFILE_BOOK1, 5, 5, DTYPE_CATACOMBS, THEME_NONE, Q_BLOOD, 0, 4, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 1, OFILE_PEDISTL, 5, 5, DTYPE_CATACOMBS, THEME_NONE, Q_BLOOD, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 1, OFILE_L3DOORS, 9, 12, DTYPE_CAVES, THEME_NONE, -1, 0, 1, 0, 64, FALSE, FALSE, TRUE, 0, 3, TRUE }, { 1, OFILE_L3DOORS, 9, 12, DTYPE_CAVES, THEME_NONE, -1, 0, 2, 0, 64, FALSE, FALSE, TRUE, 0, 3, TRUE }, { 3, OFILE_PFOUNTN, 0, 0, 0, THEME_PURIFYINGFOUNTAIN, -1, 1, 2, 10, 128, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 3, OFILE_ARMSTAND, 0, 0, 0, THEME_ARMORSTAND, -1, 0, 1, 0, 96, TRUE, FALSE, TRUE, 0, 3, FALSE }, { 3, OFILE_ARMSTAND, 0, 0, 0, THEME_ARMORSTAND, -1, 0, 2, 0, 96, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 3, OFILE_GOATSHRN, 0, 0, 0, THEME_GOATSHRINE, -1, 1, 2, 10, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 1, OFILE_CAULDREN, 13, 16, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, FALSE, TRUE, 0, 3, FALSE }, { 3, OFILE_MFOUNTN, 0, 0, 0, THEME_MURKYFOUNTAIN, -1, 1, 2, 10, 128, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 3, OFILE_TFOUNTN, 0, 0, 0, THEME_TEARFOUNTAIN, -1, 1, 2, 4, 128, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 1, OFILE_ALTBOY, 0, 0, DTYPE_CATHEDRAL, THEME_NONE, Q_BETRAYER, 0, 1, 0, 128, TRUE, TRUE, TRUE, 0, 0, FALSE }, { 1, OFILE_MCIRL, 0, 0, DTYPE_CATHEDRAL, THEME_NONE, Q_BETRAYER, 0, 1, 0, 96, FALSE, TRUE, TRUE, 0, 0, FALSE }, { 1, OFILE_MCIRL, 0, 0, DTYPE_CATHEDRAL, THEME_NONE, Q_BETRAYER, 0, 1, 0, 96, FALSE, TRUE, TRUE, 0, 0, FALSE }, #ifdef HELLFIRE { 1, OFILE_BKSLBRNT, 1, 24, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, // BUGFIX should only be loaded on level 1-12 (crypt masks as 1-4) #else { 1, OFILE_BKSLBRNT, 4, 12, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, #endif { 1, OFILE_CANDLE2, 2, 12, 0, THEME_NONE, Q_BETRAYER, 1, 2, 4, 96, TRUE, TRUE, TRUE, 0, 0, FALSE }, { 1, OFILE_BOOK1, 13, 13, DTYPE_HELL, THEME_NONE, Q_WARLORD, 0, 4, 0, 96, TRUE, TRUE, TRUE, 0, 3, FALSE }, { 1, OFILE_ARMSTAND, 13, 13, 0, THEME_NONE, Q_WARLORD, 0, 1, 0, 96, TRUE, FALSE, TRUE, 0, 3, FALSE }, { 2, OFILE_WEAPSTND, 13, 13, 0, THEME_NONE, Q_WARLORD, 0, 1, 0, 96, TRUE, FALSE, TRUE, 0, 3, FALSE }, { 2, OFILE_BURNCROS, 0, 0, 0, THEME_BRNCROSS, -1, 1, 0, 10, 160, TRUE, FALSE, FALSE, 0, 0, FALSE }, { 2, OFILE_WEAPSTND, 0, 0, 0, THEME_WEAPONRACK, -1, 0, 1, 0, 96, TRUE, FALSE, TRUE, 0, 3, FALSE }, { 2, OFILE_WEAPSTND, 0, 0, 0, THEME_WEAPONRACK, -1, 0, 2, 0, 96, TRUE, FALSE, TRUE, 0, 0, FALSE }, { 2, OFILE_MUSHPTCH, 0, 0, 0, THEME_NONE, Q_MUSHROOM, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 3, TRUE }, { 2, OFILE_LZSTAND, 0, 0, 0, THEME_NONE, Q_BETRAYER, 0, 1, 0, 128, TRUE, FALSE, TRUE, 0, 3, FALSE }, { 1, OFILE_DECAP, 9, 9, DTYPE_CAVES, THEME_NONE, -1, 0, 2, 0, 96, TRUE, TRUE, TRUE, 0, 1, FALSE }, { 2, OFILE_CHEST3, 0, 0, 0, THEME_NONE, -1, 0, 1, 0, 96, TRUE, TRUE, TRUE, 0, 1, TRUE }, { -1, 0, 0, 0, -1, THEME_NONE, -1, 0, 0, 0, 0, FALSE, FALSE, FALSE, 0, 0, FALSE } // clang-format on }; /** Maps from object_graphic_id to object CEL name. */ const char *const ObjMasterLoadList[] = { "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" }; #ifdef HELLFIRE /** Maps from object_graphic_id to object CEL name (Hellfire Crypt overwrite). */ char *ObjCryptLoadList[] = { "L1Braz", "L5Door", "L5Lever", "Chest1", "Chest2", "Banner", "SkulPile", "SkulFire", "SkulStik", "CruxSk1", "CruxSk2", "CruxSk3", "Book1", "Book2", "Rockstan", "Angel", "Chest3", "Burncros", "L5Light", "Nude2", "Switch4", "TNudeM", "TNudeW", "TSoul", "L2Doors", "WTorch4", "WTorch3", "L5Sarco", "Flame1", "Prsrplt1", "Traphole", "MiniWatr", "WTorch2", "WTorch1", "BCase", "BShelf", "WeapStnd", "Urn", "Urnexpld", "LShrineG", "RShrineG", "Bloodfnt", "Decap", "Pedistl", "L3Doors", "PFountn", "Armstand", "Goatshrn", "Cauldren", "MFountn", "TFountn", "Altboy", "Mcirl", "L5Books", "Mushptch", "LzStand", }; /** Maps from object_graphic_id to object CEL name (Hellfire Hive overwrite). */ char *ObjHiveLoadList[] = { "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", "L6Pod1", "L6Pod2", "LShrineG", "RShrineG", "Bloodfnt", "Decap", "Pedistl", "L3Doors", "PFountn", "Armstand", "Goatshrn", "Cauldren", "MFountn", "TFountn", "Altboy", "Mcirl", "Bkslbrnt", "Mushptch", "LzStand", }; #endif ================================================ FILE: Source/objdat.h ================================================ /** * @file objdat.h * * Interface of all object data. */ #ifndef __OBJDAT_H__ #define __OBJDAT_H__ extern int ObjTypeConv[]; extern ObjDataStruct AllObjects[]; extern const char *const ObjMasterLoadList[]; #ifdef HELLFIRE extern char *ObjCryptLoadList[]; extern char *ObjHiveLoadList[]; #endif #endif /* __OBJDAT_H__ */ ================================================ FILE: Source/objects.cpp ================================================ /** * @file objects.cpp * * Implementation of object functionality, interaction, spawning, loading, etc. */ #include "all.h" int trapid; int trapdir; BYTE *pObjCels[40]; char ObjFileList[40]; int objectactive[MAXOBJECTS]; /** Specifies the number of active objects. */ int nobjects; int leverid; int objectavail[MAXOBJECTS]; ObjectStruct object[MAXOBJECTS]; BOOL InitObjFlag; int numobjfiles; #ifdef HELLFIRE int dword_6DE0E0; #endif /** Specifies the X-coordinate delta between barrels. */ int bxadd[8] = { -1, 0, 1, -1, 1, -1, 0, 1 }; /** Specifies the Y-coordinate delta between barrels. */ int byadd[8] = { -1, -1, -1, 0, 0, 1, 1, 1 }; /** Maps from shrine_id to shrine name. */ const char *const 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", #ifdef HELLFIRE "Oily", "Glowing", "Mendicant's", "Sparkling", "Town", "Shimmering", "Solar", "Murphy's", #endif }; /** Specifies the minimum dungeon level on which each shrine will appear. */ char shrinemin[NUM_SHRINETYPE] = { 1, // Mysterious 1, // Hidden 1, // Gloomy 1, // Weird 1, // Magical 1, // Stone 1, // Religious 1, // Enchanted 1, // Thaumaturgic 1, // Fascinating 1, // Cryptic 1, // Magical 1, // Eldritch 1, // Eerie 1, // Divine 1, // Holy 1, // Sacred 1, // Spiritual 1, // Spooky 1, // Abandoned 1, // Creepy 1, // Quiet 1, // Secluded 1, // Ornate 1, // Glimmering 1, // Tainted #ifdef HELLFIRE 1, // Oily 1, // Glowing 1, // Mendicant's 1, // Sparkling 1, // Town 1, // Shimmering 1, // Solar, 1, // Murphy's #endif }; /** Specifies the maximum dungeon level on which each shrine will appear. */ char shrinemax[NUM_SHRINETYPE] = { MAX_LVLS, // Mysterious MAX_LVLS, // Hidden MAX_LVLS, // Gloomy MAX_LVLS, // Weird MAX_LVLS, // Magical MAX_LVLS, // Stone MAX_LVLS, // Religious 8, // Enchanted MAX_LVLS, // Thaumaturgic MAX_LVLS, // Fascinating MAX_LVLS, // Cryptic MAX_LVLS, // Magical MAX_LVLS, // Eldritch MAX_LVLS, // Eerie MAX_LVLS, // Divine MAX_LVLS, // Holy MAX_LVLS, // Sacred MAX_LVLS, // Spiritual MAX_LVLS, // Spooky MAX_LVLS, // Abandoned MAX_LVLS, // Creepy MAX_LVLS, // Quiet MAX_LVLS, // Secluded MAX_LVLS, // Ornate MAX_LVLS, // Glimmering MAX_LVLS, // Tainted #ifdef HELLFIRE MAX_LVLS, // Oily MAX_LVLS, // Glowing MAX_LVLS, // Mendicant's MAX_LVLS, // Sparkling MAX_LVLS, // Town MAX_LVLS, // Shimmering MAX_LVLS, // Solar, MAX_LVLS, // Murphy's #endif }; /** * Specifies the game type for which each shrine may appear. * SHRINETYPE_ANY - 0 - sp & mp * SHRINETYPE_SINGLE - 1 - sp only * SHRINETYPE_MULTI - 2 - mp only */ BYTE shrineavail[NUM_SHRINETYPE] = { SHRINETYPE_ANY, // SHRINE_MYSTERIOUS SHRINETYPE_ANY, // SHRINE_HIDDEN SHRINETYPE_SINGLE, // SHRINE_GLOOMY SHRINETYPE_SINGLE, // SHRINE_WEIRD SHRINETYPE_ANY, // SHRINE_MAGICAL SHRINETYPE_ANY, // SHRINE_STONE SHRINETYPE_ANY, // SHRINE_RELIGIOUS SHRINETYPE_ANY, // SHRINE_ENCHANTED SHRINETYPE_SINGLE, // SHRINE_THAUMATURGIC SHRINETYPE_ANY, // SHRINE_FASCINATING SHRINETYPE_ANY, // SHRINE_CRYPTIC SHRINETYPE_ANY, // SHRINE_MAGICAL2 SHRINETYPE_ANY, // SHRINE_ELDRITCH SHRINETYPE_ANY, // SHRINE_EERIE SHRINETYPE_ANY, // SHRINE_DIVINE SHRINETYPE_ANY, // SHRINE_HOLY SHRINETYPE_ANY, // SHRINE_SACRED SHRINETYPE_ANY, // SHRINE_SPIRITUAL SHRINETYPE_MULTI, // SHRINE_SPOOKY SHRINETYPE_ANY, // SHRINE_ABANDONED SHRINETYPE_ANY, // SHRINE_CREEPY SHRINETYPE_ANY, // SHRINE_QUIET SHRINETYPE_ANY, // SHRINE_SECLUDED SHRINETYPE_ANY, // SHRINE_ORNATE SHRINETYPE_ANY, // SHRINE_GLIMMERING SHRINETYPE_MULTI, // SHRINE_TAINTED #ifdef HELLFIRE SHRINETYPE_ANY, // SHRINE_OILY SHRINETYPE_ANY, // SHRINE_GLOWING SHRINETYPE_ANY, // SHRINE_MENDICANT SHRINETYPE_ANY, // SHRINE_SPARKLING SHRINETYPE_ANY, // SHRINE_TOWN SHRINETYPE_ANY, // SHRINE_SHIMMERING SHRINETYPE_SINGLE, // SHRINE_SOLAR SHRINETYPE_ANY, // SHRINE_MURPHYS #endif }; /** Maps from book_id to book name. */ const char *const StoryBookName[] = { "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", #ifdef HELLFIRE "Journal: The Ensorcellment", "Journal: The Meeting", "Journal: The Tirade", "Journal: His Power Grows", "Journal: NA-KRUL", "Journal: The End", "A Spellbook", #endif }; /** Specifies the speech IDs of each dungeon type narrator book, for each player class. */ int StoryText[3][3] = { { TEXT_BOOK11, TEXT_BOOK12, TEXT_BOOK13 }, { TEXT_BOOK21, TEXT_BOOK22, TEXT_BOOK23 }, { TEXT_BOOK31, TEXT_BOOK32, TEXT_BOOK33 } }; void InitObjectGFX() { BOOLEAN fileload[56]; char filestr[32]; int i, j; memset(fileload, FALSE, sizeof(fileload)); #ifdef HELLFIRE int lvl = currlevel; if (currlevel >= 21 && currlevel <= 24) lvl -= 20; else if (currlevel >= 17 && currlevel <= 20) lvl -= 8; #endif for (i = 0; AllObjects[i].oload != -1; i++) { if (AllObjects[i].oload == 1 #ifdef HELLFIRE && (int)lvl >= AllObjects[i].ominlvl && (int)lvl <= AllObjects[i].omaxlvl) { #else && (int)currlevel >= AllObjects[i].ominlvl && (int)currlevel <= AllObjects[i].omaxlvl) { #endif fileload[AllObjects[i].ofindex] = TRUE; } if (AllObjects[i].otheme != THEME_NONE) { for (j = 0; j < numthemes; j++) { if (themes[j].ttype == AllObjects[i].otheme) fileload[AllObjects[i].ofindex] = TRUE; } } if (AllObjects[i].oquest != -1) { if (QuestStatus(AllObjects[i].oquest)) fileload[AllObjects[i].ofindex] = TRUE; } } for (i = 0; i < 56; i++) { if (fileload[i]) { ObjFileList[numobjfiles] = i; sprintf(filestr, "Objects\\%s.CEL", ObjMasterLoadList[i]); #ifdef HELLFIRE if (currlevel >= 17 && currlevel < 21) sprintf(filestr, "Objects\\%s.CEL", ObjHiveLoadList[i]); else if (currlevel >= 21) sprintf(filestr, "Objects\\%s.CEL", ObjCryptLoadList[i]); #endif pObjCels[numobjfiles] = LoadFileInMem(filestr, NULL); numobjfiles++; } } } void FreeObjectGFX() { int i; for (i = 0; i < numobjfiles; i++) { MemFreeDbg(pObjCels[i]); } numobjfiles = 0; } DIABOOL RndLocOk(int xp, int yp) { if (dMonster[xp][yp] != 0) return FALSE; if (dPlayer[xp][yp] != 0) return FALSE; if (dObject[xp][yp] != 0) return FALSE; if (dFlags[xp][yp] & BFLAG_POPULATED) return FALSE; if (nSolidTable[dPiece[xp][yp]]) return FALSE; if (leveltype != DTYPE_CATHEDRAL || dPiece[xp][yp] <= 126 || dPiece[xp][yp] >= 144) return TRUE; return FALSE; } static DIABOOL WallTrapLocOkK(int xp, int yp) { if (dFlags[xp][yp] & BFLAG_POPULATED) return FALSE; if (nTrapTable[dPiece[xp][yp]] != FALSE) return TRUE; else return FALSE; } void InitRndLocObj(int min, int max, int objtype) { int i, xp, yp, numobjs; numobjs = random_(139, max - min) + min; for (i = 0; i < numobjs; i++) { while (1) { xp = random_(139, 80) + 16; yp = random_(139, 80) + 16; if (RndLocOk(xp - 1, yp - 1) && RndLocOk(xp, yp - 1) && RndLocOk(xp + 1, yp - 1) && RndLocOk(xp - 1, yp) && RndLocOk(xp, yp) && RndLocOk(xp + 1, yp) && RndLocOk(xp - 1, yp + 1) && RndLocOk(xp, yp + 1) && RndLocOk(xp + 1, yp + 1)) { AddObject(objtype, xp, yp); break; } } } } void InitRndLocBigObj(int min, int max, int objtype) { int i, xp, yp, numobjs; numobjs = random_(140, max - min) + min; for (i = 0; i < numobjs; i++) { while (1) { xp = random_(140, 80) + 16; yp = random_(140, 80) + 16; if (RndLocOk(xp - 1, yp - 2) && RndLocOk(xp, yp - 2) && RndLocOk(xp + 1, yp - 2) && RndLocOk(xp - 1, yp - 1) && RndLocOk(xp, yp - 1) && RndLocOk(xp + 1, yp - 1) && RndLocOk(xp - 1, yp) && RndLocOk(xp, yp) && RndLocOk(xp + 1, yp) && RndLocOk(xp - 1, yp + 1) && RndLocOk(xp, yp + 1) && RndLocOk(xp + 1, yp + 1)) { AddObject(objtype, xp, yp); break; } } } } void InitRndLocObj5x5(int min, int max, int objtype) { DIABOOL exit; int xp, yp, numobjs, i, cnt, m, n; numobjs = min + random_(139, max - min); for (i = 0; i < numobjs; i++) { cnt = 0; exit = FALSE; while (!exit) { exit = TRUE; xp = random_(139, 80) + 16; yp = random_(139, 80) + 16; for (n = -2; n <= 2; n++) { for (m = -2; m <= 2; m++) { if (!RndLocOk(xp + m, yp + n)) exit = FALSE; } } if (!exit) { cnt++; if (cnt > 20000) return; } } AddObject(objtype, xp, yp); } } void ClrAllObjects() { int i; #ifdef HELLFIRE memset(object, 0, sizeof(object)); #else for (i = 0; i < MAXOBJECTS; i++) { object[i]._ox = 0; object[i]._oy = 0; object[i]._oAnimData = 0; object[i]._oAnimDelay = 0; object[i]._oAnimCnt = 0; object[i]._oAnimLen = 0; object[i]._oAnimFrame = 0; object[i]._oDelFlag = FALSE; object[i]._oVar1 = 0; object[i]._oVar2 = 0; object[i]._oVar3 = 0; object[i]._oVar4 = 0; } #endif nobjects = 0; for (i = 0; i < MAXOBJECTS; i++) { objectavail[i] = i; #ifndef HELLFIRE objectactive[i] = 0; #endif } #ifdef HELLFIRE memset(objectactive, 0, sizeof(objectactive)); #endif trapdir = 0; trapid = 1; leverid = 1; } void AddTortures() { int ox, oy; for (oy = 0; oy < MAXDUNY; oy++) { for (ox = 0; ox < MAXDUNX; ox++) { if (dPiece[ox][oy] == 367) { AddObject(OBJ_TORTURE1, ox, oy + 1); AddObject(OBJ_TORTURE3, ox + 2, oy - 1); AddObject(OBJ_TORTURE2, ox, oy + 3); AddObject(OBJ_TORTURE4, ox + 4, oy - 1); AddObject(OBJ_TORTURE5, ox, oy + 5); AddObject(OBJ_TNUDEM1, ox + 1, oy + 3); AddObject(OBJ_TNUDEM2, ox + 4, oy + 5); AddObject(OBJ_TNUDEM3, ox + 2, oy); AddObject(OBJ_TNUDEM4, ox + 3, oy + 2); AddObject(OBJ_TNUDEW1, ox + 2, oy + 4); AddObject(OBJ_TNUDEW2, ox + 2, oy + 1); AddObject(OBJ_TNUDEW3, ox + 4, oy + 2); } } } } void AddCandles() { int tx, ty; tx = quests[Q_PWATER]._qtx; ty = quests[Q_PWATER]._qty; AddObject(OBJ_STORYCANDLE, tx - 2, ty + 1); AddObject(OBJ_STORYCANDLE, tx + 3, ty + 1); AddObject(OBJ_STORYCANDLE, tx - 1, ty + 2); AddObject(OBJ_STORYCANDLE, tx + 2, ty + 2); } void AddBookLever(int lx1, int ly1, int lx2, int ly2, int x1, int y1, int x2, int y2, int msg) { DIABOOL exit; int xp, yp, ob, cnt, m, n; cnt = 0; exit = FALSE; while (!exit) { exit = TRUE; xp = random_(139, 80) + 16; yp = random_(139, 80) + 16; for (n = -2; n <= 2; n++) { for (m = -2; m <= 2; m++) { if (!RndLocOk(xp + m, yp + n)) exit = FALSE; } } if (!exit) { cnt++; if (cnt > 20000) return; } } if (QuestStatus(Q_BLIND)) AddObject(OBJ_BLINDBOOK, xp, yp); if (QuestStatus(Q_WARLORD)) AddObject(OBJ_STEELTOME, xp, yp); if (QuestStatus(Q_BLOOD)) { xp = 2 * setpc_x + 25; yp = 2 * setpc_y + 40; AddObject(OBJ_BLOODBOOK, xp, yp); } ob = dObject[xp][yp] - 1; SetObjMapRange(ob, x1, y1, x2, y2, leverid); SetBookMsg(ob, msg); leverid++; object[ob]._oVar6 = object[ob]._oAnimFrame + 1; } void InitRndBarrels() { int numobjs; // number of groups of barrels to generate int xp, yp; _object_id o; DIABOOL found; int p; // regulates chance to stop placing barrels in current group int dir; int t; // number of tries of placing next barrel in current group int c; // number of barrels in current group int i; numobjs = random_(143, 5) + 3; for (i = 0; i < numobjs; i++) { do { xp = random_(143, 80) + 16; yp = random_(143, 80) + 16; } while (!RndLocOk(xp, yp)); o = (random_(143, 4) != 0) ? OBJ_BARREL : OBJ_BARRELEX; AddObject(o, xp, yp); found = TRUE; p = 0; c = 1; while (random_(143, p) == 0 && found) { t = 0; found = FALSE; while (TRUE) { if (t >= 3) break; dir = random_(143, 8); xp += bxadd[dir]; yp += byadd[dir]; found = RndLocOk(xp, yp); t++; if (found) break; } if (found) { o = (random_(143, 5) != 0) ? OBJ_BARREL : OBJ_BARRELEX; AddObject(o, xp, yp); c++; } p = c >> 1; } } } void AddL1Objs(int x1, int y1, int x2, int y2) { int i, j, pn; for (j = y1; j < y2; j++) { for (i = x1; i < x2; i++) { pn = dPiece[i][j]; if (pn == 270) AddObject(OBJ_L1LIGHT, i, j); if (pn == 44 || pn == 51 || pn == 214) AddObject(OBJ_L1LDOOR, i, j); if (pn == 46 || pn == 56) AddObject(OBJ_L1RDOOR, i, j); } } } #ifdef HELLFIRE void add_crypt_objs(int x1, int y1, int x2, int y2) { int i, j, pn; for (j = y1; j < y2; j++) { for (i = x1; i < x2; i++) { pn = dPiece[i][j]; if (pn == 77) AddObject(OBJ_L1LDOOR, i, j); if (pn == 80) AddObject(OBJ_L1RDOOR, i, j); } } } #endif void AddL2Objs(int x1, int y1, int x2, int y2) { int i, j, pn; for (j = y1; j < y2; j++) { for (i = x1; i < x2; i++) { pn = dPiece[i][j]; if (pn == 13 || pn == 541) AddObject(OBJ_L2LDOOR, i, j); if (pn == 17 || pn == 542) AddObject(OBJ_L2RDOOR, i, j); } } } void AddL3Objs(int x1, int y1, int x2, int y2) { int i, j, pn; for (j = y1; j < y2; j++) { for (i = x1; i < x2; i++) { pn = dPiece[i][j]; if (pn == 531) AddObject(OBJ_L3LDOOR, i, j); if (pn == 534) AddObject(OBJ_L3RDOOR, i, j); } } } DIABOOL TorchLocOK(int xp, int yp) { if (dFlags[xp][yp] & BFLAG_POPULATED) return FALSE; return TRUE; } void AddL2Torches() { int i, j, pn; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (!TorchLocOK(i, j)) continue; pn = dPiece[i][j]; if (pn == 1 && random_(145, 3) == 0) AddObject(OBJ_TORCHL2, i, j); if (pn == 5 && random_(145, 3) == 0) AddObject(OBJ_TORCHR2, i, j); if (pn == 37 && random_(145, 10) == 0 && dObject[i - 1][j] == 0) AddObject(OBJ_TORCHL, i - 1, j); if (pn == 41 && random_(145, 10) == 0 && dObject[i][j - 1] == 0) AddObject(OBJ_TORCHR, i, j - 1); } } } void AddObjTraps() { char oi_trap, oi; int i, j; int xp, yp; int rndv; if (currlevel == 1) rndv = 10; if (currlevel >= 2) rndv = 15; if (currlevel >= 5) rndv = 20; if (currlevel >= 7) rndv = 25; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dObject[i][j] <= 0 || random_(144, 100) >= rndv) continue; oi = dObject[i][j] - 1; if (!AllObjects[object[oi]._otype].oTrapFlag) continue; if (random_(144, 2) == 0) { xp = i - 1; while (!nSolidTable[dPiece[xp][j]]) xp--; if (!WallTrapLocOkK(xp, j) || i - xp <= 1) continue; AddObject(OBJ_TRAPL, xp, j); oi_trap = dObject[xp][j] - 1; object[oi_trap]._oVar1 = i; object[oi_trap]._oVar2 = j; object[oi]._oTrapFlag = TRUE; } else { yp = j - 1; while (!nSolidTable[dPiece[i][yp]]) yp--; if (!WallTrapLocOkK(i, yp) || j - yp <= 1) continue; AddObject(OBJ_TRAPR, i, yp); oi_trap = dObject[i][yp] - 1; object[oi_trap]._oVar1 = i; object[oi_trap]._oVar2 = j; object[oi]._oTrapFlag = TRUE; } } } } void AddChestTraps() { int i, j; char oi; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dObject[i][j] > 0) { oi = dObject[i][j] - 1; if (object[oi]._otype >= OBJ_CHEST1 && object[oi]._otype <= OBJ_CHEST3 && !object[oi]._oTrapFlag && random_(0, 100) < 10) { object[oi]._otype += OBJ_TCHEST1 - OBJ_CHEST1; object[oi]._oTrapFlag = TRUE; if (leveltype == DTYPE_CATACOMBS) { object[oi]._oVar4 = random_(0, 2); } else { #ifdef HELLFIRE object[oi]._oVar4 = random_(0, 6); #else object[oi]._oVar4 = random_(0, 3); #endif } } } } } } void LoadMapObjects(BYTE *pMap, int startx, int starty, int x1, int y1, int w, int h, int leveridx) { int rw, rh, i, j, oi, type; BYTE *lm; long mapoff; InitObjFlag = TRUE; lm = pMap; rw = *lm; lm += 2; rh = *lm; mapoff = (rw * rh + 1) * 2; rw <<= 1; rh <<= 1; mapoff += rw * 2 * rh * 2; lm += mapoff; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm) { type = *lm; AddObject(ObjTypeConv[type], startx + 16 + i, starty + 16 + j); oi = ObjIndex(startx + 16 + i, starty + 16 + j); SetObjMapRange(oi, x1, y1, x1 + w, y1 + h, leveridx); } lm += 2; } } InitObjFlag = FALSE; } void LoadMapObjs(BYTE *pMap, int startx, int starty) { int rw, rh; int i, j; BYTE *lm; long mapoff; InitObjFlag = TRUE; lm = pMap; rw = *lm; lm += 2; rh = *lm; mapoff = (rw * rh + 1) * 2; rw <<= 1; rh <<= 1; mapoff += 2 * rw * rh * 2; lm += mapoff; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm) { AddObject(ObjTypeConv[*lm], startx + 16 + i, starty + 16 + j); } lm += 2; } } InitObjFlag = FALSE; } void AddDiabObjs() { BYTE *lpSetPiece; lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab1.DUN", NULL); LoadMapObjects(lpSetPiece, 2 * diabquad1x, 2 * diabquad1y, diabquad2x, diabquad2y, 11, 12, 1); mem_free_dbg(lpSetPiece); lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab2a.DUN", NULL); LoadMapObjects(lpSetPiece, 2 * diabquad2x, 2 * diabquad2y, diabquad3x, diabquad3y, 11, 11, 2); mem_free_dbg(lpSetPiece); lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab3a.DUN", NULL); LoadMapObjects(lpSetPiece, 2 * diabquad3x, 2 * diabquad3y, diabquad4x, diabquad4y, 9, 9, 3); mem_free_dbg(lpSetPiece); } #ifdef HELLFIRE void AddCryptStoryBook(int s) { DIABOOL exit; int xp, yp, cnt, m, n; cnt = 0; exit = FALSE; while (!exit) { exit = TRUE; xp = random_(139, 80) + 16; yp = random_(139, 80) + 16; for (n = -2; n <= 2; n++) { for (m = -3; m <= 3; m++) { if (!RndLocOk(xp + m, yp + n)) exit = FALSE; } } if (!exit) { cnt++; if (cnt > 20000) return; } } AddCryptBook(OBJ_STORYBOOK, s, xp, yp); AddObject(OBJ_STORYCANDLE, xp - 2, yp + 1); AddObject(OBJ_STORYCANDLE, xp - 2, yp); AddObject(OBJ_STORYCANDLE, xp - 1, yp - 1); AddObject(OBJ_STORYCANDLE, xp + 1, yp - 1); AddObject(OBJ_STORYCANDLE, xp + 2, yp); AddObject(OBJ_STORYCANDLE, xp + 2, yp + 1); } void AddNakrulGate() { AddNakrulLeaver(); switch (random_(0, 6)) { case 0: AddNakrulBook(6, UberRow + 3, UberCol); AddNakrulBook(7, UberRow + 2, UberCol - 3); AddNakrulBook(8, UberRow + 2, UberCol + 2); break; case 1: AddNakrulBook(6, UberRow + 3, UberCol); AddNakrulBook(8, UberRow + 2, UberCol - 3); AddNakrulBook(7, UberRow + 2, UberCol + 2); break; case 2: AddNakrulBook(7, UberRow + 3, UberCol); AddNakrulBook(6, UberRow + 2, UberCol - 3); AddNakrulBook(8, UberRow + 2, UberCol + 2); break; case 3: AddNakrulBook(7, UberRow + 3, UberCol); AddNakrulBook(8, UberRow + 2, UberCol - 3); AddNakrulBook(6, UberRow + 2, UberCol + 2); break; case 4: AddNakrulBook(8, UberRow + 3, UberCol); AddNakrulBook(7, UberRow + 2, UberCol - 3); AddNakrulBook(6, UberRow + 2, UberCol + 2); break; case 5: AddNakrulBook(8, UberRow + 3, UberCol); AddNakrulBook(6, UberRow + 2, UberCol - 3); AddNakrulBook(7, UberRow + 2, UberCol + 2); break; } } void AddNakrulBook(int a1, int a2, int a3) { AddCryptBook(OBJ_STORYBOOK, a1, a2, a3); } #endif void AddStoryBooks() { int xp, yp, xx, yy; int cnt; DIABOOL done; cnt = 0; done = FALSE; while (!done) { done = TRUE; xp = random_(139, 80) + 16; yp = random_(139, 80) + 16; for (yy = -2; yy <= 2; yy++) { for (xx = -3; xx <= 3; xx++) { if (!RndLocOk(xx + xp, yy + yp)) done = FALSE; } } if (!done) { cnt++; if (cnt > 20000) return; } } AddObject(OBJ_STORYBOOK, xp, yp); AddObject(OBJ_STORYCANDLE, xp - 2, yp + 1); AddObject(OBJ_STORYCANDLE, xp - 2, yp); AddObject(OBJ_STORYCANDLE, xp - 1, yp - 1); AddObject(OBJ_STORYCANDLE, xp + 1, yp - 1); AddObject(OBJ_STORYCANDLE, xp + 2, yp); AddObject(OBJ_STORYCANDLE, xp + 2, yp + 1); } void AddHookedBodies(int freq) { int i, j, ii, jj; for (j = 0; j < DMAXY; j++) { jj = 16 + j * 2; for (i = 0; i < DMAXX; i++) { ii = 16 + i * 2; if (dungeon[i][j] != 1 && dungeon[i][j] != 2) continue; if (random_(0, freq) != 0) continue; if (!SkipThemeRoom(i, j)) continue; if (dungeon[i][j] == 1 && dungeon[i + 1][j] == 6) { switch (random_(0, 3)) { case 0: AddObject(OBJ_TORTURE1, ii + 1, jj); break; case 1: AddObject(OBJ_TORTURE2, ii + 1, jj); break; case 2: AddObject(OBJ_TORTURE5, ii + 1, jj); break; } continue; } if (dungeon[i][j] == 2 && dungeon[i][j + 1] == 6) { switch (random_(0, 2)) { case 0: AddObject(OBJ_TORTURE3, ii, jj); break; case 1: AddObject(OBJ_TORTURE4, ii, jj); break; } } } } } void 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 AddLazStand() { int xp, yp, xx, yy; int cnt; DIABOOL found; cnt = 0; found = FALSE; while (!found) { found = TRUE; xp = random_(139, 80) + 16; yp = random_(139, 80) + 16; for (yy = -3; yy <= 3; yy++) { for (xx = -2; xx <= 3; xx++) { if (!RndLocOk(xp + xx, yp + yy)) found = FALSE; } } if (!found) { cnt++; if (cnt > 10000) { InitRndLocObj(1, 1, OBJ_LAZSTAND); return; } } } AddObject(OBJ_LAZSTAND, xp, yp); AddObject(OBJ_TNUDEM2, xp, yp + 2); AddObject(OBJ_STORYCANDLE, xp + 1, yp + 2); AddObject(OBJ_TNUDEM3, xp + 2, yp + 2); AddObject(OBJ_TNUDEW1, xp, yp - 2); AddObject(OBJ_STORYCANDLE, xp + 1, yp - 2); AddObject(OBJ_TNUDEW2, xp + 2, yp - 2); AddObject(OBJ_STORYCANDLE, xp - 1, yp - 1); AddObject(OBJ_TNUDEW3, xp - 1, yp); AddObject(OBJ_STORYCANDLE, xp - 1, yp + 1); } void InitObjects() { int sp_id; BYTE *mem; ClrAllObjects(); #ifdef HELLFIRE dword_6DE0E0 = 0; #endif if (currlevel == 16) { AddDiabObjs(); } else { InitObjFlag = TRUE; GetRndSeed(); if (currlevel == 9 && gbMaxPlayers == 1) AddSlainHero(); if (currlevel == quests[Q_MUSHROOM]._qlevel && quests[Q_MUSHROOM]._qactive == QUEST_INIT) AddMushPatch(); #ifdef HELLFIRE if (currlevel == 4 || currlevel == 8 || currlevel == 12) AddStoryBooks(); if (currlevel == 21) { AddCryptStoryBook(1); } else if (currlevel == 22) { AddCryptStoryBook(2); AddCryptStoryBook(3); } else if (currlevel == 23) { AddCryptStoryBook(4); AddCryptStoryBook(5); } if (currlevel == 24) { AddNakrulGate(); } #else if (currlevel == 4) AddStoryBooks(); if (currlevel == 8) AddStoryBooks(); if (currlevel == 12) AddStoryBooks(); #endif if (leveltype == DTYPE_CATHEDRAL) { if (QuestStatus(Q_BUTCHER)) AddTortures(); if (QuestStatus(Q_PWATER)) AddCandles(); if (QuestStatus(Q_LTBANNER)) AddObject(OBJ_SIGNCHEST, 2 * setpc_x + 26, 2 * setpc_y + 19); InitRndLocBigObj(10, 15, OBJ_SARC); #ifdef HELLFIRE if (currlevel >= 21) add_crypt_objs(0, 0, MAXDUNX, MAXDUNY); else #endif AddL1Objs(0, 0, MAXDUNX, MAXDUNY); InitRndBarrels(); } if (leveltype == DTYPE_CATACOMBS) { if (QuestStatus(Q_ROCK)) InitRndLocObj5x5(1, 1, OBJ_STAND); if (QuestStatus(Q_SCHAMB)) InitRndLocObj5x5(1, 1, OBJ_BOOK2R); AddL2Objs(0, 0, MAXDUNX, MAXDUNY); AddL2Torches(); if (QuestStatus(Q_BLIND)) { if (plr[myplr]._pClass == PC_WARRIOR) { sp_id = TEXT_BLINDING; } else if (plr[myplr]._pClass == PC_ROGUE) { sp_id = TEXT_RBLINDING; } else if (plr[myplr]._pClass == PC_SORCERER) { sp_id = TEXT_MBLINDING; #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { sp_id = TEXT_HBLINDING; } else if (plr[myplr]._pClass == PC_BARD) { sp_id = TEXT_BBLINDING; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sp_id = TEXT_BLINDING; #endif } quests[Q_BLIND]._qmsg = sp_id; AddBookLever(0, 0, MAXDUNX, MAXDUNY, setpc_x, setpc_y, setpc_w + setpc_x + 1, setpc_h + setpc_y + 1, sp_id); mem = LoadFileInMem("Levels\\L2Data\\Blind2.DUN", NULL); // BUGFIX: should not invoke LoadMapObjs for Blind2.DUN, as Blind2.DUN is missing an objects layer. LoadMapObjs(mem, 2 * setpc_x, 2 * setpc_y); mem_free_dbg(mem); } if (QuestStatus(Q_BLOOD)) { if (plr[myplr]._pClass == PC_WARRIOR) { sp_id = TEXT_BLOODY; } else if (plr[myplr]._pClass == PC_ROGUE) { sp_id = TEXT_RBLOODY; } else if (plr[myplr]._pClass == PC_SORCERER) { sp_id = TEXT_MBLOODY; #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { sp_id = TEXT_HBLOODY; } else if (plr[myplr]._pClass == PC_BARD) { sp_id = TEXT_BBLOODY; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sp_id = TEXT_BLOODY; #endif } quests[Q_BLOOD]._qmsg = sp_id; AddBookLever(0, 0, MAXDUNX, MAXDUNY, setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7, sp_id); AddObject(OBJ_PEDISTAL, 2 * setpc_x + 25, 2 * setpc_y + 32); } InitRndBarrels(); } if (leveltype == DTYPE_CAVES) { AddL3Objs(0, 0, MAXDUNX, MAXDUNY); InitRndBarrels(); } if (leveltype == DTYPE_HELL) { if (QuestStatus(Q_WARLORD)) { if (plr[myplr]._pClass == PC_WARRIOR) { sp_id = TEXT_BLOODWAR; } else if (plr[myplr]._pClass == PC_ROGUE) { sp_id = TEXT_RBLOODWAR; } else if (plr[myplr]._pClass == PC_SORCERER) { sp_id = TEXT_MBLOODWAR; #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { sp_id = TEXT_HBLOODWAR; } else if (plr[myplr]._pClass == PC_BARD) { sp_id = TEXT_BBLOODWAR; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sp_id = TEXT_BLOODWAR; #endif } quests[Q_WARLORD]._qmsg = sp_id; AddBookLever(0, 0, MAXDUNX, MAXDUNY, setpc_x, setpc_y, setpc_x + setpc_w, setpc_y + setpc_h, sp_id); mem = LoadFileInMem("Levels\\L4Data\\Warlord.DUN", NULL); LoadMapObjs(mem, 2 * setpc_x, 2 * setpc_y); mem_free_dbg(mem); } if (QuestStatus(Q_BETRAYER) && gbMaxPlayers == 1) AddLazStand(); InitRndBarrels(); AddL4Goodies(); } InitRndLocObj(5, 10, OBJ_CHEST1); InitRndLocObj(3, 6, OBJ_CHEST2); InitRndLocObj(1, 5, OBJ_CHEST3); if (leveltype != DTYPE_HELL) AddObjTraps(); if (leveltype > DTYPE_CATHEDRAL) AddChestTraps(); InitObjFlag = FALSE; } } #ifndef SPAWN void SetMapObjects(BYTE *pMap, int startx, int starty) { int rw, rh; int i, j; BYTE *lm, *h; long mapoff; int fileload[56]; char filestr[32]; ClrAllObjects(); for (i = 0; i < 56; i++) fileload[i] = FALSE; InitObjFlag = TRUE; for (i = 0; AllObjects[i].oload != -1; i++) { if (AllObjects[i].oload == 1 && leveltype == AllObjects[i].olvltype) fileload[AllObjects[i].ofindex] = TRUE; } lm = pMap; rw = *lm; lm += 2; rh = *lm; mapoff = (rw * rh + 1) * 2; rw <<= 1; rh <<= 1; mapoff += 2 * rw * rh * 2; lm += mapoff; h = lm; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm) { fileload[AllObjects[ObjTypeConv[*lm]].ofindex] = TRUE; } lm += 2; } } for (i = 0; i < 56; i++) { if (!fileload[i]) continue; ObjFileList[numobjfiles] = i; sprintf(filestr, "Objects\\%s.CEL", ObjMasterLoadList[i]); pObjCels[numobjfiles] = LoadFileInMem(filestr, NULL); numobjfiles++; } lm = h; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm) AddObject(ObjTypeConv[*lm], startx + 16 + i, starty + 16 + j); lm += 2; } } InitObjFlag = FALSE; } #endif void DeleteObject_(int oi, int i) { int ox, oy; ox = object[oi]._ox; oy = object[oi]._oy; dObject[ox][oy] = 0; objectavail[-nobjects + MAXOBJECTS] = oi; nobjects--; if (nobjects > 0 && i != nobjects) objectactive[i] = objectactive[nobjects]; } void SetupObject(int i, int x, int y, int ot) { int ofi; int j; object[i]._otype = ot; ofi = AllObjects[ot].ofindex; object[i]._ox = x; object[i]._oy = y; j = 0; while (ObjFileList[j] != ofi) { j++; } object[i]._oAnimData = pObjCels[j]; object[i]._oAnimFlag = AllObjects[ot].oAnimFlag; if (AllObjects[ot].oAnimFlag) { object[i]._oAnimDelay = AllObjects[ot].oAnimDelay; object[i]._oAnimCnt = random_(146, AllObjects[ot].oAnimDelay); object[i]._oAnimLen = AllObjects[ot].oAnimLen; object[i]._oAnimFrame = random_(146, AllObjects[ot].oAnimLen - 1) + 1; } else { object[i]._oAnimDelay = 1000; object[i]._oAnimCnt = 0; object[i]._oAnimLen = AllObjects[ot].oAnimLen; object[i]._oAnimFrame = AllObjects[ot].oAnimDelay; } object[i]._oAnimWidth = AllObjects[ot].oAnimWidth; object[i]._oSolidFlag = AllObjects[ot].oSolidFlag; object[i]._oMissFlag = AllObjects[ot].oMissFlag; object[i]._oLight = AllObjects[ot].oLightFlag; object[i]._oDelFlag = FALSE; object[i]._oBreak = AllObjects[ot].oBreak; object[i]._oSelFlag = AllObjects[ot].oSelFlag; object[i]._oPreFlag = FALSE; object[i]._oTrapFlag = FALSE; object[i]._oDoorFlag = FALSE; } void 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 SetBookMsg(int i, int msg) { object[i]._oVar7 = msg; } void AddL1Door(int i, int x, int y, int ot) { object[i]._oDoorFlag = TRUE; if (ot == 1) { object[i]._oVar1 = dPiece[x][y]; object[i]._oVar2 = dPiece[x][y - 1]; } else { object[i]._oVar1 = dPiece[x][y]; object[i]._oVar2 = dPiece[x - 1][y]; } object[i]._oVar4 = 0; } void 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; } void AddChest(int i, int t) { if (random_(147, 2) == 0) object[i]._oAnimFrame += 3; object[i]._oRndSeed = GetRndSeed(); switch (t) { case OBJ_CHEST1: case OBJ_TCHEST1: if (setlevel) { object[i]._oVar1 = 1; break; } object[i]._oVar1 = random_(147, 2); break; case OBJ_TCHEST2: case OBJ_CHEST2: if (setlevel) { object[i]._oVar1 = 2; break; } object[i]._oVar1 = random_(147, 3); break; case OBJ_TCHEST3: case OBJ_CHEST3: if (setlevel) { object[i]._oVar1 = 3; break; } object[i]._oVar1 = random_(147, 4); break; } object[i]._oVar2 = random_(147, 8); } void AddL2Door(int i, int x, int y, int ot) { object[i]._oDoorFlag = TRUE; if (ot == OBJ_L2LDOOR) ObjSetMicro(x, y, 538); else ObjSetMicro(x, y, 540); object[i]._oVar4 = 0; } void AddL3Door(int i, int x, int y, int ot) { object[i]._oDoorFlag = TRUE; if (ot == OBJ_L3LDOOR) ObjSetMicro(x, y, 531); else ObjSetMicro(x, y, 534); object[i]._oVar4 = 0; } void AddSarc(int i) { dObject[object[i]._ox][object[i]._oy - 1] = -(i + 1); object[i]._oVar1 = random_(153, 10); object[i]._oRndSeed = GetRndSeed(); if (object[i]._oVar1 >= 8) object[i]._oVar2 = PreSpawnSkeleton(); } void AddFlameTrap(int i) { object[i]._oVar1 = trapid; object[i]._oVar2 = 0; object[i]._oVar3 = trapdir; object[i]._oVar4 = 0; } void AddFlameLvr(int i) { object[i]._oVar1 = trapid; object[i]._oVar2 = MIS_FLAMEC; } void AddTrap(int i, int ot) { int mt; mt = currlevel / 3 + 1; #ifdef HELLFIRE if (currlevel > 16) { mt = (currlevel - 4) / 3 + 1; } if (currlevel > 20) { mt = (currlevel - 8) / 3 + 1; } #endif mt = random_(148, mt); if (mt == 0) object[i]._oVar3 = MIS_ARROW; if (mt == 1) object[i]._oVar3 = MIS_FIREBOLT; if (mt == 2) object[i]._oVar3 = MIS_LIGHTCTRL; object[i]._oVar4 = 0; } void 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; } } void AddBarrel(int i, int t) { object[i]._oVar1 = 0; object[i]._oRndSeed = GetRndSeed(); object[i]._oVar2 = random_(149, 10); object[i]._oVar3 = random_(149, 3); if (object[i]._oVar2 >= 8) object[i]._oVar4 = PreSpawnSkeleton(); } void AddShrine(int i) { int val; DIABOOL slist[NUM_SHRINETYPE]; #ifdef HELLFIRE unsigned int j; #else int j; #endif // BUGFIX: the seed of shrine objects (object[i]._oRndSeed) was never // initialized. This lead to undefined behaviour, as the shrine object would // use whatever value was present in memory (often the seed of an object with // the same object index of a previous dungeon level). object[i]._oPreFlag = TRUE; for (j = 0; j < NUM_SHRINETYPE; j++) { if (currlevel < shrinemin[j] || currlevel > shrinemax[j]) { slist[j] = 0; } else { slist[j] = 1; } if (gbMaxPlayers != 1 && shrineavail[j] == 1) { slist[j] = 0; } if (gbMaxPlayers == 1 && shrineavail[j] == 2) { slist[j] = 0; } } do { val = random_(150, NUM_SHRINETYPE); } while (!slist[val]); object[i]._oVar1 = val; if (random_(150, 2) != 0) { object[i]._oAnimFrame = 12; object[i]._oAnimLen = 22; } } void AddBookcase(int i) { object[i]._oRndSeed = GetRndSeed(); object[i]._oPreFlag = TRUE; } void AddBookstand(int i) { object[i]._oRndSeed = GetRndSeed(); } void AddBloodFtn(int i) { object[i]._oRndSeed = GetRndSeed(); } void AddPurifyingFountain(int i) { int ox, oy; ox = object[i]._ox; oy = object[i]._oy; dObject[ox][oy - 1] = -1 - i; dObject[ox - 1][oy] = -1 - i; dObject[ox - 1][oy - 1] = -1 - i; object[i]._oRndSeed = GetRndSeed(); } void AddArmorStand(int i) { if (!armorFlag) { object[i]._oAnimFlag = 2; object[i]._oSelFlag = 0; } object[i]._oRndSeed = GetRndSeed(); } void AddGoatShrine(int i) { object[i]._oRndSeed = GetRndSeed(); } void AddCauldron(int i) { object[i]._oRndSeed = GetRndSeed(); } void AddMurkyFountain(int i) { int ox, oy; ox = object[i]._ox; oy = object[i]._oy; dObject[ox][oy - 1] = -1 - i; dObject[ox - 1][oy] = -1 - i; dObject[ox - 1][oy - 1] = -1 - i; object[i]._oRndSeed = GetRndSeed(); } void AddTearFountain(int i) { object[i]._oRndSeed = GetRndSeed(); } void AddDecap(int i) { object[i]._oRndSeed = GetRndSeed(); object[i]._oAnimFrame = random_(151, 8) + 1; object[i]._oPreFlag = TRUE; } void AddVilebook(int i) { if (setlevel && setlvlnum == SL_VILEBETRAYER) { object[i]._oAnimFrame = 4; } } void AddMagicCircle(int i) { object[i]._oRndSeed = GetRndSeed(); object[i]._oPreFlag = TRUE; object[i]._oVar6 = 0; object[i]._oVar5 = 1; } void AddBrnCross(int i) { object[i]._oRndSeed = GetRndSeed(); } void AddPedistal(int i) { object[i]._oVar1 = setpc_x; object[i]._oVar2 = setpc_y; object[i]._oVar3 = setpc_x + setpc_w; object[i]._oVar4 = setpc_y + setpc_h; } void AddStoryBook(int i) { SetRndSeed(glSeedTbl[16]); object[i]._oVar1 = random_(0, 3); if (currlevel == 4) object[i]._oVar2 = StoryText[object[i]._oVar1][0]; #ifdef HELLFIRE if (currlevel == 8) #else else if (currlevel == 8) #endif object[i]._oVar2 = StoryText[object[i]._oVar1][1]; #ifdef HELLFIRE if (currlevel == 12) #else else if (currlevel == 12) #endif object[i]._oVar2 = StoryText[object[i]._oVar1][2]; object[i]._oVar3 = (currlevel >> 2) + 3 * object[i]._oVar1 - 1; object[i]._oAnimFrame = 5 - 2 * object[i]._oVar1; object[i]._oVar4 = object[i]._oAnimFrame + 1; } void AddWeaponRack(int i) { if (!weaponFlag) { object[i]._oAnimFlag = 2; object[i]._oSelFlag = 0; } object[i]._oRndSeed = GetRndSeed(); } void AddTorturedBody(int i) { object[i]._oRndSeed = GetRndSeed(); object[i]._oAnimFrame = random_(0, 4) + 1; object[i]._oPreFlag = TRUE; } void GetRndObjLoc(int randarea, int &xx, int &yy) { DIABOOL failed; int i, j, tries; if (randarea == 0) return; tries = 0; while (1) { tries++; if (tries > 1000 && randarea > 1) randarea--; xx = random_(0, MAXDUNX); yy = random_(0, MAXDUNY); failed = FALSE; for (i = 0; i < randarea && !failed; i++) { for (j = 0; j < randarea && !failed; j++) { failed = !RndLocOk(i + xx, j + yy); } } if (!failed) break; } } void AddMushPatch() { int i; int y, x; 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 AddSlainHero() { int x, y; GetRndObjLoc(5, x, y); AddObject(OBJ_SLAINHERO, x + 2, y + 2); } #ifdef HELLFIRE void AddCryptBook(int ot, int v2, int ox, int oy) { int oi; if (nobjects >= MAXOBJECTS) return; oi = objectavail[0]; objectavail[0] = objectavail[MAXOBJECTS - 1 - nobjects]; objectactive[nobjects] = oi; dObject[ox][oy] = oi + 1; SetupObject(oi, ox, oy, ot); AddCryptObject(oi, v2); object[oi]._oAnimWidth2 = (object[oi]._oAnimWidth - 64) >> 1; nobjects++; } void AddCryptObject(int i, int a2) { int v8, v9; if (a2 > 5) { object[i]._oVar8 = a2; switch (a2) { case 6: if (plr[myplr]._pClass == PC_WARRIOR) { object[i]._oVar2 = 323; } else if (plr[myplr]._pClass == PC_ROGUE) { object[i]._oVar2 = 332; } else if (plr[myplr]._pClass == PC_SORCERER) { object[i]._oVar2 = 329; } else if (plr[myplr]._pClass == PC_MONK) { object[i]._oVar2 = 326; } else if (plr[myplr]._pClass == PC_BARD) { object[i]._oVar2 = 335; } else if (plr[myplr]._pClass == PC_BARBARIAN) { object[i]._oVar2 = 323; } break; case 7: if (plr[myplr]._pClass == PC_WARRIOR) { object[i]._oVar2 = 324; } else if (plr[myplr]._pClass == PC_ROGUE) { object[i]._oVar2 = 333; } else if (plr[myplr]._pClass == PC_SORCERER) { object[i]._oVar2 = 330; } else if (plr[myplr]._pClass == PC_MONK) { object[i]._oVar2 = 327; } else if (plr[myplr]._pClass == PC_BARD) { object[i]._oVar2 = 336; } else if (plr[myplr]._pClass == PC_BARBARIAN) { object[i]._oVar2 = 324; } break; case 8: if (plr[myplr]._pClass == PC_WARRIOR) { object[i]._oVar2 = 325; } else if (plr[myplr]._pClass == PC_ROGUE) { object[i]._oVar2 = 334; } else if (plr[myplr]._pClass == PC_SORCERER) { object[i]._oVar2 = 331; } else if (plr[myplr]._pClass == PC_MONK) { object[i]._oVar2 = 328; } else if (plr[myplr]._pClass == PC_BARD) { object[i]._oVar2 = 337; } else if (plr[myplr]._pClass == PC_BARBARIAN) { object[i]._oVar2 = 325; } break; } object[i]._oVar1 = 1; object[i]._oVar3 = 15; v8 = 2 * object[i]._oVar1; object[i]._oAnimFrame = 5 - v8; object[i]._oVar4 = object[i]._oAnimFrame + 1; } else { object[i]._oVar1 = 1; object[i]._oVar2 = a2 + 316; object[i]._oVar3 = a2 + 9; v9 = 2 * object[i]._oVar1; object[i]._oAnimFrame = 5 - v9; object[i]._oVar4 = object[i]._oAnimFrame + 1; object[i]._oVar8 = 0; } } #endif void AddObject(int ot, int ox, int oy) { int oi; if (nobjects >= MAXOBJECTS) return; oi = objectavail[0]; objectavail[0] = objectavail[MAXOBJECTS - 1 - nobjects]; objectactive[nobjects] = oi; dObject[ox][oy] = oi + 1; SetupObject(oi, ox, oy, ot); switch (ot) { case OBJ_L1LIGHT: AddObjLight(oi, 5); break; case OBJ_SKFIRE: case OBJ_CANDLE1: case OBJ_CANDLE2: case OBJ_BOOKCANDLE: AddObjLight(oi, 5); break; case OBJ_STORYCANDLE: AddObjLight(oi, 3); break; case OBJ_TORCHL: case OBJ_TORCHR: case OBJ_TORCHL2: case OBJ_TORCHR2: AddObjLight(oi, 8); break; case OBJ_L1LDOOR: case OBJ_L1RDOOR: AddL1Door(oi, ox, oy, ot); break; case OBJ_L2LDOOR: case OBJ_L2RDOOR: AddL2Door(oi, ox, oy, ot); break; case OBJ_L3LDOOR: case OBJ_L3RDOOR: AddL3Door(oi, ox, oy, ot); break; case OBJ_BOOK2R: AddSCambBook(oi); break; case OBJ_CHEST1: case OBJ_CHEST2: case OBJ_CHEST3: case OBJ_TCHEST1: case OBJ_TCHEST2: case OBJ_TCHEST3: AddChest(oi, ot); break; case OBJ_SARC: AddSarc(oi); break; case OBJ_FLAMEHOLE: AddFlameTrap(oi); break; case OBJ_FLAMELVR: AddFlameLvr(oi); break; case OBJ_WATER: object[oi]._oAnimFrame = 1; break; case OBJ_TRAPL: case OBJ_TRAPR: AddTrap(oi, ot); break; case OBJ_BARREL: case OBJ_BARRELEX: AddBarrel(oi, ot); break; case OBJ_SHRINEL: case OBJ_SHRINER: AddShrine(oi); break; case OBJ_BOOKCASEL: case OBJ_BOOKCASER: AddBookcase(oi); break; case OBJ_SKELBOOK: case OBJ_BOOKSTAND: AddBookstand(oi); break; case OBJ_BLOODFTN: AddBloodFtn(oi); break; case OBJ_DECAP: AddDecap(oi); break; case OBJ_PURIFYINGFTN: AddPurifyingFountain(oi); break; case OBJ_ARMORSTAND: case OBJ_WARARMOR: AddArmorStand(oi); break; case OBJ_GOATSHRINE: AddGoatShrine(oi); break; case OBJ_CAULDRON: AddCauldron(oi); break; case OBJ_MURKYFTN: AddMurkyFountain(oi); break; case OBJ_TEARFTN: AddTearFountain(oi); break; case OBJ_BOOK2L: AddVilebook(oi); break; case OBJ_MCIRCLE1: case OBJ_MCIRCLE2: AddMagicCircle(oi); break; case OBJ_STORYBOOK: AddStoryBook(oi); break; case OBJ_BCROSS: case OBJ_TBCROSS: AddBrnCross(oi); AddObjLight(oi, 5); break; case OBJ_PEDISTAL: AddPedistal(oi); break; case OBJ_WARWEAP: case OBJ_WEAPONRACK: AddWeaponRack(oi); break; case OBJ_TNUDEM2: AddTorturedBody(oi); break; } object[oi]._oAnimWidth2 = (object[oi]._oAnimWidth - 64) >> 1; nobjects++; } void Obj_Light(int i, int lr) { int ox, oy, dx, dy, p, tr; DIABOOL turnon; turnon = FALSE; if (object[i]._oVar1 != -1) { ox = object[i]._ox; oy = object[i]._oy; tr = lr + 10; #ifndef HELLFIRE turnon = FALSE; #endif if (!lightflag) { for (p = 0; p < MAX_PLRS && !turnon; p++) { if (plr[p].plractive) { if (currlevel == plr[p].plrlevel) { dx = abs(plr[p]._px - ox); dy = abs(plr[p]._py - oy); if (dx < tr && dy < tr) turnon = TRUE; } } } } if (turnon) { if (object[i]._oVar1 == 0) object[i]._olid = AddLight(ox, oy, lr); object[i]._oVar1 = 1; } else { if (object[i]._oVar1 == 1) AddUnLight(object[i]._olid); object[i]._oVar1 = 0; } } } void Obj_Circle(int i) { int ox, oy, wx, wy; ox = object[i]._ox; oy = object[i]._oy; wx = plr[myplr]._px; wy = plr[myplr]._py; if (wx == ox && wy == oy) { if (object[i]._otype == OBJ_MCIRCLE1) object[i]._oAnimFrame = 2; if (object[i]._otype == OBJ_MCIRCLE2) object[i]._oAnimFrame = 4; if (ox == 45 && oy == 47) { object[i]._oVar6 = 2; } else if (ox == 26 && oy == 46) { object[i]._oVar6 = 1; } else { object[i]._oVar6 = 0; } if (ox == 35 && oy == 36 && object[i]._oVar5 == 3) { object[i]._oVar6 = 4; ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); if (quests[Q_BETRAYER]._qactive == QUEST_ACTIVE) // BUGFIX stepping on the circle again will break the quest state quests[Q_BETRAYER]._qvar1 = 4; AddMissile(plr[myplr]._px, plr[myplr]._py, 35, 46, plr[myplr]._pdir, MIS_RNDTELEPORT, TARGET_MONSTERS, myplr, 0, 0); track_repeat_walk(FALSE); sgbMouseDown = CLICK_NONE; ReleaseCapture(); ClrPlrPath(myplr); StartStand(myplr, 0); } } else { if (object[i]._otype == OBJ_MCIRCLE1) object[i]._oAnimFrame = 1; if (object[i]._otype == OBJ_MCIRCLE2) object[i]._oAnimFrame = 3; object[i]._oVar6 = 0; } } void Obj_StopAnim(int i) { if (object[i]._oAnimFrame == object[i]._oAnimLen) { object[i]._oAnimCnt = 0; object[i]._oAnimDelay = 1000; } } void Obj_Door(int i) { int dx, dy; DIABOOL dok; if (object[i]._oVar4 == 0) { object[i]._oSelFlag = 3; object[i]._oMissFlag = FALSE; } else { dx = object[i]._ox; dy = object[i]._oy; dok = dMonster[dx][dy] == 0; dok = dok HFAND(dItem[dx][dy] == 0); dok = dok HFAND(dDead[dx][dy] == 0); dok = dok HFAND(dPlayer[dx][dy] == 0); object[i]._oSelFlag = 2; object[i]._oVar4 = dok ? 1 : 2; object[i]._oMissFlag = TRUE; } } void Obj_Sarc(int i) { if (object[i]._oAnimFrame == object[i]._oAnimLen) object[i]._oAnimFlag = 0; } void ActivateTrapLine(int ttype, int tid) { int i, oi; for (i = 0; i < nobjects; i++) { oi = objectactive[i]; if (object[oi]._otype == ttype && object[oi]._oVar1 == tid) { object[oi]._oVar4 = 1; object[oi]._oAnimFlag = 1; object[oi]._oAnimDelay = 1; object[oi]._olid = AddLight(object[oi]._ox, object[oi]._oy, 1); } } } void Obj_FlameTrap(int i) { int x, y; int j, k; if (object[i]._oVar2 != 0) { if (object[i]._oVar4 != 0) { object[i]._oAnimFrame--; if (object[i]._oAnimFrame == 1) { object[i]._oVar4 = 0; AddUnLight(object[i]._olid); } else if (object[i]._oAnimFrame <= 4) { ChangeLightRadius(object[i]._olid, object[i]._oAnimFrame); } } } else if (object[i]._oVar4 == 0) { if (object[i]._oVar3 == 2) { x = object[i]._ox - 2; y = object[i]._oy; for (j = 0; j < 5; j++) { if (dPlayer[x][y] != 0 || dMonster[x][y] != 0) object[i]._oVar4 = 1; x++; } } else { x = object[i]._ox; y = object[i]._oy - 2; for (k = 0; k < 5; k++) { if (dPlayer[x][y] != 0 || dMonster[x][y] != 0) object[i]._oVar4 = 1; y++; } } if (object[i]._oVar4 != 0) ActivateTrapLine(object[i]._otype, object[i]._oVar1); } else { if (object[i]._oAnimFrame == object[i]._oAnimLen) object[i]._oAnimFrame = 11; if (object[i]._oAnimFrame <= 5) ChangeLightRadius(object[i]._olid, object[i]._oAnimFrame); } } void Obj_Trap(int i) { int oti, dir; BOOLEAN otrig; int sx, sy, dx, dy, x, y; otrig = FALSE; if (object[i]._oVar4 == 0) { oti = dObject[object[i]._oVar1][object[i]._oVar2] - 1; switch (object[oti]._otype) { case OBJ_L1LDOOR: case OBJ_L1RDOOR: case OBJ_L2LDOOR: case OBJ_L2RDOOR: case OBJ_L3LDOOR: case OBJ_L3RDOOR: if (object[oti]._oVar4 != 0) otrig = TRUE; break; case OBJ_LEVER: case OBJ_CHEST1: case OBJ_CHEST2: case OBJ_CHEST3: case OBJ_SWITCHSKL: case OBJ_SARC: if (object[oti]._oSelFlag == 0) otrig = TRUE; break; } if (otrig) { object[i]._oVar4 = 1; sx = object[i]._ox; sy = object[i]._oy; dx = object[oti]._ox; dy = object[oti]._oy; for (y = dy - 1; y <= object[oti]._oy + 1; y++) { for (x = object[oti]._ox - 1; x <= object[oti]._ox + 1; x++) { if (dPlayer[x][y] != 0) { dx = x; dy = y; } } } if (!deltaload) { dir = GetDirection(sx, sy, dx, dy); AddMissile(sx, sy, dx, dy, dir, object[i]._oVar3, TARGET_PLAYERS, -1, 0, 0); PlaySfxLoc(IS_TRAP, object[oti]._ox, object[oti]._oy); } object[oti]._oTrapFlag = FALSE; } } } void Obj_BCrossDamage(int i) { int fire_resist; int damage[4] = { 6, 8, 10, 12 }; if (plr[myplr]._pmode == PM_DEATH) return; fire_resist = plr[myplr]._pFireResist; if (fire_resist > 0) damage[leveltype - 1] -= fire_resist * damage[leveltype - 1] / 100; if (plr[myplr]._px != object[i]._ox || plr[myplr]._py != object[i]._oy - 1) return; plr[myplr]._pHitPoints -= damage[leveltype - 1]; plr[myplr]._pHPBase -= damage[leveltype - 1]; if (plr[myplr]._pHitPoints >> 6 <= 0) { SyncPlrKill(myplr, 0); } else { if (plr[myplr]._pClass == PC_WARRIOR) { PlaySfxLoc(PS_WARR68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { PlaySfxLoc(PS_ROGUE68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? } else if (plr[myplr]._pClass == PC_SORCERER) { PlaySfxLoc(PS_MAGE68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { PlaySfxLoc(PS_MONK68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? } else if (plr[myplr]._pClass == PC_BARD) { PlaySfxLoc(PS_ROGUE68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? } else if (plr[myplr]._pClass == PC_BARBARIAN) { PlaySfxLoc(PS_WARR68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? #endif #endif } } drawhpflag = TRUE; } void ProcessObjects() { int oi; int i; for (i = 0; i < nobjects; ++i) { oi = objectactive[i]; switch (object[oi]._otype) { case OBJ_L1LIGHT: Obj_Light(oi, 10); break; case OBJ_SKFIRE: case OBJ_CANDLE2: case OBJ_BOOKCANDLE: Obj_Light(oi, 5); break; case OBJ_STORYCANDLE: Obj_Light(oi, 3); break; case OBJ_CRUX1: case OBJ_CRUX2: case OBJ_CRUX3: case OBJ_BARREL: case OBJ_BARRELEX: case OBJ_SHRINEL: case OBJ_SHRINER: Obj_StopAnim(oi); break; case OBJ_L1LDOOR: case OBJ_L1RDOOR: case OBJ_L2LDOOR: case OBJ_L2RDOOR: case OBJ_L3LDOOR: case OBJ_L3RDOOR: Obj_Door(oi); break; case OBJ_TORCHL: case OBJ_TORCHR: case OBJ_TORCHL2: case OBJ_TORCHR2: Obj_Light(oi, 8); break; case OBJ_SARC: Obj_Sarc(oi); break; case OBJ_FLAMEHOLE: Obj_FlameTrap(oi); break; case OBJ_TRAPL: case OBJ_TRAPR: Obj_Trap(oi); break; case OBJ_MCIRCLE1: case OBJ_MCIRCLE2: Obj_Circle(oi); break; case OBJ_BCROSS: case OBJ_TBCROSS: Obj_Light(oi, 10); Obj_BCrossDamage(oi); break; } if (object[oi]._oAnimFlag == 0) continue; object[oi]._oAnimCnt++; if (object[oi]._oAnimCnt < object[oi]._oAnimDelay) continue; object[oi]._oAnimCnt = 0; object[oi]._oAnimFrame++; if (object[oi]._oAnimFrame > object[oi]._oAnimLen) object[oi]._oAnimFrame = 1; } i = 0; while (i < nobjects) { oi = objectactive[i]; if (object[oi]._oDelFlag) { DeleteObject_(oi, i); i = 0; } else { i++; } } } void ObjSetMicro(int dx, int dy, int pn) { WORD *v; MICROS *defs; int i; dPiece[dx][dy] = pn; pn--; defs = &dpiece_defs_map_1[IsometricCoord(dx, dy)]; if (leveltype != DTYPE_HELL) { v = (WORD *)pLevelPieces + 10 * pn; for (i = 0; i < 10; i++) { defs->mt[i] = v[(i & 1) - (i & 0xE) + 8]; } } else { v = (WORD *)pLevelPieces + 16 * pn; for (i = 0; i < 16; i++) { defs->mt[i] = v[(i & 1) - (i & 0xE) + 14]; } } } void objects_set_door_piece(int x, int y) { int pn; long v1, v2; pn = dPiece[x][y] - 1; #ifdef USE_ASM __asm { mov esi, pLevelPieces xor eax, eax mov ax, word ptr pn mov ebx, 20 mul ebx add esi, eax add esi, 16 xor eax, eax lodsw mov word ptr v1, ax lodsw mov word ptr v2, ax } #else v1 = *((WORD *)pLevelPieces + 10 * pn + 8); v2 = *((WORD *)pLevelPieces + 10 * pn + 9); #endif dpiece_defs_map_1[IsometricCoord(x, y)].mt[0] = v1; dpiece_defs_map_1[IsometricCoord(x, y)].mt[1] = v2; } void ObjSetMini(int x, int y, int v) { int xx, yy; long v1, v2, v3, v4; #ifdef USE_ASM __asm { mov esi, pMegaTiles xor eax, eax mov ax, word ptr v dec eax shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax } #else v1 = *((WORD *)&pMegaTiles[((WORD)v - 1) * 8]) + 1; v2 = *((WORD *)&pMegaTiles[((WORD)v - 1) * 8] + 1) + 1; v3 = *((WORD *)&pMegaTiles[((WORD)v - 1) * 8] + 2) + 1; v4 = *((WORD *)&pMegaTiles[((WORD)v - 1) * 8] + 3) + 1; #endif xx = 2 * x + 16; yy = 2 * y + 16; ObjSetMicro(xx, yy, v1); ObjSetMicro(xx + 1, yy, v2); ObjSetMicro(xx, yy + 1, v3); ObjSetMicro(xx + 1, yy + 1, v4); } void ObjL1Special(int x1, int y1, int x2, int y2) { int i, j; for (i = y1; i <= y2; ++i) { for (j = x1; j <= x2; ++j) { dSpecial[j][i] = 0; if (dPiece[j][i] == 12) dSpecial[j][i] = 1; if (dPiece[j][i] == 11) dSpecial[j][i] = 2; if (dPiece[j][i] == 71) dSpecial[j][i] = 1; if (dPiece[j][i] == 259) dSpecial[j][i] = 5; if (dPiece[j][i] == 249) dSpecial[j][i] = 2; if (dPiece[j][i] == 325) dSpecial[j][i] = 2; if (dPiece[j][i] == 321) dSpecial[j][i] = 1; if (dPiece[j][i] == 255) dSpecial[j][i] = 4; if (dPiece[j][i] == 211) dSpecial[j][i] = 1; if (dPiece[j][i] == 344) dSpecial[j][i] = 2; if (dPiece[j][i] == 341) dSpecial[j][i] = 1; if (dPiece[j][i] == 331) dSpecial[j][i] = 2; if (dPiece[j][i] == 418) dSpecial[j][i] = 1; if (dPiece[j][i] == 421) dSpecial[j][i] = 2; } } } void ObjL2Special(int x1, int y1, int x2, int y2) { int i, j; for (j = y1; j <= y2; j++) { for (i = x1; i <= x2; i++) { dSpecial[i][j] = 0; if (dPiece[i][j] == 541) dSpecial[i][j] = 5; if (dPiece[i][j] == 178) dSpecial[i][j] = 5; if (dPiece[i][j] == 551) dSpecial[i][j] = 5; if (dPiece[i][j] == 542) dSpecial[i][j] = 6; if (dPiece[i][j] == 553) dSpecial[i][j] = 6; if (dPiece[i][j] == 13) dSpecial[i][j] = 5; if (dPiece[i][j] == 17) dSpecial[i][j] = 6; } } for (j = y1; j <= y2; j++) { for (i = x1; i <= x2; i++) { if (dPiece[i][j] == 132) { dSpecial[i][j + 1] = 2; dSpecial[i][j + 2] = 1; } if (dPiece[i][j] == 135 || dPiece[i][j] == 139) { dSpecial[i + 1][j] = 3; dSpecial[i + 2][j] = 4; } } } } void DoorSet(int oi, int dx, int dy) { int pn; pn = dPiece[dx][dy]; #ifdef HELLFIRE if (currlevel < 17) { #endif if (pn == 43) ObjSetMicro(dx, dy, 392); if (pn == 45) ObjSetMicro(dx, dy, 394); if (pn == 50 && object[oi]._otype == OBJ_L1LDOOR) ObjSetMicro(dx, dy, 411); if (pn == 50 && object[oi]._otype == OBJ_L1RDOOR) ObjSetMicro(dx, dy, 412); if (pn == 54) ObjSetMicro(dx, dy, 397); if (pn == 55) ObjSetMicro(dx, dy, 398); if (pn == 61) ObjSetMicro(dx, dy, 399); if (pn == 67) ObjSetMicro(dx, dy, 400); if (pn == 68) ObjSetMicro(dx, dy, 401); if (pn == 69) ObjSetMicro(dx, dy, 403); if (pn == 70) ObjSetMicro(dx, dy, 404); if (pn == 72) ObjSetMicro(dx, dy, 406); if (pn == 212) ObjSetMicro(dx, dy, 407); if (pn == 354) ObjSetMicro(dx, dy, 409); if (pn == 355) ObjSetMicro(dx, dy, 410); if (pn == 411) ObjSetMicro(dx, dy, 396); if (pn == 412) ObjSetMicro(dx, dy, 396); #ifdef HELLFIRE } else { if (pn == 75) ObjSetMicro(dx, dy, 204); if (pn == 79) ObjSetMicro(dx, dy, 208); if (pn == 86 && object[oi]._otype == OBJ_L1LDOOR) { ObjSetMicro(dx, dy, 232); } if (pn == 86 && object[oi]._otype == OBJ_L1RDOOR) { ObjSetMicro(dx, dy, 234); } if (pn == 91) ObjSetMicro(dx, dy, 215); if (pn == 93) ObjSetMicro(dx, dy, 218); if (pn == 99) ObjSetMicro(dx, dy, 220); if (pn == 111) ObjSetMicro(dx, dy, 222); if (pn == 113) ObjSetMicro(dx, dy, 224); if (pn == 115) ObjSetMicro(dx, dy, 226); if (pn == 117) ObjSetMicro(dx, dy, 228); if (pn == 119) ObjSetMicro(dx, dy, 230); if (pn == 232) ObjSetMicro(dx, dy, 212); if (pn == 234) ObjSetMicro(dx, dy, 212); } #endif } void RedoPlayerVision() { int p; for (p = 0; p < MAX_PLRS; p++) { if (plr[p].plractive && currlevel == plr[p].plrlevel) { ChangeVisionXY(plr[p]._pvid, plr[p]._px, plr[p]._py); } } } void OperateL1RDoor(int pnum, int oi, DIABOOL sendflag) { int xp, yp; if (object[oi]._oVar4 == 2) { if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy); return; } xp = object[oi]._ox; yp = object[oi]._oy; if (object[oi]._oVar4 == 0) { if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi); #ifdef HELLFIRE if (currlevel < 21) { if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy); } else { if (!deltaload) PlaySfxLoc(IS_CROPEN, object[oi]._ox, object[oi]._oy); } if (currlevel < 21) { ObjSetMicro(xp, yp, 395); } else { ObjSetMicro(xp, yp, 209); } if (currlevel < 17) { dSpecial[xp][yp] = 8; } else { dSpecial[xp][yp] = 2; } #else if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy); ObjSetMicro(xp, yp, 395); dSpecial[xp][yp] = 8; #endif objects_set_door_piece(xp, yp - 1); object[oi]._oAnimFrame += 2; object[oi]._oPreFlag = TRUE; DoorSet(oi, xp - 1, yp); object[oi]._oVar4 = 1; object[oi]._oSelFlag = 2; RedoPlayerVision(); return; } #ifdef HELLFIRE if (currlevel < 21) { if (!deltaload) PlaySfxLoc(IS_DOORCLOS, xp, object[oi]._oy); } else { if (!deltaload) PlaySfxLoc(IS_CRCLOS, xp, object[oi]._oy); } BOOLEAN dok = dMonster[xp][yp] == 0; dok = dok && dItem[xp][yp] == 0; dok = dok && dDead[xp][yp] == 0; if (dok) { #else if (!deltaload) PlaySfxLoc(IS_DOORCLOS, xp, object[oi]._oy); if (((dDead[xp][yp] != 0 ? 0 : 1) & (dMonster[xp][yp] != 0 ? 0 : 1) & (dItem[xp][yp] != 0 ? 0 : 1)) != 0) { #endif if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi); object[oi]._oVar4 = 0; object[oi]._oSelFlag = 3; ObjSetMicro(xp, yp, object[oi]._oVar1); #ifdef HELLFIRE if (currlevel < 17) { #endif if (object[oi]._oVar2 != 50) { ObjSetMicro(xp - 1, yp, object[oi]._oVar2); } else { if (dPiece[xp - 1][yp] == 396) ObjSetMicro(xp - 1, yp, 411); else ObjSetMicro(xp - 1, yp, 50); } #ifdef HELLFIRE } else { if (object[oi]._oVar2 != 86) { ObjSetMicro(xp - 1, yp, object[oi]._oVar2); } else { if (dPiece[xp - 1][yp] == 210) ObjSetMicro(xp - 1, yp, 232); else ObjSetMicro(xp - 1, yp, 86); } } #endif object[oi]._oAnimFrame -= 2; object[oi]._oPreFlag = FALSE; RedoPlayerVision(); } else { object[oi]._oVar4 = 2; } } void OperateL1LDoor(int pnum, int oi, DIABOOL sendflag) { int xp, yp; if (object[oi]._oVar4 == 2) { if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy); return; } xp = object[oi]._ox; yp = object[oi]._oy; if (object[oi]._oVar4 == 0) { if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi); #ifdef HELLFIRE if (currlevel < 21) { if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy); } else { if (!deltaload) PlaySfxLoc(IS_CROPEN, object[oi]._ox, object[oi]._oy); } if (currlevel < 21) { if (object[oi]._oVar1 == 214) ObjSetMicro(xp, yp, 408); else ObjSetMicro(xp, yp, 393); } else { ObjSetMicro(xp, yp, 206); } if (currlevel < 17) { dSpecial[xp][yp] = 7; } else { dSpecial[xp][yp] = 1; } #else if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy); if (object[oi]._oVar1 == 214) ObjSetMicro(xp, yp, 408); else ObjSetMicro(xp, yp, 393); dSpecial[xp][yp] = 7; #endif objects_set_door_piece(xp - 1, yp); object[oi]._oAnimFrame += 2; object[oi]._oPreFlag = TRUE; DoorSet(oi, xp, yp - 1); object[oi]._oVar4 = 1; object[oi]._oSelFlag = 2; RedoPlayerVision(); return; } #ifdef HELLFIRE if (currlevel < 21) { if (!deltaload) PlaySfxLoc(IS_DOORCLOS, xp, object[oi]._oy); } else { if (!deltaload) PlaySfxLoc(IS_CRCLOS, xp, object[oi]._oy); } BOOLEAN dok = dMonster[xp][yp] == 0; dok = dok && dItem[xp][yp] == 0; dok = dok && dDead[xp][yp] == 0; if (dok) { #else if (!deltaload) PlaySfxLoc(IS_DOORCLOS, xp, object[oi]._oy); if (((dDead[xp][yp] != 0 ? 0 : 1) & (dMonster[xp][yp] != 0 ? 0 : 1) & (dItem[xp][yp] != 0 ? 0 : 1)) != 0) { #endif if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi); object[oi]._oVar4 = 0; object[oi]._oSelFlag = 3; ObjSetMicro(xp, yp, object[oi]._oVar1); #ifdef HELLFIRE if (currlevel < 17) { #endif if (object[oi]._oVar2 != 50) { ObjSetMicro(xp, yp - 1, object[oi]._oVar2); } else { if (dPiece[xp][yp - 1] == 396) ObjSetMicro(xp, yp - 1, 412); else ObjSetMicro(xp, yp - 1, 50); } #ifdef HELLFIRE } else { if (object[oi]._oVar2 != 86) { ObjSetMicro(xp, yp - 1, object[oi]._oVar2); } else { if (dPiece[xp][yp - 1] == 210) ObjSetMicro(xp, yp - 1, 234); else ObjSetMicro(xp, yp - 1, 86); } } #endif object[oi]._oAnimFrame -= 2; object[oi]._oPreFlag = FALSE; RedoPlayerVision(); } else { object[oi]._oVar4 = 2; } } void OperateL2RDoor(int pnum, int oi, DIABOOL sendflag) { int xp, yp; DIABOOL dok; if (object[oi]._oVar4 == 2) { if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy); return; } xp = object[oi]._ox; yp = object[oi]._oy; if (object[oi]._oVar4 == 0) { if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi); if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy); ObjSetMicro(xp, yp, 17); object[oi]._oAnimFrame += 2; object[oi]._oPreFlag = TRUE; object[oi]._oVar4 = 1; object[oi]._oSelFlag = 2; RedoPlayerVision(); return; } if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, yp); dok = dMonster[xp][yp] == 0; dok = dok HFAND(dItem[xp][yp] == 0); dok = dok HFAND(dDead[xp][yp] == 0); if (dok) { if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi); object[oi]._oVar4 = 0; object[oi]._oSelFlag = 3; ObjSetMicro(xp, yp, 540); object[oi]._oAnimFrame -= 2; object[oi]._oPreFlag = FALSE; RedoPlayerVision(); } else { object[oi]._oVar4 = 2; } } void OperateL2LDoor(int pnum, int oi, BOOL sendflag) { int xp, yp; DIABOOL dok; if (object[oi]._oVar4 == 2) { if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy); return; } xp = object[oi]._ox; yp = object[oi]._oy; if (object[oi]._oVar4 == 0) { if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi); if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy); ObjSetMicro(xp, yp, 13); object[oi]._oAnimFrame += 2; object[oi]._oPreFlag = TRUE; object[oi]._oVar4 = 1; object[oi]._oSelFlag = 2; RedoPlayerVision(); return; } if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, yp); dok = dMonster[xp][yp] == 0; dok = dok HFAND(dItem[xp][yp] == 0); dok = dok HFAND(dDead[xp][yp] == 0); if (dok) { if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi); object[oi]._oVar4 = 0; object[oi]._oSelFlag = 3; ObjSetMicro(xp, yp, 538); object[oi]._oAnimFrame -= 2; object[oi]._oPreFlag = FALSE; RedoPlayerVision(); } else { object[oi]._oVar4 = 2; } } void OperateL3RDoor(int pnum, int oi, DIABOOL sendflag) { int xp, yp; DIABOOL dok; if (object[oi]._oVar4 == 2) { if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy); return; } xp = object[oi]._ox; yp = object[oi]._oy; if (object[oi]._oVar4 == 0) { if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi); if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy); ObjSetMicro(xp, yp, 541); object[oi]._oAnimFrame += 2; object[oi]._oPreFlag = TRUE; object[oi]._oVar4 = 1; object[oi]._oSelFlag = 2; RedoPlayerVision(); return; } if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, yp); dok = dMonster[xp][yp] == 0; dok = dok HFAND(dItem[xp][yp] == 0); dok = dok HFAND(dDead[xp][yp] == 0); if (dok) { if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi); object[oi]._oVar4 = 0; object[oi]._oSelFlag = 3; ObjSetMicro(xp, yp, 534); object[oi]._oAnimFrame -= 2; object[oi]._oPreFlag = FALSE; RedoPlayerVision(); } else { object[oi]._oVar4 = 2; } } void OperateL3LDoor(int pnum, int oi, DIABOOL sendflag) { int xp, yp; DIABOOL dok; if (object[oi]._oVar4 == 2) { if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy); return; } xp = object[oi]._ox; yp = object[oi]._oy; if (object[oi]._oVar4 == 0) { if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi); if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy); ObjSetMicro(xp, yp, 538); object[oi]._oAnimFrame += 2; object[oi]._oPreFlag = TRUE; object[oi]._oVar4 = 1; object[oi]._oSelFlag = 2; RedoPlayerVision(); return; } if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, yp); dok = dMonster[xp][yp] == 0; dok = dok HFAND(dItem[xp][yp] == 0); dok = dok HFAND(dDead[xp][yp] == 0); if (dok) { if (pnum == myplr && sendflag) NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi); object[oi]._oVar4 = 0; object[oi]._oSelFlag = 3; ObjSetMicro(xp, yp, 531); object[oi]._oAnimFrame -= 2; object[oi]._oPreFlag = FALSE; RedoPlayerVision(); } else { object[oi]._oVar4 = 2; } } void MonstCheckDoors(int m) { int i, oi; int dpx, dpy, mx, my; mx = monster[m]._mx; my = monster[m]._my; if (dObject[mx - 1][my - 1] != 0 || dObject[mx][my - 1] != 0 || dObject[mx + 1][my - 1] != 0 || dObject[mx - 1][my] != 0 || dObject[mx + 1][my] != 0 || dObject[mx - 1][my + 1] != 0 || dObject[mx][my + 1] != 0 || dObject[mx + 1][my + 1] != 0) { for (i = 0; i < nobjects; ++i) { oi = objectactive[i]; if ((object[oi]._otype == OBJ_L1LDOOR || object[oi]._otype == OBJ_L1RDOOR) && object[oi]._oVar4 == 0) { dpx = abs(object[oi]._ox - mx); dpy = abs(object[oi]._oy - my); if (dpx == 1 && dpy <= 1 && object[oi]._otype == OBJ_L1LDOOR) OperateL1LDoor(myplr, oi, TRUE); if (dpx <= 1 && dpy == 1 && object[oi]._otype == OBJ_L1RDOOR) OperateL1RDoor(myplr, oi, TRUE); } if ((object[oi]._otype == OBJ_L2LDOOR || object[oi]._otype == OBJ_L2RDOOR) && object[oi]._oVar4 == 0) { dpx = abs(object[oi]._ox - mx); dpy = abs(object[oi]._oy - my); if (dpx == 1 && dpy <= 1 && object[oi]._otype == OBJ_L2LDOOR) OperateL2LDoor(myplr, oi, TRUE); if (dpx <= 1 && dpy == 1 && object[oi]._otype == OBJ_L2RDOOR) OperateL2RDoor(myplr, oi, TRUE); } if ((object[oi]._otype == OBJ_L3LDOOR || object[oi]._otype == OBJ_L3RDOOR) && object[oi]._oVar4 == 0) { dpx = abs(object[oi]._ox - mx); dpy = abs(object[oi]._oy - my); if (dpx == 1 && dpy <= 1 && object[oi]._otype == OBJ_L3RDOOR) OperateL3RDoor(myplr, oi, TRUE); if (dpx <= 1 && dpy == 1 && object[oi]._otype == OBJ_L3LDOOR) OperateL3LDoor(myplr, oi, TRUE); } } } } void ObjChangeMap(int x1, int y1, int x2, int y2) { int i, j; for (j = y1; j <= y2; j++) { for (i = x1; i <= x2; i++) { ObjSetMini(i, j, pdungeon[i][j]); dungeon[i][j] = pdungeon[i][j]; } } #ifdef HELLFIRE if (leveltype == DTYPE_CATHEDRAL && currlevel < 17) { #else if (leveltype == DTYPE_CATHEDRAL) { #endif ObjL1Special(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17); AddL1Objs(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17); } if (leveltype == DTYPE_CATACOMBS) { ObjL2Special(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17); AddL2Objs(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17); } } void ObjChangeMapResync(int x1, int y1, int x2, int y2) { int i, j; for (j = y1; j <= y2; j++) { for (i = x1; i <= x2; i++) { ObjSetMini(i, j, pdungeon[i][j]); dungeon[i][j] = pdungeon[i][j]; } } #ifdef HELLFIRE if (leveltype == DTYPE_CATHEDRAL && currlevel < 17) { #else if (leveltype == DTYPE_CATHEDRAL) { #endif ObjL1Special(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17); } if (leveltype == DTYPE_CATACOMBS) { ObjL2Special(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17); } } void OperateL1Door(int pnum, int i, DIABOOL sendflag) { int dpx, dpy; dpx = abs(object[i]._ox - plr[pnum]._px); dpy = abs(object[i]._oy - plr[pnum]._py); if (dpx == 1 && dpy <= 1 && object[i]._otype == OBJ_L1LDOOR) OperateL1LDoor(pnum, i, sendflag); if (dpx <= 1 && dpy == 1 && object[i]._otype == OBJ_L1RDOOR) OperateL1RDoor(pnum, i, sendflag); } void OperateLever(int pnum, int i) { int j, oi; DIABOOL mapflag; if (object[i]._oSelFlag != 0) { if (!deltaload) PlaySfxLoc(IS_LEVER, object[i]._ox, object[i]._oy); object[i]._oSelFlag = 0; object[i]._oAnimFrame++; mapflag = TRUE; if (currlevel == 16) { for (j = 0; j < nobjects; j++) { oi = objectactive[j]; if (object[oi]._otype == OBJ_SWITCHSKL && object[i]._oVar8 == object[oi]._oVar8 && object[oi]._oSelFlag != 0) { mapflag = FALSE; } } } #ifdef HELLFIRE if (currlevel == 24) { OperateNakrulLever(); IsUberLeverActivated = 1; mapflag = FALSE; quests[Q_NAKRUL]._qactive = QUEST_DONE; } #endif if (mapflag) ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } } void OperateBook(int pnum, int i) { int j, oi; int dx, dy; int otype; DIABOOL do_add_missile, missile_added; if (object[i]._oSelFlag == 0) return; if (setlevel && setlvlnum == SL_VILEBETRAYER) { do_add_missile = FALSE; missile_added = FALSE; for (j = 0; j < nobjects; j++) { oi = objectactive[j]; otype = object[oi]._otype; if (otype == OBJ_MCIRCLE2 && object[oi]._oVar6 == 1) { dx = 27; dy = 29; object[oi]._oVar6 = 4; do_add_missile = TRUE; } if (otype == OBJ_MCIRCLE2 && object[oi]._oVar6 == 2) { dx = 43; dy = 29; object[oi]._oVar6 = 4; do_add_missile = TRUE; } if (do_add_missile) { object[dObject[35][36] - 1]._oVar5++; AddMissile(plr[pnum]._px, plr[pnum]._py, dx, dy, plr[pnum]._pdir, MIS_RNDTELEPORT, TARGET_MONSTERS, pnum, 0, 0); missile_added = TRUE; do_add_missile = FALSE; } } if (!missile_added) return; } object[i]._oSelFlag = 0; object[i]._oAnimFrame++; if (!setlevel) return; if (setlvlnum == SL_BONECHAMB) { plr[myplr]._pMemSpells |= SPELLBIT(SPL_GUARDIAN); if (plr[pnum]._pSplLvl[SPL_GUARDIAN] < MAX_SPELL_LEVEL) // BUGFIX: should use plr[myplr] or plr[pnum] consistently, not mix and match. If another connected peer interacts with the Ancient Tome (then pnum!=myplr), and they have Guardian spell level < 15, while the local player has Guardian spell level = 15; then the sanity check is skipped, and the local player gets Guardian spell level 16. plr[myplr]._pSplLvl[SPL_GUARDIAN]++; quests[Q_SCHAMB]._qactive = QUEST_DONE; if (!deltaload) PlaySfxLoc(IS_QUESTDN, object[i]._ox, object[i]._oy); InitDiabloMsg(EMSG_BONECHAMB); AddMissile( plr[myplr]._px, plr[myplr]._py, object[i]._ox - 2, object[i]._oy - 4, plr[myplr]._pdir, MIS_GUARDIAN, TARGET_MONSTERS, myplr, 0, 0); } if (setlevel && setlvlnum == SL_VILEBETRAYER) { ObjChangeMapResync( object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); for (j = 0; j < nobjects; j++) SyncObjectAnim(objectactive[j]); } } void OperateBookLever(int pnum, int i) { int x, y, tren; x = 2 * setpc_x + 16; y = 2 * setpc_y + 16; if (object[i]._oSelFlag != 0 && !qtextflag) { if (object[i]._otype == OBJ_BLINDBOOK && quests[Q_BLIND]._qvar1 == 0) { quests[Q_BLIND]._qactive = QUEST_ACTIVE; quests[Q_BLIND]._qlog = TRUE; quests[Q_BLIND]._qvar1 = 1; } if (object[i]._otype == OBJ_BLOODBOOK && quests[Q_BLOOD]._qvar1 == 0) { quests[Q_BLOOD]._qactive = QUEST_ACTIVE; quests[Q_BLOOD]._qlog = TRUE; quests[Q_BLOOD]._qvar1 = 1; SpawnQuestItem(IDI_BLDSTONE, 2 * setpc_x + 19, 2 * setpc_y + 26, 0, 1); SpawnQuestItem(IDI_BLDSTONE, 2 * setpc_x + 31, 2 * setpc_y + 26, 0, 1); SpawnQuestItem(IDI_BLDSTONE, 2 * setpc_x + 25, 2 * setpc_y + 33, 0, 1); } object[i]._otype = object[i]._otype; if (object[i]._otype == OBJ_STEELTOME && quests[Q_WARLORD]._qvar1 == 0) { quests[Q_WARLORD]._qactive = QUEST_ACTIVE; quests[Q_WARLORD]._qlog = TRUE; quests[Q_WARLORD]._qvar1 = 1; } if (object[i]._oAnimFrame != object[i]._oVar6) { if (object[i]._otype != OBJ_BLOODBOOK) ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); if (object[i]._otype == OBJ_BLINDBOOK) { CreateItem(UITEM_OPTAMULET, x + 5, y + 5); tren = TransVal; TransVal = 9; DRLG_MRectTrans(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); TransVal = tren; } } object[i]._oAnimFrame = object[i]._oVar6; InitQTextMsg(object[i]._oVar7); if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } } void OperateSChambBk(int pnum, int i) { int j, textdef; if (object[i]._oSelFlag != 0 && !qtextflag) { if (object[i]._oAnimFrame != object[i]._oVar6) { ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); for (j = 0; j < nobjects; j++) SyncObjectAnim(objectactive[j]); } object[i]._oAnimFrame = object[i]._oVar6; if (quests[Q_SCHAMB]._qactive == QUEST_INIT) { quests[Q_SCHAMB]._qactive = QUEST_ACTIVE; quests[Q_SCHAMB]._qlog = TRUE; } if (plr[myplr]._pClass == PC_WARRIOR) { textdef = TEXT_BONER; } else if (plr[myplr]._pClass == PC_ROGUE) { textdef = TEXT_RBONER; } else if (plr[myplr]._pClass == PC_SORCERER) { textdef = TEXT_MBONER; #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { textdef = TEXT_HBONER; } else if (plr[myplr]._pClass == PC_BARD) { textdef = TEXT_BBONER; } else if (plr[myplr]._pClass == PC_BARBARIAN) { textdef = TEXT_BONER; #endif } quests[Q_SCHAMB]._qmsg = textdef; InitQTextMsg(textdef); } } void OperateChest(int pnum, int i, DIABOOL sendmsg) { int j, mdir, mtype; if (object[i]._oSelFlag != 0) { if (!deltaload) PlaySfxLoc(IS_CHEST, object[i]._ox, object[i]._oy); object[i]._oSelFlag = 0; object[i]._oAnimFrame += 2; if (!deltaload) { SetRndSeed(object[i]._oRndSeed); if (setlevel) { for (j = 0; j < object[i]._oVar1; j++) { CreateRndItem(object[i]._ox, object[i]._oy, TRUE, sendmsg, FALSE); } } else { for (j = 0; j < object[i]._oVar1; j++) { if (object[i]._oVar2 != 0) CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE); else CreateRndUseful(pnum, object[i]._ox, object[i]._oy, sendmsg); } } if (object[i]._oTrapFlag && object[i]._otype >= OBJ_TCHEST1 && object[i]._otype <= OBJ_TCHEST3) { mdir = GetDirection(object[i]._ox, object[i]._oy, plr[pnum]._px, plr[pnum]._py); switch (object[i]._oVar4) { case 0: mtype = MIS_ARROW; break; case 1: mtype = MIS_FARROW; break; case 2: mtype = MIS_NOVA; break; #ifdef HELLFIRE case 3: mtype = MIS_FIRERING; break; case 4: mtype = MIS_STEALPOTS; break; case 5: mtype = MIS_MANATRAP; break; default: mtype = MIS_ARROW; #endif } AddMissile(object[i]._ox, object[i]._oy, plr[pnum]._px, plr[pnum]._py, mdir, mtype, TARGET_PLAYERS, -1, 0, 0); object[i]._oTrapFlag = FALSE; } if (pnum == myplr) NetSendCmdParam2(FALSE, CMD_PLROPOBJ, pnum, i); return; } } } void OperateMushPatch(int pnum, int i) { int x, y; if (quests[Q_MUSHROOM]._qactive != QUEST_ACTIVE || quests[Q_MUSHROOM]._qvar1 < QS_TOMEGIVEN) { if (!deltaload && pnum == myplr) { if (plr[myplr]._pClass == PC_WARRIOR) { PlaySFX(PS_WARR13); #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { PlaySFX(PS_ROGUE13); } else if (plr[myplr]._pClass == PC_SORCERER) { PlaySFX(PS_MAGE13); #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { PlaySFX(PS_MONK13); } else if (plr[myplr]._pClass == PC_BARD) { PlaySFX(PS_ROGUE13); } else if (plr[myplr]._pClass == PC_BARBARIAN) { PlaySFX(PS_WARR13); #endif #endif } } } else { if (object[i]._oSelFlag != 0) { if (!deltaload) PlaySfxLoc(IS_CHEST, object[i]._ox, object[i]._oy); object[i]._oSelFlag = 0; object[i]._oAnimFrame++; if (!deltaload) { GetSuperItemLoc(object[i]._ox, object[i]._oy, x, y); SpawnQuestItem(IDI_MUSHROOM, x, y, 0, 0); quests[Q_MUSHROOM]._qvar1 = QS_MUSHSPAWNED; } } } } void OperateInnSignChest(int pnum, int i) { int x, y; if (quests[Q_LTBANNER]._qvar1 != 2) { if (!deltaload && pnum == myplr) { if (plr[myplr]._pClass == PC_WARRIOR) { PlaySFX(PS_WARR24); #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { PlaySFX(PS_ROGUE24); } else if (plr[myplr]._pClass == PC_SORCERER) { PlaySFX(PS_MAGE24); #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { PlaySFX(PS_MONK24); } else if (plr[myplr]._pClass == PC_BARD) { PlaySFX(PS_ROGUE24); } else if (plr[myplr]._pClass == PC_BARBARIAN) { PlaySFX(PS_WARR24); #endif #endif } } } else { if (object[i]._oSelFlag != 0) { if (!deltaload) PlaySfxLoc(IS_CHEST, object[i]._ox, object[i]._oy); object[i]._oSelFlag = 0; object[i]._oAnimFrame += 2; if (!deltaload) { GetSuperItemLoc(object[i]._ox, object[i]._oy, x, y); SpawnQuestItem(IDI_BANNER, x, y, 0, 0); } } } } void OperateSlainHero(int pnum, int i, DIABOOL sendmsg) { if (object[i]._oSelFlag != 0) { object[i]._oSelFlag = 0; if (!deltaload) { if (plr[pnum]._pClass == PC_WARRIOR) { CreateMagicArmor(object[i]._ox, object[i]._oy, ITYPE_HARMOR, ICURS_BREAST_PLATE, FALSE, TRUE); #ifndef SPAWN PlaySfxLoc(PS_WARR9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #endif } else if (plr[pnum]._pClass == PC_ROGUE) { CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_BOW, ICURS_LONG_WAR_BOW, FALSE, TRUE); #ifndef SPAWN PlaySfxLoc(PS_ROGUE9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #endif } else if (plr[pnum]._pClass == PC_SORCERER) { CreateSpellBook(object[i]._ox, object[i]._oy, SPL_LIGHTNING, FALSE, TRUE); #ifndef SPAWN PlaySfxLoc(PS_MAGE9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #endif #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK) { CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_STAFF, ICURS_WAR_STAFF, FALSE, TRUE); PlaySfxLoc(PS_MONK9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #ifndef SPAWN } else if (plr[pnum]._pClass == PC_BARD) { CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_SWORD, ICURS_BASTARD_SWORD, FALSE, TRUE); PlaySfxLoc(PS_ROGUE9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #endif } else if (plr[pnum]._pClass == PC_BARBARIAN) { CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_AXE, ICURS_BATTLE_AXE, FALSE, TRUE); #ifndef SPAWN PlaySfxLoc(PS_WARR9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #endif #endif } if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } } } void OperateTrapLvr(int i) { int frame, j, oi; frame = object[i]._oAnimFrame; j = 0; if (frame == 1) { object[i]._oAnimFrame = 2; for (; j < nobjects; j++) { oi = objectactive[j]; if (object[oi]._otype == object[i]._oVar2 && object[oi]._oVar1 == object[i]._oVar1) { object[oi]._oVar2 = 1; object[oi]._oAnimFlag = 0; } } return; } object[i]._oAnimFrame = frame - 1; for (; j < nobjects; j++) { oi = objectactive[j]; if (object[oi]._otype == object[i]._oVar2 && object[oi]._oVar1 == object[i]._oVar1) { object[oi]._oVar2 = 0; if (object[oi]._oVar4 != 0) object[oi]._oAnimFlag = 1; } } } void OperateSarc(int pnum, int i, DIABOOL sendmsg) { if (object[i]._oSelFlag != 0) { if (!deltaload) PlaySfxLoc(IS_SARC, object[i]._ox, object[i]._oy); object[i]._oSelFlag = 0; if (deltaload) { object[i]._oAnimFrame = object[i]._oAnimLen; } else { object[i]._oAnimFlag = 1; object[i]._oAnimDelay = 3; SetRndSeed(object[i]._oRndSeed); if (object[i]._oVar1 <= 2) CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE); if (object[i]._oVar1 >= 8) SpawnSkeleton(object[i]._oVar2, object[i]._ox, object[i]._oy); if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } } } void OperateL2Door(int pnum, int i, DIABOOL sendflag) { int dpx, dpy; dpx = abs(object[i]._ox - plr[pnum]._px); dpy = abs(object[i]._oy - plr[pnum]._py); if (dpx == 1 && dpy <= 1 && object[i]._otype == OBJ_L2LDOOR) OperateL2LDoor(pnum, i, sendflag); if (dpx <= 1 && dpy == 1 && object[i]._otype == OBJ_L2RDOOR) OperateL2RDoor(pnum, i, sendflag); } void OperateL3Door(int pnum, int i, DIABOOL sendflag) { int dpx, dpy; dpx = abs(object[i]._ox - plr[pnum]._px); dpy = abs(object[i]._oy - plr[pnum]._py); if (dpx == 1 && dpy <= 1 && object[i]._otype == OBJ_L3RDOOR) OperateL3RDoor(pnum, i, sendflag); if (dpx <= 1 && dpy == 1 && object[i]._otype == OBJ_L3LDOOR) OperateL3LDoor(pnum, i, sendflag); } void OperatePedistal(int pnum, int i) { BYTE *mem; int iv; if (object[i]._oVar6 != 3) { if (PlrHasItem(pnum, IDI_BLDSTONE, iv)) { RemoveInvItem(pnum, iv); object[i]._oAnimFrame++; object[i]._oVar6++; } if (object[i]._oVar6 == 1) { if (!deltaload) PlaySfxLoc(LS_PUDDLE, object[i]._ox, object[i]._oy); ObjChangeMap(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7); } if (object[i]._oVar6 == 2) { if (!deltaload) PlaySfxLoc(LS_PUDDLE, object[i]._ox, object[i]._oy); ObjChangeMap(setpc_x + 6, setpc_y + 3, setpc_x + setpc_w, setpc_y + 7); } if (object[i]._oVar6 == 3) { if (!deltaload) PlaySfxLoc(LS_BLODSTAR, object[i]._ox, object[i]._oy); ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); mem = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", NULL); LoadMapObjs(mem, 2 * setpc_x, 2 * setpc_y); mem_free_dbg(mem); CreateItem(UITEM_ARMOFVAL, 2 * setpc_x + 25, 2 * setpc_y + 19); object[i]._oSelFlag = 0; } } } void TryDisarm(int pnum, int i) { int j, oi, oti, trapdisper; DIABOOL checkflag; if (pnum == myplr) SetCursor_(CURSOR_HAND); if (object[i]._oTrapFlag) { trapdisper = 2 * plr[pnum]._pDexterity - 5 * currlevel; if (random_(154, 100) <= trapdisper) { for (j = 0; j < nobjects; j++) { checkflag = FALSE; oi = objectactive[j]; oti = object[oi]._otype; if (oti == OBJ_TRAPL) checkflag = TRUE; if (oti == OBJ_TRAPR) checkflag = TRUE; if (checkflag && dObject[object[oi]._oVar1][object[oi]._oVar2] - 1 == i) { object[oi]._oVar4 = 1; object[i]._oTrapFlag = FALSE; } } #ifndef HELLFIRE oti = object[i]._otype; if (oti >= OBJ_TCHEST1 && oti <= OBJ_TCHEST3) object[i]._oTrapFlag = FALSE; #endif } } } int ItemMiscIdIdx(int imiscid) { int i; i = 0; while (AllItemsList[i].iRnd == IDROP_NEVER || AllItemsList[i].iMiscId != imiscid) { i++; } return i; } void OperateShrine(int pnum, int i, int sType) { int cnt; int r, j; DWORD lv, t; int xx, yy; int v1, v2, v3, v4; unsigned __int64 spell, spells; if (dropGoldFlag) { dropGoldFlag = FALSE; dropGoldValue = 0; } /// ASSERT: assert((DWORD)i < MAXOBJECTS); if (object[i]._oSelFlag == 0) return; SetRndSeed(object[i]._oRndSeed); object[i]._oSelFlag = 0; if (!deltaload) { PlaySfxLoc(sType, object[i]._ox, object[i]._oy); object[i]._oAnimFlag = 1; object[i]._oAnimDelay = 1; } else { object[i]._oAnimFrame = object[i]._oAnimLen; object[i]._oAnimFlag = 0; } switch (object[i]._oVar1) { case SHRINE_MYSTERIOUS: if (deltaload) return; if (pnum != myplr) return; ModifyPlrStr(pnum, -1); ModifyPlrMag(pnum, -1); ModifyPlrDex(pnum, -1); ModifyPlrVit(pnum, -1); switch (random_(0, 4)) { case 0: ModifyPlrStr(pnum, 6); break; case 1: ModifyPlrMag(pnum, 6); break; case 2: ModifyPlrDex(pnum, 6); break; case 3: ModifyPlrVit(pnum, 6); break; } CheckStats(pnum); InitDiabloMsg(EMSG_SHRINE_MYSTERIOUS); break; case SHRINE_HIDDEN: cnt = 0; if (deltaload) return; if (pnum != myplr) return; for (j = 0; j < NUM_INVLOC; j++) { if (plr[pnum].InvBody[j]._itype != ITYPE_NONE) cnt++; } if (cnt > 0) { for (j = 0; j < NUM_INVLOC; j++) { if (plr[pnum].InvBody[j]._itype != ITYPE_NONE && plr[pnum].InvBody[j]._iMaxDur != DUR_INDESTRUCTIBLE && plr[pnum].InvBody[j]._iMaxDur != 0) { plr[pnum].InvBody[j]._iDurability += 10; plr[pnum].InvBody[j]._iMaxDur += 10; if (plr[pnum].InvBody[j]._iDurability > plr[pnum].InvBody[j]._iMaxDur) plr[pnum].InvBody[j]._iDurability = plr[pnum].InvBody[j]._iMaxDur; } } while (TRUE) { cnt = 0; for (j = 0; j < NUM_INVLOC; j++) { if (plr[pnum].InvBody[j]._itype != ITYPE_NONE) #ifndef HELLFIRE if (plr[pnum].InvBody[j]._iMaxDur != DUR_INDESTRUCTIBLE && plr[pnum].InvBody[j]._iMaxDur != 0) #endif cnt++; } if (cnt == 0) break; r = random_(0, NUM_INVLOC); if (plr[pnum].InvBody[r]._itype == ITYPE_NONE || plr[pnum].InvBody[r]._iMaxDur == DUR_INDESTRUCTIBLE || plr[pnum].InvBody[r]._iMaxDur == 0) continue; plr[pnum].InvBody[r]._iDurability -= 20; plr[pnum].InvBody[r]._iMaxDur -= 20; if (plr[pnum].InvBody[r]._iDurability <= 0) plr[pnum].InvBody[r]._iDurability = 1; if (plr[pnum].InvBody[r]._iMaxDur <= 0) plr[pnum].InvBody[r]._iMaxDur = 1; break; } } InitDiabloMsg(EMSG_SHRINE_HIDDEN); break; case SHRINE_GLOOMY: if (deltaload) return; if (pnum != myplr) break; if (plr[pnum].InvBody[INVLOC_HEAD]._itype != ITYPE_NONE) plr[pnum].InvBody[INVLOC_HEAD]._iAC += 2; if (plr[pnum].InvBody[INVLOC_CHEST]._itype != ITYPE_NONE) plr[pnum].InvBody[INVLOC_CHEST]._iAC += 2; if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE) { if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD) { plr[pnum].InvBody[INVLOC_HAND_LEFT]._iAC += 2; } else { plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMaxDam--; if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMaxDam < plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMinDam) plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMaxDam = plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMinDam; } } if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE) { if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD) { plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iAC += 2; } else { plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMaxDam--; if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMaxDam < plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMinDam) plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMaxDam = plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMinDam; } } for (j = 0; j < plr[pnum]._pNumInv; j++) { switch (plr[pnum].InvList[j]._itype) { case ITYPE_SWORD: case ITYPE_AXE: case ITYPE_BOW: case ITYPE_MACE: case ITYPE_STAFF: plr[pnum].InvList[j]._iMaxDam--; if (plr[pnum].InvList[j]._iMaxDam < plr[pnum].InvList[j]._iMinDam) plr[pnum].InvList[j]._iMaxDam = plr[pnum].InvList[j]._iMinDam; break; case ITYPE_SHIELD: case ITYPE_HELM: case ITYPE_LARMOR: case ITYPE_MARMOR: case ITYPE_HARMOR: plr[pnum].InvList[j]._iAC += 2; break; } } InitDiabloMsg(EMSG_SHRINE_GLOOMY); break; case SHRINE_WEIRD: if (deltaload) return; if (pnum != myplr) break; if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_SHIELD) plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMaxDam++; if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_SHIELD) plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMaxDam++; for (j = 0; j < plr[pnum]._pNumInv; j++) { switch (plr[pnum].InvList[j]._itype) { case ITYPE_SWORD: case ITYPE_AXE: case ITYPE_BOW: case ITYPE_MACE: case ITYPE_STAFF: plr[pnum].InvList[j]._iMaxDam++; break; } } InitDiabloMsg(EMSG_SHRINE_WEIRD); break; case SHRINE_MAGICAL: case SHRINE_MAGICAL2: if (deltaload) return; AddMissile( plr[pnum]._px, plr[pnum]._py, plr[pnum]._px, plr[pnum]._py, plr[pnum]._pdir, MIS_MANASHIELD, -1, pnum, 0, 2 * leveltype); if (pnum != myplr) return; InitDiabloMsg(EMSG_SHRINE_MAGICAL); break; case SHRINE_STONE: if (deltaload) return; if (pnum != myplr) break; for (j = 0; j < NUM_INVLOC; j++) { if (plr[pnum].InvBody[j]._itype == ITYPE_STAFF) plr[pnum].InvBody[j]._iCharges = plr[pnum].InvBody[j]._iMaxCharges; } for (j = 0; j < plr[pnum]._pNumInv; j++) { if (plr[pnum].InvList[j]._itype == ITYPE_STAFF) plr[pnum].InvList[j]._iCharges = plr[pnum].InvList[j]._iMaxCharges; } for (j = 0; j < MAXBELTITEMS; j++) { if (plr[pnum].SpdList[j]._itype == ITYPE_STAFF) plr[pnum].SpdList[j]._iCharges = plr[pnum].SpdList[j]._iMaxCharges; // belt items don't have charges? } InitDiabloMsg(EMSG_SHRINE_STONE); break; case SHRINE_RELIGIOUS: if (deltaload) return; if (pnum != myplr) break; for (j = 0; j < NUM_INVLOC; j++) plr[pnum].InvBody[j]._iDurability = plr[pnum].InvBody[j]._iMaxDur; for (j = 0; j < plr[pnum]._pNumInv; j++) plr[pnum].InvList[j]._iDurability = plr[pnum].InvList[j]._iMaxDur; for (j = 0; j < MAXBELTITEMS; j++) plr[pnum].SpdList[j]._iDurability = plr[pnum].SpdList[j]._iMaxDur; // belt items don't have durability? InitDiabloMsg(EMSG_SHRINE_RELIGIOUS); break; case SHRINE_ENCHANTED: if (deltaload) return; if (pnum != myplr) return; cnt = 0; spell = 1; spells = plr[pnum]._pMemSpells; for (j = 0; j < MAX_SPELLS; j++) { #ifdef HELLFIRE if (spell & plr[pnum]._pMemSpells) #else if (spell & spells) #endif cnt++; spell <<= 1; } if (cnt > 1) { spell = 1; for (j = SPL_FIREBOLT; j <= MAX_SPELLS; j++) { // BUGFIX: < MAX_SPELLS, there is no spell with MAX_SPELLS index if (plr[pnum]._pMemSpells & spell) { if (plr[pnum]._pSplLvl[j] < MAX_SPELL_LEVEL) plr[pnum]._pSplLvl[j]++; } spell <<= 1; } do { r = random_(0, MAX_SPELLS); } while (!(plr[pnum]._pMemSpells & SPELLBIT(r + 1))); if (plr[pnum]._pSplLvl[r + 1] >= 2) plr[pnum]._pSplLvl[r + 1] -= 2; else plr[pnum]._pSplLvl[r + 1] = 0; } InitDiabloMsg(EMSG_SHRINE_ENCHANTED); break; case SHRINE_THAUMATURGIC: for (j = 0; j < nobjects; j++) { v1 = objectactive[j]; /// ASSERT: assert((DWORD)v1 < MAXOBJECTS); if ((object[v1]._otype == OBJ_CHEST1 || object[v1]._otype == OBJ_CHEST2 || object[v1]._otype == OBJ_CHEST3) && object[v1]._oSelFlag == 0) { object[v1]._oRndSeed = GetRndSeed(); object[v1]._oSelFlag = 1; object[v1]._oAnimFrame -= 2; } } if (deltaload) return; if (pnum == myplr) InitDiabloMsg(EMSG_SHRINE_THAUMATURGIC); break; case SHRINE_FASCINATING: if (deltaload) return; if (pnum != myplr) return; plr[pnum]._pMemSpells |= SPELLBIT(SPL_FIREBOLT); if (plr[pnum]._pSplLvl[SPL_FIREBOLT] < MAX_SPELL_LEVEL) plr[pnum]._pSplLvl[SPL_FIREBOLT]++; if (plr[pnum]._pSplLvl[SPL_FIREBOLT] < MAX_SPELL_LEVEL) plr[pnum]._pSplLvl[SPL_FIREBOLT]++; t = plr[pnum]._pMaxManaBase / 10; v1 = plr[pnum]._pMana - plr[pnum]._pManaBase; v2 = plr[pnum]._pMaxMana - plr[pnum]._pMaxManaBase; plr[pnum]._pManaBase -= t; plr[pnum]._pMana -= t; plr[pnum]._pMaxMana -= t; plr[pnum]._pMaxManaBase -= t; if (plr[pnum]._pMana >> 6 <= 0) { plr[pnum]._pMana = v1; plr[pnum]._pManaBase = 0; } if (plr[pnum]._pMaxMana >> 6 <= 0) { plr[pnum]._pMaxMana = v2; plr[pnum]._pMaxManaBase = 0; } InitDiabloMsg(EMSG_SHRINE_FASCINATING); break; case SHRINE_CRYPTIC: if (deltaload) return; AddMissile( plr[pnum]._px, plr[pnum]._py, plr[pnum]._px, plr[pnum]._py, plr[pnum]._pdir, MIS_NOVA, -1, pnum, 0, 2 * leveltype); if (pnum != myplr) return; plr[pnum]._pMana = plr[pnum]._pMaxMana; plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase; InitDiabloMsg(EMSG_SHRINE_CRYPTIC); break; case SHRINE_ELDRITCH: /// BUGFIX: change `plr[pnum].HoldItem` to use a temporary buffer to prevent deleting item in hand if (deltaload) return; if (pnum != myplr) break; for (j = 0; j < plr[pnum]._pNumInv; j++) { if (plr[pnum].InvList[j]._itype == ITYPE_MISC) { if (plr[pnum].InvList[j]._iMiscId == IMISC_HEAL || plr[pnum].InvList[j]._iMiscId == IMISC_MANA) { SetPlrHandItem(&plr[pnum].HoldItem, ItemMiscIdIdx(IMISC_REJUV)); GetPlrHandSeed(&plr[pnum].HoldItem); plr[pnum].HoldItem._iStatFlag = TRUE; plr[pnum].InvList[j] = plr[pnum].HoldItem; } if (plr[pnum].InvList[j]._iMiscId == IMISC_FULLHEAL || plr[pnum].InvList[j]._iMiscId == IMISC_FULLMANA) { SetPlrHandItem(&plr[pnum].HoldItem, ItemMiscIdIdx(IMISC_FULLREJUV)); GetPlrHandSeed(&plr[pnum].HoldItem); plr[pnum].HoldItem._iStatFlag = TRUE; plr[pnum].InvList[j] = plr[pnum].HoldItem; } } } for (j = 0; j < MAXBELTITEMS; j++) { if (plr[pnum].SpdList[j]._itype == ITYPE_MISC) { if (plr[pnum].SpdList[j]._iMiscId == IMISC_HEAL || plr[pnum].SpdList[j]._iMiscId == IMISC_MANA) { SetPlrHandItem(&plr[pnum].HoldItem, ItemMiscIdIdx(IMISC_REJUV)); GetPlrHandSeed(&plr[pnum].HoldItem); plr[pnum].HoldItem._iStatFlag = TRUE; plr[pnum].SpdList[j] = plr[pnum].HoldItem; } if (plr[pnum].SpdList[j]._iMiscId == IMISC_FULLHEAL || plr[pnum].SpdList[j]._iMiscId == IMISC_FULLMANA) { SetPlrHandItem(&plr[pnum].HoldItem, ItemMiscIdIdx(IMISC_FULLREJUV)); GetPlrHandSeed(&plr[pnum].HoldItem); plr[pnum].HoldItem._iStatFlag = TRUE; plr[pnum].SpdList[j] = plr[pnum].HoldItem; } } } InitDiabloMsg(EMSG_SHRINE_ELDRITCH); break; case SHRINE_EERIE: if (deltaload) return; if (pnum != myplr) return; ModifyPlrMag(pnum, 2); CheckStats(pnum); InitDiabloMsg(EMSG_SHRINE_EERIE); break; case SHRINE_DIVINE: if (deltaload) return; if (pnum != myplr) return; if (2 * currlevel < 7) { CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLMANA, FALSE, TRUE); CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLHEAL, FALSE, TRUE); } else { CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLREJUV, FALSE, TRUE); CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLREJUV, FALSE, TRUE); } plr[pnum]._pMana = plr[pnum]._pMaxMana; plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase; plr[pnum]._pHitPoints = plr[pnum]._pMaxHP; plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase; InitDiabloMsg(EMSG_SHRINE_DIVINE); break; case SHRINE_HOLY: if (deltaload) return; j = 0; do { xx = random_(159, MAXDUNX); yy = random_(159, MAXDUNY); lv = dPiece[xx][yy]; j++; // BUGFIX: should not cast phasing if still on bad tile after max amount of tries. if (j > MAXDUNX * MAXDUNY) break; } while (nSolidTable[lv] || dObject[xx][yy] != 0 || dMonster[xx][yy] != 0); AddMissile(plr[pnum]._px, plr[pnum]._py, xx, yy, plr[pnum]._pdir, MIS_RNDTELEPORT, -1, pnum, 0, 2 * leveltype); if (pnum != myplr) return; InitDiabloMsg(EMSG_SHRINE_HOLY); break; case SHRINE_SACRED: if (deltaload || pnum != myplr) return; plr[pnum]._pMemSpells |= SPELLBIT(SPL_CBOLT); if (plr[pnum]._pSplLvl[SPL_CBOLT] < MAX_SPELL_LEVEL) plr[pnum]._pSplLvl[SPL_CBOLT]++; if (plr[pnum]._pSplLvl[SPL_CBOLT] < MAX_SPELL_LEVEL) plr[pnum]._pSplLvl[SPL_CBOLT]++; t = plr[pnum]._pMaxManaBase / 10; v1 = plr[pnum]._pMana - plr[pnum]._pManaBase; v2 = plr[pnum]._pMaxMana - plr[pnum]._pMaxManaBase; plr[pnum]._pManaBase -= t; plr[pnum]._pMana -= t; plr[pnum]._pMaxMana -= t; plr[pnum]._pMaxManaBase -= t; if (plr[pnum]._pMana >> 6 <= 0) { plr[pnum]._pMana = v1; plr[pnum]._pManaBase = 0; } if (plr[pnum]._pMaxMana >> 6 <= 0) { plr[pnum]._pMaxMana = v2; plr[pnum]._pMaxManaBase = 0; } InitDiabloMsg(EMSG_SHRINE_SACRED); break; case SHRINE_SPIRITUAL: if (deltaload) return; if (pnum != myplr) return; for (j = 0; j < NUM_INV_GRID_ELEM; j++) { if (plr[pnum].InvGrid[j] == 0) { r = 5 * leveltype + random_(160, 10 * leveltype); t = plr[pnum]._pNumInv; // check plr[pnum].InvList[t] = golditem; plr[pnum].InvList[t]._iSeed = GetRndSeed(); plr[pnum]._pNumInv++; plr[pnum].InvGrid[j] = plr[pnum]._pNumInv; plr[pnum].InvList[t]._ivalue = r; plr[pnum]._pGold += r; SetGoldCurs(pnum, t); } } InitDiabloMsg(EMSG_SHRINE_SPIRITUAL); break; case SHRINE_SPOOKY: if (deltaload) return; if (pnum == myplr) { InitDiabloMsg(EMSG_SHRINE_SPOOKY1); } else { InitDiabloMsg(EMSG_SHRINE_SPOOKY2); plr[myplr]._pHitPoints = plr[myplr]._pMaxHP; plr[myplr]._pHPBase = plr[myplr]._pMaxHPBase; plr[myplr]._pMana = plr[myplr]._pMaxMana; plr[myplr]._pManaBase = plr[myplr]._pMaxManaBase; } break; case SHRINE_ABANDONED: if (deltaload) return; if (pnum != myplr) return; ModifyPlrDex(pnum, 2); CheckStats(pnum); if (pnum == myplr) InitDiabloMsg(EMSG_SHRINE_ABANDONED); break; case SHRINE_CREEPY: if (deltaload) return; if (pnum != myplr) return; ModifyPlrStr(pnum, 2); CheckStats(pnum); if (pnum == myplr) InitDiabloMsg(EMSG_SHRINE_CREEPY); break; case SHRINE_QUIET: if (deltaload) return; if (pnum != myplr) return; ModifyPlrVit(pnum, 2); CheckStats(pnum); if (pnum == myplr) InitDiabloMsg(EMSG_SHRINE_QUIET); break; case SHRINE_SECLUDED: if (deltaload) return; if (pnum != myplr) break; for (yy = 0; yy < DMAXY; yy++) { for (xx = 0; xx < DMAXX; xx++) { automapview[xx][yy] = TRUE; } } InitDiabloMsg(EMSG_SHRINE_SECLUDED); break; case SHRINE_ORNATE: if (deltaload) return; if (pnum != myplr) return; plr[pnum]._pMemSpells |= SPELLBIT(SPL_HBOLT); if (plr[pnum]._pSplLvl[SPL_HBOLT] < MAX_SPELL_LEVEL) plr[pnum]._pSplLvl[SPL_HBOLT]++; if (plr[pnum]._pSplLvl[SPL_HBOLT] < MAX_SPELL_LEVEL) plr[pnum]._pSplLvl[SPL_HBOLT]++; t = plr[pnum]._pMaxManaBase / 10; v1 = plr[pnum]._pMana - plr[pnum]._pManaBase; v2 = plr[pnum]._pMaxMana - plr[pnum]._pMaxManaBase; plr[pnum]._pManaBase -= t; plr[pnum]._pMana -= t; plr[pnum]._pMaxMana -= t; plr[pnum]._pMaxManaBase -= t; if (plr[pnum]._pMana >> 6 <= 0) { plr[pnum]._pMana = v1; plr[pnum]._pManaBase = 0; } if (plr[pnum]._pMaxMana >> 6 <= 0) { plr[pnum]._pMaxMana = v2; plr[pnum]._pMaxManaBase = 0; } InitDiabloMsg(EMSG_SHRINE_ORNATE); break; case SHRINE_GLIMMERING: if (deltaload) return; if (pnum != myplr) return; for (j = 0; j < NUM_INVLOC; j++) { if (plr[pnum].InvBody[j]._iMagical && !plr[pnum].InvBody[j]._iIdentified) plr[pnum].InvBody[j]._iIdentified = TRUE; } for (j = 0; j < plr[pnum]._pNumInv; j++) { if (plr[pnum].InvList[j]._iMagical && !plr[pnum].InvList[j]._iIdentified) plr[pnum].InvList[j]._iIdentified = TRUE; } for (j = 0; j < MAXBELTITEMS; j++) { if (plr[pnum].SpdList[j]._iMagical && !plr[pnum].SpdList[j]._iIdentified) plr[pnum].SpdList[j]._iIdentified = TRUE; // belt items can't be magical? } InitDiabloMsg(EMSG_SHRINE_GLIMMERING); break; case SHRINE_TAINTED: if (deltaload) return; if (pnum == myplr) { InitDiabloMsg(EMSG_SHRINE_TAINTED1); } else { InitDiabloMsg(EMSG_SHRINE_TAINTED2); r = random_(155, 4); if (r != 0) v1 = -1; else v1 = 1; if (r != 1) v2 = -1; else v2 = 1; if (r == 2) v3 = 1; else v3 = -1; if (r == 3) v4 = 1; else v4 = -1; ModifyPlrStr(myplr, v1); ModifyPlrMag(myplr, v2); ModifyPlrDex(myplr, v3); ModifyPlrVit(myplr, v4); CheckStats(myplr); } break; #ifdef HELLFIRE case SHRINE_OILY: if (deltaload) return; if (pnum != myplr) return; InitDiabloMsg(EMSG_SHRINE_OILY); switch (plr[myplr]._pClass) { case PC_WARRIOR: ModifyPlrStr(myplr, 2); break; case PC_ROGUE: ModifyPlrDex(myplr, 2); break; case PC_SORCERER: ModifyPlrMag(myplr, 2); break; case PC_BARBARIAN: ModifyPlrVit(myplr, 2); break; case PC_MONK: ModifyPlrStr(myplr, 1); ModifyPlrDex(myplr, 1); break; case PC_BARD: ModifyPlrDex(myplr, 1); ModifyPlrMag(myplr, 1); break; } CheckStats(pnum); AddMissile( object[i]._ox, object[i]._oy, plr[myplr]._px, plr[myplr]._py, plr[myplr]._pdir, MIS_FIREWALL, TARGET_PLAYERS, 0, 2 * currlevel + 2, 0); break; case SHRINE_GLOWING: { if (deltaload) return; if (pnum != myplr) return; InitDiabloMsg(EMSG_SHRINE_GLOWING); int playerXP = plr[myplr]._pExperience; int xpLoss, magicGain; if (playerXP > 5000) { magicGain = 5; xpLoss = (signed __int64)((double)playerXP * 0.95); } else { magicGain = playerXP / 1000; xpLoss = 0; } ModifyPlrMag(myplr, magicGain); plr[myplr]._pExperience = xpLoss; CheckStats(pnum); } break; case SHRINE_MENDICANT: { if (deltaload) return; if (pnum != myplr) return; InitDiabloMsg(EMSG_SHRINE_MENDICANT); int gold = plr[myplr]._pGold / 2; AddPlrExperience(myplr, plr[myplr]._pLevel, gold); TakePlrsMoney(gold); CheckStats(pnum); } break; case SHRINE_SPARKLING: if (deltaload) return; if (pnum != myplr) return; InitDiabloMsg(EMSG_SHRINE_SPARKLING); AddPlrExperience(myplr, plr[myplr]._pLevel, 1000 * currlevel); AddMissile( object[i]._ox, object[i]._oy, plr[myplr]._px, plr[myplr]._py, plr[myplr]._pdir, MIS_FLASH, TARGET_PLAYERS, 0, 3 * currlevel + 2, 0); CheckStats(pnum); break; case SHRINE_TOWN: if (deltaload) return; if (pnum != myplr) return; InitDiabloMsg(EMSG_SHRINE_TOWN); AddMissile( object[i]._ox, object[i]._oy, plr[myplr]._px, plr[myplr]._py, plr[myplr]._pdir, MIS_TOWN, TARGET_PLAYERS, 0, 0, 0); break; case SHRINE_SHIMMERING: if (deltaload) return; if (pnum != myplr) return; InitDiabloMsg(EMSG_SHRINE_SHIMMERING); plr[pnum]._pMana = plr[pnum]._pMaxMana; plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase; break; case SHRINE_SOLAR: { if (deltaload) return; if (pnum != myplr) return; time_t tm = time(0); int hour = localtime(&tm)->tm_hour; if (hour > 20 || hour < 4) { InitDiabloMsg(EMSG_SHRINE_SOLAR4); ModifyPlrVit(myplr, 2); } else if (hour > 18) { InitDiabloMsg(EMSG_SHRINE_SOLAR3); ModifyPlrMag(myplr, 2); } else if (hour > 12) { InitDiabloMsg(EMSG_SHRINE_SOLAR2); ModifyPlrStr(myplr, 2); } else if (hour > 4) { InitDiabloMsg(EMSG_SHRINE_SOLAR1); ModifyPlrDex(myplr, 2); } CheckStats(pnum); } break; case SHRINE_MURPHYS: if (deltaload) return; if (pnum != myplr) return; InitDiabloMsg(EMSG_SHRINE_MURPHYS); BOOL broke = FALSE; for (int j = 0; j < NUM_INVLOC; j++) { ItemStruct *item = &plr[myplr].InvBody[j]; if (item->_itype != ITYPE_NONE && random_(0, 3) == 0) { if (item->_iDurability != DUR_INDESTRUCTIBLE) { if (item->_iDurability) { item->_iDurability /= 2; broke = TRUE; break; } } } } if (!broke) { TakePlrsMoney(plr[myplr]._pGold / 3); } break; #endif } CalcPlrInv(pnum, TRUE); force_redraw = 255; if (pnum == myplr) NetSendCmdParam2(FALSE, CMD_PLROPOBJ, pnum, i); } void OperateSkelBook(int pnum, int i, DIABOOL sendmsg) { if (object[i]._oSelFlag != 0) { if (!deltaload) PlaySfxLoc(IS_ISCROL, object[i]._ox, object[i]._oy); object[i]._oSelFlag = 0; object[i]._oAnimFrame += 2; if (!deltaload) { SetRndSeed(object[i]._oRndSeed); if (random_(161, 5) != 0) CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_SCROLL, sendmsg, FALSE); else CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_BOOK, sendmsg, FALSE); if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } } } void OperateBookCase(int pnum, int i, DIABOOL sendmsg) { if (object[i]._oSelFlag != 0) { if (!deltaload) PlaySfxLoc(IS_ISCROL, object[i]._ox, object[i]._oy); object[i]._oSelFlag = 0; object[i]._oAnimFrame -= 2; if (!deltaload) { SetRndSeed(object[i]._oRndSeed); CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_BOOK, sendmsg, FALSE); if (QuestStatus(Q_ZHAR) && monster[MAX_PLRS].mName == UniqMonst[UMT_ZHAR].mName && monster[MAX_PLRS]._msquelch == UCHAR_MAX && monster[MAX_PLRS]._mhitpoints != 0) { monster[MAX_PLRS].mtalkmsg = TEXT_ZHAR2; M_StartStand(0, monster[MAX_PLRS]._mdir); // BUGFIX: first parameter in call to M_StartStand should be MAX_PLRS, not 0. monster[MAX_PLRS]._mgoal = MGOAL_ATTACK2; monster[MAX_PLRS]._mmode = MM_TALK; } if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } } } void OperateDecap(int pnum, int i, DIABOOL sendmsg) { if (object[i]._oSelFlag != 0) { object[i]._oSelFlag = 0; if (!deltaload) { SetRndSeed(object[i]._oRndSeed); CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE); if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } } } void OperateArmorStand(int pnum, int i, DIABOOL sendmsg) { BOOL uniqueRnd; if (object[i]._oSelFlag != 0) { object[i]._oSelFlag = 0; object[i]._oAnimFrame++; if (!deltaload) { SetRndSeed(object[i]._oRndSeed); uniqueRnd = random_(0, 2); if (currlevel <= 5) { CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, ITYPE_LARMOR, IMISC_NONE, sendmsg, FALSE); } else if (currlevel >= 6 && currlevel <= 9) { CreateTypeItem(object[i]._ox, object[i]._oy, uniqueRnd, ITYPE_MARMOR, IMISC_NONE, sendmsg, FALSE); } else if (currlevel >= 10 && currlevel <= 12) { CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_HARMOR, IMISC_NONE, sendmsg, FALSE); } else if (currlevel >= 13 && currlevel <= 16) { CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, ITYPE_HARMOR, IMISC_NONE, sendmsg, FALSE); #ifdef HELLFIRE } else if (currlevel >= 17) { CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, ITYPE_HARMOR, IMISC_NONE, sendmsg, FALSE); #endif } if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); return; } } } int FindValidShrine(int i) { int rv; DIABOOL done; done = FALSE; do { rv = random_(0, NUM_SHRINETYPE); if (currlevel >= shrinemin[rv] && currlevel <= shrinemax[rv] && rv != SHRINE_THAUMATURGIC) { done = TRUE; } if (done) { if (gbMaxPlayers != 1) { if (shrineavail[rv] == 1) { done = FALSE; continue; } } if (gbMaxPlayers == 1) { if (shrineavail[rv] == 2) { done = FALSE; continue; } } done = TRUE; } } while (!done); return rv; } void OperateGoatShrine(int pnum, int i, int sType) { SetRndSeed(object[i]._oRndSeed); object[i]._oVar1 = FindValidShrine(i); OperateShrine(pnum, i, sType); object[i]._oAnimDelay = 2; force_redraw = 255; } void OperateCauldron(int pnum, int i, int sType) { SetRndSeed(object[i]._oRndSeed); object[i]._oVar1 = FindValidShrine(i); OperateShrine(pnum, i, sType); object[i]._oAnimFrame = 3; object[i]._oAnimFlag = 0; force_redraw = 255; } DIABOOL OperateFountains(int pnum, int i) { int prev, add, rnd, cnt; DIABOOL applied; BOOL done; applied = FALSE; SetRndSeed(object[i]._oRndSeed); switch (object[i]._otype) { case OBJ_BLOODFTN: if (deltaload) return FALSE; if (pnum != myplr) return FALSE; if (plr[pnum]._pHitPoints < plr[pnum]._pMaxHP) { PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy); plr[pnum]._pHitPoints += 64; plr[pnum]._pHPBase += 64; if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) { plr[pnum]._pHitPoints = plr[pnum]._pMaxHP; plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase; } applied = TRUE; } else PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy); break; case OBJ_PURIFYINGFTN: if (deltaload) return FALSE; if (pnum != myplr) return FALSE; if (plr[pnum]._pMana < plr[pnum]._pMaxMana) { PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy); plr[pnum]._pMana += 64; plr[pnum]._pManaBase += 64; if (plr[pnum]._pMana > plr[pnum]._pMaxMana) { plr[pnum]._pMana = plr[pnum]._pMaxMana; plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase; } applied = TRUE; } else PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy); break; case OBJ_MURKYFTN: if (object[i]._oSelFlag == 0) break; if (!deltaload) PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy); object[i]._oSelFlag = 0; if (deltaload) return FALSE; AddMissile( plr[pnum]._px, plr[pnum]._py, plr[pnum]._px, plr[pnum]._py, plr[pnum]._pdir, MIS_INFRA, -1, pnum, 0, 2 * leveltype); applied = TRUE; if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); break; case OBJ_TEARFTN: if (object[i]._oSelFlag == 0) break; prev = -1; add = -1; done = FALSE; cnt = 0; if (!deltaload) PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy); object[i]._oSelFlag = 0; if (deltaload) return FALSE; if (pnum != myplr) return FALSE; while (!done) { rnd = random_(0, 4); if (rnd != prev) { switch (rnd) { case 0: ModifyPlrStr(pnum, add); break; case 1: ModifyPlrMag(pnum, add); break; case 2: ModifyPlrDex(pnum, add); break; case 3: ModifyPlrVit(pnum, add); break; } prev = rnd; add = 1; cnt++; } if (cnt <= 1) continue; done = TRUE; } CheckStats(pnum); applied = TRUE; if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); break; } force_redraw = 255; return applied; } void OperateWeaponRack(int pnum, int i, DIABOOL sendmsg) { int weaponType; if (object[i]._oSelFlag == 0) return; SetRndSeed(object[i]._oRndSeed); switch (random_(0, 4) + ITYPE_SWORD) { case ITYPE_SWORD: weaponType = ITYPE_SWORD; break; case ITYPE_AXE: weaponType = ITYPE_AXE; break; case ITYPE_BOW: weaponType = ITYPE_BOW; break; case ITYPE_MACE: weaponType = ITYPE_MACE; break; } object[i]._oSelFlag = 0; object[i]._oAnimFrame++; if (deltaload) return; if (leveltype > 1) CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, weaponType, IMISC_NONE, sendmsg, FALSE); else CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, weaponType, IMISC_NONE, sendmsg, FALSE); if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } void OperateStoryBook(int pnum, int i) { if (object[i]._oSelFlag != 0 && !deltaload && !qtextflag && pnum == myplr) { object[i]._oAnimFrame = object[i]._oVar4; PlaySfxLoc(IS_ISCROL, object[i]._ox, object[i]._oy); #ifdef HELLFIRE if (object[i]._oVar8 != 0 && currlevel == 24) { if (IsUberLeverActivated != 1 && quests[Q_NAKRUL]._qactive != QUEST_DONE && OperateNakrulBook(object[i]._oVar8)) { NetSendCmd(FALSE, CMD_NAKRUL); return; } } else if (currlevel >= 21) { quests[Q_NAKRUL]._qactive = QUEST_ACTIVE; quests[Q_NAKRUL]._qlog = TRUE; quests[Q_NAKRUL]._qmsg = object[i]._oVar2; } #endif InitQTextMsg(object[i]._oVar2); NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } } void OperateLazStand(int pnum, int i) { int xx, yy; if (object[i]._oSelFlag != 0 && !deltaload && !qtextflag && pnum == myplr) { object[i]._oAnimFrame++; object[i]._oSelFlag = 0; GetSuperItemLoc(object[i]._ox, object[i]._oy, xx, yy); SpawnQuestItem(IDI_LAZSTAFF, xx, yy, 0, 0); } } void OperateObject(int pnum, int i, BOOL TeleFlag) { BOOL sendmsg; sendmsg = (pnum == myplr); switch (object[i]._otype) { case OBJ_L1LDOOR: case OBJ_L1RDOOR: if (TeleFlag) { if (object[i]._otype == OBJ_L1LDOOR) OperateL1LDoor(pnum, i, TRUE); if (object[i]._otype == OBJ_L1RDOOR) OperateL1RDoor(pnum, i, TRUE); break; } if (pnum == myplr) OperateL1Door(pnum, i, TRUE); break; case OBJ_L2LDOOR: case OBJ_L2RDOOR: if (TeleFlag) { if (object[i]._otype == OBJ_L2LDOOR) OperateL2LDoor(pnum, i, TRUE); if (object[i]._otype == OBJ_L2RDOOR) OperateL2RDoor(pnum, i, TRUE); break; } if (pnum == myplr) OperateL2Door(pnum, i, TRUE); break; case OBJ_L3LDOOR: case OBJ_L3RDOOR: if (TeleFlag) { if (object[i]._otype == OBJ_L3LDOOR) OperateL3LDoor(pnum, i, TRUE); if (object[i]._otype == OBJ_L3RDOOR) OperateL3RDoor(pnum, i, TRUE); break; } if (pnum == myplr) OperateL3Door(pnum, i, TRUE); break; case OBJ_LEVER: case OBJ_SWITCHSKL: OperateLever(pnum, i); break; case OBJ_BOOK2L: OperateBook(pnum, i); break; case OBJ_BOOK2R: OperateSChambBk(pnum, i); break; case OBJ_CHEST1: case OBJ_CHEST2: case OBJ_CHEST3: case OBJ_TCHEST1: case OBJ_TCHEST2: case OBJ_TCHEST3: OperateChest(pnum, i, sendmsg); break; case OBJ_SARC: OperateSarc(pnum, i, sendmsg); break; case OBJ_FLAMELVR: OperateTrapLvr(i); break; case OBJ_BLINDBOOK: case OBJ_BLOODBOOK: case OBJ_STEELTOME: OperateBookLever(pnum, i); break; case OBJ_SHRINEL: case OBJ_SHRINER: OperateShrine(pnum, i, IS_MAGIC); break; case OBJ_SKELBOOK: case OBJ_BOOKSTAND: OperateSkelBook(pnum, i, sendmsg); break; case OBJ_BOOKCASEL: case OBJ_BOOKCASER: OperateBookCase(pnum, i, sendmsg); break; case OBJ_DECAP: OperateDecap(pnum, i, sendmsg); break; case OBJ_ARMORSTAND: case OBJ_WARARMOR: OperateArmorStand(pnum, i, sendmsg); break; case OBJ_GOATSHRINE: OperateGoatShrine(pnum, i, LS_GSHRINE); break; case OBJ_CAULDRON: OperateCauldron(pnum, i, LS_CALDRON); break; case OBJ_BLOODFTN: case OBJ_PURIFYINGFTN: case OBJ_MURKYFTN: case OBJ_TEARFTN: OperateFountains(pnum, i); break; case OBJ_STORYBOOK: OperateStoryBook(pnum, i); break; case OBJ_PEDISTAL: OperatePedistal(pnum, i); break; case OBJ_WARWEAP: case OBJ_WEAPONRACK: OperateWeaponRack(pnum, i, sendmsg); break; case OBJ_MUSHPATCH: OperateMushPatch(pnum, i); break; case OBJ_LAZSTAND: OperateLazStand(pnum, i); break; case OBJ_SLAINHERO: OperateSlainHero(pnum, i, sendmsg); break; case OBJ_SIGNCHEST: OperateInnSignChest(pnum, i); break; } } void SyncOpL1Door(int pnum, int cmd, int i) { DIABOOL do_sync; if (pnum == myplr) return; do_sync = FALSE; if (cmd == CMD_OPENDOOR && object[i]._oVar4 == 0) { do_sync = TRUE; } if (cmd == CMD_CLOSEDOOR && object[i]._oVar4 == 1) do_sync = TRUE; if (do_sync) { if (object[i]._otype == OBJ_L1LDOOR) OperateL1LDoor(-1, i, FALSE); if (object[i]._otype == OBJ_L1RDOOR) OperateL1RDoor(-1, i, FALSE); } } void SyncOpL2Door(int pnum, int cmd, int i) { DIABOOL do_sync; if (pnum == myplr) return; do_sync = FALSE; if (cmd == CMD_OPENDOOR && object[i]._oVar4 == 0) { do_sync = TRUE; } if (cmd == CMD_CLOSEDOOR && object[i]._oVar4 == 1) do_sync = TRUE; if (do_sync) { if (object[i]._otype == OBJ_L2LDOOR) OperateL2LDoor(-1, i, FALSE); if (object[i]._otype == OBJ_L2RDOOR) OperateL2RDoor(-1, i, FALSE); } } void SyncOpL3Door(int pnum, int cmd, int i) { DIABOOL do_sync; if (pnum == myplr) return; do_sync = FALSE; if (cmd == CMD_OPENDOOR && object[i]._oVar4 == 0) { do_sync = TRUE; } if (cmd == CMD_CLOSEDOOR && object[i]._oVar4 == 1) do_sync = TRUE; if (do_sync) { if (object[i]._otype == OBJ_L3LDOOR) OperateL3LDoor(-1, i, FALSE); if (object[i]._otype == OBJ_L3RDOOR) OperateL3RDoor(-1, i, FALSE); } } void SyncOpObject(int pnum, int cmd, int i) { switch (object[i]._otype) { case OBJ_L1LDOOR: case OBJ_L1RDOOR: SyncOpL1Door(pnum, cmd, i); break; case OBJ_L2LDOOR: case OBJ_L2RDOOR: SyncOpL2Door(pnum, cmd, i); break; case OBJ_L3LDOOR: case OBJ_L3RDOOR: SyncOpL3Door(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, FALSE); break; case OBJ_SARC: OperateSarc(pnum, i, FALSE); break; case OBJ_BLINDBOOK: case OBJ_BLOODBOOK: case OBJ_STEELTOME: OperateBookLever(pnum, i); break; case OBJ_SHRINEL: case OBJ_SHRINER: OperateShrine(pnum, i, IS_MAGIC); break; case OBJ_SKELBOOK: case OBJ_BOOKSTAND: OperateSkelBook(pnum, i, FALSE); break; case OBJ_BOOKCASEL: case OBJ_BOOKCASER: OperateBookCase(pnum, i, FALSE); break; case OBJ_DECAP: OperateDecap(pnum, i, FALSE); break; case OBJ_ARMORSTAND: case OBJ_WARARMOR: OperateArmorStand(pnum, i, FALSE); 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_PEDISTAL: OperatePedistal(pnum, i); break; case OBJ_WARWEAP: case OBJ_WEAPONRACK: OperateWeaponRack(pnum, i, FALSE); break; case OBJ_MUSHPATCH: OperateMushPatch(pnum, i); break; case OBJ_SLAINHERO: OperateSlainHero(pnum, i, FALSE); break; case OBJ_SIGNCHEST: OperateInnSignChest(pnum, i); break; } } void BreakCrux(int i) { int j, oi; DIABOOL triggered; object[i]._oAnimFlag = 1; object[i]._oAnimFrame = 1; object[i]._oAnimDelay = 1; object[i]._oSolidFlag = TRUE; object[i]._oMissFlag = TRUE; object[i]._oBreak = -1; object[i]._oSelFlag = 0; triggered = TRUE; for (j = 0; j < nobjects; j++) { oi = objectactive[j]; if (object[oi]._otype != OBJ_CRUX1 && object[oi]._otype != OBJ_CRUX2 && object[oi]._otype != OBJ_CRUX3) continue; if (object[i]._oVar8 != object[oi]._oVar8 || object[oi]._oBreak == -1) continue; triggered = FALSE; } if (!triggered) return; if (!deltaload) PlaySfxLoc(IS_LEVER, object[i]._ox, object[i]._oy); ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); } void BreakBarrel(int pnum, int i, int dam, BOOL forcebreak, BOOL sendmsg) { int oi; int xp, yp; if (object[i]._oSelFlag == 0) return; if (forcebreak) { object[i]._oVar1 = 0; } else { object[i]._oVar1 -= dam; if (pnum != myplr && object[i]._oVar1 <= 0) object[i]._oVar1 = 1; } if (object[i]._oVar1 > 0) { if (deltaload) return; PlaySfxLoc(IS_IBOW, object[i]._ox, object[i]._oy); return; } object[i]._oVar1 = 0; object[i]._oAnimFlag = 1; object[i]._oAnimFrame = 1; object[i]._oAnimDelay = 1; object[i]._oSolidFlag = FALSE; object[i]._oMissFlag = TRUE; object[i]._oBreak = -1; object[i]._oSelFlag = 0; object[i]._oPreFlag = TRUE; if (deltaload) { object[i]._oAnimFrame = object[i]._oAnimLen; object[i]._oAnimCnt = 0; object[i]._oAnimDelay = 1000; return; } if (object[i]._otype == OBJ_BARRELEX) { #ifdef HELLFIRE if (currlevel >= 21 && currlevel <= 24) PlaySfxLoc(IS_POPPOP3, object[i]._ox, object[i]._oy); else if (currlevel >= 17 && currlevel <= 20) PlaySfxLoc(IS_POPPOP8, object[i]._ox, object[i]._oy); else #endif PlaySfxLoc(IS_BARLFIRE, object[i]._ox, object[i]._oy); for (yp = object[i]._oy - 1; yp <= object[i]._oy + 1; yp++) { for (xp = object[i]._ox - 1; xp <= object[i]._ox + 1; xp++) { if (dMonster[xp][yp] > 0) MonsterTrapHit(dMonster[xp][yp] - 1, 1, 4, 0, MIS_FIREBOLT, FALSE); #ifdef HELLFIRE BOOLEAN unused; if (dPlayer[xp][yp] > 0) PlayerMHit(dPlayer[xp][yp] - 1, -1, 0, 8, 16, MIS_FIREBOLT, FALSE, 0, &unused); #else if (dPlayer[xp][yp] > 0) PlayerMHit(dPlayer[xp][yp] - 1, -1, 0, 8, 16, MIS_FIREBOLT, FALSE, 0); #endif if (dObject[xp][yp] > 0) { oi = dObject[xp][yp] - 1; if (object[oi]._otype == OBJ_BARRELEX && object[oi]._oBreak != -1) BreakBarrel(pnum, oi, dam, TRUE, sendmsg); } } } } else { #ifdef HELLFIRE if (currlevel >= 21 && currlevel <= 24) PlaySfxLoc(IS_POPPOP2, object[i]._ox, object[i]._oy); else if (currlevel >= 17 && currlevel <= 20) PlaySfxLoc(IS_POPPOP5, object[i]._ox, object[i]._oy); else #endif PlaySfxLoc(IS_BARREL, object[i]._ox, object[i]._oy); SetRndSeed(object[i]._oRndSeed); if (object[i]._oVar2 <= 1) { if (object[i]._oVar3 == 0) CreateRndUseful(pnum, object[i]._ox, object[i]._oy, sendmsg); else CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE); } if (object[i]._oVar2 >= 8) SpawnSkeleton(object[i]._oVar4, object[i]._ox, object[i]._oy); } if (pnum == myplr) NetSendCmdParam2(FALSE, CMD_BREAKOBJ, pnum, i); } void BreakObject(int pnum, int oi) { int objdam, mind, maxd; if (pnum != -1) { mind = plr[pnum]._pIMinDam; maxd = plr[pnum]._pIMaxDam; objdam = random_(163, maxd - mind + 1) + mind; objdam += plr[pnum]._pDamageMod + plr[pnum]._pIBonusDamMod + objdam * plr[pnum]._pIBonusDam / 100; } else { objdam = 10; } switch (object[oi]._otype) { case OBJ_CRUX1: case OBJ_CRUX2: case OBJ_CRUX3: BreakCrux(oi); break; case OBJ_BARREL: case OBJ_BARRELEX: BreakBarrel(pnum, oi, objdam, FALSE, TRUE); break; } } void SyncBreakObj(int pnum, int oi) { if (object[oi]._otype >= OBJ_BARREL && object[oi]._otype <= OBJ_BARRELEX) BreakBarrel(pnum, oi, 0, TRUE, FALSE); } void SyncL1Doors(int i) { int x, y; if (object[i]._oVar4 == 0) { object[i]._oMissFlag = FALSE; return; } #ifdef HELLFIRE else #endif object[i]._oMissFlag = TRUE; x = object[i]._ox; y = object[i]._oy; object[i]._oSelFlag = 2; #ifdef HELLFIRE if (currlevel < 17) { #endif if (object[i]._otype == OBJ_L1LDOOR) { if (object[i]._oVar1 == 214) ObjSetMicro(x, y, 408); else ObjSetMicro(x, y, 393); dSpecial[x][y] = 7; objects_set_door_piece(x - 1, y); y--; } else { ObjSetMicro(x, y, 395); #ifdef HELLFIRE if (currlevel < 17) #endif dSpecial[x][y] = 8; objects_set_door_piece(x, y - 1); x--; } #ifdef HELLFIRE } else { if (object[i]._otype == OBJ_L1LDOOR) { ObjSetMicro(x, y, 206); dSpecial[x][y] = 1; objects_set_door_piece(x - 1, y); y--; } else { ObjSetMicro(x, y, 209); dSpecial[x][y] = 2; objects_set_door_piece(x, y - 1); x--; } } #endif DoorSet(i, x, y); } void SyncCrux(int i) { DIABOOL found; int j, oi, type; found = TRUE; for (j = 0; j < nobjects; j++) { oi = objectactive[j]; type = object[oi]._otype; if (type != OBJ_CRUX1 && type != OBJ_CRUX2 && type != OBJ_CRUX3) continue; if (object[i]._oVar8 != object[oi]._oVar8 || object[oi]._oBreak == -1) continue; found = FALSE; } if (found) ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); } void SyncLever(int i) { if (object[i]._oSelFlag == 0) ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); } void SyncQSTLever(int i) { int tren; if (object[i]._oAnimFrame == object[i]._oVar6) { ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); if (object[i]._otype == OBJ_BLINDBOOK) { tren = TransVal; TransVal = 9; DRLG_MRectTrans(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); TransVal = tren; } } } void SyncPedistal(int i) { BYTE *setp; if (object[i]._oVar6 == 1) ObjChangeMapResync(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7); if (object[i]._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[i]._oVar6 == 3) { ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4); setp = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", NULL); LoadMapObjs(setp, 2 * setpc_x, 2 * setpc_y); mem_free_dbg(setp); } } void SyncL2Doors(int i) { int x, y; if (object[i]._oVar4 == 0) object[i]._oMissFlag = FALSE; else object[i]._oMissFlag = TRUE; x = object[i]._ox; y = object[i]._oy; object[i]._oSelFlag = 2; if (object[i]._otype == OBJ_L2LDOOR && object[i]._oVar4 == 0) { ObjSetMicro(x, y, 538); } else if (object[i]._otype == OBJ_L2LDOOR && (object[i]._oVar4 == 1 || object[i]._oVar4 == 2)) { ObjSetMicro(x, y, 13); } else if (object[i]._otype == OBJ_L2RDOOR && object[i]._oVar4 == 0) { ObjSetMicro(x, y, 540); } else if (object[i]._otype == OBJ_L2RDOOR && (object[i]._oVar4 == 1 || object[i]._oVar4 == 2)) { ObjSetMicro(x, y, 17); } } void SyncL3Doors(int i) { int x, y; object[i]._oMissFlag = TRUE; x = object[i]._ox; y = object[i]._oy; object[i]._oSelFlag = 2; if (object[i]._otype == OBJ_L3LDOOR && object[i]._oVar4 == 0) { ObjSetMicro(x, y, 531); } else if (object[i]._otype == OBJ_L3LDOOR && (object[i]._oVar4 == 1 || object[i]._oVar4 == 2)) { ObjSetMicro(x, y, 538); } else if (object[i]._otype == OBJ_L3RDOOR && object[i]._oVar4 == 0) { ObjSetMicro(x, y, 534); } else if (object[i]._otype == OBJ_L3RDOOR && (object[i]._oVar4 == 1 || object[i]._oVar4 == 2)) { ObjSetMicro(x, y, 541); } } void SyncObjectAnim(int o) { int i, index; index = AllObjects[object[o]._otype].ofindex; i = 0; while (ObjFileList[i] != index) { i++; } object[o]._oAnimData = pObjCels[i]; switch (object[o]._otype) { case OBJ_L1LDOOR: case OBJ_L1RDOOR: SyncL1Doors(o); break; case OBJ_L2LDOOR: case OBJ_L2RDOOR: SyncL2Doors(o); break; case OBJ_L3LDOOR: case OBJ_L3RDOOR: SyncL3Doors(o); break; case OBJ_CRUX1: case OBJ_CRUX2: case OBJ_CRUX3: SyncCrux(o); break; case OBJ_LEVER: case OBJ_BOOK2L: case OBJ_SWITCHSKL: SyncLever(o); break; case OBJ_BOOK2R: case OBJ_BLINDBOOK: case OBJ_STEELTOME: SyncQSTLever(o); break; case OBJ_PEDISTAL: SyncPedistal(o); break; } } void GetObjectStr(int i) { switch (object[i]._otype) { case OBJ_CRUX1: case OBJ_CRUX2: case OBJ_CRUX3: strcpy(infostr, "Crucified Skeleton"); break; case OBJ_LEVER: case OBJ_FLAMELVR: strcpy(infostr, "Lever"); break; case OBJ_L1LDOOR: case OBJ_L1RDOOR: case OBJ_L2LDOOR: case OBJ_L2RDOOR: case OBJ_L3LDOOR: case OBJ_L3RDOOR: if (object[i]._oVar4 == 1) strcpy(infostr, "Open Door"); if (object[i]._oVar4 == 0) strcpy(infostr, "Closed Door"); if (object[i]._oVar4 == 2) strcpy(infostr, "Blocked Door"); 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_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_SARC: strcpy(infostr, "Sarcophagus"); break; case OBJ_BOOKSHELF: strcpy(infostr, "Bookshelf"); break; case OBJ_BOOKCASEL: case OBJ_BOOKCASER: strcpy(infostr, "Bookcase"); break; case OBJ_BARREL: case OBJ_BARRELEX: #ifdef HELLFIRE if (currlevel >= 17 && currlevel <= 20) // for hive levels strcpy(infostr, "Pod"); //Then a barrel is called a pod else if (currlevel >= 21 && currlevel <= 24) // for crypt levels strcpy(infostr, "Urn"); //Then a barrel is called an urn else #endif strcpy(infostr, "Barrel"); break; case OBJ_SHRINEL: case OBJ_SHRINER: sprintf(tempstr, "%s Shrine", shrinestrs[object[i]._oVar1]); strcpy(infostr, tempstr); break; case OBJ_SKELBOOK: strcpy(infostr, "Skeleton Tome"); 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_PURIFYINGFTN: strcpy(infostr, "Purifying Spring"); break; case OBJ_ARMORSTAND: case OBJ_WARARMOR: strcpy(infostr, "Armor"); break; case OBJ_WARWEAP: strcpy(infostr, "Weapon Rack"); 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_STEELTOME: strcpy(infostr, "Steel Tome"); break; case OBJ_PEDISTAL: strcpy(infostr, "Pedestal of Blood"); break; case OBJ_STORYBOOK: strcpy(infostr, StoryBookName[object[i]._oVar3]); break; 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; } if (plr[myplr]._pClass == PC_ROGUE) { if (object[i]._oTrapFlag) { sprintf(tempstr, "Trapped %s", infostr); strcpy(infostr, tempstr); infoclr = COL_RED; } } } #ifdef HELLFIRE void OperateNakrulLever() { if (currlevel == 24) { PlaySfxLoc(IS_CROPEN, UberRow, UberCol); //the part below is the same as SyncNakrulRoom dPiece[UberRow][UberCol] = 298; dPiece[UberRow][UberCol - 1] = 301; dPiece[UberRow][UberCol - 2] = 300; dPiece[UberRow][UberCol + 1] = 299; SetDungeonMicros(); } } void SyncNakrulRoom() { dPiece[UberRow][UberCol] = 298; dPiece[UberRow][UberCol - 1] = 301; dPiece[UberRow][UberCol - 2] = 300; dPiece[UberRow][UberCol + 1] = 299; SetDungeonMicros(); } void AddNakrulLeaver() { int xp, yp; while (1) { xp = random_(141, 80) + 16; yp = random_(141, 80) + 16; if (RndLocOk(xp - 1, yp - 1) && RndLocOk(xp, yp - 1) && RndLocOk(xp + 1, yp - 1) && RndLocOk(xp - 1, yp) && RndLocOk(xp, yp) && RndLocOk(xp + 1, yp) && RndLocOk(xp - 1, yp + 1) && RndLocOk(xp, yp + 1) && RndLocOk(xp + 1, yp + 1)) { break; } } UberLeverRow = UberRow + 3; UberLeverCol = UberCol - 1; AddObject(OBJ_LEVER, UberRow + 3, UberCol - 1); } DIABOOL OperateNakrulBook(int s) { switch (s) { case 6: dword_6DE0E0 = 1; break; case 7: if (dword_6DE0E0 == 1) { dword_6DE0E0 = 2; } else { dword_6DE0E0 = 0; } break; case 8: if (dword_6DE0E0 == 2) return TRUE; dword_6DE0E0 = 0; break; } return FALSE; } #endif ================================================ FILE: Source/objects.h ================================================ /** * @file objects.h * * Interface of object functionality, interaction, spawning, loading, etc. */ #ifndef __OBJECTS_H__ #define __OBJECTS_H__ extern int objectactive[MAXOBJECTS]; extern int nobjects; extern int objectavail[MAXOBJECTS]; extern ObjectStruct object[MAXOBJECTS]; extern BOOL InitObjFlag; void InitObjectGFX(); void FreeObjectGFX(); void AddL1Objs(int x1, int y1, int x2, int y2); void AddL2Objs(int x1, int y1, int x2, int y2); void InitObjects(); void SetMapObjects(BYTE *pMap, int startx, int starty); void SetObjMapRange(int i, int x1, int y1, int x2, int y2, int v); void SetBookMsg(int i, int msg); void GetRndObjLoc(int randarea, int &xx, int &yy); void AddMushPatch(); void AddSlainHero(); #ifdef HELLFIRE void AddCryptBook(int ot, int v2, int ox, int oy); void AddCryptObject(int a1, int a2); void AddNakrulBook(int a1, int a2, int a3); #endif void AddObject(int ot, int ox, int oy); void Obj_Trap(int i); void ProcessObjects(); void ObjSetMicro(int dx, int dy, int pn); void RedoPlayerVision(); void MonstCheckDoors(int m); void ObjChangeMap(int x1, int y1, int x2, int y2); void ObjChangeMapResync(int x1, int y1, int x2, int y2); void TryDisarm(int pnum, int i); int ItemMiscIdIdx(int imiscid); void OperateObject(int pnum, int i, BOOL TeleFlag); void SyncOpObject(int pnum, int cmd, int i); void BreakObject(int pnum, int oi); void SyncBreakObj(int pnum, int oi); void SyncObjectAnim(int o); void GetObjectStr(int i); #ifdef HELLFIRE void OperateNakrulLever(); void SyncNakrulRoom(); void AddNakrulLeaver(); DIABOOL OperateNakrulBook(int s); #endif #endif /* __OBJECTS_H__ */ ================================================ FILE: Source/pack.cpp ================================================ /** * @file pack.cpp * * Implementation of functions for minifying player data structure. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" #ifndef HELLFIRE static #endif void PackItem(PkItemStruct *id, ItemStruct *is) { if (is->_itype == ITYPE_NONE) { id->idx = 0xFFFF; } else { id->idx = is->IDidx; if (is->IDidx == IDI_EAR) { id->iCreateInfo = is->_iName[8] | (is->_iName[7] << 8); 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]; id->wValue = is->_ivalue | (is->_iName[18] << 8) | ((is->_iCurs - ICURS_EAR_SORCEROR) << 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 = is->_iIdentified + 2 * is->_iMagical; id->bDur = is->_iDurability; id->bMDur = is->_iMaxDur; id->bCh = is->_iCharges; id->bMCh = is->_iMaxCharges; if (is->IDidx == IDI_GOLD) id->wValue = is->_ivalue; } } } #ifdef HELLFIRE void PackPlayer(PkPlayerStruct *pPack, int pnum) #else void PackPlayer(PkPlayerStruct *pPack, int pnum, BOOL manashield) #endif { PlayerStruct *pPlayer; int i; ItemStruct *pi; PkItemStruct *pki; memset(pPack, 0, sizeof(*pPack)); pPlayer = &plr[pnum]; pPack->destAction = pPlayer->destAction; pPack->destParam1 = pPlayer->destParam1; pPack->destParam2 = pPlayer->destParam2; pPack->plrlevel = pPlayer->plrlevel; pPack->px = pPlayer->_px; pPack->py = pPlayer->_py; 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; #ifdef HELLFIRE for (i = 0; i <= 36; i++) // Should be MAX_SPELLS-1 but set to 36 to make save games compatible pPack->pSplLvl[i] = pPlayer->_pSplLvl[i]; char *p = pPack->pSplLvl2; for (i = 37; i < 47; i++) p[i - 37] = pPlayer->_pSplLvl[i]; #else for (i = 0; i < MAX_SPELLS; i++) pPack->pSplLvl[i] = pPlayer->_pSplLvl[i]; #endif pki = &pPack->InvBody[0]; pi = &pPlayer->InvBody[0]; for (i = 0; i < NUM_INVLOC; i++) { PackItem(pki, pi); pki++; pi++; } pki = &pPack->InvList[0]; pi = &pPlayer->InvList[0]; for (i = 0; i < NUM_INV_GRID_ELEM; i++) { PackItem(pki, pi); pki++; pi++; } for (i = 0; i < NUM_INV_GRID_ELEM; i++) pPack->InvGrid[i] = pPlayer->InvGrid[i]; pPack->_pNumInv = pPlayer->_pNumInv; pki = &pPack->SpdList[0]; pi = &pPlayer->SpdList[0]; for (i = 0; i < MAXBELTITEMS; i++) { PackItem(pki, pi); pki++; pi++; } #ifdef HELLFIRE pPack->wReflections = pPlayer->wReflections; pPack->pDiabloKillLevel = pPlayer->pDiabloKillLevel; pPack->pDifficulty = pPlayer->pDifficulty; pPack->pDamAcFlags = pPlayer->pDamAcFlags; #else pPack->pDiabloKillLevel = pPlayer->pDiabloKillLevel; if (gbMaxPlayers == 1 || manashield) pPack->pManaShield = pPlayer->pManaShield; else pPack->pManaShield = FALSE; #endif } /** * Expand a PkItemStruct into an ItemStruct * * Note: last slot of item[MAXITEMS+1] used as temporary buffer * find real name reference below, possibly [sizeof(item[])/sizeof(ItemStruct)] * @param is The source packed item * @param id The destination item */ #ifndef HELLFIRE static #endif void UnPackItem(PkItemStruct *is, ItemStruct *id) { if (is->idx == 0xFFFF) { id->_itype = ITYPE_NONE; } else { if (is->idx == IDI_EAR) { RecreateEar( MAXITEMS, is->iCreateInfo, is->iSeed, is->bId, is->bDur, is->bMDur, is->bCh, is->bMCh, is->wValue, is->dwBuff); } else { RecreateItem(MAXITEMS, is->idx, is->iCreateInfo, is->iSeed, is->wValue); item[MAXITEMS]._iMagical = is->bId >> 1; item[MAXITEMS]._iIdentified = is->bId & 1; item[MAXITEMS]._iDurability = is->bDur; item[MAXITEMS]._iMaxDur = is->bMDur; item[MAXITEMS]._iCharges = is->bCh; item[MAXITEMS]._iMaxCharges = is->bMCh; } *id = item[MAXITEMS]; } } void VerifyGoldSeeds(PlayerStruct *pPlayer) { int i, j; for (i = 0; i < pPlayer->_pNumInv; i++) { if (pPlayer->InvList[i].IDidx == IDI_GOLD) { 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 UnPackPlayer(PkPlayerStruct *pPack, int pnum, BOOL killok) { PlayerStruct *pPlayer; int i; ItemStruct *pi; PkItemStruct *pki; pPlayer = &plr[pnum]; ClearPlrRVars(pPlayer); pPlayer->_px = pPack->px; pPlayer->_py = pPack->py; pPlayer->_pfutx = pPack->px; pPlayer->_pfuty = pPack->py; pPlayer->_ptargx = pPack->targx; pPlayer->_ptargy = pPack->targy; pPlayer->plrlevel = pPack->plrlevel; ClrPlrPath(pnum); pPlayer->destAction = ACTION_NONE; strcpy(pPlayer->_pName, pPack->pName); pPlayer->_pClass = pPack->pClass; InitPlayer(pnum, TRUE); pPlayer->_pBaseStr = pPack->pBaseStr; pPlayer->_pStrength = pPack->pBaseStr; pPlayer->_pBaseMag = pPack->pBaseMag; pPlayer->_pMagic = pPack->pBaseMag; pPlayer->_pBaseDex = pPack->pBaseDex; pPlayer->_pDexterity = pPack->pBaseDex; pPlayer->_pBaseVit = pPack->pBaseVit; pPlayer->_pVitality = pPack->pBaseVit; pPlayer->_pLevel = pPack->pLevel; pPlayer->_pStatPts = pPack->pStatPts; pPlayer->_pExperience = pPack->pExperience; pPlayer->_pGold = pPack->pGold; pPlayer->_pMaxHPBase = pPack->pMaxHPBase; pPlayer->_pHPBase = pPack->pHPBase; if (!killok) if ((int)(pPlayer->_pHPBase & 0xFFFFFFC0) < 64) pPlayer->_pHPBase = 64; pPlayer->_pMaxManaBase = pPack->pMaxManaBase; pPlayer->_pManaBase = pPack->pManaBase; pPlayer->_pMemSpells = pPack->pMemSpells; #ifdef HELLFIRE for (i = 0; i <= 36; i++) // Should be MAX_SPELLS-1 but set to 36 to make save games compatible pPlayer->_pSplLvl[i] = pPack->pSplLvl[i]; char *p = pPack->pSplLvl2; for (i = 37; i < 47; i++) pPlayer->_pSplLvl[i] = p[i - 37]; #else for (i = 0; i < MAX_SPELLS; i++) pPlayer->_pSplLvl[i] = pPack->pSplLvl[i]; #endif pki = &pPack->InvBody[0]; pi = &pPlayer->InvBody[0]; for (i = 0; i < NUM_INVLOC; i++) { UnPackItem(pki, pi); pki++; pi++; } pki = &pPack->InvList[0]; pi = &pPlayer->InvList[0]; for (i = 0; i < NUM_INV_GRID_ELEM; i++) { UnPackItem(pki, pi); pki++; pi++; } for (i = 0; i < NUM_INV_GRID_ELEM; i++) pPlayer->InvGrid[i] = pPack->InvGrid[i]; pPlayer->_pNumInv = pPack->_pNumInv; VerifyGoldSeeds(pPlayer); pki = &pPack->SpdList[0]; pi = &pPlayer->SpdList[0]; for (i = 0; i < MAXBELTITEMS; i++) { UnPackItem(pki, pi); pki++; pi++; } if (pnum == myplr) { for (i = 0; i < 20; i++) witchitem[i]._itype = ITYPE_NONE; } CalcPlrInv(pnum, FALSE); #ifdef HELLFIRE pPlayer->wReflections = pPack->wReflections; #endif pPlayer->pTownWarps = 0; pPlayer->pDungMsgs = 0; #ifdef HELLFIRE pPlayer->pDungMsgs2 = 0; #endif pPlayer->pLvlLoad = 0; pPlayer->pDiabloKillLevel = pPack->pDiabloKillLevel; #ifdef HELLFIRE pPlayer->pDifficulty = pPack->pDifficulty; pPlayer->pDamAcFlags = pPack->pDamAcFlags; #else pPlayer->pBattleNet = pPack->pBattleNet; pPlayer->pManaShield = pPack->pManaShield; #endif } ================================================ FILE: Source/pack.h ================================================ /** * @file pack.h * * Interface of functions for minifying player data structure. */ #ifndef __PACK_H__ #define __PACK_H__ void UnPackPlayer(PkPlayerStruct *pPack, int pnum, BOOL killok); #ifdef HELLFIRE void PackPlayer(PkPlayerStruct *pPack, int pnum); void PackItem(PkItemStruct *id, ItemStruct *is); void UnPackItem(PkItemStruct *is, ItemStruct *id); #else void PackPlayer(PkPlayerStruct *pPack, int pnum, BOOL manashield); #endif /* rdata */ #endif /* __PACK_H__ */ ================================================ FILE: Source/palette.cpp ================================================ /** * @file palette.cpp * * Implementation of functions for handling the engines color palette. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" /** In-memory palette to which gamma corrections are applied. */ PALETTEENTRY logical_palette[256]; /** The active palette of the system. */ PALETTEENTRY system_palette[256]; /** The original palette as loaded from file. */ PALETTEENTRY orig_palette[256]; int gdwPalEntries; /* data */ /** Specifies the gamma correction level. */ int gamma_correction = 100; #ifndef HELLFIRE /** Specifies whether colour cycling is enabled. */ BOOL color_cycling_enabled = TRUE; #endif /** Specifies whether the palette has max brightness. */ BOOLEAN sgbFadedIn = TRUE; static void palette_update() { int nentries; int max_entries; if (lpDDPalette) { nentries = 0; max_entries = 256; if (!fullscreen) { nentries = gdwPalEntries; max_entries = 2 * (128 - gdwPalEntries); } SDrawUpdatePalette(nentries, max_entries, &system_palette[nentries], 0); } } static void ApplyGamma(PALETTEENTRY *dst, PALETTEENTRY *src, int n) { int i; double g; g = gamma_correction / 100.0; for (i = 0; i < n; i++) { dst->peRed = pow(src->peRed / 256.0, g) * 256.0; dst->peGreen = pow(src->peGreen / 256.0, g) * 256.0; dst->peBlue = pow(src->peBlue / 256.0, g) * 256.0; dst++; src++; } } void SaveGamma() { SRegSaveValue(APP_NAME, "Gamma Correction", 0, gamma_correction); #ifndef HELLFIRE SRegSaveValue(APP_NAME, "Color Cycling", FALSE, color_cycling_enabled); #endif } static void LoadGamma() { int gamma_value; int value; value = gamma_correction; if (!SRegLoadValue(APP_NAME, "Gamma Correction", 0, &value)) value = 100; gamma_value = value; if (value < 30) { gamma_value = 30; } else if (value > 100) { gamma_value = 100; } gamma_correction = gamma_value - gamma_value % 5; #ifndef HELLFIRE if (!SRegLoadValue(APP_NAME, "Color Cycling", 0, &value)) value = 1; color_cycling_enabled = value; #endif } static void LoadSysPal() { HDC hDC; int i, iStartIndex; 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); } } void palette_init() { DWORD error_code; LoadGamma(); memcpy(system_palette, orig_palette, sizeof(orig_palette)); LoadSysPal(); #ifdef HELLFIRE error_code = lpDDInterface->CreatePalette(DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE | DDPCAPS_8BIT, system_palette, &lpDDPalette, NULL); #else error_code = lpDDInterface->CreatePalette(DDPCAPS_ALLOW256 | DDPCAPS_8BIT, system_palette, &lpDDPalette, NULL); #endif if (error_code) ErrDlg(IDD_DIALOG8, error_code, "C:\\Src\\Diablo\\Source\\PALETTE.CPP", 143); error_code = lpDDSPrimary->SetPalette(lpDDPalette); #ifndef RGBMODE if (error_code) ErrDlg(IDD_DIALOG8, error_code, "C:\\Src\\Diablo\\Source\\PALETTE.CPP", 146); #endif } void LoadPalette(const char *pszFileName) { int i; void *pBuf; BYTE PalData[256][3]; /// ASSERT: assert(pszFileName); WOpenFile(pszFileName, &pBuf, FALSE); WReadFile(pBuf, (char *)PalData, sizeof(PalData)); WCloseFile(pBuf); for (i = 0; i < 256; i++) { orig_palette[i].peRed = PalData[i][0]; orig_palette[i].peGreen = PalData[i][1]; orig_palette[i].peBlue = PalData[i][2]; orig_palette[i].peFlags = 0; } } void LoadRndLvlPal(int l) { int rv; char szFileName[MAX_PATH]; if (l == DTYPE_TOWN) { LoadPalette("Levels\\TownData\\Town.pal"); } else { rv = random_(0, 4) + 1; sprintf(szFileName, "Levels\\L%iData\\L%i_%i.PAL", l, l, rv); #ifdef HELLFIRE if (l == 5) { sprintf(szFileName, "NLevels\\L5Data\\L5Base.PAL"); } if (l == 6) { if (!UseNestArt) { rv++; } sprintf(szFileName, "NLevels\\L%iData\\L%iBase%i.PAL", 6, 6, rv); } #endif LoadPalette(szFileName); } } void ResetPal() { if (!lpDDSPrimary || lpDDSPrimary->IsLost() != DDERR_SURFACELOST || !lpDDSPrimary->Restore()) { SDrawRealizePalette(); } } void IncreaseGamma() { if (gamma_correction < 100) { gamma_correction += 5; if (gamma_correction > 100) gamma_correction = 100; ApplyGamma(system_palette, logical_palette, 256); palette_update(); } } void DecreaseGamma() { if (gamma_correction > 30) { gamma_correction -= 5; if (gamma_correction < 30) gamma_correction = 30; ApplyGamma(system_palette, logical_palette, 256); palette_update(); } } int UpdateGamma(int gamma) { if (gamma) { gamma_correction = 130 - gamma; ApplyGamma(system_palette, logical_palette, 256); palette_update(); } return 130 - gamma_correction; } static void SetFadeLevel(DWORD fadeval) { int i; if (lpDDInterface) { for (i = 0; i < 255; i++) { // BUGFIX: should be 256 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; } Sleep(3); lpDDInterface->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); palette_update(); } } void BlackPalette() { SetFadeLevel(0); } void PaletteFadeIn(int fr) { int i; ApplyGamma(logical_palette, orig_palette, 256); for (i = 0; i < 256; i += fr) { SetFadeLevel(i); } SetFadeLevel(256); memcpy(logical_palette, orig_palette, sizeof(orig_palette)); sgbFadedIn = TRUE; } void PaletteFadeOut(int fr) { int i; if (sgbFadedIn) { for (i = 256; i > 0; i -= fr) { SetFadeLevel(i); } SetFadeLevel(0); sgbFadedIn = FALSE; } } void palette_update_caves() { int i; PALETTEENTRY col; col = system_palette[1]; for (i = 1; i < 31; i++) { system_palette[i].peRed = system_palette[i + 1].peRed; system_palette[i].peGreen = system_palette[i + 1].peGreen; system_palette[i].peBlue = system_palette[i + 1].peBlue; } system_palette[i].peRed = col.peRed; system_palette[i].peGreen = col.peGreen; system_palette[i].peBlue = col.peBlue; palette_update(); } #ifdef HELLFIRE int dword_6E2D58; int dword_6E2D54; void palette_update_crypt() { int i; PALETTEENTRY col; if (dword_6E2D58 > 1) { col = system_palette[15]; for (i = 15; i > 1; i--) { system_palette[i].peRed = system_palette[i - 1].peRed; system_palette[i].peGreen = system_palette[i - 1].peGreen; system_palette[i].peBlue = system_palette[i - 1].peBlue; } system_palette[i].peRed = col.peRed; system_palette[i].peGreen = col.peGreen; system_palette[i].peBlue = col.peBlue; dword_6E2D58 = 0; } else { dword_6E2D58++; } if (dword_6E2D54 > 0) { col = system_palette[31]; for (i = 31; i > 16; i--) { system_palette[i].peRed = system_palette[i - 1].peRed; system_palette[i].peGreen = system_palette[i - 1].peGreen; system_palette[i].peBlue = system_palette[i - 1].peBlue; } system_palette[i].peRed = col.peRed; system_palette[i].peGreen = col.peGreen; system_palette[i].peBlue = col.peBlue; palette_update(); dword_6E2D54++; } else { dword_6E2D54 = 1; } } int dword_6E2D5C; int dword_6E2D60; void palette_update_hive() { int i; PALETTEENTRY col; if (dword_6E2D60 == 2) { col = system_palette[8]; for (i = 8; i > 1; i--) { system_palette[i].peRed = system_palette[i - 1].peRed; system_palette[i].peGreen = system_palette[i - 1].peGreen; system_palette[i].peBlue = system_palette[i - 1].peBlue; } system_palette[i].peRed = col.peRed; system_palette[i].peGreen = col.peGreen; system_palette[i].peBlue = col.peBlue; dword_6E2D60 = 0; } else { dword_6E2D60++; } if (dword_6E2D5C == 2) { col = system_palette[15]; for (i = 15; i > 9; i--) { system_palette[i].peRed = system_palette[i - 1].peRed; system_palette[i].peGreen = system_palette[i - 1].peGreen; system_palette[i].peBlue = system_palette[i - 1].peBlue; } system_palette[i].peRed = col.peRed; system_palette[i].peGreen = col.peGreen; system_palette[i].peBlue = col.peBlue; palette_update(); dword_6E2D5C = 0; } else { dword_6E2D5C++; } } #endif #ifndef SPAWN void palette_update_quest_palette(int n) { int i; for (i = 32 - n; i >= 0; i--) { logical_palette[i] = orig_palette[i]; } ApplyGamma(system_palette, logical_palette, 32); palette_update(); } #endif #ifndef HELLFIRE BOOL palette_get_color_cycling() { return color_cycling_enabled; } BOOL palette_set_color_cycling(BOOL enabled) { color_cycling_enabled = enabled; return enabled; } #endif ================================================ FILE: Source/palette.h ================================================ /** * @file palette.h * * Interface of functions for handling the engines color palette. */ #ifndef __PALETTE_H__ #define __PALETTE_H__ extern PALETTEENTRY system_palette[256]; void SaveGamma(); void palette_init(); void LoadPalette(const char *pszFileName); void LoadRndLvlPal(int l); void ResetPal(); void IncreaseGamma(); void DecreaseGamma(); int UpdateGamma(int gamma); void BlackPalette(); void PaletteFadeIn(int fr); void PaletteFadeOut(int fr); void palette_update_caves(); #ifdef HELLFIRE void palette_update_crypt(); void palette_update_hive(); #endif void palette_update_quest_palette(int n); #ifndef HELLFIRE BOOL palette_get_color_cycling(); BOOL palette_set_color_cycling(BOOL enabled); #endif #endif /* __PALETTE_H__ */ ================================================ FILE: Source/path.cpp ================================================ /** * @file path.cpp * * Implementation of the path finding algorithms. */ #include "all.h" /** Notes visisted by the path finding algorithm. */ PATHNODE path_nodes[MAXPATHNODES]; /** 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[MAX_PATH_LENGTH]; /** A linked list of all visited nodes */ PATHNODE *pnode_ptr; /** A stack for recursively searching nodes */ PATHNODE *pnode_tblptr[MAXPATHNODES]; /** A linked list of the A* frontier, sorted by distance */ PATHNODE *path_2_nodes; PATHNODE path_unusednodes[MAXPATHNODES]; /** 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 FindPath(BOOL (*PosOk)(int, int, int), int PosOkArg, int sx, int sy, int dx, int dy, char *path) { PATHNODE *path_start, *next_node, *current; int path_length, i; // clear all nodes, create root nodes for the visited/frontier linked lists gdwCurNodes = 0; path_2_nodes = path_new_step(); pnode_ptr = path_new_step(); gdwCurPathStep = 0; path_start = path_new_step(); path_start->g = 0; path_start->h = path_get_h_cost(sx, sy, dx, dy); path_start->x = sx; path_start->f = path_start->h + path_start->g; path_start->y = sy; path_2_nodes->NextNode = path_start; // A* search until we find (dx,dy) or fail while ((next_node = GetNextPath())) { // reached the end, success! if (next_node->x == dx && next_node->y == dy) { current = next_node; path_length = 0; while (current->Parent) { if (path_length >= MAX_PATH_LENGTH) break; pnode_vals[path_length++] = path_directions[3 * (current->y - current->Parent->y) - current->Parent->x + 4 + current->x]; current = current->Parent; } if (path_length != MAX_PATH_LENGTH) { for (i = 0; i < path_length; i++) path[i] = pnode_vals[path_length - i - 1]; return i; } return 0; } // ran out of nodes, abort! if (!path_get_path(PosOk, PosOkArg, next_node, dx, dy)) return 0; } // frontier is empty, no path! return 0; } /** * @brief heuristic, estimated cost from (sx,sy) to (dx,dy) */ int path_get_h_cost(int sx, int sy, int dx, int dy) { int delta_x = abs(sx - dx); int delta_y = abs(sy - dy); int min = delta_x < delta_y ? delta_x : delta_y; int max = delta_x > delta_y ? delta_x : delta_y; // see path_check_equal for why this is times 2 #if VERSION == 108 return min + (2 * max); #else return 2 * (min + max); #endif } /** * @brief 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 path_check_equal(PATHNODE *pPath, int dx, int dy) { if (pPath->x == dx || pPath->y == dy) return 2; return 3; } /** * @brief 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 *GetNextPath() { PATHNODE *result; result = path_2_nodes->NextNode; if (result == NULL) { return result; } path_2_nodes->NextNode = result->NextNode; result->NextNode = pnode_ptr->NextNode; pnode_ptr->NextNode = result; return result; } /** * @brief 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 path_solid_pieces(PATHNODE *pPath, int dx, int dy) { BOOL rv = TRUE; switch (path_directions[3 * (dy - pPath->y) + 3 - pPath->x + 1 + dx]) { case 5: rv = !nSolidTable[dPiece[dx][dy + 1]] && !nSolidTable[dPiece[dx + 1][dy]]; break; case 6: rv = !nSolidTable[dPiece[dx][dy + 1]] && !nSolidTable[dPiece[dx - 1][dy]]; break; case 7: rv = !nSolidTable[dPiece[dx][dy - 1]] && !nSolidTable[dPiece[dx - 1][dy]]; break; case 8: rv = !nSolidTable[dPiece[dx + 1][dy]] && !nSolidTable[dPiece[dx][dy - 1]]; break; } return rv; } /** * @brief 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 FALSE if we ran out of preallocated nodes to use, else TRUE */ BOOL path_get_path(BOOL (*PosOk)(int, int, int), int PosOkArg, PATHNODE *pPath, int x, int y) { int dx, dy; int i; BOOL ok; for (i = 0; i < 8; i++) { dx = pPath->x + pathxdir[i]; dy = pPath->y + pathydir[i]; ok = PosOk(PosOkArg, dx, dy); if (ok && path_solid_pieces(pPath, dx, dy) || !ok && dx == x && dy == y) { if (!path_parent_path(pPath, dx, dy, x, y)) return FALSE; } } return TRUE; } /** * @brief add a step from pPath to (dx,dy), return 1 if successful, and update the frontier/visited nodes accordingly * * @return TRUE if step successfully added, FALSE if we ran out of nodes to use */ BOOL path_parent_path(PATHNODE *pPath, int dx, int dy, int sx, int sy) { int next_g; PATHNODE *dxdy; int i; next_g = pPath->g + path_check_equal(pPath, dx, dy); // 3 cases to consider // case 1: (dx,dy) is already on the frontier dxdy = path_get_node1(dx, dy); if (dxdy != NULL) { for (i = 0; i < 8; i++) { if (pPath->Child[i] == NULL) break; } pPath->Child[i] = dxdy; if (next_g < dxdy->g) { if (path_solid_pieces(pPath, dx, dy)) { // we'll explore it later, just update dxdy->Parent = pPath; dxdy->g = next_g; dxdy->f = next_g + dxdy->h; } } } else { // case 2: (dx,dy) was already visited dxdy = path_get_node2(dx, dy); if (dxdy != NULL) { for (i = 0; i < 8; i++) { if (pPath->Child[i] == NULL) break; } pPath->Child[i] = dxdy; if (next_g < dxdy->g && path_solid_pieces(pPath, dx, dy)) { // update the node dxdy->Parent = pPath; dxdy->g = next_g; dxdy->f = next_g + dxdy->h; // already explored, so re-update others starting from that node path_set_coords(dxdy); } } else { // case 3: (dx,dy) is totally new dxdy = path_new_step(); if (dxdy == NULL) return FALSE; dxdy->Parent = pPath; dxdy->g = next_g; dxdy->h = path_get_h_cost(dx, dy, sx, sy); dxdy->f = next_g + dxdy->h; dxdy->x = dx; dxdy->y = dy; // add it to the frontier path_next_node(dxdy); for (i = 0; i < 8; i++) { if (pPath->Child[i] == NULL) break; } pPath->Child[i] = dxdy; } } return TRUE; } /** * @brief return a node for (dx,dy) on the frontier, or NULL if not found */ PATHNODE *path_get_node1(int dx, int dy) { PATHNODE *result = path_2_nodes->NextNode; while (result != NULL) { if (result->x == dx && result->y == dy) return result; result = result->NextNode; } return NULL; } /** * @brief return a node for (dx,dy) if it was visited, or NULL if not found */ PATHNODE *path_get_node2(int dx, int dy) { PATHNODE *result = pnode_ptr->NextNode; while (result != NULL) { if (result->x == dx && result->y == dy) return result; result = result->NextNode; } return NULL; } /** * @brief insert pPath into the frontier (keeping the frontier sorted by total distance) */ void path_next_node(PATHNODE *pPath) { PATHNODE *next, *current; int f; next = path_2_nodes; if (!path_2_nodes->NextNode) { path_2_nodes->NextNode = pPath; } else { current = path_2_nodes; next = path_2_nodes->NextNode; f = pPath->f; while (next && next->f < f) { current = next; next = next->NextNode; } pPath->NextNode = next; current->NextNode = pPath; } } /** * @brief update all path costs using depth-first search starting at pPath */ void path_set_coords(PATHNODE *pPath) { PATHNODE *PathOld; PATHNODE *PathAct; int i; path_push_active_step(pPath); while (gdwCurPathStep) { PathOld = path_pop_active_step(); for (i = 0; i < 8; i++) { PathAct = PathOld->Child[i]; if (PathAct == NULL) 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; PathAct->g = PathOld->g + path_check_equal(PathOld, PathAct->x, PathAct->y); PathAct->f = PathAct->g + PathAct->h; path_push_active_step(PathAct); } } } } } /** * @brief push pPath onto the pnode_tblptr stack */ void path_push_active_step(PATHNODE *pPath) { int stack_index = gdwCurPathStep; gdwCurPathStep++; pnode_tblptr[stack_index] = pPath; } /** * @brief pop and return a node from the pnode_tblptr stack */ PATHNODE *path_pop_active_step() { gdwCurPathStep--; return pnode_tblptr[gdwCurPathStep]; } /** * @brief zero one of the preallocated nodes and return a pointer to it, or NULL if none are available */ PATHNODE *path_new_step() { PATHNODE *new_node; if (gdwCurNodes == MAXPATHNODES) return NULL; new_node = &path_nodes[gdwCurNodes]; gdwCurNodes++; memset(new_node, 0, sizeof(PATHNODE)); return new_node; } ================================================ FILE: Source/path.h ================================================ /** * @file path.h * * Interface of the path finding algorithms. */ #ifndef __PATH_H__ #define __PATH_H__ int FindPath(BOOL (*PosOk)(int, int, int), int PosOkArg, int sx, int sy, int dx, int dy, char *path); int path_get_h_cost(int sx, int sy, int dx, int dy); PATHNODE *GetNextPath(); BOOL path_get_path(BOOL (*PosOk)(int, int, int), int PosOkArg, PATHNODE *pPath, int x, int y); BOOL path_parent_path(PATHNODE *pPath, int dx, int dy, int sx, int sy); PATHNODE *path_get_node1(int dx, int dy); PATHNODE *path_get_node2(int dx, int dy); void path_next_node(PATHNODE *pPath); void path_set_coords(PATHNODE *pPath); void path_push_active_step(PATHNODE *pPath); PATHNODE *path_pop_active_step(); PATHNODE *path_new_step(); #endif /* __PATH_H__ */ ================================================ FILE: Source/pfile.cpp ================================================ /** * @file pfile.cpp * * Implementation of the save game encoding functionality. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" #include "../DiabloUI/diabloui.h" #ifdef SPAWN #define PASSWORD_SINGLE "adslhfb1" #define PASSWORD_MULTI "lshbkfg1" #else #define PASSWORD_SINGLE "xrgyrkj1" #define PASSWORD_MULTI "szqnlsk1" #endif /** List of character names for the character selection screen. */ #ifdef HELLFIRE static char hero_names[MAX_CHARACTERS + 1][PLR_NAME_LEN]; #else static char hero_names[MAX_CHARACTERS][PLR_NAME_LEN]; #endif BOOL gbValidSaveFile; static void pfile_check_available_space(char *pszDir) { char *s; BOOL hasSpace; DWORD TotalNumberOfClusters; DWORD NumberOfFreeClusters; DWORD BytesPerSector; DWORD SectorsPerCluster; s = pszDir; while (*s) { if (*s++ != '\\') continue; *s = '\0'; break; } hasSpace = GetDiskFreeSpace(pszDir, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters); if (hasSpace) { // 10MB is the amount hardcoded in the error dialog if ((__int64)SectorsPerCluster * BytesPerSector * NumberOfFreeClusters < (__int64)(10 << 20)) hasSpace = FALSE; } if (!hasSpace) DiskFreeDlg(pszDir); } void pfile_init_save_directory() { DWORD len; char Buffer[MAX_PATH]; len = GetWindowsDirectory(Buffer, sizeof(Buffer)); if (len) { pfile_check_available_space(Buffer); len = GetModuleFileName(ghInst, Buffer, sizeof(Buffer)); } if (!len) app_fatal("Unable to initialize save directory"); else pfile_check_available_space(Buffer); } static char *GetSaveDirectory(char *dst, int dst_size, DWORD save_num) { DWORD dirLen; char FileName[MAX_PATH]; const char *savename; // BUGFIX: ignores dst_size and uses MAX_PATH instead if (gbMaxPlayers > 1) { #ifdef SPAWN savename = "\\slinfo_%d.drv"; #else savename = "\\dlinfo_%d.drv"; #endif dirLen = GetWindowsDirectory(dst, MAX_PATH); } else { char *s; #ifdef SPAWN savename = "\\spawn_%d.sv"; #else savename = "\\single_%d.sv"; #endif dirLen = GetModuleFileName(ghInst, dst, MAX_PATH); s = strrchr(dst, '\\'); if (s) *s = '\0'; } if (!dirLen) app_fatal("Unable to get save directory"); sprintf(FileName, savename, save_num); strcat(dst, FileName); return _strlwr(dst); } #ifdef HELLFIRE static void pfile_get_save_path(char *pszBuf, DWORD dwBufSize, DWORD save_num, BOOL hellfire) #else static void pfile_get_save_path(char *pszBuf, DWORD dwBufSize, DWORD save_num) #endif { const char *fmt; DWORD plen; char *s; char path[MAX_PATH]; #ifdef HELLFIRE if (gbMaxPlayers > 1) { if (!hellfire) fmt = "\\dlinfo_%d.drv"; else fmt = "\\hrinfo_%d.drv"; plen = GetWindowsDirectory(pszBuf, MAX_PATH); } else { if (!hellfire) fmt = "\\single_%d.sv"; else fmt = "\\single_%d.hsv"; #else #ifdef SPAWN fmt = "\\share_%d.sv"; if (gbMaxPlayers <= 1) fmt = "\\spawn%d.sv"; #else fmt = "\\multi_%d.sv"; if (gbMaxPlayers <= 1) fmt = "\\single_%d.sv"; #endif #endif // BUGFIX: ignores dwBufSize and uses MAX_PATH instead plen = GetModuleFileName(ghInst, pszBuf, MAX_PATH); s = strrchr(pszBuf, '\\'); if (s) *s = '\0'; #ifdef HELLFIRE } #endif if (!plen) app_fatal("Unable to get save directory"); sprintf(path, fmt, save_num); strcat(pszBuf, path); _strlwr(pszBuf); } static DWORD pfile_get_save_num_from_name(const char *name) { DWORD i; for (i = 0; i < MAX_CHARACTERS; i++) { if (!_strcmpi(hero_names[i], name)) break; } return i; } static BOOL pfile_read_hero(HANDLE archive, PkPlayerStruct *pPack) { HANDLE file; BOOL decoded; DWORD dwlen, nSize; BYTE *buf; if (!SFileOpenFileEx(archive, "hero", 0, &file)) { return FALSE; } else { buf = NULL; BOOL ret = FALSE; char password[16] = PASSWORD_SINGLE; nSize = 16; if (gbMaxPlayers > 1) #ifdef HELLFIRE GetComputerName(password, &nSize); #else strcpy(password, PASSWORD_MULTI); #endif dwlen = SFileGetFileSize(file, NULL); if (dwlen) { DWORD read; buf = DiabloAllocPtr(dwlen); if (SFileReadFile(file, buf, dwlen, &read, NULL)) { decoded = TRUE; read = codec_decode(buf, dwlen, password); #ifndef HELLFIRE if (!read && gbMaxPlayers > 1) { GetComputerName(password, &nSize); if (SFileSetFilePointer(file, 0, NULL, FILE_BEGIN) || !SFileReadFile(file, buf, dwlen, &read, NULL)) decoded = FALSE; else read = codec_decode(buf, dwlen, password); } #endif if (decoded && read == sizeof(*pPack)) { memcpy(pPack, buf, sizeof(*pPack)); ret = TRUE; } } } if (buf) mem_free_dbg(buf); SFileCloseFile(file); return ret; } } static void pfile_encode_hero(const PkPlayerStruct *pPack) { BYTE *packed; DWORD packed_len; char password[16] = PASSWORD_SINGLE; #ifdef HELLFIRE DWORD size = 161; if (gbMaxPlayers > 1) GetComputerName(password, &size); #else if (gbMaxPlayers > 1) strcpy(password, PASSWORD_MULTI); #endif packed_len = codec_get_encoded_len(sizeof(*pPack)); packed = (BYTE *)DiabloAllocPtr(packed_len); memcpy(packed, pPack, sizeof(*pPack)); codec_encode(packed, sizeof(*pPack), packed_len, password); mpqapi_write_file("hero", packed, packed_len); mem_free_dbg(packed); } static BOOL pfile_open_archive(BOOL update, DWORD save_num) { char FileName[MAX_PATH]; #ifdef HELLFIRE pfile_get_save_path(FileName, sizeof(FileName), save_num, TRUE); if (OpenMPQ(FileName, gbMaxPlayers > 1, save_num)) #else pfile_get_save_path(FileName, sizeof(FileName), save_num); if (OpenMPQ(FileName, FALSE, save_num)) #endif return TRUE; if (update && gbMaxPlayers > 1) mpqapi_store_default_time(save_num); return FALSE; } static void pfile_flush(BOOL is_single_player, DWORD save_num) { char FileName[MAX_PATH]; #ifdef HELLFIRE pfile_get_save_path(FileName, sizeof(FileName), save_num, TRUE); #else pfile_get_save_path(FileName, sizeof(FileName), save_num); #endif mpqapi_flush_and_close(FileName, is_single_player, save_num); } /** * @param showFixedMsg Display a dialog if a save file was corrected (deprecated) */ static HANDLE pfile_open_save_archive(BOOL *showFixedMsg, DWORD save_num) { char SrcStr[MAX_PATH]; HANDLE archive; #ifdef HELLFIRE pfile_get_save_path(SrcStr, sizeof(SrcStr), save_num, TRUE); #else pfile_get_save_path(SrcStr, sizeof(SrcStr), save_num); #endif if (SFileOpenArchive(SrcStr, 0x7000, FS_PC, &archive)) return archive; return NULL; } static void pfile_SFileCloseArchive(HANDLE hsArchive) { SFileCloseArchive(hsArchive); } void pfile_write_hero() { DWORD save_num; PkPlayerStruct pkplr; save_num = pfile_get_save_num_from_name(plr[myplr]._pName); if (pfile_open_archive(TRUE, save_num)) { #ifdef HELLFIRE PackPlayer(&pkplr, myplr); #else PackPlayer(&pkplr, myplr, gbMaxPlayers == 1); #endif pfile_encode_hero(&pkplr); pfile_flush(gbMaxPlayers == 1, save_num); } } BOOL pfile_create_player_description(char *dst, DWORD len) { char desc[128]; _uiheroinfo uihero; myplr = 0; pfile_read_player_from_save(); game_2_ui_player(plr, &uihero, gbValidSaveFile); UiSetupPlayerInfo(gszHero, &uihero, GAME_ID); if (dst != NULL && len) { if (UiCreatePlayerDescription(&uihero, GAME_ID, desc) == 0) return FALSE; SStrCopy(dst, desc, len); } return TRUE; } BOOL pfile_rename_hero(const char *name_1, const char *name_2) { int i; DWORD save_num; _uiheroinfo uihero; BOOL found = FALSE; if (pfile_get_save_num_from_name(name_2) == MAX_CHARACTERS) { for (i = 0; i != MAX_PLRS; i++) { if (!_strcmpi(name_1, plr[i]._pName)) { found = TRUE; break; } } } if (!found) return FALSE; save_num = pfile_get_save_num_from_name(name_1); if (save_num == MAX_CHARACTERS) return FALSE; SStrCopy(hero_names[save_num], name_2, PLR_NAME_LEN); SStrCopy(plr[i]._pName, name_2, PLR_NAME_LEN); if (!_strcmpi(gszHero, name_1)) SStrCopy(gszHero, name_2, sizeof(gszHero)); game_2_ui_player(plr, &uihero, gbValidSaveFile); UiSetupPlayerInfo(gszHero, &uihero, GAME_ID); pfile_write_hero(); return TRUE; } void pfile_flush_W() { pfile_flush(TRUE, pfile_get_save_num_from_name(plr[myplr]._pName)); } static char pfile_get_player_class(unsigned int player_class_nr) { char pc_class; if (player_class_nr == UI_WARRIOR) pc_class = PC_WARRIOR; else if (player_class_nr == UI_ROGUE) pc_class = PC_ROGUE; #ifdef HELLFIRE else if (player_class_nr == 3) pc_class = PC_MONK; else if (player_class_nr == 4) pc_class = PC_BARD; else if (player_class_nr == 5) pc_class = PC_BARBARIAN; #endif else pc_class = PC_SORCERER; return pc_class; } static BYTE game_2_ui_class(const PlayerStruct *p) { BYTE uiclass; if (p->_pClass == PC_WARRIOR) uiclass = UI_WARRIOR; else if (p->_pClass == PC_ROGUE) uiclass = UI_ROGUE; #ifdef HELLFIRE else if (p->_pClass == PC_MONK) uiclass = UI_MONK; else if (p->_pClass == PC_BARD) uiclass = UI_BARD; else if (p->_pClass == PC_BARBARIAN) uiclass = UI_BARBARIAN; #endif else uiclass = UI_SORCERER; return uiclass; } void game_2_ui_player(const PlayerStruct *p, _uiheroinfo *heroinfo, BOOL bHasSaveFile) { memset(heroinfo, 0, sizeof(*heroinfo)); strncpy(heroinfo->name, p->_pName, sizeof(heroinfo->name) - 1); heroinfo->name[sizeof(heroinfo->name) - 1] = '\0'; heroinfo->level = p->_pLevel; heroinfo->heroclass = game_2_ui_class(p); heroinfo->strength = p->_pStrength; heroinfo->magic = p->_pMagic; heroinfo->dexterity = p->_pDexterity; heroinfo->vitality = p->_pVitality; heroinfo->gold = p->_pGold; heroinfo->hassaved = bHasSaveFile; heroinfo->herorank = p->pDiabloKillLevel; #ifdef SPAWN heroinfo->spawned = TRUE; #else heroinfo->spawned = FALSE; #endif } BOOL __stdcall pfile_ui_set_hero_infos(BOOL(__stdcall *ui_add_hero_info)(_uiheroinfo *)) { DWORD i, save_num; char FileName[MAX_PATH]; char NewFileName[MAX_PATH]; BOOL showFixedMsg; memset(hero_names, 0, sizeof(hero_names)); #ifndef HELLFIRE if (gbMaxPlayers > 1) { for (i = 0, save_num = 0; i < MAX_CHARACTERS && save_num < MAX_CHARACTERS; i++) { struct _OFSTRUCT ReOpenBuff; const char *s; GetSaveDirectory(FileName, sizeof(FileName), i); s = strrchr(FileName, '\\') + 1; if (s == (const char *)1) continue; if (OpenFile(FileName, &ReOpenBuff, OF_EXIST) == HFILE_ERROR) continue; if (!SRegLoadString("Diablo\\Converted", s, 0, NewFileName, sizeof(NewFileName))) { while (save_num < MAX_CHARACTERS) { pfile_get_save_path(NewFileName, sizeof(NewFileName), save_num++); if (OpenFile(NewFileName, &ReOpenBuff, OF_EXIST) == HFILE_ERROR) { if (CopyFile(FileName, NewFileName, TRUE)) { DWORD attrib; SRegSaveString("Diablo\\Converted", s, 0, NewFileName); attrib = GetFileAttributes(NewFileName); if (attrib != INVALID_FILE_ATTRIBUTES) { attrib &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); SetFileAttributes(NewFileName, attrib); } } break; } } } } } #endif showFixedMsg = TRUE; for (i = 0; i < MAX_CHARACTERS; i++) { PkPlayerStruct pkplr; HANDLE archive = pfile_open_save_archive(&showFixedMsg, i); if (archive) { if (pfile_read_hero(archive, &pkplr)) { _uiheroinfo uihero; strcpy(hero_names[i], pkplr.pName); UnPackPlayer(&pkplr, 0, FALSE); game_2_ui_player(plr, &uihero, pfile_archive_contains_game(archive, i)); ui_add_hero_info(&uihero); } pfile_SFileCloseArchive(archive); } } return TRUE; } BOOL pfile_archive_contains_game(HANDLE hsArchive, DWORD save_num) { HANDLE file; #ifdef HELLFIRE DWORD read, size; BOOL ret = FALSE; gbLoadGame = FALSE; #endif if (gbMaxPlayers != 1) return FALSE; if (!SFileOpenFileEx(hsArchive, "game", 0, &file)) return FALSE; #ifdef HELLFIRE DWORD dwlen = SFileGetFileSize(file, NULL); if (!dwlen) app_fatal("Invalid save file"); BYTE *ptr = DiabloAllocPtr(dwlen + 8); BYTE *buf = ptr + 4; if (SFileReadFile(file, buf, dwlen, &read, NULL)) { if (read == dwlen) { char password[16] = PASSWORD_SINGLE; size = 16; if (gbMaxPlayers > 1) GetComputerName(password, &size); gbLoadGame = TRUE; if (codec_decode(buf, dwlen, password)) { int magic = *buf << 24; buf++; magic |= *buf << 16; buf++; magic |= *buf << 8; buf++; magic |= *buf; if (magic == 'HELF') { ret = TRUE; } } } } if (ptr) mem_free_dbg(ptr); SFileCloseFile(file); return ret; #else SFileCloseFile(file); return TRUE; #endif } BOOL __stdcall pfile_ui_set_class_stats(unsigned int player_class_nr, _uidefaultstats *class_stats) { int c; c = pfile_get_player_class(player_class_nr); class_stats->strength = StrengthTbl[c]; class_stats->magic = MagicTbl[c]; class_stats->dexterity = DexterityTbl[c]; class_stats->vitality = VitalityTbl[c]; return TRUE; } BOOL __stdcall pfile_ui_save_create(_uiheroinfo *heroinfo) { DWORD save_num; char cl; PkPlayerStruct pkplr; save_num = pfile_get_save_num_from_name(heroinfo->name); #ifdef HELLFIRE if (save_num >= MAX_CHARACTERS) { #else if (save_num == MAX_CHARACTERS) { #endif for (save_num = 0; save_num < MAX_CHARACTERS; save_num++) { if (!hero_names[save_num][0]) break; } #ifdef HELLFIRE if (save_num >= MAX_CHARACTERS) #else if (save_num == MAX_CHARACTERS) #endif return FALSE; } if (!pfile_open_archive(FALSE, save_num)) return FALSE; mpqapi_remove_hash_entries(pfile_get_file_name); strncpy(hero_names[save_num], heroinfo->name, PLR_NAME_LEN); hero_names[save_num][PLR_NAME_LEN - 1] = '\0'; cl = pfile_get_player_class(heroinfo->heroclass); CreatePlayer(0, cl); strncpy(plr[0]._pName, heroinfo->name, PLR_NAME_LEN); plr[0]._pName[PLR_NAME_LEN - 1] = '\0'; #ifdef HELLFIRE PackPlayer(&pkplr, 0); #else PackPlayer(&pkplr, 0, TRUE); #endif pfile_encode_hero(&pkplr); game_2_ui_player(&plr[0], heroinfo, FALSE); pfile_flush(TRUE, save_num); return TRUE; } BOOL __stdcall pfile_get_file_name(DWORD lvl, char *dst) { const char *fmt; if (gbMaxPlayers > 1) { if (lvl) return FALSE; fmt = "hero"; } else { if (lvl < NUMLEVELS) fmt = "perml%02d"; else if (lvl < NUMLEVELS * 2) { lvl -= NUMLEVELS; fmt = "perms%02d"; } else if (lvl == NUMLEVELS * 2) fmt = "game"; else if (lvl == NUMLEVELS * 2 + 1) fmt = "hero"; else return FALSE; } sprintf(dst, fmt, lvl); return TRUE; } BOOL __stdcall pfile_delete_save(_uiheroinfo *hero_info) { DWORD save_num; char FileName[MAX_PATH]; save_num = pfile_get_save_num_from_name(hero_info->name); if (save_num < MAX_CHARACTERS) { hero_names[save_num][0] = '\0'; #ifdef HELLFIRE pfile_get_save_path(FileName, sizeof(FileName), save_num, TRUE); #else pfile_get_save_path(FileName, sizeof(FileName), save_num); #endif DeleteFile(FileName); } return TRUE; } void pfile_read_player_from_save() { HANDLE archive; DWORD save_num; PkPlayerStruct pkplr; save_num = pfile_get_save_num_from_name(gszHero); archive = pfile_open_save_archive(NULL, save_num); if (archive == NULL) app_fatal("Unable to open archive"); if (!pfile_read_hero(archive, &pkplr)) app_fatal("Unable to load character"); UnPackPlayer(&pkplr, myplr, FALSE); gbValidSaveFile = pfile_archive_contains_game(archive, save_num); pfile_SFileCloseArchive(archive); } void GetTempLevelNames(char *szTemp) { // BUGFIX: function call has no purpose pfile_get_save_num_from_name(plr[myplr]._pName); if (setlevel) sprintf(szTemp, "temps%02d", setlvlnum); else sprintf(szTemp, "templ%02d", currlevel); } void GetPermLevelNames(char *szPerm) { DWORD save_num; BOOL has_file; save_num = pfile_get_save_num_from_name(plr[myplr]._pName); GetTempLevelNames(szPerm); if (!pfile_open_archive(FALSE, save_num)) app_fatal("Unable to read to save file archive"); has_file = mpqapi_has_file(szPerm); pfile_flush(TRUE, save_num); if (!has_file) { if (setlevel) sprintf(szPerm, "perms%02d", setlvlnum); else sprintf(szPerm, "perml%02d", currlevel); } } void pfile_get_game_name(char *dst) { // BUGFIX: function call with no purpose pfile_get_save_num_from_name(plr[myplr]._pName); strcpy(dst, "game"); } static BOOL __stdcall GetPermSaveNames(DWORD dwIndex, char *szPerm) { const char *fmt; if (dwIndex < NUMLEVELS) fmt = "perml%02d"; else if (dwIndex < NUMLEVELS * 2) { dwIndex -= NUMLEVELS; fmt = "perms%02d"; } else return FALSE; sprintf(szPerm, fmt, dwIndex); return TRUE; } static BOOL __stdcall GetTempSaveNames(DWORD dwIndex, char *szTemp) { const char *fmt; if (dwIndex < NUMLEVELS) fmt = "templ%02d"; else if (dwIndex < NUMLEVELS * 2) { dwIndex -= NUMLEVELS; fmt = "temps%02d"; } else return FALSE; sprintf(szTemp, fmt, dwIndex); return TRUE; } void pfile_remove_temp_files() { if (gbMaxPlayers <= 1) { DWORD save_num = pfile_get_save_num_from_name(plr[myplr]._pName); if (!pfile_open_archive(FALSE, save_num)) app_fatal("Unable to write to save file archive"); mpqapi_remove_hash_entries(GetTempSaveNames); pfile_flush(TRUE, save_num); } } void pfile_rename_temp_to_perm() { DWORD dwChar, dwIndex; BOOL bResult; char szTemp[MAX_PATH]; char szPerm[MAX_PATH]; dwChar = pfile_get_save_num_from_name(plr[myplr]._pName); /// ASSERT: assert(dwChar < MAX_CHARACTERS); /// ASSERT: assert(gbMaxPlayers == 1); if (!pfile_open_archive(FALSE, dwChar)) app_fatal("Unable to write to save file archive"); dwIndex = 0; while (GetTempSaveNames(dwIndex, szTemp)) { bResult = GetPermSaveNames(dwIndex, szPerm); /// ASSERT: assert(bResult); dwIndex++; if (mpqapi_has_file(szTemp)) { if (mpqapi_has_file(szPerm)) mpqapi_remove_hash_entry(szPerm); mpqapi_rename(szTemp, szPerm); } } /// ASSERT: assert(! GetPermSaveNames(dwIndex,szPerm)); GetPermSaveNames(dwIndex, szPerm); // BUGFIX: function call has no purpose pfile_flush(TRUE, dwChar); } void pfile_write_save_file(const char *pszName, BYTE *pbData, DWORD dwLen, DWORD qwLen) { DWORD save_num; #ifndef HELLFIRE char FileName[MAX_PATH]; pfile_strcpy(FileName, pszName); #endif save_num = pfile_get_save_num_from_name(plr[myplr]._pName); { char password[16] = PASSWORD_SINGLE; #ifdef HELLFIRE DWORD size = 16; if (gbMaxPlayers > 1) GetComputerName(password, &size); #else if (gbMaxPlayers > 1) strcpy(password, PASSWORD_MULTI); #endif codec_encode(pbData, dwLen, qwLen, password); } if (!pfile_open_archive(FALSE, save_num)) #ifdef HELLFIRE app_fatal("Unable to write to save file archive"); mpqapi_write_file(pszName, pbData, qwLen); #else app_fatal("Unable to write so save file archive"); mpqapi_write_file(FileName, pbData, qwLen); #endif pfile_flush(TRUE, save_num); } void pfile_strcpy(char *dst, const char *src) { strcpy(dst, src); } BYTE *pfile_read(const char *pszName, DWORD *pdwLen) { DWORD save_num, nread; char FileName[MAX_PATH]; HANDLE archive, save; BYTE *buf; #ifndef HELLFIRE pfile_strcpy(FileName, pszName); #endif save_num = pfile_get_save_num_from_name(plr[myplr]._pName); archive = pfile_open_save_archive(NULL, save_num); if (archive == NULL) app_fatal("Unable to open save file archive"); #ifdef HELLFIRE if (!SFileOpenFileEx(archive, pszName, 0, &save)) #else if (!SFileOpenFileEx(archive, FileName, 0, &save)) #endif app_fatal("Unable to open save file"); *pdwLen = SFileGetFileSize(save, NULL); if (*pdwLen == 0) app_fatal("Invalid save file"); buf = DiabloAllocPtr(*pdwLen); if (!SFileReadFile(save, buf, *pdwLen, &nread, NULL)) app_fatal("Unable to read save file"); SFileCloseFile(save); pfile_SFileCloseArchive(archive); char password[16] = PASSWORD_SINGLE; DWORD nSize = 16; if (gbMaxPlayers > 1) #ifdef HELLFIRE GetComputerName(password, &nSize); { { #else strcpy(password, PASSWORD_MULTI); *pdwLen = codec_decode(buf, *pdwLen, password); if (*pdwLen == 0) { // BUGFIFX: *pdwLen has already been overwritten with zero and the savefile has been closed // there is no way this can work correctly if (gbMaxPlayers > 1) { GetComputerName(password, &nSize); if (SFileSetFilePointer(save, 0, NULL, FILE_BEGIN)) app_fatal("Unable to read save file"); if (!SFileReadFile(save, buf, *pdwLen, &nread, NULL)) app_fatal("Unable to read save file"); #endif *pdwLen = codec_decode(buf, *pdwLen, password); } if (*pdwLen == 0) app_fatal("Invalid save file"); } return buf; } void pfile_update(BOOL force_save) { // BUGFIX: these tick values should be treated as unsigned to handle overflows correctly static int save_prev_tc; if (gbMaxPlayers != 1) { int tick = GetTickCount(); if (force_save || tick - save_prev_tc > 60000) { save_prev_tc = tick; pfile_write_hero(); } } } ================================================ FILE: Source/pfile.h ================================================ /** * @file pfile.h * * Interface of the save game encoding functionality. */ #ifndef __PFILE_H__ #define __PFILE_H__ extern BOOL gbValidSaveFile; void pfile_init_save_directory(); void pfile_write_hero(); BOOL pfile_create_player_description(char *dst, DWORD len); BOOL pfile_rename_hero(const char *name_1, const char *name_2); void pfile_flush_W(); void game_2_ui_player(const PlayerStruct *p, _uiheroinfo *heroinfo, BOOL bHasSaveFile); BOOL __stdcall pfile_ui_set_hero_infos(BOOL(__stdcall *ui_add_hero_info)(_uiheroinfo *)); BOOL pfile_archive_contains_game(HANDLE hsArchive, DWORD save_num); BOOL __stdcall pfile_ui_set_class_stats(unsigned int player_class_nr, _uidefaultstats *class_stats); BOOL __stdcall pfile_ui_save_create(_uiheroinfo *heroinfo); BOOL __stdcall pfile_get_file_name(DWORD lvl, char *dst); BOOL __stdcall pfile_delete_save(_uiheroinfo *hero_info); void pfile_read_player_from_save(); void GetTempLevelNames(char *szTemp); void GetPermLevelNames(char *szPerm); void pfile_get_game_name(char *dst); void pfile_remove_temp_files(); void pfile_rename_temp_to_perm(); void pfile_write_save_file(const char *pszName, BYTE *pbData, DWORD dwLen, DWORD qwLen); void pfile_strcpy(char *dst, const char *src); BYTE *pfile_read(const char *pszName, DWORD *pdwLen); void pfile_update(BOOL force_save); #endif /* __PFILE_H__ */ ================================================ FILE: Source/player.cpp ================================================ /** * @file player.cpp * * Implementation of player functionality, leveling, actions, creation, loading, etc. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" int plr_lframe_size; int plr_wframe_size; BYTE plr_gfx_flag = 0; int plr_aframe_size; int myplr; #ifdef HELLFIRE PlayerStruct *plr; #else PlayerStruct plr[MAX_PLRS]; #endif int plr_fframe_size; int plr_qframe_size; BOOL deathflag; int plr_hframe_size; int plr_bframe_size; BYTE plr_gfx_bflag = 0; int plr_sframe_size; int deathdelay; int plr_dframe_size; /** Maps from armor animation to letter used in graphic files. */ const char ArmourChar[4] = { 'L', 'M', 'H', 0 }; /** Maps from weapon animation to letter used in graphic files. */ const char WepChar[10] = { 'N', 'U', 'S', 'D', 'B', 'A', 'M', 'H', 'T', 0 }; /** Maps from player class to letter used in graphic files. */ const char CharChar[] = { 'W', 'R', 'S', #ifdef HELLFIRE 'M', 'R', 'W', 0 }; const char CharCharHF[] = { 'W', 'R', 'S', 'M', 'B', 'C', #endif 0 }; /* data */ /** Specifies the X-coordinate delta from the player start location in Tristram. */ int plrxoff[9] = { 0, 2, 0, 2, 1, 0, 1, 2, 1 }; /** Specifies the Y-coordinate delta from the player start location in Tristram. */ int plryoff[9] = { 0, 2, 2, 0, 1, 1, 0, 1, 2 }; /** Specifies the X-coordinate delta from a player, used for instanced when casting resurrect. */ int plrxoff2[9] = { 0, 1, 0, 1, 2, 0, 1, 2, 2 }; /** Specifies the Y-coordinate delta from a player, used for instanced when casting resurrect. */ int plryoff2[9] = { 0, 0, 1, 1, 0, 2, 2, 1, 2 }; /** Specifies the frame of each animation for which an action is triggered, for each player class. */ char PlrGFXAnimLens[NUM_CLASSES][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 }, #ifdef HELLFIRE { 8, 16, 8, 3, 20, 18, 6, 20, 8, 12, 13 }, { 8, 18, 8, 4, 20, 16, 7, 20, 8, 10, 12 }, { 10, 16, 8, 2, 20, 20, 6, 20, 8, 9, 14 }, #endif }; /** Maps from player class to player velocity. */ int PWVel[NUM_CLASSES][3] = { { 2048, 1024, 512 }, { 2048, 1024, 512 }, { 2048, 1024, 512 }, #ifdef HELLFIRE { 2048, 1024, 512 }, { 2048, 1024, 512 }, { 2048, 1024, 512 }, #endif }; /** Total number of frames in walk animation. */ int AnimLenFromClass[NUM_CLASSES] = { 8, 8, 8, #ifdef HELLFIRE 8, 8, 8, #endif }; /** Maps from player_class to starting stat in strength. */ int StrengthTbl[NUM_CLASSES] = { 30, 20, 15, #ifdef HELLFIRE 25, 20, 40, #endif }; /** Maps from player_class to starting stat in magic. */ int MagicTbl[NUM_CLASSES] = { // clang-format off 10, 15, 35, #ifdef HELLFIRE 15, 20, 0, #endif // clang-format on }; /** Maps from player_class to starting stat in dexterity. */ int DexterityTbl[NUM_CLASSES] = { 20, 30, 15, #ifdef HELLFIRE 25, 25, 20, #endif }; /** Maps from player_class to starting stat in vitality. */ int VitalityTbl[NUM_CLASSES] = { 25, 20, 20, #ifdef HELLFIRE 20, 20, 25, #endif }; /** Specifies the chance to block bonus of each player class.*/ int ToBlkTbl[NUM_CLASSES] = { 30, 20, 10, #ifdef HELLFIRE 25, 25, 30, #endif }; const char *const ClassStrTblOld[] = { "Warrior", "Rogue", "Sorceror", #ifdef HELLFIRE "Monk", "Bard", "Barbarian", #endif }; /** Maps from player_class to maximum stats. */ int MaxStats[NUM_CLASSES][4] = { // clang-format off { 250, 50, 60, 100 }, { 55, 70, 250, 80 }, { 45, 250, 85, 80 }, #ifdef HELLFIRE { 150, 80, 150, 80 }, { 120, 120, 120, 100 }, { 255, 0, 55, 150 }, #endif // clang-format on }; /** Specifies the experience point limit of each level. */ int ExpLvlsTbl[MAXCHARLEVEL] = { 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 }; const char *const ClassStrTbl[NUM_CLASSES] = { "Warrior", "Rogue", "Sorceror", #ifdef HELLFIRE "Monk", "Rogue", "Warrior", #endif }; /** Unused local of PM_ChangeLightOff, originally for computing light radius. */ BYTE fix[9] = { 0, 0, 3, 3, 3, 6, 6, 6, 8 }; void SetPlayerGPtrs(BYTE *pData, BYTE **pAnim) { int i; for (i = 0; i < 8; i++) { pAnim[i] = pData + ((DWORD *)pData)[i]; } } void LoadPlrGFX(int pnum, player_graphic gfxflag) { char prefix[16]; char pszName[256]; const char *szCel; PlayerStruct *p; const char *cs; BYTE *pData, *pAnim; DWORD i; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("LoadPlrGFX: illegal player %d", pnum); } p = &plr[pnum]; #ifdef HELLFIRE if ((p->_pClass != PC_BARD || hfbard_mpq == NULL) && (p->_pClass != PC_BARBARIAN || hfbarb_mpq == NULL)) { #endif sprintf(prefix, "%c%c%c", CharChar[p->_pClass], ArmourChar[p->_pgfxnum >> 4], WepChar[p->_pgfxnum & 0xF]); cs = ClassStrTbl[p->_pClass]; #ifdef HELLFIRE } else { sprintf(prefix, "%c%c%c", CharCharHF[p->_pClass], ArmourChar[p->_pgfxnum >> 4], WepChar[p->_pgfxnum & 0xF]); cs = ClassStrTbl[p->_pClass]; cs = ClassStrTblOld[p->_pClass]; } #endif for (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 = (BYTE *)p->_pNAnim; break; case PFILE_WALK: szCel = "AW"; if (leveltype == DTYPE_TOWN) { szCel = "WL"; } pData = p->_pWData; pAnim = (BYTE *)p->_pWAnim; break; case PFILE_ATTACK: if (leveltype == DTYPE_TOWN) { continue; } szCel = "AT"; pData = p->_pAData; pAnim = (BYTE *)p->_pAAnim; break; case PFILE_HIT: if (leveltype == DTYPE_TOWN) { continue; } szCel = "HT"; pData = p->_pHData; pAnim = (BYTE *)p->_pHAnim; break; case PFILE_LIGHTNING: if (leveltype == DTYPE_TOWN) { continue; } szCel = "LM"; pData = p->_pLData; pAnim = (BYTE *)p->_pLAnim; break; case PFILE_FIRE: if (leveltype == DTYPE_TOWN) { continue; } szCel = "FM"; pData = p->_pFData; pAnim = (BYTE *)p->_pFAnim; break; case PFILE_MAGIC: if (leveltype == DTYPE_TOWN) { continue; } szCel = "QM"; pData = p->_pTData; pAnim = (BYTE *)p->_pTAnim; break; case PFILE_DEATH: if (p->_pgfxnum & 0xF) { continue; } szCel = "DT"; pData = p->_pDData; pAnim = (BYTE *)p->_pDAnim; break; case PFILE_BLOCK: if (leveltype == DTYPE_TOWN) { continue; } if (!p->_pBlockFlag) { continue; } szCel = "BL"; pData = p->_pBData; pAnim = (BYTE *)p->_pBAnim; break; default: app_fatal("PLR:2"); break; } sprintf(pszName, "PlrGFX\\%s\\%s\\%s%s.CL2", cs, prefix, prefix, szCel); LoadFileWithMem(pszName, pData); SetPlayerGPtrs((BYTE *)pData, (BYTE **)pAnim); p->_pGFXLoad |= i; } } void InitPlayerGFX(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("InitPlayerGFX: illegal player %d", pnum); } if (plr[pnum]._pHitPoints >> 6 == 0) { plr[pnum]._pgfxnum = 0; LoadPlrGFX(pnum, PFILE_DEATH); } else { LoadPlrGFX(pnum, PFILE_NONDEATH); } } static DWORD GetPlrGFXSize(const char *szCel) { DWORD c; const char *a, *w; DWORD dwSize, dwMaxSize; HANDLE hsFile; char pszName[256]; char Type[16]; dwMaxSize = 0; for (c = 0; c < NUM_CLASSES; c++) { #ifdef SPAWN if (c != 0) continue; #endif for (a = &ArmourChar[0]; *a; a++) { #ifdef SPAWN if (a != &ArmourChar[0]) break; #endif for (w = &WepChar[0]; *w; w++) { // BUGFIX loads non-existing animagions; DT is only for N, BT is only for U, D & H #ifdef HELLFIRE if ((c == PC_BARD && hfbard_mpq == NULL) || (c == PC_BARBARIAN && hfbarb_mpq == NULL)) { #endif sprintf(Type, "%c%c%c", CharChar[c], *a, *w); sprintf(pszName, "PlrGFX\\%s\\%s\\%s%s.CL2", ClassStrTbl[c], Type, Type, szCel); #ifdef HELLFIRE } else { sprintf(Type, "%c%c%c", CharCharHF[c], *a, *w); sprintf(pszName, "PlrGFX\\%s\\%s\\%s%s.CL2", ClassStrTblOld[c], Type, Type, szCel); } #endif if (WOpenFile(pszName, &hsFile, TRUE)) { /// ASSERT: assert(hsFile); dwSize = WGetFileSize(hsFile, NULL); WCloseFile(hsFile); if (dwMaxSize <= dwSize) { dwMaxSize = dwSize; } } } } } return dwMaxSize; } void InitPlrGFXMem(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("InitPlrGFXMem: illegal player %d", pnum); } if (!(plr_gfx_flag & 0x1)) { //STAND plr_gfx_flag |= 0x1; if (GetPlrGFXSize("ST") > GetPlrGFXSize("AS")) { plr_sframe_size = GetPlrGFXSize("ST"); //TOWN } else { plr_sframe_size = GetPlrGFXSize("AS"); //DUNGEON } } plr[pnum]._pNData = DiabloAllocPtr(plr_sframe_size); if (!(plr_gfx_flag & 0x2)) { //WALK plr_gfx_flag |= 0x2; if (GetPlrGFXSize("WL") > GetPlrGFXSize("AW")) { plr_wframe_size = GetPlrGFXSize("WL"); //TOWN } else { plr_wframe_size = GetPlrGFXSize("AW"); //DUNGEON } } plr[pnum]._pWData = DiabloAllocPtr(plr_wframe_size); if (!(plr_gfx_flag & 0x4)) { //ATTACK plr_gfx_flag |= 0x4; plr_aframe_size = GetPlrGFXSize("AT"); } plr[pnum]._pAData = DiabloAllocPtr(plr_aframe_size); if (!(plr_gfx_flag & 0x8)) { //HIT plr_gfx_flag |= 0x8; plr_hframe_size = GetPlrGFXSize("HT"); } plr[pnum]._pHData = DiabloAllocPtr(plr_hframe_size); if (!(plr_gfx_flag & 0x10)) { //LIGHTNING plr_gfx_flag |= 0x10; plr_lframe_size = GetPlrGFXSize("LM"); } plr[pnum]._pLData = DiabloAllocPtr(plr_lframe_size); if (!(plr_gfx_flag & 0x20)) { //FIRE plr_gfx_flag |= 0x20; plr_fframe_size = GetPlrGFXSize("FM"); } plr[pnum]._pFData = DiabloAllocPtr(plr_fframe_size); if (!(plr_gfx_flag & 0x40)) { //MAGIC plr_gfx_flag |= 0x40; plr_qframe_size = GetPlrGFXSize("QM"); } plr[pnum]._pTData = DiabloAllocPtr(plr_qframe_size); if (!(plr_gfx_flag & 0x80)) { //DEATH plr_gfx_flag |= 0x80; plr_dframe_size = GetPlrGFXSize("DT"); } plr[pnum]._pDData = DiabloAllocPtr(plr_dframe_size); if (!(plr_gfx_bflag & 0x1)) { //BLOCK plr_gfx_bflag |= 0x1; plr_bframe_size = GetPlrGFXSize("BL"); } plr[pnum]._pBData = DiabloAllocPtr(plr_bframe_size); plr[pnum]._pGFXLoad = 0; } void FreePlayerGFX(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("FreePlayerGFX: illegal player %d", pnum); } MemFreeDbg(plr[pnum]._pNData); MemFreeDbg(plr[pnum]._pWData); MemFreeDbg(plr[pnum]._pAData); MemFreeDbg(plr[pnum]._pHData); MemFreeDbg(plr[pnum]._pLData); MemFreeDbg(plr[pnum]._pFData); MemFreeDbg(plr[pnum]._pTData); MemFreeDbg(plr[pnum]._pDData); MemFreeDbg(plr[pnum]._pBData); plr[pnum]._pGFXLoad = 0; } void NewPlrAnim(int pnum, BYTE *Peq, int numFrames, int Delay, int width) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("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 ClearPlrPVars(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("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 SetPlrAnims(int pnum) { int pc, gn; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("SetPlrAnims: illegal player %d", pnum); } 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; pc = plr[pnum]._pClass; 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]; gn = plr[pnum]._pgfxnum & 0xF; if (pc == PC_WARRIOR) { if (gn == ANIM_ID_BOW) { if (leveltype != DTYPE_TOWN) { plr[pnum]._pNFrames = 8; } plr[pnum]._pAWidth = 96; plr[pnum]._pAFNum = 11; } else if (gn == ANIM_ID_AXE) { plr[pnum]._pAFrames = 20; plr[pnum]._pAFNum = 10; } else if (gn == ANIM_ID_STAFF) { plr[pnum]._pAFrames = 16; plr[pnum]._pAFNum = 11; } #ifndef SPAWN } else if (pc == PC_ROGUE) { if (gn == ANIM_ID_AXE) { plr[pnum]._pAFrames = 22; plr[pnum]._pAFNum = 13; } else if (gn == ANIM_ID_BOW) { plr[pnum]._pAFrames = 12; plr[pnum]._pAFNum = 7; } else if (gn == ANIM_ID_STAFF) { plr[pnum]._pAFrames = 16; plr[pnum]._pAFNum = 11; } } else if (pc == PC_SORCERER) { plr[pnum]._pSWidth = 128; if (gn == ANIM_ID_UNARMED) { plr[pnum]._pAFrames = 20; } else if (gn == ANIM_ID_UNARMED_SHIELD) { plr[pnum]._pAFNum = 9; } else if (gn == ANIM_ID_BOW) { plr[pnum]._pAFrames = 20; plr[pnum]._pAFNum = 16; } else if (gn == ANIM_ID_AXE) { plr[pnum]._pAFrames = 24; plr[pnum]._pAFNum = 16; } #endif #ifdef HELLFIRE } else if (pc == PC_MONK) { plr[pnum]._pNWidth = 112; plr[pnum]._pWWidth = 112; plr[pnum]._pAWidth = 130; plr[pnum]._pHWidth = 98; plr[pnum]._pSWidth = 114; plr[pnum]._pDWidth = 160; plr[pnum]._pBWidth = 98; switch (gn) { case ANIM_ID_UNARMED: case ANIM_ID_UNARMED_SHIELD: plr[pnum]._pAFrames = 12; plr[pnum]._pAFNum = 7; break; case ANIM_ID_BOW: plr[pnum]._pAFrames = 20; plr[pnum]._pAFNum = 14; break; case ANIM_ID_AXE: plr[pnum]._pAFrames = 23; plr[pnum]._pAFNum = 14; break; case ANIM_ID_STAFF: plr[pnum]._pAFrames = 13; plr[pnum]._pAFNum = 8; break; } } else if (pc == PC_BARD) { if (gn == ANIM_ID_AXE) { plr[pnum]._pAFrames = 22; plr[pnum]._pAFNum = 13; } else if (gn == ANIM_ID_BOW) { plr[pnum]._pAFrames = 12; plr[pnum]._pAFNum = 11; } else if (gn == ANIM_ID_STAFF) { plr[pnum]._pAFrames = 16; plr[pnum]._pAFNum = 11; } else if (gn == ANIM_ID_SWORD_SHIELD || gn == ANIM_ID_SWORD) { plr[pnum]._pAFNum = 10; } } else if (pc == PC_BARBARIAN) { if (gn == ANIM_ID_AXE) { plr[pnum]._pAFrames = 20; plr[pnum]._pAFNum = 8; } else if (gn == ANIM_ID_BOW) { if (leveltype != DTYPE_TOWN) { plr[pnum]._pNFrames = 8; } plr[pnum]._pAWidth = 96; plr[pnum]._pAFNum = 11; } else if (gn == ANIM_ID_STAFF) { plr[pnum]._pAFrames = 16; plr[pnum]._pAFNum = 11; } else if (gn == ANIM_ID_MACE || gn == ANIM_ID_MACE_SHIELD) { plr[pnum]._pAFNum = 8; } #endif } } void ClearPlrRVars(PlayerStruct *p) { // TODO: Missing debug assert p != NULL #ifdef HELLFIRE p->pManaShield = 0; #endif p->bReserved[0] = 0; p->bReserved[1] = 0; p->bReserved[2] = 0; #ifndef HELLFIRE p->wReflections = 0; #endif 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; #ifndef HELLFIRE p->pDifficulty = 0; p->pDamAcFlags = 0; #endif p->dwReserved[0] = 0; p->dwReserved[1] = 0; p->dwReserved[2] = 0; p->dwReserved[3] = 0; p->dwReserved[4] = 0; } /** * @param c plr_classes value */ void CreatePlayer(int pnum, char c) { char val; int hp, mana; int i; #ifdef HELLFIRE memset(&plr[pnum], 0, sizeof(PlayerStruct)); #endif ClearPlrRVars(&plr[pnum]); SetRndSeed(GetTickCount()); if ((DWORD)pnum >= MAX_PLRS) { app_fatal("CreatePlayer: illegal player %d", pnum); } plr[pnum]._pClass = c; 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; #ifdef HELLFIRE plr[pnum].pDungMsgs2 = 0; #endif plr[pnum].pLvlLoad = 0; plr[pnum].pDiabloKillLevel = 0; #ifdef HELLFIRE plr[pnum].pDifficulty = DIFF_NORMAL; #endif #ifdef HELLFIRE if (plr[pnum]._pClass == PC_MONK) { plr[pnum]._pDamageMod = (plr[pnum]._pStrength + plr[pnum]._pDexterity) * plr[pnum]._pLevel / 150; } else if (plr[pnum]._pClass == PC_ROGUE || plr[pnum]._pClass == PC_BARD) { #else if (plr[pnum]._pClass == PC_ROGUE) { #endif 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]; // BUGFIX: _pBaseToBlk not set in player struct if creating a New Game using an existing save file (since CreatePlayer is never invoked in this case). plr[pnum]._pHitPoints = (plr[pnum]._pVitality + 10) << 6; if (plr[pnum]._pClass == PC_WARRIOR #ifdef HELLFIRE || plr[pnum]._pClass == PC_BARBARIAN #endif ) { plr[pnum]._pHitPoints <<= 1; #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_ROGUE || plr[pnum]._pClass == PC_MONK || plr[pnum]._pClass == PC_BARD) { #else } if (plr[pnum]._pClass == PC_ROGUE) { #endif plr[pnum]._pHitPoints += plr[pnum]._pHitPoints >> 1; } plr[pnum]._pMaxHP = plr[pnum]._pHitPoints; plr[pnum]._pHPBase = plr[pnum]._pHitPoints; plr[pnum]._pMaxHPBase = plr[pnum]._pHitPoints; plr[pnum]._pMana = plr[pnum]._pMagic << 6; if (plr[pnum]._pClass == PC_SORCERER) { plr[pnum]._pMana <<= 1; #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_BARD) { plr[pnum]._pMana += plr[pnum]._pMana * 3 / 4; } else if (plr[pnum]._pClass == PC_ROGUE || plr[pnum]._pClass == PC_MONK) { #else } if (plr[pnum]._pClass == PC_ROGUE) { #endif plr[pnum]._pMana += plr[pnum]._pMana >> 1; } plr[pnum]._pMaxMana = plr[pnum]._pMana; plr[pnum]._pManaBase = plr[pnum]._pMana; plr[pnum]._pMaxManaBase = plr[pnum]._pMana; plr[pnum]._pLevel = 1; plr[pnum]._pMaxLvl = plr[pnum]._pLevel; plr[pnum]._pExperience = 0; plr[pnum]._pMaxExp = plr[pnum]._pExperience; plr[pnum]._pNextExper = ExpLvlsTbl[1]; plr[pnum]._pArmorClass = 0; #ifdef HELLFIRE if (plr[pnum]._pClass == PC_BARBARIAN) { plr[pnum]._pMagResist = 1; plr[pnum]._pFireResist = 1; plr[pnum]._pLghtResist = 1; } else { #endif plr[pnum]._pMagResist = 0; plr[pnum]._pFireResist = 0; plr[pnum]._pLghtResist = 0; #ifdef HELLFIRE } #endif plr[pnum]._pLightRad = 10; plr[pnum]._pInfraFlag = FALSE; if (c == PC_WARRIOR) { plr[pnum]._pAblSpells = SPELLBIT(SPL_REPAIR); #ifndef SPAWN } else if (c == PC_ROGUE) { plr[pnum]._pAblSpells = SPELLBIT(SPL_DISARM); } else if (c == PC_SORCERER) { plr[pnum]._pAblSpells = SPELLBIT(SPL_RECHARGE); #endif #ifdef HELLFIRE } else if (c == PC_MONK) { plr[pnum]._pAblSpells = SPELLBIT(SPL_SEARCH); } else if (c == PC_BARD) { plr[pnum]._pAblSpells = SPELLBIT(SPL_IDENTIFY); } else if (c == PC_BARBARIAN) { plr[pnum]._pAblSpells = SPELLBIT(SPL_BLODBOIL); #endif } if (c == PC_SORCERER) { plr[pnum]._pMemSpells = SPELLBIT(SPL_FIREBOLT); } else { plr[pnum]._pMemSpells = 0; } for (i = 0; i < sizeof(plr[pnum]._pSplLvl) / sizeof(plr[pnum]._pSplLvl[0]); i++) { plr[pnum]._pSplLvl[i] = 0; } plr[pnum]._pSpellFlags = 0; if (plr[pnum]._pClass == PC_SORCERER) { plr[pnum]._pSplLvl[SPL_FIREBOLT] = 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 = ANIM_ID_SWORD_SHIELD; #ifndef SPAWN } else if (c == PC_ROGUE) { plr[pnum]._pgfxnum = ANIM_ID_BOW; } else if (c == PC_SORCERER) { plr[pnum]._pgfxnum = ANIM_ID_STAFF; #endif #ifdef HELLFIRE } else if (c == PC_MONK) { plr[pnum]._pgfxnum = ANIM_ID_STAFF; } else if (c == PC_BARD) { plr[pnum]._pgfxnum = ANIM_ID_SWORD_SHIELD; } else if (c == PC_BARBARIAN) { plr[pnum]._pgfxnum = ANIM_ID_SWORD_SHIELD; #endif } for (i = 0; i < NUMLEVELS; i++) { plr[pnum]._pLvlVisited[i] = FALSE; } for (i = 0; i < 10; i++) { plr[pnum]._pSLvlVisited[i] = FALSE; } plr[pnum]._pLvlChanging = FALSE; plr[pnum].pTownWarps = 0; plr[pnum].pLvlLoad = 0; #ifndef HELLFIRE plr[pnum].pBattleNet = FALSE; plr[pnum].pManaShield = FALSE; #else plr[pnum].pDamAcFlags = 0; plr[pnum].wReflections = 0; #endif InitDungMsgs(pnum); CreatePlrItems(pnum); SetRndSeed(0); } int CalcStatDiff(int pnum) { int c; 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 NextPlrLevel(int pnum) { int hp, mana; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("NextPlrLevel: illegal player %d", pnum); } plr[pnum]._pLevel++; plr[pnum]._pMaxLvl++; #ifdef HELLFIRE CalcPlrInv(pnum, TRUE); #endif if (CalcStatDiff(pnum) < 5) { plr[pnum]._pStatPts = CalcStatDiff(pnum); } else { plr[pnum]._pStatPts += 5; } plr[pnum]._pNextExper = ExpLvlsTbl[plr[pnum]._pLevel]; hp = plr[pnum]._pClass == 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 = TRUE; } if (plr[pnum]._pClass == PC_WARRIOR) mana = 64; #ifdef HELLFIRE else if (plr[pnum]._pClass == PC_BARBARIAN) mana = 0; #endif else mana = 128; 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) { #ifdef HELLFIRE if (plr[pnum]._pMana > 0) #endif drawmanaflag = TRUE; } } void AddPlrExperience(int pnum, int lvl, int exp) { int powerLvlCap, expCap, newLvl, i; if (pnum != myplr) { return; } if ((DWORD)myplr >= MAX_PLRS) { app_fatal("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) { 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 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 newLvl = 0; while (plr[pnum]._pExperience >= ExpLvlsTbl[newLvl]) { newLvl++; } if (newLvl != plr[pnum]._pLevel) { for (i = newLvl - plr[pnum]._pLevel; i > 0; i--) { NextPlrLevel(pnum); } } NetSendCmdParam1(FALSE, CMD_PLRLEVEL, plr[myplr]._pLevel); } void AddPlrMonstExper(int lvl, int exp, char pmask) { int totplrs, i, e; totplrs = 0; for (i = 0; i < MAX_PLRS; i++) { if ((1 << i) & pmask) { totplrs++; } } if (totplrs) { e = exp / totplrs; if (pmask & (1 << myplr)) AddPlrExperience(myplr, lvl, e); } } void InitPlayer(int pnum, BOOL FirstTime) { DWORD i; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("InitPlayer: illegal player %d", pnum); } ClearPlrRVars(&plr[pnum]); if (FirstTime) { plr[pnum]._pRSplType = RSPLTYPE_INVALID; plr[pnum]._pRSpell = SPL_INVALID; plr[pnum]._pSBkSpell = SPL_INVALID; plr[pnum]._pSpell = plr[pnum]._pRSpell; plr[pnum]._pSplType = plr[pnum]._pRSplType; if ((plr[pnum]._pgfxnum & 0xF) == ANIM_ID_BOW) { plr[pnum]._pwtype = WT_RANGED; } else { plr[pnum]._pwtype = WT_MELEE; } #ifndef HELLFIRE plr[pnum].pManaShield = FALSE; #endif } 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[DIR_S], 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[DIR_S], plr[pnum]._pDFrames, 1, plr[pnum]._pDWidth); plr[pnum]._pAnimFrame = plr[pnum]._pAnimLen - 1; plr[pnum]._pVar8 = 2 * plr[pnum]._pAnimLen; } plr[pnum]._pdir = DIR_S; plr[pnum]._peflag = 0; if (pnum == myplr) { if (!FirstTime || currlevel != 0) { plr[pnum]._px = ViewX; plr[pnum]._py = ViewY; } plr[pnum]._ptargx = plr[pnum]._px; plr[pnum]._ptargy = plr[pnum]._py; } else { plr[pnum]._ptargx = plr[pnum]._px; plr[pnum]._ptargy = plr[pnum]._py; for (i = 0; i < 8 && !PosOkPlayer(pnum, plrxoff2[i] + plr[pnum]._px, plryoff2[i] + plr[pnum]._py); i++) ; plr[pnum]._px += plrxoff2[i]; plr[pnum]._py += plryoff2[i]; } plr[pnum]._pfutx = plr[pnum]._px; plr[pnum]._pfuty = plr[pnum]._py; plr[pnum].walkpath[0] = WALK_NONE; plr[pnum].destAction = ACTION_NONE; if (pnum == myplr) { plr[pnum]._plid = AddLight(plr[pnum]._px, plr[pnum]._py, plr[pnum]._pLightRad); } else { plr[pnum]._plid = -1; } plr[pnum]._pvid = AddVision(plr[pnum]._px, plr[pnum]._py, plr[pnum]._pLightRad, pnum == myplr); } if (plr[pnum]._pClass == PC_WARRIOR) { plr[pnum]._pAblSpells = SPELLBIT(SPL_REPAIR); #ifndef SPAWN } else if (plr[pnum]._pClass == PC_ROGUE) { plr[pnum]._pAblSpells = SPELLBIT(SPL_DISARM); } else if (plr[pnum]._pClass == PC_SORCERER) { plr[pnum]._pAblSpells = SPELLBIT(SPL_RECHARGE); #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK) { plr[pnum]._pAblSpells = SPELLBIT(SPL_SEARCH); } else if (plr[pnum]._pClass == PC_BARD) { plr[pnum]._pAblSpells = SPELLBIT(SPL_IDENTIFY); } else if (plr[pnum]._pClass == PC_BARBARIAN) { plr[pnum]._pAblSpells = SPELLBIT(SPL_BLODBOIL); #endif #endif } #ifdef _DEBUG if (debug_mode_dollar_sign && FirstTime) { plr[pnum]._pMemSpells |= 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]._pMemSpells = SPL_INVALID; } #endif plr[pnum]._pNextExper = ExpLvlsTbl[plr[pnum]._pLevel]; plr[pnum]._pInvincible = FALSE; if (pnum == myplr) { deathdelay = 0; deathflag = FALSE; ScrollInfo._sxoff = 0; ScrollInfo._syoff = 0; ScrollInfo._sdir = SDIR_NONE; } } void InitMultiView() { if ((DWORD)myplr >= MAX_PLRS) { app_fatal("InitPlayer: illegal player %d", myplr); } ViewX = plr[myplr]._px; ViewY = plr[myplr]._py; } void CheckEFlag(int pnum, BOOL flag) { int x, y, i; int bitflags; MICROS *pieces; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("InitPlayer: illegal player %d", pnum); } x = plr[pnum]._px - 1; y = plr[pnum]._py + 1; bitflags = 0; pieces = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 2; i < 10; i++) { bitflags |= pieces->mt[i]; } if (bitflags | nSolidTable[dPiece[x][y]] | dSpecial[x][y]) { plr[pnum]._peflag = 1; } else { plr[pnum]._peflag = 0; } if (flag != 1 || plr[pnum]._peflag != 1) { return; } x = plr[pnum]._px; y = plr[pnum]._py + 2; bitflags = 0; pieces = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 2; i < 10; i++) { bitflags |= pieces->mt[i]; } if (bitflags | dSpecial[x][y]) { return; } x = plr[pnum]._px - 2; y = plr[pnum]._py + 1; bitflags = 0; pieces = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 2; i < 10; i++) { bitflags |= pieces->mt[i]; } if (bitflags | dSpecial[x][y]) { plr[pnum]._peflag = 2; } } BOOL SolidLoc(int x, int y) { #ifndef HELLFIRE if (x < 0 || y < 0 || x >= MAXDUNX || y >= MAXDUNY) { return FALSE; } #endif return nSolidTable[dPiece[x][y]]; } BOOL PlrDirOK(int pnum, int dir) { int px, py; BOOL isOk; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PlrDirOK: illegal player %d", pnum); } px = plr[pnum]._px + offset_x[dir]; py = plr[pnum]._py + offset_y[dir]; if (px < 0 || !dPiece[px][py] || !PosOkPlayer(pnum, px, py)) { return FALSE; } isOk = TRUE; if (dir == DIR_E) { isOk = !SolidLoc(px, py + 1) && !(dFlags[px][py + 1] & BFLAG_PLAYERLR); } if (isOk && dir == DIR_W) { isOk = !SolidLoc(px + 1, py) && !(dFlags[px + 1][py] & BFLAG_PLAYERLR); } return isOk; } void PlrClrTrans(int x, int y) { int i, j; for (i = y - 1; i <= y + 1; i++) { for (j = x - 1; j <= x + 1; j++) { TransList[dTransVal[j][i]] = FALSE; } } } void PlrDoTrans(int x, int y) { int i, j; if (leveltype != DTYPE_CATHEDRAL && leveltype != DTYPE_CATACOMBS) { TransList[1] = TRUE; } else { for (i = y - 1; i <= y + 1; i++) { for (j = x - 1; j <= x + 1; j++) { if (!nSolidTable[dPiece[j][i]] && dTransVal[j][i]) { TransList[dTransVal[j][i]] = TRUE; } } } } } void SetPlayerOld(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("SetPlayerOld: illegal player %d", pnum); } plr[pnum]._poldx = plr[pnum]._px; plr[pnum]._poldy = plr[pnum]._py; } void FixPlayerLocation(int pnum, int bDir) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("FixPlayerLocation: illegal player %d", pnum); } plr[pnum]._pfutx = plr[pnum]._px; plr[pnum]._pfuty = plr[pnum]._py; plr[pnum]._ptargx = plr[pnum]._px; plr[pnum]._ptargy = plr[pnum]._py; plr[pnum]._pxoff = 0; plr[pnum]._pyoff = 0; CheckEFlag(pnum, FALSE); plr[pnum]._pdir = bDir; if (pnum == myplr) { ScrollInfo._sxoff = 0; ScrollInfo._syoff = 0; ScrollInfo._sdir = SDIR_NONE; ViewX = plr[pnum]._px; ViewY = plr[pnum]._py; } } void StartStand(int pnum, int dir) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StartStand: illegal player %d", pnum); } if (!plr[pnum]._pInvincible || plr[pnum]._pHitPoints != 0 || 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]._px][plr[pnum]._py] = pnum + 1; SetPlayerOld(pnum); } else { SyncPlrKill(pnum, -1); } } void StartWalkStand(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StartWalkStand: illegal player %d", pnum); } plr[pnum]._pmode = PM_STAND; plr[pnum]._pfutx = plr[pnum]._px; plr[pnum]._pfuty = plr[pnum]._py; plr[pnum]._pxoff = 0; plr[pnum]._pyoff = 0; CheckEFlag(pnum, FALSE); if (pnum == myplr) { ScrollInfo._sxoff = 0; ScrollInfo._syoff = 0; ScrollInfo._sdir = SDIR_NONE; ViewX = plr[pnum]._px; ViewY = plr[pnum]._py; } } void PM_ChangeLightOff(int pnum) { int x, y; int xmul, ymul; int lx, ly; int offx, offy; const LightListStruct *l; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PM_ChangeLightOff: illegal player %d", pnum); } l = &LightList[plr[pnum]._plid]; x = 2 * plr[pnum]._pyoff + plr[pnum]._pxoff; y = 2 * plr[pnum]._pyoff - plr[pnum]._pxoff; if (x < 0) { xmul = -1; x = -x; } else { xmul = 1; } if (y < 0) { ymul = -1; y = -y; } else { ymul = 1; } x = (x >> 3) * xmul; y = (y >> 3) * ymul; lx = x + (l->_lx << 3); ly = y + (l->_ly << 3); offx = l->_xoff + (l->_lx << 3); offy = l->_yoff + (l->_ly << 3); if (abs(lx - offx) < 3 && abs(ly - offy) < 3) return; ChangeLightOff(plr[pnum]._plid, x, y); } void PM_ChangeOffset(int pnum) { int px, py; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PM_ChangeOffset: illegal player %d", pnum); } plr[pnum]._pVar8++; px = plr[pnum]._pVar6 >> 8; py = plr[pnum]._pVar7 >> 8; plr[pnum]._pVar6 += plr[pnum]._pxvel; plr[pnum]._pVar7 += plr[pnum]._pyvel; #ifdef HELLFIRE if (currlevel == 0 && jogging_opt) { plr[pnum]._pVar6 += plr[pnum]._pxvel; plr[pnum]._pVar7 += plr[pnum]._pyvel; } #endif plr[pnum]._pxoff = plr[pnum]._pVar6 >> 8; plr[pnum]._pyoff = plr[pnum]._pVar7 >> 8; px -= plr[pnum]._pVar6 >> 8; py -= plr[pnum]._pVar7 >> 8; if (pnum == myplr && ScrollInfo._sdir) { ScrollInfo._sxoff += px; ScrollInfo._syoff += py; } PM_ChangeLightOff(pnum); } /** * @brief Starting a move action towards NW, N, or NE */ void StartWalk(int pnum, int xvel, int yvel, int xadd, int yadd, int EndDir, int sdir) { int px, py; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StartWalk: illegal player %d", pnum); } if (plr[pnum]._pInvincible && plr[pnum]._pHitPoints == 0 && pnum == myplr) { SyncPlrKill(pnum, -1); return; } SetPlayerOld(pnum); px = xadd + plr[pnum]._px; py = yadd + plr[pnum]._py; if (!PlrDirOK(pnum, EndDir)) { return; } plr[pnum]._pfutx = px; plr[pnum]._pfuty = py; if (pnum == myplr) { ScrollInfo._sdx = plr[pnum]._px - ViewX; ScrollInfo._sdy = plr[pnum]._py - 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; CheckEFlag(pnum, FALSE); if (pnum != myplr) { return; } if (zoomflag) { if (abs(ScrollInfo._sdx) >= 3 || abs(ScrollInfo._sdy) >= 3) { ScrollInfo._sdir = SDIR_NONE; } else { ScrollInfo._sdir = sdir; } } else if (abs(ScrollInfo._sdx) >= 2 || abs(ScrollInfo._sdy) >= 2) { ScrollInfo._sdir = SDIR_NONE; } else { ScrollInfo._sdir = sdir; } } /** * @brief Starting a move action towards SW, S, or SE */ void StartWalk2(int pnum, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int EndDir, int sdir) { int px, py; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StartWalk2: illegal player %d", pnum); } if (plr[pnum]._pInvincible && plr[pnum]._pHitPoints == 0 && pnum == myplr) { SyncPlrKill(pnum, -1); return; } SetPlayerOld(pnum); px = xadd + plr[pnum]._px; py = yadd + plr[pnum]._py; if (!PlrDirOK(pnum, EndDir)) { return; } plr[pnum]._pfutx = px; plr[pnum]._pfuty = py; if (pnum == myplr) { ScrollInfo._sdx = plr[pnum]._px - ViewX; ScrollInfo._sdy = plr[pnum]._py - ViewY; } dPlayer[plr[pnum]._px][plr[pnum]._py] = -1 - pnum; plr[pnum]._pVar1 = plr[pnum]._px; plr[pnum]._pVar2 = plr[pnum]._py; plr[pnum]._px = px; // Move player to the next tile to maintain correct render order plr[pnum]._py = py; dPlayer[plr[pnum]._px][plr[pnum]._py] = pnum + 1; plr[pnum]._pxoff = xoff; // Offset player sprite to align with their previous tile position plr[pnum]._pyoff = yoff; // BUGFIX: missing `if (leveltype != DTYPE_TOWN) {` for call to ChangeLightXY and PM_ChangeLightOff. ChangeLightXY(plr[pnum]._plid, plr[pnum]._px, plr[pnum]._py); 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) { CheckEFlag(pnum, TRUE); } else { CheckEFlag(pnum, FALSE); } if (pnum != myplr) { return; } if (zoomflag) { if (abs(ScrollInfo._sdx) >= 3 || abs(ScrollInfo._sdy) >= 3) { ScrollInfo._sdir = SDIR_NONE; } else { ScrollInfo._sdir = sdir; } } else if (abs(ScrollInfo._sdx) >= 2 || abs(ScrollInfo._sdy) >= 2) { ScrollInfo._sdir = SDIR_NONE; } else { ScrollInfo._sdir = sdir; } } /** * @brief Starting a move action towards W or E */ void StartWalk3(int pnum, int xvel, int yvel, int xoff, int yoff, int xadd, int yadd, int mapx, int mapy, int EndDir, int sdir) { int px, py, x, y; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StartWalk3: illegal player %d", pnum); } if (plr[pnum]._pInvincible && plr[pnum]._pHitPoints == 0 && pnum == myplr) { SyncPlrKill(pnum, -1); return; } SetPlayerOld(pnum); px = xadd + plr[pnum]._px; py = yadd + plr[pnum]._py; x = mapx + plr[pnum]._px; y = mapy + plr[pnum]._py; if (!PlrDirOK(pnum, EndDir)) { return; } plr[pnum]._pfutx = px; plr[pnum]._pfuty = py; if (pnum == myplr) { ScrollInfo._sdx = plr[pnum]._px - ViewX; ScrollInfo._sdy = plr[pnum]._py - ViewY; } dPlayer[plr[pnum]._px][plr[pnum]._py] = -1 - pnum; dPlayer[px][py] = -1 - pnum; plr[pnum]._pVar4 = x; plr[pnum]._pVar5 = y; dFlags[x][y] |= BFLAG_PLAYERLR; plr[pnum]._pxoff = xoff; // Offset player sprite to align with their previous tile position plr[pnum]._pyoff = yoff; if (leveltype != DTYPE_TOWN) { 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; CheckEFlag(pnum, FALSE); if (pnum != myplr) { return; } if (zoomflag) { if (abs(ScrollInfo._sdx) >= 3 || abs(ScrollInfo._sdy) >= 3) { ScrollInfo._sdir = SDIR_NONE; } else { ScrollInfo._sdir = sdir; } } else if (abs(ScrollInfo._sdx) >= 2 || abs(ScrollInfo._sdy) >= 2) { ScrollInfo._sdir = SDIR_NONE; } else { ScrollInfo._sdir = sdir; } } void StartAttack(int pnum, int d) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StartAttack: illegal player %d", pnum); } if (plr[pnum]._pInvincible && plr[pnum]._pHitPoints == 0 && 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 StartRangeAttack(int pnum, int d, int cx, int cy) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StartRangeAttack: illegal player %d", pnum); } if (plr[pnum]._pInvincible && plr[pnum]._pHitPoints == 0 && 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 StartPlrBlock(int pnum, int dir) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StartPlrBlock: illegal player %d", pnum); } if (plr[pnum]._pInvincible && plr[pnum]._pHitPoints == 0 && pnum == myplr) { SyncPlrKill(pnum, -1); return; } PlaySfxLoc(IS_ISWORD, plr[pnum]._px, plr[pnum]._py); 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 StartSpell(int pnum, int d, int cx, int cy) { if ((DWORD)pnum >= MAX_PLRS) app_fatal("StartSpell: illegal player %d", pnum); if (plr[pnum]._pInvincible && plr[pnum]._pHitPoints == 0 && 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]._px, plr[pnum]._py); 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; } void FixPlrWalkTags(int pnum) { int pp, pn; int dx, dy, y, x; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("FixPlrWalkTags: illegal player %d", pnum); } pp = pnum + 1; pn = -(pnum + 1); dx = plr[pnum]._poldx; dy = plr[pnum]._poldy; for (y = dy - 1; y <= dy + 1; y++) { for (x = dx - 1; x <= dx + 1; x++) { if (x >= 0 && x < MAXDUNX && y >= 0 && y < MAXDUNY && (dPlayer[x][y] == pp || dPlayer[x][y] == pn)) { dPlayer[x][y] = 0; } } } if (dx >= 0 && dx < MAXDUNX - 1 && dy >= 0 && dy < MAXDUNY - 1) { dFlags[dx + 1][dy] &= ~BFLAG_PLAYERLR; dFlags[dx][dy + 1] &= ~BFLAG_PLAYERLR; } } void RemovePlrFromMap(int pnum) { int x, y; int pp, pn; pp = pnum + 1; pn = -(pnum + 1); for (y = 1; y < MAXDUNY; y++) for (x = 1; x < MAXDUNX; x++) if (dPlayer[x][y - 1] == pn || dPlayer[x - 1][y] == pn) if (dFlags[x][y] & BFLAG_PLAYERLR) dFlags[x][y] &= ~BFLAG_PLAYERLR; for (y = 0; y < MAXDUNY; y++) for (x = 0; x < MAXDUNX; x++) if (dPlayer[x][y] == pp || dPlayer[x][y] == pn) dPlayer[x][y] = 0; } void StartPlrHit(int pnum, int dam, BOOL forcehit) { int pd; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StartPlrHit: illegal player %d", pnum); } if (plr[pnum]._pInvincible && plr[pnum]._pHitPoints == 0 && pnum == myplr) { SyncPlrKill(pnum, -1); return; } if (plr[pnum]._pClass == PC_WARRIOR) { PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py); #ifndef SPAWN } else if (plr[pnum]._pClass == PC_ROGUE) { PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py); } else if (plr[pnum]._pClass == PC_SORCERER) { PlaySfxLoc(PS_MAGE69, plr[pnum]._px, plr[pnum]._py); #endif #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK) { PlaySfxLoc(PS_MONK69, plr[pnum]._px, plr[pnum]._py); } else if (plr[pnum]._pClass == PC_BARD) { PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py); } else if (plr[pnum]._pClass == PC_BARBARIAN) { PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py); #endif } drawhpflag = TRUE; #ifdef HELLFIRE if (plr[pnum]._pClass == PC_BARBARIAN) { if (dam >> 6 < plr[pnum]._pLevel + plr[pnum]._pLevel / 4 && !forcehit) { return; } } else #endif if (dam >> 6 < plr[pnum]._pLevel && !forcehit) { return; } pd = plr[pnum]._pdir; if (!(plr[pnum]._pGFXLoad & PFILE_HIT)) { LoadPlrGFX(pnum, PFILE_HIT); } NewPlrAnim(pnum, plr[pnum]._pHAnim[pd], plr[pnum]._pHFrames, 0, plr[pnum]._pHWidth); plr[pnum]._pmode = PM_GOTHIT; FixPlayerLocation(pnum, pd); plr[pnum]._pVar8 = 1; FixPlrWalkTags(pnum); dPlayer[plr[pnum]._px][plr[pnum]._py] = pnum + 1; SetPlayerOld(pnum); } void RespawnDeadItem(ItemStruct *itm, int x, int y) { int ii; if (numitems >= MAXITEMS) { return; } if (FindGetItem(itm->IDidx, itm->_iCreateInfo, itm->_iSeed) >= 0) { DrawInvMsg("A duplicate item has been detected. Destroying duplicate..."); SyncGetItem(x, y, itm->IDidx, itm->_iCreateInfo, itm->_iSeed); } ii = itemavail[0]; dItem[x][y] = ii + 1; itemavail[0] = itemavail[MAXITEMS - numitems - 1]; itemactive[numitems] = ii; item[ii] = *itm; item[ii]._ix = x; item[ii]._iy = y; RespawnItem(ii, TRUE); numitems++; itm->_itype = ITYPE_NONE; } static void PlrDeadItem(int pnum, ItemStruct *itm, int xx, int yy) { int x, y; int i, j, k; if (itm->_itype == ITYPE_NONE) return; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PlrDeadItem: illegal player %d", pnum); } x = xx + plr[pnum]._px; y = yy + plr[pnum]._py; if ((xx || yy) && ItemSpaceOk(x, y)) { RespawnDeadItem(itm, x, y); plr[pnum].HoldItem = *itm; NetSendCmdPItem(FALSE, CMD_RESPAWNITEM, x, y); return; } for (k = 1; k < 50; k++) { for (j = -k; j <= k; j++) { y = j + plr[pnum]._py; for (i = -k; i <= k; i++) { x = i + plr[pnum]._px; if (ItemSpaceOk(x, y)) { RespawnDeadItem(itm, x, y); plr[pnum].HoldItem = *itm; NetSendCmdPItem(FALSE, CMD_RESPAWNITEM, x, y); return; } } } } } void StartPlayerKill(int pnum, int earflag) { BOOL diablolevel; int i, pdd; PlayerStruct *p; ItemStruct ear; ItemStruct *pi; p = &plr[pnum]; if (p->_pHitPoints <= 0 && p->_pmode == PM_DEATH) { return; } if (myplr == pnum) { NetSendCmdParam1(TRUE, CMD_PLRDEAD, earflag); } diablolevel = gbMaxPlayers > 1 && plr[pnum].plrlevel == 16; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StartPlayerKill: illegal player %d", pnum); } if (plr[pnum]._pClass == PC_WARRIOR) { PlaySfxLoc(PS_DEAD, p->_px, p->_py); // BUGFIX: should use `PS_WARR71` like other classes #ifndef SPAWN } else if (plr[pnum]._pClass == PC_ROGUE) { PlaySfxLoc(PS_ROGUE71, p->_px, p->_py); } else if (plr[pnum]._pClass == PC_SORCERER) { PlaySfxLoc(PS_MAGE71, p->_px, p->_py); #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK) { PlaySfxLoc(PS_MONK71, p->_px, p->_py); } else if (plr[pnum]._pClass == PC_BARD) { PlaySfxLoc(PS_ROGUE71, p->_px, p->_py); } else if (plr[pnum]._pClass == PC_BARBARIAN) { PlaySfxLoc(PS_WARR71, p->_px, p->_py); #endif #endif } if (p->_pgfxnum) { p->_pgfxnum = 0; p->_pGFXLoad = 0; SetPlrAnims(pnum); } if (!(p->_pGFXLoad & PFILE_DEATH)) { LoadPlrGFX(pnum, PFILE_DEATH); } NewPlrAnim(pnum, p->_pDAnim[p->_pdir], p->_pDFrames, 1, p->_pDWidth); p->_pBlockFlag = FALSE; p->_pmode = PM_DEATH; p->_pInvincible = TRUE; SetPlayerHitPoints(pnum, 0); p->_pVar8 = 1; if (pnum != myplr && !earflag && !diablolevel) { for (i = 0; i < NUM_INVLOC; i++) { p->InvBody[i]._itype = ITYPE_NONE; } CalcPlrInv(pnum, FALSE); } if (plr[pnum].plrlevel == currlevel) { FixPlayerLocation(pnum, p->_pdir); RemovePlrFromMap(pnum); dFlags[p->_px][p->_py] |= BFLAG_DEAD_PLAYER; SetPlayerOld(pnum); if (pnum == myplr) { drawhpflag = TRUE; deathdelay = 30; if (pcurs >= CURSOR_FIRSTITEM) { PlrDeadItem(pnum, &p->HoldItem, 0, 0); SetCursor_(CURSOR_HAND); } if (!diablolevel) { DropHalfPlayersGold(pnum); if (earflag != -1) { if (earflag != 0) { SetPlrHandItem(&ear, IDI_EAR); sprintf(ear._iName, "Ear of %s", plr[pnum]._pName); if (plr[pnum]._pClass == PC_SORCERER) { ear._iCurs = ICURS_EAR_SORCEROR; } else if (plr[pnum]._pClass == PC_WARRIOR) { ear._iCurs = ICURS_EAR_WARRIOR; } else if (plr[pnum]._pClass == PC_ROGUE) { ear._iCurs = ICURS_EAR_ROGUE; #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK || plr[pnum]._pClass == PC_BARD || plr[pnum]._pClass == PC_BARBARIAN) { ear._iCurs = ICURS_EAR_ROGUE; #endif } ear._iCreateInfo = plr[pnum]._pName[0] << 8 | plr[pnum]._pName[1]; ear._iSeed = plr[pnum]._pName[2] << 24 | plr[pnum]._pName[3] << 16 | plr[pnum]._pName[4] << 8 | plr[pnum]._pName[5]; ear._ivalue = plr[pnum]._pLevel; if (FindGetItem(IDI_EAR, ear._iCreateInfo, ear._iSeed) == -1) { PlrDeadItem(pnum, &ear, 0, 0); } } else { pi = &p->InvBody[0]; i = NUM_INVLOC; while (i--) { pdd = (i + p->_pdir) & 7; PlrDeadItem(pnum, pi, offset_x[pdd], offset_y[pdd]); pi++; } CalcPlrInv(pnum, FALSE); } } } } } #ifndef HELLFIRE SetPlayerHitPoints(pnum, 0); #endif } void DropHalfPlayersGold(int pnum) { int i, hGold; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("DropHalfPlayersGold: illegal player %d", pnum); } hGold = plr[pnum]._pGold >> 1; for (i = 0; i < MAXBELTITEMS && hGold > 0; i++) { if (plr[pnum].SpdList[i]._itype == ITYPE_GOLD && #ifndef HELLFIRE plr[pnum].SpdList[i]._ivalue != GOLD_MAX_LIMIT) { #else plr[pnum].SpdList[i]._ivalue != MaxGold) { #endif if (hGold < plr[pnum].SpdList[i]._ivalue) { plr[pnum].SpdList[i]._ivalue -= hGold; SetSpdbarGoldCurs(pnum, i); SetPlrHandItem(&plr[pnum].HoldItem, IDI_GOLD); GetGoldSeed(pnum, &plr[pnum].HoldItem); SetPlrHandGoldCurs(&plr[pnum].HoldItem); plr[pnum].HoldItem._ivalue = hGold; PlrDeadItem(pnum, &plr[pnum].HoldItem, 0, 0); hGold = 0; } else { hGold -= plr[pnum].SpdList[i]._ivalue; RemoveSpdBarItem(pnum, i); SetPlrHandItem(&plr[pnum].HoldItem, IDI_GOLD); GetGoldSeed(pnum, &plr[pnum].HoldItem); SetPlrHandGoldCurs(&plr[pnum].HoldItem); plr[pnum].HoldItem._ivalue = plr[pnum].SpdList[i]._ivalue; PlrDeadItem(pnum, &plr[pnum].HoldItem, 0, 0); i = -1; } } } if (hGold > 0) { for (i = 0; i < MAXBELTITEMS && hGold > 0; i++) { if (plr[pnum].SpdList[i]._itype == ITYPE_GOLD) { if (hGold < plr[pnum].SpdList[i]._ivalue) { plr[pnum].SpdList[i]._ivalue -= hGold; SetSpdbarGoldCurs(pnum, i); SetPlrHandItem(&plr[pnum].HoldItem, IDI_GOLD); GetGoldSeed(pnum, &plr[pnum].HoldItem); SetPlrHandGoldCurs(&plr[pnum].HoldItem); plr[pnum].HoldItem._ivalue = hGold; PlrDeadItem(pnum, &plr[pnum].HoldItem, 0, 0); hGold = 0; } else { hGold -= plr[pnum].SpdList[i]._ivalue; RemoveSpdBarItem(pnum, i); SetPlrHandItem(&plr[pnum].HoldItem, IDI_GOLD); GetGoldSeed(pnum, &plr[pnum].HoldItem); SetPlrHandGoldCurs(&plr[pnum].HoldItem); plr[pnum].HoldItem._ivalue = plr[pnum].SpdList[i]._ivalue; PlrDeadItem(pnum, &plr[pnum].HoldItem, 0, 0); i = -1; } } } } force_redraw = 255; if (hGold > 0) { for (i = 0; i < plr[pnum]._pNumInv && hGold > 0; i++) { if (plr[pnum].InvList[i]._itype == ITYPE_GOLD && #ifndef HELLFIRE plr[pnum].InvList[i]._ivalue != GOLD_MAX_LIMIT) { #else plr[pnum].InvList[i]._ivalue != MaxGold) { #endif if (hGold < plr[pnum].InvList[i]._ivalue) { plr[pnum].InvList[i]._ivalue -= hGold; SetGoldCurs(pnum, i); SetPlrHandItem(&plr[pnum].HoldItem, IDI_GOLD); GetGoldSeed(pnum, &plr[pnum].HoldItem); SetPlrHandGoldCurs(&plr[pnum].HoldItem); plr[pnum].HoldItem._ivalue = hGold; PlrDeadItem(pnum, &plr[pnum].HoldItem, 0, 0); hGold = 0; } else { hGold -= plr[pnum].InvList[i]._ivalue; RemoveInvItem(pnum, i); SetPlrHandItem(&plr[pnum].HoldItem, IDI_GOLD); GetGoldSeed(pnum, &plr[pnum].HoldItem); SetPlrHandGoldCurs(&plr[pnum].HoldItem); plr[pnum].HoldItem._ivalue = plr[pnum].InvList[i]._ivalue; PlrDeadItem(pnum, &plr[pnum].HoldItem, 0, 0); i = -1; } } } } if (hGold > 0) { for (i = 0; i < plr[pnum]._pNumInv && hGold > 0; i++) { if (plr[pnum].InvList[i]._itype == ITYPE_GOLD) { if (hGold < plr[pnum].InvList[i]._ivalue) { plr[pnum].InvList[i]._ivalue -= hGold; SetGoldCurs(pnum, i); SetPlrHandItem(&plr[pnum].HoldItem, IDI_GOLD); GetGoldSeed(pnum, &plr[pnum].HoldItem); SetPlrHandGoldCurs(&plr[pnum].HoldItem); plr[pnum].HoldItem._ivalue = hGold; PlrDeadItem(pnum, &plr[pnum].HoldItem, 0, 0); hGold = 0; } else { hGold -= plr[pnum].InvList[i]._ivalue; RemoveInvItem(pnum, i); SetPlrHandItem(&plr[pnum].HoldItem, IDI_GOLD); GetGoldSeed(pnum, &plr[pnum].HoldItem); SetPlrHandGoldCurs(&plr[pnum].HoldItem); plr[pnum].HoldItem._ivalue = plr[pnum].InvList[i]._ivalue; PlrDeadItem(pnum, &plr[pnum].HoldItem, 0, 0); i = -1; } } } } plr[pnum]._pGold = CalculateGold(pnum); } #ifdef HELLFIRE void StripTopGold(int pnum) { ItemStruct tmpItem; int i, val; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("StripTopGold: illegal player %d", pnum); } tmpItem = plr[pnum].HoldItem; for (i = 0; i < plr[pnum]._pNumInv; i++) { if (plr[pnum].InvList[i]._itype == ITYPE_GOLD) { if (plr[pnum].InvList[i]._ivalue > MaxGold) { val = plr[pnum].InvList[i]._ivalue - MaxGold; plr[pnum].InvList[i]._ivalue = MaxGold; SetGoldCurs(pnum, i); SetPlrHandItem(&plr[pnum].HoldItem, 0); GetGoldSeed(pnum, &plr[pnum].HoldItem); SetPlrHandGoldCurs(&plr[pnum].HoldItem); plr[pnum].HoldItem._ivalue = val; if (!GoldAutoPlace(pnum)) PlrDeadItem(pnum, &plr[pnum].HoldItem, 0, 0); } } } plr[pnum]._pGold = CalculateGold(pnum); plr[pnum].HoldItem = tmpItem; } #endif void SyncPlrKill(int pnum, int earflag) { int ma, i; #ifdef HELLFIRE if (plr[pnum]._pHitPoints <= 0 && currlevel == 0) { #else if (plr[pnum]._pHitPoints == 0 && currlevel == 0) { #endif SetPlayerHitPoints(pnum, 64); return; } for (i = 0; i < nummissiles; i++) { ma = missileactive[i]; if (missile[ma]._mitype == MIS_MANASHIELD && missile[ma]._misource == pnum && missile[ma]._miDelFlag == FALSE) { if (earflag != -1) { missile[ma]._miVar8 = earflag; } return; } } SetPlayerHitPoints(pnum, 0); StartPlayerKill(pnum, earflag); } void RemovePlrMissiles(int pnum) { int i, am; int mx, my; 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, monster[myplr]._mdir); mx = monster[myplr]._mx; my = monster[myplr]._my; dMonster[mx][my] = 0; monster[myplr]._mDelFlag = TRUE; DeleteMonsterList(); } for (i = 0; i < nummissiles; i++) { am = missileactive[i]; 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, i); } if (missile[am]._mitype == MIS_ETHEREALIZE && missile[am]._misource == pnum) { ClearMissileSpot(am); DeleteMissile(am, i); } } } void InitLevelChange(int pnum) { RemovePlrMissiles(pnum); if (pnum == myplr && qtextflag) { qtextflag = FALSE; stream_stop(); } RemovePlrFromMap(pnum); SetPlayerOld(pnum); if (pnum == myplr) { dPlayer[plr[myplr]._px][plr[myplr]._py] = myplr + 1; } else { plr[pnum]._pLvlVisited[plr[pnum].plrlevel] = TRUE; } ClrPlrPath(pnum); plr[pnum].destAction = ACTION_NONE; plr[pnum]._pLvlChanging = TRUE; if (pnum == myplr) { plr[pnum].pLvlLoad = 10; } } void StartNewLvl(int pnum, int fom, int lvl) { InitLevelChange(pnum); if ((DWORD)pnum >= MAX_PLRS) { app_fatal("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: app_fatal("StartNewLvl"); break; } 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); } } } void RestartTownLvl(int pnum) { InitLevelChange(pnum); if ((DWORD)pnum >= MAX_PLRS) { app_fatal("RestartTownLvl: illegal player %d", pnum); } plr[pnum].plrlevel = 0; plr[pnum]._pInvincible = FALSE; SetPlayerHitPoints(pnum, 64); plr[pnum]._pMana = 0; plr[pnum]._pManaBase = plr[pnum]._pMana - (plr[pnum]._pMaxMana - plr[pnum]._pMaxManaBase); CalcPlrInv(pnum, FALSE); if (pnum == myplr) { plr[pnum]._pmode = PM_NEWLVL; plr[pnum]._pInvincible = TRUE; PostMessage(ghMainWnd, WM_DIABRETOWN, 0, 0); } } void 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); } } BOOL PM_DoStand(int pnum) { return FALSE; } /** * @brief Movement towards NW, N, and NE */ BOOL PM_DoWalk(int pnum) { int anim_len; BOOL rv; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PM_DoWalk: illegal player %d", pnum); } #ifndef HELLFIRE 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]._px, plr[pnum]._py); } #else if (currlevel == 0 && jogging_opt) { if (plr[pnum]._pAnimFrame % 2 == 0) { plr[pnum]._pAnimFrame++; plr[pnum]._pVar8++; } if (plr[pnum]._pAnimFrame >= plr[pnum]._pWFrames) { plr[pnum]._pAnimFrame = 0; } } #endif anim_len = 8; if (currlevel != 0) { anim_len = AnimLenFromClass[plr[pnum]._pClass]; } #ifndef HELLFIRE if (plr[pnum]._pVar8 == anim_len) { #else if (plr[pnum]._pVar8 >= anim_len) { #endif dPlayer[plr[pnum]._px][plr[pnum]._py] = 0; plr[pnum]._px += plr[pnum]._pVar1; plr[pnum]._py += plr[pnum]._pVar2; dPlayer[plr[pnum]._px][plr[pnum]._py] = pnum + 1; if (leveltype != DTYPE_TOWN) { ChangeLightXY(plr[pnum]._plid, plr[pnum]._px, plr[pnum]._py); ChangeVisionXY(plr[pnum]._pvid, plr[pnum]._px, plr[pnum]._py); } if (pnum == myplr && ScrollInfo._sdir) { ViewX = plr[pnum]._px - ScrollInfo._sdx; ViewY = plr[pnum]._py - ScrollInfo._sdy; } if (plr[pnum].walkpath[0] != WALK_NONE) { StartWalkStand(pnum); } else { StartStand(pnum, plr[pnum]._pVar3); } ClearPlrPVars(pnum); if (leveltype != DTYPE_TOWN) { ChangeLightOff(plr[pnum]._plid, 0, 0); } rv = TRUE; } else { PM_ChangeOffset(pnum); rv = FALSE; } return rv; } /** * @brief Movement towards SW, S, and SE */ BOOL PM_DoWalk2(int pnum) { int anim_len; BOOL rv; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PM_DoWalk2: illegal player %d", pnum); } #ifndef HELLFIRE 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]._px, plr[pnum]._py); } #else if (currlevel == 0 && jogging_opt) { if (plr[pnum]._pAnimFrame % 2 == 0) { plr[pnum]._pAnimFrame++; plr[pnum]._pVar8++; } if (plr[pnum]._pAnimFrame >= plr[pnum]._pWFrames) { plr[pnum]._pAnimFrame = 0; } } #endif anim_len = 8; if (currlevel != 0) { anim_len = AnimLenFromClass[plr[pnum]._pClass]; } #ifndef HELLFIRE if (plr[pnum]._pVar8 == anim_len) { #else if (plr[pnum]._pVar8 >= anim_len) { #endif dPlayer[plr[pnum]._pVar1][plr[pnum]._pVar2] = 0; if (leveltype != DTYPE_TOWN) { ChangeLightXY(plr[pnum]._plid, plr[pnum]._px, plr[pnum]._py); ChangeVisionXY(plr[pnum]._pvid, plr[pnum]._px, plr[pnum]._py); } if (pnum == myplr && ScrollInfo._sdir) { ViewX = plr[pnum]._px - ScrollInfo._sdx; ViewY = plr[pnum]._py - ScrollInfo._sdy; } if (plr[pnum].walkpath[0] != WALK_NONE) { StartWalkStand(pnum); } else { StartStand(pnum, plr[pnum]._pVar3); } ClearPlrPVars(pnum); if (leveltype != DTYPE_TOWN) { ChangeLightOff(plr[pnum]._plid, 0, 0); } rv = TRUE; } else { PM_ChangeOffset(pnum); rv = FALSE; } return rv; } /** * @brief Movement towards W and E */ BOOL PM_DoWalk3(int pnum) { int anim_len; BOOL rv; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PM_DoWalk3: illegal player %d", pnum); } #ifndef HELLFIRE 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]._px, plr[pnum]._py); } #else if (currlevel == 0 && jogging_opt) { if (plr[pnum]._pAnimFrame % 2 == 0) { plr[pnum]._pAnimFrame++; plr[pnum]._pVar8++; } if (plr[pnum]._pAnimFrame >= plr[pnum]._pWFrames) { plr[pnum]._pAnimFrame = 0; } } #endif anim_len = 8; if (currlevel != 0) { anim_len = AnimLenFromClass[plr[pnum]._pClass]; } #ifndef HELLFIRE if (plr[pnum]._pVar8 == anim_len) { #else if (plr[pnum]._pVar8 >= anim_len) { #endif dPlayer[plr[pnum]._px][plr[pnum]._py] = 0; dFlags[plr[pnum]._pVar4][plr[pnum]._pVar5] &= ~BFLAG_PLAYERLR; plr[pnum]._px = plr[pnum]._pVar1; plr[pnum]._py = plr[pnum]._pVar2; dPlayer[plr[pnum]._px][plr[pnum]._py] = pnum + 1; if (leveltype != DTYPE_TOWN) { ChangeLightXY(plr[pnum]._plid, plr[pnum]._px, plr[pnum]._py); ChangeVisionXY(plr[pnum]._pvid, plr[pnum]._px, plr[pnum]._py); } if (pnum == myplr && ScrollInfo._sdir) { ViewX = plr[pnum]._px - ScrollInfo._sdx; ViewY = plr[pnum]._py - ScrollInfo._sdy; } if (plr[pnum].walkpath[0] != WALK_NONE) { StartWalkStand(pnum); } else { StartStand(pnum, plr[pnum]._pVar3); } ClearPlrPVars(pnum); if (leveltype != DTYPE_TOWN) { ChangeLightOff(plr[pnum]._plid, 0, 0); } rv = TRUE; } else { PM_ChangeOffset(pnum); rv = FALSE; } return rv; } BOOL WeaponDur(int pnum, int durrnd) { if (pnum != myplr) { return FALSE; } #ifdef HELLFIRE if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDamAcFlags & ISPLHF_DECAY) { plr[pnum].InvBody[INVLOC_HAND_LEFT]._iPLDam -= 5; if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._iPLDam <= -100) { NetSendCmdDelItem(TRUE, INVLOC_HAND_LEFT); plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype = ITYPE_NONE; CalcPlrInv(pnum, TRUE); return TRUE; } CalcPlrInv(pnum, TRUE); } if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iDamAcFlags & ISPLHF_DECAY) { plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iPLDam -= 5; if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iPLDam <= -100) { NetSendCmdDelItem(TRUE, INVLOC_HAND_LEFT); // BUGFIX: INVLOC_HAND_RIGHT plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype = ITYPE_NONE; CalcPlrInv(pnum, TRUE); return TRUE; } CalcPlrInv(pnum, TRUE); } #endif if (random_(3, durrnd) != 0) { return FALSE; } if ((DWORD)pnum >= MAX_PLRS) { app_fatal("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 == DUR_INDESTRUCTIBLE) { return FALSE; } plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability--; #ifdef HELLFIRE if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability <= 0) { #else if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability == 0) { #endif 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 == DUR_INDESTRUCTIBLE) { 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 == DUR_INDESTRUCTIBLE) { 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 == DUR_INDESTRUCTIBLE) { 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; } } return FALSE; } BOOL PlrHitMonst(int pnum, int m) { BOOL rv, ret; int hit, hper, mind, maxd, ddp, dam, skdam, phanditype, tmac; hper = 0; #ifdef HELLFIRE ret = FALSE; BOOL adjacentDamage = FALSE; #endif if ((DWORD)m >= MAXMONSTERS) { app_fatal("PlrHitMonst: illegal monster %d", m); } if ((monster[m]._mhitpoints >> 6) <= 0) { return FALSE; } if (monster[m].MType->mtype == MT_ILLWEAV && monster[m]._mgoal == MGOAL_RETREAT) { return FALSE; } if (monster[m]._mmode == MM_CHARGE) { return FALSE; } #ifdef HELLFIRE if (pnum < 0) { adjacentDamage = TRUE; pnum = -pnum; if (plr[pnum]._pLevel > 20) hper -= 30; else hper -= (35 - plr[pnum]._pLevel) * 2; } #endif if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PlrHitMonst: illegal player %d", pnum); } rv = FALSE; hit = random_(4, 100); if (monster[m]._mmode == MM_STONE) { hit = 0; } tmac = monster[m].mArmorClass; #ifdef HELLFIRE if (plr[pnum]._pIEnAc > 0) { int _pIEnAc = plr[pnum]._pIEnAc - 1; if (_pIEnAc > 0) tmac >>= _pIEnAc; else tmac -= tmac >> 2; if (plr[pnum]._pClass == PC_BARBARIAN) { tmac -= monster[m].mArmorClass / 8; } if (tmac < 0) tmac = 0; } #else tmac -= plr[pnum]._pIEnAc; #endif hper += (plr[pnum]._pDexterity >> 1) + plr[pnum]._pLevel + 50 - tmac; if (plr[pnum]._pClass == PC_WARRIOR) { hper += 20; } hper += plr[pnum]._pIBonusToHit; if (hper < 5) { hper = 5; } if (hper > 95) { hper = 95; } if (CheckMonsterHit(m, ret)) { return ret; } #ifdef _DEBUG if (hit < hper || debug_mode_key_inverted_v || debug_mode_dollar_sign) { #else if (hit < hper) { #endif #ifdef HELLFIRE if (plr[pnum]._pIFlags & ISPL_FIREDAM && plr[pnum]._pIFlags & ISPL_LIGHTDAM) { int midam = plr[pnum]._pIFMinDam + random_(3, plr[pnum]._pIFMaxDam - plr[pnum]._pIFMinDam); AddMissile(plr[pnum]._px, plr[pnum]._py, plr[pnum]._pVar1, plr[pnum]._pVar2, plr[pnum]._pdir, MIS_SPECARROW, TARGET_MONSTERS, pnum, midam, 0); } #endif mind = plr[pnum]._pIMinDam; maxd = plr[pnum]._pIMaxDam; dam = random_(5, maxd - mind + 1) + mind; dam += dam * plr[pnum]._pIBonusDam / 100; dam += plr[pnum]._pIBonusDamMod; #ifdef HELLFIRE int dam2 = dam << 6; #endif dam += plr[pnum]._pDamageMod; if (plr[pnum]._pClass == PC_WARRIOR #ifdef HELLFIRE || plr[pnum]._pClass == PC_BARBARIAN #endif ) { ddp = plr[pnum]._pLevel; if (random_(6, 100) < ddp) { dam <<= 1; } } phanditype = ITYPE_NONE; if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD || plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SWORD) { phanditype = ITYPE_SWORD; } if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_MACE || plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_MACE) { phanditype = ITYPE_MACE; } switch (monster[m].MData->mMonstClass) { case MC_UNDEAD: if (phanditype == ITYPE_SWORD) { dam -= dam >> 1; } #ifdef HELLFIRE else #endif if (phanditype == ITYPE_MACE) { dam += dam >> 1; } break; case MC_ANIMAL: if (phanditype == ITYPE_MACE) { dam -= dam >> 1; } #ifdef HELLFIRE else #endif if (phanditype == ITYPE_SWORD) { dam += dam >> 1; } break; } if (plr[pnum]._pIFlags & ISPL_3XDAMVDEM && monster[m].MData->mMonstClass == MC_DEMON) { dam *= 3; } #ifdef HELLFIRE if (plr[pnum].pDamAcFlags & ISPLHF_DEVASTATION && random_(6, 100) < 5) { dam *= 3; } if (plr[pnum].pDamAcFlags & ISPLHF_DOPPELGANGER && monster[m].MType->mtype != MT_DIABLO && monster[m]._uniqtype == 0 && random_(6, 100) < 10) { AddDoppelganger(m); } #endif dam <<= 6; #ifdef HELLFIRE if (plr[pnum].pDamAcFlags & ISPLHF_JESTERS) { int r = random_(6, 201); if (r >= 100) r = 100 + (r - 100) * 5; dam = dam * r / 100; } if (adjacentDamage) dam >>= 2; #endif if (pnum == myplr) { #ifdef HELLFIRE if (plr[pnum].pDamAcFlags & ISPLHF_PERIL) { dam2 += plr[pnum]._pIGetHit << 6; if (dam2 >= 0) { if (plr[pnum]._pHitPoints > dam2) { plr[pnum]._pHitPoints -= dam2; plr[pnum]._pHPBase -= dam2; } else { dam2 = (1 << 6); plr[pnum]._pHPBase -= plr[pnum]._pHitPoints - dam2; plr[pnum]._pHitPoints = dam2; } } dam <<= 1; } #endif monster[m]._mhitpoints -= dam; } if (plr[pnum]._pIFlags & ISPL_RNDSTEALLIFE) { skdam = random_(7, dam >> 3); plr[pnum]._pHitPoints += skdam; if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) { plr[pnum]._pHitPoints = plr[pnum]._pMaxHP; } plr[pnum]._pHPBase += skdam; if (plr[pnum]._pHPBase > plr[pnum]._pMaxHPBase) { plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase; } drawhpflag = TRUE; } if (plr[pnum]._pIFlags & (ISPL_STEALMANA_3 | ISPL_STEALMANA_5) && !(plr[pnum]._pIFlags & ISPL_NOMANA)) { if (plr[pnum]._pIFlags & ISPL_STEALMANA_3) { skdam = 3 * dam / 100; } if (plr[pnum]._pIFlags & ISPL_STEALMANA_5) { skdam = 5 * dam / 100; } plr[pnum]._pMana += skdam; if (plr[pnum]._pMana > plr[pnum]._pMaxMana) { plr[pnum]._pMana = plr[pnum]._pMaxMana; } plr[pnum]._pManaBase += skdam; if (plr[pnum]._pManaBase > plr[pnum]._pMaxManaBase) { plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase; } drawmanaflag = TRUE; } if (plr[pnum]._pIFlags & (ISPL_STEALLIFE_3 | ISPL_STEALLIFE_5)) { if (plr[pnum]._pIFlags & ISPL_STEALLIFE_3) { skdam = 3 * dam / 100; } if (plr[pnum]._pIFlags & ISPL_STEALLIFE_5) { skdam = 5 * dam / 100; } plr[pnum]._pHitPoints += skdam; if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) { plr[pnum]._pHitPoints = plr[pnum]._pMaxHP; } plr[pnum]._pHPBase += skdam; if (plr[pnum]._pHPBase > plr[pnum]._pMaxHPBase) { plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase; } drawhpflag = TRUE; } if (plr[pnum]._pIFlags & ISPL_NOHEALPLR) { monster[m]._mFlags |= MFLAG_NOHEAL; } #ifdef _DEBUG if (debug_mode_dollar_sign || debug_mode_key_inverted_v) { monster[m]._mhitpoints = 0; /* double check */ } #endif if ((monster[m]._mhitpoints >> 6) <= 0) { if (monster[m]._mmode == MM_STONE) { M_StartKill(m, pnum); monster[m]._mmode = MM_STONE; } else { M_StartKill(m, pnum); } } else { if (monster[m]._mmode == MM_STONE) { M_StartHit(m, pnum, dam); monster[m]._mmode = MM_STONE; } else { if (plr[pnum]._pIFlags & ISPL_KNOCKBACK) { M_GetKnockback(m); } M_StartHit(m, pnum, dam); } } rv = TRUE; } return rv; } BOOL PlrHitPlr(int pnum, char p) { BOOL rv; int hit, hper, blk, blkper, dir, mind, maxd, dam, lvl, skdam, tac; if ((DWORD)p >= MAX_PLRS) { app_fatal("PlrHitPlr: illegal target player %d", p); } rv = FALSE; if (plr[p]._pInvincible) { return rv; } if (plr[p]._pSpellFlags & 1) { return rv; } if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PlrHitPlr: illegal attacking player %d", pnum); } hit = random_(4, 100); hper = (plr[pnum]._pDexterity >> 1) + plr[pnum]._pLevel + 50 - (plr[p]._pIBonusAC + plr[p]._pIAC + plr[p]._pDexterity / 5); if (plr[pnum]._pClass == PC_WARRIOR) { hper += 20; } hper += plr[pnum]._pIBonusToHit; if (hper < 5) { hper = 5; } if (hper > 95) { hper = 95; } if ((plr[p]._pmode == PM_STAND || plr[p]._pmode == PM_ATTACK) && plr[p]._pBlockFlag) { blk = random_(5, 100); } else { blk = 100; } blkper = plr[p]._pDexterity + plr[p]._pBaseToBlk + (plr[p]._pLevel << 1) - (plr[pnum]._pLevel << 1); if (blkper < 0) { blkper = 0; } if (blkper > 100) { blkper = 100; } if (hit < hper) { if (blk < blkper) { dir = GetDirection(plr[p]._px, plr[p]._py, plr[pnum]._px, plr[pnum]._py); StartPlrBlock(p, dir); } else { mind = plr[pnum]._pIMinDam; maxd = plr[pnum]._pIMaxDam; dam = random_(5, maxd - mind + 1) + mind; dam += (dam * plr[pnum]._pIBonusDam) / 100; dam += plr[pnum]._pIBonusDamMod + plr[pnum]._pDamageMod; if (plr[pnum]._pClass == PC_WARRIOR #ifdef HELLFIRE || plr[pnum]._pClass == PC_BARBARIAN #endif ) { lvl = plr[pnum]._pLevel; if (random_(6, 100) < lvl) { dam <<= 1; } } skdam = dam << 6; if (plr[pnum]._pIFlags & ISPL_RNDSTEALLIFE) { tac = random_(7, skdam >> 3); plr[pnum]._pHitPoints += tac; if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) { plr[pnum]._pHitPoints = plr[pnum]._pMaxHP; } plr[pnum]._pHPBase += tac; if (plr[pnum]._pHPBase > plr[pnum]._pMaxHPBase) { plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase; } drawhpflag = TRUE; } if (pnum == myplr) { NetSendCmdDamage(TRUE, p, skdam); } StartPlrHit(p, skdam, FALSE); } rv = TRUE; } return rv; } BOOL 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; } BOOL PM_DoAttack(int pnum) { int frame, dir, dx, dy, m; BOOL didhit = FALSE; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PM_DoAttack: illegal player %d", pnum); } frame = plr[pnum]._pAnimFrame; if (plr[pnum]._pIFlags & ISPL_QUICKATTACK && frame == 1) { plr[pnum]._pAnimFrame++; } if (plr[pnum]._pIFlags & ISPL_FASTATTACK && (frame == 1 || frame == 3)) { plr[pnum]._pAnimFrame++; } if (plr[pnum]._pIFlags & ISPL_FASTERATTACK && (frame == 1 || frame == 3 || frame == 5)) { plr[pnum]._pAnimFrame++; } if (plr[pnum]._pIFlags & ISPL_FASTESTATTACK && (frame == 1 || frame == 4)) { plr[pnum]._pAnimFrame += 2; } if (plr[pnum]._pAnimFrame == plr[pnum]._pAFNum - 1) { PlaySfxLoc(PS_SWING, plr[pnum]._px, plr[pnum]._py); } if (plr[pnum]._pAnimFrame == plr[pnum]._pAFNum) { dx = plr[pnum]._px + offset_x[plr[pnum]._pdir]; dy = plr[pnum]._py + offset_y[plr[pnum]._pdir]; if (dMonster[dx][dy] != 0) { if (dMonster[dx][dy] > 0) { m = dMonster[dx][dy] - 1; } else { m = -(dMonster[dx][dy] + 1); } if (CanTalkToMonst(m)) { plr[pnum]._pVar1 = 0; return FALSE; } } #ifdef HELLFIRE if (!(plr[pnum]._pIFlags & ISPL_FIREDAM) || !(plr[pnum]._pIFlags & ISPL_LIGHTDAM)) #endif if (plr[pnum]._pIFlags & ISPL_FIREDAM) { AddMissile(dx, dy, 1, 0, 0, MIS_WEAPEXP, TARGET_MONSTERS, pnum, 0, 0); } #ifdef HELLFIRE else #endif if (plr[pnum]._pIFlags & ISPL_LIGHTDAM) { AddMissile(dx, dy, 2, 0, 0, MIS_WEAPEXP, TARGET_MONSTERS, pnum, 0, 0); } if (dMonster[dx][dy]) { m = dMonster[dx][dy]; if (dMonster[dx][dy] > 0) { m = dMonster[dx][dy] - 1; } else { m = -(dMonster[dx][dy] + 1); } didhit = PlrHitMonst(pnum, m); } else if (dPlayer[dx][dy] != 0 && !FriendlyMode) { BYTE p = dPlayer[dx][dy]; if (dPlayer[dx][dy] > 0) { p = dPlayer[dx][dy] - 1; } else { p = -(dPlayer[dx][dy] + 1); } didhit = PlrHitPlr(pnum, p); } else if (dObject[dx][dy] > 0) { didhit = PlrHitObj(pnum, dx, dy); } #ifdef HELLFIRE if ((plr[pnum]._pClass == PC_MONK && (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_STAFF || plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_STAFF)) || (plr[pnum]._pClass == PC_BARD && plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SWORD) || (plr[pnum]._pClass == PC_BARBARIAN && (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_AXE || plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_AXE || (((plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_MACE && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iLoc == ILOC_TWOHAND) || (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_MACE && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iLoc == ILOC_TWOHAND) || (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iLoc == ILOC_TWOHAND) || (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SWORD && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iLoc == ILOC_TWOHAND)) && !(plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD || plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD))))) { dx = plr[pnum]._px + offset_x[(plr[pnum]._pdir + 1) % 8]; dy = plr[pnum]._py + offset_y[(plr[pnum]._pdir + 1) % 8]; m = ((dMonster[dx][dy] > 0) ? dMonster[dx][dy] : -dMonster[dx][dy]) - 1; if (dMonster[dx][dy] != 0 && !CanTalkToMonst(m) && monster[m]._moldx == dx && monster[m]._moldy == dy) { if (PlrHitMonst(-pnum, m)) didhit = TRUE; } dx = plr[pnum]._px + offset_x[(plr[pnum]._pdir + 7) % 8]; dy = plr[pnum]._py + offset_y[(plr[pnum]._pdir + 7) % 8]; m = ((dMonster[dx][dy] > 0) ? dMonster[dx][dy] : -dMonster[dx][dy]) - 1; if (dMonster[dx][dy] != 0 && !CanTalkToMonst(m) && monster[m]._moldx == dx && monster[m]._moldy == dy) { if (PlrHitMonst(-pnum, m)) didhit = TRUE; } } #endif if (didhit && WeaponDur(pnum, 30)) { 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; } } BOOL PM_DoRangeAttack(int pnum) { int origFrame, mistype; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PM_DoRangeAttack: illegal player %d", pnum); } 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) { 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]._px, plr[pnum]._py, plr[pnum]._pVar1, plr[pnum]._pVar2, plr[pnum]._pdir, mistype, TARGET_MONSTERS, pnum, 4, 0); PlaySfxLoc(PS_BFIRE, plr[pnum]._px, plr[pnum]._py); 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 ShieldDur(int pnum) { if (pnum != myplr) { return; } if ((DWORD)pnum >= MAX_PLRS) { app_fatal("ShieldDur: illegal player %d", pnum); } if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD) { if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._iDurability == DUR_INDESTRUCTIBLE) { 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 != DUR_INDESTRUCTIBLE) { 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 PM_DoBlock(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("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) == 0) { ShieldDur(pnum); } return TRUE; } return FALSE; } static void ArmorDur(int pnum) { int a; ItemStruct *pi; PlayerStruct *p; if (pnum != myplr) { return; } if ((DWORD)pnum >= MAX_PLRS) { app_fatal("ArmorDur: illegal player %d", pnum); } p = &plr[pnum]; if (p->InvBody[INVLOC_CHEST]._itype == ITYPE_NONE && p->InvBody[INVLOC_HEAD]._itype == ITYPE_NONE) { return; } a = random_(8, 3); if (p->InvBody[INVLOC_CHEST]._itype != ITYPE_NONE && p->InvBody[INVLOC_HEAD]._itype == ITYPE_NONE) { a = 1; } if (p->InvBody[INVLOC_CHEST]._itype == ITYPE_NONE && p->InvBody[INVLOC_HEAD]._itype != ITYPE_NONE) { a = 0; } if (a != 0) { pi = &p->InvBody[INVLOC_CHEST]; } else { pi = &p->InvBody[INVLOC_HEAD]; } if (pi->_iDurability == DUR_INDESTRUCTIBLE) { return; } pi->_iDurability--; if (pi->_iDurability != 0) { return; } if (a != 0) { NetSendCmdDelItem(TRUE, INVLOC_CHEST); } else { NetSendCmdDelItem(TRUE, INVLOC_HEAD); } pi->_itype = ITYPE_NONE; CalcPlrInv(pnum, TRUE); } BOOL PM_DoSpell(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PM_DoSpell: illegal player %d", pnum); } if (plr[pnum]._pVar8 == plr[pnum]._pSFNum) { CastSpell( pnum, plr[pnum]._pSpell, plr[pnum]._px, plr[pnum]._py, plr[pnum]._pVar1, plr[pnum]._pVar2, TARGET_MONSTERS, plr[pnum]._pVar4); if (plr[pnum]._pSplFrom == 0) { if (plr[pnum]._pRSplType == RSPLTYPE_SCROLL) { if (!(plr[pnum]._pScrlSpells & SPELLBIT(plr[pnum]._pRSpell))) { plr[pnum]._pRSpell = SPL_INVALID; plr[pnum]._pRSplType = RSPLTYPE_INVALID; force_redraw = 255; } } if (plr[pnum]._pRSplType == RSPLTYPE_CHARGES) { if (!(plr[pnum]._pISpells & SPELLBIT(plr[pnum]._pRSpell))) { plr[pnum]._pRSpell = SPL_INVALID; plr[pnum]._pRSplType = RSPLTYPE_INVALID; force_redraw = 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; } BOOL PM_DoGotHit(int pnum) { int frame; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PM_DoGotHit: illegal player %d", pnum); } #ifdef HELLFIRE if (plr[pnum]._pIFlags & (ISPL_FASTRECOVER | ISPL_FASTERRECOVER | ISPL_FASTESTRECOVER)) { frame = 3; if (plr[pnum]._pIFlags & ISPL_FASTERRECOVER) frame = 4; if (plr[pnum]._pIFlags & ISPL_FASTESTRECOVER) frame = 5; if (plr[pnum]._pVar8 > 1 && plr[pnum]._pVar8 < frame) { plr[pnum]._pVar8 = frame; } if (plr[pnum]._pVar8 > plr[pnum]._pHFrames) plr[pnum]._pVar8 = plr[pnum]._pHFrames; } if (plr[pnum]._pVar8 == plr[pnum]._pHFrames) { #else frame = plr[pnum]._pAnimFrame; if (plr[pnum]._pIFlags & ISPL_FASTRECOVER && frame == 3) { plr[pnum]._pAnimFrame++; } if (plr[pnum]._pIFlags & ISPL_FASTERRECOVER && (frame == 3 || frame == 5)) { plr[pnum]._pAnimFrame++; } if (plr[pnum]._pIFlags & ISPL_FASTESTRECOVER && (frame == 1 || frame == 3 || frame == 5)) { plr[pnum]._pAnimFrame++; } if (plr[pnum]._pAnimFrame >= plr[pnum]._pHFrames) { #endif StartStand(pnum, plr[pnum]._pdir); ClearPlrPVars(pnum); if (random_(3, 4) != 0) { ArmorDur(pnum); } return TRUE; } #ifdef HELLFIRE plr[pnum]._pVar8++; #endif return FALSE; } BOOL PM_DoDeath(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("PM_DoDeath: illegal player %d", pnum); } if (plr[pnum]._pVar8 >= 2 * plr[pnum]._pDFrames) { if (deathdelay > 1 && pnum == myplr) { deathdelay--; if (deathdelay == 1) { deathflag = TRUE; if (gbMaxPlayers == 1) { gamemenu_on(); } } } plr[pnum]._pAnimDelay = 10000; plr[pnum]._pAnimFrame = plr[pnum]._pAnimLen; dFlags[plr[pnum]._px][plr[pnum]._py] |= BFLAG_DEAD_PLAYER; } if (plr[pnum]._pVar8 < 100) { plr[pnum]._pVar8++; } return FALSE; } BOOL PM_DoNewLvl(int pnum) { return FALSE; } void CheckNewPath(int pnum) { int i, x, y, d; int xvel3, xvel, yvel; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("CheckNewPath: illegal player %d", pnum); } if (plr[pnum].destAction == ACTION_ATTACKMON) { i = plr[pnum].destParam1; MakePlrPath(pnum, monster[i]._mfutx, monster[i]._mfuty, FALSE); } if (plr[pnum].destAction == ACTION_ATTACKPLR) { i = plr[pnum].destParam1; MakePlrPath(pnum, plr[i]._pfutx, plr[i]._pfuty, FALSE); } if (plr[pnum].walkpath[0] != WALK_NONE) { if (plr[pnum]._pmode == PM_STAND) { if (pnum == myplr) { if (plr[pnum].destAction == ACTION_ATTACKMON || plr[pnum].destAction == ACTION_ATTACKPLR) { i = plr[pnum].destParam1; if (plr[pnum].destAction == ACTION_ATTACKMON) { x = abs(plr[pnum]._pfutx - monster[i]._mfutx); y = abs(plr[pnum]._pfuty - monster[i]._mfuty); d = GetDirection(plr[pnum]._pfutx, plr[pnum]._pfuty, monster[i]._mfutx, monster[i]._mfuty); } else { x = abs(plr[pnum]._pfutx - plr[i]._pfutx); y = abs(plr[pnum]._pfuty - plr[i]._pfuty); d = GetDirection(plr[pnum]._pfutx, plr[pnum]._pfuty, plr[i]._pfutx, plr[i]._pfuty); } if (x < 2 && y < 2) { ClrPlrPath(pnum); // BUGFIX: missing check for `destAction == ACTION_ATTACKMON` in if-statement of `TalktoMonster` branch. if (monster[i].mtalkmsg && monster[i].mtalkmsg != TEXT_VILE14) { TalktoMonster(i); } else { StartAttack(pnum, d); } plr[pnum].destAction = ACTION_NONE; } } } if (currlevel != 0) { xvel3 = PWVel[plr[pnum]._pClass][0]; xvel = PWVel[plr[pnum]._pClass][1]; yvel = PWVel[plr[pnum]._pClass][2]; } else { xvel3 = 2048; xvel = 1024; yvel = 512; } switch (plr[pnum].walkpath[0]) { case WALK_N: StartWalk(pnum, 0, -xvel, -1, -1, DIR_N, SDIR_N); break; case WALK_NE: StartWalk(pnum, xvel, -yvel, 0, -1, DIR_NE, SDIR_NE); break; case WALK_E: StartWalk3(pnum, xvel3, 0, -32, -16, 1, -1, 1, 0, DIR_E, SDIR_E); break; case WALK_SE: StartWalk2(pnum, xvel, yvel, -32, -16, 1, 0, DIR_SE, SDIR_SE); break; case WALK_S: StartWalk2(pnum, 0, xvel, 0, -32, 1, 1, DIR_S, SDIR_S); break; case WALK_SW: StartWalk2(pnum, -xvel, yvel, 32, -16, 0, 1, DIR_SW, SDIR_SW); break; case WALK_W: StartWalk3(pnum, -xvel3, 0, 32, -16, -1, 1, 0, 1, DIR_W, SDIR_W); break; case WALK_NW: StartWalk(pnum, -xvel, -yvel, -1, 0, DIR_NW, SDIR_NW); break; } for (i = 1; i < MAX_PATH_LENGTH; i++) { plr[pnum].walkpath[i - 1] = plr[pnum].walkpath[i]; } plr[pnum].walkpath[MAX_PATH_LENGTH - 1] = WALK_NONE; if (plr[pnum]._pmode == PM_STAND) { StartStand(pnum, plr[pnum]._pdir); plr[pnum].destAction = ACTION_NONE; } } return; } if (plr[pnum].destAction == ACTION_NONE) { return; } if (plr[pnum]._pmode == PM_STAND) { switch (plr[pnum].destAction) { case ACTION_ATTACK: d = GetDirection(plr[pnum]._px, plr[pnum]._py, plr[pnum].destParam1, plr[pnum].destParam2); StartAttack(pnum, d); break; case ACTION_ATTACKMON: i = plr[pnum].destParam1; x = abs(plr[pnum]._px - monster[i]._mfutx); y = abs(plr[pnum]._py - monster[i]._mfuty); if (x <= 1 && y <= 1) { d = GetDirection(plr[pnum]._pfutx, plr[pnum]._pfuty, monster[i]._mfutx, monster[i]._mfuty); if (monster[i].mtalkmsg && monster[i].mtalkmsg != TEXT_VILE14) { TalktoMonster(i); } else { StartAttack(pnum, d); } } break; case ACTION_ATTACKPLR: i = plr[pnum].destParam1; x = abs(plr[pnum]._px - plr[i]._pfutx); y = abs(plr[pnum]._py - plr[i]._pfuty); if (x <= 1 && y <= 1) { d = GetDirection(plr[pnum]._pfutx, plr[pnum]._pfuty, plr[i]._pfutx, plr[i]._pfuty); StartAttack(pnum, d); } break; case ACTION_RATTACK: d = GetDirection(plr[pnum]._px, plr[pnum]._py, plr[pnum].destParam1, plr[pnum].destParam2); StartRangeAttack(pnum, d, plr[pnum].destParam1, plr[pnum].destParam2); break; case ACTION_RATTACKMON: i = plr[pnum].destParam1; d = GetDirection(plr[pnum]._pfutx, plr[pnum]._pfuty, monster[i]._mfutx, monster[i]._mfuty); if (monster[i].mtalkmsg && monster[i].mtalkmsg != TEXT_VILE14) { TalktoMonster(i); } else { StartRangeAttack(pnum, d, monster[i]._mfutx, monster[i]._mfuty); } break; case ACTION_RATTACKPLR: i = plr[pnum].destParam1; d = GetDirection(plr[pnum]._pfutx, plr[pnum]._pfuty, plr[i]._pfutx, plr[i]._pfuty); StartRangeAttack(pnum, d, plr[i]._pfutx, plr[i]._pfuty); break; case ACTION_SPELL: d = GetDirection(plr[pnum]._px, plr[pnum]._py, plr[pnum].destParam1, plr[pnum].destParam2); StartSpell(pnum, d, plr[pnum].destParam1, plr[pnum].destParam2); plr[pnum]._pVar4 = plr[pnum].destParam3; break; case ACTION_SPELLWALL: StartSpell(pnum, plr[pnum].destParam3, plr[pnum].destParam1, plr[pnum].destParam2); plr[pnum]._pVar3 = plr[pnum].destParam3; plr[pnum]._pVar4 = plr[pnum].destParam4; break; case ACTION_SPELLMON: i = plr[pnum].destParam1; d = GetDirection(plr[pnum]._px, plr[pnum]._py, monster[i]._mfutx, monster[i]._mfuty); StartSpell(pnum, d, monster[i]._mfutx, monster[i]._mfuty); plr[pnum]._pVar4 = plr[pnum].destParam2; break; case ACTION_SPELLPLR: i = plr[pnum].destParam1; d = GetDirection(plr[pnum]._px, plr[pnum]._py, plr[i]._pfutx, plr[i]._pfuty); StartSpell(pnum, d, plr[i]._pfutx, plr[i]._pfuty); plr[pnum]._pVar4 = plr[pnum].destParam2; break; case ACTION_OPERATE: i = plr[pnum].destParam1; x = abs(plr[pnum]._px - object[i]._ox); y = abs(plr[pnum]._py - object[i]._oy); if (y > 1 && dObject[object[i]._ox][object[i]._oy - 1] == -1 - i) { y = abs(plr[pnum]._py - object[i]._oy + 1); } if (x <= 1 && y <= 1) { if (object[i]._oBreak == 1) { d = GetDirection(plr[pnum]._px, plr[pnum]._py, object[i]._ox, object[i]._oy); StartAttack(pnum, d); } else { OperateObject(pnum, i, FALSE); } } break; case ACTION_DISARM: i = plr[pnum].destParam1; x = abs(plr[pnum]._px - object[i]._ox); y = abs(plr[pnum]._py - object[i]._oy); if (y > 1 && dObject[object[i]._ox][object[i]._oy - 1] == -1 - i) { y = abs(plr[pnum]._py - object[i]._oy + 1); } if (x <= 1 && y <= 1) { if (object[i]._oBreak == 1) { d = GetDirection(plr[pnum]._px, plr[pnum]._py, object[i]._ox, object[i]._oy); StartAttack(pnum, d); } else { TryDisarm(pnum, i); OperateObject(pnum, i, FALSE); } } break; case ACTION_OPERATETK: i = plr[pnum].destParam1; if (object[i]._oBreak != 1) { OperateObject(pnum, i, TRUE); } break; case ACTION_PICKUPITEM: if (pnum == myplr) { i = plr[pnum].destParam1; x = abs(plr[pnum]._px - item[i]._ix); y = abs(plr[pnum]._py - item[i]._iy); if (x <= 1 && y <= 1 && pcurs == CURSOR_HAND && !item[i]._iRequest) { NetSendCmdGItem(TRUE, CMD_REQUESTGITEM, myplr, myplr, i); item[i]._iRequest = TRUE; } } break; case ACTION_PICKUPAITEM: if (pnum == myplr) { i = plr[pnum].destParam1; x = abs(plr[pnum]._px - item[i]._ix); y = abs(plr[pnum]._py - item[i]._iy); if (x <= 1 && y <= 1 && pcurs == CURSOR_HAND) { NetSendCmdGItem(TRUE, CMD_REQUESTAGITEM, myplr, myplr, i); } } break; case ACTION_TALK: if (pnum == myplr) { TalkToTowner(pnum, plr[pnum].destParam1); } break; } FixPlayerLocation(pnum, plr[pnum]._pdir); plr[pnum].destAction = ACTION_NONE; return; } if (plr[pnum]._pmode == PM_ATTACK && plr[pnum]._pAnimFrame > plr[myplr]._pAFNum) { if (plr[pnum].destAction == ACTION_ATTACK) { d = GetDirection(plr[pnum]._pfutx, plr[pnum]._pfuty, plr[pnum].destParam1, plr[pnum].destParam2); StartAttack(pnum, d); plr[pnum].destAction = ACTION_NONE; } else if (plr[pnum].destAction == ACTION_ATTACKMON) { i = plr[pnum].destParam1; x = abs(plr[pnum]._px - monster[i]._mfutx); y = abs(plr[pnum]._py - monster[i]._mfuty); if (x <= 1 && y <= 1) { d = GetDirection(plr[pnum]._pfutx, plr[pnum]._pfuty, monster[i]._mfutx, monster[i]._mfuty); StartAttack(pnum, d); } plr[pnum].destAction = ACTION_NONE; } else if (plr[pnum].destAction == ACTION_ATTACKPLR) { i = plr[pnum].destParam1; x = abs(plr[pnum]._px - plr[i]._pfutx); y = abs(plr[pnum]._py - plr[i]._pfuty); if (x <= 1 && y <= 1) { d = GetDirection(plr[pnum]._pfutx, plr[pnum]._pfuty, plr[i]._pfutx, plr[i]._pfuty); StartAttack(pnum, d); } plr[pnum].destAction = ACTION_NONE; } else if (plr[pnum].destAction == ACTION_OPERATE) { i = plr[pnum].destParam1; x = abs(plr[pnum]._px - object[i]._ox); y = abs(plr[pnum]._py - object[i]._oy); if (y > 1 && dObject[object[i]._ox][object[i]._oy - 1] == -1 - i) { y = abs(plr[pnum]._py - object[i]._oy + 1); } if (x <= 1 && y <= 1) { if (object[i]._oBreak == 1) { d = GetDirection(plr[pnum]._px, plr[pnum]._py, object[i]._ox, object[i]._oy); StartAttack(pnum, d); } else { OperateObject(pnum, i, FALSE); } } } } if (plr[pnum]._pmode == PM_RATTACK && plr[pnum]._pAnimFrame > plr[myplr]._pAFNum) { if (plr[pnum].destAction == ACTION_RATTACK) { d = GetDirection(plr[pnum]._px, plr[pnum]._py, plr[pnum].destParam1, plr[pnum].destParam2); StartRangeAttack(pnum, d, plr[pnum].destParam1, plr[pnum].destParam2); plr[pnum].destAction = ACTION_NONE; } else if (plr[pnum].destAction == ACTION_RATTACKMON) { i = plr[pnum].destParam1; d = GetDirection(plr[pnum]._px, plr[pnum]._py, monster[i]._mfutx, monster[i]._mfuty); StartRangeAttack(pnum, d, monster[i]._mfutx, monster[i]._mfuty); plr[pnum].destAction = ACTION_NONE; } else if (plr[pnum].destAction == ACTION_RATTACKPLR) { i = plr[pnum].destParam1; d = GetDirection(plr[pnum]._px, plr[pnum]._py, plr[i]._pfutx, plr[i]._pfuty); StartRangeAttack(pnum, d, plr[i]._pfutx, plr[i]._pfuty); plr[pnum].destAction = ACTION_NONE; } } if (plr[pnum]._pmode == PM_SPELL && plr[pnum]._pAnimFrame > plr[pnum]._pSFNum) { if (plr[pnum].destAction == ACTION_SPELL) { d = GetDirection(plr[pnum]._px, plr[pnum]._py, plr[pnum].destParam1, plr[pnum].destParam2); StartSpell(pnum, d, plr[pnum].destParam1, plr[pnum].destParam2); plr[pnum].destAction = ACTION_NONE; } else if (plr[pnum].destAction == ACTION_SPELLMON) { i = plr[pnum].destParam1; d = GetDirection(plr[pnum]._px, plr[pnum]._py, monster[i]._mfutx, monster[i]._mfuty); StartSpell(pnum, d, monster[i]._mfutx, monster[i]._mfuty); plr[pnum].destAction = ACTION_NONE; } else if (plr[pnum].destAction == ACTION_SPELLPLR) { i = plr[pnum].destParam1; d = GetDirection(plr[pnum]._px, plr[pnum]._py, plr[i]._pfutx, plr[i]._pfuty); StartSpell(pnum, d, plr[i]._pfutx, plr[i]._pfuty); plr[pnum].destAction = ACTION_NONE; } } } BOOL PlrDeathModeOK(int p) { if (p != myplr) { return TRUE; } if ((DWORD)p >= MAX_PLRS) { app_fatal("PlrDeathModeOK: illegal player %d", p); } if (plr[p]._pmode == PM_DEATH) { return TRUE; } else if (plr[p]._pmode == PM_QUIT) { return TRUE; } else if (plr[p]._pmode == PM_NEWLVL) { return TRUE; } return FALSE; } void ValidatePlayer() { __int64 msk; int gt, pc, i, b; msk = 0; if ((DWORD)myplr >= MAX_PLRS) { app_fatal("ValidatePlayer: illegal player %d", myplr); } if (plr[myplr]._pLevel > MAXCHARLEVEL - 1) plr[myplr]._pLevel = MAXCHARLEVEL - 1; if (plr[myplr]._pExperience > plr[myplr]._pNextExper) plr[myplr]._pExperience = plr[myplr]._pNextExper; gt = 0; for (i = 0; i < plr[myplr]._pNumInv; i++) { if (plr[myplr].InvList[i]._itype == ITYPE_GOLD) { #ifdef HELLFIRE if (plr[myplr].InvList[i]._ivalue > auricGold) { plr[myplr].InvList[i]._ivalue = auricGold; #else if (plr[myplr].InvList[i]._ivalue > GOLD_MAX_LIMIT) { plr[myplr].InvList[i]._ivalue = GOLD_MAX_LIMIT; #endif } gt += plr[myplr].InvList[i]._ivalue; } } if (gt != plr[myplr]._pGold) plr[myplr]._pGold = gt; pc = plr[myplr]._pClass; if (plr[myplr]._pBaseStr > MaxStats[pc][ATTRIB_STR]) { plr[myplr]._pBaseStr = MaxStats[pc][ATTRIB_STR]; } if (plr[myplr]._pBaseMag > MaxStats[pc][ATTRIB_MAG]) { plr[myplr]._pBaseMag = MaxStats[pc][ATTRIB_MAG]; } if (plr[myplr]._pBaseDex > MaxStats[pc][ATTRIB_DEX]) { plr[myplr]._pBaseDex = MaxStats[pc][ATTRIB_DEX]; } if (plr[myplr]._pBaseVit > MaxStats[pc][ATTRIB_VIT]) { plr[myplr]._pBaseVit = MaxStats[pc][ATTRIB_VIT]; } for (b = 1; b < MAX_SPELLS; b++) { if (spelldata[b].sBookLvl != -1) { msk |= SPELLBIT(b); if (plr[myplr]._pSplLvl[b] > MAX_SPELL_LEVEL) plr[myplr]._pSplLvl[b] = MAX_SPELL_LEVEL; } } plr[myplr]._pMemSpells &= msk; } static void 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 ProcessPlayers() { int pnum; BOOL tplayer; if ((DWORD)myplr >= MAX_PLRS) { app_fatal("ProcessPlayers: illegal player %d", myplr); } if (plr[myplr].pLvlLoad > 0) { plr[myplr].pLvlLoad--; } if (sfxdelay > 0) { sfxdelay--; if (sfxdelay == 0) { #ifdef HELLFIRE switch (sfxdnum) { case USFX_DEFILER1: InitQTextMsg(286); break; case USFX_DEFILER2: InitQTextMsg(287); break; case USFX_DEFILER3: InitQTextMsg(288); break; case USFX_DEFILER4: InitQTextMsg(289); break; default: #endif PlaySFX(sfxdnum); #ifdef HELLFIRE } #endif } } ValidatePlayer(); for (pnum = 0; pnum < MAX_PLRS; pnum++) { if (plr[pnum].plractive && currlevel == plr[pnum].plrlevel && (pnum == myplr || !plr[pnum]._pLvlChanging)) { CheckCheatStats(pnum); if (!PlrDeathModeOK(pnum) && (plr[pnum]._pHitPoints >> 6) <= 0) { SyncPlrKill(pnum, -1); } if (pnum == myplr) { if ((plr[pnum]._pIFlags & ISPL_DRAINLIFE) && currlevel != 0) { plr[pnum]._pHitPoints -= 4; plr[pnum]._pHPBase -= 4; if ((plr[pnum]._pHitPoints >> 6) <= 0) { SyncPlrKill(pnum, 0); } drawhpflag = TRUE; } if (plr[pnum]._pIFlags & ISPL_NOMANA && plr[pnum]._pManaBase > 0) { plr[pnum]._pManaBase -= plr[pnum]._pMana; plr[pnum]._pMana = 0; drawmanaflag = TRUE; } } tplayer = FALSE; do { switch (plr[pnum]._pmode) { case PM_STAND: tplayer = PM_DoStand(pnum); break; case PM_WALK: tplayer = PM_DoWalk(pnum); break; case PM_WALK2: tplayer = PM_DoWalk2(pnum); break; case PM_WALK3: tplayer = PM_DoWalk3(pnum); break; case PM_ATTACK: tplayer = PM_DoAttack(pnum); break; case PM_RATTACK: tplayer = PM_DoRangeAttack(pnum); break; case PM_BLOCK: tplayer = PM_DoBlock(pnum); break; case PM_SPELL: tplayer = PM_DoSpell(pnum); break; case PM_GOTHIT: tplayer = PM_DoGotHit(pnum); break; case PM_DEATH: tplayer = PM_DoDeath(pnum); break; case PM_NEWLVL: tplayer = PM_DoNewLvl(pnum); break; } CheckNewPath(pnum); } while (tplayer); plr[pnum]._pAnimCnt++; if (plr[pnum]._pAnimCnt > plr[pnum]._pAnimDelay) { plr[pnum]._pAnimCnt = 0; plr[pnum]._pAnimFrame++; if (plr[pnum]._pAnimFrame > plr[pnum]._pAnimLen) { plr[pnum]._pAnimFrame = 1; } } } } } void ClrPlrPath(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("ClrPlrPath: illegal player %d", pnum); } memset(plr[pnum].walkpath, WALK_NONE, sizeof(plr[pnum].walkpath)); } BOOL PosOkPlayer(int pnum, int x, int y) { BOOL PosOK; DWORD p; char bv; #ifndef HELLFIRE PosOK = FALSE; if (x >= 0 && x < MAXDUNX && y >= 0 && y < MAXDUNY && !SolidLoc(x, y) && dPiece[x][y] != 0) { #else if (dPiece[x][y] == 0) return FALSE; if (SolidLoc(x, y)) return FALSE; #endif if (dPlayer[x][y] != 0) { if (dPlayer[x][y] > 0) { p = dPlayer[x][y] - 1; } else { p = -(dPlayer[x][y] + 1); } if (p != pnum #ifndef HELLFIRE && p < MAX_PLRS #endif && plr[p]._pHitPoints != 0) { return FALSE; } } if (dMonster[x][y] != 0) { if (currlevel == 0) { return FALSE; } if (dMonster[x][y] <= 0) { return FALSE; } if ((monster[dMonster[x][y] - 1]._mhitpoints >> 6) > 0) { return FALSE; } } if (dObject[x][y] != 0) { if (dObject[x][y] > 0) { bv = dObject[x][y] - 1; } else { bv = -(dObject[x][y] + 1); } if (object[bv]._oSolidFlag) { return FALSE; } } #ifndef HELLFIRE PosOK = TRUE; } if (!PosOK) return FALSE; #endif return TRUE; } void MakePlrPath(int pnum, int xx, int yy, BOOL endspace) { int path; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("MakePlrPath: illegal player %d", pnum); } plr[pnum]._ptargx = xx; plr[pnum]._ptargy = yy; if (plr[pnum]._pfutx == xx && plr[pnum]._pfuty == yy) { return; } path = FindPath(PosOkPlayer, pnum, plr[pnum]._pfutx, plr[pnum]._pfuty, xx, yy, plr[pnum].walkpath); if (!path) { return; } if (!endspace) { path--; switch (plr[pnum].walkpath[path]) { case WALK_NE: yy++; break; case WALK_NW: xx++; break; case WALK_SE: xx--; break; case WALK_SW: yy--; break; case WALK_N: xx++; yy++; break; case WALK_E: xx--; yy++; break; case WALK_S: xx--; yy--; break; case WALK_W: xx++; yy--; break; } plr[pnum]._ptargx = xx; plr[pnum]._ptargy = yy; } plr[pnum].walkpath[path] = WALK_NONE; } void CheckPlrSpell() { BOOL addflag = FALSE; int rspell, sd, sl; if ((DWORD)myplr >= MAX_PLRS) { app_fatal("CheckPlrSpell: illegal player %d", myplr); } rspell = plr[myplr]._pRSpell; if (rspell == SPL_INVALID) { if (plr[myplr]._pClass == PC_WARRIOR) { PlaySFX(PS_WARR34); #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { PlaySFX(PS_ROGUE34); } else if (plr[myplr]._pClass == PC_SORCERER) { PlaySFX(PS_MAGE34); #endif #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { PlaySFX(PS_MONK34); } else if (plr[myplr]._pClass == PC_BARD) { PlaySFX(PS_ROGUE34); } else if (plr[myplr]._pClass == PC_BARBARIAN) { PlaySFX(PS_WARR34); #endif } return; } if (leveltype == DTYPE_TOWN && !spelldata[rspell].sTownSpell) { if (plr[myplr]._pClass == PC_WARRIOR) { PlaySFX(PS_WARR27); #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { PlaySFX(PS_ROGUE27); } else if (plr[myplr]._pClass == PC_SORCERER) { PlaySFX(PS_MAGE27); #endif #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { PlaySFX(PS_MONK27); } else if (plr[myplr]._pClass == PC_BARD) { PlaySFX(PS_ROGUE27); } else if (plr[myplr]._pClass == PC_BARBARIAN) { PlaySFX(PS_WARR27); #endif } return; } if (pcurs != CURSOR_HAND) return; if (((MouseY >= PANEL_TOP) || (chrflag && MouseX < SPANEL_WIDTH) || (invflag && MouseX > RIGHT_PANEL)) && ((MouseY >= PANEL_TOP) || (rspell != SPL_HEAL && rspell != SPL_IDENTIFY && rspell != SPL_REPAIR && rspell != SPL_INFRA && rspell != SPL_RECHARGE))) { return; } switch (plr[myplr]._pRSplType) { case RSPLTYPE_SKILL: case RSPLTYPE_SPELL: addflag = CheckSpell(myplr, rspell, plr[myplr]._pRSplType, FALSE); break; case RSPLTYPE_SCROLL: addflag = UseScroll(); break; case RSPLTYPE_CHARGES: addflag = UseStaff(); break; } if (addflag) { if (plr[myplr]._pRSpell == SPL_FIREWALL #ifdef HELLFIRE || plr[myplr]._pRSpell == SPL_LIGHTWALL #endif ) { sd = GetDirection(plr[myplr]._px, plr[myplr]._py, cursmx, cursmy); sl = GetSpellLevel(myplr, plr[myplr]._pRSpell); NetSendCmdLocParam3(TRUE, CMD_SPELLXYD, cursmx, cursmy, plr[myplr]._pRSpell, sd, sl); } else if (pcursmonst != -1) { sl = GetSpellLevel(myplr, plr[myplr]._pRSpell); NetSendCmdParam3(TRUE, CMD_SPELLID, pcursmonst, plr[myplr]._pRSpell, sl); } else if (pcursplr != -1) { sl = GetSpellLevel(myplr, plr[myplr]._pRSpell); NetSendCmdParam3(TRUE, CMD_SPELLPID, pcursplr, plr[myplr]._pRSpell, sl); } else { //145 sl = GetSpellLevel(myplr, plr[myplr]._pRSpell); NetSendCmdLocParam2(TRUE, CMD_SPELLXY, cursmx, cursmy, plr[myplr]._pRSpell, sl); } return; } if (plr[myplr]._pRSplType == RSPLTYPE_SPELL) { if (plr[myplr]._pClass == PC_WARRIOR) { PlaySFX(PS_WARR35); #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { PlaySFX(PS_ROGUE35); } else if (plr[myplr]._pClass == PC_SORCERER) { PlaySFX(PS_MAGE35); #endif #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { PlaySFX(PS_MONK35); } else if (plr[myplr]._pClass == PC_BARD) { PlaySFX(PS_ROGUE35); } else if (plr[myplr]._pClass == PC_BARBARIAN) { PlaySFX(PS_WARR35); #endif } } } void SyncPlrAnim(int pnum) { int dir, sType; if ((DWORD)pnum >= MAX_PLRS) { app_fatal("SyncPlrAnim: illegal player %d", pnum); } dir = plr[pnum]._pdir; switch (plr[pnum]._pmode) { case PM_STAND: plr[pnum]._pAnimData = plr[pnum]._pNAnim[dir]; break; case PM_WALK: case PM_WALK2: case PM_WALK3: plr[pnum]._pAnimData = plr[pnum]._pWAnim[dir]; break; case PM_ATTACK: plr[pnum]._pAnimData = plr[pnum]._pAAnim[dir]; break; case PM_RATTACK: plr[pnum]._pAnimData = plr[pnum]._pAAnim[dir]; break; case PM_BLOCK: plr[pnum]._pAnimData = plr[pnum]._pBAnim[dir]; break; case PM_SPELL: if (pnum == myplr) sType = spelldata[plr[pnum]._pSpell].sType; else sType = STYPE_FIRE; if (sType == STYPE_FIRE) plr[pnum]._pAnimData = plr[pnum]._pFAnim[dir]; if (sType == STYPE_LIGHTNING) plr[pnum]._pAnimData = plr[pnum]._pLAnim[dir]; if (sType == STYPE_MAGIC) plr[pnum]._pAnimData = plr[pnum]._pTAnim[dir]; break; case PM_GOTHIT: plr[pnum]._pAnimData = plr[pnum]._pHAnim[dir]; break; case PM_NEWLVL: plr[pnum]._pAnimData = plr[pnum]._pNAnim[dir]; break; case PM_DEATH: plr[pnum]._pAnimData = plr[pnum]._pDAnim[dir]; break; case PM_QUIT: plr[pnum]._pAnimData = plr[pnum]._pNAnim[dir]; break; default: app_fatal("SyncPlrAnim"); break; } } void SyncInitPlrPos(int pnum) { int x, y, xx, yy, range; DWORD i; BOOL posOk; plr[pnum]._ptargx = plr[pnum]._px; plr[pnum]._ptargy = plr[pnum]._py; if (gbMaxPlayers == 1 || plr[pnum].plrlevel != currlevel) { return; } for (i = 0; i < 8; i++) { x = plr[pnum]._px + plrxoff2[i]; y = plr[pnum]._py + plryoff2[i]; if (PosOkPlayer(pnum, x, y)) { break; } } #ifdef HELLFIRE plr[pnum]._px += plrxoff2[i]; plr[pnum]._py += plryoff2[i]; dPlayer[plr[pnum]._px][plr[pnum]._py] = pnum + 1; #else if (!PosOkPlayer(pnum, x, y)) { posOk = FALSE; for (range = 1; range < 50 && !posOk; range++) { for (yy = -range; yy <= range && !posOk; yy++) { y = yy + plr[pnum]._py; for (xx = -range; xx <= range && !posOk; xx++) { x = xx + plr[pnum]._px; if (PosOkPlayer(pnum, x, y) && !PosOkPortal(currlevel, x, y)) { posOk = TRUE; } } } } } plr[pnum]._px = x; plr[pnum]._py = y; dPlayer[x][y] = pnum + 1; if (pnum == myplr) { plr[pnum]._pfutx = x; plr[pnum]._pfuty = y; plr[pnum]._ptargx = x; plr[pnum]._ptargy = y; ViewX = x; ViewY = y; } #endif } void SyncInitPlr(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("SyncInitPlr: illegal player %d", pnum); } SetPlrAnims(pnum); SyncInitPlrPos(pnum); } void CheckStats(int p) { int c, i; if ((DWORD)p >= MAX_PLRS) { app_fatal("CheckStats: illegal player %d", p); } if (plr[p]._pClass == PC_WARRIOR) { c = PC_WARRIOR; } else if (plr[p]._pClass == PC_ROGUE) { c = PC_ROGUE; } else if (plr[p]._pClass == PC_SORCERER) { c = PC_SORCERER; } #ifdef HELLFIRE else if (plr[p]._pClass == PC_MONK) { c = PC_MONK; } else if (plr[p]._pClass == PC_BARD) { c = PC_BARD; } else if (plr[p]._pClass == PC_BARBARIAN) { c = PC_BARBARIAN; } #endif for (i = 0; i < 4; i++) { switch (i) { case ATTRIB_STR: if (plr[p]._pBaseStr > MaxStats[c][ATTRIB_STR]) { plr[p]._pBaseStr = MaxStats[c][ATTRIB_STR]; } else if (plr[p]._pBaseStr < 0) { plr[p]._pBaseStr = 0; } break; case ATTRIB_MAG: if (plr[p]._pBaseMag > MaxStats[c][ATTRIB_MAG]) { plr[p]._pBaseMag = MaxStats[c][ATTRIB_MAG]; } else if (plr[p]._pBaseMag < 0) { plr[p]._pBaseMag = 0; } break; case ATTRIB_DEX: if (plr[p]._pBaseDex > MaxStats[c][ATTRIB_DEX]) { plr[p]._pBaseDex = MaxStats[c][ATTRIB_DEX]; } else if (plr[p]._pBaseDex < 0) { plr[p]._pBaseDex = 0; } break; case ATTRIB_VIT: if (plr[p]._pBaseVit > MaxStats[c][ATTRIB_VIT]) { plr[p]._pBaseVit = MaxStats[c][ATTRIB_VIT]; } else if (plr[p]._pBaseVit < 0) { plr[p]._pBaseVit = 0; } break; } } } void ModifyPlrStr(int p, int l) { int max; if ((DWORD)p >= MAX_PLRS) { app_fatal("ModifyPlrStr: illegal player %d", p); } max = MaxStats[plr[p]._pClass][ATTRIB_STR]; if (plr[p]._pBaseStr + l > max) { l = max - plr[p]._pBaseStr; } plr[p]._pStrength += l; plr[p]._pBaseStr += l; #ifndef HELLFIRE 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; } #endif CalcPlrInv(p, TRUE); if (p == myplr) { NetSendCmdParam1(FALSE, CMD_SETSTR, plr[p]._pBaseStr); } } void ModifyPlrMag(int p, int l) { int max, ms; if ((DWORD)p >= MAX_PLRS) { app_fatal("ModifyPlrMag: illegal player %d", p); } max = MaxStats[plr[p]._pClass][ATTRIB_MAG]; if (plr[p]._pBaseMag + l > max) { l = max - plr[p]._pBaseMag; } plr[p]._pMagic += l; plr[p]._pBaseMag += l; ms = l << 6; if (plr[p]._pClass == PC_SORCERER) { ms <<= 1; } #ifdef HELLFIRE else if (plr[p]._pClass == PC_BARD) { ms += ms >> 1; } #endif plr[p]._pMaxManaBase += ms; plr[p]._pMaxMana += ms; if (!(plr[p]._pIFlags & ISPL_NOMANA)) { plr[p]._pManaBase += ms; plr[p]._pMana += ms; } CalcPlrInv(p, TRUE); if (p == myplr) { NetSendCmdParam1(FALSE, CMD_SETMAG, plr[p]._pBaseMag); } } void ModifyPlrDex(int p, int l) { int max; if ((DWORD)p >= MAX_PLRS) { app_fatal("ModifyPlrDex: illegal player %d", p); } max = MaxStats[plr[p]._pClass][ATTRIB_DEX]; if (plr[p]._pBaseDex + l > max) { l = max - plr[p]._pBaseDex; } plr[p]._pDexterity += l; plr[p]._pBaseDex += l; CalcPlrInv(p, TRUE); #ifndef HELLFIRE if (plr[p]._pClass == PC_ROGUE) { plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pDexterity + plr[p]._pStrength) / 200; } #endif if (p == myplr) { NetSendCmdParam1(FALSE, CMD_SETDEX, plr[p]._pBaseDex); } } void ModifyPlrVit(int p, int l) { int max, ms; if ((DWORD)p >= MAX_PLRS) { app_fatal("ModifyPlrVit: illegal player %d", p); } max = MaxStats[plr[p]._pClass][ATTRIB_VIT]; if (plr[p]._pBaseVit + l > max) { l = max - plr[p]._pBaseVit; } plr[p]._pVitality += l; plr[p]._pBaseVit += l; ms = l << 6; if (plr[p]._pClass == PC_WARRIOR) { ms <<= 1; #ifdef HELLFIRE } else if (plr[p]._pClass == PC_BARBARIAN) { ms <<= 1; #endif } plr[p]._pHPBase += ms; plr[p]._pMaxHPBase += ms; plr[p]._pHitPoints += ms; plr[p]._pMaxHP += ms; CalcPlrInv(p, TRUE); if (p == myplr) { NetSendCmdParam1(FALSE, CMD_SETVIT, plr[p]._pBaseVit); } } void SetPlayerHitPoints(int pnum, int val) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("SetPlayerHitPoints: illegal player %d", pnum); } plr[pnum]._pHitPoints = val; plr[pnum]._pHPBase = val + plr[pnum]._pMaxHPBase - plr[pnum]._pMaxHP; if (pnum == myplr) { drawhpflag = TRUE; } } void SetPlrStr(int p, int v) { int dm; if ((DWORD)p >= MAX_PLRS) { app_fatal("SetPlrStr: illegal player %d", p); } plr[p]._pBaseStr = v; CalcPlrInv(p, TRUE); #ifndef HELLFIRE if (plr[p]._pClass == PC_ROGUE) { dm = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 200; } else { dm = plr[p]._pLevel * plr[p]._pStrength / 100; } plr[p]._pDamageMod = dm; #endif } void SetPlrMag(int p, int v) { int m; if ((DWORD)p >= MAX_PLRS) { app_fatal("SetPlrMag: illegal player %d", p); } plr[p]._pBaseMag = v; m = v << 6; if (plr[p]._pClass == PC_SORCERER) { m <<= 1; #ifdef HELLFIRE } else if (plr[p]._pClass == PC_BARD) { m += m >> 1; #endif } plr[p]._pMaxManaBase = m; plr[p]._pMaxMana = m; CalcPlrInv(p, TRUE); } void SetPlrDex(int p, int v) { int dm; if ((DWORD)p >= MAX_PLRS) { app_fatal("SetPlrDex: illegal player %d", p); } plr[p]._pBaseDex = v; CalcPlrInv(p, TRUE); #ifndef HELLFIRE if (plr[p]._pClass == PC_ROGUE) { dm = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 200; } else { dm = plr[p]._pStrength * plr[p]._pLevel / 100; } plr[p]._pDamageMod = dm; #endif } void SetPlrVit(int p, int v) { int hp; if ((DWORD)p >= MAX_PLRS) { app_fatal("SetPlrVit: illegal player %d", p); } plr[p]._pBaseVit = v; hp = v << 6; if (plr[p]._pClass == PC_WARRIOR) { hp <<= 1; } #ifdef HELLFIRE else if (plr[p]._pClass == PC_BARBARIAN) { hp <<= 1; } #endif plr[p]._pHPBase = hp; plr[p]._pMaxHPBase = hp; CalcPlrInv(p, TRUE); } void InitDungMsgs(int pnum) { if ((DWORD)pnum >= MAX_PLRS) { app_fatal("InitDungMsgs: illegal player %d", pnum); } plr[pnum].pDungMsgs = 0; #ifdef HELLFIRE plr[pnum].pDungMsgs2 = 0; #endif } void PlayDungMsgs() { if ((DWORD)myplr >= MAX_PLRS) { app_fatal("PlayDungMsgs: illegal player %d", myplr); } if (currlevel == 1 && !plr[myplr]._pLvlVisited[1] && gbMaxPlayers == 1 && !(plr[myplr].pDungMsgs & DMSG_CATHEDRAL)) { sfxdelay = 40; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR97; #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE97; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE97; #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK97; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE97; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR97; #endif #endif } plr[myplr].pDungMsgs = plr[myplr].pDungMsgs | DMSG_CATHEDRAL; } else if (currlevel == 5 && !plr[myplr]._pLvlVisited[5] && gbMaxPlayers == 1 && !(plr[myplr].pDungMsgs & DMSG_CATACOMBS)) { sfxdelay = 40; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR96B; #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE96; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE96; #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK96; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE96; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR96B; #endif #endif } plr[myplr].pDungMsgs |= DMSG_CATACOMBS; } else if (currlevel == 9 && !plr[myplr]._pLvlVisited[9] && gbMaxPlayers == 1 && !(plr[myplr].pDungMsgs & DMSG_CAVES)) { sfxdelay = 40; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR98; #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE98; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE98; #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK98; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE98; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR98; #endif #endif } plr[myplr].pDungMsgs |= DMSG_CAVES; } else if (currlevel == 13 && !plr[myplr]._pLvlVisited[13] && gbMaxPlayers == 1 && !(plr[myplr].pDungMsgs & DMSG_HELL)) { sfxdelay = 40; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR99; #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE99; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE99; #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK99; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE99; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR99; #endif #endif } plr[myplr].pDungMsgs |= DMSG_HELL; } else if (currlevel == 16 && !plr[myplr]._pLvlVisited[15] && gbMaxPlayers == 1 && !(plr[myplr].pDungMsgs & DMSG_DIABLO)) { // BUGFIX: _pLvlVisited should check 16 or this message will never play sfxdelay = 40; #ifndef SPAWN #ifdef HELLFIRE if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_ROGUE || plr[myplr]._pClass == PC_SORCERER || plr[myplr]._pClass == PC_MONK || plr[myplr]._pClass == PC_BARD || plr[myplr]._pClass == PC_BARBARIAN) { #else if (plr[myplr]._pClass == PC_WARRIOR || plr[myplr]._pClass == PC_ROGUE || plr[myplr]._pClass == PC_SORCERER) { #endif sfxdnum = PS_DIABLVLINT; } #endif plr[myplr].pDungMsgs |= DMSG_DIABLO; #ifdef HELLFIRE } else if (currlevel == 17 && !plr[myplr]._pLvlVisited[17] && gbMaxPlayers == 1 && !(plr[myplr].pDungMsgs2 & 1)) { sfxdelay = 10; sfxdnum = USFX_DEFILER1; quests[Q_DEFILER]._qactive = QUEST_ACTIVE; quests[Q_DEFILER]._qlog = TRUE; quests[Q_DEFILER]._qmsg = 286; plr[myplr].pDungMsgs2 |= 1; } else if (currlevel == 19 && !plr[myplr]._pLvlVisited[19] && gbMaxPlayers == 1 && !(plr[myplr].pDungMsgs2 & 4)) { sfxdelay = 10; sfxdnum = USFX_DEFILER3; plr[myplr].pDungMsgs2 |= 4; } else if (currlevel == 21 && !plr[myplr]._pLvlVisited[21] && gbMaxPlayers == 1 && !(plr[myplr].pDungMsgs & 32)) { sfxdelay = 30; #ifndef SPAWN if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR92; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE92; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE92; } else #endif if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK92; } #ifndef SPAWN else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE92; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR92; } #endif plr[myplr].pDungMsgs |= 32; #endif } else { sfxdelay = 0; } } #ifdef HELLFIRE int get_max_strength(int i) { return MaxStats[i][ATTRIB_STR]; } int get_max_magic(int i) { return MaxStats[i][ATTRIB_MAG]; } int get_max_dexterity(int i) { return MaxStats[i][ATTRIB_DEX]; } #endif ================================================ FILE: Source/player.h ================================================ /** * @file player.h * * Interface of player functionality, leveling, actions, creation, loading, etc. */ #ifndef __PLAYER_H__ #define __PLAYER_H__ extern int myplr; #ifdef HELLFIRE extern PlayerStruct *plr; #else extern PlayerStruct plr[MAX_PLRS]; #endif extern BOOL deathflag; void LoadPlrGFX(int pnum, player_graphic gfxflag); void InitPlayerGFX(int pnum); void InitPlrGFXMem(int pnum); void FreePlayerGFX(int pnum); void NewPlrAnim(int pnum, BYTE *Peq, int numFrames, int Delay, int width); void SetPlrAnims(int pnum); void ClearPlrRVars(PlayerStruct *p); void CreatePlayer(int pnum, char c); int CalcStatDiff(int pnum); void NextPlrLevel(int pnum); void AddPlrExperience(int pnum, int lvl, int exp); void AddPlrMonstExper(int lvl, int exp, char pmask); void InitPlayer(int pnum, BOOL FirstTime); void InitMultiView(); void CheckEFlag(int pnum, BOOL flag); BOOL SolidLoc(int x, int y); void PlrClrTrans(int x, int y); void PlrDoTrans(int x, int y); void SetPlayerOld(int pnum); void FixPlayerLocation(int pnum, int bDir); void StartStand(int pnum, int dir); void StartAttack(int pnum, int d); void StartPlrBlock(int pnum, int dir); void FixPlrWalkTags(int pnum); void RemovePlrFromMap(int pnum); void StartPlrHit(int pnum, int dam, BOOL forcehit); void StartPlayerKill(int pnum, int earflag); void DropHalfPlayersGold(int pnum); #ifdef HELLFIRE void StripTopGold(int pnum); #endif void SyncPlrKill(int pnum, int earflag); void RemovePlrMissiles(int pnum); void StartNewLvl(int pnum, int fom, int lvl); void RestartTownLvl(int pnum); void StartWarpLvl(int pnum, int pidx); void ProcessPlayers(); void ClrPlrPath(int pnum); BOOL PosOkPlayer(int pnum, int x, int y); void MakePlrPath(int pnum, int xx, int yy, BOOL endspace); void CheckPlrSpell(); void SyncPlrAnim(int pnum); void SyncInitPlrPos(int pnum); void SyncInitPlr(int pnum); void CheckStats(int p); void ModifyPlrStr(int p, int l); void ModifyPlrMag(int p, int l); void ModifyPlrDex(int p, int l); void ModifyPlrVit(int p, int l); void SetPlayerHitPoints(int pnum, int val); void SetPlrStr(int p, int v); void SetPlrMag(int p, int v); void SetPlrDex(int p, int v); void SetPlrVit(int p, int v); void InitDungMsgs(int pnum); void PlayDungMsgs(); #ifdef HELLFIRE int get_max_strength(int i); int get_max_magic(int i); int get_max_dexterity(int i); #endif /* data */ extern int plrxoff[9]; extern int plryoff[9]; extern int plrxoff2[9]; extern int plryoff2[9]; extern int StrengthTbl[NUM_CLASSES]; extern int MagicTbl[NUM_CLASSES]; extern int DexterityTbl[NUM_CLASSES]; extern int VitalityTbl[NUM_CLASSES]; extern int MaxStats[NUM_CLASSES][4]; extern const char *const ClassStrTbl[NUM_CLASSES]; #endif /* __PLAYER_H__ */ ================================================ FILE: Source/plrmsg.cpp ================================================ /** * @file plrmsg.cpp * * Implementation of functionality for printing the ingame chat messages. */ #include "all.h" static BYTE plr_msg_slot; _plrmsg plr_msgs[PMSG_COUNT]; /** Maps from player_num to text colour, as used in chat messages. */ const char text_color_from_player_num[MAX_PLRS + 1] = { COL_WHITE, COL_WHITE, COL_WHITE, COL_WHITE, COL_GOLD }; void plrmsg_delay(BOOL delay) { int i; _plrmsg *pMsg; static DWORD plrmsg_ticks; if (delay) { plrmsg_ticks = -GetTickCount(); return; } plrmsg_ticks += GetTickCount(); pMsg = plr_msgs; for (i = 0; i < PMSG_COUNT; i++, pMsg++) pMsg->time += plrmsg_ticks; } char *ErrorPlrMsg(const char *pszMsg) { char *result; _plrmsg *pMsg = &plr_msgs[plr_msg_slot]; plr_msg_slot = (plr_msg_slot + 1) & (PMSG_COUNT - 1); pMsg->player = MAX_PLRS; pMsg->time = GetTickCount(); result = strncpy(pMsg->str, pszMsg, sizeof(pMsg->str)); pMsg->str[sizeof(pMsg->str) - 1] = '\0'; return result; } size_t __cdecl EventPlrMsg(const char *pszFmt, ...) { _plrmsg *pMsg; va_list va; va_start(va, pszFmt); pMsg = &plr_msgs[plr_msg_slot]; plr_msg_slot = (plr_msg_slot + 1) & (PMSG_COUNT - 1); pMsg->player = MAX_PLRS; pMsg->time = GetTickCount(); vsprintf(pMsg->str, pszFmt, va); va_end(va); return strlen(pMsg->str); } void SendPlrMsg(int pnum, const char *pszStr) { _plrmsg *pMsg = &plr_msgs[plr_msg_slot]; plr_msg_slot = (plr_msg_slot + 1) & (PMSG_COUNT - 1); pMsg->player = pnum; pMsg->time = GetTickCount(); strlen(plr[pnum]._pName); /* these are used in debug */ strlen(pszStr); sprintf(pMsg->str, "%s (lvl %d): %s", plr[pnum]._pName, plr[pnum]._pLevel, pszStr); } void ClearPlrMsg() { int i; _plrmsg *pMsg = plr_msgs; DWORD tick = GetTickCount(); for (i = 0; i < PMSG_COUNT; i++, pMsg++) { if ((int)(tick - pMsg->time) > 10000) pMsg->str[0] = '\0'; } } void InitPlrMsg() { memset(plr_msgs, 0, sizeof(plr_msgs)); plr_msg_slot = 0; } void DrawPlrMsg() { int i; DWORD x = 10 + SCREEN_X; DWORD y = 70 + SCREEN_Y; DWORD width = SCREEN_WIDTH - 20; _plrmsg *pMsg; if (chrflag || questlog) { if (invflag || sbookflag) return; x += SPANEL_WIDTH; width -= SPANEL_WIDTH; } else if (invflag || sbookflag) width -= SPANEL_WIDTH; pMsg = plr_msgs; for (i = 0; i < PMSG_COUNT; i++) { if (pMsg->str[0]) PrintPlrMsg(x, y, width, pMsg->str, text_color_from_player_num[pMsg->player]); pMsg++; y += 35; } } void PrintPlrMsg(DWORD x, DWORD y, DWORD width, const char *str, BYTE col) { int line = 0; while (*str) { BYTE c; int screen = PitchTbl[y] + x; DWORD len = 0; const char *sstr = str; const char *endstr = sstr; while (1) { if (*sstr) { c = gbFontTransTbl[(BYTE)*sstr++]; c = fontframe[c]; len += fontkern[c] + 1; if (!c) // allow wordwrap on blank glyph endstr = sstr; else if (len >= width) break; } else { endstr = sstr; break; } } while (str < endstr) { c = gbFontTransTbl[(BYTE)*str++]; c = fontframe[c]; if (c) PrintChar(screen, c, col); screen += fontkern[c] + 1; } y += 10; line++; if (line == 3) break; } } ================================================ FILE: Source/plrmsg.h ================================================ /** * @file plrmsg.h * * Interface of functionality for printing the ingame chat messages. */ #ifndef __PLRMSG_H__ #define __PLRMSG_H__ void plrmsg_delay(BOOL delay); char *ErrorPlrMsg(const char *pszMsg); size_t __cdecl EventPlrMsg(const char *pszFmt, ...); void SendPlrMsg(int pnum, const char *pszStr); void ClearPlrMsg(); void InitPlrMsg(); void DrawPlrMsg(); void PrintPlrMsg(DWORD x, DWORD y, DWORD width, const char *str, BYTE col); #endif /* __PLRMSG_H__ */ ================================================ FILE: Source/portal.cpp ================================================ /** * @file portal.cpp * * Implementation of functionality for handling town portals. */ #include "all.h" /** In-game state of portals. */ PortalStruct portal[MAXPORTAL]; /** Current portal number (a portal array index). */ int portalindex; /** X-coordinate of each players portal in town. */ int WarpDropX[MAXPORTAL] = { 57, 59, 61, 63 }; /** Y-coordinate of each players portal in town. */ int WarpDropY[MAXPORTAL] = { 40, 40, 40, 40 }; void InitPortals() { int i; for (i = 0; i < MAXPORTAL; i++) { if (delta_portal_inited(i)) portal[i].open = FALSE; } } void SetPortalStats(int i, BOOL o, int x, int y, int lvl, int lvltype) { portal[i].open = o; portal[i].x = x; portal[i].y = y; portal[i].level = lvl; portal[i].ltype = lvltype; portal[i].setlvl = FALSE; } void AddWarpMissile(int i, int x, int y) { int mi; missiledata[MIS_TOWN].mlSFX = -1; dMissile[x][y] = 0; mi = AddMissile(0, 0, x, y, 0, MIS_TOWN, TARGET_MONSTERS, i, 0, 0); if (mi != -1) { SetMissDir(mi, 1); if (currlevel != 0) missile[mi]._mlid = AddLight(missile[mi]._mix, missile[mi]._miy, 15); missiledata[MIS_TOWN].mlSFX = LS_SENTINEL; } } void SyncPortals() { int i; for (i = 0; i < MAXPORTAL; i++) { if (!portal[i].open) continue; if (currlevel == 0) AddWarpMissile(i, WarpDropX[i], WarpDropY[i]); else { int lvl = currlevel; if (setlevel) lvl = setlvlnum; if (portal[i].level == lvl) AddWarpMissile(i, portal[i].x, portal[i].y); } } } void AddInTownPortal(int i) { AddWarpMissile(i, WarpDropX[i], WarpDropY[i]); } void ActivatePortal(int i, int x, int y, int lvl, int lvltype, BOOL sp) { portal[i].open = TRUE; if (lvl != 0) { portal[i].x = x; portal[i].y = y; portal[i].level = lvl; portal[i].ltype = lvltype; portal[i].setlvl = sp; } } void DeactivatePortal(int i) { portal[i].open = FALSE; } BOOL PortalOnLevel(int i) { if (portal[i].level == currlevel) return TRUE; else return currlevel == 0; } void RemovePortalMissile(int id) { int i; int mi; 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] &= ~BFLAG_MISSILE; dMissile[missile[mi]._mix][missile[mi]._miy] = 0; if (portal[id].level != 0) AddUnLight(missile[mi]._mlid); DeleteMissile(mi, i); } } } void SetCurrentPortal(int p) { portalindex = p; } void GetPortalLevel() { if (currlevel != 0) { setlevel = FALSE; currlevel = 0; plr[myplr].plrlevel = 0; leveltype = DTYPE_TOWN; } else { if (portal[portalindex].setlvl) { setlevel = TRUE; setlvlnum = portal[portalindex].level; currlevel = portal[portalindex].level; plr[myplr].plrlevel = setlvlnum; leveltype = portal[portalindex].ltype; } else { setlevel = FALSE; currlevel = portal[portalindex].level; plr[myplr].plrlevel = currlevel; leveltype = portal[portalindex].ltype; } if (portalindex == myplr) { NetSendCmd(TRUE, CMD_DEACTIVATEPORTAL); DeactivatePortal(portalindex); } } } void GetPortalLvlPos() { if (currlevel == 0) { ViewX = WarpDropX[portalindex] + 1; ViewY = WarpDropY[portalindex] + 1; } else { ViewX = portal[portalindex].x; ViewY = portal[portalindex].y; if (portalindex != myplr) { ViewX++; ViewY++; } } } BOOL PosOkPortal(int lvl, int x, int y) { int i; for (i = 0; i < MAXPORTAL; i++) { if (portal[i].open && portal[i].level == lvl && ((portal[i].x == x && portal[i].y == y) || (portal[i].x == x - 1 && portal[i].y == y - 1))) return TRUE; } return FALSE; } ================================================ FILE: Source/portal.h ================================================ /** * @file portal.h * * Interface of functionality for handling town portals. */ #ifndef __PORTAL_H__ #define __PORTAL_H__ extern PortalStruct portal[MAXPORTAL]; void InitPortals(); void SetPortalStats(int i, BOOL o, int x, int y, int lvl, int lvltype); void AddWarpMissile(int i, int x, int y); void SyncPortals(); void AddInTownPortal(int i); void ActivatePortal(int i, int x, int y, int lvl, int lvltype, BOOL sp); void DeactivatePortal(int i); BOOL PortalOnLevel(int i); void RemovePortalMissile(int id); void SetCurrentPortal(int p); void GetPortalLevel(); void GetPortalLvlPos(); BOOL PosOkPortal(int lvl, int x, int y); #endif /* __PORTAL_H__ */ ================================================ FILE: Source/quests.cpp ================================================ /** * @file quests.cpp * * Implementation of functionality for handling quests. */ #include "all.h" int qtopline; BOOL questlog; BYTE *pQLogCel; /** Contains the quests of the current game. */ QuestStruct quests[MAXQUESTS]; int qline; int qlist[MAXQUESTS]; int numqlines; int WaterDone; int ReturnLvlX; int ReturnLvlY; int ReturnLvlT; /** current frame # for the quest pentagram selector */ int questpentframe; int ReturnLvl; /** Contains the data related to each quest_id. */ QuestData questlist[MAXQUESTS] = { // clang-format off // _qdlvl, _qdmultlvl, _qlvlt, _qdtype, _qdrnd, _qslvl, _qflags, _qdmsg, _qlstr { 5, -1, DTYPE_NONE, Q_ROCK, 100, 0, QUEST_SINGLE, TEXT_INFRA5, "The Magic Rock" }, { 9, -1, DTYPE_NONE, Q_MUSHROOM, 100, 0, QUEST_SINGLE, TEXT_MUSH8, "Black Mushroom" }, { 4, -1, DTYPE_NONE, Q_GARBUD, 100, 0, QUEST_SINGLE, TEXT_GARBUD1, "Gharbad The Weak" }, { 8, -1, DTYPE_NONE, Q_ZHAR, 100, 0, QUEST_SINGLE, TEXT_ZHAR1, "Zhar the Mad" }, { 14, -1, DTYPE_NONE, Q_VEIL, 100, 0, QUEST_SINGLE, TEXT_VEIL9, "Lachdanan" }, { 15, -1, DTYPE_NONE, Q_DIABLO, 100, 0, QUEST_ANY, TEXT_VILE3, "Diablo" }, { 2, 2, DTYPE_NONE, Q_BUTCHER, 100, 0, QUEST_ANY, TEXT_BUTCH9, "The Butcher" }, { 4, -1, DTYPE_NONE, Q_LTBANNER, 100, 0, QUEST_SINGLE, TEXT_BANNER2, "Ogden's Sign" }, { 7, -1, DTYPE_NONE, Q_BLIND, 100, 0, QUEST_SINGLE, TEXT_BLINDING, "Halls of the Blind" }, { 5, -1, DTYPE_NONE, Q_BLOOD, 100, 0, QUEST_SINGLE, TEXT_BLOODY, "Valor" }, { 10, -1, DTYPE_NONE, Q_ANVIL, 100, 0, QUEST_SINGLE, TEXT_ANVIL5, "Anvil of Fury" }, { 13, -1, DTYPE_NONE, Q_WARLORD, 100, 0, QUEST_SINGLE, TEXT_BLOODWAR, "Warlord of Blood" }, { 3, 3, DTYPE_CATHEDRAL, Q_SKELKING, 100, 1, QUEST_ANY, TEXT_KING2, "The Curse of King Leoric" }, { 2, -1, DTYPE_CAVES, Q_PWATER, 100, 4, QUEST_SINGLE, TEXT_POISON3, "Poisoned Water Supply" }, { 6, -1, DTYPE_CATACOMBS, Q_SCHAMB, 100, 2, QUEST_SINGLE, TEXT_BONER, "The Chamber of Bone" }, { 15, 15, DTYPE_CATHEDRAL, Q_BETRAYER, 100, 5, QUEST_ANY, TEXT_VILE1, "Archbishop Lazarus" }, #ifdef HELLFIRE { 17, 17, DTYPE_NONE, Q_GRAVE, 100, 0, QUEST_ANY, TEXT_GRAVE7, "Grave Matters" }, { 9, 9, DTYPE_NONE, Q_FARMER, 100, 0, QUEST_ANY, TEXT_FARMER1, "Farmer's Orchard" }, { 17, -1, DTYPE_NONE, Q_GIRL, 100, 0, QUEST_SINGLE, TEXT_GIRL2, "Little Girl" }, { 19, -1, DTYPE_NONE, Q_TRADER, 100, 0, QUEST_SINGLE, TEXT_TRADER, "Wandering Trader" }, { 17, 17, DTYPE_NONE, Q_DEFILER, 100, 0, QUEST_ANY, TEXT_DEFILER1, "The Defiler" }, { 21, 21, DTYPE_NONE, Q_NAKRUL, 100, 0, QUEST_ANY, TEXT_NAKRUL1, "Na-Krul" }, { 21, -1, DTYPE_NONE, Q_CORNSTN, 100, 0, QUEST_SINGLE, TEXT_CORNSTN, "Cornerstone of the World" }, { 9, 9, DTYPE_NONE, Q_JERSEY, 100, 0, QUEST_ANY, TEXT_JERSEY4, "The Jersey's Jersey" }, #endif // clang-format on }; /** * Specifies a delta in X-coordinates from the quest entrance for * which the hover text of the cursor will be visible. */ char questxoff[7] = { 0, -1, 0, -1, -2, -1, -2 }; /** * Specifies a delta in Y-coordinates from the quest entrance for * which the hover text of the cursor will be visible. */ char questyoff[7] = { 0, 0, -1, -1, -1, -2, -2 }; const char *const questtrigstr[5] = { "King Leoric's Tomb", "The Chamber of Bone", "Maze", "A Dark Passage", "Unholy Altar" }; /** * A quest group containing the three quests the Butcher, * Ogden's Sign and Gharbad the Weak, which ensures that exactly * two of these three quests appear in any single player game. */ int QuestGroup1[3] = { Q_BUTCHER, Q_LTBANNER, Q_GARBUD }; /** * A quest group containing the three quests Halls of the Blind, * the Magic Rock and Valor, which ensures that exactly two of * these three quests appear in any single player game. */ int QuestGroup2[3] = { Q_BLIND, Q_ROCK, Q_BLOOD }; /** * A quest group containing the three quests Black Mushroom, * Zhar the Mad and Anvil of Fury, which ensures that exactly * two of these three quests appear in any single player game. */ int QuestGroup3[3] = { Q_MUSHROOM, Q_ZHAR, Q_ANVIL }; /** * A quest group containing the two quests Lachdanan and Warlord * of Blood, which ensures that exactly one of these two quests * appears in any single player game. */ int QuestGroup4[2] = { Q_VEIL, Q_WARLORD }; void InitQuests() { int i, initiatedQuests; DWORD z; if (gbMaxPlayers == 1) { for (i = 0; i < MAXQUESTS; i++) { quests[i]._qactive = QUEST_NOTAVAIL; } } else { for (i = 0; i < MAXQUESTS; i++) { if (!(questlist[i]._qflags & QUEST_ANY)) { quests[i]._qactive = QUEST_NOTAVAIL; } } } questlog = FALSE; questpentframe = 1; WaterDone = 0; initiatedQuests = 0; for (z = 0; z < MAXQUESTS; z++) { if (gbMaxPlayers > 1 && !(questlist[z]._qflags & QUEST_ANY)) continue; quests[z]._qtype = questlist[z]._qdtype; if (gbMaxPlayers > 1) { quests[z]._qlevel = questlist[z]._qdmultlvl; if (!delta_quest_inited(initiatedQuests)) { quests[z]._qactive = QUEST_INIT; quests[z]._qvar1 = 0; quests[z]._qlog = FALSE; } initiatedQuests++; } else { quests[z]._qactive = QUEST_INIT; quests[z]._qlevel = questlist[z]._qdlvl; quests[z]._qvar1 = 0; quests[z]._qlog = FALSE; } quests[z]._qslvl = questlist[z]._qslvl; quests[z]._qtx = 0; quests[z]._qty = 0; quests[z]._qidx = z; quests[z]._qlvltype = questlist[z]._qlvlt; quests[z]._qvar2 = 0; quests[z]._qmsg = questlist[z]._qdmsg; } if (gbMaxPlayers == 1) { SetRndSeed(glSeedTbl[15]); if (random_(0, 2) != 0) quests[Q_PWATER]._qactive = QUEST_NOTAVAIL; else quests[Q_SKELKING]._qactive = QUEST_NOTAVAIL; quests[QuestGroup1[random_(0, sizeof(QuestGroup1) / sizeof(int))]]._qactive = QUEST_NOTAVAIL; quests[QuestGroup2[random_(0, sizeof(QuestGroup2) / sizeof(int))]]._qactive = QUEST_NOTAVAIL; quests[QuestGroup3[random_(0, sizeof(QuestGroup3) / sizeof(int))]]._qactive = QUEST_NOTAVAIL; quests[QuestGroup4[random_(0, sizeof(QuestGroup4) / sizeof(int))]]._qactive = QUEST_NOTAVAIL; } #ifdef _DEBUG if (questdebug != -1) quests[questdebug]._qactive = QUEST_ACTIVE; #endif #ifdef SPAWN for (z = 0; z < MAXQUESTS; z++) { quests[z]._qactive = QUEST_NOTAVAIL; } #endif if (quests[Q_SKELKING]._qactive == QUEST_NOTAVAIL) quests[Q_SKELKING]._qvar2 = 2; if (quests[Q_ROCK]._qactive == QUEST_NOTAVAIL) quests[Q_ROCK]._qvar2 = 2; quests[Q_LTBANNER]._qvar1 = 1; if (gbMaxPlayers != 1) quests[Q_BETRAYER]._qvar1 = 2; } void CheckQuests() { #ifndef SPAWN int i, rportx, rporty; if (QuestStatus(Q_BETRAYER) && gbMaxPlayers != 1 && quests[Q_BETRAYER]._qvar1 == 2) { AddObject(OBJ_ALTBOY, 2 * setpc_x + 20, 2 * setpc_y + 22); quests[Q_BETRAYER]._qvar1 = 3; NetSendCmdQuest(TRUE, Q_BETRAYER); } if (gbMaxPlayers != 1) { return; } if (currlevel == quests[Q_BETRAYER]._qlevel && !setlevel && quests[Q_BETRAYER]._qvar1 >= 2 && (quests[Q_BETRAYER]._qactive == QUEST_ACTIVE || quests[Q_BETRAYER]._qactive == QUEST_DONE) && (quests[Q_BETRAYER]._qvar2 == 0 || quests[Q_BETRAYER]._qvar2 == 2)) { quests[Q_BETRAYER]._qtx = 2 * quests[Q_BETRAYER]._qtx + 16; quests[Q_BETRAYER]._qty = 2 * quests[Q_BETRAYER]._qty + 16; rportx = quests[Q_BETRAYER]._qtx; rporty = quests[Q_BETRAYER]._qty; AddMissile(rportx, rporty, rportx, rporty, 0, MIS_RPORTAL, TARGET_MONSTERS, myplr, 0, 0); quests[Q_BETRAYER]._qvar2 = 1; if (quests[Q_BETRAYER]._qactive == QUEST_ACTIVE) { quests[Q_BETRAYER]._qvar1 = 3; } } if (quests[Q_BETRAYER]._qactive == QUEST_DONE && setlevel && setlvlnum == SL_VILEBETRAYER && quests[Q_BETRAYER]._qvar2 == 4) { rportx = 35; rporty = 32; AddMissile(rportx, rporty, rportx, rporty, 0, MIS_RPORTAL, TARGET_MONSTERS, myplr, 0, 0); quests[Q_BETRAYER]._qvar2 = 3; } if (setlevel) { if (setlvlnum == quests[Q_PWATER]._qslvl && quests[Q_PWATER]._qactive != QUEST_INIT && leveltype == quests[Q_PWATER]._qlvltype && nummonsters == 4 && quests[Q_PWATER]._qactive != QUEST_DONE) { quests[Q_PWATER]._qactive = QUEST_DONE; PlaySfxLoc(IS_QUESTDN, plr[myplr]._px, plr[myplr]._py); LoadPalette("Levels\\L3Data\\L3pwater.pal"); WaterDone = 32; } if (WaterDone > 0) { palette_update_quest_palette(WaterDone); WaterDone--; } } else if (plr[myplr]._pmode == PM_STAND) { for (i = 0; i < MAXQUESTS; i++) { if (currlevel == quests[i]._qlevel && quests[i]._qslvl != 0 && quests[i]._qactive != QUEST_NOTAVAIL && plr[myplr]._px == quests[i]._qtx && plr[myplr]._py == quests[i]._qty) { if (quests[i]._qlvltype != DTYPE_NONE) { setlvltype = quests[i]._qlvltype; } StartNewLvl(myplr, WM_DIABSETLVL, quests[i]._qslvl); } } } #endif } BOOL ForceQuests() { #ifndef SPAWN int i, j, qx, qy, ql; if (gbMaxPlayers != 1) { return FALSE; } for (i = 0; i < MAXQUESTS; i++) { if (i != Q_BETRAYER && currlevel == quests[i]._qlevel && quests[i]._qslvl != 0) { ql = quests[quests[i]._qidx]._qslvl - 1; qx = quests[i]._qtx; qy = quests[i]._qty; for (j = 0; j < 7; j++) { if (qx + questxoff[j] == cursmx && qy + questyoff[j] == cursmy) { sprintf(infostr, "To %s", questtrigstr[ql]); cursmx = qx; cursmy = qy; return TRUE; } } } } #endif return FALSE; } BOOL QuestStatus(int i) { if (setlevel) return FALSE; if (currlevel != quests[i]._qlevel) return FALSE; if (quests[i]._qactive == QUEST_NOTAVAIL) return FALSE; if (gbMaxPlayers != 1 && !(questlist[i]._qflags & QUEST_ANY)) return FALSE; return TRUE; } void CheckQuestKill(int m, BOOL sendmsg) { #ifndef SPAWN int i, j; if (monster[m].MType->mtype == MT_SKING) { quests[Q_SKELKING]._qactive = QUEST_DONE; sfxdelay = 30; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR82; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE82; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE82; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK82; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE82; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR82; } #endif if (sendmsg) NetSendCmdQuest(TRUE, Q_SKELKING); } else if (monster[m].MType->mtype == MT_CLEAVER) { quests[Q_BUTCHER]._qactive = QUEST_DONE; sfxdelay = 30; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR80; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE80; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE80; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK80; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE80; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR80; } #endif if (sendmsg) NetSendCmdQuest(TRUE, Q_BUTCHER); } else if (monster[m].mName == UniqMonst[UMT_GARBUD].mName) { //"Gharbad the Weak" quests[Q_GARBUD]._qactive = QUEST_DONE; sfxdelay = 30; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR61; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE61; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE61; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK61; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE61; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR61; } #endif } else if (monster[m].mName == UniqMonst[UMT_ZHAR].mName) { //"Zhar the Mad" quests[Q_ZHAR]._qactive = QUEST_DONE; sfxdelay = 30; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR62; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE62; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE62; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK62; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE62; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR62; } #endif } else if (monster[m].mName == UniqMonst[UMT_LAZURUS].mName && gbMaxPlayers != 1) { //"Arch-Bishop Lazarus" quests[Q_BETRAYER]._qactive = QUEST_DONE; quests[Q_BETRAYER]._qvar1 = 7; sfxdelay = 30; quests[Q_DIABLO]._qactive = QUEST_ACTIVE; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 370) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR83; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE83; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE83; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK83; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE83; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR83; } #endif if (sendmsg) { NetSendCmdQuest(TRUE, Q_BETRAYER); NetSendCmdQuest(TRUE, Q_DIABLO); } } else if (monster[m].mName == UniqMonst[UMT_LAZURUS].mName && gbMaxPlayers == 1) { //"Arch-Bishop Lazarus" quests[Q_BETRAYER]._qactive = QUEST_DONE; sfxdelay = 30; InitVPTriggers(); quests[Q_BETRAYER]._qvar1 = 7; quests[Q_BETRAYER]._qvar2 = 4; quests[Q_DIABLO]._qactive = QUEST_ACTIVE; AddMissile(35, 32, 35, 32, 0, MIS_RPORTAL, TARGET_MONSTERS, myplr, 0, 0); if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR83; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE83; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE83; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK83; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE83; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR83; } #endif } else if (monster[m].mName == UniqMonst[UMT_WARLORD].mName) { //"Warlord of Blood" quests[Q_WARLORD]._qactive = QUEST_DONE; sfxdelay = 30; if (plr[myplr]._pClass == PC_WARRIOR) { sfxdnum = PS_WARR94; } else if (plr[myplr]._pClass == PC_ROGUE) { sfxdnum = PS_ROGUE94; } else if (plr[myplr]._pClass == PC_SORCERER) { sfxdnum = PS_MAGE94; } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { sfxdnum = PS_MONK94; } else if (plr[myplr]._pClass == PC_BARD) { sfxdnum = PS_ROGUE94; } else if (plr[myplr]._pClass == PC_BARBARIAN) { sfxdnum = PS_WARR94; } #endif } #endif } void DrawButcher() { int x, y; x = 2 * setpc_x + 16; y = 2 * setpc_y + 16; DRLG_RectTrans(x + 3, y + 3, x + 10, y + 10); } void DrawSkelKing(int q, int x, int y) { quests[q]._qtx = 2 * x + 28; quests[q]._qty = 2 * y + 23; } void DrawWarLord(int x, int y) { int rw, rh; int i, j; BYTE *sp, *setp; int v; setp = LoadFileInMem("Levels\\L4Data\\Warlord2.DUN", NULL); rw = *setp; sp = setp + 2; rh = *sp; sp += 2; setpc_w = rw; setpc_h = rh; setpc_x = x; setpc_y = y; for (j = y; j < y + rh; j++) { for (i = x; i < x + rw; i++) { if (*sp != 0) { v = *sp; } else { v = 6; } dungeon[i][j] = v; sp += 2; } } mem_free_dbg(setp); } void DrawSChamber(int q, int x, int y) { int i, j; int rw, rh; int xx, yy; BYTE *sp, *setp; int v; setp = LoadFileInMem("Levels\\L2Data\\Bonestr1.DUN", NULL); rw = *setp; sp = setp + 2; rh = *sp; sp += 2; setpc_w = rw; setpc_h = rh; setpc_x = x; setpc_y = y; for (j = y; j < y + rh; j++) { for (i = x; i < x + rw; i++) { if (*sp != 0) { v = *sp; } else { v = 3; } dungeon[i][j] = v; sp += 2; } } xx = 2 * x + 22; yy = 2 * y + 23; quests[q]._qtx = xx; quests[q]._qty = yy; mem_free_dbg(setp); } void DrawLTBanner(int x, int y) { int rw, rh; int i, j; BYTE *sp, *setp; setp = LoadFileInMem("Levels\\L1Data\\Banner1.DUN", NULL); rw = *setp; sp = setp + 2; rh = *sp; sp += 2; setpc_w = rw; setpc_h = rh; setpc_x = x; setpc_y = y; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*sp != 0) { pdungeon[x + i][y + j] = *sp; } sp += 2; } } mem_free_dbg(setp); } void DrawBlind(int x, int y) { int rw, rh; int i, j; BYTE *sp, *setp; setp = LoadFileInMem("Levels\\L2Data\\Blind1.DUN", NULL); rw = *setp; sp = setp + 2; rh = *sp; sp += 2; setpc_x = x; setpc_y = y; setpc_w = rw; setpc_h = rh; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*sp != 0) { pdungeon[x + i][y + j] = *sp; } sp += 2; } } mem_free_dbg(setp); } void DrawBlood(int x, int y) { int rw, rh; int i, j; BYTE *sp, *setp; setp = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", NULL); rw = *setp; sp = setp + 2; rh = *sp; sp += 2; setpc_x = x; setpc_y = y; setpc_w = rw; setpc_h = rh; for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*sp != 0) { dungeon[x + i][y + j] = *sp; } sp += 2; } } mem_free_dbg(setp); } void DRLG_CheckQuests(int x, int y) { int i; for (i = 0; i < MAXQUESTS; i++) { if (QuestStatus(i)) { switch (quests[i]._qtype) { case Q_BUTCHER: DrawButcher(); break; case Q_LTBANNER: DrawLTBanner(x, y); break; case Q_BLIND: DrawBlind(x, y); break; case Q_BLOOD: DrawBlood(x, y); break; case Q_WARLORD: DrawWarLord(x, y); break; case Q_SKELKING: DrawSkelKing(i, x, y); break; case Q_SCHAMB: DrawSChamber(i, x, y); break; } } } } void SetReturnLvlPos() { switch (setlvlnum) { case SL_SKELKING: ReturnLvlX = quests[Q_SKELKING]._qtx + 1; ReturnLvlY = quests[Q_SKELKING]._qty; ReturnLvl = quests[Q_SKELKING]._qlevel; ReturnLvlT = DTYPE_CATHEDRAL; break; case SL_BONECHAMB: ReturnLvlX = quests[Q_SCHAMB]._qtx + 1; ReturnLvlY = quests[Q_SCHAMB]._qty; ReturnLvl = quests[Q_SCHAMB]._qlevel; ReturnLvlT = DTYPE_CATACOMBS; break; case SL_POISONWATER: ReturnLvlX = quests[Q_PWATER]._qtx; ReturnLvlY = quests[Q_PWATER]._qty + 1; ReturnLvl = quests[Q_PWATER]._qlevel; ReturnLvlT = DTYPE_CATHEDRAL; break; case SL_VILEBETRAYER: ReturnLvlX = quests[Q_BETRAYER]._qtx + 1; ReturnLvlY = quests[Q_BETRAYER]._qty - 1; ReturnLvl = quests[Q_BETRAYER]._qlevel; ReturnLvlT = DTYPE_HELL; break; } } void GetReturnLvlPos() { if (quests[Q_BETRAYER]._qactive == QUEST_DONE) quests[Q_BETRAYER]._qvar2 = 2; ViewX = ReturnLvlX; ViewY = ReturnLvlY; currlevel = ReturnLvl; leveltype = ReturnLvlT; } void ResyncMPQuests() { #ifndef SPAWN if (quests[Q_SKELKING]._qactive == QUEST_INIT && currlevel >= quests[Q_SKELKING]._qlevel - 1 && currlevel <= quests[Q_SKELKING]._qlevel + 1) { quests[Q_SKELKING]._qactive = QUEST_ACTIVE; NetSendCmdQuest(TRUE, Q_SKELKING); } if (quests[Q_BUTCHER]._qactive == QUEST_INIT && currlevel >= quests[Q_BUTCHER]._qlevel - 1 && currlevel <= quests[Q_BUTCHER]._qlevel + 1) { quests[Q_BUTCHER]._qactive = QUEST_ACTIVE; NetSendCmdQuest(TRUE, Q_BUTCHER); } if (quests[Q_BETRAYER]._qactive == QUEST_INIT && currlevel == quests[Q_BETRAYER]._qlevel - 1) { quests[Q_BETRAYER]._qactive = QUEST_ACTIVE; NetSendCmdQuest(TRUE, Q_BETRAYER); } if (QuestStatus(Q_BETRAYER)) AddObject(OBJ_ALTBOY, 2 * setpc_x + 20, 2 * setpc_y + 22); #ifdef HELLFIRE if (quests[Q_GRAVE]._qactive == QUEST_INIT && currlevel == quests[Q_GRAVE]._qlevel - 1) { quests[Q_GRAVE]._qactive = QUEST_ACTIVE; NetSendCmdQuest(TRUE, Q_GRAVE); } if (quests[Q_DEFILER]._qactive == QUEST_INIT && currlevel == quests[Q_DEFILER]._qlevel - 1) { quests[Q_DEFILER]._qactive = QUEST_ACTIVE; NetSendCmdQuest(TRUE, Q_DEFILER); } if (quests[Q_NAKRUL]._qactive == QUEST_INIT && currlevel == quests[Q_NAKRUL]._qlevel - 1) { quests[Q_NAKRUL]._qactive = QUEST_ACTIVE; NetSendCmdQuest(TRUE, Q_NAKRUL); } if (quests[Q_JERSEY]._qactive == QUEST_INIT && currlevel == quests[Q_JERSEY]._qlevel - 1) { quests[Q_JERSEY]._qactive = QUEST_ACTIVE; NetSendCmdQuest(TRUE, Q_JERSEY); } #endif #endif } void ResyncQuests() { #ifndef SPAWN int i, tren, x, y; if (setlevel && setlvlnum == quests[Q_PWATER]._qslvl && quests[Q_PWATER]._qactive != QUEST_INIT && leveltype == quests[Q_PWATER]._qlvltype) { if (quests[Q_PWATER]._qactive == QUEST_DONE) LoadPalette("Levels\\L3Data\\L3pwater.pal"); else LoadPalette("Levels\\L3Data\\L3pfoul.pal"); for (i = 0; i <= 32; i++) palette_update_quest_palette(i); } if (QuestStatus(Q_LTBANNER)) { if (quests[Q_LTBANNER]._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[Q_LTBANNER]._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]); tren = TransVal; TransVal = 9; DRLG_MRectTrans(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 4, setpc_y + (setpc_h >> 1)); TransVal = tren; } if (quests[Q_LTBANNER]._qvar1 == 3) { x = setpc_x; y = setpc_y; ObjChangeMapResync(x, y, x + setpc_w + 1, y + setpc_h + 1); for (i = 0; i < nobjects; i++) SyncObjectAnim(objectactive[i]); tren = TransVal; TransVal = 9; DRLG_MRectTrans(setpc_x, setpc_y, (setpc_w >> 1) + setpc_x + 4, setpc_y + (setpc_h >> 1)); TransVal = tren; } } if (currlevel == quests[Q_MUSHROOM]._qlevel) { if (quests[Q_MUSHROOM]._qactive == QUEST_INIT && quests[Q_MUSHROOM]._qvar1 == 0) { SpawnQuestItem(IDI_FUNGALTM, 0, 0, 5, 1); quests[Q_MUSHROOM]._qvar1 = QS_TOMESPAWNED; } else { if (quests[Q_MUSHROOM]._qactive == QUEST_ACTIVE) { if (quests[Q_MUSHROOM]._qvar1 >= QS_MUSHGIVEN) { Qtalklist[TOWN_WITCH]._qblkm = -1; Qtalklist[TOWN_HEALER]._qblkm = TEXT_MUSH3; } else if (quests[Q_MUSHROOM]._qvar1 >= QS_BRAINGIVEN) { Qtalklist[TOWN_HEALER]._qblkm = -1; } } } } if (currlevel == quests[Q_VEIL]._qlevel + 1 && quests[Q_VEIL]._qactive == QUEST_ACTIVE && quests[Q_VEIL]._qvar1 == 0) { quests[Q_VEIL]._qvar1 = 1; SpawnQuestItem(IDI_GLDNELIX, 0, 0, 5, 1); } if (setlevel && setlvlnum == SL_VILEBETRAYER) { if (quests[Q_BETRAYER]._qvar1 >= 4) ObjChangeMapResync(1, 11, 20, 18); if (quests[Q_BETRAYER]._qvar1 >= 6) ObjChangeMapResync(1, 18, 20, 24); if (quests[Q_BETRAYER]._qvar1 >= 7) InitVPTriggers(); for (i = 0; i < nobjects; i++) SyncObjectAnim(objectactive[i]); } if (currlevel == quests[Q_BETRAYER]._qlevel && !setlevel && (quests[Q_BETRAYER]._qvar2 == 1 || quests[Q_BETRAYER]._qvar2 >= 3) && (quests[Q_BETRAYER]._qactive == QUEST_ACTIVE || quests[Q_BETRAYER]._qactive == QUEST_DONE)) { quests[Q_BETRAYER]._qvar2 = 2; } #endif } void PrintQLString(int x, int y, BOOL cjustflag, const char *str, int col) { int len, width, off, i, k, s; BYTE c; s = SStringY[y]; off = x + PitchTbl[SStringY[y] + 44 + SCREEN_Y] + 32 + SCREEN_X; len = strlen(str); k = 0; if (cjustflag) { width = 0; for (i = 0; i < len; i++) width += fontkern[fontframe[gbFontTransTbl[(BYTE)str[i]]]] + 1; if (width < 257) k = (257 - width) >> 1; off += k; } if (qline == y) { CelDraw(cjustflag ? x + k + 12 + SCREEN_X : x + 12 + SCREEN_X, s + 205, pSPentSpn2Cels, questpentframe, 12); } for (i = 0; i < len; i++) { c = fontframe[gbFontTransTbl[(BYTE)str[i]]]; k += fontkern[c] + 1; if (c && k <= 257) { PrintChar(off, c, col); } off += fontkern[c] + 1; } if (qline == y) { CelDraw(cjustflag ? x + k + 36 + SCREEN_X : 276 + SCREEN_X - x, s + 205, pSPentSpn2Cels, questpentframe, 12); } } void DrawQuestLog() { int y, i; PrintQLString(0, 2, TRUE, "Quest Log", 3); CelDraw(64, 511, pQLogCel, 1, 320); y = qtopline; for (i = 0; i < numqlines; i++) { PrintQLString(0, y, TRUE, questlist[qlist[i]]._qlstr, 0); y += 2; } PrintQLString(0, 22, TRUE, "Close Quest Log", 0); questpentframe = (questpentframe & 7) + 1; } void StartQuestlog() { DWORD i; numqlines = 0; for (i = 0; i < MAXQUESTS; i++) { if (quests[i]._qactive == QUEST_ACTIVE && quests[i]._qlog) { qlist[numqlines] = i; numqlines++; } } if (numqlines > 5) { qtopline = 5 - (numqlines >> 1); } else { qtopline = 8; } qline = 22; if (numqlines != 0) qline = qtopline; questlog = TRUE; questpentframe = 1; } void QuestlogUp() { if (numqlines) { if (qline == qtopline) { qline = 22; } else if (qline == 22) { qline = qtopline + 2 * numqlines - 2; } else { qline -= 2; } PlaySFX(IS_TITLEMOV); } } void QuestlogDown() { if (numqlines) { if (qline == 22) { qline = qtopline; } else if (qline == qtopline + 2 * numqlines - 2) { qline = 22; } else { qline += 2; } PlaySFX(IS_TITLEMOV); } } void QuestlogEnter() { PlaySFX(IS_TITLSLCT); if (numqlines && qline != 22) InitQTextMsg(quests[qlist[(qline - qtopline) >> 1]]._qmsg); questlog = FALSE; } void QuestlogESC() { int y, i; y = (MouseY - 32) / 12; if (numqlines) { for (i = 0; i < numqlines; i++) { if (y == qtopline + 2 * i) { qline = y; QuestlogEnter(); } } } if (y == 22) { qline = 22; QuestlogEnter(); } } void SetMultiQuest(int q, int s, int l, int v1) { #ifndef SPAWN if (quests[q]._qactive != QUEST_DONE) { if (s > quests[q]._qactive) quests[q]._qactive = s; quests[q]._qlog |= l; if (v1 > quests[q]._qvar1) quests[q]._qvar1 = v1; } #endif } ================================================ FILE: Source/quests.h ================================================ /** * @file quests.cpp * * Interface of functionality for handling quests. */ #ifndef __QUESTS_H__ #define __QUESTS_H__ extern BOOL questlog; extern BYTE *pQLogCel; extern QuestStruct quests[MAXQUESTS]; extern int ReturnLvlX; extern int ReturnLvlY; extern int ReturnLvlT; extern int ReturnLvl; void InitQuests(); void CheckQuests(); BOOL ForceQuests(); BOOL QuestStatus(int i); void CheckQuestKill(int m, BOOL sendmsg); void DRLG_CheckQuests(int x, int y); void SetReturnLvlPos(); void GetReturnLvlPos(); void ResyncMPQuests(); void ResyncQuests(); void DrawQuestLog(); void StartQuestlog(); void QuestlogUp(); void QuestlogDown(); void QuestlogEnter(); void QuestlogESC(); void SetMultiQuest(int q, int s, int l, int v1); /* rdata */ extern QuestData questlist[MAXQUESTS]; #endif /* __QUESTS_H__ */ ================================================ FILE: Source/render.cpp ================================================ /** * @file render.cpp * * Implementation of functionality for rendering the level tiles. */ #include "all.h" #include "_asm.cpp" int WorldBoolFlag = 0; DWORD gdwCurrentMask = 0; // char world_4B3264 = 0; BYTE *gpCelFrame = NULL; DWORD *gpDrawMask = NULL; // char world_4B326D[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /** Specifies the draw masks used to render transparency of the right side of tiles. */ DWORD RightMask[TILE_WIDTH] = { 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 }; /** Specifies the draw masks used to render transparency of the left side of tiles. */ DWORD LeftMask[TILE_WIDTH] = { 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 }; /** Specifies the draw masks used to render transparency of wall tiles. */ DWORD WallMask[TILE_WIDTH] = { 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) |/ */ #ifdef USE_ASM #include "_render.cpp" #else /** * While blitting this function will check for the upper bound of the buffer * @brief Blit upper part of transparent world CELs * @param pBuff Output buffer */ void drawTopArchesUpperScreen(BYTE *pBuff) { BYTE *dst, *src; BYTE *tbl; short cel_type_16; unsigned int width; unsigned int chk_sh_and; unsigned int n_draw_shift; unsigned int x_minus; unsigned int y_minus; int xx_32, yy_32; int i, j; gpCelFrame = (BYTE *)SpeedFrameTbl; dst = pBuff; if (!(BYTE)light_table_index) { if (level_cel_block & 0x8000) level_cel_block = *(DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + (WORD)(level_cel_block & 0xF000); src = 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)) { src = pDungeonCels + *((DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); tbl = &pLightTbl[256 * light_table_index]; cel_type_16 = (BYTE)(level_cel_block >> 12); switch (cel_type_16) { case 0: // upper (top transparent), with lighting i = 16; do { if (dst < gpBufEnd) break; asm_trans_light_square_1_3(8, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) break; asm_trans_light_square_0_2(8, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; case 1: // upper (top transparent), with lighting WorldBoolFlag = (BYTE)pBuff & 1; xx_32 = 32; do { yy_32 = 32; do { while (1) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; yy_32 -= width; if (!yy_32) goto LABEL_67; } if (dst < gpBufEnd) return; if (((BYTE)dst & 1) == WorldBoolFlag) { asm_trans_light_cel_0_2(width, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(width, tbl, &dst, &src); } yy_32 -= width; } while (yy_32); LABEL_67: WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; dst -= (SCREEN_WIDTH + 160); --xx_32; } while (xx_32); break; case 2: // upper (top transparent), with lighting WorldBoolFlag = 0; xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - xx_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - xx_32, tbl, &dst, &src); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; dst += yy_32; src += (32 - (BYTE)yy_32) & 2; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - yy_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - yy_32, tbl, &dst, &src); } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } } break; case 3: // upper (top transparent), with lighting WorldBoolFlag = 0; xx_32 = 30; while (dst >= gpBufEnd) { WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - xx_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - xx_32, tbl, &dst, &src); } src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - yy_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - yy_32, tbl, &dst, &src); } src += (BYTE)src & 2; dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } } break; case 4: // upper (top transparent), with lighting WorldBoolFlag = 0; xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - xx_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - xx_32, tbl, &dst, &src); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { i = 8; do { if (dst < gpBufEnd) break; asm_trans_light_square_1_3(8, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) break; asm_trans_light_square_0_2(8, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } } break; default: // upper (top transparent), with lighting WorldBoolFlag = 0; xx_32 = 30; while (dst >= gpBufEnd) { WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - xx_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - xx_32, tbl, &dst, &src); } src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { i = 8; do { if (dst < gpBufEnd) break; asm_trans_light_square_1_3(8, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) break; asm_trans_light_square_0_2(8, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } } break; } return; } src = pSpeedCels + *(DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; cel_type_16 = (BYTE)(level_cel_block >> 12); LABEL_11: switch (cel_type_16) { case 8: // upper (top transparent), without lighting i = 16; do { if (dst < gpBufEnd) break; j = 8; do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) break; j = 8; do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; case 9: // upper (top transparent), without lighting WorldBoolFlag = (BYTE)pBuff & 1; yy_32 = 32; LABEL_251: xx_32 = 32; while (1) { while (1) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; xx_32 -= width; if (!xx_32) { LABEL_271: WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; dst -= (SCREEN_WIDTH + 160); if (!--yy_32) return; goto LABEL_251; } } xx_32 -= width; if (dst < gpBufEnd) return; if (((BYTE)dst & 1) == WorldBoolFlag) { chk_sh_and = width >> 1; if (!(width & 1)) goto LABEL_258; ++src; ++dst; if (chk_sh_and) { LABEL_265: n_draw_shift = chk_sh_and >> 1; if (chk_sh_and & 1) { dst[0] = src[0]; src += 2; dst += 2; } if (n_draw_shift) { do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } goto LABEL_268; } } else { chk_sh_and = width >> 1; if (!(width & 1)) goto LABEL_265; *dst++ = *src++; if (chk_sh_and) { LABEL_258: n_draw_shift = chk_sh_and >> 1; if (chk_sh_and & 1) { dst[1] = src[1]; src += 2; dst += 2; } if (n_draw_shift) { do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 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 (dst >= gpBufEnd) { dst += xx_32; x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = src[3]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = src[2]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; dst += yy_32; y_minus = 32 - yy_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[1] = src[3]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[0] = src[2]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } } break; case 11: // upper (top transparent), without lighting WorldBoolFlag = 0; xx_32 = 30; while (dst >= 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) { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; } if (x_minus & 2) { dst[1] = src[1]; src += 4; dst += 2; } } else { for (n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift) { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; } if (x_minus & 2) { dst[0] = src[0]; src += 4; dst += 2; } } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < 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) { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; } if (x_minus & 2) /// BUGFIX: change to `y_minus & 2` { dst[1] = src[1]; src += 4; dst += 2; } } else { for (n_draw_shift = y_minus >> 2; n_draw_shift; --n_draw_shift) { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; } if (x_minus & 2) /// BUGFIX: change to `y_minus & 2` { dst[0] = src[0]; src += 4; dst += 2; } } dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } } break; case 12: // upper (top transparent), without lighting WorldBoolFlag = 0; xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = src[3]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = src[2]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { i = 8; do { if (dst < gpBufEnd) break; j = 8; do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) break; j = 8; do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } } break; default: // upper (top transparent), without lighting WorldBoolFlag = 0; xx_32 = 30; while (dst >= 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) { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { dst[1] = src[1]; src += 4; dst += 2; } } else { for (n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift) { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { dst[0] = src[0]; src += 4; dst += 2; } } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { i = 8; do { if (dst < gpBufEnd) break; j = 8; do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) break; j = 8; do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } } break; } return; } if (level_cel_block & 0x8000) level_cel_block = *(DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + (WORD)(level_cel_block & 0xF000); src = 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 (dst < gpBufEnd) break; j = 8; do { dst[1] = 0; dst[3] = 0; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) break; j = 8; do { dst[0] = 0; dst[2] = 0; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; case 1: // upper (top transparent), black WorldBoolFlag = (BYTE)pBuff & 1; xx_32 = 32; while (1) { yy_32 = 32; do { while (1) { width = *src++; if ((width & 0x80) != 0) break; yy_32 -= width; if (dst < gpBufEnd) return; src += width; if (((BYTE)dst & 1) == WorldBoolFlag) { chk_sh_and = width >> 1; if (!(width & 1)) goto LABEL_378; ++dst; if (chk_sh_and) { LABEL_385: n_draw_shift = chk_sh_and >> 1; if (chk_sh_and & 1) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } goto LABEL_388; } } else { chk_sh_and = width >> 1; if (!(width & 1)) goto LABEL_385; *dst++ = 0; if (chk_sh_and) { LABEL_378: n_draw_shift = chk_sh_and >> 1; if (chk_sh_and & 1) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } goto LABEL_388; } } LABEL_388: if (!yy_32) goto LABEL_391; } width = -(char)width; dst += width; yy_32 -= width; } while (yy_32); LABEL_391: WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; dst -= (SCREEN_WIDTH + 160); if (!--xx_32) return; } case 2: // upper (top transparent), black WorldBoolFlag = 0; for (xx_32 = 30;; xx_32 -= 2) { if (dst < gpBufEnd) return; dst += xx_32; x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); if (!xx_32) break; } yy_32 = 2; do { if (dst < gpBufEnd) break; dst += yy_32; y_minus = 32 - yy_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); break; case 3: // upper (top transparent), black WorldBoolFlag = 0; for (xx_32 = 30;; xx_32 -= 2) { if (dst < gpBufEnd) return; x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); if (!xx_32) break; dst += xx_32; } yy_32 = 2; do { if (dst < gpBufEnd) break; y_minus = 32 - yy_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); break; case 4: // upper (top transparent), black WorldBoolFlag = 0; for (xx_32 = 30;; xx_32 -= 2) { if (dst < gpBufEnd) return; dst += xx_32; x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); if (!xx_32) break; } i = 8; do { if (dst < gpBufEnd) break; j = 8; do { dst[1] = 0; dst[3] = 0; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) break; j = 8; do { dst[0] = 0; dst[2] = 0; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; default: // upper (top transparent), black WorldBoolFlag = 0; for (xx_32 = 30;; xx_32 -= 2) { if (dst < gpBufEnd) return; x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); if (!xx_32) break; dst += xx_32; } i = 8; do { if (dst < gpBufEnd) break; j = 8; do { dst[1] = 0; dst[3] = 0; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) break; j = 8; do { dst[0] = 0; dst[2] = 0; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; } } /** * While blitting this function will check for the upper bound of the buffer * @brief Blit lower part of transparent world CELs * @param pBuff Output buffer * @param pMask Transparancy pattern */ void drawBottomArchesUpperScreen(BYTE *pBuff, DWORD *pMask) { BYTE *dst, *src; BYTE *tbl; short cel_type_16; unsigned int left_shift; unsigned int n_draw_shift; int width; int and80_i; int i; int xx_32, yy_32; gpCelFrame = (BYTE *)SpeedFrameTbl; dst = pBuff; gpDrawMask = pMask; if ((BYTE)light_table_index == 0) { if (level_cel_block & 0x8000) level_cel_block = *(DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + (WORD)(level_cel_block & 0xF000); src = 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 (dst < gpBufEnd) break; left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = src[0]; left_shift *= 2; ++src; ++dst; --i; } while (i); dst -= (SCREEN_WIDTH + 160); --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) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; if (width & 0x1F) gdwCurrentMask <<= width & 0x1F; yy_32 -= width; if (!yy_32) goto LABEL_129; } yy_32 -= width; if (dst < gpBufEnd) return; left_shift = gdwCurrentMask; and80_i = width; do { if (left_shift & 0x80000000) dst[0] = src[0]; left_shift *= 2; ++src; ++dst; --and80_i; } while (and80_i); gdwCurrentMask = left_shift; } while (yy_32); LABEL_129: dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --xx_32; } while (xx_32); break; case 10: // upper (bottom transparent), without lighting xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; dst += yy_32; n_draw_shift = (unsigned int)(32 - yy_32) >> 2; if ((32 - yy_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } } break; case 11: // upper (bottom transparent), without lighting xx_32 = 30; while (dst >= gpBufEnd) { for (n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift) { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; for (n_draw_shift = (unsigned int)(32 - yy_32) >> 2; n_draw_shift; --n_draw_shift) { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)yy_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } } break; case 12: // upper (bottom transparent), without lighting xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) break; left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = src[0]; left_shift *= 2; ++src; ++dst; --i; } while (i); dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); return; } } break; default: // upper (bottom transparent), without lighting xx_32 = 30; while (dst >= gpBufEnd) { for (n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift) { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) break; left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = src[0]; left_shift *= 2; ++src; ++dst; --i; } while (i); src += (BYTE)src & 2; dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); return; } } break; } return; } if ((BYTE)light_table_index != lightmax) { if (!(level_cel_block & 0x8000)) { src = pDungeonCels + *((DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); tbl = &pLightTbl[256 * light_table_index]; cel_type_16 = (BYTE)(level_cel_block >> 12); switch (cel_type_16) { case 0: // upper (bottom transparent), with lighting xx_32 = 32; do { if (dst < gpBufEnd) break; asm_trans_light_mask(32, tbl, &dst, &src, *gpDrawMask); dst -= (SCREEN_WIDTH + 160); --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) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; if (width & 0x1F) gdwCurrentMask <<= width & 0x1F; yy_32 -= width; if (!yy_32) goto LABEL_50; } yy_32 -= width; if (dst < gpBufEnd) return; gdwCurrentMask = asm_trans_light_mask(width, tbl, &dst, &src, gdwCurrentMask); } while (yy_32); LABEL_50: dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --xx_32; } while (xx_32); break; case 2: // upper (bottom transparent), with lighting xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; dst += yy_32; src += (32 - (BYTE)yy_32) & 2; asm_cel_light_edge(32 - yy_32, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } } break; case 3: // upper (bottom transparent), with lighting xx_32 = 30; while (dst >= gpBufEnd) { asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; asm_cel_light_edge(32 - yy_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } } break; case 4: // upper (bottom transparent), with lighting xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) break; src += (BYTE)src & 2; asm_trans_light_mask(32, tbl, &dst, &src, *gpDrawMask); dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); return; } } break; default: // upper (bottom transparent), with lighting xx_32 = 30; while (dst >= gpBufEnd) { asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) break; asm_trans_light_mask(32, tbl, &dst, &src, *gpDrawMask); src += (BYTE)src & 2; dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); return; } } break; } return; } src = pSpeedCels + *(DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; cel_type_16 = (BYTE)(level_cel_block >> 12); goto LABEL_12; } if (level_cel_block & 0x8000) level_cel_block = *(DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + (WORD)(level_cel_block & 0xF000); src = 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 (dst < gpBufEnd) break; left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = 0; left_shift *= 2; ++dst; --i; } while (i); dst -= (SCREEN_WIDTH + 160); --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) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; if (width & 0x1F) gdwCurrentMask <<= width & 0x1F; yy_32 -= width; if (!yy_32) goto LABEL_208; } yy_32 -= width; if (dst < gpBufEnd) return; left_shift = gdwCurrentMask; and80_i = width; src += width; do { if (left_shift & 0x80000000) dst[0] = 0; left_shift *= 2; ++dst; --and80_i; } while (and80_i); gdwCurrentMask = left_shift; } while (yy_32); LABEL_208: dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --xx_32; } while (xx_32); break; case 2: // upper (bottom transparent), black xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); if (!xx_32) { yy_32 = 2; do { if (dst < gpBufEnd) break; dst += yy_32; n_draw_shift = (unsigned int)(32 - yy_32) >> 2; if ((32 - yy_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } xx_32 -= 2; } break; case 3: // upper (bottom transparent), black xx_32 = 30; while (dst >= gpBufEnd) { n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); if (!xx_32) { yy_32 = 2; do { if (dst < gpBufEnd) break; n_draw_shift = (unsigned int)(32 - yy_32) >> 2; if ((32 - yy_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } dst += xx_32; xx_32 -= 2; } break; case 4: // upper (bottom transparent), black xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); if (!xx_32) { gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) break; left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = 0; left_shift *= 2; ++dst; --i; } while (i); dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); return; } xx_32 -= 2; } break; default: // upper (bottom transparent), black xx_32 = 30; while (dst >= gpBufEnd) { n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); if (!xx_32) { gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) break; left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = 0; left_shift *= 2; ++dst; --i; } while (i); dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); return; } dst += xx_32; xx_32 -= 2; } break; } } /** * While blitting this function will check for the upper bound of the buffer * @brief Blit current world CEL to the given buffer * @param pBuff Output buffer */ void drawUpperScreen(BYTE *pBuff) { BYTE *dst, *src; BYTE *tbl; short cel_type_16; unsigned int width; unsigned int chk_sh_and; unsigned int n_draw_shift; int i, j; int xx_32, yy_32; if (cel_transparency_active) { if (!arch_draw_type) { drawTopArchesUpperScreen(pBuff); return; } if (arch_draw_type == 1) { if (block_lvid[level_piece_id] == 1 || block_lvid[level_piece_id] == 3) { drawBottomArchesUpperScreen(pBuff, &LeftMask[31]); return; } } if (arch_draw_type == 2) { if (block_lvid[level_piece_id] == 2 || block_lvid[level_piece_id] == 3) { drawBottomArchesUpperScreen(pBuff, &RightMask[31]); return; } } } gpCelFrame = (BYTE *)SpeedFrameTbl; dst = pBuff; if ((BYTE)light_table_index == 0) { if (level_cel_block & 0x8000) level_cel_block = *(DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + (WORD)(level_cel_block & 0xF000); src = 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 (dst < gpBufEnd) break; j = 8; do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; case 9: // upper (solid), without lighting xx_32 = 32; do { yy_32 = 32; do { while (1) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; yy_32 -= width; if (!yy_32) goto LABEL_133; } yy_32 -= width; if (dst < gpBufEnd) return; chk_sh_and = width >> 1; if (width & 1) { *dst++ = *src++; if (!chk_sh_and) continue; } n_draw_shift = chk_sh_and >> 1; if (chk_sh_and & 1) { *(WORD *)dst = *(WORD *)src; src += 2; dst += 2; if (!n_draw_shift) continue; } do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } while (yy_32); LABEL_133: dst -= (SCREEN_WIDTH + 160); --xx_32; } while (xx_32); break; case 10: // upper (solid), without lighting xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; dst += yy_32; n_draw_shift = (unsigned int)(32 - yy_32) >> 2; if ((32 - yy_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } } break; case 11: // upper (solid), without lighting xx_32 = 30; while (dst >= gpBufEnd) { for (n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift) { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; for (n_draw_shift = (unsigned int)(32 - yy_32) >> 2; n_draw_shift; --n_draw_shift) { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)yy_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } } break; case 12: // upper (solid), without lighting xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { i = 16; do { if (dst < gpBufEnd) break; j = 8; do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } } break; default: // upper (solid), without lighting xx_32 = 30; while (dst >= gpBufEnd) { for (n_draw_shift = (unsigned int)(32 - xx_32) >> 2; n_draw_shift; --n_draw_shift) { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { i = 16; do { if (dst < gpBufEnd) break; j = 8; do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } } break; } return; } if ((BYTE)light_table_index != lightmax) { if (!(level_cel_block & 0x8000)) { src = pDungeonCels + *((DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); tbl = &pLightTbl[256 * light_table_index]; cel_type_16 = (WORD)level_cel_block >> 12; switch (cel_type_16) { case 0: // upper (solid), with lighting xx_32 = 32; do { if (dst < gpBufEnd) break; asm_cel_light_square(8, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); --xx_32; } while (xx_32); break; case 1: // upper (solid), with lighting xx_32 = 32; do { yy_32 = 32; do { while (1) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; yy_32 -= width; if (!yy_32) goto LABEL_58; } yy_32 -= width; if (dst < gpBufEnd) return; asm_cel_light_edge(width, tbl, &dst, &src); } while (yy_32); LABEL_58: dst -= (SCREEN_WIDTH + 160); --xx_32; } while (xx_32); break; case 2: // upper (solid), with lighting xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; dst += yy_32; src += (32 - (BYTE)yy_32) & 2; asm_cel_light_edge(32 - yy_32, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } } break; case 3: // upper (solid), with lighting xx_32 = 30; while (dst >= gpBufEnd) { asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { yy_32 = 2; do { if (dst < gpBufEnd) break; asm_cel_light_edge(32 - yy_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } } break; case 4: // upper (solid), with lighting xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; if (xx_32 < 0) { yy_32 = 16; do { if (dst < gpBufEnd) break; asm_cel_light_square(8, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); --yy_32; } while (yy_32); return; } } break; default: // upper (solid), with lighting xx_32 = 30; while (dst >= gpBufEnd) { asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; if (xx_32 < 0) { yy_32 = 16; do { if (dst < gpBufEnd) break; asm_cel_light_square(8, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); --yy_32; } while (yy_32); return; } } break; } return; } src = pSpeedCels + *(DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; cel_type_16 = (WORD)level_cel_block >> 12; goto LABEL_22; } if (level_cel_block & 0x8000) level_cel_block = *(DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + (WORD)(level_cel_block & 0xF000); src = 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 (dst < gpBufEnd) break; j = 8; do { *(DWORD *)dst = 0; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; case 1: // upper (solid), black xx_32 = 32; do { yy_32 = 32; do { while (1) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; yy_32 -= width; if (!yy_32) goto LABEL_205; } yy_32 -= width; if (dst < gpBufEnd) return; src += width; chk_sh_and = width >> 1; if (width & 1) { *dst++ = 0; if (!chk_sh_and) continue; } n_draw_shift = width >> 2; if (chk_sh_and & 1) { *(WORD *)dst = 0; dst += 2; if (!n_draw_shift) continue; } do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } while (yy_32); LABEL_205: dst -= (SCREEN_WIDTH + 160); --xx_32; } while (xx_32); break; case 2: // upper (solid), black xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); if (!xx_32) { yy_32 = 2; do { if (dst < gpBufEnd) break; dst += yy_32; n_draw_shift = (unsigned int)(32 - yy_32) >> 2; if ((32 - yy_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } xx_32 -= 2; } break; case 3: // upper (solid), black xx_32 = 30; while (dst >= gpBufEnd) { n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); if (!xx_32) { yy_32 = 2; do { if (dst < gpBufEnd) break; n_draw_shift = (unsigned int)(32 - yy_32) >> 2; if ((32 - yy_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } dst += xx_32; xx_32 -= 2; } break; case 4: // upper (solid), black xx_32 = 30; while (dst >= gpBufEnd) { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); if (!xx_32) { i = 16; do { if (dst < gpBufEnd) break; j = 8; do { *(DWORD *)dst = 0; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } xx_32 -= 2; } break; default: // upper (solid), black xx_32 = 30; while (dst >= gpBufEnd) { n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); if (!xx_32) { i = 16; do { if (dst < gpBufEnd) break; j = 8; do { *(DWORD *)dst = 0; dst += 4; --j; } while (j); dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } dst += xx_32; xx_32 -= 2; } break; } } /** * While blitting this function will check for the lower bound of the buffer * @brief Blit upper part of transparent world CELs * @param pBuff Output buffer */ void drawTopArchesLowerScreen(BYTE *pBuff) { BYTE *dst, *src; BYTE *tbl; short cel_type_16; unsigned int world_tbl; unsigned int width; unsigned int chk_sh_and; unsigned int x_minus; unsigned int n_draw_shift; unsigned int y_minus; int tile_42_45; int xx_32, yy_32; int i, j; gpCelFrame = (BYTE *)SpeedFrameTbl; dst = pBuff; if ((BYTE)light_table_index == 0) { if (level_cel_block & 0x8000) level_cel_block = *(DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + (WORD)(level_cel_block & 0xF000); src = 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)] + (WORD)(level_cel_block & 0xF000); src = 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 (dst < gpBufEnd) { j = 8; do { dst[1] = 0; dst[3] = 0; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) { j = 8; do { dst[0] = 0; dst[2] = 0; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; case 1: // lower (top transparent), black WorldBoolFlag = (BYTE)pBuff & 1; xx_32 = 32; LABEL_412: yy_32 = 32; while (1) { while (1) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; yy_32 -= width; if (!yy_32) { LABEL_433: WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; dst -= (SCREEN_WIDTH + 160); if (!--xx_32) return; goto LABEL_412; } } yy_32 -= width; if (dst < gpBufEnd) { src += width; if (((BYTE)dst & 1) == WorldBoolFlag) { chk_sh_and = width >> 1; if (!(width & 1)) goto LABEL_420; ++dst; if (chk_sh_and) { LABEL_427: n_draw_shift = chk_sh_and >> 1; if (chk_sh_and & 1) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } goto LABEL_430; } } else { chk_sh_and = width >> 1; if (!(width & 1)) goto LABEL_427; *dst++ = 0; if (chk_sh_and) { LABEL_420: n_draw_shift = chk_sh_and >> 1; if (chk_sh_and & 1) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } goto LABEL_430; } } } else { src += width; dst += width; } 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 (dst < gpBufEnd) { dst += xx_32; x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } } else { src = &src[-xx_32 + 32]; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (!xx_32) break; } yy_32 = 2; do { if (dst < gpBufEnd) { dst += yy_32; y_minus = 32 - yy_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } } else { src = &src[-yy_32 + 32]; dst += 32; } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); break; case 3: // lower (top transparent), black WorldBoolFlag = 0; for (xx_32 = 30;; xx_32 -= 2) { if (dst < gpBufEnd) { x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } } else { src = &src[-xx_32 + 32]; dst = &dst[-xx_32 + 32]; } dst -= (SCREEN_WIDTH + 160); if (!xx_32) break; dst += xx_32; } yy_32 = 2; do { if (dst < gpBufEnd) { y_minus = 32 - yy_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } } else { src = &src[-yy_32 + 32]; dst = &dst[-yy_32 + 32]; } dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); break; case 4: // lower (top transparent), black WorldBoolFlag = 0; for (xx_32 = 30;; xx_32 -= 2) { if (dst < gpBufEnd) { dst += xx_32; x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } } else { src = &src[-xx_32 + 32]; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (!xx_32) break; } i = 8; do { if (dst < gpBufEnd) { j = 8; do { dst[1] = 0; dst[3] = 0; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) { j = 8; do { dst[0] = 0; dst[2] = 0; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; default: // lower (top transparent), black WorldBoolFlag = 0; for (xx_32 = 30;; xx_32 -= 2) { if (dst < gpBufEnd) { x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = 0; dst += 2; } if (n_draw_shift) { do { dst[1] = 0; dst[3] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = 0; dst += 2; } if (n_draw_shift) { do { dst[0] = 0; dst[2] = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } } else { src = &src[-xx_32 + 32]; dst = &dst[-xx_32 + 32]; } dst -= (SCREEN_WIDTH + 160); if (!xx_32) break; dst += xx_32; } i = 8; do { if (dst < gpBufEnd) { j = 8; do { dst[1] = 0; dst[3] = 0; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) { j = 8; do { dst[0] = 0; dst[2] = 0; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; } return; } if (!(level_cel_block & 0x8000)) { src = pDungeonCels + *((DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); tbl = &pLightTbl[256 * light_table_index]; cel_type_16 = (BYTE)(level_cel_block >> 12); switch (cel_type_16) { case 0: // lower (top transparent), with lighting i = 16; do { if (dst < gpBufEnd) { asm_trans_light_square_1_3(8, tbl, &dst, &src); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) { asm_trans_light_square_0_2(8, tbl, &dst, &src); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; case 1: // lower (top transparent), with lighting WorldBoolFlag = (BYTE)pBuff & 1; xx_32 = 32; do { yy_32 = 32; do { while (1) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; yy_32 -= width; if (!yy_32) goto LABEL_69; } yy_32 -= width; if (dst < gpBufEnd) { if (((BYTE)dst & 1) == WorldBoolFlag) { asm_trans_light_cel_0_2(width, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(width, tbl, &dst, &src); } } else { src += width; dst += width; } } while (yy_32); LABEL_69: WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; dst -= (SCREEN_WIDTH + 160); --xx_32; } while (xx_32); break; case 2: // lower (top transparent), with lighting WorldBoolFlag = 0; xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_98: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; yy_32 = world_tbl + 2; WorldBoolFlag += world_tbl >> 1; } do { dst += yy_32; src += (32 - (BYTE)yy_32) & 2; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - yy_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - yy_32, tbl, &dst, &src); } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; xx_32 = 30 - world_tbl; WorldBoolFlag += world_tbl >> 1; } do { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - xx_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - xx_32, tbl, &dst, &src); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_98; case 3: // lower (top transparent), with lighting WorldBoolFlag = 0; xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_154: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; yy_32 = world_tbl + 2; WorldBoolFlag += world_tbl >> 1; } do { WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - yy_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - yy_32, tbl, &dst, &src); } src += (BYTE)src & 2; dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; xx_32 = 30 - world_tbl; WorldBoolFlag += world_tbl >> 1; } do { WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - xx_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - xx_32, tbl, &dst, &src); } src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_154; case 4: // lower (top transparent), with lighting WorldBoolFlag = 0; xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_210: i = 8; do { if (dst < gpBufEnd) { asm_trans_light_square_1_3(8, tbl, &dst, &src); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) { asm_trans_light_square_0_2(8, tbl, &dst, &src); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; xx_32 = 30 - world_tbl; WorldBoolFlag += world_tbl >> 1; } do { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - xx_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - xx_32, tbl, &dst, &src); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_210; default: // lower (top transparent), with lighting WorldBoolFlag = 0; xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_249: i = 8; do { if (dst < gpBufEnd) { asm_trans_light_square_1_3(8, tbl, &dst, &src); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) { asm_trans_light_square_0_2(8, tbl, &dst, &src); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; xx_32 = 30 - world_tbl; WorldBoolFlag += world_tbl >> 1; } do { WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { asm_trans_light_cel_0_2(32 - xx_32, tbl, &dst, &src); } else { asm_trans_light_cel_1_3(32 - xx_32, tbl, &dst, &src); } src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_249; } return; } src = pSpeedCels + *(DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; cel_type_16 = (BYTE)(level_cel_block >> 12); LABEL_11: switch (cel_type_16) { case 8: // lower (top transparent), without lighting i = 16; do { if (dst < gpBufEnd) { j = 8; do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) { j = 8; do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; case 9: // lower (top transparent), without lighting WorldBoolFlag = (BYTE)pBuff & 1; xx_32 = 32; while (1) { yy_32 = 32; do { while (1) { width = *src++; if ((width & 0x80) != 0) break; yy_32 -= width; if (dst < gpBufEnd) { if (((BYTE)dst & 1) == WorldBoolFlag) { chk_sh_and = width >> 1; if (!(width & 1)) goto LABEL_280; ++src; ++dst; if (chk_sh_and) { LABEL_287: n_draw_shift = chk_sh_and >> 1; if (chk_sh_and & 1) { dst[0] = src[0]; src += 2; dst += 2; } if (n_draw_shift) { do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } goto LABEL_290; } } else { chk_sh_and = width >> 1; if (!(width & 1)) goto LABEL_287; *dst++ = *src++; if (chk_sh_and) { LABEL_280: n_draw_shift = chk_sh_and >> 1; if (chk_sh_and & 1) { dst[1] = src[1]; src += 2; dst += 2; } if (n_draw_shift) { do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } goto LABEL_290; } } } else { src += width; dst += width; } LABEL_290: if (!yy_32) goto LABEL_293; } width = -(char)width; dst += width; yy_32 -= width; } while (yy_32); LABEL_293: WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; dst -= (SCREEN_WIDTH + 160); if (!--xx_32) return; } case 10: // lower (top transparent), without lighting WorldBoolFlag = 0; xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_308: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; yy_32 = world_tbl + 2; WorldBoolFlag += world_tbl >> 1; } do { dst += yy_32; y_minus = 32 - yy_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[1] = src[3]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = y_minus >> 2; if (y_minus & 2) { dst[0] = src[2]; src += 4; dst += 2; --n_draw_shift; /// BUGFIX: delete this line } if (n_draw_shift) { do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; xx_32 = 30 - world_tbl; WorldBoolFlag += world_tbl >> 1; } do { dst += xx_32; x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = src[3]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = src[2]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_308; case 11: // lower (top transparent), without lighting WorldBoolFlag = 0; xx_32 = 30; if (pBuff < gpBufEnd) goto LABEL_326; tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 <= 45) { world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; 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) { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { dst[1] = src[1]; src += 4; dst += 2; } } else { for (n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift) { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { dst[0] = src[0]; src += 4; dst += 2; } } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_336; } dst = pBuff - 12288; src += 288; LABEL_336: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; 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) { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; } if ((32 - (BYTE)yy_32) & 2) { dst[1] = src[1]; src += 4; dst += 2; } } else { for (n_draw_shift = y_minus >> 2; n_draw_shift; --n_draw_shift) { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; } if ((32 - (BYTE)yy_32) & 2) { dst[0] = src[0]; src += 4; dst += 2; } } dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); break; case 12: // lower (top transparent), without lighting WorldBoolFlag = 0; xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_364: i = 8; do { if (dst < gpBufEnd) { j = 8; do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) { j = 8; do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; xx_32 = 30 - world_tbl; WorldBoolFlag += world_tbl >> 1; } do { dst += xx_32; x_minus = 32 - xx_32; WorldBoolFlag = ((BYTE)WorldBoolFlag + 1) & 1; if (WorldBoolFlag) { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[1] = src[3]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { n_draw_shift = x_minus >> 2; if (x_minus & 2) { dst[0] = src[2]; src += 4; dst += 2; } if (n_draw_shift) { do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_364; default: // lower (top transparent), without lighting WorldBoolFlag = 0; xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_389: i = 8; do { if (dst < gpBufEnd) { j = 8; do { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (dst < gpBufEnd) { j = 8; do { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; world_tbl >>= 1; 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) { dst[1] = src[1]; dst[3] = src[3]; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { dst[1] = src[1]; src += 4; dst += 2; } } else { for (n_draw_shift = x_minus >> 2; n_draw_shift; --n_draw_shift) { dst[0] = src[0]; dst[2] = src[2]; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { dst[0] = src[0]; src += 4; dst += 2; } } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_389; } } /** * While blitting this function will check for the lower bound of the buffer * @brief Blit lower part of transparent world CELs * @param pBuff Output buffer * @param pMask Transparancy pattern */ void drawBottomArchesLowerScreen(BYTE *pBuff, DWORD *pMask) { BYTE *dst, *src; BYTE *tbl; short cel_type_16; int and80_i; unsigned int world_tbl; unsigned int left_shift; unsigned int n_draw_shift; int tile_42_45; int width; int xx_32, yy_32; int i; gpCelFrame = (BYTE *)SpeedFrameTbl; dst = pBuff; 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)] + (WORD)(level_cel_block & 0xF000); src = 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 (dst < gpBufEnd) { left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = 0; left_shift *= 2; ++dst; --i; } while (i); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --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) { width = *src++; if ((width & 0x80) != 0) break; yy_32 -= width; if (dst < gpBufEnd) { and80_i = width; src += width; left_shift = gdwCurrentMask; do { if (left_shift & 0x80000000) dst[0] = 0; left_shift *= 2; ++dst; --and80_i; } while (and80_i); gdwCurrentMask = left_shift; } else { src += width; dst += width; } if (!yy_32) goto LABEL_252; } width = -(char)width; dst += width; if (width & 0x1F) gdwCurrentMask <<= width & 0x1F; yy_32 -= width; } while (yy_32); LABEL_252: dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --xx_32; } while (xx_32); break; case 2: // lower (bottom transparent), black for (i = 30;; i -= 2) { if (dst < gpBufEnd) { dst += i; n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (!i) break; } i = 2; do { if (dst < gpBufEnd) { dst += i; n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst += 32; } dst -= (SCREEN_WIDTH + 160); i += 2; } while (i != 32); break; case 3: // lower (bottom transparent), black for (i = 30;; i -= 2) { if (dst < gpBufEnd) { n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst = &dst[32 - i]; } dst -= (SCREEN_WIDTH + 160); if (!i) break; dst += i; } i = 2; do { if (dst < gpBufEnd) { n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst = &dst[32 - i]; } dst = &dst[i - (SCREEN_WIDTH + 160)]; i += 2; } while (i != 32); break; case 4: // lower (bottom transparent), black for (i = 30;; i -= 2) { if (dst < gpBufEnd) { dst += i; n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (!i) break; } gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) { left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = 0; left_shift *= 2; ++dst; --i; } while (i); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); break; default: // lower (bottom transparent), black for (i = 30;; i -= 2) { if (dst < gpBufEnd) { n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst = &dst[32 - i]; } dst -= (SCREEN_WIDTH + 160); if (!i) break; dst += i; } gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) { left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = 0; left_shift *= 2; ++dst; --i; } while (i); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); break; } return; } if (!(level_cel_block & 0x8000)) { src = pDungeonCels + *((DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); tbl = &pLightTbl[256 * light_table_index]; cel_type_16 = (BYTE)(level_cel_block >> 12); switch (cel_type_16) { case 0: // lower (bottom transparent), with lighting yy_32 = 32; do { if (dst < gpBufEnd) { asm_trans_light_mask(32, tbl, &dst, &src, *gpDrawMask); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --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) { width = *src++; if ((width & 0x80) != 0) break; yy_32 -= width; if (dst < gpBufEnd) { gdwCurrentMask = asm_trans_light_mask(width, tbl, &dst, &src, gdwCurrentMask); } else { src += width; dst += width; } if (!yy_32) goto LABEL_52; } width = -(char)width; dst += width; if (width & 0x1F) gdwCurrentMask <<= width & 0x1F; yy_32 -= width; } while (yy_32); LABEL_52: dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --xx_32; } while (xx_32); break; case 2: // lower (bottom transparent), with lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_62: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 192 * world_tbl; yy_32 = (world_tbl >> 1) + 2; } do { dst += yy_32; src += (32 - (BYTE)yy_32) & 2; asm_cel_light_edge(32 - yy_32, tbl, &dst, &src); yy_32 += 2; dst -= (SCREEN_WIDTH + 160); } while (yy_32 != 32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_62; case 3: // lower (bottom transparent), with lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_80: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 192 * world_tbl; yy_32 = (world_tbl >> 1) + 2; } do { asm_cel_light_edge(32 - yy_32, tbl, &dst, &src); /// BUGFIX: uncomment this line // src += (BYTE)src & 2; dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_80; case 4: // lower (bottom transparent), with lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_98: gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) { asm_trans_light_mask(32, tbl, &dst, &src, *gpDrawMask); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_98; default: // lower (bottom transparent), with lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_117: gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) { asm_trans_light_mask(32, tbl, &dst, &src, *gpDrawMask); src += (BYTE)src & 2; } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_117; } return; } src = pSpeedCels + *(DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; cel_type_16 = (BYTE)(level_cel_block >> 12); } else { if (level_cel_block & 0x8000) level_cel_block = *(DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + (WORD)(level_cel_block & 0xF000); src = 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 (dst < gpBufEnd) { left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = src[0]; left_shift *= 2; ++src; ++dst; --i; } while (i); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --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) { width = *src++; if ((width & 0x80) != 0) break; yy_32 -= width; if (dst < gpBufEnd) { and80_i = width; left_shift = gdwCurrentMask; do { if (left_shift & 0x80000000) dst[0] = src[0]; left_shift *= 2; ++src; ++dst; --and80_i; } while (and80_i); gdwCurrentMask = left_shift; } else { src += width; dst += width; } if (!yy_32) goto LABEL_152; } width = -(char)width; dst += width; if (width & 0x1F) gdwCurrentMask <<= width & 0x1F; yy_32 -= width; } while (yy_32); LABEL_152: dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --xx_32; } while (xx_32); break; case 10: // lower (bottom transparent), without lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_162: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 192 * world_tbl; yy_32 = (world_tbl >> 1) + 2; } do { dst += yy_32; n_draw_shift = (unsigned int)(32 - yy_32) >> 2; if ((32 - yy_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); yy_32 += 2; } while (yy_32 != 32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_162; case 11: // lower (bottom transparent), without lighting xx_32 = 30; if (pBuff < gpBufEnd) goto LABEL_175; tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 <= 45) { world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 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 *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_180; } dst = pBuff - 12288; src += 288; LABEL_180: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 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 *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)yy_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); break; case 12: // lower (bottom transparent), without lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_198: gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) { left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = src[0]; left_shift *= 2; ++src; ++dst; --i; } while (i); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_198; default: // lower (bottom transparent), without lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_217: gpDrawMask -= 16; yy_32 = 16; do { if (dst < gpBufEnd) { left_shift = *gpDrawMask; i = 32; do { if (left_shift & 0x80000000) dst[0] = src[0]; left_shift *= 2; ++src; ++dst; --i; } while (i); src += (BYTE)src & 2; } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --gpDrawMask; --yy_32; } while (yy_32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 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 *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_217; } } /** * While blitting this function will check for the lower bound of the buffer * @brief Blit current world CEL to the given buffer * @param pBuff Output buffer */ void drawLowerScreen(BYTE *pBuff) { BYTE *dst, *src; BYTE *tbl; short cel_type_16; unsigned int chk_sh_and; unsigned int world_tbl; unsigned int n_draw_shift; unsigned int width; int tile_42_45; int xx_32, yy_32; int i, j; if (cel_transparency_active) { if (!arch_draw_type) { drawTopArchesLowerScreen(pBuff); return; } if (arch_draw_type == 1) { if (block_lvid[level_piece_id] == 1 || block_lvid[level_piece_id] == 3) { drawBottomArchesLowerScreen(pBuff, &LeftMask[31]); return; } } if (arch_draw_type == 2) { if (block_lvid[level_piece_id] == 2 || block_lvid[level_piece_id] == 3) { drawBottomArchesLowerScreen(pBuff, &RightMask[31]); return; } } } gpCelFrame = (BYTE *)SpeedFrameTbl; dst = pBuff; 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)] + (WORD)(level_cel_block & 0xF000); src = 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 (dst < gpBufEnd) { j = 8; do { *(DWORD *)dst = 0; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; case 1: // lower (solid), black xx_32 = 32; do { yy_32 = 32; do { while (1) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; yy_32 -= width; if (!yy_32) goto LABEL_232; } yy_32 -= width; if (dst < gpBufEnd) { src += width; chk_sh_and = width >> 1; if (width & 1) { dst[0] = 0; ++dst; } if (chk_sh_and) { n_draw_shift = width >> 2; if (chk_sh_and & 1) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } } else { src += width; dst += width; } } while (yy_32); LABEL_232: dst -= (SCREEN_WIDTH + 160); --xx_32; } while (xx_32); break; case 2: // lower (solid), black for (i = 30;; i -= 2) { if (dst < gpBufEnd) { dst += i; n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (!i) break; } i = 2; do { if (dst < gpBufEnd) { dst += i; n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst += 32; } dst -= (SCREEN_WIDTH + 160); i += 2; } while (i != 32); break; case 3: // lower (solid), black for (i = 30;; i -= 2) { if (dst < gpBufEnd) { n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst = &dst[32 - i]; } dst -= (SCREEN_WIDTH + 160); if (!i) break; dst += i; } i = 2; do { if (dst < gpBufEnd) { n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst = &dst[32 - i]; } dst = &dst[i - (SCREEN_WIDTH + 160)]; i += 2; } while (i != 32); break; case 4: // lower (solid), black for (i = 30;; i -= 2) { if (dst < gpBufEnd) { dst += i; n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst += 32; } dst -= (SCREEN_WIDTH + 160); if (!i) break; } i = 16; do { if (dst < gpBufEnd) { j = 8; do { *(DWORD *)dst = 0; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; default: // lower (solid), black for (i = 30;; i -= 2) { if (dst < gpBufEnd) { n_draw_shift = (unsigned int)(32 - i) >> 2; if ((32 - i) & 2) { *(WORD *)dst = 0; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = 0; dst += 4; --n_draw_shift; } while (n_draw_shift); } } else { src = &src[32 - i]; dst = &dst[32 - i]; } dst -= (SCREEN_WIDTH + 160); if (!i) break; dst += i; } i = 16; do { if (dst < gpBufEnd) { j = 8; do { *(DWORD *)dst = 0; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; } return; } if (!(level_cel_block & 0x8000)) { src = pDungeonCels + *((DWORD *)pDungeonCels + (level_cel_block & 0xFFF)); tbl = &pLightTbl[256 * light_table_index]; cel_type_16 = (WORD)level_cel_block >> 12; switch (cel_type_16) { case 0: // lower (solid), with lighting xx_32 = 32; do { if (dst < gpBufEnd) { asm_cel_light_square(8, tbl, &dst, &src); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --xx_32; } while (xx_32); break; case 1: // lower (solid), with lighting xx_32 = 32; do { yy_32 = 32; do { width = *src++; if ((width & 0x80) == 0) { yy_32 -= width; if (dst < gpBufEnd) { asm_cel_light_edge(width, tbl, &dst, &src); } else { src += width; dst += width; } } else { width = -(char)width; dst += width; yy_32 -= width; } } while (yy_32); dst -= (SCREEN_WIDTH + 160); --xx_32; } while (xx_32); break; case 2: // lower (solid), with lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_68: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 192 * world_tbl; yy_32 = (world_tbl >> 1) + 2; } do { dst += yy_32; src += (32 - (BYTE)yy_32) & 2; asm_cel_light_edge(32 - yy_32, tbl, &dst, &src); yy_32 += 2; dst -= (SCREEN_WIDTH + 160); } while (yy_32 != 32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_68; case 3: // lower (solid), with lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_83: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 192 * world_tbl; yy_32 = (world_tbl >> 1) + 2; } do { asm_cel_light_edge(32 - yy_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[yy_32 - (SCREEN_WIDTH + 160)]; yy_32 += 2; } while (yy_32 != 32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_83; case 4: // lower (solid), with lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_100: i = 16; do { if (dst < gpBufEnd) { asm_cel_light_square(8, tbl, &dst, &src); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { dst += xx_32; src += (32 - (BYTE)xx_32) & 2; asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_100; default: // lower (solid), with lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_116: j = 16; do { if (dst < gpBufEnd) { asm_cel_light_square(8, tbl, &dst, &src); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --j; } while (j); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { asm_cel_light_edge(32 - xx_32, tbl, &dst, &src); src += (BYTE)src & 2; dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_116; } return; } src = pSpeedCels + *(DWORD *)&gpCelFrame[4 * (light_table_index + 16 * (level_cel_block & 0xFFF))]; cel_type_16 = (WORD)level_cel_block >> 12; } else { if (level_cel_block & 0x8000) level_cel_block = *(DWORD *)&gpCelFrame[64 * (level_cel_block & 0xFFF)] + (WORD)(level_cel_block & 0xF000); src = 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 (dst < gpBufEnd) { j = 8; do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); break; case 9: // lower (solid), without lighting xx_32 = 32; do { yy_32 = 32; do { while (1) { width = *src++; if ((width & 0x80) == 0) break; width = -(char)width; dst += width; yy_32 -= width; if (!yy_32) goto LABEL_143; } yy_32 -= width; if (dst < gpBufEnd) { chk_sh_and = width >> 1; if (width & 1) { dst[0] = src[0]; ++src; ++dst; } if (chk_sh_and) { n_draw_shift = chk_sh_and >> 1; if (chk_sh_and & 1) { *(WORD *)dst = *(WORD *)src; src += 2; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } } } else { src += width; dst += width; } } while (yy_32); LABEL_143: dst -= (SCREEN_WIDTH + 160); --xx_32; } while (xx_32); break; case 10: // lower (solid), without lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_153: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 192 * world_tbl; yy_32 = (world_tbl >> 1) + 2; } do { dst += yy_32; n_draw_shift = (unsigned int)(32 - yy_32) >> 2; if ((32 - yy_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } yy_32 += 2; dst -= (SCREEN_WIDTH + 160); } while (yy_32 < 32); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_153; case 11: // lower (solid), without lighting xx_32 = 30; if (pBuff < gpBufEnd) goto LABEL_166; tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 <= 45) { world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 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 *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_171; } dst = pBuff - 12288; src += 288; LABEL_171: yy_32 = 2; if (dst >= gpBufEnd) { tile_42_45 = (unsigned int)(dst - gpBufEnd + 1023) >> 8; if (tile_42_45 > 42) return; world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_2[world_tbl >> 2]; dst -= 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 *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)yy_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst += yy_32; yy_32 += 2; dst -= (SCREEN_WIDTH + 160); } while (yy_32 < 32); break; case 12: // lower (solid), without lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_189: i = 16; do { if (dst < gpBufEnd) { j = 8; do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 192 * world_tbl; xx_32 = 30 - (world_tbl >> 1); } do { dst += xx_32; n_draw_shift = (unsigned int)(32 - xx_32) >> 2; if ((32 - xx_32) & 2) { *(WORD *)dst = *((WORD *)src + 1); src += 4; dst += 2; } if (n_draw_shift) { do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --n_draw_shift; } while (n_draw_shift); } dst -= (SCREEN_WIDTH + 160); xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_189; default: // lower (solid), without lighting xx_32 = 30; if (pBuff >= gpBufEnd) { tile_42_45 = (unsigned int)(pBuff - gpBufEnd + 1023) >> 8; if (tile_42_45 > 45) { dst = pBuff - 12288; src += 288; LABEL_205: i = 16; do { if (dst < gpBufEnd) { j = 8; do { *(DWORD *)dst = *(DWORD *)src; src += 4; dst += 4; --j; } while (j); } else { src += 32; dst += 32; } dst -= (SCREEN_WIDTH + 160); --i; } while (i); return; } world_tbl = WorldTbl3x16[tile_42_45]; src += WorldTbl17_1[world_tbl >> 2]; dst -= 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 *)dst = *(DWORD *)src; src += 4; dst += 4; } if ((32 - (BYTE)xx_32) & 2) { *(WORD *)dst = *(WORD *)src; src += 4; dst += 2; } dst = &dst[xx_32 - (SCREEN_WIDTH + 160)]; xx_32 -= 2; } while (xx_32 >= 0); goto LABEL_205; } } /** * @brief Render a black tile * @param pBuff pointer where to render the tile */ void world_draw_black_tile(BYTE *pBuff) { BYTE *dst; int i, j; int xx, yy; dst = pBuff; xx = 30; for (i = 1;; i++) { dst += xx; j = i; do { *(DWORD *)dst = 0; dst += 4; j--; } while (j); dst = &dst[xx - 832]; if (!xx) break; xx -= 2; } yy = 2; i = 15; do { dst += yy; j = i; do { *(DWORD *)dst = 0; dst += 4; j--; } while (j); dst = &dst[yy - 832]; i--; yy += 2; } while (yy != 32); } #endif ================================================ FILE: Source/render.h ================================================ /** * @file render.h * * Interface of functionality for rendering the level tiles. */ #ifndef __RENDER_H__ #define __RENDER_H__ void drawUpperScreen(BYTE *pBuff); void drawLowerScreen(BYTE *pBuff); void world_draw_black_tile(BYTE *pBuff); /* rdata */ extern int WorldBoolFlag; extern DWORD gdwCurrentMask; extern BYTE *gpCelFrame; extern DWORD *gpDrawMask; extern DWORD RightMask[TILE_WIDTH]; extern DWORD LeftMask[TILE_WIDTH]; extern int WorldTbl3x16[48]; extern int WorldTbl17_1[17]; extern int WorldTbl17_2[17]; #endif /* __RENDER_H__ */ ================================================ FILE: Source/restrict.cpp ================================================ /** * @file restrict.cpp * * Implementation of functionality for checking if the game will be able run on the system. */ #include "all.h" /** * @brief Check that the OS version is the minimum required by the game * @return True if suported */ BOOL SystemSupported() { OSVERSIONINFO VersionInformation; BOOL ret = FALSE; memset(&VersionInformation, 0, sizeof(VersionInformation)); VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation); if (GetVersionEx(&VersionInformation) && VersionInformation.dwPlatformId == VER_PLATFORM_WIN32_NT && VersionInformation.dwMajorVersion >= 5) { ret = TRUE; } return ret; } /** * @brief Check that we have write access to the Windows install folder * @return False if we have write access */ BOOL RestrictedTest() { FILE *f; char Buffer[MAX_PATH]; BOOL ret = FALSE; if (SystemSupported() && GetWindowsDirectory(Buffer, sizeof(Buffer))) { strcat(Buffer, "\\Diablo1RestrictedTest.foo"); f = fopen(Buffer, "wt"); if (f) { fclose(f); remove(Buffer); } else { ret = TRUE; } } return ret; } /** * @brief Check that we have write access to the game install folder * @return False if we have write access */ BOOL ReadOnlyTest() { char *c; FILE *f; char Filename[MAX_PATH]; BOOL ret = FALSE; if (GetModuleFileName(ghInst, Filename, sizeof(Filename))) { c = strrchr(Filename, '\\'); if (c) { strcpy(c + 1, "Diablo1ReadOnlyTest.foo"); f = fopen(Filename, "wt"); if (f) { fclose(f); remove(Filename); } else { ret = TRUE; } } } return ret; } ================================================ FILE: Source/restrict.h ================================================ /** * @file restrict.h * * Interface of functionality for checking if the game will be able run on the system. */ #ifndef __RESTRICT_H__ #define __RESTRICT_H__ BOOL RestrictedTest(); BOOL ReadOnlyTest(); #endif /* __RESTRICT_H__ */ ================================================ FILE: Source/scrollrt.cpp ================================================ /** * @file scrollrt.cpp * * Implementation of functionality for rendering the dungeons, monsters and calling other render routines. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" /** * Specifies the current light entry. */ int light_table_index; int PitchTbl[1024]; DWORD sgdwCursWdtOld; DWORD sgdwCursX; DWORD sgdwCursY; /** * Lower bound of back buffer. */ BYTE *gpBufEnd; DWORD sgdwCursHgt; /** * Specifies the current MIN block of the level CEL file, as used during rendering of the level tiles. * * frameNum := block & 0x0FFF * frameType := block & 0x7000 >> 12 */ DWORD level_cel_block; DWORD sgdwCursXOld; DWORD sgdwCursYOld; #ifdef HELLFIRE BOOLEAN AutoMapShowItems; #endif /** * Specifies the type of arches to render. */ char arch_draw_type; /** * Describes the surface being rendered. */ DDSURFACEDESC DDS_desc; /** * Specifies whether transparency is active for the current CEL file being decoded. */ int cel_transparency_active; /** * Specifies the current dungeon piece ID of the level, as used during rendering of the level tiles. */ int level_piece_id; DWORD sgdwCursWdt; void (*DrawPlrProc)(int, int, int, int, int, BYTE *, int, int, int, int); BYTE sgSaveBack[8192]; /** * Specifies the monster_num to render. */ int draw_monster_num; DWORD sgdwCursHgtOld; /* data */ /* used in 1.00 debug */ const char *const 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" }; const char *const szPlrModeAssert[12] = { "standing", "walking (1)", "walking (2)", "walking (3)", "attacking (melee)", "attacking (ranged)", "blocking", "getting hit", "dying", "casting a spell", "changing levels", "quitting" }; /** * @brief Clear cursor state */ void ClearCursor() // CODE_FIX: this was supposed to be in cursor.cpp { sgdwCursWdt = 0; sgdwCursWdtOld = 0; } /** * @brief Remove the cursor from the back buffer */ static void scrollrt_draw_cursor_back_buffer() { int i; BYTE *src, *dst; if (sgdwCursWdt == 0) { return; } /// ASSERT: assert(gpBuffer); src = sgSaveBack; dst = &gpBuffer[SCREENXY(sgdwCursX, sgdwCursY)]; i = sgdwCursHgt; if (sgdwCursHgt != 0) { while (i--) { memcpy(dst, src, sgdwCursWdt); src += sgdwCursWdt; dst += BUFFER_WIDTH; } } sgdwCursXOld = sgdwCursX; sgdwCursYOld = sgdwCursY; sgdwCursWdtOld = sgdwCursWdt; sgdwCursHgtOld = sgdwCursHgt; sgdwCursWdt = 0; } /** * @brief Draw the cursor on the back buffer */ static void scrollrt_draw_cursor_item() { int i, mx, my, col; BYTE *src, *dst; /// ASSERT: assert(! sgdwCursWdt); if (pcurs <= CURSOR_NONE || cursW == 0 || cursH == 0) { return; } mx = MouseX - 1; if (mx < 0) { mx = 0; } else if (mx > SCREEN_WIDTH - 1) { return; } my = MouseY - 1; if (my < 0) { my = 0; } else if (my > SCREEN_HEIGHT - 1) { return; } sgdwCursX = mx; sgdwCursWdt = sgdwCursX + cursW + 1; if (sgdwCursWdt > SCREEN_WIDTH - 1) { sgdwCursWdt = SCREEN_WIDTH - 1; } sgdwCursX &= ~3; sgdwCursWdt |= 3; sgdwCursWdt -= sgdwCursX; sgdwCursWdt++; sgdwCursY = my; sgdwCursHgt = sgdwCursY + cursH + 1; if (sgdwCursHgt > SCREEN_HEIGHT - 1) { sgdwCursHgt = SCREEN_HEIGHT - 1; } sgdwCursHgt -= sgdwCursY; sgdwCursHgt++; /// ASSERT: assert(sgdwCursWdt * sgdwCursHgt < sizeof sgSaveBack); /// ASSERT: assert(gpBuffer); dst = sgSaveBack; src = &gpBuffer[SCREENXY(sgdwCursX, sgdwCursY)]; for (i = sgdwCursHgt; i != 0; i--, dst += sgdwCursWdt, src += BUFFER_WIDTH) { memcpy(dst, src, sgdwCursWdt); } mx++; my++; gpBufEnd = &gpBuffer[PitchTbl[SCREEN_HEIGHT + SCREEN_Y] - cursW - 2]; if (pcurs >= CURSOR_FIRSTITEM) { col = PAL16_YELLOW + 5; if (plr[myplr].HoldItem._iMagical != 0) { col = PAL16_BLUE + 5; } if (!plr[myplr].HoldItem._iStatFlag) { col = PAL16_RED + 5; } #ifdef HELLFIRE if (pcurs <= 179) { #endif CelBlitOutlineSafe(col, mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels, pcurs, cursW, 0, 8); if (col != PAL16_RED + 5) { CelClippedDrawSafe(mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels, pcurs, cursW, 0, 8); } else { CelDrawLightRedSafe(mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels, pcurs, cursW, 0, 8, 1); } #ifdef HELLFIRE } else { CelBlitOutlineSafe(col, mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels2, pcurs - 179, cursW, 0, 8); if (col != PAL16_RED + 5) { CelClippedDrawSafe(mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels2, pcurs - 179, cursW, 0, 8); } else { CelDrawLightRedSafe(mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels2, pcurs - 179, cursW, 0, 8, 1); } } #endif } else { CelClippedDrawSafe(mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels, pcurs, cursW, 0, 8); } } /** * @brief Render a missile sprites for a given tile * @param x dPiece coordinate * @param y dPiece coordinate * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param CelSkip Skip part of sprite, see Cl2Draw * @param CelCap Skip part of sprite, see Cl2Draw * @param pre Is the sprite in the background */ void DrawMissile(int x, int y, int sx, int sy, int CelSkip, int CelCap, BOOL pre) { int i, mx, my, nCel; MissileStruct *m; BYTE *pCelBuff; DWORD *pFrameTable; if (dMissile[x][y] == -1) { for (i = 0; i < nummissiles; i++) { /// ASSERT: assert(missileactive[i] < MAXMISSILES); if (missileactive[i] >= MAXMISSILES) break; #ifdef HELLFIRE if (missileactive[i] < 0) break; #endif m = &missile[missileactive[i]]; if (m->_mix == x && m->_miy == y && m->_miPreFlag == pre && m->_miDrawFlag) { pCelBuff = m->_miAnimData; if (!pCelBuff) { // app_fatal("Draw Missile type %d: NULL Cel Buffer", m->_mitype); return; } nCel = m->_miAnimFrame; pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Draw Missile: frame %d of %d, missile type==%d", nCel, pFrameTable[0], m->_mitype); return; } mx = sx + m->_mixoff - m->_miAnimWidth2; my = sy + m->_miyoff; if (m->_miUniqTrans) Cl2DrawLightTbl(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap, m->_miUniqTrans + 3); else if (m->_miLightFlag) Cl2DrawLight(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap); else Cl2Draw(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap); } } } else { m = &missile[dMissile[x][y] - 1]; #ifdef HELLFIRE if (m->_miPreFlag == pre) { #else if (m->_miPreFlag == pre && m->_miDrawFlag) { #endif pCelBuff = m->_miAnimData; if (!pCelBuff) { // app_fatal("Draw Missile 2 type %d: NULL Cel Buffer", m->_mitype); return; } nCel = m->_miAnimFrame; pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Draw Missile 2: frame %d of %d, missile type==%d", nCel, pFrameTable[0], m->_mitype); return; } mx = sx + m->_mixoff - m->_miAnimWidth2; my = sy + m->_miyoff; if (m->_miUniqTrans) Cl2DrawLightTbl(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap, m->_miUniqTrans + 3); else if (m->_miLightFlag) Cl2DrawLight(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap); else Cl2Draw(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap); } } } /** * @brief Render a missile sprite, check for overdraw on lower screen * @param x dPiece coordinate * @param y dPiece coordinate * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param CelSkip Skip part of sprite, see Cl2Draw * @param CelCap Skip part of sprite, see Cl2Draw * @param pre Is the sprite in the background */ void DrawClippedMissile(int x, int y, int sx, int sy, int CelSkip, int CelCap, BOOL pre) { int i, mx, my, nCel; MissileStruct *m; BYTE *pCelBuff; DWORD *pFrameTable; if (dMissile[x][y] == -1) { for (i = 0; i < nummissiles; i++) { /// ASSERT: assert(missileactive[i] < MAXMISSILES); if (missileactive[i] >= MAXMISSILES) break; #ifdef HELLFIRE if (missileactive[i] < 0) break; #endif m = &missile[missileactive[i]]; if (m->_mix == x && m->_miy == y && m->_miPreFlag == pre && m->_miDrawFlag) { pCelBuff = m->_miAnimData; if (!pCelBuff) { // app_fatal("Draw Missile type %d Clipped: NULL Cel Buffer", m->_mitype); return; } nCel = m->_miAnimFrame; pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Draw Clipped Missile: frame %d of %d, missile type==%d", nCel, pFrameTable[0], m->_mitype); return; } mx = sx + m->_mixoff - m->_miAnimWidth2; my = sy + m->_miyoff; if (m->_miUniqTrans) Cl2DrawLightTblSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap, m->_miUniqTrans + 3); else if (m->_miLightFlag) Cl2DrawLightSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap); else Cl2DrawSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap); } } } else { m = &missile[dMissile[x][y] - 1]; #ifdef HELLFIRE if (m->_miPreFlag == pre) { #else if (m->_miPreFlag == pre && m->_miDrawFlag) { #endif pCelBuff = m->_miAnimData; if (!pCelBuff) { // app_fatal("Draw Missile 2 type %d Clipped: NULL Cel Buffer", m->_mitype); return; } nCel = m->_miAnimFrame; pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Draw Clipped Missile 2: frame %d of %d, missile type==%d", nCel, pFrameTable[0], m->_mitype); return; } mx = sx + m->_mixoff - m->_miAnimWidth2; my = sy + m->_miyoff; if (m->_miUniqTrans) Cl2DrawLightTblSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap, m->_miUniqTrans + 3); else if (m->_miLightFlag) Cl2DrawLightSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap); else Cl2DrawSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap); } } } /** * @brief Render a monster sprite * @param x dPiece coordinate * @param y dPiece coordinate * @param mx Back buffer coordinate * @param my Back buffer coordinate * @param CelSkip Skip part of sprite, see Cl2Draw * @param CelCap Skip part of sprite, see Cl2Draw */ static void DrawMonster(int x, int y, int mx, int my, int m, int CelSkip, int CelCap) { int nCel; char trans; BYTE *pCelBuff; DWORD *pFrameTable; if ((DWORD)m >= MAXMONSTERS) { // app_fatal("Draw Monster: tried to draw illegal monster %d", m); return; } pCelBuff = monster[m]._mAnimData; if (!pCelBuff) { // app_fatal("Draw Monster \"%s\": NULL Cel Buffer", monster[m].mName); return; } nCel = monster[m]._mAnimFrame; pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { /* const char *szMode = "unknown action"; if(monster[m]._mmode <= 17) szMode = szMonModeAssert[monster[m]._mmode]; app_fatal( "Draw Monster \"%s\" %s: facing %d, frame %d of %d", monster[m].mName, szMode, monster[m]._mdir, nCel, pFrameTable[0]); */ return; } if (!(dFlags[x][y] & BFLAG_LIT)) { Cl2DrawLightTbl(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap, 1); } else { trans = 0; if (monster[m]._uniqtype) trans = monster[m]._uniqtrans + 4; if (monster[m]._mmode == MM_STONE) trans = 2; if (plr[myplr]._pInfraFlag && light_table_index > 8) trans = 1; if (trans) Cl2DrawLightTbl(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap, trans); else Cl2DrawLight(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap); } } /** * @brief Render a monster sprite, check for overdraw on lower screen * @param x dPiece coordinate * @param y dPiece coordinate * @param mx Back buffer coordinate * @param my Back buffer coordinate * @param CelSkip Skip part of sprite, see Cl2Draw * @param CelCap Skip part of sprite, see Cl2Draw */ static void DrawClippedMonster(int x, int y, int mx, int my, int m, int CelSkip, int CelCap) { int nCel; char trans; BYTE *pCelBuff; DWORD *pFrameTable; if ((DWORD)m >= MAXMONSTERS) { // app_fatal("Draw Monster Clipped: tried to draw illegal monster %d", m); return; } pCelBuff = monster[m]._mAnimData; if (!pCelBuff) { // app_fatal("Draw Monster \"%s\" Clipped: NULL Cel Buffer", monster[m].mName); return; } nCel = monster[m]._mAnimFrame; pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { /* const char *szMode = "unknown action"; if(monster[m]._mmode <= 17) szMode = szMonModeAssert[monster[m]._mmode]; app_fatal( "Draw Monster \"%s\" %s Clipped: facing %d, frame %d of %d", monster[m].mName, szMode, monster[m]._mdir, nCel, pFrameTable[0]); */ return; } if (!(dFlags[x][y] & BFLAG_LIT)) { Cl2DrawLightTblSafe(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap, 1); } else { trans = 0; if (monster[m]._uniqtype) trans = monster[m]._uniqtrans + 4; if (monster[m]._mmode == MM_STONE) trans = 2; if (plr[myplr]._pInfraFlag && light_table_index > 8) trans = 1; if (trans) Cl2DrawLightTblSafe(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap, trans); else Cl2DrawLightSafe(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap); } } /** * @brief Render a player sprite * @param pnum Player id * @param x dPiece coordinate * @param y dPiece coordinate * @param px Back buffer coordinate * @param py Back buffer coordinate * @param pCelBuff sprite buffer * @param nCel frame * @param nWidth width * @param CelSkip Skip part of sprite, see Cl2Draw * @param CelCap Skip part of sprite, see Cl2Draw */ static void DrawPlayer(int pnum, int x, int y, int px, int py, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int l; DWORD *pFrameTable; if (dFlags[x][y] & BFLAG_LIT || plr[myplr]._pInfraFlag || !setlevel && currlevel == 0) { if (!pCelBuff) { // app_fatal("Drawing player %d \"%s\": NULL Cel Buffer", pnum, plr[pnum]._pName); return; } pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { /* const char *szMode = "unknown action"; if(plr[pnum]._pmode <= PM_QUIT) szMode = szPlrModeAssert[plr[pnum]._pmode]; app_fatal( "Drawing player %d \"%s\" %s: facing %d, frame %d of %d", pnum, plr[pnum]._pName, szMode, plr[pnum]._pdir, nCel, pFrameTable[0]); */ return; } if (pnum == pcursplr) Cl2DrawOutline(165, px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap); if (pnum == myplr) { Cl2Draw(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap); #ifndef HELLFIRE if (plr[pnum].pManaShield) Cl2Draw( px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0], py, misfiledata[MFILE_MANASHLD].mAnimData[0], 1, misfiledata[MFILE_MANASHLD].mAnimWidth[0], CelSkip, CelCap); #endif } else if (!(dFlags[x][y] & BFLAG_LIT) || plr[myplr]._pInfraFlag && light_table_index > 8) { Cl2DrawLightTbl(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap, 1); #ifndef HELLFIRE if (plr[pnum].pManaShield) Cl2DrawLightTbl( px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0], py, misfiledata[MFILE_MANASHLD].mAnimData[0], 1, misfiledata[MFILE_MANASHLD].mAnimWidth[0], CelSkip, CelCap, 1); #endif } else { l = light_table_index; if (light_table_index < 5) light_table_index = 0; else light_table_index -= 5; Cl2DrawLight(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap); #ifndef HELLFIRE if (plr[pnum].pManaShield) Cl2DrawLight( px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0], py, misfiledata[MFILE_MANASHLD].mAnimData[0], 1, misfiledata[MFILE_MANASHLD].mAnimWidth[0], CelSkip, CelCap); #endif light_table_index = l; } } } /** * @brief Render a monster sprite, check for overdraw on lower screen * @param pnum Player id * @param x dPiece coordinate * @param y dPiece coordinate * @param px Back buffer coordinate * @param py Back buffer coordinate * @param pCelBuff sprite buffer * @param nCel frame * @param nWidth width * @param CelSkip Skip part of sprite, see Cl2Draw * @param CelCap Skip part of sprite, see Cl2Draw */ static void DrawClippedPlayer(int pnum, int x, int y, int px, int py, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int l; DWORD *pFrameTable; if (dFlags[x][y] & BFLAG_LIT || plr[myplr]._pInfraFlag) { if (!pCelBuff) { // app_fatal("Drawing player %d \"%s\" clipped: NULL Cel Buffer", pnum, plr[pnum]._pName); return; } pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { /* const char *szMode = "unknown action"; if(plr[pnum]._pmode <= PM_QUIT) szMode = szPlrModeAssert[plr[pnum]._pmode]; app_fatal( "Drawing player %d \"%s\" %s clipped: facing %d, frame %d of %d", pnum, plr[pnum]._pName, szMode, plr[pnum]._pdir, nCel, pFrameTable[0]); */ return; } if (pnum == pcursplr) Cl2DrawOutlineSafe(165, px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap); if (pnum == myplr) { Cl2DrawSafe(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap); #ifndef HELLFIRE if (plr[pnum].pManaShield) Cl2DrawSafe( px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0], py, misfiledata[MFILE_MANASHLD].mAnimData[0], 1, misfiledata[MFILE_MANASHLD].mAnimWidth[0], CelSkip, CelCap); #endif } else if (!(dFlags[x][y] & BFLAG_LIT) || plr[myplr]._pInfraFlag && light_table_index > 8) { Cl2DrawLightTblSafe(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap, 1); #ifndef HELLFIRE if (plr[pnum].pManaShield) Cl2DrawLightTblSafe( px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0], py, misfiledata[MFILE_MANASHLD].mAnimData[0], 1, misfiledata[MFILE_MANASHLD].mAnimWidth[0], CelSkip, CelCap, 1); #endif } else { l = light_table_index; if (light_table_index < 5) light_table_index = 0; else light_table_index -= 5; Cl2DrawLightSafe(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap); #ifndef HELLFIRE if (plr[pnum].pManaShield) Cl2DrawLightSafe( px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0], py, misfiledata[MFILE_MANASHLD].mAnimData[0], 1, misfiledata[MFILE_MANASHLD].mAnimWidth[0], CelSkip, CelCap); #endif light_table_index = l; } } } /** * @brief Render a player sprite * @param x dPiece coordinate * @param y dPiece coordinate * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param CelSkip Skip part of sprite, see Cl2Draw * @param CelCap Skip part of sprite, see Cl2Draw * @param clipped check for overdraw on lower screen */ void DrawDeadPlayer(int x, int y, int sx, int sy, int CelSkip, int CelCap, BOOL clipped) { int i, px, py, nCel; PlayerStruct *p; BYTE *pCelBuff; DWORD *pFrameTable; if (clipped) DrawPlrProc = DrawClippedPlayer; else DrawPlrProc = DrawPlayer; dFlags[x][y] &= ~BFLAG_DEAD_PLAYER; for (i = 0; i < MAX_PLRS; i++) { p = &plr[i]; if (p->plractive && p->_pHitPoints == 0 && p->plrlevel == (BYTE)currlevel && p->_px == x && p->_py == y) { pCelBuff = p->_pAnimData; if (!pCelBuff) { // app_fatal("Drawing dead player %d \"%s\": NULL Cel Buffer", i, p->_pName); break; } nCel = p->_pAnimFrame; pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Drawing dead player %d \"%s\": facing %d, frame %d of %d", i, p->_pName, p->_pdir, nCel, pFrameTable[0]); break; } dFlags[x][y] |= BFLAG_DEAD_PLAYER; px = sx + p->_pxoff - p->_pAnimWidth2; py = sy + p->_pyoff; DrawPlrProc(i, x, y, px, py, p->_pAnimData, p->_pAnimFrame, p->_pAnimWidth, CelSkip, CelCap); } } } /** * @brief Render an object sprite * @param x dPiece coordinate * @param y dPiece coordinate * @param ox Back buffer coordinate * @param oy Back buffer coordinate * @param pre Is the sprite in the background * @param CelSkip Skip part of sprite, see Cl2Draw * @param CelCap Skip part of sprite, see Cl2Draw */ static void DrawObject(int x, int y, int ox, int oy, BOOL pre, int CelSkip, int CelCap) { int sx, sy, xx, yy, nCel; char bv; BYTE *pCelBuff; DWORD *pFrameTable; if (dObject[x][y] > 0) { bv = dObject[x][y] - 1; if (object[bv]._oPreFlag != pre) return; sx = ox - object[bv]._oAnimWidth2; sy = oy; } else { bv = -(dObject[x][y] + 1); if (object[bv]._oPreFlag != pre) return; xx = object[bv]._ox - x; yy = object[bv]._oy - y; sx = (xx << 5) + ox - object[bv]._oAnimWidth2 - (yy << 5); sy = oy + (yy << 4) + (xx << 4); CelSkip = 0; CelCap = 8; } /// ASSERT: assert((unsigned char)bv < MAXOBJECTS); #ifdef HELLFIRE if (bv >= MAXOBJECTS) return; if (bv < 0) return; #else if ((BYTE)bv >= MAXOBJECTS) return; #endif pCelBuff = object[bv]._oAnimData; if (!pCelBuff) { // app_fatal("Draw Object type %d: NULL Cel Buffer", object[bv]._otype); return; } nCel = object[bv]._oAnimFrame; pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Draw Object: frame %d of %d, object type==%d", nCel, pFrameTable[0], object[bv]._otype); return; } if (bv == pcursobj) CelBlitOutline(194, sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap); if (object[bv]._oLight) { CelClippedDrawLight(sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap); } else { /// ASSERT: assert(object[bv]._oAnimData); if (object[bv]._oAnimData) // BUGFIX: _oAnimData was already checked, this is redundant CelClippedDraw(sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap); } } /** * @brief Render an object sprite, check for overdraw on lower screen * @param x dPiece coordinate * @param y dPiece coordinate * @param ox Back buffer coordinate * @param oy Back buffer coordinate * @param pre Is the sprite in the background * @param CelSkip Skip part of sprite, see Cl2Draw * @param CelCap Skip part of sprite, see Cl2Draw */ static void DrawClippedObject(int x, int y, int ox, int oy, BOOL pre, int CelSkip, int CelCap) { int sx, sy, xx, yy, nCel; char bv; BYTE *pCelBuff; DWORD *pFrameTable; if (dObject[x][y] > 0) { bv = dObject[x][y] - 1; if (object[bv]._oPreFlag != pre) return; sx = ox - object[bv]._oAnimWidth2; sy = oy; } else { bv = -(dObject[x][y] + 1); if (object[bv]._oPreFlag != pre) return; xx = object[bv]._ox - x; yy = object[bv]._oy - y; sx = (xx << 5) + ox - object[bv]._oAnimWidth2 - (yy << 5); sy = oy + (yy << 4) + (xx << 4); CelSkip = 0; CelCap = 8; } /// ASSERT: assert((unsigned char)bv < MAXOBJECTS); #ifdef HELLFIRE if (bv >= MAXOBJECTS) #else if ((BYTE)bv >= MAXOBJECTS) #endif return; pCelBuff = object[bv]._oAnimData; if (!pCelBuff) { // app_fatal("Draw Object type %d Clipped: NULL Cel Buffer", object[bv]._otype); return; } nCel = object[bv]._oAnimFrame; pFrameTable = (DWORD *)pCelBuff; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Draw Clipped Object: frame %d of %d, object type==%d", nCel, pFrameTable[0], object[bv]._otype); return; } if (bv == pcursobj) CelBlitOutlineSafe(194, sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap); if (object[bv]._oLight) CelDrawLightSafe(sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap); else CelClippedDrawSafe(sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap); } static void scrollrt_draw_clipped_dungeon(BYTE *pBuff, int sx, int sy, int dx, int dy, BOOL eflag); /** * This variant checks for of screen element on the lower screen * This function it self causes rendering issues since it will render on top of objects on the other side of walls * @brief Re render tile to workaround sorting issues with players walking east/west * @param pBuff Pointer to output buffer at location sx,sy * @param y dPiece coordinate * @param x dPiece coordinate * @param sx Back buffer coordinate * @param sy Back buffer coordinate */ static void scrollrt_draw_clipped_e_flag(BYTE *pBuff, int x, int y, int sx, int sy) { int i, lti_old, cta_old, lpi_old; BYTE *dst; MICROS *pMap; lti_old = light_table_index; cta_old = cel_transparency_active; lpi_old = level_piece_id; level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; dst = pBuff; arch_draw_type = 1; level_cel_block = pMap->mt[0]; if (level_cel_block != 0) { drawLowerScreen(dst); } arch_draw_type = 2; level_cel_block = pMap->mt[1]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } dst = pBuff; arch_draw_type = 0; for (i = 2; i < MicroTileLen; i += 2) { dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[i]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[i + 1]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } } scrollrt_draw_clipped_dungeon(pBuff, x, y, sx, sy, FALSE); light_table_index = lti_old; cel_transparency_active = cta_old; level_piece_id = lpi_old; } /** * @brief Render object sprites * @param pBuff where to render to with sx,sy already applied * @param sx dPiece coordinate * @param sy dPiece coordinate * @param dx Back buffer coordinate * @param dy Back buffer coordinate * @param eflag Should the sorting workaround be applied */ static void scrollrt_draw_clipped_dungeon(BYTE *pBuff, int sx, int sy, int dx, int dy, BOOL eflag) { int px, py, nCel, nMon, negMon, p; char bFlag, bDead, bObj, bItem, bPlr, bArch, bMap, negPlr, dd; DeadStruct *pDeadGuy; ItemStruct *pItem; PlayerStruct *pPlayer; MonsterStruct *pMonster; BYTE *pCelBuff; DWORD *pFrameTable; /// ASSERT: assert((DWORD)sx < MAXDUNX); /// ASSERT: assert((DWORD)sy < MAXDUNY); bFlag = dFlags[sx][sy]; bDead = dDead[sx][sy]; bObj = dObject[sx][sy]; bItem = dItem[sx][sy]; bPlr = dPlayer[sx][sy]; bArch = dSpecial[sx][sy]; bMap = dTransVal[sx][sy]; nMon = dMonster[sx][sy]; /// ASSERT: assert((DWORD)(sy-1) < MAXDUNY); negPlr = dPlayer[sx][sy - 1]; negMon = dMonster[sx][sy - 1]; if (visiondebug && bFlag & BFLAG_LIT) { CelClippedBlitSafe(pBuff, pSquareCel, 1, 64, 0, 8); } if (MissilePreFlag && bFlag & BFLAG_MISSILE) { DrawClippedMissile(sx, sy, dx, dy, 0, 8, TRUE); } if (light_table_index < lightmax) { if (bDead != 0) { do { pDeadGuy = &dead[(bDead & 0x1F) - 1]; dd = (bDead >> 5) & 7; px = dx - pDeadGuy->_deadWidth2; pCelBuff = pDeadGuy->_deadData[dd]; /// ASSERT: assert(pDeadGuy->_deadData[dd] != NULL); if (pCelBuff == NULL) break; pFrameTable = (DWORD *)pDeadGuy->_deadData[dd]; nCel = pDeadGuy->_deadFrame; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Clipped dead sub: frame %d of %d, deadnum==%d", nCel, pFrameTable[0], (bDead & 0x1F) - 1); break; } if (pDeadGuy->_deadtrans != 0) { Cl2DrawLightTblSafe(px, dy, pCelBuff, nCel, pDeadGuy->_deadWidth, 0, 8, pDeadGuy->_deadtrans); } else { Cl2DrawLightSafe(px, dy, pCelBuff, pDeadGuy->_deadFrame, pDeadGuy->_deadWidth, 0, 8); } } while (0); } if (bObj != 0) { DrawClippedObject(sx, sy, dx, dy, TRUE, 0, 8); } } if (bItem != 0) { do { pItem = &item[bItem - 1]; if (!pItem->_iPostDraw) { /// ASSERT: assert((unsigned char)bItem <= MAXITEMS); #ifdef HELLFIRE if (bItem > MAXITEMS || bItem < 0) #else if ((BYTE)bItem > MAXITEMS) #endif break; pCelBuff = pItem->_iAnimData; if (pCelBuff == NULL) { // app_fatal("Draw Item \"%s\" Clipped 1: NULL Cel Buffer", pItem->_iIName); break; } pFrameTable = (DWORD *)pCelBuff; nCel = pItem->_iAnimFrame; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { /* app_fatal( "Draw Clipped \"%s\" Item: frame %d of %d, item type==%d", pItem->_iIName, nCel, pFrameTable[0], pItem->_itype); */ break; } px = dx - pItem->_iAnimWidth2; if (bItem - 1 == pcursitem #ifdef HELLFIRE || AutoMapShowItems == TRUE #endif ) { CelBlitOutlineSafe(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, 0, 8); } CelDrawLightSafe(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, 0, 8); } } while (0); } if (bFlag & BFLAG_PLAYERLR) { do { p = -(negPlr + 1); if ((DWORD)p >= MAX_PLRS) { // app_fatal("draw player clipped: tried to draw illegal player %d", p); break; } pPlayer = &plr[p]; px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2; py = dy + pPlayer->_pyoff; DrawClippedPlayer(p, sx, sy - 1, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, 0, 8); if (eflag && pPlayer->_peflag != 0) { if (pPlayer->_peflag == 2) { scrollrt_draw_clipped_e_flag(pBuff - (BUFFER_WIDTH * TILE_HEIGHT / 2 + TILE_WIDTH + TILE_WIDTH / 2), sx - 2, sy + 1, dx - (TILE_WIDTH + TILE_WIDTH / 2), dy - TILE_HEIGHT / 2); } scrollrt_draw_clipped_e_flag(pBuff - TILE_WIDTH, sx - 1, sy + 1, dx - TILE_WIDTH, dy); } } while (0); } if (bFlag & BFLAG_MONSTLR && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag) && negMon < 0) { do { draw_monster_num = -(negMon + 1); if ((DWORD)draw_monster_num >= MAXMONSTERS) { // app_fatal("Draw Monster Clipped: tried to draw illegal monster %d", draw_monster_num); break; } pMonster = &monster[draw_monster_num]; if (!(pMonster->_mFlags & MFLAG_HIDDEN)) { if (pMonster->MType == NULL) { // app_fatal("Draw Monster \"%s\" Clipped: uninitialized monster", pMonster->mName); break; } px = dx + pMonster->_mxoff - pMonster->MType->width2; py = dy + pMonster->_myoff; if (draw_monster_num == pcursmonst) { Cl2DrawOutlineSafe(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, 0, 8); } DrawClippedMonster(sx, sy, px, py, draw_monster_num, 0, 8); if (eflag && pMonster->_meflag) { scrollrt_draw_clipped_e_flag(pBuff - TILE_WIDTH, sx - 1, sy + 1, dx - TILE_WIDTH, dy); } } } while (0); } if (bFlag & BFLAG_DEAD_PLAYER) { DrawDeadPlayer(sx, sy, dx, dy, 0, 8, TRUE); } if (bPlr > 0) { do { p = bPlr - 1; if ((DWORD)p >= MAX_PLRS) { // app_fatal("draw player clipped: tried to draw illegal player %d", p); break; } pPlayer = &plr[p]; px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2; py = dy + pPlayer->_pyoff; DrawClippedPlayer(bPlr - 1, sx, sy, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, 0, 8); if (eflag && pPlayer->_peflag != 0) { if (pPlayer->_peflag == 2) { scrollrt_draw_clipped_e_flag(pBuff - (BUFFER_WIDTH * TILE_HEIGHT / 2 + TILE_WIDTH + TILE_WIDTH / 2), sx - 2, sy + 1, dx - (TILE_WIDTH + TILE_WIDTH / 2), dy - TILE_HEIGHT / 2); } scrollrt_draw_clipped_e_flag(pBuff - TILE_WIDTH, sx - 1, sy + 1, dx - TILE_WIDTH, dy); } } while (0); } if (nMon > 0 && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag)) { do { draw_monster_num = nMon - 1; if ((DWORD)draw_monster_num >= MAXMONSTERS) { // app_fatal("Draw Monster Clipped: tried to draw illegal monster %d", draw_monster_num); break; } pMonster = &monster[draw_monster_num]; if (!(pMonster->_mFlags & MFLAG_HIDDEN)) { if (pMonster->MType == NULL) { // app_fatal("Draw Monster \"%s\" Clipped: uninitialized monster", pMonster->mName); break; } px = dx + pMonster->_mxoff - pMonster->MType->width2; py = dy + pMonster->_myoff; if (draw_monster_num == pcursmonst) { Cl2DrawOutlineSafe(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, 0, 8); } DrawClippedMonster(sx, sy, px, py, draw_monster_num, 0, 8); if (eflag && pMonster->_meflag) { scrollrt_draw_clipped_e_flag(pBuff - TILE_WIDTH, sx - 1, sy + 1, dx - TILE_WIDTH, dy); } } } while (0); } if (bFlag & BFLAG_MISSILE) { DrawClippedMissile(sx, sy, dx, dy, 0, 8, FALSE); } if (bObj != 0 && light_table_index < lightmax) { DrawClippedObject(sx, sy, dx, dy, FALSE, 0, 8); } if (bItem != 0) { do { pItem = &item[bItem - 1]; if (pItem->_iPostDraw) { /// ASSERT: assert((unsigned char)bItem <= MAXITEMS); #ifdef HELLFIRE if (bItem > MAXITEMS || bItem < 0) #else if ((BYTE)bItem > MAXITEMS) #endif break; pCelBuff = pItem->_iAnimData; if (pCelBuff == NULL) { // app_fatal("Draw Item \"%s\" Clipped 2: NULL Cel Buffer", pItem->_iIName); break; } pFrameTable = (DWORD *)pCelBuff; nCel = pItem->_iAnimFrame; if (pItem->_iAnimFrame < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { /* app_fatal( "Draw Clipped \"%s\" Item 2: frame %d of %d, item type==%d", pItem->_iIName, nCel, pFrameTable[0], pItem->_itype); */ break; } px = dx - pItem->_iAnimWidth2; if (bItem - 1 == pcursitem #ifdef HELLFIRE || AutoMapShowItems == TRUE #endif ) { CelBlitOutlineSafe(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, 0, 8); } CelDrawLightSafe(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, 0, 8); } } while (0); } if (bArch != 0) { cel_transparency_active = TransList[bMap]; CelClippedBlitLightTransSafe(pBuff, pSpecialCels, bArch, 64, 0, 8); } } /** * @brief Render a row of tiles * @param x dPiece coordinate * @param y dPiece coordinate * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param chunks tile width of row * @param eflag is it an even (0) or odd (1) row */ static void scrollrt_draw_lower(int x, int y, int sx, int sy, int chunks, BOOL eflag) { int i, j; BYTE *dst; MICROS *pMap; /// ASSERT: assert(gpBuffer); pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; if (eflag) { if ((DWORD)y < MAXDUNY && (DWORD)x < MAXDUNX) { level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; if (level_piece_id != 0) { dst = &gpBuffer[sx + TILE_WIDTH / 2 + PitchTbl[sy]]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); arch_draw_type = 2; level_cel_block = pMap->mt[1]; if (level_cel_block != 0) { drawLowerScreen(dst); } arch_draw_type = 0; dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[3]; if (level_cel_block != 0) { drawLowerScreen(dst); } dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[5]; if (level_cel_block != 0) { drawLowerScreen(dst); } dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[7]; if (level_cel_block != 0) { drawLowerScreen(dst); } dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[9]; if (level_cel_block != 0) { drawLowerScreen(dst); } dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[11]; if (level_cel_block != 0 && leveltype == DTYPE_HELL) { drawLowerScreen(dst); } scrollrt_draw_clipped_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, FALSE); } else { world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]); } } x++; y--; sx += TILE_WIDTH; pMap++; chunks--; } j = chunks; while (j-- != 0) { if (y < 0 || x >= MAXDUNX) { break; } if (y < MAXDUNY && x >= 0) { level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; if (level_piece_id == 0) { world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]); } else { dst = &gpBuffer[sx + PitchTbl[sy]]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); arch_draw_type = 1; level_cel_block = pMap->mt[0]; if (level_cel_block != 0) { drawLowerScreen(dst); } arch_draw_type = 2; level_cel_block = pMap->mt[1]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } arch_draw_type = 0; for (i = 2; i < MicroTileLen; i += 2) { dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[i]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[i + 1]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } } scrollrt_draw_clipped_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, TRUE); } } x++; y--; sx += TILE_WIDTH; pMap++; } if (eflag && (DWORD)y < MAXDUNY && (DWORD)x < MAXDUNX) { level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; if (level_piece_id == 0) { world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]); } else { dst = &gpBuffer[sx + PitchTbl[sy]]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); arch_draw_type = 1; level_cel_block = pMap->mt[0]; if (level_cel_block != 0) { drawLowerScreen(dst); } arch_draw_type = 0; dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[2]; if (level_cel_block != 0) { drawLowerScreen(dst); } dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[4]; if (level_cel_block != 0) { drawLowerScreen(dst); } dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[6]; if (level_cel_block != 0) { drawLowerScreen(dst); } dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[8]; if (level_cel_block != 0) { drawLowerScreen(dst); } dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[10]; if (level_cel_block != 0 && leveltype == DTYPE_HELL) { drawLowerScreen(dst); } scrollrt_draw_clipped_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, FALSE); } } } static void scrollrt_draw_clipped_dungeon_2(BYTE *pBuff, int sx, int sy, int row, int CelSkip, int dx, int dy, BOOL eflag); /** * This variant checks for of screen element on the lower screen * This function it self causes rendering issues since it will render on top of objects on the other side of walls * @brief Re render tile to workaround sorting issues with players walking east/west * @param pBuff Pointer to output buffer at location sx,sy * @param y dPiece coordinate * @param x dPiece coordinate * @param row The current row being rendered * @param CelSkip chunks of cell to skip * @param sx Back buffer coordinate * @param sy Back buffer coordinate */ static void scrollrt_draw_clipped_e_flag_2(BYTE *pBuff, int x, int y, int row, int CelSkip, int sx, int sy) { int lti_old, cta_old, lpi_old; BYTE *dst; MICROS *pMap; lti_old = light_table_index; cta_old = cel_transparency_active; lpi_old = level_piece_id; level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; dst = &pBuff[BUFFER_WIDTH * TILE_HEIGHT * row]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; switch (row) { case 0: level_cel_block = pMap->mt[2]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[3]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } case 1: dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[4]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[5]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } case 2: dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[6]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[7]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } case 3: dst -= BUFFER_WIDTH * TILE_HEIGHT; level_cel_block = pMap->mt[8]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[9]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } break; } if (CelSkip < 8) { scrollrt_draw_clipped_dungeon_2(pBuff, x, y, row, CelSkip, sx, sy, FALSE); } light_table_index = lti_old; cel_transparency_active = cta_old; level_piece_id = lpi_old; } /** * This variant checks for of screen element on the lower screen * @brief Render object sprites, skip offscreen parts for lower screen * @param pBuff where to render to with sx,sy already applied * @param sx dPiece coordinate * @param sy dPiece coordinate * @param row The current row being rendered * @param CelSkip chunks of cell to skip * @param dx Back buffer coordinate * @param dy Back buffer coordinate * @param eflag Should the sorting workaround be applied */ static void scrollrt_draw_clipped_dungeon_2(BYTE *pBuff, int sx, int sy, int row, int CelSkip, int dx, int dy, BOOL eflag) { int px, py, nCel, nMon, negMon, p; char bFlag, bDead, bObj, bItem, bPlr, bArch, bMap, negPlr, dd; DeadStruct *pDeadGuy; ItemStruct *pItem; PlayerStruct *pPlayer; MonsterStruct *pMonster; BYTE *pCelBuff; DWORD *pFrameTable; /// ASSERT: assert((DWORD)sx < MAXDUNX); /// ASSERT: assert((DWORD)sy < MAXDUNY); bFlag = dFlags[sx][sy]; bDead = dDead[sx][sy]; bObj = dObject[sx][sy]; bItem = dItem[sx][sy]; bPlr = dPlayer[sx][sy]; bArch = dSpecial[sx][sy]; bMap = dTransVal[sx][sy]; nMon = dMonster[sx][sy]; /// ASSERT: assert((DWORD)(sy-1) < MAXDUNY); negPlr = dPlayer[sx][sy - 1]; negMon = dMonster[sx][sy - 1]; if (visiondebug && bFlag & BFLAG_LIT) { CelClippedBlitSafe(pBuff, pSquareCel, 1, 64, CelSkip, 8); } if (MissilePreFlag && bFlag & BFLAG_MISSILE) { DrawClippedMissile(sx, sy, dx, dy, CelSkip, 8, TRUE); } if (light_table_index < lightmax) { if (bDead != 0) { do { pDeadGuy = &dead[(bDead & 0x1F) - 1]; dd = (bDead >> 5) & 7; px = dx - pDeadGuy->_deadWidth2; pCelBuff = pDeadGuy->_deadData[dd]; /// ASSERT: assert(pDeadGuy->_deadData[dd] != NULL); if (pCelBuff == NULL) break; pFrameTable = (DWORD *)pDeadGuy->_deadData[dd]; nCel = pDeadGuy->_deadFrame; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Clipped dead sub2: frame %d of %d, deadnum==%d", nCel, pFrameTable[0], (bDead & 0x1F) - 1); break; } if (pDeadGuy->_deadtrans != 0) { Cl2DrawLightTblSafe(px, dy, pCelBuff, nCel, pDeadGuy->_deadWidth, CelSkip, 8, pDeadGuy->_deadtrans); } else { Cl2DrawLightSafe(px, dy, pCelBuff, pDeadGuy->_deadFrame, pDeadGuy->_deadWidth, CelSkip, 8); } } while (0); } if (bObj != 0) { DrawClippedObject(sx, sy, dx, dy, TRUE, CelSkip, 8); } } if (bItem != 0) { do { pItem = &item[bItem - 1]; if (!pItem->_iPostDraw) { /// ASSERT: assert((unsigned char)bItem <= MAXITEMS); #ifdef HELLFIRE if (bItem > MAXITEMS || bItem < 0) #else if ((BYTE)bItem > MAXITEMS) #endif break; pCelBuff = pItem->_iAnimData; if (pCelBuff == NULL) { // app_fatal("Draw Item \"%s\" Clipped 3: NULL Cel Buffer", pItem->_iIName); break; } pFrameTable = (DWORD *)pCelBuff; nCel = pItem->_iAnimFrame; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { /* app_fatal( "Draw Clipped \"%s\" Item 3: frame %d of %d, item type==%d", pItem->_iIName, nCel, pFrameTable[0], pItem->_itype); */ break; } px = dx - pItem->_iAnimWidth2; if (bItem - 1 == pcursitem #ifdef HELLFIRE || AutoMapShowItems == TRUE #endif ) { CelBlitOutlineSafe(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, CelSkip, 8); } CelDrawLightSafe(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, CelSkip, 8); } } while (0); } if (bFlag & BFLAG_PLAYERLR) { do { p = -(negPlr + 1); #ifdef HELLFIRE if (p >= MAX_PLRS) { #else if ((DWORD)p >= MAX_PLRS) { #endif // app_fatal("draw player clipped: tried to draw illegal player %d", p); break; } pPlayer = &plr[p]; px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2; py = dy + pPlayer->_pyoff; DrawClippedPlayer(p, sx, sy - 1, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, CelSkip, 8); if (eflag && pPlayer->_peflag != 0) { if (pPlayer->_peflag == 2) { scrollrt_draw_clipped_e_flag_2(pBuff - (BUFFER_WIDTH * TILE_HEIGHT / 2 + TILE_WIDTH + TILE_WIDTH / 2), sx - 2, sy + 1, row, CelSkip, dx - (TILE_WIDTH + TILE_WIDTH / 2), dy - TILE_HEIGHT / 2); } scrollrt_draw_clipped_e_flag_2(pBuff - TILE_WIDTH, sx - 1, sy + 1, row, CelSkip, dx - TILE_WIDTH, dy); } } while (0); } if (bFlag & BFLAG_MONSTLR && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag) && negMon < 0) { do { draw_monster_num = -(negMon + 1); #ifdef HELLFIRE if (draw_monster_num >= MAXMONSTERS) { #else if ((DWORD)draw_monster_num >= MAXMONSTERS) { #endif // app_fatal("Draw Monster Clipped: tried to draw illegal monster %d", draw_monster_num); break; } pMonster = &monster[draw_monster_num]; if (!(pMonster->_mFlags & MFLAG_HIDDEN)) { if (pMonster->MType == NULL) { // app_fatal("Draw Monster \"%s\" Clipped: uninitialized monster", pMonster->mName); break; } px = dx + pMonster->_mxoff - pMonster->MType->width2; py = dy + pMonster->_myoff; if (draw_monster_num == pcursmonst) { Cl2DrawOutlineSafe(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, CelSkip, 8); } DrawClippedMonster(sx, sy, px, py, draw_monster_num, CelSkip, 8); if (eflag && !pMonster->_meflag) { scrollrt_draw_clipped_e_flag_2(pBuff - TILE_WIDTH, sx - 1, sy + 1, row, CelSkip, dx - TILE_WIDTH, dy); } } } while (0); } if (bFlag & BFLAG_DEAD_PLAYER) { DrawDeadPlayer(sx, sy, dx, dy, CelSkip, 8, TRUE); } if (bPlr > 0) { do { p = bPlr - 1; if ((DWORD)p >= MAX_PLRS) { // app_fatal("draw player clipped: tried to draw illegal player %d", p); break; } pPlayer = &plr[p]; px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2; py = dy + pPlayer->_pyoff; DrawClippedPlayer(p, sx, sy, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, CelSkip, 8); if (eflag && pPlayer->_peflag != 0) { if (pPlayer->_peflag == 2) { scrollrt_draw_clipped_e_flag_2(pBuff - (BUFFER_WIDTH * TILE_HEIGHT / 2 + TILE_WIDTH + TILE_WIDTH / 2), sx - 2, sy + 1, row, CelSkip, dx - (TILE_WIDTH + TILE_WIDTH / 2), dy - TILE_HEIGHT / 2); } scrollrt_draw_clipped_e_flag_2(pBuff - TILE_WIDTH, sx - 1, sy + 1, row, CelSkip, dx - TILE_WIDTH, dy); } } while (0); } if (nMon > 0 && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag)) { do { draw_monster_num = nMon - 1; if ((DWORD)draw_monster_num >= MAXMONSTERS) { // app_fatal("Draw Monster Clipped: tried to draw illegal monster %d", draw_monster_num); break; } pMonster = &monster[draw_monster_num]; if (!(pMonster->_mFlags & MFLAG_HIDDEN)) { if (pMonster->MType == NULL) { // app_fatal("Draw Monster \"%s\" Clipped: uninitialized monster", pMonster->mName); break; } px = dx + pMonster->_mxoff - pMonster->MType->width2; py = dy + pMonster->_myoff; if (draw_monster_num == pcursmonst) { Cl2DrawOutlineSafe(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, CelSkip, 8); } DrawClippedMonster(sx, sy, px, py, draw_monster_num, CelSkip, 8); if (eflag && !pMonster->_meflag) { scrollrt_draw_clipped_e_flag_2(pBuff - TILE_WIDTH, sx - 1, sy + 1, row, CelSkip, dx - TILE_WIDTH, dy); } } } while (0); } if (bFlag & BFLAG_MISSILE) { DrawClippedMissile(sx, sy, dx, dy, CelSkip, 8, FALSE); } if (bObj != 0 && light_table_index < lightmax) { DrawClippedObject(sx, sy, dx, dy, FALSE, CelSkip, 8); } if (bItem != 0) { do { pItem = &item[bItem - 1]; if (pItem->_iPostDraw) { /// ASSERT: assert((unsigned char)bItem <= MAXITEMS); #ifdef HELLFIRE if (bItem > MAXITEMS || bItem < 0) #else if ((BYTE)bItem > MAXITEMS) #endif break; pCelBuff = pItem->_iAnimData; if (pCelBuff == NULL) { // app_fatal("Draw Item \"%s\" Clipped 4: NULL Cel Buffer", pItem->_iIName); break; } pFrameTable = (DWORD *)pCelBuff; nCel = pItem->_iAnimFrame; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { /* app_fatal( "Draw Clipped \"%s\" Item 4: frame %d of %d, item type==%d", pItem->_iIName, nCel, pFrameTable[0], pItem->_itype); */ break; } px = dx - pItem->_iAnimWidth2; if (bItem - 1 == pcursitem #ifdef HELLFIRE || AutoMapShowItems == TRUE #endif ) { CelBlitOutlineSafe(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, CelSkip, 8); } CelDrawLightSafe(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, CelSkip, 8); } } while (0); } if (bArch != 0) { cel_transparency_active = TransList[bMap]; CelClippedBlitLightTransSafe(pBuff, pSpecialCels, bArch, 64, CelSkip, 8); } } /** * @brief Render a row of tile, checking for overdrawing on lower part of screen * @param x dPiece coordinate * @param y dPiece coordinate * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param chunks tile width of row * @param row current row being rendered * @param eflag is it an even (0) or odd (1) row */ static void scrollrt_draw_lower_2(int x, int y, int sx, int sy, int chunks, int row, BOOL eflag) { int i, j, CelSkip; BYTE *dst; MICROS *pMap; /// ASSERT: assert(gpBuffer); pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; CelSkip = 2 * row + 2; if (eflag) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; if (level_piece_id != 0) { dst = &gpBuffer[sx - (BUFFER_WIDTH * TILE_HEIGHT - 32) + PitchTbl[sy]]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); for (i = 0; i < (MicroTileLen >> 1) - 1; i++) { if (row <= i) { level_cel_block = pMap->mt[2 * i + 3]; if (level_cel_block != 0) { drawLowerScreen(dst); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; } if (CelSkip < 8) { scrollrt_draw_clipped_dungeon_2(&gpBuffer[sx + PitchTbl[sy] - BUFFER_WIDTH * TILE_HEIGHT / 2 * CelSkip], x, y, row, CelSkip, sx, sy, FALSE); } } } x++; y--; sx += TILE_WIDTH; chunks--; pMap++; } j = chunks; while (j-- != 0) { if (x >= MAXDUNX || y < 0) { break; } if (y < MAXDUNY && x >= 0) { level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; if (level_piece_id != 0) { dst = &gpBuffer[sx - BUFFER_WIDTH * TILE_HEIGHT + PitchTbl[sy]]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); i = 0; while (i < (MicroTileLen >> 1) - 1) { if (row <= i) { level_cel_block = pMap->mt[2 * i + 2]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[2 * i + 3]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } } i++; dst -= BUFFER_WIDTH * TILE_HEIGHT; } if (CelSkip < 8) { scrollrt_draw_clipped_dungeon_2(&gpBuffer[sx + PitchTbl[sy] - BUFFER_WIDTH * TILE_HEIGHT * (row + 1)], x, y, row, CelSkip, sx, sy, TRUE); } } } x++; y--; sx += TILE_WIDTH; pMap++; } if (eflag) { if ((DWORD)y < MAXDUNY && (DWORD)x < MAXDUNX) { level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; if (level_piece_id != 0) { dst = &gpBuffer[sx - BUFFER_WIDTH * TILE_HEIGHT + PitchTbl[sy]]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); for (i = 0; i < (MicroTileLen >> 1) - 1; i++) { if (row <= i) { level_cel_block = pMap->mt[2 * i + 2]; if (level_cel_block != 0) { drawLowerScreen(dst); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; } if (CelSkip < 8) { scrollrt_draw_clipped_dungeon_2(&gpBuffer[sx + PitchTbl[sy] - BUFFER_WIDTH * TILE_HEIGHT / 2 * CelSkip], x, y, row, CelSkip, sx, sy, FALSE); } } } } } static void scrollrt_draw_dungeon(BYTE *pBuff, int sx, int sy, int row, int CelCap, int dx, int dy, BOOL eflag); /** * This variant checks for of screen element on the upper screen * This function it self causes rendering issues since it will render on top of objects on the other side of walls * @brief Re render tile to workaround sorting issues with players walking east/west * @param pBuff Pointer to output buffer at location sx,sy * @param y dPiece coordinate * @param x dPiece coordinate * @param row The current row being rendered * @param CelCap chunks of cell to skip * @param sx Back buffer coordinate * @param sy Back buffer coordinate */ static void scrollrt_draw_e_flag(BYTE *pBuff, int x, int y, int row, int CelCap, int sx, int sy) { int i, lti_old, cta_old, lpi_old; BYTE *dst; MICROS *pMap; lti_old = light_table_index; cta_old = cel_transparency_active; lpi_old = level_piece_id; level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; dst = pBuff; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; arch_draw_type = 1; level_cel_block = pMap->mt[0]; if (level_cel_block != 0) { drawUpperScreen(dst); } arch_draw_type = 2; level_cel_block = pMap->mt[1]; if (level_cel_block != 0) { drawUpperScreen(dst + TILE_WIDTH / 2); } arch_draw_type = 0; for (i = 1; i < (MicroTileLen >> 1) - 1; i++) { dst -= BUFFER_WIDTH * TILE_HEIGHT; if (row >= i) { level_cel_block = pMap->mt[2 * i]; if (level_cel_block != 0) { drawUpperScreen(dst); } level_cel_block = pMap->mt[2 * i + 1]; if (level_cel_block != 0) { drawUpperScreen(dst + TILE_WIDTH / 2); } } } scrollrt_draw_dungeon(pBuff, x, y, row, CelCap, sx, sy, FALSE); light_table_index = lti_old; cel_transparency_active = cta_old; level_piece_id = lpi_old; } /** * @brief Render object sprites, skip offscreen parts for upper screen * @param pBuff where to render to with sx,sx already applied * @param sx dPiece coordinate * @param sy dPiece coordinate * @param row The current row being rendered * @param CelCap chunks of cell to skip * @param dx Back buffer coordinate * @param dy Back buffer coordinate * @param eflag Should the sorting workaround be applied */ static void scrollrt_draw_dungeon(BYTE *pBuff, int sx, int sy, int row, int CelCap, int dx, int dy, BOOL eflag) { int px, py, nCel, nMon, negMon, p; char bFlag, bDead, bObj, bItem, bPlr, bArch, bMap, negPlr, dd; DeadStruct *pDeadGuy; ItemStruct *pItem; PlayerStruct *pPlayer; MonsterStruct *pMonster; BYTE *pCelBuff; DWORD *pFrameTable; /// ASSERT: assert((DWORD)sx < MAXDUNX); /// ASSERT: assert((DWORD)sy < MAXDUNY); bFlag = dFlags[sx][sy]; bDead = dDead[sx][sy]; bObj = dObject[sx][sy]; bItem = dItem[sx][sy]; bPlr = dPlayer[sx][sy]; bArch = dSpecial[sx][sy]; bMap = dTransVal[sx][sy]; nMon = dMonster[sx][sy]; /// ASSERT: assert((DWORD)(sy-1) < MAXDUNY); negPlr = dPlayer[sx][sy - 1]; negMon = dMonster[sx][sy - 1]; if (visiondebug && bFlag & BFLAG_LIT) { CelClippedBlit(pBuff, pSquareCel, 1, 64, 0, CelCap); } if (MissilePreFlag && bFlag & BFLAG_MISSILE) { DrawMissile(sx, sy, dx, dy, 0, CelCap, TRUE); } if (light_table_index < lightmax) { if (bDead != 0) { do { pDeadGuy = &dead[(bDead & 0x1F) - 1]; dd = (bDead >> 5) & 7; px = dx - pDeadGuy->_deadWidth2; pCelBuff = pDeadGuy->_deadData[dd]; /// ASSERT: assert(pDeadGuy->_deadData[dd] != NULL); if (pCelBuff == NULL) break; pFrameTable = (DWORD *)pDeadGuy->_deadData[dd]; nCel = pDeadGuy->_deadFrame; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Unclipped dead: frame %d of %d, deadnum==%d", nCel, pFrameTable[0], (bDead & 0x1F) - 1); break; } if (pDeadGuy->_deadtrans != 0) { Cl2DrawLightTbl(px, dy, pCelBuff, nCel, pDeadGuy->_deadWidth, 0, CelCap, pDeadGuy->_deadtrans); } else { Cl2DrawLight(px, dy, pCelBuff, pDeadGuy->_deadFrame, pDeadGuy->_deadWidth, 0, CelCap); } } while (0); } if (bObj != 0) { DrawObject(sx, sy, dx, dy, TRUE, 0, CelCap); } } if (bItem != 0) { do { pItem = &item[bItem - 1]; if (!pItem->_iPostDraw) { /// ASSERT: assert((unsigned char)bItem <= MAXITEMS); #ifdef HELLFIRE if (bItem > MAXITEMS || bItem < 0) #else if ((BYTE)bItem > MAXITEMS) #endif break; pCelBuff = pItem->_iAnimData; if (pCelBuff == NULL) { // app_fatal("Draw Item \"%s\" 1: NULL Cel Buffer", pItem->_iIName); break; } pFrameTable = (DWORD *)pCelBuff; nCel = pItem->_iAnimFrame; if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) { // app_fatal("Draw \"%s\" Item 1: frame %d of %d, item type==%d", pItem->_iIName, nCel, pFrameTable[0], pItem->_itype); break; } px = dx - pItem->_iAnimWidth2; if (bItem - 1 == pcursitem #ifdef HELLFIRE || AutoMapShowItems == TRUE #endif ) { CelBlitOutline(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, 0, CelCap); } CelClippedDrawLight(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, 0, CelCap); } } while (0); } if (bFlag & BFLAG_PLAYERLR) { do { p = -(negPlr + 1); #ifdef HELLFIRE if (p >= MAX_PLRS) { #else if ((DWORD)p >= MAX_PLRS) { #endif // app_fatal("draw player: tried to draw illegal player %d", p); break; } pPlayer = &plr[p]; px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2; py = dy + pPlayer->_pyoff; DrawPlayer(p, sx, sy - 1, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, 0, CelCap); if (eflag && pPlayer->_peflag != 0) { if (pPlayer->_peflag == 2) { scrollrt_draw_e_flag(pBuff - (BUFFER_WIDTH * TILE_HEIGHT / 2 + TILE_WIDTH + TILE_WIDTH / 2), sx - 2, sy + 1, row, CelCap, dx - (TILE_WIDTH + TILE_WIDTH / 2), dy - TILE_HEIGHT / 2); } scrollrt_draw_e_flag(pBuff - TILE_WIDTH, sx - 1, sy + 1, row, CelCap, dx - TILE_WIDTH, dy); } } while (0); } if (bFlag & BFLAG_MONSTLR && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag) && negMon < 0) { do { draw_monster_num = -(negMon + 1); #ifdef HELLFIRE if (draw_monster_num >= MAXMONSTERS) { #else if ((DWORD)draw_monster_num >= MAXMONSTERS) { #endif // app_fatal("Draw Monster: tried to draw illegal monster %d", draw_monster_num); break; } pMonster = &monster[draw_monster_num]; if (!(pMonster->_mFlags & MFLAG_HIDDEN)) { if (pMonster->MType == NULL) { // app_fatal("Draw Monster \"%s\": uninitialized monster", pMonster->mName); break; } px = dx + pMonster->_mxoff - pMonster->MType->width2; py = dy + pMonster->_myoff; if (draw_monster_num == pcursmonst) { Cl2DrawOutline(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, 0, CelCap); } DrawMonster(sx, sy, px, py, draw_monster_num, 0, CelCap); if (eflag && !pMonster->_meflag) { scrollrt_draw_e_flag(pBuff - TILE_WIDTH, sx - 1, sy + 1, row, CelCap, dx - TILE_WIDTH, dy); } } } while (0); } if (bFlag & BFLAG_DEAD_PLAYER) { DrawDeadPlayer(sx, sy, dx, dy, 0, CelCap, FALSE); } if (bPlr > 0) { do { p = bPlr - 1; #ifdef HELLFIRE if (p >= MAX_PLRS) { #else if ((DWORD)p >= MAX_PLRS) { #endif // app_fatal("draw player: tried to draw illegal player %d", p); break; } pPlayer = &plr[p]; px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2; py = dy + pPlayer->_pyoff; DrawPlayer(p, sx, sy, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, 0, CelCap); if (eflag && pPlayer->_peflag != 0) { if (pPlayer->_peflag == 2) { scrollrt_draw_e_flag(pBuff - (BUFFER_WIDTH * TILE_HEIGHT / 2 + TILE_WIDTH + TILE_WIDTH / 2), sx - 2, sy + 1, row, CelCap, dx - (TILE_WIDTH + TILE_WIDTH / 2), dy - TILE_HEIGHT / 2); } scrollrt_draw_e_flag(pBuff - TILE_WIDTH, sx - 1, sy + 1, row, CelCap, dx - TILE_WIDTH, dy); } } while (0); } if (nMon > 0 && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag)) { do { draw_monster_num = nMon - 1; if ((DWORD)draw_monster_num >= MAXMONSTERS) { // app_fatal("Draw Monster: tried to draw illegal monster %d", draw_monster_num); break; } pMonster = &monster[draw_monster_num]; if (!(pMonster->_mFlags & MFLAG_HIDDEN)) { if (pMonster->MType == NULL) { // app_fatal("Draw Monster \"%s\": uninitialized monster", pMonster->mName); break; } px = dx + pMonster->_mxoff - pMonster->MType->width2; py = dy + pMonster->_myoff; if (draw_monster_num == pcursmonst) { Cl2DrawOutline(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, 0, CelCap); } DrawMonster(sx, sy, px, py, draw_monster_num, 0, CelCap); if (eflag && !pMonster->_meflag) { scrollrt_draw_e_flag(pBuff - TILE_WIDTH, sx - 1, sy + 1, row, CelCap, dx - TILE_WIDTH, dy); } } } while (0); } if (bFlag & BFLAG_MISSILE) { DrawMissile(sx, sy, dx, dy, 0, CelCap, FALSE); } if (bObj != 0 && light_table_index < lightmax) { DrawObject(sx, sy, dx, dy, FALSE, 0, CelCap); } if (bItem != 0) { do { pItem = &item[bItem - 1]; if (pItem->_iPostDraw) { /// ASSERT: assert((unsigned char)bItem <= MAXITEMS); #ifdef HELLFIRE if (bItem > MAXITEMS || bItem < 0) #else if ((BYTE)bItem > MAXITEMS) #endif break; pCelBuff = pItem->_iAnimData; if (pCelBuff == NULL) { // app_fatal("Draw Item \"%s\" 2: NULL Cel Buffer", pItem->_iIName); break; } pFrameTable = (DWORD *)pCelBuff; nCel = pItem->_iAnimFrame; if (nCel < 1 || ((DWORD *)pCelBuff)[0] > 50 || pItem->_iAnimFrame > ((int *)pCelBuff)[0]) { // app_fatal("Draw \"%s\" Item 2: frame %d of %d, item type==%d", pItem->_iIName, nCel, pFrameTable[0], pItem->_itype); break; } px = dx - pItem->_iAnimWidth2; if (bItem - 1 == pcursitem #ifdef HELLFIRE || AutoMapShowItems == TRUE #endif ) { CelBlitOutline(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, 0, CelCap); } CelClippedDrawLight(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, 0, CelCap); } } while (0); } if (bArch != 0) { cel_transparency_active = TransList[bMap]; CelClippedBlitLightTrans(pBuff, pSpecialCels, bArch, 64, 0, CelCap); } } /** * @brief Render a row of tile, checking for overdrawing on upper part of screen * @param x dPiece coordinate * @param y dPiece coordinate * @param sx Back buffer coordinate * @param sy Back buffer coordinate * @param chunks tile width of row * @param row current row being rendered * @param eflag is it an even (0) or odd (1) row */ static void scrollrt_draw_upper(int x, int y, int sx, int sy, int chunks, int row, BOOL eflag) { int i, j, CelCap; BYTE *dst; MICROS *pMap; /// ASSERT: assert(gpBuffer); pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; CelCap = 2 * row + 2; if (CelCap > 8) { CelCap = 8; } if (eflag) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; if (level_piece_id != 0) { dst = &gpBuffer[sx + TILE_HEIGHT + PitchTbl[sy]]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); if (row >= 0) { level_cel_block = pMap->mt[1]; if (level_cel_block != 0) { arch_draw_type = 2; drawUpperScreen(dst); arch_draw_type = 0; } } dst -= BUFFER_WIDTH * TILE_HEIGHT; if (row >= 1) { level_cel_block = pMap->mt[3]; if (level_cel_block != 0) { drawUpperScreen(dst); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; if (row >= 2) { level_cel_block = pMap->mt[5]; if (level_cel_block != 0) { drawUpperScreen(dst); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; if (row >= 3) { level_cel_block = pMap->mt[7]; if (level_cel_block != 0) { drawUpperScreen(dst); } } scrollrt_draw_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelCap, sx, sy, FALSE); } else { world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]); } } x++; y--; sx += TILE_WIDTH; chunks--; pMap++; } for (j = 0; j < chunks; j++) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; if (level_piece_id != 0) { dst = &gpBuffer[sx + PitchTbl[sy]]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); arch_draw_type = 1; level_cel_block = pMap->mt[0]; if (level_cel_block != 0) { drawUpperScreen(dst); } arch_draw_type = 2; level_cel_block = pMap->mt[1]; if (level_cel_block != 0) { drawUpperScreen(dst + TILE_HEIGHT); } arch_draw_type = 0; for (i = 1; i < (MicroTileLen >> 1) - 1; i++) { dst -= BUFFER_WIDTH * TILE_HEIGHT; if (row >= i) { level_cel_block = pMap->mt[2 * i]; if (level_cel_block != 0) { drawUpperScreen(dst); } level_cel_block = pMap->mt[2 * i + 1]; if (level_cel_block != 0) { drawUpperScreen(dst + TILE_HEIGHT); } } } scrollrt_draw_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelCap, sx, sy, TRUE); } else { world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]); } } x++; y--; sx += TILE_WIDTH; pMap++; } if (eflag) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_piece_id = dPiece[x][y]; light_table_index = dLight[x][y]; if (level_piece_id != 0) { dst = &gpBuffer[sx + PitchTbl[sy]]; cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); arch_draw_type = 1; if (row >= 0) { level_cel_block = pMap->mt[0]; if (level_cel_block != 0) { drawUpperScreen(dst); } } arch_draw_type = 0; dst -= BUFFER_WIDTH * TILE_HEIGHT; if (row >= 1) { level_cel_block = pMap->mt[2]; if (level_cel_block != 0) { drawUpperScreen(dst); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; if (row >= 2) { level_cel_block = pMap->mt[4]; if (level_cel_block != 0) { drawUpperScreen(dst); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; if (row >= 3) { level_cel_block = pMap->mt[6]; if (level_cel_block != 0) { drawUpperScreen(dst); } } scrollrt_draw_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelCap, sx, sy, FALSE); } else { world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]); } } } } /** * @brief Configure render and process screen rows * @param x Center of view in dPiece coordinate * @param y Center of view in dPiece coordinate */ static void DrawGame(int x, int y) { int i, sx, sy, chunks, blocks; ViewDX = SCREEN_WIDTH; ViewDY = VIEWPORT_HEIGHT; ViewBX = SCREEN_WIDTH / TILE_WIDTH; ViewBY = VIEWPORT_HEIGHT / TILE_HEIGHT; sx = ScrollInfo._sxoff + SCREEN_X; sy = ScrollInfo._syoff + SCREEN_Y + (TILE_HEIGHT / 2 - 1); x -= SCREEN_WIDTH / TILE_WIDTH; y--; chunks = SCREEN_WIDTH / TILE_WIDTH; blocks = 8; if (chrflag || questlog) { x += 2; y -= 2; sx += (SCREEN_WIDTH / 2) - TILE_WIDTH / 2; chunks = (SCREEN_WIDTH / TILE_WIDTH) - 4; } if (invflag || sbookflag) { x += 2; y -= 2; sx -= TILE_WIDTH / 2; chunks = (SCREEN_WIDTH / TILE_WIDTH) - 4; } switch (ScrollInfo._sdir) { case SDIR_NE: chunks++; case SDIR_N: sy -= TILE_HEIGHT; x--; y--; #ifndef HELLFIRE blocks++; #endif break; case SDIR_SE: blocks++; case SDIR_E: chunks++; break; case SDIR_S: blocks++; break; case SDIR_SW: blocks++; case SDIR_W: sx -= TILE_WIDTH; x--; y++; chunks++; break; case SDIR_NW: sx -= TILE_WIDTH; sy -= TILE_HEIGHT; x -= 2; chunks++; blocks++; break; } /// ASSERT: assert(gpBuffer); gpBufEnd = &gpBuffer[PitchTbl[0 + SCREEN_Y]]; for (i = 0; i < 4; i++) { scrollrt_draw_upper(x, y, sx, sy, chunks, i, FALSE); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; scrollrt_draw_upper(x, y, sx, sy, chunks, i, TRUE); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } /// ASSERT: assert(gpBuffer); gpBufEnd = &gpBuffer[PitchTbl[VIEWPORT_HEIGHT + SCREEN_Y]]; for (i = 0; i < blocks; i++) { scrollrt_draw_lower(x, y, sx, sy, chunks, FALSE); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; scrollrt_draw_lower(x, y, sx, sy, chunks, TRUE); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } arch_draw_type = 0; for (i = 0; i < 4; i++) { scrollrt_draw_lower_2(x, y, sx, sy, chunks, i, FALSE); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; scrollrt_draw_lower_2(x, y, sx, sy, chunks, i, TRUE); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } } /** * @brief Configure render for zoomed view and process screen rows * @param x Center of view in dPiece coordinate * @param y Center of view in dPiece coordinate */ static void DrawZoom(int x, int y) { int i, sx, sy, chunks, blocks; int wdt, nSrcOff, nDstOff; ViewDX = ZOOM_WIDTH; ViewDY = ZOOM_HEIGHT - TILE_HEIGHT; ViewBX = ZOOM_WIDTH / TILE_WIDTH; ViewBY = (ZOOM_HEIGHT - TILE_HEIGHT) / TILE_HEIGHT; sx = ScrollInfo._sxoff + SCREEN_X; sy = ScrollInfo._syoff + SCREEN_Y - (TILE_HEIGHT / 2 + 1); x -= ZOOM_WIDTH / TILE_WIDTH; y--; chunks = ZOOM_WIDTH / TILE_WIDTH; blocks = 3; switch (ScrollInfo._sdir) { case SDIR_NE: chunks++; case SDIR_N: sy -= TILE_HEIGHT; x--; y--; blocks++; break; case SDIR_SE: blocks++; case SDIR_E: chunks++; break; case SDIR_S: blocks++; break; case SDIR_SW: blocks++; case SDIR_W: sx -= TILE_WIDTH; x--; y++; chunks++; break; case SDIR_NW: sx -= TILE_WIDTH; sy -= TILE_HEIGHT; x -= 2; chunks++; blocks++; break; } /// ASSERT: assert(gpBuffer); gpBufEnd = &gpBuffer[PitchTbl[-(TILE_HEIGHT / 2 + 1) + SCREEN_Y]]; for (i = 0; i < 4; i++) { scrollrt_draw_upper(x, y, sx, sy, chunks, i, FALSE); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; scrollrt_draw_upper(x, y, sx, sy, chunks, i, TRUE); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } /// ASSERT: assert(gpBuffer); gpBufEnd = &gpBuffer[PitchTbl[(VIEWPORT_HEIGHT - TILE_HEIGHT) / 2 + SCREEN_Y]]; for (i = 0; i < blocks; i++) { scrollrt_draw_lower(x, y, sx, sy, chunks, FALSE); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; scrollrt_draw_lower(x, y, sx, sy, chunks, TRUE); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } arch_draw_type = 0; for (i = 0; i < 4; i++) { scrollrt_draw_lower_2(x, y, sx, sy, chunks, i, FALSE); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; scrollrt_draw_lower_2(x, y, sx, sy, chunks, i, TRUE); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } if (chrflag || questlog) { nSrcOff = SCREENXY(TILE_WIDTH / 2 + SPANEL_WIDTH / 4, VIEWPORT_HEIGHT / 2 - (TILE_HEIGHT / 2 + 1)); nDstOff = SCREENXY(SPANEL_WIDTH, VIEWPORT_HEIGHT - 2); wdt = (SCREEN_WIDTH - SPANEL_WIDTH) / 2; } else if (invflag || sbookflag) { nSrcOff = SCREENXY(TILE_WIDTH / 2 + SPANEL_WIDTH / 4, VIEWPORT_HEIGHT / 2 - (TILE_HEIGHT / 2 + 1)); nDstOff = SCREENXY(0, VIEWPORT_HEIGHT - 2); wdt = (SCREEN_WIDTH - SPANEL_WIDTH) / 2; } else { nSrcOff = SCREENXY(TILE_WIDTH / 2, VIEWPORT_HEIGHT / 2 - (TILE_HEIGHT / 2 + 1)); nDstOff = SCREENXY(0, VIEWPORT_HEIGHT - 2); wdt = SCREEN_WIDTH / 2; } assert(gpBuffer); #ifdef USE_ASM __asm { mov esi, gpBuffer mov edx, nDstOff mov edi, esi mov ecx, nSrcOff add edi, edx add esi, ecx mov ebx, edi add ebx, BUFFER_WIDTH mov edx, (VIEWPORT_HEIGHT / 2) label1: mov ecx, wdt label2: mov al, [esi] inc esi mov ah, al mov [edi], ax mov [ebx], ax add edi, 2 add ebx, 2 dec ecx jnz label2 mov eax, BUFFER_WIDTH add eax, wdt sub esi, eax add eax, eax sub ebx, eax sub edi, eax dec edx jnz label1 } #else int hgt; BYTE *src, *dst1, *dst2; src = &gpBuffer[nSrcOff]; dst1 = &gpBuffer[nDstOff]; dst2 = &gpBuffer[nDstOff + BUFFER_WIDTH]; for (hgt = VIEWPORT_HEIGHT / 2; hgt != 0; hgt--, src -= BUFFER_WIDTH + wdt, dst1 -= 2 * (BUFFER_WIDTH + wdt), dst2 -= 2 * (BUFFER_WIDTH + wdt)) { for (i = wdt; i != 0; i--) { *dst1++ = *src; *dst1++ = *src; *dst2++ = *src; *dst2++ = *src; src++; } } #endif } /** * @brief Start rendering of screen, town variation * @param StartX Center of view in dPiece coordinate * @param StartY Center of view in dPiece coordinate */ void 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 != 0 && !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 != 0) { gmenu_draw_pause(); } DrawPlrMsg(); gmenu_draw(); doom_draw(); DrawInfoBox(); DrawLifeFlask(); DrawManaFlask(); } /** * @brief Render the whole screen black */ void ClearScreenBuffer() { lock_buf(3); assert(gpBuffer); #ifdef USE_ASM __asm { mov edi, gpBuffer add edi, SCREENXY(0, 0) mov edx, SCREEN_HEIGHT xor eax, eax zeroline: mov ecx, SCREEN_WIDTH / 4 rep stosd add edi, BUFFER_WIDTH - SCREEN_WIDTH dec edx jnz zeroline } #else int i; BYTE *dst; dst = &gpBuffer[SCREENXY(0, 0)]; for (i = 0; i < SCREEN_HEIGHT; i++, dst += BUFFER_WIDTH) { memset(dst, 0, SCREEN_WIDTH); } #endif unlock_buf(3); } #ifdef _DEBUG /** * @brief Scroll the screen when mouse is close to the edge */ void ScrollView() { BOOL scroll; if (pcurs >= CURSOR_FIRSTITEM) return; scroll = FALSE; if (MouseX < 20) { if (dmaxy - 1 <= ViewY || dminx >= ViewX) { if (dmaxy - 1 > ViewY) { ViewY++; scroll = TRUE; } if (dminx < ViewX) { ViewX--; scroll = TRUE; } } else { ViewY++; ViewX--; scroll = TRUE; } } if (MouseX > SCREEN_WIDTH - 20) { if (dmaxx - 1 <= ViewX || dminy >= ViewY) { if (dmaxx - 1 > ViewX) { ViewX++; scroll = TRUE; } if (dminy < ViewY) { ViewY--; scroll = TRUE; } } else { ViewY--; ViewX++; scroll = TRUE; } } if (MouseY < 20) { if (dminy >= ViewY || dminx >= ViewX) { if (dminy < ViewY) { ViewY--; scroll = TRUE; } if (dminx < ViewX) { ViewX--; scroll = TRUE; } } else { ViewX--; ViewY--; scroll = TRUE; } } if (MouseY > SCREEN_HEIGHT - 20) { if (dmaxy - 1 <= ViewY || dmaxx - 1 <= ViewX) { if (dmaxy - 1 > ViewY) { ViewY++; scroll = TRUE; } if (dmaxx - 1 > ViewX) { ViewX++; scroll = TRUE; } } else { ViewX++; ViewY++; scroll = TRUE; } } if (scroll) ScrollInfo._sdir = SDIR_NONE; } /** * @brief Initialize the FPS meter */ void EnableFrameCount() { frameflag = frameflag == 0; framestart = GetTickCount(); } /** * @brief Display the current average FPS over 1 sec */ static void DrawFPS() { DWORD tc, frames; char String[12]; HDC hdc; if (frameflag && gbActive) { frameend++; tc = GetTickCount(); frames = tc - framestart; if (tc - framestart >= 1000) { framestart = tc; framerate = 1000 * frameend / frames; 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 /** * @brief Update part of the screen from the back buffer * @param dwX Back buffer coordinate * @param dwY Back buffer coordinate * @param dwWdt Back buffer coordinate * @param dwHgt Back buffer coordinate */ static void DoBlitScreen(DWORD dwX, DWORD dwY, DWORD dwWdt, DWORD dwHgt) { int nSrcOff, nDstOff, nSrcWdt, nDstWdt; DWORD dwTicks; HRESULT hDDVal; RECT SrcRect; assert(!(dwX & 3)); assert(!(dwWdt & 3)); if (lpDDSBackBuf != NULL) { SrcRect.left = dwX + SCREEN_X; SrcRect.top = dwY + SCREEN_Y; SrcRect.right = SrcRect.left + dwWdt - 1; SrcRect.bottom = SrcRect.top + dwHgt - 1; /// ASSERT: assert(! gpBuffer); dwTicks = GetTickCount(); while (1) { hDDVal = lpDDSPrimary->BltFast(dwX, dwY, lpDDSBackBuf, &SrcRect, DDBLTFAST_WAIT); if (hDDVal == DD_OK) { break; } if (dwTicks - GetTickCount() > 5000) { break; } Sleep(1); if (hDDVal == DDERR_SURFACELOST) { return; } if (hDDVal != DDERR_WASSTILLDRAWING && hDDVal != DDERR_SURFACEBUSY) { break; } } if (hDDVal != DDERR_SURFACELOST && hDDVal != DDERR_WASSTILLDRAWING && hDDVal != DDERR_SURFACEBUSY && hDDVal != DD_OK) { DDErrMsg(hDDVal, 3596, "C:\\Src\\Diablo\\Source\\SCROLLRT.CPP"); } } else { nSrcOff = SCREENXY(dwX, dwY); nDstOff = dwX * (SCREEN_BPP / 8) + dwY * DDS_desc.lPitch; nSrcWdt = BUFFER_WIDTH - dwWdt; nDstWdt = DDS_desc.lPitch - dwWdt * (SCREEN_BPP / 8); dwWdt >>= 2; lock_buf(6); /// ASSERT: assert(gpBuffer); #if defined(USE_ASM) && !defined(RGBMODE) __asm { mov esi, gpBuffer mov edi, DDS_desc.lpSurface add esi, nSrcOff add edi, nDstOff mov eax, nSrcWdt mov ebx, nDstWdt mov edx, dwHgt blitline: mov ecx, dwWdt rep movsd add esi, eax add edi, ebx dec edx jnz blitline } #else int wdt, hgt; BYTE *src, *dst; src = &gpBuffer[nSrcOff]; dst = (BYTE *)DDS_desc.lpSurface + nDstOff; for (hgt = 0; hgt < dwHgt; hgt++, src += nSrcWdt, dst += nDstWdt) { for (wdt = 0; wdt < 4 * dwWdt; wdt++) { #ifndef RGBMODE *dst++ = *src++; #else PALETTEENTRY pal = system_palette[*src++]; dst[0] = pal.peBlue; dst[1] = pal.peGreen; dst[2] = pal.peRed; dst += 4; #endif } } #endif unlock_buf(6); } } /** * @brief Check render pipeline and blit individual screen parts * @param dwHgt Section of screen to update from top to bottom * @param draw_desc Render info box * @param draw_hp Render health bar * @param draw_mana Render mana bar * @param draw_sbar Render belt * @param draw_btn Render panel buttons */ static void DrawMain(int dwHgt, BOOL draw_desc, BOOL draw_hp, BOOL draw_mana, BOOL draw_sbar, BOOL draw_btn) { int ysize; DWORD dwTicks; BOOL retry; HRESULT hDDVal; ysize = dwHgt; if (!gbActive || lpDDSPrimary == NULL) { return; } if (lpDDSPrimary->IsLost() == DDERR_SURFACELOST) { if (lpDDSPrimary->Restore() != DD_OK) { return; } ResetPal(); ysize = SCREEN_HEIGHT; } if (lpDDSBackBuf == NULL) { retry = TRUE; dwTicks = GetTickCount(); while (1) { DDS_desc.dwSize = sizeof(DDS_desc); hDDVal = lpDDSPrimary->Lock(NULL, &DDS_desc, DDLOCK_WRITEONLY | DDLOCK_WAIT, NULL); if (hDDVal == DD_OK) { break; } if (dwTicks - GetTickCount() > 5000) { break; } Sleep(1); if (hDDVal == DDERR_SURFACELOST) { return; } if (hDDVal != DDERR_WASSTILLDRAWING && hDDVal != DDERR_SURFACEBUSY) { if (!retry || hDDVal != DDERR_GENERIC) { break; } retry = FALSE; j_dx_reinit(); ysize = SCREEN_HEIGHT; dwTicks = GetTickCount(); } } if (hDDVal == DDERR_SURFACELOST || hDDVal == DDERR_WASSTILLDRAWING || hDDVal == DDERR_SURFACEBUSY) { return; } if (hDDVal != DD_OK) { DDErrMsg(hDDVal, 3707, "C:\\Src\\Diablo\\Source\\SCROLLRT.CPP"); } } /// ASSERT: assert(ysize >= 0 && ysize <= 480); // SCREEN_HEIGHT if (ysize > 0) { DoBlitScreen(0, 0, SCREEN_WIDTH, ysize); } if (ysize < SCREEN_HEIGHT) { if (draw_sbar) { DoBlitScreen(PANEL_LEFT + 204, PANEL_TOP + 5, 232, 28); } if (draw_desc) { DoBlitScreen(PANEL_LEFT + 176, PANEL_TOP + 46, 288, 60); } if (draw_mana) { DoBlitScreen(PANEL_LEFT + 460, PANEL_TOP, 88, 72); DoBlitScreen(PANEL_LEFT + 564, PANEL_TOP + 64, 56, 56); } if (draw_hp) { DoBlitScreen(PANEL_LEFT + 96, PANEL_TOP, 88, 72); } if (draw_btn) { DoBlitScreen(PANEL_LEFT + 8, PANEL_TOP + 5, 72, 119); DoBlitScreen(PANEL_LEFT + 556, PANEL_TOP + 5, 72, 48); if (gbMaxPlayers > 1) { DoBlitScreen(PANEL_LEFT + 84, PANEL_TOP + 91, 36, 32); DoBlitScreen(PANEL_LEFT + 524, PANEL_TOP + 91, 36, 32); } } if (sgdwCursWdtOld != 0) { DoBlitScreen(sgdwCursXOld, sgdwCursYOld, sgdwCursWdtOld, sgdwCursHgtOld); } if (sgdwCursWdt != 0) { DoBlitScreen(sgdwCursX, sgdwCursY, sgdwCursWdt, sgdwCursHgt); } } if (lpDDSBackBuf == NULL) { hDDVal = lpDDSPrimary->Unlock(NULL); if (hDDVal != DDERR_SURFACELOST && hDDVal != DD_OK) { DDErrMsg(hDDVal, 3779, "C:\\Src\\Diablo\\Source\\SCROLLRT.CPP"); } } #ifdef _DEBUG DrawFPS(); #endif } /** * @brief Redraw screen * @param draw_cursor */ void scrollrt_draw_game_screen(BOOL draw_cursor) { int hgt; if (force_redraw == 255) { force_redraw = 0; hgt = SCREEN_HEIGHT; } else { hgt = 0; } if (draw_cursor) { lock_buf(0); scrollrt_draw_cursor_item(); unlock_buf(0); } DrawMain(hgt, FALSE, FALSE, FALSE, FALSE, FALSE); if (draw_cursor) { lock_buf(0); scrollrt_draw_cursor_back_buffer(); unlock_buf(0); } } /** * @brief Render the game */ void DrawAndBlit() { int hgt; BOOL ddsdesc, ctrlPan; if (!gbRunGame) { return; } if (force_redraw == 255) { drawhpflag = TRUE; drawmanaflag = TRUE; drawbtnflag = TRUE; drawsbarflag = TRUE; ddsdesc = FALSE; ctrlPan = TRUE; hgt = SCREEN_HEIGHT; } else if (force_redraw == 1) { ddsdesc = TRUE; ctrlPan = FALSE; hgt = VIEWPORT_HEIGHT; } else { return; } force_redraw = 0; lock_buf(0); if (leveltype != DTYPE_TOWN) { DrawView(ViewX, ViewY); } else { T_DrawView(ViewX, ViewY); } if (ctrlPan) { DrawCtrlPan(); } if (drawhpflag) { UpdateLifeFlask(); } if (drawmanaflag) { UpdateManaFlask(); } if (drawbtnflag) { DrawCtrlBtns(); } if (drawsbarflag) { DrawInvBelt(); } if (talkflag) { DrawTalkPan(); hgt = SCREEN_HEIGHT; } scrollrt_draw_cursor_item(); unlock_buf(0); DrawMain(hgt, ddsdesc, drawhpflag, drawmanaflag, drawsbarflag, drawbtnflag); lock_buf(0); scrollrt_draw_cursor_back_buffer(); unlock_buf(0); drawhpflag = FALSE; drawmanaflag = FALSE; drawbtnflag = FALSE; drawsbarflag = FALSE; } ================================================ FILE: Source/scrollrt.h ================================================ /** * @file scrollrt.h * * Interface of functionality for rendering the dungeons, monsters and calling other render routines. */ #ifndef __SCROLLRT_H__ #define __SCROLLRT_H__ extern int light_table_index; extern int PitchTbl[1024]; extern BYTE *gpBufEnd; extern DWORD level_cel_block; extern char arch_draw_type; extern int cel_transparency_active; extern int level_piece_id; #ifdef HELLFIRE extern BOOLEAN AutoMapShowItems; #endif void ClearCursor(); void DrawMissile(int x, int y, int sx, int sy, int CelSkip, int CelCap, BOOL pre); void DrawClippedMissile(int x, int y, int sx, int sy, int CelSkip, int CelCap, BOOL pre); void DrawDeadPlayer(int x, int y, int sx, int sy, int CelSkip, int CelCap, BOOL clipped); void DrawView(int StartX, int StartY); void ClearScreenBuffer(); #ifdef _DEBUG void ScrollView(); void EnableFrameCount(); #endif void scrollrt_draw_game_screen(BOOL draw_cursor); void DrawAndBlit(); #endif /* __SCROLLRT_H__ */ ================================================ FILE: Source/setmaps.cpp ================================================ /** * @file setmaps.cpp * * Implementation of functionality the special quest dungeons. */ #include "all.h" // BUGFIX: constant data should be const BYTE SkelKingTrans1[] = { 19, 47, 26, 55, 26, 49, 30, 53 }; BYTE SkelKingTrans2[] = { 33, 19, 47, 29, 37, 29, 43, 39 }; BYTE SkelKingTrans3[] = { 27, 53, 35, 61, 27, 35, 34, 42, 45, 35, 53, 43, 45, 53, 53, 61, 31, 39, 49, 57 }; BYTE SkelKingTrans4[] = { 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 }; BYTE SkelChamTrans1[] = { 43, 19, 50, 26, 51, 19, 59, 26, 35, 27, 42, 34, 43, 27, 49, 34, 50, 27, 59, 34 }; BYTE SkelChamTrans2[] = { 19, 31, 34, 47, 34, 35, 42, 42 }; BYTE SkelChamTrans3[] = { 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 }; /** Maps from quest level to quest level names. */ const char *const quest_level_names[] = { "", "Skeleton King's Lair", "Bone Chamber", "Maze", "Poisoned Water Supply", "Archbishop Lazarus' Lair", }; int ObjIndex(int x, int y) { int i; int oi; for (i = 0; i < nobjects; i++) { oi = objectactive[i]; if (object[oi]._ox == x && object[oi]._oy == y) return oi; } app_fatal("ObjIndex: Active object not found at (%d,%d)", x, y); return -1; } #ifndef SPAWN void 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 AddSChamObjs() { SetObjMapRange(ObjIndex(37, 30), 17, 0, 21, 5, 1); SetObjMapRange(ObjIndex(37, 46), 13, 0, 16, 5, 2); } void 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 DRLG_SetMapTrans(const char *sFileName) { int x, y; int i, j; BYTE *pLevelMap; BYTE *d; DWORD dwOffset; pLevelMap = LoadFileInMem(sFileName, NULL); d = pLevelMap + 2; x = pLevelMap[0]; y = *d; dwOffset = (x * y + 1) * 2; x <<= 1; y <<= 1; dwOffset += 3 * x * y * 2; d += dwOffset; for (j = 0; j < y; j++) { for (i = 0; i < x; i++) { dTransVal[16 + i][16 + j] = *d; d += 2; } } mem_free_dbg(pLevelMap); } /** * @brief Load a quest map, the given map is specified via the global setlvlnum */ void LoadSetMap() { switch (setlvlnum) { case SL_SKELKING: if (quests[Q_SKELKING]._qactive == QUEST_INIT) { quests[Q_SKELKING]._qactive = QUEST_ACTIVE; quests[Q_SKELKING]._qvar1 = 1; } LoadPreL1Dungeon("Levels\\L1Data\\SklKng1.DUN", 83, 45); LoadL1Dungeon("Levels\\L1Data\\SklKng2.DUN", 83, 45); LoadPalette("Levels\\L1Data\\L1_2.pal"); DRLG_AreaTrans(sizeof(SkelKingTrans1) / 4, &SkelKingTrans1[0]); DRLG_ListTrans(sizeof(SkelKingTrans2) / 4, &SkelKingTrans2[0]); DRLG_AreaTrans(sizeof(SkelKingTrans3) / 4, &SkelKingTrans3[0]); DRLG_ListTrans(sizeof(SkelKingTrans4) / 4, &SkelKingTrans4[0]); AddL1Objs(0, 0, MAXDUNX, MAXDUNY); 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(sizeof(SkelChamTrans1) / 4, &SkelChamTrans1[0]); DRLG_AreaTrans(sizeof(SkelChamTrans2) / 4, &SkelChamTrans2[0]); DRLG_ListTrans(sizeof(SkelChamTrans3) / 4, &SkelChamTrans3[0]); AddL2Objs(0, 0, MAXDUNX, MAXDUNY); 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, MAXDUNX, MAXDUNY); DRLG_SetMapTrans("Levels\\L1Data\\Lv1MazeA.DUN"); break; case SL_POISONWATER: if (quests[Q_PWATER]._qactive == QUEST_INIT) quests[Q_PWATER]._qactive = QUEST_ACTIVE; 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[Q_BETRAYER]._qactive == QUEST_DONE) { quests[Q_BETRAYER]._qvar2 = 4; } else if (quests[Q_BETRAYER]._qactive == QUEST_ACTIVE) { quests[Q_BETRAYER]._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, MAXDUNX, MAXDUNY); AddVileObjs(); DRLG_SetMapTrans("Levels\\L1Data\\Vile1.DUN"); InitNoTriggers(); break; } } #endif ================================================ FILE: Source/setmaps.h ================================================ /** * @file setmaps.cpp * * Interface of functionality for the special quest dungeons. */ #ifndef __SETMAPS_H__ #define __SETMAPS_H__ int ObjIndex(int x, int y); void LoadSetMap(); /* rdata */ extern const char *const quest_level_names[]; #endif /* __SETMAPS_H__ */ ================================================ FILE: Source/sha.cpp ================================================ /** * @file sha.cpp * * Implementation of functionality for calculating X-SHA-1 (a flawed implementation of SHA-1). */ #include "all.h" /** * Define the SHA1 circular left shift macro */ #define SHA1CircularShift(bits, word) \ (((word) << (bits)) | ((word) >> (32 - (bits)))) SHA1Context sgSHA1[3]; static void SHA1Init(SHA1Context *context) { context->count[0] = 0; context->count[1] = 0; context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; } // Global Optimizations (/Og) cause the compiler to interpret // `SHA1CircularShift(5, A)` as `ror edx, 0x1b`, as if A were an unsigned integer. // This results in save files being incompatible between vanilla and MSVC Release builds. #if (_MSC_VER >= 1930) && NDEBUG #pragma optimize("g", off) #endif static void SHA1ProcessMessageBlock(SHA1Context *context) { int i, temp; int W[80]; int A, B, C, D, E; DWORD *buf = (DWORD *)context->buffer; for (i = 0; i < 16; i++) W[i] = buf[i]; for (i = 16; i < 80; i++) { W[i] = W[i - 16] ^ W[i - 14] ^ W[i - 8] ^ W[i - 3]; } 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; } #if (_MSC_VER >= 1930) && NDEBUG #pragma optimize("g", on) #endif static void SHA1Input(SHA1Context *context, const char *message_array, int len) { int i, count; count = context->count[0] + 8 * len; if (count < context->count[0]) context->count[1]++; context->count[0] = count; context->count[1] += len >> 29; for (i = len; i >= 64; i -= 64) { memcpy(context->buffer, message_array, sizeof(context->buffer)); SHA1ProcessMessageBlock(context); message_array += 64; } } void SHA1Clear() { memset(sgSHA1, 0, sizeof(sgSHA1)); } void SHA1Result(int n, char Message_Digest[SHA1HashSize]) { DWORD *Message_Digest_Block; int i; Message_Digest_Block = (DWORD *)Message_Digest; if (Message_Digest) { for (i = 0; i < 5; i++) { *Message_Digest_Block = sgSHA1[n].state[i]; Message_Digest_Block++; } } } void SHA1Calculate(int n, const char *data, char Message_Digest[SHA1HashSize]) { SHA1Input(&sgSHA1[n], data, 64); if (Message_Digest) SHA1Result(n, Message_Digest); } void SHA1Reset(int n) { SHA1Init(&sgSHA1[n]); } ================================================ FILE: Source/sha.h ================================================ /** * @file sha.cpp * * Interface of functionality for calculating X-SHA-1 (a flawed implementation of SHA-1). */ #ifndef __SHA_H__ #define __SHA_H__ #define SHA1HashSize 20 void SHA1Clear(); void SHA1Result(int n, char Message_Digest[SHA1HashSize]); void SHA1Calculate(int n, const char *data, char Message_Digest[SHA1HashSize]); void SHA1Reset(int n); #endif /* __SHA_H__ */ ================================================ FILE: Source/sound.cpp ================================================ /** * @file sound.cpp * * Implementation of functions setting up the audio pipeline. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" /** Contains the audio channels used for playback of sounds. */ LPDIRECTSOUNDBUFFER DSBs[8]; LPDIRECTSOUND sglpDS; BOOLEAN gbSndInited; int sglMusicVolume; int sglSoundVolume; /** Provides a handle to the dynamic library dsound.dll. */ HMODULE hDsound_dll; /** Specifies whether background music is enabled. */ HANDLE sghMusic; LPDIRECTSOUNDBUFFER sglpDSB; /* data */ BOOLEAN gbMusicOn = TRUE; /** Specifies whether sound effects are enabled. */ BOOLEAN gbSoundOn = TRUE; /** Specifies that no duplicate audio channel should be used. */ BOOLEAN gbDupSounds = TRUE; /** Specifies the active background music track id. */ int sgnMusicTrack = NUM_MUSIC; /** Maps from track ID to track name. */ const char *const sgszMusicTracks[NUM_MUSIC] = { #ifdef SPAWN "Music\\sTowne.wav", "Music\\sLvlA.wav", "Music\\sLvlA.wav", "Music\\sLvlA.wav", "Music\\sLvlA.wav", #ifdef HELLFIRE "Music\\sLvlA.wav", "Music\\sLvlA.wav", #endif "Music\\sintro.wav", #else "Music\\DTowne.wav", "Music\\DLvlA.wav", "Music\\DLvlB.wav", "Music\\DLvlC.wav", "Music\\DLvlD.wav", #ifdef HELLFIRE "Music\\DLvlE.wav", "Music\\DLvlF.wav", #endif "Music\\Dintro.wav", #endif }; char unk_volume[4][2] = { { 15, -16 }, { 15, -16 }, { 30, -31 }, { 30, -31 } }; void snd_update(BOOL bStopAll) { DWORD dwStatus, i; for (i = 0; i < 8; i++) { if (!DSBs[i]) continue; if (!bStopAll && DSBs[i]->GetStatus(&dwStatus) == DS_OK && dwStatus == DSBSTATUS_PLAYING) continue; DSBs[i]->Stop(); DSBs[i]->Release(); DSBs[i] = NULL; } } static LPDIRECTSOUNDBUFFER sound_dup_channel(LPDIRECTSOUNDBUFFER DSB) { DWORD i; if (!gbDupSounds) { return NULL; } for (i = 0; i < 8; i++) { if (!DSBs[i]) { if (sglpDS->DuplicateSoundBuffer(DSB, &DSBs[i]) != DS_OK) { return NULL; } return DSBs[i]; } } return NULL; } static void snd_get_volume(const char *value_name, int *value) { int v = *value; if (!SRegLoadValue(APP_NAME, value_name, 0, &v)) { v = VOLUME_MAX; } *value = v; if (*value < VOLUME_MIN) { *value = VOLUME_MIN; } else if (*value > VOLUME_MAX) { *value = VOLUME_MAX; } *value -= *value % 100; } static void snd_set_volume(const char *key, int value) { SRegSaveValue(APP_NAME, key, 0, value); } static BOOL sound_file_reload(TSnd *sound_file, LPDIRECTSOUNDBUFFER DSB) { HANDLE file; LPVOID buf1, buf2; DWORD size1, size2; BOOL rv; HRESULT error_code; if (DSB->Restore() != DS_OK) return FALSE; rv = FALSE; WOpenFile(sound_file->sound_path, &file, FALSE); WSetFilePointer(file, sound_file->chunk.dwOffset, NULL, FILE_BEGIN); error_code = DSB->Lock(0, sound_file->chunk.dwSize, &buf1, &size1, &buf2, &size2, 0); if (error_code == DS_OK) { WReadFile(file, buf1, size1); error_code = DSB->Unlock(buf1, size1, buf2, size2); if (error_code == DS_OK) rv = TRUE; } WCloseFile(file); return rv; } void snd_stop_snd(TSnd *pSnd) { if (pSnd && pSnd->DSB) pSnd->DSB->Stop(); } BOOL snd_playing(TSnd *pSnd) { DWORD dwStatus; if (!pSnd) return FALSE; if (pSnd->DSB == NULL) return FALSE; if (pSnd->DSB->GetStatus(&dwStatus) != DS_OK) return FALSE; return dwStatus == DSBSTATUS_PLAYING; } void snd_play_snd(TSnd *pSnd, int lVolume, int lPan) { LPDIRECTSOUNDBUFFER DSB; DWORD tc; HRESULT error_code; if (!pSnd || !gbSoundOn) { return; } DSB = pSnd->DSB; if (DSB == NULL) { return; } tc = GetTickCount(); if (tc - pSnd->start_tc < 80) { GetTickCount(); // BUGFIX: unnecessary GetTickCount return; } if (snd_playing(pSnd)) { DSB = sound_dup_channel(pSnd->DSB); if (DSB == NULL) { return; } } lVolume += sglSoundVolume; if (lVolume < VOLUME_MIN) { lVolume = VOLUME_MIN; } else if (lVolume > VOLUME_MAX) { lVolume = VOLUME_MAX; } DSB->SetVolume(lVolume); DSB->SetPan(lPan); error_code = DSB->Play(0, 0, 0); if (error_code != DSERR_BUFFERLOST) { if (error_code != DS_OK) { DSErrMsg(error_code, 261, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); } } else if (sound_file_reload(pSnd, DSB)) { DSB->Play(0, 0, 0); } pSnd->start_tc = tc; } static void sound_CreateSoundBuffer(TSnd *sound_file) { DSBUFFERDESC DSB; HRESULT error_code; memset(&DSB, 0, sizeof(DSBUFFERDESC)); DSB.dwSize = sizeof(DSBUFFERDESC); DSB.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_STATIC; DSB.dwBufferBytes = sound_file->chunk.dwSize; DSB.lpwfxFormat = &sound_file->fmt; error_code = sglpDS->CreateSoundBuffer(&DSB, &sound_file->DSB, NULL); if (error_code != ERROR_SUCCESS) DSErrMsg(error_code, 282, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); } TSnd *sound_file_load(const char *path) { HANDLE file; BYTE *wave_file; TSnd *pSnd; LPVOID buf1, buf2; DWORD size1, size2; HRESULT error_code; if (!sglpDS) return NULL; WOpenFile(path, &file, FALSE); pSnd = (TSnd *)DiabloAllocPtr(sizeof(TSnd)); memset(pSnd, 0, sizeof(TSnd)); pSnd->sound_path = path; pSnd->start_tc = GetTickCount() - 80 - 1; wave_file = LoadWaveFile(file, &pSnd->fmt, &pSnd->chunk); if (!wave_file) app_fatal("Invalid sound format on file %s", pSnd->sound_path); sound_CreateSoundBuffer(pSnd); error_code = pSnd->DSB->Lock(0, pSnd->chunk.dwSize, &buf1, &size1, &buf2, &size2, 0); if (error_code != DS_OK) DSErrMsg(error_code, 318, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); memcpy(buf1, wave_file + pSnd->chunk.dwOffset, size1); error_code = pSnd->DSB->Unlock(buf1, size1, buf2, size2); if (error_code != DS_OK) DSErrMsg(error_code, 325, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); mem_free_dbg((void *)wave_file); WCloseFile(file); return pSnd; } void sound_file_cleanup(TSnd *sound_file) { if (sound_file) { if (sound_file->DSB) { sound_file->DSB->Stop(); sound_file->DSB->Release(); sound_file->DSB = NULL; } mem_free_dbg(sound_file); } } static void sound_create_primary_buffer(HANDLE music_track) { HRESULT error_code; DSBUFFERDESC dsbuf; WAVEFORMATEX format; if (music_track == NULL) { memset(&dsbuf, 0, sizeof(DSBUFFERDESC)); dsbuf.dwSize = sizeof(DSBUFFERDESC); dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER; error_code = sglpDS->CreateSoundBuffer(&dsbuf, &sglpDSB, NULL); if (error_code != DS_OK) DSErrMsg(error_code, 375, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); } if (sglpDSB) { DSCAPS dsbcaps; dsbcaps.dwSize = sizeof(DSCAPS); error_code = sglpDS->GetCaps(&dsbcaps); if (error_code != DS_OK) DSErrMsg(error_code, 383, "C:\\Src\\Diablo\\Source\\SOUND.CPP"); if (!music_track || !LoadWaveFormat(music_track, &format)) { memset(&format, 0, sizeof(WAVEFORMATEX)); format.wFormatTag = WAVE_FORMAT_PCM; format.nSamplesPerSec = 22050; format.wBitsPerSample = 16; format.cbSize = 0; } format.nChannels = 2; format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; sglpDSB->SetFormat(&format); } } static HRESULT sound_DirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter) { HRESULT(WINAPI * DirectSoundCreate) (LPGUID lpGuid, LPDIRECTSOUND * ppDS, LPUNKNOWN pUnkOuter); if (hDsound_dll == NULL) { hDsound_dll = LoadLibrary("dsound.dll"); } if (hDsound_dll == NULL) { ErrDlg(IDD_DIALOG5, GetLastError(), "C:\\Src\\Diablo\\Source\\SOUND.CPP", 422); } DirectSoundCreate = (HRESULT(WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN))GetProcAddress(hDsound_dll, "DirectSoundCreate"); if (DirectSoundCreate == NULL) { ErrDlg(IDD_DIALOG5, GetLastError(), "C:\\Src\\Diablo\\Source\\SOUND.CPP", 427); } return DirectSoundCreate(lpGuid, ppDS, pUnkOuter); } void snd_init(HWND hWnd) { int error_code; snd_get_volume("Sound Volume", &sglSoundVolume); gbSoundOn = sglSoundVolume > VOLUME_MIN; snd_get_volume("Music Volume", &sglMusicVolume); gbMusicOn = sglMusicVolume > VOLUME_MIN; error_code = sound_DirectSoundCreate(NULL, &sglpDS, NULL); if (error_code != DS_OK) sglpDS = NULL; if (sglpDS && sglpDS->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE) == DS_OK) sound_create_primary_buffer(NULL); SVidInitialize(sglpDS); SFileDdaInitialize(sglpDS); gbSndInited = sglpDS != NULL; } void sound_cleanup() { snd_update(TRUE); SVidDestroy(); SFileDdaDestroy(); if (sglpDS) { sglpDS->Release(); sglpDS = NULL; } if (gbSndInited) { gbSndInited = FALSE; snd_set_volume("Sound Volume", sglSoundVolume); snd_set_volume("Music Volume", sglMusicVolume); } } void music_stop() { if (sghMusic) { SFileDdaEnd(sghMusic); SFileCloseFile(sghMusic); sghMusic = NULL; sgnMusicTrack = NUM_MUSIC; } } void music_start(int nTrack) { BOOL success; assert((DWORD)nTrack < NUM_MUSIC); music_stop(); if (sglpDS && gbMusicOn) { #ifdef _DEBUG SFileEnableDirectAccess(FALSE); #endif success = SFileOpenFile(sgszMusicTracks[nTrack], &sghMusic); #ifdef _DEBUG SFileEnableDirectAccess(TRUE); #endif sound_create_primary_buffer(sghMusic); if (!success) { sghMusic = NULL; } else { SFileDdaBeginEx(sghMusic, 0x40000, 0x40000, 0, sglMusicVolume, 0, 0); sgnMusicTrack = nTrack; } } } void sound_disable_music(BOOL disable) { if (disable) { music_stop(); } else if (sgnMusicTrack != NUM_MUSIC) { music_start(sgnMusicTrack); } } int sound_get_or_set_music_volume(int volume) { if (volume == 1) return sglMusicVolume; sglMusicVolume = volume; if (sghMusic) SFileDdaSetVolume(sghMusic, volume, 0); return sglMusicVolume; } int sound_get_or_set_sound_volume(int volume) { if (volume == 1) return sglSoundVolume; sglSoundVolume = volume; return sglSoundVolume; } ================================================ FILE: Source/sound.h ================================================ /** * @file sound.h * * Interface of functions setting up the audio pipeline. */ #ifndef __SOUND_H__ #define __SOUND_H__ extern BOOLEAN gbSndInited; void snd_update(BOOL bStopAll); void snd_stop_snd(TSnd *pSnd); BOOL snd_playing(TSnd *pSnd); void snd_play_snd(TSnd *pSnd, int lVolume, int lPan); TSnd *sound_file_load(const char *path); void sound_file_cleanup(TSnd *sound_file); void snd_init(HWND hWnd); void sound_cleanup(); void music_stop(); void music_start(int nTrack); void sound_disable_music(BOOL disable); int sound_get_or_set_music_volume(int volume); int sound_get_or_set_sound_volume(int volume); /* data */ extern BOOLEAN gbMusicOn; extern BOOLEAN gbSoundOn; extern BOOLEAN gbDupSounds; #endif /* __SOUND_H__ */ ================================================ FILE: Source/spelldat.cpp ================================================ /** * @file spelldat.cpp * * Implementation of all spell data. */ #include "all.h" /** Data related to each spell ID. */ SpellData spelldata[] = { // clang-format off // sName, sManaCost, sType, sNameText, sSkillText, sBookLvl, sStaffLvl, sTargeted, sTownSpell, sMinInt, sSFX, sMissiles[3], sManaAdj, sMinMana, sStaffMin, sStaffMax, sBookCost, sStaffCost { SPL_NULL, 0, 0, NULL, NULL, 0, 0, FALSE, FALSE, 0, 0, { 0, 0, 0 }, 0, 0, 40, 80, 0, 0 }, { SPL_FIREBOLT, 6, STYPE_FIRE, "Firebolt", "Firebolt", 1, 1, TRUE, FALSE, 15, IS_CAST2, { MIS_FIREBOLT, 0, 0 }, 1, 3, 40, 80, 1000, 50 }, { SPL_HEAL, 5, STYPE_MAGIC, "Healing", NULL, 1, 1, FALSE, TRUE, 17, IS_CAST8, { MIS_HEAL, 0, 0 }, 3, 1, 20, 40, 1000, 50 }, { SPL_LIGHTNING, 10, STYPE_LIGHTNING, "Lightning", NULL, 4, 3, TRUE, FALSE, 20, IS_CAST4, { MIS_LIGHTCTRL, 0, 0 }, 1, 6, 20, 60, 3000, 150 }, { SPL_FLASH, 30, STYPE_LIGHTNING, "Flash", NULL, 5, 4, FALSE, FALSE, 33, IS_CAST4, { MIS_FLASH, MIS_FLASH2, 0 }, 2, 16, 20, 40, 7500, 500 }, { SPL_IDENTIFY, 13, STYPE_MAGIC, "Identify", "Identify", -1, -1, FALSE, TRUE, 23, IS_CAST6, { MIS_IDENTIFY, 0, 0 }, 2, 1, 8, 12, 0, 100 }, { SPL_FIREWALL, 28, STYPE_FIRE, "Fire Wall", NULL, 3, 2, TRUE, FALSE, 27, IS_CAST2, { MIS_FIREWALLC, 0, 0 }, 2, 16, 8, 16, 6000, 400 }, { SPL_TOWN, 35, STYPE_MAGIC, "Town Portal", NULL, 3, 3, TRUE, FALSE, 20, IS_CAST6, { MIS_TOWN, 0, 0 }, 3, 18, 8, 12, 3000, 200 }, #ifndef SPAWN { SPL_STONE, 60, STYPE_MAGIC, "Stone Curse", NULL, 6, 5, TRUE, FALSE, 51, IS_CAST2, { MIS_STONE, 0, 0 }, 3, 40, 8, 16, 12000, 800 }, #else { SPL_STONE, 60, STYPE_MAGIC, "Stone Curse", NULL, -1, -1, TRUE, FALSE, 51, IS_CAST2, { MIS_STONE, 0, 0 }, 3, 40, 8, 16, 12000, 800 }, #endif { SPL_INFRA, 40, STYPE_MAGIC, "Infravision", NULL, -1, -1, FALSE, FALSE, 36, IS_CAST8, { MIS_INFRA, 0, 0 }, 5, 20, 0, 0, 0, 600 }, { SPL_RNDTELEPORT, 12, STYPE_MAGIC, "Phasing", NULL, 7, 6, FALSE, FALSE, 39, IS_CAST2, { MIS_RNDTELEPORT, 0, 0 }, 2, 4, 40, 80, 3500, 200 }, { SPL_MANASHIELD, 33, STYPE_MAGIC, "Mana Shield", NULL, 6, 5, FALSE, FALSE, 25, IS_CAST2, { MIS_MANASHIELD, 0, 0 }, 0, 33, 4, 10, 16000, 1200 }, { SPL_FIREBALL, 16, STYPE_FIRE, "Fireball", NULL, 8, 7, TRUE, FALSE, 48, IS_CAST2, { MIS_FIREBALL, 0, 0 }, 1, 10, 40, 80, 8000, 300 }, #ifndef SPAWN { SPL_GUARDIAN, 50, STYPE_FIRE, "Guardian", NULL, 9, 8, TRUE, FALSE, 61, IS_CAST2, { MIS_GUARDIAN, 0, 0 }, 2, 30, 16, 32, 14000, 950 }, #else { SPL_GUARDIAN, 50, STYPE_FIRE, "Guardian", NULL, -1, -1, TRUE, FALSE, 61, IS_CAST2, { MIS_GUARDIAN, 0, 0 }, 2, 30, 16, 32, 14000, 950 }, #endif { SPL_CHAIN, 30, STYPE_LIGHTNING, "Chain Lightning", NULL, 8, 7, FALSE, FALSE, 54, IS_CAST2, { MIS_CHAIN, 0, 0 }, 1, 18, 20, 60, 11000, 750 }, { SPL_WAVE, 35, STYPE_FIRE, "Flame Wave", NULL, 9, 8, TRUE, FALSE, 54, IS_CAST2, { MIS_WAVE, 0, 0 }, 3, 20, 20, 40, 10000, 650 }, { SPL_DOOMSERP, 0, STYPE_LIGHTNING, "Doom Serpents", NULL, -1, -1, FALSE, FALSE, 0, IS_CAST2, { 0, 0, 0 }, 0, 0, 40, 80, 0, 0 }, { SPL_BLODRIT, 0, STYPE_MAGIC, "Blood Ritual", NULL, -1, -1, FALSE, FALSE, 0, IS_CAST2, { 0, 0, 0 }, 0, 0, 40, 80, 0, 0 }, #ifndef HELLFIRE { SPL_NOVA, 60, STYPE_MAGIC, "Nova", NULL, -1, 10, FALSE, FALSE, 87, IS_CAST4, { MIS_NOVA, 0, 0 }, 3, 35, 16, 32, 21000, 1300 }, #else { SPL_NOVA, 60, STYPE_MAGIC, "Nova", NULL, 14, 10, FALSE, FALSE, 87, IS_CAST4, { MIS_NOVA, 0, 0 }, 3, 35, 16, 32, 21000, 1300 }, #endif { SPL_INVISIBIL, 0, STYPE_MAGIC, "Invisibility", NULL, -1, -1, FALSE, FALSE, 0, IS_CAST2, { 0, 0, 0 }, 0, 0, 40, 80, 0, 0 }, { SPL_FLAME, 11, STYPE_FIRE, "Inferno", NULL, 3, 2, TRUE, FALSE, 20, IS_CAST2, { MIS_FLAMEC, 0, 0 }, 1, 6, 20, 40, 2000, 100 }, #ifndef SPAWN { SPL_GOLEM, 100, STYPE_FIRE, "Golem", NULL, 11, 9, FALSE, FALSE, 81, IS_CAST2, { MIS_GOLEM, 0, 0 }, 6, 60, 16, 32, 18000, 1100 }, #else { SPL_GOLEM, 100, STYPE_FIRE, "Golem", NULL, -1, -1, FALSE, FALSE, 81, IS_CAST2, { MIS_GOLEM, 0, 0 }, 6, 60, 16, 32, 18000, 1100 }, #endif #ifndef HELLFIRE { SPL_BLODBOIL, 0, STYPE_LIGHTNING, "Blood Boil", NULL, -1, -1, TRUE, FALSE, 0, IS_CAST8, { 0, 0, 0 }, 0, 0, 0, 0, 0, 0 }, #else { SPL_BLODBOIL, 15, STYPE_MAGIC, "Rage", "Rage", -1, -1, FALSE, FALSE, 0, IS_CAST8, { MIS_BLODBOIL, 0, 0 }, 1, 1, 0, 0, 0, 0 }, #endif { SPL_TELEPORT, 35, STYPE_MAGIC, "Teleport", NULL, 14, 12, TRUE, FALSE, 105, IS_CAST6, { MIS_TELEPORT, 0, 0 }, 3, 15, 16, 32, 20000, 1250 }, #if !defined(SPAWN) && !defined(HELLFIRE) { SPL_APOCA, 150, STYPE_FIRE, "Apocalypse", NULL, -1, 15, FALSE, FALSE, 149, IS_CAST2, { MIS_APOCA, 0, 0 }, 6, 90, 8, 12, 30000, 2000 }, #elif !defined(SPAWN) { SPL_APOCA, 150, STYPE_FIRE, "Apocalypse", NULL, 19, 15, FALSE, FALSE, 149, IS_CAST2, { MIS_APOCA, 0, 0 }, 6, 90, 8, 12, 30000, 2000 }, #else { SPL_APOCA, 150, STYPE_FIRE, "Apocalypse", NULL, -1, -1, FALSE, FALSE, 149, IS_CAST2, { MIS_APOCA, 0, 0 }, 6, 90, 8, 12, 30000, 2000 }, #endif { SPL_ETHEREALIZE, 100, STYPE_MAGIC, "Etherealize", NULL, -1, -1, FALSE, FALSE, 93, IS_CAST2, { MIS_ETHEREALIZE, 0, 0 }, 0, 100, 2, 6, 26000, 1600 }, { SPL_REPAIR, 0, STYPE_MAGIC, "Item Repair", "Item Repair", -1, -1, FALSE, TRUE, -1, IS_CAST6, { MIS_REPAIR, 0, 0 }, 0, 0, 40, 80, 0, 0 }, { SPL_RECHARGE, 0, STYPE_MAGIC, "Staff Recharge", "Staff Recharge", -1, -1, FALSE, TRUE, -1, IS_CAST6, { MIS_RECHARGE, 0, 0 }, 0, 0, 40, 80, 0, 0 }, { SPL_DISARM, 0, STYPE_MAGIC, "Trap Disarm", "Trap Disarm", -1, -1, FALSE, FALSE, -1, IS_CAST6, { MIS_DISARM, 0, 0 }, 0, 0, 40, 80, 0, 0 }, #ifndef SPAWN { SPL_ELEMENT, 35, STYPE_FIRE, "Elemental", NULL, 8, 6, FALSE, FALSE, 68, IS_CAST2, { MIS_ELEMENT, 0, 0 }, 2, 20, 20, 60, 10500, 700 }, #else { SPL_ELEMENT, 35, STYPE_FIRE, "Elemental", NULL, -1, -1, FALSE, FALSE, 68, IS_CAST2, { MIS_ELEMENT, 0, 0 }, 2, 20, 20, 60, 10500, 700 }, #endif { SPL_CBOLT, 6, STYPE_LIGHTNING, "Charged Bolt", NULL, 1, 1, TRUE, FALSE, 25, IS_CAST2, { MIS_CBOLT, 0, 0 }, 1, 6, 40, 80, 1000, 50 }, { SPL_HBOLT, 7, STYPE_MAGIC, "Holy Bolt", NULL, 1, 1, TRUE, FALSE, 20, IS_CAST2, { MIS_HBOLT, 0, 0 }, 1, 3, 40, 80, 1000, 50 }, { SPL_RESURRECT, 20, STYPE_MAGIC, "Resurrect", NULL, -1, 5, FALSE, TRUE, 30, IS_CAST8, { MIS_RESURRECT, 0, 0 }, 0, 20, 4, 10, 4000, 250 }, { SPL_TELEKINESIS, 15, STYPE_MAGIC, "Telekinesis", NULL, 2, 2, FALSE, FALSE, 33, IS_CAST2, { MIS_TELEKINESIS, 0, 0 }, 2, 8, 20, 40, 2500, 200 }, { SPL_HEALOTHER, 5, STYPE_MAGIC, "Heal Other", NULL, 1, 1, FALSE, TRUE, 17, IS_CAST8, { MIS_HEALOTHER, 0, 0 }, 3, 1, 20, 40, 1000, 50 }, #ifndef SPAWN { SPL_FLARE, 25, STYPE_MAGIC, "Blood Star", NULL, 14, 13, FALSE, FALSE, 70, IS_CAST2, { MIS_FLARE, 0, 0 }, 2, 14, 20, 60, 27500, 1800 }, { SPL_BONESPIRIT, 24, STYPE_MAGIC, "Bone Spirit", NULL, 9, 7, FALSE, FALSE, 34, IS_CAST2, { MIS_BONESPIRIT, 0, 0 }, 1, 12, 20, 60, 11500, 800 }, #else { SPL_FLARE, 25, STYPE_MAGIC, "Blood Star", NULL, -1, -1, FALSE, FALSE, 70, IS_CAST2, { MIS_FLARE, 0, 0 }, 2, 14, 20, 60, 27500, 1800 }, { SPL_BONESPIRIT, 24, STYPE_MAGIC, "Bone Spirit", NULL, -1, -1, FALSE, FALSE, 34, IS_CAST2, { MIS_BONESPIRIT, 0, 0 }, 1, 12, 20, 60, 11500, 800 }, #endif #ifdef HELLFIRE { SPL_MANA, 255, STYPE_MAGIC, "Mana", NULL, -1, 5, FALSE, TRUE, 17, IS_CAST8, { MIS_MANA, 0, 0 }, 3, 1, 12, 24, 1000, 50 }, { SPL_MAGI, 255, STYPE_MAGIC, "the Magi", NULL, -1, 20, FALSE, TRUE, 45, IS_CAST8, { MIS_MAGI, 0, 0 }, 3, 1, 15, 30, 100000, 200 }, { SPL_JESTER, 255, STYPE_MAGIC, "the Jester", NULL, -1, 4, TRUE, FALSE, 30, IS_CAST8, { MIS_JESTER, 0, 0 }, 3, 1, 15, 30, 100000, 200 }, { SPL_LIGHTWALL, 28, STYPE_LIGHTNING, "Lightning Wall", NULL, 3, 2, TRUE, FALSE, 27, IS_CAST4, { MIS_LIGHTNINGWALL, 0, 0 }, 2, 16, 8, 16, 6000, 400 }, { SPL_IMMOLAT, 60, STYPE_FIRE, "Immolation", NULL, 14, 10, FALSE, FALSE, 87, IS_CAST2, { MIS_IMMOLATION, 0, 0 }, 3, 35, 16, 32, 21000, 1300 }, { SPL_WARP, 35, STYPE_MAGIC, "Warp", NULL, 3, 3, FALSE, FALSE, 25, IS_CAST6, { MIS_WARP, 0, 0 }, 3, 18, 8, 12, 3000, 200 }, { SPL_REFLECT, 35, STYPE_MAGIC, "Reflect", NULL, 3, 3, FALSE, FALSE, 25, IS_CAST6, { MIS_REFLECT, 0, 0 }, 3, 15, 8, 12, 3000, 200 }, { SPL_BERSERK, 35, STYPE_MAGIC, "Berserk", NULL, 3, 3, TRUE, FALSE, 35, IS_CAST6, { MIS_BERSERK, 0, 0 }, 3, 15, 8, 12, 3000, 200 }, { SPL_FIRERING, 28, STYPE_FIRE, "Ring of Fire", NULL, 5, 5, FALSE, FALSE, 27, IS_CAST2, { MIS_FIRERING, 0, 0 }, 2, 16, 8, 16, 6000, 400 }, { SPL_SEARCH, 15, STYPE_MAGIC, "Search", "Search", 1, 3, FALSE, FALSE, 25, IS_CAST6, { MIS_SEARCH, 0, 0 }, 1, 1, 8, 12, 3000, 200 }, { SPL_RUNEFIRE, 255, STYPE_MAGIC, "Rune of Fire", NULL, -1, -1, TRUE, FALSE, 48, IS_CAST8, { MIS_RUNEFIRE, 0, 0 }, 1, 10, 40, 80, 8000, 300 }, { SPL_RUNELIGHT, 255, STYPE_MAGIC, "Rune of Light", NULL, -1, -1, TRUE, FALSE, 48, IS_CAST8, { MIS_RUNELIGHT, 0, 0 }, 1, 10, 40, 80, 8000, 300 }, { SPL_RUNENOVA, 255, STYPE_MAGIC, "Rune of Nova", NULL, -1, -1, TRUE, FALSE, 48, IS_CAST8, { MIS_RUNENOVA, 0, 0 }, 1, 10, 40, 80, 8000, 300 }, { SPL_RUNEIMMOLAT, 255, STYPE_MAGIC, "Rune of Immolation", NULL, -1, -1, TRUE, FALSE, 48, IS_CAST8, { MIS_RUNEIMMOLAT, 0, 0 }, 1, 10, 40, 80, 8000, 300 }, { SPL_RUNESTONE, 255, STYPE_MAGIC, "Rune of Stone", NULL, -1, -1, TRUE, FALSE, 48, IS_CAST8, { MIS_RUNESTONE, 0, 0 }, 1, 10, 40, 80, 8000, 300 }, #endif // clang-format on }; ================================================ FILE: Source/spelldat.h ================================================ /** * @file spelldat.h * * Interface of all spell data. */ #ifndef __SPELLDAT_H__ #define __SPELLDAT_H__ extern SpellData spelldata[]; #endif /* __SPELLDAT_H__ */ ================================================ FILE: Source/spells.cpp ================================================ /** * @file spells.cpp * * Implementation of functionality for casting player spells. */ #include "all.h" int GetManaAmount(int id, int sn) { 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) { ma = ((BYTE)plr[id]._pMaxManaBase - adj); } else { ma = (spelldata[sn].sManaCost - adj); } ma <<= 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; } #ifdef HELLFIRE if (plr[id]._pClass == PC_SORCERER) { ma >>= 1; } else if (plr[id]._pClass == PC_ROGUE || plr[id]._pClass == PC_MONK || plr[id]._pClass == PC_BARD) { ma -= ma >> 2; } #else if (plr[id]._pClass == PC_ROGUE) { ma -= ma >> 2; } #endif if (spelldata[sn].sMinMana > ma >> 6) { ma = spelldata[sn].sMinMana << 6; } return ma * (100 - plr[id]._pISplCost) / 100; } void UseMana(int id, int sn) { int ma; // mana cost if (id == myplr) { switch (plr[id]._pSplType) { case RSPLTYPE_SKILL: case RSPLTYPE_INVALID: break; case RSPLTYPE_SCROLL: RemoveScroll(id); break; case RSPLTYPE_CHARGES: UseStaffCharge(id); break; 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 = TRUE; #ifdef _DEBUG } #endif break; } } } BOOL CheckSpell(int id, int sn, char st, BOOL manaonly) { BOOL result; #ifdef _DEBUG if (debug_mode_key_inverted_v) return TRUE; #endif result = TRUE; if (!manaonly && pcurs != CURSOR_HAND) { 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 CastSpell(int id, int spl, int sx, int sy, int dx, int dy, int caster, int spllvl) { int i; int dir; // missile direction switch (caster) { case TARGET_PLAYERS: dir = monster[id]._mdir; break; case TARGET_MONSTERS: // caster must be 0 already in this case, but oh well, // it's needed to generate the right code caster = TARGET_MONSTERS; dir = plr[id]._pdir; #ifdef HELLFIRE if (spl == SPL_FIREWALL || spl == SPL_LIGHTWALL) { #else if (spl == SPL_FIREWALL) { #endif dir = plr[id]._pVar3; } break; } for (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 (i = (spllvl >> 1) + 3; i > 0; i--) { AddMissile(sx, sy, dx, dy, dir, MIS_CBOLT, caster, id, 0, spllvl); } } } static void PlacePlayer(int pnum) { int nx, ny, max, min, x, y; DWORD i; BOOL done; if (plr[pnum].plrlevel == currlevel) { for (i = 0; i < 8; i++) { nx = plr[pnum]._px + plrxoff2[i]; ny = plr[pnum]._py + plryoff2[i]; if (PosOkPlayer(pnum, nx, ny)) { break; } } if (!PosOkPlayer(pnum, nx, ny)) { done = FALSE; for (max = 1, min = -1; min > -50 && !done; max++, min--) { for (y = min; y <= max && !done; y++) { ny = plr[pnum]._py + y; for (x = min; x <= max && !done; x++) { nx = plr[pnum]._px + x; if (PosOkPlayer(pnum, nx, ny)) { done = TRUE; } } } } } plr[pnum]._px = nx; plr[pnum]._py = ny; dPlayer[nx][ny] = pnum + 1; if (pnum == myplr) { ViewX = nx; ViewY = ny; } } } /** * @param pnum player index * @param rid target player index */ void DoResurrect(int pnum, int rid) { int hp; if ((char)rid != -1) { AddMissile(plr[rid]._px, plr[rid]._py, plr[rid]._px, plr[rid]._py, 0, MIS_RESURRECTBEAM, TARGET_MONSTERS, pnum, 0, 0); } if (pnum == myplr) { NewCursor(CURSOR_HAND); } if ((char)rid != -1 && plr[rid]._pHitPoints == 0) { if (rid == myplr) { deathflag = FALSE; gamemenu_off(); drawhpflag = TRUE; drawmanaflag = TRUE; } ClrPlrPath(rid); plr[rid].destAction = ACTION_NONE; plr[rid]._pInvincible = FALSE; #ifndef HELLFIRE PlacePlayer(rid); #endif hp = 10 << 6; #ifndef HELLFIRE if (plr[rid]._pMaxHPBase < (10 << 6)) { hp = plr[rid]._pMaxHPBase; } #endif SetPlayerHitPoints(rid, hp); plr[rid]._pHPBase = plr[rid]._pHitPoints + (plr[rid]._pMaxHPBase - plr[rid]._pMaxHP); // CODEFIX: does the same stuff as SetPlayerHitPoints above, can be removed plr[rid]._pMana = 0; plr[rid]._pManaBase = plr[rid]._pMana + (plr[rid]._pMaxManaBase - plr[rid]._pMaxMana); CalcPlrInv(rid, TRUE); if (plr[rid].plrlevel == currlevel) { StartStand(rid, plr[rid]._pdir); } else { plr[rid]._pmode = PM_STAND; } } } void DoHealOther(int pnum, int rid) { int i, j, hp; if (pnum == myplr) { NewCursor(CURSOR_HAND); } if ((char)rid != -1 && (plr[rid]._pHitPoints >> 6) > 0) { hp = (random_(57, 10) + 1) << 6; for (i = 0; i < plr[pnum]._pLevel; i++) { hp += (random_(57, 4) + 1) << 6; } for (j = 0; j < GetSpellLevel(pnum, SPL_HEALOTHER); ++j) { hp += (random_(57, 6) + 1) << 6; } #ifdef HELLFIRE if (plr[pnum]._pClass == PC_WARRIOR || plr[pnum]._pClass == PC_BARBARIAN) { hp <<= 1; } else if (plr[pnum]._pClass == PC_ROGUE || plr[pnum]._pClass == PC_BARD) { hp += hp >> 1; } else if (plr[pnum]._pClass == PC_MONK) { hp *= 3; } #else if (plr[pnum]._pClass == PC_WARRIOR) { hp <<= 1; } if (plr[pnum]._pClass == PC_ROGUE) { hp += hp >> 1; } #endif 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 = TRUE; } } ================================================ FILE: Source/spells.h ================================================ /** * @file spells.h * * Interface of functionality for casting player spells. */ #ifndef __SPELLS_H__ #define __SPELLS_H__ int GetManaAmount(int id, int sn); void UseMana(int id, int sn); BOOL CheckSpell(int id, int sn, char st, BOOL manaonly); void CastSpell(int id, int spl, int sx, int sy, int dx, int dy, int caster, int spllvl); void DoResurrect(int pnum, int rid); void DoHealOther(int pnum, int rid); #endif /* __SPELLS_H__ */ ================================================ FILE: Source/stores.cpp ================================================ /** * @file stores.cpp * * Implementation of functionality for stores and towner dialogs. */ #include "all.h" int stextup; int storenumh; int stextlhold; ItemStruct boyitem; int stextshold; ItemStruct premiumitem[SMITH_PREMIUM_ITEMS]; BYTE *pSTextBoxCels; int premiumlevel; int talker; STextStruct stext[STORE_LINES]; char stextsize; int stextsmax; int InStoreFlag; /** current frame # for the pentagram selector */ ItemStruct storehold[48]; int gossipstart; ItemStruct witchitem[WITCH_ITEMS]; BOOL stextscrl; int numpremium; ItemStruct healitem[20]; ItemStruct golditem; char storehidx[48]; BYTE *pSTextSlidCels; int stextvhold; int stextsel; char stextscrldbtn; int gossipend; BYTE *pSPentSpn2Cels; int stextsval; int boylevel; ItemStruct smithitem[SMITH_ITEMS]; int stextdown; char stextscrlubtn; char stextflag; 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 }; /** Maps from towner IDs to NPC names. */ const char *const talkname[9] = { "Griswold", "Pepin", "", "Ogden", "Cain", "Farnham", "Adria", "Gillian", "Wirt" }; void InitStores() { int i; pSTextBoxCels = LoadFileInMem("Data\\TextBox2.CEL", NULL); pSPentSpn2Cels = LoadFileInMem("Data\\PentSpn2.CEL", NULL); pSTextSlidCels = LoadFileInMem("Data\\TextSlid.CEL", NULL); ClearSText(0, STORE_LINES); stextflag = STORE_NONE; InStoreFlag = 1; stextsize = FALSE; stextscrl = FALSE; numpremium = 0; premiumlevel = 1; for (i = 0; i < SMITH_PREMIUM_ITEMS; i++) premiumitem[i]._itype = ITYPE_NONE; boyitem._itype = ITYPE_NONE; boylevel = 0; } void SetupTownStores() { int i, l; SetRndSeed(glSeedTbl[currlevel] * GetTickCount()); if (gbMaxPlayers == 1) { l = 0; for (i = 0; i < NUMLEVELS; 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); #ifdef HELLFIRE SpawnPremium(myplr); #else SpawnPremium(plr[myplr]._pLevel); #endif } void FreeStoreMem() { MemFreeDbg(pSTextBoxCels); MemFreeDbg(pSPentSpn2Cels); MemFreeDbg(pSTextSlidCels); } void DrawSTextBack() { CelDraw(PANEL_X + 344, 327 + SCREEN_Y, pSTextBoxCels, 1, 271); #define TRANS_RECT_X (PANEL_LEFT + 347) #define TRANS_RECT_Y 28 #define TRANS_RECT_WIDTH 265 #define TRANS_RECT_HEIGHT 297 #include "asm_trans_rect.inc" } void PrintSString(int x, int y, BOOL cjustflag, const char *str, char col, int val) { int len, width, off, i, k, s; int xx, yy; BYTE c; char valstr[32]; s = SStringY[y] + stext[y]._syoff; if (stextsize != 0) xx = PANEL_X + 32; else xx = PANEL_X + 352; off = xx + x + PitchTbl[s + 44 + SCREEN_Y]; len = strlen(str); if (stextsize != 0) yy = 577; else yy = 257; k = 0; if (cjustflag) { width = 0; for (i = 0; i < len; i++) width += fontkern[fontframe[gbFontTransTbl[(BYTE)str[i]]]] + 1; if (width < yy) k = (yy - width) >> 1; off += k; } if (stextsel == y) { CelDraw(cjustflag ? xx + x + k - 20 : xx + x - 20, s + 45 + SCREEN_Y, pSPentSpn2Cels, InStoreFlag, 12); } for (i = 0; i < len; i++) { c = fontframe[gbFontTransTbl[(BYTE)str[i]]]; k += fontkern[c] + 1; if (c != 0 && k <= yy) { PrintChar(off, c, col); } off += fontkern[c] + 1; } if (!cjustflag && val >= 0) { sprintf(valstr, "%i", val); off = PitchTbl[s + 44 + SCREEN_Y] + PANEL_X + 592 - x; len = strlen(valstr); for (i = len - 1; i >= 0; i--) { c = fontframe[gbFontTransTbl[(BYTE)valstr[i]]]; off -= fontkern[c] + 1; if (c != 0) { PrintChar(off, c, col); } } } if (stextsel == y) { CelDraw(cjustflag ? (xx + x + k + 4) : (PANEL_X + 596 - x), s + 45 + SCREEN_Y, pSPentSpn2Cels, InStoreFlag, 12); } } void DrawSLine(int y) { int xy, yy, width, line, sy; sy = SStringY[y]; if (stextsize) { xy = SCREENXY(PANEL_LEFT + 26, 25); yy = PitchTbl[sy + 38 + SCREEN_Y] + 26 + PANEL_X; width = 586 / 4; // BUGFIX: should be 587, not 586 line = BUFFER_WIDTH - 586; // BUGFIX: should be 587, not 586 } else { xy = SCREENXY(PANEL_LEFT + 346, 25); yy = PitchTbl[sy + 38 + SCREEN_Y] + 346 + PANEL_X; width = 266 / 4; // BUGFIX: should be 267, not 266 line = BUFFER_WIDTH - 266; // BUGFIX: should be 267, not 266 } /// ASSERT: assert(gpBuffer); #ifdef USE_ASM __asm { mov esi, gpBuffer mov edi, esi add esi, xy add edi, yy mov ebx, line mov edx, 3 copyline: mov ecx, width rep movsd movsw add esi, ebx add edi, ebx dec edx jnz copyline } #else int i; BYTE *src, *dst; src = &gpBuffer[xy]; dst = &gpBuffer[yy]; for (i = 0; i < 3; i++, src += BUFFER_WIDTH, dst += BUFFER_WIDTH) memcpy(dst, src, BUFFER_WIDTH - line); #endif } void DrawSSlider(int y1, int y2) { int yd1, yd2, yd3; yd1 = SStringY[y1] + 44 + SCREEN_Y; yd2 = SStringY[y2] + 44 + SCREEN_Y; if (stextscrlubtn != -1) CelDraw(PANEL_X + 601, yd1, pSTextSlidCels, 12, 12); else CelDraw(PANEL_X + 601, yd1, pSTextSlidCels, 10, 12); if (stextscrldbtn != -1) CelDraw(PANEL_X + 601, yd2, pSTextSlidCels, 11, 12); else CelDraw(PANEL_X + 601, yd2, pSTextSlidCels, 9, 12); yd1 += 12; for (yd3 = yd1; yd3 < yd2; yd3 += 12) { CelDraw(PANEL_X + 601, yd3, pSTextSlidCels, 14, 12); } if (stextsel == 22) yd3 = stextlhold; else yd3 = stextsel; if (storenumh > 1) yd3 = 1000 * (stextsval + ((yd3 - stextup) >> 2)) / (storenumh - 1) * (SStringY[y2] - SStringY[y1] - 24) / 1000; else yd3 = 0; CelDraw(PANEL_X + 601, SStringY[y1 + 1] + 44 + SCREEN_Y + yd3, pSTextSlidCels, 13, 12); } void DrawSTextHelp() { stextsel = -1; stextsize = TRUE; } void ClearSText(int s, int e) { int i; for (i = s; i < e; i++) { stext[i]._sx = 0; stext[i]._syoff = 0; stext[i]._sstr[0] = 0; stext[i]._sjust = FALSE; stext[i]._sclr = COL_WHITE; stext[i]._sline = 0; stext[i]._ssel = FALSE; stext[i]._sval = -1; } } void AddSLine(int y) { stext[y]._sx = 0; stext[y]._syoff = 0; stext[y]._sstr[0] = 0; stext[y]._sline = 1; } void AddSTextVal(int y, int val) { stext[y]._sval = val; } void OffsetSTextY(int y, int yo) { stext[y]._syoff = yo; } void AddSText(int x, int y, BOOL j, const char *str, char clr, BOOL sel) { stext[y]._sx = x; stext[y]._syoff = 0; strcpy(stext[y]._sstr, str); stext[y]._sjust = j; stext[y]._sclr = clr; stext[y]._sline = 0; stext[y]._ssel = sel; } static void PrintStoreItem(ItemStruct *x, int l, char iclr) { char sstr[128]; char str, dex; BYTE mag; sstr[0] = '\0'; if (x->_iIdentified) { if (x->_iMagical != ITEM_QUALITY_UNIQUE) { if (x->_iPrePower != -1) { PrintItemPower(x->_iPrePower, x); strcat(sstr, tempstr); } } if (x->_iSufPower != -1) { PrintItemPower(x->_iSufPower, x); if (sstr[0]) strcat(sstr, ", "); strcat(sstr, tempstr); } } if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) { sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges); if (sstr[0]) strcat(sstr, ", "); strcat(sstr, tempstr); } if (sstr[0]) { AddSText(40, l, FALSE, sstr, iclr, FALSE); l++; } sstr[0] = '\0'; if (x->_iClass == ICLASS_WEAPON) sprintf(sstr, "Damage: %i-%i ", x->_iMinDam, x->_iMaxDam); if (x->_iClass == ICLASS_ARMOR) sprintf(sstr, "Armor: %i ", x->_iAC); if (x->_iMaxDur != DUR_INDESTRUCTIBLE && x->_iMaxDur) { sprintf(tempstr, "Dur: %i/%i, ", x->_iDurability, x->_iMaxDur); strcat(sstr, tempstr); } else { strcat(sstr, "Indestructible, "); } if (x->_itype == ITYPE_MISC) sstr[0] = '\0'; str = x->_iMinStr; dex = x->_iMinDex; mag = x->_iMinMag; if ((str + mag + dex) == 0) { strcat(sstr, "No required attributes"); } else { strcpy(tempstr, "Required:"); if (x->_iMinStr) sprintf(tempstr, "%s %i Str", tempstr, x->_iMinStr); if (x->_iMinMag) sprintf(tempstr, "%s %i Mag", tempstr, x->_iMinMag); if (x->_iMinDex) sprintf(tempstr, "%s %i Dex", tempstr, x->_iMinDex); strcat(sstr, tempstr); } AddSText(40, l++, FALSE, sstr, iclr, FALSE); if (x->_iMagical == ITEM_QUALITY_UNIQUE) { if (x->_iIdentified) AddSText(40, l, FALSE, "Unique Item", iclr, FALSE); } } void StoreAutoPlace() { BOOL done; int i, w, h, idx; SetICursor(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM); w = icursW28; h = icursH28; done = FALSE; if (w == 1 && h == 1) { idx = plr[myplr].HoldItem.IDidx; if (plr[myplr].HoldItem._iStatFlag && AllItemsList[idx].iUsable) { for (i = 0; i < MAXBELTITEMS && !done; i++) { if (plr[myplr].SpdList[i]._itype == ITYPE_NONE) { plr[myplr].SpdList[i] = plr[myplr].HoldItem; done = TRUE; } } } for (i = 30; i <= 39 && !done; i++) { done = AutoPlace(myplr, i, w, h, TRUE); } for (i = 20; i <= 29 && !done; i++) { done = AutoPlace(myplr, i, w, h, TRUE); } for (i = 10; i <= 19 && !done; i++) { done = AutoPlace(myplr, i, w, h, TRUE); } for (i = 0; i <= 9 && !done; i++) { done = AutoPlace(myplr, i, w, h, TRUE); } } if (w == 1 && h == 2) { for (i = 29; i >= 20 && !done; i--) { done = AutoPlace(myplr, i, w, h, TRUE); } for (i = 9; i >= 0 && !done; i--) { done = AutoPlace(myplr, i, w, h, TRUE); } for (i = 19; i >= 10 && !done; i--) { done = AutoPlace(myplr, i, w, h, TRUE); } } if (w == 1 && h == 3) { for (i = 0; i < 20 && !done; i++) { done = AutoPlace(myplr, i, w, h, TRUE); } } if (w == 2 && h == 2) { for (i = 0; i < 10 && !done; i++) { done = AutoPlace(myplr, AP2x2Tbl[i], w, h, TRUE); } for (i = 21; i < 29 && !done; i += 2) { done = AutoPlace(myplr, i, w, h, TRUE); } for (i = 1; i < 9 && !done; i += 2) { done = AutoPlace(myplr, i, w, h, TRUE); } for (i = 10; i < 19 && !done; i++) { done = AutoPlace(myplr, i, w, h, TRUE); } } if (w == 2 && h == 3) { for (i = 0; i < 9 && !done; i++) { done = AutoPlace(myplr, i, w, h, TRUE); } for (i = 10; i < 19 && !done; i++) { done = AutoPlace(myplr, i, w, h, TRUE); } } } void S_StartSmith() { stextsize = FALSE; stextscrl = FALSE; AddSText(0, 1, TRUE, "Welcome to the", COL_GOLD, FALSE); AddSText(0, 3, TRUE, "Blacksmith's shop", COL_GOLD, FALSE); AddSText(0, 7, TRUE, "Would you like to:", COL_GOLD, FALSE); AddSText(0, 10, TRUE, "Talk to Griswold", COL_BLUE, TRUE); AddSText(0, 12, TRUE, "Buy basic items", COL_WHITE, TRUE); AddSText(0, 14, TRUE, "Buy premium items", COL_WHITE, TRUE); AddSText(0, 16, TRUE, "Sell items", COL_WHITE, TRUE); AddSText(0, 18, TRUE, "Repair items", COL_WHITE, TRUE); AddSText(0, 20, TRUE, "Leave the shop", COL_WHITE, TRUE); AddSLine(5); storenumh = 20; } void S_ScrollSBuy(int idx) { int l, ls; char iclr; ls = idx; ClearSText(5, 21); stextup = 5; for (l = 5; l < 20; l += 4) { if (smithitem[ls]._itype != ITYPE_NONE) { iclr = COL_WHITE; if (smithitem[ls]._iMagical) { iclr = COL_BLUE; } if (!smithitem[ls]._iStatFlag) { iclr = COL_RED; } if (smithitem[ls]._iMagical) { AddSText(20, l, FALSE, smithitem[ls]._iIName, iclr, TRUE); } else { AddSText(20, l, FALSE, smithitem[ls]._iName, iclr, TRUE); } AddSTextVal(l, smithitem[ls]._iIvalue); PrintStoreItem(&smithitem[ls], l + 1, iclr); stextdown = l; ls++; } } if (!stext[stextsel]._ssel && stextsel != 22) stextsel = stextdown; } void S_StartSBuy() { int i; stextsize = TRUE; stextscrl = TRUE; stextsval = 0; sprintf(tempstr, "I have these items for sale : Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); S_ScrollSBuy(stextsval); AddSText(0, 22, TRUE, "Back", COL_WHITE, FALSE); OffsetSTextY(22, 6); storenumh = 0; for (i = 0; smithitem[i]._itype != ITYPE_NONE; i++) { storenumh++; } stextsmax = storenumh - 4; if (stextsmax < 0) stextsmax = 0; } void S_ScrollSPBuy(int idx) { int l, boughtitems; char iclr; ClearSText(5, 21); boughtitems = idx; stextup = 5; for (idx = 0; boughtitems; idx++) { if (premiumitem[idx]._itype != ITYPE_NONE) boughtitems--; } for (l = 5; l < 20 && idx < SMITH_PREMIUM_ITEMS; l += 4) { if (premiumitem[idx]._itype != ITYPE_NONE) { iclr = COL_WHITE; if (premiumitem[idx]._iMagical) iclr = COL_BLUE; if (!premiumitem[idx]._iStatFlag) iclr = COL_RED; AddSText(20, l, FALSE, premiumitem[idx]._iIName, iclr, TRUE); AddSTextVal(l, premiumitem[idx]._iIvalue); PrintStoreItem(&premiumitem[idx], l + 1, iclr); stextdown = l; } else { l -= 4; } idx++; } if (!stext[stextsel]._ssel && stextsel != 22) stextsel = stextdown; } BOOL S_StartSPBuy() { int i; storenumh = 0; for (i = 0; i < SMITH_PREMIUM_ITEMS; i++) { if (premiumitem[i]._itype != ITYPE_NONE) storenumh++; } if (!storenumh) { StartStore(STORE_SMITH); stextsel = 14; return FALSE; } stextsize = TRUE; stextscrl = TRUE; stextsval = 0; sprintf(tempstr, "I have these premium items for sale : Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); AddSText(0, 22, TRUE, "Back", COL_WHITE, FALSE); OffsetSTextY(22, 6); stextsmax = storenumh - 4; if (stextsmax < 0) stextsmax = 0; S_ScrollSPBuy(stextsval); return TRUE; } BOOL SmithSellOk(int i) { #ifdef HELLFIRE ItemStruct *pI; if (i >= 0) { pI = &plr[myplr].InvList[i]; } else { pI = &plr[myplr].SpdList[-(i + 1)]; } if (pI->_itype == ITYPE_NONE) return FALSE; if (pI->_iMiscId > IMISC_OILFIRST && pI->_iMiscId < IMISC_OILLAST) return TRUE; if (pI->_itype == ITYPE_MISC) return FALSE; if (pI->_itype == ITYPE_GOLD) return FALSE; if (pI->_itype == ITYPE_FOOD) return FALSE; if (pI->_itype == ITYPE_STAFF && pI->_iSpell != SPL_NULL) return FALSE; if (pI->_iClass == ICLASS_QUEST) return FALSE; if (pI->IDidx == IDI_LAZSTAFF) return FALSE; #else if (plr[myplr].InvList[i]._itype == ITYPE_NONE) return FALSE; if (plr[myplr].InvList[i]._itype == ITYPE_MISC) return FALSE; if (plr[myplr].InvList[i]._itype == ITYPE_GOLD) return FALSE; if (plr[myplr].InvList[i]._itype == ITYPE_FOOD) return FALSE; if (plr[myplr].InvList[i]._itype == ITYPE_STAFF) return FALSE; if (plr[myplr].InvList[i].IDidx == IDI_LAZSTAFF) return FALSE; #endif return TRUE; } void S_ScrollSSell(int idx) { int l; char iclr; ClearSText(5, 21); stextup = 5; for (l = 5; l < 20; l += 4) { if (idx >= storenumh) break; if (storehold[idx]._itype != ITYPE_NONE) { iclr = COL_WHITE; if (storehold[idx]._iMagical) { iclr = COL_BLUE; } if (!storehold[idx]._iStatFlag) { iclr = COL_RED; } if (storehold[idx]._iMagical && storehold[idx]._iIdentified) { AddSText(20, l, FALSE, storehold[idx]._iIName, iclr, TRUE); AddSTextVal(l, storehold[idx]._iIvalue); } else { AddSText(20, l, FALSE, storehold[idx]._iName, iclr, TRUE); AddSTextVal(l, storehold[idx]._ivalue); } PrintStoreItem(&storehold[idx], l + 1, iclr); stextdown = l; } idx++; } stextsmax = storenumh - 4; if (stextsmax < 0) stextsmax = 0; } void S_StartSSell() { int i; BOOL sellok; stextsize = TRUE; sellok = FALSE; storenumh = 0; for (i = 0; i < 48; i++) storehold[i]._itype = ITYPE_NONE; for (i = 0; i < plr[myplr]._pNumInv; i++) { #ifdef HELLFIRE if (storenumh >= 48) break; #endif if (SmithSellOk(i)) { sellok = TRUE; storehold[storenumh] = plr[myplr].InvList[i]; if (storehold[storenumh]._iMagical != ITEM_QUALITY_NORMAL && storehold[storenumh]._iIdentified) storehold[storenumh]._ivalue = storehold[storenumh]._iIvalue; if ((storehold[storenumh]._ivalue >>= 2) == 0) storehold[storenumh]._ivalue = 1; storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue; storehidx[storenumh++] = i; } } #ifdef HELLFIRE for (i = 0; i < MAXBELTITEMS; i++) { if (storenumh >= 48) break; if (SmithSellOk(-(i + 1))) { storehold[storenumh] = plr[myplr].SpdList[i]; sellok = TRUE; if (storehold[storenumh]._iMagical != ITEM_QUALITY_NORMAL && 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 + 1); } } #endif if (!sellok) { stextscrl = FALSE; sprintf(tempstr, "You have nothing I want. Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); OffsetSTextY(22, 6); } else { stextscrl = TRUE; stextsval = 0; stextsmax = plr[myplr]._pNumInv; sprintf(tempstr, "Which item is for sale? Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); S_ScrollSSell(stextsval); AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); OffsetSTextY(22, 6); } } BOOL SmithRepairOk(int i) { if (plr[myplr].InvList[i]._itype == ITYPE_NONE) return FALSE; if (plr[myplr].InvList[i]._itype == ITYPE_MISC) return FALSE; if (plr[myplr].InvList[i]._itype == ITYPE_GOLD) return FALSE; if (plr[myplr].InvList[i]._itype == ITYPE_FOOD) return FALSE; if (plr[myplr].InvList[i]._iDurability == plr[myplr].InvList[i]._iMaxDur) return FALSE; return TRUE; } static void AddStoreHoldRepair(ItemStruct *itm, int i) { ItemStruct *item; int v; item = &storehold[storenumh]; storehold[storenumh] = *itm; if (item->_iMagical != ITEM_QUALITY_NORMAL && item->_iIdentified) item->_ivalue = 30 * item->_iIvalue / 100; v = item->_ivalue * (100 * (item->_iMaxDur - item->_iDurability) / item->_iMaxDur) / 100; if (!v) { if (item->_iMagical != ITEM_QUALITY_NORMAL && item->_iIdentified) return; v = 1; } if (v > 1) v >>= 1; item->_iIvalue = v; item->_ivalue = v; storehidx[storenumh] = i; storenumh++; } void S_StartSRepair() { BOOL repairok; int i; stextsize = TRUE; repairok = FALSE; storenumh = 0; for (i = 0; i < 48; i++) storehold[i]._itype = ITYPE_NONE; if (plr[myplr].InvBody[INVLOC_HEAD]._itype != ITYPE_NONE && plr[myplr].InvBody[INVLOC_HEAD]._iDurability != plr[myplr].InvBody[INVLOC_HEAD]._iMaxDur) { repairok = TRUE; AddStoreHoldRepair(plr[myplr].InvBody, -1); } if (plr[myplr].InvBody[INVLOC_CHEST]._itype != ITYPE_NONE && plr[myplr].InvBody[INVLOC_CHEST]._iDurability != plr[myplr].InvBody[INVLOC_CHEST]._iMaxDur) { repairok = TRUE; AddStoreHoldRepair(&plr[myplr].InvBody[INVLOC_CHEST], -2); } if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_NONE && plr[myplr].InvBody[INVLOC_HAND_LEFT]._iDurability != plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMaxDur) { repairok = TRUE; AddStoreHoldRepair(&plr[myplr].InvBody[INVLOC_HAND_LEFT], -3); } if (plr[myplr].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_NONE && plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iDurability != plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iMaxDur) { repairok = TRUE; AddStoreHoldRepair(&plr[myplr].InvBody[INVLOC_HAND_RIGHT], -4); } for (i = 0; i < plr[myplr]._pNumInv; i++) { #ifdef HELLFIRE if (storenumh >= 48) break; #endif if (SmithRepairOk(i)) { repairok = TRUE; AddStoreHoldRepair(&plr[myplr].InvList[i], i); } } if (!repairok) { stextscrl = FALSE; sprintf(tempstr, "You have nothing to repair. Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); OffsetSTextY(22, 6); return; } stextscrl = TRUE; stextsval = 0; stextsmax = plr[myplr]._pNumInv; sprintf(tempstr, "Repair which item? Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); S_ScrollSSell(stextsval); AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); OffsetSTextY(22, 6); } void S_StartWitch() { stextsize = FALSE; stextscrl = FALSE; AddSText(0, 2, TRUE, "Witch's shack", COL_GOLD, FALSE); AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE); AddSText(0, 12, TRUE, "Talk to Adria", COL_BLUE, TRUE); AddSText(0, 14, TRUE, "Buy items", COL_WHITE, TRUE); AddSText(0, 16, TRUE, "Sell items", COL_WHITE, TRUE); AddSText(0, 18, TRUE, "Recharge staves", COL_WHITE, TRUE); AddSText(0, 20, TRUE, "Leave the shack", COL_WHITE, TRUE); AddSLine(5); storenumh = 20; } void S_ScrollWBuy(int idx) { int l, ls; char iclr; ls = idx; ClearSText(5, 21); stextup = 5; for (l = 5; l < 20; l += 4) { if (witchitem[ls]._itype != ITYPE_NONE) { iclr = COL_WHITE; if (witchitem[ls]._iMagical) { iclr = COL_BLUE; } if (!witchitem[ls]._iStatFlag) { iclr = COL_RED; } if (witchitem[ls]._iMagical) { AddSText(20, l, FALSE, witchitem[ls]._iIName, iclr, TRUE); } else { AddSText(20, l, FALSE, witchitem[ls]._iName, iclr, TRUE); } AddSTextVal(l, witchitem[ls]._iIvalue); PrintStoreItem(&witchitem[ls], l + 1, iclr); stextdown = l; ls++; } } if (!stext[stextsel]._ssel && stextsel != 22) stextsel = stextdown; } void S_StartWBuy() { int i; stextsize = TRUE; stextscrl = TRUE; stextsval = 0; stextsmax = 20; sprintf(tempstr, "I have these items for sale : Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); S_ScrollWBuy(stextsval); AddSText(0, 22, TRUE, "Back", COL_WHITE, FALSE); OffsetSTextY(22, 6); storenumh = 0; for (i = 0; witchitem[i]._itype != ITYPE_NONE; i++) { storenumh++; } stextsmax = storenumh - 4; if (stextsmax < 0) stextsmax = 0; } BOOL WitchSellOk(int i) { BOOL rv; ItemStruct *pI; rv = FALSE; if (i >= 0) pI = &plr[myplr].InvList[i]; else pI = &plr[myplr].SpdList[-(i + 1)]; if (pI->_itype == ITYPE_MISC) rv = TRUE; #ifdef HELLFIRE if (pI->_iMiscId > 29 && pI->_iMiscId < 41) rv = FALSE; if (pI->_iClass == ICLASS_QUEST) rv = FALSE; if (pI->_itype == ITYPE_STAFF && pI->_iSpell != SPL_NULL) #else if (pI->_itype == ITYPE_STAFF) #endif rv = TRUE; if (pI->IDidx >= IDI_FIRSTQUEST && pI->IDidx <= IDI_LASTQUEST) rv = FALSE; if (pI->IDidx == IDI_LAZSTAFF) rv = FALSE; return rv; } void S_StartWSell() { int i; BOOL sellok; stextsize = TRUE; sellok = FALSE; storenumh = 0; for (i = 0; i < 48; i++) storehold[i]._itype = ITYPE_NONE; for (i = 0; i < plr[myplr]._pNumInv; i++) { #ifdef HELLFIRE if (storenumh >= 48) break; #endif if (WitchSellOk(i)) { sellok = TRUE; storehold[storenumh] = plr[myplr].InvList[i]; if (storehold[storenumh]._iMagical != ITEM_QUALITY_NORMAL && storehold[storenumh]._iIdentified) storehold[storenumh]._ivalue = storehold[storenumh]._iIvalue; if ((storehold[storenumh]._ivalue >>= 2) == 0) storehold[storenumh]._ivalue = 1; storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue; storehidx[storenumh++] = i; } } for (i = 0; i < MAXBELTITEMS; i++) { #ifdef HELLFIRE if (storenumh >= 48) break; #endif if (plr[myplr].SpdList[i]._itype != ITYPE_NONE && WitchSellOk(-(i + 1))) { sellok = TRUE; storehold[storenumh] = plr[myplr].SpdList[i]; if (storehold[storenumh]._iMagical != ITEM_QUALITY_NORMAL && storehold[storenumh]._iIdentified) storehold[storenumh]._ivalue = storehold[storenumh]._iIvalue; if ((storehold[storenumh]._ivalue >>= 2) == 0) storehold[storenumh]._ivalue = 1; storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue; storehidx[storenumh++] = -(i + 1); } } if (!sellok) { stextscrl = FALSE; sprintf(tempstr, "You have nothing I want. Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); OffsetSTextY(22, 6); } else { stextscrl = TRUE; stextsval = 0; stextsmax = plr[myplr]._pNumInv; sprintf(tempstr, "Which item is for sale? Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); S_ScrollSSell(stextsval); AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); OffsetSTextY(22, 6); } } BOOL WitchRechargeOk(int i) { BOOL rv; rv = FALSE; if (plr[myplr].InvList[i]._itype == ITYPE_STAFF && plr[myplr].InvList[i]._iCharges != plr[myplr].InvList[i]._iMaxCharges) { rv = TRUE; } #ifdef HELLFIRE if ((plr[myplr].InvList[i]._iMiscId == IMISC_UNIQUE || plr[myplr].InvList[i]._iMiscId == IMISC_STAFF) && plr[myplr].InvList[i]._iCharges < plr[myplr].InvList[i]._iMaxCharges) { rv = TRUE; } #endif return rv; } void AddStoreHoldRecharge(ItemStruct itm, int i) { storehold[storenumh] = itm; storehold[storenumh]._ivalue += spelldata[itm._iSpell].sStaffCost; storehold[storenumh]._ivalue = storehold[storenumh]._ivalue * (100 * (storehold[storenumh]._iMaxCharges - storehold[storenumh]._iCharges) / storehold[storenumh]._iMaxCharges) / 100 >> 1; storehold[storenumh]._iIvalue = storehold[storenumh]._ivalue; storehidx[storenumh] = i; storenumh++; } void S_StartWRecharge() { int i; BOOL rechargeok; stextsize = TRUE; rechargeok = FALSE; storenumh = 0; for (i = 0; i < 48; i++) { storehold[i]._itype = ITYPE_NONE; } #ifdef HELLFIRE if ((plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_STAFF || plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_UNIQUE) #else if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_STAFF #endif && plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges != plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMaxCharges) { rechargeok = TRUE; AddStoreHoldRecharge(plr[myplr].InvBody[INVLOC_HAND_LEFT], -1); } for (i = 0; i < plr[myplr]._pNumInv; i++) { #ifdef HELLFIRE if (storenumh >= 48) break; #endif if (WitchRechargeOk(i)) { rechargeok = TRUE; AddStoreHoldRecharge(plr[myplr].InvList[i], i); } } if (!rechargeok) { stextscrl = FALSE; sprintf(tempstr, "You have nothing to recharge. Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); OffsetSTextY(22, 6); } else { stextscrl = TRUE; stextsval = 0; stextsmax = plr[myplr]._pNumInv; sprintf(tempstr, "Recharge which item? Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); S_ScrollSSell(stextsval); AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); OffsetSTextY(22, 6); } } void S_StartNoMoney() { StartStore(stextshold); stextscrl = FALSE; stextsize = TRUE; ClearSText(5, 23); AddSText(0, 14, TRUE, "You do not have enough gold", COL_WHITE, TRUE); } void S_StartNoRoom() { StartStore(stextshold); stextscrl = FALSE; ClearSText(5, 23); AddSText(0, 14, TRUE, "You do not have enough room in inventory", COL_WHITE, TRUE); } void S_StartConfirm() { BOOL idprint; char iclr; StartStore(stextshold); stextscrl = FALSE; ClearSText(5, 23); iclr = COL_WHITE; if (plr[myplr].HoldItem._iMagical != ITEM_QUALITY_NORMAL) iclr = COL_BLUE; if (!plr[myplr].HoldItem._iStatFlag) iclr = COL_RED; idprint = plr[myplr].HoldItem._iMagical != ITEM_QUALITY_NORMAL; if (stextshold == STORE_SIDENTIFY) idprint = FALSE; if (plr[myplr].HoldItem._iMagical != ITEM_QUALITY_NORMAL && !plr[myplr].HoldItem._iIdentified) { if (stextshold == STORE_SSELL) idprint = FALSE; if (stextshold == STORE_WSELL) idprint = FALSE; if (stextshold == STORE_SREPAIR) idprint = FALSE; if (stextshold == STORE_WRECHARGE) idprint = FALSE; } if (idprint) AddSText(20, 8, FALSE, plr[myplr].HoldItem._iIName, iclr, FALSE); else AddSText(20, 8, FALSE, plr[myplr].HoldItem._iName, iclr, FALSE); AddSTextVal(8, plr[myplr].HoldItem._iIvalue); PrintStoreItem(&plr[myplr].HoldItem, 9, iclr); switch (stextshold) { case STORE_BBOY: strcpy(tempstr, "Do we have a deal?"); break; case STORE_SIDENTIFY: strcpy(tempstr, "Are you sure you want to identify this item?"); break; case STORE_HBUY: case STORE_SPBUY: case STORE_WBUY: case STORE_SBUY: strcpy(tempstr, "Are you sure you want to buy this item?"); break; case STORE_WRECHARGE: strcpy(tempstr, "Are you sure you want to recharge this item?"); break; case STORE_SSELL: case STORE_WSELL: 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; } AddSText(0, 15, TRUE, tempstr, COL_WHITE, FALSE); AddSText(0, 18, TRUE, "Yes", COL_WHITE, TRUE); AddSText(0, 20, TRUE, "No", COL_WHITE, TRUE); } void S_StartBoy() { stextsize = FALSE; stextscrl = FALSE; AddSText(0, 2, TRUE, "Wirt the Peg-legged boy", COL_GOLD, FALSE); AddSLine(5); if (boyitem._itype != ITYPE_NONE) { AddSText(0, 8, TRUE, "Talk to Wirt", COL_BLUE, TRUE); AddSText(0, 12, TRUE, "I have something for sale,", COL_GOLD, FALSE); AddSText(0, 14, TRUE, "but it will cost 50 gold", COL_GOLD, FALSE); AddSText(0, 16, TRUE, "just to take a look. ", COL_GOLD, FALSE); AddSText(0, 18, TRUE, "What have you got?", COL_WHITE, TRUE); AddSText(0, 20, TRUE, "Say goodbye", COL_WHITE, TRUE); } else { AddSText(0, 12, TRUE, "Talk to Wirt", COL_BLUE, TRUE); AddSText(0, 18, TRUE, "Say goodbye", COL_WHITE, TRUE); } } void S_StartBBoy() { int iclr; stextsize = TRUE; stextscrl = FALSE; sprintf(tempstr, "I have this item for sale : Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); iclr = COL_WHITE; if (boyitem._iMagical != ITEM_QUALITY_NORMAL) iclr = COL_BLUE; if (!boyitem._iStatFlag) iclr = COL_RED; if (boyitem._iMagical != ITEM_QUALITY_NORMAL) AddSText(20, 10, FALSE, boyitem._iIName, iclr, TRUE); else AddSText(20, 10, FALSE, boyitem._iName, iclr, TRUE); #ifdef HELLFIRE AddSTextVal(10, boyitem._iIvalue - (boyitem._iIvalue >> 2)); #else AddSTextVal(10, boyitem._iIvalue + (boyitem._iIvalue >> 1)); #endif PrintStoreItem(&boyitem, 11, iclr); AddSText(0, 22, TRUE, "Leave", COL_WHITE, TRUE); OffsetSTextY(22, 6); } void S_StartHealer() { #ifdef HELLFIRE if (plr[myplr]._pHitPoints != plr[myplr]._pMaxHP) { PlaySFX(IS_CAST8); } plr[myplr]._pHitPoints = plr[myplr]._pMaxHP; plr[myplr]._pHPBase = plr[myplr]._pMaxHPBase; drawhpflag = TRUE; #endif stextsize = FALSE; stextscrl = FALSE; AddSText(0, 1, TRUE, "Welcome to the", COL_GOLD, FALSE); AddSText(0, 3, TRUE, "Healer's home", COL_GOLD, FALSE); AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE); AddSText(0, 12, TRUE, "Talk to Pepin", COL_BLUE, TRUE); #ifdef HELLFIRE AddSText(0, 14, TRUE, "Buy items", COL_WHITE, TRUE); AddSText(0, 16, TRUE, "Leave Healer's home", COL_WHITE, TRUE); #else AddSText(0, 14, TRUE, "Receive healing", COL_WHITE, TRUE); AddSText(0, 16, TRUE, "Buy items", COL_WHITE, TRUE); AddSText(0, 18, TRUE, "Leave Healer's home", COL_WHITE, TRUE); #endif AddSLine(5); storenumh = 20; } void S_ScrollHBuy(int idx) { int l; char iclr; ClearSText(5, 21); stextup = 5; for (l = 5; l < 20; l += 4) { if (healitem[idx]._itype != ITYPE_NONE) { iclr = COL_WHITE; if (!healitem[idx]._iStatFlag) { iclr = COL_RED; } AddSText(20, l, FALSE, healitem[idx]._iName, iclr, TRUE); AddSTextVal(l, healitem[idx]._iIvalue); PrintStoreItem(&healitem[idx], l + 1, iclr); stextdown = l; idx++; } } if (!stext[stextsel]._ssel && stextsel != 22) stextsel = stextdown; } void S_StartHBuy() { int i; stextsize = TRUE; stextscrl = TRUE; stextsval = 0; sprintf(tempstr, "I have these items for sale : Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); S_ScrollHBuy(stextsval); AddSText(0, 22, TRUE, "Back", COL_WHITE, FALSE); OffsetSTextY(22, 6); storenumh = 0; for (i = 0; healitem[i]._itype != ITYPE_NONE; i++) { storenumh++; } stextsmax = storenumh - 4; if (stextsmax < 0) stextsmax = 0; } void S_StartStory() { stextsize = FALSE; stextscrl = FALSE; AddSText(0, 2, TRUE, "The Town Elder", COL_GOLD, FALSE); AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE); AddSText(0, 12, TRUE, "Talk to Cain", COL_BLUE, TRUE); AddSText(0, 14, TRUE, "Identify an item", COL_WHITE, TRUE); AddSText(0, 18, TRUE, "Say goodbye", COL_WHITE, TRUE); AddSLine(5); } BOOL IdItemOk(ItemStruct *i) { if (i->_itype == ITYPE_NONE) { return FALSE; } if (i->_iMagical == ITEM_QUALITY_NORMAL) { return FALSE; } return !i->_iIdentified; } void AddStoreHoldId(ItemStruct itm, int i) { storehold[storenumh] = itm; storehold[storenumh]._ivalue = 100; storehold[storenumh]._iIvalue = 100; storehidx[storenumh] = i; storenumh++; } void S_StartSIdentify() { BOOL idok; int i; idok = FALSE; stextsize = TRUE; storenumh = 0; for (i = 0; i < 48; i++) storehold[i]._itype = ITYPE_NONE; if (IdItemOk(&plr[myplr].InvBody[INVLOC_HEAD])) { idok = TRUE; AddStoreHoldId(plr[myplr].InvBody[INVLOC_HEAD], -1); } if (IdItemOk(&plr[myplr].InvBody[INVLOC_CHEST])) { idok = TRUE; AddStoreHoldId(plr[myplr].InvBody[INVLOC_CHEST], -2); } if (IdItemOk(&plr[myplr].InvBody[INVLOC_HAND_LEFT])) { idok = TRUE; AddStoreHoldId(plr[myplr].InvBody[INVLOC_HAND_LEFT], -3); } if (IdItemOk(&plr[myplr].InvBody[INVLOC_HAND_RIGHT])) { idok = TRUE; AddStoreHoldId(plr[myplr].InvBody[INVLOC_HAND_RIGHT], -4); } if (IdItemOk(&plr[myplr].InvBody[INVLOC_RING_LEFT])) { idok = TRUE; AddStoreHoldId(plr[myplr].InvBody[INVLOC_RING_LEFT], -5); } if (IdItemOk(&plr[myplr].InvBody[INVLOC_RING_RIGHT])) { idok = TRUE; AddStoreHoldId(plr[myplr].InvBody[INVLOC_RING_RIGHT], -6); } if (IdItemOk(&plr[myplr].InvBody[INVLOC_AMULET])) { idok = TRUE; AddStoreHoldId(plr[myplr].InvBody[INVLOC_AMULET], -7); } for (i = 0; i < plr[myplr]._pNumInv; i++) { #ifdef HELLFIRE if (storenumh >= 48) break; #endif if (IdItemOk(&plr[myplr].InvList[i])) { idok = TRUE; AddStoreHoldId(plr[myplr].InvList[i], i); } } if (!idok) { stextscrl = FALSE; sprintf(tempstr, "You have nothing to identify. Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); OffsetSTextY(22, 6); } else { stextscrl = TRUE; stextsval = 0; stextsmax = plr[myplr]._pNumInv; sprintf(tempstr, "Identify which item? Your gold : %i", plr[myplr]._pGold); AddSText(0, 1, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(3); AddSLine(21); S_ScrollSSell(stextsval); AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); OffsetSTextY(22, 6); } } void S_StartIdShow() { char iclr; StartStore(stextshold); stextscrl = FALSE; ClearSText(5, 23); iclr = COL_WHITE; if (plr[myplr].HoldItem._iMagical != ITEM_QUALITY_NORMAL) iclr = COL_BLUE; if (!plr[myplr].HoldItem._iStatFlag) iclr = COL_RED; AddSText(0, 7, TRUE, "This item is:", COL_WHITE, FALSE); AddSText(20, 11, FALSE, plr[myplr].HoldItem._iIName, iclr, FALSE); PrintStoreItem(&plr[myplr].HoldItem, 12, iclr); AddSText(0, 18, TRUE, "Done", COL_WHITE, TRUE); } void S_StartTalk() { int i, sn, sn2, la; stextsize = FALSE; stextscrl = FALSE; sprintf(tempstr, "Talk to %s", talkname[talker]); AddSText(0, 2, TRUE, tempstr, COL_GOLD, FALSE); AddSLine(5); #ifdef SPAWN sprintf(tempstr, "Talking to %s", talkname[talker]); AddSText(0, 10, TRUE, tempstr, COL_WHITE, FALSE); AddSText(0, 12, TRUE, "is not available", COL_WHITE, FALSE); AddSText(0, 14, TRUE, "in the shareware", COL_WHITE, FALSE); AddSText(0, 16, TRUE, "version", COL_WHITE, FALSE); #else sn = 0; for (i = 0; i < MAXQUESTS; i++) { if (quests[i]._qactive == QUEST_ACTIVE && ((DWORD *)&Qtalklist[talker])[i] != -1 && quests[i]._qlog) sn++; } if (sn > 6) { sn = 14 - (sn >> 1); la = 1; } else { sn = 15 - sn; la = 2; } sn2 = sn - 2; for (i = 0; i < MAXQUESTS; i++) { if (quests[i]._qactive == QUEST_ACTIVE && ((DWORD *)&Qtalklist[talker])[i] != -1 && quests[i]._qlog) { AddSText(0, sn, TRUE, questlist[i]._qlstr, COL_WHITE, TRUE); sn += la; } } AddSText(0, sn2, TRUE, "Gossip", COL_BLUE, TRUE); #endif AddSText(0, 22, TRUE, "Back", COL_WHITE, TRUE); } void S_StartTavern() { stextsize = FALSE; stextscrl = FALSE; AddSText(0, 1, TRUE, "Welcome to the", COL_GOLD, FALSE); AddSText(0, 3, TRUE, "Rising Sun", COL_GOLD, FALSE); AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE); AddSText(0, 12, TRUE, "Talk to Ogden", COL_BLUE, TRUE); AddSText(0, 18, TRUE, "Leave the tavern", COL_WHITE, TRUE); AddSLine(5); storenumh = 20; } void S_StartBarMaid() { stextsize = FALSE; stextscrl = FALSE; AddSText(0, 2, TRUE, "Gillian", COL_GOLD, FALSE); AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE); AddSText(0, 12, TRUE, "Talk to Gillian", COL_BLUE, TRUE); AddSText(0, 18, TRUE, "Say goodbye", COL_WHITE, TRUE); AddSLine(5); storenumh = 20; } void S_StartDrunk() { stextsize = FALSE; stextscrl = FALSE; AddSText(0, 2, TRUE, "Farnham the Drunk", COL_GOLD, FALSE); AddSText(0, 9, TRUE, "Would you like to:", COL_GOLD, FALSE); AddSText(0, 12, TRUE, "Talk to Farnham", COL_BLUE, TRUE); AddSText(0, 18, TRUE, "Say Goodbye", COL_WHITE, TRUE); AddSLine(5); storenumh = 20; } void StartStore(char s) { char t; int i; for (t = s;; t = STORE_SMITH) { sbookflag = FALSE; invflag = FALSE; chrflag = FALSE; questlog = FALSE; dropGoldFlag = FALSE; ClearSText(0, STORE_LINES); 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; } for (i = 0; i < STORE_LINES; i++) { if (stext[i]._ssel) break; } stextsel = i == STORE_LINES ? -1 : i; stextflag = t; if (t != STORE_SBUY || storenumh) break; } } void DrawSText() { int i; if (!stextsize) DrawSTextBack(); else DrawQTextBack(); if (stextscrl) { switch (stextflag) { case STORE_SBUY: S_ScrollSBuy(stextsval); break; case STORE_SSELL: case STORE_SREPAIR: case STORE_WSELL: case STORE_WRECHARGE: case STORE_SIDENTIFY: S_ScrollSSell(stextsval); break; case STORE_WBUY: S_ScrollWBuy(stextsval); break; case STORE_HBUY: S_ScrollHBuy(stextsval); break; case STORE_SPBUY: S_ScrollSPBuy(stextsval); break; } } for (i = 0; i < STORE_LINES; i++) { if (stext[i]._sline) DrawSLine(i); if (stext[i]._sstr[0]) PrintSString(stext[i]._sx, i, stext[i]._sjust, stext[i]._sstr, stext[i]._sclr, stext[i]._sval); } if (stextscrl) DrawSSlider(4, 20); InStoreFlag = (InStoreFlag & 7) + 1; } void STextESC() { if (qtextflag) { qtextflag = FALSE; if (leveltype == DTYPE_TOWN) stream_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 = STORE_NONE; break; case STORE_GOSSIP: StartStore(stextshold); stextsel = stextlhold; break; case STORE_SBUY: StartStore(STORE_SMITH); stextsel = 12; break; case STORE_SPBUY: StartStore(STORE_SMITH); stextsel = 14; break; case STORE_SSELL: StartStore(STORE_SMITH); stextsel = 16; break; case STORE_SREPAIR: StartStore(STORE_SMITH); stextsel = 18; break; case STORE_WBUY: StartStore(STORE_WITCH); stextsel = 14; break; case STORE_WSELL: StartStore(STORE_WITCH); stextsel = 16; break; case STORE_WRECHARGE: StartStore(STORE_WITCH); stextsel = 18; break; case STORE_HBUY: StartStore(STORE_HEALER); stextsel = 16; break; case STORE_SIDENTIFY: StartStore(STORE_STORY); stextsel = 14; break; case STORE_IDSHOW: StartStore(STORE_SIDENTIFY); break; case STORE_NOMONEY: case STORE_NOROOM: case STORE_CONFIRM: StartStore(stextshold); stextsel = stextlhold; stextsval = stextvhold; break; } } } void STextUp() { PlaySFX(IS_TITLEMOV); if (stextsel == -1) { return; } if (stextscrl) { if (stextsel == stextup) { if (stextsval) stextsval--; return; } stextsel--; while (!stext[stextsel]._ssel) { if (!stextsel) stextsel = STORE_LINES - 1; else stextsel--; } return; } if (!stextsel) stextsel = STORE_LINES - 1; else stextsel--; while (!stext[stextsel]._ssel) { if (!stextsel) stextsel = STORE_LINES - 1; else stextsel--; } } void STextDown() { PlaySFX(IS_TITLEMOV); if (stextsel == -1) { return; } if (stextscrl) { if (stextsel == stextdown) { if (stextsval < stextsmax) stextsval++; return; } stextsel++; while (!stext[stextsel]._ssel) { if (stextsel == STORE_LINES - 1) stextsel = 0; else stextsel++; } return; } if (stextsel == STORE_LINES - 1) stextsel = 0; else stextsel++; while (!stext[stextsel]._ssel) { if (stextsel == STORE_LINES - 1) stextsel = 0; else stextsel++; } } void STextPrior() { PlaySFX(IS_TITLEMOV); if (stextsel != -1 && stextscrl) { if (stextsel == stextup) { if (stextsval) stextsval -= 4; stextsval = stextsval; if (stextsval < 0) stextsval = 0; } else { stextsel = stextup; } } } void STextNext() { PlaySFX(IS_TITLEMOV); if (stextsel != -1 && stextscrl) { if (stextsel == stextdown) { if (stextsval < stextsmax) stextsval += 4; if (stextsval > stextsmax) stextsval = stextsmax; } else { stextsel = stextdown; } } } void S_SmithEnter() { switch (stextsel) { case 10: talker = 0; stextlhold = 10; stextshold = STORE_SMITH; gossipstart = TEXT_GRISWOLD2; gossipend = TEXT_GRISWOLD13; StartStore(STORE_GOSSIP); break; case 12: StartStore(STORE_SBUY); break; case 14: StartStore(STORE_SPBUY); break; case 16: StartStore(STORE_SSELL); break; case 18: StartStore(STORE_SREPAIR); break; case 20: stextflag = STORE_NONE; break; } } void SetGoldCurs(int pnum, int i) { if (plr[pnum].InvList[i]._ivalue >= GOLD_MEDIUM_LIMIT) plr[pnum].InvList[i]._iCurs = ICURS_GOLD_LARGE; else if (plr[pnum].InvList[i]._ivalue <= GOLD_SMALL_LIMIT) plr[pnum].InvList[i]._iCurs = ICURS_GOLD_SMALL; else plr[pnum].InvList[i]._iCurs = ICURS_GOLD_MEDIUM; } void SetSpdbarGoldCurs(int pnum, int i) { if (plr[pnum].SpdList[i]._ivalue >= GOLD_MEDIUM_LIMIT) plr[pnum].SpdList[i]._iCurs = ICURS_GOLD_LARGE; else if (plr[pnum].SpdList[i]._ivalue <= GOLD_SMALL_LIMIT) plr[pnum].SpdList[i]._iCurs = ICURS_GOLD_SMALL; else plr[pnum].SpdList[i]._iCurs = ICURS_GOLD_MEDIUM; } void TakePlrsMoney(int cost) { int i; plr[myplr]._pGold = CalculateGold(myplr) - cost; for (i = 0; i < MAXBELTITEMS && cost > 0; i++) { if (plr[myplr].SpdList[i]._itype == ITYPE_GOLD && plr[myplr].SpdList[i]._ivalue != GOLD_MAX_LIMIT) { if (cost < plr[myplr].SpdList[i]._ivalue) { plr[myplr].SpdList[i]._ivalue -= cost; SetSpdbarGoldCurs(myplr, i); cost = 0; } else { cost -= plr[myplr].SpdList[i]._ivalue; RemoveSpdBarItem(myplr, i); i = -1; } } } if (cost > 0) { for (i = 0; i < MAXBELTITEMS && cost > 0; i++) { if (plr[myplr].SpdList[i]._itype == ITYPE_GOLD) { if (cost < plr[myplr].SpdList[i]._ivalue) { plr[myplr].SpdList[i]._ivalue -= cost; SetSpdbarGoldCurs(myplr, i); cost = 0; } else { cost -= plr[myplr].SpdList[i]._ivalue; RemoveSpdBarItem(myplr, i); i = -1; } } } } force_redraw = 255; if (cost > 0) { for (i = 0; i < plr[myplr]._pNumInv && cost > 0; i++) { if (plr[myplr].InvList[i]._itype == ITYPE_GOLD && plr[myplr].InvList[i]._ivalue != GOLD_MAX_LIMIT) { if (cost < plr[myplr].InvList[i]._ivalue) { plr[myplr].InvList[i]._ivalue -= cost; SetGoldCurs(myplr, i); cost = 0; } else { cost -= plr[myplr].InvList[i]._ivalue; RemoveInvItem(myplr, i); i = -1; } } } if (cost > 0) { for (i = 0; i < plr[myplr]._pNumInv && cost > 0; i++) { if (plr[myplr].InvList[i]._itype == ITYPE_GOLD) { if (cost < plr[myplr].InvList[i]._ivalue) { plr[myplr].InvList[i]._ivalue -= cost; SetGoldCurs(myplr, i); cost = 0; } else { cost -= plr[myplr].InvList[i]._ivalue; RemoveInvItem(myplr, i); i = -1; } } } } } } void SmithBuyItem() { int idx; TakePlrsMoney(plr[myplr].HoldItem._iIvalue); if (plr[myplr].HoldItem._iMagical == ITEM_QUALITY_NORMAL) plr[myplr].HoldItem._iIdentified = FALSE; StoreAutoPlace(); idx = stextvhold + ((stextlhold - stextup) >> 2); if (idx == SMITH_ITEMS - 1) { smithitem[SMITH_ITEMS - 1]._itype = ITYPE_NONE; } else { for (; smithitem[idx + 1]._itype != ITYPE_NONE; idx++) { smithitem[idx] = smithitem[idx + 1]; } smithitem[idx]._itype = ITYPE_NONE; } CalcPlrInv(myplr, TRUE); } void S_SBuyEnter() { int idx, i; BOOL done; if (stextsel == 22) { StartStore(STORE_SMITH); stextsel = 12; } else { stextlhold = stextsel; stextvhold = stextsval; stextshold = STORE_SBUY; idx = stextsval + ((stextsel - stextup) >> 2); if (plr[myplr]._pGold < smithitem[idx]._iIvalue) { StartStore(STORE_NOMONEY); } else { plr[myplr].HoldItem = smithitem[idx]; SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM); done = FALSE; for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) { done = AutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE); } if (done) StartStore(STORE_CONFIRM); else StartStore(STORE_NOROOM); SetCursor_(CURSOR_HAND); } } } void SmithBuyPItem() { int i, xx, idx; TakePlrsMoney(plr[myplr].HoldItem._iIvalue); if (plr[myplr].HoldItem._iMagical == ITEM_QUALITY_NORMAL) plr[myplr].HoldItem._iIdentified = FALSE; StoreAutoPlace(); idx = stextvhold + ((stextlhold - stextup) >> 2); xx = 0; for (i = 0; idx >= 0; i++) { if (premiumitem[i]._itype != ITYPE_NONE) { idx--; xx = i; } } premiumitem[xx]._itype = ITYPE_NONE; numpremium--; #ifdef HELLFIRE SpawnPremium(myplr); #else SpawnPremium(plr[myplr]._pLevel); #endif } void S_SPBuyEnter() { int i, idx, xx; BOOL done; if (stextsel == 22) { StartStore(STORE_SMITH); stextsel = 14; } else { stextshold = STORE_SPBUY; stextlhold = stextsel; stextvhold = stextsval; xx = stextsval + ((stextsel - stextup) >> 2); idx = 0; for (i = 0; xx >= 0; i++) { if (premiumitem[i]._itype != ITYPE_NONE) { xx--; idx = i; } } if (plr[myplr]._pGold < premiumitem[idx]._iIvalue) { StartStore(STORE_NOMONEY); } else { plr[myplr].HoldItem = premiumitem[idx]; SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM); done = FALSE; for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) { done = AutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE); } if (done) StartStore(STORE_CONFIRM); else StartStore(STORE_NOROOM); SetCursor_(CURSOR_HAND); } } } BOOL StoreGoldFit(int idx) { int i, sz, cost, numsqrs; cost = storehold[idx]._iIvalue; sz = cost / GOLD_MAX_LIMIT; if (cost % GOLD_MAX_LIMIT != 0) sz++; SetCursor_(storehold[idx]._iCurs + CURSOR_FIRSTITEM); numsqrs = cursW / 28 * (cursH / 28); SetCursor_(CURSOR_HAND); if (numsqrs >= sz) return TRUE; for (i = 0; i < NUM_INV_GRID_ELEM; i++) { if (plr[myplr].InvGrid[i] == 0) numsqrs++; } for (i = 0; i < plr[myplr]._pNumInv; i++) { if (plr[myplr].InvList[i]._itype == ITYPE_GOLD && plr[myplr].InvList[i]._ivalue != GOLD_MAX_LIMIT) { if (cost + plr[myplr].InvList[i]._ivalue <= GOLD_MAX_LIMIT) cost = 0; else cost -= GOLD_MAX_LIMIT - plr[myplr].InvList[i]._ivalue; } } sz = cost / GOLD_MAX_LIMIT; if (cost % GOLD_MAX_LIMIT) sz++; return numsqrs >= sz; } void PlaceStoreGold(int v) { BOOL done; int ii, xx, yy, i; done = FALSE; for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) { yy = 10 * (i / 10); xx = i % 10; if (plr[myplr].InvGrid[xx + yy] == 0) { ii = plr[myplr]._pNumInv; GetGoldSeed(myplr, &golditem); plr[myplr].InvList[ii] = golditem; plr[myplr]._pNumInv++; plr[myplr].InvGrid[xx + yy] = plr[myplr]._pNumInv; plr[myplr].InvList[ii]._ivalue = v; SetGoldCurs(myplr, ii); done = TRUE; } } } void StoreSellItem() { int i, idx, cost; idx = stextvhold + ((stextlhold - stextup) >> 2); if (storehidx[idx] >= 0) RemoveInvItem(myplr, storehidx[idx]); else RemoveSpdBarItem(myplr, -(storehidx[idx] + 1)); cost = storehold[idx]._iIvalue; storenumh--; if (idx != storenumh) { while (idx < storenumh) { storehold[idx] = storehold[idx + 1]; storehidx[idx] = storehidx[idx + 1]; idx++; } } plr[myplr]._pGold += cost; for (i = 0; i < plr[myplr]._pNumInv && cost > 0; i++) { if (plr[myplr].InvList[i]._itype == ITYPE_GOLD && plr[myplr].InvList[i]._ivalue != GOLD_MAX_LIMIT) { if (cost + plr[myplr].InvList[i]._ivalue <= GOLD_MAX_LIMIT) { plr[myplr].InvList[i]._ivalue += cost; SetGoldCurs(myplr, i); cost = 0; } else { cost -= GOLD_MAX_LIMIT - plr[myplr].InvList[i]._ivalue; plr[myplr].InvList[i]._ivalue = GOLD_MAX_LIMIT; SetGoldCurs(myplr, i); } } } if (cost > 0) { while (cost > GOLD_MAX_LIMIT) { PlaceStoreGold(GOLD_MAX_LIMIT); cost -= GOLD_MAX_LIMIT; } PlaceStoreGold(cost); } } void S_SSellEnter() { int idx; if (stextsel == 22) { StartStore(STORE_SMITH); stextsel = 16; } else { stextlhold = stextsel; idx = stextsval + ((stextsel - stextup) >> 2); stextshold = STORE_SSELL; stextvhold = stextsval; plr[myplr].HoldItem = storehold[idx]; if (StoreGoldFit(idx)) StartStore(STORE_CONFIRM); else StartStore(STORE_NOROOM); } } void SmithRepairItem() { int i, idx; TakePlrsMoney(plr[myplr].HoldItem._iIvalue); idx = stextvhold + ((stextlhold - stextup) >> 2); storehold[idx]._iDurability = storehold[idx]._iMaxDur; i = storehidx[idx]; if (i < 0) { if (i == -1) plr[myplr].InvBody[INVLOC_HEAD]._iDurability = plr[myplr].InvBody[INVLOC_HEAD]._iMaxDur; if (i == -2) plr[myplr].InvBody[INVLOC_CHEST]._iDurability = plr[myplr].InvBody[INVLOC_CHEST]._iMaxDur; if (i == -3) plr[myplr].InvBody[INVLOC_HAND_LEFT]._iDurability = plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMaxDur; if (i == -4) plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iDurability = plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iMaxDur; } else { plr[myplr].InvList[i]._iDurability = plr[myplr].InvList[i]._iMaxDur; } } void S_SRepairEnter() { int idx; if (stextsel == 22) { StartStore(STORE_SMITH); stextsel = 18; } else { stextshold = STORE_SREPAIR; stextlhold = stextsel; stextvhold = stextsval; idx = stextsval + ((stextsel - stextup) >> 2); plr[myplr].HoldItem = storehold[idx]; if (plr[myplr]._pGold < storehold[idx]._iIvalue) StartStore(STORE_NOMONEY); else StartStore(STORE_CONFIRM); } } void S_WitchEnter() { switch (stextsel) { case 12: stextlhold = 12; talker = 6; stextshold = STORE_WITCH; gossipstart = TEXT_ADRIA2; gossipend = TEXT_ADRIA13; StartStore(STORE_GOSSIP); return; case 14: StartStore(STORE_WBUY); return; case 16: StartStore(STORE_WSELL); return; case 18: StartStore(STORE_WRECHARGE); return; case 20: stextflag = STORE_NONE; break; } } void WitchBuyItem() { int idx; idx = stextvhold + ((stextlhold - stextup) >> 2); if (idx < 3) plr[myplr].HoldItem._iSeed = GetRndSeed(); TakePlrsMoney(plr[myplr].HoldItem._iIvalue); StoreAutoPlace(); if (idx >= 3) { if (idx == WITCH_ITEMS - 1) { witchitem[WITCH_ITEMS - 1]._itype = ITYPE_NONE; } else { for (; witchitem[idx + 1]._itype != ITYPE_NONE; idx++) { witchitem[idx] = witchitem[idx + 1]; } witchitem[idx]._itype = ITYPE_NONE; } } CalcPlrInv(myplr, TRUE); } void S_WBuyEnter() { int i, idx; BOOL done; if (stextsel == 22) { StartStore(STORE_WITCH); stextsel = 14; } else { stextlhold = stextsel; stextvhold = stextsval; stextshold = STORE_WBUY; idx = stextsval + ((stextsel - stextup) >> 2); if (plr[myplr]._pGold < witchitem[idx]._iIvalue) { StartStore(STORE_NOMONEY); } else { plr[myplr].HoldItem = witchitem[idx]; SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM); done = FALSE; for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) { done = SpecialAutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE); } if (done) StartStore(STORE_CONFIRM); else StartStore(STORE_NOROOM); SetCursor_(CURSOR_HAND); } } } void S_WSellEnter() { int idx; if (stextsel == 22) { StartStore(STORE_WITCH); stextsel = 16; } else { stextlhold = stextsel; idx = stextsval + ((stextsel - stextup) >> 2); stextshold = STORE_WSELL; stextvhold = stextsval; plr[myplr].HoldItem = storehold[idx]; if (StoreGoldFit(idx)) StartStore(STORE_CONFIRM); else StartStore(STORE_NOROOM); } } void WitchRechargeItem() { int i, idx; TakePlrsMoney(plr[myplr].HoldItem._iIvalue); idx = stextvhold + ((stextlhold - stextup) >> 2); storehold[idx]._iCharges = storehold[idx]._iMaxCharges; i = storehidx[idx]; if (i < 0) plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges = plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMaxCharges; else plr[myplr].InvList[i]._iCharges = plr[myplr].InvList[i]._iMaxCharges; CalcPlrInv(myplr, TRUE); } void S_WRechargeEnter() { int idx; if (stextsel == 22) { StartStore(STORE_WITCH); stextsel = 18; } else { stextshold = STORE_WRECHARGE; stextlhold = stextsel; stextvhold = stextsval; idx = stextsval + ((stextsel - stextup) >> 2); plr[myplr].HoldItem = storehold[idx]; if (plr[myplr]._pGold < storehold[idx]._iIvalue) StartStore(STORE_NOMONEY); else StartStore(STORE_CONFIRM); } } void S_BoyEnter() { if (boyitem._itype != ITYPE_NONE && stextsel == 18) { if (plr[myplr]._pGold < 50) { stextshold = STORE_BOY; stextlhold = 18; stextvhold = stextsval; StartStore(STORE_NOMONEY); } else { TakePlrsMoney(50); StartStore(STORE_BBOY); } } else if (stextsel == 8 && boyitem._itype != ITYPE_NONE || stextsel == 12 && boyitem._itype == ITYPE_NONE) { talker = 8; stextshold = STORE_BOY; stextlhold = stextsel; gossipstart = TEXT_WIRT2; gossipend = TEXT_WIRT12; StartStore(STORE_GOSSIP); } else { stextflag = STORE_NONE; } } void BoyBuyItem() { TakePlrsMoney(plr[myplr].HoldItem._iIvalue); StoreAutoPlace(); boyitem._itype = ITYPE_NONE; stextshold = STORE_BOY; CalcPlrInv(myplr, TRUE); } void HealerBuyItem() { int idx; idx = stextvhold + ((stextlhold - stextup) >> 2); if (gbMaxPlayers == 1) { if (idx < 2) plr[myplr].HoldItem._iSeed = GetRndSeed(); } else { if (idx < 3) plr[myplr].HoldItem._iSeed = GetRndSeed(); } TakePlrsMoney(plr[myplr].HoldItem._iIvalue); if (plr[myplr].HoldItem._iMagical == ITEM_QUALITY_NORMAL) plr[myplr].HoldItem._iIdentified = FALSE; StoreAutoPlace(); if (gbMaxPlayers == 1) { if (idx < 2) return; } else { if (idx < 3) return; } idx = stextvhold + ((stextlhold - stextup) >> 2); if (idx == 19) { healitem[19]._itype = ITYPE_NONE; } else { for (; healitem[idx + 1]._itype != ITYPE_NONE; idx++) { healitem[idx] = healitem[idx + 1]; } healitem[idx]._itype = ITYPE_NONE; } CalcPlrInv(myplr, TRUE); } void S_BBuyEnter() { BOOL done; int i; if (stextsel == 10) { stextshold = STORE_BBOY; stextvhold = stextsval; stextlhold = 10; #ifdef HELLFIRE if (plr[myplr]._pGold < boyitem._iIvalue - (boyitem._iIvalue >> 2)) { #else if (plr[myplr]._pGold < boyitem._iIvalue + (boyitem._iIvalue >> 1)) { #endif StartStore(STORE_NOMONEY); } else { plr[myplr].HoldItem = boyitem; #ifdef HELLFIRE plr[myplr].HoldItem._iIvalue -= plr[myplr].HoldItem._iIvalue >> 2; #else plr[myplr].HoldItem._iIvalue += plr[myplr].HoldItem._iIvalue >> 1; #endif SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM); done = FALSE; for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) { done = AutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE); } if (done) StartStore(STORE_CONFIRM); else StartStore(STORE_NOROOM); SetCursor_(CURSOR_HAND); } } else { stextflag = STORE_NONE; } } void StoryIdItem() { int idx; idx = storehidx[((stextlhold - stextup) >> 2) + stextvhold]; if (idx < 0) { if (idx == -1) plr[myplr].InvBody[INVLOC_HEAD]._iIdentified = TRUE; if (idx == -2) plr[myplr].InvBody[INVLOC_CHEST]._iIdentified = TRUE; if (idx == -3) plr[myplr].InvBody[INVLOC_HAND_LEFT]._iIdentified = TRUE; if (idx == -4) plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iIdentified = TRUE; if (idx == -5) plr[myplr].InvBody[INVLOC_RING_LEFT]._iIdentified = TRUE; if (idx == -6) plr[myplr].InvBody[INVLOC_RING_RIGHT]._iIdentified = TRUE; if (idx == -7) plr[myplr].InvBody[INVLOC_AMULET]._iIdentified = TRUE; } else { plr[myplr].InvList[idx]._iIdentified = TRUE; } plr[myplr].HoldItem._iIdentified = TRUE; TakePlrsMoney(plr[myplr].HoldItem._iIvalue); CalcPlrInv(myplr, TRUE); } void S_ConfirmEnter() { if (stextsel == 18) { switch (stextshold) { case STORE_SBUY: SmithBuyItem(); break; case STORE_SSELL: case STORE_WSELL: StoreSellItem(); break; case STORE_SREPAIR: SmithRepairItem(); break; case STORE_WBUY: WitchBuyItem(); break; case STORE_WRECHARGE: WitchRechargeItem(); break; case STORE_BBOY: BoyBuyItem(); break; case STORE_HBUY: HealerBuyItem(); break; case STORE_SIDENTIFY: StoryIdItem(); StartStore(STORE_IDSHOW); return; case STORE_SPBUY: SmithBuyPItem(); break; } StartStore(stextshold); } else { StartStore(stextshold); stextsel = stextlhold; stextsval = stextvhold; } } void S_HealerEnter() { switch (stextsel) { case 12: stextlhold = 12; talker = 1; stextshold = STORE_HEALER; gossipstart = TEXT_PEPIN2; gossipend = TEXT_PEPIN11; StartStore(STORE_GOSSIP); break; #ifdef HELLFIRE case 14: StartStore(STORE_HBUY); break; case 16: stextflag = STORE_NONE; break; #else case 14: if (plr[myplr]._pHitPoints != plr[myplr]._pMaxHP) PlaySFX(IS_CAST8); drawhpflag = TRUE; plr[myplr]._pHitPoints = plr[myplr]._pMaxHP; plr[myplr]._pHPBase = plr[myplr]._pMaxHPBase; break; case 16: StartStore(STORE_HBUY); break; case 18: stextflag = STORE_NONE; break; #endif } } void S_HBuyEnter() { int i, idx; BOOL done; if (stextsel == 22) { StartStore(STORE_HEALER); stextsel = 16; } else { stextlhold = stextsel; stextvhold = stextsval; stextshold = STORE_HBUY; idx = stextsval + ((stextsel - stextup) >> 2); if (plr[myplr]._pGold < healitem[idx]._iIvalue) { StartStore(STORE_NOMONEY); } else { plr[myplr].HoldItem = healitem[idx]; SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM); done = FALSE; i = 0; for (i = 0; i < NUM_INV_GRID_ELEM && !done; i++) { done = SpecialAutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE); } if (done) StartStore(STORE_CONFIRM); else StartStore(STORE_NOROOM); SetCursor_(CURSOR_HAND); } } } void S_StoryEnter() { switch (stextsel) { case 12: stextlhold = 12; talker = 4; stextshold = STORE_STORY; gossipstart = TEXT_STORY2; gossipend = TEXT_STORY11; StartStore(STORE_GOSSIP); break; case 14: StartStore(STORE_SIDENTIFY); break; case 18: stextflag = STORE_NONE; break; } } void S_SIDEnter() { int idx; if (stextsel == 22) { StartStore(STORE_STORY); stextsel = 14; } else { stextshold = STORE_SIDENTIFY; stextlhold = stextsel; stextvhold = stextsval; idx = stextsval + ((stextsel - stextup) >> 2); plr[myplr].HoldItem = storehold[idx]; if (plr[myplr]._pGold < storehold[idx]._iIvalue) StartStore(STORE_NOMONEY); else StartStore(STORE_CONFIRM); } } void S_TalkEnter() { int i, tq, sn, la; if (stextsel == 22) { StartStore(stextshold); stextsel = stextlhold; return; } sn = 0; for (i = 0; i < MAXQUESTS; i++) { if (quests[i]._qactive == QUEST_ACTIVE && ((DWORD *)&Qtalklist[talker])[i] != -1 && quests[i]._qlog) sn++; } if (sn > 6) { sn = 14 - (sn >> 1); la = 1; } else { sn = 15 - sn; la = 2; } if (stextsel == sn - 2) { SetRndSeed(towner[talker]._tSeed); tq = gossipstart + random_(0, gossipend - gossipstart + 1); InitQTextMsg(tq); return; } for (i = 0; i < MAXQUESTS; i++) { if (quests[i]._qactive == QUEST_ACTIVE && ((DWORD *)&Qtalklist[talker])[i] != -1 && quests[i]._qlog) { if (sn == stextsel) { InitQTextMsg(((DWORD *)&Qtalklist[talker])[i]); } sn += la; } } } void S_TavernEnter() { switch (stextsel) { case 12: stextlhold = 12; talker = 3; stextshold = STORE_TAVERN; gossipstart = TEXT_OGDEN2; gossipend = TEXT_OGDEN10; StartStore(STORE_GOSSIP); break; case 18: stextflag = STORE_NONE; break; } } void S_BarmaidEnter() { switch (stextsel) { case 12: stextlhold = 12; talker = 7; stextshold = STORE_BARMAID; gossipstart = TEXT_GILLIAN2; gossipend = TEXT_GILLIAN10; StartStore(STORE_GOSSIP); break; case 18: stextflag = STORE_NONE; break; } } void S_DrunkEnter() { switch (stextsel) { case 12: stextlhold = 12; talker = 5; stextshold = STORE_DRUNK; gossipstart = TEXT_FARNHAM2; gossipend = TEXT_FARNHAM13; StartStore(STORE_GOSSIP); break; case 18: stextflag = STORE_NONE; break; } } void STextEnter() { if (qtextflag) { qtextflag = FALSE; if (leveltype == DTYPE_TOWN) stream_stop(); } else { PlaySFX(IS_TITLSLCT); switch (stextflag) { case STORE_SMITH: S_SmithEnter(); break; case STORE_SPBUY: S_SPBuyEnter(); 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_GOSSIP: S_TalkEnter(); break; case STORE_IDSHOW: StartStore(STORE_SIDENTIFY); break; case STORE_DRUNK: S_DrunkEnter(); break; case STORE_TAVERN: S_TavernEnter(); break; case STORE_BARMAID: S_BarmaidEnter(); break; } } } void CheckStoreBtn() { int y; if (qtextflag) { qtextflag = FALSE; if (leveltype == DTYPE_TOWN) stream_stop(); } else if (stextsel != -1 && MouseY >= 32 && MouseY <= 320) { if (!stextsize) { if (MouseX < 344 + PANEL_LEFT || MouseX > 616 + PANEL_LEFT) return; } else { if (MouseX < 24 + PANEL_LEFT || MouseX > 616 + PANEL_LEFT) return; } y = (MouseY - 32) / 12; if (stextscrl && MouseX > 600 + PANEL_LEFT) { if (y == 4) { if (stextscrlubtn <= 0) { STextUp(); stextscrlubtn = 10; } else { stextscrlubtn--; } } if (y == 20) { if (stextscrldbtn <= 0) { STextDown(); stextscrldbtn = 10; } else { stextscrldbtn--; } } } else if (y >= 5) { if (y >= 23) y = 22; if (stextscrl && y < 21 && !stext[y]._ssel) { if (stext[y - 2]._ssel) { y -= 2; } else if (stext[y - 1]._ssel) { y--; } } if (stext[y]._ssel || stextscrl && y == 22) { stextsel = y; STextEnter(); } } } } void ReleaseStoreBtn() { stextscrlubtn = -1; stextscrldbtn = -1; } ================================================ FILE: Source/stores.h ================================================ /** * @file stores.h * * Interface of functionality for stores and towner dialogs. */ #ifndef __STORES_H__ #define __STORES_H__ extern ItemStruct boyitem; extern ItemStruct premiumitem[SMITH_PREMIUM_ITEMS]; extern BYTE *pSTextBoxCels; extern int premiumlevel; extern int talker; extern ItemStruct witchitem[WITCH_ITEMS]; extern int numpremium; extern ItemStruct healitem[20]; extern ItemStruct golditem; extern BYTE *pSTextSlidCels; extern BYTE *pSPentSpn2Cels; extern int boylevel; extern ItemStruct smithitem[SMITH_ITEMS]; extern int stextdown; extern char stextflag; void InitStores(); void SetupTownStores(); void FreeStoreMem(); void PrintSString(int x, int y, BOOL cjustflag, const char *str, char col, int val); void DrawSLine(int y); void DrawSTextHelp(); void ClearSText(int s, int e); void StartStore(char s); void DrawSText(); void STextESC(); void STextUp(); void STextDown(); void STextPrior(); void STextNext(); void SetGoldCurs(int pnum, int i); void SetSpdbarGoldCurs(int pnum, int i); void TakePlrsMoney(int cost); void STextEnter(); void CheckStoreBtn(); void ReleaseStoreBtn(); /* rdata */ extern int SStringY[24]; #endif /* __STORES_H__ */ ================================================ FILE: Source/sync.cpp ================================================ /** * @file sync.cpp * * Implementation of functionality for syncing game state with other players. */ #include "all.h" WORD sync_word_6AA708[MAXMONSTERS]; int sgnMonsters; WORD sgwLRU[MAXMONSTERS]; int sgnSyncItem; int sgnSyncPInv; static void sync_one_monster() { int i, m; for (i = 0; i < nummonsters; i++) { m = monstactive[i]; sync_word_6AA708[m] = abs(plr[myplr]._px - monster[m]._mx) + abs(plr[myplr]._py - monster[m]._my); if (monster[m]._msquelch == 0) { sync_word_6AA708[m] += 0x1000; } else if (sgwLRU[m] != 0) { sgwLRU[m]--; } } } static void sync_monster_pos(TSyncMonster *p, int ndx) { p->_mndx = ndx; p->_mx = monster[ndx]._mx; p->_my = monster[ndx]._my; p->_menemy = encode_enemy(ndx); p->_mdelta = sync_word_6AA708[ndx] > 255 ? 255 : sync_word_6AA708[ndx]; sync_word_6AA708[ndx] = 0xFFFF; sgwLRU[ndx] = monster[ndx]._msquelch == 0 ? 0xFFFF : 0xFFFE; } static BOOL sync_monster_active(TSyncMonster *p) { int i, m, ndx; DWORD lru; ndx = -1; lru = 0xFFFFFFFF; for (i = 0; i < nummonsters; i++) { m = monstactive[i]; if (sync_word_6AA708[m] < lru && sgwLRU[m] < 0xFFFE) { lru = sync_word_6AA708[m]; ndx = monstactive[i]; } } if (ndx == -1) { return FALSE; } sync_monster_pos(p, ndx); return TRUE; } static BOOL sync_monster_active2(TSyncMonster *p) { int i, m, ndx; DWORD lru; ndx = -1; lru = 0xFFFE; for (i = 0; i < nummonsters; i++) { if (sgnMonsters >= nummonsters) { sgnMonsters = 0; } m = monstactive[sgnMonsters]; if (sgwLRU[m] < lru) { lru = sgwLRU[m]; ndx = monstactive[sgnMonsters]; } sgnMonsters++; } if (ndx == -1) { return FALSE; } sync_monster_pos(p, ndx); return TRUE; } static void SyncPlrInv(TSyncHeader *pHdr) { int ii; ItemStruct *pItem; if (numitems > 0) { if (sgnSyncItem >= numitems) { sgnSyncItem = 0; } ii = itemactive[sgnSyncItem++]; pHdr->bItemI = ii; pHdr->bItemX = item[ii]._ix; pHdr->bItemY = item[ii]._iy; pHdr->wItemIndx = item[ii].IDidx; if (item[ii].IDidx == IDI_EAR) { pHdr->wItemCI = (item[ii]._iName[7] << 8) | item[ii]._iName[8]; pHdr->dwItemSeed = (item[ii]._iName[9] << 24) | (item[ii]._iName[10] << 16) | (item[ii]._iName[11] << 8) | item[ii]._iName[12]; pHdr->bItemId = item[ii]._iName[13]; pHdr->bItemDur = item[ii]._iName[14]; pHdr->bItemMDur = item[ii]._iName[15]; pHdr->bItemCh = item[ii]._iName[16]; pHdr->bItemMCh = item[ii]._iName[17]; pHdr->wItemVal = (item[ii]._iName[18] << 8) | ((item[ii]._iCurs - ICURS_EAR_SORCEROR) << 6) | item[ii]._ivalue; pHdr->dwItemBuff = (item[ii]._iName[19] << 24) | (item[ii]._iName[20] << 16) | (item[ii]._iName[21] << 8) | item[ii]._iName[22]; } else { pHdr->wItemCI = item[ii]._iCreateInfo; pHdr->dwItemSeed = item[ii]._iSeed; pHdr->bItemId = item[ii]._iIdentified; pHdr->bItemDur = item[ii]._iDurability; pHdr->bItemMDur = item[ii]._iMaxDur; pHdr->bItemCh = item[ii]._iCharges; pHdr->bItemMCh = item[ii]._iMaxCharges; if (item[ii].IDidx == IDI_GOLD) { pHdr->wItemVal = item[ii]._ivalue; } } } else { pHdr->bItemI = -1; } assert((DWORD)sgnSyncPInv < NUM_INVLOC); pItem = &plr[myplr].InvBody[sgnSyncPInv]; if (pItem->_itype != ITYPE_NONE) { pHdr->bPInvLoc = sgnSyncPInv; pHdr->wPInvIndx = pItem->IDidx; pHdr->wPInvCI = pItem->_iCreateInfo; pHdr->dwPInvSeed = pItem->_iSeed; pHdr->bPInvId = pItem->_iIdentified; } else { pHdr->bPInvLoc = -1; } sgnSyncPInv++; if (sgnSyncPInv >= NUM_INVLOC) { sgnSyncPInv = 0; } } DWORD sync_all_monsters(const BYTE *pbBuf, DWORD dwMaxLen) { TSyncHeader *pHdr; int i; BOOL sync; if (nummonsters < 1) { return dwMaxLen; } if (dwMaxLen < sizeof(*pHdr) + sizeof(TSyncMonster)) { return dwMaxLen; } pHdr = (TSyncHeader *)pbBuf; pbBuf += sizeof(*pHdr); dwMaxLen -= sizeof(*pHdr); pHdr->bCmd = CMD_SYNCDATA; pHdr->bLevel = currlevel; pHdr->wLen = 0; SyncPlrInv(pHdr); assert(dwMaxLen <= 0xffff); sync_one_monster(); for (i = 0; i < nummonsters && dwMaxLen >= sizeof(TSyncMonster); i++) { sync = FALSE; if (i < 2) { sync = sync_monster_active2((TSyncMonster *)pbBuf); } if (!sync) { sync = sync_monster_active((TSyncMonster *)pbBuf); } if (!sync) { break; } pbBuf += sizeof(TSyncMonster); pHdr->wLen += sizeof(TSyncMonster); dwMaxLen -= sizeof(TSyncMonster); } return dwMaxLen; } static void sync_monster(int pnum, const TSyncMonster *p) { int i, ndx, md, mdx, mdy; DWORD delta; ndx = p->_mndx; #ifdef HELLFIRE if (monster[ndx]._mhitpoints <= 0) { #else if (monster[ndx]._mhitpoints == 0) { #endif return; } for (i = 0; i < nummonsters; i++) { // CODEFIX: this loop does nothing if (monstactive[i] == ndx) { break; } } delta = abs(plr[myplr]._px - monster[ndx]._mx) + abs(plr[myplr]._py - monster[ndx]._my); if (delta > 255) { delta = 255; } if (delta < p->_mdelta || (delta == p->_mdelta && pnum > myplr)) { return; } if (monster[ndx]._mfutx == p->_mx && monster[ndx]._mfuty == p->_my) { return; } if (monster[ndx]._mmode == MM_CHARGE || monster[ndx]._mmode == MM_STONE) { return; } mdx = abs(monster[ndx]._mx - p->_mx); mdy = abs(monster[ndx]._my - p->_my); if (mdx <= 2 && mdy <= 2) { if (monster[ndx]._mmode < MM_WALK || monster[ndx]._mmode > MM_WALK3) { md = GetDirection(monster[ndx]._mx, monster[ndx]._my, p->_mx, p->_my); if (DirOK(ndx, md)) { M_ClearSquares(ndx); dMonster[monster[ndx]._mx][monster[ndx]._my] = ndx + 1; M_WalkDir(ndx, md); monster[ndx]._msquelch = UCHAR_MAX; } } } else if (dMonster[p->_mx][p->_my] == 0) { M_ClearSquares(ndx); dMonster[p->_mx][p->_my] = ndx + 1; monster[ndx]._mx = p->_mx; monster[ndx]._my = p->_my; decode_enemy(ndx, p->_menemy); md = GetDirection(p->_mx, p->_my, monster[ndx]._menemyx, monster[ndx]._menemyy); M_StartStand(ndx, md); monster[ndx]._msquelch = UCHAR_MAX; } decode_enemy(ndx, p->_menemy); } DWORD sync_update(int pnum, const BYTE *pbBuf) { TSyncHeader *pHdr; WORD wLen; pHdr = (TSyncHeader *)pbBuf; pbBuf += sizeof(*pHdr); if (pHdr->bCmd != CMD_SYNCDATA) { app_fatal("bad sync command"); } /// ASSERT: assert(gbBufferMsgs != BUFFER_PROCESS); if (gbBufferMsgs == 1) { return pHdr->wLen + sizeof(*pHdr); } if (pnum == myplr) { return pHdr->wLen + sizeof(*pHdr); } for (wLen = pHdr->wLen; wLen >= sizeof(TSyncMonster); wLen -= sizeof(TSyncMonster)) { if (currlevel == pHdr->bLevel) { sync_monster(pnum, (TSyncMonster *)pbBuf); } delta_sync_monster((TSyncMonster *)pbBuf, pHdr->bLevel); pbBuf += sizeof(TSyncMonster); } assert(wLen == 0); return pHdr->wLen + sizeof(*pHdr); } void sync_init() { sgnMonsters = 16 * myplr; memset(sgwLRU, 255, sizeof(sgwLRU)); } ================================================ FILE: Source/sync.h ================================================ /** * @file sync.h * * Interface of functionality for syncing game state with other players. */ #ifndef __SYNC_H__ #define __SYNC_H__ DWORD sync_all_monsters(const BYTE *pbBuf, DWORD dwMaxLen); DWORD sync_update(int pnum, const BYTE *pbBuf); void sync_init(); #endif /* __SYNC_H__ */ ================================================ FILE: Source/textdat.cpp ================================================ /** * @file textdat.cpp * * Implementation of all dialog texts. */ #include "all.h" /* todo: move text out of struct */ /** Contains the data related to each speech ID. */ const TextDataStruct alltext[] = { #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { " 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 }, #endif { "Hello, my friend. Stay awhile and listen... |", 0, 5, TSFX_STORY25 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "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 }, #endif { "Greetings, good master. Welcome to the Tavern of the Rising Sun! |", 0, 5, TSFX_TAVERN36 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "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 }, #endif { "What ails you, my friend? |", 0, 5, TSFX_HEALER37 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "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 }, #endif { "Good day! How may I serve you? |", 0, 5, TSFX_BMAID31 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "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 }, #endif { "Well, what can I do for ya? |", 0, 5, TSFX_SMITH44 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "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 }, #endif { "Can't a fella drink in peace? |", 0, 5, TSFX_DRUNK27 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "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 }, #endif { "I sense a soul in search of answers... |", 0, 5, TSFX_WITCH38 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "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 }, #endif { "Pssst... over here... |", 0, 5, TSFX_PEGBOY32 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "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 }, #endif { " |", 0, 5, TSFX_COW1 }, { " |", 0, 5, TSFX_COW2 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "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 }, #endif { "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 }, #ifdef HELLFIRE { "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_MONK1 }, { "...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_MONK10 }, { "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_MONK11 }, { "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_MONK12 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "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 }, { "Maintain your quest. Finding a treasure that is lost is not easy. Finding a treasure that is hidden less so. I will leave you with this. Do not let the sands of time confuse your search.|", 1, 5, TSFX_WITCH19 }, { "A what?! This is foolishness. There's no treasure buried here in Tristram. Let me see that!! Ah, Look these drawings are inaccurate. They don't match our town at all. I'd keep my mind on what lies below the cathedral and not what lies below our topsoil.|", 1, 5, TSFX_SMITH18 }, { "I really don't have time to discuss some map you are looking for. I have many sick people that require my help and yours as well.|", 1, 5, TSFX_HEALER17 }, { "The once proud Iswall is trapped deep beneath the surface of this world. His honor stripped and his visage altered. He is trapped in immortal torment. Charged to conceal the very thing that could free him.|", 1, 5, TSFX_WITCH9 }, { "I'll bet that Wirt saw you coming and put on an act just so he could laugh at you later when you were running around the town with your nose in the dirt. I'd ignore it.|", 1, 5, TSFX_TAVERN17 }, { "There was a time when this town was a frequent stop for travelers from far and wide. Much has changed since then. But hidden caves and buried treasure are common fantasies of any child. Wirt seldom indulges in youthful games. So it may just be his imagination.|", 1, 5, TSFX_STORY19 }, { "Listen here. Come close. I don't know if you know what I know, but you've have really got something here. That's a map.|", 1, 5, TSFX_DRUNK21 }, { "My grandmother often tells me stories about the strange forces that inhabit the graveyard outside of the church. And it may well interest you to hear one of them. She said that if you were to leave the proper offering in the cemetary, enter the cathedral to pray for the dead, and then return, the offering would be altered in some strange way. I don't know if this is just the talk of an old sick woman, but anything seems possible these days.|", 1, 5, TSFX_BMAID27 }, { "Hmmm. A vast and mysterious treasure you say. Mmmm. 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 }, { "The once proud Iswall is trapped deep beneath the surface of this world. His honor stripped and his visage altered. He is trapped in immortal torment. Charged to conceal the very thing that could free him.|", 1, 5, TSFX_WITCH9 }, #endif { "So, you're the hero everyone's been talking about. Perhaps you could help a poor, simple farmer out of a terrible mess? At the edge of my orchard, just south of here, there's a horrible thing swelling out of the ground! I can't get to my crops or my bales of hay, and my poor cows will starve. The witch gave this to me and said that it would blast that thing out of my field. If you could destroy it, I would be forever grateful. I'd do it myself, but someone has to stay here with the cows...|", 1, 3, TSFX_FARMER1 }, { "I knew that it couldn't be as simple as that witch made it sound. It's a sad world when you can't even trust your neighbors.|", 1, 5, TSFX_FARMER2 }, { "Is it gone? Did you send it back to the dark recesses of Hades that spawned it? You what? Oh, don't tell me you lost it! Those things don't come cheap, you know. You've got to find it, and then blast that horror out of our town.|", 1, 5, TSFX_FARMER3 }, { "I heard the explosion from here! Many thanks to you, kind stranger. What with all these things comin' out of the ground, monsters taking over the church, and so forth, these are trying times. I am but a poor farmer, but here -- take this with my great thanks.|", 1, 5, TSFX_FARMER4 }, { "Oh, such a trouble I have...maybe...No, I couldn't impose on you, what with all the other troubles. Maybe after you've cleansed the church of some of those creatures you could come back... and spare a little time to help a poor farmer?|", 1, 5, TSFX_FARMER5 }, { "Waaaah! (sniff) Waaaah! (sniff)|", 1, 5, TSFX_TEDDYBR1 }, { "I lost Theo! I lost my best friend! We were playing over by the river, and Theo said he wanted to go look at the big green thing. I said we shouldn't, but we snuck over there, and then suddenly this BUG came out! We ran away but Theo fell down and the bug GRABBED him and took him away!|", 1, 5, TSFX_TEDDYBR2 }, { "Didja find him? You gotta find Theodore, please! He's just little. He can't take care of himself! Please!|", 1, 5, TSFX_TEDDYBR3 }, { "You found him! You found him! Thank you! Oh Theo, did those nasty bugs scare you? Hey! Ugh! There's something stuck to your fur! Ick! Come on, Theo, let's go home! Thanks again, hero person!|", 1, 5, TSFX_TEDDYBR4 }, { "We have long lain dormant, and the time to awaken has come. After our long sleep, we are filled with great hunger. Soon, now, we shall feed...|", 1, 5, USFX_DEFILER6 }, { "Have you been enjoying yourself, little mammal? How pathetic. Your little world will be no challenge at all.|", 1, 5, USFX_DEFILER2 }, { "These lands shall be defiled, and our brood shall overrun the fields that men call home. Our tendrils shall envelop this world, and we will feast on the flesh of its denizens. Man shall become our chattel and sustenance.|", 1, 5, USFX_DEFILER7 }, { "Ah, I can smell you...you are close! Close! Ssss...the scent of blood and fear...how enticing...|", 1, 5, USFX_DEFILER4 }, { " |", 1, 5, USFX_DEFILER8 }, { " |", 1, 5, USFX_NAKRUL1 }, { " |", 1, 5, USFX_NAKRUL2 }, { " |", 1, 5, USFX_NAKRUL3 }, { " |", 1, 5, USFX_NAKRUL4 }, { " |", 1, 5, USFX_NAKRUL5 }, { "And in the year of the Golden Light, it was so decreed that a great Cathedral be raised. The cornerstone of this holy place was to be carved from the translucent stone Antyrael, named for the Angel who shared his power with the Horadrim. \n \nIn the Year of Drawing Shadows, the ground shook and the Cathedral shattered and fell. As the building of catacombs and castles began and man stood against the ravages of the Sin War, the ruins were scavenged for their stones. And so it was that the cornerstone vanished from the eyes of man. \n \nThe stone was of this world -- and of all worlds -- as the Light is both within all things and beyond all things. Light and unity are the products of this holy foundation, a unity of purpose and a unity of possession.|", 1, 2, PS_NARATR3 }, { "Moo.|", 1, 5, TSFX_COWSUT1 }, { "I said, Moo.|", 1, 5, TSFX_COWSUT2 }, { "Look I'm just a cow, OK?|", 1, 5, TSFX_COWSUT3 }, { "All right, all right. I'm not really a cow. I don't normally go around like this; but, I was sitting at home minding my own business and all of a sudden these bugs & vines & bulbs & stuff started coming out of the floor... it was horrible! If only I had something normal to wear, it wouldn't be so bad. Hey! Could you go back to my place and get my suit for me? The brown one, not the gray one, that's for evening wear. I'd do it myself, but I don't want anyone seeing me like this. Here, take this, you might need it... to kill those things that have overgrown everything. You can't miss my house, it's just south of the fork in the river... you know... the one with the overgrown vegetable garden.|", 1, 5, TSFX_COWSUT4 }, { "What are you wasting time for? Go get my suit! And hurry! That Holstein over there keeps winking at me! |", 1, 5, TSFX_COWSUT5 }, { "Hey, have you got my suit there? Quick, pass it over! These ears itch like you wouldn't believe!|", 1, 5, TSFX_COWSUT6 }, { "No no no no! This is my GRAY suit! It's for evening wear! Formal occasions! I can't wear THIS. What are you, some kind of weirdo? I need the BROWN suit.|", 1, 5, TSFX_COWSUT7 }, { "Ahh, that's MUCH better. Whew! At last, some dignity! Are my antlers on straight? Good. Look, thanks a lot for helping me out. Here, take this as a gift; and, you know... a little fashion tip... you could use a little... you could use a new... yknowwhatImean? The whole adventurer motif is just so... retro. Just a word of advice, eh? Ciao.|", 1, 5, TSFX_COWSUT8 }, { "Look. I'm a cow. And you, you're monster bait. Get some experience under your belt! We'll talk...|", 1, 5, TSFX_COWSUT9 }, { "|", 1, 5, TSFX_TRADER1 }, { "It must truly be a fearsome task I've set before you. If there was just some way that I could... would a flagon of some nice, fresh milk help?|", 1, 5, TSFX_FARMER2A }, { "Oh, I could use your help, but perhaps after you've saved the catacombs from the desecration of those beasts.|", 1, 5, TSFX_FARMER6 }, { "I need something done, but I couldn't impose on a perfect stranger. Perhaps after you've been here a while I might feel more comfortable asking a favor.|", 1, 5, TSFX_FARMER7 }, { "I see in you the potential for greatness. Perhaps sometime while you are fulfilling your destiny, you could stop by and do a little favor for me?|", 1, 5, TSFX_FARMER8 }, { "I think you could probably help me, but perhaps after you've gotten a little more powerful. I wouldn't want to injure the village's only chance to destroy the menace in the church!|", 1, 5, TSFX_FARMER9 }, { "Me, I'm a self-made cow. Make something of yourself, and... then we'll talk.|", 1, 5, TSFX_COWSUT10 }, { "I don't have to explain myself to every tourist that walks by! Don't you have some monsters to kill? Maybe we'll talk later. If you live...|", 1, 5, TSFX_COWSUT11 }, { "Quit bugging me. I'm looking for someone really heroic. And you're not it. I can't trust you, you're going to get eaten by monsters any day now... I need someone who's an experienced hero.|", 1, 5, TSFX_COWSUT12 }, { "All right, I'll cut the bull. I didn't mean to steer you wrong. I was sitting at home, feeling moo-dy, when things got really un-stable; a whole stampede of monsters came out of the floor! I just cowed. I just happened to be wearing this Jersey when I ran out the door, and now I look udderly ridiculous. If only I had something normal to wear, it wouldn't be so bad. Hey! Can you go back to my place and get my suit for me? The brown one, not the gray one, that's for evening wear. I'd do it myself, but I don't want anyone seeing me like this. Here, take this, you might need it... to kill those things that have overgrown everything. You can't miss my house, it's just south of the fork in the river... you know... the one with the overgrown vegetable garden.|", 1, 5, TSFX_COWSUT4A }, { "Cloudy and cooler today. Casting the nets of necromancy across the void landed two new subspecies of flying horror; a good day's work. Must remember to order some more bat guano and black candles from Adria; I'm running a bit low.|", 1, 5, USFX_SKLJRN1 }, { "I have tried spells, threats, abjuration and bargaining with this foul creature -- to no avail. My methods of enslaving lesser demons seem to have no effect on this fearsome beast.|", 1, 5, PS_NARATR6 }, { "My home is slowly becoming corrupted by the vileness of this unwanted prisoner. The crypts are full of shadows that move just beyond the corners of my vision. The faint scrabble of claws dances at the edges of my hearing. They are searching, I think, for this journal.|", 1, 5, PS_NARATR7 }, { "In its ranting, the creature has let slip its name -- Na-Krul. I have attempted to research the name, but the smaller demons have somehow destroyed my library. Na-Krul... The name fills me with a cold dread. I prefer to think of it only as The Creature rather than ponder its true name.|", 1, 5, PS_NARATR8 }, { "The entrapped creature's howls of fury keep me from gaining much needed sleep. It rages against the one who sent it to the Void, and it calls foul curses upon me for trapping it here. Its words fill my heart with terror, and yet I cannot block out its voice.|", 1, 5, PS_NARATR5 }, { "My time is quickly running out. I must record the ways to weaken the demon, and then conceal that text, lest his minions find some way to use my knowledge to free their lord. I hope that whoever finds this journal will seek the knowledge.|", 1, 5, PS_NARATR9 }, { "Whoever finds this scroll is charged with stopping the demonic creature that lies within these walls. My time is over. Even now, its hellish minions claw at the frail door behind which I hide. \n \nI have hobbled the demon with arcane magic and encased it within great walls, but I fear that will not be enough. \n \nThe spells found in my three grimoires will provide you protected entrance to his domain, but only if cast in their proper sequence. The levers at the entryway will remove the barriers and free the demon; touch them not! Use only these spells to gain entry or his power may be too great for you to defeat.|", 1, 2, PS_NARATR4 }, { "In Spiritu Sanctum. |", 1, 5, PS_WARR54 }, { "Praedictum Otium. |", 1, 5, PS_WARR55 }, { "Efficio Obitus Ut Inimicus. |", 1, 5, PS_WARR56 }, { "In Spiritu Sanctum. |", 1, 5, PS_MONK54 }, { "Praedictum Otium. |", 1, 5, PS_MONK55 }, { "Efficio Obitus Ut Inimicus. |", 1, 5, PS_MONK56 }, #ifdef SPAWN { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, { "Nice try... ", 0, 0, TSFX_TAVERN36 }, #else { "In Spiritu Sanctum. |", 1, 5, PS_MAGE54 }, { "Praedictum Otium. |", 1, 5, PS_MAGE55 }, { "Efficio Obitus Ut Inimicus. |", 1, 5, PS_MAGE56 }, { "In Spiritu Sanctum. |", 1, 5, PS_ROGUE54 }, { "Praedictum Otium. |", 1, 5, PS_ROGUE55 }, { "Efficio Obitus Ut Inimicus. |", 1, 5, PS_ROGUE56 }, { "In Spiritu Sanctum. |", 1, 5, PS_ROGUE54 }, { "Praedictum Otium. |", 1, 5, PS_ROGUE55 }, { "Efficio Obitus Ut Inimicus. |", 1, 5, PS_ROGUE56 }, #endif #endif }; /** unused */ const DWORD gdwAllTextEntries = 259; ================================================ FILE: Source/textdat.h ================================================ /** * @file textdat.h * * Interface of all dialog texts. */ #ifndef __TEXTDAT_H__ #define __TEXTDAT_H__ extern const TextDataStruct alltext[]; #endif /* __TEXTDAT_H__ */ ================================================ FILE: Source/themes.cpp ================================================ /** * @file themes.cpp * * Implementation of the theme room placing algorithms. */ #include "all.h" int numthemes; BOOL armorFlag; BOOL ThemeGoodIn[4]; BOOL weaponFlag; BOOL treasureFlag; BOOL mFountainFlag; BOOL cauldronFlag; BOOL tFountainFlag; int zharlib; int themex; int themey; int themeVar1; ThemeStruct themes[MAXTHEMES]; BOOL pFountainFlag; BOOL bFountainFlag; BOOL bCrossFlag; /** Specifies the set of special theme IDs from which one will be selected at random. */ int ThemeGood[4] = { THEME_GOATSHRINE, THEME_SHRINE, THEME_SKELROOM, THEME_LIBRARY }; /** Specifies a 5x5 area to fit theme objects. */ int trm5x[] = { -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 }; /** Specifies a 5x5 area to fit theme objects. */ int trm5y[] = { -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 }; /** Specifies a 3x3 area to fit theme objects. */ int trm3x[] = { -1, 0, 1, -1, 0, 1, -1, 0, 1 }; /** Specifies a 3x3 area to fit theme objects. */ int trm3y[] = { -1, -1, -1, 0, 0, 0, 1, 1, 1 }; BOOL TFit_Shrine(int i) { int xp, yp, found; xp = 0; yp = 0; found = 0; while (found == 0) { if (dTransVal[xp][yp] == themes[i].ttval) { if (nTrapTable[dPiece[xp][yp - 1]] && !nSolidTable[dPiece[xp - 1][yp]] && !nSolidTable[dPiece[xp + 1][yp]] && dTransVal[xp - 1][yp] == themes[i].ttval && dTransVal[xp + 1][yp] == themes[i].ttval && dObject[xp - 1][yp - 1] == 0 && dObject[xp + 1][yp - 1] == 0) { found = 1; } if (found == 0 && nTrapTable[dPiece[xp - 1][yp]] && !nSolidTable[dPiece[xp][yp - 1]] && !nSolidTable[dPiece[xp][yp + 1]] && dTransVal[xp][yp - 1] == themes[i].ttval && dTransVal[xp][yp + 1] == themes[i].ttval && dObject[xp - 1][yp - 1] == 0 && dObject[xp - 1][yp + 1] == 0) { found = 2; } } if (found == 0) { xp++; if (xp == MAXDUNX) { xp = 0; yp++; if (yp == MAXDUNY) return FALSE; } } } themex = xp; themey = yp; themeVar1 = found; return TRUE; } BOOL TFit_Obj5(int t) { int xp, yp; int i, r, rs; BOOL found; xp = 0; yp = 0; r = random_(0, 5) + 1; rs = r; while (r > 0) { found = FALSE; if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) { found = TRUE; for (i = 0; found && i < 25; i++) { if (nSolidTable[dPiece[xp + trm5x[i]][yp + trm5y[i]]]) { found = FALSE; } if (dTransVal[xp + trm5x[i]][yp + trm5y[i]] != themes[t].ttval) { found = FALSE; } } } if (!found) { xp++; if (xp == MAXDUNX) { xp = 0; yp++; if (yp == MAXDUNY) { if (r == rs) { return FALSE; } yp = 0; } } continue; } r--; } themex = xp; themey = yp; return TRUE; } BOOL TFit_SkelRoom(int t) { int i; if (leveltype != DTYPE_CATHEDRAL && leveltype != DTYPE_CATACOMBS) { return FALSE; } for (i = 0; i < nummtypes; i++) { if (IsSkel(Monsters[i].mtype)) { themeVar1 = i; return TFit_Obj5(t); } } return FALSE; } BOOL TFit_GoatShrine(int t) { int i; for (i = 0; i < nummtypes; i++) { if (IsGoat(Monsters[i].mtype)) { themeVar1 = i; return TFit_Obj5(t); } } return FALSE; } BOOL CheckThemeObj3(int xp, int yp, int t, int f) { int i; for (i = 0; i < 9; i++) { if (xp + trm3x[i] < 0 || yp + trm3y[i] < 0) return FALSE; if (nSolidTable[dPiece[xp + trm3x[i]][yp + trm3y[i]]]) return FALSE; if (dTransVal[xp + trm3x[i]][yp + trm3y[i]] != themes[t].ttval) return FALSE; if (dObject[xp + trm3x[i]][yp + trm3y[i]]) return FALSE; if (f != -1 && random_(0, f) == 0) return FALSE; } return TRUE; } BOOL TFit_Obj3(int t) { int xp, yp; char objrnd[4] = { 4, 4, 3, 5 }; for (yp = 1; yp < MAXDUNY - 1; yp++) { for (xp = 1; xp < MAXDUNX - 1; xp++) { if (CheckThemeObj3(xp, yp, t, objrnd[leveltype - 1])) { themex = xp; themey = yp; return TRUE; } } } return FALSE; } BOOL CheckThemeReqs(int t) { BOOL rv; rv = TRUE; switch (t) { case THEME_SHRINE: case THEME_SKELROOM: case THEME_LIBRARY: if (leveltype == DTYPE_CAVES || leveltype == DTYPE_HELL) { rv = FALSE; } break; case THEME_BLOODFOUNTAIN: if (!bFountainFlag) { rv = FALSE; } break; case THEME_PURIFYINGFOUNTAIN: if (!pFountainFlag) { rv = FALSE; } break; case THEME_ARMORSTAND: if (leveltype == DTYPE_CATHEDRAL) { rv = FALSE; } break; case THEME_CAULDRON: if (leveltype != DTYPE_HELL || !cauldronFlag) { rv = FALSE; } break; case THEME_MURKYFOUNTAIN: if (!mFountainFlag) { rv = FALSE; } break; case THEME_TEARFOUNTAIN: if (!tFountainFlag) { rv = FALSE; } break; case THEME_WEAPONRACK: if (leveltype == DTYPE_CATHEDRAL) { rv = FALSE; } break; } return rv; } BOOL SpecialThemeFit(int i, int t) { BOOL rv; 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_BLOODFOUNTAIN: if (rv) { rv = TFit_Obj5(i); } if (rv) { bFountainFlag = FALSE; } break; case THEME_PURIFYINGFOUNTAIN: if (rv) { rv = TFit_Obj5(i); } if (rv) { pFountainFlag = FALSE; } break; case THEME_MURKYFOUNTAIN: if (rv) { rv = TFit_Obj5(i); } if (rv) { mFountainFlag = FALSE; } break; case THEME_TEARFOUNTAIN: if (rv) { rv = TFit_Obj5(i); } if (rv) { tFountainFlag = FALSE; } break; case THEME_CAULDRON: if (rv) { rv = TFit_Obj5(i); } if (rv) { cauldronFlag = FALSE; } break; case THEME_GOATSHRINE: if (rv) { rv = TFit_GoatShrine(i); } 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_TREASURE: rv = treasureFlag; if (rv) { treasureFlag = FALSE; } break; } return rv; } BOOL CheckThemeRoom(int tv) { int i, j, tarea; for (i = 0; i < numtrigs; i++) { if (dTransVal[trigs[i]._tx][trigs[i]._ty] == tv) return FALSE; } tarea = 0; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dTransVal[i][j] != tv) continue; if (dFlags[i][j] & BFLAG_POPULATED) return FALSE; tarea++; } } if (leveltype == DTYPE_CATHEDRAL && (tarea < 9 || tarea > 100)) return FALSE; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dTransVal[i][j] != tv || nSolidTable[dPiece[i][j]]) continue; if (dTransVal[i - 1][j] != tv && !nSolidTable[dPiece[i - 1][j]]) return FALSE; if (dTransVal[i + 1][j] != tv && !nSolidTable[dPiece[i + 1][j]]) return FALSE; if (dTransVal[i][j - 1] != tv && !nSolidTable[dPiece[i][j - 1]]) return FALSE; if (dTransVal[i][j + 1] != tv && !nSolidTable[dPiece[i][j + 1]]) return FALSE; } } return TRUE; } void InitThemes() { int i, j; zharlib = -1; numthemes = 0; armorFlag = TRUE; bFountainFlag = TRUE; cauldronFlag = TRUE; mFountainFlag = TRUE; pFountainFlag = TRUE; tFountainFlag = TRUE; treasureFlag = TRUE; bCrossFlag = FALSE; weaponFlag = TRUE; if (currlevel == 16) return; if (leveltype == DTYPE_CATHEDRAL) { for (i = 0; i < sizeof(ThemeGoodIn) / sizeof(ThemeGoodIn[0]); i++) ThemeGoodIn[i] = FALSE; for (i = 0; i < 256 && numthemes < MAXTHEMES; i++) { if (CheckThemeRoom(i)) { themes[numthemes].ttval = i; for (j = ThemeGood[random_(0, 4)];; j = random_(0, 17)) { if (SpecialThemeFit(numthemes, j)) { break; } } themes[numthemes].ttype = j; numthemes++; } } } if (leveltype == DTYPE_CATACOMBS || leveltype == DTYPE_CAVES || leveltype == DTYPE_HELL) { for (i = 0; i < themeCount; i++) themes[i].ttype = THEME_NONE; if (QuestStatus(Q_ZHAR)) { for (j = 0; j < themeCount; j++) { themes[j].ttval = themeLoc[j].ttval; if (SpecialThemeFit(j, THEME_LIBRARY)) { themes[j].ttype = THEME_LIBRARY; zharlib = j; break; } } } for (i = 0; i < themeCount; i++) { if (themes[i].ttype == THEME_NONE) { themes[i].ttval = themeLoc[i].ttval; for (j = ThemeGood[random_(0, 4)];; j = random_(0, 17)) { if (SpecialThemeFit(i, j)) { break; } } themes[i].ttype = j; } } numthemes += themeCount; } } /** * @brief HoldThemeRooms marks theme rooms as populated. */ void HoldThemeRooms() { int i, x, y; char v; if (currlevel != 16) { if (leveltype == DTYPE_CATHEDRAL) { for (i = 0; i < numthemes; i++) { v = themes[i].ttval; for (y = 0; y < MAXDUNY; y++) { for (x = 0; x < MAXDUNX; x++) { if (dTransVal[x][y] == v) { dFlags[x][y] |= BFLAG_POPULATED; } } } } } else { DRLG_HoldThemeRooms(); } } } /** * PlaceThemeMonsts places theme monsters with the specified frequency. * * @param t theme number (index into themes array). * @param f frequency (1/f likelihood of adding monster). */ void PlaceThemeMonsts(int t, int f) { int xp, yp; #ifdef HELLFIRE int scattertypes[138]; #else int scattertypes[111]; #endif int numscattypes, mtype, i; numscattypes = 0; for (i = 0; i < nummtypes; i++) { if (Monsters[i].mPlaceFlags & PLACE_SCATTER) { scattertypes[numscattypes] = i; numscattypes++; } } mtype = scattertypes[random_(0, numscattypes)]; for (yp = 0; yp < MAXDUNY; yp++) { for (xp = 0; xp < MAXDUNX; xp++) { if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]] && dItem[xp][yp] == 0 && dObject[xp][yp] == 0) { if (random_(0, f) == 0) { AddMonster(xp, yp, random_(0, 8), mtype, TRUE); } } } } } /** * Theme_Barrel initializes the barrel theme. * * @param t theme number (index into themes array). */ void Theme_Barrel(int t) { int xp, yp, r; char barrnd[4] = { 2, 6, 4, 8 }; char monstrnd[4] = { 5, 7, 3, 9 }; for (yp = 0; yp < MAXDUNY; yp++) { for (xp = 0; xp < MAXDUNX; xp++) { if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) { if (random_(0, barrnd[leveltype - 1]) == 0) { if (random_(0, barrnd[leveltype - 1]) == 0) { r = OBJ_BARREL; } else { r = OBJ_BARRELEX; } AddObject(r, xp, yp); } } } } PlaceThemeMonsts(t, monstrnd[leveltype - 1]); } /** * Theme_Shrine initializes the shrine theme. * * @param t theme number (index into themes array). */ void Theme_Shrine(int t) { char monstrnd[4] = { 6, 6, 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]); } /** * Theme_MonstPit initializes the monster pit theme. * * @param t theme number (index into themes array). */ void Theme_MonstPit(int t) { int r; int ixp, iyp; char monstrnd[4] = { 6, 7, 3, 9 }; r = random_(0, 100) + 1; ixp = 0; iyp = 0; while (r > 0) { if (dTransVal[ixp][iyp] == themes[t].ttval && !nSolidTable[dPiece[ixp][iyp]]) { --r; } if (r <= 0) continue; ixp++; if (ixp == MAXDUNX) { ixp = 0; iyp++; if (iyp == MAXDUNY) { iyp = 0; } } } CreateRndItem(ixp, iyp, TRUE, FALSE, TRUE); ItemNoFlippy(); PlaceThemeMonsts(t, monstrnd[leveltype - 1]); } /** * Theme_SkelRoom initializes the skeleton room theme. * * @param t theme number (index into themes array). */ void Theme_SkelRoom(int t) { int xp, yp, i; char monstrnd[4] = { 6, 7, 3, 9 }; TFit_SkelRoom(t); xp = themex; yp = themey; AddObject(OBJ_SKFIRE, xp, yp); if (random_(0, monstrnd[leveltype - 1]) != 0) { i = PreSpawnSkeleton(); SpawnSkeleton(i, xp - 1, yp - 1); } else { AddObject(OBJ_BANNERL, xp - 1, yp - 1); } i = PreSpawnSkeleton(); SpawnSkeleton(i, xp, yp - 1); if (random_(0, monstrnd[leveltype - 1]) != 0) { i = PreSpawnSkeleton(); SpawnSkeleton(i, xp + 1, yp - 1); } else { AddObject(OBJ_BANNERR, xp + 1, yp - 1); } if (random_(0, monstrnd[leveltype - 1]) != 0) { i = PreSpawnSkeleton(); SpawnSkeleton(i, xp - 1, yp); } else { AddObject(OBJ_BANNERM, xp - 1, yp); } if (random_(0, monstrnd[leveltype - 1]) != 0) { i = PreSpawnSkeleton(); SpawnSkeleton(i, xp + 1, yp); } else { AddObject(OBJ_BANNERM, xp + 1, yp); } if (random_(0, monstrnd[leveltype - 1]) != 0) { i = PreSpawnSkeleton(); SpawnSkeleton(i, xp - 1, yp + 1); } else { AddObject(OBJ_BANNERR, xp - 1, yp + 1); } i = PreSpawnSkeleton(); SpawnSkeleton(i, xp, yp + 1); if (random_(0, monstrnd[leveltype - 1]) != 0) { i = PreSpawnSkeleton(); SpawnSkeleton(i, xp + 1, yp + 1); } else { AddObject(OBJ_BANNERL, xp + 1, yp + 1); } if (dObject[xp][yp - 3] == 0) { AddObject(OBJ_SKELBOOK, xp, yp - 2); } if (dObject[xp][yp + 3] == 0) { AddObject(OBJ_SKELBOOK, xp, yp + 2); } } /** * Theme_Treasure initializes the treasure theme. * * @param t theme number (index into themes array). */ void Theme_Treasure(int t) { int xp, yp; int i; char treasrnd[4] = { 4, 9, 7, 10 }; char monstrnd[4] = { 6, 8, 3, 7 }; GetRndSeed(); for (yp = 0; yp < MAXDUNY; yp++) { for (xp = 0; xp < MAXDUNX; xp++) { if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) { int rv = random_(0, treasrnd[leveltype - 1]); // BUGFIX: the `2*` in `2*random_(0, treasrnd...) == 0` has no effect, should probably be `random_(0, 2*treasrnd...) == 0` if ((2 * random_(0, treasrnd[leveltype - 1])) == 0) { CreateTypeItem(xp, yp, FALSE, ITYPE_GOLD, IMISC_NONE, FALSE, TRUE); ItemNoFlippy(); } if (rv == 0) { CreateRndItem(xp, yp, FALSE, FALSE, TRUE); ItemNoFlippy(); } // BUGFIX: the following code is likely not working as intended. // // `rv == 0` has no effect. // // `rv >= treasrnd[leveltype - 1] - 2` is not connected to either // of the item creation branches above, thus the last (unrelated) // item spawned/dropped on ground would be halved in value. if (rv == 0 || rv >= treasrnd[leveltype - 1] - 2) { i = ItemNoFlippy(); if (rv >= treasrnd[leveltype - 1] - 2 && leveltype != DTYPE_CATHEDRAL) { item[i]._ivalue >>= 1; } } } } } PlaceThemeMonsts(t, monstrnd[leveltype - 1]); } /** * Theme_Library initializes the library theme. * * @param t theme number (index into themes array). */ void Theme_Library(int t) { int xp, yp, oi; char librnd[4] = { 1, 2, 2, 5 }; char monstrnd[4] = { 5, 7, 3, 9 }; TFit_Shrine(t); 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); } for (yp = 1; yp < MAXDUNY - 1; yp++) { for (xp = 1; xp < MAXDUNX - 1; xp++) { if (CheckThemeObj3(xp, yp, t, -1) && dMonster[xp][yp] == 0 && random_(0, librnd[leveltype - 1]) == 0) { AddObject(OBJ_BOOKSTAND, xp, yp); if (random_(0, 2 * librnd[leveltype - 1]) != 0) { /// BUGFIX: check dObject[xp][yp] was populated by AddObject oi = dObject[xp][yp] - 1; object[oi]._oSelFlag = 0; object[oi]._oAnimFrame += 2; } } } } if (QuestStatus(Q_ZHAR)) { if (t == zharlib) { return; } PlaceThemeMonsts(t, monstrnd[leveltype]); /// BUGFIX: `leveltype - 1` } else { PlaceThemeMonsts(t, monstrnd[leveltype]); /// BUGFIX: `leveltype - 1` } } /** * Theme_Torture initializes the torture theme. * * @param t theme number (index into themes array). */ void Theme_Torture(int t) { int xp, yp; char tortrnd[4] = { 6, 8, 3, 8 }; char monstrnd[4] = { 6, 8, 3, 9 }; for (yp = 1; yp < MAXDUNY - 1; yp++) { for (xp = 1; xp < MAXDUNX - 1; xp++) { if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) { if (CheckThemeObj3(xp, yp, t, -1)) { if (random_(0, tortrnd[leveltype - 1]) == 0) { AddObject(OBJ_TNUDEM2, xp, yp); } } } } } PlaceThemeMonsts(t, monstrnd[leveltype - 1]); } /** * Theme_BloodFountain initializes the blood fountain theme. * @param t Theme number (index into themes array). */ void Theme_BloodFountain(int t) { char monstrnd[4] = { 6, 8, 3, 9 }; TFit_Obj5(t); AddObject(OBJ_BLOODFTN, themex, themey); PlaceThemeMonsts(t, monstrnd[leveltype - 1]); } /** * Theme_Decap initializes the decapitated theme. * * @param t theme number (index into themes array). */ void Theme_Decap(int t) { int xp, yp; char decaprnd[4] = { 6, 8, 3, 8 }; char monstrnd[4] = { 6, 8, 3, 9 }; for (yp = 1; yp < MAXDUNY - 1; yp++) { for (xp = 1; xp < MAXDUNX - 1; xp++) { if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) { if (CheckThemeObj3(xp, yp, t, -1)) { if (random_(0, decaprnd[leveltype - 1]) == 0) { AddObject(OBJ_DECAP, xp, yp); } } } } } PlaceThemeMonsts(t, monstrnd[leveltype - 1]); } /** * Theme_PurifyingFountain initializes the purifying fountain theme. * * @param t theme number (index into themes array). */ void Theme_PurifyingFountain(int t) { char monstrnd[4] = { 6, 7, 3, 9 }; TFit_Obj5(t); AddObject(OBJ_PURIFYINGFTN, themex, themey); PlaceThemeMonsts(t, monstrnd[leveltype - 1]); } /** * Theme_ArmorStand initializes the armor stand theme. * * @param t theme number (index into themes array). */ void Theme_ArmorStand(int t) { int xp, yp; char armorrnd[4] = { 6, 8, 3, 8 }; char monstrnd[4] = { 6, 7, 3, 9 }; if (armorFlag) { TFit_Obj3(t); AddObject(OBJ_ARMORSTAND, themex, themey); } for (yp = 0; yp < MAXDUNY; yp++) { for (xp = 0; xp < MAXDUNX; xp++) { if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) { if (CheckThemeObj3(xp, yp, t, -1)) { if (random_(0, armorrnd[leveltype - 1]) == 0) { AddObject(OBJ_ARMORSTANDN, xp, yp); } } } } } PlaceThemeMonsts(t, monstrnd[leveltype - 1]); armorFlag = FALSE; } /** * Theme_GoatShrine initializes the goat shrine theme. * * @param t theme number (index into themes array). */ void Theme_GoatShrine(int t) { int xx, yy; TFit_GoatShrine(t); AddObject(OBJ_GOATSHRINE, themex, themey); for (yy = themey - 1; yy <= themey + 1; yy++) { for (xx = themex - 1; xx <= themex + 1; xx++) { if (dTransVal[xx][yy] == themes[t].ttval && !nSolidTable[dPiece[xx][yy]] && (xx != themex || yy != themey)) { AddMonster(xx, yy, DIR_SW, themeVar1, TRUE); } } } } /** * Theme_Cauldron initializes the cauldron theme. * * @param t theme number (index into themes array). */ void Theme_Cauldron(int t) { char monstrnd[4] = { 6, 7, 3, 9 }; TFit_Obj5(t); AddObject(OBJ_CAULDRON, themex, themey); PlaceThemeMonsts(t, monstrnd[leveltype - 1]); } /** * Theme_MurkyFountain initializes the murky fountain theme. * * @param t theme number (index into themes array). */ void Theme_MurkyFountain(int t) { char monstrnd[4] = { 6, 7, 3, 9 }; TFit_Obj5(t); AddObject(OBJ_MURKYFTN, themex, themey); PlaceThemeMonsts(t, monstrnd[leveltype - 1]); } /** * Theme_TearFountain initializes the tear fountain theme. * * @param t theme number (index into themes array). */ void Theme_TearFountain(int t) { char monstrnd[4] = { 6, 7, 3, 9 }; TFit_Obj5(t); AddObject(OBJ_TEARFTN, themex, themey); PlaceThemeMonsts(t, monstrnd[leveltype - 1]); } /** * Theme_BrnCross initializes the burning cross theme. * * @param t theme number (index into themes array). */ void Theme_BrnCross(int t) { int xp, yp; char monstrnd[4] = { 6, 8, 3, 9 }; char bcrossrnd[4] = { 5, 7, 3, 8 }; for (yp = 0; yp < MAXDUNY; yp++) { for (xp = 0; xp < MAXDUNX; xp++) { if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) { if (CheckThemeObj3(xp, yp, t, -1)) { if (random_(0, bcrossrnd[leveltype - 1]) == 0) { AddObject(OBJ_TBCROSS, xp, yp); } } } } } PlaceThemeMonsts(t, monstrnd[leveltype - 1]); bCrossFlag = TRUE; } /** * Theme_WeaponRack initializes the weapon rack theme. * * @param t theme number (index into themes array). */ void Theme_WeaponRack(int t) { int xp, yp; char weaponrnd[4] = { 6, 8, 5, 8 }; char monstrnd[4] = { 6, 7, 3, 9 }; if (weaponFlag) { TFit_Obj3(t); AddObject(OBJ_WEAPONRACK, themex, themey); } for (yp = 0; yp < MAXDUNY; yp++) { for (xp = 0; xp < MAXDUNX; xp++) { if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) { if (CheckThemeObj3(xp, yp, t, -1)) { if (random_(0, weaponrnd[leveltype - 1]) == 0) { AddObject(OBJ_WEAPONRACKN, xp, yp); } } } } } PlaceThemeMonsts(t, monstrnd[leveltype - 1]); weaponFlag = FALSE; } /** * UpdateL4Trans sets each value of the transparency map to 1. */ void UpdateL4Trans() { int i, j; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dTransVal[i][j] != 0) { dTransVal[i][j] = 1; } } } } /** * CreateThemeRooms adds thematic elements to rooms. */ void CreateThemeRooms() { int i; if (currlevel == 16) { return; } InitObjFlag = TRUE; 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; } } InitObjFlag = FALSE; if (leveltype == DTYPE_HELL && themeCount > 0) { UpdateL4Trans(); } } ================================================ FILE: Source/themes.h ================================================ /** * @file themes.h * * Interface of the theme room placing algorithms. */ #ifndef __THEMES_H__ #define __THEMES_H__ extern int numthemes; extern BOOL armorFlag; extern BOOL weaponFlag; extern int zharlib; extern ThemeStruct themes[MAXTHEMES]; void InitThemes(); void HoldThemeRooms(); void CreateThemeRooms(); #endif /* __THEMES_H__ */ ================================================ FILE: Source/tmsg.cpp ================================================ /** * @file tmsg.cpp * * Implementation of functionality transmitting chat messages. */ #include "all.h" static TMsg *sgpTimedMsgHead; int tmsg_get(BYTE *pbMsg, DWORD dwMaxLen) { int len; TMsg *head; if (!sgpTimedMsgHead) return 0; if ((int)(sgpTimedMsgHead->hdr.dwTime - GetTickCount()) >= 0) return 0; head = sgpTimedMsgHead; sgpTimedMsgHead = head->hdr.pNext; len = head->hdr.bLen; // BUGFIX: ignores dwMaxLen memcpy(pbMsg, head->body, len); mem_free_dbg(head); return len; } void tmsg_add(BYTE *pbMsg, BYTE bLen) { TMsg **tail; TMsg *msg = (TMsg *)DiabloAllocPtr(bLen + sizeof(*msg)); msg->hdr.pNext = NULL; msg->hdr.dwTime = GetTickCount() + 500; msg->hdr.bLen = bLen; memcpy(msg->body, pbMsg, bLen); for (tail = &sgpTimedMsgHead; *tail; tail = &(*tail)->hdr.pNext) { ; } *tail = msg; } void tmsg_start() { assert(!sgpTimedMsgHead); } void tmsg_cleanup() { TMsg *next; while (sgpTimedMsgHead) { next = sgpTimedMsgHead->hdr.pNext; MemFreeDbg(sgpTimedMsgHead); sgpTimedMsgHead = next; } } ================================================ FILE: Source/tmsg.h ================================================ /** * @file tmsg.h * * Interface of functionality transmitting chat messages. */ #ifndef __TMSG_H__ #define __TMSG_H__ int tmsg_get(BYTE *pbMsg, DWORD dwMaxLen); void tmsg_add(BYTE *pbMsg, BYTE bLen); void tmsg_start(); void tmsg_cleanup(); #endif /* __TMSG_H__ */ ================================================ FILE: Source/town.cpp ================================================ /** * @file town.h * * Implementation of functionality for rendering the town, towners and calling other render routines. */ #include "all.h" /** * @brief Render a black tile * @brief world_draw_black_tile but limited to upper half of screen * @param pBuff location in back buffer to render the tile, must be on upper half of screen */ void town_clear_upper_buf(BYTE *pBuff) { assert(gpBuffer); #ifdef USE_ASM __asm { mov edi, pBuff mov edx, TILE_HEIGHT - 2 mov ebx, 1 xor eax, eax label1: cmp edi, gpBufEnd jb label4 add edi, edx mov ecx, ebx rep stosd add edi, edx sub edi, BUFFER_WIDTH + TILE_WIDTH or edx, edx jz label2 sub edx, 2 inc ebx jmp label1 label2: mov edx, 2 mov ebx, TILE_HEIGHT / 2 - 1 label3: cmp edi, gpBufEnd jb label4 add edi, edx mov ecx, ebx rep stosd add edi, edx sub edi, BUFFER_WIDTH + TILE_WIDTH dec ebx add edx, 2 cmp edx, TILE_HEIGHT jnz label3 label4: nop } #else int i, j, k; BYTE *dst; dst = pBuff; for (i = TILE_HEIGHT - 2, j = 1; i >= 0 && dst >= gpBufEnd; i -= 2, j++, dst -= BUFFER_WIDTH + TILE_WIDTH) { dst += i; for (k = 0; k < 4 * j; k++) *dst++ = 0; dst += i; } for (i = 2, j = TILE_HEIGHT / 2 - 1; i != TILE_HEIGHT && dst >= gpBufEnd; i += 2, j--, dst -= BUFFER_WIDTH + TILE_WIDTH) { dst += i; for (k = 0; k < 4 * j; k++) *dst++ = 0; dst += i; } #endif } /** * @brief Render a black tile * @brief world_draw_black_tile but limited to lower half of screen * @param pBuff location in back buffer to render the tile, must be on lower half of screen */ void town_clear_low_buf(BYTE *pBuff) { assert(gpBuffer); #ifdef USE_ASM __asm { mov edi, pBuff mov edx, TILE_HEIGHT - 2 mov ebx, 1 xor eax, eax label1: cmp edi, gpBufEnd jb label2 add edi, TILE_WIDTH jmp label3 label2: add edi, edx mov ecx, ebx rep stosd add edi, edx label3: sub edi, BUFFER_WIDTH + TILE_WIDTH or edx, edx jz label4 sub edx, 2 inc ebx jmp label1 label4: mov edx, 2 mov ebx, TILE_HEIGHT / 2 - 1 label5: cmp edi, gpBufEnd jb label6 add edi, TILE_WIDTH jmp label7 label6: add edi, edx mov ecx, ebx rep stosd add edi, edx label7: sub edi, BUFFER_WIDTH + TILE_WIDTH dec ebx add edx, 2 cmp edx, TILE_HEIGHT jnz label5 } #else int i, j, k; BYTE *dst; dst = pBuff; for (i = TILE_HEIGHT - 2, j = 1; i >= 0; i -= 2, j++, dst -= BUFFER_WIDTH + TILE_WIDTH) { if (dst < gpBufEnd) { dst += i; for (k = 0; k < 4 * j; k++) *dst++ = 0; dst += i; } else { dst += TILE_WIDTH; } } for (i = 2, j = TILE_HEIGHT / 2 - 1; i != TILE_HEIGHT; i += 2, j--, dst -= BUFFER_WIDTH + TILE_WIDTH) { if (dst < gpBufEnd) { dst += i; for (k = 0; k < 4 * j; k++) *dst++ = 0; dst += i; } else { dst += TILE_WIDTH; } } #endif } /** * @brief Render trees on top of player, buggy disabled in 1.09 * @param pBuff backbuffer pointing where to render on lower part of screen * @param nCel Frame number for pSpecialCels tile to draw */ void town_special_lower(BYTE *pBuff, int nCel) { #if 0 int w; BYTE *end; #ifdef USE_ASM __asm { mov ebx, pSpecialCels mov eax, nCel shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov end, eax mov esi, pSpecialCels add esi, [ebx] mov edi, pBuff mov eax, BUFFER_WIDTH + 64 mov w, eax mov ebx, end add ebx, esi label1: mov edx, 64 label2: xor eax, eax lodsb or al, al js label7 sub edx, eax cmp edi, gpBufEnd jb label3 add esi, eax add edi, eax jmp label6 label3: mov ecx, eax shr ecx, 1 jnb label4 movsb jecxz label6 label4: shr ecx, 1 jnb label5 movsw jecxz label6 label5: rep movsd label6: or edx, edx jz label8 jmp label2 label7: neg al add edi, eax sub edx, eax jnz label2 label8: sub edi, w cmp ebx, esi jnz label1 } #else BYTE width; BYTE *src, *dst; DWORD *pFrameTable; pFrameTable = (DWORD *)pSpecialCels; src = &pSpecialCels[pFrameTable[nCel]]; dst = pBuff; end = &src[pFrameTable[nCel + 1] - pFrameTable[nCel]]; for(; src != end; dst -= BUFFER_WIDTH + 64) { for(w = 64; w;) { width = *src++; if(!(width & 0x80)) { w -= width; if(dst < gpBufEnd) { if(width & 1) { dst[0] = src[0]; src++; dst++; } width >>= 1; if(width & 1) { dst[0] = src[0]; dst[1] = src[1]; src += 2; dst += 2; } width >>= 1; for(; width; width--) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; src += 4; dst += 4; } } else { src += width; dst += width; } } else { width = -(char)width; dst += width; w -= width; } } } #endif #endif } /** * @brief Render trees on top of player, buggy disabled in 1.09 * @param pBuff backbuffer pointing where to render on upper part of screen * @param nCel Frame number for pSpecialCels tile to draw */ void town_special_upper(BYTE *pBuff, int nCel) { #if 0 int w; BYTE *end; #ifdef USE_ASM __asm { mov ebx, pSpecialCels mov eax, nCel shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov end, eax mov esi, pSpecialCels add esi, [ebx] mov edi, pBuff mov eax, BUFFER_WIDTH + 64 mov w, eax mov ebx, end add ebx, esi label1: mov edx, 64 label2: xor eax, eax lodsb or al, al js label6 sub edx, eax cmp edi, gpBufEnd jb label8 mov ecx, eax shr ecx, 1 jnb label3 movsb jecxz label5 label3: shr ecx, 1 jnb label4 movsw jecxz label5 label4: rep movsd label5: or edx, edx jz label7 jmp label2 label6: neg al add edi, eax sub edx, eax jnz label2 label7: sub edi, w cmp ebx, esi jnz label1 label8: nop } #else BYTE width; BYTE *src, *dst; DWORD *pFrameTable; pFrameTable = (DWORD *)pSpecialCels; src = &pSpecialCels[pFrameTable[nCel]]; dst = pBuff; end = &src[pFrameTable[nCel + 1] - pFrameTable[nCel]]; for(; src != end; dst -= BUFFER_WIDTH + 64) { for(w = 64; w;) { width = *src++; if(!(width & 0x80)) { w -= width; if(dst < gpBufEnd) { return; } if(width & 1) { dst[0] = src[0]; src++; dst++; } width >>= 1; if(width & 1) { dst[0] = src[0]; dst[1] = src[1]; src += 2; dst += 2; } width >>= 1; for(; width; width--) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; src += 4; dst += 4; } } else { width = -(char)width; dst += width; w -= width; } } } #endif #endif } /** * This variant checks for of screen element on the lower screen * This function it self causes rendering issues since it will render on top of objects on the other side of walls * @brief Re render tile to workaround sorting issues with players walking east/west * @param pBuff Pointer to output buffer at location sx,sy * @param y dPiece coordinate * @param x dPiece coordinate * @param sx Backbuffer coordinate * @param sy Backbuffer coordinate */ void town_draw_clipped_e_flag(BYTE *pBuff, int x, int y, int sx, int sy) { int i; BYTE *dst; MICROS *pMap; dst = pBuff; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 12; i += 2) { level_cel_block = pMap->mt[i]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[i + 1]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } dst -= BUFFER_WIDTH * TILE_HEIGHT; } town_draw_clipped_town(pBuff, x, y, sx, sy, 0); } /** * @brief Render object sprites * @param pBuff where to render to with sx,sy already applied * @param sx dPiece coordinate * @param sy dPiece coordinate * @param dx Backbuffer coordinate * @param dy Backbuffer coordinate * @param eflag Should the sorting workaround be applied */ void town_draw_clipped_town(BYTE *pBuff, int sx, int sy, int dx, int dy, int eflag) { int mi, px, py; char bv; assert(gpBuffer); pBuff = &gpBuffer[dx + PitchTbl[dy]]; if (dItem[sx][sy] != 0) { bv = dItem[sx][sy] - 1; px = dx - item[bv]._iAnimWidth2; if (bv == pcursitem) { CelBlitOutlineSafe(181, px, dy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, 0, 8); } CelClippedDrawSafe(px, dy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, 0, 8); } if (dFlags[sx][sy] & BFLAG_MONSTLR) { mi = -(dMonster[sx][sy - 1] + 1); px = dx - towner[mi]._tAnimWidth2; if (mi == pcursmonst) { CelBlitOutlineSafe(166, px, dy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, 8); } CelClippedDrawSafe(px, dy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, 8); } if (dMonster[sx][sy] > 0) { mi = dMonster[sx][sy] - 1; px = dx - towner[mi]._tAnimWidth2; if (mi == pcursmonst) { CelBlitOutlineSafe(166, px, dy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, 8); } CelClippedDrawSafe(px, dy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, 8); } if (dFlags[sx][sy] & BFLAG_PLAYERLR) { bv = -(dPlayer[sx][sy - 1] + 1); px = dx + plr[bv]._pxoff - plr[bv]._pAnimWidth2; py = dy + plr[bv]._pyoff; if (bv == pcursplr) { Cl2DrawOutlineSafe(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, 8); } Cl2DrawSafe(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, 8); if (eflag && plr[bv]._peflag) { town_draw_clipped_e_flag(pBuff - TILE_WIDTH, sx - 1, sy + 1, dx - TILE_WIDTH, dy); } } if (dFlags[sx][sy] & BFLAG_DEAD_PLAYER) { DrawDeadPlayer(sx, sy, dx, dy, 0, 8, TRUE); } if (dPlayer[sx][sy] > 0) { bv = dPlayer[sx][sy] - 1; px = dx + plr[bv]._pxoff - plr[bv]._pAnimWidth2; py = dy + plr[bv]._pyoff; if (bv == pcursplr) { Cl2DrawOutlineSafe(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, 8); } Cl2DrawSafe(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, 8); if (eflag && plr[bv]._peflag) { town_draw_clipped_e_flag(pBuff - TILE_WIDTH, sx - 1, sy + 1, dx - TILE_WIDTH, dy); } } if (dFlags[sx][sy] & BFLAG_MISSILE) { DrawClippedMissile(sx, sy, dx, dy, 0, 8, 0); } if (dSpecial[sx][sy] != 0) { town_special_lower(pBuff, dSpecial[sx][sy]); } } /** * @brief Render a row of tile * @param x dPiece coordinate * @param y dPiece coordinate * @param sx Backbuffer coordinate * @param sy Backbuffer coordinate * @param chunks tile width of row * @param eflag is it an even (0) or odd (1) row */ void town_draw_lower(int x, int y, int sx, int sy, int chunks, int eflag) { int i, j; BYTE *dst; MICROS *pMap; /// ASSERT: assert(gpBuffer); if (eflag) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_cel_block = dPiece[x][y]; if (level_cel_block != 0) { dst = &gpBuffer[sx + TILE_WIDTH / 2 + PitchTbl[sy]]; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 1; i < 17; i += 2) { level_cel_block = pMap->mt[i]; if (level_cel_block != 0) { drawLowerScreen(dst); } dst -= BUFFER_WIDTH * TILE_HEIGHT; } town_draw_clipped_town(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, 0); } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } x++; y--; sx += TILE_WIDTH; } for (j = 0; j < chunks - eflag; j++) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_cel_block = dPiece[x][y]; if (level_cel_block != 0) { dst = &gpBuffer[sx + PitchTbl[sy]]; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 16; i += 2) { level_cel_block = pMap->mt[i]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[i + 1]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } dst -= BUFFER_WIDTH * TILE_HEIGHT; } town_draw_clipped_town(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, 1); } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } x++; y--; sx += TILE_WIDTH; } if (eflag) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_cel_block = dPiece[x][y]; if (level_cel_block != 0) { dst = &gpBuffer[sx + PitchTbl[sy]]; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 16; i += 2) { level_cel_block = pMap->mt[i]; if (level_cel_block != 0) { drawLowerScreen(dst); } dst -= BUFFER_WIDTH * TILE_HEIGHT; } town_draw_clipped_town(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, 0); } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } } } /** * This variant checks for of screen element on the lower screen * This function it self causes rendering issues since it will render on top of objects on the other side of walls * @brief Re render tile to workaround sorting issues with players walking east/west * @param pBuff Pointer to output buffer at location sx,sy * @param y dPiece coordinate * @param x dPiece coordinate * @param row The current row being rendered * @param CelSkip chunks of cell to skip * @param sx Backbuffer coordinate * @param sy Backbuffer coordinate */ void town_draw_clipped_e_flag_2(BYTE *pBuff, int x, int y, int row, int CelSkip, int sx, int sy) { int i; BYTE *dst; MICROS *pMap; if (row == 0) { dst = pBuff; } else { dst = &pBuff[BUFFER_WIDTH * TILE_HEIGHT * row]; } pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 6; i++) { if (row <= i) { level_cel_block = pMap->mt[2 * i + 2]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[2 * i + 3]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; } if (CelSkip < 8) { town_draw_clipped_town_2(pBuff, x, y, row, CelSkip, sx, sy, 0); } } /** * @brief Render object sprites, skip offscreen parts for lower screen * @param pBuff where to render to with sx,sy already applied * @param sx dPiece coordinate * @param sy dPiece coordinate * @param row The current row being rendered * @param CelSkip chunks of cell to skip * @param dx Backbuffer coordinate * @param dy Backbuffer coordinate * @param eflag Should the sorting workaround be applied */ void town_draw_clipped_town_2(BYTE *pBuff, int sx, int sy, int row, int CelSkip, int dx, int dy, int eflag) { int mi, px, py; char bv; if (dItem[sx][sy] != 0) { bv = dItem[sx][sy] - 1; px = dx - item[bv]._iAnimWidth2; if (bv == pcursitem) { CelBlitOutlineSafe(181, px, dy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, CelSkip, 8); } CelClippedDrawSafe(px, dy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, CelSkip, 8); } if (dFlags[sx][sy] & BFLAG_MONSTLR) { mi = -(dMonster[sx][sy - 1] + 1); px = dx - towner[mi]._tAnimWidth2; if (mi == pcursmonst) { CelBlitOutlineSafe(166, px, dy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, CelSkip, 8); } CelClippedDrawSafe(px, dy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, CelSkip, 8); } if (dMonster[sx][sy] > 0) { mi = dMonster[sx][sy] - 1; px = dx - towner[mi]._tAnimWidth2; if (mi == pcursmonst) { CelBlitOutlineSafe(166, px, dy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, CelSkip, 8); } CelClippedDrawSafe(px, dy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, CelSkip, 8); } if (dFlags[sx][sy] & BFLAG_PLAYERLR) { bv = -(dPlayer[sx][sy - 1] + 1); px = dx + plr[bv]._pxoff - plr[bv]._pAnimWidth2; py = dy + plr[bv]._pyoff; if (bv == pcursplr) { Cl2DrawOutlineSafe(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, CelSkip, 8); } Cl2DrawSafe(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, CelSkip, 8); if (eflag && plr[bv]._peflag) { town_draw_clipped_e_flag_2(pBuff - TILE_WIDTH, sx - 1, sy + 1, row, CelSkip, dx - TILE_WIDTH, dy); } } if (dFlags[sx][sy] & BFLAG_DEAD_PLAYER) { DrawDeadPlayer(sx, sy, dx, dy, CelSkip, 8, TRUE); } if (dPlayer[sx][sy] > 0) { bv = dPlayer[sx][sy] - 1; px = dx + plr[bv]._pxoff - plr[bv]._pAnimWidth2; py = dy + plr[bv]._pyoff; if (bv == pcursplr) { Cl2DrawOutlineSafe(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, CelSkip, 8); } Cl2DrawSafe(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, CelSkip, 8); if (eflag && plr[bv]._peflag) { town_draw_clipped_e_flag_2(pBuff - TILE_WIDTH, sx - 1, sy + 1, row, CelSkip, dx - TILE_WIDTH, dy); } } if (dFlags[sx][sy] & BFLAG_MISSILE) { DrawClippedMissile(sx, sy, dx, dy, CelSkip, 8, 0); } if (dSpecial[sx][sy] != 0) { town_special_lower(&pBuff[PitchTbl[16 * CelSkip]], dSpecial[sx][sy]); } } /** * @brief Render a row of tile, checking for overdrawing on lower part of screen * @param x dPiece coordinate * @param y dPiece coordinate * @param sx Backbuffer coordinate * @param sy Backbuffer coordinate * @param chunks tile width of row * @param row current row being rendered * @param eflag is it an even (0) or odd (1) row */ void town_draw_lower_2(int x, int y, int sx, int sy, int chunks, int row, int eflag) { int i, j, CelSkip; BYTE *dst; MICROS *pMap; /// ASSERT: assert(gpBuffer); CelSkip = 2 * row + 2; if (eflag) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_cel_block = dPiece[x][y]; if (level_cel_block != 0) { dst = &gpBuffer[sx + TILE_WIDTH / 2 - BUFFER_WIDTH * TILE_HEIGHT + PitchTbl[sy]]; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 7; i++) { if (row <= i) { level_cel_block = pMap->mt[2 * i + 3]; if (level_cel_block != 0) { drawLowerScreen(dst); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; } if (CelSkip < 8) { town_draw_clipped_town_2(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelSkip, sx, sy, 0); } } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } x++; y--; sx += TILE_WIDTH; } for (j = 0; j < chunks - eflag; j++) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_cel_block = dPiece[x][y]; if (level_cel_block != 0) { dst = &gpBuffer[sx - BUFFER_WIDTH * TILE_HEIGHT + PitchTbl[sy]]; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 7; i++) { if (row <= i) { level_cel_block = pMap->mt[2 * i + 2]; if (level_cel_block != 0) { drawLowerScreen(dst); } level_cel_block = pMap->mt[2 * i + 3]; if (level_cel_block != 0) { drawLowerScreen(dst + TILE_WIDTH / 2); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; } if (CelSkip < 8) { town_draw_clipped_town_2(&gpBuffer[sx + PitchTbl[sy] - BUFFER_WIDTH * 16 * CelSkip], x, y, row, CelSkip, sx, sy, 1); } } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } x++; y--; sx += TILE_WIDTH; } if (eflag) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_cel_block = dPiece[x][y]; if (level_cel_block != 0) { dst = &gpBuffer[sx - BUFFER_WIDTH * TILE_HEIGHT + PitchTbl[sy]]; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 7; i++) { if (row <= i) { level_cel_block = pMap->mt[2 * i + 2]; if (level_cel_block != 0) { drawLowerScreen(dst); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; } if (CelSkip < 8) { town_draw_clipped_town_2(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelSkip, sx, sy, 0); } } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } } else { town_clear_low_buf(&gpBuffer[sx + PitchTbl[sy]]); } } } /** * This variant checks for of screen element on the upper screen * This function it self causes rendering issues since it will render on top of objects on the other side of walls * @brief Re render tile to workaround sorting issues with players walking east/west * @param pBuff Pointer to output buffer at location sx,sy * @param y dPiece coordinate * @param x dPiece coordinate * @param row The current row being rendered * @param CelCap chunks of cell to skip * @param sx Backbuffer coordinate * @param sy Backbuffer coordinate */ void town_draw_e_flag(BYTE *pBuff, int x, int y, int row, int CelCap, int sx, int sy) { int i; BYTE *dst; MICROS *pMap; dst = pBuff; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 7; i++) { if (row >= i) { level_cel_block = pMap->mt[2 * i]; if (level_cel_block != 0) { drawUpperScreen(dst); } level_cel_block = pMap->mt[2 * i + 1]; if (level_cel_block != 0) { drawUpperScreen(dst + TILE_WIDTH / 2); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; } town_draw_town_all(pBuff, x, y, row, CelCap, sx, sy, 0); } /** * @brief Render object sprites, skip offscreen parts for upper screen * @param pBuff where to render to with sx,sx already applied * @param x dPiece coordinate * @param y dPiece coordinate * @param row The current row being rendered * @param CelCap chunks of cell to skip * @param sx Backbuffer coordinate * @param sy Backbuffer coordinate * @param eflag Should the sorting workaround be applied */ void town_draw_town_all(BYTE *pBuff, int x, int y, int row, int CelCap, int sx, int sy, int eflag) { int mi, px, py; char bv; if (dItem[x][y] != 0) { bv = dItem[x][y] - 1; px = sx - item[bv]._iAnimWidth2; if (bv == pcursitem) { CelBlitOutline(181, px, sy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, 0, CelCap); } /// ASSERT: assert(item[bv]._iAnimData); CelClippedDraw(px, sy, item[bv]._iAnimData, item[bv]._iAnimFrame, item[bv]._iAnimWidth, 0, CelCap); } if (dFlags[x][y] & BFLAG_MONSTLR) { mi = -(dMonster[x][y - 1] + 1); px = sx - towner[mi]._tAnimWidth2; if (mi == pcursmonst) { CelBlitOutline(166, px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, CelCap); } /// ASSERT: assert(towner[mi]._tAnimData); CelClippedDraw(px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, CelCap); } if (dMonster[x][y] > 0) { mi = dMonster[x][y] - 1; px = sx - towner[mi]._tAnimWidth2; if (mi == pcursmonst) { CelBlitOutline(166, px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, CelCap); } /// ASSERT: assert(towner[mi]._tAnimData); CelClippedDraw(px, sy, towner[mi]._tAnimData, towner[mi]._tAnimFrame, towner[mi]._tAnimWidth, 0, CelCap); } if (dFlags[x][y] & BFLAG_PLAYERLR) { bv = -(dPlayer[x][y - 1] + 1); px = sx + plr[bv]._pxoff - plr[bv]._pAnimWidth2; py = sy + plr[bv]._pyoff; if (bv == pcursplr) { Cl2DrawOutline(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, CelCap); } /// ASSERT: assert(plr[bv]._pAnimData); Cl2Draw(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, CelCap); if (eflag && plr[bv]._peflag) { town_draw_e_flag(pBuff - TILE_WIDTH, x - 1, y + 1, row, CelCap, sx - TILE_WIDTH, sy); } } if (dFlags[x][y] & BFLAG_DEAD_PLAYER) { DrawDeadPlayer(x, y, sx, sy, 0, CelCap, FALSE); } if (dPlayer[x][y] > 0) { bv = dPlayer[x][y] - 1; px = sx + plr[bv]._pxoff - plr[bv]._pAnimWidth2; py = sy + plr[bv]._pyoff; if (bv == pcursplr) { Cl2DrawOutline(165, px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, CelCap); } /// ASSERT: assert(plr[bv]._pAnimData); Cl2Draw(px, py, plr[bv]._pAnimData, plr[bv]._pAnimFrame, plr[bv]._pAnimWidth, 0, CelCap); if (eflag && plr[bv]._peflag) { town_draw_e_flag(pBuff - TILE_WIDTH, x - 1, y + 1, row, CelCap, sx - TILE_WIDTH, sy); } } if (dFlags[x][y] & BFLAG_MISSILE) { DrawMissile(x, y, sx, sy, 0, CelCap, FALSE); } if (dSpecial[x][y] != 0) { town_special_upper(pBuff, dSpecial[x][y]); } } /** * @brief Render a row of tile, checking for overdrawing on upper part of screen * @param x dPiece coordinate * @param y dPiece coordinate * @param sx Backbuffer coordinate * @param sy Backbuffer coordinate * @param chunks tile width of row * @param row current row being rendered * @param eflag is it an even (0) or odd (1) row */ void town_draw_upper(int x, int y, int sx, int sy, int chunks, int row, int eflag) { int i, j, CelCap; BYTE *dst; MICROS *pMap; /// ASSERT: assert(gpBuffer); CelCap = 2 * row + 2; if (CelCap > 8) { CelCap = 8; } if (eflag) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_cel_block = dPiece[x][y]; if (level_cel_block != 0) { dst = &gpBuffer[sx + TILE_WIDTH / 2 + PitchTbl[sy]]; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 7; i++) { if (row >= i) { level_cel_block = pMap->mt[2 * i + 1]; if (level_cel_block != 0) { drawUpperScreen(dst); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; } town_draw_town_all(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelCap, sx, sy, 0); } else { town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]); } } else { town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]); } x++; y--; sx += TILE_WIDTH; } for (j = 0; j < chunks - eflag; j++) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_cel_block = dPiece[x][y]; if (level_cel_block != 0) { dst = &gpBuffer[sx + PitchTbl[sy]]; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 7; i++) { if (row >= i) { level_cel_block = pMap->mt[2 * i]; if (level_cel_block != 0) { drawUpperScreen(dst); } level_cel_block = pMap->mt[2 * i + 1]; if (level_cel_block != 0) { drawUpperScreen(dst + TILE_WIDTH / 2); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; } town_draw_town_all(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelCap, sx, sy, 1); } else { town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]); } } else { town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]); } x++; y--; sx += TILE_WIDTH; } if (eflag) { if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { level_cel_block = dPiece[x][y]; if (level_cel_block != 0) { dst = &gpBuffer[sx + PitchTbl[sy]]; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; for (i = 0; i < 7; i++) { if (row >= i) { level_cel_block = pMap->mt[2 * i]; if (level_cel_block != 0) { drawUpperScreen(dst); } } dst -= BUFFER_WIDTH * TILE_HEIGHT; } town_draw_town_all(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelCap, sx, sy, 0); } else { town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]); } } else { town_clear_upper_buf(&gpBuffer[sx + PitchTbl[sy]]); } } } /** * @brief Configure render and process screen rows * @param x Center of view in dPiece coordinate * @param y Center of view in dPiece coordinate */ void T_DrawGame(int x, int y) { int i, sx, sy, chunks, blocks; ViewDX = SCREEN_WIDTH; ViewDY = VIEWPORT_HEIGHT; ViewBX = SCREEN_WIDTH / TILE_WIDTH; ViewBY = VIEWPORT_HEIGHT / TILE_HEIGHT; sx = ScrollInfo._sxoff + TILE_WIDTH; sy = ScrollInfo._syoff + SCREEN_Y + (TILE_HEIGHT / 2 - 1); x -= SCREEN_WIDTH / TILE_WIDTH; y--; chunks = SCREEN_WIDTH / TILE_WIDTH; blocks = 5; if (chrflag || questlog) { x += 2; y -= 2; sx += (SCREEN_WIDTH / 2) - TILE_WIDTH / 2; chunks = 6; } if (invflag || sbookflag) { x += 2; y -= 2; sx -= TILE_WIDTH / 2; chunks = 6; } switch (ScrollInfo._sdir) { case SDIR_NONE: break; case SDIR_N: sy -= TILE_HEIGHT; x--; y--; blocks++; break; case SDIR_NE: sy -= TILE_HEIGHT; x--; y--; chunks++; blocks++; break; case SDIR_E: chunks++; break; case SDIR_SE: chunks++; blocks++; break; case SDIR_S: blocks++; break; case SDIR_SW: sx -= TILE_WIDTH; x--; y++; chunks++; blocks++; break; case SDIR_W: sx -= TILE_WIDTH; x--; y++; chunks++; break; case SDIR_NW: sx -= TILE_WIDTH; sy -= TILE_HEIGHT; x -= 2; chunks++; blocks++; break; } /// ASSERT: assert(gpBuffer); gpBufEnd = &gpBuffer[PitchTbl[SCREEN_Y]]; for (i = 0; i < 7; i++) { town_draw_upper(x, y, sx, sy, chunks, i, 0); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; town_draw_upper(x, y, sx, sy, chunks, i, 1); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } /// ASSERT: assert(gpBuffer); gpBufEnd = &gpBuffer[PitchTbl[VIEWPORT_HEIGHT + SCREEN_Y]]; for (i = 0; i < blocks; i++) { town_draw_lower(x, y, sx, sy, chunks, 0); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; town_draw_lower(x, y, sx, sy, chunks, 1); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } for (i = 0; i < 7; i++) { town_draw_lower_2(x, y, sx, sy, chunks, i, 0); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; town_draw_lower_2(x, y, sx, sy, chunks, i, 1); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } } /** * @brief Configure render for zoomed view and process screen rows * @param x Center of view in dPiece coordinate * @param y Center of view in dPiece coordinate */ void T_DrawZoom(int x, int y) { int i, sx, sy, chunks, blocks; int wdt, nSrcOff, nDstOff; ViewDX = ZOOM_WIDTH; ViewDY = ZOOM_HEIGHT - TILE_HEIGHT; ViewBX = ZOOM_WIDTH / TILE_WIDTH; ViewBY = (ZOOM_HEIGHT - TILE_HEIGHT) / TILE_HEIGHT; sx = ScrollInfo._sxoff + SCREEN_X; sy = ScrollInfo._syoff + SCREEN_Y - (TILE_HEIGHT / 2 + 1); x -= ZOOM_WIDTH / TILE_WIDTH; y--; chunks = ZOOM_WIDTH / TILE_WIDTH; blocks = 0; switch (ScrollInfo._sdir) { case SDIR_NONE: break; case SDIR_N: sy -= TILE_HEIGHT; x--; y--; blocks++; break; case SDIR_NE: sy -= TILE_HEIGHT; x--; y--; chunks++; blocks++; break; case SDIR_E: chunks++; break; case SDIR_SE: chunks++; blocks++; break; case SDIR_S: blocks++; break; case SDIR_SW: sx -= TILE_WIDTH; x--; y++; chunks++; blocks++; break; case SDIR_W: sx -= TILE_WIDTH; x--; y++; chunks++; break; case SDIR_NW: sx -= TILE_WIDTH; sy -= TILE_HEIGHT; x -= 2; chunks++; blocks++; break; } assert(gpBuffer); gpBufEnd = &gpBuffer[PitchTbl[-17 + SCREEN_Y]]; for (i = 0; i < 7; i++) { town_draw_upper(x, y, sx, sy, chunks, i, 0); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; town_draw_upper(x, y, sx, sy, chunks, i, 1); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } assert(gpBuffer); gpBufEnd = &gpBuffer[PitchTbl[160 + SCREEN_Y]]; for (i = 0; i < blocks; i++) { town_draw_lower(x, y, sx, sy, chunks, 0); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; town_draw_lower(x, y, sx, sy, chunks, 1); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } for (i = 0; i < 7; i++) { town_draw_lower_2(x, y, sx, sy, chunks, i, 0); y++; sx -= TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; town_draw_lower_2(x, y, sx, sy, chunks, i, 1); x++; sx += TILE_WIDTH / 2; sy += TILE_HEIGHT / 2; } if (chrflag || questlog) { nSrcOff = SCREENXY(TILE_WIDTH / 2 + SPANEL_WIDTH / 4, VIEWPORT_HEIGHT / 2 - (TILE_HEIGHT / 2 + 1)); nDstOff = SCREENXY(SPANEL_WIDTH, VIEWPORT_HEIGHT - 2); wdt = (SCREEN_WIDTH - SPANEL_WIDTH) / 2; } else if (invflag || sbookflag) { nSrcOff = SCREENXY(TILE_WIDTH / 2 + SPANEL_WIDTH / 4, VIEWPORT_HEIGHT / 2 - (TILE_HEIGHT / 2 + 1)); nDstOff = SCREENXY(0, VIEWPORT_HEIGHT - 2); wdt = (SCREEN_WIDTH - SPANEL_WIDTH) / 2; } else { nSrcOff = SCREENXY(TILE_WIDTH / 2, VIEWPORT_HEIGHT / 2 - (TILE_HEIGHT / 2 + 1)); nDstOff = SCREENXY(0, VIEWPORT_HEIGHT - 2); wdt = SCREEN_WIDTH / 2; } assert(gpBuffer); #ifdef USE_ASM __asm { mov esi, gpBuffer mov edx, nDstOff mov edi, esi mov ecx, nSrcOff add edi, edx add esi, ecx mov ebx, edi add ebx, BUFFER_WIDTH mov edx, VIEWPORT_HEIGHT / 2 label1: mov ecx, wdt label2: mov al, [esi] inc esi mov ah, al mov [edi], ax mov [ebx], ax add edi, 2 add ebx, 2 dec ecx jnz label2 mov eax, BUFFER_WIDTH add eax, wdt sub esi, eax add eax, eax sub ebx, eax sub edi, eax dec edx jnz label1 } #else int hgt; BYTE *src, *dst1, *dst2; src = &gpBuffer[nSrcOff]; dst1 = &gpBuffer[nDstOff]; dst2 = &gpBuffer[nDstOff + BUFFER_WIDTH]; for (hgt = VIEWPORT_HEIGHT / 2; hgt != 0; hgt--, src -= BUFFER_WIDTH + wdt, dst1 -= 2 * (BUFFER_WIDTH + wdt), dst2 -= 2 * (BUFFER_WIDTH + wdt)) { for (i = wdt; i != 0; i--) { *dst1++ = *src; *dst1++ = *src; *dst2++ = *src; *dst2++ = *src; src++; } } #endif } /** * Mostly like DrawView but enables stores and lacks death screen * @brief Start rendering of screen, town variation * @param StartX Center of view in dPiece coordinate * @param StartY Center of view in dPiece coordinate */ void 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 != 0 && !spselflag) { DrawLevelUpIcon(); } if (uitemflag) { DrawUniqueInfo(); } if (qtextflag) { DrawQText(); } if (spselflag) { DrawSpellList(); } if (dropGoldFlag) { DrawGoldSplit(dropGoldValue); } if (helpflag) { DrawHelp(); } if (msgflag) { DrawDiabloMsg(); } if (PauseMode != 0 && !deathflag) { gmenu_draw_pause(); } DrawPlrMsg(); gmenu_draw(); doom_draw(); DrawInfoBox(); DrawLifeFlask(); DrawManaFlask(); } /** * @brief Build tile columns */ void SetTownMicros() { int i, x, y, lv; WORD *pPiece; MICROS *pMap; for (y = 0; y < MAXDUNY; y++) { for (x = 0; x < MAXDUNX; x++) { lv = dPiece[x][y]; pMap = &dpiece_defs_map_1[IsometricCoord(x, y)]; if (lv != 0) { lv--; pPiece = (WORD *)&pLevelPieces[32 * lv]; for (i = 0; i < 16; i++) { pMap->mt[i] = pPiece[(i & 1) + 16 - 2 - (i & 0xE)]; } } else { for (i = 0; i < 16; i++) { pMap->mt[i] = 0; } } } } if (zoomflag) { ViewDX = SCREEN_WIDTH; ViewDY = VIEWPORT_HEIGHT; ViewBX = SCREEN_WIDTH / TILE_WIDTH; ViewBY = VIEWPORT_HEIGHT / TILE_HEIGHT; } else { ViewDX = ZOOM_WIDTH; ViewDY = ZOOM_HEIGHT; ViewBX = ZOOM_WIDTH / TILE_WIDTH; ViewBY = ZOOM_HEIGHT / TILE_HEIGHT; } } /** * @brief Load level data into dPiece * @param P3Tiles Tile set * @param pSector Sector data * @param xi upper left destination * @param yi upper left destination * @param w width of sector * @param h height of sector */ void T_FillSector(BYTE *P3Tiles, BYTE *pSector, int xi, int yi, int w, int h) { int i, j, xx, yy; long v1, v2, v3, v4, ii; ii = 4; yy = yi; for (j = 0; j < h; j++) { xx = xi; for (i = 0; i < w; i++) { #ifdef USE_ASM __asm { mov esi, pSector mov eax, ii add esi, eax xor eax, eax lodsw or eax, eax jz label1 dec eax mov esi, P3Tiles shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax jmp label2 label1: mov v1, eax mov v2, eax mov v3, eax mov v4, eax label2: nop } #else WORD *Map; Map = (WORD *)&pSector[ii]; if (*Map) { v1 = *((WORD *)&P3Tiles[(*Map - 1) * 8] + 0) + 1; v2 = *((WORD *)&P3Tiles[(*Map - 1) * 8] + 1) + 1; v3 = *((WORD *)&P3Tiles[(*Map - 1) * 8] + 2) + 1; v4 = *((WORD *)&P3Tiles[(*Map - 1) * 8] + 3) + 1; } else { v1 = 0; v2 = 0; v3 = 0; v4 = 0; } #endif dPiece[xx][yy] = v1; dPiece[xx + 1][yy] = v2; dPiece[xx][yy + 1] = v3; dPiece[xx + 1][yy + 1] = v4; xx += 2; ii += 2; } yy += 2; } } /** * @brief Load a tile in to dPiece * @param P3Tiles Tile set * @param xx upper left destination * @param yy upper left destination * @param t tile id */ void T_FillTile(BYTE *P3Tiles, int xx, int yy, int t) { long v1, v2, v3, v4; #ifdef USE_ASM __asm { mov eax, t dec eax mov esi, P3Tiles shl eax, 3 add esi, eax xor eax, eax lodsw inc eax mov v1, eax lodsw inc eax mov v2, eax lodsw inc eax mov v3, eax lodsw inc eax mov v4, eax jmp label1 mov v1, eax mov v2, eax mov v3, eax mov v4, eax label1: nop } #else v1 = *((WORD *)&P3Tiles[(t - 1) * 8] + 0) + 1; v2 = *((WORD *)&P3Tiles[(t - 1) * 8] + 1) + 1; v3 = *((WORD *)&P3Tiles[(t - 1) * 8] + 2) + 1; v4 = *((WORD *)&P3Tiles[(t - 1) * 8] + 3) + 1; #endif dPiece[xx][yy] = v1; dPiece[xx + 1][yy] = v2; dPiece[xx][yy + 1] = v3; dPiece[xx + 1][yy + 1] = v4; } #ifdef HELLFIRE void TownOpenHive() { dPiece[78][60] = 0x48a; dPiece[79][60] = 0x48b; dPiece[78][61] = 0x48c; dPiece[79][61] = 0x50e; dPiece[78][62] = 0x4ee; dPiece[78][63] = 0x4f0; dPiece[79][62] = 0x510; dPiece[79][63] = 0x511; dPiece[79][64] = 0x512; dPiece[78][64] = 0x11a; dPiece[78][65] = 0x11c; dPiece[79][65] = 0x11d; dPiece[80][60] = 0x513; dPiece[80][61] = 0x515; dPiece[81][61] = 0x516; dPiece[82][60] = 0x517; dPiece[83][60] = 0x518; dPiece[82][61] = 0x519; dPiece[83][61] = 0x51a; dPiece[80][62] = 0x51b; dPiece[81][62] = 0x51c; dPiece[80][63] = 0x51d; dPiece[81][63] = 0x51e; dPiece[80][64] = 0x51f; dPiece[81][64] = 0x520; dPiece[80][65] = 0x521; dPiece[81][65] = 0x522; dPiece[82][64] = 0x527; dPiece[83][64] = 0x528; dPiece[82][65] = 0x529; dPiece[83][65] = 0x52a; dPiece[82][62] = 0x523; dPiece[83][62] = 0x524; dPiece[82][63] = 0x525; dPiece[83][63] = 0x526; dPiece[84][61] = 0x118; dPiece[84][62] = 0x118; dPiece[84][63] = 0x118; dPiece[85][60] = 0x118; dPiece[85][61] = 0x118; dPiece[85][63] = 8; dPiece[85][64] = 8; dPiece[86][60] = 0xd9; dPiece[86][61] = 0x18; dPiece[85][62] = 0x13; dPiece[84][64] = 0x118; SetTownMicros(); } void TownCloseHive() { dPiece[78][60] = 0x48a; dPiece[79][60] = 0x4eb; dPiece[78][61] = 0x4ec; dPiece[79][61] = 0x4ed; dPiece[78][62] = 0x4ee; dPiece[79][62] = 0x4ef; dPiece[78][63] = 0x4f0; dPiece[79][63] = 0x4f1; dPiece[78][64] = 0x4f2; dPiece[79][64] = 0x4f3; dPiece[78][65] = 0x4f4; dPiece[80][60] = 0x4f5; dPiece[81][60] = 0x4f6; dPiece[80][61] = 0x4f7; dPiece[81][61] = 0x4f8; dPiece[82][60] = 0x4f9; dPiece[83][60] = 0x4fa; dPiece[82][61] = 0x4fb; dPiece[83][61] = 0x4fc; dPiece[80][62] = 0x4fd; dPiece[81][62] = 0x4fe; dPiece[80][63] = 0x4ff; dPiece[81][63] = 0x500; dPiece[80][64] = 0x501; dPiece[81][64] = 0x502; dPiece[80][65] = 0x503; dPiece[81][65] = 0x504; dPiece[82][64] = 0x509; dPiece[83][64] = 0x50a; dPiece[82][65] = 0x50b; dPiece[83][65] = 0x50c; dPiece[82][62] = 0x505; dPiece[83][62] = 0x506; dPiece[82][63] = 0x507; dPiece[83][63] = 0x508; dPiece[84][61] = 0x118; dPiece[84][62] = 0x118; dPiece[84][63] = 0x118; dPiece[85][60] = 0x118; dPiece[85][61] = 0x118; dPiece[85][63] = 8; dPiece[85][64] = 8; dPiece[86][60] = 0xd9; dPiece[86][61] = 0x18; dPiece[85][62] = 0x13; dPiece[84][64] = 0x118; SetTownMicros(); } void TownCloseGrave() { dPiece[36][21] = 0x52b; dPiece[37][21] = 0x52c; dPiece[36][22] = 0x52d; dPiece[37][22] = 0x52e; dPiece[36][23] = 0x52f; dPiece[37][23] = 0x530; dPiece[36][24] = 0x531; dPiece[37][24] = 0x532; dPiece[35][21] = 0x53b; dPiece[34][21] = 0x53c; SetTownMicros(); } void TownOpenGrave() { dPiece[36][21] = 0x533; dPiece[37][21] = 0x534; dPiece[36][22] = 0x535; dPiece[37][22] = 0x536; dPiece[36][23] = 0x537; dPiece[37][23] = 0x538; dPiece[36][24] = 0x539; dPiece[37][24] = 0x53a; dPiece[35][21] = 0x53b; dPiece[34][21] = 0x53c; SetTownMicros(); } #endif /** * @brief Initialize all of the levels data */ void T_Pass3() { int xx, yy, x; BYTE *P3Tiles, *pSector; for (yy = 0; yy < MAXDUNY; yy += 2) { for (xx = 0; xx < MAXDUNX; xx += 2) { dPiece[xx][yy] = 0; dPiece[xx + 1][yy] = 0; dPiece[xx][yy + 1] = 0; dPiece[xx + 1][yy + 1] = 0; } } P3Tiles = LoadFileInMem("Levels\\TownData\\Town.TIL", NULL); pSector = LoadFileInMem("Levels\\TownData\\Sector1s.DUN", NULL); T_FillSector(P3Tiles, pSector, 46, 46, 25, 25); mem_free_dbg(pSector); pSector = LoadFileInMem("Levels\\TownData\\Sector2s.DUN", NULL); T_FillSector(P3Tiles, pSector, 46, 0, 25, 23); mem_free_dbg(pSector); pSector = LoadFileInMem("Levels\\TownData\\Sector3s.DUN", NULL); T_FillSector(P3Tiles, pSector, 0, 46, 23, 25); mem_free_dbg(pSector); pSector = LoadFileInMem("Levels\\TownData\\Sector4s.DUN", NULL); T_FillSector(P3Tiles, pSector, 0, 0, 23, 23); mem_free_dbg(pSector); #ifndef SPAWN if (gbMaxPlayers == 1) { #endif #ifdef HELLFIRE if (quests[Q_FARMER]._qactive == QUEST_DONE || quests[Q_FARMER]._qactive == 10 || quests[Q_JERSEY]._qactive == QUEST_DONE || quests[Q_JERSEY]._qactive == 10) { TownOpenHive(); } else { TownCloseHive(); } if (quests[Q_GRAVE]._qactive == QUEST_DONE || plr[myplr]._pLvlVisited[21]) TownOpenGrave(); else TownCloseGrave(); #endif #ifndef SPAWN #ifdef HELLFIRE if (!(plr[myplr].pTownWarps & 1) && plr[myplr]._pLevel < 10) #else if (!(plr[myplr].pTownWarps & 1)) #endif #endif { T_FillTile(P3Tiles, 48, 20, 320); } #ifndef SPAWN #ifdef HELLFIRE if (!(plr[myplr].pTownWarps & 2) && plr[myplr]._pLevel < 15) #else if (!(plr[myplr].pTownWarps & 2)) #endif #endif { T_FillTile(P3Tiles, 16, 68, 332); T_FillTile(P3Tiles, 16, 70, 331); } #ifndef SPAWN #ifdef HELLFIRE if (!(plr[myplr].pTownWarps & 4) && plr[myplr]._pLevel < 20) { #else if (!(plr[myplr].pTownWarps & 4)) { #endif #endif for (x = 36; x < 46; x++) { T_FillTile(P3Tiles, x, 78, random_(0, 4) + 1); } #ifndef SPAWN } } #ifdef HELLFIRE else { if (quests[Q_FARMER]._qactive == QUEST_DONE || quests[Q_FARMER]._qactive == 10 || quests[Q_JERSEY]._qactive == QUEST_DONE || quests[Q_JERSEY]._qactive == 10) { TownOpenHive(); } else { TownCloseHive(); } if (quests[Q_GRAVE]._qactive == QUEST_DONE || plr[myplr]._pLvlVisited[21]) TownOpenGrave(); else TownCloseGrave(); } #endif #endif if (quests[Q_PWATER]._qactive != QUEST_DONE && quests[Q_PWATER]._qactive) { T_FillTile(P3Tiles, 60, 70, 342); } else { T_FillTile(P3Tiles, 60, 70, 71); } mem_free_dbg(P3Tiles); } /** * @brief Initialize town level * @param entry Methode of entry */ void CreateTown(int entry) { int x, y; dminx = 10; dminy = 10; dmaxx = 84; dmaxy = 84; if (entry == ENTRY_MAIN) { // New game ViewX = 75; ViewY = 68; } else if (entry == ENTRY_PREV) { // Cathedral ViewX = 25; ViewY = 31; } else if (entry == ENTRY_TWARPUP) { if (TWarpFrom == 5) { ViewX = 49; ViewY = 22; } if (TWarpFrom == 9) { ViewX = 18; ViewY = 69; } if (TWarpFrom == 13) { ViewX = 41; ViewY = 81; } #ifdef HELLFIRE if (TWarpFrom == 21) { ViewX = 36; ViewY = 25; } if (TWarpFrom == 17) { ViewX = 79; ViewY = 62; } #endif } T_Pass3(); memset(dLight, 0, sizeof(dLight)); memset(dFlags, 0, sizeof(dFlags)); memset(dPlayer, 0, sizeof(dPlayer)); memset(dMonster, 0, sizeof(dMonster)); memset(dObject, 0, sizeof(dObject)); memset(dItem, 0, sizeof(dItem)); memset(dSpecial, 0, sizeof(dSpecial)); for (y = 0; y < MAXDUNY; y++) { for (x = 0; x < MAXDUNX; x++) { if (dPiece[x][y] == 360) { dSpecial[x][y] = 1; } else if (dPiece[x][y] == 358) { dSpecial[x][y] = 2; } else if (dPiece[x][y] == 129) { dSpecial[x][y] = 6; } else if (dPiece[x][y] == 130) { dSpecial[x][y] = 7; } else if (dPiece[x][y] == 128) { dSpecial[x][y] = 8; } else if (dPiece[x][y] == 117) { dSpecial[x][y] = 9; } else if (dPiece[x][y] == 157) { dSpecial[x][y] = 10; } else if (dPiece[x][y] == 158) { dSpecial[x][y] = 11; } else if (dPiece[x][y] == 156) { dSpecial[x][y] = 12; } else if (dPiece[x][y] == 162) { dSpecial[x][y] = 13; } else if (dPiece[x][y] == 160) { dSpecial[x][y] = 14; } else if (dPiece[x][y] == 214) { dSpecial[x][y] = 15; } else if (dPiece[x][y] == 212) { dSpecial[x][y] = 16; } else if (dPiece[x][y] == 217) { dSpecial[x][y] = 17; } else if (dPiece[x][y] == 216) { dSpecial[x][y] = 18; } } } SetTownMicros(); } ================================================ FILE: Source/town.h ================================================ /** * @file town.h * * Interface of functionality for rendering the town, towners and calling other render routines. */ #ifndef __TOWN_H__ #define __TOWN_H__ void town_draw_clipped_town(BYTE *pBuff, int sx, int sy, int dx, int dy, int eflag); void town_draw_clipped_town_2(BYTE *pBuff, int sx, int sy, int row, int CelSkip, int dx, int dy, int eflag); void town_draw_town_all(BYTE *pBuff, int x, int y, int row, int CelCap, int sx, int sy, int eflag); void T_DrawView(int StartX, int StartY); #ifdef HELLFIRE void TownOpenHive(); void TownOpenGrave(); #endif void CreateTown(int entry); #endif /* __TOWN_H__ */ ================================================ FILE: Source/towners.cpp ================================================ /** * @file towners.cpp * * Implementation of functionality for loading and spawning towners. */ #include "all.h" BOOL storeflag; int sgnCowMsg; int numtowners; DWORD sgdwCowClicks; /** unused 0x6AAC28 */ BOOL bannerflag; BOOL boyloadflag; BYTE *pCowCels; TownerStruct towner[NUM_TOWNERS]; #ifndef SPAWN /** * Maps from active cow sound effect index and player class to sound * effect ID for interacting with cows in Tristram. * * ref: enum _sfx_id * ref: enum plr_class */ const int snSFX[3][NUM_CLASSES] = { #ifdef HELLFIRE { PS_WARR52, PS_ROGUE52, PS_MAGE52, PS_MONK52, 0 }, // BUGFIX: add warrior sounds for barbarian instead of 0 - walk sound { PS_WARR49, PS_ROGUE49, PS_MAGE49, PS_MONK49, 0 }, { PS_WARR50, PS_ROGUE50, PS_MAGE50, PS_MONK50, 0 }, #else { PS_WARR52, PS_ROGUE52, PS_MAGE52 }, { PS_WARR49, PS_ROGUE49, PS_MAGE49 }, { PS_WARR50, PS_ROGUE50, PS_MAGE50 }, #endif }; #endif /* data */ /** Specifies the animation frame sequence of a given NPC. */ char AnimOrder[6][148] = { // BUGFIX: was `15, 5, 1`, should be `15, 16, 1` in Griswold anim. { 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 } }; /** Specifies the start X-coordinates of the cows in Tristram. */ int TownCowX[] = { 58, 56, 59 }; /** Specifies the start Y-coordinates of the cows in Tristram. */ int TownCowY[] = { 16, 14, 20 }; /** Specifies the start directions of the cows in Tristram. */ int TownCowDir[] = { DIR_SW, DIR_NW, DIR_N }; /** Maps from direction to X-coordinate delta, which is used when * placing cows in Tristram. A single cow may require space of up * to three tiles when being placed on the map. */ int cowoffx[8] = { -1, 0, -1, -1, -1, 0, -1, -1 }; /** Maps from direction to Y-coordinate delta, which is used when * placing cows in Tristram. A single cow may require space of up * to three tiles when being placed on the map. */ int cowoffy[8] = { -1, -1, -1, 0, -1, -1, -1, 0 }; /** Contains the data related to quest gossip for each towner ID. */ QuestTalkData Qtalklist[] = { // clang-format off #ifdef HELLFIRE // _qinfra, _qblkm, _qgarb, _qzhar, _qveil, _qmod, _qbutch, _qbol, _qblind, _qblood, _qanvil, _qwarlrd, _qking, _qpw, _qbone, _qvb, _qgrv, _qfarm, _qgirl, _qtrade, _qdefiler, _qnakrul, _qjersy, _qhf8 { TEXT_INFRA6, TEXT_MUSH6, -1, -1, TEXT_VEIL5, -1, TEXT_BUTCH5, TEXT_BANNER6, TEXT_BLIND5, TEXT_BLOOD5, TEXT_ANVIL6, TEXT_WARLRD5, TEXT_KING7, TEXT_POISON7, TEXT_BONE5, TEXT_VILE9, TEXT_GRAVE2, -1, -1, -1, -1, -1, -1, -1 }, { TEXT_INFRA3, -1, -1, -1, TEXT_VEIL3, -1, TEXT_BUTCH3, TEXT_BANNER4, TEXT_BLIND3, TEXT_BLOOD3, TEXT_ANVIL3, TEXT_WARLRD3, TEXT_KING5, TEXT_POISON4, TEXT_BONE3, TEXT_VILE7, TEXT_GRAVE3, -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 }, { TEXT_INFRA2, TEXT_MUSH2, -1, -1, TEXT_VEIL2, -1, TEXT_BUTCH2, -1, TEXT_BLIND2, TEXT_BLOOD2, TEXT_ANVIL2, TEXT_WARLRD2, TEXT_KING3, TEXT_POISON2, TEXT_BONE2, TEXT_VILE4, TEXT_GRAVE5, -1, -1, -1, -1, -1, -1, -1 }, { TEXT_INFRA1, TEXT_MUSH1, -1, -1, TEXT_VEIL1, TEXT_VILE3, TEXT_BUTCH1, TEXT_BANNER1, TEXT_BLIND1, TEXT_BLOOD1, TEXT_ANVIL1, TEXT_WARLRD1, TEXT_KING1, TEXT_POISON1, TEXT_BONE1, TEXT_VILE2, TEXT_GRAVE6, -1, -1, -1, -1, -1, -1, -1 }, { TEXT_INFRA8, TEXT_MUSH7, -1, -1, TEXT_VEIL6, -1, TEXT_BUTCH6, TEXT_BANNER7, TEXT_BLIND6, TEXT_BLOOD6, TEXT_ANVIL8, TEXT_WARLRD6, TEXT_KING8, TEXT_POISON8, TEXT_BONE6, TEXT_VILE10, TEXT_GRAVE7, -1, -1, -1, -1, -1, -1, -1 }, { TEXT_INFRA9, TEXT_MUSH9, -1, -1, TEXT_VEIL7, -1, TEXT_BUTCH7, TEXT_BANNER8, TEXT_BLIND7, TEXT_BLOOD7, TEXT_ANVIL9, TEXT_WARLRD7, TEXT_KING9, TEXT_POISON9, TEXT_BONE7, TEXT_VILE11, TEXT_GRAVE1, -1, -1, -1, -1, -1, -1, -1 }, { TEXT_INFRA4, TEXT_MUSH5, -1, -1, TEXT_VEIL4, -1, TEXT_BUTCH4, TEXT_BANNER5, TEXT_BLIND4, TEXT_BLOOD4, TEXT_ANVIL4, TEXT_WARLRD4, TEXT_KING6, TEXT_POISON6, TEXT_BONE4, TEXT_VILE8, TEXT_GRAVE8, -1, -1, -1, -1, -1, -1, -1 }, { TEXT_INFRA10, TEXT_MUSH13, -1, -1, TEXT_VEIL8, -1, TEXT_BUTCH8, TEXT_BANNER9, TEXT_BLIND8, TEXT_BLOOD8, TEXT_ANVIL10,TEXT_WARLRD8, TEXT_KING10, TEXT_POISON10, TEXT_BONE8, TEXT_VILE12, TEXT_GRAVE9, -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 }, { -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, -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, -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, -1, -1, -1 }, #else // _qinfra, _qblkm, _qgarb, _qzhar, _qveil, _qmod, _qbutch, _qbol, _qblind, _qblood, _qanvil, _qwarlrd, _qking, _qpw, _qbone, _qvb { TEXT_INFRA6, TEXT_MUSH6, -1, -1, TEXT_VEIL5, -1, TEXT_BUTCH5, TEXT_BANNER6, TEXT_BLIND5, TEXT_BLOOD5, TEXT_ANVIL6, TEXT_WARLRD5, TEXT_KING7, TEXT_POISON7, TEXT_BONE5, TEXT_VILE9 }, { TEXT_INFRA3, -1, -1, -1, TEXT_VEIL3, -1, TEXT_BUTCH3, TEXT_BANNER4, TEXT_BLIND3, TEXT_BLOOD3, TEXT_ANVIL3, TEXT_WARLRD3, TEXT_KING5, TEXT_POISON4, TEXT_BONE3, TEXT_VILE7 }, { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { TEXT_INFRA2, TEXT_MUSH2, -1, -1, TEXT_VEIL2, -1, TEXT_BUTCH2, -1, TEXT_BLIND2, TEXT_BLOOD2, TEXT_ANVIL2, TEXT_WARLRD2, TEXT_KING3, TEXT_POISON2, TEXT_BONE2, TEXT_VILE4 }, { TEXT_INFRA1, TEXT_MUSH1, -1, -1, TEXT_VEIL1, TEXT_VILE3, TEXT_BUTCH1, TEXT_BANNER1, TEXT_BLIND1, TEXT_BLOOD1, TEXT_ANVIL1, TEXT_WARLRD1, TEXT_KING1, TEXT_POISON1, TEXT_BONE1, TEXT_VILE2 }, { TEXT_INFRA8, TEXT_MUSH7, -1, -1, TEXT_VEIL6, -1, TEXT_BUTCH6, TEXT_BANNER7, TEXT_BLIND6, TEXT_BLOOD6, TEXT_ANVIL8, TEXT_WARLRD6, TEXT_KING8, TEXT_POISON8, TEXT_BONE6, TEXT_VILE10 }, { TEXT_INFRA9, TEXT_MUSH9, -1, -1, TEXT_VEIL7, -1, TEXT_BUTCH7, TEXT_BANNER8, TEXT_BLIND7, TEXT_BLOOD7, TEXT_ANVIL9, TEXT_WARLRD7, TEXT_KING9, TEXT_POISON9, TEXT_BONE7, TEXT_VILE11 }, { TEXT_INFRA4, TEXT_MUSH5, -1, -1, TEXT_VEIL4, -1, TEXT_BUTCH4, TEXT_BANNER5, TEXT_BLIND4, TEXT_BLOOD4, TEXT_ANVIL4, TEXT_WARLRD4, TEXT_KING6, TEXT_POISON6, TEXT_BONE4, TEXT_VILE8 }, { TEXT_INFRA10, TEXT_MUSH13, -1, -1, TEXT_VEIL8, -1, TEXT_BUTCH8, TEXT_BANNER9, TEXT_BLIND8, TEXT_BLOOD8, TEXT_ANVIL10,TEXT_WARLRD8, TEXT_KING10, TEXT_POISON10, TEXT_BONE8, TEXT_VILE12 }, { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1, TEXT_KING1 } #endif // clang-format on }; /** Specifies the active sound effect ID for interacting with cows. */ int CowPlaying = -1; static void CowSFX(int pnum) { if (CowPlaying == -1 || !effect_is_playing(CowPlaying)) { sgdwCowClicks++; #ifdef SPAWN if (sgdwCowClicks == 4) { sgdwCowClicks = 0; CowPlaying = TSFX_COW2; } else { CowPlaying = TSFX_COW1; } #else if (sgdwCowClicks >= 8) { PlaySfxLoc(TSFX_COW1, plr[pnum]._px, plr[pnum]._py + 5); sgdwCowClicks = 4; CowPlaying = snSFX[sgnCowMsg][plr[pnum]._pClass]; /* snSFX is local */ sgnCowMsg++; if (sgnCowMsg >= 3) sgnCowMsg = 0; } else { CowPlaying = sgdwCowClicks == 4 ? TSFX_COW2 : TSFX_COW1; } #endif PlaySfxLoc(CowPlaying, plr[pnum]._px, plr[pnum]._py); } } int GetActiveTowner(int t) { int i; for (i = 0; i < numtowners; i++) { if (towner[i]._ttype == t) return i; } return -1; } void SetTownerGPtrs(BYTE *pData, BYTE **pAnim) { int i; #ifdef USE_ASM BYTE *src; for (i = 0; i < 8; i++) { src = pData; __asm { mov eax, src mov ebx, eax mov edx, i shl edx, 2 add ebx, edx mov edx, [ebx] add eax, edx mov src, eax } pAnim[i] = src; } #else DWORD *pFrameTable; pFrameTable = (DWORD *)pData; for (i = 0; i < 8; i++) { pAnim[i] = &pData[pFrameTable[i]]; } #endif } void NewTownerAnim(int tnum, BYTE *pAnim, int numFrames, int Delay) { towner[tnum]._tAnimData = pAnim; towner[tnum]._tAnimLen = numFrames; towner[tnum]._tAnimFrame = 1; towner[tnum]._tAnimCnt = 0; towner[tnum]._tAnimDelay = Delay; } void InitTownerInfo(int i, int w, int sel, int t, int x, int y, int ao, int tp) { memset(&towner[i], 0, sizeof(TownerStruct)); towner[i]._tSelFlag = sel; towner[i]._tAnimWidth = w; towner[i]._tAnimWidth2 = (w - 64) >> 1; towner[i]._tMsgSaid = FALSE; towner[i]._ttype = t; towner[i]._tx = x; towner[i]._ty = y; dMonster[x][y] = i + 1; towner[i]._tAnimOrder = ao; towner[i]._tTenPer = tp; towner[i]._tSeed = GetRndSeed(); } void InitQstSnds(int i) { int j, tl; tl = i; if (boyloadflag) tl++; for (j = 0; j < MAXQUESTS; j++) { towner[i].qsts[j]._qsttype = quests[j]._qtype; towner[i].qsts[j]._qstmsg = ((int *)(Qtalklist + tl))[j]; if (((int *)(Qtalklist + tl))[j] != -1) towner[i].qsts[j]._qstmsgact = TRUE; else towner[i].qsts[j]._qstmsgact = FALSE; } } /** * @brief Load Griswold into the game */ void InitSmith() { int i; InitTownerInfo(numtowners, 96, TRUE, TOWN_SMITH, 62, 63, 0, 10); InitQstSnds(numtowners); towner[numtowners]._tNData = LoadFileInMem("Towners\\Smith\\SmithN.CEL", NULL); for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 16; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_SW], towner[numtowners]._tNFrames, 3); strcpy(towner[numtowners]._tName, "Griswold the Blacksmith"); numtowners++; } void InitBarOwner() { int i; bannerflag = FALSE; // unused InitTownerInfo(numtowners, 96, TRUE, TOWN_TAVERN, 55, 62, 3, 10); InitQstSnds(numtowners); towner[numtowners]._tNData = LoadFileInMem("Towners\\TwnF\\TwnFN.CEL", NULL); for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 16; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_SW], towner[numtowners]._tNFrames, 3); strcpy(towner[numtowners]._tName, "Ogden the Tavern owner"); numtowners++; } void InitTownDead() { int i; InitTownerInfo(numtowners, 96, TRUE, TOWN_DEADGUY, 24, 32, -1, 10); InitQstSnds(numtowners); towner[numtowners]._tNData = LoadFileInMem("Towners\\Butch\\Deadguy.CEL", NULL); for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 8; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_N], towner[numtowners]._tNFrames, 6); strcpy(towner[numtowners]._tName, "Wounded Townsman"); numtowners++; } void InitWitch() { int i; InitTownerInfo(numtowners, 96, TRUE, TOWN_WITCH, 80, 20, 5, 10); InitQstSnds(numtowners); towner[numtowners]._tNData = LoadFileInMem("Towners\\TownWmn1\\Witch.CEL", NULL); for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 19; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_S], towner[numtowners]._tNFrames, 6); strcpy(towner[numtowners]._tName, "Adria the Witch"); numtowners++; } void InitBarmaid() { int i; InitTownerInfo(numtowners, 96, TRUE, TOWN_BMAID, 43, 66, -1, 10); InitQstSnds(numtowners); towner[numtowners]._tNData = LoadFileInMem("Towners\\TownWmn1\\WmnN.CEL", NULL); for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 18; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_S], towner[numtowners]._tNFrames, 6); strcpy(towner[numtowners]._tName, "Gillian the Barmaid"); numtowners++; } void InitBoy() { int i; boyloadflag = TRUE; InitTownerInfo(numtowners, 96, TRUE, TOWN_PEGBOY, 11, 53, -1, 10); InitQstSnds(numtowners); towner[numtowners]._tNData = LoadFileInMem("Towners\\TownBoy\\PegKid1.CEL", NULL); for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 20; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_S], towner[numtowners]._tNFrames, 6); strcpy(towner[numtowners]._tName, "Wirt the Peg-legged boy"); numtowners++; } void InitHealer() { int i; InitTownerInfo(numtowners, 96, TRUE, TOWN_HEALER, 55, 79, 1, 10); InitQstSnds(numtowners); towner[numtowners]._tNData = LoadFileInMem("Towners\\Healer\\Healer.CEL", NULL); for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 20; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_SE], towner[numtowners]._tNFrames, 6); strcpy(towner[numtowners]._tName, "Pepin the Healer"); numtowners++; } void InitTeller() { int i; InitTownerInfo(numtowners, 96, TRUE, TOWN_STORY, 62, 71, 2, 10); InitQstSnds(numtowners); towner[numtowners]._tNData = LoadFileInMem("Towners\\Strytell\\Strytell.CEL", NULL); for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 25; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_S], towner[numtowners]._tNFrames, 3); strcpy(towner[numtowners]._tName, "Cain the Elder"); numtowners++; } void InitDrunk() { int i; InitTownerInfo(numtowners, 96, TRUE, TOWN_DRUNK, 71, 84, 4, 10); InitQstSnds(numtowners); towner[numtowners]._tNData = LoadFileInMem("Towners\\Drunk\\TwnDrunk.CEL", NULL); for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 18; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_S], towner[numtowners]._tNFrames, 3); strcpy(towner[numtowners]._tName, "Farnham the Drunk"); numtowners++; } void InitCows() { int i, dir; int x, y, xo, yo; //if ( pCowCels ) // assertion_failed(300, "C:\\Diablo\\Direct\\towners.cpp", "! pCowCels"); pCowCels = LoadFileInMem("Towners\\Animals\\Cow.CEL", NULL); for (i = 0; i < 3; i++) { x = TownCowX[i]; y = TownCowY[i]; dir = TownCowDir[i]; InitTownerInfo(numtowners, 128, FALSE, TOWN_COW, x, y, -1, 10); towner[numtowners]._tNData = pCowCels; SetTownerGPtrs(towner[numtowners]._tNData, towner[numtowners]._tNAnim); towner[numtowners]._tNFrames = 12; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[dir], towner[numtowners]._tNFrames, 3); towner[numtowners]._tAnimFrame = random_(0, 11) + 1; towner[numtowners]._tSelFlag = TRUE; strcpy(towner[numtowners]._tName, "Cow"); xo = x + cowoffx[dir]; yo = y + cowoffy[dir]; if (dMonster[x][yo] == 0) dMonster[x][yo] = -(numtowners + 1); if (dMonster[xo][y] == 0) dMonster[xo][y] = -(numtowners + 1); if (dMonster[xo][yo] == 0) dMonster[xo][yo] = -(numtowners + 1); numtowners++; } } #ifdef HELLFIRE void InitFarmer() { int i; InitTownerInfo(numtowners, 96, 1, TOWN_FARMER, 62, 16, -1, 10); InitQstSnds(numtowners); towner[numtowners]._tNData = LoadFileInMem("Towners\\Farmer\\Farmrn2.CEL", NULL); for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 15; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_S], towner[numtowners]._tNFrames, 3); strcpy(towner[numtowners]._tName, "Lester the farmer"); numtowners++; } void InitCowFarmer() { int i; InitTownerInfo(numtowners, 96, 1, TOWN_COWFARM, 61, 22, -1, 10); InitQstSnds(numtowners); if (quests[Q_JERSEY]._qactive != QUEST_DONE) { towner[numtowners]._tNData = LoadFileInMem("Towners\\Farmer\\cfrmrn2.CEL", NULL); } else { towner[numtowners]._tNData = LoadFileInMem("Towners\\Farmer\\mfrmrn2.CEL", NULL); } for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 15; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_SW], towner[numtowners]._tNFrames, 3); strcpy(towner[numtowners]._tName, "Complete Nut"); numtowners++; } void InitGirl() { int i; InitTownerInfo(numtowners, 96, 1, TOWN_GIRL, 77, 43, -1, 10); InitQstSnds(numtowners); if (quests[Q_GIRL]._qactive != QUEST_DONE) { towner[numtowners]._tNData = LoadFileInMem("Towners\\Girl\\Girlw1.CEL", NULL); } else { towner[numtowners]._tNData = LoadFileInMem("Towners\\Girl\\Girls1.CEL", NULL); } for (i = 0; i < 8; i++) { towner[numtowners]._tNAnim[i] = towner[numtowners]._tNData; } towner[numtowners]._tNFrames = 20; NewTownerAnim(numtowners, towner[numtowners]._tNAnim[DIR_S], towner[numtowners]._tNFrames, 6); strcpy(towner[numtowners]._tName, "Celia"); numtowners++; } #endif void InitTowners() { numtowners = 0; boyloadflag = FALSE; InitSmith(); InitHealer(); if (quests[Q_BUTCHER]._qactive != QUEST_NOTAVAIL && quests[Q_BUTCHER]._qactive != QUEST_DONE) InitTownDead(); InitBarOwner(); InitTeller(); InitDrunk(); InitWitch(); InitBarmaid(); InitBoy(); InitCows(); #ifdef HELLFIRE if (UseCowFarmer) { InitCowFarmer(); } else if (quests[Q_FARMER]._qactive != 10) { InitFarmer(); } if (UseTheoQuest && plr->_pLvlVisited[17]) { InitGirl(); } #endif } void FreeTownerGFX() { int i; for (i = 0; i < NUM_TOWNERS; i++) { if (towner[i]._tNData == pCowCels) { towner[i]._tNData = NULL; } else if (towner[i]._tNData) { MemFreeDbg(towner[i]._tNData); } } MemFreeDbg(pCowCels); } void TownCtrlMsg(int i) { int p; int dx, dy; if (towner[i]._tbtcnt != 0) { p = towner[i]._tVar1; dx = abs(towner[i]._tx - plr[p]._px); dy = abs(towner[i]._ty - plr[p]._py); #ifdef HELLFIRE if (dx >= 2 || dy >= 2) { towner[i]._tbtcnt = 0; qtextflag = FALSE; stream_stop(); } #else if (dx >= 2 || dy >= 2) towner[i]._tbtcnt = 0; if (!towner[i]._tbtcnt) { qtextflag = FALSE; stream_stop(); } #endif } } void TownBlackSmith() { int i; i = GetActiveTowner(TOWN_SMITH); TownCtrlMsg(i); } void TownBarOwner() { int i; i = GetActiveTowner(TOWN_TAVERN); TownCtrlMsg(i); } void TownDead() { int tidx; tidx = GetActiveTowner(TOWN_DEADGUY); TownCtrlMsg(tidx); if (!qtextflag) { if (quests[Q_BUTCHER]._qactive == QUEST_ACTIVE && !quests[Q_BUTCHER]._qlog) { return; } if (quests[Q_BUTCHER]._qactive != QUEST_INIT) { towner[tidx]._tAnimDelay = 1000; towner[tidx]._tAnimFrame = 1; strcpy(towner[tidx]._tName, "Slain Townsman"); } } if (quests[Q_BUTCHER]._qactive != QUEST_INIT) towner[tidx]._tAnimCnt = 0; } void TownHealer() { int i; i = GetActiveTowner(TOWN_HEALER); TownCtrlMsg(i); } void TownStory() { int i; i = GetActiveTowner(TOWN_STORY); TownCtrlMsg(i); } void TownDrunk() { int i; i = GetActiveTowner(TOWN_DRUNK); TownCtrlMsg(i); } void TownBoy() { int i; i = GetActiveTowner(TOWN_PEGBOY); TownCtrlMsg(i); } void TownWitch() { int i; i = GetActiveTowner(TOWN_WITCH); TownCtrlMsg(i); } void TownBarMaid() { int i; i = GetActiveTowner(TOWN_BMAID); TownCtrlMsg(i); } void TownCow() { int i; i = GetActiveTowner(TOWN_COW); TownCtrlMsg(i); } #ifdef HELLFIRE void TownFarmer() { int i; i = GetActiveTowner(TOWN_FARMER); TownCtrlMsg(i); } void TownCowFarmer() { int i; i = GetActiveTowner(TOWN_COWFARM); TownCtrlMsg(i); } void TownGirl() { int i; i = GetActiveTowner(TOWN_GIRL); TownCtrlMsg(i); } #endif void ProcessTowners() { int i, ao; // BUGFIX: should be `i < numtowners`, was `i < NUM_TOWNERS`. for (i = 0; i < NUM_TOWNERS; i++) { switch (towner[i]._ttype) { 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; #ifdef HELLFIRE case TOWN_FARMER: TownFarmer(); break; case TOWN_GIRL: TownGirl(); break; case TOWN_COWFARM: TownCowFarmer(); break; #endif } towner[i]._tAnimCnt++; if (towner[i]._tAnimCnt >= towner[i]._tAnimDelay) { towner[i]._tAnimCnt = 0; if (towner[i]._tAnimOrder >= 0) { ao = towner[i]._tAnimOrder; towner[i]._tAnimFrameCnt++; if (AnimOrder[ao][towner[i]._tAnimFrameCnt] == -1) towner[i]._tAnimFrameCnt = 0; towner[i]._tAnimFrame = AnimOrder[ao][towner[i]._tAnimFrameCnt]; } else { towner[i]._tAnimFrame++; if (towner[i]._tAnimFrame > towner[i]._tAnimLen) towner[i]._tAnimFrame = 1; } } } } ItemStruct *PlrHasItem(int pnum, int item, int &i) { for (i = 0; i < plr[pnum]._pNumInv; i++) { if (plr[pnum].InvList[i].IDidx == item) return &plr[pnum].InvList[i]; } return NULL; } void TownerTalk(int first, int t) { sgdwCowClicks = 0; sgnCowMsg = 0; storeflag = TRUE; InitQTextMsg(first); } void TalkToTowner(int p, int t) { int i, dx, dy, rv1, rv2, rv3; ItemStruct *Item; #ifdef HELLFIRE int qt, t2; #endif rv1 = random_(6, 3); /* unused */ rv2 = random_(6, 4); /* unused */ rv3 = random_(6, 5); /* unused */ dx = abs(plr[p]._px - towner[t]._tx); dy = abs(plr[p]._py - towner[t]._ty); #ifdef _DEBUG if (!debug_mode_key_d && (dx >= 2 || dy >= 2)) { return; } #else if (dx >= 2 || dy >= 2) { return; } #endif if (qtextflag) { return; } towner[t]._tMsgSaid = FALSE; if (pcurs >= CURSOR_FIRSTITEM && !DropItemBeforeTrig()) { return; } if (t == GetActiveTowner(TOWN_TAVERN)) { if (!plr[p]._pLvlVisited[0] && !towner[t]._tMsgSaid) { towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_INTRO); towner[t]._tMsgSaid = TRUE; } if ((plr[p]._pLvlVisited[2] || plr[p]._pLvlVisited[4]) && quests[Q_SKELKING]._qactive != QUEST_NOTAVAIL) { #ifdef HELLFIRE if (quests[Q_SKELKING]._qactive != QUEST_NOTAVAIL) #endif if (quests[Q_SKELKING]._qvar2 == 0 && !towner[t]._tMsgSaid) { quests[Q_SKELKING]._qvar2 = 1; quests[Q_SKELKING]._qlog = TRUE; if (quests[Q_SKELKING]._qactive == QUEST_INIT) { quests[Q_SKELKING]._qactive = QUEST_ACTIVE; quests[Q_SKELKING]._qvar1 = 1; } towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_KING2); towner[t]._tMsgSaid = TRUE; NetSendCmdQuest(TRUE, Q_SKELKING); } if (quests[Q_SKELKING]._qactive == QUEST_DONE && quests[Q_SKELKING]._qvar2 == 1 && !towner[t]._tMsgSaid) { quests[Q_SKELKING]._qvar2 = 2; quests[Q_SKELKING]._qvar1 = 2; towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_KING4); towner[t]._tMsgSaid = TRUE; NetSendCmdQuest(TRUE, Q_SKELKING); } } if (gbMaxPlayers == 1) { if (plr[p]._pLvlVisited[3] && quests[Q_LTBANNER]._qactive != QUEST_NOTAVAIL) { if ((quests[Q_LTBANNER]._qactive == QUEST_INIT || quests[Q_LTBANNER]._qactive == QUEST_ACTIVE) && quests[Q_LTBANNER]._qvar2 == 0 && !towner[t]._tMsgSaid) { quests[Q_LTBANNER]._qvar2 = 1; if (quests[Q_LTBANNER]._qactive == QUEST_INIT) { quests[Q_LTBANNER]._qvar1 = 1; quests[Q_LTBANNER]._qactive = QUEST_ACTIVE; } quests[Q_LTBANNER]._qlog = TRUE; towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_BANNER2); towner[t]._tMsgSaid = TRUE; } #ifdef HELLFIRE } if (!towner[t]._tMsgSaid && PlrHasItem(p, IDI_BANNER, i) != NULL) { #else if (quests[Q_LTBANNER]._qvar2 == 1 && PlrHasItem(p, IDI_BANNER, i) != NULL && !towner[t]._tMsgSaid) { #endif quests[Q_LTBANNER]._qactive = QUEST_DONE; quests[Q_LTBANNER]._qvar1 = 3; RemoveInvItem(p, i); CreateItem(UITEM_HARCREST, towner[t]._tx, towner[t]._ty + 1); towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_BANNER3); towner[t]._tMsgSaid = TRUE; } } #ifndef HELLFIRE } #endif if (!qtextflag) { TownerTalk(TEXT_OGDEN1, t); if (storeflag) { StartStore(STORE_TAVERN); } } } else if (t == GetActiveTowner(TOWN_DEADGUY)) { if (quests[Q_BUTCHER]._qactive == QUEST_ACTIVE && quests[Q_BUTCHER]._qvar1 == 1) { towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; quests[Q_BUTCHER]._qvar1 = 1; #ifndef SPAWN if (plr[p]._pClass == PC_WARRIOR && !effect_is_playing(PS_WARR8)) { PlaySFX(PS_WARR8); } else if (plr[p]._pClass == PC_ROGUE && !effect_is_playing(PS_ROGUE8)) { PlaySFX(PS_ROGUE8); } else if (plr[p]._pClass == PC_SORCERER && !effect_is_playing(PS_MAGE8)) { PlaySFX(PS_MAGE8); #ifdef HELLFIRE } else if (plr[p]._pClass == PC_MONK && !effect_is_playing(PS_MONK8)) { PlaySFX(PS_MONK8); } else if (plr[p]._pClass == PC_BARD && !effect_is_playing(PS_ROGUE8)) { PlaySFX(PS_ROGUE8); } else if (plr[p]._pClass == PC_BARBARIAN && !effect_is_playing(PS_WARR8)) { PlaySFX(PS_WARR8); #endif } #endif towner[t]._tMsgSaid = TRUE; } else if (quests[Q_BUTCHER]._qactive == QUEST_DONE && quests[Q_BUTCHER]._qvar1 == 1) { quests[Q_BUTCHER]._qvar1 = 1; towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; towner[t]._tMsgSaid = TRUE; } else if (quests[Q_BUTCHER]._qactive == QUEST_INIT || quests[Q_BUTCHER]._qactive == QUEST_ACTIVE && quests[Q_BUTCHER]._qvar1 == 0) { quests[Q_BUTCHER]._qactive = QUEST_ACTIVE; quests[Q_BUTCHER]._qlog = TRUE; quests[Q_BUTCHER]._qmsg = TEXT_BUTCH9; quests[Q_BUTCHER]._qvar1 = 1; towner[t]._tbtcnt = 50; towner[t]._tVar1 = p; towner[t]._tVar2 = 3; InitQTextMsg(TEXT_BUTCH9); towner[t]._tMsgSaid = TRUE; NetSendCmdQuest(TRUE, Q_BUTCHER); } } else if (t == GetActiveTowner(TOWN_SMITH)) { if (gbMaxPlayers == 1) { if (plr[p]._pLvlVisited[4] && quests[Q_ROCK]._qactive != QUEST_NOTAVAIL) { #ifdef HELLFIRE if (quests[Q_ROCK]._qactive != QUEST_NOTAVAIL) #endif if (quests[Q_ROCK]._qvar2 == 0) { quests[Q_ROCK]._qvar2 = 1; quests[Q_ROCK]._qlog = TRUE; if (quests[Q_ROCK]._qactive == QUEST_INIT) { quests[Q_ROCK]._qactive = QUEST_ACTIVE; quests[Q_ROCK]._qvar1 = 1; } towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_INFRA5); towner[t]._tMsgSaid = TRUE; } #ifdef HELLFIRE } if (!towner[t]._tMsgSaid && PlrHasItem(p, IDI_ROCK, i) != NULL) { #else if (quests[Q_ROCK]._qvar2 == 1 && PlrHasItem(p, IDI_ROCK, i) != NULL && !towner[t]._tMsgSaid) { #endif quests[Q_ROCK]._qactive = QUEST_DONE; quests[Q_ROCK]._qvar2 = 2; quests[Q_ROCK]._qvar1 = 2; RemoveInvItem(p, i); CreateItem(UITEM_INFRARING, towner[t]._tx, towner[t]._ty + 1); towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_INFRA7); towner[t]._tMsgSaid = TRUE; } #ifndef HELLFIRE } #endif if (plr[p]._pLvlVisited[9] && quests[Q_ANVIL]._qactive != QUEST_NOTAVAIL) { if ((quests[Q_ANVIL]._qactive == QUEST_INIT || quests[Q_ANVIL]._qactive == QUEST_ACTIVE) && quests[Q_ANVIL]._qvar2 == 0 && !towner[t]._tMsgSaid) { if (quests[Q_ROCK]._qvar2 == 2 || quests[Q_ROCK]._qactive == QUEST_ACTIVE && quests[Q_ROCK]._qvar2 == 1) { quests[Q_ANVIL]._qvar2 = 1; quests[Q_ANVIL]._qlog = TRUE; if (quests[Q_ANVIL]._qactive == QUEST_INIT) { quests[Q_ANVIL]._qactive = QUEST_ACTIVE; quests[Q_ANVIL]._qvar1 = 1; } towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_ANVIL5); towner[t]._tMsgSaid = TRUE; } } #ifdef HELLFIRE } if (!towner[t]._tMsgSaid && PlrHasItem(p, IDI_ANVIL, i) != NULL) { #else if (quests[Q_ANVIL]._qvar2 == 1 && PlrHasItem(p, IDI_ANVIL, i) != NULL) { if (!towner[t]._tMsgSaid) { #endif quests[Q_ANVIL]._qactive = QUEST_DONE; quests[Q_ANVIL]._qvar2 = 2; quests[Q_ANVIL]._qvar1 = 2; RemoveInvItem(p, i); CreateItem(UITEM_GRISWOLD, towner[t]._tx, towner[t]._ty + 1); towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_ANVIL7); towner[t]._tMsgSaid = TRUE; #ifndef HELLFIRE } } #endif } } if (!qtextflag) { TownerTalk(TEXT_GRISWOLD1, t); if (storeflag) { StartStore(STORE_SMITH); } } } else if (t == GetActiveTowner(TOWN_WITCH)) { if (quests[Q_MUSHROOM]._qactive == QUEST_INIT && PlrHasItem(p, IDI_FUNGALTM, i) != NULL) { RemoveInvItem(p, i); quests[Q_MUSHROOM]._qactive = QUEST_ACTIVE; quests[Q_MUSHROOM]._qlog = TRUE; quests[Q_MUSHROOM]._qvar1 = QS_TOMEGIVEN; towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_MUSH8); towner[t]._tMsgSaid = TRUE; } else if (quests[Q_MUSHROOM]._qactive == QUEST_ACTIVE) { if (quests[Q_MUSHROOM]._qvar1 >= QS_TOMEGIVEN && quests[Q_MUSHROOM]._qvar1 <= QS_MUSHPICKED) { if (PlrHasItem(p, IDI_MUSHROOM, i) != NULL) { RemoveInvItem(p, i); quests[Q_MUSHROOM]._qvar1 = 5; Qtalklist[TOWN_HEALER]._qblkm = TEXT_MUSH3; Qtalklist[TOWN_WITCH]._qblkm = -1; towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; quests[Q_MUSHROOM]._qmsg = TEXT_MUSH10; InitQTextMsg(TEXT_MUSH10); towner[t]._tMsgSaid = TRUE; } else if (quests[Q_MUSHROOM]._qmsg != TEXT_MUSH9) { towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; quests[Q_MUSHROOM]._qmsg = TEXT_MUSH9; InitQTextMsg(TEXT_MUSH9); towner[t]._tMsgSaid = TRUE; } } else { Item = PlrHasItem(p, IDI_SPECELIX, i); if (Item != NULL) { towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_MUSH12); quests[Q_MUSHROOM]._qactive = QUEST_DONE; towner[t]._tMsgSaid = TRUE; AllItemsList[Item->IDidx].iUsable = TRUE; /// BUGFIX: This will cause the elixir to be usable in the next game } else if (PlrHasItem(p, IDI_BRAIN, i) != NULL && quests[Q_MUSHROOM]._qvar2 != TEXT_MUSH11) { towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; quests[Q_MUSHROOM]._qvar2 = TEXT_MUSH11; InitQTextMsg(TEXT_MUSH11); towner[t]._tMsgSaid = TRUE; } } } if (!qtextflag) { TownerTalk(TEXT_ADRIA1, t); if (storeflag) { StartStore(STORE_WITCH); } } } else if (t == GetActiveTowner(TOWN_BMAID)) { #ifdef HELLFIRE if (plr[p]._pLvlVisited[21] == false && PlrHasItem(p, IDI_MAPOFDOOM, i)) { quests[Q_GRAVE]._qactive = QUEST_ACTIVE; quests[Q_GRAVE]._qlog = TRUE; quests[Q_GRAVE]._qmsg = TEXT_GRAVE8; InitQTextMsg(TEXT_GRAVE8); towner[t]._tMsgSaid = TRUE; } #endif if (!qtextflag) { TownerTalk(TEXT_GILLIAN1, t); if (storeflag) { StartStore(STORE_BARMAID); } } } else if (t == GetActiveTowner(TOWN_DRUNK)) { if (!qtextflag) { TownerTalk(TEXT_FARNHAM1, t); if (storeflag) { StartStore(STORE_DRUNK); } } } else if (t == GetActiveTowner(TOWN_HEALER)) { if (gbMaxPlayers == 1) { #ifdef HELLFIRE if (plr[p]._pLvlVisited[1] || plr[p]._pLvlVisited[5]) { #else if (plr[p]._pLvlVisited[1]) { #endif if (!towner[t]._tMsgSaid) { if (quests[Q_PWATER]._qactive == QUEST_INIT) { quests[Q_PWATER]._qactive = QUEST_ACTIVE; quests[Q_PWATER]._qlog = TRUE; quests[Q_PWATER]._qmsg = TEXT_POISON3; quests[Q_PWATER]._qvar1 = 1; towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_POISON3); towner[t]._tMsgSaid = TRUE; } else if (quests[Q_PWATER]._qactive == QUEST_DONE && quests[Q_PWATER]._qvar1 != 2) { quests[Q_PWATER]._qvar1 = 2; towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_POISON5); CreateItem(UITEM_TRING, towner[t]._tx, towner[t]._ty + 1); towner[t]._tMsgSaid = TRUE; } } } if (quests[Q_MUSHROOM]._qactive == QUEST_ACTIVE && quests[Q_MUSHROOM]._qmsg == TEXT_MUSH10 && PlrHasItem(p, IDI_BRAIN, i) != NULL) { RemoveInvItem(p, i); SpawnQuestItem(IDI_SPECELIX, towner[t]._tx, towner[t]._ty + 1, 0, 0); InitQTextMsg(TEXT_MUSH4); quests[Q_MUSHROOM]._qvar1 = QS_BRAINGIVEN; Qtalklist[TOWN_HEALER]._qblkm = -1; } } if (!qtextflag) { TownerTalk(TEXT_PEPIN1, t); if (storeflag) { StartStore(STORE_HEALER); } } } else if (t == GetActiveTowner(TOWN_PEGBOY)) { if (!qtextflag) { TownerTalk(TEXT_WIRT1, t); if (storeflag) { StartStore(STORE_BOY); } } } else if (t == GetActiveTowner(TOWN_STORY)) { if (gbMaxPlayers == 1) { if (quests[Q_BETRAYER]._qactive == QUEST_INIT && PlrHasItem(p, IDI_LAZSTAFF, i) != NULL) { RemoveInvItem(p, i); quests[Q_BETRAYER]._qvar1 = 2; towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_VILE1); towner[t]._tMsgSaid = TRUE; quests[Q_BETRAYER]._qactive = QUEST_ACTIVE; quests[Q_BETRAYER]._qlog = TRUE; } else if (quests[Q_BETRAYER]._qactive == QUEST_DONE && quests[Q_BETRAYER]._qvar1 == 7) { quests[Q_BETRAYER]._qvar1 = 8; towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_VILE3); towner[t]._tMsgSaid = TRUE; quests[Q_DIABLO]._qlog = TRUE; } } if (gbMaxPlayers != 1) { if (quests[Q_BETRAYER]._qactive == QUEST_ACTIVE && !quests[Q_BETRAYER]._qlog) { towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_VILE1); towner[t]._tMsgSaid = TRUE; quests[Q_BETRAYER]._qlog = TRUE; NetSendCmdQuest(TRUE, Q_BETRAYER); } else if (quests[Q_BETRAYER]._qactive == QUEST_DONE && quests[Q_BETRAYER]._qvar1 == 7) { quests[Q_BETRAYER]._qvar1 = 8; towner[t]._tbtcnt = 150; towner[t]._tVar1 = p; InitQTextMsg(TEXT_VILE3); towner[t]._tMsgSaid = TRUE; NetSendCmdQuest(TRUE, Q_BETRAYER); quests[Q_DIABLO]._qlog = TRUE; NetSendCmdQuest(TRUE, Q_DIABLO); } } if (!qtextflag) { TownerTalk(TEXT_STORY1, t); if (storeflag) { StartStore(STORE_STORY); } } } else if (towner[t]._ttype == TOWN_COW) { if (!qtextflag) CowSFX(p); #ifdef HELLFIRE } else if (towner[t]._ttype == TOWN_FARMER) { if (!qtextflag) { qt = 277; t2 = 1; switch (quests[Q_FARMER]._qactive) { case 0: if (PlrHasItem(p, IDI_RUNEBOMB, i)) { qt = TEXT_FARMER2; quests[Q_FARMER]._qactive = QUEST_ACTIVE; quests[Q_FARMER]._qvar1 = 1; quests[Q_FARMER]._qlog = TRUE; quests[Q_FARMER]._qmsg = TEXT_FARMER1; break; } else if (!plr[myplr]._pLvlVisited[9] && plr[myplr]._pLevel < 15) { qt = 309; if (plr[myplr]._pLvlVisited[2]) qt = 281; if (plr[myplr]._pLvlVisited[5]) qt = 308; if (plr[myplr]._pLvlVisited[7]) qt = 310; } else { qt = TEXT_FARMER1; quests[Q_FARMER]._qactive = QUEST_ACTIVE; quests[Q_FARMER]._qvar1 = 1; quests[Q_FARMER]._qlog = TRUE; quests[Q_FARMER]._qmsg = TEXT_FARMER1; SpawnRuneBomb(towner[t]._tx + 1, towner[t]._ty); t2 = 1; break; } case 2: if (PlrHasItem(p, IDI_RUNEBOMB, i)) qt = TEXT_FARMER2; else qt = TEXT_FARMER3; break; case 1: if (PlrHasItem(p, IDI_RUNEBOMB, i)) { qt = TEXT_FARMER2; quests[Q_FARMER]._qactive = QUEST_ACTIVE; quests[Q_FARMER]._qvar1 = 1; quests[Q_FARMER]._qmsg = TEXT_FARMER1; quests[Q_FARMER]._qlog = TRUE; } else if (!plr[myplr]._pLvlVisited[9] && plr[myplr]._pLevel < 15) { qt = TEXT_FARMER8; if (plr[myplr]._pLvlVisited[2]) { qt = TEXT_FARMER5; } if (plr[myplr]._pLvlVisited[5]) { qt = TEXT_FARMER7; } if (plr[myplr]._pLvlVisited[7]) { qt = TEXT_FARMER9; } } else { qt = TEXT_FARMER1; quests[Q_FARMER]._qactive = QUEST_ACTIVE; quests[Q_FARMER]._qvar1 = 1; quests[Q_FARMER]._qlog = TRUE; quests[Q_FARMER]._qmsg = TEXT_FARMER1; SpawnRuneBomb(towner[t]._tx + 1, towner[t]._ty); t2 = 1; } break; case 3: qt = TEXT_FARMER4; SpawnRewardItem(IDI_AURIC, towner[t]._tx + 1, towner[t]._ty); quests[Q_FARMER]._qactive = 10; quests[Q_FARMER]._qlog = FALSE; t2 = 1; break; case 10: qt = -1; break; default: quests[Q_FARMER]._qactive = QUEST_NOTAVAIL; qt = TEXT_FARMER4; break; } if (qt != -1) { if (t2) InitQTextMsg(qt); else PlaySFX(alltext[qt].sfxnr); } if (gbMaxPlayers != 1) { NetSendCmdQuest(TRUE, Q_FARMER); } } } else if (towner[t]._ttype == TOWN_COWFARM) { if (!qtextflag) { qt = 297; t2 = 1; if (PlrHasItem(p, IDI_GREYSUIT, i)) { qt = TEXT_JERSEY7; RemoveInvItem(p, i); } else if (PlrHasItem(p, IDI_BROWNSUIT, i)) { CreateItem(UITEM_BOVINE, towner[t]._tx + 1, towner[t]._ty); RemoveInvItem(p, i); qt = TEXT_JERSEY8; quests[Q_JERSEY]._qactive = QUEST_DONE; } else if (PlrHasItem(p, IDI_RUNEBOMB, i)) { qt = TEXT_JERSEY5; quests[Q_JERSEY]._qactive = QUEST_ACTIVE; quests[Q_JERSEY]._qvar1 = 1; quests[Q_JERSEY]._qmsg = TEXT_JERSEY4; quests[Q_JERSEY]._qlog = TRUE; } else { switch (quests[Q_JERSEY]._qactive) { case 0: qt = TEXT_JERSEY1; quests[Q_JERSEY]._qactive = 7; break; case 1: qt = TEXT_JERSEY1; quests[23]._qactive = 7; break; case 2: qt = TEXT_JERSEY5; break; case 3: qt = TEXT_JERSEY1; break; case 7: qt = TEXT_JERSEY2; quests[Q_JERSEY]._qactive = 8; break; case 8: qt = TEXT_JERSEY3; quests[Q_JERSEY]._qactive = 9; break; case 9: if (!plr[myplr]._pLvlVisited[9] && plr[myplr]._pLevel < 15) { switch (random_(0, 4) + 9) { case 9: qt = TEXT_JERSEY9; break; case 10: qt = TEXT_JERSEY10; break; case 11: qt = TEXT_JERSEY11; break; default: qt = TEXT_JERSEY12; } break; } else { qt = TEXT_JERSEY4; quests[Q_JERSEY]._qactive = QUEST_ACTIVE; quests[Q_JERSEY]._qvar1 = 1; quests[Q_JERSEY]._qmsg = TEXT_JERSEY4; quests[Q_JERSEY]._qlog = TRUE; SpawnRuneBomb(towner[t]._tx + 1, towner[t]._ty); t2 = 1; } break; default: qt = TEXT_JERSEY5; quests[Q_JERSEY]._qactive = QUEST_NOTAVAIL; break; } } if (qt != -1) { if (t2) InitQTextMsg(qt); else PlaySFX(alltext[qt].sfxnr); } if (gbMaxPlayers != 1) { NetSendCmdQuest(TRUE, Q_JERSEY); } } } else if (towner[t]._ttype == TOWN_GIRL) { if (!qtextflag) { qt = 282; t2 = 0; if (!PlrHasItem(p, IDI_THEODORE, i) || quests[Q_GIRL]._qactive == QUEST_DONE) { switch (quests[Q_GIRL]._qactive) { case 0: qt = TEXT_GIRL2; quests[Q_GIRL]._qactive = QUEST_ACTIVE; quests[Q_GIRL]._qvar1 = 1; quests[Q_GIRL]._qlog = TRUE; quests[Q_GIRL]._qmsg = TEXT_GIRL2; t2 = 1; break; case 1: qt = TEXT_GIRL2; quests[Q_GIRL]._qvar1 = 1; quests[Q_GIRL]._qlog = TRUE; quests[Q_GIRL]._qmsg = TEXT_GIRL2; quests[Q_GIRL]._qactive = QUEST_ACTIVE; t2 = 1; break; case 2: qt = TEXT_GIRL3; t2 = 1; break; case 3: qt = -1; break; default: quests[Q_GIRL]._qactive = QUEST_NOTAVAIL; qt = TEXT_GIRL1; break; } } else { qt = TEXT_GIRL4; RemoveInvItem(p, i); CreateAmulet(towner[t]._tx, towner[t]._ty, 13, 0, 1); quests[Q_GIRL]._qlog = FALSE; quests[Q_GIRL]._qactive = QUEST_DONE; t2 = 1; } if (qt != -1) { if (t2 != 0) { InitQTextMsg(qt); } else { PlaySFX(alltext[qt].sfxnr); } } if (gbMaxPlayers != 1) { NetSendCmdQuest(TRUE, Q_GIRL); } } #endif } } ================================================ FILE: Source/towners.h ================================================ /** * @file towners.h * * Interface of functionality for loading and spawning towners. */ #ifndef __TOWNERS_H__ #define __TOWNERS_H__ extern TownerStruct towner[NUM_TOWNERS]; void InitTowners(); void FreeTownerGFX(); void ProcessTowners(); ItemStruct *PlrHasItem(int pnum, int item, int &i); void TalkToTowner(int p, int t); /* data */ extern QuestTalkData Qtalklist[]; #endif /* __TOWNERS_H__ */ ================================================ FILE: Source/track.cpp ================================================ /** * @file track.cpp * * Implementation of functionality tracking what the mouse cursor is pointing at. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" static BYTE sgbIsScrolling; static DWORD sgdwLastWalk; static BOOL sgbIsWalking; void track_process() { if (!sgbIsWalking) return; if (cursmx < 0 || cursmx >= MAXDUNX - 1 || cursmy < 0 || cursmy >= MAXDUNY - 1) return; if (plr[myplr]._pVar8 <= 6 && plr[myplr]._pmode != PM_STAND) return; if (cursmx != plr[myplr]._ptargx || cursmy != plr[myplr]._ptargy) { DWORD tick = GetTickCount(); if ((int)(tick - sgdwLastWalk) >= 300) { sgdwLastWalk = tick; NetSendCmdLoc(TRUE, CMD_WALKXY, cursmx, cursmy); if (!sgbIsScrolling) sgbIsScrolling = TRUE; } } } void track_repeat_walk(BOOL rep) { if (sgbIsWalking == rep) return; sgbIsWalking = rep; if (rep) { sgbIsScrolling = FALSE; sgdwLastWalk = GetTickCount() - 50; NetSendCmdLoc(TRUE, CMD_WALKXY, cursmx, cursmy); } else if (sgbIsScrolling) { sgbIsScrolling = FALSE; } } BOOL track_isscrolling() { return sgbIsScrolling; } ================================================ FILE: Source/track.h ================================================ /** * @file track.h * * Interface of functionality tracking what the mouse cursor is pointing at. */ #ifndef __TRACK_H__ #define __TRACK_H__ void track_process(); void track_repeat_walk(BOOL rep); BOOL track_isscrolling(); #endif /* __TRACK_H__ */ ================================================ FILE: Source/trigs.cpp ================================================ /** * @file trigs.cpp * * Implementation of functionality for triggering events when the player enters an area. */ #include "all.h" BOOL townwarps[3]; BOOL trigflag; int numtrigs; TriggerStruct trigs[MAXTRIGGERS]; int TWarpFrom; /** Specifies the dungeon piece IDs which constitute stairways leading down to the cathedral from town. */ int TownDownList[] = { 716, 715, 719, 720, 721, 723, 724, 725, 726, 727, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading down to the catacombs from town. */ int TownWarp1List[] = { 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1181, 1183, 1185, -1 }; #ifdef HELLFIRE int TownCryptList[] = { 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, -1 }; int TownHiveList[] = { 1307, 1308, 1309, 1310, -1 }; #endif /** Specifies the dungeon piece IDs which constitute stairways leading up from the cathedral. */ int L1UpList[] = { 127, 129, 130, 131, 132, 133, 135, 137, 138, 139, 140, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading down from the cathedral. */ int L1DownList[] = { 106, 107, 108, 109, 110, 112, 114, 115, 118, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading up from the catacombs. */ int L2UpList[] = { 266, 267, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading down from the catacombs. */ int L2DownList[] = { 269, 270, 271, 272, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading up to town from the catacombs. */ int L2TWarpUpList[] = { 558, 559, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading up from the caves. */ int L3UpList[] = { 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading down from the caves. */ int L3DownList[] = { 162, 163, 164, 165, 166, 167, 168, 169, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading up to town from the caves. */ int L3TWarpUpList[] = { 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading up from hell. */ int L4UpList[] = { 82, 83, 90, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading down from hell. */ int L4DownList[] = { 120, 130, 131, 132, 133, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading up to town from hell. */ int L4TWarpUpList[] = { 421, 422, 429, -1 }; /** Specifies the dungeon piece IDs which constitute stairways leading down to Diablo from hell. */ int L4PentaList[] = { 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 }; #ifdef HELLFIRE int L5TWarpUpList[] = { 172, 173, 174, 175, 176, 177, 178, 179, 184, -1 }; int L5UpList[] = { 149, 150, 151, 152, 153, 154, 155, 157, 158, 159, -1 }; int L5DownList[] = { 125, 126, 129, 131, 132, 135, 136, 140, 142, -1 }; int L6TWarpUpList[] = { 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, -1 }; int L6UpList[] = { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, -1 }; int L6DownList[] = { 57, 58, 59, 60, 61, 62, 63, 64, -1 }; #endif #ifndef SPAWN void InitNoTriggers() { numtrigs = 0; trigflag = FALSE; } #endif void InitTownTriggers() { int i; numtrigs = 0; trigs[numtrigs]._tx = 25; trigs[numtrigs]._ty = 29; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; #ifndef SPAWN if (gbMaxPlayers == MAX_PLRS) { for (i = 0; i < sizeof(townwarps) / sizeof(townwarps[0]); i++) { townwarps[i] = TRUE; } trigs[numtrigs]._tx = 49; trigs[numtrigs]._ty = 21; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 5; numtrigs++; trigs[numtrigs]._tx = 17; trigs[numtrigs]._ty = 69; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 9; numtrigs++; trigs[numtrigs]._tx = 41; trigs[numtrigs]._ty = 80; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 13; numtrigs++; #ifdef HELLFIRE trigs[numtrigs]._tx = 36; trigs[numtrigs]._ty = 24; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 21; numtrigs++; trigs[numtrigs]._tx = 80; trigs[numtrigs]._ty = 62; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 17; numtrigs++; #endif } else { #endif for (i = 0; i < sizeof(townwarps) / sizeof(townwarps[0]); i++) { townwarps[i] = FALSE; } #ifndef SPAWN #ifdef HELLFIRE if (plr[myplr].pTownWarps & 1 || plr[myplr]._pLevel >= 10) { #else if (plr[myplr].pTownWarps & 1) { #endif trigs[numtrigs]._tx = 49; trigs[numtrigs]._ty = 21; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 5; numtrigs++; townwarps[0] = TRUE; } #ifdef HELLFIRE if (plr[myplr].pTownWarps & 2 || plr[myplr]._pLevel >= 15) { #else if (plr[myplr].pTownWarps & 2) { #endif townwarps[1] = TRUE; trigs[numtrigs]._tx = 17; trigs[numtrigs]._ty = 69; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 9; numtrigs++; } #ifdef HELLFIRE if (plr[myplr].pTownWarps & 4 || plr[myplr]._pLevel >= 20) { #else if (plr[myplr].pTownWarps & 4) { #endif townwarps[2] = TRUE; trigs[numtrigs]._tx = 41; trigs[numtrigs]._ty = 80; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 13; numtrigs++; } #ifdef HELLFIRE if (quests[Q_GRAVE]._qactive == QUEST_DONE) { trigs[numtrigs]._tx = 36; trigs[numtrigs]._ty = 24; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 21; numtrigs++; } trigs[numtrigs]._tx = 80; trigs[numtrigs]._ty = 62; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 17; numtrigs++; #endif } #endif trigflag = FALSE; } void InitL1Triggers() { int i, j; numtrigs = 0; #ifdef HELLFIRE if (currlevel < 17) { #endif for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 129) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 115) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } #ifdef HELLFIRE } else { for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 184) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABTWARPUP; trigs[numtrigs]._tlvl = 0; numtrigs++; } if (dPiece[i][j] == 158) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 126) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } } #endif trigflag = FALSE; } #ifndef SPAWN void InitL2Triggers() { int i, j; numtrigs = 0; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 267 && (i != quests[Q_SCHAMB]._qtx || j != quests[Q_SCHAMB]._qty)) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 559) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABTWARPUP; trigs[numtrigs]._tlvl = 0; numtrigs++; } if (dPiece[i][j] == 271) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } trigflag = FALSE; } void InitL3Triggers() { int i, j; #ifdef HELLFIRE if (currlevel < 17) { #endif numtrigs = 0; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 171) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 168) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } if (dPiece[i][j] == 549) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABTWARPUP; numtrigs++; } } } #ifdef HELLFIRE } else { numtrigs = 0; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 66) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 63) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } if (dPiece[i][j] == 80) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABTWARPUP; numtrigs++; } } } } #endif trigflag = FALSE; } void InitL4Triggers() { int i, j; numtrigs = 0; for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 83) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 422) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABTWARPUP; trigs[numtrigs]._tlvl = 0; numtrigs++; } if (dPiece[i][j] == 120) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 370 && quests[Q_BETRAYER]._qactive == QUEST_DONE) { trigs[numtrigs]._tx = i; trigs[numtrigs]._ty = j; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } trigflag = FALSE; } void InitSKingTriggers() { trigflag = FALSE; numtrigs = 1; trigs[0]._tx = 82; trigs[0]._ty = 42; trigs[0]._tmsg = WM_DIABRTNLVL; } void InitSChambTriggers() { trigflag = FALSE; numtrigs = 1; trigs[0]._tx = 70; trigs[0]._ty = 39; trigs[0]._tmsg = WM_DIABRTNLVL; } void InitPWaterTriggers() { trigflag = FALSE; numtrigs = 1; trigs[0]._tx = 30; trigs[0]._ty = 83; trigs[0]._tmsg = WM_DIABRTNLVL; } void InitVPTriggers() { trigflag = FALSE; numtrigs = 1; trigs[0]._tx = 35; trigs[0]._ty = 32; trigs[0]._tmsg = WM_DIABRTNLVL; } #endif BOOL ForceTownTrig() { int i, j, k, l; #ifdef HELLFIRE for (i = 0; TownCryptList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == TownCryptList[i]) { strcpy(infostr, "Down to Crypt"); cursmx = 36; cursmy = 24; return TRUE; } } for (i = 0; TownHiveList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == TownHiveList[i]) { strcpy(infostr, "Down to Hive"); cursmx = 80; cursmy = 62; return TRUE; } } #endif for (i = 0; TownDownList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == TownDownList[i]) { strcpy(infostr, "Down to dungeon"); cursmx = 25; cursmy = 29; return TRUE; } } if (townwarps[0]) { for (j = 0; TownWarp1List[j] != -1; j++) { if (dPiece[cursmx][cursmy] == TownWarp1List[j]) { strcpy(infostr, "Down to catacombs"); cursmx = 49; cursmy = 21; return TRUE; } } } if (townwarps[1]) { for (k = 1199; k <= 1220; k++) { if (dPiece[cursmx][cursmy] == k) { strcpy(infostr, "Down to caves"); cursmx = 17; cursmy = 69; return TRUE; } } } if (townwarps[2]) { for (l = 1240; l <= 1255; l++) { if (dPiece[cursmx][cursmy] == l) { strcpy(infostr, "Down to hell"); cursmx = 41; cursmy = 80; return TRUE; } } } return FALSE; } BOOL ForceL1Trig() { int i, j; #ifdef HELLFIRE int dx, dy; #endif #ifdef HELLFIRE if (currlevel < 17) { #endif for (i = 0; L1UpList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L1UpList[i]) { if (currlevel > 1) sprintf(infostr, "Up to level %i", currlevel - 1); else strcpy(infostr, "Up to town"); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } for (i = 0; L1DownList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L1DownList[i]) { sprintf(infostr, "Down to level %i", currlevel + 1); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } #ifdef HELLFIRE } else { for (i = 0; L5UpList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L5UpList[i]) { sprintf(infostr, "Up to Crypt level %i", currlevel - 21); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } if (dPiece[cursmx][cursmy] == 317) { strcpy(infostr, "Cornerstone of the World"); return TRUE; } for (i = 0; L5DownList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L5DownList[i]) { sprintf(infostr, "Down to Crypt level %i", currlevel - 19); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } if (currlevel == 21) { for (i = 0; L5TWarpUpList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L5TWarpUpList[i]) { for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABTWARPUP) { dx = abs(trigs[j]._tx - cursmx); dy = abs(trigs[j]._ty - cursmy); if (dx < 4 && dy < 4) { strcpy(infostr, "Up to town"); cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } } } } #endif return FALSE; } BOOL ForceL2Trig() { int i, j, dx, dy; for (i = 0; L2UpList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L2UpList[i]) { for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { dx = abs(trigs[j]._tx - cursmx); dy = abs(trigs[j]._ty - cursmy); if (dx < 4 && dy < 4) { sprintf(infostr, "Up to level %i", currlevel - 1); cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } } for (i = 0; L2DownList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L2DownList[i]) { sprintf(infostr, "Down to level %i", currlevel + 1); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } if (currlevel == 5) { for (i = 0; L2TWarpUpList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L2TWarpUpList[i]) { for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABTWARPUP) { dx = abs(trigs[j]._tx - cursmx); dy = abs(trigs[j]._ty - cursmy); if (dx < 4 && dy < 4) { strcpy(infostr, "Up to town"); cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } } } return FALSE; } BOOL ForceL3Trig() { int i, j, dx, dy; #ifdef HELLFIRE if (currlevel < 17) { #endif for (i = 0; L3UpList[i] != -1; ++i) { if (dPiece[cursmx][cursmy] == L3UpList[i]) { sprintf(infostr, "Up to level %i", currlevel - 1); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } for (i = 0; L3DownList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L3DownList[i] || dPiece[cursmx + 1][cursmy] == L3DownList[i] || dPiece[cursmx + 2][cursmy] == L3DownList[i]) { sprintf(infostr, "Down to level %i", currlevel + 1); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } #ifdef HELLFIRE } else { for (i = 0; L6UpList[i] != -1; ++i) { if (dPiece[cursmx][cursmy] == L6UpList[i]) { sprintf(infostr, "Up to Nest level %i", currlevel - 17); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } for (i = 0; L6DownList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L6DownList[i] || dPiece[cursmx + 1][cursmy] == L6DownList[i] || dPiece[cursmx + 2][cursmy] == L6DownList[i]) { sprintf(infostr, "Down to level %i", currlevel - 15); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } } #endif if (currlevel == 9) { for (i = 0; L3TWarpUpList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L3TWarpUpList[i]) { for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABTWARPUP) { dx = abs(trigs[j]._tx - cursmx); dy = abs(trigs[j]._ty - cursmy); if (dx < 4 && dy < 4) { strcpy(infostr, "Up to town"); cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } } } #ifdef HELLFIRE if (currlevel == 17) { for (i = 0; L6TWarpUpList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L6TWarpUpList[i]) { for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABTWARPUP) { dx = abs(trigs[j]._tx - cursmx); dy = abs(trigs[j]._ty - cursmy); if (dx < 4 && dy < 4) { strcpy(infostr, "Up to town"); cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } } } #endif return FALSE; } BOOL ForceL4Trig() { int i, j, dx, dy; for (i = 0; L4UpList[i] != -1; ++i) { if (dPiece[cursmx][cursmy] == L4UpList[i]) { sprintf(infostr, "Up to level %i", currlevel - 1); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } for (i = 0; L4DownList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L4DownList[i]) { sprintf(infostr, "Down to level %i", currlevel + 1); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } if (currlevel == 13) { for (i = 0; L4TWarpUpList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L4TWarpUpList[i]) { for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABTWARPUP) { dx = abs(trigs[j]._tx - cursmx); dy = abs(trigs[j]._ty - cursmy); if (dx < 4 && dy < 4) { strcpy(infostr, "Up to town"); cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } } } if (currlevel == 15) { for (i = 0; L4PentaList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L4PentaList[i]) { strcpy(infostr, "Down to Diablo"); for (j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursmx = trigs[j]._tx; cursmy = trigs[j]._ty; return TRUE; } } } } } return FALSE; } void Freeupstairs() { int i, tx, ty, xx, yy; for (i = 0; i < numtrigs; i++) { tx = trigs[i]._tx; ty = trigs[i]._ty; for (yy = -2; yy <= 2; yy++) { for (xx = -2; xx <= 2; xx++) { dFlags[tx + xx][ty + yy] |= BFLAG_POPULATED; } } } } BOOL ForceSKingTrig() { int i; for (i = 0; L1UpList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L1UpList[i]) { sprintf(infostr, "Back to Level %i", quests[Q_SKELKING]._qlevel); cursmx = trigs[0]._tx; cursmy = trigs[0]._ty; return TRUE; } } return FALSE; } BOOL ForceSChambTrig() { int i; for (i = 0; L2DownList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L2DownList[i]) { sprintf(infostr, "Back to Level %i", quests[Q_SCHAMB]._qlevel); cursmx = trigs[0]._tx; cursmy = trigs[0]._ty; return TRUE; } } return FALSE; } BOOL ForcePWaterTrig() { int i; for (i = 0; L3DownList[i] != -1; i++) { if (dPiece[cursmx][cursmy] == L3DownList[i]) { sprintf(infostr, "Back to Level %i", quests[Q_PWATER]._qlevel); cursmx = trigs[0]._tx; cursmy = trigs[0]._ty; return TRUE; } } return FALSE; } void CheckTrigForce() { trigflag = FALSE; if (MouseY > PANEL_TOP - 1) { return; } if (!setlevel) { switch (leveltype) { case DTYPE_TOWN: trigflag = ForceTownTrig(); break; case DTYPE_CATHEDRAL: trigflag = ForceL1Trig(); break; case DTYPE_CATACOMBS: trigflag = ForceL2Trig(); break; case DTYPE_CAVES: trigflag = ForceL3Trig(); break; case DTYPE_HELL: trigflag = ForceL4Trig(); break; } if (leveltype != DTYPE_TOWN && !trigflag) { trigflag = ForceQuests(); } } else { switch (setlvlnum) { case SL_SKELKING: trigflag = ForceSKingTrig(); break; case SL_BONECHAMB: trigflag = ForceSChambTrig(); break; case SL_POISONWATER: trigflag = ForcePWaterTrig(); break; } } if (trigflag) { ClearPanel(); } } void CheckTriggers() { int x, y, i; BOOL abort; char abortflag; if (plr[myplr]._pmode != PM_STAND) return; for (i = 0; i < numtrigs; i++) { if (plr[myplr]._px != trigs[i]._tx || plr[myplr]._py != trigs[i]._ty) { continue; } switch (trigs[i]._tmsg) { case WM_DIABNEXTLVL: #ifdef SPAWN if (currlevel >= 2) { NetSendCmdLoc(TRUE, CMD_WALKXY, plr[myplr]._px, plr[myplr]._py + 1); PlaySFX(PS_WARR18); InitDiabloMsg(EMSG_NOT_IN_SHAREWARE); } else { #endif if (pcurs >= CURSOR_FIRSTITEM && DropItemBeforeTrig()) return; StartNewLvl(myplr, trigs[i]._tmsg, currlevel + 1); #ifdef SPAWN } #endif break; case WM_DIABPREVLVL: if (pcurs >= CURSOR_FIRSTITEM && DropItemBeforeTrig()) return; StartNewLvl(myplr, trigs[i]._tmsg, currlevel - 1); break; case WM_DIABRTNLVL: StartNewLvl(myplr, trigs[i]._tmsg, ReturnLvl); break; case WM_DIABTOWNWARP: if (gbMaxPlayers != 1) { abort = FALSE; if (trigs[i]._tlvl == 5 && plr[myplr]._pLevel < 8) { abort = TRUE; x = plr[myplr]._px; y = plr[myplr]._py + 1; abortflag = EMSG_REQUIRES_LVL_8; } if (trigs[i]._tlvl == 9 && plr[myplr]._pLevel < 13) { abort = TRUE; x = plr[myplr]._px + 1; y = plr[myplr]._py; abortflag = EMSG_REQUIRES_LVL_13; } if (trigs[i]._tlvl == 13 && plr[myplr]._pLevel < 17) { abort = TRUE; x = plr[myplr]._px; y = plr[myplr]._py + 1; abortflag = EMSG_REQUIRES_LVL_17; } if (abort) { if (plr[myplr]._pClass == PC_WARRIOR) { PlaySFX(PS_WARR43); #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { PlaySFX(PS_ROGUE43); } else if (plr[myplr]._pClass == PC_SORCERER) { PlaySFX(PS_MAGE43); #endif } #ifdef HELLFIRE else if (plr[myplr]._pClass == PC_MONK) { PlaySFX(PS_MONK43); #ifndef SPAWN } else if (plr[myplr]._pClass == PC_BARD) { PlaySFX(PS_ROGUE43); #endif } else if (plr[myplr]._pClass == PC_BARBARIAN) { PlaySFX(PS_WARR43); } #endif InitDiabloMsg(abortflag); NetSendCmdLoc(TRUE, CMD_WALKXY, x, y); return; } } StartNewLvl(myplr, trigs[i]._tmsg, trigs[i]._tlvl); break; case WM_DIABTWARPUP: TWarpFrom = currlevel; StartNewLvl(myplr, trigs[i]._tmsg, 0); break; default: app_fatal("Unknown trigger msg"); break; } } } ================================================ FILE: Source/trigs.h ================================================ /** * @file trigs.h * * Interface of functionality for triggering events when the player enters an area. */ #ifndef __TRIGS_H__ #define __TRIGS_H__ extern BOOL trigflag; extern int numtrigs; extern TriggerStruct trigs[MAXTRIGGERS]; extern int TWarpFrom; void InitNoTriggers(); void InitTownTriggers(); void InitL1Triggers(); void InitL2Triggers(); void InitL3Triggers(); void InitL4Triggers(); void InitSKingTriggers(); void InitSChambTriggers(); void InitPWaterTriggers(); void InitVPTriggers(); void Freeupstairs(); void CheckTrigForce(); void CheckTriggers(); #endif /* __TRIGS_H__ */ ================================================ FILE: Source/wave.cpp ================================================ /** * @file wave.cpp * * Implementation of functionality for loading and processing wave files. */ #include "all.h" #include "../3rdParty/Storm/Source/storm.h" static void WGetFileArchive(HANDLE hsFile, DWORD *retries, const char *FileName) { HANDLE archive; if (*retries >= 5) FileErrDlg(FileName); if (hsFile && SFileGetFileArchive(hsFile, &archive) && archive != diabdat_mpq) { Sleep(20); (*retries)++; } else if (!InsertCDDlg()) FileErrDlg(FileName); } void WCloseFile(HANDLE file) { SFileCloseFile(file); } LONG WGetFileSize(HANDLE hsFile, DWORD *lpFileSizeHigh) { DWORD retry = 0; LONG ret; while ((ret = SFileGetFileSize(hsFile, lpFileSizeHigh)) == 0) WGetFileArchive(hsFile, &retry, NULL); return ret; } BOOL WOpenFile(const char *FileName, HANDLE *phsFile, BOOL mayNotExist) { DWORD retry = 0; while (1) { if (SFileOpenFile(FileName, phsFile)) return TRUE; if (mayNotExist && DERROR() == ERROR_FILE_NOT_FOUND) break; WGetFileArchive(NULL, &retry, FileName); } return FALSE; } void WReadFile(HANDLE hsFile, LPVOID buf, DWORD to_read) { DWORD retry = 0; DWORD readed; int initial_pos = WSetFilePointer(hsFile, 0, NULL, FILE_CURRENT); while (!SFileReadFile(hsFile, buf, to_read, &readed, NULL)) { WGetFileArchive(hsFile, &retry, NULL); WSetFilePointer(hsFile, initial_pos, NULL, FILE_BEGIN); } } int WSetFilePointer(HANDLE file1, int offset, HANDLE file2, int whence) { DWORD retry = 0; int result; while (1) { result = SFileSetFilePointer(file1, offset, file2, whence); if (result != -1) break; WGetFileArchive(file1, &retry, NULL); } return result; } static void FillMemFile(MEMFILE *pMemFile) { DWORD to_read; WSetFilePointer(pMemFile->file, pMemFile->offset, NULL, FILE_BEGIN); to_read = pMemFile->end - pMemFile->offset; if (pMemFile->buf_len < to_read) to_read = pMemFile->buf_len; if (to_read) WReadFile(pMemFile->file, pMemFile->buf, to_read); pMemFile->dist = 0; pMemFile->bytes_to_read = to_read; } static void FreeMemFile(MEMFILE *pMemFile) { MemFreeDbg(pMemFile->buf); } static BOOL ReadMemFile(MEMFILE *pMemFile, void *lpBuf, size_t length) { while (length) { size_t to_copy; if (!pMemFile->bytes_to_read) FillMemFile(pMemFile); to_copy = pMemFile->bytes_to_read; if (length < to_copy) to_copy = length; if (!to_copy) return FALSE; memcpy(lpBuf, &pMemFile->buf[pMemFile->dist], to_copy); pMemFile->offset += to_copy; pMemFile->dist += to_copy; pMemFile->bytes_to_read -= to_copy; // BUGFIX: lpBuf is not incremented, next read will overwrite data length -= to_copy; } return TRUE; } static int SeekMemFile(MEMFILE *pMemFile, ULONG lDist, DWORD dwMethod) { if (lDist < pMemFile->bytes_to_read) { pMemFile->bytes_to_read -= lDist; pMemFile->dist += lDist; } else pMemFile->bytes_to_read = 0; pMemFile->offset += lDist; return pMemFile->offset; } static BOOL ReadWaveSection(MEMFILE *pMemFile, DWORD id, CKINFO *chunk) { DWORD hdr[2]; while (1) { if (!ReadMemFile(pMemFile, hdr, sizeof(hdr))) return FALSE; if (hdr[0] == id) break; if (SeekMemFile(pMemFile, hdr[1], FILE_CURRENT) == -1) return FALSE; } chunk->dwSize = hdr[1]; chunk->dwOffset = SeekMemFile(pMemFile, 0, FILE_CURRENT); return chunk->dwOffset != (DWORD)-1; } static BOOL ReadWaveFile(MEMFILE *pMemFile, WAVEFORMATEX *pwfx, CKINFO *chunk) { MMCKINFO hdr; CKINFO fmt; PCMWAVEFORMAT wf; if (!ReadMemFile(pMemFile, &hdr, 12)) return FALSE; if (hdr.ckid != FOURCC_RIFF || hdr.fccType != MAKEFOURCC('W', 'A', 'V', 'E')) return FALSE; if (!ReadWaveSection(pMemFile, MAKEFOURCC('f', 'm', 't', ' '), &fmt)) return FALSE; if (fmt.dwSize < sizeof(PCMWAVEFORMAT)) return FALSE; if (!ReadMemFile(pMemFile, &wf, sizeof(wf))) return FALSE; if (SeekMemFile(pMemFile, fmt.dwSize - sizeof(wf), FILE_CURRENT) == -1) return FALSE; pwfx->cbSize = 0; pwfx->wFormatTag = wf.wf.wFormatTag; pwfx->nChannels = wf.wf.nChannels; pwfx->nSamplesPerSec = wf.wf.nSamplesPerSec; pwfx->nAvgBytesPerSec = wf.wf.nAvgBytesPerSec; pwfx->nBlockAlign = wf.wf.nBlockAlign; pwfx->wBitsPerSample = wf.wBitsPerSample; if (chunk == NULL) return TRUE; return ReadWaveSection(pMemFile, MAKEFOURCC('d', 'a', 't', 'a'), chunk); } BOOL LoadWaveFormat(HANDLE hsFile, WAVEFORMATEX *pwfx) { BOOL ret; MEMFILE wave_file; AllocateMemFile(hsFile, &wave_file, 0); ret = ReadWaveFile(&wave_file, pwfx, NULL); FreeMemFile(&wave_file); return ret; } void AllocateMemFile(HANDLE hsFile, MEMFILE *pMemFile, DWORD dwPos) { DWORD length; memset(pMemFile, 0, sizeof(*pMemFile)); pMemFile->end = WGetFileSize(hsFile, NULL); length = 4096; if (dwPos > length) length = dwPos; pMemFile->buf_len = length; if (length >= pMemFile->end) length = pMemFile->end; pMemFile->buf_len = length; pMemFile->buf = DiabloAllocPtr(length); pMemFile->file = hsFile; } BYTE *LoadWaveFile(HANDLE hsFile, WAVEFORMATEX *pwfx, CKINFO *chunk) { MEMFILE wave_file; AllocateMemFile(hsFile, &wave_file, (DWORD)-1); if (!ReadWaveFile(&wave_file, pwfx, chunk)) { FreeMemFile(&wave_file); return NULL; } return wave_file.buf; } ================================================ FILE: Source/wave.h ================================================ /** * @file wave.h * * Interface of functionality for loading files and processing wave files. */ #ifndef __WAVE_H__ #define __WAVE_H__ void WCloseFile(HANDLE file); LONG WGetFileSize(HANDLE hsFile, DWORD *lpFileSizeHigh); BOOL WOpenFile(const char *FileName, HANDLE *phsFile, BOOL mayNotExist); void WReadFile(HANDLE hsFile, LPVOID buf, DWORD to_read); int WSetFilePointer(HANDLE file1, int offset, HANDLE file2, int whence); BOOL LoadWaveFormat(HANDLE hsFile, WAVEFORMATEX *pwfx); void AllocateMemFile(HANDLE hsFile, MEMFILE *pMemFile, DWORD dwPos); BYTE *LoadWaveFile(HANDLE hsFile, WAVEFORMATEX *pwfx, CKINFO *chunk); #endif /* __WAVE_H__ */ ================================================ FILE: appveyor.yml ================================================ version: 1.0.{build} pull_requests: do_not_increment_build_number: true clone_depth: 1 image: Visual Studio 2017 configuration: Release platform: x86 build: project: Diablo.sln verbosity: minimal artifacts: - path: Source\WinRel\Diablo.exe name: Diablo.exe ================================================ FILE: comparer-config/diablo.toml ================================================ # conversion between function and file location of the functions # = (0x401000 - PE header offset) (0x400 for VC5 linker) address_offset = 0x400C00 [[func]] name = "operator delete" addr = 0x401010 size = 0x1A [[func]] name = "GetErrorStr" addr = 0x40102A size = 0xA4 [[func]] name = "TraceErrorDD" addr = 0x4010CE size = 0x6B8 [[func]] name = "TraceErrorDS" addr = 0x401831 size = 0x109 [[func]] name = "TraceLastError" addr = 0x40193A size = 0xD [[func]] name = "app_fatal" addr = 0x401947 size = 0x2E [[func]] name = "MsgBox" addr = 0x401975 size = 0x52 [[func]] name = "FreeDlg" addr = 0x4019C7 size = 0x69 [[func]] name = "DrawDlg" addr = 0x401A30 size = 0x35 [[func]] name = "DDErrMsg" addr = 0x401A65 size = 0x23 [[func]] name = "DSErrMsg" addr = 0x401A88 size = 0x23 [[func]] name = "center_window" addr = 0x401AAB size = 0x92 [[func]] name = "ErrDlg" addr = 0x401B3D size = 0x8D [[func]] name = "FuncDlg" addr = 0x401BCA size = 0x45 [[func]] name = "TextDlg" addr = 0x401C0F size = 0x1F [[func]] name = "ErrOkDlg" addr = 0x401C2E size = 0x6E [[func]] name = "FileErrDlg" addr = 0x401C9C size = 0x45 [[func]] name = "DiskFreeDlg" addr = 0x401CE1 size = 0x3C [[func]] name = "InsertCDDlg" addr = 0x401D1D size = 0x4B [[func]] name = "DirErrorDlg" addr = 0x401D68 size = 0x3C [[func]] name = "InitAutomapOnce" addr = 0x401DA4 size = 0x44 [[func]] name = "InitAutomap" addr = 0x401DE8 size = 0x10C [[func]] name = "StartAutomap" addr = 0x401EF4 size = 0x19 [[func]] name = "AutomapUp" addr = 0x401F0D size = 0xD [[func]] name = "AutomapDown" addr = 0x401F1A size = 0xD [[func]] name = "AutomapLeft" addr = 0x401F27 size = 0xD [[func]] name = "AutomapRight" addr = 0x401F34 size = 0xD [[func]] name = "AutomapZoomIn" addr = 0x401F41 size = 0x3F [[func]] name = "AutomapZoomOut" addr = 0x401F80 size = 0x3D [[func]] name = "DrawAutomap" addr = 0x401FBD size = 0x276 [[func]] name = "DrawAutomapTile" addr = 0x402233 size = 0x745 [[func]] name = "DrawAutomapPlr" addr = 0x4029A8 size = 0x3BB [[func]] name = "GetAutomapType" addr = 0x402D83 size = 0xC7 [[func]] name = "DrawAutomapText" addr = 0x402E4A size = 0xDD [[func]] name = "SetAutomapView" addr = 0x402F27 size = 0x1B6 [[func]] name = "AutomapZoomReset" addr = 0x4030DD size = 0x3E [[func]] name = "CaptureScreen" addr = 0x40311B size = 0xE9 [[func]] name = "CaptureHdr" addr = 0x403204 size = 0x90 [[func]] name = "CapturePal" addr = 0x403294 size = 0x69 [[func]] name = "CapturePix" addr = 0x4032FD size = 0x6D [[func]] name = "CaptureEnc" addr = 0x40336A size = 0x3E [[func]] name = "CaptureFile" addr = 0x4033A8 size = 0xC8 [[func]] name = "RedPalette" addr = 0x403470 size = 0x69 [[func]] name = "codec_decode" addr = 0x4034D9 size = 0xFD [[func]] name = "codec_init_key" addr = 0x4035DB size = 0xD1 [[func]] name = "codec_get_encoded_len" addr = 0x4036AC size = 0x12 [[func]] name = "codec_encode" addr = 0x4036BE size = 0x116 [[func]] name = "DrawSpellCel" addr = 0x4037D4 size = 0xAA [[func]] name = "SetSpellTrans" addr = 0x40387E size = 0x149 [[func]] name = "DrawSpell" addr = 0x4039C7 size = 0xC7 [[func]] name = "DrawSpellList" addr = 0x403A8E size = 0x4DB [[func]] name = "SetSpell" addr = 0x403F69 size = 0x43 [[func]] name = "SetSpeedSpell" addr = 0x403FAC size = 0x6B [[func]] name = "ToggleSpell" addr = 0x404017 size = 0xC3 [[func]] name = "PrintChar" addr = 0x4040DA size = 0x13E [[func]] name = "AddPanelString" addr = 0x404218 size = 0x32 [[func]] name = "ClearPanel" addr = 0x40424A size = 0xF [[func]] name = "DrawPanelBox" addr = 0x404259 size = 0x6C [[func]] name = "SetFlaskHeight" addr = 0x4042CA size = 0x51 [[func]] name = "DrawFlask" addr = 0x40431B size = 0x40 [[func]] name = "DrawLifeFlask" addr = 0x40435B size = 0x99 [[func]] name = "UpdateLifeFlask" addr = 0x4043F4 size = 0x81 [[func]] name = "DrawManaFlask" addr = 0x404475 size = 0x81 [[func]] name = "control_update_life_mana" addr = 0x4044F6 size = 0x74 [[func]] name = "UpdateManaFlask" addr = 0x40456A size = 0xAC [[func]] name = "InitControlPan" addr = 0x404616 size = 0x31E [[func]] name = "DrawCtrlPan" addr = 0x404934 size = 0x25 [[func]] name = "DrawCtrlBtns" addr = 0x404959 size = 0xB1 [[func]] name = "DoSpeedBook" addr = 0x404A0A size = 0x148 [[func]] name = "DoPanBtn" addr = 0x404B52 size = 0x99 [[func]] name = "control_set_button_down" addr = 0x404BEB size = 0x15 [[func]] name = "control_check_btn_press" addr = 0x404C00 size = 0x74 [[func]] name = "DoAutoMap" addr = 0x404C74 size = 0x2C [[func]] name = "CheckPanelInfo" addr = 0x404CA0 size = 0x344 [[func]] name = "CheckBtnUp" addr = 0x404FE4 size = 0x17D [[func]] name = "FreeControlPan" addr = 0x405181 size = 0x114 [[func]] name = "control_WriteStringToBuffer" addr = 0x405295 size = 0x33 [[func]] name = "DrawInfoBox" addr = 0x4052C8 size = 0x289 [[func]] name = "PrintInfo" addr = 0x405551 size = 0x6B [[func]] name = "CPrintString" addr = 0x4055BC size = 0xC5 [[func]] name = "PrintGameStr" addr = 0x405681 size = 0x57 [[func]] name = "DrawChr" addr = 0x4056D8 size = 0x980 [[func]] name = "ADD_PlrStringXY" addr = 0x406058 size = 0xB7 [[func]] name = "MY_PlrStringXY" addr = 0x40610F size = 0xBB [[func]] name = "CheckLvlBtn" addr = 0x4061CA size = 0x36 [[func]] name = "ReleaseLvlBtn" addr = 0x406200 size = 0x34 [[func]] name = "DrawLevelUpIcon" addr = 0x406234 size = 0x46 [[func]] name = "CheckChrBtns" addr = 0x40627A size = 0xEC [[func]] name = "ReleaseChrBtns" addr = 0x406366 size = 0xA2 [[func]] name = "DrawDurIcon" addr = 0x406408 size = 0x86 [[func]] name = "DrawDurIcon4Item" addr = 0x40648E size = 0x7A [[func]] name = "RedBack" addr = 0x406508 size = 0x8A [[func]] name = "GetSBookTrans" addr = 0x406592 size = 0xD5 [[func]] name = "DrawSpellBook" addr = 0x406667 size = 0x28D [[func]] name = "PrintSBookStr" addr = 0x4068F4 size = 0xC2 [[func]] name = "CheckSBook" addr = 0x4069B6 size = 0x142 [[func]] name = "get_pieces_str" addr = 0x406AF8 size = 0x10 [[func]] name = "DrawGoldSplit" addr = 0x406B08 size = 0x138 [[func]] name = "control_drop_gold" addr = 0x406C40 size = 0x12E [[func]] name = "control_remove_gold" addr = 0x406D6E size = 0xB6 [[func]] name = "control_set_gold_curs" addr = 0x406E24 size = 0x46 [[func]] name = "DrawTalkPan" addr = 0x406E6A size = 0x207 [[func]] name = "control_print_talk_msg" addr = 0x407071 size = 0x82 [[func]] name = "control_check_talk_btn" addr = 0x4070F3 size = 0x5A [[func]] name = "control_release_talk_btn" addr = 0x40714D size = 0x73 [[func]] name = "control_reset_talk_msg" addr = 0x4071C0 size = 0x3A [[func]] name = "control_type_message" addr = 0x4071FA size = 0x47 [[func]] name = "control_reset_talk" addr = 0x407241 size = 0x19 [[func]] name = "control_talk_last_key" addr = 0x40725A size = 0x40 [[func]] name = "control_presskeys" addr = 0x40729A size = 0x6A [[func]] name = "control_press_enter" addr = 0x407304 size = 0xBE [[func]] name = "control_up_down" addr = 0x4073C2 size = 0x48 [[func]] name = "InitCursor" addr = 0x40740A size = 0x16 [[func]] name = "FreeCursor" addr = 0x407420 size = 0x17 [[func]] name = "SetICursor" addr = 0x407437 size = 0x34 [[func]] name = "SetCursor_" addr = 0x40746B size = 0x23 [[func]] name = "NewCursor" addr = 0x40748E size = 0x5 [[func]] name = "InitLevelCursor" addr = 0x407493 size = 0x3D [[func]] name = "CheckTown" addr = 0x4074D0 size = 0x12D [[func]] name = "CheckRportal" addr = 0x4075FD size = 0x12C [[func]] name = "CheckCursMove" addr = 0x407729 size = 0xD7D [[func]] name = "InitDead" addr = 0x4084A6 size = 0x1B6 [[func]] name = "AddDead" addr = 0x40865C size = 0x21 [[func]] name = "SyncUniqDead" addr = 0x40867D size = 0x77 [[func]] name = "LoadDebugGFX" addr = 0x4086F4 size = 0x1B [[func]] name = "FreeDebugGFX" addr = 0x40870F size = 0x12 [[func]] name = "CheckDungeonClear" addr = 0x408721 size = 0x90 [[func]] name = "FreeGameMem" addr = 0x4087C1 size = 0x77 [[func]] name = "StartGame" addr = 0x408838 size = 0xAA [[func]] name = "run_game_loop" addr = 0x4088E2 size = 0x1AA [[func]] name = "start_game" addr = 0x408A8C size = 0x4F [[func]] name = "free_game" addr = 0x408ADB size = 0x43 [[func]] name = "diablo_get_not_running" addr = 0x408B1E size = 0x2C [[func]] name = "WinMain" addr = 0x408B4A size = 0x167 [[func]] name = "diablo_parse_flags" addr = 0x408CB1 size = 0xB0 [[func]] name = "diablo_init_screen" addr = 0x408D61 size = 0x50 [[func]] name = "diablo_find_window" addr = 0x408DB1 size = 0x43 [[func]] name = "diablo_reload_process" addr = 0x408DF4 size = 0x1DB [[func]] name = "PressEscKey" addr = 0x408FCF size = 0x8F [[func]] name = "DisableInputWndProc" addr = 0x40905E size = 0xD3 [[func]] name = "GM_Game" addr = 0x409131 size = 0x281 [[func]] name = "LeftMouseDown" addr = 0x4093B2 size = 0x1F3 [[func]] name = "LeftMouseCmd" addr = 0x4095A5 size = 0x247 [[func]] name = "TryIconCurs" addr = 0x4097EC size = 0x177 [[func]] name = "LeftMouseUp" addr = 0x409963 size = 0x45 [[func]] name = "RightMouseDown" addr = 0x4099A8 size = 0xE1 [[func]] name = "PressSysKey" addr = 0x409A8E size = 0x22 [[func]] name = "diablo_hotkey_msg" addr = 0x409AB0 size = 0xA1 [[func]] name = "ReleaseKey" addr = 0x409B51 size = 0xB [[func]] name = "PressKey" addr = 0x409B5C size = 0x3E7 [[func]] name = "diablo_pause_game" addr = 0x409F43 size = 0x3C [[func]] name = "PressChar" addr = 0x409F7F size = 0x364 [[func]] name = "LoadLvlGFX" addr = 0x40A391 size = 0x123 [[func]] name = "LoadAllGFX" addr = 0x40A4B4 size = 0x2D [[func]] name = "CreateLevel" addr = 0x40A4E1 size = 0xC3 [[func]] name = "LoadGameLevel" addr = 0x40A5A4 size = 0x53F [[func]] name = "game_loop" addr = 0x40AAE3 size = 0x50 [[func]] name = "game_logic" addr = 0x40AB33 size = 0xB4 [[func]] name = "timeout_cursor" addr = 0x40ABE7 size = 0x84 [[func]] name = "diablo_color_cyc_logic" addr = 0x40AC6B size = 0x42 [[func]] name = "doom_get_frame_from_time" addr = 0x40ACAD size = 0x19 [[func]] name = "doom_alloc_cel" addr = 0x40ACC6 size = 0x10 [[func]] name = "doom_cleanup" addr = 0x40ACD6 size = 0x12 [[func]] name = "doom_load_graphics" addr = 0x40ACE8 size = 0x4C [[func]] name = "doom_init" addr = 0x40AD34 size = 0x2A [[func]] name = "doom_close" addr = 0x40AD5E size = 0x16 [[func]] name = "doom_draw" addr = 0x40AD74 size = 0x62 [[func]] name = "DRLG_Init_Globals" addr = 0x40ADD6 size = 0xA3 [[func]] name = "LoadL1Dungeon" addr = 0x40AE79 size = 0xEC [[func]] name = "DRLG_L1Floor" addr = 0x40AF65 size = 0x4E [[func]] name = "DRLG_L1Pass3" addr = 0x40AFB3 size = 0xF2 [[func]] name = "DRLG_InitL1Vals" addr = 0x40B0A5 size = 0xBB [[func]] name = "LoadPreL1Dungeon" addr = 0x40B160 size = 0xC9 [[func]] name = "CreateL5Dungeon" addr = 0x40B229 size = 0x4D [[func]] name = "DRLG_LoadL1SP" addr = 0x40B276 size = 0x7E [[func]] name = "DRLG_FreeL1SP" addr = 0x40B2F4 size = 0x12 [[func]] name = "DRLG_L5" addr = 0x40B306 size = 0x269 [[func]] name = "DRLG_PlaceDoor" addr = 0x40B56F size = 0x12A [[func]] name = "DRLG_L1Shadows" addr = 0x40B699 size = 0x1E8 [[func]] name = "DRLG_PlaceMiniSet" addr = 0x40B881 size = 0x275 [[func]] name = "InitL5Dungeon" addr = 0x40BAF6 size = 0x22 [[func]] name = "L5ClearFlags" addr = 0x40BB18 size = 0x1B [[func]] name = "L5firstRoom" addr = 0x40BB33 size = 0x233 [[func]] name = "L5drawRoom" addr = 0x40BD66 size = 0x37 [[func]] name = "L5roomGen" addr = 0x40BD9D size = 0x207 [[func]] name = "L5checkRoom" addr = 0x40BFA4 size = 0x64 [[func]] name = "L5GetArea" addr = 0x40C008 size = 0x22 [[func]] name = "L5makeDungeon" addr = 0x40C02A size = 0x44 [[func]] name = "L5makeDmt" addr = 0x40C06E size = 0x72 [[func]] name = "L5AddWall" addr = 0x40C0E0 size = 0x15C [[func]] name = "L5HWallOk" addr = 0x40C23C size = 0xA0 [[func]] name = "L5VWallOk" addr = 0x40C2DC size = 0x7F [[func]] name = "L5HorizWall" addr = 0x40C35B size = 0xEE [[func]] name = "L5VertWall" addr = 0x40C449 size = 0x108 [[func]] name = "L5tileFix" addr = 0x40C551 size = 0x36F [[func]] name = "DRLG_L5Subs" addr = 0x40C8C0 size = 0xDD [[func]] name = "L5FillChambers" addr = 0x40C99D size = 0x3E9 [[func]] name = "DRLG_L5GChamber" addr = 0x40CD86 size = 0x141 [[func]] name = "DRLG_L5GHall" addr = 0x40CEC7 size = 0x50 [[func]] name = "DRLG_L5SetRoom" addr = 0x40CF17 size = 0x85 [[func]] name = "DRLG_L5FloodTVal" addr = 0x40CF9C size = 0x6F [[func]] name = "DRLG_L5FTVR" addr = 0x40D00B size = 0x1F0 [[func]] name = "DRLG_L5TransFix" addr = 0x40D1FB size = 0x88 [[func]] name = "DRLG_L5DirtFix" addr = 0x40D283 size = 0x6C [[func]] name = "DRLG_L5CornerFix" addr = 0x40D2EF size = 0x68 [[func]] name = "InitDungeon" addr = 0x40D357 size = 0x22 [[func]] name = "L2LockoutFix" addr = 0x40D379 size = 0x153 [[func]] name = "L2DoorFix" addr = 0x40D4CC size = 0x35 [[func]] name = "LoadL2Dungeon" addr = 0x40D501 size = 0x1C0 [[func]] name = "DRLG_L2Pass3" addr = 0x40D6C1 size = 0xF2 [[func]] name = "LoadPreL2Dungeon" addr = 0x40D7B3 size = 0xD5 [[func]] name = "CreateL2Dungeon" addr = 0x40D888 size = 0xC7 [[func]] name = "DRLG_LoadL2SP" addr = 0x40D94F size = 0x55 [[func]] name = "DRLG_FreeL2SP" addr = 0x40D9A4 size = 0x12 [[func]] name = "DRLG_L2" addr = 0x40D9B6 size = 0x6BE [[func]] name = "DRLG_L2PlaceMiniSet" addr = 0x40E074 size = 0x25D [[func]] name = "DRLG_L2PlaceRndSet" addr = 0x40E2D1 size = 0x1CB [[func]] name = "DRLG_L2Subs" addr = 0x40E49C size = 0x100 [[func]] name = "DRLG_L2Shadows" addr = 0x40E59C size = 0xCF [[func]] name = "DRLG_L2SetRoom" addr = 0x40E66B size = 0x85 [[func]] name = "L2TileFix" addr = 0x40E6F0 size = 0x5F [[func]] name = "CreateDungeon" addr = 0x40E74F size = 0x155 [[func]] name = "CreateRoom" addr = 0x40E8A4 size = 0x455 [[func]] name = "DefineRoom" addr = 0x40ECF9 size = 0x124 [[func]] name = "AddHall" addr = 0x40EE1D size = 0x8F [[func]] name = "GetHall" addr = 0x40EEAC size = 0x5D [[func]] name = "ConnectHall" addr = 0x40EF09 size = 0x35C [[func]] name = "CreateDoorType" addr = 0x40F265 size = 0x58 [[func]] name = "PlaceHallExt" addr = 0x40F2BD size = 0x13 [[func]] name = "DoPatternCheck" addr = 0x40F2D0 size = 0x165 [[func]] name = "DL2_FillVoids" addr = 0x40F459 size = 0x558 [[func]] name = "DL2_Cont" addr = 0x40F9B1 size = 0x3D [[func]] name = "DL2_NumNoChar" addr = 0x40F9EE size = 0x22 [[func]] name = "DL2_DrawRoom" addr = 0x40FA10 size = 0x87 [[func]] name = "DL2_KnockWalls" addr = 0x40FA97 size = 0xD5 [[func]] name = "DRLG_L2FloodTVal" addr = 0x40FB6C size = 0x6F [[func]] name = "DRLG_L2FTVR" addr = 0x40FBDB size = 0x1F0 [[func]] name = "DRLG_L2TransFix" addr = 0x40FDCB size = 0x88 [[func]] name = "L2DirtFix" addr = 0x40FE53 size = 0x6C [[func]] name = "DRLG_InitL2Vals" addr = 0x40FEBF size = 0xC2 [[func]] name = "AddFenceDoors" addr = 0x40FF81 size = 0x6B [[func]] name = "FenceDoorFix" addr = 0x40FFEC size = 0x119 [[func]] name = "DRLG_L3Anvil" addr = 0x410105 size = 0x110 [[func]] name = "FixL3Warp" addr = 0x410215 size = 0x68 [[func]] name = "FixL3HallofHeroes" addr = 0x41027D size = 0x74 [[func]] name = "DRLG_L3LockRec" addr = 0x4102F1 size = 0x53 [[func]] name = "DRLG_L3Lockout" addr = 0x410344 size = 0x5D [[func]] name = "CreateL3Dungeon" addr = 0x4103A1 size = 0xAD [[func]] name = "DRLG_L3" addr = 0x41044E size = 0x431 [[func]] name = "InitL3Dungeon" addr = 0x41087F size = 0x36 [[func]] name = "DRLG_L3FillRoom" addr = 0x4108B5 size = 0x13B [[func]] name = "DRLG_L3CreateBlock" addr = 0x4109F0 size = 0x1D0 [[func]] name = "DRLG_L3FloorArea" addr = 0x410BC0 size = 0x34 [[func]] name = "DRLG_L3FillDiags" addr = 0x410BF4 size = 0x71 [[func]] name = "DRLG_L3FillSingles" addr = 0x410C65 size = 0x5F [[func]] name = "DRLG_L3FillStraights" addr = 0x410CC4 size = 0x217 [[func]] name = "DRLG_L3Edges" addr = 0x410EDB size = 0x21 [[func]] name = "DRLG_L3GetFloorArea" addr = 0x410EFC size = 0x23 [[func]] name = "DRLG_L3MakeMegas" addr = 0x410F1F size = 0x8E [[func]] name = "DRLG_L3River" addr = 0x410FAD size = 0x667 [[func]] name = "DRLG_L3Pool" addr = 0x411614 size = 0x15E [[func]] name = "DRLG_L3Spawn" addr = 0x411772 size = 0x12A [[func]] name = "DRLG_L3SpawnEdge" addr = 0x41189C size = 0x144 [[func]] name = "DRLG_L3PoolFix" addr = 0x4119E0 size = 0x94 [[func]] name = "DRLG_L3PlaceMiniSet" addr = 0x411A74 size = 0x20F [[func]] name = "DRLG_L3PlaceRndSet" addr = 0x411C83 size = 0x18B [[func]] name = "DRLG_L3Wood" addr = 0x411E0E size = 0x430 [[func]] name = "WoodVertU" addr = 0x41223E size = 0x4C [[func]] name = "WoodVertD" addr = 0x41228A size = 0x44 [[func]] name = "WoodHorizL" addr = 0x4122CE size = 0x4C [[func]] name = "WoodHorizR" addr = 0x41231A size = 0x44 [[func]] name = "DRLG_L3Pass3" addr = 0x41235E size = 0x108 [[func]] name = "LoadL3Dungeon" addr = 0x412466 size = 0x14A [[func]] name = "LoadPreL3Dungeon" addr = 0x4125B0 size = 0xA5 [[func]] name = "DRLG_LoadL4SP" addr = 0x412655 size = 0x58 [[func]] name = "DRLG_FreeL4SP" addr = 0x4126AD size = 0x12 [[func]] name = "DRLG_L4SetSPRoom" addr = 0x4126BF size = 0x85 [[func]] name = "L4SaveQuads" addr = 0x412744 size = 0x8F [[func]] name = "DRLG_L4SetRoom" addr = 0x4127D3 size = 0x5E [[func]] name = "DRLG_LoadDiabQuads" addr = 0x412831 size = 0x102 [[func]] name = "IsDURWall" addr = 0x412933 size = 0x15 [[func]] name = "IsDLLWall" addr = 0x412948 size = 0x15 [[func]] name = "L4FixRim" addr = 0x41295D size = 0x1E [[func]] name = "DRLG_L4GeneralFix" addr = 0x41297B size = 0x35 [[func]] name = "CreateL4Dungeon" addr = 0x4129B0 size = 0x50 [[func]] name = "DRLG_L4" addr = 0x412A00 size = 0x3DD [[func]] name = "DRLG_L4Shadows" addr = 0x412DDD size = 0x57 [[func]] name = "InitL4Dungeon" addr = 0x412E34 size = 0x47 [[func]] name = "L4makeDmt" addr = 0x412E7B size = 0x50 [[func]] name = "L4AddWall" addr = 0x412ECB size = 0x2F7 [[func]] name = "L4HWallOk" addr = 0x4131C2 size = 0xAE [[func]] name = "L4VWallOk" addr = 0x413270 size = 0x9B [[func]] name = "L4HorizWall" addr = 0x41330B size = 0xCB [[func]] name = "L4VertWall" addr = 0x4133D6 size = 0xDE [[func]] name = "L4tileFix" addr = 0x4134B4 size = 0xE29 [[func]] name = "DRLG_L4Subs" addr = 0x4142DD size = 0xBD [[func]] name = "L4makeDungeon" addr = 0x41439A size = 0x117 [[func]] name = "uShape" addr = 0x4144B1 size = 0x133 [[func]] name = "GetArea" addr = 0x4145E4 size = 0x22 [[func]] name = "L4firstRoom" addr = 0x414606 size = 0x132 [[func]] name = "L4drawRoom" addr = 0x414738 size = 0x37 [[func]] name = "L4roomGen" addr = 0x41476F size = 0x207 [[func]] name = "L4checkRoom" addr = 0x414976 size = 0x6C [[func]] name = "DRLG_L4PlaceMiniSet" addr = 0x4149E2 size = 0x262 [[func]] name = "DRLG_L4FloodTVal" addr = 0x414C44 size = 0x6F [[func]] name = "DRLG_L4FTVR" addr = 0x414CB3 size = 0x1F0 [[func]] name = "DRLG_L4TransFix" addr = 0x414EA3 size = 0xB8 [[func]] name = "DRLG_L4Corners" addr = 0x414F5B size = 0x35 [[func]] name = "DRLG_L4Pass3" addr = 0x414F90 size = 0x108 [[func]] name = "dthread_remove_player" addr = 0x4150D6 size = 0x33 [[func]] name = "dthread_send_delta" addr = 0x415109 size = 0x7D [[func]] name = "dthread_start" addr = 0x415186 size = 0x6D [[func]] name = "dthread_handler" addr = 0x4151F3 size = 0xCD [[func]] name = "dthread_cleanup" addr = 0x4152C0 size = 0xA2 [[func]] name = "dx_init" addr = 0x4153A0 size = 0x115 [[func]] name = "dx_create_back_buffer" addr = 0x4154B5 size = 0x10D [[func]] name = "dx_create_primary_surface" addr = 0x4155C2 size = 0x58 [[func]] name = "dx_DirectDrawCreate" addr = 0x41561A size = 0x7B [[func]] name = "lock_buf" addr = 0x415695 size = 0x5 [[func]] name = "lock_buf_priv" addr = 0x41569A size = 0x86 [[func]] name = "unlock_buf" addr = 0x415720 size = 0x5 [[func]] name = "unlock_buf_priv" addr = 0x415725 size = 0x7B [[func]] name = "dx_cleanup" addr = 0x4157A0 size = 0xA8 [[func]] name = "dx_reinit" addr = 0x415848 size = 0x5C [[func]] name = "effect_is_playing" addr = 0x4158B9 size = 0x29 [[func]] name = "stream_stop" addr = 0x4158E2 size = 0x29 [[func]] name = "InitMonsterSND" addr = 0x41590B size = 0xD0 [[func]] name = "FreeMonsterSnd" addr = 0x4159DB size = 0x6A [[func]] name = "PlayEffect" addr = 0x415A45 size = 0x9C [[func]] name = "calc_snd_position" addr = 0x415AE1 size = 0x78 [[func]] name = "PlaySFX" addr = 0x415B59 size = 0x18 [[func]] name = "PlaySFX_priv" addr = 0x415B71 size = 0xB9 [[func]] name = "stream_play" addr = 0x415C2A size = 0x6D [[func]] name = "RndSFX" addr = 0x415C97 size = 0x6A [[func]] name = "PlaySfxLoc" addr = 0x415D01 size = 0x38 [[func]] name = "sound_stop" addr = 0x415D39 size = 0x61 [[func]] name = "sfx_stop" addr = 0x415D9A size = 0x20 [[func]] name = "sound_update" addr = 0x415DBA size = 0x16 [[func]] name = "stream_update" addr = 0x415DD0 size = 0x2F [[func]] name = "effects_cleanup_sfx" addr = 0x415DFF size = 0x2B [[func]] name = "sound_init" addr = 0x415E2A size = 0x4D [[func]] name = "priv_sound_init" addr = 0x415E77 size = 0x61 [[func]] name = "ui_sound_init" addr = 0x415ED8 size = 0x7 [[func]] name = "effects_play_sound" addr = 0x415EDF size = 0x64 [[func]] name = "Decrypt" addr = 0x415F43 size = 0x4C [[func]] name = "Encrypt" addr = 0x415F8F size = 0x50 [[func]] name = "Hash" addr = 0x415FDF size = 0x4F [[func]] name = "InitHash" addr = 0x41602E size = 0x6F [[func]] name = "PkwareCompress" addr = 0x41609D size = 0x96 [[func]] name = "PkwareBufferRead" addr = 0x416133 size = 0x34 [[func]] name = "PkwareBufferWrite" addr = 0x416167 size = 0x27 [[func]] name = "PkwareDecompress" addr = 0x41618E size = 0x6E [[func]] name = "CelBlit" addr = 0x41620C size = 0x68 [[func]] name = "CelDraw" addr = 0x416274 size = 0x44 [[func]] name = "CelBlitFrame" addr = 0x4162B8 size = 0x26 [[func]] name = "CelClippedDraw" addr = 0x4162DE size = 0x7B [[func]] name = "CelClippedBlit" addr = 0x416359 size = 0x53 [[func]] name = "CelBlitLight" addr = 0x4163AC size = 0xDC [[func]] name = "CelBlitLightTrans" addr = 0x416488 size = 0xDD [[func]] name = "CelDrawLight" addr = 0x416565 size = 0x58 [[func]] name = "CelClippedDrawLight" addr = 0x4165BD size = 0x8E [[func]] name = "CelClippedBlitLightTrans" addr = 0x41664B size = 0x74 [[func]] name = "CelDrawLightRed" addr = 0x4166BF size = 0x11C [[func]] name = "CelBlitSafe" addr = 0x4167DB size = 0x7F [[func]] name = "CelClippedDrawSafe" addr = 0x41685A size = 0x7B [[func]] name = "CelClippedBlitSafe" addr = 0x4168D5 size = 0x55 [[func]] name = "CelBlitLightSafe" addr = 0x41692A size = 0xF7 [[func]] name = "CelBlitLightTransSafe" addr = 0x416A21 size = 0xF8 [[func]] name = "CelDrawLightSafe" addr = 0x416B19 size = 0x90 [[func]] name = "CelClippedBlitLightTransSafe" addr = 0x416BA9 size = 0x72 [[func]] name = "CelDrawLightRedSafe" addr = 0x416C1B size = 0x121 [[func]] name = "CelBlitWidth" addr = 0x416D3C size = 0x8A [[func]] name = "CelBlitOutline" addr = 0x416DC6 size = 0xFA [[func]] name = "CelBlitOutlineSafe" addr = 0x416EC0 size = 0x12F [[func]] name = "ENG_set_pixel" addr = 0x416FEF size = 0x45 [[func]] name = "engine_draw_pixel" addr = 0x417034 size = 0x89 [[func]] name = "DrawLine" addr = 0x4170BD size = 0x3F6 [[func]] name = "GetDirection" addr = 0x4174B3 size = 0x65 [[func]] name = "SetRndSeed" addr = 0x417518 size = 0x14 [[func]] name = "GetRndSeed" addr = 0x41752C size = 0x1F [[func]] name = "random_" addr = 0x41754B size = 0x22 [[func]] name = "DiabloAllocPtr" addr = 0x41759B size = 0x4D [[func]] name = "mem_free_dbg" addr = 0x4175E8 size = 0x30 [[func]] name = "LoadFileInMem" addr = 0x417618 size = 0x5B [[func]] name = "LoadFileWithMem" addr = 0x417673 size = 0x5F [[func]] name = "Cl2ApplyTrans" addr = 0x4176D2 size = 0x73 [[func]] name = "Cl2Draw" addr = 0x417745 size = 0x7A [[func]] name = "Cl2Blit" addr = 0x4177BF size = 0x88 [[func]] name = "Cl2DrawOutline" addr = 0x417847 size = 0x7E [[func]] name = "Cl2BlitOutline" addr = 0x4178C5 size = 0xBC [[func]] name = "Cl2DrawLightTbl" addr = 0x417981 size = 0xC3 [[func]] name = "Cl2BlitLight" addr = 0x417A44 size = 0xA5 [[func]] name = "Cl2DrawLight" addr = 0x417AE9 size = 0x9A [[func]] name = "Cl2DrawSafe" addr = 0x417B83 size = 0x7A [[func]] name = "Cl2BlitSafe" addr = 0x417BFD size = 0x9C [[func]] name = "Cl2DrawOutlineSafe" addr = 0x417C99 size = 0x8F [[func]] name = "Cl2BlitOutlineSafe" addr = 0x417D28 size = 0xD0 [[func]] name = "Cl2DrawLightTblSafe" addr = 0x417DF8 size = 0xC3 [[func]] name = "Cl2BlitLightSafe" addr = 0x417EBB size = 0xBD [[func]] name = "Cl2DrawLightSafe" addr = 0x417F78 size = 0x9A [[func]] name = "PlayInGameMovie" addr = 0x418012 size = 0x3C [[func]] name = "InitDiabloMsg" addr = 0x41804E size = 0x41 [[func]] name = "ClrDiabloMsg" addr = 0x41808F size = 0x1B [[func]] name = "DrawDiabloMsg" addr = 0x4180AA size = 0x203 [[func]] name = "fault_init_filter" addr = 0x4182B7 size = 0xA [[func]] name = "fault_cleanup_filter_atexit" addr = 0x4182C1 size = 0xC [[func]] name = "fault_cleanup_filter" addr = 0x4182CD size = 0xA [[func]] name = "TopLevelExceptionFilter" addr = 0x4182D7 size = 0x17E [[func]] name = "fault_hex_format" addr = 0x418455 size = 0xC3 [[func]] name = "fault_unknown_module" addr = 0x418518 size = 0xE7 [[func]] name = "fault_call_stack" addr = 0x4185FF size = 0x89 [[func]] name = "fault_get_error_type" addr = 0x418688 size = 0x190 [[func]] name = "fault_set_filter" addr = 0x41883C size = 0x17 [[func]] name = "fault_reset_filter" addr = 0x418853 size = 0xD [[func]] name = "fault_get_filter" addr = 0x418860 size = 0x6 [[func]] name = "gamemenu_on" addr = 0x418866 size = 0x29 [[func]] name = "gamemenu_update_single" addr = 0x41888F size = 0x39 [[func]] name = "gamemenu_update_multi" addr = 0x4188C8 size = 0x10 [[func]] name = "gamemenu_off" addr = 0x4188D8 size = 0x9 [[func]] name = "gamemenu_handle_previous" addr = 0x4188E1 size = 0x13 [[func]] name = "gamemenu_previous" addr = 0x4188F4 size = 0x5 [[func]] name = "gamemenu_new_game" addr = 0x4188F9 size = 0x42 [[func]] name = "gamemenu_quit_game" addr = 0x41893B size = 0xD [[func]] name = "gamemenu_load_game" addr = 0x418948 size = 0x76 [[func]] name = "gamemenu_save_game" addr = 0x4189BE size = 0x84 [[func]] name = "gamemenu_restart_town" addr = 0x418A42 size = 0xA [[func]] name = "gamemenu_options" addr = 0x418A4C size = 0x20 [[func]] name = "gamemenu_get_music" addr = 0x418A6C size = 0x19 [[func]] name = "gamemenu_sound_music_toggle" addr = 0x418A85 size = 0x41 [[func]] name = "gamemenu_get_sound" addr = 0x418AC6 size = 0x19 [[func]] name = "gamemenu_get_color_cycling" addr = 0x418ADF size = 0x15 [[func]] name = "gamemenu_get_gamma" addr = 0x418AF4 size = 0x26 [[func]] name = "gamemenu_music_volume" addr = 0x418B1A size = 0x89 [[func]] name = "gamemenu_slider_music_sound" addr = 0x418BA3 size = 0xD [[func]] name = "gamemenu_sound_volume" addr = 0x418BB0 size = 0x80 [[func]] name = "gamemenu_gamma" addr = 0x418C30 size = 0x2A [[func]] name = "gamemenu_slider_gamma" addr = 0x418C5A size = 0x10 [[func]] name = "gamemenu_color_cycling" addr = 0x418C6A size = 0x21 [[func]] name = "FillSolidBlockTbls" addr = 0x418C8B size = 0x106 [[func]] name = "MakeSpeedCels" addr = 0x418D91 size = 0x42E [[func]] name = "SortTiles" addr = 0x4191BF size = 0x3C [[func]] name = "SwapTile" addr = 0x4191FB size = 0x7F [[func]] name = "IsometricCoord" addr = 0x41927A size = 0x48 [[func]] name = "SetSpeedCels" addr = 0x4192C2 size = 0x49 [[func]] name = "SetDungeonMicros" addr = 0x41930B size = 0x13F [[func]] name = "DRLG_InitTrans" addr = 0x41944A size = 0x2D [[func]] name = "DRLG_MRectTrans" addr = 0x419477 size = 0x59 [[func]] name = "DRLG_RectTrans" addr = 0x4194D0 size = 0x45 [[func]] name = "DRLG_CopyTrans" addr = 0x419515 size = 0x1F [[func]] name = "DRLG_ListTrans" addr = 0x419534 size = 0x31 [[func]] name = "DRLG_AreaTrans" addr = 0x419565 size = 0x3D [[func]] name = "DRLG_InitSetPC" addr = 0x4195A2 size = 0x17 [[func]] name = "DRLG_SetPC" addr = 0x4195B9 size = 0x53 [[func]] name = "Make_SetPC" addr = 0x41960C size = 0x4F [[func]] name = "DRLG_WillThemeRoomFit" addr = 0x41965B size = 0x199 [[func]] name = "DRLG_CreateThemeRoom" addr = 0x4197F4 size = 0x41C [[func]] name = "DRLG_PlaceThemeRooms" addr = 0x419C10 size = 0x182 [[func]] name = "DRLG_HoldThemeRooms" addr = 0x419D92 size = 0x8D [[func]] name = "SkipThemeRoom" addr = 0x419E1F size = 0x52 [[func]] name = "InitLevels" addr = 0x419E71 size = 0x1A [[func]] name = "gmenu_draw_pause" addr = 0x419E8B size = 0x33 [[func]] name = "gmenu_print_text" addr = 0x419EBE size = 0x59 [[func]] name = "FreeGMenu" addr = 0x419F17 size = 0x59 [[func]] name = "gmenu_init_menu" addr = 0x419F70 size = 0x78 [[func]] name = "gmenu_is_active" addr = 0x419FE8 size = 0xC [[func]] name = "gmenu_set_items" addr = 0x419FF4 size = 0x5A [[func]] name = "gmenu_up_down" addr = 0x41A04E size = 0x68 [[func]] name = "gmenu_draw" addr = 0x41A0B6 size = 0x8F [[func]] name = "gmenu_draw_menu_item" addr = 0x41A145 size = 0xF4 [[func]] name = "gmenu_clear_buffer" addr = 0x41A239 size = 0x39 [[func]] name = "gmenu_get_lfont" addr = 0x41A272 size = 0x3C [[func]] name = "gmenu_presskeys" addr = 0x41A2AE size = 0x7C [[func]] name = "gmenu_left_right" addr = 0x41A32A size = 0x50 [[func]] name = "gmenu_on_mouse_move" addr = 0x41A37A size = 0x58 [[func]] name = "gmenu_get_mouse_slider" addr = 0x41A3D2 size = 0x2F [[func]] name = "gmenu_left_mouse" addr = 0x41A401 size = 0xB7 [[func]] name = "gmenu_enable" addr = 0x41A4B8 size = 0xE [[func]] name = "gmenu_slider_set" addr = 0x41A4C6 size = 0x42 [[func]] name = "gmenu_slider_get" addr = 0x41A508 size = 0x3D [[func]] name = "gmenu_slider_steps" addr = 0x41A545 size = 0xE [[func]] name = "InitHelp" addr = 0x41A553 size = 0x12 [[func]] name = "DrawHelp" addr = 0x41A565 size = 0x195 [[func]] name = "DrawHelpLine" addr = 0x41A6FA size = 0x79 [[func]] name = "DisplayHelp" addr = 0x41A773 size = 0x1C [[func]] name = "HelpScrollUp" addr = 0x41A78F size = 0x10 [[func]] name = "HelpScrollDown" addr = 0x41A79F size = 0x14 [[func]] name = "init_cleanup" addr = 0x41A7C3 size = 0x89 [[func]] name = "init_run_office_from_start_menu" addr = 0x41A84C size = 0x6D [[func]] name = "init_run_office" addr = 0x41A8B9 size = 0x173 [[func]] name = "init_disable_screensaver" addr = 0x41AA2C size = 0x99 [[func]] name = "init_create_window" addr = 0x41AAC5 size = 0x13B [[func]] name = "init_kill_mom_parent" addr = 0x41AC00 size = 0x21 [[func]] name = "init_find_mom_parent" addr = 0x41AC21 size = 0x50 [[func]] name = "init_await_mom_parent_exit" addr = 0x41AC71 size = 0x30 [[func]] name = "init_archives" addr = 0x41ACA1 size = 0xD1 [[func]] name = "init_test_access" addr = 0x41AD72 size = 0x1B0 [[func]] name = "init_strip_trailing_slash" addr = 0x41AF22 size = 0x18 [[func]] name = "init_read_test_file" addr = 0x41AF3A size = 0x94 [[func]] name = "init_get_file_info" addr = 0x41AFCE size = 0x9E [[func]] name = "MainWndProc" addr = 0x41B06C size = 0x99 [[func]] name = "init_activate_window" addr = 0x41B105 size = 0x5A [[func]] name = "WindowProc" addr = 0x41B15F size = 0x25 [[func]] name = "SetWindowProc" addr = 0x41B184 size = 0xC [[func]] name = "interface_msg_pump" addr = 0x41B1A0 size = 0x3F [[func]] name = "IncProgress" addr = 0x41B1DF size = 0x39 [[func]] name = "DrawCutscene" addr = 0x41B218 size = 0x75 [[func]] name = "DrawProgress" addr = 0x41B28D size = 0x29 [[func]] name = "ShowProgress" addr = 0x41B2B6 size = 0x317 [[func]] name = "FreeInterface" addr = 0x41B5F5 size = 0x12 [[func]] name = "InitCutscene" addr = 0x41B607 size = 0x1E5 [[func]] name = "FreeInvGFX" addr = 0x41B814 size = 0x12 [[func]] name = "InitInv" addr = 0x41B826 size = 0x4B [[func]] name = "InvDrawSlotBack" addr = 0x41B871 size = 0x53 [[func]] name = "DrawInv" addr = 0x41B8C4 size = 0x79C [[func]] name = "DrawInvBelt" addr = 0x41C060 size = 0x1DF [[func]] name = "AutoPlace" addr = 0x41C23F size = 0x134 [[func]] name = "SpecialAutoPlace" addr = 0x41C373 size = 0x16D [[func]] name = "GoldAutoPlace" addr = 0x41C4E0 size = 0x1C9 [[func]] name = "WeaponAutoPlace" addr = 0x41C6A9 size = 0x9D [[func]] name = "SwapItem" addr = 0x41C746 size = 0x3D [[func]] name = "CheckInvPaste" addr = 0x41C783 size = 0xB2C [[func]] name = "CheckInvSwap" addr = 0x41D2CF size = 0xA9 [[func]] name = "CheckInvCut" addr = 0x41D378 size = 0x373 [[func]] name = "inv_update_rem_item" addr = 0x41D6EB size = 0x37 [[func]] name = "RemoveInvItem" addr = 0x41D722 size = 0xEE [[func]] name = "RemoveSpdBarItem" addr = 0x41D810 size = 0x5C [[func]] name = "CheckInvItem" addr = 0x41D86C size = 0x27 [[func]] name = "CheckInvScrn" addr = 0x41D893 size = 0x2C [[func]] name = "CheckItemStats" addr = 0x41D8BF size = 0x4C [[func]] name = "CheckBookLevel" addr = 0x41D90B size = 0x74 [[func]] name = "CheckQuestItem" addr = 0x41D97F size = 0x1E6 [[func]] name = "InvGetItem" addr = 0x41DB65 size = 0x114 [[func]] name = "AutoGetItem" addr = 0x41DC79 size = 0x48A [[func]] name = "FindGetItem" addr = 0x41E103 size = 0x55 [[func]] name = "SyncGetItem" addr = 0x41E158 size = 0xCA [[func]] name = "CanPut" addr = 0x41E222 size = 0xD7 [[func]] name = "TryInvPut" addr = 0x41E2F9 size = 0xC3 [[func]] name = "DrawInvMsg" addr = 0x41E3BC size = 0x28 [[func]] name = "InvPutItem" addr = 0x41E3E4 size = 0x255 [[func]] name = "SyncPutItem" addr = 0x41E639 size = 0x2A4 [[func]] name = "CheckInvHLight" addr = 0x41E8DD size = 0x20D [[func]] name = "RemoveScroll" addr = 0x41EAEA size = 0xA1 [[func]] name = "UseScroll" addr = 0x41EB8B size = 0xB7 [[func]] name = "UseStaffCharge" addr = 0x41EC42 size = 0x3D [[func]] name = "UseStaff" addr = 0x41EC7F size = 0x44 [[func]] name = "StartGoldDrop" addr = 0x41ECC3 size = 0x66 [[func]] name = "UseInvItem" addr = 0x41ED29 size = 0x278 [[func]] name = "DoTelekinesis" addr = 0x41EFA1 size = 0x72 [[func]] name = "CalculateGold" addr = 0x41F013 size = 0x55 [[func]] name = "DropItemBeforeTrig" addr = 0x41F068 size = 0x2E [[func]] name = "InitItemGFX" addr = 0x41F096 size = 0x52 [[func]] name = "ItemPlace" addr = 0x41F0E8 size = 0x52 [[func]] name = "AddInitItems" addr = 0x41F13A size = 0x114 [[func]] name = "InitItems" addr = 0x41F24E size = 0xD2 [[func]] name = "CalcPlrItemVals" addr = 0x41F320 size = 0x633 [[func]] name = "CalcPlrScrolls" addr = 0x41F953 size = 0xF7 [[func]] name = "CalcPlrStaff" addr = 0x41FA4A size = 0x4D [[func]] name = "CalcSelfItems" addr = 0x41FA97 size = 0xFA [[func]] name = "CalcPlrItemMin" addr = 0x41FB91 size = 0x65 [[func]] name = "ItemMinStats" addr = 0x41FBF6 size = 0x36 [[func]] name = "CalcPlrBookVals" addr = 0x41FC2C size = 0x112 [[func]] name = "CalcPlrInv" addr = 0x41FD3E size = 0x5A [[func]] name = "SetPlrHandItem" addr = 0x41FD98 size = 0x100 [[func]] name = "GetPlrHandSeed" addr = 0x41FE98 size = 0xC [[func]] name = "GetGoldSeed" addr = 0x41FEA4 size = 0x72 [[func]] name = "SetPlrHandSeed" addr = 0x41FF16 size = 0x3 [[func]] name = "SetPlrHandGoldCurs" addr = 0x41FF19 size = 0x35 [[func]] name = "CreatePlrItems" addr = 0x41FF4E size = 0x1AA [[func]] name = "ItemSpaceOk" addr = 0x4200F8 size = 0xFA [[func]] name = "GetItemSpace" addr = 0x4201F2 size = 0xF6 [[func]] name = "GetSuperItemSpace" addr = 0x4202E8 size = 0x8E [[func]] name = "GetSuperItemLoc" addr = 0x420376 size = 0x6A [[func]] name = "CalcItemValue" addr = 0x4203E0 size = 0x4C [[func]] name = "GetBookSpell" addr = 0x42042C size = 0xE8 [[func]] name = "GetStaffPower" addr = 0x420514 size = 0x1D1 [[func]] name = "GetStaffSpell" addr = 0x4206E5 size = 0x165 [[func]] name = "GetItemAttrs" addr = 0x42084A size = 0x2CD [[func]] name = "RndPL" addr = 0x420B17 size = 0x11 [[func]] name = "PLVal" addr = 0x420B28 size = 0x40 [[func]] name = "SaveItemPower" addr = 0x420B68 size = 0x947 [[func]] name = "GetItemPower" addr = 0x4215EF size = 0x32D [[func]] name = "GetItemBonus" addr = 0x42191C size = 0x7C [[func]] name = "SetupItem" addr = 0x4219C1 size = 0x8A [[func]] name = "RndItem" addr = 0x421A4B size = 0xE7 [[func]] name = "RndUItem" addr = 0x421B32 size = 0xF8 [[func]] name = "RndAllItems" addr = 0x421C2A size = 0x8D [[func]] name = "RndTypeItems" addr = 0x421CB7 size = 0x8A [[func]] name = "CheckUnique" addr = 0x421D41 size = 0xD0 [[func]] name = "GetUniqueItem" addr = 0x421E11 size = 0x14B [[func]] name = "SpawnUnique" addr = 0x421F5C size = 0x8A [[func]] name = "ItemRndDur" addr = 0x421FE6 size = 0x3E [[func]] name = "SetupAllItems" addr = 0x422024 size = 0x156 [[func]] name = "SpawnItem" addr = 0x42217A size = 0x116 [[func]] name = "CreateItem" addr = 0x422290 size = 0x9B [[func]] name = "CreateRndItem" addr = 0x42232B size = 0xA5 [[func]] name = "SetupAllUseful" addr = 0x4223D0 size = 0x6D [[func]] name = "CreateRndUseful" addr = 0x42243D size = 0x69 [[func]] name = "CreateTypeItem" addr = 0x4224A6 size = 0xA4 [[func]] name = "RecreateItem" addr = 0x42254A size = 0x112 [[func]] name = "RecreateEar" addr = 0x42265C size = 0x139 [[func]] name = "SpawnQuestItem" addr = 0x422795 size = 0x11C [[func]] name = "SpawnRock" addr = 0x4228B1 size = 0xD8 [[func]] name = "RespawnItem" addr = 0x422989 size = 0xC7 [[func]] name = "DeleteItem" addr = 0x422A50 size = 0x34 [[func]] name = "ItemDoppel" addr = 0x422A84 size = 0x5A [[func]] name = "ProcessItems" addr = 0x422ADE size = 0xD4 [[func]] name = "FreeItemGFX" addr = 0x422BB2 size = 0x1D [[func]] name = "GetItemFrm" addr = 0x422BCF size = 0x21 [[func]] name = "GetItemStr" addr = 0x422BF0 size = 0x73 [[func]] name = "CheckIdentify" addr = 0x422C63 size = 0x39 [[func]] name = "DoRepair" addr = 0x422C9C size = 0x5A [[func]] name = "RepairItem" addr = 0x422CF6 size = 0x76 [[func]] name = "DoRecharge" addr = 0x422D6C size = 0x71 [[func]] name = "RechargeItem" addr = 0x422DDD size = 0x37 [[func]] name = "PrintItemOil" addr = 0x422E14 size = 0x98 [[func]] name = "PrintItemPower" addr = 0x422EF4 size = 0x4FC [[func]] name = "DrawUTextBack" addr = 0x423530 size = 0x5C [[func]] name = "PrintUString" addr = 0x42358C size = 0xCF [[func]] name = "DrawULine" addr = 0x42365B size = 0x4B [[func]] name = "DrawUniqueInfo" addr = 0x4236A6 size = 0x136 [[func]] name = "PrintItemMisc" addr = 0x4237DC size = 0xF8 [[func]] name = "PrintItemDetails" addr = 0x4238D4 size = 0x20D [[func]] name = "PrintItemDur" addr = 0x423AE1 size = 0x1FF [[func]] name = "UseItem" addr = 0x423CE0 size = 0x4F7 [[func]] name = "StoreStatOk" addr = 0x4241D7 size = 0x45 [[func]] name = "SmithItemOk" addr = 0x42421C size = 0x36 [[func]] name = "RndSmithItem" addr = 0x424252 size = 0x6F [[func]] name = "BubbleSwapItem" addr = 0x4242C1 size = 0x34 [[func]] name = "SortSmith" addr = 0x4242F5 size = 0x5C [[func]] name = "SpawnSmith" addr = 0x424351 size = 0xCF [[func]] name = "PremiumItemOk" addr = 0x424420 size = 0x3F [[func]] name = "RndPremiumItem" addr = 0x42445F size = 0x67 [[func]] name = "SpawnOnePremium" addr = 0x4244C6 size = 0xDA [[func]] name = "SpawnPremium" addr = 0x4245A0 size = 0xCC [[func]] name = "WitchItemOk" addr = 0x42466C size = 0x66 [[func]] name = "RndWitchItem" addr = 0x4246D2 size = 0x63 [[func]] name = "SortWitch" addr = 0x424735 size = 0x60 [[func]] name = "WitchBookLevel" addr = 0x424795 size = 0x80 [[func]] name = "SpawnWitch" addr = 0x424815 size = 0x18F [[func]] name = "RndBoyItem" addr = 0x4249A4 size = 0x5F [[func]] name = "SpawnBoy" addr = 0x424A03 size = 0x98 [[func]] name = "HealerItemOk" addr = 0x424A9B size = 0xAE [[func]] name = "RndHealerItem" addr = 0x424B49 size = 0x63 [[func]] name = "SortHealer" addr = 0x424BAC size = 0x60 [[func]] name = "SpawnHealer" addr = 0x424C0C size = 0x14B [[func]] name = "SpawnStoreGold" addr = 0x424D57 size = 0x29 [[func]] name = "RecreateSmithItem" addr = 0x424D80 size = 0x51 [[func]] name = "RecreatePremiumItem" addr = 0x424DD1 size = 0x6B [[func]] name = "RecreateBoyItem" addr = 0x424E3C size = 0x65 [[func]] name = "RecreateWitchItem" addr = 0x424EA1 size = 0xB1 [[func]] name = "RecreateHealerItem" addr = 0x424F52 size = 0x66 [[func]] name = "RecreateTownItem" addr = 0x424FB8 size = 0x67 [[func]] name = "RecalcStoreStats" addr = 0x42501F size = 0xA1 [[func]] name = "ItemNoFlippy" addr = 0x4250C0 size = 0x2F [[func]] name = "CreateSpellBook" addr = 0x4250EF size = 0xC9 [[func]] name = "CreateMagicArmor" addr = 0x4251B8 size = 0xB6 [[func]] name = "CreateMagicWeapon" addr = 0x4251B8 size = 0xB6 [[func]] name = "GetItemRecord" addr = 0x42526E size = 0xA3 [[func]] name = "NextItemRecord" addr = 0x425311 size = 0x46 [[func]] name = "SetItemRecord" addr = 0x425357 size = 0x47 [[func]] name = "PutItemRecord" addr = 0x42539E size = 0xA5 [[func]] name = "RotateRadius" addr = 0x425443 size = 0x77 [[func]] name = "DoLighting" addr = 0x4254BA size = 0x3F6 [[func]] name = "DoUnLight" addr = 0x4258B0 size = 0x80 [[func]] name = "DoUnVision" addr = 0x425930 size = 0x5A [[func]] name = "DoVision" addr = 0x42598A size = 0x289 [[func]] name = "FreeLightTable" addr = 0x425C13 size = 0x12 [[func]] name = "InitLightTable" addr = 0x425C25 size = 0x10 [[func]] name = "MakeLightTable" addr = 0x425C35 size = 0x383 [[func]] name = "InitLightMax" addr = 0x425FB8 size = 0x16 [[func]] name = "InitLighting" addr = 0x425FCE size = 0x1E [[func]] name = "AddLight" addr = 0x425FEC size = 0x6A [[func]] name = "AddUnLight" addr = 0x426056 size = 0x20 [[func]] name = "ChangeLightRadius" addr = 0x426076 size = 0x4F [[func]] name = "ChangeLightXY" addr = 0x4260C5 size = 0x5B [[func]] name = "ChangeLightOff" addr = 0x426120 size = 0x5B [[func]] name = "ChangeLight" addr = 0x42617B size = 0x6C [[func]] name = "ProcessLightList" addr = 0x4261E7 size = 0xF9 [[func]] name = "SavePreLighting" addr = 0x4262E0 size = 0x18 [[func]] name = "InitVision" addr = 0x4262F8 size = 0x3B [[func]] name = "AddVision" addr = 0x426333 size = 0x6D [[func]] name = "ChangeVisionRadius" addr = 0x4263A0 size = 0x41 [[func]] name = "ChangeVisionXY" addr = 0x4263E1 size = 0x4A [[func]] name = "ProcessVisionList" addr = 0x42642B size = 0xF4 [[func]] name = "lighting_color_cycling" addr = 0x42651F size = 0x45 [[func]] name = "LoadGame" addr = 0x426564 size = 0x57E [[func]] name = "BLoad" addr = 0x426AE2 size = 0xE [[func]] name = "WLoad" addr = 0x426AF0 size = 0x3C [[func]] name = "ILoad" addr = 0x426B2C size = 0x3C [[func]] name = "OLoad" addr = 0x426B68 size = 0x17 [[func]] name = "LoadPlayer" addr = 0x426B7F size = 0x2A [[func]] name = "LoadMonster" addr = 0x426BA9 size = 0x35 [[func]] name = "LoadMissile" addr = 0x426BDE size = 0x2A [[func]] name = "LoadObject" addr = 0x426C08 size = 0x22 [[func]] name = "LoadItem" addr = 0x426C2A size = 0x35 [[func]] name = "LoadPremium" addr = 0x426C5F size = 0x2A [[func]] name = "LoadQuest" addr = 0x426C89 size = 0x55 [[func]] name = "LoadLighting" addr = 0x426CDE size = 0x22 [[func]] name = "LoadVision" addr = 0x426D00 size = 0x22 [[func]] name = "LoadPortal" addr = 0x426D22 size = 0x23 [[func]] name = "SaveGame" addr = 0x426D45 size = 0x4BE [[func]] name = "BSave" addr = 0x427203 size = 0xE [[func]] name = "WSave" addr = 0x427211 size = 0x47 [[func]] name = "ISave" addr = 0x427258 size = 0x47 [[func]] name = "OSave" addr = 0x42729F size = 0x18 [[func]] name = "SavePlayer" addr = 0x4272B7 size = 0x2A [[func]] name = "SaveMonster" addr = 0x4272E1 size = 0x2A [[func]] name = "SaveMissile" addr = 0x42730B size = 0x2A [[func]] name = "SaveObject" addr = 0x427335 size = 0x22 [[func]] name = "SaveItem" addr = 0x427357 size = 0x2A [[func]] name = "SavePremium" addr = 0x427381 size = 0x2A [[func]] name = "SaveQuest" addr = 0x4273AB size = 0x59 [[func]] name = "SaveLighting" addr = 0x427404 size = 0x22 [[func]] name = "SaveVision" addr = 0x427426 size = 0x22 [[func]] name = "SavePortal" addr = 0x427448 size = 0x23 [[func]] name = "SaveLevel" addr = 0x42746B size = 0x2C4 [[func]] name = "LoadLevel" addr = 0x42772F size = 0x2C3 [[func]] name = "log_flush" addr = 0x427A30 size = 0x92 [[func]] name = "log_create" addr = 0x427AC2 size = 0x156 [[func]] name = "log_get_version" addr = 0x427C18 size = 0xB1 [[func]] name = "log_printf" addr = 0x427CC9 size = 0xAC [[func]] name = "log_dump_computer_info" addr = 0x427D75 size = 0x99 [[func]] name = "mainmenu_refresh_music" addr = 0x427E1E size = 0x27 [[func]] name = "mainmenu_change_name" addr = 0x427E45 size = 0x1D [[func]] name = "mainmenu_select_hero_dialog" addr = 0x427E62 size = 0x114 [[func]] name = "mainmenu_loop" addr = 0x427F76 size = 0x76 [[func]] name = "mainmenu_single_player" addr = 0x427FEC size = 0xE [[func]] name = "mainmenu_init_menu" addr = 0x427FFA size = 0x36 [[func]] name = "mainmenu_multi_player" addr = 0x428030 size = 0xF [[func]] name = "mainmenu_play_intro" addr = 0x42803F size = 0x17 [[func]] name = "FreeQuestText" addr = 0x428056 size = 0x24 [[func]] name = "InitQuestText" addr = 0x42807A size = 0x2A [[func]] name = "InitQTextMsg" addr = 0x4280A4 size = 0x60 [[func]] name = "DrawQTextBack" addr = 0x428104 size = 0x5C [[func]] name = "PrintQTextChr" addr = 0x428160 size = 0xA2 [[func]] name = "DrawQText" addr = 0x428202 size = 0x1BE [[func]] name = "GetDamageAmt" addr = 0x4283C0 size = 0x4F1 [[func]] name = "CheckBlock" addr = 0x428921 size = 0x59 [[func]] name = "FindClosest" addr = 0x42897A size = 0x11F [[func]] name = "GetSpellLevel" addr = 0x428A99 size = 0x2B [[func]] name = "GetDirection8" addr = 0x428AC4 size = 0x62A [[func]] name = "GetDirection16" addr = 0x4290EE size = 0x690 [[func]] name = "DeleteMissile" addr = 0x42977E size = 0x70 [[func]] name = "GetMissileVel" addr = 0x4297EE size = 0xBF [[func]] name = "PutMissile" addr = 0x4298AD size = 0x6B [[func]] name = "GetMissilePos" addr = 0x429918 size = 0xD2 [[func]] name = "MoveMissilePos" addr = 0x4299EA size = 0x8F [[func]] name = "MonsterTrapHit" addr = 0x429A99 size = 0x1A2 [[func]] name = "MonsterMHit" addr = 0x429C3B size = 0x313 [[func]] name = "PlayerMHit" addr = 0x429F4E size = 0x3B9 [[func]] name = "Plr2PlrMHit" addr = 0x42A307 size = 0x2D4 [[func]] name = "CheckMissileCol" addr = 0x42A5DB size = 0x2FA [[func]] name = "SetMissAnim" addr = 0x42A8D5 size = 0x84 [[func]] name = "SetMissDir" addr = 0x42A959 size = 0x1A [[func]] name = "LoadMissileGFX" addr = 0x42A973 size = 0xE9 [[func]] name = "InitMissileGFX" addr = 0x42AA5C size = 0x2D [[func]] name = "FreeMissileGFX" addr = 0x42AA89 size = 0x69 [[func]] name = "FreeMissiles" addr = 0x42AAF2 size = 0x2E [[func]] name = "FreeMissiles2" addr = 0x42AB20 size = 0x2E [[func]] name = "InitMissiles" addr = 0x42AB4E size = 0xBE [[func]] name = "AddLArrow" addr = 0x42AC0C size = 0xCD [[func]] name = "AddArrow" addr = 0x42ACD9 size = 0xD1 [[func]] name = "GetVileMissPos" addr = 0x42ADAA size = 0x9E [[func]] name = "AddRndTeleport" addr = 0x42AE48 size = 0x143 [[func]] name = "AddFirebolt" addr = 0x42AF8B size = 0x10F [[func]] name = "AddMagmaball" addr = 0x42B09A size = 0x79 [[func]] name = "miss_null_33" addr = 0x42B113 size = 0x46 [[func]] name = "AddTeleport" addr = 0x42B159 size = 0x12B [[func]] name = "AddLightball" addr = 0x42B284 size = 0x7F [[func]] name = "AddFirewall" addr = 0x42B303 size = 0xBD [[func]] name = "AddFireball" addr = 0x42B3C0 size = 0x127 [[func]] name = "AddLightctrl" addr = 0x42B4E7 size = 0x6C [[func]] name = "AddLightning" addr = 0x42B553 size = 0xCD [[func]] name = "AddMisexp" addr = 0x42B620 size = 0xF1 [[func]] name = "AddWeapexp" addr = 0x42B711 size = 0x6B [[func]] name = "CheckIfTrig" addr = 0x42B77C size = 0x63 [[func]] name = "AddTown" addr = 0x42B7DF size = 0x21D [[func]] name = "AddFlash" addr = 0x42B9FC size = 0xC5 [[func]] name = "AddFlash2" addr = 0x42BAC1 size = 0xC2 [[func]] name = "AddManashield" addr = 0x42BB83 size = 0x77 [[func]] name = "AddFiremove" addr = 0x42BBFA size = 0x7C [[func]] name = "AddGuardian" addr = 0x42BC76 size = 0x222 [[func]] name = "AddChain" addr = 0x42BE98 size = 0x33 [[func]] name = "miss_null_11" addr = 0x42BECB size = 0x33 [[func]] name = "miss_null_12" addr = 0x42BEFE size = 0x3D [[func]] name = "miss_null_13" addr = 0x42BF3B size = 0x3F [[func]] name = "AddRhino" addr = 0x42BF7A size = 0x111 [[func]] name = "miss_null_32" addr = 0x42C08B size = 0xDC [[func]] name = "AddFlare" addr = 0x42C167 size = 0x10F [[func]] name = "AddAcid" addr = 0x42C276 size = 0x78 [[func]] name = "miss_null_1D" addr = 0x42C2EE size = 0x3C [[func]] name = "AddAcidpud" addr = 0x42C32A size = 0x64 [[func]] name = "AddStone" addr = 0x42C38E size = 0x18A [[func]] name = "AddGolem" addr = 0x42C518 size = 0xC2 [[func]] name = "AddEtherealize" addr = 0x42C5DA size = 0x8A [[func]] name = "miss_null_1F" addr = 0x42C664 size = 0x13 [[func]] name = "miss_null_23" addr = 0x42C677 size = 0x62 [[func]] name = "AddBoom" addr = 0x42C6D9 size = 0x53 [[func]] name = "AddHeal" addr = 0x42C72C size = 0xE0 [[func]] name = "AddHealOther" addr = 0x42C80C size = 0x33 [[func]] name = "AddElement" addr = 0x42C83F size = 0x103 [[func]] name = "AddIdentify" addr = 0x42C942 size = 0x51 [[func]] name = "AddFirewallC" addr = 0x42C993 size = 0x162 [[func]] name = "AddInfra" addr = 0x42CAF5 size = 0x67 [[func]] name = "AddWave" addr = 0x42CB5C size = 0x4B [[func]] name = "AddNova" addr = 0x42CBA7 size = 0xF1 [[func]] name = "AddRepair" addr = 0x42CC98 size = 0x51 [[func]] name = "AddRecharge" addr = 0x42CCE9 size = 0x51 [[func]] name = "AddDisarm" addr = 0x42CD3A size = 0x33 [[func]] name = "AddApoca" addr = 0x42CD6D size = 0xC5 [[func]] name = "AddFlame" addr = 0x42CE32 size = 0x103 [[func]] name = "AddFlamec" addr = 0x42CF35 size = 0x78 [[func]] name = "AddCbolt" addr = 0x42CFAD size = 0xEB [[func]] name = "AddHbolt" addr = 0x42D098 size = 0xE0 [[func]] name = "AddResurrect" addr = 0x42D178 size = 0x37 [[func]] name = "AddResurrectBeam" addr = 0x42D1AF size = 0x44 [[func]] name = "AddTelekinesis" addr = 0x42D1F3 size = 0x33 [[func]] name = "AddBoneSpirit" addr = 0x42D226 size = 0xEB [[func]] name = "AddRportal" addr = 0x42D311 size = 0x4A [[func]] name = "AddDiabApoca" addr = 0x42D35B size = 0x7F [[func]] name = "AddMissile" addr = 0x42D3DA size = 0x1C9 [[func]] name = "Sentfire" addr = 0x42D5A3 size = 0xDC [[func]] name = "MI_Dummy" addr = 0x42D67F size = 0x1 [[func]] name = "MI_Golem" addr = 0x42D680 size = 0x147 [[func]] name = "MI_SetManashield" addr = 0x42D7C7 size = 0xB [[func]] name = "MI_LArrow" addr = 0x42D7D2 size = 0x2FE [[func]] name = "MI_Arrow" addr = 0x42DAD0 size = 0xD1 [[func]] name = "MI_Firebolt" addr = 0x42DBA1 size = 0x2B9 [[func]] name = "MI_Lightball" addr = 0x42DE5A size = 0xE8 [[func]] name = "mi_null_33" addr = 0x42DF42 size = 0x69 [[func]] name = "MI_Acidpud" addr = 0x42DFAB size = 0x73 [[func]] name = "MI_Firewall" addr = 0x42E01E size = 0x171 [[func]] name = "MI_Fireball" addr = 0x42E18F size = 0x418 [[func]] name = "MI_Lightctrl" addr = 0x42E5A7 size = 0x1F4 [[func]] name = "MI_Lightning" addr = 0x42E79B size = 0x85 [[func]] name = "MI_Town" addr = 0x42E820 size = 0x1AB [[func]] name = "MI_Flash" addr = 0x42E9CB size = 0x126 [[func]] name = "MI_Flash2" addr = 0x42EAF1 size = 0xCE [[func]] name = "MI_Manashield" addr = 0x42EBBF size = 0x25A [[func]] name = "MI_Etherealize" addr = 0x42EE19 size = 0xE4 [[func]] name = "MI_Firemove" addr = 0x42EEFD size = 0x1CB [[func]] name = "MI_Guardian" addr = 0x42F0C8 size = 0x1FA [[func]] name = "MI_Chain" addr = 0x42F2C2 size = 0x1B3 [[func]] name = "mi_null_11" addr = 0x42F475 size = 0x34 [[func]] name = "MI_Weapexp" addr = 0x42F4A9 size = 0x12D [[func]] name = "MI_Misexp" addr = 0x42F5D6 size = 0xBC [[func]] name = "MI_Acidsplat" addr = 0x42F692 size = 0x91 [[func]] name = "MI_Teleport" addr = 0x42F723 size = 0x109 [[func]] name = "MI_Stone" addr = 0x42F82C size = 0xC2 [[func]] name = "MI_Boom" addr = 0x42F8EE size = 0x61 [[func]] name = "MI_Rhino" addr = 0x42F94F size = 0x181 [[func]] name = "mi_null_32" addr = 0x42FAD0 size = 0x1A4 [[func]] name = "MI_FirewallC" addr = 0x42FC74 size = 0x16F [[func]] name = "MI_Infra" addr = 0x42FDE3 size = 0x3D [[func]] name = "MI_Apoca" addr = 0x42FE20 size = 0xEB [[func]] name = "MI_Wave" addr = 0x42FF0B size = 0x249 [[func]] name = "MI_Nova" addr = 0x430154 size = 0x153 [[func]] name = "MI_Blodboil" addr = 0x4302A7 size = 0x11 [[func]] name = "MI_Flame" addr = 0x4302B8 size = 0xC6 [[func]] name = "MI_Flamec" addr = 0x43037E size = 0xDE [[func]] name = "MI_Cbolt" addr = 0x43045C size = 0x186 [[func]] name = "MI_Hbolt" addr = 0x4305E2 size = 0x13D [[func]] name = "MI_Element" addr = 0x43071F size = 0x379 [[func]] name = "MI_Bonespirit" addr = 0x430A98 size = 0x1F5 [[func]] name = "MI_ResurrectBeam" addr = 0x430C8D size = 0x1F [[func]] name = "MI_Rportal" addr = 0x430CAC size = 0x12E [[func]] name = "ProcessMissiles" addr = 0x430DDA size = 0x15B [[func]] name = "missiles_process_charge" addr = 0x430F35 size = 0x84 [[func]] name = "ClearMissileSpot" addr = 0x430FB9 size = 0x26 [[func]] name = "InitMonsterTRN" addr = 0x430FEF size = 0x8C [[func]] name = "InitLevelMonsters" addr = 0x43107B size = 0x54 [[func]] name = "AddMonsterType" addr = 0x4310CF size = 0x80 [[func]] name = "GetLevelMTypes" addr = 0x43114F size = 0x2AA [[func]] name = "InitMonsterGFX" addr = 0x4313F9 size = 0x2B5 [[func]] name = "ClearMVars" addr = 0x4316AE size = 0x39 [[func]] name = "InitMonster" addr = 0x4316E7 size = 0x384 [[func]] name = "ClrAllMonsters" addr = 0x431A6B size = 0xA5 [[func]] name = "MonstPlace" addr = 0x431B10 size = 0x4D [[func]] name = "PlaceMonster" addr = 0x431B5D size = 0x3C [[func]] name = "PlaceUniqueMonst" addr = 0x431B99 size = 0x4EF [[func]] name = "PlaceQuestMonsters" addr = 0x432088 size = 0x272 [[func]] name = "PlaceGroup" addr = 0x4322FA size = 0x28B [[func]] name = "LoadDiabMonsts" addr = 0x432585 size = 0xB2 [[func]] name = "InitMonsters" addr = 0x432637 size = 0x206 [[func]] name = "PlaceUniques" addr = 0x43283D size = 0xD1 [[func]] name = "SetMapMonsters" addr = 0x43290E size = 0x13F [[func]] name = "DeleteMonster" addr = 0x432A4D size = 0x24 [[func]] name = "AddMonster" addr = 0x432A71 size = 0x50 [[func]] name = "NewMonsterAnim" addr = 0x432AC1 size = 0x3E [[func]] name = "M_Ranged" addr = 0x432AFF size = 0x27 [[func]] name = "M_Talker" addr = 0x432B26 size = 0x36 [[func]] name = "M_Enemy" addr = 0x432B5C size = 0x2B9 [[func]] name = "M_GetDir" addr = 0x432E15 size = 0x28 [[func]] name = "M_CheckEFlag" addr = 0x432E3D size = 0x60 [[func]] name = "M_StartStand" addr = 0x432E9D size = 0x8C [[func]] name = "M_StartDelay" addr = 0x432F29 size = 0x26 [[func]] name = "M_StartSpStand" addr = 0x432F4F size = 0x6D [[func]] name = "M_StartWalk" addr = 0x432FBC size = 0xD3 [[func]] name = "M_StartWalk2" addr = 0x43308F size = 0x11B [[func]] name = "M_StartWalk3" addr = 0x4331AA size = 0x14C [[func]] name = "M_StartAttack" addr = 0x4332F6 size = 0x71 [[func]] name = "M_StartRAttack" addr = 0x433367 size = 0x88 [[func]] name = "M_StartRSpAttack" addr = 0x4333EF size = 0x91 [[func]] name = "M_StartSpAttack" addr = 0x433480 size = 0x74 [[func]] name = "M_StartEat" addr = 0x4334F4 size = 0x68 [[func]] name = "M_ClearSquares" addr = 0x43355C size = 0xBF [[func]] name = "M_GetKnockback" addr = 0x43361B size = 0xCA [[func]] name = "M_StartHit" addr = 0x4336E5 size = 0x175 [[func]] name = "M_DiabloDeath" addr = 0x43385A size = 0x1F2 [[func]] name = "M2MStartHit" addr = 0x433A4C size = 0x180 [[func]] name = "MonstStartKill" addr = 0x433BCC size = 0x1F6 [[func]] name = "M2MStartKill" addr = 0x433DC2 size = 0x205 [[func]] name = "M_StartKill" addr = 0x433FC7 size = 0x7E [[func]] name = "M_SyncStartKill" addr = 0x434045 size = 0x9B [[func]] name = "M_StartFadein" addr = 0x4340E0 size = 0xCD [[func]] name = "M_StartFadeout" addr = 0x4341AD size = 0xC5 [[func]] name = "M_StartHeal" addr = 0x434272 size = 0x98 [[func]] name = "M_ChangeLightOffset" addr = 0x43430A size = 0x6A [[func]] name = "M_DoStand" addr = 0x434374 size = 0x7F [[func]] name = "M_DoWalk" addr = 0x4343F3 size = 0x116 [[func]] name = "M_DoWalk2" addr = 0x434509 size = 0xF3 [[func]] name = "M_DoWalk3" addr = 0x4345FC size = 0x126 [[func]] name = "M_TryM2MHit" addr = 0x434722 size = 0x10A [[func]] name = "M_TryH2HHit" addr = 0x43482C size = 0x40F [[func]] name = "M_DoAttack" addr = 0x434C3B size = 0x182 [[func]] name = "M_DoRAttack" addr = 0x434DBD size = 0xF5 [[func]] name = "M_DoRSpAttack" addr = 0x434EB2 size = 0x115 [[func]] name = "M_DoSAttack" addr = 0x434FC7 size = 0xB7 [[func]] name = "M_DoFadein" addr = 0x43507E size = 0x65 [[func]] name = "M_DoFadeout" addr = 0x4350E3 size = 0x82 [[func]] name = "M_DoHeal" addr = 0x435165 size = 0x90 [[func]] name = "M_DoTalk" addr = 0x4351F5 size = 0x285 [[func]] name = "M_Teleport" addr = 0x43547A size = 0x141 [[func]] name = "M_DoGotHit" addr = 0x4355BB size = 0x63 [[func]] name = "M_UpdateLeader" addr = 0x43561E size = 0x79 [[func]] name = "DoEnding" addr = 0x435697 size = 0xC5 [[func]] name = "PrepDoEnding" addr = 0x43575C size = 0x83 [[func]] name = "M_DoDeath" addr = 0x4357DF size = 0x10D [[func]] name = "M_DoSpStand" addr = 0x4358EC size = 0x7F [[func]] name = "M_DoDelay" addr = 0x43596B size = 0xA9 [[func]] name = "M_DoStone" addr = 0x435A14 size = 0x4E [[func]] name = "M_WalkDir" addr = 0x435A62 size = 0x133 [[func]] name = "GroupUnity" addr = 0x435BB5 size = 0x1F3 [[func]] name = "M_CallWalk" addr = 0x435DA8 size = 0x10D [[func]] name = "M_PathWalk" addr = 0x435EB5 size = 0x80 [[func]] name = "M_CallWalk2" addr = 0x435F35 size = 0x85 [[func]] name = "M_DumbWalk" addr = 0x435FBA size = 0x21 [[func]] name = "M_RoundWalk" addr = 0x435FDB size = 0xD6 [[func]] name = "MAI_Zombie" addr = 0x4360B1 size = 0x146 [[func]] name = "MAI_SkelSd" addr = 0x4361F7 size = 0x13A [[func]] name = "MAI_Path" addr = 0x436331 size = 0xC8 [[func]] name = "MAI_Snake" addr = 0x4363F9 size = 0x296 [[func]] name = "MAI_Bat" addr = 0x43668F size = 0x268 [[func]] name = "MAI_SkelBow" addr = 0x4368F7 size = 0x141 [[func]] name = "MAI_Fat" addr = 0x436A38 size = 0x128 [[func]] name = "MAI_Sneak" addr = 0x436B60 size = 0x268 [[func]] name = "MAI_Fireman" addr = 0x436DC8 size = 0x224 [[func]] name = "MAI_Fallen" addr = 0x436FEC size = 0x1EB [[func]] name = "MAI_Cleaver" addr = 0x4371D7 size = 0xAE [[func]] name = "MAI_Round" addr = 0x437285 size = 0x29B [[func]] name = "MAI_GoatMc" addr = 0x437520 size = 0x8 [[func]] name = "MAI_Ranged" addr = 0x437528 size = 0x18B [[func]] name = "MAI_GoatBow" addr = 0x4376B3 size = 0xA [[func]] name = "MAI_Succ" addr = 0x4376BD size = 0xB [[func]] name = "MAI_AcidUniq" addr = 0x4376C8 size = 0xB [[func]] name = "MAI_Scav" addr = 0x4376D3 size = 0x284 [[func]] name = "MAI_Garg" addr = 0x437957 size = 0x134 [[func]] name = "MAI_RoundRanged" addr = 0x437A8B size = 0x308 [[func]] name = "MAI_Magma" addr = 0x437D93 size = 0xF [[func]] name = "MAI_Storm" addr = 0x437DA2 size = 0xF [[func]] name = "MAI_Acid" addr = 0x437DB1 size = 0xF [[func]] name = "MAI_Diablo" addr = 0x437DC0 size = 0xF [[func]] name = "MAI_RR2" addr = 0x437DCF size = 0x30F [[func]] name = "MAI_Mega" addr = 0x4380DE size = 0xB [[func]] name = "MAI_Golum" addr = 0x4380E9 size = 0x21B [[func]] name = "MAI_SkelKing" addr = 0x438304 size = 0x329 [[func]] name = "MAI_Rhino" addr = 0x43862D size = 0x2F2 [[func]] name = "MAI_Counselor" addr = 0x43891F size = 0x35A [[func]] name = "MAI_Garbud" addr = 0x438C79 size = 0x105 [[func]] name = "MAI_Zhar" addr = 0x438D7E size = 0x144 [[func]] name = "MAI_SnotSpil" addr = 0x438EC2 size = 0x154 [[func]] name = "MAI_Lazurus" addr = 0x439016 size = 0x180 [[func]] name = "MAI_Lazhelp" addr = 0x439196 size = 0xBD [[func]] name = "MAI_Lachdanan" addr = 0x439253 size = 0xE5 [[func]] name = "MAI_Warlord" addr = 0x439338 size = 0xE1 [[func]] name = "DeleteMonsterList" addr = 0x439419 size = 0x65 [[func]] name = "ProcessMonsters" addr = 0x43947E size = 0x2FF [[func]] name = "FreeMonsters" addr = 0x4397C5 size = 0x6C [[func]] name = "DirOK" addr = 0x439831 size = 0x201 [[func]] name = "PosOkMissile" addr = 0x439A32 size = 0x25 [[func]] name = "CheckNoSolid" addr = 0x439A57 size = 0x1A [[func]] name = "LineClearF" addr = 0x439A71 size = 0x16F [[func]] name = "LineClear" addr = 0x439BE0 size = 0x1A [[func]] name = "LineClearF1" addr = 0x439BFA size = 0x17B [[func]] name = "SyncMonsterAnim" addr = 0x439D75 size = 0xEB [[func]] name = "M_FallenFear" addr = 0x439EA8 size = 0xEA [[func]] name = "PrintMonstHistory" addr = 0x439F92 size = 0x1A8 [[func]] name = "PrintUniqueHistory" addr = 0x43A13A size = 0x87 [[func]] name = "MissToMonst" addr = 0x43A1C1 size = 0x29D [[func]] name = "PosOkMonst" addr = 0x43A45E size = 0xE9 [[func]] name = "PosOkMonst2" addr = 0x43A547 size = 0xCC [[func]] name = "PosOkMonst3" addr = 0x43A613 size = 0x128 [[func]] name = "IsSkel" addr = 0x43A73B size = 0x25 [[func]] name = "IsGoat" addr = 0x43A760 size = 0x1B [[func]] name = "M_SpawnSkel" addr = 0x43A77B size = 0xAD [[func]] name = "ActivateSpawn" addr = 0x43A828 size = 0x51 [[func]] name = "SpawnSkeleton" addr = 0x43A879 size = 0x100 [[func]] name = "PreSpawnSkeleton" addr = 0x43A979 size = 0x93 [[func]] name = "TalktoMonster" addr = 0x43AA0C size = 0xCE [[func]] name = "SpawnGolum" addr = 0x43AADA size = 0x132 [[func]] name = "CanTalkToMonst" addr = 0x43AC0C size = 0x37 [[func]] name = "CheckMonsterHit" addr = 0x43AC43 size = 0x72 [[func]] name = "encode_enemy" addr = 0x43ACB5 size = 0x19 [[func]] name = "decode_enemy" addr = 0x43ACCE size = 0x65 [[func]] name = "play_movie" addr = 0x43AD43 size = 0xFB [[func]] name = "MovieWndProc" addr = 0x43AE3E size = 0x52 [[func]] name = "mpqapi_set_hidden" addr = 0x43AEA0 size = 0x3C [[func]] name = "mpqapi_store_creation_time" addr = 0x43AEDC size = 0x73 [[func]] name = "mpqapi_reg_load_modification_time" addr = 0x43AF4F size = 0x56 [[func]] name = "mpqapi_xor_buf" addr = 0x43AFA5 size = 0x1F [[func]] name = "mpqapi_reg_store_modification_time" addr = 0x43AFC4 size = 0x39 [[func]] name = "mpqapi_remove_hash_entry" addr = 0x43B002 size = 0x52 [[func]] name = "mpqapi_alloc_block" addr = 0x43B054 size = 0x90 [[func]] name = "mpqapi_new_block" addr = 0x43B0E4 size = 0x3F [[func]] name = "FetchHandle" addr = 0x43B123 size = 0x30 [[func]] name = "mpqapi_get_hash_index" addr = 0x43B153 size = 0x6A [[func]] name = "mpqapi_remove_hash_entries" addr = 0x43B1BD size = 0x3B [[func]] name = "mpqapi_write_file" addr = 0x43B1F8 size = 0x45 [[func]] name = "mpqapi_add_file" addr = 0x43B23D size = 0xDA [[func]] name = "mpqapi_write_file_contents" addr = 0x43B317 size = 0x205 [[func]] name = "mpqapi_find_free_block" addr = 0x43B51C size = 0x54 [[func]] name = "mpqapi_rename" addr = 0x43B570 size = 0x3F [[func]] name = "mpqapi_has_file" addr = 0x43B5AF size = 0x10 [[func]] name = "OpenMPQ" addr = 0x43B5BF size = 0x1D2 [[func]] name = "ParseMPQHeader" addr = 0x43B791 size = 0xF1 [[func]] name = "CloseMPQ" addr = 0x43B882 size = 0x7B [[func]] name = "mpqapi_store_modified_time" addr = 0x43B8FD size = 0x73 [[func]] name = "mpqapi_flush_and_close" addr = 0x43B970 size = 0x5A [[func]] name = "WriteMPQHeader" addr = 0x43B9CA size = 0x96 [[func]] name = "mpqapi_write_block_table" addr = 0x43BA60 size = 0x8B [[func]] name = "mpqapi_write_hash_table" addr = 0x43BAEB size = 0x8E [[func]] name = "mpqapi_can_seek" addr = 0x43BB79 size = 0x2B [[func]] name = "msg_send_drop_pkt" addr = 0x43BBB4 size = 0x1B [[func]] name = "msg_send_packet" addr = 0x43BBCF size = 0x62 [[func]] name = "msg_get_next_packet" addr = 0x43BC31 size = 0x3C [[func]] name = "msg_wait_resync" addr = 0x43BC6D size = 0x80 [[func]] name = "msg_free_packets" addr = 0x43BCED size = 0x2C [[func]] name = "msg_wait_for_turns" addr = 0x43BD19 size = 0xD2 [[func]] name = "run_delta_info" addr = 0x43BDEB size = 0x22 [[func]] name = "msg_pre_packet" addr = 0x43BE0D size = 0x67 [[func]] name = "DeltaExportData" addr = 0x43BE74 size = 0xB7 [[func]] name = "DeltaExportItem" addr = 0x43BF2B size = 0x30 [[func]] name = "DeltaExportObject" addr = 0x43BF5B size = 0x14 [[func]] name = "DeltaExportMonster" addr = 0x43BF6F size = 0x32 [[func]] name = "DeltaExportJunk" addr = 0x43BFA1 size = 0x78 [[func]] name = "msg_comp_level" addr = 0x43C019 size = 0x1C [[func]] name = "delta_init" addr = 0x43C035 size = 0x47 [[func]] name = "delta_kill_monster" addr = 0x43C07C size = 0x46 [[func]] name = "delta_monster_hp" addr = 0x43C0C2 size = 0x30 [[func]] name = "delta_sync_monster" addr = 0x43C0F2 size = 0x42 [[func]] name = "delta_sync_golem" addr = 0x43C134 size = 0x49 [[func]] name = "delta_leave_sync" addr = 0x43C17D size = 0xD2 [[func]] name = "delta_portal_inited" addr = 0x43C24F size = 0xE [[func]] name = "delta_quest_inited" addr = 0x43C25D size = 0xE [[func]] name = "DeltaAddItem" addr = 0x43C26B size = 0x107 [[func]] name = "DeltaSaveLevel" addr = 0x43C372 size = 0x48 [[func]] name = "DeltaLoadLevel" addr = 0x43C3BA size = 0x4B9 [[func]] name = "NetSendCmd" addr = 0x43C873 size = 0x1E [[func]] name = "NetSendCmdGolem" addr = 0x43C891 size = 0x36 [[func]] name = "NetSendCmdLoc" addr = 0x43C8C7 size = 0x2C [[func]] name = "NetSendCmdLocParam1" addr = 0x43C8F3 size = 0x35 [[func]] name = "NetSendCmdLocParam2" addr = 0x43C928 size = 0x3D [[func]] name = "NetSendCmdLocParam3" addr = 0x43C965 size = 0x46 [[func]] name = "NetSendCmdParam1" addr = 0x43C9AB size = 0x28 [[func]] name = "NetSendCmdParam2" addr = 0x43C9D3 size = 0x31 [[func]] name = "NetSendCmdParam3" addr = 0x43CA04 size = 0x39 [[func]] name = "NetSendCmdQuest" addr = 0x43CA3D size = 0x47 [[func]] name = "NetSendCmdGItem" addr = 0x43CA84 size = 0x185 [[func]] name = "NetSendCmdGItem2" addr = 0x43CC09 size = 0x6B [[func]] name = "NetSendCmdReq2" addr = 0x43CC74 size = 0x5B [[func]] name = "NetSendCmdExtra" addr = 0x43CCCF size = 0x29 [[func]] name = "NetSendCmdPItem" addr = 0x43CCF8 size = 0x163 [[func]] name = "NetSendCmdChItem" addr = 0x43CE5B size = 0x57 [[func]] name = "NetSendCmdDelItem" addr = 0x43CEB2 size = 0x22 [[func]] name = "NetSendCmdDItem" addr = 0x43CED4 size = 0x165 [[func]] name = "NetSendCmdDamage" addr = 0x43D039 size = 0x2B [[func]] name = "NetSendCmdString" addr = 0x43D064 size = 0x39 [[func]] name = "delta_close_portal" addr = 0x43D09D size = 0x1F [[func]] name = "ParseCmd" addr = 0x43D0BC size = 0x33F [[func]] name = "On_DLEVEL" addr = 0x43D56F size = 0xC3 [[func]] name = "DeltaImportData" addr = 0x43D632 size = 0x88 [[func]] name = "DeltaImportItem" addr = 0x43D6BA size = 0x3B [[func]] name = "DeltaImportObject" addr = 0x43D6F5 size = 0x14 [[func]] name = "DeltaImportMonster" addr = 0x43D709 size = 0x3D [[func]] name = "DeltaImportJunk" addr = 0x43D746 size = 0xAB [[func]] name = "On_SYNCDATA" addr = 0x43D7F1 size = 0xB [[func]] name = "On_WALKXY" addr = 0x43D7FC size = 0x4E [[func]] name = "On_ADDSTR" addr = 0x43D84A size = 0x31 [[func]] name = "On_ADDMAG" addr = 0x43D87B size = 0x31 [[func]] name = "On_ADDDEX" addr = 0x43D8AC size = 0x31 [[func]] name = "On_ADDVIT" addr = 0x43D8DD size = 0x31 [[func]] name = "On_SBSPELL" addr = 0x43D90E size = 0x6F [[func]] name = "msg_errorf" addr = 0x43D97D size = 0x47 [[func]] name = "On_GOTOGETITEM" addr = 0x43D9C4 size = 0x52 [[func]] name = "On_REQUESTGITEM" addr = 0x43DA16 size = 0xD0 [[func]] name = "i_own_level" addr = 0x43DAE6 size = 0x47 [[func]] name = "On_GETITEM" addr = 0x43DB2D size = 0x110 [[func]] name = "delta_get_item" addr = 0x43DC3D size = 0x103 [[func]] name = "On_GOTOAGETITEM" addr = 0x43DD40 size = 0x52 [[func]] name = "On_REQUESTAGITEM" addr = 0x43DD92 size = 0xCE [[func]] name = "On_AGETITEM" addr = 0x43DE60 size = 0x10E [[func]] name = "On_ITEMEXTRA" addr = 0x43DF6E size = 0x5B [[func]] name = "On_PUTITEM" addr = 0x43DFC9 size = 0x105 [[func]] name = "delta_put_item" addr = 0x43E0CE size = 0xAB [[func]] name = "check_update_plr" addr = 0x43E179 size = 0x1A [[func]] name = "On_SYNCPUTITEM" addr = 0x43E193 size = 0xF1 [[func]] name = "On_RESPAWNITEM" addr = 0x43E284 size = 0xA6 [[func]] name = "On_ATTACKXY" addr = 0x43E32A size = 0x5C [[func]] name = "On_SATTACKXY" addr = 0x43E386 size = 0x4F [[func]] name = "On_RATTACKXY" addr = 0x43E3D5 size = 0x4F [[func]] name = "On_SPELLXYD" addr = 0x43E424 size = 0xAE [[func]] name = "On_SPELLXY" addr = 0x43E4D2 size = 0xA4 [[func]] name = "On_TSPELLXY" addr = 0x43E576 size = 0xA4 [[func]] name = "On_OPOBJXY" addr = 0x43E61A size = 0x70 [[func]] name = "On_DISARMXY" addr = 0x43E68A size = 0x70 [[func]] name = "On_OPOBJT" addr = 0x43E6FA size = 0x38 [[func]] name = "On_ATTACKID" addr = 0x43E732 size = 0xAD [[func]] name = "On_ATTACKPID" addr = 0x43E7DF size = 0x61 [[func]] name = "On_RATTACKID" addr = 0x43E840 size = 0x45 [[func]] name = "On_RATTACKPID" addr = 0x43E885 size = 0x45 [[func]] name = "On_SPELLID" addr = 0x43E8CA size = 0x9A [[func]] name = "On_SPELLPID" addr = 0x43E964 size = 0x9A [[func]] name = "On_TSPELLID" addr = 0x43E9FE size = 0x9A [[func]] name = "On_TSPELLPID" addr = 0x43EA98 size = 0x9A [[func]] name = "On_KNOCKBACK" addr = 0x43EB32 size = 0x42 [[func]] name = "On_RESURRECT" addr = 0x43EB74 size = 0x30 [[func]] name = "On_HEALOTHER" addr = 0x43EBA4 size = 0x31 [[func]] name = "On_TALKXY" addr = 0x43EBD5 size = 0x52 [[func]] name = "On_NEWLVL" addr = 0x43EC27 size = 0x34 [[func]] name = "On_WARP" addr = 0x43EC5B size = 0x5F [[func]] name = "On_MONSTDEATH" addr = 0x43ECBA size = 0x69 [[func]] name = "On_KILLGOLEM" addr = 0x43ED23 size = 0x66 [[func]] name = "On_AWAKEGOLEM" addr = 0x43ED89 size = 0xB4 [[func]] name = "On_MONSTDAMAGE" addr = 0x43EE3D size = 0xB8 [[func]] name = "On_PLRDEAD" addr = 0x43EEF5 size = 0x38 [[func]] name = "On_PLRDAMAGE" addr = 0x43EF2D size = 0xB0 [[func]] name = "On_OPENDOOR" addr = 0x43EFDD size = 0x56 [[func]] name = "delta_sync_object" addr = 0x43F033 size = 0x25 [[func]] name = "On_CLOSEDOOR" addr = 0x43F058 size = 0x56 [[func]] name = "On_OPERATEOBJ" addr = 0x43F0AE size = 0x56 [[func]] name = "On_PLROPOBJ" addr = 0x43F104 size = 0x58 [[func]] name = "On_BREAKOBJ" addr = 0x43F15C size = 0x54 [[func]] name = "On_CHANGEPLRITEMS" addr = 0x43F1B0 size = 0x40 [[func]] name = "On_DELPLRITEMS" addr = 0x43F1F0 size = 0x2E [[func]] name = "On_PLRLEVEL" addr = 0x43F21E size = 0x3A [[func]] name = "On_DROPITEM" addr = 0x43F258 size = 0x37 [[func]] name = "On_SEND_PLRINFO" addr = 0x43F28F size = 0x3A [[func]] name = "On_ACK_PLRINFO" addr = 0x43F2C9 size = 0x5 [[func]] name = "On_PLAYER_JOINLEVEL" addr = 0x43F2CE size = 0x17A [[func]] name = "On_ACTIVATEPORTAL" addr = 0x43F448 size = 0xD9 [[func]] name = "delta_open_portal" addr = 0x43F521 size = 0x3B [[func]] name = "On_DEACTIVATEPORTAL" addr = 0x43F55C size = 0x3E [[func]] name = "On_RETOWN" addr = 0x43F59A size = 0x39 [[func]] name = "On_SETSTR" addr = 0x43F5D3 size = 0x39 [[func]] name = "On_SETDEX" addr = 0x43F60C size = 0x39 [[func]] name = "On_SETMAG" addr = 0x43F645 size = 0x39 [[func]] name = "On_SETVIT" addr = 0x43F67E size = 0x39 [[func]] name = "On_STRING" addr = 0x43F6B7 size = 0x0B [[func]] name = "On_STRING2" addr = 0x43F6C2 size = 0x2A [[func]] name = "On_SYNCQUEST" addr = 0x43F6EC size = 0x42 [[func]] name = "On_ENDSHIELD" addr = 0x43F72E size = 0x77 [[func]] name = "On_CHEAT_EXPERIENCE" addr = 0x43F7A5 size = 0x4 [[func]] name = "On_CHEAT_SPELL_LEVEL" addr = 0x43F7A5 size = 0x4 [[func]] name = "On_DEBUG" addr = 0x43F7A5 size = 0x4 [[func]] name = "On_NOVA" addr = 0x43F7A9 size = 0x6F [[func]] name = "On_SETSHIELD" addr = 0x43F818 size = 0x18 [[func]] name = "On_REMSHIELD" addr = 0x43F830 size = 0x19 [[func]] name = "msgcmd_cmd_cleanup" addr = 0x43F88D size = 0xA [[func]] name = "msgcmd_send_chat" addr = 0x43F897 size = 0x3D [[func]] name = "msgcmd_add_server_cmd_W" addr = 0x43F8D4 size = 0x11 [[func]] name = "msgcmd_add_server_cmd" addr = 0x43F8E5 size = 0x3B [[func]] name = "TList::TList" addr = 0x43F920 size = 0x16 [[func]] name = "TList::DeleteAll" addr = 0x43F936 size = 0x28 [[func]] name = "TList::Remove" addr = 0x43F95E size = 0x3B [[func]] name = "TList::Create" addr = 0x43F999 size = 0x4C [[func]] name = "EXTERNMESSAGE::Delete" addr = 0x43F9E5 size = 0x2F [[func]] name = "TList::Insert" addr = 0x43FA14 size = 0x71 [[func]] name = "TList::UnlinkAll" addr = 0x43FA85 size = 0x13 [[func]] name = "TLink::Unlink" addr = 0x43FA98 size = 0x2C [[func]] name = "multi_msg_add" addr = 0x43FAD4 size = 0xE [[func]] name = "NetSendLoPri" addr = 0x43FAE2 size = 0x29 [[func]] name = "multi_copy_packet" addr = 0x43FB0B size = 0x42 [[func]] name = "multi_send_packet" addr = 0x43FB4D size = 0x68 [[func]] name = "NetRecvPlrData" addr = 0x43FBB5 size = 0xBA [[func]] name = "NetSendHiPri" addr = 0x43FC6F size = 0xB8 [[func]] name = "multi_recv_packet" addr = 0x43FD27 size = 0x69 [[func]] name = "multi_send_msg_packet" addr = 0x43FD90 size = 0x7E [[func]] name = "multi_msg_countdown" addr = 0x43FE0E size = 0x2F [[func]] name = "multi_parse_turn" addr = 0x43FE3D size = 0x48 [[func]] name = "multi_handle_turn_upper_bit" addr = 0x43FE85 size = 0x32 [[func]] name = "multi_player_left" addr = 0x43FEB7 size = 0x13 [[func]] name = "multi_clear_left_tbl" addr = 0x43FECA size = 0x44 [[func]] name = "multi_player_left_msg" addr = 0x43FF0E size = 0x8F [[func]] name = "multi_net_ping" addr = 0x43FF9D size = 0x13 [[func]] name = "multi_handle_delta" addr = 0x43FFB0 size = 0xA8 [[func]] name = "multi_check_pkt_valid" addr = 0x440058 size = 0x8 [[func]] name = "multi_mon_seeds" addr = 0x440060 size = 0x33 [[func]] name = "multi_begin_timeout" addr = 0x440093 size = 0x95 [[func]] name = "multi_check_drop_player" addr = 0x440128 size = 0x2B [[func]] name = "multi_process_network_packets" addr = 0x440153 size = 0x2CA [[func]] name = "multi_handle_all_packets" addr = 0x44041D size = 0x27 [[func]] name = "multi_process_tmsgs" addr = 0x440444 size = 0x33 [[func]] name = "multi_send_zero_packet" addr = 0x440477 size = 0xE6 [[func]] name = "NetClose" addr = 0x44055D size = 0x47 [[func]] name = "multi_event_handler" addr = 0x4405A4 size = 0x48 [[func]] name = "multi_handle_events" addr = 0x4405EC size = 0xA8 [[func]] name = "NetInit" addr = 0x440694 size = 0x2FE [[func]] name = "buffer_init" addr = 0x440992 size = 0x8 [[func]] name = "multi_send_pinfo" addr = 0x44099A size = 0x3B [[func]] name = "InitLevelType" addr = 0x4409D5 size = 0x30 [[func]] name = "SetupLocalCoords" addr = 0x440A05 size = 0x96 [[func]] name = "multi_init_single" addr = 0x440A9B size = 0x6E [[func]] name = "multi_init_multi" addr = 0x440B09 size = 0xD2 [[func]] name = "multi_upgrade" addr = 0x440BDB size = 0x3C [[func]] name = "recv_plrinfo" addr = 0x440C17 size = 0x197 [[func]] name = "nthread_terminate_game" addr = 0x440DEC size = 0x3C [[func]] name = "nthread_send_and_recv_turn" addr = 0x440E28 size = 0x82 [[func]] name = "nthread_recv_turns" addr = 0x440EAA size = 0xAC [[func]] name = "nthread_set_turn_upper_bit" addr = 0x440F56 size = 0xB [[func]] name = "nthread_start" addr = 0x440F61 size = 0x16E [[func]] name = "nthread_handler" addr = 0x4410CF size = 0x76 [[func]] name = "nthread_cleanup" addr = 0x441145 size = 0x7F [[func]] name = "nthread_ignore_mutex" addr = 0x4411C4 size = 0x2B [[func]] name = "nthread_has_500ms_passed" addr = 0x4411EF size = 0x2E [[func]] name = "InitObjectGFX" addr = 0x44121D size = 0xFA [[func]] name = "FreeObjectGFX" addr = 0x441317 size = 0x2E [[func]] name = "RndLocOk" addr = 0x441345 size = 0x5B [[func]] name = "InitRndLocObj" addr = 0x4413A0 size = 0xD7 [[func]] name = "InitRndLocBigObj" addr = 0x441477 size = 0x10D [[func]] name = "InitRndLocObj5x5" addr = 0x441584 size = 0xB7 [[func]] name = "ClrAllObjects" addr = 0x44163B size = 0x6D [[func]] name = "AddTortures" addr = 0x4416A8 size = 0xF7 [[func]] name = "AddCandles" addr = 0x44179F size = 0x49 [[func]] name = "AddBookLever" addr = 0x4417E8 size = 0x11C [[func]] name = "InitRndBarrels" addr = 0x441904 size = 0xFC [[func]] name = "AddL1Objs" addr = 0x441A00 size = 0x98 [[func]] name = "AddL2Objs" addr = 0x441A98 size = 0x7E [[func]] name = "AddL3Objs" addr = 0x441B16 size = 0x74 [[func]] name = "WallTrapLocOk" addr = 0x441B8A size = 0x16 [[func]] name = "AddL2Torches" addr = 0x441BA0 size = 0xEC [[func]] name = "TorchLocOK" addr = 0x441C8C size = 0x27 [[func]] name = "AddObjTraps" addr = 0x441CB3 size = 0x1A5 [[func]] name = "AddChestTraps" addr = 0x441E58 size = 0x8C [[func]] name = "LoadMapObjects" addr = 0x441EE4 size = 0xCB [[func]] name = "LoadMapObjs" addr = 0x441FAF size = 0x87 [[func]] name = "AddDiabObjs" addr = 0x442036 size = 0xBC [[func]] name = "AddStoryBooks" addr = 0x4420F2 size = 0xD8 [[func]] name = "AddHookedBodies" addr = 0x4421CA size = 0xD5 [[func]] name = "AddL4Goodies" addr = 0x44229F size = 0x77 [[func]] name = "AddLazStand" addr = 0x442316 size = 0x102 [[func]] name = "InitObjects" addr = 0x442418 size = 0x3AD [[func]] name = "SetMapObjects" addr = 0x4427C5 size = 0x166 [[func]] name = "DeleteObject_" addr = 0x44292B size = 0x50 [[func]] name = "SetupObject" addr = 0x44297B size = 0x122 [[func]] name = "SetObjMapRange" addr = 0x442A9D size = 0x34 [[func]] name = "SetBookMsg" addr = 0x442AD1 size = 0xA [[func]] name = "AddL1Door" addr = 0x442ADB size = 0x51 [[func]] name = "AddSCambBook" addr = 0x442B2C size = 0x49 [[func]] name = "AddChest" addr = 0x442B75 size = 0xB2 [[func]] name = "AddL2Door" addr = 0x442C27 size = 0x3B [[func]] name = "AddL3Door" addr = 0x442C62 size = 0x3B [[func]] name = "AddSarc" addr = 0x442C9D size = 0x51 [[func]] name = "AddFlameTrap" addr = 0x442CEE size = 0x28 [[func]] name = "AddFlameLvr" addr = 0x442D16 size = 0x19 [[func]] name = "AddTrap" addr = 0x442D2F size = 0x5B [[func]] name = "AddObjLight" addr = 0x442D8A size = 0x37 [[func]] name = "AddBarrel" addr = 0x442DC1 size = 0x4E [[func]] name = "AddShrine" addr = 0x442E0F size = 0xA3 [[func]] name = "AddBookcase" addr = 0x442EB2 size = 0x1D [[func]] name = "AddPurifyingFountain" addr = 0x442ECF size = 0x39 [[func]] name = "AddArmorStand" addr = 0x442F08 size = 0x32 [[func]] name = "AddDecap" addr = 0x442F3A size = 0x2E [[func]] name = "AddVilebook" addr = 0x442F68 size = 0x20 [[func]] name = "AddMagicCircle" addr = 0x442F88 size = 0x29 [[func]] name = "AddBookstand" addr = 0x442FB1 size = 0x13 [[func]] name = "AddPedistal" addr = 0x442FC4 size = 0x38 [[func]] name = "AddStoryBook" addr = 0x442FFC size = 0x92 [[func]] name = "AddWeaponRack" addr = 0x44308E size = 0x32 [[func]] name = "AddTorturedBody" addr = 0x4430C0 size = 0x2E [[func]] name = "GetRndObjLoc" addr = 0x4430EE size = 0x8A [[func]] name = "AddMushPatch" addr = 0x443178 size = 0x5C [[func]] name = "AddSlainHero" addr = 0x4431D4 size = 0x2B [[func]] name = "AddObject" addr = 0x4431FF size = 0x1EB [[func]] name = "Obj_Light" addr = 0x4434CB size = 0xEA [[func]] name = "Obj_Circle" addr = 0x4435B5 size = 0x172 [[func]] name = "Obj_StopAnim" addr = 0x443727 size = 0x23 [[func]] name = "Obj_Door" addr = 0x44374A size = 0x83 [[func]] name = "Obj_Sarc" addr = 0x4437CD size = 0x19 [[func]] name = "ActivateTrapLine" addr = 0x4437E6 size = 0x6F [[func]] name = "Obj_FlameTrap" addr = 0x443855 size = 0x111 [[func]] name = "Obj_Trap" addr = 0x443966 size = 0x16F [[func]] name = "Obj_BCrossDamage" addr = 0x443AD5 size = 0xFD [[func]] name = "ProcessObjects" addr = 0x443BD2 size = 0x197 [[func]] name = "ObjSetMicro" addr = 0x443D69 size = 0x81 [[func]] name = "objects_set_door_piece" addr = 0x443DEA size = 0x78 [[func]] name = "ObjSetMini" addr = 0x443E62 size = 0x78 [[func]] name = "ObjL1Special" addr = 0x443EDA size = 0xEC [[func]] name = "ObjL2Special" addr = 0x443FC6 size = 0xFC [[func]] name = "DoorSet" addr = 0x4440C2 size = 0x184 [[func]] name = "RedoPlayerVision" addr = 0x444246 size = 0x35 [[func]] name = "OperateL1RDoor" addr = 0x44427B size = 0x1C1 [[func]] name = "OperateL1LDoor" addr = 0x44443C size = 0x1D7 [[func]] name = "OperateL2RDoor" addr = 0x444613 size = 0x162 [[func]] name = "OperateL2LDoor" addr = 0x444775 size = 0x162 [[func]] name = "OperateL3RDoor" addr = 0x4448D7 size = 0x165 [[func]] name = "OperateL3LDoor" addr = 0x444A3C size = 0x165 [[func]] name = "MonstCheckDoors" addr = 0x444BA1 size = 0x222 [[func]] name = "ObjChangeMap" addr = 0x444DC3 size = 0xDB [[func]] name = "ObjChangeMapResync" addr = 0x444E9E size = 0xB1 [[func]] name = "OperateL1Door" addr = 0x444F4F size = 0x8F [[func]] name = "OperateLever" addr = 0x444FDE size = 0xCE [[func]] name = "OperateBook" addr = 0x4450AC size = 0x225 [[func]] name = "OperateBookLever" addr = 0x4452D1 size = 0x1B2 [[func]] name = "OperateSChambBk" addr = 0x445483 size = 0xD7 [[func]] name = "OperateChest" addr = 0x44555A size = 0x189 [[func]] name = "OperateMushPatch" addr = 0x4456E3 size = 0xD5 [[func]] name = "OperateInnSignChest" addr = 0x4457B8 size = 0xC8 [[func]] name = "OperateSlainHero" addr = 0x445880 size = 0xD4 [[func]] name = "OperateTrapLvr" addr = 0x445954 size = 0xB7 [[func]] name = "OperateSarc" addr = 0x445A0B size = 0xD1 [[func]] name = "OperateL2Door" addr = 0x445ADC size = 0x90 [[func]] name = "OperateL3Door" addr = 0x445B6C size = 0x90 [[func]] name = "OperatePedistal" addr = 0x445BFC size = 0x163 [[func]] name = "TryDisarm" addr = 0x445D5F size = 0xD4 [[func]] name = "ItemMiscIdIdx" addr = 0x445E33 size = 0x18 [[func]] name = "OperateShrine" addr = 0x445E4B size = 0xFB7 [[func]] name = "OperateSkelBook" addr = 0x446E6A size = 0x9E [[func]] name = "OperateBookCase" addr = 0x446F08 size = 0xE0 [[func]] name = "OperateDecap" addr = 0x446FE8 size = 0x5E [[func]] name = "OperateArmorStand" addr = 0x447046 size = 0xC6 [[func]] name = "FindValidShrine" addr = 0x44710C size = 0x53 [[func]] name = "OperateGoatShrine" addr = 0x44715F size = 0x4B [[func]] name = "OperateCauldron" addr = 0x4471AA size = 0x52 [[func]] name = "OperateFountains" addr = 0x4471FC size = 0x2B1 [[func]] name = "OperateWeaponRack" addr = 0x4474AD size = 0xAB [[func]] name = "OperateStoryBook" addr = 0x447558 size = 0x63 [[func]] name = "OperateLazStand" addr = 0x4475BB size = 0x65 [[func]] name = "OperateObject" addr = 0x447620 size = 0x249 [[func]] name = "SyncOpL1Door" addr = 0x447932 size = 0x71 [[func]] name = "SyncOpL2Door" addr = 0x4479A3 size = 0x72 [[func]] name = "SyncOpL3Door" addr = 0x447A15 size = 0x72 [[func]] name = "SyncOpObject" addr = 0x447A87 size = 0xED [[func]] name = "BreakCrux" addr = 0x447C2D size = 0xC2 [[func]] name = "BreakBarrel" addr = 0x447CEF size = 0x274 [[func]] name = "BreakObject" addr = 0x447F63 size = 0x8C [[func]] name = "SyncBreakObj" addr = 0x447FEF size = 0x21 [[func]] name = "SyncL1Doors" addr = 0x448010 size = 0xAB [[func]] name = "SyncCrux" addr = 0x4480BB size = 0x7E [[func]] name = "SyncLever" addr = 0x448139 size = 0x2A [[func]] name = "SyncQSTLever" addr = 0x448163 size = 0x6F [[func]] name = "SyncPedistal" addr = 0x4481D2 size = 0xC6 [[func]] name = "SyncL2Doors" addr = 0x448298 size = 0x86 [[func]] name = "SyncL3Doors" addr = 0x44831E size = 0x92 [[func]] name = "SyncObjectAnim" addr = 0x4483B0 size = 0xAE [[func]] name = "GetObjectStr" addr = 0x44845E size = 0x20E [[func]] name = "PackPlayer" addr = 0x448765 size = 0x1EE [[func]] name = "PackItem" addr = 0x448953 size = 0x10B [[func]] name = "VerifyGoldSeeds" addr = 0x448A5E size = 0x72 [[func]] name = "UnPackPlayer" addr = 0x448AD0 size = 0x278 [[func]] name = "UnPackItem" addr = 0x448D48 size = 0xAD [[func]] name = "SaveGamma" addr = 0x448E05 size = 0x2E [[func]] name = "palette_init" addr = 0x448E33 size = 0x78 [[func]] name = "LoadGamma" addr = 0x448EAB size = 0x75 [[func]] name = "LoadSysPal" addr = 0x448F20 size = 0xA9 [[func]] name = "LoadPalette" addr = 0x448FC9 size = 0x5C [[func]] name = "LoadRndLvlPal" addr = 0x449025 size = 0x47 [[func]] name = "ResetPal" addr = 0x44906C size = 0x2B [[func]] name = "IncreaseGamma" addr = 0x449097 size = 0x39 [[func]] name = "palette_update" addr = 0x4490D0 size = 0x37 [[func]] name = "ApplyGamma" addr = 0x449107 size = 0xC9 [[func]] name = "DecreaseGamma" addr = 0x4491D0 size = 0x39 [[func]] name = "UpdateGamma" addr = 0x449209 size = 0x35 [[func]] name = "BlackPalette" addr = 0x44923E size = 0x7 [[func]] name = "SetFadeLevel" addr = 0x449245 size = 0x6B [[func]] name = "PaletteFadeIn" addr = 0x4492B0 size = 0x56 [[func]] name = "PaletteFadeOut" addr = 0x449306 size = 0x30 [[func]] name = "palette_update_caves" addr = 0x449336 size = 0x62 [[func]] name = "palette_update_quest_palette" addr = 0x449398 size = 0x2E [[func]] name = "palette_get_color_cycling" addr = 0x4493C6 size = 0x6 [[func]] name = "palette_set_color_cycling" addr = 0x4493CC size = 0x8 [[func]] name = "FindPath" addr = 0x4493D4 size = 0xFF [[func]] name = "path_get_h_cost" addr = 0x4494D3 size = 0x31 [[func]] name = "path_check_equal" addr = 0x449504 size = 0x18 [[func]] name = "GetNextPath" addr = 0x44951C size = 0x2A [[func]] name = "path_solid_pieces" addr = 0x449546 size = 0xA7 [[func]] name = "path_get_path" addr = 0x4495ED size = 0x82 [[func]] name = "path_parent_path" addr = 0x44966F size = 0x12B [[func]] name = "path_get_node1" addr = 0x44979A size = 0x19 [[func]] name = "path_get_node2" addr = 0x4497B3 size = 0x19 [[func]] name = "path_next_node" addr = 0x4497CC size = 0x2B [[func]] name = "path_set_coords" addr = 0x4497F7 size = 0x99 [[func]] name = "path_push_active_step" addr = 0x449890 size = 0x13 [[func]] name = "path_pop_active_step" addr = 0x4498A3 size = 0x13 [[func]] name = "path_new_step" addr = 0x4498B6 size = 0x36 [[func]] name = "pfile_init_save_directory" addr = 0x4498FC size = 0x5F [[func]] name = "pfile_check_available_space" addr = 0x44995B size = 0x68 [[func]] name = "pfile_write_hero" addr = 0x4499C3 size = 0x70 [[func]] name = "pfile_get_save_num_from_name" addr = 0x449A33 size = 0x28 [[func]] name = "pfile_encode_hero" addr = 0x449A5B size = 0x84 [[func]] name = "pfile_open_archive" addr = 0x449ADF size = 0x51 [[func]] name = "pfile_get_save_path" addr = 0x449B30 size = 0x82 [[func]] name = "pfile_flush" addr = 0x449BB2 size = 0x32 [[func]] name = "pfile_create_player_description" addr = 0x449BE4 size = 0x76 [[func]] name = "pfile_rename_hero" addr = 0x449C5A size = 0xC8 [[func]] name = "pfile_flush_W" addr = 0x449D22 size = 0x21 [[func]] name = "game_2_ui_player" addr = 0x449D43 size = 0x8D [[func]] name = "game_2_ui_class" addr = 0x449DD0 size = 0x13 [[func]] name = "pfile_ui_set_hero_infos" addr = 0x449DE3 size = 0x1C7 [[func]] name = "GetSaveDirectory" addr = 0x449FAA size = 0x8C [[func]] name = "pfile_read_hero" addr = 0x44A036 size = 0x122 [[func]] name = "pfile_open_save_archive" addr = 0x44A158 size = 0x3A [[func]] name = "pfile_SFileCloseArchive" addr = 0x44A192 size = 0x7 [[func]] name = "pfile_archive_contains_game" addr = 0x44A199 size = 0x33 [[func]] name = "pfile_ui_set_class_stats" addr = 0x44A1CC size = 0x44 [[func]] name = "pfile_get_player_class" addr = 0x44A210 size = 0x10 [[func]] name = "pfile_ui_save_create" addr = 0x44A220 size = 0xDF [[func]] name = "pfile_get_file_name" addr = 0x44A2FF size = 0x57 [[func]] name = "pfile_delete_save" addr = 0x44A356 size = 0x4A [[func]] name = "pfile_read_player_from_save" addr = 0x44A3A0 size = 0x79 [[func]] name = "GetTempLevelNames" addr = 0x44A419 size = 0x4A [[func]] name = "GetPermLevelNames" addr = 0x44A463 size = 0x86 [[func]] name = "pfile_get_game_name" addr = 0x44A4E9 size = 0x29 [[func]] name = "pfile_remove_temp_files" addr = 0x44A512 size = 0x51 [[func]] name = "GetTempSaveNames" addr = 0x44A563 size = 0x35 [[func]] name = "pfile_rename_temp_to_perm" addr = 0x44A598 size = 0xAC [[func]] name = "GetPermSaveNames" addr = 0x44A644 size = 0x35 [[func]] name = "pfile_write_save_file" addr = 0x44A679 size = 0xAE [[func]] name = "pfile_strcpy" addr = 0x44A727 size = 0xA [[func]] name = "pfile_read" addr = 0x44A731 size = 0x182 [[func]] name = "pfile_update" addr = 0x44A8B3 size = 0x33 [[func]] name = "SetPlayerGPtrs" addr = 0x44A8F6 size = 0x1B [[func]] name = "LoadPlrGFX" addr = 0x44A911 size = 0x25F [[func]] name = "InitPlayerGFX" addr = 0x44AB70 size = 0x44 [[func]] name = "InitPlrGFXMem" addr = 0x44ABB4 size = 0x214 [[func]] name = "GetPlrGFXSize" addr = 0x44ADC8 size = 0xC1 [[func]] name = "FreePlayerGFX" addr = 0x44AE89 size = 0xAE [[func]] name = "NewPlrAnim" addr = 0x44AF37 size = 0x65 [[func]] name = "ClearPlrPVars" addr = 0x44AF9C size = 0x51 [[func]] name = "SetPlrAnims" addr = 0x44AFED size = 0x210 [[func]] name = "ClearPlrRVars" addr = 0x44B1FD size = 0x77 [[func]] name = "CreatePlayer" addr = 0x44B274 size = 0x30E [[func]] name = "CalcStatDiff" addr = 0x44B582 size = 0x41 [[func]] name = "NextPlrLevel" addr = 0x44B5C3 size = 0x105 [[func]] name = "AddPlrExperience" addr = 0x44B6C8 size = 0x130 [[func]] name = "AddPlrMonstExper" addr = 0x44B7F8 size = 0x44 [[func]] name = "InitPlayer" addr = 0x44B83C size = 0x2F7 [[func]] name = "InitMultiView" addr = 0x44BB33 size = 0x3A [[func]] name = "CheckEFlag" addr = 0x44BB6D size = 0x155 [[func]] name = "SolidLoc" addr = 0x44BCC2 size = 0x29 [[func]] name = "PlrDirOK" addr = 0x44BCEB size = 0xAF [[func]] name = "PlrClrTrans" addr = 0x44BD9A size = 0x43 [[func]] name = "PlrDoTrans" addr = 0x44BDDD size = 0x81 [[func]] name = "SetPlayerOld" addr = 0x44BE5E size = 0x37 [[func]] name = "FixPlayerLocation" addr = 0x44BE95 size = 0x98 [[func]] name = "StartStand" addr = 0x44BF2D size = 0xBB [[func]] name = "StartWalkStand" addr = 0x44BFE8 size = 0x88 [[func]] name = "PM_ChangeLightOff" addr = 0x44C070 size = 0xCD [[func]] name = "PM_ChangeOffset" addr = 0x44C13D size = 0xA5 [[func]] name = "StartWalk" addr = 0x44C1E2 size = 0x1CA [[func]] name = "StartWalk2" addr = 0x44C3AC size = 0x223 [[func]] name = "StartWalk3" addr = 0x44C5CF size = 0x24F [[func]] name = "StartAttack" addr = 0x44C81E size = 0x9D [[func]] name = "StartRangeAttack" addr = 0x44C8BB size = 0xB8 [[func]] name = "StartPlrBlock" addr = 0x44C973 size = 0xB3 [[func]] name = "StartSpell" addr = 0x44CA26 size = 0x16F [[func]] name = "FixPlrWalkTags" addr = 0x44CB95 size = 0xCD [[func]] name = "RemovePlrFromMap" addr = 0x44CC62 size = 0x76 [[func]] name = "StartPlrHit" addr = 0x44CCD8 size = 0x125 [[func]] name = "RespawnDeadItem" addr = 0x44CDFD size = 0xCC [[func]] name = "StartPlayerKill" addr = 0x44CEC9 size = 0x32B [[func]] name = "PlrDeadItem" addr = 0x44D1F4 size = 0xFF [[func]] name = "DropHalfPlayersGold" addr = 0x44D2F3 size = 0x418 [[func]] name = "SyncPlrKill" addr = 0x44D70B size = 0x90 [[func]] name = "RemovePlrMissiles" addr = 0x44D7A0 size = 0x131 [[func]] name = "InitLevelChange" addr = 0x44D8D1 size = 0xA2 [[func]] name = "StartNewLvl" addr = 0x44D973 size = 0xFC [[func]] name = "RestartTownLvl" addr = 0x44DA6F size = 0x8D [[func]] name = "StartWarpLvl" addr = 0x44DAFC size = 0x78 [[func]] name = "PM_DoStand" addr = 0x44DB74 size = 0x3 [[func]] name = "PM_DoWalk" addr = 0x44DB77 size = 0x16E [[func]] name = "PM_DoWalk2" addr = 0x44DCE5 size = 0x14B [[func]] name = "PM_DoWalk3" addr = 0x44DE30 size = 0x181 [[func]] name = "WeaponDur" addr = 0x44DFB1 size = 0x10B [[func]] name = "PlrHitMonst" addr = 0x44E0BC size = 0x386 [[func]] name = "PlrHitPlr" addr = 0x44E442 size = 0x227 [[func]] name = "PlrHitObj" addr = 0x44E669 size = 0x3D [[func]] name = "PM_DoAttack" addr = 0x44E6A6 size = 0x212 [[func]] name = "PM_DoRangeAttack" addr = 0x44E8B8 size = 0xF4 [[func]] name = "ShieldDur" addr = 0x44E9AC size = 0xA1 [[func]] name = "PM_DoBlock" addr = 0x44EA4D size = 0x79 [[func]] name = "PM_DoSpell" addr = 0x44EAC6 size = 0x140 [[func]] name = "PM_DoGotHit" addr = 0x44EC06 size = 0xB6 [[func]] name = "ArmorDur" addr = 0x44ECBC size = 0xBF [[func]] name = "PM_DoDeath" addr = 0x44ED7B size = 0xA7 [[func]] name = "PM_DoNewLvl" addr = 0x44DB74 size = 0x3 [[func]] name = "CheckNewPath" addr = 0x44EE22 size = 0xB30 [[func]] name = "PlrDeathModeOK" addr = 0x44F9BA size = 0x42 [[func]] name = "ValidatePlayer" addr = 0x44F9FC size = 0x136 [[func]] name = "ProcessPlayers" addr = 0x44FB32 size = 0x1D3 [[func]] name = "CheckCheatStats" addr = 0x44FD31 size = 0x59 [[func]] name = "ClrPlrPath" addr = 0x44FD8A size = 0x30 [[func]] name = "PosOkPlayer" addr = 0x44FDBA size = 0xE4 [[func]] name = "MakePlrPath" addr = 0x44FE9E size = 0xB1 [[func]] name = "CheckPlrSpell" addr = 0x44FF6F size = 0x2A8 [[func]] name = "SyncPlrAnim" addr = 0x450217 size = 0x126 [[func]] name = "SyncInitPlrPos" addr = 0x45036D size = 0x177 [[func]] name = "SyncInitPlr" addr = 0x4504E4 size = 0x24 [[func]] name = "CheckStats" addr = 0x450508 size = 0x119 [[func]] name = "ModifyPlrStr" addr = 0x450621 size = 0xBA [[func]] name = "ModifyPlrMag" addr = 0x4506DB size = 0xAD [[func]] name = "ModifyPlrDex" addr = 0x450788 size = 0xA4 [[func]] name = "ModifyPlrVit" addr = 0x45082C size = 0xA3 [[func]] name = "SetPlayerHitPoints" addr = 0x4508CF size = 0x4F [[func]] name = "SetPlrStr" addr = 0x45091E size = 0x75 [[func]] name = "SetPlrMag" addr = 0x450993 size = 0x4C [[func]] name = "SetPlrDex" addr = 0x4509DF size = 0x75 [[func]] name = "SetPlrVit" addr = 0x450A54 size = 0x4C [[func]] name = "InitDungMsgs" addr = 0x450AA0 size = 0x24 [[func]] name = "PlayDungMsgs" addr = 0x450AC4 size = 0x26F [[func]] name = "plrmsg_delay" addr = 0x450D33 size = 0x37 [[func]] name = "ErrorPlrMsg" addr = 0x450D6A size = 0x49 [[func]] name = "EventPlrMsg" addr = 0x450DB3 size = 0x47 [[func]] name = "SendPlrMsg" addr = 0x450DFA size = 0x6A [[func]] name = "ClearPlrMsg" addr = 0x450E64 size = 0x2A [[func]] name = "InitPlrMsg" addr = 0x450E8E size = 0x1C [[func]] name = "DrawPlrMsg" addr = 0x450EAA size = 0x8D [[func]] name = "PrintPlrMsg" addr = 0x450F37 size = 0xC7 [[func]] name = "InitPortals" addr = 0x450FFE size = 0x26 [[func]] name = "SetPortalStats" addr = 0x451024 size = 0x3E [[func]] name = "AddWarpMissile" addr = 0x451062 size = 0x74 [[func]] name = "SyncPortals" addr = 0x4510D6 size = 0x5B [[func]] name = "AddInTownPortal" addr = 0x451131 size = 0x14 [[func]] name = "ActivatePortal" addr = 0x451145 size = 0x45 [[func]] name = "DeactivatePortal" addr = 0x45118A size = 0xC [[func]] name = "PortalOnLevel" addr = 0x451196 size = 0x22 [[func]] name = "RemovePortalMissile" addr = 0x4511B8 size = 0x7C [[func]] name = "SetCurrentPortal" addr = 0x451234 size = 0x7 [[func]] name = "GetPortalLevel" addr = 0x45123B size = 0xA8 [[func]] name = "GetPortalLvlPos" addr = 0x4512E3 size = 0x63 [[func]] name = "PosOkPortal" addr = 0x451346 size = 0x48 [[func]] name = "InitQuests" addr = 0x45138E size = 0x1CE [[func]] name = "CheckQuests" addr = 0x45155C size = 0x233 [[func]] name = "ForceQuests" addr = 0x45178F size = 0xA2 [[func]] name = "QuestStatus" addr = 0x451831 size = 0x40 [[func]] name = "CheckQuestKill" addr = 0x451871 size = 0x379 [[func]] name = "DrawButcher" addr = 0x451BEA size = 0x27 [[func]] name = "DrawSkelKing" addr = 0x451C11 size = 0x21 [[func]] name = "DrawWarLord" addr = 0x451C32 size = 0x90 [[func]] name = "DrawSChamber" addr = 0x451CC2 size = 0xBA [[func]] name = "DrawLTBanner" addr = 0x451D7C size = 0x8C [[func]] name = "DrawBlind" addr = 0x451E08 size = 0x8C [[func]] name = "DrawBlood" addr = 0x451E94 size = 0x8C [[func]] name = "DRLG_CheckQuests" addr = 0x451F20 size = 0x91 [[func]] name = "SetReturnLvlPos" addr = 0x451FB1 size = 0xB3 [[func]] name = "GetReturnLvlPos" addr = 0x452064 size = 0x39 [[func]] name = "ResyncMPQuests" addr = 0x45209D size = 0xBC [[func]] name = "ResyncQuests" addr = 0x452159 size = 0x326 [[func]] name = "PrintQLString" addr = 0x45247F size = 0x14E [[func]] name = "DrawQuestLog" addr = 0x4525CD size = 0x8C [[func]] name = "StartQuestlog" addr = 0x452659 size = 0x70 [[func]] name = "QuestlogUp" addr = 0x4526C9 size = 0x47 [[func]] name = "QuestlogDown" addr = 0x452710 size = 0x4A [[func]] name = "QuestlogEnter" addr = 0x45275A size = 0x42 [[func]] name = "QuestlogESC" addr = 0x45279C size = 0x55 [[func]] name = "SetMultiQuest" addr = 0x4527F1 size = 0x40 [[func]] name = "SystemSupported" addr = 0x452831 size = 0x54 [[func]] name = "RestrictedTest" addr = 0x452885 size = 0x72 [[func]] name = "ReadOnlyTest" addr = 0x4528F7 size = 0x7E [[func]] name = "ClearCursor" addr = 0x452985 size = 0xF [[func]] name = "DrawMissile" addr = 0x452994 size = 0x196 [[func]] name = "DrawClippedMissile" addr = 0x452B2A size = 0x196 [[func]] name = "DrawDeadPlayer" addr = 0x452CC0 size = 0xE0 [[func]] name = "DrawPlayer" addr = 0x452DA0 size = 0x1EB [[func]] name = "DrawClippedPlayer" addr = 0x452F8B size = 0x1D5 [[func]] name = "DrawView" addr = 0x453160 size = 0x112 [[func]] name = "DrawGame" addr = 0x453272 size = 0x1E5 [[func]] name = "scrollrt_draw_lower" addr = 0x453477 size = 0x46B [[func]] name = "scrollrt_draw_clipped_dungeon" addr = 0x4538E2 size = 0x5F7 [[func]] name = "DrawClippedMonster" addr = 0x453ED9 size = 0xF3 [[func]] name = "DrawClippedObject" addr = 0x453FCC size = 0x119 [[func]] name = "scrollrt_draw_clipped_e_flag" addr = 0x4540E5 size = 0x144 [[func]] name = "scrollrt_draw_lower_2" addr = 0x454229 size = 0x3A9 [[func]] name = "scrollrt_draw_clipped_dungeon_2" addr = 0x4545D2 size = 0x637 [[func]] name = "scrollrt_draw_clipped_e_flag_2" addr = 0x454C09 size = 0x194 [[func]] name = "scrollrt_draw_upper" addr = 0x454D9D size = 0x47A [[func]] name = "scrollrt_draw_dungeon" addr = 0x455217 size = 0x62D [[func]] name = "DrawMonster" addr = 0x455844 size = 0xF3 [[func]] name = "DrawObject" addr = 0x455937 size = 0x146 [[func]] name = "scrollrt_draw_e_flag" addr = 0x455A7D size = 0x157 [[func]] name = "DrawZoom" addr = 0x455BD4 size = 0x23E [[func]] name = "ClearScreenBuffer" addr = 0x455E32 size = 0x33 [[func]] name = "scrollrt_draw_game_screen" addr = 0x455E65 size = 0x62 [[func]] name = "scrollrt_draw_cursor_back_buffer" addr = 0x455EC7 size = 0x8F [[func]] name = "scrollrt_draw_cursor_item" addr = 0x455F56 size = 0x1CE [[func]] name = "DrawMain" addr = 0x456124 size = 0x28F [[func]] name = "DoBlitScreen" addr = 0x4563B3 size = 0x146 [[func]] name = "DrawAndBlit" addr = 0x4564F9 size = 0x12C [[func]] name = "ObjIndex" addr = 0x456625 size = 0x46 [[func]] name = "AddSKingObjs" addr = 0x45666B size = 0xAF [[func]] name = "AddSChamObjs" addr = 0x45671A size = 0x3B [[func]] name = "AddVileObjs" addr = 0x456755 size = 0x58 [[func]] name = "DRLG_SetMapTrans" addr = 0x4567AD size = 0x6C [[func]] name = "LoadSetMap" addr = 0x456819 size = 0x1FD [[func]] name = "SHA1Clear" addr = 0x456A16 size = 0x15 [[func]] name = "SHA1Result" addr = 0x456A2B size = 0x22 [[func]] name = "SHA1Calculate" addr = 0x456A4D size = 0x26 [[func]] name = "SHA1Input" addr = 0x456A73 size = 0x51 [[func]] name = "SHA1ProcessMessageBlock" addr = 0x456AC4 size = 0x1BE [[func]] name = "SHA1Reset" addr = 0x456C82 size = 0xE [[func]] name = "SHA1Init" addr = 0x456C90 size = 0x2B [[func]] name = "snd_update" addr = 0x456CCB size = 0x57 [[func]] name = "snd_stop_snd" addr = 0x456D22 size = 0x12 [[func]] name = "snd_playing" addr = 0x456D34 size = 0x2C [[func]] name = "snd_play_snd" addr = 0x456D60 size = 0xD9 [[func]] name = "sound_dup_channel" addr = 0x456E39 size = 0x3B [[func]] name = "sound_file_reload" addr = 0x456E74 size = 0x93 [[func]] name = "sound_file_load" addr = 0x456F07 size = 0xFC [[func]] name = "sound_CreateSoundBuffer" addr = 0x457003 size = 0x5D [[func]] name = "sound_file_cleanup" addr = 0x457060 size = 0x2B [[func]] name = "snd_init" addr = 0x45708B size = 0xA0 [[func]] name = "snd_get_volume" addr = 0x45712B size = 0x51 [[func]] name = "sound_create_primary_buffer" addr = 0x45717C size = 0x102 [[func]] name = "sound_DirectSoundCreate" addr = 0x45727E size = 0x81 [[func]] name = "sound_cleanup" addr = 0x4572FF size = 0x59 [[func]] name = "snd_set_volume" addr = 0x457358 size = 0xF [[func]] name = "music_stop" addr = 0x457367 size = 0x2C [[func]] name = "music_start" addr = 0x457393 size = 0x6B [[func]] name = "sound_disable_music" addr = 0x4573FE size = 0x1A [[func]] name = "sound_get_or_set_music_volume" addr = 0x457418 size = 0x23 [[func]] name = "sound_get_or_set_sound_volume" addr = 0x45743B size = 0x13 [[func]] name = "GetManaAmount" addr = 0x45744E size = 0xEC [[func]] name = "UseMana" addr = 0x45753A size = 0x4A [[func]] name = "CheckSpell" addr = 0x457584 size = 0x51 [[func]] name = "CastSpell" addr = 0x4575D5 size = 0xDC [[func]] name = "DoResurrect" addr = 0x4576B1 size = 0x11A [[func]] name = "PlacePlayer" addr = 0x4577CB size = 0x123 [[func]] name = "DoHealOther" addr = 0x4578EE size = 0x113 [[func]] name = "InitStores" addr = 0x457A01 size = 0x86 [[func]] name = "SetupTownStores" addr = 0x457A87 size = 0xBB [[func]] name = "FreeStoreMem" addr = 0x457B42 size = 0x36 [[func]] name = "DrawSTextBack" addr = 0x457B78 size = 0x5E [[func]] name = "PrintSString" addr = 0x457BD6 size = 0x20C [[func]] name = "DrawSLine" addr = 0x457DE2 size = 0x80 [[func]] name = "DrawSSlider" addr = 0x457E62 size = 0xF0 [[func]] name = "DrawSTextHelp" addr = 0x457F52 size = 0xF [[func]] name = "ClearSText" addr = 0x457F61 size = 0x45 [[func]] name = "AddSLine" addr = 0x457FA6 size = 0x25 [[func]] name = "AddSTextVal" addr = 0x457FCB size = 0xD [[func]] name = "OffsetSTextY" addr = 0x457FD8 size = 0xD [[func]] name = "AddSText" addr = 0x457FE5 size = 0x51 [[func]] name = "StoreAutoPlace" addr = 0x458036 size = 0x27D [[func]] name = "S_StartSmith" addr = 0x4582B3 size = 0xCA [[func]] name = "S_ScrollSBuy" addr = 0x45837D size = 0xBC [[func]] name = "PrintStoreItem" addr = 0x458439 size = 0x27A [[func]] name = "S_StartSBuy" addr = 0x4586B3 size = 0xC0 [[func]] name = "S_ScrollSPBuy" addr = 0x458773 size = 0xDE [[func]] name = "S_StartSPBuy" addr = 0x458851 size = 0xE0 [[func]] name = "SmithSellOk" addr = 0x458931 size = 0x41 [[func]] name = "S_ScrollSSell" addr = 0x458972 size = 0xE7 [[func]] name = "S_StartSSell" addr = 0x458A59 size = 0x1B2 [[func]] name = "SmithRepairOk" addr = 0x458C0B size = 0x43 [[func]] name = "S_StartSRepair" addr = 0x458C4E size = 0x24C [[func]] name = "AddStoreHoldRepair" addr = 0x458E9A size = 0xA3 [[func]] name = "S_StartWitch" addr = 0x458F3D size = 0xA6 [[func]] name = "S_ScrollWBuy" addr = 0x458FE3 size = 0xBC [[func]] name = "S_StartWBuy" addr = 0x45909F size = 0xCA [[func]] name = "WitchSellOk" addr = 0x459169 size = 0x5B [[func]] name = "S_StartWSell" addr = 0x4591C4 size = 0x26D [[func]] name = "WitchRechargeOk" addr = 0x459431 size = 0x2F [[func]] name = "AddStoreHoldRecharge" addr = 0x459460 size = 0x86 [[func]] name = "S_StartWRecharge" addr = 0x4594E6 size = 0x1AD [[func]] name = "S_StartNoMoney" addr = 0x459693 size = 0x3A [[func]] name = "S_StartNoRoom" addr = 0x4596CD size = 0x33 [[func]] name = "S_StartConfirm" addr = 0x459700 size = 0x173 [[func]] name = "S_StartBoy" addr = 0x459873 size = 0xBD [[func]] name = "S_StartBBoy" addr = 0x459930 size = 0xCD [[func]] name = "S_StartHealer" addr = 0x4599FD size = 0xA8 [[func]] name = "S_ScrollHBuy" addr = 0x459AA5 size = 0xB0 [[func]] name = "S_StartHBuy" addr = 0x459B55 size = 0xC0 [[func]] name = "S_StartStory" addr = 0x459C15 size = 0x79 [[func]] name = "IdItemOk" addr = 0x459C8E size = 0x14 [[func]] name = "AddStoreHoldId" addr = 0x459CA2 size = 0x44 [[func]] name = "S_StartSIdentify" addr = 0x459CE6 size = 0x2AF [[func]] name = "S_StartIdShow" addr = 0x459F95 size = 0xB1 [[func]] name = "S_StartTalk" addr = 0x45A046 size = 0x122 [[func]] name = "S_StartTavern" addr = 0x45A168 size = 0x84 [[func]] name = "S_StartBarMaid" addr = 0x45A1EC size = 0x72 [[func]] name = "S_StartDrunk" addr = 0x45A25E size = 0x72 [[func]] name = "StartStore" addr = 0x45A2D0 size = 0x163 [[func]] name = "DrawSText" addr = 0x45A48F size = 0xF5 [[func]] name = "STextESC" addr = 0x45A584 size = 0xE0 [[func]] name = "STextUp" addr = 0x45A6AF size = 0xA8 [[func]] name = "STextDown" addr = 0x45A757 size = 0xAD [[func]] name = "STextPrior" addr = 0x45A804 size = 0x4A [[func]] name = "STextNext" addr = 0x45A84E size = 0x4D [[func]] name = "S_SmithEnter" addr = 0x45A89B size = 0x69 [[func]] name = "SetGoldCurs" addr = 0x45A904 size = 0x46 [[func]] name = "SetSpdbarGoldCurs" addr = 0x45A94A size = 0x46 [[func]] name = "TakePlrsMoney" addr = 0x45A990 size = 0x1D9 [[func]] name = "SmithBuyItem" addr = 0x45AB69 size = 0xAB [[func]] name = "S_SBuyEnter" addr = 0x45AC14 size = 0xD5 [[func]] name = "SmithBuyPItem" addr = 0x45ACE9 size = 0x95 [[func]] name = "S_SPBuyEnter" addr = 0x45AD7E size = 0xF4 [[func]] name = "StoreGoldFit" addr = 0x45AE72 size = 0xD6 [[func]] name = "PlaceStoreGold" addr = 0x45AF48 size = 0xC8 [[func]] name = "StoreSellItem" addr = 0x45B010 size = 0x150 [[func]] name = "S_SSellEnter" addr = 0x45B160 size = 0x7F [[func]] name = "SmithRepairItem" addr = 0x45B1DF size = 0xD7 [[func]] name = "S_SRepairEnter" addr = 0x45B2B6 size = 0x81 [[func]] name = "S_WitchEnter" addr = 0x45B337 size = 0x68 [[func]] name = "WitchBuyItem" addr = 0x45B39F size = 0xB8 [[func]] name = "S_WBuyEnter" addr = 0x45B457 size = 0xD5 [[func]] name = "S_WSellEnter" addr = 0x45B52C size = 0x7F [[func]] name = "WitchRechargeItem" addr = 0x45B5AB size = 0x89 [[func]] name = "S_WRechargeEnter" addr = 0x45B634 size = 0x81 [[func]] name = "S_BoyEnter" addr = 0x45B6B5 size = 0xA2 [[func]] name = "BoyBuyItem" addr = 0x45B757 size = 0x3A [[func]] name = "HealerBuyItem" addr = 0x45B791 size = 0x104 [[func]] name = "S_BBuyEnter" addr = 0x45B895 size = 0xD3 [[func]] name = "StoryIdItem" addr = 0x45B968 size = 0xEF [[func]] name = "S_ConfirmEnter" addr = 0x45BA57 size = 0xA0 [[func]] name = "S_HealerEnter" addr = 0x45BAF7 size = 0xA8 [[func]] name = "S_HBuyEnter" addr = 0x45BB9F size = 0xD5 [[func]] name = "S_StoryEnter" addr = 0x45BC74 size = 0x56 [[func]] name = "S_SIDEnter" addr = 0x45BCCA size = 0x81 [[func]] name = "S_TalkEnter" addr = 0x45BD4B size = 0xFF [[func]] name = "S_TavernEnter" addr = 0x45BE4A size = 0x4E [[func]] name = "S_BarmaidEnter" addr = 0x45BE98 size = 0x4E [[func]] name = "S_DrunkEnter" addr = 0x45BEE6 size = 0x4E [[func]] name = "STextEnter" addr = 0x45BF34 size = 0xC3 [[func]] name = "CheckStoreBtn" addr = 0x45C053 size = 0x137 [[func]] name = "ReleaseStoreBtn" addr = 0x45C18A size = 0xF [[func]] name = "sync_all_monsters" addr = 0x45C199 size = 0x85 [[func]] name = "sync_one_monster" addr = 0x45C21E size = 0xA6 [[func]] name = "sync_monster_active" addr = 0x45C2C4 size = 0x53 [[func]] name = "sync_monster_pos" addr = 0x45C317 size = 0x6F [[func]] name = "sync_monster_active2" addr = 0x45C386 size = 0x60 [[func]] name = "SyncPlrInv" addr = 0x45C3E6 size = 0x1E1 [[func]] name = "sync_update" addr = 0x45C5C7 size = 0x74 [[func]] name = "sync_monster" addr = 0x45C63B size = 0x210 [[func]] name = "sync_init" addr = 0x45C84B size = 0x25 [[func]] name = "TFit_Shrine" addr = 0x45C870 size = 0x123 [[func]] name = "TFit_Obj5" addr = 0x45C993 size = 0xDF [[func]] name = "TFit_SkelRoom" addr = 0x45CA72 size = 0x52 [[func]] name = "TFit_GoatShrine" addr = 0x45CAC4 size = 0x45 [[func]] name = "CheckThemeObj3" addr = 0x45CB09 size = 0x7F [[func]] name = "TFit_Obj3" addr = 0x45CB88 size = 0x5C [[func]] name = "CheckThemeReqs" addr = 0x45CBE4 size = 0x80 [[func]] name = "SpecialThemeFit" addr = 0x45CC64 size = 0xF6 [[func]] name = "CheckThemeRoom" addr = 0x45CD9A size = 0x138 [[func]] name = "InitThemes" addr = 0x45CED2 size = 0x1B5 [[func]] name = "HoldThemeRooms" addr = 0x45D087 size = 0x5A [[func]] name = "PlaceThemeMonsts" addr = 0x45D0E1 size = 0xE1 [[func]] name = "Theme_Barrel" addr = 0x45D1C2 size = 0xD8 [[func]] name = "Theme_Shrine" addr = 0x45D29A size = 0xB3 [[func]] name = "Theme_MonstPit" addr = 0x45D34D size = 0x99 [[func]] name = "Theme_SkelRoom" addr = 0x45D3E6 size = 0x1D6 [[func]] name = "Theme_Treasure" addr = 0x45D5BC size = 0x14B [[func]] name = "Theme_Library" addr = 0x45D707 size = 0x183 [[func]] name = "Theme_Torture" addr = 0x45D88A size = 0xD3 [[func]] name = "Theme_BloodFountain" addr = 0x45D95D size = 0x46 [[func]] name = "Theme_Decap" addr = 0x45D9A3 size = 0xD3 [[func]] name = "Theme_PurifyingFountain" addr = 0x45DA76 size = 0x46 [[func]] name = "Theme_ArmorStand" addr = 0x45DABC size = 0xF1 [[func]] name = "Theme_GoatShrine" addr = 0x45DBAD size = 0xCE [[func]] name = "Theme_Cauldron" addr = 0x45DC7B size = 0x46 [[func]] name = "Theme_MurkyFountain" addr = 0x45DCC1 size = 0x46 [[func]] name = "Theme_TearFountain" addr = 0x45DD07 size = 0x46 [[func]] name = "Theme_BrnCross" addr = 0x45DD4D size = 0xD3 [[func]] name = "Theme_WeaponRack" addr = 0x45DE20 size = 0xF1 [[func]] name = "UpdateL4Trans" addr = 0x45DF11 size = 0x20 [[func]] name = "CreateThemeRooms" addr = 0x45DF31 size = 0x117 [[func]] name = "tmsg_get" addr = 0x45E08C size = 0x4B [[func]] name = "tmsg_add" addr = 0x45E0D7 size = 0x53 [[func]] name = "tmsg_cleanup" addr = 0x45E12A size = 0x27 [[func]] name = "town_clear_upper_buf" addr = 0x45E151 size = 0x66 [[func]] name = "town_clear_low_buf" addr = 0x45E1B7 size = 0x6F [[func]] name = "town_draw_clipped_e_flag" addr = 0x45E226 size = 0x7F [[func]] name = "town_draw_clipped_town" addr = 0x45E2A5 size = 0x30B [[func]] name = "town_draw_lower" addr = 0x45E5B0 size = 0x2E8 [[func]] name = "town_draw_clipped_e_flag_2" addr = 0x45E898 size = 0xA1 [[func]] name = "town_draw_clipped_town_2" addr = 0x45E939 size = 0x310 [[func]] name = "town_draw_lower_2" addr = 0x45EC49 size = 0x341 [[func]] name = "town_draw_e_flag" addr = 0x45EF8A size = 0x89 [[func]] name = "town_draw_town_all" addr = 0x45F013 size = 0x310 [[func]] name = "town_draw_upper" addr = 0x45F323 size = 0x33A [[func]] name = "T_DrawGame" addr = 0x45F65D size = 0x1D9 [[func]] name = "T_DrawZoom" addr = 0x45F856 size = 0x235 [[func]] name = "T_DrawView" addr = 0x45FAAB size = 0x12C [[func]] name = "SetTownMicros" addr = 0x45FBD7 size = 0xE8 [[func]] name = "T_FillSector" addr = 0x45FCBF size = 0xB6 [[func]] name = "T_FillTile" addr = 0x45FD75 size = 0x71 [[func]] name = "T_Pass3" addr = 0x45FDE6 size = 0x19D [[func]] name = "CreateTown" addr = 0x45FF83 size = 0x218 [[func]] name = "GetActiveTowner" addr = 0x46019B size = 0x26 [[func]] name = "SetTownerGPtrs" addr = 0x4601C1 size = 0x3A [[func]] name = "NewTownerAnim" addr = 0x4601FB size = 0x34 [[func]] name = "InitTownerInfo" addr = 0x46022F size = 0x95 [[func]] name = "InitQstSnds" addr = 0x4602C4 size = 0x4D [[func]] name = "InitSmith" addr = 0x460311 size = 0x8F [[func]] name = "InitBarOwner" addr = 0x4603A0 size = 0x96 [[func]] name = "InitTownDead" addr = 0x460436 size = 0x90 [[func]] name = "InitWitch" addr = 0x4604C6 size = 0x8F [[func]] name = "InitBarmaid" addr = 0x460555 size = 0x8F [[func]] name = "InitBoy" addr = 0x4605E4 size = 0x96 [[func]] name = "InitHealer" addr = 0x46067A size = 0x8F [[func]] name = "InitTeller" addr = 0x460709 size = 0x8F [[func]] name = "InitDrunk" addr = 0x460798 size = 0x8F [[func]] name = "InitCows" addr = 0x460827 size = 0x14F [[func]] name = "InitTowners" addr = 0x460976 size = 0x4D [[func]] name = "FreeTownerGFX" addr = 0x4609C3 size = 0x42 [[func]] name = "TownCtrlMsg" addr = 0x460A05 size = 0x73 [[func]] name = "TownBlackSmith" addr = 0x460A78 size = 0xE [[func]] name = "TownBarOwner" addr = 0x460A86 size = 0xF [[func]] name = "TownDead" addr = 0x460A95 size = 0x78 [[func]] name = "TownHealer" addr = 0x460B0D size = 0xF [[func]] name = "TownStory" addr = 0x460B1C size = 0xF [[func]] name = "TownDrunk" addr = 0x460B2B size = 0xF [[func]] name = "TownBoy" addr = 0x460B3A size = 0xF [[func]] name = "TownWitch" addr = 0x460B49 size = 0xF [[func]] name = "TownBarMaid" addr = 0x460B58 size = 0xF [[func]] name = "TownCow" addr = 0x460B67 size = 0xF [[func]] name = "ProcessTowners" addr = 0x460B76 size = 0xBE [[func]] name = "PlrHasItem" addr = 0x460C5C size = 0x50 [[func]] name = "TownerTalk" addr = 0x460CAC size = 0x1D [[func]] name = "TalkToTowner" addr = 0x460CC9 size = 0xB1F [[func]] name = "CowSFX" addr = 0x4617E8 size = 0xBD [[func]] name = "track_process" addr = 0x4618B5 size = 0x9E [[func]] name = "track_repeat_walk" addr = 0x461953 size = 0x4C [[func]] name = "track_isscrolling" addr = 0x46199F size = 0x8 [[func]] name = "InitNoTriggers" addr = 0x4619A7 size = 0xF [[func]] name = "InitTownTriggers" addr = 0x4619B6 size = 0x18F [[func]] name = "InitL1Triggers" addr = 0x461B45 size = 0xA9 [[func]] name = "InitL2Triggers" addr = 0x461BEE size = 0x108 [[func]] name = "InitL3Triggers" addr = 0x461CF6 size = 0xD0 [[func]] name = "InitL4Triggers" addr = 0x461DC6 size = 0x144 [[func]] name = "InitSKingTriggers" addr = 0x461F0A size = 0x30 [[func]] name = "InitSChambTriggers" addr = 0x461F3A size = 0x30 [[func]] name = "InitPWaterTriggers" addr = 0x461F6A size = 0x30 [[func]] name = "InitVPTriggers" addr = 0x461F9A size = 0x30 [[func]] name = "ForceTownTrig" addr = 0x461FCA size = 0x166 [[func]] name = "ForceL1Trig" addr = 0x462130 size = 0x11C [[func]] name = "ForceL2Trig" addr = 0x46224C size = 0x203 [[func]] name = "ForceL3Trig" addr = 0x46244F size = 0x1DE [[func]] name = "ForceL4Trig" addr = 0x46262D size = 0x249 [[func]] name = "Freeupstairs" addr = 0x462876 size = 0x41 [[func]] name = "ForceSKingTrig" addr = 0x4628B7 size = 0x68 [[func]] name = "ForceSChambTrig" addr = 0x46291F size = 0x68 [[func]] name = "ForcePWaterTrig" addr = 0x462987 size = 0x68 [[func]] name = "CheckTrigForce" addr = 0x4629EF size = 0xAE [[func]] name = "CheckTriggers" addr = 0x462A9D size = 0x1D0 [[func]] name = "WCloseFile" addr = 0x462C7D size = 0x7 [[func]] name = "WGetFileSize" addr = 0x462C84 size = 0x2B [[func]] name = "WGetFileArchive" addr = 0x462CAF size = 0x57 [[func]] name = "WOpenFile" addr = 0x462D06 size = 0x42 [[func]] name = "WReadFile" addr = 0x462D48 size = 0x52 [[func]] name = "WSetFilePointer" addr = 0x462D9A size = 0x34 [[func]] name = "LoadWaveFormat" addr = 0x462DCE size = 0x2E [[func]] name = "AllocateMemFile" addr = 0x462DFC size = 0x49 [[func]] name = "FreeMemFile" addr = 0x462E45 size = 0xE [[func]] name = "ReadWaveFile" addr = 0x462E53 size = 0xCA [[func]] name = "ReadMemFile" addr = 0x462F1D size = 0x56 [[func]] name = "FillMemFile" addr = 0x462F73 size = 0x3B [[func]] name = "SeekMemFile" addr = 0x462FAE size = 0x1E [[func]] name = "ReadWaveSection" addr = 0x462FCC size = 0x57 [[func]] name = "LoadWaveFile" addr = 0x463023 size = 0x38 [[func]] name = "drawTopArchesUpperScreen" addr = 0x463060 size = 0x162D [[func]] name = "drawBottomArchesUpperScreen" addr = 0x46468D size = 0xC38 [[func]] name = "drawUpperScreen" addr = 0x4652C5 size = 0xC73 [[func]] name = "drawTopArchesLowerScreen" addr = 0x465F38 size = 0x1A11 [[func]] name = "drawBottomArchesLowerScreen" addr = 0x467949 size = 0xF22 [[func]] name = "drawLowerScreen" addr = 0x46886B size = 0xE53 [[func]] name = "world_draw_black_tile" addr = 0x4696BE size = 0x5C ================================================ FILE: comparer-config/hellfire.toml ================================================ # conversion between function and file location of the functions # = (0x401000 - PE header offset) (0x400 for VC5 linker) address_offset = 0x400C00 [[func]] name = "GetErrorStr" addr = 0x401000 size = 0xAE [[func]] name = "TraceErrorDD" addr = 0x4010AE size = 0x6D5 [[func]] name = "TraceErrorDS" addr = 0x401848 size = 0x110 [[func]] name = "TraceLastError" addr = 0x401958 size = 0xD [[func]] name = "app_fatal" addr = 0x401965 size = 0x32 [[func]] name = "MsgBox" addr = 0x401998 size = 0x52 [[func]] name = "FreeDlg" addr = 0x4019EA size = 0x69 [[func]] name = "DrawDlg" addr = 0x401A53 size = 0x35 [[func]] name = "DDErrMsg" addr = 0x401A88 size = 0x23 [[func]] name = "DSErrMsg" addr = 0x401AAB size = 0x23 [[func]] name = "center_window" addr = 0x401ACE size = 0x92 [[func]] name = "ErrDlg" addr = 0x401B60 size = 0x8D [[func]] name = "FuncDlg" addr = 0x401BED size = 0x45 [[func]] name = "TextDlg" addr = 0x401C32 size = 0x1F [[func]] name = "FileErrDlg" addr = 0x401C51 size = 0x45 [[func]] name = "DiskFreeDlg" addr = 0x401C96 size = 0x3C [[func]] name = "InsertCDDlg" addr = 0x401CD2 size = 0x4B [[func]] name = "InitAutomapOnce" addr = 0x401D1D size = 0x44 [[func]] name = "InitAutomap" addr = 0x401D61 size = 0x148 [[func]] name = "StartAutomap" addr = 0x401EA9 size = 0x19 [[func]] name = "AutomapUp" addr = 0x401EC2 size = 0xD [[func]] name = "AutomapDown" addr = 0x401ECF size = 0xD [[func]] name = "AutomapLeft" addr = 0x401EDC size = 0xD [[func]] name = "AutomapRight" addr = 0x401EE9 size = 0xD [[func]] name = "AutomapZoomIn" addr = 0x401EF6 size = 0x3F [[func]] name = "AutomapZoomOut" addr = 0x401F35 size = 0x3D [[func]] name = "DrawAutomap" addr = 0x401F72 size = 0x284 [[func]] name = "DrawAutomapTile" addr = 0x4021F6 size = 0x781 [[func]] name = "SearchAutomapItem" addr = 0x4029A7 size = 0x1A3 [[func]] name = "DrawAutomapItem" addr = 0x402B4A size = 0x8E [[func]] name = "DrawAutomapPlr" addr = 0x402BD8 size = 0x3B4 [[func]] name = "GetAutomapType" addr = 0x402FAC size = 0xD4 [[func]] name = "DrawAutomapText" addr = 0x403080 size = 0x109 [[func]] name = "SetAutomapView" addr = 0x403189 size = 0x1A1 [[func]] name = "AutomapZoomReset" addr = 0x40332A size = 0x3E [[func]] name = "CaptureScreen" addr = 0x403368 size = 0xE9 [[func]] name = "CaptureHdr" addr = 0x403451 size = 0x96 [[func]] name = "CapturePal" addr = 0x4034E7 size = 0x69 [[func]] name = "CapturePix" addr = 0x403550 size = 0x79 [[func]] name = "CaptureEnc" addr = 0x4035C9 size = 0x3C [[func]] name = "CaptureFile" addr = 0x403605 size = 0xCA [[func]] name = "RedPalette" addr = 0x4036CF size = 0x53 [[func]] name = "codec_decode" addr = 0x403722 size = 0x106 [[func]] name = "codec_init_key" addr = 0x40382D size = 0xD4 [[func]] name = "codec_get_encoded_len" addr = 0x403901 size = 0x12 [[func]] name = "codec_encode" addr = 0x403913 size = 0x119 [[func]] name = "DrawSpellCel" addr = 0x403A2C size = 0xAA [[func]] name = "SetSpellTrans" addr = 0x403AD6 size = 0x11D [[func]] name = "DrawSpell" addr = 0x403BF3 size = 0xDA [[func]] name = "DrawSpellList" addr = 0x403CCD size = 0x54C [[func]] name = "SetSpell" addr = 0x404219 size = 0x5C [[func]] name = "SetSpeedSpell" addr = 0x404275 size = 0xA2 [[func]] name = "ToggleSpell" addr = 0x404317 size = 0xF5 [[func]] name = "PrintChar" addr = 0x40440C size = 0x13E [[func]] name = "AddPanelString" addr = 0x40454A size = 0x32 [[func]] name = "ClearPanel" addr = 0x40457C size = 0xF [[func]] name = "DrawPanelBox" addr = 0x40458B size = 0x6C [[func]] name = "SetFlaskHeight" addr = 0x4045FC size = 0x51 [[func]] name = "DrawFlask" addr = 0x40464D size = 0x40 [[func]] name = "DrawLifeFlask" addr = 0x40468D size = 0xC5 [[func]] name = "UpdateLifeFlask" addr = 0x404752 size = 0x95 [[func]] name = "DrawManaFlask" addr = 0x4047E7 size = 0x80 [[func]] name = "control_update_life_mana" addr = 0x404867 size = 0x92 [[func]] name = "UpdateManaFlask" addr = 0x4048F9 size = 0xB5 [[func]] name = "InitControlPan" addr = 0x4049AE size = 0x358 [[func]] name = "DrawCtrlPan" addr = 0x404D06 size = 0x25 [[func]] name = "DrawCtrlBtns" addr = 0x404D2B size = 0xBB [[func]] name = "DoSpeedBook" addr = 0x404DE6 size = 0x14D [[func]] name = "DoPanBtn" addr = 0x404F33 size = 0xA2 [[func]] name = "control_set_button_down" addr = 0x404FD5 size = 0x15 [[func]] name = "control_check_btn_press" addr = 0x404FEA size = 0x84 [[func]] name = "DoAutoMap" addr = 0x40506E size = 0x2C [[func]] name = "CheckPanelInfo" addr = 0x40509A size = 0x36E [[func]] name = "CheckBtnUp" addr = 0x405408 size = 0x182 [[func]] name = "FreeControlPan" addr = 0x4055AA size = 0x115 [[func]] name = "control_WriteStringToBuffer" addr = 0x4056BF size = 0x31 [[func]] name = "DrawInfoBox" addr = 0x4056F0 size = 0x2C8 [[func]] name = "PrintInfo" addr = 0x4059B8 size = 0x76 [[func]] name = "CPrintString" addr = 0x405A2E size = 0xBE [[func]] name = "PrintGameStr" addr = 0x405AEC size = 0x57 [[func]] name = "DrawChr" addr = 0x405B43 size = 0xA9F [[func]] name = "ADD_PlrStringXY" addr = 0x4065E2 size = 0xB7 [[func]] name = "MY_PlrStringXY" addr = 0x406699 size = 0xBF [[func]] name = "CheckLvlBtn" addr = 0x406758 size = 0x36 [[func]] name = "ReleaseLvlBtn" addr = 0x40678E size = 0x34 [[func]] name = "DrawLevelUpIcon" addr = 0x4067C2 size = 0x46 [[func]] name = "CheckChrBtns" addr = 0x406808 size = 0xF7 [[func]] name = "ReleaseChrBtns" addr = 0x4068FF size = 0xBA [[func]] name = "DrawDurIcon" addr = 0x4069B9 size = 0x86 [[func]] name = "DrawDurIcon4Item" addr = 0x406A3F size = 0x79 [[func]] name = "RedBack" addr = 0x406AB8 size = 0x8A [[func]] name = "GetSBookTrans" addr = 0x406B42 size = 0xE2 [[func]] name = "DrawSpellBook" addr = 0x406C24 size = 0x2B1 [[func]] name = "PrintSBookStr" addr = 0x406ED5 size = 0xBB [[func]] name = "CheckSBook" addr = 0x406F90 size = 0x148 [[func]] name = "get_pieces_str" addr = 0x4070D8 size = 0x10 [[func]] name = "DrawGoldSplit" addr = 0x4070E8 size = 0x12F [[func]] name = "control_drop_gold" addr = 0x407217 size = 0x12F [[func]] name = "control_remove_gold" addr = 0x407346 size = 0x114 [[func]] name = "control_set_gold_curs" addr = 0x40745A size = 0x59 [[func]] name = "DrawTalkPan" addr = 0x4074B3 size = 0x20F [[func]] name = "control_print_talk_msg" addr = 0x4076C2 size = 0x83 [[func]] name = "control_check_talk_btn" addr = 0x407745 size = 0x5B [[func]] name = "control_release_talk_btn" addr = 0x4077A0 size = 0x74 [[func]] name = "control_type_message" addr = 0x407814 size = 0x47 [[func]] name = "control_reset_talk" addr = 0x40785B size = 0x19 [[func]] name = "control_talk_last_key" addr = 0x407874 size = 0x40 [[func]] name = "control_presskeys" addr = 0x4078B4 size = 0x6A [[func]] name = "control_press_enter" addr = 0x40791E size = 0xDB [[func]] name = "control_up_down" addr = 0x4079F9 size = 0x4D [[func]] name = "InitCursor" addr = 0x407A46 size = 0x27 [[func]] name = "FreeCursor" addr = 0x407A6D size = 0x29 [[func]] name = "SetICursor" addr = 0x407A96 size = 0x34 [[func]] name = "SetCursor_" addr = 0x407ACA size = 0x23 [[func]] name = "NewCursor" addr = 0x407AED size = 0x5 [[func]] name = "InitLevelCursor" addr = 0x407AF2 size = 0x3D [[func]] name = "CheckTown" addr = 0x407B2F size = 0x144 [[func]] name = "CheckRportal" addr = 0x407C73 size = 0x136 [[func]] name = "CheckCursMove" addr = 0x407DA9 size = 0xE2F [[func]] name = "InitDead" addr = 0x408BD8 size = 0x1B0 [[func]] name = "AddDead" addr = 0x408D88 size = 0x21 [[func]] name = "SyncUniqDead" addr = 0x408DA9 size = 0x84 [[func]] name = "LoadDebugGFX" addr = 0x408E2D size = 0x1B [[func]] name = "FreeDebugGFX" addr = 0x408E48 size = 0x12 [[func]] name = "CheckDungeonClear" addr = 0x408E5A size = 0x8F [[func]] name = "FreeGameMem" addr = 0x408EE9 size = 0x78 [[func]] name = "StartGame" addr = 0x408F61 size = 0xB4 [[func]] name = "run_game_loop" addr = 0x409015 size = 0x1A0 [[func]] name = "start_game" addr = 0x4091B5 size = 0x50 [[func]] name = "free_game" addr = 0x409205 size = 0x44 [[func]] name = "diablo_get_not_running" addr = 0x409249 size = 0x3A [[func]] name = "WinMain" addr = 0x409283 size = 0x176 [[func]] name = "diablo_parse_flags" addr = 0x4093F9 size = 0x203 [[func]] name = "diablo_init_screen" addr = 0x4095FC size = 0x50 [[func]] name = "diablo_TopLevelExceptionFilter" addr = 0x40964C size = 0x22 [[func]] name = "diablo_find_window" addr = 0x40966E size = 0x43 [[func]] name = "diablo_reload_process" addr = 0x4096B1 size = 0x211 [[func]] name = "PressEscKey" addr = 0x4098C2 size = 0x8F [[func]] name = "DisableInputWndProc" addr = 0x409951 size = 0xC9 [[func]] name = "GM_Game" addr = 0x409A1A size = 0x278 [[func]] name = "LeftMouseDown" addr = 0x409C92 size = 0x1FA [[func]] name = "LeftMouseCmd" addr = 0x409E8C size = 0x24D [[func]] name = "TryIconCurs" addr = 0x40A0D9 size = 0x1F0 [[func]] name = "LeftMouseUp" addr = 0x40A2C9 size = 0x45 [[func]] name = "RightMouseDown" addr = 0x40A30E size = 0xE8 [[func]] name = "PressSysKey" addr = 0x40A3FB size = 0x22 [[func]] name = "diablo_hotkey_msg" addr = 0x40A41D size = 0xA1 [[func]] name = "ReleaseKey" addr = 0x40A4BE size = 0xB [[func]] name = "PressKey" addr = 0x40A4C9 size = 0x433 [[func]] name = "diablo_pause_game" addr = 0x40A8FC size = 0x3C [[func]] name = "PressChar" addr = 0x40A938 size = 0x530 [[func]] name = "LoadLvlGFX" addr = 0x40AE68 size = 0x1C5 [[func]] name = "LoadAllGFX" addr = 0x40B02D size = 0x2D [[func]] name = "CreateLevel" addr = 0x40B05A size = 0xF7 [[func]] name = "LoadGameLevel" addr = 0x40B151 size = 0x5A8 [[func]] name = "game_loop" addr = 0x40B6F9 size = 0x53 [[func]] name = "game_logic" addr = 0x40B74C size = 0xB4 [[func]] name = "timeout_cursor" addr = 0x40B800 size = 0x84 [[func]] name = "diablo_color_cyc_logic" addr = 0x40B884 size = 0x53 [[func]] name = "alloc_plr" addr = 0x40B8D7 size = 0x31 [[func]] name = "get_plr_mem" addr = 0x40B908 size = 0x57 [[func]] name = "doom_get_frame_from_time" addr = 0x40B95F size = 0x19 [[func]] name = "doom_alloc_cel" addr = 0x40B9CC size = 0x1E [[func]] name = "doom_cleanup" addr = 0x40B978 size = 0x1F [[func]] name = "doom_load_graphics" addr = 0x40B9EA size = 0x2E [[func]] name = "doom_init" addr = 0x40B997 size = 0x35 [[func]] name = "doom_close" addr = 0x40BA18 size = 0xC [[func]] name = "doom_draw" addr = 0x40BA24 size = 0x24 [[func]] name = "DRLG_Init_Globals" addr = 0x40BA48 size = 0xB5 [[func]] name = "LoadL1Dungeon" addr = 0x40BAFD size = 0xF6 [[func]] name = "DRLG_L1Floor" addr = 0x40BBF3 size = 0x4E [[func]] name = "DRLG_L1Pass3" addr = 0x40BC41 size = 0xF2 [[func]] name = "DRLG_InitL1Vals" addr = 0x40BD33 size = 0xBB [[func]] name = "LoadPreL1Dungeon" addr = 0x40BDEE size = 0xCA [[func]] name = "CreateL5Dungeon" addr = 0x40BEB8 size = 0xF1 [[func]] name = "DRLG_LoadL1SP" addr = 0x40BFA9 size = 0x7E [[func]] name = "DRLG_FreeL1SP" addr = 0x40C027 size = 0x12 [[func]] name = "DRLG_InitL5Vals" addr = 0x40C039 size = 0x46 [[func]] name = "DRLG_L5" addr = 0x40C07F size = 0x50F [[func]] name = "DRLG_PlaceDoor" addr = 0x40C58E size = 0x190 [[func]] name = "drlg_l1_crypt_lavafloor" addr = 0x40C71E size = 0x1BC [[func]] name = "DRLG_L1Shadows" addr = 0x40CA03 size = 0x1ED [[func]] name = "DRLG_PlaceMiniSet" addr = 0x40CBF0 size = 0x291 [[func]] name = "InitL5Dungeon" addr = 0x40CE81 size = 0x22 [[func]] name = "L5ClearFlags" addr = 0x40CEA3 size = 0x1B [[func]] name = "L5firstRoom" addr = 0x40CEBE size = 0x237 [[func]] name = "L5drawRoom" addr = 0x40D0F5 size = 0x37 [[func]] name = "L5roomGen" addr = 0x40D12C size = 0x209 [[func]] name = "L5checkRoom" addr = 0x40D335 size = 0x64 [[func]] name = "L5GetArea" addr = 0x40D399 size = 0x22 [[func]] name = "L5makeDungeon" addr = 0x40D3BB size = 0x44 [[func]] name = "L5makeDmt" addr = 0x40D3FF size = 0x76 [[func]] name = "L5AddWall" addr = 0x40D475 size = 0x15C [[func]] name = "L5HWallOk" addr = 0x40D5D1 size = 0x8F [[func]] name = "L5VWallOk" addr = 0x40D660 size = 0x7C [[func]] name = "L5HorizWall" addr = 0x40D6DC size = 0xED [[func]] name = "L5VertWall" addr = 0x40D7C9 size = 0x106 [[func]] name = "L5tileFix" addr = 0x40D8CF size = 0x46F [[func]] name = "drlg_l1_crypt_rndset" addr = 0x40DD3E size = 0x17E [[func]] name = "DRLG_L5Subs" addr = 0x40DEBC size = 0xE3 [[func]] name = "L5FillChambers" addr = 0x40DF9F size = 0x76E [[func]] name = "DRLG_L5GChamber" addr = 0x40E70D size = 0x14B [[func]] name = "DRLG_L5GHall" addr = 0x40E858 size = 0x50 [[func]] name = "DRLG_L5SetRoom" addr = 0x40E8A8 size = 0x85 [[func]] name = "drlg_l1_set_crypt_room" addr = 0x40E92D size = 0xAF [[func]] name = "drlg_l1_set_corner_room" addr = 0x40E9DC size = 0x8B [[func]] name = "DRLG_L5FloodTVal" addr = 0x40EA67 size = 0x6F [[func]] name = "DRLG_L5FTVR" addr = 0x40EAD6 size = 0x1F4 [[func]] name = "DRLG_L5TransFix" addr = 0x40ECCA size = 0x94 [[func]] name = "DRLG_L5DirtFix" addr = 0x40ED5E size = 0xB5 [[func]] name = "DRLG_L5CornerFix" addr = 0x40EE13 size = 0x67 [[func]] name = "drlg_l1_crypt_pattern1" addr = 0x40EE7A size = 0x35 [[func]] name = "drlg_l1_crypt_pattern2" addr = 0x40EEAF size = 0xD1 [[func]] name = "drlg_l1_crypt_pattern3" addr = 0x40EF80 size = 0xD1 [[func]] name = "drlg_l1_crypt_pattern4" addr = 0x40F051 size = 0xD1 [[func]] name = "drlg_l1_crypt_pattern5" addr = 0x40F122 size = 0x7D [[func]] name = "drlg_l1_crypt_pattern6" addr = 0x40F19F size = 0x13D [[func]] name = "drlg_l1_crypt_pattern7" addr = 0x40F2DC size = 0x35 [[func]] name = "InitDungeon" addr = 0x40F311 size = 0x22 [[func]] name = "L2LockoutFix" addr = 0x40F333 size = 0x150 [[func]] name = "L2DoorFix" addr = 0x40F483 size = 0x35 [[func]] name = "LoadL2Dungeon" addr = 0x40F4B8 size = 0x1C0 [[func]] name = "DRLG_L2Pass3" addr = 0x40F678 size = 0xF2 [[func]] name = "LoadPreL2Dungeon" addr = 0x40F76A size = 0xD6 [[func]] name = "CreateL2Dungeon" addr = 0x40F840 size = 0xCB [[func]] name = "DRLG_LoadL2SP" addr = 0x40F90B size = 0x59 [[func]] name = "DRLG_FreeL2SP" addr = 0x40F964 size = 0x12 [[func]] name = "DRLG_L2" addr = 0x40F976 size = 0x6CF [[func]] name = "DRLG_L2PlaceMiniSet" addr = 0x410045 size = 0x25D [[func]] name = "DRLG_L2PlaceRndSet" addr = 0x4102A2 size = 0x1A7 [[func]] name = "DRLG_L2Subs" addr = 0x410449 size = 0xF7 [[func]] name = "DRLG_L2Shadows" addr = 0x410540 size = 0xD0 [[func]] name = "DRLG_L2SetRoom" addr = 0x410610 size = 0x85 [[func]] name = "L2TileFix" addr = 0x410695 size = 0x63 [[func]] name = "CreateDungeon" addr = 0x4106F8 size = 0x152 [[func]] name = "CreateRoom" addr = 0x41084A size = 0x45F [[func]] name = "DefineRoom" addr = 0x410CA9 size = 0x124 [[func]] name = "AddHall" addr = 0x410DCD size = 0x8F [[func]] name = "GetHall" addr = 0x410E5C size = 0x5D [[func]] name = "ConnectHall" addr = 0x410EB9 size = 0x35D [[func]] name = "CreateDoorType" addr = 0x411216 size = 0x61 [[func]] name = "PlaceHallExt" addr = 0x411277 size = 0x18 [[func]] name = "DoPatternCheck" addr = 0x41128F size = 0x16D [[func]] name = "DL2_FillVoids" addr = 0x411420 size = 0x57A [[func]] name = "DL2_Cont" addr = 0x41199A size = 0x46 [[func]] name = "DL2_NumNoChar" addr = 0x4119E0 size = 0x22 [[func]] name = "DL2_DrawRoom" addr = 0x411A02 size = 0x89 [[func]] name = "DL2_KnockWalls" addr = 0x411A8B size = 0xDB [[func]] name = "DRLG_L2FloodTVal" addr = 0x411B66 size = 0x6F [[func]] name = "DRLG_L2FTVR" addr = 0x411BD5 size = 0x1F4 [[func]] name = "DRLG_L2TransFix" addr = 0x411DC9 size = 0x94 [[func]] name = "L2DirtFix" addr = 0x411E5D size = 0x6C [[func]] name = "DRLG_InitL2Vals" addr = 0x411EC9 size = 0xC2 [[func]] name = "AddFenceDoors" addr = 0x411F8B size = 0x64 [[func]] name = "FenceDoorFix" addr = 0x411FEF size = 0x113 [[func]] name = "DRLG_L3Anvil" addr = 0x412102 size = 0x152 [[func]] name = "FixL3Warp" addr = 0x412254 size = 0x64 [[func]] name = "FixL3HallofHeroes" addr = 0x4122B8 size = 0x74 [[func]] name = "DRLG_L3LockRec" addr = 0x41232C size = 0x58 [[func]] name = "DRLG_L3Lockout" addr = 0x412384 size = 0x5D [[func]] name = "CreateL3Dungeon" addr = 0x4123E1 size = 0xEA [[func]] name = "DRLG_L3" addr = 0x4124CB size = 0x882 [[func]] name = "InitL3Dungeon" addr = 0x412D4D size = 0x36 [[func]] name = "DRLG_L3FillRoom" addr = 0x412D83 size = 0x13B [[func]] name = "DRLG_L3CreateBlock" addr = 0x412EBE size = 0x1EB [[func]] name = "DRLG_L3FloorArea" addr = 0x4130A9 size = 0x34 [[func]] name = "DRLG_L3FillDiags" addr = 0x4130DD size = 0x71 [[func]] name = "DRLG_L3FillSingles" addr = 0x41314E size = 0x5E [[func]] name = "DRLG_L3FillStraights" addr = 0x4131AC size = 0x207 [[func]] name = "DRLG_L3Edges" addr = 0x4133B3 size = 0x21 [[func]] name = "DRLG_L3GetFloorArea" addr = 0x4133D4 size = 0x23 [[func]] name = "DRLG_L3MakeMegas" addr = 0x4133F7 size = 0x8E [[func]] name = "DRLG_L3River" addr = 0x413485 size = 0x634 [[func]] name = "DRLG_L3Pool" addr = 0x413AB9 size = 0x159 [[func]] name = "DRLG_L3Spawn" addr = 0x413C12 size = 0x12F [[func]] name = "DRLG_L3SpawnEdge" addr = 0x413D41 size = 0x14A [[func]] name = "DRLG_L3PoolFix" addr = 0x413E8B size = 0x83 [[func]] name = "DRLG_L3PlaceMiniSet" addr = 0x413F0E size = 0x20A [[func]] name = "DRLG_L3PlaceRndSet" addr = 0x414118 size = 0x17E [[func]] name = "drlg_l3_hive_rnd_piece" addr = 0x414296 size = 0x18F [[func]] name = "DRLG_L3Wood" addr = 0x414425 size = 0x42B [[func]] name = "WoodVertU" addr = 0x414850 size = 0x4D [[func]] name = "WoodVertD" addr = 0x41489D size = 0x45 [[func]] name = "WoodHorizL" addr = 0x4148E2 size = 0x4D [[func]] name = "WoodHorizR" addr = 0x41492F size = 0x45 [[func]] name = "DRLG_L3Pass3" addr = 0x414974 size = 0x108 [[func]] name = "LoadL3Dungeon" addr = 0x414A7C size = 0x14B [[func]] name = "LoadPreL3Dungeon" addr = 0x414BC7 size = 0xA6 [[func]] name = "DRLG_LoadL4SP" addr = 0x414C6D size = 0x58 [[func]] name = "DRLG_FreeL4SP" addr = 0x414CC5 size = 0x12 [[func]] name = "DRLG_L4SetSPRoom" addr = 0x414CD7 size = 0x85 [[func]] name = "L4SaveQuads" addr = 0x414D5C size = 0x7D [[func]] name = "DRLG_L4SetRoom" addr = 0x414DD9 size = 0x5E [[func]] name = "DRLG_LoadDiabQuads" addr = 0x414E37 size = 0x10F [[func]] name = "IsDURWall" addr = 0x414F46 size = 0x17 [[func]] name = "IsDLLWall" addr = 0x414F5D size = 0x17 [[func]] name = "L4FixRim" addr = 0x414F74 size = 0x1E [[func]] name = "DRLG_L4GeneralFix" addr = 0x414F92 size = 0x35 [[func]] name = "CreateL4Dungeon" addr = 0x414FC7 size = 0x51 [[func]] name = "DRLG_L4" addr = 0x415018 size = 0x443 [[func]] name = "DRLG_L4Shadows" addr = 0x41545B size = 0x59 [[func]] name = "InitL4Dungeon" addr = 0x4154B4 size = 0x4A [[func]] name = "L4makeDmt" addr = 0x4154FE size = 0x5C [[func]] name = "L4AddWall" addr = 0x41555A size = 0x2F7 [[func]] name = "L4HWallOk" addr = 0x415851 size = 0x97 [[func]] name = "L4VWallOk" addr = 0x4158E8 size = 0x9B [[func]] name = "L4HorizWall" addr = 0x415983 size = 0xD4 [[func]] name = "L4VertWall" addr = 0x415A57 size = 0xE4 [[func]] name = "L4tileFix" addr = 0x415B3B size = 0x113B [[func]] name = "DRLG_L4Subs" addr = 0x416C76 size = 0xC6 [[func]] name = "L4makeDungeon" addr = 0x416D3C size = 0x119 [[func]] name = "uShape" addr = 0x416E55 size = 0x12D [[func]] name = "GetArea" addr = 0x416F82 size = 0x22 [[func]] name = "L4firstRoom" addr = 0x416FA4 size = 0x131 [[func]] name = "L4drawRoom" addr = 0x4170D5 size = 0x37 [[func]] name = "L4roomGen" addr = 0x41710C size = 0x209 [[func]] name = "L4checkRoom" addr = 0x417315 size = 0x6C [[func]] name = "DRLG_L4PlaceMiniSet" addr = 0x417381 size = 0x262 [[func]] name = "DRLG_L4FloodTVal" addr = 0x4175E3 size = 0x6F [[func]] name = "DRLG_L4FTVR" addr = 0x417652 size = 0x1F4 [[func]] name = "DRLG_L4TransFix" addr = 0x417846 size = 0xCB [[func]] name = "DRLG_L4Corners" addr = 0x417911 size = 0x35 [[func]] name = "DRLG_L4Pass3" addr = 0x417946 size = 0x108 [[func]] name = "dthread_remove_player" addr = 0x417A7C size = 0x33 [[func]] name = "dthread_send_delta" addr = 0x417AAF size = 0x7D [[func]] name = "dthread_start" addr = 0x417B2C size = 0x6D [[func]] name = "dthread_handler" addr = 0x417B99 size = 0xCD [[func]] name = "dthread_cleanup" addr = 0x417C66 size = 0xA2 [[func]] name = "dx_init" addr = 0x417D36 size = 0x116 [[func]] name = "dx_create_back_buffer" addr = 0x417E4C size = 0x10D [[func]] name = "dx_create_primary_surface" addr = 0x417F59 size = 0x58 [[func]] name = "dx_DirectDrawCreate" addr = 0x417FB1 size = 0x7B [[func]] name = "lock_buf" addr = 0x41802C size = 0x5 [[func]] name = "lock_buf_priv" addr = 0x418031 size = 0x8D [[func]] name = "unlock_buf" addr = 0x4180BE size = 0x5 [[func]] name = "unlock_buf_priv" addr = 0x4180C3 size = 0x7B [[func]] name = "dx_cleanup" addr = 0x41813E size = 0xA8 [[func]] name = "dx_reinit" addr = 0x4181E6 size = 0x60 [[func]] name = "effect_is_playing" addr = 0x41824B size = 0x2D [[func]] name = "stream_stop" addr = 0x418278 size = 0x29 [[func]] name = "InitMonsterSND" addr = 0x4182A1 size = 0xE5 [[func]] name = "FreeMonsterSnd" addr = 0x418386 size = 0x6A [[func]] name = "PlayEffect" addr = 0x4183F0 size = 0xA3 [[func]] name = "calc_snd_position" addr = 0x418493 size = 0x7A [[func]] name = "PlaySFX" addr = 0x41850D size = 0x18 [[func]] name = "PlaySFX_priv" addr = 0x418525 size = 0xC0 [[func]] name = "stream_play" addr = 0x4185E5 size = 0x6D [[func]] name = "RndSFX" addr = 0x418652 size = 0x72 [[func]] name = "PlaySfxLoc" addr = 0x4186C4 size = 0x38 [[func]] name = "sound_stop" addr = 0x4186FC size = 0x61 [[func]] name = "sfx_stop" addr = 0x41875D size = 0x20 [[func]] name = "sound_update" addr = 0x41877D size = 0x16 [[func]] name = "stream_update" addr = 0x418793 size = 0x2F [[func]] name = "effects_cleanup_sfx" addr = 0x4187C2 size = 0x26 [[func]] name = "sound_init" addr = 0x4187E8 size = 0x65 [[func]] name = "priv_sound_init" addr = 0x41884D size = 0x57 [[func]] name = "ui_sound_init" addr = 0x4188A4 size = 0x7 [[func]] name = "effects_play_sound" addr = 0x4188AB size = 0x65 [[func]] name = "Decrypt" addr = 0x418910 size = 0x56 [[func]] name = "Encrypt" addr = 0x418966 size = 0x5A [[func]] name = "Hash" addr = 0x4189C0 size = 0x4F [[func]] name = "InitHash" addr = 0x418A0F size = 0x6F [[func]] name = "PkwareCompress" addr = 0x418A7E size = 0x96 [[func]] name = "PkwareBufferRead" addr = 0x418B14 size = 0x34 [[func]] name = "PkwareBufferWrite" addr = 0x418B48 size = 0x27 [[func]] name = "PkwareDecompress" addr = 0x418B6F size = 0x71 [[func]] name = "CelBlit" addr = 0x418BE0 size = 0x68 [[func]] name = "CelDraw" addr = 0x418C48 size = 0x44 [[func]] name = "CelBlitFrame" addr = 0x418C8C size = 0x26 [[func]] name = "CelClippedDraw" addr = 0x418CB2 size = 0x7F [[func]] name = "CelClippedBlit" addr = 0x418D31 size = 0x57 [[func]] name = "CelBlitLight" addr = 0x418D88 size = 0xDC [[func]] name = "CelBlitLightTrans" addr = 0x418E64 size = 0xDD [[func]] name = "CelDrawLight" addr = 0x418F41 size = 0x58 [[func]] name = "CelClippedDrawLight" addr = 0x418F99 size = 0x92 [[func]] name = "CelClippedBlitLightTrans" addr = 0x41902B size = 0x7C [[func]] name = "CelDrawLightRed" addr = 0x4190A7 size = 0x120 [[func]] name = "CelBlitSafe" addr = 0x4191C7 size = 0x7F [[func]] name = "CelClippedDrawSafe" addr = 0x419246 size = 0x7F [[func]] name = "CelClippedBlitSafe" addr = 0x4192C5 size = 0x55 [[func]] name = "CelBlitLightSafe" addr = 0x41931A size = 0xF7 [[func]] name = "CelBlitLightTransSafe" addr = 0x419411 size = 0xF8 [[func]] name = "CelDrawLightSafe" addr = 0x419509 size = 0x90 [[func]] name = "CelClippedBlitLightTransSafe" addr = 0x419599 size = 0x76 [[func]] name = "CelDrawLightRedSafe" addr = 0x41960F size = 0x125 [[func]] name = "CelBlitWidth" addr = 0x419734 size = 0x8A [[func]] name = "CelBlitOutline" addr = 0x4197BE size = 0xFA [[func]] name = "CelBlitOutlineSafe" addr = 0x4198B8 size = 0x12F [[func]] name = "ENG_set_pixel" addr = 0x4199E7 size = 0x45 [[func]] name = "engine_draw_pixel" addr = 0x419A2C size = 0x83 [[func]] name = "DrawLine" addr = 0x419AAF size = 0x40B [[func]] name = "GetDirection" addr = 0x419EBA size = 0x6D [[func]] name = "SetRndSeed" addr = 0x419F27 size = 0x14 [[func]] name = "GetRndSeed" addr = 0x419F3B size = 0x1F [[func]] name = "random_" addr = 0x419F5A size = 0x29 [[func]] name = "engine_debug_trap" addr = 0x419FB1 size = 0x1 [[func]] name = "DiabloAllocPtr" addr = 0x419FB2 size = 0x4D [[func]] name = "mem_free_dbg" addr = 0x419FFF size = 0x30 [[func]] name = "LoadFileInMem" addr = 0x41A02F size = 0x5B [[func]] name = "LoadFileWithMem" addr = 0x41A08A size = 0x5F [[func]] name = "Cl2ApplyTrans" addr = 0x41A0E9 size = 0x84 [[func]] name = "Cl2Draw" addr = 0x41A16D size = 0x7F [[func]] name = "Cl2Blit" addr = 0x41A1EC size = 0x88 [[func]] name = "Cl2DrawOutline" addr = 0x41A274 size = 0x83 [[func]] name = "Cl2BlitOutline" addr = 0x41A2F7 size = 0xBC [[func]] name = "Cl2DrawLightTbl" addr = 0x41A3B3 size = 0xC7 [[func]] name = "Cl2BlitLight" addr = 0x41A47A size = 0xA5 [[func]] name = "Cl2DrawLight" addr = 0x41A51F size = 0xA2 [[func]] name = "Cl2DrawSafe" addr = 0x41A5C1 size = 0x7F [[func]] name = "Cl2BlitSafe" addr = 0x41A640 size = 0x9C [[func]] name = "Cl2DrawOutlineSafe" addr = 0x41A6DC size = 0x93 [[func]] name = "Cl2BlitOutlineSafe" addr = 0x41A76F size = 0xD0 [[func]] name = "Cl2DrawLightTblSafe" addr = 0x41A83F size = 0xC7 [[func]] name = "Cl2BlitLightSafe" addr = 0x41A906 size = 0xBD [[func]] name = "Cl2DrawLightSafe" addr = 0x41A9C3 size = 0xA2 [[func]] name = "PlayInGameMovie" addr = 0x41AA65 size = 0x3C [[func]] name = "InitDiabloMsg" addr = 0x41AAA1 size = 0x41 [[func]] name = "ClrDiabloMsg" addr = 0x41AAE2 size = 0x1B [[func]] name = "DrawDiabloMsg" addr = 0x41AAFD size = 0x203 [[func]] name = "fault_init_filter" addr = 0x41AD0A size = 0xA [[func]] name = "log_create" addr = 0x41AD2A size = 0xBF [[func]] name = "TopLevelExceptionFilter" addr = 0x41ADE9 size = 0x134 [[func]] name = "log_printf" addr = 0x41AF1D size = 0x36 [[func]] name = "fault_unknown_module" addr = 0x41AF53 size = 0x8F [[func]] name = "fault_call_stack" addr = 0x41AFE2 size = 0xB7 [[func]] name = "fault_get_error_type" addr = 0x41B099 size = 0x14C [[func]] name = "log_reset" addr = 0x41B20D size = 0x5F [[func]] name = "fault_reset_filter" addr = 0x41B26C size = 0xD [[func]] name = "gamemenu_on" addr = 0x41B279 size = 0x29 [[func]] name = "gamemenu_update_single" addr = 0x41B2A2 size = 0x3E [[func]] name = "gamemenu_update_multi" addr = 0x41B2E0 size = 0x10 [[func]] name = "gamemenu_off" addr = 0x41B2F0 size = 0x9 [[func]] name = "gamemenu_handle_previous" addr = 0x41B2F9 size = 0x13 [[func]] name = "gamemenu_previous" addr = 0x41B30C size = 0x5 [[func]] name = "gamemenu_new_game" addr = 0x41B311 size = 0x54 [[func]] name = "gamemenu_quit_game" addr = 0x41B365 size = 0xD [[func]] name = "gamemenu_load_game" addr = 0x41B372 size = 0x7E [[func]] name = "gamemenu_save_game" addr = 0x41B3F0 size = 0x9B [[func]] name = "gamemenu_restart_town" addr = 0x41B48B size = 0xA [[func]] name = "gamemenu_options" addr = 0x41B495 size = 0x20 [[func]] name = "gamemenu_get_music" addr = 0x41B4B5 size = 0x19 [[func]] name = "gamemenu_sound_music_toggle" addr = 0x41B4CE size = 0x41 [[func]] name = "gamemenu_get_sound" addr = 0x41B50F size = 0x19 [[func]] name = "gamemenu_jogging" addr = 0x41B528 size = 0x3A [[func]] name = "gamemenu_get_gamma" addr = 0x41B562 size = 0x26 [[func]] name = "gamemenu_music_volume" addr = 0x41B588 size = 0x9E [[func]] name = "gamemenu_slider_music_sound" addr = 0x41B626 size = 0xD [[func]] name = "gamemenu_sound_volume" addr = 0x41B633 size = 0x81 [[func]] name = "gamemenu_loadjog" addr = 0x41B6B4 size = 0x3A [[func]] name = "gamemenu_gamma" addr = 0x41B6EE size = 0x2F [[func]] name = "gamemenu_slider_gamma" addr = 0x41B71D size = 0x10 [[func]] name = "FillSolidBlockTbls" addr = 0x41B72D size = 0x13C [[func]] name = "MakeSpeedCels" addr = 0x41B869 size = 0x436 [[func]] name = "SortTiles" addr = 0x41BC9F size = 0x3F [[func]] name = "SwapTile" addr = 0x41BCDE size = 0x8C [[func]] name = "IsometricCoord" addr = 0x41BD6A size = 0x48 [[func]] name = "SetSpeedCels" addr = 0x41BDB2 size = 0x49 [[func]] name = "SetDungeonMicros" addr = 0x41BDFB size = 0x149 [[func]] name = "DRLG_InitTrans" addr = 0x41BF44 size = 0x30 [[func]] name = "DRLG_MRectTrans" addr = 0x41BF74 size = 0x59 [[func]] name = "DRLG_RectTrans" addr = 0x41BFCD size = 0x45 [[func]] name = "DRLG_CopyTrans" addr = 0x41C012 size = 0x1F [[func]] name = "DRLG_ListTrans" addr = 0x41C031 size = 0x33 [[func]] name = "DRLG_AreaTrans" addr = 0x41C064 size = 0x3F [[func]] name = "DRLG_InitSetPC" addr = 0x41C0A3 size = 0x17 [[func]] name = "DRLG_SetPC" addr = 0x41C0BA size = 0x54 [[func]] name = "Make_SetPC" addr = 0x41C10E size = 0x4F [[func]] name = "DRLG_WillThemeRoomFit" addr = 0x41C15D size = 0x19C [[func]] name = "DRLG_CreateThemeRoom" addr = 0x41C2F9 size = 0x40F [[func]] name = "DRLG_PlaceThemeRooms" addr = 0x41C708 size = 0x18C [[func]] name = "DRLG_HoldThemeRooms" addr = 0x41C894 size = 0x9A [[func]] name = "SkipThemeRoom" addr = 0x41C92E size = 0x52 [[func]] name = "InitLevels" addr = 0x41C980 size = 0x1A [[func]] name = "gmenu_draw_pause" addr = 0x41C99A size = 0x33 [[func]] name = "gmenu_print_text" addr = 0x41C9CD size = 0x59 [[func]] name = "FreeGMenu" addr = 0x41CA26 size = 0x5A [[func]] name = "gmenu_init_menu" addr = 0x41CA80 size = 0x7F [[func]] name = "gmenu_is_active" addr = 0x41CAFF size = 0xC [[func]] name = "gmenu_set_items" addr = 0x41CB0B size = 0x5A [[func]] name = "gmenu_up_down" addr = 0x41CB65 size = 0x6D [[func]] name = "gmenu_draw" addr = 0x41CBD2 size = 0xC1 [[func]] name = "gmenu_draw_menu_item" addr = 0x41CC93 size = 0xF4 [[func]] name = "gmenu_clear_buffer" addr = 0x41CD87 size = 0x3F [[func]] name = "gmenu_get_lfont" addr = 0x41CDC6 size = 0x3C [[func]] name = "gmenu_presskeys" addr = 0x41CE02 size = 0x7C [[func]] name = "gmenu_left_right" addr = 0x41CE7E size = 0x50 [[func]] name = "gmenu_on_mouse_move" addr = 0x41CECE size = 0x58 [[func]] name = "gmenu_get_mouse_slider" addr = 0x41CF26 size = 0x2F [[func]] name = "gmenu_left_mouse" addr = 0x41CF55 size = 0xB2 [[func]] name = "gmenu_enable" addr = 0x41D007 size = 0xE [[func]] name = "gmenu_slider_set" addr = 0x41D015 size = 0x42 [[func]] name = "gmenu_slider_get" addr = 0x41D057 size = 0x3D [[func]] name = "gmenu_slider_steps" addr = 0x41D094 size = 0x15 [[func]] name = "InitHelp" addr = 0x41D0A9 size = 0x12 [[func]] name = "DrawHelp" addr = 0x41D0BB size = 0x18B [[func]] name = "DrawHelpLine" addr = 0x41D246 size = 0x79 [[func]] name = "DisplayHelp" addr = 0x41D2BF size = 0x1C [[func]] name = "HelpScrollUp" addr = 0x41D2DB size = 0x10 [[func]] name = "HelpScrollDown" addr = 0x41D2EB size = 0x14 [[func]] name = "init_cleanup" addr = 0x41D2FF size = 0x11D [[func]] name = "init_run_office_from_start_menu" addr = 0x41D41C size = 0x6D [[func]] name = "init_run_office" addr = 0x41D489 size = 0x179 [[func]] name = "init_disable_screensaver" addr = 0x41D602 size = 0x9C [[func]] name = "init_create_window" addr = 0x41D69E size = 0x143 [[func]] name = "init_kill_mom_parent" addr = 0x41D7E1 size = 0x21 [[func]] name = "init_find_mom_parent" addr = 0x41D802 size = 0x50 [[func]] name = "init_await_mom_parent_exit" addr = 0x41D852 size = 0x2E [[func]] name = "init_archives" addr = 0x41D880 size = 0x1AC [[func]] name = "init_test_access" addr = 0x41DA2C size = 0x1B3 [[func]] name = "init_strip_trailing_slash" addr = 0x41DBDF size = 0x18 [[func]] name = "init_read_test_file" addr = 0x41DBF7 size = 0x95 [[func]] name = "init_get_file_info" addr = 0x41DC8C size = 0xA0 [[func]] name = "MainWndProc" addr = 0x41DD2C size = 0x9E [[func]] name = "init_activate_window" addr = 0x41DDCA size = 0x5A [[func]] name = "WindowProc" addr = 0x41DE24 size = 0x25 [[func]] name = "SetWindowProc" addr = 0x41DE49 size = 0xC [[func]] name = "interface_msg_pump" addr = 0x41DE55 size = 0x48 [[func]] name = "IncProgress" addr = 0x41DE9D size = 0x39 [[func]] name = "DrawCutscene" addr = 0x41DED6 size = 0x76 [[func]] name = "DrawProgress" addr = 0x41DF4C size = 0x29 [[func]] name = "ShowProgress" addr = 0x41DF75 size = 0x326 [[func]] name = "FreeInterface" addr = 0x41E2C3 size = 0x12 [[func]] name = "InitCutscene" addr = 0x41E2D5 size = 0x287 [[func]] name = "FreeInvGFX" addr = 0x41E584 size = 0x12 [[func]] name = "InitInv" addr = 0x41E596 size = 0x62 [[func]] name = "InvDrawSlotBack" addr = 0x41E5F8 size = 0x53 [[func]] name = "DrawInv" addr = 0x41E64B size = 0xAFC [[func]] name = "DrawInvBelt" addr = 0x41F147 size = 0x22C [[func]] name = "AutoPlace" addr = 0x41F373 size = 0x192 [[func]] name = "SpecialAutoPlace" addr = 0x41F505 size = 0x1C6 [[func]] name = "GoldAutoPlace" addr = 0x41F6CB size = 0x2E4 [[func]] name = "WeaponAutoPlace" addr = 0x41F9AF size = 0xE9 [[func]] name = "SwapItem" addr = 0x41FA98 size = 0x3D [[func]] name = "CheckInvPaste" addr = 0x41FAD5 size = 0xE07 [[func]] name = "CheckInvSwap" addr = 0x4208FC size = 0xAA [[func]] name = "CheckInvCut" addr = 0x4209A6 size = 0x490 [[func]] name = "inv_update_rem_item" addr = 0x420E36 size = 0x49 [[func]] name = "RemoveInvItem" addr = 0x420E7F size = 0x151 [[func]] name = "inv_diablo_to_hellfire" addr = 0x420FD0 size = 0x152 [[func]] name = "RemoveSpdBarItem" addr = 0x421122 size = 0x69 [[func]] name = "CheckInvItem" addr = 0x42118B size = 0x27 [[func]] name = "CheckInvScrn" addr = 0x4211B2 size = 0x2C [[func]] name = "CheckItemStats" addr = 0x4211DE size = 0x4D [[func]] name = "CheckBookLevel" addr = 0x42122B size = 0xB7 [[func]] name = "CheckQuestItem" addr = 0x4212E2 size = 0x4F9 [[func]] name = "InvGetItem" addr = 0x4217DB size = 0x19D [[func]] name = "AutoGetItem" addr = 0x421978 size = 0x555 [[func]] name = "FindGetItem" addr = 0x421ECD size = 0x5E [[func]] name = "SyncGetItem" addr = 0x421F2B size = 0x121 [[func]] name = "CanPut" addr = 0x42204C size = 0xD7 [[func]] name = "TryInvPut" addr = 0x422123 size = 0xFE [[func]] name = "DrawInvMsg" addr = 0x422221 size = 0x27 [[func]] name = "InvPutItem" addr = 0x422248 size = 0x373 [[func]] name = "SyncPutItem" addr = 0x4225BB size = 0x33A [[func]] name = "CheckInvHLight" addr = 0x4228F5 size = 0x22E [[func]] name = "RemoveScroll" addr = 0x422B23 size = 0xA6 [[func]] name = "UseScroll" addr = 0x422BC9 size = 0xC0 [[func]] name = "UseStaffCharge" addr = 0x422C89 size = 0x60 [[func]] name = "UseStaff" addr = 0x422CE9 size = 0x53 [[func]] name = "StartGoldDrop" addr = 0x422D3C size = 0x76 [[func]] name = "UseInvItem" addr = 0x422DB2 size = 0x31B [[func]] name = "DoTelekinesis" addr = 0x4230CD size = 0x72 [[func]] name = "CalculateGold" addr = 0x42313F size = 0x5D [[func]] name = "DropItemBeforeTrig" addr = 0x42319C size = 0x2E [[func]] name = "get_ring_max_value" addr = 0x4231CA size = 0x66 [[func]] name = "get_bow_max_value" addr = 0x423230 size = 0x66 [[func]] name = "get_staff_max_value" addr = 0x423296 size = 0x66 [[func]] name = "get_sword_max_value" addr = 0x4232FC size = 0x66 [[func]] name = "get_helm_max_value" addr = 0x423362 size = 0x66 [[func]] name = "get_shield_max_value" addr = 0x4233C8 size = 0x66 [[func]] name = "get_armor_max_value" addr = 0x42342E size = 0x84 [[func]] name = "get_mace_max_value" addr = 0x4234B2 size = 0x66 [[func]] name = "get_amulet_max_value" addr = 0x423518 size = 0x66 [[func]] name = "get_axe_max_value" addr = 0x42357E size = 0x66 [[func]] name = "items_get_currlevel" addr = 0x4235F6 size = 0x26 [[func]] name = "InitItemGFX" addr = 0x42361C size = 0x52 [[func]] name = "ItemPlace" addr = 0x42366E size = 0x4D [[func]] name = "AddInitItems" addr = 0x4236BB size = 0x12C [[func]] name = "InitItems" addr = 0x4237E7 size = 0x128 [[func]] name = "SpawnNote" addr = 0x42390F size = 0x56 [[func]] name = "CalcPlrItemVals" addr = 0x423965 size = 0xCD9 [[func]] name = "CalcPlrScrolls" addr = 0x42463E size = 0x131 [[func]] name = "CalcPlrStaff" addr = 0x42476F size = 0x5D [[func]] name = "CalcSelfItems" addr = 0x4247CC size = 0xFA [[func]] name = "CalcPlrItemMin" addr = 0x4248C6 size = 0x69 [[func]] name = "ItemMinStats" addr = 0x42492F size = 0x36 [[func]] name = "CalcPlrBookVals" addr = 0x424965 size = 0x15A [[func]] name = "CalcPlrInv" addr = 0x424ABF size = 0x58 [[func]] name = "SetPlrHandItem" addr = 0x424B17 size = 0x104 [[func]] name = "GetPlrHandSeed" addr = 0x424C1B size = 0xC [[func]] name = "GetGoldSeed" addr = 0x424C27 size = 0x86 [[func]] name = "SetPlrHandSeed" addr = 0x424CAD size = 0x3 [[func]] name = "SetPlrHandGoldCurs" addr = 0x424CB0 size = 0x35 [[func]] name = "CreatePlrItems" addr = 0x424CE5 size = 0x2B2 [[func]] name = "ItemSpaceOk" addr = 0x424F97 size = 0xF2 [[func]] name = "GetItemSpace" addr = 0x425089 size = 0xFB [[func]] name = "GetSuperItemSpace" addr = 0x425184 size = 0x99 [[func]] name = "GetSuperItemLoc" addr = 0x42521D size = 0x6A [[func]] name = "CalcItemValue" addr = 0x425287 size = 0x4C [[func]] name = "GetBookSpell" addr = 0x4252D3 size = 0x102 [[func]] name = "GetStaffPower" addr = 0x4253D5 size = 0x1DF [[func]] name = "GetStaffSpell" addr = 0x4255B4 size = 0x14B [[func]] name = "GetOilType" addr = 0x4256FF size = 0xB5 [[func]] name = "GetItemAttrs" addr = 0x4257B4 size = 0x2C2 [[func]] name = "RndPL" addr = 0x425A76 size = 0x11 [[func]] name = "PLVal" addr = 0x425A87 size = 0x40 [[func]] name = "SaveItemPower" addr = 0x425AC7 size = 0xBB1 [[func]] name = "GetItemPower" addr = 0x4267F0 size = 0x342 [[func]] name = "GetItemBonus" addr = 0x426B32 size = 0xAE [[func]] name = "SetupItem" addr = 0x426BE0 size = 0x9C [[func]] name = "RndItem" addr = 0x426C7C size = 0x10F [[func]] name = "RndUItem" addr = 0x426D8B size = 0x115 [[func]] name = "RndAllItems" addr = 0x426EA0 size = 0xA3 [[func]] name = "RndTypeItems" addr = 0x426F43 size = 0x9A [[func]] name = "CheckUnique" addr = 0x426FDD size = 0xD1 [[func]] name = "GetUniqueItem" addr = 0x4270AE size = 0x14B [[func]] name = "SpawnUnique" addr = 0x4271F9 size = 0x93 [[func]] name = "ItemRndDur" addr = 0x42728C size = 0x42 [[func]] name = "SetupAllItems" addr = 0x4272CE size = 0x160 [[func]] name = "SpawnItem" addr = 0x42742E size = 0x116 [[func]] name = "CreateItem" addr = 0x427544 size = 0xA0 [[func]] name = "CreateRndItem" addr = 0x4275E4 size = 0xA9 [[func]] name = "SetupAllUseful" addr = 0x42768D size = 0x7E [[func]] name = "CreateRndUseful" addr = 0x42770B size = 0x6F [[func]] name = "CreateTypeItem" addr = 0x42777A size = 0xAA [[func]] name = "RecreateItem" addr = 0x427824 size = 0x115 [[func]] name = "RecreateEar" addr = 0x427939 size = 0x139 [[func]] name = "CornerstoneSave" addr = 0x427A72 size = 0x48 [[func]] name = "CornerstoneLoad" addr = 0x427ABA size = 0x114 [[func]] name = "SpawnQuestItem" addr = 0x427BCE size = 0x120 [[func]] name = "SpawnRock" addr = 0x427CEE size = 0xD8 [[func]] name = "SpawnItem" addr = 0x427DC6 size = 0x9B [[func]] name = "SpawnMapOfDoom" addr = 0x427E61 size = 0xE [[func]] name = "SpawnRuneBomb" addr = 0x427E6F size = 0xE [[func]] name = "SpawnTheodore" addr = 0x427E7D size = 0xE [[func]] name = "RespawnItem" addr = 0x427E8B size = 0xDD [[func]] name = "DeleteItem" addr = 0x427F68 size = 0x34 [[func]] name = "ItemDoppel" addr = 0x427F9C size = 0x5D [[func]] name = "ProcessItems" addr = 0x427FF9 size = 0xE0 [[func]] name = "FreeItemGFX" addr = 0x4280D9 size = 0x1D [[func]] name = "GetItemFrm" addr = 0x4280F6 size = 0x21 [[func]] name = "GetItemStr" addr = 0x428117 size = 0x73 [[func]] name = "CheckIdentify" addr = 0x42818A size = 0x46 [[func]] name = "DoRepair" addr = 0x4281D0 size = 0x5A [[func]] name = "RepairItem" addr = 0x42822A size = 0x78 [[func]] name = "DoRecharge" addr = 0x4282A2 size = 0x74 [[func]] name = "RechargeItem" addr = 0x428316 size = 0x47 [[func]] name = "DoOil" addr = 0x42835D size = 0x58 [[func]] name = "OilItem" addr = 0x4283B5 size = 0x1FD [[func]] name = "PrintItemOil" addr = 0x4285DA size = 0x213 [[func]] name = "PrintItemPower" addr = 0x42889B size = 0x5CC [[func]] name = "DrawUTextBack" addr = 0x428FDF size = 0x5C [[func]] name = "PrintUString" addr = 0x42903B size = 0xCE [[func]] name = "DrawULine" addr = 0x429109 size = 0x4B [[func]] name = "DrawUniqueInfo" addr = 0x429154 size = 0x136 [[func]] name = "PrintItemMisc" addr = 0x42928A size = 0x191 [[func]] name = "PrintItemDetails" addr = 0x42941B size = 0x25A [[func]] name = "PrintItemDur" addr = 0x429675 size = 0x22E [[func]] name = "UseItem" addr = 0x4298A3 size = 0x7C7 [[func]] name = "StoreStatOk" addr = 0x42A06A size = 0x49 [[func]] name = "SmithItemOk" addr = 0x42A0B3 size = 0x3F [[func]] name = "RndSmithItem" addr = 0x42A0F2 size = 0x88 [[func]] name = "BubbleSwapItem" addr = 0x42A17A size = 0x34 [[func]] name = "SortSmith" addr = 0x42A1AE size = 0x63 [[func]] name = "SpawnSmith" addr = 0x42A211 size = 0xE4 [[func]] name = "PremiumItemOk" addr = 0x42A2F5 size = 0x3B [[func]] name = "RndPremiumItem" addr = 0x42A330 size = 0x7D [[func]] name = "SpawnPremium" addr = 0x42A3AD size = 0x18F [[func]] name = "SpawnOnePremium" addr = 0x42A53C size = 0x24F [[func]] name = "WitchItemOk" addr = 0x42A7BF size = 0x6B [[func]] name = "RndWitchItem" addr = 0x42A82A size = 0x75 [[func]] name = "SortWitch" addr = 0x42A89F size = 0x67 [[func]] name = "WitchBookLevel" addr = 0x42A906 size = 0x98 [[func]] name = "SpawnWitch" addr = 0x42A99E size = 0x281 [[func]] name = "RndBoyItem" addr = 0x42AC1F size = 0x75 [[func]] name = "SpawnBoy" addr = 0x42AC94 size = 0x2AF [[func]] name = "HealerItemOk" addr = 0x42AFEF size = 0x135 [[func]] name = "RndHealerItem" addr = 0x42B124 size = 0x75 [[func]] name = "SortHealer" addr = 0x42B199 size = 0x67 [[func]] name = "SpawnHealer" addr = 0x42B200 size = 0x14B [[func]] name = "SpawnStoreGold" addr = 0x42B34B size = 0x29 [[func]] name = "RecreateSmithItem" addr = 0x42B374 size = 0x51 [[func]] name = "RecreatePremiumItem" addr = 0x42B3C5 size = 0x6D [[func]] name = "RecreateBoyItem" addr = 0x42B432 size = 0x6B [[func]] name = "RecreateWitchItem" addr = 0x42B49D size = 0xE8 [[func]] name = "RecreateHealerItem" addr = 0x42B585 size = 0x67 [[func]] name = "RecreateTownItem" addr = 0x42B5EC size = 0x67 [[func]] name = "RecalcStoreStats" addr = 0x42B653 size = 0xA1 [[func]] name = "ItemNoFlippy" addr = 0x42B6F4 size = 0x2F [[func]] name = "CreateSpellBook" addr = 0x42B723 size = 0xE0 [[func]] name = "CreateMagicArmor" addr = 0x42B803 size = 0xD9 [[func]] name = "CreateAmulet" addr = 0x42B8DC size = 0xC7 [[func]] name = "CreateMagicWeapon" addr = 0x42B9A3 size = 0xEF [[func]] name = "GetItemRecord" addr = 0x42BA92 size = 0xA3 [[func]] name = "NextItemRecord" addr = 0x42BB35 size = 0x46 [[func]] name = "SetItemRecord" addr = 0x42BB7B size = 0x47 [[func]] name = "PutItemRecord" addr = 0x42BBC2 size = 0xA5 [[func]] name = "RotateRadius" addr = 0x42BC67 size = 0x77 [[func]] name = "DoLighting" addr = 0x42BCDE size = 0x37E [[func]] name = "DoUnLight" addr = 0x42C05C size = 0x6B [[func]] name = "DoUnVision" addr = 0x42C0C7 size = 0x5A [[func]] name = "DoVision" addr = 0x42C121 size = 0x2AA [[func]] name = "FreeLightTable" addr = 0x42C3CB size = 0x12 [[func]] name = "InitLightTable" addr = 0x42C3DD size = 0x10 [[func]] name = "MakeLightTable" addr = 0x42C3ED size = 0x453 [[func]] name = "InitLightMax" addr = 0x42C840 size = 0x16 [[func]] name = "InitLighting" addr = 0x42C856 size = 0x1E [[func]] name = "AddLight" addr = 0x42C874 size = 0x6F [[func]] name = "AddUnLight" addr = 0x42C8E3 size = 0x20 [[func]] name = "ChangeLightRadius" addr = 0x42C903 size = 0x53 [[func]] name = "ChangeLightXY" addr = 0x42C956 size = 0x5F [[func]] name = "ChangeLightOff" addr = 0x42C9B5 size = 0x5B [[func]] name = "ChangeLight" addr = 0x42CA10 size = 0x6C [[func]] name = "ProcessLightList" addr = 0x42CA7C size = 0x10A [[func]] name = "SavePreLighting" addr = 0x42CB86 size = 0x18 [[func]] name = "InitVision" addr = 0x42CB9E size = 0x3B [[func]] name = "AddVision" addr = 0x42CBD9 size = 0x72 [[func]] name = "ChangeVisionRadius" addr = 0x42CC4B size = 0x41 [[func]] name = "ChangeVisionXY" addr = 0x42CC8C size = 0x4A [[func]] name = "ProcessVisionList" addr = 0x42CCD6 size = 0x101 [[func]] name = "lighting_color_cycling" addr = 0x42CDD7 size = 0x5B [[func]] name = "LoadGame" addr = 0x42CE32 size = 0x552 [[func]] name = "BLoad" addr = 0x42D384 size = 0xE [[func]] name = "WLoad" addr = 0x42D392 size = 0x3C [[func]] name = "ILoad" addr = 0x42D3CE size = 0x3C [[func]] name = "OLoad" addr = 0x42D40A size = 0x17 [[func]] name = "LoadPlayer" addr = 0x42D421 size = 0x2A [[func]] name = "LoadMonster" addr = 0x42D44B size = 0x36 [[func]] name = "LoadMissile" addr = 0x42D481 size = 0x2A [[func]] name = "LoadObject" addr = 0x42D4AB size = 0x22 [[func]] name = "LoadItem" addr = 0x42D4CD size = 0x36 [[func]] name = "LoadPremium" addr = 0x42D503 size = 0x2A [[func]] name = "LoadQuest" addr = 0x42D52D size = 0x54 [[func]] name = "LoadLighting" addr = 0x42D581 size = 0x22 [[func]] name = "LoadVision" addr = 0x42D5A3 size = 0x22 [[func]] name = "LoadPortal" addr = 0x42D5C5 size = 0x23 [[func]] name = "SaveGame" addr = 0x42D5E8 size = 0x4D0 [[func]] name = "BSave" addr = 0x42DAB8 size = 0xE [[func]] name = "WSave" addr = 0x42DAC6 size = 0x47 [[func]] name = "ISave" addr = 0x42DB0D size = 0x47 [[func]] name = "OSave" addr = 0x42DB54 size = 0x18 [[func]] name = "SavePlayer" addr = 0x42DB6C size = 0x2A [[func]] name = "SaveMonster" addr = 0x42DB96 size = 0x2A [[func]] name = "SaveMissile" addr = 0x42DBC0 size = 0x2A [[func]] name = "SaveObject" addr = 0x42DBEA size = 0x22 [[func]] name = "SaveItem" addr = 0x42DC0C size = 0x2A [[func]] name = "SavePremium" addr = 0x42DC36 size = 0x2A [[func]] name = "SaveQuest" addr = 0x42DC60 size = 0x58 [[func]] name = "SaveLighting" addr = 0x42DCB8 size = 0x22 [[func]] name = "SaveVision" addr = 0x42DCDA size = 0x22 [[func]] name = "SavePortal" addr = 0x42DCFC size = 0x23 [[func]] name = "SaveLevel" addr = 0x42DD1F size = 0x2E8 [[func]] name = "LoadLevel" addr = 0x42E007 size = 0x2E6 [[func]] name = "mainmenu_refresh_music" addr = 0x42E2ED size = 0x27 [[func]] name = "mainmenu_loop" addr = 0x42E314 size = 0x90 [[func]] name = "mainmenu_single_player" addr = 0x42E3A4 size = 0x95 [[func]] name = "mainmenu_init_menu" addr = 0x42E439 size = 0x36 [[func]] name = "mainmenu_multi_player" addr = 0x42E46F size = 0x6F [[func]] name = "mainmenu_play_intro" addr = 0x42E4DE size = 0x17 [[func]] name = "FreeQuestText" addr = 0x42E4F5 size = 0x24 [[func]] name = "InitQuestText" addr = 0x42E519 size = 0x2A [[func]] name = "InitQTextMsg" addr = 0x42E543 size = 0x61 [[func]] name = "DrawQTextBack" addr = 0x42E5A4 size = 0x5C [[func]] name = "PrintQTextChr" addr = 0x42E600 size = 0xA2 [[func]] name = "DrawQText" addr = 0x42E6A2 size = 0x1B4 [[func]] name = "GetDamageAmt" addr = 0x42E856 size = 0x639 [[func]] name = "CheckBlock" addr = 0x42EF52 size = 0x59 [[func]] name = "FindClosest" addr = 0x42EFAB size = 0xAA [[func]] name = "GetSpellLevel" addr = 0x42F055 size = 0x36 [[func]] name = "DeleteMissile" addr = 0x42F08B size = 0x34 [[func]] name = "MonsterTrapHit" addr = 0x42F0BF size = 0x1BE [[func]] name = "MonsterMHit" addr = 0x42F27D size = 0x392 [[func]] name = "PlayerMHit" addr = 0x42F60F size = 0x477 [[func]] name = "SetMissDir" addr = 0x42FA86 size = 0x1A [[func]] name = "SetMissAnim" addr = 0x42FAA0 size = 0x84 [[func]] name = "LoadMissileGFX" addr = 0x42FB24 size = 0xEE [[func]] name = "InitMissileGFX" addr = 0x42FC12 size = 0x2D [[func]] name = "FreeMissiles" addr = 0x42FC3F size = 0x2E [[func]] name = "FreeMissileGFX" addr = 0x42FC6D size = 0x69 [[func]] name = "FreeMissiles2" addr = 0x42FCD6 size = 0x2E [[func]] name = "InitMissiles" addr = 0x42FD04 size = 0x22F [[func]] name = "missiles_hive_explosion" addr = 0x42FF33 size = 0x95 [[func]] name = "missiles_fire_rune" addr = 0x42FFC8 size = 0x80 [[func]] name = "missiles_found_target" addr = 0x430048 size = 0xF6 [[func]] name = "missiles_light_rune" addr = 0x43013E size = 0x80 [[func]] name = "missiles_great_light_rune" addr = 0x4301BE size = 0x80 [[func]] name = "missiles_immolation_rune" addr = 0x43023E size = 0x80 [[func]] name = "missiles_stone_rune" addr = 0x4302BE size = 0x80 [[func]] name = "missiles_reflection" addr = 0x43033E size = 0x6A [[func]] name = "missiles_berserk" addr = 0x4303A8 size = 0x27C [[func]] name = "missiles_hork_spawn" addr = 0x430624 size = 0x3D [[func]] name = "GetMissileVel" addr = 0x430661 size = 0x99 [[func]] name = "PutMissile" addr = 0x4306FA size = 0x70 [[func]] name = "missiles_jester" addr = 0x43076A size = 0x9B [[func]] name = "missiles_steal_pots" addr = 0x43082D size = 0x24B [[func]] name = "missiles_mana_trap" addr = 0x430A78 size = 0x111 [[func]] name = "AddLArrow" addr = 0x430B89 size = 0x10A [[func]] name = "GetDirection16" addr = 0x430C93 size = 0x690 [[func]] name = "AddArrow" addr = 0x431323 size = 0x111 [[func]] name = "missiles_spec_arrow" addr = 0x431434 size = 0xA9 [[func]] name = "GetVileMissPos" addr = 0x4314DD size = 0x9E [[func]] name = "AddRndTeleport" addr = 0x43157B size = 0x157 [[func]] name = "missiles_warp" addr = 0x4316D2 size = 0x131 [[func]] name = "AddFirebolt" addr = 0x431803 size = 0x119 [[func]] name = "AddMagmaball" addr = 0x43191C size = 0x97 [[func]] name = "GetMissilePos" addr = 0x4319B3 size = 0xDC [[func]] name = "miss_null_33" addr = 0x431A8F size = 0x46 [[func]] name = "AddTeleport" addr = 0x431AD5 size = 0x100 [[func]] name = "AddLightball" addr = 0x431BD5 size = 0x81 [[func]] name = "missiles_light_wall" addr = 0x431C56 size = 0x8A [[func]] name = "AddFirewall" addr = 0x431CE0 size = 0xEA [[func]] name = "AddFireball" addr = 0x431DCA size = 0x13E [[func]] name = "missiles_rune_explosion" addr = 0x431F08 size = 0x1C6 [[func]] name = "CheckMissileCol" addr = 0x4320CE size = 0x392 [[func]] name = "Plr2PlrMHit" addr = 0x432460 size = 0x369 [[func]] name = "missiles_immo_1" addr = 0x4327C9 size = 0x14D [[func]] name = "missiles_immo_2" addr = 0x432916 size = 0xC4 [[func]] name = "AddLightctrl" addr = 0x4329DA size = 0x6C [[func]] name = "missiles_larrow" addr = 0x432A46 size = 0x9F [[func]] name = "AddLightning" addr = 0x432AE5 size = 0xD1 [[func]] name = "AddMisexp" addr = 0x432BB6 size = 0xDB [[func]] name = "AddWeapexp" addr = 0x432C91 size = 0x6B [[func]] name = "CheckIfTrig" addr = 0x432CFC size = 0x63 [[func]] name = "AddTown" addr = 0x432D5F size = 0x1FA [[func]] name = "AddFlash" addr = 0x432F59 size = 0xE4 [[func]] name = "missiles_43303D" addr = 0x43303D size = 0x3 [[func]] name = "missiles_433040" addr = 0x433040 size = 0x5C [[func]] name = "AddFlash2" addr = 0x43309C size = 0xDC [[func]] name = "AddManashield" addr = 0x433178 size = 0x62 [[func]] name = "AddFiremove" addr = 0x4331DA size = 0x83 [[func]] name = "AddGuardian" addr = 0x43325D size = 0x21C [[func]] name = "AddChain" addr = 0x433479 size = 0x33 [[func]] name = "miss_null_11" addr = 0x4334AC size = 0x33 [[func]] name = "miss_null_12" addr = 0x4334DF size = 0x3D [[func]] name = "miss_null_13" addr = 0x43351C size = 0x3F [[func]] name = "AddRhino" addr = 0x43355B size = 0x111 [[func]] name = "miss_null_32" addr = 0x43366C size = 0xDE [[func]] name = "AddFlare" addr = 0x43374A size = 0x182 [[func]] name = "AddAcid" addr = 0x4338CC size = 0x99 [[func]] name = "miss_null_1D" addr = 0x433965 size = 0x3C [[func]] name = "AddAcidpud" addr = 0x4339A1 size = 0x64 [[func]] name = "AddStone" addr = 0x433A05 size = 0x1A2 [[func]] name = "AddGolem" addr = 0x433BA7 size = 0xC9 [[func]] name = "AddEtherealize" addr = 0x433C70 size = 0x9A [[func]] name = "miss_null_1F" addr = 0x433D0A size = 0x13 [[func]] name = "miss_null_23" addr = 0x433D1D size = 0x66 [[func]] name = "AddBoom" addr = 0x433D83 size = 0x53 [[func]] name = "AddHeal" addr = 0x433DD6 size = 0x123 [[func]] name = "missiles_rech_mana" addr = 0x433EF9 size = 0x11A [[func]] name = "missiles_magi" addr = 0x434013 size = 0x59 [[func]] name = "AddHealOther" addr = 0x43406C size = 0x33 [[func]] name = "AddElement" addr = 0x43409F size = 0x119 [[func]] name = "GetDirection8" addr = 0x4341B8 size = 0x636 [[func]] name = "AddIdentify" addr = 0x4347EE size = 0x51 [[func]] name = "AddFirewallC" addr = 0x43483F size = 0x13C [[func]] name = "missiles_ring" addr = 0x43497B size = 0x75 [[func]] name = "missiles_search" addr = 0x4349F0 size = 0x101 [[func]] name = "AddInfra" addr = 0x434AF1 size = 0x73 [[func]] name = "AddWave" addr = 0x434B64 size = 0x4B [[func]] name = "AddNova" addr = 0x434BAF size = 0x106 [[func]] name = "AddBlodboil" addr = 0x434CB5 size = 0x122 [[func]] name = "AddRepair" addr = 0x434DD7 size = 0x51 [[func]] name = "AddRecharge" addr = 0x434E28 size = 0x51 [[func]] name = "AddDisarm" addr = 0x434E79 size = 0x33 [[func]] name = "AddApoca" addr = 0x434EAC size = 0xF5 [[func]] name = "AddFlame" addr = 0x434FA1 size = 0x111 [[func]] name = "AddFlamec" addr = 0x4350B2 size = 0x78 [[func]] name = "AddCbolt" addr = 0x43512A size = 0xFB [[func]] name = "missiles_cbolt_arrow" addr = 0x435225 size = 0xDA [[func]] name = "AddHbolt" addr = 0x4352FF size = 0xE7 [[func]] name = "missiles_hbolt_arrow" addr = 0x4353E6 size = 0xAC [[func]] name = "AddResurrect" addr = 0x435492 size = 0x37 [[func]] name = "AddResurrectBeam" addr = 0x4354C9 size = 0x4E [[func]] name = "AddTelekinesis" addr = 0x435517 size = 0x33 [[func]] name = "AddBoneSpirit" addr = 0x43554A size = 0x10F [[func]] name = "AddRportal" addr = 0x435659 size = 0x4A [[func]] name = "AddDiabApoca" addr = 0x4356A3 size = 0x8C [[func]] name = "AddMissile" addr = 0x43572F size = 0x192 [[func]] name = "Sentfire" addr = 0x4358C1 size = 0xDF [[func]] name = "mi_hork_spawn" addr = 0x4359A0 size = 0x138 [[func]] name = "MI_Rune" addr = 0x435AD8 size = 0xDB [[func]] name = "MI_Golem" addr = 0x435BB3 size = 0x126 [[func]] name = "MI_SetManashield" addr = 0x435CD9 size = 0xB [[func]] name = "MI_LArrow" addr = 0x435CE4 size = 0x32B [[func]] name = "MI_Arrow" addr = 0x43600F size = 0xD9 [[func]] name = "MI_Firebolt" addr = 0x4360E8 size = 0x351 [[func]] name = "MI_Lightball" addr = 0x436439 size = 0xE8 [[func]] name = "mi_light_wall" addr = 0x436521 size = 0x62 [[func]] name = "mi_null_33" addr = 0x436583 size = 0x6A [[func]] name = "MI_Acidpud" addr = 0x4365ED size = 0x74 [[func]] name = "MI_Firewall" addr = 0x436661 size = 0x171 [[func]] name = "MI_Fireball" addr = 0x4367D2 size = 0x413 [[func]] name = "mi_hive_explode" addr = 0x436BE5 size = 0x3E [[func]] name = "mi_immolation" addr = 0x436C23 size = 0x46D [[func]] name = "MI_Lightctrl" addr = 0x4370B0 size = 0x20B [[func]] name = "mi_light_arrow" addr = 0x4372BB size = 0x183 [[func]] name = "MI_Lightning" addr = 0x43743E size = 0x86 [[func]] name = "MI_Town" addr = 0x4374C4 size = 0x1B3 [[func]] name = "MI_Flash" addr = 0x437677 size = 0x134 [[func]] name = "mi_flashfr" addr = 0x4377AB size = 0x9A [[func]] name = "mi_flashbk" addr = 0x437845 size = 0x66 [[func]] name = "MI_Flash2" addr = 0x4378AB size = 0xDC [[func]] name = "mi_reflect" addr = 0x437987 size = 0xCD [[func]] name = "MI_Manashield" addr = 0x437A54 size = 0x26C [[func]] name = "MI_Etherealize" addr = 0x437CC0 size = 0xD9 [[func]] name = "MI_Firemove" addr = 0x437D99 size = 0x1D7 [[func]] name = "MI_Guardian" addr = 0x437F70 size = 0x1FD [[func]] name = "MI_Chain" addr = 0x43816D size = 0x131 [[func]] name = "mi_null_11" addr = 0x43829E size = 0x35 [[func]] name = "MI_Weapexp" addr = 0x4382D3 size = 0x14C [[func]] name = "MI_Misexp" addr = 0x43841F size = 0xCC [[func]] name = "MI_Acidsplat" addr = 0x4384EB size = 0x91 [[func]] name = "MI_Teleport" addr = 0x43857C size = 0x14F [[func]] name = "MI_Stone" addr = 0x4386CB size = 0xB3 [[func]] name = "MI_Boom" addr = 0x43877E size = 0x62 [[func]] name = "MI_Rhino" addr = 0x4387E0 size = 0x181 [[func]] name = "MoveMissilePos" addr = 0x438961 size = 0x8F [[func]] name = "mi_null_32" addr = 0x438A10 size = 0x1BD [[func]] name = "MI_FirewallC" addr = 0x438BCD size = 0x176 [[func]] name = "mi_fire_ring" addr = 0x438D43 size = 0x150 [[func]] name = "mi_light_ring" addr = 0x438E93 size = 0x150 [[func]] name = "mi_search" addr = 0x438FE3 size = 0x42 [[func]] name = "mi_lightning_wall" addr = 0x439025 size = 0x1BE [[func]] name = "MI_Infra" addr = 0x4391E3 size = 0x49 [[func]] name = "MI_Apoca" addr = 0x43922C size = 0x11D [[func]] name = "MI_Wave" addr = 0x439349 size = 0x269 [[func]] name = "MI_Nova" addr = 0x4395B2 size = 0x15E [[func]] name = "mi_fire_nova" addr = 0x439710 size = 0x15E [[func]] name = "mi_spec_arrow" addr = 0x43986E size = 0x124 [[func]] name = "MI_Blodboil" addr = 0x439992 size = 0x1D3 [[func]] name = "MI_Flame" addr = 0x439B65 size = 0xC9 [[func]] name = "MI_Flamec" addr = 0x439C2E size = 0xDE [[func]] name = "MI_Cbolt" addr = 0x439D0C size = 0x18A [[func]] name = "MI_Hbolt" addr = 0x439E96 size = 0x149 [[func]] name = "MI_Element" addr = 0x439FDF size = 0x378 [[func]] name = "MI_Bonespirit" addr = 0x43A357 size = 0x201 [[func]] name = "MI_ResurrectBeam" addr = 0x43A558 size = 0x1F [[func]] name = "MI_Rportal" addr = 0x43A577 size = 0x12E [[func]] name = "ProcessMissiles" addr = 0x43A6A5 size = 0x1AC [[func]] name = "missiles_process_charge" addr = 0x43A851 size = 0x8C [[func]] name = "ClearMissileSpot" addr = 0x43A8DD size = 0x28 [[func]] name = "InitLevelMonsters" addr = 0x43A905 size = 0x59 [[func]] name = "AddMonsterType" addr = 0x43A95E size = 0x7D [[func]] name = "GetLevelMTypes" addr = 0x43A9DB size = 0x35E [[func]] name = "InitMonsterGFX" addr = 0x43AD39 size = 0x392 [[func]] name = "InitMonsterTRN" addr = 0x43B0CB size = 0x8E [[func]] name = "InitMonster" addr = 0x43B159 size = 0x3FB [[func]] name = "ClrAllMonsters" addr = 0x43B554 size = 0xAD [[func]] name = "ClearMVars" addr = 0x43B601 size = 0x39 [[func]] name = "MonstPlace" addr = 0x43B63A size = 0x48 [[func]] name = "monster_some_crypt" addr = 0x43B682 size = 0x63 [[func]] name = "LoadDiabMonsts" addr = 0x43B6E5 size = 0xB3 [[func]] name = "InitMonsters" addr = 0x43B798 size = 0x218 [[func]] name = "PlaceUniques" addr = 0x43B9B0 size = 0xC8 [[func]] name = "PlaceUniqueMonst" addr = 0x43BA78 size = 0x55D [[func]] name = "PlaceMonster" addr = 0x43BFD5 size = 0x82 [[func]] name = "PlaceQuestMonsters" addr = 0x43C057 size = 0x2E6 [[func]] name = "PlaceGroup" addr = 0x43C33D size = 0x28F [[func]] name = "SetMapMonsters" addr = 0x43C5CC size = 0x140 [[func]] name = "DeleteMonster" addr = 0x43C70C size = 0x29 [[func]] name = "AddMonster" addr = 0x43C735 size = 0x50 [[func]] name = "AddDoppelganger" addr = 0x43C785 size = 0xEC [[func]] name = "M_Ranged" addr = 0x43C871 size = 0x27 [[func]] name = "M_Talker" addr = 0x43C898 size = 0x36 [[func]] name = "M_Enemy" addr = 0x43C8CE size = 0x32F [[func]] name = "M_StartStand" addr = 0x43CBFD size = 0x9D [[func]] name = "NewMonsterAnim" addr = 0x43CC9A size = 0x3E [[func]] name = "M_CheckEFlag" addr = 0x43CCD8 size = 0x5A [[func]] name = "M_ClearSquares" addr = 0x43CD32 size = 0x8F [[func]] name = "M_GetKnockback" addr = 0x43CDC1 size = 0xEE [[func]] name = "M_StartHit" addr = 0x43CEAF size = 0x1B5 [[func]] name = "M_GetDir" addr = 0x43D064 size = 0x28 [[func]] name = "M_StartKill" addr = 0x43D08C size = 0x7D [[func]] name = "MonstStartKill" addr = 0x43D109 size = 0x1A8 [[func]] name = "M_DiabloDeath" addr = 0x43D2B1 size = 0x230 [[func]] name = "SpawnLoot" addr = 0x43D4E1 size = 0x174 [[func]] name = "M_SyncStartKill" addr = 0x43D655 size = 0x73 [[func]] name = "M_DoStand" addr = 0x43D6C8 size = 0x58 [[func]] name = "M_DoWalk" addr = 0x43D720 size = 0x12D [[func]] name = "M_ChangeLightOffset" addr = 0x43D84D size = 0x5F [[func]] name = "M_DoWalk2" addr = 0x43D8AC size = 0x10A [[func]] name = "M_DoWalk3" addr = 0x43D9B6 size = 0x13E [[func]] name = "M_TryM2MHit" addr = 0x43DAF4 size = 0xEA [[func]] name = "M2MStartHit" addr = 0x43DBDE size = 0x1AC [[func]] name = "M2MStartKill" addr = 0x43DD8A size = 0x214 [[func]] name = "M_DoAttack" addr = 0x43DF9E size = 0x14E [[func]] name = "M_TryH2HHit" addr = 0x43E0EC size = 0x619 [[func]] name = "M_DoRAttack" addr = 0x43E705 size = 0xD0 [[func]] name = "M_DoRSpAttack" addr = 0x43E7D5 size = 0x106 [[func]] name = "M_DoSAttack" addr = 0x43E8DB size = 0x77 [[func]] name = "M_DoFadein" addr = 0x43E952 size = 0x52 [[func]] name = "M_DoFadeout" addr = 0x43E9A4 size = 0x70 [[func]] name = "M_DoHeal" addr = 0x43EA14 size = 0x71 [[func]] name = "M_DoTalk" addr = 0x43EA85 size = 0x27B [[func]] name = "M_Teleport" addr = 0x43ED00 size = 0x133 [[func]] name = "M_DoGotHit" addr = 0x43EE33 size = 0x39 [[func]] name = "M_UpdateLeader" addr = 0x43EE6C size = 0x72 [[func]] name = "DoEnding" addr = 0x43EEDE size = 0xDA [[func]] name = "PrepDoEnding" addr = 0x43EFB8 size = 0xB6 [[func]] name = "M_DoDeath" addr = 0x43F06E size = 0xFA [[func]] name = "M_DoSpStand" addr = 0x43F168 size = 0x5C [[func]] name = "M_DoDelay" addr = 0x43F1C4 size = 0x94 [[func]] name = "M_DoStone" addr = 0x43F258 size = 0x3E [[func]] name = "M_WalkDir" addr = 0x43F296 size = 0x123 [[func]] name = "M_StartWalk" addr = 0x43F3D9 size = 0xCD [[func]] name = "M_StartWalk2" addr = 0x43F4A6 size = 0x136 [[func]] name = "M_StartWalk3" addr = 0x43F5DC size = 0x159 [[func]] name = "GroupUnity" addr = 0x43F735 size = 0x202 [[func]] name = "M_CallWalk" addr = 0x43F937 size = 0x111 [[func]] name = "M_PathWalk" addr = 0x43FA48 size = 0x73 [[func]] name = "M_CallWalk2" addr = 0x43FABB size = 0x89 [[func]] name = "M_DumbWalk" addr = 0x43FB44 size = 0x21 [[func]] name = "M_RoundWalk" addr = 0x43FB65 size = 0xD1 [[func]] name = "MAI_Zombie" addr = 0x43FC36 size = 0x13D [[func]] name = "M_StartAttack" addr = 0x43FD73 size = 0x82 [[func]] name = "MAI_SkelSd" addr = 0x43FDF5 size = 0x131 [[func]] name = "M_StartDelay" addr = 0x43FF26 size = 0x26 [[func]] name = "MAI_Path" addr = 0x43FF4C size = 0xBF [[func]] name = "MAI_Snake" addr = 0x44000B size = 0x28D [[func]] name = "MAI_Bat" addr = 0x440298 size = 0x25F [[func]] name = "MAI_SkelBow" addr = 0x4404F7 size = 0x135 [[func]] name = "M_StartRAttack" addr = 0x44062C size = 0x98 [[func]] name = "MAI_Fat" addr = 0x4406C4 size = 0x11C [[func]] name = "M_StartSpAttack" addr = 0x4407E0 size = 0x85 [[func]] name = "MAI_Sneak" addr = 0x440865 size = 0x275 [[func]] name = "M_StartFadein" addr = 0x440ADA size = 0xBB [[func]] name = "M_StartFadeout" addr = 0x440B95 size = 0xAA [[func]] name = "MAI_Fireman" addr = 0x440C3F size = 0x220 [[func]] name = "MAI_Fallen" addr = 0x440E5F size = 0x1FA [[func]] name = "M_StartSpStand" addr = 0x441059 size = 0x7E [[func]] name = "MAI_Cleaver" addr = 0x4410D7 size = 0xA5 [[func]] name = "MAI_Round" addr = 0x44117C size = 0x292 [[func]] name = "MAI_GoatMc" addr = 0x44140E size = 0x8 [[func]] name = "MAI_Ranged" addr = 0x441416 size = 0x17D [[func]] name = "M_StartRSpAttack" addr = 0x441593 size = 0xA1 [[func]] name = "MAI_GoatBow" addr = 0x441634 size = 0xA [[func]] name = "MAI_Succ" addr = 0x44163E size = 0xB [[func]] name = "MAI_Lich" addr = 0x441649 size = 0xB [[func]] name = "MAI_ArchLich" addr = 0x441654 size = 0xB [[func]] name = "MAI_Psychorb" addr = 0x44165F size = 0xB [[func]] name = "MAI_Necromorb" addr = 0x44166A size = 0xB [[func]] name = "MAI_AcidUniq" addr = 0x441675 size = 0xB [[func]] name = "MAI_Firebat" addr = 0x441680 size = 0xB [[func]] name = "MAI_Torchant" addr = 0x44168B size = 0xB [[func]] name = "MAI_Scav" addr = 0x441696 size = 0x2DD [[func]] name = "M_StartEat" addr = 0x441973 size = 0x79 [[func]] name = "MAI_Garg" addr = 0x4419EC size = 0x123 [[func]] name = "M_StartHeal" addr = 0x441B0F size = 0x73 [[func]] name = "MAI_RoundRanged" addr = 0x441B82 size = 0x300 [[func]] name = "MAI_Magma" addr = 0x441E82 size = 0xF [[func]] name = "MAI_Storm" addr = 0x441E91 size = 0xF [[func]] name = "MAI_BoneDemon" addr = 0x441EA0 size = 0xF [[func]] name = "MAI_Acid" addr = 0x441EAF size = 0xF [[func]] name = "MAI_Diablo" addr = 0x441EBE size = 0xF [[func]] name = "MAI_RR2" addr = 0x441ECD size = 0x308 [[func]] name = "MAI_Mega" addr = 0x4421D5 size = 0xB [[func]] name = "MAI_Golum" addr = 0x4421E0 size = 0x219 [[func]] name = "MAI_SkelKing" addr = 0x4423F9 size = 0x321 [[func]] name = "MAI_Rhino" addr = 0x44271A size = 0x2EA [[func]] name = "MAI_HorkDemon" addr = 0x442A04 size = 0x2B1 [[func]] name = "MAI_Counselor" addr = 0x442CB5 size = 0x36B [[func]] name = "MAI_Garbud" addr = 0x443020 size = 0x101 [[func]] name = "MAI_Zhar" addr = 0x443121 size = 0x13F [[func]] name = "MAI_SnotSpil" addr = 0x443260 size = 0x14B [[func]] name = "MAI_Lazurus" addr = 0x4433AB size = 0x170 [[func]] name = "MAI_Lazhelp" addr = 0x44351B size = 0xBA [[func]] name = "MAI_Lachdanan" addr = 0x4435D5 size = 0xDC [[func]] name = "MAI_Warlord" addr = 0x4436B1 size = 0xD8 [[func]] name = "DeleteMonsterList" addr = 0x443789 size = 0x65 [[func]] name = "ProcessMonsters" addr = 0x4437EE size = 0x362 [[func]] name = "FreeMonsters" addr = 0x443B98 size = 0x6A [[func]] name = "DirOK" addr = 0x443C02 size = 0x1F6 [[func]] name = "PosOkMissile" addr = 0x443DF8 size = 0x26 [[func]] name = "CheckNoSolid" addr = 0x443E1E size = 0x1A [[func]] name = "LineClearF" addr = 0x443E38 size = 0x18F [[func]] name = "LineClear" addr = 0x443FC7 size = 0x1A [[func]] name = "LineClearF1" addr = 0x443FE1 size = 0x19B [[func]] name = "SyncMonsterAnim" addr = 0x44417C size = 0x132 [[func]] name = "M_FallenFear" addr = 0x4442F6 size = 0xE6 [[func]] name = "PrintMonstHistory" addr = 0x44440C size = 0x1BE [[func]] name = "PrintUniqueHistory" addr = 0x4445CA size = 0x8C [[func]] name = "MissToMonst" addr = 0x444656 size = 0x2AB [[func]] name = "PosOkMonst" addr = 0x444901 size = 0x80 [[func]] name = "monster_posok" addr = 0x444981 size = 0x11F [[func]] name = "PosOkMonst2" addr = 0x444AA0 size = 0x5F [[func]] name = "PosOkMonst3" addr = 0x444AFF size = 0xB9 [[func]] name = "IsSkel" addr = 0x444BB8 size = 0x25 [[func]] name = "IsGoat" addr = 0x444BDD size = 0x1B [[func]] name = "M_SpawnSkel" addr = 0x444BF8 size = 0xB0 [[func]] name = "ActivateSpawn" addr = 0x444CA8 size = 0x51 [[func]] name = "SpawnSkeleton" addr = 0x444CF9 size = 0x104 [[func]] name = "PreSpawnSkeleton" addr = 0x444DFD size = 0x9A [[func]] name = "TalktoMonster" addr = 0x444E97 size = 0xC5 [[func]] name = "SpawnGolum" addr = 0x444F5C size = 0x130 [[func]] name = "CanTalkToMonst" addr = 0x44508C size = 0x29 [[func]] name = "CheckMonsterHit" addr = 0x4450B5 size = 0x63 [[func]] name = "encode_enemy" addr = 0x445118 size = 0x20 [[func]] name = "decode_enemy" addr = 0x445138 size = 0x6B [[func]] name = "play_movie" addr = 0x4451A3 size = 0xFB [[func]] name = "MovieWndProc" addr = 0x44529E size = 0x54 [[func]] name = "mpqapi_set_hidden" addr = 0x4452F2 size = 0x3C [[func]] name = "mpqapi_store_creation_time" addr = 0x44532E size = 0x73 [[func]] name = "mpqapi_reg_load_modification_time" addr = 0x4453A1 size = 0x56 [[func]] name = "mpqapi_xor_buf" addr = 0x4453F7 size = 0x1F [[func]] name = "mpqapi_reg_store_modification_time" addr = 0x445416 size = 0x39 [[func]] name = "mpqapi_remove_hash_entry" addr = 0x445454 size = 0x52 [[func]] name = "mpqapi_alloc_block" addr = 0x4454A6 size = 0x90 [[func]] name = "mpqapi_new_block" addr = 0x445536 size = 0x3F [[func]] name = "FetchHandle" addr = 0x445575 size = 0x30 [[func]] name = "mpqapi_get_hash_index" addr = 0x4455A5 size = 0x6E [[func]] name = "mpqapi_remove_hash_entries" addr = 0x445613 size = 0x3B [[func]] name = "mpqapi_write_file" addr = 0x44564E size = 0x45 [[func]] name = "mpqapi_add_file" addr = 0x445693 size = 0xD6 [[func]] name = "mpqapi_write_file_contents" addr = 0x445769 size = 0x208 [[func]] name = "mpqapi_find_free_block" addr = 0x445971 size = 0x58 [[func]] name = "mpqapi_rename" addr = 0x4459C9 size = 0x3F [[func]] name = "mpqapi_has_file" addr = 0x445A08 size = 0x10 [[func]] name = "OpenMPQ" addr = 0x445A18 size = 0x1D2 [[func]] name = "ParseMPQHeader" addr = 0x445BEA size = 0xF1 [[func]] name = "CloseMPQ" addr = 0x445CDB size = 0x7B [[func]] name = "mpqapi_store_modified_time" addr = 0x445D56 size = 0x73 [[func]] name = "mpqapi_flush_and_close" addr = 0x445DC9 size = 0x5C [[func]] name = "WriteMPQHeader" addr = 0x445E25 size = 0x96 [[func]] name = "mpqapi_write_block_table" addr = 0x445EBB size = 0x8B [[func]] name = "mpqapi_write_hash_table" addr = 0x445F46 size = 0x8E [[func]] name = "mpqapi_can_seek" addr = 0x445FD4 size = 0x2B [[func]] name = "msg_send_drop_pkt" addr = 0x445FFF size = 0x1B [[func]] name = "msg_send_packet" addr = 0x44601A size = 0x62 [[func]] name = "msg_get_next_packet" addr = 0x44607C size = 0x3C [[func]] name = "msg_wait_resync" addr = 0x4460B8 size = 0x80 [[func]] name = "msg_free_packets" addr = 0x446138 size = 0x2C [[func]] name = "msg_wait_for_turns" addr = 0x446164 size = 0xD0 [[func]] name = "run_delta_info" addr = 0x446234 size = 0x22 [[func]] name = "msg_pre_packet" addr = 0x446256 size = 0x67 [[func]] name = "DeltaExportData" addr = 0x4462BD size = 0xB7 [[func]] name = "DeltaExportItem" addr = 0x446374 size = 0x2B [[func]] name = "DeltaExportObject" addr = 0x44639F size = 0x14 [[func]] name = "DeltaExportMonster" addr = 0x4463B3 size = 0x27 [[func]] name = "DeltaExportJunk" addr = 0x4463DA size = 0x6C [[func]] name = "msg_comp_level" addr = 0x446446 size = 0x1E [[func]] name = "delta_init" addr = 0x446464 size = 0x4D [[func]] name = "delta_kill_monster" addr = 0x4464B1 size = 0x4B [[func]] name = "delta_monster_hp" addr = 0x4464FC size = 0x34 [[func]] name = "delta_sync_monster" addr = 0x446530 size = 0x46 [[func]] name = "delta_sync_golem" addr = 0x446576 size = 0x49 [[func]] name = "delta_leave_sync" addr = 0x4465BF size = 0xDE [[func]] name = "delta_portal_inited" addr = 0x44669D size = 0xE [[func]] name = "delta_quest_inited" addr = 0x4466AB size = 0xE [[func]] name = "DeltaAddItem" addr = 0x4466B9 size = 0x144 [[func]] name = "DeltaSaveLevel" addr = 0x4467FD size = 0x5E [[func]] name = "DeltaLoadLevel" addr = 0x44685B size = 0x523 [[func]] name = "NetSendCmd" addr = 0x446D7E size = 0x1E [[func]] name = "NetSendCmdGolem" addr = 0x446D9C size = 0x36 [[func]] name = "NetSendCmdLoc" addr = 0x446DD2 size = 0x2C [[func]] name = "NetSendCmdLocParam1" addr = 0x446DFE size = 0x35 [[func]] name = "NetSendCmdLocParam2" addr = 0x446E33 size = 0x3D [[func]] name = "NetSendCmdLocParam3" addr = 0x446E70 size = 0x46 [[func]] name = "NetSendCmdParam1" addr = 0x446EB6 size = 0x28 [[func]] name = "NetSendCmdParam2" addr = 0x446EDE size = 0x31 [[func]] name = "NetSendCmdParam3" addr = 0x446F0F size = 0x39 [[func]] name = "NetSendCmdQuest" addr = 0x446F48 size = 0x44 [[func]] name = "NetSendCmdGItem" addr = 0x446F8C size = 0x1CC [[func]] name = "NetSendCmdReq2" addr = 0x447158 size = 0x53 [[func]] name = "NetSendCmdExtra" addr = 0x4471AB size = 0x2A [[func]] name = "NetSendCmdPItem" addr = 0x4471D5 size = 0x1AD [[func]] name = "NetSendCmdChItem" addr = 0x447382 size = 0x5F [[func]] name = "NetSendCmdDelItem" addr = 0x4473E1 size = 0x22 [[func]] name = "NetSendCmdDItem" addr = 0x447403 size = 0x1A9 [[func]] name = "NetSendCmdDamage" addr = 0x4475AC size = 0x2B [[func]] name = "NetSendCmdMonDmg" addr = 0x4475D7 size = 0x2C [[func]] name = "NetSendCmdString" addr = 0x447603 size = 0x39 [[func]] name = "delta_close_portal" addr = 0x44763C size = 0x1F [[func]] name = "ParseCmd" addr = 0x44765B size = 0x395 [[func]] name = "On_DLEVEL" addr = 0x447B88 size = 0xBE [[func]] name = "DeltaImportData" addr = 0x447C46 size = 0x88 [[func]] name = "DeltaImportItem" addr = 0x447CCE size = 0x48 [[func]] name = "DeltaImportObject" addr = 0x447D16 size = 0x14 [[func]] name = "DeltaImportMonster" addr = 0x447D2A size = 0x44 [[func]] name = "DeltaImportJunk" addr = 0x447D6E size = 0xB9 [[func]] name = "On_SYNCDATA" addr = 0x447E27 size = 0xB [[func]] name = "On_WALKXY" addr = 0x447E32 size = 0x55 [[func]] name = "On_ADDSTR" addr = 0x447E87 size = 0x31 [[func]] name = "On_ADDMAG" addr = 0x447EB8 size = 0x31 [[func]] name = "On_ADDDEX" addr = 0x447EE9 size = 0x31 [[func]] name = "On_ADDVIT" addr = 0x447F1A size = 0x31 [[func]] name = "On_SBSPELL" addr = 0x447F4B size = 0x93 [[func]] name = "msg_errorf" addr = 0x447FDE size = 0x47 [[func]] name = "On_GOTOGETITEM" addr = 0x448025 size = 0x5D [[func]] name = "On_REQUESTGITEM" addr = 0x448082 size = 0xD3 [[func]] name = "NetSendCmdGItem2" addr = 0x448155 size = 0x64 [[func]] name = "i_own_level" addr = 0x4481B9 size = 0x4A [[func]] name = "On_GETITEM" addr = 0x448203 size = 0x134 [[func]] name = "delta_get_item" addr = 0x448337 size = 0x131 [[func]] name = "On_GOTOAGETITEM" addr = 0x448468 size = 0x5D [[func]] name = "On_REQUESTAGITEM" addr = 0x4484C5 size = 0xD1 [[func]] name = "On_AGETITEM" addr = 0x448596 size = 0x132 [[func]] name = "On_ITEMEXTRA" addr = 0x4486C8 size = 0x5F [[func]] name = "On_PUTITEM" addr = 0x448727 size = 0x129 [[func]] name = "delta_put_item" addr = 0x448850 size = 0xAC [[func]] name = "check_update_plr" addr = 0x4488FC size = 0x1A [[func]] name = "On_SYNCPUTITEM" addr = 0x448916 size = 0x10F [[func]] name = "On_RESPAWNITEM" addr = 0x448A25 size = 0xCF [[func]] name = "On_ATTACKXY" addr = 0x448AF4 size = 0x6B [[func]] name = "On_SATTACKXY" addr = 0x448B5F size = 0x5E [[func]] name = "On_RATTACKXY" addr = 0x448BBD size = 0x5E [[func]] name = "On_SPELLXYD" addr = 0x448C1B size = 0xE1 [[func]] name = "On_SPELLXY" addr = 0x448CFC size = 0xD3 [[func]] name = "On_TSPELLXY" addr = 0x448DCF size = 0xD3 [[func]] name = "On_OPOBJXY" addr = 0x448EA2 size = 0x7B [[func]] name = "On_DISARMXY" addr = 0x448F1D size = 0x7B [[func]] name = "On_OPOBJT" addr = 0x448F98 size = 0x40 [[func]] name = "On_ATTACKID" addr = 0x448FD8 size = 0xBD [[func]] name = "On_ATTACKPID" addr = 0x449095 size = 0x68 [[func]] name = "On_RATTACKID" addr = 0x4490FD size = 0x50 [[func]] name = "On_RATTACKPID" addr = 0x44914D size = 0x50 [[func]] name = "On_SPELLID" addr = 0x44919D size = 0xC5 [[func]] name = "On_SPELLPID" addr = 0x449262 size = 0xC5 [[func]] name = "On_TSPELLID" addr = 0x449327 size = 0xC5 [[func]] name = "On_TSPELLPID" addr = 0x4493EC size = 0xC5 [[func]] name = "On_KNOCKBACK" addr = 0x4494B1 size = 0x46 [[func]] name = "On_RESURRECT" addr = 0x4494F7 size = 0x30 [[func]] name = "On_HEALOTHER" addr = 0x449527 size = 0x37 [[func]] name = "On_TALKXY" addr = 0x44955E size = 0x5D [[func]] name = "On_NEWLVL" addr = 0x4495BB size = 0x34 [[func]] name = "On_WARP" addr = 0x4495EF size = 0x66 [[func]] name = "On_MONSTDEATH" addr = 0x449655 size = 0x72 [[func]] name = "On_KILLGOLEM" addr = 0x4496C7 size = 0x6A [[func]] name = "On_AWAKEGOLEM" addr = 0x449731 size = 0xB4 [[func]] name = "On_MONSTDAMAGE" addr = 0x4497E5 size = 0xC1 [[func]] name = "On_PLRDEAD" addr = 0x4498A6 size = 0x38 [[func]] name = "On_PLRDAMAGE" addr = 0x4498DE size = 0x115 [[func]] name = "On_OPENDOOR" addr = 0x4499F3 size = 0x61 [[func]] name = "delta_sync_object" addr = 0x449A54 size = 0x25 [[func]] name = "On_CLOSEDOOR" addr = 0x449A79 size = 0x61 [[func]] name = "On_OPERATEOBJ" addr = 0x449ADA size = 0x61 [[func]] name = "On_PLROPOBJ" addr = 0x449B3B size = 0x61 [[func]] name = "On_BREAKOBJ" addr = 0x449B9C size = 0x5D [[func]] name = "On_CHANGEPLRITEMS" addr = 0x449BF9 size = 0x40 [[func]] name = "On_DELPLRITEMS" addr = 0x449C39 size = 0x2E [[func]] name = "On_PLRLEVEL" addr = 0x449C67 size = 0x41 [[func]] name = "On_DROPITEM" addr = 0x449CA8 size = 0x3B [[func]] name = "On_SEND_PLRINFO" addr = 0x449CE3 size = 0x3C [[func]] name = "On_ACK_PLRINFO" addr = 0x449D1F size = 0x5 [[func]] name = "On_PLAYER_JOINLEVEL" addr = 0x449D24 size = 0x1D8 [[func]] name = "On_ACTIVATEPORTAL" addr = 0x449EFC size = 0xDF [[func]] name = "delta_open_portal" addr = 0x449FDB size = 0x3B [[func]] name = "On_DEACTIVATEPORTAL" addr = 0x44A016 size = 0x3E [[func]] name = "On_RETOWN" addr = 0x44A054 size = 0x39 [[func]] name = "On_SETSTR" addr = 0x44A08D size = 0x39 [[func]] name = "On_SETDEX" addr = 0x44A0C6 size = 0x39 [[func]] name = "On_SETMAG" addr = 0x44A0FF size = 0x39 [[func]] name = "On_SETVIT" addr = 0x44A138 size = 0x39 [[func]] name = "On_STRING" addr = 0x44A171 size = 0xB [[func]] name = "On_STRING2" addr = 0x44A17C size = 0x2A [[func]] name = "On_SYNCQUEST" addr = 0x44A1A6 size = 0x42 [[func]] name = "On_ENDSHIELD" addr = 0x44A1E8 size = 0x87 [[func]] name = "On_ENDREFLECT" addr = 0x44A26F size = 0x87 [[func]] name = "On_DEBUG" addr = 0x44A2F6 size = 0x4 [[func]] name = "On_CHEAT_EXPERIENCE" addr = 0x44A2F6 size = 0x4 [[func]] name = "On_CHEAT_SPELL_LEVEL" addr = 0x44A2F6 size = 0x4 [[func]] name = "On_NAKRUL" addr = 0x44A2FA size = 0x28 [[func]] name = "On_OPENHIVE" addr = 0x44A322 size = 0x32 [[func]] name = "On_OPENCRYPT" addr = 0x44A354 size = 0x28 [[func]] name = "multi_msg_add" addr = 0x44A37C size = 0xE [[func]] name = "NetSendLoPri" addr = 0x44A38A size = 0x2E [[func]] name = "multi_copy_packet" addr = 0x44A3B8 size = 0x42 [[func]] name = "multi_send_packet" addr = 0x44A3FA size = 0x68 [[func]] name = "NetRecvPlrData" addr = 0x44A462 size = 0xED [[func]] name = "NetSendHiPri" addr = 0x44A54F size = 0xBA [[func]] name = "multi_recv_packet" addr = 0x44A609 size = 0x69 [[func]] name = "multi_send_msg_packet" addr = 0x44A672 size = 0x81 [[func]] name = "multi_msg_countdown" addr = 0x44A6F3 size = 0x37 [[func]] name = "multi_parse_turn" addr = 0x44A72A size = 0x4D [[func]] name = "multi_handle_turn_upper_bit" addr = 0x44A777 size = 0x39 [[func]] name = "multi_player_left" addr = 0x44A7B0 size = 0x13 [[func]] name = "multi_clear_left_tbl" addr = 0x44A7C3 size = 0x49 [[func]] name = "multi_player_left_msg" addr = 0x44A80C size = 0xA6 [[func]] name = "multi_net_ping" addr = 0x44A8B2 size = 0x13 [[func]] name = "multi_handle_delta" addr = 0x44A8C5 size = 0xAC [[func]] name = "multi_check_pkt_valid" addr = 0x44A971 size = 0x8 [[func]] name = "multi_mon_seeds" addr = 0x44A979 size = 0x33 [[func]] name = "multi_begin_timeout" addr = 0x44A9AC size = 0xA8 [[func]] name = "multi_check_drop_player" addr = 0x44AA54 size = 0x33 [[func]] name = "multi_process_network_packets" addr = 0x44AA87 size = 0x3AE [[func]] name = "multi_handle_all_packets" addr = 0x44AE35 size = 0x27 [[func]] name = "multi_process_tmsgs" addr = 0x44AE5C size = 0x33 [[func]] name = "multi_send_zero_packet" addr = 0x44AE8F size = 0xE4 [[func]] name = "NetClose" addr = 0x44AF73 size = 0x42 [[func]] name = "multi_event_handler" addr = 0x44AFB5 size = 0x4A [[func]] name = "multi_handle_events" addr = 0x44AFFF size = 0xA8 [[func]] name = "NetInit" addr = 0x44B0A7 size = 0x446 [[func]] name = "buffer_init" addr = 0x44B4ED size = 0x8 [[func]] name = "multi_send_pinfo" addr = 0x44B4F5 size = 0x39 [[func]] name = "InitLevelType" addr = 0x44B52E size = 0x52 [[func]] name = "SetupLocalCoords" addr = 0x44B580 size = 0x13D [[func]] name = "multi_upgrade" addr = 0x44B6BD size = 0x3C [[func]] name = "recv_plrinfo" addr = 0x44B6F9 size = 0x1D5 [[func]] name = "nthread_terminate_game" addr = 0x44B8FC size = 0x3D [[func]] name = "nthread_send_and_recv_turn" addr = 0x44B939 size = 0x85 [[func]] name = "nthread_recv_turns" addr = 0x44B9BE size = 0xAD [[func]] name = "nthread_set_turn_upper_bit" addr = 0x44BA6B size = 0xB [[func]] name = "nthread_start" addr = 0x44BA76 size = 0x16D [[func]] name = "nthread_handler" addr = 0x44BBE3 size = 0x76 [[func]] name = "nthread_cleanup" addr = 0x44BC59 size = 0x7F [[func]] name = "nthread_ignore_mutex" addr = 0x44BCD8 size = 0x2B [[func]] name = "nthread_has_500ms_passed" addr = 0x44BD03 size = 0x2E [[func]] name = "InitObjectGFX" addr = 0x44BD31 size = 0x17A [[func]] name = "FreeObjectGFX" addr = 0x44BEAB size = 0x31 [[func]] name = "InitRndLocObj" addr = 0x44BEDC size = 0xF0 [[func]] name = "RndLocOk" addr = 0x44BFCC size = 0x56 [[func]] name = "AddL1Objs" addr = 0x44C022 size = 0x98 [[func]] name = "add_crypt_objs" addr = 0x44C0BA size = 0x6E [[func]] name = "AddL2Objs" addr = 0x44C128 size = 0x7E [[func]] name = "InitObjects" addr = 0x44C1A6 size = 0x461 [[func]] name = "InitRndLocBigObj" addr = 0x44C607 size = 0x129 [[func]] name = "InitRndLocObj5x5" addr = 0x44C730 size = 0xB2 [[func]] name = "ClrAllObjects" addr = 0x44C7E2 size = 0x58 [[func]] name = "AddTortures" addr = 0x44C83A size = 0xF7 [[func]] name = "AddCandles" addr = 0x44C931 size = 0x49 [[func]] name = "AddBookLever" addr = 0x44C97A size = 0x11E [[func]] name = "InitRndBarrels" addr = 0x44CA98 size = 0xFE [[func]] name = "AddL3Objs" addr = 0x44CB96 size = 0x74 [[func]] name = "AddL2Torches" addr = 0x44CC0A size = 0xED [[func]] name = "WallTrapLocOk" addr = 0x44CCF7 size = 0x12 [[func]] name = "AddObjTraps" addr = 0x44CD09 size = 0x18E [[func]] name = "TorchLocOK" addr = 0x44CE97 size = 0x24 [[func]] name = "AddChestTraps" addr = 0x44CEBB size = 0x94 [[func]] name = "LoadMapObjs" addr = 0x44CF4F size = 0x87 [[func]] name = "AddDiabObjs" addr = 0x44CFD6 size = 0xBD [[func]] name = "LoadMapObjects" addr = 0x44D093 size = 0xD8 [[func]] name = "AddCryptStoryBook" addr = 0x44D16B size = 0xDE [[func]] name = "AddStoryBooks" addr = 0x44D249 size = 0xD9 [[func]] name = "AddL4Goodies" addr = 0x44D322 size = 0x77 [[func]] name = "AddHookedBodies" addr = 0x44D399 size = 0xD8 [[func]] name = "AddLazStand" addr = 0x44D471 size = 0x109 [[func]] name = "SetMapObjects" addr = 0x44D57A size = 0x168 [[func]] name = "SetObjMapRange" addr = 0x44D6E2 size = 0x34 [[func]] name = "SetBookMsg" addr = 0x44D716 size = 0xA [[func]] name = "AddVilebook" addr = 0x44D720 size = 0x20 [[func]] name = "AddMagicCircle" addr = 0x44D740 size = 0x29 [[func]] name = "AddBrnCross" addr = 0x44D769 size = 0x13 [[func]] name = "AddPedistal" addr = 0x44D77C size = 0x38 [[func]] name = "AddMushPatch" addr = 0x44D7B4 size = 0x5C [[func]] name = "GetRndObjLoc" addr = 0x44D810 size = 0x8A [[func]] name = "AddSlainHero" addr = 0x44D89A size = 0x2B [[func]] name = "AddCryptBook" addr = 0x44D8C5 size = 0x81 [[func]] name = "SetupObject" addr = 0x44D946 size = 0x122 [[func]] name = "AddCryptObject" addr = 0x44DA68 size = 0x20D [[func]] name = "AddObject" addr = 0x44DC75 size = 0x24E [[func]] name = "AddL1Door" addr = 0x44DF7B size = 0x5F [[func]] name = "AddSCambBook" addr = 0x44DFDA size = 0x49 [[func]] name = "AddChest" addr = 0x44E023 size = 0xB6 [[func]] name = "AddL2Door" addr = 0x44E0D9 size = 0x3B [[func]] name = "AddL3Door" addr = 0x44E114 size = 0x3B [[func]] name = "AddSarc" addr = 0x44E14F size = 0x51 [[func]] name = "AddFlameTrap" addr = 0x44E1A0 size = 0x28 [[func]] name = "AddFlameLvr" addr = 0x44E1C8 size = 0x19 [[func]] name = "AddTrap" addr = 0x44E1E1 size = 0x7E [[func]] name = "AddObjLight" addr = 0x44E25F size = 0x37 [[func]] name = "AddBarrel" addr = 0x44E296 size = 0x4E [[func]] name = "AddShrine" addr = 0x44E2E4 size = 0xB0 [[func]] name = "AddBookcase" addr = 0x44E394 size = 0x1D [[func]] name = "AddBookstand" addr = 0x44E3B1 size = 0x13 [[func]] name = "AddArmorStand" addr = 0x44E3C4 size = 0x32 [[func]] name = "AddPurifyingFountain" addr = 0x44E3F6 size = 0x39 [[func]] name = "AddDecap" addr = 0x44E42F size = 0x2E [[func]] name = "AddStoryBook" addr = 0x44E45D size = 0x95 [[func]] name = "AddWeaponRack" addr = 0x44E4F2 size = 0x32 [[func]] name = "AddTorturedBody" addr = 0x44E524 size = 0x2E [[func]] name = "Obj_Light" addr = 0x44E552 size = 0xF0 [[func]] name = "Obj_Circle" addr = 0x44E642 size = 0x17A [[func]] name = "Obj_StopAnim" addr = 0x44E7BC size = 0x23 [[func]] name = "Obj_Door" addr = 0x44E7DF size = 0x91 [[func]] name = "Obj_Sarc" addr = 0x44E870 size = 0x19 [[func]] name = "ActivateTrapLine" addr = 0x44E889 size = 0x7F [[func]] name = "Obj_FlameTrap" addr = 0x44E908 size = 0x12B [[func]] name = "Obj_Trap" addr = 0x44EA33 size = 0x15D [[func]] name = "ProcessObjects" addr = 0x44EB90 size = 0x1BF [[func]] name = "DeleteObject_" addr = 0x44ED4F size = 0x50 [[func]] name = "Obj_BCrossDamage" addr = 0x44ED9F size = 0x15C [[func]] name = "ObjSetMicro" addr = 0x44EEFB size = 0x83 [[func]] name = "RedoPlayerVision" addr = 0x44EF7E size = 0x3D [[func]] name = "OperateL1RDoor" addr = 0x44EFBB size = 0x260 [[func]] name = "objects_set_door_piece" addr = 0x44F21B size = 0x78 [[func]] name = "DoorSet" addr = 0x44F293 size = 0x2B7 [[func]] name = "OperateL1LDoor" addr = 0x44F54A size = 0x275 [[func]] name = "OperateL2LDoor" addr = 0x44F7BF size = 0x175 [[func]] name = "MonstCheckDoors" addr = 0x44F934 size = 0x230 [[func]] name = "OperateL2RDoor" addr = 0x44FB64 size = 0x175 [[func]] name = "OperateL3RDoor" addr = 0x44FCD9 size = 0x178 [[func]] name = "OperateL3LDoor" addr = 0x44FE51 size = 0x178 [[func]] name = "ObjChangeMap" addr = 0x44FFC9 size = 0xEA [[func]] name = "ObjSetMini" addr = 0x4500B3 size = 0x78 [[func]] name = "ObjL1Special" addr = 0x45012B size = 0xEC [[func]] name = "ObjL2Special" addr = 0x450217 size = 0xFC [[func]] name = "ObjChangeMapResync" addr = 0x450313 size = 0xBE [[func]] name = "TryDisarm" addr = 0x4503D1 size = 0xC9 [[func]] name = "ItemMiscIdIdx" addr = 0x45049A size = 0x18 [[func]] name = "OperateObject" addr = 0x4504B2 size = 0x2C0 [[func]] name = "OperateL1Door" addr = 0x4507F7 size = 0x97 [[func]] name = "OperateLever" addr = 0x45088E size = 0xF4 [[func]] name = "OperateBook" addr = 0x450982 size = 0x260 [[func]] name = "OperateBookLever" addr = 0x450BE2 size = 0x1B2 [[func]] name = "OperateSChambBk" addr = 0x450D94 size = 0x100 [[func]] name = "OperateChest" addr = 0x450E94 size = 0x1AD [[func]] name = "OperateMushPatch" addr = 0x451041 size = 0xF7 [[func]] name = "OperateInnSignChest" addr = 0x451138 size = 0xE4 [[func]] name = "OperateSlainHero" addr = 0x45121C size = 0x18A [[func]] name = "OperateTrapLvr" addr = 0x4513A6 size = 0xBF [[func]] name = "OperateSarc" addr = 0x451465 size = 0xD7 [[func]] name = "OperateL2Door" addr = 0x45153C size = 0x9A [[func]] name = "OperateL3Door" addr = 0x4515D6 size = 0x98 [[func]] name = "OperatePedistal" addr = 0x45166E size = 0x166 [[func]] name = "OperateShrine" addr = 0x4517D4 size = 0x189F [[func]] name = "OperateSkelBook" addr = 0x4530FB size = 0xA0 [[func]] name = "OperateBookCase" addr = 0x45319B size = 0xE2 [[func]] name = "OperateDecap" addr = 0x45327D size = 0x64 [[func]] name = "OperateArmorStand" addr = 0x4532E1 size = 0xD7 [[func]] name = "OperateGoatShrine" addr = 0x4533B8 size = 0x4B [[func]] name = "FindValidShrine" addr = 0x453403 size = 0x63 [[func]] name = "OperateCauldron" addr = 0x453466 size = 0x52 [[func]] name = "OperateFountains" addr = 0x4534B8 size = 0x30D [[func]] name = "OperateWeaponRack" addr = 0x4537C5 size = 0xAC [[func]] name = "OperateStoryBook" addr = 0x453871 size = 0xCD [[func]] name = "OperateLazStand" addr = 0x45393E size = 0x65 [[func]] name = "SyncOpObject" addr = 0x4539A3 size = 0x1D5 [[func]] name = "SyncOpL1Door" addr = 0x453B78 size = 0x74 [[func]] name = "SyncOpL2Door" addr = 0x453BEC size = 0x74 [[func]] name = "SyncOpL3Door" addr = 0x453C60 size = 0x74 [[func]] name = "BreakObject" addr = 0x453CD4 size = 0xA3 [[func]] name = "BreakCrux" addr = 0x453D77 size = 0xC3 [[func]] name = "BreakBarrel" addr = 0x453E3A size = 0x2DE [[func]] name = "SyncBreakObj" addr = 0x454118 size = 0x21 [[func]] name = "SyncObjectAnim" addr = 0x454139 size = 0xC2 [[func]] name = "SyncL1Doors" addr = 0x4541FB size = 0x106 [[func]] name = "SyncCrux" addr = 0x454301 size = 0x7D [[func]] name = "SyncLever" addr = 0x45437E size = 0x2A [[func]] name = "SyncQSTLever" addr = 0x4543A8 size = 0x6F [[func]] name = "SyncPedistal" addr = 0x454417 size = 0xC5 [[func]] name = "SyncL2Doors" addr = 0x4544DC size = 0x9D [[func]] name = "SyncL3Doors" addr = 0x454579 size = 0x92 [[func]] name = "GetObjectStr" addr = 0x45460B size = 0x293 [[func]] name = "AddNakrulGate" addr = 0x454963 size = 0x18D [[func]] name = "AddNakrulBook" addr = 0x454AF0 size = 0x14 [[func]] name = "OperateNakrulBook" addr = 0x454B04 size = 0x42 [[func]] name = "OperateNakrulLever" addr = 0x454B46 size = 0x62 [[func]] name = "SyncNakrulRoom" addr = 0x454BA8 size = 0x42 [[func]] name = "AddNakrulLeaver" addr = 0x454BEA size = 0xD5 [[func]] name = "PackItem" addr = 0x454CBF size = 0x110 [[func]] name = "PackPlayer" addr = 0x454DCF size = 0x207 [[func]] name = "UnPackItem" addr = 0x454FD6 size = 0xAD [[func]] name = "VerifyGoldSeeds" addr = 0x455083 size = 0x6F [[func]] name = "UnPackPlayer" addr = 0x4550F2 size = 0x2A4 [[func]] name = "SaveGamma" addr = 0x455396 size = 0x18 [[func]] name = "palette_init" addr = 0x4553AE size = 0x78 [[func]] name = "LoadGamma" addr = 0x455426 size = 0x52 [[func]] name = "LoadSysPal" addr = 0x455478 size = 0xB3 [[func]] name = "LoadPalette" addr = 0x45552B size = 0x5C [[func]] name = "LoadRndLvlPal" addr = 0x455587 size = 0x90 [[func]] name = "ResetPal" addr = 0x455617 size = 0x2B [[func]] name = "IncreaseGamma" addr = 0x455642 size = 0x39 [[func]] name = "palette_update" addr = 0x45567B size = 0x3B [[func]] name = "ApplyGamma" addr = 0x4556B6 size = 0xD1 [[func]] name = "DecreaseGamma" addr = 0x455787 size = 0x39 [[func]] name = "UpdateGamma" addr = 0x4557C0 size = 0x35 [[func]] name = "BlackPalette" addr = 0x4557F5 size = 0x7 [[func]] name = "SetFadeLevel" addr = 0x4557FC size = 0x6B [[func]] name = "PaletteFadeIn" addr = 0x455867 size = 0x56 [[func]] name = "PaletteFadeOut" addr = 0x4558BD size = 0x30 [[func]] name = "palette_update_caves" addr = 0x4558ED size = 0x4C [[func]] name = "palette_update_crypt" addr = 0x455939 size = 0xCE [[func]] name = "palette_update_hive" addr = 0x455A07 size = 0xCB [[func]] name = "palette_update_quest_palette" addr = 0x455AD2 size = 0x2E [[func]] name = "FindPath" addr = 0x455B00 size = 0x110 [[func]] name = "path_get_h_cost" addr = 0x455C10 size = 0x33 [[func]] name = "path_check_equal" addr = 0x455C43 size = 0x18 [[func]] name = "GetNextPath" addr = 0x455C5B size = 0x2A [[func]] name = "path_solid_pieces" addr = 0x455C85 size = 0xA7 [[func]] name = "path_get_path" addr = 0x455D2C size = 0x89 [[func]] name = "path_parent_path" addr = 0x455DB5 size = 0x12B [[func]] name = "path_get_node1" addr = 0x455EE0 size = 0x1A [[func]] name = "path_get_node2" addr = 0x455EFA size = 0x1A [[func]] name = "path_next_node" addr = 0x455F14 size = 0x31 [[func]] name = "path_set_coords" addr = 0x455F45 size = 0x93 [[func]] name = "path_push_active_step" addr = 0x455FD8 size = 0x13 [[func]] name = "path_pop_active_step" addr = 0x455FEB size = 0x13 [[func]] name = "path_new_step" addr = 0x455FFE size = 0x36 [[func]] name = "pfile_init_save_directory" addr = 0x456034 size = 0x5F [[func]] name = "pfile_check_available_space" addr = 0x456093 size = 0x77 [[func]] name = "pfile_write_hero" addr = 0x45610A size = 0x69 [[func]] name = "pfile_get_save_num_from_name" addr = 0x456173 size = 0x2B [[func]] name = "pfile_encode_hero" addr = 0x45619E size = 0x89 [[func]] name = "pfile_open_archive" addr = 0x456227 size = 0x5D [[func]] name = "pfile_get_save_path" addr = 0x456284 size = 0xAB [[func]] name = "pfile_flush" addr = 0x45632F size = 0x34 [[func]] name = "pfile_flush_W" addr = 0x456363 size = 0x27 [[func]] name = "game_2_ui_player" addr = 0x45638A size = 0x90 [[func]] name = "game_2_ui_class" addr = 0x45641A size = 0x26 [[func]] name = "pfile_ui_set_hero_infos" addr = 0x456440 size = 0xA4 [[func]] name = "pfile_read_hero" addr = 0x4564E4 size = 0xD1 [[func]] name = "pfile_update" addr = 0x456DAF size = 0x32 [[func]] name = "pfile_open_save_archive" addr = 0x4565B5 size = 0x3C [[func]] name = "pfile_SFileCloseArchive" addr = 0x4565F1 size = 0x7 [[func]] name = "pfile_archive_contains_game" addr = 0x4565F8 size = 0x10C [[func]] name = "pfile_ui_set_class_stats" addr = 0x456704 size = 0x44 [[func]] name = "pfile_get_player_class" addr = 0x456748 size = 0x2A [[func]] name = "pfile_ui_save_create" addr = 0x456772 size = 0xEB [[func]] name = "pfile_get_file_name" addr = 0x45685d size = 0x57 [[func]] name = "pfile_delete_save" addr = 0x4568B4 size = 0x4C [[func]] name = "pfile_read_player_from_save" addr = 0x456900 size = 0x79 [[func]] name = "GetTempLevelNames" addr = 0x456979 size = 0x50 [[func]] name = "GetPermLevelNames" addr = 0x4569C9 size = 0x8B [[func]] name = "pfile_get_game_name" addr = 0x456A54 size = 0x2F [[func]] name = "pfile_remove_temp_files" addr = 0x456A83 size = 0x57 [[func]] name = "GetTempSaveNames" addr = 0x456ADA size = 0x35 [[func]] name = "pfile_rename_temp_to_perm" addr = 0x456B0F size = 0xB2 [[func]] name = "GetPermSaveNames" addr = 0x456BC1 size = 0x35 [[func]] name = "pfile_write_save_file" addr = 0x456BF6 size = 0xA9 [[func]] name = "pfile_read" addr = 0x456C9F size = 0x110 [[func]] name = "SetPlayerGPtrs" addr = 0x456DE1 size = 0x1B [[func]] name = "LoadPlrGFX" addr = 0x456DFC size = 0x2C4 [[func]] name = "InitPlayerGFX" addr = 0x4570C0 size = 0x4A [[func]] name = "InitPlrGFXMem" addr = 0x45710A size = 0x35A [[func]] name = "GetPlrGFXSize" addr = 0x457464 size = 0x12A [[func]] name = "FreePlayerGFX" addr = 0x45758E size = 0x117 [[func]] name = "NewPlrAnim" addr = 0x4576A5 size = 0x93 [[func]] name = "ClearPlrPVars" addr = 0x457738 size = 0x89 [[func]] name = "SetPlrAnims" addr = 0x4577C1 size = 0x497 [[func]] name = "ClearPlrRVars" addr = 0x457C58 size = 0x6A [[func]] name = "CreatePlayer" addr = 0x457CC2 size = 0x5DD [[func]] name = "CalcStatDiff" addr = 0x45829F size = 0x48 [[func]] name = "NextPlrLevel" addr = 0x4582E7 size = 0x1AB [[func]] name = "AddPlrExperience" addr = 0x458492 size = 0x16C [[func]] name = "AddPlrMonstExper" addr = 0x4585FE size = 0x44 [[func]] name = "InitPlayer" addr = 0x458642 size = 0x400 [[func]] name = "InitMultiView" addr = 0x458A42 size = 0x3C [[func]] name = "CheckEFlag" addr = 0x458A7E size = 0x15D [[func]] name = "SolidLoc" addr = 0x458BDB size = 0x14 [[func]] name = "PlrDirOK" addr = 0x458BEF size = 0xC1 [[func]] name = "PlrClrTrans" addr = 0x458CB0 size = 0x43 [[func]] name = "PlrDoTrans" addr = 0x458CF3 size = 0x81 [[func]] name = "SetPlayerOld" addr = 0x458D74 size = 0x3C [[func]] name = "FixPlayerLocation" addr = 0x458DB0 size = 0xB4 [[func]] name = "StartStand" addr = 0x458E64 size = 0xCD [[func]] name = "StartWalkStand" addr = 0x458F31 size = 0x94 [[func]] name = "PM_ChangeLightOff" addr = 0x458FC5 size = 0xC5 [[func]] name = "PM_ChangeOffset" addr = 0x45908A size = 0x110 [[func]] name = "StartWalk" addr = 0x45919A size = 0x21A [[func]] name = "StartWalk2" addr = 0x4593B4 size = 0x284 [[func]] name = "StartWalk3" addr = 0x459638 size = 0x2B7 [[func]] name = "StartAttack" addr = 0x4598EF size = 0xAD [[func]] name = "StartRangeAttack" addr = 0x45999C size = 0xD6 [[func]] name = "StartPlrBlock" addr = 0x459A72 size = 0xC3 [[func]] name = "StartSpell" addr = 0x459B35 size = 0x1CB [[func]] name = "FixPlrWalkTags" addr = 0x459D00 size = 0xCD [[func]] name = "RemovePlrFromMap" addr = 0x459DCD size = 0x7B [[func]] name = "StartPlrHit" addr = 0x459E48 size = 0x19F [[func]] name = "RespawnDeadItem" addr = 0x459FE7 size = 0xCC [[func]] name = "StartPlayerKill" addr = 0x45A0B3 size = 0x374 [[func]] name = "PlrDeadItem" addr = 0x45A427 size = 0x11D [[func]] name = "DropHalfPlayersGold" addr = 0x45A544 size = 0x550 [[func]] name = "StripTopGold" addr = 0x45AA94 size = 0x143 [[func]] name = "SyncPlrKill" addr = 0x45ABD7 size = 0x9B [[func]] name = "RemovePlrMissiles" addr = 0x45AC77 size = 0x149 [[func]] name = "InitLevelChange" addr = 0x45ADC0 size = 0xBC [[func]] name = "StartNewLvl" addr = 0x45AE7C size = 0x103 [[func]] name = "RestartTownLvl" addr = 0x45AF7F size = 0xB1 [[func]] name = "StartWarpLvl" addr = 0x45B030 size = 0x88 [[func]] name = "PM_DoStand" addr = 0x45B0B8 size = 0x3 [[func]] name = "PM_DoNewLvl" addr = 0x45B0B8 size = 0x3 [[func]] name = "PM_DoWalk" addr = 0x45B0BB size = 0x1CE [[func]] name = "PM_DoWalk2" addr = 0x45B289 size = 0x1B1 [[func]] name = "PM_DoWalk3" addr = 0x45B43A size = 0x1EC [[func]] name = "WeaponDur" addr = 0x45B626 size = 0x222 [[func]] name = "PlrHitMonst" addr = 0x45B848 size = 0x61E [[func]] name = "PlrHitPlr" addr = 0x45BE66 size = 0x29A [[func]] name = "PlrHitObj" addr = 0x45C100 size = 0x3D [[func]] name = "PM_DoAttack" addr = 0x45C13D size = 0x402 [[func]] name = "PM_DoRangeAttack" addr = 0x45C53F size = 0x1F5 [[func]] name = "ShieldDur" addr = 0x45C734 size = 0xDC [[func]] name = "PM_DoBlock" addr = 0x45C810 size = 0x8A [[func]] name = "PM_DoSpell" addr = 0x45C89A size = 0x177 [[func]] name = "PM_DoGotHit" addr = 0x45CA11 size = 0xCE [[func]] name = "ArmorDur" addr = 0x45CADF size = 0xC5 [[func]] name = "PM_DoDeath" addr = 0x45CBA4 size = 0xC3 [[func]] name = "CheckNewPath" addr = 0x45CC67 size = 0xB9C [[func]] name = "PlrDeathModeOK" addr = 0x45D86B size = 0x44 [[func]] name = "ValidatePlayer" addr = 0x45D8AF size = 0x228 [[func]] name = "ProcessPlayers" addr = 0x45DAD7 size = 0x29B [[func]] name = "CheckCheatStats" addr = 0x45DD9E size = 0x95 [[func]] name = "ClrPlrPath" addr = 0x45DE33 size = 0x33 [[func]] name = "PosOkPlayer" addr = 0x45DE66 size = 0xBE [[func]] name = "MakePlrPath" addr = 0x45DF24 size = 0xBF [[func]] name = "CheckPlrSpell" addr = 0x45E003 size = 0x336 [[func]] name = "SyncPlrAnim" addr = 0x45E339 size = 0x133 [[func]] name = "SyncInitPlrPos" addr = 0x45E49C size = 0xBD [[func]] name = "SyncInitPlr" addr = 0x45E559 size = 0x25 [[func]] name = "CheckStats" addr = 0x45E57E size = 0x10E [[func]] name = "ModifyPlrStr" addr = 0x45E68C size = 0x98 [[func]] name = "ModifyPlrMag" addr = 0x45E724 size = 0xFE [[func]] name = "ModifyPlrDex" addr = 0x45E822 size = 0x98 [[func]] name = "ModifyPlrVit" addr = 0x45E8BA size = 0xF2 [[func]] name = "SetPlayerHitPoints" addr = 0x45E9AC size = 0x5E [[func]] name = "SetPlrStr" addr = 0x45EA0A size = 0x3A [[func]] name = "SetPlrMag" addr = 0x45EA44 size = 0x72 [[func]] name = "SetPlrDex" addr = 0x45EAB6 size = 0x3A [[func]] name = "SetPlrVit" addr = 0x45EAF0 size = 0x69 [[func]] name = "InitDungMsgs" addr = 0x45EB59 size = 0x3B [[func]] name = "PlayDungMsgs" addr = 0x45EB94 size = 0x40D [[func]] name = "get_max_strength" addr = 0x45EFA1 size = 0xA [[func]] name = "get_max_magic" addr = 0x45EFAB size = 0xA [[func]] name = "get_max_dexterity" addr = 0x45EFB5 size = 0xA [[func]] name = "plrmsg_delay" addr = 0x45EFBF size = 0x37 [[func]] name = "ErrorPlrMsg" addr = 0x45EFF6 size = 0x49 [[func]] name = "EventPlrMsg" addr = 0x45F03F size = 0x48 [[func]] name = "SendPlrMsg" addr = 0x45F087 size = 0x7E [[func]] name = "ClearPlrMsg" addr = 0x45F105 size = 0x2A [[func]] name = "InitPlrMsg" addr = 0x45F12F size = 0x1C [[func]] name = "DrawPlrMsg" addr = 0x45F14B size = 0x8D [[func]] name = "PrintPlrMsg" addr = 0x45F1D8 size = 0xC7 [[func]] name = "InitPortals" addr = 0x45F29F size = 0x26 [[func]] name = "SetPortalStats" addr = 0x45F2C5 size = 0x3E [[func]] name = "AddWarpMissile" addr = 0x45F303 size = 0x74 [[func]] name = "SyncPortals" addr = 0x45F377 size = 0x5B [[func]] name = "AddInTownPortal" addr = 0x45F3D2 size = 0x14 [[func]] name = "ActivatePortal" addr = 0x45F3E6 size = 0x45 [[func]] name = "DeactivatePortal" addr = 0x45F42B size = 0xC [[func]] name = "PortalOnLevel" addr = 0x45F437 size = 0x22 [[func]] name = "RemovePortalMissile" addr = 0x45F459 size = 0x8F [[func]] name = "SetCurrentPortal" addr = 0x45F4E8 size = 0x7 [[func]] name = "GetPortalLevel" addr = 0x45F4EF size = 0xB5 [[func]] name = "GetPortalLvlPos" addr = 0x45F5A4 size = 0x63 [[func]] name = "InitQuests" addr = 0x45F607 size = 0x1B5 [[func]] name = "CheckQuests" addr = 0x45F7BC size = 0x236 [[func]] name = "ForceQuests" addr = 0x45F9F2 size = 0xA1 [[func]] name = "QuestStatus" addr = 0x45FA93 size = 0x3F [[func]] name = "CheckQuestKill" addr = 0x45FAD2 size = 0x487 [[func]] name = "DrawButcher" addr = 0x45FF59 size = 0x27 [[func]] name = "DrawSkelKing" addr = 0x45FF80 size = 0x1E [[func]] name = "DrawWarLord" addr = 0x45FF9E size = 0x91 [[func]] name = "DrawSChamber" addr = 0x46002F size = 0xB8 [[func]] name = "DrawLTBanner" addr = 0x4600E7 size = 0x8D [[func]] name = "DrawBlind" addr = 0x460174 size = 0x8D [[func]] name = "DrawBlood" addr = 0x460201 size = 0x8D [[func]] name = "DRLG_CheckQuests" addr = 0x46028E size = 0x91 [[func]] name = "SetReturnLvlPos" addr = 0x46031F size = 0xBF [[func]] name = "GetReturnLvlPos" addr = 0x4603DE size = 0x39 [[func]] name = "ResyncMPQuests" addr = 0x460417 size = 0x168 [[func]] name = "ResyncQuests" addr = 0x46057F size = 0x333 [[func]] name = "PrintQLString" addr = 0x4608B2 size = 0x14D [[func]] name = "DrawQuestLog" addr = 0x4609FF size = 0x91 [[func]] name = "StartQuestlog" addr = 0x460A90 size = 0x71 [[func]] name = "QuestlogUp" addr = 0x460B01 size = 0x47 [[func]] name = "QuestlogDown" addr = 0x460B48 size = 0x4A [[func]] name = "QuestlogEnter" addr = 0x460B92 size = 0x40 [[func]] name = "QuestlogESC" addr = 0x460BD2 size = 0x55 [[func]] name = "SetMultiQuest" addr = 0x460C27 size = 0x41 [[func]] name = "drawTopArchesUpperScreen" addr = 0x460C68 size = 0x162D [[func]] name = "drawBottomArchesUpperScreen" addr = 0x462295 size = 0xC38 [[func]] name = "drawUpperScreen" addr = 0x462ECD size = 0xC73 [[func]] name = "drawTopArchesLowerScreen" addr = 0x463B40 size = 0x1A11 [[func]] name = "drawBottomArchesLowerScreen" addr = 0x465551 size = 0xF22 [[func]] name = "drawLowerScreen" addr = 0x466473 size = 0xE53 [[func]] name = "world_draw_black_tile" addr = 0x4672C6 size = 0x5C [[func]] name = "ClearCursor" addr = 0x467322 size = 0xF [[func]] name = "DrawMissile" addr = 0x467331 size = 0x1A4 [[func]] name = "DrawClippedMissile" addr = 0x4674D5 size = 0x1A4 [[func]] name = "DrawDeadPlayer" addr = 0x467679 size = 0xE2 [[func]] name = "DrawPlayer" addr = 0x46775B size = 0x142 [[func]] name = "DrawClippedPlayer" addr = 0x46789D size = 0x12C [[func]] name = "DrawView" addr = 0x4679C9 size = 0x11A [[func]] name = "DrawGame" addr = 0x467AE3 size = 0x1E5 [[func]] name = "scrollrt_draw_lower" addr = 0x467CE8 size = 0x480 [[func]] name = "scrollrt_draw_clipped_dungeon" addr = 0x468168 size = 0x63C [[func]] name = "DrawClippedMonster" addr = 0x4687A4 size = 0xFA [[func]] name = "DrawClippedObject" addr = 0x46889E size = 0x119 [[func]] name = "scrollrt_draw_clipped_e_flag" addr = 0x4689B7 size = 0x144 [[func]] name = "scrollrt_draw_lower_2" addr = 0x468AFB size = 0x3D8 [[func]] name = "scrollrt_draw_clipped_dungeon_2" addr = 0x468ED3 size = 0x66C [[func]] name = "scrollrt_draw_clipped_e_flag_2" addr = 0x46953F size = 0x194 [[func]] name = "scrollrt_draw_upper" addr = 0x4696D3 size = 0x4B9 [[func]] name = "scrollrt_draw_dungeon" addr = 0x469B8C size = 0x66F [[func]] name = "DrawMonster" addr = 0x46A1FB size = 0xFA [[func]] name = "DrawObject" addr = 0x46A2F5 size = 0x14E [[func]] name = "scrollrt_draw_e_flag" addr = 0x46A443 size = 0x158 [[func]] name = "DrawZoom" addr = 0x46A59B size = 0x245 [[func]] name = "ClearScreenBuffer" addr = 0x46A800 size = 0x34 [[func]] name = "scrollrt_draw_game_screen" addr = 0x46A834 size = 0x62 [[func]] name = "scrollrt_draw_cursor_back_buffer" addr = 0x46A896 size = 0x8F [[func]] name = "scrollrt_draw_cursor_item" addr = 0x46A925 size = 0x271 [[func]] name = "DrawMain" addr = 0x46AB96 size = 0x28F [[func]] name = "DoBlitScreen" addr = 0x46AE25 size = 0x141 [[func]] name = "DrawAndBlit" addr = 0x46AF66 size = 0x12C [[func]] name = "ObjIndex" addr = 0x46B092 size = 0x4B [[func]] name = "AddSKingObjs" addr = 0x46B0DD size = 0xAF [[func]] name = "AddSChamObjs" addr = 0x46B18C size = 0x3B [[func]] name = "AddVileObjs" addr = 0x46B1C7 size = 0x58 [[func]] name = "DRLG_SetMapTrans" addr = 0x46B21F size = 0x6D [[func]] name = "LoadSetMap" addr = 0x46B28C size = 0x200 [[func]] name = "SHA1Clear" addr = 0x46B48C size = 0x15 [[func]] name = "SHA1Result" addr = 0x46B4A1 size = 0x22 [[func]] name = "SHA1Calculate" addr = 0x46B4C3 size = 0x26 [[func]] name = "SHA1Input" addr = 0x46B4E9 size = 0x51 [[func]] name = "SHA1ProcessMessageBlock" addr = 0x46B53A size = 0x1FD [[func]] name = "SHA1Reset" addr = 0x46B737 size = 0xE [[func]] name = "SHA1Init" addr = 0x46B745 size = 0x2B [[func]] name = "snd_update" addr = 0x46B770 size = 0x4D [[func]] name = "snd_stop_snd" addr = 0x46B7BD size = 0x12 [[func]] name = "snd_playing" addr = 0x46B7CF size = 0x2C [[func]] name = "snd_play_snd" addr = 0x46B7FB size = 0xD9 [[func]] name = "sound_dup_channel" addr = 0x46B8D4 size = 0x42 [[func]] name = "sound_file_reload" addr = 0x46B916 size = 0x93 [[func]] name = "sound_file_load" addr = 0x46B9A9 size = 0xFC [[func]] name = "sound_CreateSoundBuffer" addr = 0x46BAA5 size = 0x5D [[func]] name = "sound_file_cleanup" addr = 0x46BB02 size = 0x2A [[func]] name = "snd_init" addr = 0x46BB2C size = 0xA6 [[func]] name = "snd_get_volume" addr = 0x46BBD2 size = 0x51 [[func]] name = "sound_create_primary_buffer" addr = 0x46BC23 size = 0x102 [[func]] name = "sound_DirectSoundCreate" addr = 0x46BD25 size = 0x81 [[func]] name = "sound_cleanup" addr = 0x46BDA6 size = 0x59 [[func]] name = "snd_set_volume" addr = 0x46BDFF size = 0xF [[func]] name = "music_stop" addr = 0x46BE0E size = 0x2C [[func]] name = "music_start" addr = 0x46BE3A size = 0x6B [[func]] name = "sound_disable_music" addr = 0x46BEA5 size = 0x1A [[func]] name = "sound_get_or_set_music_volume" addr = 0x46BEBF size = 0x23 [[func]] name = "sound_get_or_set_sound_volume" addr = 0x46BEE2 size = 0x13 [[func]] name = "GetManaAmount" addr = 0x46BEF5 size = 0x107 [[func]] name = "UseMana" addr = 0x46BFFC size = 0x73 [[func]] name = "CheckSpell" addr = 0x46C06F size = 0x58 [[func]] name = "CastSpell" addr = 0x46C0C7 size = 0xE7 [[func]] name = "DoResurrect" addr = 0x46C1AE size = 0x131 [[func]] name = "DoHealOther" addr = 0x46C2DF size = 0x15E [[func]] name = "InitStores" addr = 0x46C43D size = 0x86 [[func]] name = "SetupTownStores" addr = 0x46C4C3 size = 0xC5 [[func]] name = "FreeStoreMem" addr = 0x46C588 size = 0x36 [[func]] name = "DrawSTextBack" addr = 0x46C5BE size = 0x5E [[func]] name = "PrintSString" addr = 0x46C61C size = 0x20E [[func]] name = "DrawSLine" addr = 0x46C82A size = 0x8A [[func]] name = "DrawSSlider" addr = 0x46C8B4 size = 0xF1 [[func]] name = "DrawSTextHelp" addr = 0x46C9A5 size = 0xF [[func]] name = "ClearSText" addr = 0x46C9B4 size = 0x45 [[func]] name = "AddSLine" addr = 0x46C9F9 size = 0x25 [[func]] name = "AddSTextVal" addr = 0x46CA1E size = 0xD [[func]] name = "OffsetSTextY" addr = 0x46CA2B size = 0xD [[func]] name = "AddSText" addr = 0x46CA38 size = 0x51 [[func]] name = "StoreAutoPlace" addr = 0x46CA89 size = 0x2A1 [[func]] name = "S_StartSmith" addr = 0x46CD2A size = 0xCA [[func]] name = "S_ScrollSBuy" addr = 0x46CDF4 size = 0xBC [[func]] name = "PrintStoreItem" addr = 0x46CEB0 size = 0x275 [[func]] name = "S_StartSBuy" addr = 0x46D125 size = 0xC7 [[func]] name = "S_ScrollSPBuy" addr = 0x46D1EC size = 0xE9 [[func]] name = "S_StartSPBuy" addr = 0x46D2D5 size = 0xEA [[func]] name = "SmithSellOk" addr = 0x46D3BF size = 0x99 [[func]] name = "S_ScrollSSell" addr = 0x46D458 size = 0xE7 [[func]] name = "S_StartSSell" addr = 0x46D53F size = 0x2C7 [[func]] name = "SmithRepairOk" addr = 0x46D806 size = 0x4C [[func]] name = "S_StartSRepair" addr = 0x46D852 size = 0x267 [[func]] name = "AddStoreHoldRepair" addr = 0x46DAB9 size = 0xA5 [[func]] name = "S_StartWitch" addr = 0x46DB5E size = 0xA6 [[func]] name = "S_ScrollWBuy" addr = 0x46DC04 size = 0xBC [[func]] name = "S_StartWBuy" addr = 0x46DCC0 size = 0xD1 [[func]] name = "WitchSellOk" addr = 0x46DD91 size = 0x9E [[func]] name = "S_StartWSell" addr = 0x46DE2F size = 0x300 [[func]] name = "WitchRechargeOk" addr = 0x46E12F size = 0x5E [[func]] name = "AddStoreHoldRecharge" addr = 0x46E18D size = 0x86 [[func]] name = "S_StartWRecharge" addr = 0x46E213 size = 0x1EC [[func]] name = "S_StartNoMoney" addr = 0x46E3FF size = 0x3A [[func]] name = "S_StartNoRoom" addr = 0x46E439 size = 0x33 [[func]] name = "S_StartConfirm" addr = 0x46E46C size = 0x197 [[func]] name = "S_StartBoy" addr = 0x46E603 size = 0xBF [[func]] name = "S_StartBBoy" addr = 0x46E6C2 size = 0xD7 [[func]] name = "S_StartHealer" addr = 0x46E799 size = 0x105 [[func]] name = "S_ScrollHBuy" addr = 0x46E89E size = 0xB0 [[func]] name = "S_StartHBuy" addr = 0x46E94E size = 0xC7 [[func]] name = "S_StartStory" addr = 0x46EA15 size = 0x7A [[func]] name = "IdItemOk" addr = 0x46EA8F size = 0x18 [[func]] name = "AddStoreHoldId" addr = 0x46EAA7 size = 0x44 [[func]] name = "S_StartSIdentify" addr = 0x46EAEB size = 0x3FA [[func]] name = "S_StartIdShow" addr = 0x46EEE5 size = 0xC7 [[func]] name = "S_StartTalk" addr = 0x46EFAC size = 0x12A [[func]] name = "S_StartTavern" addr = 0x46F0D6 size = 0x84 [[func]] name = "S_StartBarMaid" addr = 0x46F15A size = 0x72 [[func]] name = "S_StartDrunk" addr = 0x46F1CC size = 0x72 [[func]] name = "StartStore" addr = 0x46F23E size = 0x165 [[func]] name = "DrawSText" addr = 0x46F3FF size = 0xFC [[func]] name = "STextESC" addr = 0x46F4FB size = 0xD9 [[func]] name = "STextUp" addr = 0x46F630 size = 0xA8 [[func]] name = "STextDown" addr = 0x46F6D8 size = 0xAD [[func]] name = "STextPrior" addr = 0x46F785 size = 0x4A [[func]] name = "STextNext" addr = 0x46F7CF size = 0x4D [[func]] name = "S_SmithEnter" addr = 0x46F81C size = 0x77 [[func]] name = "SetGoldCurs" addr = 0x46F893 size = 0x4D [[func]] name = "SetSpdbarGoldCurs" addr = 0x46F8E0 size = 0x4D [[func]] name = "TakePlrsMoney" addr = 0x46F92D size = 0x23B [[func]] name = "SmithBuyItem" addr = 0x46FB68 size = 0xBB [[func]] name = "S_SBuyEnter" addr = 0x46FC23 size = 0xF5 [[func]] name = "SmithBuyPItem" addr = 0x46FD18 size = 0x99 [[func]] name = "S_SPBuyEnter" addr = 0x46FDB1 size = 0x115 [[func]] name = "StoreGoldFit" addr = 0x46FEC6 size = 0xDB [[func]] name = "PlaceStoreGold" addr = 0x46FFA1 size = 0x11C [[func]] name = "StoreSellItem" addr = 0x4700BD size = 0x17C [[func]] name = "S_SSellEnter" addr = 0x470239 size = 0x88 [[func]] name = "SmithRepairItem" addr = 0x4702C1 size = 0x113 [[func]] name = "S_SRepairEnter" addr = 0x4703D4 size = 0x9D [[func]] name = "S_WitchEnter" addr = 0x470471 size = 0x71 [[func]] name = "WitchBuyItem" addr = 0x4704E2 size = 0xC2 [[func]] name = "S_WBuyEnter" addr = 0x4705A4 size = 0xF5 [[func]] name = "S_WSellEnter" addr = 0x470699 size = 0x88 [[func]] name = "WitchRechargeItem" addr = 0x470721 size = 0xA9 [[func]] name = "S_WRechargeEnter" addr = 0x4707CA size = 0x9D [[func]] name = "S_BoyEnter" addr = 0x470867 size = 0xAB [[func]] name = "BoyBuyItem" addr = 0x470912 size = 0x41 [[func]] name = "HealerBuyItem" addr = 0x470953 size = 0x114 [[func]] name = "S_BBuyEnter" addr = 0x470A67 size = 0x107 [[func]] name = "StoryIdItem" addr = 0x470B6E size = 0x163 [[func]] name = "S_ConfirmEnter" addr = 0x470CD1 size = 0xA5 [[func]] name = "S_HealerEnter" addr = 0x470D76 size = 0x58 [[func]] name = "S_HBuyEnter" addr = 0x470DCE size = 0xF5 [[func]] name = "S_StoryEnter" addr = 0x470EC3 size = 0x59 [[func]] name = "S_SIDEnter" addr = 0x470F1C size = 0x9D [[func]] name = "S_TalkEnter" addr = 0x470FB9 size = 0xF5 [[func]] name = "S_TavernEnter" addr = 0x4710AE size = 0x4E [[func]] name = "S_BarmaidEnter" addr = 0x4710FC size = 0x4E [[func]] name = "S_DrunkEnter" addr = 0x47114A size = 0x4E [[func]] name = "STextEnter" addr = 0x471198 size = 0xC3 [[func]] name = "CheckStoreBtn" addr = 0x4712B7 size = 0x153 [[func]] name = "ReleaseStoreBtn" addr = 0x47140A size = 0xF [[func]] name = "sync_all_monsters" addr = 0x471419 size = 0x87 [[func]] name = "sync_one_monster" addr = 0x4714A0 size = 0xC7 [[func]] name = "sync_monster_active" addr = 0x471567 size = 0x5C [[func]] name = "sync_monster_pos" addr = 0x4715C3 size = 0x6F [[func]] name = "sync_monster_active2" addr = 0x471632 size = 0x60 [[func]] name = "SyncPlrInv" addr = 0x471692 size = 0x1EE [[func]] name = "sync_update" addr = 0x471880 size = 0x73 [[func]] name = "sync_monster" addr = 0x4718F3 size = 0x21B [[func]] name = "sync_init" addr = 0x471B0E size = 0x25 [[func]] name = "TFit_Shrine" addr = 0x471B33 size = 0x124 [[func]] name = "TFit_Obj5" addr = 0x471C57 size = 0xDE [[func]] name = "TFit_SkelRoom" addr = 0x471D35 size = 0x50 [[func]] name = "TFit_GoatShrine" addr = 0x471D85 size = 0x43 [[func]] name = "CheckThemeObj3" addr = 0x471DC8 size = 0x7F [[func]] name = "TFit_Obj3" addr = 0x471E47 size = 0x5C [[func]] name = "CheckThemeReqs" addr = 0x471EA3 size = 0x80 [[func]] name = "SpecialThemeFit" addr = 0x471F23 size = 0xFC [[func]] name = "CheckThemeRoom" addr = 0x47205F size = 0x134 [[func]] name = "InitThemes" addr = 0x472193 size = 0x1B3 [[func]] name = "HoldThemeRooms" addr = 0x472346 size = 0x5A [[func]] name = "PlaceThemeMonsts" addr = 0x4723A0 size = 0xE5 [[func]] name = "Theme_Barrel" addr = 0x472485 size = 0xD8 [[func]] name = "Theme_Shrine" addr = 0x47255D size = 0xB3 [[func]] name = "Theme_MonstPit" addr = 0x472610 size = 0x9C [[func]] name = "Theme_SkelRoom" addr = 0x4726AC size = 0x1D6 [[func]] name = "Theme_Treasure" addr = 0x472882 size = 0x152 [[func]] name = "Theme_Library" addr = 0x4729D4 size = 0x194 [[func]] name = "Theme_Torture" addr = 0x472B68 size = 0xD3 [[func]] name = "Theme_BloodFountain" addr = 0x472C3B size = 0x46 [[func]] name = "Theme_Decap" addr = 0x472C81 size = 0xD3 [[func]] name = "Theme_PurifyingFountain" addr = 0x472D54 size = 0x46 [[func]] name = "Theme_ArmorStand" addr = 0x472D9A size = 0xF1 [[func]] name = "Theme_GoatShrine" addr = 0x472E8B size = 0xCE [[func]] name = "Theme_Cauldron" addr = 0x472F59 size = 0x46 [[func]] name = "Theme_MurkyFountain" addr = 0x472F9F size = 0x46 [[func]] name = "Theme_TearFountain" addr = 0x472FE5 size = 0x46 [[func]] name = "Theme_BrnCross" addr = 0x47302B size = 0xD3 [[func]] name = "Theme_WeaponRack" addr = 0x4730FE size = 0xF1 [[func]] name = "UpdateL4Trans" addr = 0x4731EF size = 0x20 [[func]] name = "CreateThemeRooms" addr = 0x47320F size = 0x11B [[func]] name = "tmsg_get" addr = 0x47336E size = 0x4B [[func]] name = "tmsg_add" addr = 0x4733B9 size = 0x53 [[func]] name = "tmsg_cleanup" addr = 0x47340C size = 0x27 [[func]] name = "town_clear_upper_buf" addr = 0x473433 size = 0x66 [[func]] name = "town_clear_low_buf" addr = 0x473499 size = 0x6F [[func]] name = "town_draw_clipped_e_flag" addr = 0x473508 size = 0x7D [[func]] name = "town_draw_clipped_town" addr = 0x473585 size = 0x333 [[func]] name = "town_draw_lower" addr = 0x4738B8 size = 0x2FB [[func]] name = "town_draw_clipped_e_flag_2" addr = 0x473BB3 size = 0xB1 [[func]] name = "town_draw_clipped_town_2" addr = 0x473C64 size = 0x347 [[func]] name = "town_draw_lower_2" addr = 0x473FAB size = 0x377 [[func]] name = "town_draw_e_flag" addr = 0x474322 size = 0x89 [[func]] name = "town_draw_town_all" addr = 0x4743AB size = 0x338 [[func]] name = "town_draw_upper" addr = 0x4746E3 size = 0x340 [[func]] name = "T_DrawGame" addr = 0x474A23 size = 0x1D8 [[func]] name = "T_DrawZoom" addr = 0x474C1F size = 0x23F [[func]] name = "T_DrawView" addr = 0x474E82 size = 0x134 [[func]] name = "SetTownMicros" addr = 0x474FB6 size = 0xE9 [[func]] name = "T_FillSector" addr = 0x47509F size = 0xB6 [[func]] name = "T_FillTile" addr = 0x475155 size = 0x71 [[func]] name = "TownOpenHive" addr = 0x4751C6 size = 0x1B3 [[func]] name = "TownCloseHive" addr = 0x475379 size = 0x1B3 [[func]] name = "TownCloseGrave" addr = 0x47552C size = 0x69 [[func]] name = "TownOpenGrave" addr = 0x475595 size = 0x69 [[func]] name = "T_Pass3" addr = 0x4755FE size = 0x27E [[func]] name = "CreateTown" addr = 0x47587C size = 0x264 [[func]] name = "GetActiveTowner" addr = 0x475AE0 size = 0x26 [[func]] name = "SetTownerGPtrs" addr = 0x475B06 size = 0x3A [[func]] name = "NewTownerAnim" addr = 0x475B40 size = 0x33 [[func]] name = "InitTownerInfo" addr = 0x475B73 size = 0x92 [[func]] name = "InitQstSnds" addr = 0x475C05 size = 0x4D [[func]] name = "InitSmith" addr = 0x475C52 size = 0x97 [[func]] name = "InitBarOwner" addr = 0x475CE9 size = 0x9E [[func]] name = "InitTownDead" addr = 0x475D87 size = 0x98 [[func]] name = "InitWitch" addr = 0x475E1F size = 0x97 [[func]] name = "InitBarmaid" addr = 0x475EB6 size = 0x97 [[func]] name = "InitBoy" addr = 0x475F4D size = 0x9E [[func]] name = "InitHealer" addr = 0x475FEB size = 0x97 [[func]] name = "InitTeller" addr = 0x476082 size = 0x97 [[func]] name = "InitDrunk" addr = 0x476119 size = 0x97 [[func]] name = "InitCows" addr = 0x4761B0 size = 0x158 [[func]] name = "InitFarmer" addr = 0x476308 size = 0x97 [[func]] name = "InitCowFarmer" addr = 0x47639F size = 0xAC [[func]] name = "InitGirl" addr = 0x47644B size = 0xAC [[func]] name = "InitTowners" addr = 0x4764F7 size = 0x87 [[func]] name = "FreeTownerGFX" addr = 0x47657E size = 0x43 [[func]] name = "TownCtrlMsg" addr = 0x4765C1 size = 0x6E [[func]] name = "TownBlackSmith" addr = 0x47662F size = 0xE [[func]] name = "TownBarOwner" addr = 0x47663D size = 0xF [[func]] name = "TownDead" addr = 0x47664C size = 0x72 [[func]] name = "TownHealer" addr = 0x4766BE size = 0xF [[func]] name = "TownStory" addr = 0x4766CD size = 0xF [[func]] name = "TownDrunk" addr = 0x4766DC size = 0xF [[func]] name = "TownBoy" addr = 0x4766EB size = 0xF [[func]] name = "TownWitch" addr = 0x4766FA size = 0xF [[func]] name = "TownBarMaid" addr = 0x476709 size = 0xF [[func]] name = "TownCow" addr = 0x476718 size = 0xF [[func]] name = "TownFarmer" addr = 0x476727 size = 0xF [[func]] name = "TownCowFarmer" addr = 0x476736 size = 0xF [[func]] name = "TownGirl" addr = 0x476745 size = 0xF [[func]] name = "ProcessTowners" addr = 0x476754 size = 0xD5 [[func]] name = "PlrHasItem" addr = 0x47685D size = 0x64 [[func]] name = "TownerTalk" addr = 0x4768C1 size = 0x1D [[func]] name = "TalkToTowner" addr = 0x4768DE size = 0x10F2 [[func]] name = "CowSFX" addr = 0x4779D0 size = 0xC5 [[func]] name = "track_process" addr = 0x477A95 size = 0x9E [[func]] name = "track_repeat_walk" addr = 0x477B33 size = 0x4C [[func]] name = "track_isscrolling" addr = 0x477B7F size = 0x8 [[func]] name = "InitNoTriggers" addr = 0x477B87 size = 0xF [[func]] name = "InitTownTriggers" addr = 0x477B96 size = 0x24E [[func]] name = "InitL1Triggers" addr = 0x477DE4 size = 0x198 [[func]] name = "InitL2Triggers" addr = 0x477F7C size = 0x108 [[func]] name = "InitL3Triggers" addr = 0x478084 size = 0x1A8 [[func]] name = "InitL4Triggers" addr = 0x47822C size = 0x145 [[func]] name = "InitSKingTriggers" addr = 0x478371 size = 0x30 [[func]] name = "InitSChambTriggers" addr = 0x4783A1 size = 0x30 [[func]] name = "InitPWaterTriggers" addr = 0x4783D1 size = 0x30 [[func]] name = "InitVPTriggers" addr = 0x478401 size = 0x30 [[func]] name = "ForceTownTrig" addr = 0x478431 size = 0x220 [[func]] name = "ForceL1Trig" addr = 0x478651 size = 0x30E [[func]] name = "ForceL2Trig" addr = 0x47895F size = 0x206 [[func]] name = "ForceL3Trig" addr = 0x478B65 size = 0x384 [[func]] name = "ForceL4Trig" addr = 0x478EE9 size = 0x245 [[func]] name = "Freeupstairs" addr = 0x47912E size = 0x48 [[func]] name = "ForceSKingTrig" addr = 0x479176 size = 0x69 [[func]] name = "ForceSChambTrig" addr = 0x4791DF size = 0x69 [[func]] name = "ForcePWaterTrig" addr = 0x479248 size = 0x69 [[func]] name = "CheckTrigForce" addr = 0x4792B1 size = 0xAD [[func]] name = "CheckTriggers" addr = 0x47935E size = 0x1F5 [[func]] name = "WCloseFile" addr = 0x479553 size = 0x7 [[func]] name = "WGetFileSize" addr = 0x47955A size = 0x2A [[func]] name = "WGetFileArchive" addr = 0x479584 size = 0x57 [[func]] name = "WOpenFile" addr = 0x4795DB size = 0x43 [[func]] name = "WReadFile" addr = 0x47961E size = 0x52 [[func]] name = "WSetFilePointer" addr = 0x479670 size = 0x34 [[func]] name = "LoadWaveFormat" addr = 0x4796A4 size = 0x2E [[func]] name = "AllocateMemFile" addr = 0x4796D2 size = 0x49 [[func]] name = "FreeMemFile" addr = 0x47971B size = 0xE [[func]] name = "ReadWaveFile" addr = 0x479729 size = 0xCA [[func]] name = "ReadMemFile" addr = 0x4797F3 size = 0x56 [[func]] name = "FillMemFile" addr = 0x479849 size = 0x3B [[func]] name = "SeekMemFile" addr = 0x479884 size = 0x1E [[func]] name = "ReadWaveSection" addr = 0x4798A2 size = 0x5B [[func]] name = "LoadWaveFile" addr = 0x4798FD size = 0x38 ================================================ FILE: comparer-config/spawn.toml ================================================ # conversion between function and file location of the functions # = (0x401000 - PE header offset) (0x400 for VC5 linker) address_offset = 0x400C00 [[func]] name = "operator delete" addr = 0x401010 size = 0x1A [[func]] name = "GetErrorStr" addr = 0x40102A size = 0xA4 [[func]] name = "TraceErrorDD" addr = 0x4010CE size = 0x6B8 [[func]] name = "TraceErrorDS" addr = 0x401831 size = 0x109 [[func]] name = "TraceLastError" addr = 0x40193A size = 0xD [[func]] name = "app_fatal" addr = 0x401947 size = 0x24 [[func]] name = "MsgBox" addr = 0x401975 size = 0x52 [[func]] name = "FreeDlg" addr = 0x4019C7 size = 0x69 [[func]] name = "DrawDlg" addr = 0x401A30 size = 0x35 [[func]] name = "DDErrMsg" addr = 0x401A65 size = 0x23 [[func]] name = "DSErrMsg" addr = 0x401A88 size = 0x23 [[func]] name = "center_window" addr = 0x401AAB size = 0x92 [[func]] name = "ErrDlg" addr = 0x401B3D size = 0x8D [[func]] name = "FuncDlg" addr = 0x401BCA size = 0x45 [[func]] name = "TextDlg" addr = 0x401C0F size = 0x1F [[func]] name = "ErrOkDlg" addr = 0x401C2E size = 0x6E [[func]] name = "FileErrDlg" addr = 0x401C9C size = 0x45 [[func]] name = "DiskFreeDlg" addr = 0x401CE1 size = 0x3C [[func]] name = "InsertCDDlg" addr = 0x401D1D size = 0x4B [[func]] name = "DirErrorDlg" addr = 0x401D68 size = 0x3C [[func]] name = "InitAutomapOnce" addr = 0x401DA4 size = 0x44 [[func]] name = "InitAutomap" addr = 0x401DE8 size = 0x10C [[func]] name = "StartAutomap" addr = 0x401EF4 size = 0x19 [[func]] name = "AutomapUp" addr = 0x401F0D size = 0xD [[func]] name = "AutomapDown" addr = 0x401F1A size = 0xD [[func]] name = "AutomapLeft" addr = 0x401F27 size = 0xD [[func]] name = "AutomapRight" addr = 0x401F34 size = 0xD [[func]] name = "AutomapZoomIn" addr = 0x401F41 size = 0x3F [[func]] name = "AutomapZoomOut" addr = 0x401F80 size = 0x3D [[func]] name = "DrawAutomap" addr = 0x401FBD size = 0x276 [[func]] name = "DrawAutomapTile" addr = 0x402233 size = 0x745 [[func]] name = "DrawAutomapPlr" addr = 0x4029A8 size = 0x3BB [[func]] name = "GetAutomapType" addr = 0x402D83 size = 0xC7 [[func]] name = "DrawAutomapText" addr = 0x402E4A size = 0xDD [[func]] name = "SetAutomapView" addr = 0x402F27 size = 0x1B6 [[func]] name = "AutomapZoomReset" addr = 0x4030DD size = 0x3E [[func]] name = "CaptureScreen" addr = 0x40311B size = 0xE9 [[func]] name = "CaptureHdr" addr = 0x403204 size = 0x90 [[func]] name = "CapturePal" addr = 0x403294 size = 0x69 [[func]] name = "CapturePix" addr = 0x4032FD size = 0x6D [[func]] name = "CaptureEnc" addr = 0x40336A size = 0x3E [[func]] name = "CaptureFile" addr = 0x4033A8 size = 0xC8 [[func]] name = "RedPalette" addr = 0x403470 size = 0x69 [[func]] name = "codec_decode" addr = 0x4034D9 size = 0xFD [[func]] name = "codec_init_key" addr = 0x4035DB size = 0xD1 [[func]] name = "codec_get_encoded_len" addr = 0x4036AC size = 0x12 [[func]] name = "codec_encode" addr = 0x4036BE size = 0x116 [[func]] name = "DrawSpellCel" addr = 0x4037D4 size = 0xAA [[func]] name = "SetSpellTrans" addr = 0x40387E size = 0x149 [[func]] name = "DrawSpell" addr = 0x4039C7 size = 0xC7 [[func]] name = "DrawSpellList" addr = 0x403A8E size = 0x4DB [[func]] name = "SetSpell" addr = 0x403F69 size = 0x43 [[func]] name = "SetSpeedSpell" addr = 0x403FAC size = 0x6B [[func]] name = "ToggleSpell" addr = 0x404017 size = 0xC3 [[func]] name = "PrintChar" addr = 0x4040DA size = 0x13E [[func]] name = "AddPanelString" addr = 0x404218 size = 0x32 [[func]] name = "ClearPanel" addr = 0x40424A size = 0xF [[func]] name = "DrawPanelBox" addr = 0x404259 size = 0x6C [[func]] name = "SetFlaskHeight" addr = 0x4042CA size = 0x51 [[func]] name = "DrawFlask" addr = 0x40431B size = 0x40 [[func]] name = "DrawLifeFlask" addr = 0x40435B size = 0x99 [[func]] name = "UpdateLifeFlask" addr = 0x4043F4 size = 0x81 [[func]] name = "DrawManaFlask" addr = 0x404475 size = 0x81 [[func]] name = "control_update_life_mana" addr = 0x4044F6 size = 0x74 [[func]] name = "UpdateManaFlask" addr = 0x40456A size = 0xAC [[func]] name = "InitControlPan" addr = 0x404616 size = 0x2FC [[func]] name = "DrawCtrlPan" addr = 0x404912 size = 0x25 [[func]] name = "DrawCtrlBtns" addr = 0x404937 size = 0xB1 [[func]] name = "DoSpeedBook" addr = 0x4049E8 size = 0x148 [[func]] name = "DoPanBtn" addr = 0x404B30 size = 0x99 [[func]] name = "control_set_button_down" addr = 0x404BC9 size = 0x15 [[func]] name = "control_check_btn_press" addr = 0x404BDE size = 0x74 [[func]] name = "DoAutoMap" addr = 0x404C52 size = 0x2C [[func]] name = "CheckPanelInfo" addr = 0x404C7E size = 0x344 [[func]] name = "CheckBtnUp" addr = 0x404FC2 size = 0x17D [[func]] name = "FreeControlPan" addr = 0x40515F size = 0x114 [[func]] name = "control_WriteStringToBuffer" addr = 0x405273 size = 0x33 [[func]] name = "DrawInfoBox" addr = 0x4052A6 size = 0x289 [[func]] name = "PrintInfo" addr = 0x40552F size = 0x6B [[func]] name = "CPrintString" addr = 0x40559A size = 0xC5 [[func]] name = "PrintGameStr" addr = 0x40565F size = 0x57 [[func]] name = "DrawChr" addr = 0x4056B6 size = 0x968 [[func]] name = "ADD_PlrStringXY" addr = 0x40601E size = 0xB7 [[func]] name = "MY_PlrStringXY" addr = 0x4060D5 size = 0xBB [[func]] name = "CheckLvlBtn" addr = 0x406190 size = 0x36 [[func]] name = "ReleaseLvlBtn" addr = 0x4061C6 size = 0x34 [[func]] name = "DrawLevelUpIcon" addr = 0x4061FA size = 0x46 [[func]] name = "CheckChrBtns" addr = 0x406240 size = 0xEC [[func]] name = "ReleaseChrBtns" addr = 0x40632C size = 0xA2 [[func]] name = "DrawDurIcon" addr = 0x4063CE size = 0x86 [[func]] name = "DrawDurIcon4Item" addr = 0x406454 size = 0x7A [[func]] name = "RedBack" addr = 0x4064CE size = 0x8A [[func]] name = "GetSBookTrans" addr = 0x406558 size = 0xD5 [[func]] name = "DrawSpellBook" addr = 0x40662D size = 0x28D [[func]] name = "PrintSBookStr" addr = 0x4068BA size = 0xC2 [[func]] name = "CheckSBook" addr = 0x40697C size = 0x142 [[func]] name = "get_pieces_str" addr = 0x406ABE size = 0x10 [[func]] name = "DrawGoldSplit" addr = 0x406ACE size = 0x138 [[func]] name = "control_drop_gold" addr = 0x406C06 size = 0x12E [[func]] name = "control_remove_gold" addr = 0x406D34 size = 0xB6 [[func]] name = "control_set_gold_curs" addr = 0x406DEA size = 0x46 [[func]] name = "DrawTalkPan" addr = 0x406E30 size = 0x207 [[func]] name = "control_print_talk_msg" addr = 0x407037 size = 0x82 [[func]] name = "control_check_talk_btn" addr = 0x4070B9 size = 0x5A [[func]] name = "control_release_talk_btn" addr = 0x407113 size = 0x73 [[func]] name = "control_reset_talk_msg" addr = 0x407186 size = 0x3A [[func]] name = "control_type_message" addr = 0x4071C0 size = 0x47 [[func]] name = "control_reset_talk" addr = 0x407207 size = 0x19 [[func]] name = "control_talk_last_key" addr = 0x407220 size = 0x40 [[func]] name = "control_presskeys" addr = 0x407260 size = 0x6A [[func]] name = "control_press_enter" addr = 0x4072CA size = 0xBE [[func]] name = "control_up_down" addr = 0x407388 size = 0x48 [[func]] name = "InitCursor" addr = 0x4073D0 size = 0x16 [[func]] name = "FreeCursor" addr = 0x4073E6 size = 0x17 [[func]] name = "SetICursor" addr = 0x4073FD size = 0x34 [[func]] name = "SetCursor_" addr = 0x407431 size = 0x23 [[func]] name = "NewCursor" addr = 0x407454 size = 0x5 [[func]] name = "InitLevelCursor" addr = 0x407459 size = 0x3D [[func]] name = "CheckTown" addr = 0x407496 size = 0x12D [[func]] name = "CheckRportal" addr = 0x4075C3 size = 0x12C [[func]] name = "CheckCursMove" addr = 0x4076EF size = 0xD7D [[func]] name = "InitDead" addr = 0x40846C size = 0x1B6 [[func]] name = "AddDead" addr = 0x408622 size = 0x21 [[func]] name = "SyncUniqDead" addr = 0x408643 size = 0x77 [[func]] name = "LoadDebugGFX" addr = 0x4086BA size = 0x1B [[func]] name = "FreeDebugGFX" addr = 0x4086D5 size = 0x12 [[func]] name = "CheckDungeonClear" addr = 0x4086E7 size = 0x90 [[func]] name = "FreeGameMem" addr = 0x408787 size = 0x77 [[func]] name = "StartGame" addr = 0x4087FE size = 0xAA [[func]] name = "run_game_loop" addr = 0x4088A8 size = 0x1AA [[func]] name = "start_game" addr = 0x408A52 size = 0x4F [[func]] name = "free_game" addr = 0x408AA1 size = 0x43 [[func]] name = "diablo_get_not_running" addr = 0x408AE4 size = 0x2C [[func]] name = "WinMain" addr = 0x408B10 size = 0x11A [[func]] name = "diablo_parse_flags" addr = 0x408C2A size = 0xB0 [[func]] name = "diablo_init_screen" addr = 0x408CDA size = 0x50 [[func]] name = "diablo_find_window" addr = 0x408D2A size = 0x43 [[func]] name = "diablo_reload_process" addr = 0x408D6D size = 0x1DB [[func]] name = "PressEscKey" addr = 0x408F48 size = 0x8F [[func]] name = "DisableInputWndProc" addr = 0x408FD7 size = 0xD3 [[func]] name = "GM_Game" addr = 0x4090AA size = 0x281 [[func]] name = "LeftMouseDown" addr = 0x40932B size = 0x1F3 [[func]] name = "LeftMouseCmd" addr = 0x40951E size = 0x247 [[func]] name = "TryIconCurs" addr = 0x409765 size = 0x177 [[func]] name = "LeftMouseUp" addr = 0x4098DC size = 0x45 [[func]] name = "RightMouseDown" addr = 0x409921 size = 0xE1 [[func]] name = "PressSysKey" addr = 0x409A07 size = 0x22 [[func]] name = "diablo_hotkey_msg" addr = 0x409A29 size = 0xA1 [[func]] name = "ReleaseKey" addr = 0x409ACA size = 0xB [[func]] name = "PressKey" addr = 0x409AD5 size = 0x3E7 [[func]] name = "diablo_pause_game" addr = 0x409EBC size = 0x3C [[func]] name = "PressChar" addr = 0x409EF8 size = 0x364 [[func]] name = "LoadLvlGFX" addr = 0x40A30A size = 0x95 [[func]] name = "LoadAllGFX" addr = 0x40A39F size = 0x2D [[func]] name = "CreateLevel" addr = 0x40A3CC size = 0x50 [[func]] name = "LoadGameLevel" addr = 0x40A41C size = 0x445 [[func]] name = "game_loop" addr = 0x40A861 size = 0x50 [[func]] name = "game_logic" addr = 0x40A8B1 size = 0xB4 [[func]] name = "timeout_cursor" addr = 0x40A965 size = 0x84 [[func]] name = "diablo_color_cyc_logic" addr = 0x40A9E9 size = 0x42 [[func]] name = "doom_get_frame_from_time" addr = 0x40AA2B size = 0x19 [[func]] name = "doom_alloc_cel" addr = 0x40AA44 size = 0x10 [[func]] name = "doom_cleanup" addr = 0x40AA54 size = 0x12 [[func]] name = "doom_load_graphics" addr = 0x40AA66 size = 0x4C [[func]] name = "doom_init" addr = 0x40AAB2 size = 0x2A [[func]] name = "doom_close" addr = 0x40AADC size = 0x16 [[func]] name = "doom_draw" addr = 0x40AAF2 size = 0x62 [[func]] name = "DRLG_Init_Globals" addr = 0x40AB54 size = 0xA3 [[func]] name = "DRLG_L1Floor" addr = 0x40ABF7 size = 0x4E [[func]] name = "DRLG_L1Pass3" addr = 0x40AC45 size = 0xF2 [[func]] name = "DRLG_InitL1Vals" addr = 0x40AD37 size = 0xBB [[func]] name = "CreateL5Dungeon" addr = 0x40ADF2 size = 0x4D [[func]] name = "DRLG_LoadL1SP" addr = 0x40AE3F size = 0x7E [[func]] name = "DRLG_FreeL1SP" addr = 0x40AEBD size = 0x12 [[func]] name = "DRLG_L5" addr = 0x40AECF size = 0x269 [[func]] name = "DRLG_PlaceDoor" addr = 0x40B138 size = 0x12A [[func]] name = "DRLG_L1Shadows" addr = 0x40B262 size = 0x1E8 [[func]] name = "DRLG_PlaceMiniSet" addr = 0x40B44A size = 0x275 [[func]] name = "InitL5Dungeon" addr = 0x40B6BF size = 0x22 [[func]] name = "L5ClearFlags" addr = 0x40B6E1 size = 0x1B [[func]] name = "L5firstRoom" addr = 0x40B6FC size = 0x233 [[func]] name = "L5drawRoom" addr = 0x40B92F size = 0x37 [[func]] name = "L5roomGen" addr = 0x40B966 size = 0x207 [[func]] name = "L5checkRoom" addr = 0x40BB6D size = 0x64 [[func]] name = "L5GetArea" addr = 0x40BBD1 size = 0x22 [[func]] name = "L5makeDungeon" addr = 0x40BBF3 size = 0x44 [[func]] name = "L5makeDmt" addr = 0x40BC37 size = 0x72 [[func]] name = "L5AddWall" addr = 0x40BCA9 size = 0x15C [[func]] name = "L5HWallOk" addr = 0x40BE05 size = 0xA0 [[func]] name = "L5VWallOk" addr = 0x40BEA5 size = 0x7F [[func]] name = "L5HorizWall" addr = 0x40BF24 size = 0xEE [[func]] name = "L5VertWall" addr = 0x40C012 size = 0x108 [[func]] name = "L5tileFix" addr = 0x40C11A size = 0x36F [[func]] name = "DRLG_L5Subs" addr = 0x40C489 size = 0xDD [[func]] name = "L5FillChambers" addr = 0x40C566 size = 0x3E9 [[func]] name = "DRLG_L5GChamber" addr = 0x40C94F size = 0x141 [[func]] name = "DRLG_L5GHall" addr = 0x40CA90 size = 0x50 [[func]] name = "DRLG_L5SetRoom" addr = 0x40CAE0 size = 0x85 [[func]] name = "DRLG_L5FloodTVal" addr = 0x40CB65 size = 0x6F [[func]] name = "DRLG_L5FTVR" addr = 0x40CBD4 size = 0x1F0 [[func]] name = "DRLG_L5TransFix" addr = 0x40CDC4 size = 0x88 [[func]] name = "DRLG_L5DirtFix" addr = 0x40CE4C size = 0x6C [[func]] name = "DRLG_L5CornerFix" addr = 0x40CEB8 size = 0x68 [[func]] name = "dthread_remove_player" addr = 0x40CF5E size = 0x33 [[func]] name = "dthread_send_delta" addr = 0x40CF91 size = 0x7D [[func]] name = "dthread_start" addr = 0x40D00E size = 0x6D [[func]] name = "dthread_handler" addr = 0x40D07B size = 0xCD [[func]] name = "dthread_cleanup" addr = 0x40D148 size = 0xA2 [[func]] name = "dx_init" addr = 0x40D228 size = 0x115 [[func]] name = "dx_create_back_buffer" addr = 0x40D33D size = 0x10D [[func]] name = "dx_create_primary_surface" addr = 0x40D44A size = 0x58 [[func]] name = "dx_DirectDrawCreate" addr = 0x40D4A2 size = 0x7B [[func]] name = "lock_buf" addr = 0x40D51D size = 0x5 [[func]] name = "lock_buf_priv" addr = 0x40D522 size = 0x86 [[func]] name = "unlock_buf" addr = 0x40D5A8 size = 0x5 [[func]] name = "unlock_buf_priv" addr = 0x40D5AD size = 0x7B [[func]] name = "dx_cleanup" addr = 0x40D628 size = 0xA8 [[func]] name = "dx_reinit" addr = 0x40D6D0 size = 0x5C [[func]] name = "effect_is_playing" addr = 0x40D741 size = 0x29 [[func]] name = "stream_stop" addr = 0x40D76A size = 0x29 [[func]] name = "InitMonsterSND" addr = 0x40D793 size = 0xD0 [[func]] name = "FreeMonsterSnd" addr = 0x40D863 size = 0x6A [[func]] name = "PlayEffect" addr = 0x40D8CD size = 0x9C [[func]] name = "calc_snd_position" addr = 0x40D969 size = 0x78 [[func]] name = "PlaySFX" addr = 0x40D9E1 size = 0x18 [[func]] name = "PlaySFX_priv" addr = 0x40D9F9 size = 0xB9 [[func]] name = "stream_play" addr = 0x40DAB2 size = 0x6D [[func]] name = "RndSFX" addr = 0x40DB1F size = 0x52 [[func]] name = "PlaySfxLoc" addr = 0x40DB71 size = 0x38 [[func]] name = "sound_stop" addr = 0x40DBA9 size = 0x61 [[func]] name = "sfx_stop" addr = 0x40DC0A size = 0x20 [[func]] name = "sound_update" addr = 0x40DC2A size = 0x16 [[func]] name = "stream_update" addr = 0x40DC40 size = 0x2F [[func]] name = "effects_cleanup_sfx" addr = 0x40DC6F size = 0x2B [[func]] name = "sound_init" addr = 0x40DC9A size = 0x4D [[func]] name = "priv_sound_init" addr = 0x40DCE7 size = 0x61 [[func]] name = "ui_sound_init" addr = 0x40DD48 size = 0x7 [[func]] name = "effects_play_sound" addr = 0x40DD4F size = 0x64 [[func]] name = "Decrypt" addr = 0x40DDB3 size = 0x4C [[func]] name = "Encrypt" addr = 0x40DDFF size = 0x50 [[func]] name = "Hash" addr = 0x40DE4F size = 0x4F [[func]] name = "InitHash" addr = 0x40DE9E size = 0x6F [[func]] name = "PkwareCompress" addr = 0x40DF0D size = 0x96 [[func]] name = "PkwareBufferRead" addr = 0x40DFA3 size = 0x34 [[func]] name = "PkwareBufferWrite" addr = 0x40DFD7 size = 0x27 [[func]] name = "PkwareDecompress" addr = 0x40DFFE size = 0x6E [[func]] name = "CelBlit" addr = 0x40E07C size = 0x68 [[func]] name = "CelDraw" addr = 0x40E0E4 size = 0x44 [[func]] name = "CelBlitFrame" addr = 0x40E128 size = 0x26 [[func]] name = "CelClippedDraw" addr = 0x40E14E size = 0x7B [[func]] name = "CelClippedBlit" addr = 0x40E1C9 size = 0x53 [[func]] name = "CelBlitLight" addr = 0x40E21C size = 0xDC [[func]] name = "CelBlitLightTrans" addr = 0x40E2F8 size = 0xDD [[func]] name = "CelDrawLight" addr = 0x40E3D5 size = 0x58 [[func]] name = "CelClippedDrawLight" addr = 0x40E42D size = 0x8E [[func]] name = "CelClippedBlitLightTrans" addr = 0x40E4BB size = 0x74 [[func]] name = "CelDrawLightRed" addr = 0x40E52F size = 0x11C [[func]] name = "CelBlitSafe" addr = 0x40E64B size = 0x7F [[func]] name = "CelClippedDrawSafe" addr = 0x40E6CA size = 0x7B [[func]] name = "CelClippedBlitSafe" addr = 0x40E745 size = 0x55 [[func]] name = "CelBlitLightSafe" addr = 0x40E79A size = 0xF7 [[func]] name = "CelBlitLightTransSafe" addr = 0x40E891 size = 0xF8 [[func]] name = "CelDrawLightSafe" addr = 0x40E989 size = 0x90 [[func]] name = "CelClippedBlitLightTransSafe" addr = 0x40EA19 size = 0x72 [[func]] name = "CelDrawLightRedSafe" addr = 0x40EA8B size = 0x121 [[func]] name = "CelBlitWidth" addr = 0x40EBAC size = 0x8A [[func]] name = "CelBlitOutline" addr = 0x40EC36 size = 0xFA [[func]] name = "CelBlitOutlineSafe" addr = 0x40ED30 size = 0x12F [[func]] name = "ENG_set_pixel" addr = 0x40EE5F size = 0x45 [[func]] name = "engine_draw_pixel" addr = 0x40EEA4 size = 0x89 [[func]] name = "DrawLine" addr = 0x40EF2D size = 0x3F6 [[func]] name = "GetDirection" addr = 0x40F323 size = 0x65 [[func]] name = "SetRndSeed" addr = 0x40F388 size = 0x14 [[func]] name = "GetRndSeed" addr = 0x40F39C size = 0x1F [[func]] name = "random_" addr = 0x40F3BB size = 0x22 [[func]] name = "DiabloAllocPtr" addr = 0x40F40B size = 0x4D [[func]] name = "mem_free_dbg" addr = 0x40F458 size = 0x30 [[func]] name = "LoadFileInMem" addr = 0x40F488 size = 0x5B [[func]] name = "LoadFileWithMem" addr = 0x40F4E3 size = 0x5F [[func]] name = "Cl2ApplyTrans" addr = 0x40F542 size = 0x73 [[func]] name = "Cl2Draw" addr = 0x40F5B5 size = 0x7A [[func]] name = "Cl2Blit" addr = 0x40F62F size = 0x88 [[func]] name = "Cl2DrawOutline" addr = 0x40F6B7 size = 0x7E [[func]] name = "Cl2BlitOutline" addr = 0x40F735 size = 0xBC [[func]] name = "Cl2DrawLightTbl" addr = 0x40F7F1 size = 0xC3 [[func]] name = "Cl2BlitLight" addr = 0x40F8B4 size = 0xA5 [[func]] name = "Cl2DrawLight" addr = 0x40F959 size = 0x9A [[func]] name = "Cl2DrawSafe" addr = 0x40F9F3 size = 0x7A [[func]] name = "Cl2BlitSafe" addr = 0x40FA6D size = 0x9C [[func]] name = "Cl2DrawOutlineSafe" addr = 0x40FB09 size = 0x8F [[func]] name = "Cl2BlitOutlineSafe" addr = 0x40FB98 size = 0xD0 [[func]] name = "Cl2DrawLightTblSafe" addr = 0x40FC68 size = 0xC3 [[func]] name = "Cl2BlitLightSafe" addr = 0x40FD2B size = 0xBD [[func]] name = "Cl2DrawLightSafe" addr = 0x40FDE8 size = 0x9A [[func]] name = "PlayInGameMovie" addr = 0x40FE82 size = 0x3C [[func]] name = "InitDiabloMsg" addr = 0x40FEBE size = 0x41 [[func]] name = "ClrDiabloMsg" addr = 0x40FEFF size = 0x1B [[func]] name = "DrawDiabloMsg" addr = 0x40FF1A size = 0x203 [[func]] name = "fault_init_filter" addr = 0x410127 size = 0xA [[func]] name = "fault_cleanup_filter_atexit" addr = 0x410131 size = 0xC [[func]] name = "fault_cleanup_filter" addr = 0x41013D size = 0xA [[func]] name = "TopLevelExceptionFilter" addr = 0x410147 size = 0x17E [[func]] name = "fault_hex_format" addr = 0x4102C5 size = 0xC3 [[func]] name = "fault_unknown_module" addr = 0x410388 size = 0xE7 [[func]] name = "fault_call_stack" addr = 0x41046F size = 0x89 [[func]] name = "fault_get_error_type" addr = 0x4104F8 size = 0x190 [[func]] name = "fault_set_filter" addr = 0x4106AC size = 0x17 [[func]] name = "fault_reset_filter" addr = 0x4106C3 size = 0xD [[func]] name = "fault_get_filter" addr = 0x4106D0 size = 0x6 [[func]] name = "gamemenu_on" addr = 0x4106D6 size = 0x29 [[func]] name = "gamemenu_update_single" addr = 0x4106FF size = 0x39 [[func]] name = "gamemenu_update_multi" addr = 0x410738 size = 0x10 [[func]] name = "gamemenu_off" addr = 0x410748 size = 0x9 [[func]] name = "gamemenu_handle_previous" addr = 0x410751 size = 0x13 [[func]] name = "gamemenu_previous" addr = 0x410764 size = 0x5 [[func]] name = "gamemenu_new_game" addr = 0x410769 size = 0x42 [[func]] name = "gamemenu_quit_game" addr = 0x4107AB size = 0xD [[func]] name = "gamemenu_load_game" addr = 0x4107B8 size = 0x76 [[func]] name = "gamemenu_save_game" addr = 0x41082E size = 0x84 [[func]] name = "gamemenu_restart_town" addr = 0x4108B2 size = 0xA [[func]] name = "gamemenu_options" addr = 0x4108BC size = 0x20 [[func]] name = "gamemenu_get_music" addr = 0x4108DC size = 0x19 [[func]] name = "gamemenu_sound_music_toggle" addr = 0x4108F5 size = 0x41 [[func]] name = "gamemenu_get_sound" addr = 0x410936 size = 0x19 [[func]] name = "gamemenu_get_color_cycling" addr = 0x41094F size = 0x15 [[func]] name = "gamemenu_get_gamma" addr = 0x410964 size = 0x26 [[func]] name = "gamemenu_music_volume" addr = 0x41098A size = 0x89 [[func]] name = "gamemenu_slider_music_sound" addr = 0x410A13 size = 0xD [[func]] name = "gamemenu_sound_volume" addr = 0x410A20 size = 0x80 [[func]] name = "gamemenu_gamma" addr = 0x410AA0 size = 0x2A [[func]] name = "gamemenu_slider_gamma" addr = 0x410ACA size = 0x10 [[func]] name = "gamemenu_color_cycling" addr = 0x410ADA size = 0x21 [[func]] name = "FillSolidBlockTbls" addr = 0x410AFB size = 0x106 [[func]] name = "MakeSpeedCels" addr = 0x410C01 size = 0x42E [[func]] name = "SortTiles" addr = 0x41102F size = 0x3C [[func]] name = "SwapTile" addr = 0x41106B size = 0x7F [[func]] name = "IsometricCoord" addr = 0x4110EA size = 0x48 [[func]] name = "SetSpeedCels" addr = 0x411132 size = 0x49 [[func]] name = "SetDungeonMicros" addr = 0x41117B size = 0x13F [[func]] name = "DRLG_InitTrans" addr = 0x4112BA size = 0x2D [[func]] name = "DRLG_MRectTrans" addr = 0x4112E7 size = 0x59 [[func]] name = "DRLG_RectTrans" addr = 0x411340 size = 0x45 [[func]] name = "DRLG_CopyTrans" addr = 0x411385 size = 0x1F [[func]] name = "DRLG_InitSetPC" addr = 0x4113A4 size = 0x17 [[func]] name = "DRLG_SetPC" addr = 0x4113BB size = 0x53 [[func]] name = "DRLG_HoldThemeRooms" addr = 0x41140E size = 0x8D [[func]] name = "SkipThemeRoom" addr = 0x41149B size = 0x52 [[func]] name = "InitLevels" addr = 0x4114ED size = 0x1A [[func]] name = "gmenu_draw_pause" addr = 0x411507 size = 0x33 [[func]] name = "gmenu_print_text" addr = 0x41153A size = 0x59 [[func]] name = "FreeGMenu" addr = 0x411593 size = 0x59 [[func]] name = "gmenu_init_menu" addr = 0x4115EC size = 0x78 [[func]] name = "gmenu_is_active" addr = 0x411664 size = 0xC [[func]] name = "gmenu_set_items" addr = 0x411670 size = 0x5A [[func]] name = "gmenu_up_down" addr = 0x4116CA size = 0x68 [[func]] name = "gmenu_draw" addr = 0x411732 size = 0x8F [[func]] name = "gmenu_draw_menu_item" addr = 0x4117C1 size = 0xF4 [[func]] name = "gmenu_clear_buffer" addr = 0x4118B5 size = 0x39 [[func]] name = "gmenu_get_lfont" addr = 0x4118EE size = 0x3C [[func]] name = "gmenu_presskeys" addr = 0x41192A size = 0x7C [[func]] name = "gmenu_left_right" addr = 0x4119A6 size = 0x50 [[func]] name = "gmenu_on_mouse_move" addr = 0x4119F6 size = 0x58 [[func]] name = "gmenu_get_mouse_slider" addr = 0x411A4E size = 0x2F [[func]] name = "gmenu_left_mouse" addr = 0x411A7D size = 0xB7 [[func]] name = "gmenu_enable" addr = 0x411B34 size = 0xE [[func]] name = "gmenu_slider_set" addr = 0x411B42 size = 0x42 [[func]] name = "gmenu_slider_get" addr = 0x411B84 size = 0x3D [[func]] name = "gmenu_slider_steps" addr = 0x411BC1 size = 0xE [[func]] name = "InitHelp" addr = 0x411BCF size = 0x12 [[func]] name = "DrawHelp" addr = 0x411BE1 size = 0x195 [[func]] name = "DrawHelpLine" addr = 0x411D76 size = 0x79 [[func]] name = "DisplayHelp" addr = 0x411DEF size = 0x1C [[func]] name = "HelpScrollUp" addr = 0x411E0B size = 0x10 [[func]] name = "HelpScrollDown" addr = 0x411E1B size = 0x14 [[func]] name = "init_cleanup" addr = 0x411E3F size = 0x89 [[func]] name = "init_run_office_from_start_menu" addr = 0x411EC8 size = 0x6D [[func]] name = "init_run_office" addr = 0x411F35 size = 0x173 [[func]] name = "init_disable_screensaver" addr = 0x4120A8 size = 0x99 [[func]] name = "init_create_window" addr = 0x412141 size = 0x13B [[func]] name = "init_kill_mom_parent" addr = 0x41227C size = 0x21 [[func]] name = "init_find_mom_parent" addr = 0x41229D size = 0x50 [[func]] name = "init_await_mom_parent_exit" addr = 0x4122ED size = 0x30 [[func]] name = "init_archives" addr = 0x41231D size = 0xB0 [[func]] name = "init_test_access" addr = 0x4123CD size = 0x1B0 [[func]] name = "init_strip_trailing_slash" addr = 0x41257D size = 0x18 [[func]] name = "init_read_test_file" addr = 0x412595 size = 0x94 [[func]] name = "init_get_file_info" addr = 0x412629 size = 0x9E [[func]] name = "MainWndProc" addr = 0x4126C7 size = 0x99 [[func]] name = "init_activate_window" addr = 0x412760 size = 0x5A [[func]] name = "WindowProc" addr = 0x4127BA size = 0x25 [[func]] name = "SetWindowProc" addr = 0x4127DF size = 0xC [[func]] name = "interface_msg_pump" addr = 0x4127FB size = 0x3F [[func]] name = "IncProgress" addr = 0x41283A size = 0x39 [[func]] name = "DrawCutscene" addr = 0x412873 size = 0x75 [[func]] name = "DrawProgress" addr = 0x4128E8 size = 0x29 [[func]] name = "ShowProgress" addr = 0x412911 size = 0x317 [[func]] name = "FreeInterface" addr = 0x412C50 size = 0x12 [[func]] name = "InitCutscene" addr = 0x412C62 size = 0x1E5 [[func]] name = "FreeInvGFX" addr = 0x412E6F size = 0x12 [[func]] name = "InitInv" addr = 0x412E81 size = 0x34 [[func]] name = "InvDrawSlotBack" addr = 0x412EB5 size = 0x53 [[func]] name = "DrawInv" addr = 0x412F08 size = 0x79C [[func]] name = "DrawInvBelt" addr = 0x4136A4 size = 0x1DF [[func]] name = "AutoPlace" addr = 0x413883 size = 0x134 [[func]] name = "SpecialAutoPlace" addr = 0x4139B7 size = 0x16D [[func]] name = "GoldAutoPlace" addr = 0x413B24 size = 0x1C9 [[func]] name = "WeaponAutoPlace" addr = 0x413CED size = 0x9D [[func]] name = "SwapItem" addr = 0x413D8A size = 0x3D [[func]] name = "CheckInvPaste" addr = 0x413DC7 size = 0xB14 [[func]] name = "CheckInvSwap" addr = 0x4148FB size = 0xA9 [[func]] name = "CheckInvCut" addr = 0x4149A4 size = 0x373 [[func]] name = "inv_update_rem_item" addr = 0x414D17 size = 0x37 [[func]] name = "RemoveInvItem" addr = 0x414D4E size = 0xEE [[func]] name = "RemoveSpdBarItem" addr = 0x414E3C size = 0x5C [[func]] name = "CheckInvItem" addr = 0x414E98 size = 0x27 [[func]] name = "CheckInvScrn" addr = 0x414EBF size = 0x2C [[func]] name = "CheckItemStats" addr = 0x414EEB size = 0x4C [[func]] name = "CheckBookLevel" addr = 0x414F37 size = 0x74 [[func]] name = "CheckQuestItem" addr = 0x414FAB size = 0x7B [[func]] name = "InvGetItem" addr = 0x415026 size = 0x119 [[func]] name = "AutoGetItem" addr = 0x41513F size = 0x43B [[func]] name = "FindGetItem" addr = 0x41557A size = 0x55 [[func]] name = "SyncGetItem" addr = 0x4155CF size = 0xCA [[func]] name = "CanPut" addr = 0x415699 size = 0xD7 [[func]] name = "TryInvPut" addr = 0x415770 size = 0xC3 [[func]] name = "DrawInvMsg" addr = 0x415833 size = 0x28 [[func]] name = "InvPutItem" addr = 0x41585B size = 0x255 [[func]] name = "SyncPutItem" addr = 0x415AB0 size = 0x2A4 [[func]] name = "CheckInvHLight" addr = 0x415D54 size = 0x20D [[func]] name = "RemoveScroll" addr = 0x415F61 size = 0xA1 [[func]] name = "UseScroll" addr = 0x416002 size = 0xB7 [[func]] name = "UseStaffCharge" addr = 0x4160B9 size = 0x3D [[func]] name = "UseStaff" addr = 0x4160F6 size = 0x44 [[func]] name = "StartGoldDrop" addr = 0x41613A size = 0x66 [[func]] name = "UseInvItem" addr = 0x4161A0 size = 0x1F5 [[func]] name = "DoTelekinesis" addr = 0x416395 size = 0x72 [[func]] name = "CalculateGold" addr = 0x416407 size = 0x55 [[func]] name = "DropItemBeforeTrig" addr = 0x41645C size = 0x2E [[func]] name = "InitItemGFX" addr = 0x41648A size = 0x52 [[func]] name = "ItemPlace" addr = 0x4164DC size = 0x52 [[func]] name = "AddInitItems" addr = 0x41652E size = 0x114 [[func]] name = "InitItems" addr = 0x416642 size = 0xD2 [[func]] name = "CalcPlrItemVals" addr = 0x416714 size = 0x60E [[func]] name = "CalcPlrScrolls" addr = 0x416D22 size = 0xF7 [[func]] name = "CalcPlrStaff" addr = 0x416E19 size = 0x4D [[func]] name = "CalcSelfItems" addr = 0x416E66 size = 0xFA [[func]] name = "CalcPlrItemMin" addr = 0x416F60 size = 0x65 [[func]] name = "ItemMinStats" addr = 0x416FC5 size = 0x36 [[func]] name = "CalcPlrBookVals" addr = 0x416FFB size = 0x112 [[func]] name = "CalcPlrInv" addr = 0x41710D size = 0x5A [[func]] name = "SetPlrHandItem" addr = 0x417167 size = 0x100 [[func]] name = "GetPlrHandSeed" addr = 0x417267 size = 0xC [[func]] name = "GetGoldSeed" addr = 0x417273 size = 0x72 [[func]] name = "SetPlrHandSeed" addr = 0x4172E5 size = 0x3 [[func]] name = "SetPlrHandGoldCurs" addr = 0x4172E8 size = 0x35 [[func]] name = "CreatePlrItems" addr = 0x41731D size = 0x14E [[func]] name = "ItemSpaceOk" addr = 0x41746B size = 0xFA [[func]] name = "GetItemSpace" addr = 0x417565 size = 0xF6 [[func]] name = "GetSuperItemSpace" addr = 0x41765B size = 0x8E [[func]] name = "GetSuperItemLoc" addr = 0x4176E9 size = 0x6A [[func]] name = "CalcItemValue" addr = 0x417753 size = 0x4C [[func]] name = "GetBookSpell" addr = 0x41779F size = 0xF0 [[func]] name = "GetStaffPower" addr = 0x41788F size = 0x1D1 [[func]] name = "GetStaffSpell" addr = 0x417A60 size = 0x171 [[func]] name = "GetItemAttrs" addr = 0x417BD1 size = 0x2CD [[func]] name = "RndPL" addr = 0x417E9E size = 0x11 [[func]] name = "PLVal" addr = 0x417EAF size = 0x40 [[func]] name = "SaveItemPower" addr = 0x417EEF size = 0x947 [[func]] name = "GetItemPower" addr = 0x418976 size = 0x32D [[func]] name = "GetItemBonus" addr = 0x418CA3 size = 0x7C [[func]] name = "SetupItem" addr = 0x418D48 size = 0x8A [[func]] name = "RndItem" addr = 0x418DD2 size = 0xE7 [[func]] name = "RndUItem" addr = 0x418EB9 size = 0xF8 [[func]] name = "RndAllItems" addr = 0x418FB1 size = 0x8D [[func]] name = "RndTypeItems" addr = 0x41903E size = 0x8A [[func]] name = "CheckUnique" addr = 0x4190C8 size = 0xD0 [[func]] name = "GetUniqueItem" addr = 0x419198 size = 0x14B [[func]] name = "SpawnUnique" addr = 0x4192E3 size = 0x8A [[func]] name = "ItemRndDur" addr = 0x41936D size = 0x3E [[func]] name = "SetupAllItems" addr = 0x4193AB size = 0x156 [[func]] name = "SpawnItem" addr = 0x419501 size = 0x116 [[func]] name = "CreateItem" addr = 0x419617 size = 0x9B [[func]] name = "CreateRndItem" addr = 0x4196B2 size = 0xA5 [[func]] name = "SetupAllUseful" addr = 0x419757 size = 0x6D [[func]] name = "CreateRndUseful" addr = 0x4197C4 size = 0x69 [[func]] name = "CreateTypeItem" addr = 0x41982D size = 0xA4 [[func]] name = "RecreateItem" addr = 0x4198D1 size = 0x112 [[func]] name = "RecreateEar" addr = 0x4199E3 size = 0x139 [[func]] name = "SpawnQuestItem" addr = 0x419B1C size = 0x11C [[func]] name = "SpawnRock" addr = 0x419C38 size = 0xD8 [[func]] name = "RespawnItem" addr = 0x419D10 size = 0xC7 [[func]] name = "DeleteItem" addr = 0x419DD7 size = 0x34 [[func]] name = "ItemDoppel" addr = 0x419E0B size = 0x5A [[func]] name = "ProcessItems" addr = 0x419E65 size = 0xD4 [[func]] name = "FreeItemGFX" addr = 0x419F39 size = 0x1D [[func]] name = "GetItemFrm" addr = 0x419F56 size = 0x21 [[func]] name = "GetItemStr" addr = 0x419F77 size = 0x73 [[func]] name = "CheckIdentify" addr = 0x419FEA size = 0x39 [[func]] name = "DoRepair" addr = 0x41A023 size = 0x5A [[func]] name = "RepairItem" addr = 0x41A07D size = 0x76 [[func]] name = "DoRecharge" addr = 0x41A0F3 size = 0x71 [[func]] name = "RechargeItem" addr = 0x41A164 size = 0x37 [[func]] name = "PrintItemOil" addr = 0x41A19B size = 0x98 [[func]] name = "PrintItemPower" addr = 0x41A27B size = 0x4FC [[func]] name = "DrawUTextBack" addr = 0x41A8B7 size = 0x5C [[func]] name = "PrintUString" addr = 0x41A913 size = 0xCF [[func]] name = "DrawULine" addr = 0x41A9E2 size = 0x4B [[func]] name = "DrawUniqueInfo" addr = 0x41AA2D size = 0x136 [[func]] name = "PrintItemMisc" addr = 0x41AB63 size = 0xF8 [[func]] name = "PrintItemDetails" addr = 0x41AC5B size = 0x20D [[func]] name = "PrintItemDur" addr = 0x41AE68 size = 0x1FF [[func]] name = "UseItem" addr = 0x41B067 size = 0x4F7 [[func]] name = "StoreStatOk" addr = 0x41B55E size = 0x45 [[func]] name = "SmithItemOk" addr = 0x41B5A3 size = 0x36 [[func]] name = "RndSmithItem" addr = 0x41B5D9 size = 0x6F [[func]] name = "BubbleSwapItem" addr = 0x41B648 size = 0x34 [[func]] name = "SortSmith" addr = 0x41B67C size = 0x5C [[func]] name = "SpawnSmith" addr = 0x41B6D8 size = 0xCF [[func]] name = "PremiumItemOk" addr = 0x41B7A7 size = 0x3F [[func]] name = "RndPremiumItem" addr = 0x41B7E6 size = 0x67 [[func]] name = "SpawnOnePremium" addr = 0x41B84D size = 0xDA [[func]] name = "SpawnPremium" addr = 0x41B927 size = 0xCC [[func]] name = "WitchItemOk" addr = 0x41B9F3 size = 0x66 [[func]] name = "RndWitchItem" addr = 0x41BA59 size = 0x63 [[func]] name = "SortWitch" addr = 0x41BABC size = 0x60 [[func]] name = "WitchBookLevel" addr = 0x41BB1C size = 0x80 [[func]] name = "SpawnWitch" addr = 0x41BB9C size = 0x18F [[func]] name = "RndBoyItem" addr = 0x41BD2B size = 0x5F [[func]] name = "SpawnBoy" addr = 0x41BD8A size = 0x98 [[func]] name = "HealerItemOk" addr = 0x41BE22 size = 0xAE [[func]] name = "RndHealerItem" addr = 0x41BED0 size = 0x63 [[func]] name = "SortHealer" addr = 0x41BF33 size = 0x60 [[func]] name = "SpawnHealer" addr = 0x41BF93 size = 0x14B [[func]] name = "SpawnStoreGold" addr = 0x41C0DE size = 0x29 [[func]] name = "RecreateSmithItem" addr = 0x41C107 size = 0x51 [[func]] name = "RecreatePremiumItem" addr = 0x41C158 size = 0x6B [[func]] name = "RecreateBoyItem" addr = 0x41C1C3 size = 0x65 [[func]] name = "RecreateWitchItem" addr = 0x41C228 size = 0xB1 [[func]] name = "RecreateHealerItem" addr = 0x41C2D9 size = 0x66 [[func]] name = "RecreateTownItem" addr = 0x41C33F size = 0x67 [[func]] name = "RecalcStoreStats" addr = 0x41C3A6 size = 0xA1 [[func]] name = "ItemNoFlippy" addr = 0x41C447 size = 0x2F [[func]] name = "CreateSpellBook" addr = 0x41C476 size = 0xC9 [[func]] name = "CreateMagicArmor" addr = 0x41C53F size = 0xB6 [[func]] name = "CreateMagicWeapon" addr = 0x41C53F size = 0xB6 [[func]] name = "GetItemRecord" addr = 0x41C5F5 size = 0xA3 [[func]] name = "NextItemRecord" addr = 0x41C698 size = 0x46 [[func]] name = "SetItemRecord" addr = 0x41C6DE size = 0x47 [[func]] name = "PutItemRecord" addr = 0x41C725 size = 0xA5 [[func]] name = "RotateRadius" addr = 0x41C7CA size = 0x77 [[func]] name = "DoLighting" addr = 0x41C841 size = 0x3F6 [[func]] name = "DoUnLight" addr = 0x41CC37 size = 0x80 [[func]] name = "DoUnVision" addr = 0x41CCB7 size = 0x5A [[func]] name = "DoVision" addr = 0x41CD11 size = 0x289 [[func]] name = "FreeLightTable" addr = 0x41CF9A size = 0x12 [[func]] name = "InitLightTable" addr = 0x41CFAC size = 0x10 [[func]] name = "MakeLightTable" addr = 0x41CFBC size = 0x383 [[func]] name = "InitLightMax" addr = 0x41D33F size = 0x16 [[func]] name = "InitLighting" addr = 0x41D355 size = 0x1E [[func]] name = "AddLight" addr = 0x41D373 size = 0x6A [[func]] name = "AddUnLight" addr = 0x41D3DD size = 0x20 [[func]] name = "ChangeLightRadius" addr = 0x41D3FD size = 0x4F [[func]] name = "ChangeLightXY" addr = 0x41D44C size = 0x5B [[func]] name = "ChangeLightOff" addr = 0x41D4A7 size = 0x5B [[func]] name = "ChangeLight" addr = 0x41D502 size = 0x6C [[func]] name = "ProcessLightList" addr = 0x41D56E size = 0xF9 [[func]] name = "SavePreLighting" addr = 0x41D667 size = 0x18 [[func]] name = "InitVision" addr = 0x41D67F size = 0x3B [[func]] name = "AddVision" addr = 0x41D6BA size = 0x6D [[func]] name = "ChangeVisionRadius" addr = 0x41D727 size = 0x41 [[func]] name = "ChangeVisionXY" addr = 0x41D768 size = 0x4A [[func]] name = "ProcessVisionList" addr = 0x41D7B2 size = 0xF4 [[func]] name = "lighting_color_cycling" addr = 0x41D8A6 size = 0x45 [[func]] name = "LoadGame" addr = 0x41D8EB size = 0x57E [[func]] name = "BLoad" addr = 0x41DE69 size = 0xE [[func]] name = "WLoad" addr = 0x41DE77 size = 0x3C [[func]] name = "ILoad" addr = 0x41DEB3 size = 0x3C [[func]] name = "OLoad" addr = 0x41DEEF size = 0x17 [[func]] name = "LoadPlayer" addr = 0x41DF06 size = 0x2A [[func]] name = "LoadMonster" addr = 0x41DF30 size = 0x35 [[func]] name = "LoadMissile" addr = 0x41DF65 size = 0x2A [[func]] name = "LoadObject" addr = 0x41DF8F size = 0x22 [[func]] name = "LoadItem" addr = 0x41DFB1 size = 0x35 [[func]] name = "LoadPremium" addr = 0x41DFE6 size = 0x2A [[func]] name = "LoadQuest" addr = 0x41E010 size = 0x55 [[func]] name = "LoadLighting" addr = 0x41E065 size = 0x22 [[func]] name = "LoadVision" addr = 0x41E087 size = 0x22 [[func]] name = "LoadPortal" addr = 0x41E0A9 size = 0x23 [[func]] name = "SaveGame" addr = 0x41E0CC size = 0x4BE [[func]] name = "BSave" addr = 0x41E58A size = 0xE [[func]] name = "WSave" addr = 0x41E598 size = 0x47 [[func]] name = "ISave" addr = 0x41E5DF size = 0x47 [[func]] name = "OSave" addr = 0x41E626 size = 0x18 [[func]] name = "SavePlayer" addr = 0x41E63E size = 0x2A [[func]] name = "SaveMonster" addr = 0x41E668 size = 0x2A [[func]] name = "SaveMissile" addr = 0x41E692 size = 0x2A [[func]] name = "SaveObject" addr = 0x41E6BC size = 0x22 [[func]] name = "SaveItem" addr = 0x41E6DE size = 0x2A [[func]] name = "SavePremium" addr = 0x41E708 size = 0x2A [[func]] name = "SaveQuest" addr = 0x41E732 size = 0x59 [[func]] name = "SaveLighting" addr = 0x41E78B size = 0x22 [[func]] name = "SaveVision" addr = 0x41E7AD size = 0x22 [[func]] name = "SavePortal" addr = 0x41E7CF size = 0x23 [[func]] name = "SaveLevel" addr = 0x41E7F2 size = 0x2C4 [[func]] name = "LoadLevel" addr = 0x41EAB6 size = 0x2C3 [[func]] name = "log_flush" addr = 0x41EDB7 size = 0x92 [[func]] name = "log_create" addr = 0x41EE49 size = 0x156 [[func]] name = "log_get_version" addr = 0x41EF9F size = 0xB1 [[func]] name = "log_printf" addr = 0x41F050 size = 0xAC [[func]] name = "log_dump_computer_info" addr = 0x41F0FC size = 0x99 [[func]] name = "mainmenu_refresh_music" addr = 0x41F1A5 size = 0xB [[func]] name = "mainmenu_change_name" addr = 0x41F1B0 size = 0x1D [[func]] name = "mainmenu_select_hero_dialog" addr = 0x41F1CD size = 0x114 [[func]] name = "mainmenu_loop" addr = 0x41F2E1 size = 0x65 [[func]] name = "mainmenu_single_player" addr = 0x41F346 size = 0xE [[func]] name = "mainmenu_init_menu" addr = 0x41F354 size = 0x36 [[func]] name = "mainmenu_multi_player" addr = 0x41F38A size = 0xF [[func]] name = "FreeQuestText" addr = 0x41F399 size = 0x24 [[func]] name = "InitQuestText" addr = 0x41F3BD size = 0x2A [[func]] name = "InitQTextMsg" addr = 0x41F3E7 size = 0x60 [[func]] name = "DrawQTextBack" addr = 0x41F447 size = 0x5C [[func]] name = "PrintQTextChr" addr = 0x41F4A3 size = 0xA2 [[func]] name = "DrawQText" addr = 0x41F545 size = 0x1BE [[func]] name = "GetDamageAmt" addr = 0x41F703 size = 0x4F1 [[func]] name = "CheckBlock" addr = 0x41FC64 size = 0x59 [[func]] name = "FindClosest" addr = 0x41FCBD size = 0x11F [[func]] name = "GetSpellLevel" addr = 0x41FDDC size = 0x2B [[func]] name = "GetDirection8" addr = 0x41FE07 size = 0x62A [[func]] name = "GetDirection16" addr = 0x420431 size = 0x690 [[func]] name = "DeleteMissile" addr = 0x420AC1 size = 0x70 [[func]] name = "GetMissileVel" addr = 0x420B31 size = 0xBF [[func]] name = "PutMissile" addr = 0x420BF0 size = 0x6B [[func]] name = "GetMissilePos" addr = 0x420C5B size = 0xD2 [[func]] name = "MoveMissilePos" addr = 0x420D2D size = 0x8F [[func]] name = "MonsterTrapHit" addr = 0x420DDC size = 0x1A2 [[func]] name = "MonsterMHit" addr = 0x420F7E size = 0x313 [[func]] name = "PlayerMHit" addr = 0x421291 size = 0x3A2 [[func]] name = "Plr2PlrMHit" addr = 0x421633 size = 0x2BD [[func]] name = "CheckMissileCol" addr = 0x4218F0 size = 0x2FA [[func]] name = "SetMissAnim" addr = 0x421BEA size = 0x84 [[func]] name = "SetMissDir" addr = 0x421C6E size = 0x1A [[func]] name = "LoadMissileGFX" addr = 0x421C88 size = 0xE9 [[func]] name = "InitMissileGFX" addr = 0x421D71 size = 0x2D [[func]] name = "FreeMissileGFX" addr = 0x421D9E size = 0x69 [[func]] name = "FreeMissiles" addr = 0x421E07 size = 0x2E [[func]] name = "FreeMissiles2" addr = 0x421E35 size = 0x2E [[func]] name = "InitMissiles" addr = 0x421E63 size = 0xBE [[func]] name = "AddLArrow" addr = 0x421F21 size = 0xCD [[func]] name = "AddArrow" addr = 0x421FEE size = 0xD1 [[func]] name = "GetVileMissPos" addr = 0x4220BF size = 0x9E [[func]] name = "AddRndTeleport" addr = 0x42215D size = 0x143 [[func]] name = "AddFirebolt" addr = 0x4222A0 size = 0x10F [[func]] name = "AddMagmaball" addr = 0x4223AF size = 0x79 [[func]] name = "miss_null_33" addr = 0x422428 size = 0x46 [[func]] name = "AddTeleport" addr = 0x42246E size = 0x12B [[func]] name = "AddLightball" addr = 0x422599 size = 0x7F [[func]] name = "AddFirewall" addr = 0x422618 size = 0xBD [[func]] name = "AddFireball" addr = 0x4226D5 size = 0x127 [[func]] name = "AddLightctrl" addr = 0x4227FC size = 0x6C [[func]] name = "AddLightning" addr = 0x422868 size = 0xCD [[func]] name = "AddMisexp" addr = 0x422935 size = 0xF1 [[func]] name = "AddWeapexp" addr = 0x422A26 size = 0x6B [[func]] name = "CheckIfTrig" addr = 0x422A91 size = 0x63 [[func]] name = "AddTown" addr = 0x422AF4 size = 0x21D [[func]] name = "AddFlash" addr = 0x422D11 size = 0xC5 [[func]] name = "AddFlash2" addr = 0x422DD6 size = 0xC2 [[func]] name = "AddManashield" addr = 0x422E98 size = 0x77 [[func]] name = "AddFiremove" addr = 0x422F0F size = 0x7C [[func]] name = "AddGuardian" addr = 0x422F8B size = 0x222 [[func]] name = "AddChain" addr = 0x4231AD size = 0x33 [[func]] name = "miss_null_11" addr = 0x4231E0 size = 0x33 [[func]] name = "miss_null_12" addr = 0x423213 size = 0x3D [[func]] name = "miss_null_13" addr = 0x423250 size = 0x3F [[func]] name = "AddRhino" addr = 0x42328F size = 0x111 [[func]] name = "miss_null_32" addr = 0x4233A0 size = 0xDC [[func]] name = "AddFlare" addr = 0x42347C size = 0x10F [[func]] name = "AddAcid" addr = 0x42358B size = 0x78 [[func]] name = "miss_null_1D" addr = 0x423603 size = 0x3C [[func]] name = "AddAcidpud" addr = 0x42363F size = 0x64 [[func]] name = "AddStone" addr = 0x4236A3 size = 0x18A [[func]] name = "AddGolem" addr = 0x42382D size = 0xC2 [[func]] name = "AddEtherealize" addr = 0x4238EF size = 0x8A [[func]] name = "miss_null_1F" addr = 0x423F9A size = 0x13 [[func]] name = "miss_null_23" addr = 0x423979 size = 0x62 [[func]] name = "AddBoom" addr = 0x4239DB size = 0x53 [[func]] name = "AddHeal" addr = 0x423A2E size = 0xE0 [[func]] name = "AddHealOther" addr = 0x423B0E size = 0x33 [[func]] name = "AddElement" addr = 0x423B41 size = 0x103 [[func]] name = "AddIdentify" addr = 0x423C44 size = 0x51 [[func]] name = "AddFirewallC" addr = 0x423C95 size = 0x162 [[func]] name = "AddInfra" addr = 0x423DF7 size = 0x67 [[func]] name = "AddWave" addr = 0x423E5E size = 0x4B [[func]] name = "AddNova" addr = 0x423EA9 size = 0xF1 [[func]] name = "AddRepair" addr = 0x423FAD size = 0x51 [[func]] name = "AddRecharge" addr = 0x423FFE size = 0x51 [[func]] name = "AddDisarm" addr = 0x42404F size = 0x33 [[func]] name = "AddApoca" addr = 0x424082 size = 0xC5 [[func]] name = "AddFlame" addr = 0x424147 size = 0x103 [[func]] name = "AddFlamec" addr = 0x42424A size = 0x78 [[func]] name = "AddCbolt" addr = 0x4242C2 size = 0xEB [[func]] name = "AddHbolt" addr = 0x4243AD size = 0xE0 [[func]] name = "AddResurrect" addr = 0x42448D size = 0x37 [[func]] name = "AddResurrectBeam" addr = 0x4244C4 size = 0x44 [[func]] name = "AddTelekinesis" addr = 0x424508 size = 0x33 [[func]] name = "AddBoneSpirit" addr = 0x42453B size = 0xEB [[func]] name = "AddRportal" addr = 0x424626 size = 0x4A [[func]] name = "AddDiabApoca" addr = 0x424670 size = 0x7F [[func]] name = "AddMissile" addr = 0x4246EF size = 0x1C9 [[func]] name = "Sentfire" addr = 0x4248B8 size = 0xDC [[func]] name = "MI_Dummy" addr = 0x44777C size = 0x1 [[func]] name = "MI_Golem" addr = 0x424994 size = 0x147 [[func]] name = "MI_SetManashield" addr = 0x424ADB size = 0xB [[func]] name = "MI_LArrow" addr = 0x424AE6 size = 0x2FE [[func]] name = "MI_Arrow" addr = 0x424DE4 size = 0xD1 [[func]] name = "MI_Firebolt" addr = 0x424EB5 size = 0x2B9 [[func]] name = "MI_Lightball" addr = 0x42516E size = 0xE8 [[func]] name = "mi_null_33" addr = 0x425256 size = 0x69 [[func]] name = "MI_Acidpud" addr = 0x4252BF size = 0x73 [[func]] name = "MI_Firewall" addr = 0x425332 size = 0x171 [[func]] name = "MI_Fireball" addr = 0x4254A3 size = 0x418 [[func]] name = "MI_Lightctrl" addr = 0x4258BB size = 0x1F4 [[func]] name = "MI_Lightning" addr = 0x425AAF size = 0x85 [[func]] name = "MI_Town" addr = 0x425B34 size = 0x1AB [[func]] name = "MI_Flash" addr = 0x425CDF size = 0x126 [[func]] name = "MI_Flash2" addr = 0x425E05 size = 0xCE [[func]] name = "MI_Manashield" addr = 0x425ED3 size = 0x25A [[func]] name = "MI_Etherealize" addr = 0x42612D size = 0xE4 [[func]] name = "MI_Firemove" addr = 0x426211 size = 0x1CB [[func]] name = "MI_Guardian" addr = 0x4263DC size = 0x1FA [[func]] name = "MI_Chain" addr = 0x4265D6 size = 0x1B3 [[func]] name = "mi_null_11" addr = 0x426789 size = 0x34 [[func]] name = "MI_Weapexp" addr = 0x4267BD size = 0x12D [[func]] name = "MI_Misexp" addr = 0x4268EA size = 0xBC [[func]] name = "MI_Acidsplat" addr = 0x4269A6 size = 0x91 [[func]] name = "MI_Teleport" addr = 0x426A37 size = 0x109 [[func]] name = "MI_Stone" addr = 0x426B40 size = 0xC2 [[func]] name = "MI_Boom" addr = 0x426C02 size = 0x61 [[func]] name = "MI_Rhino" addr = 0x426C63 size = 0x181 [[func]] name = "mi_null_32" addr = 0x426DE4 size = 0x1A4 [[func]] name = "MI_FirewallC" addr = 0x426F88 size = 0x16F [[func]] name = "MI_Infra" addr = 0x4270F7 size = 0x3D [[func]] name = "MI_Apoca" addr = 0x427134 size = 0xEB [[func]] name = "MI_Wave" addr = 0x42721F size = 0x249 [[func]] name = "MI_Nova" addr = 0x427468 size = 0x153 [[func]] name = "MI_Blodboil" addr = 0x4275BB size = 0x11 [[func]] name = "MI_Flame" addr = 0x4275CC size = 0xC6 [[func]] name = "MI_Flamec" addr = 0x427692 size = 0xDE [[func]] name = "MI_Cbolt" addr = 0x427770 size = 0x186 [[func]] name = "MI_Hbolt" addr = 0x4278F6 size = 0x13D [[func]] name = "MI_Element" addr = 0x427A33 size = 0x379 [[func]] name = "MI_Bonespirit" addr = 0x427DAC size = 0x1F5 [[func]] name = "MI_ResurrectBeam" addr = 0x427FA1 size = 0x1F [[func]] name = "MI_Rportal" addr = 0x427FC0 size = 0x12E [[func]] name = "ProcessMissiles" addr = 0x4280EE size = 0x15B [[func]] name = "missiles_process_charge" addr = 0x428249 size = 0x84 [[func]] name = "ClearMissileSpot" addr = 0x4282CD size = 0x26 [[func]] name = "InitMonsterTRN" addr = 0x428303 size = 0x8C [[func]] name = "InitLevelMonsters" addr = 0x42838F size = 0x54 [[func]] name = "AddMonsterType" addr = 0x4283E3 size = 0x80 [[func]] name = "GetLevelMTypes" addr = 0x428463 size = 0x2AA [[func]] name = "InitMonsterGFX" addr = 0x42870D size = 0x2B5 [[func]] name = "ClearMVars" addr = 0x4289C2 size = 0x39 [[func]] name = "InitMonster" addr = 0x4289FB size = 0x384 [[func]] name = "ClrAllMonsters" addr = 0x428D7F size = 0xA5 [[func]] name = "MonstPlace" addr = 0x428E24 size = 0x4D [[func]] name = "PlaceMonster" addr = 0x428E71 size = 0x3C [[func]] name = "PlaceGroup" addr = 0x428EAD size = 0x28B [[func]] name = "InitMonsters" addr = 0x429138 size = 0x1E5 [[func]] name = "DeleteMonster" addr = 0x42931D size = 0x24 [[func]] name = "AddMonster" addr = 0x429341 size = 0x50 [[func]] name = "NewMonsterAnim" addr = 0x429391 size = 0x3E [[func]] name = "M_Ranged" addr = 0x4293CF size = 0x27 [[func]] name = "M_Talker" addr = 0x4293F6 size = 0x36 [[func]] name = "M_Enemy" addr = 0x42942C size = 0x2B9 [[func]] name = "M_GetDir" addr = 0x4296E5 size = 0x28 [[func]] name = "M_CheckEFlag" addr = 0x42970D size = 0x60 [[func]] name = "M_StartStand" addr = 0x42976D size = 0x8C [[func]] name = "M_StartDelay" addr = 0x4297F9 size = 0x26 [[func]] name = "M_StartSpStand" addr = 0x42981F size = 0x6D [[func]] name = "M_StartWalk" addr = 0x42988C size = 0xD3 [[func]] name = "M_StartWalk2" addr = 0x42995F size = 0x11B [[func]] name = "M_StartWalk3" addr = 0x429A7A size = 0x14C [[func]] name = "M_StartAttack" addr = 0x429BC6 size = 0x71 [[func]] name = "M_StartRAttack" addr = 0x429C37 size = 0x88 [[func]] name = "M_StartRSpAttack" addr = 0x429CBF size = 0x91 [[func]] name = "M_StartSpAttack" addr = 0x429D50 size = 0x74 [[func]] name = "M_StartEat" addr = 0x429DC4 size = 0x68 [[func]] name = "M_ClearSquares" addr = 0x429E2C size = 0xBF [[func]] name = "M_GetKnockback" addr = 0x429EEB size = 0xCA [[func]] name = "M_StartHit" addr = 0x429FB5 size = 0x175 [[func]] name = "M_DiabloDeath" addr = 0x42A12A size = 0x1E6 [[func]] name = "M2MStartHit" addr = 0x42A310 size = 0x180 [[func]] name = "MonstStartKill" addr = 0x42A490 size = 0x1F6 [[func]] name = "M2MStartKill" addr = 0x42A686 size = 0x205 [[func]] name = "M_StartKill" addr = 0x42A88B size = 0x7E [[func]] name = "M_SyncStartKill" addr = 0x42A909 size = 0x9B [[func]] name = "M_StartFadein" addr = 0x42A9A4 size = 0xCD [[func]] name = "M_StartFadeout" addr = 0x42AA71 size = 0xC5 [[func]] name = "M_StartHeal" addr = 0x42AB36 size = 0x98 [[func]] name = "M_ChangeLightOffset" addr = 0x42ABCE size = 0x6A [[func]] name = "M_DoStand" addr = 0x42AC38 size = 0x7F [[func]] name = "M_DoWalk" addr = 0x42ACB7 size = 0x116 [[func]] name = "M_DoWalk2" addr = 0x42ADCD size = 0xF3 [[func]] name = "M_DoWalk3" addr = 0x42AEC0 size = 0x126 [[func]] name = "M_TryM2MHit" addr = 0x42AFE6 size = 0x10A [[func]] name = "M_TryH2HHit" addr = 0x42B0F0 size = 0x40F [[func]] name = "M_DoAttack" addr = 0x42B4FF size = 0x182 [[func]] name = "M_DoRAttack" addr = 0x42B681 size = 0xF5 [[func]] name = "M_DoRSpAttack" addr = 0x42B776 size = 0x115 [[func]] name = "M_DoSAttack" addr = 0x42B88B size = 0xB7 [[func]] name = "M_DoFadein" addr = 0x42B942 size = 0x65 [[func]] name = "M_DoFadeout" addr = 0x42B9A7 size = 0x82 [[func]] name = "M_DoHeal" addr = 0x42BA29 size = 0x90 [[func]] name = "M_DoTalk" addr = 0x42BAB9 size = 0x285 [[func]] name = "M_Teleport" addr = 0x42BD3E size = 0x141 [[func]] name = "M_DoGotHit" addr = 0x42BE7F size = 0x63 [[func]] name = "M_UpdateLeader" addr = 0x42BEE2 size = 0x79 [[func]] name = "DoEnding" addr = 0x42BF5B size = 0x2D [[func]] name = "PrepDoEnding" addr = 0x42BF88 size = 0x83 [[func]] name = "M_DoDeath" addr = 0x42C00B size = 0x10D [[func]] name = "M_DoSpStand" addr = 0x42C118 size = 0x7F [[func]] name = "M_DoDelay" addr = 0x42C197 size = 0xA9 [[func]] name = "M_DoStone" addr = 0x42C240 size = 0x4E [[func]] name = "M_WalkDir" addr = 0x42C28E size = 0x133 [[func]] name = "GroupUnity" addr = 0x42C3E1 size = 0x1F3 [[func]] name = "M_CallWalk" addr = 0x42C5D4 size = 0x10D [[func]] name = "M_PathWalk" addr = 0x42C6E1 size = 0x80 [[func]] name = "M_CallWalk2" addr = 0x42C761 size = 0x85 [[func]] name = "M_DumbWalk" addr = 0x42C7E6 size = 0x21 [[func]] name = "M_RoundWalk" addr = 0x42C807 size = 0xD6 [[func]] name = "MAI_Zombie" addr = 0x42C8DD size = 0x146 [[func]] name = "MAI_SkelSd" addr = 0x42CA23 size = 0x13A [[func]] name = "MAI_Path" addr = 0x42CB5D size = 0xC8 [[func]] name = "MAI_Snake" addr = 0x42CC25 size = 0x296 [[func]] name = "MAI_Bat" addr = 0x42CEBB size = 0x268 [[func]] name = "MAI_SkelBow" addr = 0x42D123 size = 0x141 [[func]] name = "MAI_Fat" addr = 0x42D264 size = 0x128 [[func]] name = "MAI_Sneak" addr = 0x42D38C size = 0x268 [[func]] name = "MAI_Fireman" addr = 0x42D5F4 size = 0x224 [[func]] name = "MAI_Fallen" addr = 0x42D818 size = 0x1EB [[func]] name = "MAI_Cleaver" addr = 0x42DA03 size = 0xAE [[func]] name = "MAI_Round" addr = 0x42DAB1 size = 0x29B [[func]] name = "MAI_GoatMc" addr = 0x42DD4C size = 0x8 [[func]] name = "MAI_Ranged" addr = 0x42DD54 size = 0x18B [[func]] name = "MAI_GoatBow" addr = 0x42DEDF size = 0xA [[func]] name = "MAI_Succ" addr = 0x42DEE9 size = 0xB [[func]] name = "MAI_AcidUniq" addr = 0x42DEF4 size = 0xB [[func]] name = "MAI_Scav" addr = 0x42DEFF size = 0x284 [[func]] name = "MAI_Garg" addr = 0x42E183 size = 0x134 [[func]] name = "MAI_RoundRanged" addr = 0x42E2B7 size = 0x308 [[func]] name = "MAI_Magma" addr = 0x42E5BF size = 0xF [[func]] name = "MAI_Storm" addr = 0x42E5CE size = 0xF [[func]] name = "MAI_Acid" addr = 0x42E5DD size = 0xF [[func]] name = "MAI_Diablo" addr = 0x42E5EC size = 0xF [[func]] name = "MAI_RR2" addr = 0x42E5FB size = 0x30F [[func]] name = "MAI_Mega" addr = 0x42E90A size = 0xB [[func]] name = "MAI_Golum" addr = 0x42E915 size = 0x21B [[func]] name = "MAI_SkelKing" addr = 0x42EB30 size = 0x329 [[func]] name = "MAI_Rhino" addr = 0x42EE59 size = 0x2F2 [[func]] name = "MAI_Counselor" addr = 0x42F14B size = 0x35A [[func]] name = "MAI_Garbud" addr = 0x42F4A5 size = 0xC4 [[func]] name = "MAI_Zhar" addr = 0x42F569 size = 0x10E [[func]] name = "MAI_SnotSpil" addr = 0x42F677 size = 0xE5 [[func]] name = "MAI_Lazurus" addr = 0x42F75C size = 0x129 [[func]] name = "MAI_Lazhelp" addr = 0x42F885 size = 0xBD [[func]] name = "MAI_Lachdanan" addr = 0x42F942 size = 0x53 [[func]] name = "MAI_Warlord" addr = 0x42F995 size = 0xAC [[func]] name = "DeleteMonsterList" addr = 0x42FA41 size = 0x65 [[func]] name = "ProcessMonsters" addr = 0x42FAA6 size = 0x2E5 [[func]] name = "FreeMonsters" addr = 0x42FDD3 size = 0x6C [[func]] name = "DirOK" addr = 0x42FE3F size = 0x201 [[func]] name = "PosOkMissile" addr = 0x430040 size = 0x25 [[func]] name = "CheckNoSolid" addr = 0x430065 size = 0x1A [[func]] name = "LineClearF" addr = 0x43007F size = 0x16F [[func]] name = "LineClear" addr = 0x4301EE size = 0x1A [[func]] name = "LineClearF1" addr = 0x430208 size = 0x17B [[func]] name = "SyncMonsterAnim" addr = 0x430383 size = 0xEB [[func]] name = "M_FallenFear" addr = 0x4304B6 size = 0xEA [[func]] name = "PrintMonstHistory" addr = 0x4305A0 size = 0x1A8 [[func]] name = "PrintUniqueHistory" addr = 0x430748 size = 0x87 [[func]] name = "MissToMonst" addr = 0x4307CF size = 0x29D [[func]] name = "PosOkMonst" addr = 0x430A6C size = 0xE9 [[func]] name = "PosOkMonst2" addr = 0x430B55 size = 0xCC [[func]] name = "PosOkMonst3" addr = 0x430C21 size = 0x128 [[func]] name = "IsSkel" addr = 0x430D49 size = 0x25 [[func]] name = "IsGoat" addr = 0x430D6E size = 0x1B [[func]] name = "M_SpawnSkel" addr = 0x430D89 size = 0xAD [[func]] name = "ActivateSpawn" addr = 0x430E36 size = 0x51 [[func]] name = "SpawnSkeleton" addr = 0x430E87 size = 0x100 [[func]] name = "PreSpawnSkeleton" addr = 0x430F87 size = 0x93 [[func]] name = "TalktoMonster" addr = 0x43101A size = 0xCE [[func]] name = "SpawnGolum" addr = 0x4310E8 size = 0x132 [[func]] name = "CanTalkToMonst" addr = 0x43121A size = 0x37 [[func]] name = "CheckMonsterHit" addr = 0x431251 size = 0x72 [[func]] name = "encode_enemy" addr = 0x4312C3 size = 0x19 [[func]] name = "decode_enemy" addr = 0x4312DC size = 0x65 [[func]] name = "play_movie" addr = 0x431351 size = 0xFB [[func]] name = "MovieWndProc" addr = 0x43144C size = 0x52 [[func]] name = "mpqapi_set_hidden" addr = 0x4314AE size = 0x3C [[func]] name = "mpqapi_store_creation_time" addr = 0x4314EA size = 0x73 [[func]] name = "mpqapi_reg_load_modification_time" addr = 0x43155D size = 0x56 [[func]] name = "mpqapi_xor_buf" addr = 0x4315B3 size = 0x1F [[func]] name = "mpqapi_reg_store_modification_time" addr = 0x4315D2 size = 0x39 [[func]] name = "mpqapi_remove_hash_entry" addr = 0x431610 size = 0x52 [[func]] name = "mpqapi_alloc_block" addr = 0x431662 size = 0x90 [[func]] name = "mpqapi_new_block" addr = 0x4316F2 size = 0x3F [[func]] name = "FetchHandle" addr = 0x431731 size = 0x30 [[func]] name = "mpqapi_get_hash_index" addr = 0x431761 size = 0x6A [[func]] name = "mpqapi_remove_hash_entries" addr = 0x4317CB size = 0x3B [[func]] name = "mpqapi_write_file" addr = 0x431806 size = 0x45 [[func]] name = "mpqapi_add_file" addr = 0x43184B size = 0xDA [[func]] name = "mpqapi_write_file_contents" addr = 0x431925 size = 0x205 [[func]] name = "mpqapi_find_free_block" addr = 0x431B2A size = 0x54 [[func]] name = "mpqapi_rename" addr = 0x431B7E size = 0x3F [[func]] name = "mpqapi_has_file" addr = 0x431BBD size = 0x10 [[func]] name = "OpenMPQ" addr = 0x431BCD size = 0x1D2 [[func]] name = "ParseMPQHeader" addr = 0x431D9F size = 0xF1 [[func]] name = "CloseMPQ" addr = 0x431E90 size = 0x7B [[func]] name = "mpqapi_store_modified_time" addr = 0x431F0B size = 0x73 [[func]] name = "mpqapi_flush_and_close" addr = 0x431F7E size = 0x5A [[func]] name = "WriteMPQHeader" addr = 0x431FD8 size = 0x96 [[func]] name = "mpqapi_write_block_table" addr = 0x43206E size = 0x8B [[func]] name = "mpqapi_write_hash_table" addr = 0x4320F9 size = 0x8E [[func]] name = "mpqapi_can_seek" addr = 0x432187 size = 0x2B [[func]] name = "msg_send_drop_pkt" addr = 0x4321C2 size = 0x1B [[func]] name = "msg_send_packet" addr = 0x4321DD size = 0x62 [[func]] name = "msg_get_next_packet" addr = 0x43223F size = 0x3C [[func]] name = "msg_wait_resync" addr = 0x43227B size = 0x80 [[func]] name = "msg_free_packets" addr = 0x4322FB size = 0x2C [[func]] name = "msg_wait_for_turns" addr = 0x432327 size = 0xD2 [[func]] name = "run_delta_info" addr = 0x4323F9 size = 0x22 [[func]] name = "msg_pre_packet" addr = 0x43241B size = 0x67 [[func]] name = "DeltaExportData" addr = 0x432482 size = 0xB7 [[func]] name = "DeltaExportItem" addr = 0x432539 size = 0x30 [[func]] name = "DeltaExportObject" addr = 0x432569 size = 0x14 [[func]] name = "DeltaExportMonster" addr = 0x43257D size = 0x32 [[func]] name = "DeltaExportJunk" addr = 0x4325AF size = 0x78 [[func]] name = "msg_comp_level" addr = 0x432627 size = 0x1C [[func]] name = "delta_init" addr = 0x432643 size = 0x47 [[func]] name = "delta_kill_monster" addr = 0x43268A size = 0x46 [[func]] name = "delta_monster_hp" addr = 0x4326D0 size = 0x30 [[func]] name = "delta_sync_monster" addr = 0x432700 size = 0x42 [[func]] name = "delta_sync_golem" addr = 0x432742 size = 0x49 [[func]] name = "delta_leave_sync" addr = 0x43278B size = 0xD2 [[func]] name = "delta_portal_inited" addr = 0x43285D size = 0xE [[func]] name = "delta_quest_inited" addr = 0x43286B size = 0xE [[func]] name = "DeltaAddItem" addr = 0x432879 size = 0x107 [[func]] name = "DeltaSaveLevel" addr = 0x432980 size = 0x48 [[func]] name = "DeltaLoadLevel" addr = 0x4329C8 size = 0x4B9 [[func]] name = "NetSendCmd" addr = 0x432E81 size = 0x1E [[func]] name = "NetSendCmdGolem" addr = 0x432E9F size = 0x36 [[func]] name = "NetSendCmdLoc" addr = 0x432ED5 size = 0x2C [[func]] name = "NetSendCmdLocParam1" addr = 0x432F01 size = 0x35 [[func]] name = "NetSendCmdLocParam2" addr = 0x432F36 size = 0x3D [[func]] name = "NetSendCmdLocParam3" addr = 0x432F73 size = 0x46 [[func]] name = "NetSendCmdParam1" addr = 0x432FB9 size = 0x28 [[func]] name = "NetSendCmdParam2" addr = 0x432FE1 size = 0x31 [[func]] name = "NetSendCmdParam3" addr = 0x433012 size = 0x39 [[func]] name = "NetSendCmdQuest" addr = 0x43304B size = 0x47 [[func]] name = "NetSendCmdGItem" addr = 0x433092 size = 0x185 [[func]] name = "NetSendCmdGItem2" addr = 0x433217 size = 0x6B [[func]] name = "NetSendCmdReq2" addr = 0x433282 size = 0x5B [[func]] name = "NetSendCmdExtra" addr = 0x4332DD size = 0x29 [[func]] name = "NetSendCmdPItem" addr = 0x433306 size = 0x163 [[func]] name = "NetSendCmdChItem" addr = 0x433469 size = 0x57 [[func]] name = "NetSendCmdDelItem" addr = 0x4334C0 size = 0x22 [[func]] name = "NetSendCmdDItem" addr = 0x4334E2 size = 0x165 [[func]] name = "NetSendCmdDamage" addr = 0x433647 size = 0x2B [[func]] name = "NetSendCmdString" addr = 0x433672 size = 0x39 [[func]] name = "delta_close_portal" addr = 0x4336AB size = 0x1F [[func]] name = "ParseCmd" addr = 0x4336CA size = 0x33F [[func]] name = "On_DLEVEL" addr = 0x433B7D size = 0xC3 [[func]] name = "DeltaImportData" addr = 0x433C40 size = 0x88 [[func]] name = "DeltaImportItem" addr = 0x433CC8 size = 0x3B [[func]] name = "DeltaImportObject" addr = 0x433D03 size = 0x14 [[func]] name = "DeltaImportMonster" addr = 0x433D17 size = 0x3D [[func]] name = "DeltaImportJunk" addr = 0x433D54 size = 0xAB [[func]] name = "On_SYNCDATA" addr = 0x433DFF size = 0xB [[func]] name = "On_WALKXY" addr = 0x433E0A size = 0x4E [[func]] name = "On_ADDSTR" addr = 0x433E58 size = 0x31 [[func]] name = "On_ADDMAG" addr = 0x433E89 size = 0x31 [[func]] name = "On_ADDDEX" addr = 0x433EBA size = 0x31 [[func]] name = "On_ADDVIT" addr = 0x433EEB size = 0x31 [[func]] name = "On_SBSPELL" addr = 0x433F1C size = 0x6F [[func]] name = "msg_errorf" addr = 0x433F8B size = 0x47 [[func]] name = "On_GOTOGETITEM" addr = 0x433FD2 size = 0x52 [[func]] name = "On_REQUESTGITEM" addr = 0x434024 size = 0xD0 [[func]] name = "i_own_level" addr = 0x4340F4 size = 0x47 [[func]] name = "On_GETITEM" addr = 0x43413B size = 0x110 [[func]] name = "delta_get_item" addr = 0x43424B size = 0x103 [[func]] name = "On_GOTOAGETITEM" addr = 0x43434E size = 0x52 [[func]] name = "On_REQUESTAGITEM" addr = 0x4343A0 size = 0xCE [[func]] name = "On_AGETITEM" addr = 0x43446E size = 0x10E [[func]] name = "On_ITEMEXTRA" addr = 0x43457C size = 0x5B [[func]] name = "On_PUTITEM" addr = 0x4345D7 size = 0x105 [[func]] name = "delta_put_item" addr = 0x4346DC size = 0xAB [[func]] name = "check_update_plr" addr = 0x434787 size = 0x1A [[func]] name = "On_SYNCPUTITEM" addr = 0x4347A1 size = 0xF1 [[func]] name = "On_RESPAWNITEM" addr = 0x434892 size = 0xA6 [[func]] name = "On_ATTACKXY" addr = 0x434938 size = 0x5C [[func]] name = "On_SATTACKXY" addr = 0x434994 size = 0x4F [[func]] name = "On_RATTACKXY" addr = 0x4349E3 size = 0x4F [[func]] name = "On_SPELLXYD" addr = 0x434A32 size = 0xAE [[func]] name = "On_SPELLXY" addr = 0x434AE0 size = 0xA4 [[func]] name = "On_TSPELLXY" addr = 0x434B84 size = 0xA4 [[func]] name = "On_OPOBJXY" addr = 0x434C28 size = 0x70 [[func]] name = "On_DISARMXY" addr = 0x434C98 size = 0x70 [[func]] name = "On_OPOBJT" addr = 0x434D08 size = 0x38 [[func]] name = "On_ATTACKID" addr = 0x434D40 size = 0xAD [[func]] name = "On_ATTACKPID" addr = 0x434DED size = 0x61 [[func]] name = "On_RATTACKID" addr = 0x434E4E size = 0x45 [[func]] name = "On_RATTACKPID" addr = 0x434E93 size = 0x45 [[func]] name = "On_SPELLID" addr = 0x434ED8 size = 0x9A [[func]] name = "On_SPELLPID" addr = 0x434F72 size = 0x9A [[func]] name = "On_TSPELLID" addr = 0x43500C size = 0x9A [[func]] name = "On_TSPELLPID" addr = 0x4350A6 size = 0x9A [[func]] name = "On_KNOCKBACK" addr = 0x435140 size = 0x42 [[func]] name = "On_RESURRECT" addr = 0x435182 size = 0x30 [[func]] name = "On_HEALOTHER" addr = 0x4351B2 size = 0x31 [[func]] name = "On_TALKXY" addr = 0x4351E3 size = 0x52 [[func]] name = "On_NEWLVL" addr = 0x435235 size = 0x34 [[func]] name = "On_WARP" addr = 0x435269 size = 0x5F [[func]] name = "On_MONSTDEATH" addr = 0x4352C8 size = 0x69 [[func]] name = "On_KILLGOLEM" addr = 0x435331 size = 0x66 [[func]] name = "On_AWAKEGOLEM" addr = 0x435397 size = 0xB4 [[func]] name = "On_MONSTDAMAGE" addr = 0x43544B size = 0xB8 [[func]] name = "On_PLRDEAD" addr = 0x435503 size = 0x38 [[func]] name = "On_PLRDAMAGE" addr = 0x43553B size = 0xB0 [[func]] name = "On_OPENDOOR" addr = 0x4355EB size = 0x56 [[func]] name = "delta_sync_object" addr = 0x435641 size = 0x25 [[func]] name = "On_CLOSEDOOR" addr = 0x435666 size = 0x56 [[func]] name = "On_OPERATEOBJ" addr = 0x4356BC size = 0x56 [[func]] name = "On_PLROPOBJ" addr = 0x435712 size = 0x58 [[func]] name = "On_BREAKOBJ" addr = 0x43576A size = 0x54 [[func]] name = "On_CHANGEPLRITEMS" addr = 0x4357BE size = 0x40 [[func]] name = "On_DELPLRITEMS" addr = 0x4357FE size = 0x2E [[func]] name = "On_PLRLEVEL" addr = 0x43582C size = 0x3A [[func]] name = "On_DROPITEM" addr = 0x435866 size = 0x37 [[func]] name = "On_SEND_PLRINFO" addr = 0x43589D size = 0x3A [[func]] name = "On_ACK_PLRINFO" addr = 0x4358D7 size = 0x5 [[func]] name = "On_PLAYER_JOINLEVEL" addr = 0x4358DC size = 0x17A [[func]] name = "On_ACTIVATEPORTAL" addr = 0x435A56 size = 0xD9 [[func]] name = "delta_open_portal" addr = 0x435B2F size = 0x3B [[func]] name = "On_DEACTIVATEPORTAL" addr = 0x435B6A size = 0x3E [[func]] name = "On_RETOWN" addr = 0x435BA8 size = 0x39 [[func]] name = "On_SETSTR" addr = 0x435BE1 size = 0x39 [[func]] name = "On_SETDEX" addr = 0x435C1A size = 0x39 [[func]] name = "On_SETMAG" addr = 0x435C53 size = 0x39 [[func]] name = "On_SETVIT" addr = 0x435C8C size = 0x39 [[func]] name = "On_STRING" addr = 0x435CC5 size = 0xB [[func]] name = "On_STRING2" addr = 0x435CD0 size = 0x2A [[func]] name = "On_SYNCQUEST" addr = 0x435CFA size = 0x42 [[func]] name = "On_ENDSHIELD" addr = 0x435D3C size = 0x77 [[func]] name = "On_CHEAT_EXPERIENCE" addr = 0x435E53 size = 0x4 [[func]] name = "On_CHEAT_SPELL_LEVEL" addr = 0x435E53 size = 0x4 [[func]] name = "On_DEBUG" addr = 0x435E53 size = 0x4 [[func]] name = "On_NOVA" addr = 0x435DB3 size = 0x6F [[func]] name = "On_SETSHIELD" addr = 0x435E22 size = 0x18 [[func]] name = "On_REMSHIELD" addr = 0x435E3A size = 0x19 [[func]] name = "msgcmd_cmd_cleanup" addr = 0x435E9B size = 0xA [[func]] name = "msgcmd_send_chat" addr = 0x435EA5 size = 0x3D [[func]] name = "msgcmd_add_server_cmd_W" addr = 0x435EE2 size = 0x11 [[func]] name = "msgcmd_add_server_cmd" addr = 0x435EF3 size = 0x3B [[func]] name = "TList::TList" addr = 0x435F2E size = 0x16 [[func]] name = "TList::DeleteAll" addr = 0x435F44 size = 0x28 [[func]] name = "TList::Remove" addr = 0x435F6C size = 0x3B [[func]] name = "TList::Create" addr = 0x435FA7 size = 0x4C [[func]] name = "EXTERNMESSAGE::Delete" addr = 0x435FF3 size = 0x2F [[func]] name = "TList::Insert" addr = 0x436022 size = 0x71 [[func]] name = "TList::UnlinkAll" addr = 0x436093 size = 0x13 [[func]] name = "TLink::Unlink" addr = 0x4360A6 size = 0x2C [[func]] name = "multi_msg_add" addr = 0x4360E2 size = 0xE [[func]] name = "NetSendLoPri" addr = 0x4360F0 size = 0x29 [[func]] name = "multi_copy_packet" addr = 0x436119 size = 0x42 [[func]] name = "multi_send_packet" addr = 0x43615B size = 0x68 [[func]] name = "NetRecvPlrData" addr = 0x4361C3 size = 0xBA [[func]] name = "NetSendHiPri" addr = 0x43627D size = 0xB8 [[func]] name = "multi_recv_packet" addr = 0x436335 size = 0x69 [[func]] name = "multi_send_msg_packet" addr = 0x43639E size = 0x7E [[func]] name = "multi_msg_countdown" addr = 0x43641C size = 0x2F [[func]] name = "multi_parse_turn" addr = 0x43644B size = 0x48 [[func]] name = "multi_handle_turn_upper_bit" addr = 0x436493 size = 0x32 [[func]] name = "multi_player_left" addr = 0x4364C5 size = 0x13 [[func]] name = "multi_clear_left_tbl" addr = 0x4364D8 size = 0x44 [[func]] name = "multi_player_left_msg" addr = 0x43651C size = 0x8F [[func]] name = "multi_net_ping" addr = 0x4365AB size = 0x13 [[func]] name = "multi_handle_delta" addr = 0x4365BE size = 0xA8 [[func]] name = "multi_check_pkt_valid" addr = 0x436666 size = 0x8 [[func]] name = "multi_mon_seeds" addr = 0x43666E size = 0x33 [[func]] name = "multi_begin_timeout" addr = 0x4366A1 size = 0x95 [[func]] name = "multi_check_drop_player" addr = 0x436736 size = 0x2B [[func]] name = "multi_process_network_packets" addr = 0x436761 size = 0x2CA [[func]] name = "multi_handle_all_packets" addr = 0x436A2B size = 0x27 [[func]] name = "multi_process_tmsgs" addr = 0x436A52 size = 0x33 [[func]] name = "multi_send_zero_packet" addr = 0x436A85 size = 0xE6 [[func]] name = "NetClose" addr = 0x436B6B size = 0x47 [[func]] name = "multi_event_handler" addr = 0x436BB2 size = 0x48 [[func]] name = "multi_handle_events" addr = 0x436BFA size = 0xA8 [[func]] name = "NetInit" addr = 0x436CA2 size = 0x2FE [[func]] name = "buffer_init" addr = 0x436FA0 size = 0x8 [[func]] name = "multi_send_pinfo" addr = 0x436FA8 size = 0x3B [[func]] name = "InitLevelType" addr = 0x436FE3 size = 0x30 [[func]] name = "SetupLocalCoords" addr = 0x437013 size = 0x96 [[func]] name = "multi_init_single" addr = 0x4370A9 size = 0x6E [[func]] name = "multi_init_multi" addr = 0x437117 size = 0xD2 [[func]] name = "multi_upgrade" addr = 0x4371E9 size = 0x3C [[func]] name = "recv_plrinfo" addr = 0x437225 size = 0x197 [[func]] name = "nthread_terminate_game" addr = 0x4373FA size = 0x3C [[func]] name = "nthread_send_and_recv_turn" addr = 0x437436 size = 0x82 [[func]] name = "nthread_recv_turns" addr = 0x4374B8 size = 0xAC [[func]] name = "nthread_set_turn_upper_bit" addr = 0x437564 size = 0xB [[func]] name = "nthread_start" addr = 0x43756F size = 0x16E [[func]] name = "nthread_handler" addr = 0x4376DD size = 0x76 [[func]] name = "nthread_cleanup" addr = 0x437753 size = 0x7F [[func]] name = "nthread_ignore_mutex" addr = 0x4377D2 size = 0x2B [[func]] name = "nthread_has_500ms_passed" addr = 0x4377FD size = 0x2E [[func]] name = "InitObjectGFX" addr = 0x43782B size = 0xFA [[func]] name = "FreeObjectGFX" addr = 0x437925 size = 0x2E [[func]] name = "RndLocOk" addr = 0x437953 size = 0x5B [[func]] name = "InitRndLocObj" addr = 0x4379AE size = 0xD7 [[func]] name = "InitRndLocBigObj" addr = 0x437A85 size = 0x10D [[func]] name = "InitRndLocObj5x5" addr = 0x437B92 size = 0xB7 [[func]] name = "ClrAllObjects" addr = 0x437C49 size = 0x6D [[func]] name = "AddTortures" addr = 0x437CB6 size = 0xF7 [[func]] name = "AddCandles" addr = 0x437DAD size = 0x49 [[func]] name = "AddBookLever" addr = 0x437DF6 size = 0x11C [[func]] name = "InitRndBarrels" addr = 0x437F12 size = 0xFC [[func]] name = "AddL1Objs" addr = 0x43800E size = 0x98 [[func]] name = "AddL2Objs" addr = 0x4380A6 size = 0x7E [[func]] name = "AddL3Objs" addr = 0x438124 size = 0x74 [[func]] name = "WallTrapLocOk" addr = 0x438198 size = 0x16 [[func]] name = "AddL2Torches" addr = 0x4381AE size = 0xEC [[func]] name = "TorchLocOK" addr = 0x43829A size = 0x27 [[func]] name = "AddObjTraps" addr = 0x4382C1 size = 0x1A5 [[func]] name = "AddChestTraps" addr = 0x438466 size = 0x8C [[func]] name = "LoadMapObjects" addr = 0x4384F2 size = 0xCB [[func]] name = "LoadMapObjs" addr = 0x4385BD size = 0x87 [[func]] name = "AddDiabObjs" addr = 0x438644 size = 0xBC [[func]] name = "AddStoryBooks" addr = 0x438700 size = 0xD8 [[func]] name = "AddHookedBodies" addr = 0x4387D8 size = 0xD5 [[func]] name = "AddL4Goodies" addr = 0x4388AD size = 0x77 [[func]] name = "AddLazStand" addr = 0x438924 size = 0x102 [[func]] name = "InitObjects" addr = 0x438A26 size = 0x3AD [[func]] name = "DeleteObject_" addr = 0x438DD3 size = 0x50 [[func]] name = "SetupObject" addr = 0x438E23 size = 0x122 [[func]] name = "SetObjMapRange" addr = 0x438F45 size = 0x34 [[func]] name = "SetBookMsg" addr = 0x438F79 size = 0xA [[func]] name = "AddL1Door" addr = 0x438F83 size = 0x51 [[func]] name = "AddSCambBook" addr = 0x438FD4 size = 0x49 [[func]] name = "AddChest" addr = 0x43901D size = 0xB2 [[func]] name = "AddL2Door" addr = 0x4390CF size = 0x3B [[func]] name = "AddL3Door" addr = 0x43910A size = 0x3B [[func]] name = "AddSarc" addr = 0x439145 size = 0x51 [[func]] name = "AddFlameTrap" addr = 0x439196 size = 0x28 [[func]] name = "AddFlameLvr" addr = 0x4391BE size = 0x19 [[func]] name = "AddTrap" addr = 0x4391D7 size = 0x5B [[func]] name = "AddObjLight" addr = 0x439232 size = 0x37 [[func]] name = "AddBarrel" addr = 0x439269 size = 0x4E [[func]] name = "AddShrine" addr = 0x4392B7 size = 0xA3 [[func]] name = "AddBookcase" addr = 0x43935A size = 0x1D [[func]] name = "AddPurifyingFountain" addr = 0x43938A size = 0x39 [[func]] name = "AddArmorStand" addr = 0x4393C3 size = 0x32 [[func]] name = "AddDecap" addr = 0x4393F5 size = 0x2E [[func]] name = "AddVilebook" addr = 0x439423 size = 0x20 [[func]] name = "AddMagicCircle" addr = 0x439443 size = 0x29 [[func]] name = "AddBookstand" addr = 0x439377 size = 0x13 [[func]] name = "AddPedistal" addr = 0x43946C size = 0x38 [[func]] name = "AddStoryBook" addr = 0x4394A4 size = 0x92 [[func]] name = "AddWeaponRack" addr = 0x439536 size = 0x32 [[func]] name = "AddTorturedBody" addr = 0x439568 size = 0x2E [[func]] name = "GetRndObjLoc" addr = 0x439596 size = 0x8A [[func]] name = "AddMushPatch" addr = 0x439620 size = 0x5C [[func]] name = "AddSlainHero" addr = 0x43967C size = 0x2B [[func]] name = "AddObject" addr = 0x4396A7 size = 0x1EB [[func]] name = "Obj_Light" addr = 0x439973 size = 0xEA [[func]] name = "Obj_Circle" addr = 0x439A5D size = 0x172 [[func]] name = "Obj_StopAnim" addr = 0x439BCF size = 0x23 [[func]] name = "Obj_Door" addr = 0x439BF2 size = 0x83 [[func]] name = "Obj_Sarc" addr = 0x439C75 size = 0x19 [[func]] name = "ActivateTrapLine" addr = 0x439C8E size = 0x6F [[func]] name = "Obj_FlameTrap" addr = 0x439CFD size = 0x111 [[func]] name = "Obj_Trap" addr = 0x439E0E size = 0x16F [[func]] name = "Obj_BCrossDamage" addr = 0x439F7D size = 0xE7 [[func]] name = "ProcessObjects" addr = 0x43A064 size = 0x197 [[func]] name = "ObjSetMicro" addr = 0x43A1FB size = 0x81 [[func]] name = "objects_set_door_piece" addr = 0x43A27C size = 0x78 [[func]] name = "ObjSetMini" addr = 0x43A2F4 size = 0x78 [[func]] name = "ObjL1Special" addr = 0x43A36C size = 0xEC [[func]] name = "ObjL2Special" addr = 0x43A458 size = 0xFC [[func]] name = "DoorSet" addr = 0x43A554 size = 0x184 [[func]] name = "RedoPlayerVision" addr = 0x43A6D8 size = 0x35 [[func]] name = "OperateL1RDoor" addr = 0x43A70D size = 0x1C1 [[func]] name = "OperateL1LDoor" addr = 0x43A8CE size = 0x1D7 [[func]] name = "OperateL2RDoor" addr = 0x43AAA5 size = 0x162 [[func]] name = "OperateL2LDoor" addr = 0x43AC07 size = 0x162 [[func]] name = "OperateL3RDoor" addr = 0x43AD69 size = 0x165 [[func]] name = "OperateL3LDoor" addr = 0x43AECE size = 0x165 [[func]] name = "MonstCheckDoors" addr = 0x43B033 size = 0x222 [[func]] name = "ObjChangeMap" addr = 0x43B255 size = 0xDB [[func]] name = "ObjChangeMapResync" addr = 0x43B330 size = 0xB1 [[func]] name = "OperateL1Door" addr = 0x43B3E1 size = 0x8F [[func]] name = "OperateLever" addr = 0x43B470 size = 0xCE [[func]] name = "OperateBook" addr = 0x43B53E size = 0x225 [[func]] name = "OperateBookLever" addr = 0x43B763 size = 0x1B2 [[func]] name = "OperateSChambBk" addr = 0x43B915 size = 0xD7 [[func]] name = "OperateChest" addr = 0x43B9EC size = 0x189 [[func]] name = "OperateMushPatch" addr = 0x43BB75 size = 0xBD [[func]] name = "OperateInnSignChest" addr = 0x43BC32 size = 0xB0 [[func]] name = "OperateSlainHero" addr = 0x43BCE2 size = 0xA5 [[func]] name = "OperateTrapLvr" addr = 0x43BD87 size = 0xB7 [[func]] name = "OperateSarc" addr = 0x43BE3E size = 0xD1 [[func]] name = "OperateL2Door" addr = 0x43BF0F size = 0x90 [[func]] name = "OperateL3Door" addr = 0x43BF9F size = 0x90 [[func]] name = "OperatePedistal" addr = 0x43C02F size = 0x163 [[func]] name = "TryDisarm" addr = 0x43C192 size = 0xD4 [[func]] name = "ItemMiscIdIdx" addr = 0x43C266 size = 0x18 [[func]] name = "OperateShrine" addr = 0x43C27E size = 0xFB7 [[func]] name = "OperateSkelBook" addr = 0x43D29D size = 0x9E [[func]] name = "OperateBookCase" addr = 0x43D33B size = 0xE0 [[func]] name = "OperateDecap" addr = 0x43D41B size = 0x5E [[func]] name = "OperateArmorStand" addr = 0x43D479 size = 0xC6 [[func]] name = "FindValidShrine" addr = 0x43D53F size = 0x53 [[func]] name = "OperateGoatShrine" addr = 0x43D592 size = 0x4B [[func]] name = "OperateCauldron" addr = 0x43D5DD size = 0x52 [[func]] name = "OperateFountains" addr = 0x43D62F size = 0x2B1 [[func]] name = "OperateWeaponRack" addr = 0x43D8E0 size = 0xAB [[func]] name = "OperateStoryBook" addr = 0x43D98B size = 0x63 [[func]] name = "OperateLazStand" addr = 0x43D9EE size = 0x65 [[func]] name = "OperateObject" addr = 0x43DA53 size = 0x249 [[func]] name = "SyncOpL1Door" addr = 0x43DD65 size = 0x71 [[func]] name = "SyncOpL2Door" addr = 0x43DDD6 size = 0x72 [[func]] name = "SyncOpL3Door" addr = 0x43DE48 size = 0x72 [[func]] name = "SyncOpObject" addr = 0x43DEBA size = 0xED [[func]] name = "BreakCrux" addr = 0x43E060 size = 0xC2 [[func]] name = "BreakBarrel" addr = 0x43E122 size = 0x274 [[func]] name = "BreakObject" addr = 0x43E396 size = 0x8C [[func]] name = "SyncBreakObj" addr = 0x43E422 size = 0x21 [[func]] name = "SyncL1Doors" addr = 0x43E443 size = 0xAB [[func]] name = "SyncCrux" addr = 0x43E4EE size = 0x7E [[func]] name = "SyncLever" addr = 0x43E56C size = 0x2A [[func]] name = "SyncQSTLever" addr = 0x43E596 size = 0x6F [[func]] name = "SyncPedistal" addr = 0x43E605 size = 0xC6 [[func]] name = "SyncL2Doors" addr = 0x43E6CB size = 0x86 [[func]] name = "SyncL3Doors" addr = 0x43E751 size = 0x92 [[func]] name = "SyncObjectAnim" addr = 0x43E7E3 size = 0xAE [[func]] name = "GetObjectStr" addr = 0x43E891 size = 0x20E [[func]] name = "PackPlayer" addr = 0x43EB98 size = 0x1EE [[func]] name = "PackItem" addr = 0x43ED86 size = 0x10B [[func]] name = "VerifyGoldSeeds" addr = 0x43EE91 size = 0x72 [[func]] name = "UnPackPlayer" addr = 0x43EF03 size = 0x278 [[func]] name = "UnPackItem" addr = 0x43F17B size = 0xAD [[func]] name = "SaveGamma" addr = 0x43F238 size = 0x2E [[func]] name = "palette_init" addr = 0x43F266 size = 0x78 [[func]] name = "LoadGamma" addr = 0x43F2DE size = 0x75 [[func]] name = "LoadSysPal" addr = 0x43F353 size = 0xA9 [[func]] name = "LoadPalette" addr = 0x43F3FC size = 0x5C [[func]] name = "LoadRndLvlPal" addr = 0x43F458 size = 0x47 [[func]] name = "ResetPal" addr = 0x43F49F size = 0x2B [[func]] name = "IncreaseGamma" addr = 0x43F4CA size = 0x39 [[func]] name = "palette_update" addr = 0x43F503 size = 0x37 [[func]] name = "ApplyGamma" addr = 0x43F53A size = 0xC9 [[func]] name = "DecreaseGamma" addr = 0x43F603 size = 0x39 [[func]] name = "UpdateGamma" addr = 0x43F63C size = 0x35 [[func]] name = "BlackPalette" addr = 0x43F671 size = 0x7 [[func]] name = "SetFadeLevel" addr = 0x43F678 size = 0x6B [[func]] name = "PaletteFadeIn" addr = 0x43F6E3 size = 0x56 [[func]] name = "PaletteFadeOut" addr = 0x43F739 size = 0x30 [[func]] name = "palette_update_caves" addr = 0x43F769 size = 0x62 [[func]] name = "palette_get_colour_cycling" addr = 0x43F7CB size = 0x6 [[func]] name = "palette_set_color_cycling" addr = 0x43F7D1 size = 0x8 [[func]] name = "FindPath" addr = 0x43F7D9 size = 0xFF [[func]] name = "path_get_h_cost" addr = 0x43F8D8 size = 0x31 [[func]] name = "path_check_equal" addr = 0x43F909 size = 0x18 [[func]] name = "GetNextPath" addr = 0x43F921 size = 0x2A [[func]] name = "path_solid_pieces" addr = 0x43F94B size = 0xA7 [[func]] name = "path_get_path" addr = 0x43F9F2 size = 0x82 [[func]] name = "path_parent_path" addr = 0x43FA74 size = 0x12B [[func]] name = "path_get_node1" addr = 0x43FB9F size = 0x19 [[func]] name = "path_get_node2" addr = 0x43FBB8 size = 0x19 [[func]] name = "path_next_node" addr = 0x43FBD1 size = 0x2B [[func]] name = "path_set_coords" addr = 0x43FBFC size = 0x99 [[func]] name = "path_push_active_step" addr = 0x43FC95 size = 0x13 [[func]] name = "path_pop_active_step" addr = 0x43FCA8 size = 0x13 [[func]] name = "path_new_step" addr = 0x43FCBB size = 0x36 [[func]] name = "pfile_init_save_directory" addr = 0x43FD01 size = 0x5F [[func]] name = "pfile_check_available_space" addr = 0x43FD60 size = 0x68 [[func]] name = "pfile_write_hero" addr = 0x43FDC8 size = 0x70 [[func]] name = "pfile_get_save_num_from_name" addr = 0x43FE38 size = 0x28 [[func]] name = "pfile_encode_hero" addr = 0x43FE60 size = 0x84 [[func]] name = "pfile_open_archive" addr = 0x43FEE4 size = 0x51 [[func]] name = "pfile_get_save_path" addr = 0x43FF35 size = 0x82 [[func]] name = "pfile_flush" addr = 0x43FFB7 size = 0x32 [[func]] name = "pfile_create_player_description" addr = 0x43FFE9 size = 0x76 [[func]] name = "pfile_rename_hero" addr = 0x44005F size = 0xC8 [[func]] name = "pfile_flush_W" addr = 0x440127 size = 0x21 [[func]] name = "game_2_ui_player" addr = 0x440148 size = 0x90 [[func]] name = "game_2_ui_class" addr = 0x4401D8 size = 0x13 [[func]] name = "pfile_ui_set_hero_infos" addr = 0x4401EB size = 0x1C7 [[func]] name = "GetSaveDirectory" addr = 0x4403B2 size = 0x8C [[func]] name = "pfile_read_hero" addr = 0x44043E size = 0x122 [[func]] name = "pfile_open_save_archive" addr = 0x440560 size = 0x3A [[func]] name = "pfile_SFileCloseArchive" addr = 0x44059A size = 0x7 [[func]] name = "pfile_archive_contains_game" addr = 0x4405A1 size = 0x33 [[func]] name = "pfile_ui_set_class_stats" addr = 0x4405D4 size = 0x44 [[func]] name = "pfile_get_player_class" addr = 0x440618 size = 0x10 [[func]] name = "pfile_ui_save_create" addr = 0x440628 size = 0xDF [[func]] name = "pfile_get_file_name" addr = 0x440707 size = 0x57 [[func]] name = "pfile_delete_save" addr = 0x44075E size = 0x4A [[func]] name = "pfile_read_player_from_save" addr = 0x4407A8 size = 0x79 [[func]] name = "GetTempLevelNames" addr = 0x440821 size = 0x4A [[func]] name = "GetPermLevelNames" addr = 0x44086B size = 0x86 [[func]] name = "pfile_get_game_name" addr = 0x4408F1 size = 0x29 [[func]] name = "pfile_remove_temp_files" addr = 0x44091A size = 0x51 [[func]] name = "GetTempSaveNames" addr = 0x44096B size = 0x35 [[func]] name = "pfile_rename_temp_to_perm" addr = 0x4409A0 size = 0xAC [[func]] name = "GetPermSaveNames" addr = 0x440A4C size = 0x35 [[func]] name = "pfile_write_save_file" addr = 0x440A81 size = 0xAE [[func]] name = "pfile_strcpy" addr = 0x440B2F size = 0xA [[func]] name = "pfile_read" addr = 0x440B39 size = 0x182 [[func]] name = "pfile_update" addr = 0x440CBB size = 0x33 [[func]] name = "SetPlayerGPtrs" addr = 0x440CFE size = 0x1B [[func]] name = "LoadPlrGFX" addr = 0x440D19 size = 0x25F [[func]] name = "InitPlayerGFX" addr = 0x440F78 size = 0x44 [[func]] name = "InitPlrGFXMem" addr = 0x440FBC size = 0x214 [[func]] name = "GetPlrGFXSize" addr = 0x4411D0 size = 0xC9 [[func]] name = "FreePlayerGFX" addr = 0x441299 size = 0xAE [[func]] name = "NewPlrAnim" addr = 0x441347 size = 0x65 [[func]] name = "ClearPlrPVars" addr = 0x4413AC size = 0x51 [[func]] name = "SetPlrAnims" addr = 0x4413FD size = 0x172 [[func]] name = "ClearPlrRVars" addr = 0x44156F size = 0x77 [[func]] name = "CreatePlayer" addr = 0x4415E6 size = 0x2CB [[func]] name = "CalcStatDiff" addr = 0x4418B1 size = 0x41 [[func]] name = "NextPlrLevel" addr = 0x4418F2 size = 0x105 [[func]] name = "AddPlrExperience" addr = 0x4419F7 size = 0x130 [[func]] name = "AddPlrMonstExper" addr = 0x441B27 size = 0x44 [[func]] name = "InitPlayer" addr = 0x441B6B size = 0x2D2 [[func]] name = "InitMultiView" addr = 0x441E3D size = 0x3A [[func]] name = "CheckEFlag" addr = 0x441E77 size = 0x155 [[func]] name = "SolidLoc" addr = 0x441FCC size = 0x29 [[func]] name = "PlrDirOK" addr = 0x441FF5 size = 0xAF [[func]] name = "PlrClrTrans" addr = 0x4420A4 size = 0x43 [[func]] name = "PlrDoTrans" addr = 0x4420E7 size = 0x81 [[func]] name = "SetPlayerOld" addr = 0x442168 size = 0x37 [[func]] name = "FixPlayerLocation" addr = 0x44219F size = 0x98 [[func]] name = "StartStand" addr = 0x442237 size = 0xBB [[func]] name = "StartWalkStand" addr = 0x4422F2 size = 0x88 [[func]] name = "PM_ChangeLightOff" addr = 0x44237A size = 0xCD [[func]] name = "PM_ChangeOffset" addr = 0x442447 size = 0xA5 [[func]] name = "StartWalk" addr = 0x4424EC size = 0x1CA [[func]] name = "StartWalk2" addr = 0x4426B6 size = 0x223 [[func]] name = "StartWalk3" addr = 0x4428D9 size = 0x24F [[func]] name = "StartAttack" addr = 0x442B28 size = 0x9D [[func]] name = "StartRangeAttack" addr = 0x442BC5 size = 0xB8 [[func]] name = "StartPlrBlock" addr = 0x442C7D size = 0xB3 [[func]] name = "StartSpell" addr = 0x442D30 size = 0x16F [[func]] name = "FixPlrWalkTags" addr = 0x442E9F size = 0xCD [[func]] name = "RemovePlrFromMap" addr = 0x442F6C size = 0x76 [[func]] name = "StartPlrHit" addr = 0x442FE2 size = 0x10E [[func]] name = "RespawnDeadItem" addr = 0x4430F0 size = 0xCC [[func]] name = "StartPlayerKill" addr = 0x4431BC size = 0x30E [[func]] name = "PlrDeadItem" addr = 0x4434CA size = 0xFF [[func]] name = "DropHalfPlayersGold" addr = 0x4435C9 size = 0x418 [[func]] name = "SyncPlrKill" addr = 0x4439E1 size = 0x90 [[func]] name = "RemovePlrMissiles" addr = 0x443A76 size = 0x131 [[func]] name = "InitLevelChange" addr = 0x443BA7 size = 0xA2 [[func]] name = "StartNewLvl" addr = 0x443C49 size = 0xFC [[func]] name = "RestartTownLvl" addr = 0x443D45 size = 0x8D [[func]] name = "StartWarpLvl" addr = 0x443DD2 size = 0x78 [[func]] name = "PM_DoStand" addr = 0x443E4A size = 0x3 [[func]] name = "PM_DoWalk" addr = 0x443E4D size = 0x16E [[func]] name = "PM_DoWalk2" addr = 0x443FBB size = 0x14B [[func]] name = "PM_DoWalk3" addr = 0x444106 size = 0x181 [[func]] name = "WeaponDur" addr = 0x444287 size = 0x10B [[func]] name = "PlrHitMonst" addr = 0x444392 size = 0x386 [[func]] name = "PlrHitPlr" addr = 0x444718 size = 0x227 [[func]] name = "PlrHitObj" addr = 0x44493F size = 0x3D [[func]] name = "PM_DoAttack" addr = 0x44497C size = 0x212 [[func]] name = "PM_DoRangeAttack" addr = 0x444B8E size = 0xF4 [[func]] name = "ShieldDur" addr = 0x444C82 size = 0xA1 [[func]] name = "PM_DoBlock" addr = 0x444D23 size = 0x79 [[func]] name = "PM_DoSpell" addr = 0x444D9C size = 0x140 [[func]] name = "PM_DoGotHit" addr = 0x444EDC size = 0xB6 [[func]] name = "ArmorDur" addr = 0x444F92 size = 0xBF [[func]] name = "PM_DoDeath" addr = 0x445051 size = 0xA7 [[func]] name = "PM_DoNewLvl" addr = 0x443E4A size = 0x3 [[func]] name = "CheckNewPath" addr = 0x4450F8 size = 0xB30 [[func]] name = "PlrDeathModeOK" addr = 0x445C90 size = 0x42 [[func]] name = "ValidatePlayer" addr = 0x445CD2 size = 0x136 [[func]] name = "ProcessPlayers" addr = 0x445E08 size = 0x1D3 [[func]] name = "CheckCheatStats" addr = 0x446007 size = 0x59 [[func]] name = "ClrPlrPath" addr = 0x446060 size = 0x30 [[func]] name = "PosOkPlayer" addr = 0x446090 size = 0xE4 [[func]] name = "MakePlrPath" addr = 0x446174 size = 0xB1 [[func]] name = "CheckPlrSpell" addr = 0x446245 size = 0x255 [[func]] name = "SyncPlrAnim" addr = 0x44649A size = 0x126 [[func]] name = "SyncInitPlrPos" addr = 0x4465F0 size = 0x177 [[func]] name = "SyncInitPlr" addr = 0x446767 size = 0x24 [[func]] name = "CheckStats" addr = 0x44678B size = 0x119 [[func]] name = "ModifyPlrStr" addr = 0x4468A4 size = 0xBA [[func]] name = "ModifyPlrMag" addr = 0x44695E size = 0xAD [[func]] name = "ModifyPlrDex" addr = 0x446A0B size = 0xA4 [[func]] name = "ModifyPlrVit" addr = 0x446AAF size = 0xA3 [[func]] name = "SetPlayerHitPoints" addr = 0x446B52 size = 0x4F [[func]] name = "SetPlrStr" addr = 0x446BA1 size = 0x75 [[func]] name = "SetPlrMag" addr = 0x446C16 size = 0x4C [[func]] name = "SetPlrDex" addr = 0x446C62 size = 0x75 [[func]] name = "SetPlrVit" addr = 0x446CD7 size = 0x4C [[func]] name = "InitDungMsgs" addr = 0x446D23 size = 0x24 [[func]] name = "PlayDungMsgs" addr = 0x446D47 size = 0x1BA [[func]] name = "plrmsg_delay" addr = 0x446F01 size = 0x37 [[func]] name = "ErrorPlrMsg" addr = 0x446F38 size = 0x49 [[func]] name = "EventPlrMsg" addr = 0x446F81 size = 0x47 [[func]] name = "SendPlrMsg" addr = 0x446FC8 size = 0x6A [[func]] name = "ClearPlrMsg" addr = 0x447032 size = 0x2A [[func]] name = "InitPlrMsg" addr = 0x44705C size = 0x1C [[func]] name = "DrawPlrMsg" addr = 0x447078 size = 0x8D [[func]] name = "PrintPlrMsg" addr = 0x447105 size = 0xC7 [[func]] name = "InitPortals" addr = 0x4471CC size = 0x26 [[func]] name = "SetPortalStats" addr = 0x4471F2 size = 0x3E [[func]] name = "AddWarpMissile" addr = 0x447230 size = 0x74 [[func]] name = "SyncPortals" addr = 0x4472A4 size = 0x5B [[func]] name = "AddInTownPortal" addr = 0x4472FF size = 0x14 [[func]] name = "ActivatePortal" addr = 0x447313 size = 0x45 [[func]] name = "DeactivatePortal" addr = 0x447358 size = 0xC [[func]] name = "PortalOnLevel" addr = 0x447364 size = 0x22 [[func]] name = "RemovePortalMissile" addr = 0x447386 size = 0x7C [[func]] name = "SetCurrentPortal" addr = 0x447402 size = 0x7 [[func]] name = "GetPortalLevel" addr = 0x447409 size = 0xA8 [[func]] name = "GetPortalLvlPos" addr = 0x4474B1 size = 0x63 [[func]] name = "PosOkPortal" addr = 0x447514 size = 0x48 [[func]] name = "InitQuests" addr = 0x44755C size = 0x1E0 [[func]] name = "CheckQuests" addr = 0x44777C size = 0x1 [[func]] name = "ForceQuests" addr = 0x443E4A size = 0x3 [[func]] name = "QuestStatus" addr = 0x44773C size = 0x40 [[func]] name = "CheckQuestKill" addr = 0x44777C size = 0x1 [[func]] name = "DrawButcher" addr = 0x44777D size = 0x27 [[func]] name = "DrawSkelKing" addr = 0x4477A4 size = 0x21 [[func]] name = "DrawWarLord" addr = 0x4477C5 size = 0x90 [[func]] name = "DrawSChamber" addr = 0x447855 size = 0xBA [[func]] name = "DrawLTBanner" addr = 0x44790F size = 0x8C [[func]] name = "DrawBlind" addr = 0x44799B size = 0x8C [[func]] name = "DrawBlood" addr = 0x447A27 size = 0x8C [[func]] name = "DRLG_CheckQuests" addr = 0x447AB3 size = 0x91 [[func]] name = "SetReturnLvlPos" addr = 0x447B44 size = 0xB3 [[func]] name = "GetReturnLvlPos" addr = 0x447BF7 size = 0x39 [[func]] name = "ResyncMPQuests" addr = 0x44777C size = 0x1 [[func]] name = "ResyncQuests" addr = 0x44777C size = 0x1 [[func]] name = "PrintQLString" addr = 0x447C30 size = 0x14E [[func]] name = "DrawQuestLog" addr = 0x447D7E size = 0x8C [[func]] name = "StartQuestlog" addr = 0x447E0A size = 0x70 [[func]] name = "QuestlogUp" addr = 0x447E7A size = 0x47 [[func]] name = "QuestlogDown" addr = 0x447EC1 size = 0x4A [[func]] name = "QuestlogEnter" addr = 0x447F0B size = 0x42 [[func]] name = "QuestlogESC" addr = 0x447F4D size = 0x55 [[func]] name = "SetMultiQuest" addr = 0x447FA2 size = 0x3 [[func]] name = "SystemSupported" addr = 0x447FA5 size = 0x54 [[func]] name = "RestrictedTest" addr = 0x447FF9 size = 0x72 [[func]] name = "ReadOnlyTest" addr = 0x44806B size = 0x7E [[func]] name = "ClearCursor" addr = 0x4480F9 size = 0xF [[func]] name = "DrawMissile" addr = 0x448108 size = 0x196 [[func]] name = "DrawClippedMissile" addr = 0x44829E size = 0x196 [[func]] name = "DrawDeadPlayer" addr = 0x448434 size = 0xE0 [[func]] name = "DrawPlayer" addr = 0x448514 size = 0x1EB [[func]] name = "DrawClippedPlayer" addr = 0x4486FF size = 0x1D5 [[func]] name = "DrawView" addr = 0x4488D4 size = 0x112 [[func]] name = "DrawGame" addr = 0x4489E6 size = 0x1E5 [[func]] name = "scrollrt_draw_lower" addr = 0x448BEB size = 0x46B [[func]] name = "scrollrt_draw_clipped_dungeon" addr = 0x449056 size = 0x5F7 [[func]] name = "DrawClippedMonster" addr = 0x44964D size = 0xF3 [[func]] name = "DrawClippedObject" addr = 0x449740 size = 0x119 [[func]] name = "scrollrt_draw_clipped_e_flag" addr = 0x449859 size = 0x144 [[func]] name = "scrollrt_draw_lower_2" addr = 0x44999D size = 0x3A9 [[func]] name = "scrollrt_draw_clipped_dungeon_2" addr = 0x449D46 size = 0x637 [[func]] name = "scrollrt_draw_clipped_e_flag_2" addr = 0x44A37D size = 0x194 [[func]] name = "scrollrt_draw_upper" addr = 0x44A511 size = 0x47A [[func]] name = "scrollrt_draw_dungeon" addr = 0x44A98B size = 0x62D [[func]] name = "DrawMonster" addr = 0x44AFB8 size = 0xF3 [[func]] name = "DrawObject" addr = 0x44B0AB size = 0x146 [[func]] name = "scrollrt_draw_e_flag" addr = 0x44B1F1 size = 0x157 [[func]] name = "DrawZoom" addr = 0x44B348 size = 0x23E [[func]] name = "ClearScreenBuffer" addr = 0x44B5A6 size = 0x33 [[func]] name = "scrollrt_draw_game_screen" addr = 0x44B5D9 size = 0x62 [[func]] name = "scrollrt_draw_cursor_back_buffer" addr = 0x44B63B size = 0x8F [[func]] name = "scrollrt_draw_cursor_item" addr = 0x44B6CA size = 0x1CE [[func]] name = "DrawMain" addr = 0x44B898 size = 0x28F [[func]] name = "DoBlitScreen" addr = 0x44BB27 size = 0x146 [[func]] name = "DrawAndBlit" addr = 0x44BC6D size = 0x12C [[func]] name = "ObjIndex" addr = 0x44BD99 size = 0x46 [[func]] name = "SHA1Clear" addr = 0x44BDDF size = 0x15 [[func]] name = "SHA1Result" addr = 0x44BDF4 size = 0x22 [[func]] name = "SHA1Calculate" addr = 0x44BE16 size = 0x26 [[func]] name = "SHA1Input" addr = 0x44BE3C size = 0x51 [[func]] name = "SHA1ProcessMessageBlock" addr = 0x44BE8D size = 0x1BE [[func]] name = "SHA1Reset" addr = 0x44C04B size = 0xE [[func]] name = "SHA1Init" addr = 0x44C059 size = 0x2B [[func]] name = "snd_update" addr = 0x44C094 size = 0x57 [[func]] name = "snd_stop_snd" addr = 0x44C0EB size = 0x12 [[func]] name = "snd_playing" addr = 0x44C0FD size = 0x2C [[func]] name = "snd_play_snd" addr = 0x44C129 size = 0xD9 [[func]] name = "sound_dup_channel" addr = 0x44C202 size = 0x3B [[func]] name = "sound_file_reload" addr = 0x44C23D size = 0x93 [[func]] name = "sound_file_load" addr = 0x44C2D0 size = 0xFC [[func]] name = "sound_CreateSoundBuffer" addr = 0x44C3CC size = 0x5D [[func]] name = "sound_file_cleanup" addr = 0x44C429 size = 0x2B [[func]] name = "snd_init" addr = 0x44C454 size = 0xA0 [[func]] name = "snd_get_volume" addr = 0x44C4F4 size = 0x51 [[func]] name = "sound_create_primary_buffer" addr = 0x44C545 size = 0x102 [[func]] name = "sound_DirectSoundCreate" addr = 0x44C647 size = 0x81 [[func]] name = "sound_cleanup" addr = 0x44C6C8 size = 0x59 [[func]] name = "snd_set_volume" addr = 0x44C721 size = 0xF [[func]] name = "music_stop" addr = 0x44C730 size = 0x2C [[func]] name = "music_start" addr = 0x44C75C size = 0x6B [[func]] name = "sound_disable_music" addr = 0x44C7C7 size = 0x1A [[func]] name = "sound_get_or_set_music_volume" addr = 0x44C7E1 size = 0x23 [[func]] name = "sound_get_or_set_sound_volume" addr = 0x44C804 size = 0x13 [[func]] name = "GetManaAmount" addr = 0x44C817 size = 0xEC [[func]] name = "UseMana" addr = 0x44C903 size = 0x4A [[func]] name = "CheckSpell" addr = 0x44C94D size = 0x51 [[func]] name = "CastSpell" addr = 0x44C99E size = 0xDC [[func]] name = "DoResurrect" addr = 0x44CA7A size = 0x11A [[func]] name = "PlacePlayer" addr = 0x44CB94 size = 0x123 [[func]] name = "DoHealOther" addr = 0x44CCB7 size = 0x113 [[func]] name = "InitStores" addr = 0x44CDCA size = 0x86 [[func]] name = "SetupTownStores" addr = 0x44CE50 size = 0xBB [[func]] name = "FreeStoreMem" addr = 0x44CF0B size = 0x36 [[func]] name = "DrawSTextBack" addr = 0x44CF41 size = 0x5E [[func]] name = "PrintSString" addr = 0x44CF9F size = 0x20C [[func]] name = "DrawSLine" addr = 0x44D1AB size = 0x80 [[func]] name = "DrawSSlider" addr = 0x44D22B size = 0xF0 [[func]] name = "DrawSTextHelp" addr = 0x44D31B size = 0xF [[func]] name = "ClearSText" addr = 0x44D32A size = 0x45 [[func]] name = "AddSLine" addr = 0x44D36F size = 0x25 [[func]] name = "AddSTextVal" addr = 0x44D394 size = 0xD [[func]] name = "OffsetSTextY" addr = 0x44D3A1 size = 0xD [[func]] name = "AddSText" addr = 0x44D3AE size = 0x51 [[func]] name = "StoreAutoPlace" addr = 0x44D3FF size = 0x27D [[func]] name = "S_StartSmith" addr = 0x44D67C size = 0xCA [[func]] name = "S_ScrollSBuy" addr = 0x44D746 size = 0xBC [[func]] name = "PrintStoreItem" addr = 0x44D802 size = 0x27A [[func]] name = "S_StartSBuy" addr = 0x44DA7C size = 0xC0 [[func]] name = "S_ScrollSPBuy" addr = 0x44DB3C size = 0xDE [[func]] name = "S_StartSPBuy" addr = 0x44DC1A size = 0xE0 [[func]] name = "SmithSellOk" addr = 0x44DCFA size = 0x41 [[func]] name = "S_ScrollSSell" addr = 0x44DD3B size = 0xE7 [[func]] name = "S_StartSSell" addr = 0x44DE22 size = 0x1B2 [[func]] name = "SmithRepairOk" addr = 0x44DFD4 size = 0x43 [[func]] name = "S_StartSRepair" addr = 0x44E017 size = 0x24C [[func]] name = "AddStoreHoldRepair" addr = 0x44E263 size = 0xA3 [[func]] name = "S_StartWitch" addr = 0x44E306 size = 0xA6 [[func]] name = "S_ScrollWBuy" addr = 0x44E3AC size = 0xBC [[func]] name = "S_StartWBuy" addr = 0x44E468 size = 0xCA [[func]] name = "WitchSellOk" addr = 0x44E532 size = 0x5B [[func]] name = "S_StartWSell" addr = 0x44E58D size = 0x26D [[func]] name = "WitchRechargeOk" addr = 0x44E7FA size = 0x2F [[func]] name = "AddStoreHoldRecharge" addr = 0x44E829 size = 0x86 [[func]] name = "S_StartWRecharge" addr = 0x44E8AF size = 0x1AD [[func]] name = "S_StartNoMoney" addr = 0x44EA5C size = 0x3A [[func]] name = "S_StartNoRoom" addr = 0x44EA96 size = 0x33 [[func]] name = "S_StartConfirm" addr = 0x44EAC9 size = 0x173 [[func]] name = "S_StartBoy" addr = 0x44EC3C size = 0xBD [[func]] name = "S_StartBBoy" addr = 0x44ECF9 size = 0xCD [[func]] name = "S_StartHealer" addr = 0x44EDC6 size = 0xA8 [[func]] name = "S_ScrollHBuy" addr = 0x44EE6E size = 0xB0 [[func]] name = "S_StartHBuy" addr = 0x44EF1E size = 0xC0 [[func]] name = "S_StartStory" addr = 0x44EFDE size = 0x79 [[func]] name = "IdItemOk" addr = 0x44F057 size = 0x14 [[func]] name = "AddStoreHoldId" addr = 0x44F06B size = 0x44 [[func]] name = "S_StartSIdentify" addr = 0x44F0AF size = 0x2AF [[func]] name = "S_StartIdShow" addr = 0x44F35E size = 0xB1 [[func]] name = "S_StartTalk" addr = 0x44F40F size = 0xBE [[func]] name = "S_StartTavern" addr = 0x44F4CD size = 0x84 [[func]] name = "S_StartBarMaid" addr = 0x44F551 size = 0x72 [[func]] name = "S_StartDrunk" addr = 0x44F5C3 size = 0x72 [[func]] name = "StartStore" addr = 0x44F635 size = 0x163 [[func]] name = "DrawSText" addr = 0x44F7F4 size = 0xF5 [[func]] name = "STextESC" addr = 0x44F8E9 size = 0xE0 [[func]] name = "STextUp" addr = 0x44FA14 size = 0xA8 [[func]] name = "STextDown" addr = 0x44FABC size = 0xAD [[func]] name = "STextPrior" addr = 0x44FB69 size = 0x4A [[func]] name = "STextNext" addr = 0x44FBB3 size = 0x4D [[func]] name = "S_SmithEnter" addr = 0x44FC00 size = 0x69 [[func]] name = "SetGoldCurs" addr = 0x44FC69 size = 0x46 [[func]] name = "SetSpdbarGoldCurs" addr = 0x44FCAF size = 0x46 [[func]] name = "TakePlrsMoney" addr = 0x44FCF5 size = 0x1D9 [[func]] name = "SmithBuyItem" addr = 0x44FECE size = 0xAB [[func]] name = "S_SBuyEnter" addr = 0x44FF79 size = 0xD5 [[func]] name = "SmithBuyPItem" addr = 0x45004E size = 0x95 [[func]] name = "S_SPBuyEnter" addr = 0x4500E3 size = 0xF4 [[func]] name = "StoreGoldFit" addr = 0x4501D7 size = 0xD6 [[func]] name = "PlaceStoreGold" addr = 0x4502AD size = 0xC8 [[func]] name = "StoreSellItem" addr = 0x450375 size = 0x150 [[func]] name = "S_SSellEnter" addr = 0x4504C5 size = 0x7F [[func]] name = "SmithRepairItem" addr = 0x450544 size = 0xD7 [[func]] name = "S_SRepairEnter" addr = 0x45061B size = 0x81 [[func]] name = "S_WitchEnter" addr = 0x45069C size = 0x68 [[func]] name = "WitchBuyItem" addr = 0x450704 size = 0xB8 [[func]] name = "S_WBuyEnter" addr = 0x4507BC size = 0xD5 [[func]] name = "S_WSellEnter" addr = 0x450891 size = 0x7F [[func]] name = "WitchRechargeItem" addr = 0x450910 size = 0x89 [[func]] name = "S_WRechargeEnter" addr = 0x450999 size = 0x81 [[func]] name = "S_BoyEnter" addr = 0x450A1A size = 0xA2 [[func]] name = "BoyBuyItem" addr = 0x450ABC size = 0x3A [[func]] name = "HealerBuyItem" addr = 0x450AF6 size = 0x104 [[func]] name = "S_BBuyEnter" addr = 0x450BFA size = 0xD3 [[func]] name = "StoryIdItem" addr = 0x450CCD size = 0xEF [[func]] name = "S_ConfirmEnter" addr = 0x450DBC size = 0xA0 [[func]] name = "S_HealerEnter" addr = 0x450E5C size = 0xA8 [[func]] name = "S_HBuyEnter" addr = 0x450F04 size = 0xD5 [[func]] name = "S_StoryEnter" addr = 0x450FD9 size = 0x56 [[func]] name = "S_SIDEnter" addr = 0x45102F size = 0x81 [[func]] name = "S_TalkEnter" addr = 0x4510B0 size = 0xFF [[func]] name = "S_TavernEnter" addr = 0x4511AF size = 0x4E [[func]] name = "S_BarmaidEnter" addr = 0x4511FD size = 0x4E [[func]] name = "S_DrunkEnter" addr = 0x45124B size = 0x4E [[func]] name = "STextEnter" addr = 0x451299 size = 0x85 [[func]] name = "CheckStoreBtn" addr = 0x4513B8 size = 0x137 [[func]] name = "ReleaseStoreBtn" addr = 0x4514EF size = 0xF [[func]] name = "sync_all_monsters" addr = 0x4514FE size = 0x85 [[func]] name = "sync_one_monster" addr = 0x451583 size = 0xA6 [[func]] name = "sync_monster_active" addr = 0x451629 size = 0x53 [[func]] name = "sync_monster_pos" addr = 0x45167C size = 0x6F [[func]] name = "sync_monster_active2" addr = 0x4516EB size = 0x60 [[func]] name = "SyncPlrInv" addr = 0x45174B size = 0x1E1 [[func]] name = "sync_update" addr = 0x45192C size = 0x74 [[func]] name = "sync_monster" addr = 0x4519A0 size = 0x210 [[func]] name = "sync_init" addr = 0x451BB0 size = 0x25 [[func]] name = "TFit_Shrine" addr = 0x451BD5 size = 0x123 [[func]] name = "TFit_Obj5" addr = 0x451CF8 size = 0xDF [[func]] name = "TFit_SkelRoom" addr = 0x451DD7 size = 0x52 [[func]] name = "TFit_GoatShrine" addr = 0x451E29 size = 0x45 [[func]] name = "CheckThemeObj3" addr = 0x451E6E size = 0x7F [[func]] name = "TFit_Obj3" addr = 0x451EED size = 0x5C [[func]] name = "CheckThemeReqs" addr = 0x451F49 size = 0x80 [[func]] name = "SpecialThemeFit" addr = 0x451FC9 size = 0xF6 [[func]] name = "CheckThemeRoom" addr = 0x4520FF size = 0x138 [[func]] name = "InitThemes" addr = 0x452237 size = 0x1B5 [[func]] name = "HoldThemeRooms" addr = 0x4523EC size = 0x5A [[func]] name = "PlaceThemeMonsts" addr = 0x452446 size = 0xE1 [[func]] name = "Theme_Barrel" addr = 0x452527 size = 0xD8 [[func]] name = "Theme_Shrine" addr = 0x4525FF size = 0xB3 [[func]] name = "Theme_MonstPit" addr = 0x4526B2 size = 0x99 [[func]] name = "Theme_SkelRoom" addr = 0x45274B size = 0x1D6 [[func]] name = "Theme_Treasure" addr = 0x452921 size = 0x14B [[func]] name = "Theme_Library" addr = 0x452A6C size = 0x183 [[func]] name = "Theme_Torture" addr = 0x452BEF size = 0xD3 [[func]] name = "Theme_BloodFountain" addr = 0x452CC2 size = 0x46 [[func]] name = "Theme_Decap" addr = 0x452D08 size = 0xD3 [[func]] name = "Theme_PurifyingFountain" addr = 0x452DDB size = 0x46 [[func]] name = "Theme_ArmorStand" addr = 0x452E21 size = 0xF1 [[func]] name = "Theme_GoatShrine" addr = 0x452F12 size = 0xCE [[func]] name = "Theme_Cauldron" addr = 0x452FE0 size = 0x46 [[func]] name = "Theme_MurkyFountain" addr = 0x453026 size = 0x46 [[func]] name = "Theme_TearFountain" addr = 0x45306C size = 0x46 [[func]] name = "Theme_BrnCross" addr = 0x4530B2 size = 0xD3 [[func]] name = "Theme_WeaponRack" addr = 0x453185 size = 0xF1 [[func]] name = "UpdateL4Trans" addr = 0x453276 size = 0x20 [[func]] name = "CreateThemeRooms" addr = 0x453296 size = 0x117 [[func]] name = "tmsg_get" addr = 0x4533F1 size = 0x4B [[func]] name = "tmsg_add" addr = 0x45343C size = 0x53 [[func]] name = "tmsg_cleanup" addr = 0x45348F size = 0x27 [[func]] name = "town_clear_upper_buf" addr = 0x4534B6 size = 0x66 [[func]] name = "town_clear_low_buf" addr = 0x45351C size = 0x6F [[func]] name = "town_draw_clipped_e_flag" addr = 0x45358B size = 0x7F [[func]] name = "town_draw_clipped_town" addr = 0x45360A size = 0x30B [[func]] name = "town_draw_lower" addr = 0x453915 size = 0x2E8 [[func]] name = "town_draw_clipped_e_flag_2" addr = 0x453BFD size = 0xA1 [[func]] name = "town_draw_clipped_town_2" addr = 0x453C9E size = 0x310 [[func]] name = "town_draw_lower_2" addr = 0x453FAE size = 0x341 [[func]] name = "town_draw_e_flag" addr = 0x4542EF size = 0x89 [[func]] name = "town_draw_town_all" addr = 0x454378 size = 0x310 [[func]] name = "town_draw_upper" addr = 0x454688 size = 0x33A [[func]] name = "T_DrawGame" addr = 0x4549C2 size = 0x1D9 [[func]] name = "T_DrawZoom" addr = 0x454BBB size = 0x235 [[func]] name = "T_DrawView" addr = 0x454E10 size = 0x12C [[func]] name = "SetTownMicros" addr = 0x454F3C size = 0xE8 [[func]] name = "T_FillSector" addr = 0x455024 size = 0xB6 [[func]] name = "T_FillTile" addr = 0x4550DA size = 0x71 [[func]] name = "T_Pass3" addr = 0x45514B size = 0x14E [[func]] name = "CreateTown" addr = 0x455299 size = 0x218 [[func]] name = "GetActiveTowner" addr = 0x4554B1 size = 0x26 [[func]] name = "SetTownerGPtrs" addr = 0x4554D7 size = 0x3A [[func]] name = "NewTownerAnim" addr = 0x455511 size = 0x34 [[func]] name = "InitTownerInfo" addr = 0x455545 size = 0x95 [[func]] name = "InitQstSnds" addr = 0x4555DA size = 0x4D [[func]] name = "InitSmith" addr = 0x455627 size = 0x8F [[func]] name = "InitBarOwner" addr = 0x4556B6 size = 0x96 [[func]] name = "InitTownDead" addr = 0x45574C size = 0x90 [[func]] name = "InitWitch" addr = 0x4557DC size = 0x8F [[func]] name = "InitBarmaid" addr = 0x45586B size = 0x8F [[func]] name = "InitBoy" addr = 0x4558FA size = 0x96 [[func]] name = "InitHealer" addr = 0x455990 size = 0x8F [[func]] name = "InitTeller" addr = 0x455A1F size = 0x8F [[func]] name = "InitDrunk" addr = 0x455AAE size = 0x8F [[func]] name = "InitCows" addr = 0x455B3D size = 0x14F [[func]] name = "InitTowners" addr = 0x455C8C size = 0x4D [[func]] name = "FreeTownerGFX" addr = 0x455CD9 size = 0x42 [[func]] name = "TownCtrlMsg" addr = 0x455D1B size = 0x73 [[func]] name = "TownBlackSmith" addr = 0x455D8E size = 0xE [[func]] name = "TownBarOwner" addr = 0x455D9C size = 0xF [[func]] name = "TownDead" addr = 0x455DAB size = 0x78 [[func]] name = "TownHealer" addr = 0x455E23 size = 0xF [[func]] name = "TownStory" addr = 0x455E32 size = 0xF [[func]] name = "TownDrunk" addr = 0x455E41 size = 0xF [[func]] name = "TownBoy" addr = 0x455E50 size = 0xF [[func]] name = "TownWitch" addr = 0x455E5F size = 0xF [[func]] name = "TownBarMaid" addr = 0x455E6E size = 0xF [[func]] name = "TownCow" addr = 0x455E7D size = 0xF [[func]] name = "ProcessTowners" addr = 0x455E8C size = 0xBE [[func]] name = "PlrHasItem" addr = 0x455F72 size = 0x50 [[func]] name = "TownerTalk" addr = 0x455FC2 size = 0x1D [[func]] name = "TalkToTowner" addr = 0x455FDF size = 0xAB6 [[func]] name = "CowSFX" addr = 0x456A95 size = 0x5A [[func]] name = "track_process" addr = 0x456AFF size = 0x9E [[func]] name = "track_repeat_walk" addr = 0x456B9D size = 0x4C [[func]] name = "track_isscrolling" addr = 0x456BE9 size = 0x8 [[func]] name = "InitTownTriggers" addr = 0x456BF1 size = 0x3C [[func]] name = "InitL1Triggers" addr = 0x456C2D size = 0xA9 [[func]] name = "ForceTownTrig" addr = 0x456CD6 size = 0x166 [[func]] name = "ForceL1Trig" addr = 0x456E3C size = 0x11C [[func]] name = "ForceL2Trig" addr = 0x456F58 size = 0x203 [[func]] name = "ForceL3Trig" addr = 0x45715B size = 0x1DE [[func]] name = "ForceL4Trig" addr = 0x457339 size = 0x249 [[func]] name = "Freeupstairs" addr = 0x457582 size = 0x41 [[func]] name = "ForceSKingTrig" addr = 0x4575C3 size = 0x68 [[func]] name = "ForceSChambTrig" addr = 0x45762B size = 0x68 [[func]] name = "ForcePWaterTrig" addr = 0x457693 size = 0x68 [[func]] name = "CheckTrigForce" addr = 0x4576FB size = 0xAE [[func]] name = "CheckTriggers" addr = 0x4577A9 size = 0x1F2 [[func]] name = "WCloseFile" addr = 0x4579AB size = 0x7 [[func]] name = "WGetFileSize" addr = 0x4579B2 size = 0x2B [[func]] name = "WGetFileArchive" addr = 0x4579DD size = 0x57 [[func]] name = "WOpenFile" addr = 0x457A34 size = 0x42 [[func]] name = "WReadFile" addr = 0x457A76 size = 0x52 [[func]] name = "WSetFilePointer" addr = 0x457AC8 size = 0x34 [[func]] name = "LoadWaveFormat" addr = 0x457AFC size = 0x2E [[func]] name = "AllocateMemFile" addr = 0x457B2A size = 0x49 [[func]] name = "FreeMemFile" addr = 0x457B73 size = 0xE [[func]] name = "ReadWaveFile" addr = 0x457B81 size = 0xCA [[func]] name = "ReadMemFile" addr = 0x457C4B size = 0x56 [[func]] name = "FillMemFile" addr = 0x457CA1 size = 0x3B [[func]] name = "SeekMemFile" addr = 0x457CDC size = 0x1E [[func]] name = "ReadWaveSection" addr = 0x457CFA size = 0x57 [[func]] name = "LoadWaveFile" addr = 0x457D51 size = 0x38 [[func]] name = "drawTopArchesUpperScreen" addr = 0x457D90 size = 0x162D [[func]] name = "drawBottomArchesUpperScreen" addr = 0x4593BD size = 0xC38 [[func]] name = "drawUpperScreen" addr = 0x459FF5 size = 0xC73 [[func]] name = "drawTopArchesLowerScreen" addr = 0x45AC68 size = 0x1A11 [[func]] name = "drawBottomArchesLowerScreen" addr = 0x45C679 size = 0xF22 [[func]] name = "drawLowerScreen" addr = 0x45D59B size = 0xE53 [[func]] name = "world_draw_black_tile" addr = 0x45E3EE size = 0x5C ================================================ FILE: defs.h ================================================ /** * @file defs.h * * Global definitions and Macros. */ #ifdef HELLFIRE #define DIABOOL BOOLEAN #define GAME_NAME "HELLFIRE" #define APP_NAME "Hellfire" #else #define DIABOOL BOOL #define GAME_NAME "DIABLO" #define APP_NAME "Diablo" #endif #ifdef HELLFIRE #define HFAND && #define DERROR GetLastError #else #define HFAND & #define DERROR SErrGetLastError #endif #define DMAXX 40 #define DMAXY 40 #define LIGHTSIZE 6912 // 27 * 256 #define GMENU_SLIDER 0x40000000 #define GMENU_ENABLED 0x80000000 // must be unsigned to generate unsigned comparisons with pnum #define MAX_PLRS 4 #define MAX_CHARACTERS 10 #ifdef HELLFIRE #define MAX_LVLS 24 #define MAX_LVLMTYPES 24 #define MAX_SPELLS 52 #else #define MAX_LVLS 16 #define MAX_LVLMTYPES 16 #define MAX_SPELLS 37 #endif #define MAX_SPELL_LEVEL 15 #define SPELLBIT(s) ((__int64)1 << (s - 1)) #define MAX_CHUNKS (MAX_LVLS + 5) // #define MAX_PATH 260 #define MAX_SEND_STR_LEN 80 #define MAXDEAD 31 #define MAXDUNX 112 #define MAXDUNY 112 #define MAXITEMS 127 #define MAXBELTITEMS 8 #define MAXLIGHTS 32 #define MAXMISSILES 125 #define MAXMONSTERS 200 #define MAXOBJECTS 127 #define MAXPORTAL 4 #ifdef HELLFIRE #define MAXQUESTS 24 #define MAXMULTIQUESTS 10 #else #define MAXQUESTS 16 #define MAXMULTIQUESTS 4 #endif #define MAXTHEMES 50 #define MAXTILES 2048 #ifdef HELLFIRE #define MAXTRIGGERS 7 #else #define MAXTRIGGERS 5 #endif #define MAXVISION 32 #define MDMAXX 40 #define MDMAXY 40 #define MAXCHARLEVEL 51 #ifdef HELLFIRE #define ITEMTYPES 43 #else #define ITEMTYPES 35 #endif // number of inventory grid cells #define NUM_INV_GRID_ELEM 40 #define INV_SLOT_SIZE_PX 28 // Item indestructible durability #define DUR_INDESTRUCTIBLE 255 #define VOLUME_MIN -1600 #define VOLUME_MAX 0 #define NUM_TOWNERS 16 // todo: enums #ifdef HELLFIRE #define NUMLEVELS 25 #define BOY_MAX_VALUE 200000 #define WITCH_ITEMS 25 #define WITCH_MAX_VALUE 200000 #define SMITH_ITEMS 25 #define SMITH_PREMIUM_ITEMS 15 #define SMITH_MAX_VALUE 200000 #define SMITH_MAX_PREMIUM_VALUE 200000 #define STORE_LINES 104 #else #define NUMLEVELS 17 #define BOY_MAX_VALUE 90000 #define WITCH_ITEMS 20 #define WITCH_MAX_VALUE 140000 #define SMITH_ITEMS 20 #define SMITH_PREMIUM_ITEMS 6 #define SMITH_MAX_VALUE 140000 #define SMITH_MAX_PREMIUM_VALUE 140000 #define STORE_LINES 24 #endif // from diablo 2 beta #define MAXEXP 2000000000 #define MAXRESIST 75 #define GOLD_SMALL_LIMIT 1000 #define GOLD_MEDIUM_LIMIT 2500 #define GOLD_MAX_LIMIT 5000 #define PLR_NAME_LEN 32 #define MAXPATHNODES 300 #define MAX_PATH_LENGTH 25 // 256 kilobytes + 3 bytes (demo leftover) for file magic (262147) // final game uses 4-byte magic instead of 3 #define FILEBUFF ((256 * 1024) + 3) #define PMSG_COUNT 8 // Diablo Retail Version Game ID #ifdef HELLFIRE #define GAME_ID ((int)'HRTL') #define GAME_VERSION 34 #define PROGRAM_NAME "Hellfire Retail" #else #define GAME_ID ((int)'DRTL') #define GAME_VERSION 42 #define PROGRAM_NAME "Diablo Retail" #endif // 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 #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 #define ZOOM_WIDTH (SCREEN_WIDTH / 2 + TILE_WIDTH) #define ZOOM_HEIGHT (VIEWPORT_HEIGHT / 2 + TILE_HEIGHT + TILE_HEIGHT / 2) // If defined, use 32-bit colors instead of 8-bit [Default -> Undefined] //#define RGBMODE #ifndef RGBMODE #define SCREEN_BPP 8 #else #define SCREEN_BPP 32 #endif #define BORDER_LEFT 64 #define BORDER_TOP 160 #define BORDER_RIGHT 64 #define BORDER_BOTTOM 16 #define SCREEN_X BORDER_LEFT #define SCREEN_Y BORDER_TOP #define BUFFER_WIDTH (BORDER_LEFT + SCREEN_WIDTH + BORDER_RIGHT) #define BUFFER_HEIGHT (BORDER_TOP + SCREEN_HEIGHT + BORDER_BOTTOM) #define TILE_WIDTH 64 #define TILE_HEIGHT 32 #define PANEL_WIDTH 640 #define PANEL_HEIGHT 128 #define PANEL_TOP (SCREEN_HEIGHT - PANEL_HEIGHT) #define PANEL_LEFT (SCREEN_WIDTH - PANEL_WIDTH) / 2 #define PANEL_X (SCREEN_X + PANEL_LEFT) #define PANEL_Y (SCREEN_Y + PANEL_TOP) #define SPANEL_WIDTH 320 #define SPANEL_HEIGHT 352 #define RIGHT_PANEL (SCREEN_WIDTH - SPANEL_WIDTH) #define RIGHT_PANEL_X (SCREEN_X + RIGHT_PANEL) #if SCREEN_WIDTH <= PANEL_WIDTH #define VIEWPORT_HEIGHT (SCREEN_HEIGHT - PANEL_HEIGHT) #else #define VIEWPORT_HEIGHT SCREEN_HEIGHT #endif #define DIALOG_TOP ((SCREEN_HEIGHT - PANEL_HEIGHT) / 2 - 18) #define DIALOG_Y (SCREEN_Y + DIALOG_TOP) #define SCREENXY(x, y) ((x) + SCREEN_X + ((y) + SCREEN_Y) * BUFFER_WIDTH) #define MemFreeDbg(p) \ { \ void *p__p; \ p__p = p; \ p = NULL; \ mem_free_dbg(p__p); \ } #undef assert #ifndef _DEBUG #define assert(exp) ((void)(exp)) #else #define assert(exp) (void)((exp) || (assert_fail(__LINE__, __FILE__, #exp), 0)) #endif #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif // Typedef for the function pointer typedef void (*_PVFV)(void); #if defined(_MSC_VER) && !defined(__APPLE__) // Define our segment names #define SEGMENT_C_INIT ".CRT$XCU" // Build our various function tables and insert them into the correct segments. #pragma data_seg(SEGMENT_C_INIT) #pragma data_seg() // Switch back to the default segment // Call function pointer arrays and place them in the segments created above #define SEG_ALLOCATE(SEGMENT) __declspec(allocate(SEGMENT)) #else #define SEG_ALLOCATE(SEGMENT) #endif // To apply to certain functions which have local variables aligned by 1 for unknown yet reason #if (_MSC_VER == 1200) #define ALIGN_BY_1 __declspec(align(1)) #else #define ALIGN_BY_1 #endif #if (_MSC_VER == 1200) #define __FINLINE __forceinline #else #define __FINLINE #endif #ifndef _BIG_ENDIAN_ #define SwapLE32 #else #define SwapLE32(value) (value << 24 | (value & 0xFF00) << 8 | (value & 0xFF0000) >> 8 | value >> 24); #endif ================================================ FILE: docs/BACKGROUND.md ================================================ # Project background To give further background, the Devilution team has primarily relied on these resources: 1. The Japanese Playstation port with debug symbols contained in `DIABPSX.SYM`. (see [[1]]). Example debug info of the Cathedral dungeon generation algorithm: ```cpp // address: 0x801259D0 // line start: 612 // line end: 624 void DRLG_L1Floor__Fv() { // register: 19 register int i; // register: 20 register int j; // register: 3 register long rv; } ``` 2. The debug release of the PE executable, which contained assert strings (see [[2]]). Example assert string: ```cpp "plr[myplr].InvGrid[i] <= plr[myplr]._pNumInv" ``` 3. The Rich header of the PE executable, which details the exact version of the original compilers and linkers used to build `Diablo.exe` (see [[3]], [[4]]). Example information recovered from the Rich header of `Diablo.exe`: ``` Id Build Count Name Description 0 0 155 Unknown [---] Number of imported functions (old) 1 0 229 Import0 [---] Number of imported functions 6 1668 1 Cvtres500 [RES] VS97 (5.0) SP3 cvtres 5.00.1668 2 7303 29 Linker510 [IMP] VS97 (5.0) SP3 link 5.10.7303 3 7303 1 Cvtomf510 VS97 (5.0) SP3 cvtomf 5.10.7303 4 8447 2 Linker600 [LNK] VC++ 6.0 SP3,SP4,SP5,SP6 link 6.00.8447 48 9044 72 Utc12_2_C [---] VC++ 6.0 SP5 Processor Pack 19 9049 12 Linker512 Microsoft LINK 5.12.9049 ``` 4. Discovery of the original set of compiler flags used to build `Diablo.exe` (see [[5]]). Primarily "/O1" was used, but there are also peculiarities such as the use of both Microsoft Visual Studio 6 and Microsoft Visual Code 5 for linking the game. 5. The heartfelt dedication of a team of people. GalaXyHaXz did the initial heavy lifting and succeeded in the tremendous task of getting the decompiled source code of Diablo 1 compiling with the original toolchain. Later on she released the project open source and a community of open source collaborators formed. Most of us have never met in real life prior to joining the project, which stands to show that there is strength in online collaboration that transcend both culture and borders. 6. The Beta release and the Alpha4 release of Diablo 1 has also proved invaluable resources for cross-validation as the compiler optimization level was not set to release mode for these binaries. Interestingly, in the process a number of bugs in the original implementation of Diablo 1 were discovered. These have been documented in the source code of Devilution with `// BUGFIX: foo` comments, and have also been detailed in [[6]]. To track the progress of the project, the "Binary identical functions" milestone has been used in tandem with an assembly diffing tool developed in Rust (see [[7]], [[8]]). Anecdotally, it was an incredible moment when we first managed to run the cross-platform port of Diablo 1 (DevilutionX, see [[9]]) natively on Linux and succeeded in playing a multiplayer game connecting our computers in Korea and Denmark. It is equally thrilling to see the modding and porting community picking up the torch and already succeeding in porting Diablo 1 to Nintendo Switch! The main reason for conducting this bit of software archeology is to preserve the classic title that is Diablo 1, for generations to come. And to revive it for modern hardware platforms and make it more mod-friendly in the age of open source software. Happy coding! - The Devilution Team P.S. the project README explicitly states that to play the game, you still need to have access to the original game assets released on the Diablo 1 CD. To acquire a legal copy, please refer to https://www.gog.com/game/diablo P.P.S. for the verification process, there have been proposals that are both ambitious at a level of PhD research (see [[10]]) and that made us feel warm and fuzzy <3 In the end, many of the techniques outlined were discussed mostly on a design level, some were included as Proof of Concepts, but most of the work in reverse engineering Diablo 1 was from tender labour of a team that care for Diablo 1 the way you would your firstborn child. P.P.P.S. you can also view our presentation slides here: https://docs.google.com/presentation/d/1ghmOFFgA3MfuJALMo8hmfNCL6pWWaW3plAbRtmSwfXY/edit?usp=sharing [1]: https://github.com/diasurgical/scalpel/blob/master/psx/_dump_/_dump_merge_c_src_/diabpsx/source/drlg_l1.cpp [2]: http://diablo1.se/notes/debug.html [3]: https://github.com/diasurgical/devilution/issues/111#issuecomment-426059660 [4]: http://bytepointer.com/articles/the_microsoft_rich_header.htm [5]: https://github.com/diasurgical/devilution/issues/111 [6]: https://github.com/diasurgical/devilution/issues/64 [7]: https://github.com/diasurgical/devilution/milestone/3 [8]: https://github.com/diasurgical/devilution-comparer [9]: https://github.com/diasurgical/devilutionX [10]: https://github.com/diasurgical/devilution/issues/171 ================================================ FILE: docs/CHANGELOG.md ================================================ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [0.10.0](https://github.com/diasurgical/devilution/compare/0.9.6...0.10.0) ### June 22, 2019 - [All functions are now binary identical](https://github.com/diasurgical/devilution/milestone/3) to the 1.09b version - Fix buying from Wirt - Replace many magic numbers with constants - Fix a handful of minor issues - Add toggle fullscreen with alt+enter in debug builds ### June 21, 2019 - All functions are now [binary identical](https://github.com/diasurgical/devilution/milestone/3) to Diablo 1.09b ### June 1, 2019 - MVG posts [a video about the project](https://www.youtube.com/watch?v=5tADL_fmsHQ) and releases a Nintendo Switch port ## [0.9.6](https://github.com/diasurgical/devilution/compare/0.9.0...0.9.6) ### May 19, 2019 - [96% of functions are now binary identical](https://github.com/diasurgical/devilution/milestone/3) to the 1.09b version - Fix several item corruption issues introduced in 0.9.0 ## [0.9.0](https://github.com/diasurgical/devilution/compare/0.8.0...0.9.0) ### May 2, 2019 - [90% of functions are now binary identical](https://github.com/diasurgical/devilution/milestone/3) to the 1.09b version - Mute buttons now work correctly ### April 15, 2019 - Code is once again compiled as C++ as some parts appear to require despite the indications in Rich header ## [0.8.0](https://github.com/diasurgical/devilution/compare/0.7.0...0.8.0) ### April 12, 2019 - [80% of functions are now binary identical](https://github.com/diasurgical/devilution/milestone/3) to the 1.09b version - Fixes a few minor issues with generated items ## [0.7.0](https://github.com/diasurgical/devilution/compare/0.6.0...0.7.0) ### April 9, 2019 - [70% of functions are now binary identical](https://github.com/diasurgical/devilution/milestone/3) to the 1.09b version ### April 9, 2019 - The last of the compiler flags are figured out ### March 22, 2019 - Devilution appears on [Phoronix](https://www.phoronix.com/scan.php?page=news_item&px=DeviluitionX-Open-Diablo) ## [0.6.0](https://github.com/diasurgical/devilution/compare/v0.5.0...0.6.0) ### March 19, 2019 - [60% of functions are now binary identical](https://github.com/diasurgical/devilution/milestone/3) to the 1.09b version - Added a guide for people wanting to join in [Cleaning the code](https://github.com/diasurgical/devilution/wiki/Cleaning-Code) - File size is now only 968 bytes (0.13%) larger than the original Diablo 1.09b. ### March 7, 2019 - [GOG re-release Diablo](https://www.gog.com/news/release_diablo) ## [0.5.0](https://github.com/diasurgical/devilution/compare/0.4...v0.5.0) ### January 14, 2019 - [50% of functions are now binary identical](https://github.com/diasurgical/devilution/milestone/3) to the 1.09b version - [#456](https://github.com/diasurgical/devilution/pull/456) Assets can now be loaded directly form disk (no need for MPQ-files when modding) - [#528](https://github.com/diasurgical/devilution/pull/528) Code ported to C (can still be compiled as C++) - [#111](https://github.com/diasurgical/devilution/pull/111) Rich Header no longer contains incorrect sections - [#182](https://github.com/diasurgical/devilution/pull/182) defined a [Code Style](https://github.com/diasurgical/devilution/wiki/Code-style-guide) with accompanying clang-format definition - `Diabloui.dll` is now also part of the source tree - Added [Contribution Guide](https://github.com/diasurgical/devilution/blob/master/docs/CONTRIBUTING.md) - Added PDB build option for comparing with [devilution-comparer](https://github.com/diasurgical/devilution-comparer) - CI now runs the original build chain - Most magic numbers are now replaced by enums - The code was reduced by 10,000 lines - Fix a few issues, mostly relating to multiplayer ### November 17, 2018 - An older and more original PSX symbol file is discovered ### October 1, 2018 - Compiler version is confirmed to be correct by discovery of the [Rich header](http://bytepointer.com/articles/the_microsoft_rich_header.htm) ### September 18, 2018 - Merge nightly back in to devilution ### September 3, 2018 - Travis is configured to report the overall project delta to 1.09b on every change ### September 1, 2018 - Devilution-comparer is developed for comparing binary diff in compiled functions ### August 28, 2018 - The correct compiler combination is found by trial and error plus a bit of luck ## [0.4.0](https://github.com/diasurgical/devilution/compare/0.3...0.4) ### September 16, 2018 - Fix crash - Get the first functions bin exact - Fix render issues - Introduce debug functions from the 1.00 debug release - Fix missiles - More consts, sizeof and defines - Fix several issues with dungeon generation code - Fix multiplayer - Fix error messages - Correct names based on PSX symbols and DX SDK ### August 20, 2018 - Created nightly fork where code clean up can take place until major bugs are fixed in the main project ### July 6, 2018 - Setup a Discord channel ### July 1, 2018 - Diablo 1.09b is determined to have been compiled with the /O1 flag ## [0.3.0](https://github.com/diasurgical/devilution/compare/0.1.0...0.3) ### June 28, 2018 - Windows binary can now be compiled under Linux and Mac OS X - Windows binary can now be compiled under VS 5.10 - Fix multiple crashes - Remove cheesy copyright notice - Set up continuous building via Travis and AppVeyor - Icon added - Fix Zhar quest, monster squelching and golems - Use consts for various values ### June 20, 2018 - The [media](https://www.pcgamer.com/a-coder-spent-1200-hours-reverse-engineering-diablos-source-code/) catches wind and [several](https://bloody-disgusting.com/video-games/3505673/fan-completes-reverse-engineering-source-code-diablo/) [articles](https://kotaku.com/coder-spends-1-200-hours-piecing-together-diablos-sourc-1827001247) [appear](https://www.diabloii.net/blog/comments/reverse-engineered-diablo-source-code-released) ### June 18, 2018 - Devilution gets posted on [Y Combinator](https://news.ycombinator.com/item?id=17338886) ## 0.1.0 ### June 6, 2018 - Devilution is unleashed upon the world! Version 0.1.0! ### June 3, 2018 - Polishing things up for final release - Added a cheesy fake copyright notice to dissuade monetary gain - Properly integrated Storm and DiabloUI into the project ### May 28, 2018 - Fixed bugs with save files - You can now load Devilution saves in the vanilla game ### May 25, 2018 - Finally! Figured it out and now monsters spawn correctly - The game can be completed from start to finish with a few tricks ### May 21, 2018 - Took a week break, begin working on monster code again - Nearly all quests work now - Fixed a bug with Adria ### May 8, 2018 - Fix bugs with character drawing - Fix bugs relating to item affix generation - Towners no longer crash the game ### May 7, 2018 - Port debugging functions from the debug release - Still can't figure out the zombie problem ### May 5, 2018 - Begin fixing quest code and testing completion ### April 26, 2018 - Zombies are spawning in all dungeon types... sigh ### April 20, 2018 - Split code from IDA's C file into separate CPP files - All dungeon types can now be entered - Objects are now mostly working - Begin uncommenting monster code and fixing them ### April 11, 2018 - Begin fixing up dungeon generation and objects ### April 4, 2018 - Fixed many crashing bugs when in town and dungeon - Items, missiles, and spells are now drawn ### April 1, 2018 - Finally fixed the render bug, everything draws correctly! - Character animation now draws correctly - The cathedral is now mostly working ### March 29, 2018 - Fixed tons of bugs - You can now walk around in town - Entering the dungeon almost always crashes ### March 27, 2018 - Uncommented and fixed lots of broken code - The game screen now appears, although very glitchy ### March 22, 2018 - Control panel and inventory now work almost flawlessly ### March 21, 2018 - Temporarily commented out tons of broken code - You can now get past the loading screen and into town - Music also works - Control panel mostly works but game screen is black ### March 18, 2018 - The title screen now works - Freezes during the loading screen ### March 16, 2018 - Fixed enough bugs that you can now launch binary - Crashes during title screen ### March 14, 2018 - Fix remaining errors in code - Code now compiles and produces a non-working binary ### March 13, 2018 -- *! SPECIAL DAY !* - Dump the database to C code via IDA ### March 8, 2018 - Correct various function signatures - Correct struct names and types - Plug in enumerates - Finish correcting and documenting data sections ### February 26, 2018 - Finish documenting functions - Begin correcting names to match PSX ### February 18, 2018 - Begin adding enumerates - Add more minor structs - Clean up data sections ### February 15, 2018 - Almost finished adding every function - Begin working on major structs ### February 8, 2018 - Add more functions - Begin adding data from Sanctuary project ### February 4, 2018 - IDA disassembly begin - Start adding function names from [Sanctuary project](https://github.com/sanctuary/notes) ### January 15, 2018 - The concept of Devilution is born - Research into Diablo's code and mechanics - Research from [Jarulf's guide](http://www.bigd-online.com/JG/JGFrame.html) ================================================ FILE: docs/CONTRIBUTING.md ================================================ # Contribution Guide This guide outlines useful resources, tools and processes for contribution to Devilution. ## Code style guide [The code style guide](https://github.com/diasurgical/devilution/wiki/Code-Style) is evolving with the project. ## 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` (version 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/devilution/#compiling) 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. ``` ================================================ FILE: docs/INSTALL_linux.md ================================================ # 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 ``` ================================================ FILE: docs/INSTALL_mac.md ================================================ # 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 ``` ================================================ FILE: docs/INSTALL_windows.md ================================================ # 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/ ``` ================================================ FILE: docs/TODO.md ================================================ ### Comments - `BUGFIX` known bugs in original (vanilla) code - `/* */` block comments are things to be fixed/checked - `FIX_ME` bad data Code issues (incorrect code that still works) - Critical sections should be constructors using `CCritSect` - Some functions/structures have incorrect signing (signed/unsigned BYTE) ================================================ FILE: docs/compatibility_matrix.md ================================================ # 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 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ================================================ FILE: docs/debug.md ================================================ 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` : enable 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 ================================================ FILE: docs/troubleshooting.md ================================================ # 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. ================================================ FILE: doxygen.config ================================================ PROJECT_NAME = "Devilution" PROJECT_BRIEF = "Diablo devolved - magic behind the 1996 computer game" USE_MDFILE_AS_MAINPAGE = README.md OUTPUT_DIRECTORY = docs INPUT = ./ ./Source ./docs INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c \ *.cpp \ *.h \ *.inc \ *.md GENERATE_LATEX = NO WARNINGS = YES SOURCE_BROWSER = YES EXTRACT_STATIC = YES JAVADOC_AUTOBRIEF = YES OPTIMIZE_OUTPUT_FOR_C = YES SEPARATE_MEMBER_PAGES = YES DOT_IMAGE_FORMAT = svg INTERACTIVE_SVG = YES HTML_COLORSTYLE_HUE = 0 HTML_COLORSTYLE_SAT = 125 HTML_COLORSTYLE_GAMMA = 200 # Call graphces alows logical navigation of the docs CALL_GRAPH = YES CALLER_GRAPH = YES # all.h includes everything and everything inclues it so the graph is usless past depth 1 MAX_DOT_GRAPH_DEPTH = 1 # Not all files are documented yet EXTRACT_ALL = YES ================================================ FILE: enums.h ================================================ /** * @file enums.h * * Various global enumerators. */ typedef enum item_quality { ITEM_QUALITY_NORMAL = 0, ITEM_QUALITY_MAGIC = 1, ITEM_QUALITY_UNIQUE = 2, } item_quality; typedef 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, #ifdef HELLFIRE UITYPE_BOVINE = 0x45, #endif UITYPE_INVALID = -1, } unique_base_item; typedef 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_SPLCOST = 0xC, /* only used in beta */ IPL_SPLDUR = 0xD, /* only used in beta */ 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_FIREBALL = 0x32, /* only used in hellfire */ 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, #ifdef HELLFIRE IPL_FIRERES_CURSE = 0x50, IPL_LIGHTRES_CURSE = 0x51, IPL_MAGICRES_CURSE = 0x52, IPL_ALLRES_CURSE = 0x53, IPL_DEVASTATION = 0x54, IPL_DECAY = 0x55, IPL_PERIL = 0x56, IPL_JESTERS = 0x57, IPL_CRYSTALLINE = 0x58, IPL_DOPPELGANGER = 0x59, IPL_ACDEMON = 0x5A, IPL_ACUNDEAD = 0x5B, IPL_MANATOLIFE = 0x5C, IPL_LIFETOMANA = 0x5D, #endif IPL_INVALID = -1, } item_effect_type; typedef enum affix_item_type { PLT_MISC = 0x1, PLT_BOW = 0x10, PLT_STAFF = 0x100, PLT_WEAP = 0x1000, PLT_SHLD = 0x10000, PLT_ARMO = 0x100000, } affix_item_type; /// Item graphic IDs; frame_num-11 of objcurs.cel. typedef enum item_cursor_graphic { ICURS_POTION_OF_FULL_MANA = 0, ICURS_SCROLL_OF = 1, ICURS_GOLD_SMALL = 4, ICURS_GOLD_MEDIUM = 5, ICURS_GOLD_LARGE = 6, ICURS_RING_OF_TRUTH = 10, ICURS_RING = 12, ICURS_SPECTRAL_ELIXIR = 15, ICURS_GOLDEN_ELIXIR = 17, ICURS_EMPYREAN_BAND = 18, ICURS_EAR_SORCEROR = 19, ICURS_EAR_WARRIOR = 20, ICURS_EAR_ROGUE = 21, ICURS_BLOOD_STONE = 25, #ifdef HELLFIRE ICURS_OIL = 30, #endif ICURS_ELIXIR_OF_VITALITY = 31, ICURS_POTION_OF_HEALING = 32, ICURS_POTION_OF_FULL_REJUVENATION = 33, ICURS_ELIXIR_OF_MAGIC = 34, ICURS_POTION_OF_FULL_HEALING = 35, ICURS_ELIXIR_OF_DEXTERITY = 36, ICURS_POTION_OF_REJUVENATION = 37, ICURS_ELIXIR_OF_STRENGTH = 38, ICURS_POTION_OF_MANA = 39, ICURS_BRAIN = 40, ICURS_OPTIC_AMULET = 44, ICURS_AMULET = 45, ICURS_DAGGER = 51, ICURS_BLADE = 56, ICURS_BASTARD_SWORD = 57, ICURS_MACE = 59, ICURS_LONG_SWORD = 60, ICURS_BROAD_SWORD = 61, ICURS_FALCHION = 62, ICURS_MORNING_STAR = 63, ICURS_SHORT_SWORD = 64, ICURS_CLAYMORE = 65, ICURS_CLUB = 66, ICURS_SABRE = 67, ICURS_SPIKED_CLUB = 70, ICURS_SCIMITAR = 72, ICURS_FULL_HELM = 75, ICURS_MAGIC_ROCK = 76, ICURS_THE_UNDEAD_CROWN = 78, ICURS_HELM = 82, ICURS_BUCKLER = 83, ICURS_VIEL_OF_STEEL = 85, ICURS_BOOK_GREY = 86, ICURS_BOOK_RED = 87, ICURS_BOOK_BLUE = 88, ICURS_BLACK_MUSHROOM = 89, ICURS_SKULL_CAP = 90, ICURS_CAP = 91, ICURS_HARLEQUIN_CREST = 93, ICURS_CROWN = 95, ICURS_MAP_OF_THE_STARS = 96, ICURS_FUNGAL_TOME = 97, ICURS_GREAT_HELM = 98, ICURS_BATTLE_AXE = 101, ICURS_HUNTERS_BOW = 102, ICURS_FIELD_PLATE = 103, ICURS_SMALL_SHIELD = 105, ICURS_CLEAVER = 106, ICURS_STUDDED_LEATHER_ARMOR = 107, ICURS_SHORT_STAFF = 109, ICURS_TWO_HANDED_SWORD = 110, ICURS_CHAIN_MAIL = 111, ICURS_SMALL_AXE = 112, ICURS_KITE_SHIELD = 113, ICURS_SCALE_MAIL = 114, ICURS_SHORT_BOW = 118, ICURS_LONG_WAR_BOW = 119, ICURS_WAR_HAMMER = 121, ICURS_MAUL = 122, ICURS_LONG_STAFF = 123, ICURS_WAR_STAFF = 124, ICURS_TAVERN_SIGN = 126, ICURS_HARD_LEATHER_ARMOR = 127, ICURS_RAGS = 128, ICURS_QUILTED_ARMOR = 129, ICURS_FLAIL = 131, ICURS_TOWER_SHIELD = 132, ICURS_COMPOSITE_BOW = 133, ICURS_GREAT_SWORD = 134, ICURS_LEATHER_ARMOR = 135, ICURS_SPLINT_MAIL = 136, ICURS_ROBE = 137, ICURS_ANVIL_OF_FURY = 140, ICURS_BROAD_AXE = 141, ICURS_LARGE_AXE = 142, ICURS_GREAT_AXE = 143, ICURS_AXE = 144, ICURS_LARGE_SHIELD = 147, ICURS_GOTHIC_SHIELD = 148, ICURS_CLOAK = 149, ICURS_CAPE = 150, ICURS_FULL_PLATE_MAIL = 151, ICURS_GOTHIC_PLATE = 152, ICURS_BREAST_PLATE = 153, ICURS_RING_MAIL = 154, ICURS_STAFF_OF_LAZARUS = 155, ICURS_ARKAINES_VALOR = 157, ICURS_SHORT_WAR_BOW = 165, ICURS_COMPOSITE_STAFF = 166, ICURS_SHORT_BATTLE_BOW = 167, ICURS_GOLD = 168, #ifdef HELLFIRE ICURS_AURIC_AMULET = 180, ICURS_RUNE_BOMB = 187, ICURS_THEODORE = 188, ICURS_TORN_NOTE_1 = 189, ICURS_TORN_NOTE_2 = 190, ICURS_TORN_NOTE_3 = 191, ICURS_RECONSTRUCTED_NOTE = 192, ICURS_RUNE_OF_FIRE = 193, ICURS_GREATER_RUNE_OF_FIRE = 194, ICURS_RUNE_OF_LIGHTNING = 195, ICURS_GREATER_RUNE_OF_LIGHTNING = 196, ICURS_RUNE_OF_STONE = 197, ICURS_GREY_SUIT = 198, ICURS_BROWN_SUIT = 199, ICURS_BOVINE = 226, #endif } item_cursor_graphic; typedef enum _sfx_id { PS_WALK1, PS_WALK2, PS_WALK3, PS_WALK4, PS_BFIRE, PS_FMAG, PS_TMAG, PS_LGHIT, PS_LGHIT1, PS_SWING, PS_SWING2, PS_DEAD, #ifdef HELLFIRE IS_STING1, IS_FBALLBOW, #endif IS_QUESTDN, IS_ARMRFKD, IS_BARLFIRE, IS_BARREL, #ifdef HELLFIRE IS_POPPOP8, IS_POPPOP5, IS_POPPOP3, IS_POPPOP2, #endif IS_BHIT, IS_BHIT1, IS_CHEST, IS_DOORCLOS, IS_DOOROPEN, IS_FANVL, IS_FAXE, IS_FBLST, IS_FBODY, IS_FBOOK, IS_FBOW, IS_FCAP, IS_FHARM, IS_FLARM, IS_FMAG, IS_FMAG1, IS_FMUSH, IS_FPOT, IS_FRING, IS_FROCK, IS_FSCRL, IS_FSHLD, IS_FSIGN, IS_FSTAF, IS_FSWOR, IS_GOLD, IS_HLMTFKD, IS_IANVL, IS_IAXE, IS_IBLST, IS_IBODY, IS_IBOOK, IS_IBOW, IS_ICAP, IS_IGRAB, IS_IHARM, IS_ILARM, IS_IMUSH, IS_IPOT, IS_IRING, IS_IROCK, IS_ISCROL, IS_ISHIEL, IS_ISIGN, IS_ISTAF, IS_ISWORD, IS_LEVER, IS_MAGIC, IS_MAGIC1, IS_RBOOK, IS_SARC, IS_SHLDFKD, IS_SWRDFKD, IS_TITLEMOV, IS_TITLSLCT, SFX_SILENCE, IS_TRAP, IS_CAST1, IS_CAST10, IS_CAST12, IS_CAST2, IS_CAST3, IS_CAST4, IS_CAST5, IS_CAST6, IS_CAST7, IS_CAST8, IS_CAST9, LS_HEALING, IS_REPAIR, LS_ACID, LS_ACIDS, LS_APOC, LS_ARROWALL, LS_BLODBOIL, LS_BLODSTAR, LS_BLSIMPT, LS_BONESP, LS_BSIMPCT, LS_CALDRON, LS_CBOLT, LS_CHLTNING, LS_DSERP, LS_ELECIMP1, LS_ELEMENTL, LS_ETHEREAL, LS_FBALL, LS_FBOLT1, LS_FBOLT2, LS_FIRIMP1, LS_FIRIMP2, LS_FLAMWAVE, LS_FLASH, LS_FOUNTAIN, LS_GOLUM, LS_GOLUMDED, LS_GSHRINE, LS_GUARD, LS_GUARDLAN, LS_HOLYBOLT, LS_HYPER, LS_INFRAVIS, LS_INVISIBL, LS_INVPOT, LS_LNING1, LS_LTNING, LS_MSHIELD, #ifdef HELLFIRE LS_NESTXPLD, #endif LS_NOVA, LS_PORTAL, LS_PUDDLE, LS_RESUR, LS_SCURSE, LS_SCURIMP, LS_SENTINEL, LS_SHATTER, LS_SOULFIRE, LS_SPOUTLOP, LS_SPOUTSTR, LS_STORM, LS_TRAPDIS, LS_TELEPORT, LS_VTHEFT, LS_WALLLOOP, LS_WALLSTRT, #ifdef HELLFIRE LS_LMAG, #endif #ifndef SPAWN TSFX_BMAID1, TSFX_BMAID2, TSFX_BMAID3, TSFX_BMAID4, TSFX_BMAID5, TSFX_BMAID6, TSFX_BMAID7, TSFX_BMAID8, TSFX_BMAID9, TSFX_BMAID10, TSFX_BMAID11, TSFX_BMAID12, TSFX_BMAID13, TSFX_BMAID14, TSFX_BMAID15, TSFX_BMAID16, TSFX_BMAID17, TSFX_BMAID18, TSFX_BMAID19, TSFX_BMAID20, TSFX_BMAID21, TSFX_BMAID22, TSFX_BMAID23, TSFX_BMAID24, TSFX_BMAID25, TSFX_BMAID26, TSFX_BMAID27, TSFX_BMAID28, TSFX_BMAID29, TSFX_BMAID30, #endif TSFX_BMAID31, #ifndef SPAWN TSFX_BMAID32, TSFX_BMAID33, TSFX_BMAID34, TSFX_BMAID35, TSFX_BMAID36, TSFX_BMAID37, TSFX_BMAID38, TSFX_BMAID39, TSFX_BMAID40, TSFX_SMITH1, TSFX_SMITH2, TSFX_SMITH3, TSFX_SMITH4, TSFX_SMITH5, TSFX_SMITH6, TSFX_SMITH7, TSFX_SMITH8, TSFX_SMITH9, TSFX_SMITH10, TSFX_SMITH11, TSFX_SMITH12, TSFX_SMITH13, TSFX_SMITH14, TSFX_SMITH15, TSFX_SMITH16, TSFX_SMITH17, TSFX_SMITH18, TSFX_SMITH19, TSFX_SMITH20, TSFX_SMITH21, TSFX_SMITH22, TSFX_SMITH23, TSFX_SMITH24, TSFX_SMITH25, TSFX_SMITH26, TSFX_SMITH27, TSFX_SMITH28, TSFX_SMITH29, TSFX_SMITH30, TSFX_SMITH31, TSFX_SMITH32, TSFX_SMITH33, TSFX_SMITH34, TSFX_SMITH35, TSFX_SMITH36, TSFX_SMITH37, TSFX_SMITH38, TSFX_SMITH39, TSFX_SMITH40, TSFX_SMITH41, TSFX_SMITH42, TSFX_SMITH43, #endif TSFX_SMITH44, #ifndef SPAWN TSFX_SMITH45, TSFX_SMITH46, TSFX_SMITH47, TSFX_SMITH48, TSFX_SMITH49, TSFX_SMITH50, TSFX_SMITH51, TSFX_SMITH52, TSFX_SMITH53, TSFX_SMITH54, TSFX_SMITH55, TSFX_SMITH56, #endif TSFX_COW1, TSFX_COW2, #ifdef HELLFIRE TSFX_COW7, TSFX_COW8, #endif #ifndef SPAWN TSFX_DEADGUY, TSFX_DRUNK1, TSFX_DRUNK2, TSFX_DRUNK3, TSFX_DRUNK4, TSFX_DRUNK5, TSFX_DRUNK6, TSFX_DRUNK7, TSFX_DRUNK8, TSFX_DRUNK9, TSFX_DRUNK10, TSFX_DRUNK11, TSFX_DRUNK12, TSFX_DRUNK13, TSFX_DRUNK14, TSFX_DRUNK15, TSFX_DRUNK16, TSFX_DRUNK17, TSFX_DRUNK18, TSFX_DRUNK19, TSFX_DRUNK20, TSFX_DRUNK21, TSFX_DRUNK22, TSFX_DRUNK23, TSFX_DRUNK24, TSFX_DRUNK25, TSFX_DRUNK26, #endif TSFX_DRUNK27, #ifndef SPAWN TSFX_DRUNK28, TSFX_DRUNK29, TSFX_DRUNK30, TSFX_DRUNK31, TSFX_DRUNK32, TSFX_DRUNK33, TSFX_DRUNK34, TSFX_DRUNK35, TSFX_HEALER1, TSFX_HEALER2, TSFX_HEALER3, TSFX_HEALER4, TSFX_HEALER5, TSFX_HEALER6, TSFX_HEALER7, TSFX_HEALER8, TSFX_HEALER9, TSFX_HEALER10, TSFX_HEALER11, TSFX_HEALER12, TSFX_HEALER13, TSFX_HEALER14, TSFX_HEALER15, TSFX_HEALER16, TSFX_HEALER17, TSFX_HEALER18, TSFX_HEALER19, TSFX_HEALER20, TSFX_HEALER21, TSFX_HEALER22, TSFX_HEALER23, TSFX_HEALER24, TSFX_HEALER25, TSFX_HEALER26, TSFX_HEALER27, TSFX_HEALER28, TSFX_HEALER29, TSFX_HEALER30, TSFX_HEALER31, TSFX_HEALER32, TSFX_HEALER33, TSFX_HEALER34, TSFX_HEALER35, TSFX_HEALER36, #endif TSFX_HEALER37, #ifndef SPAWN TSFX_HEALER38, TSFX_HEALER39, TSFX_HEALER40, TSFX_HEALER41, TSFX_HEALER42, TSFX_HEALER43, TSFX_HEALER44, TSFX_HEALER45, TSFX_HEALER46, TSFX_HEALER47, TSFX_PEGBOY1, TSFX_PEGBOY2, TSFX_PEGBOY3, TSFX_PEGBOY4, TSFX_PEGBOY5, TSFX_PEGBOY6, TSFX_PEGBOY7, TSFX_PEGBOY8, TSFX_PEGBOY9, TSFX_PEGBOY10, TSFX_PEGBOY11, TSFX_PEGBOY12, TSFX_PEGBOY13, TSFX_PEGBOY14, TSFX_PEGBOY15, TSFX_PEGBOY16, TSFX_PEGBOY17, TSFX_PEGBOY18, TSFX_PEGBOY19, TSFX_PEGBOY20, TSFX_PEGBOY21, TSFX_PEGBOY22, TSFX_PEGBOY23, TSFX_PEGBOY24, TSFX_PEGBOY25, TSFX_PEGBOY26, TSFX_PEGBOY27, TSFX_PEGBOY28, TSFX_PEGBOY29, TSFX_PEGBOY30, TSFX_PEGBOY31, #endif TSFX_PEGBOY32, #ifndef SPAWN TSFX_PEGBOY33, TSFX_PEGBOY34, TSFX_PEGBOY35, TSFX_PEGBOY36, TSFX_PEGBOY37, TSFX_PEGBOY38, TSFX_PEGBOY39, TSFX_PEGBOY40, TSFX_PEGBOY41, TSFX_PEGBOY42, TSFX_PEGBOY43, TSFX_PRIEST0, TSFX_PRIEST1, TSFX_PRIEST2, TSFX_PRIEST3, TSFX_PRIEST4, TSFX_PRIEST5, TSFX_PRIEST6, TSFX_PRIEST7, TSFX_STORY0, TSFX_STORY1, TSFX_STORY2, TSFX_STORY3, TSFX_STORY4, TSFX_STORY5, TSFX_STORY6, TSFX_STORY7, TSFX_STORY8, TSFX_STORY9, TSFX_STORY10, TSFX_STORY11, TSFX_STORY12, TSFX_STORY13, TSFX_STORY14, TSFX_STORY15, TSFX_STORY16, TSFX_STORY17, TSFX_STORY18, TSFX_STORY19, TSFX_STORY20, TSFX_STORY21, TSFX_STORY22, TSFX_STORY23, TSFX_STORY24, #endif TSFX_STORY25, #ifndef SPAWN TSFX_STORY26, TSFX_STORY27, TSFX_STORY28, TSFX_STORY29, TSFX_STORY30, TSFX_STORY31, TSFX_STORY32, TSFX_STORY33, TSFX_STORY34, TSFX_STORY35, TSFX_STORY36, TSFX_STORY37, TSFX_STORY38, #endif TSFX_TAVERN0, #ifndef SPAWN TSFX_TAVERN1, TSFX_TAVERN2, TSFX_TAVERN3, TSFX_TAVERN4, TSFX_TAVERN5, TSFX_TAVERN6, TSFX_TAVERN7, TSFX_TAVERN8, TSFX_TAVERN9, TSFX_TAVERN10, TSFX_TAVERN11, TSFX_TAVERN12, TSFX_TAVERN13, TSFX_TAVERN14, TSFX_TAVERN15, TSFX_TAVERN16, TSFX_TAVERN17, TSFX_TAVERN18, TSFX_TAVERN19, TSFX_TAVERN20, TSFX_TAVERN21, TSFX_TAVERN22, TSFX_TAVERN23, TSFX_TAVERN24, TSFX_TAVERN25, TSFX_TAVERN26, TSFX_TAVERN27, TSFX_TAVERN28, TSFX_TAVERN29, TSFX_TAVERN30, TSFX_TAVERN31, TSFX_TAVERN32, TSFX_TAVERN33, TSFX_TAVERN34, TSFX_TAVERN35, #endif TSFX_TAVERN36, #ifndef SPAWN TSFX_TAVERN37, TSFX_TAVERN38, TSFX_TAVERN39, TSFX_TAVERN40, TSFX_TAVERN41, TSFX_TAVERN42, TSFX_TAVERN43, TSFX_TAVERN44, TSFX_TAVERN45, TSFX_WITCH1, TSFX_WITCH2, TSFX_WITCH3, TSFX_WITCH4, TSFX_WITCH5, TSFX_WITCH6, TSFX_WITCH7, TSFX_WITCH8, TSFX_WITCH9, TSFX_WITCH10, TSFX_WITCH11, TSFX_WITCH12, TSFX_WITCH13, TSFX_WITCH14, TSFX_WITCH15, TSFX_WITCH16, TSFX_WITCH17, TSFX_WITCH18, TSFX_WITCH19, TSFX_WITCH20, TSFX_WITCH21, TSFX_WITCH22, TSFX_WITCH23, TSFX_WITCH24, TSFX_WITCH25, TSFX_WITCH26, TSFX_WITCH27, TSFX_WITCH28, TSFX_WITCH29, TSFX_WITCH30, TSFX_WITCH31, TSFX_WITCH32, TSFX_WITCH33, TSFX_WITCH34, TSFX_WITCH35, TSFX_WITCH36, TSFX_WITCH37, #endif TSFX_WITCH38, #ifndef SPAWN TSFX_WITCH39, TSFX_WITCH40, TSFX_WITCH41, TSFX_WITCH42, TSFX_WITCH43, TSFX_WITCH44, TSFX_WITCH45, TSFX_WITCH46, TSFX_WITCH47, TSFX_WITCH48, TSFX_WITCH49, TSFX_WITCH50, TSFX_WOUND, PS_MAGE1, PS_MAGE2, PS_MAGE3, PS_MAGE4, PS_MAGE5, PS_MAGE6, PS_MAGE7, PS_MAGE8, PS_MAGE9, PS_MAGE10, PS_MAGE11, PS_MAGE12, PS_MAGE13, PS_MAGE14, PS_MAGE15, PS_MAGE16, PS_MAGE17, PS_MAGE18, PS_MAGE19, PS_MAGE20, PS_MAGE21, PS_MAGE22, PS_MAGE23, PS_MAGE24, PS_MAGE25, PS_MAGE26, PS_MAGE27, PS_MAGE28, PS_MAGE29, PS_MAGE30, PS_MAGE31, PS_MAGE32, PS_MAGE33, PS_MAGE34, PS_MAGE35, PS_MAGE36, PS_MAGE37, PS_MAGE38, PS_MAGE39, PS_MAGE40, PS_MAGE41, PS_MAGE42, PS_MAGE43, PS_MAGE44, PS_MAGE45, PS_MAGE46, PS_MAGE47, PS_MAGE48, PS_MAGE49, PS_MAGE50, PS_MAGE51, PS_MAGE52, PS_MAGE53, PS_MAGE54, PS_MAGE55, PS_MAGE56, PS_MAGE57, PS_MAGE58, PS_MAGE59, PS_MAGE60, PS_MAGE61, PS_MAGE62, PS_MAGE63, PS_MAGE64, PS_MAGE65, PS_MAGE66, PS_MAGE67, PS_MAGE68, PS_MAGE69, PS_MAGE69B, PS_MAGE70, PS_MAGE71, PS_MAGE72, PS_MAGE73, PS_MAGE74, PS_MAGE75, PS_MAGE76, PS_MAGE77, PS_MAGE78, PS_MAGE79, PS_MAGE80, PS_MAGE81, PS_MAGE82, PS_MAGE83, PS_MAGE84, PS_MAGE85, PS_MAGE86, PS_MAGE87, PS_MAGE88, PS_MAGE89, PS_MAGE90, PS_MAGE91, PS_MAGE92, PS_MAGE93, PS_MAGE94, PS_MAGE95, PS_MAGE96, PS_MAGE97, PS_MAGE98, PS_MAGE99, PS_MAGE100, PS_MAGE101, PS_MAGE102, PS_ROGUE1, PS_ROGUE2, PS_ROGUE3, PS_ROGUE4, PS_ROGUE5, PS_ROGUE6, PS_ROGUE7, PS_ROGUE8, PS_ROGUE9, PS_ROGUE10, PS_ROGUE11, PS_ROGUE12, PS_ROGUE13, PS_ROGUE14, PS_ROGUE15, PS_ROGUE16, PS_ROGUE17, PS_ROGUE18, PS_ROGUE19, PS_ROGUE20, PS_ROGUE21, PS_ROGUE22, PS_ROGUE23, PS_ROGUE24, PS_ROGUE25, PS_ROGUE26, PS_ROGUE27, PS_ROGUE28, PS_ROGUE29, PS_ROGUE30, PS_ROGUE31, PS_ROGUE32, PS_ROGUE33, PS_ROGUE34, PS_ROGUE35, PS_ROGUE36, PS_ROGUE37, PS_ROGUE38, PS_ROGUE39, PS_ROGUE40, PS_ROGUE41, PS_ROGUE42, PS_ROGUE43, PS_ROGUE44, PS_ROGUE45, PS_ROGUE46, PS_ROGUE47, PS_ROGUE48, PS_ROGUE49, PS_ROGUE50, PS_ROGUE51, PS_ROGUE52, PS_ROGUE53, PS_ROGUE54, PS_ROGUE55, PS_ROGUE56, PS_ROGUE57, PS_ROGUE58, PS_ROGUE59, PS_ROGUE60, PS_ROGUE61, PS_ROGUE62, PS_ROGUE63, PS_ROGUE64, PS_ROGUE65, PS_ROGUE66, PS_ROGUE67, PS_ROGUE68, PS_ROGUE69, PS_ROGUE69B, PS_ROGUE70, PS_ROGUE71, PS_ROGUE72, PS_ROGUE73, PS_ROGUE74, PS_ROGUE75, PS_ROGUE76, PS_ROGUE77, PS_ROGUE78, PS_ROGUE79, PS_ROGUE80, PS_ROGUE81, PS_ROGUE82, PS_ROGUE83, PS_ROGUE84, PS_ROGUE85, PS_ROGUE86, PS_ROGUE87, PS_ROGUE88, PS_ROGUE89, PS_ROGUE90, PS_ROGUE91, PS_ROGUE92, PS_ROGUE93, PS_ROGUE94, PS_ROGUE95, PS_ROGUE96, PS_ROGUE97, PS_ROGUE98, PS_ROGUE99, PS_ROGUE100, PS_ROGUE101, PS_ROGUE102, PS_WARR1, PS_WARR2, PS_WARR3, PS_WARR4, PS_WARR5, PS_WARR6, PS_WARR7, PS_WARR8, PS_WARR9, PS_WARR10, PS_WARR11, PS_WARR12, #endif PS_WARR13, PS_WARR14, PS_WARR14B, PS_WARR14C, PS_WARR15, PS_WARR15B, PS_WARR15C, PS_WARR16, PS_WARR16B, PS_WARR16C, PS_WARR17, PS_WARR18, PS_WARR19, PS_WARR20, PS_WARR21, PS_WARR22, PS_WARR23, PS_WARR24, PS_WARR25, PS_WARR26, PS_WARR27, PS_WARR28, PS_WARR29, PS_WARR30, PS_WARR31, PS_WARR32, PS_WARR33, PS_WARR34, PS_WARR35, PS_WARR36, PS_WARR37, PS_WARR38, PS_WARR39, PS_WARR40, PS_WARR41, PS_WARR42, PS_WARR43, PS_WARR44, PS_WARR45, PS_WARR46, PS_WARR47, PS_WARR48, PS_WARR49, PS_WARR50, PS_WARR51, PS_WARR52, PS_WARR53, PS_WARR54, PS_WARR55, PS_WARR56, PS_WARR57, PS_WARR58, PS_WARR59, PS_WARR60, PS_WARR61, PS_WARR62, PS_WARR63, PS_WARR64, PS_WARR65, PS_WARR66, PS_WARR67, PS_WARR68, PS_WARR69, PS_WARR69B, PS_WARR70, PS_WARR71, PS_WARR72, PS_WARR73, PS_WARR74, PS_WARR75, PS_WARR76, PS_WARR77, PS_WARR78, PS_WARR79, #ifndef SPAWN PS_WARR80, PS_WARR81, PS_WARR82, PS_WARR83, PS_WARR84, PS_WARR85, PS_WARR86, PS_WARR87, PS_WARR88, PS_WARR89, PS_WARR90, PS_WARR91, PS_WARR92, PS_WARR93, PS_WARR94, PS_WARR95, PS_WARR95B, PS_WARR95C, PS_WARR95D, PS_WARR95E, PS_WARR95F, #endif PS_WARR96B, PS_WARR97, PS_WARR98, PS_WARR99, #ifndef SPAWN PS_WARR100, PS_WARR101, PS_WARR102, #endif #ifdef HELLFIRE PS_MONK1, PS_MONK2, PS_MONK3, PS_MONK4, PS_MONK5, PS_MONK6, PS_MONK7, PS_MONK8, PS_MONK9, PS_MONK10, PS_MONK11, PS_MONK12, PS_MONK13, PS_MONK14, PS_MONK15, PS_MONK16, PS_MONK17, PS_MONK18, PS_MONK19, PS_MONK20, PS_MONK21, PS_MONK22, PS_MONK23, PS_MONK24, PS_MONK25, PS_MONK26, PS_MONK27, PS_MONK28, PS_MONK29, PS_MONK30, PS_MONK31, PS_MONK32, PS_MONK33, PS_MONK34, PS_MONK35, PS_MONK36, PS_MONK37, PS_MONK38, PS_MONK39, PS_MONK40, PS_MONK41, PS_MONK42, PS_MONK43, PS_MONK44, PS_MONK45, PS_MONK46, PS_MONK47, PS_MONK48, PS_MONK49, PS_MONK50, PS_MONK51, PS_MONK52, PS_MONK53, PS_MONK54, PS_MONK55, PS_MONK56, PS_MONK57, PS_MONK58, PS_MONK59, PS_MONK60, PS_MONK61, PS_MONK62, PS_MONK63, PS_MONK64, PS_MONK65, PS_MONK66, PS_MONK67, PS_MONK68, PS_MONK69, PS_MONK69B, PS_MONK70, PS_MONK71, PS_MONK72, PS_MONK73, PS_MONK74, PS_MONK75, PS_MONK76, PS_MONK77, PS_MONK78, PS_MONK79, PS_MONK80, PS_MONK81, PS_MONK82, PS_MONK83, PS_MONK84, PS_MONK85, PS_MONK86, PS_MONK87, PS_MONK88, PS_MONK89, PS_MONK90, PS_MONK91, PS_MONK92, PS_MONK93, PS_MONK94, PS_MONK95, PS_MONK96, PS_MONK97, PS_MONK98, PS_MONK99, PS_MONK100, PS_MONK101, PS_MONK102, #endif #ifndef SPAWN PS_NAR1, PS_NAR2, PS_NAR3, PS_NAR4, PS_NAR5, PS_NAR6, PS_NAR7, PS_NAR8, PS_NAR9, PS_DIABLVLINT, USFX_CLEAVER, USFX_GARBUD1, USFX_GARBUD2, USFX_GARBUD3, USFX_GARBUD4, USFX_IZUAL1, USFX_LACH1, USFX_LACH2, USFX_LACH3, USFX_LAZ1, USFX_LAZ2, USFX_SKING1, USFX_SNOT1, USFX_SNOT2, USFX_SNOT3, USFX_WARLRD1, USFX_WLOCK1, USFX_ZHAR1, USFX_ZHAR2, USFX_DIABLOD, #endif #ifdef HELLFIRE TSFX_FARMER1, TSFX_FARMER2, TSFX_FARMER2A, TSFX_FARMER3, TSFX_FARMER4, TSFX_FARMER5, TSFX_FARMER6, TSFX_FARMER7, TSFX_FARMER8, TSFX_FARMER9, TSFX_TEDDYBR1, TSFX_TEDDYBR2, TSFX_TEDDYBR3, TSFX_TEDDYBR4, USFX_DEFILER1, USFX_DEFILER2, USFX_DEFILER3, USFX_DEFILER4, USFX_DEFILER8, USFX_DEFILER6, USFX_DEFILER7, USFX_NAKRUL1, USFX_NAKRUL2, USFX_NAKRUL3, USFX_NAKRUL4, USFX_NAKRUL5, USFX_NAKRUL6, PS_NARATR3, TSFX_COWSUT1, TSFX_COWSUT2, TSFX_COWSUT3, TSFX_COWSUT4, TSFX_COWSUT4A, TSFX_COWSUT5, TSFX_COWSUT6, TSFX_COWSUT7, TSFX_COWSUT8, TSFX_COWSUT9, TSFX_COWSUT10, TSFX_COWSUT11, TSFX_COWSUT12, USFX_SKLJRN1, PS_NARATR6, PS_NARATR7, PS_NARATR8, PS_NARATR5, PS_NARATR9, PS_NARATR4, TSFX_TRADER1, IS_CROPEN, IS_CRCLOS, #endif } _sfx_id; typedef enum sfx_flag { sfx_STREAM = 0x01, sfx_MISC = 0x02, sfx_UI = 0x04, sfx_MONK = 0x08, sfx_ROGUE = 0x10, sfx_WARRIOR = 0x20, sfx_SORCEROR = 0x40, sfx_LOADED = 0x80, } sfx_flag; typedef 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, } item_equip_type; typedef 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_SENTINAL = 0x10, // TODO: Check beta MIS_BLODSTAR = 0x11, // TODO: Check beta MIS_BONE = 0x12, // TODO: Check beta MIS_METLHIT = 0x13, // TODO: Check beta 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_FIREWALLA = 0x1D, // TODO: Check beta MIS_STONE = 0x1E, MIS_NULL_1F = 0x1F, MIS_INVISIBL = 0x20, MIS_GOLEM = 0x21, MIS_ETHEREALIZE = 0x22, MIS_BLODBUR = 0x23, // TODO: Check beta 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_FIREMAN = 0x32, // TODO: Check beta MIS_KRULL = 0x33, // TODO: Check beta 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, #ifdef HELLFIRE MIS_MANA = 0x44, MIS_MAGI = 0x45, MIS_LIGHTWALL = 0x46, MIS_LIGHTNINGWALL = 0x47, MIS_IMMOLATION = 0x48, MIS_SPECARROW = 0x49, MIS_FIRENOVA = 0x4A, MIS_LIGHTARROW = 0x4B, MIS_CBOLTARROW = 0x4C, MIS_HBOLTARROW = 0x4D, MIS_WARP = 0x4E, MIS_REFLECT = 0x4F, MIS_BERSERK = 0x50, MIS_FIRERING = 0x51, MIS_STEALPOTS = 0x52, MIS_MANATRAP = 0x53, MIS_LIGHTRING = 0x54, MIS_SEARCH = 0x55, MIS_FLASHFR = 0x56, MIS_FLASHBK = 0x57, MIS_IMMOLATION2 = 0x58, MIS_RUNEFIRE = 0x59, MIS_RUNELIGHT = 0x5A, MIS_RUNENOVA = 0x5B, MIS_RUNEIMMOLAT = 0x5C, MIS_RUNESTONE = 0x5D, MIS_HIVEEXP = 0x5E, MIS_HORKDMN = 0x5F, MIS_JESTER = 0x60, MIS_HIVEEXP2 = 0x61, MIS_LICH = 0x62, MIS_PSYCHORB = 0x63, MIS_NECROMORB = 0x64, MIS_ARCHLICH = 0x65, MIS_BONEDEMON = 0x66, MIS_EXYEL2 = 0x67, MIS_EXRED3 = 0x68, MIS_EXBL2 = 0x69, MIS_EXBL3 = 0x6A, MIS_EXORA1 = 0x6B, #endif } missile_id; typedef enum missile_graphic_id { MFILE_ARROWS, MFILE_FIREBA, MFILE_GUARD, MFILE_LGHNING, MFILE_FIREWAL, MFILE_MAGBLOS, MFILE_PORTAL, MFILE_BLUEXFR, MFILE_BLUEXBK, MFILE_MANASHLD, MFILE_BLOOD, MFILE_BONE, MFILE_METLHIT, MFILE_FARROW, MFILE_DOOM, MFILE_0F, MFILE_BLODBUR, MFILE_NEWEXP, MFILE_SHATTER1, MFILE_BIGEXP, MFILE_INFERNO, MFILE_THINLGHT, MFILE_FLARE, MFILE_FLAREEXP, MFILE_MAGBALL, MFILE_KRULL, MFILE_MINILTNG, MFILE_HOLY, MFILE_HOLYEXPL, MFILE_LARROW, MFILE_FIRARWEX, MFILE_ACIDBF, MFILE_ACIDSPLA, MFILE_ACIDPUD, MFILE_ETHRSHLD, MFILE_FIRERUN, MFILE_RESSUR1, MFILE_SKLBALL, MFILE_RPORTAL, MFILE_FIREPLAR, MFILE_SCUBMISB, MFILE_SCBSEXPB, MFILE_SCUBMISC, MFILE_SCBSEXPC, MFILE_SCUBMISD, MFILE_SCBSEXPD, #ifdef HELLFIRE MFILE_SPAWNS, MFILE_REFLECT, MFILE_LICH, MFILE_MSBLA, MFILE_NECROMORB, MFILE_ARCHLICH, MFILE_RUNE, MFILE_EXYEL2, MFILE_EXBL2, MFILE_EXRED3, MFILE_BONEDEMON, MFILE_EXORA1, MFILE_EXBL3, #endif MFILE_NULL, MFILE_NONE = 0xFF, // BUGFIX: should be `MFILE_NONE = MFILE_SCBSEXPD+1`, i.e. MFILE_NULL, since there would otherwise be an out-of-bounds in SetMissAnim when accessing misfiledata for any of the missiles that have MFILE_NONE as mFileNum in missiledata. } missile_graphic_id; typedef 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, #ifdef HELLFIRE AI_FIREBAT = 32, AI_TORCHANT = 33, AI_HORKDMN = 34, AI_LICH = 35, AI_ARCHLICH = 36, AI_PSYCHORB = 37, AI_NECROMORB = 38, AI_BONEDEMON = 39, #endif } _mai_id; typedef enum _mc_id { MC_UNDEAD = 0, MC_DEMON = 1, MC_ANIMAL = 2, } _mc_id; typedef enum FILE_SYSTEM { FS_PC = 0, FS_CD = 1, } FILE_SYSTEM; typedef enum _artfonts { AF_SMALL = 0, AF_SMALLGRAY = 1, AF_MED = 2, AF_MEDGRAY = 3, AF_BIG = 4, AF_BIGGRAY = 5, AF_HUGE = 6, AF_HUGEGRAY = 7, } _artfonts; typedef 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, #ifdef HELLFIRE MT_HELLBOAR = 0x70, MT_STINGER = 0x71, MT_PSYCHORB = 0x72, MT_ARACHNON = 0x73, MT_FELLTWIN = 0x74, MT_HORKSPWN = 0x75, MT_VENMTAIL = 0x76, MT_NECRMORB = 0x77, MT_SPIDLORD = 0x78, MT_LASHWORM = 0x79, MT_TORCHANT = 0x7A, MT_HORKDMN = 0x7B, MT_DEFILER = 0x7C, MT_GRAVEDIG = 0x7D, MT_TOMBRAT = 0x7E, MT_FIREBAT = 0x7F, MT_SKLWING = 0x80, MT_LICH = 0x81, MT_CRYPTDMN = 0x82, MT_HELLBAT = 0x83, MT_BONEDEMN = 0x84, MT_ARCHLICH = 0x85, MT_BICLOPS = 0x86, MT_FLESTHNG = 0x87, MT_REAPER = 0x88, MT_NAKRUL = 0x89, NUM_MTYPES, #else NUM_MTYPES = 0x6F, /// BUGFIX the count is off by one #endif } _monster_id; // this enum contains indexes from UniqMonst array for special unique monsters (usually quest related) typedef enum { UMT_GARBUD = 0, UMT_SKELKING = 1, UMT_ZHAR = 2, UMT_SNOTSPIL = 3, UMT_LAZURUS = 4, UMT_RED_VEX = 5, UMT_BLACKJADE = 6, UMT_LACHDAN = 7, UMT_WARLORD = 8, UMT_BUTCHER = 9, #ifdef HELLFIRE UMT_HORKDMN = 10, UMT_DEFILER = 11, UMT_NAKRUL = 12, #endif } _uniq_monsterid; typedef enum monster_flag { MFLAG_HIDDEN = 0x01, MFLAG_LOCK_ANIMATION = 0x02, MFLAG_ALLOW_SPECIAL = 0x04, MFLAG_NOHEAL = 0x08, MFLAG_TARGETS_MONSTER = 0x10, MFLAG_GOLEM = 0x20, MFLAG_QUEST_COMPLETE = 0x40, MFLAG_KNOCKBACK = 0x80, MFLAG_SEARCH = 0x100, MFLAG_CAN_OPEN_DOOR = 0x200, MFLAG_NO_ENEMY = 0x400, MFLAG_BERSERK = 0x800, MFLAG_NOLIFESTEAL = 0x1000 } monster_flag; typedef enum monster_goal { MGOAL_NORMAL = 1, MGOAL_RETREAT = 2, MGOAL_HEALING = 3, MGOAL_MOVE = 4, MGOAL_ATTACK2 = 5, MGOAL_INQUIRING = 6, MGOAL_TALKING = 7, } monster_goal; typedef enum monster_resistance { RESIST_MAGIC = 0x01, RESIST_FIRE = 0x02, RESIST_LIGHTNING = 0x04, IMMUNE_MAGIC = 0x08, IMMUNE_FIRE = 0x10, IMMUNE_LIGHTNING = 0x20, IMMUNE_NULL_40 = 0x40, IMMUNE_ACID = 0x80, } monster_resistance; typedef enum missile_resistance { MISR_NONE = 0, MISR_FIRE = 1, MISR_LIGHTNING = 2, MISR_MAGIC = 3, MISR_ACID = 4, } missile_resistance; typedef enum _speech_id { TEXT_KING1 = 0x0, TEXT_KING2 = 0x1, TEXT_KING3 = 0x2, TEXT_KING4 = 0x3, TEXT_KING5 = 0x4, TEXT_KING6 = 0x5, TEXT_KING7 = 0x6, TEXT_KING8 = 0x7, TEXT_KING9 = 0x8, TEXT_KING10 = 0x9, TEXT_KING11 = 0xA, TEXT_BANNER1 = 0xB, TEXT_BANNER2 = 0xC, TEXT_BANNER3 = 0xD, TEXT_BANNER4 = 0xE, TEXT_BANNER5 = 0xF, TEXT_BANNER6 = 0x10, TEXT_BANNER7 = 0x11, TEXT_BANNER8 = 0x12, TEXT_BANNER9 = 0x13, TEXT_BANNER10 = 0x14, TEXT_BANNER11 = 0x15, TEXT_BANNER12 = 0x16, TEXT_VILE1 = 0x17, TEXT_VILE2 = 0x18, TEXT_VILE3 = 0x19, TEXT_VILE4 = 0x1A, TEXT_VILE5 = 0x1B, TEXT_VILE6 = 0x1C, TEXT_VILE7 = 0x1D, TEXT_VILE8 = 0x1E, TEXT_VILE9 = 0x1F, TEXT_VILE10 = 0x20, TEXT_VILE11 = 0x21, TEXT_VILE12 = 0x22, TEXT_VILE13 = 0x23, TEXT_VILE14 = 0x24, TEXT_POISON1 = 0x25, TEXT_POISON2 = 0x26, TEXT_POISON3 = 0x27, TEXT_POISON4 = 0x28, TEXT_POISON5 = 0x29, TEXT_POISON6 = 0x2A, TEXT_POISON7 = 0x2B, TEXT_POISON8 = 0x2C, TEXT_POISON9 = 0x2D, TEXT_POISON10 = 0x2E, TEXT_BONE1 = 0x2F, TEXT_BONE2 = 0x30, TEXT_BONE3 = 0x31, TEXT_BONE4 = 0x32, TEXT_BONE5 = 0x33, TEXT_BONE6 = 0x34, TEXT_BONE7 = 0x35, TEXT_BONE8 = 0x36, TEXT_BUTCH1 = 0x37, TEXT_BUTCH2 = 0x38, TEXT_BUTCH3 = 0x39, TEXT_BUTCH4 = 0x3A, TEXT_BUTCH5 = 0x3B, TEXT_BUTCH6 = 0x3C, TEXT_BUTCH7 = 0x3D, TEXT_BUTCH8 = 0x3E, TEXT_BUTCH9 = 0x3F, TEXT_BUTCH10 = 0x40, TEXT_BLIND1 = 0x41, TEXT_BLIND2 = 0x42, TEXT_BLIND3 = 0x43, TEXT_BLIND4 = 0x44, TEXT_BLIND5 = 0x45, TEXT_BLIND6 = 0x46, TEXT_BLIND7 = 0x47, TEXT_BLIND8 = 0x48, TEXT_VEIL1 = 0x49, TEXT_VEIL2 = 0x4A, TEXT_VEIL3 = 0x4B, TEXT_VEIL4 = 0x4C, TEXT_VEIL5 = 0x4D, TEXT_VEIL6 = 0x4E, TEXT_VEIL7 = 0x4F, TEXT_VEIL8 = 0x50, TEXT_VEIL9 = 0x51, TEXT_VEIL10 = 0x52, TEXT_VEIL11 = 0x53, TEXT_ANVIL1 = 0x54, TEXT_ANVIL2 = 0x55, TEXT_ANVIL3 = 0x56, TEXT_ANVIL4 = 0x57, TEXT_ANVIL5 = 0x58, TEXT_ANVIL6 = 0x59, TEXT_ANVIL7 = 0x5A, TEXT_ANVIL8 = 0x5B, TEXT_ANVIL9 = 0x5C, TEXT_ANVIL10 = 0x5D, TEXT_BLOOD1 = 0x5E, TEXT_BLOOD2 = 0x5F, TEXT_BLOOD3 = 0x60, TEXT_BLOOD4 = 0x61, TEXT_BLOOD5 = 0x62, TEXT_BLOOD6 = 0x63, TEXT_BLOOD7 = 0x64, TEXT_BLOOD8 = 0x65, TEXT_WARLRD1 = 0x66, TEXT_WARLRD2 = 0x67, TEXT_WARLRD3 = 0x68, TEXT_WARLRD4 = 0x69, TEXT_WARLRD5 = 0x6A, TEXT_WARLRD6 = 0x6B, TEXT_WARLRD7 = 0x6C, TEXT_WARLRD8 = 0x6D, TEXT_WARLRD9 = 0x6E, TEXT_INFRA1 = 0x6F, TEXT_INFRA2 = 0x70, TEXT_INFRA3 = 0x71, TEXT_INFRA4 = 0x72, TEXT_INFRA5 = 0x73, TEXT_INFRA6 = 0x74, TEXT_INFRA7 = 0x75, TEXT_INFRA8 = 0x76, TEXT_INFRA9 = 0x77, TEXT_INFRA10 = 0x78, TEXT_MUSH1 = 0x79, TEXT_MUSH2 = 0x7A, TEXT_MUSH3 = 0x7B, TEXT_MUSH4 = 0x7C, TEXT_MUSH5 = 0x7D, TEXT_MUSH6 = 0x7E, TEXT_MUSH7 = 0x7F, TEXT_MUSH8 = 0x80, TEXT_MUSH9 = 0x81, TEXT_MUSH10 = 0x82, TEXT_MUSH11 = 0x83, TEXT_MUSH12 = 0x84, TEXT_MUSH13 = 0x85, TEXT_DOOM1 = 0x86, TEXT_DOOM2 = 0x87, TEXT_DOOM3 = 0x88, TEXT_DOOM4 = 0x89, TEXT_DOOM5 = 0x8A, TEXT_DOOM6 = 0x8B, TEXT_DOOM7 = 0x8C, TEXT_DOOM8 = 0x8D, TEXT_DOOM9 = 0x8E, TEXT_DOOM10 = 0x8F, TEXT_GARBUD1 = 0x90, TEXT_GARBUD2 = 0x91, TEXT_GARBUD3 = 0x92, TEXT_GARBUD4 = 0x93, TEXT_ZHAR1 = 0x94, TEXT_ZHAR2 = 0x95, TEXT_STORY1 = 0x96, TEXT_STORY2 = 0x97, TEXT_STORY3 = 0x98, TEXT_STORY4 = 0x99, TEXT_STORY5 = 0x9A, TEXT_STORY6 = 0x9B, TEXT_STORY7 = 0x9C, TEXT_STORY9 = 0x9D, TEXT_STORY10 = 0x9E, TEXT_STORY11 = 0x9F, TEXT_OGDEN1 = 0xA0, TEXT_OGDEN2 = 0xA1, TEXT_OGDEN3 = 0xA2, TEXT_OGDEN4 = 0xA3, TEXT_OGDEN5 = 0xA4, TEXT_OGDEN6 = 0xA5, TEXT_OGDEN8 = 0xA6, TEXT_OGDEN9 = 0xA7, TEXT_OGDEN10 = 0xA8, TEXT_PEPIN1 = 0xA9, TEXT_PEPIN2 = 0xAA, TEXT_PEPIN3 = 0xAB, TEXT_PEPIN4 = 0xAC, TEXT_PEPIN5 = 0xAD, TEXT_PEPIN6 = 0xAE, TEXT_PEPIN7 = 0xAF, TEXT_PEPIN9 = 0xB0, TEXT_PEPIN10 = 0xB1, TEXT_PEPIN11 = 0xB2, TEXT_GILLIAN1 = 0xB3, TEXT_GILLIAN2 = 0xB4, TEXT_GILLIAN3 = 0xB5, TEXT_GILLIAN4 = 0xB6, TEXT_GILLIAN5 = 0xB7, TEXT_GILLIAN6 = 0xB8, TEXT_GILLIAN7 = 0xB9, TEXT_GILLIAN9 = 0xBA, TEXT_GILLIAN10 = 0xBB, TEXT_GRISWOLD1 = 0xBC, TEXT_GRISWOLD2 = 0xBD, TEXT_GRISWOLD3 = 0xBE, TEXT_GRISWOLD4 = 0xBF, TEXT_GRISWOLD5 = 0xC0, TEXT_GRISWOLD6 = 0xC1, TEXT_GRISWOLD7 = 0xC2, TEXT_GRISWOLD8 = 0xC3, TEXT_GRISWOLD9 = 0xC4, TEXT_GRISWOLD10 = 0xC5, TEXT_GRISWOLD12 = 0xC6, TEXT_GRISWOLD13 = 0xC7, TEXT_FARNHAM1 = 0xC8, TEXT_FARNHAM2 = 0xC9, TEXT_FARNHAM3 = 0xCA, TEXT_FARNHAM4 = 0xCB, TEXT_FARNHAM5 = 0xCC, TEXT_FARNHAM6 = 0xCD, TEXT_FARNHAM8 = 0xCE, TEXT_FARNHAM9 = 0xCF, TEXT_FARNHAM10 = 0xD0, TEXT_FARNHAM11 = 0xD1, TEXT_FARNHAM12 = 0xD2, TEXT_FARNHAM13 = 0xD3, TEXT_ADRIA1 = 0xD4, TEXT_ADRIA2 = 0xD5, TEXT_ADRIA3 = 0xD6, TEXT_ADRIA4 = 0xD7, TEXT_ADRIA5 = 0xD8, TEXT_ADRIA6 = 0xD9, TEXT_ADRIA7 = 0xDA, TEXT_ADRIA8 = 0xDB, TEXT_ADRIA9 = 0xDC, TEXT_ADRIA10 = 0xDD, TEXT_ADRIA12 = 0xDE, TEXT_ADRIA13 = 0xDF, TEXT_WIRT1 = 0xE0, TEXT_WIRT2 = 0xE1, TEXT_WIRT3 = 0xE2, TEXT_WIRT4 = 0xE3, TEXT_WIRT5 = 0xE4, TEXT_WIRT6 = 0xE5, TEXT_WIRT7 = 0xE6, TEXT_WIRT8 = 0xE7, TEXT_WIRT9 = 0xE8, TEXT_WIRT11 = 0xE9, TEXT_WIRT12 = 0xEA, TEXT_BONER = 0xEB, TEXT_BLOODY = 0xEC, TEXT_BLINDING = 0xED, TEXT_BLOODWAR = 0xEE, TEXT_MBONER = 0xEF, TEXT_MBLOODY = 0xF0, TEXT_MBLINDING = 0xF1, TEXT_MBLOODWAR = 0xF2, TEXT_RBONER = 0xF3, TEXT_RBLOODY = 0xF4, TEXT_RBLINDING = 0xF5, TEXT_RBLOODWAR = 0xF6, TEXT_COW1 = 0xF7, TEXT_COW2 = 0xF8, TEXT_BOOK11 = 0xF9, TEXT_BOOK12 = 0xFA, TEXT_BOOK13 = 0xFB, TEXT_BOOK21 = 0xFC, TEXT_BOOK22 = 0xFD, TEXT_BOOK23 = 0xFE, TEXT_BOOK31 = 0xFF, TEXT_BOOK32 = 0x100, TEXT_BOOK33 = 0x101, TEXT_INTRO = 0x102, #ifdef HELLFIRE TEXT_HBONER = 0x103, TEXT_HBLOODY = 0x104, TEXT_HBLINDING = 0x105, TEXT_HBLOODWAR = 0x106, TEXT_BBONER = 0x107, TEXT_BBLOODY = 0x108, TEXT_BBLINDING = 0x109, TEXT_BBLOODWAR = 0x10A, TEXT_GRAVE1 = 0x10B, TEXT_GRAVE2 = 0x10C, TEXT_GRAVE3 = 0x10D, TEXT_GRAVE4 = 0x10E, TEXT_GRAVE5 = 0x10F, TEXT_GRAVE6 = 0x110, TEXT_GRAVE7 = 0x111, TEXT_GRAVE8 = 0x112, TEXT_GRAVE9 = 0x113, TEXT_GRAVE10 = 0x114, TEXT_FARMER1 = 0x115, TEXT_FARMER2 = 0x116, TEXT_FARMER3 = 0x117, TEXT_FARMER4 = 0x118, TEXT_FARMER5 = 0x119, TEXT_GIRL1 = 0x11A, TEXT_GIRL2 = 0x11B, TEXT_GIRL3 = 0x11C, TEXT_GIRL4 = 0x11D, TEXT_DEFILER1 = 0x11E, TEXT_DEFILER2 = 0x11F, TEXT_DEFILER3 = 0x120, TEXT_DEFILER4 = 0x121, TEXT_DEFILER5 = 0x122, TEXT_NAKRUL1 = 0x123, TEXT_NAKRUL2 = 0x124, TEXT_NAKRUL3 = 0x125, TEXT_NAKRUL4 = 0x126, TEXT_NAKRUL5 = 0x127, TEXT_CORNSTN = 0x128, TEXT_JERSEY1 = 0x129, TEXT_JERSEY2 = 0x12A, TEXT_JERSEY3 = 0x12B, TEXT_JERSEY4 = 0x12C, TEXT_JERSEY5 = 0x12D, TEXT_JERSEY6 = 0x12E, TEXT_JERSEY7 = 0x12F, TEXT_JERSEY8 = 0x130, TEXT_JERSEY9 = 0x131, TEXT_TRADER = 0x132, TEXT_FARMER6 = 0x133, TEXT_FARMER7 = 0x134, TEXT_FARMER8 = 0x135, TEXT_FARMER9 = 0x136, TEXT_FARMER10 = 0x137, TEXT_JERSEY10 = 0x138, TEXT_JERSEY11 = 0x139, TEXT_JERSEY12 = 0x13A, TEXT_JERSEY13 = 0x13B, TEXT_SKLJRN = 0x13C, TEXT_BOOK4 = 0x13D, TEXT_BOOK5 = 0x13E, TEXT_BOOK6 = 0x13F, TEXT_BOOK7 = 0x140, TEXT_BOOK8 = 0x141, TEXT_BOOK9 = 0x142, TEXT_BOOKA = 0x143, TEXT_BOOKB = 0x144, TEXT_BOOKC = 0x145, TEXT_OBOOKA = 0x146, TEXT_OBOOKB = 0x147, TEXT_OBOOKC = 0x148, TEXT_MBOOKA = 0x149, TEXT_MBOOKB = 0x14A, TEXT_MBOOKC = 0x14B, TEXT_RBOOKA = 0x14C, TEXT_RBOOKB = 0x14D, TEXT_RBOOKC = 0x14E, TEXT_BBOOKA = 0x14F, TEXT_BBOOKB = 0x150, TEXT_BBOOKC = 0x151, #endif } _speech_id; typedef 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, } object_graphic_id; typedef enum dungeon_type { DTYPE_TOWN = 0x0, DTYPE_CATHEDRAL = 0x1, DTYPE_CATACOMBS = 0x2, DTYPE_CAVES = 0x3, DTYPE_HELL = 0x4, #ifdef HELLFIRE DTYPE_NEST = 0x5, DTYPE_CRYPT = 0x6, #endif DTYPE_NONE = 0xFF, } dungeon_type; typedef enum dflag { BFLAG_MISSILE = 0x01, BFLAG_VISIBLE = 0x02, BFLAG_DEAD_PLAYER = 0x04, BFLAG_POPULATED = 0x08, BFLAG_MONSTLR = 0x10, BFLAG_PLAYERLR = 0x20, BFLAG_LIT = 0x40, BFLAG_EXPLORED = 0x80, } dflag; typedef enum clicktype { CLICK_NONE = 0, CLICK_LEFT = 1, CLICK_RIGHT = 2, } clicktype; typedef enum placeflag { PLACE_SCATTER = 1, PLACE_SPECIAL = 2, PLACE_UNIQUE = 4, } placeflag; typedef enum mienemy_type { TARGET_MONSTERS = 0, TARGET_PLAYERS = 1, TARGET_BOTH = 2, } mienemy_type; /* Looks like someone treated hex values as binary, so 0x10 came after 0x01, that's why we have 1 and 16, they did the same thing with affix_item_type */ typedef enum goodorevil { GOE_ANY = 0x00, GOE_EVIL = 0x01, GOE_GOOD = 0x10, } goodorevil; /* First 5 bits store level 6th bit stores onlygood flag 7th bit stores uper15 flag - uper means unique percent, this flag is true for unique monsters and loot from them has 15% to become unique 8th bit stores uper1 flag - this is loot from normal monsters, which has 1% to become unique 9th bit stores info if item is unique 10th bit stores info if item is a basic one from griswold 11th bit stores info if item is a premium one from griswold 12th bit stores info if item is from wirt 13th bit stores info if item is from adria 14th bit stores info if item is from pepin 15th bit stores pregen flag combining CF_UPER15 and CF_UPER1 flags (CF_USEFUL) is used to mark potions and town portal scrolls created on the ground CF_TOWN is combining all store flags and indicates if item has been bought from a NPC */ typedef enum icreateinfo_flag { CF_LEVEL = (1 << 6) - 1, CF_ONLYGOOD = 1 << 6, CF_UPER15 = 1 << 7, CF_UPER1 = 1 << 8, CF_UNIQUE = 1 << 9, CF_SMITH = 1 << 10, CF_SMITHPREMIUM = 1 << 11, CF_BOY = 1 << 12, CF_WITCH = 1 << 13, CF_HEALER = 1 << 14, CF_PREGEN = 1 << 15, CF_USEFUL = CF_UPER15 | CF_UPER1, CF_TOWN = CF_SMITH | CF_SMITHPREMIUM | CF_BOY | CF_WITCH | CF_HEALER, } icreateinfo_flag; typedef enum dungeon_message { DMSG_CATHEDRAL = 1 << 0, DMSG_CATACOMBS = 1 << 1, DMSG_CAVES = 1 << 2, DMSG_HELL = 1 << 3, DMSG_DIABLO = 1 << 4, } dungeon_message; typedef enum diablo_message { EMSG_NONE = 0, EMSG_NO_AUTOMAP_IN_TOWN = 1, EMSG_NO_MULTIPLAYER_IN_DEMO = 2, EMSG_DIRECT_SOUND_FAILED = 3, EMSG_NOT_IN_SHAREWARE = 4, EMSG_NO_SPACE_TO_SAVE = 5, EMSG_NO_PAUSE_IN_TOWN = 6, EMSG_COPY_TO_HDD = 7, EMSG_DESYNC = 8, EMSG_NO_PAUSE_IN_MP = 9, EMSG_LOADING = 10, EMSG_SAVING = 11, EMSG_SHRINE_MYSTERIOUS = 12, EMSG_SHRINE_HIDDEN = 13, EMSG_SHRINE_GLOOMY = 14, EMSG_SHRINE_WEIRD = 15, EMSG_SHRINE_MAGICAL = 16, EMSG_SHRINE_STONE = 17, EMSG_SHRINE_RELIGIOUS = 18, EMSG_SHRINE_ENCHANTED = 19, EMSG_SHRINE_THAUMATURGIC = 20, EMSG_SHRINE_FASCINATING = 21, EMSG_SHRINE_CRYPTIC = 22, EMSG_SHRINE_UNUSED = 23, EMSG_SHRINE_ELDRITCH = 24, EMSG_SHRINE_EERIE = 25, EMSG_SHRINE_DIVINE = 26, EMSG_SHRINE_HOLY = 27, EMSG_SHRINE_SACRED = 28, EMSG_SHRINE_SPIRITUAL = 29, EMSG_SHRINE_SPOOKY1 = 30, EMSG_SHRINE_SPOOKY2 = 31, EMSG_SHRINE_ABANDONED = 32, EMSG_SHRINE_CREEPY = 33, EMSG_SHRINE_QUIET = 34, EMSG_SHRINE_SECLUDED = 35, EMSG_SHRINE_ORNATE = 36, EMSG_SHRINE_GLIMMERING = 37, EMSG_SHRINE_TAINTED1 = 38, EMSG_SHRINE_TAINTED2 = 39, EMSG_REQUIRES_LVL_8 = 40, EMSG_REQUIRES_LVL_13 = 41, EMSG_REQUIRES_LVL_17 = 42, EMSG_BONECHAMB = 43, #ifdef HELLFIRE EMSG_SHRINE_OILY = 44, EMSG_SHRINE_GLOWING = 45, EMSG_SHRINE_MENDICANT = 46, EMSG_SHRINE_SPARKLING = 47, EMSG_SHRINE_TOWN = 48, EMSG_SHRINE_SHIMMERING = 49, EMSG_SHRINE_SOLAR1 = 50, EMSG_SHRINE_SOLAR2 = 51, EMSG_SHRINE_SOLAR3 = 52, EMSG_SHRINE_SOLAR4 = 53, EMSG_SHRINE_MURPHYS = 54, #endif } diablo_message; typedef enum magic_type { STYPE_FIRE = 0x0, STYPE_LIGHTNING = 0x1, STYPE_MAGIC = 0x2, } magic_type; typedef 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 = -1, } theme_id; typedef 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, } event_type; typedef enum _copyprot_results { COPYPROT_OK = 1, COPYPROT_CANCEL = 2, } _copyprot_results; typedef enum text_color { COL_WHITE = 0x0, COL_BLUE = 0x1, COL_RED = 0x2, COL_GOLD = 0x3, } text_color; typedef enum item_color { ICOL_WHITE = PAL16_YELLOW + 5, ICOL_BLUE = PAL16_BLUE + 5, ICOL_RED = PAL16_RED + 5, } item_color; typedef enum _difficulty { DIFF_NORMAL = 0x0, DIFF_NIGHTMARE = 0x1, DIFF_HELL = 0x2, NUM_DIFFICULTIES = 0x3, } _difficulty; typedef 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, } MON_MODE; typedef enum MON_ANIM { MA_STAND = 0, MA_WALK = 1, MA_ATTACK = 2, MA_GOTHIT = 3, MA_DEATH = 4, MA_SPECIAL = 5, } MON_ANIM; typedef 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, } PLR_MODE; typedef enum spell_type { RSPLTYPE_SKILL = 0x0, RSPLTYPE_SPELL = 0x1, RSPLTYPE_SCROLL = 0x2, RSPLTYPE_CHARGES = 0x3, RSPLTYPE_INVALID = 0x4, } spell_type; typedef 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, } cursor_id; typedef 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, } direction; typedef enum _scroll_direction { SDIR_NONE = 0x0, SDIR_N = 0x1, SDIR_NE = 0x2, SDIR_E = 0x3, SDIR_SE = 0x4, SDIR_S = 0x5, SDIR_SW = 0x6, SDIR_W = 0x7, SDIR_NW = 0x8, } _scroll_direction; typedef enum interface_mode { 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 } interface_mode; typedef enum lvl_entry { ENTRY_MAIN = 0, ENTRY_PREV = 1, ENTRY_SETLVL = 2, ENTRY_RTNLVL = 3, ENTRY_LOAD = 4, ENTRY_WARPLVL = 5, ENTRY_TWARPDN = 6, ENTRY_TWARPUP = 7, } lvl_entry; typedef enum game_info { GAMEINFO_NAME = 1, GAMEINFO_PASSWORD = 2, GAMEINFO_STATS = 3, GAMEINFO_MODEFLAG = 4, GAMEINFO_GAMETEMPLATE = 5, GAMEINFO_PLAYERS = 6, } game_info; typedef 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, #ifdef HELLFIRE SPL_MANA = 0x25, SPL_MAGI = 0x26, SPL_JESTER = 0x27, SPL_LIGHTWALL = 0x28, SPL_IMMOLAT = 0x29, SPL_WARP = 0x2A, SPL_REFLECT = 0x2B, SPL_BERSERK = 0x2C, SPL_FIRERING = 0x2D, SPL_SEARCH = 0x2E, SPL_RUNEFIRE = 0x2F, SPL_RUNELIGHT = 0x30, SPL_RUNENOVA = 0x31, SPL_RUNEIMMOLAT = 0x32, SPL_RUNESTONE = 0x33, #endif SPL_INVALID = -1, } spell_id; typedef enum _cmd_id { CMD_STAND, CMD_WALKXY, CMD_ACK_PLRINFO, CMD_ADDSTR, CMD_ADDMAG, CMD_ADDDEX, CMD_ADDVIT, CMD_SBSPELL, CMD_GETITEM, CMD_AGETITEM, CMD_PUTITEM, CMD_RESPAWNITEM, CMD_ATTACKXY, CMD_RATTACKXY, CMD_SPELLXY, CMD_TSPELLXY, CMD_OPOBJXY, CMD_DISARMXY, CMD_ATTACKID, CMD_ATTACKPID, CMD_RATTACKID, CMD_RATTACKPID, CMD_SPELLID, CMD_SPELLPID, CMD_TSPELLID, CMD_TSPELLPID, CMD_RESURRECT, CMD_OPOBJT, CMD_KNOCKBACK, CMD_TALKXY, CMD_NEWLVL, CMD_WARP, CMD_CHEAT_EXPERIENCE, CMD_CHEAT_SPELL_LEVEL, CMD_DEBUG, CMD_SYNCDATA, CMD_MONSTDEATH, CMD_MONSTDAMAGE, CMD_PLRDEAD, CMD_REQUESTGITEM, CMD_REQUESTAGITEM, CMD_GOTOGETITEM, CMD_GOTOAGETITEM, CMD_OPENDOOR, CMD_CLOSEDOOR, CMD_OPERATEOBJ, CMD_PLROPOBJ, CMD_BREAKOBJ, CMD_CHANGEPLRITEMS, CMD_DELPLRITEMS, CMD_PLRDAMAGE, CMD_PLRLEVEL, CMD_DROPITEM, CMD_PLAYER_JOINLEVEL, CMD_SEND_PLRINFO, CMD_SATTACKXY, CMD_ACTIVATEPORTAL, CMD_DEACTIVATEPORTAL, CMD_DLEVEL_0, CMD_DLEVEL_1, CMD_DLEVEL_2, CMD_DLEVEL_3, CMD_DLEVEL_4, CMD_DLEVEL_5, CMD_DLEVEL_6, CMD_DLEVEL_7, CMD_DLEVEL_8, CMD_DLEVEL_9, CMD_DLEVEL_10, CMD_DLEVEL_11, CMD_DLEVEL_12, CMD_DLEVEL_13, CMD_DLEVEL_14, CMD_DLEVEL_15, CMD_DLEVEL_16, #ifdef HELLFIRE CMD_DLEVEL_17, CMD_DLEVEL_18, CMD_DLEVEL_19, CMD_DLEVEL_20, CMD_DLEVEL_21, CMD_DLEVEL_22, CMD_DLEVEL_23, CMD_DLEVEL_24, #endif CMD_DLEVEL_JUNK, CMD_DLEVEL_END, CMD_HEALOTHER, CMD_STRING, CMD_SETSTR, CMD_SETMAG, CMD_SETDEX, CMD_SETVIT, CMD_RETOWN, CMD_SPELLXYD, CMD_ITEMEXTRA, CMD_SYNCPUTITEM, CMD_KILLGOLEM, CMD_SYNCQUEST, CMD_ENDSHIELD, CMD_AWAKEGOLEM, #ifdef HELLFIRE CMD_REFLECT, CMD_NAKRUL, CMD_OPENHIVE, CMD_OPENCRYPT, #else CMD_NOVA, CMD_SETSHIELD, CMD_REMSHIELD, #endif FAKE_CMD_SETID, FAKE_CMD_DROPID, NUM_CMDS, } _cmd_id; typedef 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, #ifdef HELLFIRE TOWN_FARMER = 0xA, TOWN_GIRL = 0xB, TOWN_COWFARM = 0xC, #else TOWN_PRIEST = 0xA, #endif } _talker_id; typedef enum _music_id { TMUSIC_TOWN, TMUSIC_L1, TMUSIC_L2, TMUSIC_L3, TMUSIC_L4, #ifdef HELLFIRE TMUSIC_L5, TMUSIC_L6, #endif TMUSIC_INTRO, NUM_MUSIC, } _music_id; typedef enum _mainmenu_selections { MAINMENU_SINGLE_PLAYER = 1, MAINMENU_MULTIPLAYER, MAINMENU_REPLAY_INTRO, #ifdef HELLFIRE MAINMENU_SHOW_SUPPORT, #endif MAINMENU_SHOW_CREDITS, MAINMENU_EXIT_DIABLO, MAINMENU_ATTRACT_MODE, } _mainmenu_selections; typedef enum _selhero_selections { SELHERO_NEW_DUNGEON = 1, SELHERO_CONTINUE = 2, SELHERO_CONNECT = 3, SELHERO_PREVIOUS = 4 } _selhero_selections; typedef 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, } panel_button_id; typedef enum attribute_id { ATTRIB_STR = 0, ATTRIB_MAG = 1, ATTRIB_DEX = 2, ATTRIB_VIT = 3, } attribute_id; typedef 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, } _object_id; typedef 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_FOOD = 0x1C, /* from demo/PSX */ 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, #ifdef HELLFIRE IMISC_RUNEFIRST = 0x2E, IMISC_RUNEF = 0x2F, IMISC_RUNEL = 0x30, IMISC_GR_RUNEL = 0x31, IMISC_GR_RUNEF = 0x32, IMISC_RUNES = 0x33, IMISC_RUNELAST = 0x34, IMISC_AURIC = 0x35, IMISC_NOTE = 0x36, #endif IMISC_INVALID = -1, } item_misc_id; typedef 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_FOOD = 0xE, /* used in demo */ ITYPE_NONE = -1, } item_type; typedef enum _item_indexes { IDI_GOLD, IDI_WARRIOR, IDI_WARRSHLD, IDI_WARRCLUB, IDI_ROGUE, IDI_SORCEROR, IDI_CLEAVER, IDI_FIRSTQUEST = IDI_CLEAVER, IDI_SKCROWN, IDI_INFRARING, IDI_ROCK, IDI_OPTAMULET, IDI_TRING, IDI_BANNER, IDI_HARCREST, IDI_STEELVEIL, IDI_GLDNELIX, IDI_ANVIL, IDI_MUSHROOM, IDI_BRAIN, IDI_FUNGALTM, IDI_SPECELIX, IDI_BLDSTONE, IDI_MAPOFDOOM, IDI_LASTQUEST = IDI_MAPOFDOOM, IDI_EAR, IDI_HEAL, IDI_MANA, IDI_IDENTIFY, IDI_PORTAL, IDI_ARMOFVAL, IDI_FULLHEAL, IDI_FULLMANA, IDI_GRISWOLD, IDI_LGTFORGE, IDI_LAZSTAFF, IDI_RESURRECT, #ifdef HELLFIRE IDI_OIL, IDI_SHORTSTAFF, IDI_BARDSWORD, IDI_BARDDAGGER, IDI_RUNEBOMB, IDI_THEODORE, IDI_AURIC, IDI_NOTE1, IDI_NOTE2, IDI_NOTE3, IDI_FULLNOTE, IDI_BROWNSUIT, IDI_GREYSUIT, #endif } _item_indexes; typedef enum _setlevels { //SL_BUTCHCHAMB = 0x0, SL_SKELKING = 0x1, SL_BONECHAMB = 0x2, SL_MAZE = 0x3, SL_POISONWATER = 0x4, SL_VILEBETRAYER = 0x5, } _setlevels; typedef enum quest_id { Q_ROCK = 0x00, Q_MUSHROOM = 0x01, Q_GARBUD = 0x02, Q_ZHAR = 0x03, Q_VEIL = 0x04, Q_DIABLO = 0x05, Q_BUTCHER = 0x06, Q_LTBANNER = 0x07, Q_BLIND = 0x08, Q_BLOOD = 0x09, Q_ANVIL = 0x0A, Q_WARLORD = 0x0B, Q_SKELKING = 0x0C, Q_PWATER = 0x0D, Q_SCHAMB = 0x0E, Q_BETRAYER = 0x0F, #ifdef HELLFIRE Q_GRAVE = 0x10, Q_FARMER = 0x11, Q_GIRL = 0x12, Q_TRADER = 0x13, Q_DEFILER = 0x14, Q_NAKRUL = 0x15, Q_CORNSTN = 0x16, Q_JERSEY = 0x17, #endif Q_INVALID = -1, } quest_id; typedef enum quest_state { QUEST_NOTAVAIL = 0, QUEST_INIT = 1, QUEST_ACTIVE = 2, QUEST_DONE = 3 } quest_state; typedef enum quest_gametype { QUEST_SINGLE = 0, QUEST_ANY = 1, QUEST_MULTI = 2, } quest_gametype; typedef enum quest_mush_state { QS_INIT = 0, QS_TOMESPAWNED = 1, QS_TOMEGIVEN = 2, QS_MUSHSPAWNED = 3, QS_MUSHPICKED = 4, QS_MUSHGIVEN = 5, QS_BRAINSPAWNED = 6, QS_BRAINGIVEN = 7, } quest_mush_state; typedef 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, } talk_id; typedef 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, #ifndef HELLFIRE UITEM_LGTFORGE = 0x9, #else UITEM_BOVINE = 0x9, #endif 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, } _unique_items; typedef enum plr_class { PC_WARRIOR = 0x0, PC_ROGUE = 0x1, PC_SORCERER = 0x2, #ifdef HELLFIRE PC_MONK = 0x3, PC_BARD = 0x4, PC_BARBARIAN = 0x5, #endif NUM_CLASSES } plr_class; typedef enum _ui_classes { UI_WARRIOR = 0x0, UI_ROGUE = 0x1, UI_SORCERER = 0x2, #ifdef HELLFIRE UI_MONK = 0x3, UI_BARD = 0x4, UI_BARBARIAN = 0x5, #endif UI_NUM_CLASSES, } _ui_classes; typedef enum _walk_path { WALK_NE = 0x1, WALK_NW = 0x2, WALK_SE = 0x3, WALK_SW = 0x4, WALK_N = 0x5, WALK_E = 0x6, WALK_S = 0x7, WALK_W = 0x8, WALK_NONE = -1, } _walk_path; typedef enum player_weapon_type { WT_MELEE = 0, WT_RANGED = 1, } player_weapon_type; typedef enum item_class { ICLASS_NONE = 0, ICLASS_WEAPON = 1, ICLASS_ARMOR = 2, ICLASS_MISC = 3, ICLASS_GOLD = 4, ICLASS_QUEST = 5, } item_class; typedef enum item_drop_rate { IDROP_NEVER = 0, IDROP_REGULAR = 1, IDROP_DOUBLE = 2, } item_drop_rate; typedef 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_MULT_ARROWS = 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, } item_special_effect; typedef enum item_special_effect_hf { ISPLHF_DEVASTATION = 0x01, ISPLHF_DECAY = 0x02, ISPLHF_PERIL = 0x04, ISPLHF_JESTERS = 0x08, ISPLHF_DOPPELGANGER = 0x10, ISPLHF_ACDEMON = 0x20, ISPLHF_ACUNDEAD = 0x40, } item_special_effect_hf; // Logical equipment locations typedef 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, } inv_body_loc; typedef 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 } inv_item; // identifiers for each of the inventory squares // see https://github.com/sanctuary/graphics/blob/master/inventory.png typedef 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 } inv_xy_slot; typedef 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 } player_graphic; typedef enum anim_weapon_id { ANIM_ID_UNARMED = 0x00, ANIM_ID_UNARMED_SHIELD = 0x01, ANIM_ID_SWORD = 0x02, ANIM_ID_SWORD_SHIELD = 0x03, ANIM_ID_BOW = 0x04, ANIM_ID_AXE = 0x05, ANIM_ID_MACE = 0x06, ANIM_ID_MACE_SHIELD = 0x07, ANIM_ID_STAFF = 0x08 } anim_weapon_id; typedef enum anim_armor_id { ANIM_ID_LIGHT_ARMOR = 0x00, #ifndef SPAWN ANIM_ID_MEDIUM_ARMOR = 0x10, ANIM_ID_HEAVY_ARMOR = 0x20 #endif } anim_armor_id; typedef enum shrine_gametype { SHRINETYPE_ANY = 0, SHRINETYPE_SINGLE = 1, SHRINETYPE_MULTI = 2, } shrine_gametype; typedef 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, #ifdef HELLFIRE SHRINE_OILY = 26, SHRINE_GLOWING = 27, SHRINE_MENDICANT = 28, SHRINE_SPARKLING = 29, SHRINE_TOWN = 30, SHRINE_SHIMMERING = 31, SHRINE_SOLAR = 32, SHRINE_MURPHYS = 33, #endif NUM_SHRINETYPE } shrine_type; typedef enum action_id { ACTION_NONE = -1, ACTION_ATTACK = 9, ACTION_RATTACK = 10, ACTION_SPELL = 12, ACTION_OPERATE = 13, ACTION_DISARM = 14, ACTION_PICKUPITEM = 15, // put item in hand (inventory screen open) ACTION_PICKUPAITEM = 16, // put item in inventory ACTION_TALK = 17, ACTION_OPERATETK = 18, // operate via telekinesis ACTION_ATTACKMON = 20, ACTION_ATTACKPLR = 21, ACTION_RATTACKMON = 22, ACTION_RATTACKPLR = 23, ACTION_SPELLMON = 24, ACTION_SPELLPLR = 25, ACTION_SPELLWALL = 26, } action_id; typedef enum dlrg_flag { DLRG_HDOOR = 0x01, DLRG_VDOOR = 0x02, DLRG_CHAMBER = 0x40, DLRG_PROTECTED = 0x80, } dlrg_flag; ================================================ FILE: resource.h ================================================ /** * @file resource.h * * 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 ================================================ FILE: structs.h ================================================ /** * @file structs.h * * Various global structures. */ ////////////////////////////////////////////////// // control ////////////////////////////////////////////////// typedef struct RECT32 { int x; int y; int w; int h; } RECT32; ////////////////////////////////////////////////// // items ////////////////////////////////////////////////// typedef struct PLStruct { const char *PLName; int PLPower; int PLParam1; int PLParam2; char PLMinLvl; int PLIType; BYTE PLGOE; BOOL PLDouble; BOOL PLOk; int PLMinVal; int PLMaxVal; int PLMultVal; } PLStruct; typedef struct UItemStruct { const 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; } UItemStruct; typedef struct ItemDataStruct { int iRnd; char iClass; char iLoc; int iCurs; char itype; char iItemId; const char *iName; const char *iSName; char 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; BOOL iUsable; int iValue; int iMaxValue; } ItemDataStruct; typedef struct ItemGetRecordStruct { int nSeed; unsigned short wCI; int nIndex; unsigned int dwTimestamp; } ItemGetRecordStruct; typedef struct ItemStruct { int _iSeed; WORD _iCreateInfo; int _itype; int _ix; int _iy; BOOL _iAnimFlag; unsigned char *_iAnimData; // PSX name -> ItemFrame int _iAnimLen; // Number of frames in current animation int _iAnimFrame; // Current frame of animation. int _iAnimWidth; int _iAnimWidth2; // width 2? BOOL _iDelFlag; // set when item is flagged for deletion, deprecated in 1.02 char _iSelFlag; BOOL _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 #ifdef HELLFIRE int _iDamAcFlags; #endif } ItemStruct; ////////////////////////////////////////////////// // player ////////////////////////////////////////////////// typedef struct PlayerStruct { int _pmode; char walkpath[MAX_PATH_LENGTH]; BOOLEAN plractive; int destAction; int destParam1; int destParam2; int destParam3; int destParam4; int plrlevel; int _px; // Tile X-position of player int _py; // Tile Y-position of player int _pfutx; // Future tile X-position of player. Set at start of walking animation int _pfuty; // Future tile Y-position of player. Set at start of walking animation int _ptargx; // Target tile X-position for player movment. Set during pathfinding int _ptargy; // Target tile Y-position for player movment. Set during pathfinding int _pownerx; // Tile X-position of player. Set via network on player input int _pownery; // Tile X-position of player. Set via network on player input int _poldx; // Most recent X-position in dPlayer. int _poldy; // Most recent Y-position in dPlayer. int _pxoff; // Player sprite's pixel X-offset from tile. int _pyoff; // Player sprite's pixel Y-offset from tile. int _pxvel; // Pixel X-velocity while walking. Indirectly applied to _pxoff via _pvar6 int _pyvel; // Pixel Y-velocity while walking. Indirectly applied to _pyoff via _pvar7 int _pdir; // Direction faced by player (direction enum) int _nextdir; // Unused int _pgfxnum; // Bitmask indicating what variant of the sprite the player is using. Lower byte define weapon (anim_weapon_id) and higher values define armour (starting with anim_armor_id) unsigned char *_pAnimData; int _pAnimDelay; // Tick length of each frame in the current animation int _pAnimCnt; // Increases by one each game tick, counting how close we are to _pAnimDelay int _pAnimLen; // Number of frames in current animation int _pAnimFrame; // Current frame of animation. int _pAnimWidth; int _pAnimWidth2; int _peflag; int _plid; int _pvid; int _pSpell; char _pSplType; char _pSplFrom; int _pTSpell; char _pTSplType; int _pRSpell; // enum spell_type char _pRSplType; int _pSBkSpell; char _pSBkSplType; char _pSplLvl[64]; unsigned __int64 _pMemSpells; // Bitmask of learned spells unsigned __int64 _pAblSpells; // Bitmask of abilities unsigned __int64 _pScrlSpells; // Bitmask of spells avalible via scrolls UCHAR _pSpellFlags; int _pSplHotKey[4]; char _pSplTHotKey[4]; int _pwtype; BOOLEAN _pBlockFlag; BOOLEAN _pInvincible; char _pLightRad; BOOLEAN _pLvlChanging; // True when the player is transitioning between levels char _pName[PLR_NAME_LEN]; // 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; BOOL _pInfraFlag; int _pVar1; // Used for referring to X-position of player when finishing moving one tile (also used to define target coordinates for spells and ranged attacks) int _pVar2; // Used for referring to Y-position of player when finishing moving one tile (also used to define target coordinates for spells and ranged attacks) int _pVar3; // Player's direction when ending movement. Also used for casting direction of SPL_FIREWALL. int _pVar4; // Used for storing X-position of a tile which should have its BFLAG_PLAYERLR flag removed after walking. When starting to walk the game places the player in the dPlayer array -1 in the Y coordinate, and uses BFLAG_PLAYERLR to check if it should be using -1 to the Y coordinate when rendering the player (also used for storing the level of a spell when the player casts it) int _pVar5; // Used for storing Y-position of a tile which should have its BFLAG_PLAYERLR flag removed after walking. When starting to walk the game places the player in the dPlayer array -1 in the Y coordinate, and uses BFLAG_PLAYERLR to check if it should be using -1 to the Y coordinate when rendering the player (also used for storing the level of a spell when the player casts it) int _pVar6; // Same as _pxoff but contains the value in a higher range int _pVar7; // Same as _pyoff but contains the value in a higher range int _pVar8; // Used for counting how close we are to reaching the next tile when walking (usually counts to 8, which is equal to the walk animation length). Also used for stalling the appearance of the options screen after dying in singleplayer BOOLEAN _pLvlVisited[NUMLEVELS]; BOOLEAN _pSLvlVisited[NUMLEVELS]; // only 10 used int _pGFXLoad; unsigned char *_pNAnim[8]; // Stand animations int _pNFrames; int _pNWidth; unsigned char *_pWAnim[8]; // Walk animations int _pWFrames; int _pWWidth; unsigned char *_pAAnim[8]; // Attack animations int _pAFrames; int _pAWidth; int _pAFNum; unsigned char *_pLAnim[8]; // Lightning spell cast animations unsigned char *_pFAnim[8]; // Fire spell cast animations unsigned char *_pTAnim[8]; // Generic spell cast animations int _pSFrames; int _pSWidth; int _pSFNum; unsigned char *_pHAnim[8]; // Getting hit animations int _pHFrames; int _pHWidth; unsigned char *_pDAnim[8]; // Death animations int _pDFrames; int _pDWidth; unsigned char *_pBAnim[8]; // Block animations int _pBFrames; int _pBWidth; ItemStruct InvBody[NUM_INVLOC]; ItemStruct InvList[NUM_INV_GRID_ELEM]; int _pNumInv; char InvGrid[NUM_INV_GRID_ELEM]; ItemStruct SpdList[MAXBELTITEMS]; ItemStruct HoldItem; int _pIMinDam; int _pIMaxDam; int _pIAC; int _pIBonusDam; int _pIBonusToHit; int _pIBonusAC; int _pIBonusDamMod; unsigned __int64 _pISpells; // Bitmask of staff spell 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; #ifdef HELLFIRE unsigned char pDungMsgs2; #else unsigned char pBattleNet; #endif BOOLEAN pManaShield; char bReserved[3]; WORD wReflections; short wReserved[7]; DWORD pDiabloKillLevel; int pDifficulty; int pDamAcFlags; int dwReserved[5]; 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; void *pReserved; } PlayerStruct; ////////////////////////////////////////////////// // textdat ////////////////////////////////////////////////// typedef struct TextDataStruct { const char *txtstr; int scrlltxt; int txtspd; int sfxnr; } TextDataStruct; ////////////////////////////////////////////////// // missiles ////////////////////////////////////////////////// // TPDEF PTR FCN VOID MIADDPRC // TPDEF PTR FCN VOID MIPROC typedef struct MissileData { unsigned char mName; void (*mAddProc)(int, int, int, int, int, int, char, int, int); void (*mProc)(int); BOOL mDraw; unsigned char mType; unsigned char mResist; unsigned char mFileNum; int mlSFX; int miSFX; } MissileData; typedef struct MisFileData { unsigned char mAnimName; unsigned char mAnimFAmt; const char *mName; int mFlags; unsigned char *mAnimData[16]; unsigned char mAnimDelay[16]; unsigned char mAnimLen[16]; int mAnimWidth[16]; int mAnimWidth2[16]; } MisFileData; typedef struct ChainStruct { int idx; int _mitype; int _mirange; } ChainStruct; typedef struct MissileStruct { int _mitype; // Type of projectile (missile_id) int _mix; // Tile X-position of the missile int _miy; // Tile Y-position of the missile int _mixoff; // Sprite pixel X-offset for the missile int _miyoff; // Sprite pixel Y-offset for the missile int _mixvel; // Missile tile X-velocity while walking. This gets added onto _mitxoff each game tick int _miyvel; // Missile tile Y-velocity while walking. This gets added onto _mitxoff each game tick int _misx; // Initial tile X-position for missile int _misy; // Initial tile Y-position for missile int _mitxoff; // How far the missile has travelled in its lifespan along the X-axis. mix/miy/mxoff/myoff get updated every game tick based on this int _mityoff; // How far the missile has travelled in its lifespan along the Y-axis. mix/miy/mxoff/myoff get updated every game tick based on this int _mimfnum; // The direction of the missile (direction enum) int _mispllvl; BOOL _miDelFlag; // Indicate weather the missile should be deleted BYTE _miAnimType; int _miAnimFlags; unsigned char *_miAnimData; int _miAnimDelay; // Tick length of each frame in the current animation int _miAnimLen; // Number of frames in current animation int _miAnimWidth; int _miAnimWidth2; int _miAnimCnt; // Increases by one each game tick, counting how close we are to _pAnimDelay int _miAnimAdd; int _miAnimFrame; // Current frame of animation. BOOL _miDrawFlag; BOOL _miLightFlag; BOOL _miPreFlag; int _miUniqTrans; int _mirange; // Time to live for the missile in game ticks, oncs 0 the missile will be marked for deletion via _miDelFlag int _misource; int _micaster; int _midam; BOOL _miHitFlag; int _midist; // Used for arrows to measure distance travelled (increases by 1 each game tick). Higher value is a penalty for accuracy calculation when hitting enemy int _mlid; int _mirnd; int _miVar1; int _miVar2; int _miVar3; int _miVar4; int _miVar5; int _miVar6; int _miVar7; int _miVar8; } MissileStruct; ////////////////////////////////////////////////// // effects/sound ////////////////////////////////////////////////// typedef struct CKINFO { DWORD dwSize; DWORD dwOffset; } CKINFO; typedef struct TSnd { WAVEFORMATEX fmt; CKINFO chunk; const char *sound_path; LPDIRECTSOUNDBUFFER DSB; int start_tc; } TSnd; #pragma pack(push, 1) typedef struct TSFX { unsigned char bFlags; const char *pszName; TSnd *pSnd; } TSFX; #pragma pack(pop) ////////////////////////////////////////////////// // monster ////////////////////////////////////////////////// typedef struct AnimStruct { BYTE *CMem; BYTE *Data[8]; int Frames; int Rate; } AnimStruct; typedef struct MonsterData { int width; int mImage; const char *GraphicType; BOOL has_special; const char *sndfile; BOOL snd_special; BOOL has_trans; const char *TransFile; int Frames[6]; int Rate[6]; const char *mName; char mMinDLvl; char mMaxDLvl; char mLevel; int mMinHP; int mMaxHP; char mAi; int mFlags; unsigned char mInt; unsigned char mHit; // BUGFIX: Some monsters overflow this value on high difficulty unsigned char mAFNum; unsigned char mMinDamage; unsigned char mMaxDamage; unsigned char mHit2; // BUGFIX: Some monsters overflow this value on high difficulty unsigned char mAFNum2; unsigned char mMinDamage2; unsigned char mMaxDamage2; unsigned char mArmorClass; char mMonstClass; unsigned short mMagicRes; unsigned short mMagicRes2; unsigned short mTreasure; char mSelFlag; unsigned short mExp; } MonsterData; typedef struct CMonster { #ifdef HELLFIRE int mtype; #else unsigned char mtype; #endif // TODO: Add enum for place flags unsigned char mPlaceFlags; AnimStruct Anims[6]; TSnd *Snds[4][2]; int width; int width2; #ifdef HELLFIRE int mMinHP; int mMaxHP; #else unsigned char mMinHP; unsigned char mMaxHP; #endif BOOL 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) BYTE *trans_file; } CMonster; typedef 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; // Tile X-position of monster int _my; // Tile Y-position of monster int _mfutx; // Future tile X-position of monster. Set at start of walking animation int _mfuty; // Future tile Y-position of monster. Set at start of walking animation int _moldx; // Most recent X-position in dMonster. int _moldy; // Most recent Y-position in dMonster. int _mxoff; // Monster sprite's pixel X-offset from tile. int _myoff; // Monster sprite's pixel Y-offset from tile. int _mxvel; // Pixel X-velocity while walking. Applied to _mxoff int _myvel; // Pixel Y-velocity while walking. Applied to _myoff int _mdir; // Direction faced by monster (direction enum) int _menemy; // The current target of the monster. An index into either the plr or monster array based on the _meflag value. unsigned char _menemyx; // X-coordinate of enemy (usually correspond's to the enemy's futx value) unsigned char _menemyy; // Y-coordinate of enemy (usually correspond's to the enemy's futy value) short falign_52; // probably _mAFNum (unused) unsigned char *_mAnimData; int _mAnimDelay; // Tick length of each frame in the current animation int _mAnimCnt; // Increases by one each game tick, counting how close we are to _pAnimDelay int _mAnimLen; // Number of frames in current animation int _mAnimFrame; // Current frame of animation. BOOL _meflag; BOOL _mDelFlag; int _mVar1; int _mVar2; int _mVar3; int _mVar4; int _mVar5; int _mVar6; // Used as _mxoff but with a higher range so that we can correctly apply velocities of a smaller number int _mVar7; // Used as _myoff but with a higher range so that we can correctly apply velocities of a smaller number int _mVar8; // Value used to measure progress for moving from one tile to another int _mmaxhp; int _mhitpoints; unsigned char _mAi; unsigned char _mint; short falign_9A; int _mFlags; BYTE _msquelch; 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; #ifdef HELLFIRE char mArmorClass; #else unsigned char mArmorClass; #endif char falign_CB; unsigned short mMagicRes; int mtalkmsg; unsigned char leader; unsigned char leaderflag; unsigned char packsize; unsigned char mlid; const char *mName; CMonster *MType; MonsterData *MData; } MonsterStruct; typedef struct UniqMonstStruct { #ifdef HELLFIRE int mtype; #else char mtype; #endif const char *mName; const char *mTrnName; 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; } UniqMonstStruct; ////////////////////////////////////////////////// // objects ////////////////////////////////////////////////// typedef struct ObjDataStruct { char oload; char ofindex; char ominlvl; char omaxlvl; char olvltype; char otheme; char oquest; int oAnimFlag; int oAnimDelay; // Tick length of each frame in the current animation int oAnimLen; // Number of frames in current animation int oAnimWidth; BOOL oSolidFlag; BOOL oMissFlag; BOOL oLightFlag; char oBreak; char oSelFlag; BOOL oTrapFlag; } ObjDataStruct; typedef struct ObjectStruct { int _otype; int _ox; int _oy; int _oLight; int _oAnimFlag; unsigned char *_oAnimData; int _oAnimDelay; // Tick length of each frame in the current animation int _oAnimCnt; // Increases by one each game tick, counting how close we are to _pAnimDelay int _oAnimLen; // Number of frames in current animation int _oAnimFrame; // Current frame of animation. int _oAnimWidth; int _oAnimWidth2; BOOL _oDelFlag; char _oBreak; // check BOOL _oSolidFlag; BOOL _oMissFlag; char _oSelFlag; // check BOOL _oPreFlag; BOOL _oTrapFlag; BOOL _oDoorFlag; int _olid; int _oRndSeed; int _oVar1; int _oVar2; int _oVar3; int _oVar4; int _oVar5; int _oVar6; int _oVar7; int _oVar8; } ObjectStruct; ////////////////////////////////////////////////// // portal ////////////////////////////////////////////////// typedef struct PortalStruct { BOOL open; int x; int y; int level; int ltype; BOOL setlvl; } PortalStruct; ////////////////////////////////////////////////// // msg ////////////////////////////////////////////////// #pragma pack(push, 1) typedef struct TCmd { BYTE bCmd; } TCmd; typedef struct TCmdLoc { BYTE bCmd; BYTE x; BYTE y; } TCmdLoc; typedef struct TCmdLocParam1 { BYTE bCmd; BYTE x; BYTE y; WORD wParam1; } TCmdLocParam1; typedef struct TCmdLocParam2 { BYTE bCmd; BYTE x; BYTE y; WORD wParam1; WORD wParam2; } TCmdLocParam2; typedef struct TCmdLocParam3 { BYTE bCmd; BYTE x; BYTE y; WORD wParam1; WORD wParam2; WORD wParam3; } TCmdLocParam3; typedef struct TCmdParam1 { BYTE bCmd; WORD wParam1; } TCmdParam1; typedef struct TCmdParam2 { BYTE bCmd; WORD wParam1; WORD wParam2; } TCmdParam2; typedef struct TCmdParam3 { BYTE bCmd; WORD wParam1; WORD wParam2; WORD wParam3; } TCmdParam3; typedef struct TCmdGolem { BYTE bCmd; BYTE _mx; BYTE _my; BYTE _mdir; char _menemy; int _mhitpoints; BYTE _currlevel; } TCmdGolem; typedef struct TCmdQuest { BYTE bCmd; BYTE q; BYTE qstate; BYTE qlog; BYTE qvar1; } TCmdQuest; typedef struct TCmdGItem { BYTE bCmd; BYTE bMaster; BYTE bPnum; BYTE bCursitem; BYTE bLevel; BYTE x; BYTE y; WORD wIndx; WORD wCI; int dwSeed; BYTE bId; BYTE bDur; BYTE bMDur; BYTE bCh; BYTE bMCh; WORD wValue; DWORD dwBuff; int dwTime; #ifdef HELLFIRE WORD wToHit; WORD wMaxDam; BYTE bMinStr; BYTE bMinMag; BYTE bMinDex; BYTE bAC; #endif } TCmdGItem; typedef struct TCmdPItem { BYTE bCmd; BYTE x; BYTE y; WORD wIndx; WORD wCI; int dwSeed; BYTE bId; BYTE bDur; BYTE bMDur; BYTE bCh; BYTE bMCh; WORD wValue; DWORD dwBuff; #ifdef HELLFIRE WORD wToHit; WORD wMaxDam; BYTE bMinStr; BYTE bMinMag; BYTE bMinDex; BYTE bAC; #endif } TCmdPItem; typedef struct TCmdChItem { BYTE bCmd; BYTE bLoc; WORD wIndx; WORD wCI; int dwSeed; BOOLEAN bId; } TCmdChItem; typedef struct TCmdDelItem { BYTE bCmd; BYTE bLoc; } TCmdDelItem; typedef struct TCmdDamage { BYTE bCmd; BYTE bPlr; DWORD dwDam; } TCmdDamage; #ifdef HELLFIRE typedef struct TCmdMonDamage { BYTE bCmd; WORD wMon; DWORD dwDam; } TCmdMonDamage; #endif typedef struct TCmdPlrInfoHdr { BYTE bCmd; WORD wOffset; WORD wBytes; } TCmdPlrInfoHdr; typedef struct TCmdString { BYTE bCmd; char str[MAX_SEND_STR_LEN]; } TCmdString; typedef struct TFakeCmdPlr { BYTE bCmd; BYTE bPlr; } TFakeCmdPlr; typedef struct TFakeDropPlr { BYTE bCmd; BYTE bPlr; DWORD dwReason; } TFakeDropPlr; typedef struct TSyncHeader { BYTE bCmd; BYTE bLevel; WORD wLen; BYTE bObjId; BYTE bObjCmd; BYTE bItemI; BYTE bItemX; BYTE bItemY; WORD wItemIndx; WORD wItemCI; DWORD dwItemSeed; BYTE bItemId; BYTE bItemDur; BYTE bItemMDur; BYTE bItemCh; BYTE bItemMCh; WORD wItemVal; DWORD dwItemBuff; BYTE bPInvLoc; WORD wPInvIndx; WORD wPInvCI; DWORD dwPInvSeed; BYTE bPInvId; #ifdef HELLFIRE WORD wToHit; WORD wMaxDam; BYTE bMinStr; BYTE bMinMag; BYTE bMinDex; BYTE bAC; #endif } TSyncHeader; typedef struct TSyncMonster { BYTE _mndx; BYTE _mx; BYTE _my; BYTE _menemy; BYTE _mdelta; } TSyncMonster; typedef struct TPktHdr { BYTE px; BYTE py; BYTE targx; BYTE targy; int php; int pmhp; BYTE bstr; BYTE bmag; BYTE bdex; WORD wCheck; WORD wLen; } TPktHdr; typedef struct TPkt { TPktHdr hdr; BYTE body[493]; } TPkt; typedef struct DMonsterStr { BYTE _mx; BYTE _my; BYTE _mdir; BYTE _menemy; BYTE _mactive; int _mhitpoints; } DMonsterStr; typedef struct DObjectStr { BYTE bCmd; } DObjectStr; typedef struct DLevel { TCmdPItem item[MAXITEMS]; DObjectStr object[MAXOBJECTS]; DMonsterStr monster[MAXMONSTERS]; } DLevel; typedef struct LocalLevel { BYTE automapsv[DMAXX][DMAXY]; } LocalLevel; typedef struct DPortal { BYTE x; BYTE y; BYTE level; BYTE ltype; BYTE setlvl; } DPortal; typedef struct MultiQuests { BYTE qstate; BYTE qlog; BYTE qvar1; } MultiQuests; typedef struct DJunk { DPortal portal[MAXPORTAL]; MultiQuests quests[MAXMULTIQUESTS]; } DJunk; #pragma pack(pop) typedef struct TMegaPkt { struct TMegaPkt *pNext; DWORD dwSpaceLeft; BYTE data[32000]; } TMegaPkt; typedef struct TBuffer { DWORD dwNextWriteOffset; BYTE bData[4096]; } TBuffer; ////////////////////////////////////////////////// // quests ////////////////////////////////////////////////// typedef struct QuestStruct { unsigned char _qlevel; unsigned char _qtype; unsigned char _qactive; unsigned char _qlvltype; int _qtx; int _qty; unsigned char _qslvl; unsigned char _qidx; #ifndef HELLFIRE unsigned char _qmsg; #else unsigned int _qmsg; #endif unsigned char _qvar1; unsigned char _qvar2; BOOL _qlog; } QuestStruct; typedef 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; const char *_qlstr; } QuestData; #ifdef HELLFIRE typedef struct CornerStoneStruct { int x; int y; BOOL activated; ItemStruct item; } CornerStoneStruct; #endif ////////////////////////////////////////////////// // gamemenu/gmenu ////////////////////////////////////////////////// // TPDEF PTR FCN VOID TMenuFcn typedef struct TMenuItem { DWORD dwFlags; const char *pszStr; void (*fnMenu)(BOOL); /* fix, should have one arg */ } TMenuItem; // TPDEF PTR FCN VOID TMenuUpdateFcn ////////////////////////////////////////////////// // spells ////////////////////////////////////////////////// typedef struct SpellData { unsigned char sName; unsigned char sManaCost; unsigned char sType; const char *sNameText; const char *sSkillText; int sBookLvl; int sStaffLvl; BOOL sTargeted; BOOL sTownSpell; int sMinInt; unsigned char sSFX; unsigned char sMissiles[3]; unsigned char sManaAdj; unsigned char sMinMana; int sStaffMin; int sStaffMax; int sBookCost; int sStaffCost; } SpellData; ////////////////////////////////////////////////// // towners ////////////////////////////////////////////////// typedef struct TNQ { unsigned char _qsttype; unsigned char _qstmsg; BOOLEAN _qstmsgact; } TNQ; typedef struct TownerStruct { int _tmode; int _ttype; int _tx; // Tile X-position of NPC int _ty; // Tile Y-position of NPC int _txoff; // Sprite X-offset (unused) int _tyoff; // Sprite Y-offset (unused) int _txvel; // X-velocity during movement (unused) int _tyvel; // Y-velocity during movement (unused) int _tdir; // Facing of NPC (unused) unsigned char *_tAnimData; int _tAnimDelay; // Tick length of each frame in the current animation int _tAnimCnt; // Increases by one each game tick, counting how close we are to _pAnimDelay int _tAnimLen; // Number of frames in current animation int _tAnimFrame; // Current frame of animation. int _tAnimFrameCnt; char _tAnimOrder; int _tAnimWidth; int _tAnimWidth2; int _tTenPer; int _teflag; int _tbtcnt; int _tSelFlag; BOOL _tMsgSaid; TNQ qsts[MAXQUESTS]; int _tSeed; int _tVar1; int _tVar2; int _tVar3; int _tVar4; char _tName[PLR_NAME_LEN]; unsigned char *_tNAnim[8]; int _tNFrames; unsigned char *_tNData; } TownerStruct; typedef 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; #ifdef HELLFIRE int _qgrv; int _qfarm; int _qgirl; int _qtrade; int _qdefiler; int _qnakrul; int _qjersy; int _qhf8; #endif } QuestTalkData; ////////////////////////////////////////////////// // gendung ////////////////////////////////////////////////// typedef struct ScrollStruct { int _sxoff; // X-offset of camera position. This usually corresponds to a negative version of plr[myplr]._pxoff int _syoff; // Y-offset of camera position. This usually corresponds to a negative version of plr[myplr]._pyoff int _sdx; int _sdy; int _sdir; } ScrollStruct; typedef struct THEME_LOC { int x; int y; int ttval; int width; int height; } THEME_LOC; typedef struct MICROS { WORD mt[16]; } MICROS; ////////////////////////////////////////////////// // drlg ////////////////////////////////////////////////// typedef struct ShadowStruct { unsigned char strig; unsigned char s1; unsigned char s2; unsigned char s3; unsigned char nv1; unsigned char nv2; unsigned char nv3; } ShadowStruct; typedef struct HALLNODE { int nHallx1; int nHally1; int nHallx2; int nHally2; int nHalldir; struct HALLNODE *pNext; } HALLNODE; typedef struct ROOMNODE { int nRoomx1; int nRoomy1; int nRoomx2; int nRoomy2; int nRoomDest; } ROOMNODE; ////////////////////////////////////////////////// // themes ////////////////////////////////////////////////// typedef struct ThemeStruct { char ttype; /* aligned 4 */ int ttval; } ThemeStruct; ////////////////////////////////////////////////// // inv ////////////////////////////////////////////////// typedef struct InvXY { int X; int Y; } InvXY; ////////////////////////////////////////////////// // lighting ////////////////////////////////////////////////// typedef 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; } LightListStruct; ////////////////////////////////////////////////// // dead ////////////////////////////////////////////////// typedef struct DeadStruct { unsigned char *_deadData[8]; int _deadFrame; int _deadWidth; int _deadWidth2; char _deadtrans; } DeadStruct; ////////////////////////////////////////////////// // diabloui ////////////////////////////////////////////////// // TPDEF PTR FCN VOID PLAYSND typedef struct _gamedata { int dwSeed; BYTE bDiff; } _gamedata; typedef struct _uidefaultstats { WORD strength; WORD magic; WORD dexterity; WORD vitality; } _uidefaultstats; typedef struct _uiheroinfo { struct _uiheroinfo *next; char name[16]; WORD level; BYTE heroclass; BYTE herorank; WORD strength; WORD magic; WORD dexterity; WORD vitality; int gold; int hassaved; BOOL spawned; } _uiheroinfo; // 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 ////////////////////////////////////////////////// // storm ////////////////////////////////////////////////// // TPDEF PTR FCN UCHAR SMSGIDLEPROC // TPDEF PTR FCN VOID SMSGHANDLER typedef struct _SNETCAPS { DWORD size; DWORD flags; DWORD maxmessagesize; DWORD maxqueuesize; DWORD maxplayers; DWORD bytessec; DWORD latencyms; DWORD defaultturnssec; DWORD defaultturnsintransit; } _SNETCAPS; typedef struct _SNETEVENT { DWORD eventid; DWORD playerid; void *data; DWORD databytes; } _SNETEVENT; // 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 typedef struct _SNETPLAYERDATA { int size; char *playername; char *playerdescription; int reserved; } _SNETPLAYERDATA; typedef struct _SNETPROGRAMDATA { int size; const char *programname; const char *programdescription; int programid; int versionid; int reserved1; int maxplayers; _gamedata *initdata; int initdatabytes; void *reserved2; int optcategorybits; char *cdkey; char *registereduser; int spawned; int lcid; } _SNETPROGRAMDATA; typedef struct _SNETUIDATA { int size; int uiflags; HWND parentwindow; void (*artcallback)(); void (*authcallback)(); void (*createcallback)(); void (*drawdesccallback)(); void (*selectedcallback)(); void (*messageboxcallback)(); void (*soundcallback)(); void (*statuscallback)(); void (*getdatacallback)(); void (*categorycallback)(); void (*categorylistcallback)(); void (*newaccountcallback)(); void (*profilecallback)(); const char **profilefields; void (*profilebitmapcallback)(); int(__stdcall *selectnamecallback)( const struct _SNETPROGRAMDATA *, const struct _SNETPLAYERDATA *, const struct _SNETUIDATA *, const struct _SNETVERSIONDATA *, DWORD provider, /* e.g. 'IPXN', 'BNET' etc. */ char *, DWORD, /* character name will be copied here */ char *, DWORD, /* character "description" will be copied here (used to advertise games) */ BOOL * /* new character? - unsure about this */ ); void (*changenamecallback)(); } _SNETUIDATA; typedef struct _SNETVERSIONDATA { int size; const char *versionstring; const char *executablefile; const char *originalarchivefile; const char *patcharchivefile; } _SNETVERSIONDATA; // TPDEF PTR FCN UCHAR SNETSPIBIND // TPDEF PTR FCN UCHAR SNETSPIQUERY ////////////////////////////////////////////////// // pack ////////////////////////////////////////////////// #pragma pack(push, 1) typedef struct PkItemStruct { DWORD iSeed; WORD iCreateInfo; WORD idx; BYTE bId; BYTE bDur; BYTE bMDur; BYTE bCh; BYTE bMCh; WORD wValue; DWORD dwBuff; } PkItemStruct; typedef struct PkPlayerStruct { FILETIME archiveTime; char destAction; char destParam1; char destParam2; BYTE plrlevel; BYTE px; BYTE py; BYTE targx; BYTE targy; char pName[PLR_NAME_LEN]; char pClass; BYTE pBaseStr; BYTE pBaseMag; BYTE pBaseDex; BYTE pBaseVit; char pLevel; BYTE pStatPts; int pExperience; int pGold; int pHPBase; int pMaxHPBase; int pManaBase; int pMaxManaBase; char pSplLvl[37]; // Should be MAX_SPELLS but set to 37 to make save games compatible unsigned __int64 pMemSpells; PkItemStruct InvBody[NUM_INVLOC]; PkItemStruct InvList[NUM_INV_GRID_ELEM]; char InvGrid[NUM_INV_GRID_ELEM]; BYTE _pNumInv; PkItemStruct SpdList[MAXBELTITEMS]; char pTownWarps; char pDungMsgs; char pLvlLoad; #ifdef HELLFIRE unsigned char pDungMsgs2; #else char pBattleNet; #endif BOOLEAN pManaShield; char bReserved[3]; WORD wReflections; short wReserved2; char pSplLvl2[10]; // Hellfire spells short wReserved8; DWORD pDiabloKillLevel; int pDifficulty; int pDamAcFlags; int dwReserved[5]; } PkPlayerStruct; #pragma pack(pop) ////////////////////////////////////////////////// // path ////////////////////////////////////////////////// typedef struct PATHNODE { char f; char h; char g; int x; int y; struct PATHNODE *Parent; struct PATHNODE *Child[8]; struct PATHNODE *NextNode; } PATHNODE; // TPDEF PTR FCN UCHAR CHECKFUNC1 // TPDEF PTR FCN UCHAR CHECKFUNC ////////////////////////////////////////////////// // sha ////////////////////////////////////////////////// typedef struct SHA1Context { int state[5]; int count[2]; char buffer[64]; } SHA1Context; ////////////////////////////////////////////////// // tmsg ////////////////////////////////////////////////// #pragma pack(push, 1) typedef struct TMsg TMsg; typedef struct TMsgHdr { TMsg *pNext; int dwTime; BYTE bLen; } TMsgHdr; typedef struct TMsg { TMsgHdr hdr; // this is actually alignment padding, but the message body is appended to the struct // so it's convenient to use byte-alignment and name it "body" unsigned char body[3]; } TMsg; #pragma pack(pop) ////////////////////////////////////////////////// // mpqapi ////////////////////////////////////////////////// typedef struct _FILEHEADER { int signature; int headersize; int filesize; WORD version; short sectorsizeid; int hashoffset; int blockoffset; int hashcount; int blockcount; char pad[72]; } _FILEHEADER; typedef struct _HASHENTRY { int hashcheck[2]; int lcid; int block; } _HASHENTRY; typedef struct _BLOCKENTRY { int offset; int sizealloc; int sizefile; int flags; } _BLOCKENTRY; // TPDEF PTR FCN UCHAR TGetNameFcn // TPDEF PTR FCN VOID TCrypt ////////////////////////////////////////////////// // trigs ////////////////////////////////////////////////// typedef struct TriggerStruct { int _tx; int _ty; int _tmsg; int _tlvl; } TriggerStruct; ////////////////////////////////////////////////// // stores ////////////////////////////////////////////////// typedef struct STextStruct { int _sx; int _syoff; char _sstr[128]; BOOL _sjust; char _sclr; int _sline; BOOL _ssel; int _sval; } STextStruct; ////////////////////////////////////////////////// // wave ////////////////////////////////////////////////// typedef struct MEMFILE { DWORD end; LONG offset; DWORD buf_len; DWORD dist; DWORD bytes_to_read; BYTE *buf; HANDLE file; } MEMFILE; ////////////////////////////////////////////////// // plrmsg ////////////////////////////////////////////////// typedef struct _plrmsg { DWORD time; unsigned char player; char str[144]; } _plrmsg; ////////////////////////////////////////////////// // capture ////////////////////////////////////////////////// typedef struct _PcxHeader { BYTE Manufacturer; BYTE Version; BYTE Encoding; BYTE BitsPerPixel; WORD Xmin; WORD Ymin; WORD Xmax; WORD Ymax; WORD HDpi; WORD VDpi; BYTE Colormap[48]; BYTE Reserved; BYTE NPlanes; WORD BytesPerLine; WORD PaletteInfo; WORD HscreenSize; WORD VscreenSize; BYTE Filler[54]; } PCXHEADER; ////////////////////////////////////////////////// // encrypt ////////////////////////////////////////////////// typedef struct TDataInfo { BYTE *srcData; DWORD srcOffset; BYTE *destData; DWORD destOffset; DWORD size; } TDataInfo; ================================================ FILE: types.h ================================================ /** * @file types.h * * Include OS headers and set compiler state. */ #ifndef _TYPES_H #define _TYPES_H #define WIN32_LEAN_AND_MEAN #include "resource.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __GNUC__ #include #endif // tell Visual C++ to shut the hell up #ifdef _MSC_VER #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 : 4244) // conversion loss #pragma warning(disable : 4146) // negative unsigned #pragma warning(disable : 4996) // deprecation warning #pragma warning(disable : 4309) // VC2017: truncation of constant value #pragma warning(disable : 4267) // VC2017: conversion from 'size_t' to 'char' #pragma warning(disable : 4302) // VC2017: type cast truncation #pragma warning(disable : 4334) // VC2017: result of 32-bit shift implicitly converted to 64 bits #endif #include "defs.h" #include "enums.h" #include "structs.h" #if (_MSC_VER >= 800) && (_MSC_VER <= 1200) #define USE_ASM #endif // If defined, use copy protection [Default -> Defined] #if !defined(_DEBUG) && !defined(SPAWN) #define COPYPROT #endif // 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] #ifdef _DEBUG #define SLEEPFIX #endif // If defined, fix palette glitch in Windows Vista+ [Default -> Undefined] //#define COLORFIX #endif