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
================================================
[](https://circleci.com/gh/diasurgical/devilution)
[](https://www.travis-ci.com/diasurgical/devilution)
[](https://ci.appveyor.com/project/AJenbo/devilution)
[](https://github.com/diasurgical/devilution/releases)
[](https://github.com/diasurgical/devilution/stargazers)
 [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

Example 2: New Diablo 2-like trade screen

# 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:


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