Extract baked sprite shadows and draw them separately

The original sprites have their shadow drawn into them as black pixels.
All of these shadows were made by one function: the sprite squashed to
a third of its height and sheared to the left, measured from a baseline
row B:

    v  = (B - y) / 3
    ys = B - 2 - v
    xs = x - (3 * v) / 4

Only the choice of baseline differs between sprites. It is now recorded
per sprite in a new `shadowRule` column of the monster, object, towner
and class sprite data files:

 * `FirstFrame`: the lowest opaque row of the first frame
 * `EachFrame`: the lowest opaque row of each frame
 * `FirstFrame+N`: the same plus N rows, for flying monsters
 * `None`: no shadow
 * `Baked`: a shadow that cannot be told apart from black parts of the
   sprite, so it is left in the sprite

A rule can be followed by `|Unexplained` and `|Stray` for the few
sprites that the function does not reproduce exactly. The rule is empty
for the Hellfire bard and barbarian, whose sprites were not available.

When sprites are loaded, `ExtractClxShadows` removes the shadow from
each sprite and stores it as a mask of horizontal spans in the CLX
frame header, so it is available wherever the sprite is. The shadow is
drawn right before its sprite, which gives the same picture as before.

A new "Transparent Shadows" graphics option blends the shadows with
what is underneath instead of covering it. It is off by default.
In debug builds, `dev.display.shadows()` toggles drawing them.

Transparent shadows are not perfect. A black pixel of a sprite that
lies inside the sprite's own shadow looks exactly like shadow, so it is
extracted with it and becomes see-through. For example, the warrior in
light armor with a sword and shield, facing southwest, is missing a few
pixels from his left knee. Getting this perfect will likely require
overriding the shadow masks of a handful of sprites, which is something
that can be done with AI in the future.

The rules were found and checked with `tools/shadow_search`, against
all player, monster, towner and object sprites of Diablo and Hellfire:
139,943 frames in 1,438 files. Of the 136,918 frames that have an
extractable shadow, 99.77% are reproduced pixel for pixel.

Extraction adds about 14 us per frame when a sprite is loaded
(about 14 ms for all animations of a character). For the original
player sprites, the sprites with their shadow masks take 0.3% less
memory than before.

Drawing a sprite with its shadow, per sprite, for all sprites of each
kind (`shadow_extract_check <mpq> render`, release build, fully visible
sprites, Ryzen AI Max+ 395):

                          Players    Monsters   Monk
    Without lighting
      Before              2,111 ns   2,444 ns   2,109 ns
      Opaque shadow       -9.5%      -10.1%     -6.1%
      Transparent shadow  +10.0%     +7.5%      +9.0%
    With a light table
      Before              2,659 ns   2,983 ns   2,548 ns
      Opaque shadow       -5.2%      -4.5%      -2.3%
      Transparent shadow  +10.9%     +10.2%     +10.4%

Opaque shadows are a little faster to draw than before: a shadow is now
a short list of spans instead of many commands in the sprite. Blending
a shadow costs about as much again as that saves. Either way the frame
rate is practically unchanged: with about 10 such sprites per frame,
it comes to about +0.2% FPS with opaque shadows and -0.3% with
transparent ones in an unthrottled demo playback, where the 3 modes
measured within noise of each other.

Selection outlines can differ by a pixel where a shadow touches the
sprite: their shape used to depend on how the black pixels of the
shadow were encoded.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Gleb Mazovetskiy
2026-10-11 21:18:52 +01:00
co-authored by Claude Opus 5.5
parent 3755190275
commit debe33ca7b
50 changed files with 7429 additions and 400 deletions
+1
View File
@@ -475,3 +475,4 @@ uwp-project/Assets/ui_art
/tmp/
/compile_commands.json
/tools/tmp
/.claude/
+14
View File
@@ -51,6 +51,7 @@ set(tests
)
set(standalone_tests
cl2_to_clx_test
clx_shadow_test
codec_test
crawl_test
data_file_test
@@ -64,6 +65,7 @@ set(standalone_tests
vision_test
random_test
rectangle_test
shadow_rule_test
sheen_bidi_test
static_vector_test
str_cat_test
@@ -125,6 +127,17 @@ target_link_dependencies(cl2_to_clx_test
libdevilutionx_log
libdevilutionx_surface
)
target_link_dependencies(clx_shadow_test
PRIVATE
DevilutionX::SDL
app_fatal_for_testing
language_for_testing
libdevilutionx_clx_render
libdevilutionx_clx_shadow
libdevilutionx_endian_write
libdevilutionx_log
libdevilutionx_surface
)
target_link_dependencies(codec_test PRIVATE libdevilutionx_codec app_fatal_for_testing)
add_custom_target(clx_render_benchmark_resources
@@ -174,6 +187,7 @@ target_link_dependencies(palette_blending_benchmark
app_fatal_for_testing
)
target_link_dependencies(parse_int_test PRIVATE libdevilutionx_parse_int)
target_link_dependencies(shadow_rule_test PRIVATE libdevilutionx_strings)
target_link_dependencies(path_test PRIVATE libdevilutionx_pathfinding libdevilutionx_direction app_fatal_for_testing)
target_link_dependencies(vision_test PRIVATE libdevilutionx_vision)
target_link_dependencies(path_benchmark PRIVATE libdevilutionx_pathfinding app_fatal_for_testing)
+5
View File
@@ -39,6 +39,7 @@ if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg.cmake$")
option(USE_GETTEXT_FROM_VCPKG "Add vcpkg dependency for gettext[tools] for compiling translations" OFF)
endif()
option(BUILD_TESTING "Build tests." ON)
option(BUILD_SHADOW_SEARCH "Build the player sprite shadow transform search tool (tools/shadow_search)." OFF)
# These must be included after the options above but before the `project` call.
include(VcPkgManifestFeatures)
@@ -443,6 +444,10 @@ if(BUILD_TESTING)
include(Tests)
endif()
if(BUILD_SHADOW_SEARCH)
add_subdirectory(tools/shadow_search)
endif()
include(functions/set_relative_file_macro)
set_relative_file_macro(${BIN_TARGET})
+11
View File
@@ -228,6 +228,16 @@ target_link_dependencies(libdevilutionx_cl2_to_clx
libdevilutionx_endian_write
)
add_devilutionx_object_library(libdevilutionx_clx_shadow
utils/clx_shadow.cpp
)
target_link_dependencies(libdevilutionx_clx_shadow
PUBLIC
libdevilutionx_strings
PRIVATE
libdevilutionx_endian_write
)
add_devilutionx_object_library(libdevilutionx_clx_render
engine/render/clx_render.cpp
)
@@ -1060,6 +1070,7 @@ target_link_dependencies(libdevilutionx PUBLIC
unordered_dense::unordered_dense
libdevilutionx_assets
libdevilutionx_clx_render
libdevilutionx_clx_shadow
libdevilutionx_codec
libdevilutionx_config
libdevilutionx_control
+1
View File
@@ -35,6 +35,7 @@ bool DebugInvisible = false;
bool DebugVision = false;
bool DebugPath = false;
bool DebugGrid = false;
bool DebugHideShadows = false;
ankerl::unordered_dense::map<int, Point> DebugCoordsMap;
bool DebugScrollViewEnabled = false;
std::string debugTRN;
+2
View File
@@ -25,6 +25,8 @@ extern bool DebugInvisible;
extern bool DebugVision;
extern bool DebugPath;
extern bool DebugGrid;
/** Hides the shadows that are drawn separately from their sprites (see `shadow_mask.hpp`). */
extern bool DebugHideShadows;
extern ankerl::unordered_dense::map<int, Point> DebugCoordsMap;
extern bool DebugScrollViewEnabled;
extern std::string debugTRN;
+18 -1
View File
@@ -12,7 +12,7 @@
* 1. CLX frame header stores frame width and height.
* 2. CLX frame header does not store 32-pixel block offsets.
*
* CLX frame header is 6 bytes:
* CLX frame header is at least 6 bytes:
*
* Bytes | Type | Value
* :-----:|:--------:|-------------
@@ -20,6 +20,8 @@
* 2..4 | uint16_t | width
* 4..6 | uint16_t | height
*
* A header larger than 6 bytes holds the shadow mask of the sprite, see `shadow_mask.hpp`.
*
* CL2 reference: https://github.com/savagesteel/d1-file-formats/blob/master/PC-Mac/CL2.md#2-file-structure
*/
@@ -42,6 +44,9 @@ class OptionalClxSprite;
*/
class ClxSprite {
public:
/** The size of a frame header without an extension. */
static constexpr uint16_t BaseHeaderSize = 6;
explicit constexpr ClxSprite(const uint8_t *data, uint32_t dataSize)
: data_(data)
, pixel_data_size_(dataSize - LoadLE16(data))
@@ -59,6 +64,18 @@ public:
return LoadLE16(&data_[4]);
}
/** @brief The size of the frame header, including anything that follows the height. */
[[nodiscard]] constexpr uint16_t headerSize() const
{
return LoadLE16(data_);
}
/** @brief The part of the frame header that follows the height. Empty for most sprites. */
[[nodiscard]] constexpr const uint8_t *headerExtension() const
{
return &data_[BaseHeaderSize];
}
/**
* @brief The raw pixel data (CL2 frame data).
*
+62
View File
@@ -7,10 +7,12 @@
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <format>
#include "engine/point.hpp"
#include "engine/render/blit_impl.hpp"
#include "engine/shadow_mask.hpp"
#include "engine/surface.hpp"
#include "utils/attributes.h"
#include "utils/clx_decode.hpp"
@@ -604,6 +606,66 @@ void ClxDrawBlended(const Surface &out, Point position, ClxSprite clx)
DoRenderBackwards(out, position, clx.pixelData(), clx.pixelDataSize(), clx.width(), clx.height(), BlitBlended {});
}
namespace {
/**
* @brief Calls `spanFn(dst, width)` for every span of the shadow mask, clipped to the output buffer.
*/
template <typename SpanFn>
DVL_ALWAYS_INLINE void DoRenderShadow(const Surface &out, Point position, ShadowMask mask, SpanFn &&spanFn)
{
const int outWidth = out.w();
const int outHeight = out.h();
mask.forEachSpan([&](uint16_t rowFromBottom, ShadowSpan span) {
const int y = position.y - rowFromBottom;
if (y < 0 || y >= outHeight) return;
int x = position.x + span.x;
int width = span.width;
if (x < 0) {
width += x;
x = 0;
}
if (x + width > outWidth) width = outWidth - x;
if (width <= 0) return;
spanFn(out.at(x, y), static_cast<unsigned>(width));
});
}
/** Blends `width` pixels with black. */
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void BlendWithBlack(uint8_t *dst, unsigned width)
{
#if DEVILUTIONX_PALETTE_TRANSPARENCY_BLACK_16_LUT
// Two pixels per lookup. Unlike the rectangle blend in `primitive_render.cpp`, this does
// not need the pixels to be aligned, which matters because shadow spans are short.
for (; width >= 2; width -= 2, dst += 2) {
const uint16_t blended = paletteTransparencyLookupBlack16[dst[0] | (dst[1] << 8U)];
dst[0] = static_cast<uint8_t>(blended);
dst[1] = static_cast<uint8_t>(blended >> 8U);
}
if (width != 0) *dst = paletteTransparencyLookup[0][*dst];
#else
const uint8_t *const lookupTable = paletteTransparencyLookup[0];
for (; width != 0; --width, ++dst)
*dst = lookupTable[*dst];
#endif
}
} // namespace
void ClxDrawShadow(const Surface &out, Point position, ClxSprite clx)
{
if (!HasShadowMask(clx)) return;
DoRenderShadow(out, position, GetShadowMask(clx), [](uint8_t *dst, unsigned width) {
std::memset(dst, 0, width);
});
}
void ClxDrawShadowBlended(const Surface &out, Point position, ClxSprite clx)
{
if (!HasShadowMask(clx)) return;
DoRenderShadow(out, position, GetShadowMask(clx), BlendWithBlack);
}
void ClxDrawBlendedTRN(const Surface &out, Point position, ClxSprite clx, const uint8_t *trn)
{
DoRenderBackwards(out, position, clx.pixelData(), clx.pixelDataSize(), clx.width(), clx.height(), BlitBlendedWithMap { trn });
+17
View File
@@ -88,6 +88,23 @@ void ClxDrawBlendedTRN(const Surface &out, Point position, ClxSprite clx, const
*/
void ClxDrawBlended(const Surface &out, Point position, ClxSprite clx);
/**
* @brief Draws the shadow of the sprite in black.
*
* Does nothing if the sprite has no shadow mask (see `shadow_mask.hpp`).
* Drawing the shadow and then the sprite itself gives the sprite as it was before its shadow was extracted.
*
* @param out Output buffer
* @param position Target buffer coordinate, the same as for drawing the sprite
* @param clx CLX frame
*/
void ClxDrawShadow(const Surface &out, Point position, ClxSprite clx);
/**
* @brief Same as `ClxDrawShadow` but darkens what is underneath instead of covering it with black.
*/
void ClxDrawShadowBlended(const Surface &out, Point position, ClxSprite clx);
/**
* @brief Blit CL2 sprite, and apply lighting, to the given buffer at the given coordinates
* @param out Output buffer
+36 -3
View File
@@ -244,13 +244,36 @@ bool ShouldShowCursor()
}
/**
* @brief Blit CL2 sprite, and apply lighting, to the given buffer at the given coordinates
* @brief Draws the shadow of a sprite whose shadow is stored separately (see `shadow_mask.hpp`).
*
* Must be called right before drawing the sprite itself, after its outline:
* a shadow that is baked into a sprite covers the outline, and so must this one.
* Does nothing for sprites without a separate shadow.
*/
inline void DrawShadow(const Surface &out, Point position, ClxSprite clx)
{
static const bool skipDraw = getenv("SHADOW_NO_DRAW") != nullptr;
if (skipDraw) return;
#ifdef _DEBUG
if (DebugHideShadows)
return;
#endif
if (*GetOptions().Graphics.transparentShadows) {
ClxDrawShadowBlended(out, position, clx);
} else {
ClxDrawShadow(out, position, clx);
}
}
/**
* @brief Blit CL2 sprite and its shadow, and apply lighting, to the given buffer at the given coordinates
* @param out Output buffer
* @param position Target buffer coordinate
* @param clx CLX frame
*/
inline void ClxDrawLight(const Surface &out, Point position, ClxSprite clx, int lightTableIndex)
{
DrawShadow(out, position, clx);
if (lightTableIndex != 0) {
ClxDrawTRN(out, position, clx, LightTables[lightTableIndex].data());
} else {
@@ -344,10 +367,12 @@ void DrawMissilePrivate(const Surface &out, const Missile &missile, Point target
const Point missileRenderPosition { targetBufferPosition + missile.position.offsetForRendering - Displacement { missile._miAnimWidth2, 0 } };
const ClxSprite sprite = (*missile._miAnimData)[missile._miAnimFrame - 1];
if (missile._miUniqTrans != 0) {
DrawShadow(out, missileRenderPosition, sprite);
ClxDrawTRN(out, missileRenderPosition, sprite, Monsters[missile._misource].uniqueMonsterTRN.get());
} else if (missile._miLightFlag) {
ClxDrawLight(out, missileRenderPosition, sprite, lightTableIndex);
} else {
DrawShadow(out, missileRenderPosition, sprite);
ClxDraw(out, missileRenderPosition, sprite);
}
}
@@ -385,6 +410,7 @@ void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosit
const ClxSprite sprite = monster.animInfo.currentSprite();
if (!IsTileLit(tilePosition)) {
DrawShadow(out, targetBufferPosition, sprite);
ClxDrawTRN(out, targetBufferPosition, sprite, GetInfravisionTRN());
return;
}
@@ -395,10 +421,12 @@ void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosit
trn = GetStoneTRN();
if (MyPlayer->_pInfraFlag && lightTableIndex > 8)
trn = GetInfravisionTRN();
if (trn != nullptr)
if (trn != nullptr) {
DrawShadow(out, targetBufferPosition, sprite);
ClxDrawTRN(out, targetBufferPosition, sprite, trn);
else
} else {
ClxDrawLight(out, targetBufferPosition, sprite, lightTableIndex);
}
}
/**
@@ -478,12 +506,14 @@ void DrawPlayer(const Surface &out, const Player &player, Point tilePosition, Po
ClxDrawOutlineSkipColorZero(out, GetPlayerOutlineColor(player.getId()), spriteBufferPosition, sprite);
if (&player == MyPlayer && IsNoneOf(leveltype, DTYPE_NEST, DTYPE_CRYPT)) {
DrawShadow(out, spriteBufferPosition, sprite);
ClxDraw(out, spriteBufferPosition, sprite);
DrawPlayerIcons(out, player, targetBufferPosition, /*infraVision=*/false, lightTableIndex);
return;
}
if (!IsTileLit(tilePosition) || ((MyPlayer->_pInfraFlag || MyPlayer->isOnArenaLevel()) && lightTableIndex > 8)) {
DrawShadow(out, spriteBufferPosition, sprite);
ClxDrawTRN(out, spriteBufferPosition, sprite, GetInfravisionTRN());
DrawPlayerIcons(out, player, targetBufferPosition, /*infraVision=*/true, lightTableIndex);
return;
@@ -533,6 +563,7 @@ void DrawObject(const Surface &out, const Object &objectToDraw, Point tilePositi
if (objectToDraw.applyLighting) {
ClxDrawLight(out, screenPosition, sprite, lightTableIndex);
} else {
DrawShadow(out, screenPosition, sprite);
ClxDraw(out, screenPosition, sprite);
}
}
@@ -743,6 +774,7 @@ void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBuffe
if (mi == pcursmonst) {
ClxDrawOutlineSkipColorZero(out, OutlineColorsTowner, position, sprite);
}
DrawShadow(out, position, sprite);
ClxDraw(out, position, sprite);
return;
}
@@ -804,6 +836,7 @@ void DrawDungeon(const Surface &out, const Lightmap &lightmap, Point tilePositio
const ClxSprite sprite = corpse.spritesForDirection(static_cast<Direction>((bDead >> 5) & 7))[corpse.frame];
if (corpse.translationPaletteIndex != 0) {
const uint8_t *trn = Monsters[corpse.translationPaletteIndex - 1].uniqueMonsterTRN.get();
DrawShadow(out, position, sprite);
ClxDrawTRN(out, position, sprite, trn);
} else {
ClxDrawLight(out, position, sprite, lightTableIndex);
+140
View File
@@ -0,0 +1,140 @@
#pragma once
/**
* @file shadow_mask.hpp
*
* @brief Shadow masks: the shadows extracted from sprites, stored as horizontal spans.
*
* A shadow is a single-colour shape that is drawn by darkening what is underneath it,
* so it is stored as spans rather than as pixels.
*
* Shadow mask of a single sprite:
*
* Bytes | Type | Value
* :-----:|:-------:|------------------------------------------------------
* 0 | uint8_t | number of sprite rows below the lowest shadow row
* 1 | uint8_t | number of shadow rows
* 2.. | rows | from the lowest row upwards
*
* Each row is a sequence of spans sorted by x. A span is 2 bytes:
*
* Byte | Bits | Value
* :----:|:----:|--------------------------------------------
* 0 | 0..7 | x coordinate of the first pixel
* 1 | 0..6 | width
* 1 | 7 | set if this is the last span of the row
*
* A row without shadow pixels is a single span of width 0.
* Runs longer than `MaxShadowSpanWidth` are stored as several spans.
*
* Rows keep their own spans, with absolute x coordinates, instead of letting runs flow from
* one row into the next like CLX does: that way a span can be drawn or clipped on its own,
* without tracking where the previous one ended.
*
* Like CLX sprites, masks are stored bottom-up, so that a mask can be drawn knowing only the
* position of the bottom-left corner of its sprite.
*
* The mask of a sprite is stored in the CLX frame header of that sprite, after the height,
* so it is available wherever the sprite is. Sprites without a shadow have a plain header.
*/
#include <cstddef>
#include <cstdint>
#include "appfat.h"
#include "engine/clx_sprite.hpp"
namespace devilution {
constexpr size_t ShadowMaskHeaderSize = 2;
/** The largest sprite that a shadow mask can describe. */
constexpr unsigned MaxShadowMaskSpriteWidth = 256;
constexpr unsigned MaxShadowMaskSpriteHeight = 255;
/** The largest shadow mask, in bytes: it has to fit in a CLX frame header. */
constexpr size_t MaxShadowMaskSize = 0xFFFF - ClxSprite::BaseHeaderSize;
constexpr uint8_t MaxShadowSpanWidth = 0x7F;
constexpr uint8_t ShadowSpanEndOfRow = 0x80;
struct ShadowSpan {
uint8_t x;
uint8_t width;
};
/**
* @brief The shadow mask of a single sprite.
*/
class ShadowMask {
public:
explicit constexpr ShadowMask(const uint8_t *data)
: data_(data)
{
assert(data != nullptr);
}
/** @brief The number of sprite rows below the lowest shadow row. */
[[nodiscard]] constexpr uint8_t bottomOffset() const
{
return data_[0];
}
[[nodiscard]] constexpr uint8_t numRows() const
{
return data_[1];
}
[[nodiscard]] constexpr bool empty() const
{
return numRows() == 0;
}
/** @brief The rows, from the lowest one upwards. */
[[nodiscard]] constexpr const uint8_t *rows() const
{
return &data_[ShadowMaskHeaderSize];
}
/**
* @brief Calls `fn(rowFromBottom, span)` for every span.
*
* `rowFromBottom` is the number of sprite rows below the span.
*/
template <typename F>
constexpr void forEachSpan(F &&fn) const
{
const uint8_t *src = rows();
uint16_t row = bottomOffset();
for (unsigned i = numRows(); i != 0; --i, ++row) {
uint8_t widthAndFlag;
do {
widthAndFlag = src[1];
const uint8_t width = widthAndFlag & MaxShadowSpanWidth;
if (width != 0) fn(row, ShadowSpan { src[0], width });
src += 2;
} while ((widthAndFlag & ShadowSpanEndOfRow) == 0);
}
}
private:
const uint8_t *data_;
};
/** @brief Whether the sprite carries a shadow mask. */
[[nodiscard]] constexpr bool HasShadowMask(ClxSprite sprite)
{
return sprite.headerSize() > ClxSprite::BaseHeaderSize;
}
/**
* @brief The shadow mask of the sprite.
*
* Requires `HasShadowMask(sprite)`.
*/
[[nodiscard]] constexpr ShadowMask GetShadowMask(ClxSprite sprite)
{
assert(HasShadowMask(sprite));
return ShadowMask { sprite.headerExtension() };
}
} // namespace devilution
+148
View File
@@ -0,0 +1,148 @@
#pragma once
/**
* @file shadow_rule.hpp
*
* @brief Describes how the shadow baked into a sprite was generated.
*
* The original sprites have their shadow drawn into them as black (palette index 0) pixels.
* Every shadow was cast by the same function, measured from a baseline row `B`:
*
* v = (B - y) / 3
* ys = B - 2 - v
* xs = x - (3 * v) / 4
*
* where `(x, y)` is a pixel of the sprite at or above the baseline, `(xs, ys)` is the shadow
* pixel it casts, and both divisions are integer divisions.
*
* The sprites only differ in how the baseline was chosen. That choice is the shadow rule.
*/
#include <algorithm>
#include <cstdint>
#include <expected>
#include <string>
#include <string_view>
#include "utils/parse_int.hpp"
#include "utils/str_cat.hpp"
namespace devilution {
enum class ShadowRuleType : uint8_t {
/** The sprite has black pixels but no known rule reproduces them, or it was never analysed. */
Unknown,
/** The sprite has no shadow. */
None,
/** The baseline is the lowest opaque row of the first frame of the animation (per direction). */
FirstFrame,
/** The baseline is the lowest opaque row of each frame. */
EachFrame,
/**
* The sprite has a shadow, but it cannot be told apart from the black pixels of the sprite itself:
* part of the sprite is black and lies inside its own shadow. The shadow stays part of the sprite.
*/
Baked,
};
/**
* Notes on how well the shadow rule reproduces the shadow of the sprite.
*
* They do not change how the shadow is extracted.
*/
enum class ShadowRuleFlags : uint8_t {
// clang-format off
None = 0,
/** Some black pixels of the sprite are neither a shadow that the rule casts nor plausibly part of the sprite itself. */
Unexplained = 1 << 0,
/** The rule casts a shadow onto some pixels that are transparent in the sprite. */
Stray = 1 << 1,
// clang-format on
};
[[nodiscard]] constexpr ShadowRuleFlags operator|(ShadowRuleFlags a, ShadowRuleFlags b)
{
return static_cast<ShadowRuleFlags>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
}
[[nodiscard]] constexpr bool HasAnyOf(ShadowRuleFlags flags, ShadowRuleFlags test)
{
return (static_cast<uint8_t>(flags) & static_cast<uint8_t>(test)) != 0;
}
struct ShadowRule {
ShadowRuleType type = ShadowRuleType::Unknown;
/**
* @brief Number of rows added to the baseline.
*
* Used by flying monsters, whose shadow is detached from the body. Only valid with `FirstFrame`.
*/
uint8_t baselineOffset = 0;
ShadowRuleFlags flags = ShadowRuleFlags::None;
constexpr bool operator==(const ShadowRule &other) const = default;
/** @brief Whether the sprite has a shadow that can be separated from it. */
[[nodiscard]] constexpr bool canExtractShadow() const
{
return type == ShadowRuleType::FirstFrame || type == ShadowRuleType::EachFrame;
}
};
/**
* @brief Parses a shadow rule as written in the TSV data files.
*
* A rule is one of: an empty string (same as `Unknown`), `Unknown`, `None`, `Baked`, `FirstFrame`,
* `EachFrame`, and `FirstFrame+N` where `N` is the baseline offset (1 to 255).
*
* It can be followed by the tags `Unexplained` and `Stray` (see `ShadowRuleFlags`),
* each preceded by `|`, e.g. `FirstFrame|Stray`.
*/
inline std::expected<ShadowRule, std::string> ParseShadowRule(std::string_view value)
{
constexpr char Separator = '|';
const size_t ruleEnd = std::min(value.find(Separator), value.size());
const std::string_view ruleStr = value.substr(0, ruleEnd);
ShadowRule result;
constexpr std::string_view FirstFrame = "FirstFrame";
if (ruleStr.empty() || ruleStr == "Unknown") {
result.type = ShadowRuleType::Unknown;
} else if (ruleStr == "None") {
result.type = ShadowRuleType::None;
} else if (ruleStr == "Baked") {
result.type = ShadowRuleType::Baked;
} else if (ruleStr == "EachFrame") {
result.type = ShadowRuleType::EachFrame;
} else if (ruleStr == FirstFrame) {
result.type = ShadowRuleType::FirstFrame;
} else if (ruleStr.starts_with(FirstFrame) && ruleStr.size() > FirstFrame.size() + 1 && ruleStr[FirstFrame.size()] == '+') {
const std::string_view offsetStr = ruleStr.substr(FirstFrame.size() + 1);
const char *end = nullptr;
const ParseIntResult<uint8_t> offset = ParseInt<uint8_t>(offsetStr, 1, 255, &end);
if (!offset.has_value() || end != offsetStr.data() + offsetStr.size())
return std::unexpected(StrCat("Unknown shadow rule: ", ruleStr));
result.type = ShadowRuleType::FirstFrame;
result.baselineOffset = *offset;
} else {
return std::unexpected(StrCat("Unknown shadow rule: ", ruleStr));
}
for (size_t pos = ruleEnd; pos < value.size();) {
const size_t tagBegin = pos + 1;
const size_t tagEnd = std::min(value.find(Separator, tagBegin), value.size());
const std::string_view tag = value.substr(tagBegin, tagEnd - tagBegin);
if (tag == "Unexplained") {
result.flags = result.flags | ShadowRuleFlags::Unexplained;
} else if (tag == "Stray") {
result.flags = result.flags | ShadowRuleFlags::Stray;
} else {
return std::unexpected(StrCat("Unknown shadow rule tag: ", tag));
}
pos = tagEnd;
}
return result;
}
} // namespace devilution
+7
View File
@@ -34,6 +34,12 @@ std::string DebugCmdPath(std::optional<bool> on)
return StrCat("Path highlighting: ", DebugPath ? "On" : "Off");
}
std::string DebugCmdShadows(std::optional<bool> on)
{
DebugHideShadows = !on.value_or(DebugHideShadows);
return StrCat("Sprite shadows: ", DebugHideShadows ? "Off" : "On");
}
std::string DebugCmdFullbright(std::optional<bool> on)
{
ToggleLighting();
@@ -126,6 +132,7 @@ sol::table LuaDevDisplayModule(sol::state_view &lua)
LuaSetDocFn(table, "grid", "(on: boolean = nil)", "Toggle showing the grid.", &DebugCmdShowGrid);
LuaSetDocFn(table, "path", "(on: boolean = nil)", "Toggle path debug rendering.", &DebugCmdPath);
LuaSetDocFn(table, "scrollView", "(on: boolean = nil)", "Toggle view scrolling via Shift+Mouse.", &DebugCmdScrollView);
LuaSetDocFn(table, "shadows", "(on: boolean = nil)", "Toggle drawing the shadows of sprites. Shadows that are still part of their sprite stay visible.", &DebugCmdShadows);
LuaSetDocFn(table, "tileData", "(name: string = nil)", "Toggle showing tile data.", &DebugCmdShowTileData);
LuaSetDocFn(table, "vision", "(on: boolean = nil)", "Toggle vision debug rendering.", &DebugCmdVision);
return table;
+49
View File
@@ -90,6 +90,7 @@
#include "utils/algorithm/container.hpp"
#include "utils/attributes.h"
#include "utils/cl2_to_clx.hpp"
#include "utils/clx_shadow.hpp"
#include "utils/endian_swap.hpp"
#include "utils/enum_traits.h"
#include "utils/file_name_generator.hpp"
@@ -3211,6 +3212,52 @@ bool UpdateModeStance(Monster &monster)
}
}
namespace {
/**
* @brief Separates the shadows baked into the monster's sprites (see `utils/clx_shadow.hpp`).
*
* Each animation has its own shadow rule.
*/
void ExtractMonsterShadows(const MonsterData &monsterData, MonsterSpritesData &sprites)
{
const size_t numAnims = GetNumAnims(monsterData);
std::array<std::optional<OwnedClxSpriteListOrSheet>, MonsterSpritesData::MaxAnims> extracted;
std::array<uint32_t, MonsterSpritesData::MaxAnims + 1> offsets;
bool anyExtracted = false;
size_t size = 0;
size_t j = 0;
for (size_t i = 0; i < numAnims; ++i) {
if (!monsterData.hasAnim(i))
continue;
const auto *data = reinterpret_cast<const uint8_t *>(&sprites.data[sprites.offsets[j]]);
const size_t dataSize = sprites.offsets[j + 1] - sprites.offsets[j];
const uint16_t numLists = GetNumListsFromClxListOrSheetBuffer(data, dataSize);
extracted[j] = ExtractClxShadows(ClxSpriteListOrSheet { data, numLists }, monsterData.shadowRules[i]);
anyExtracted = anyExtracted || extracted[j].has_value();
offsets[j] = static_cast<uint32_t>(size);
size += extracted[j].has_value() ? extracted[j]->dataSize() : dataSize;
++j;
}
if (!anyExtracted)
return;
offsets[j] = static_cast<uint32_t>(size);
std::unique_ptr<std::byte[]> data { new std::byte[size] };
for (size_t k = 0; k < j; ++k) {
if (extracted[k].has_value()) {
const ClxSpriteListOrSheet clx { *extracted[k] };
memcpy(&data[offsets[k]], clx.isSheet() ? clx.sheet().data() : clx.list().data(), offsets[k + 1] - offsets[k]);
} else {
memcpy(&data[offsets[k]], &sprites.data[sprites.offsets[k]], offsets[k + 1] - offsets[k]);
}
}
sprites.data = std::move(data);
sprites.offsets = offsets;
}
} // namespace
MonsterSpritesData LoadMonsterSpritesData(const MonsterData &monsterData)
{
const size_t numAnims = GetNumAnims(monsterData);
@@ -3246,6 +3293,8 @@ MonsterSpritesData LoadMonsterSpritesData(const MonsterData &monsterData)
}
#endif
ExtractMonsterShadows(monsterData, result);
return result;
}
+5
View File
@@ -44,6 +44,7 @@
#include "towners.h"
#include "track.h"
#include "utils/algorithm/container.hpp"
#include "utils/clx_shadow.hpp"
#include "utils/endian_swap.hpp"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
@@ -3705,6 +3706,10 @@ std::expected<void, std::string> LoadLevelObjects(uint16_t filesWidths[65])
char filestr[32];
*BufCopy(filestr, "objects\\", ObjMasterLoadList[i]) = '\0';
ASSIGN_OR_RETURN(pObjCels[numobjfiles], LoadCelWithStatus(filestr, filesWidths[i]));
// Objects that share a sprite file share its shadow rule.
const auto objectDataIt = std::find_if(AllObjects.begin(), AllObjects.end(), [i](const ObjectData &objectData) { return objectData.ofindex == i; });
if (objectDataIt != AllObjects.end())
ExtractClxShadowsInPlace(*pObjCels[numobjfiles], objectDataIt->shadowRule);
numobjfiles++;
}
return {};
+2
View File
@@ -797,6 +797,7 @@ GraphicsOptions::GraphicsOptions()
, zoom("Zoom", OptionEntryFlags::None, N_("Zoom"), N_("Zoom on when enabled."), false)
, perPixelLighting("Per-pixel Lighting", OptionEntryFlags::None, N_("Per-pixel Lighting"), N_("Subtile lighting for smoother light gradients."), DEFAULT_PER_PIXEL_LIGHTING)
, colorCycling("Color Cycling", OptionEntryFlags::None, N_("Color Cycling"), N_("Color cycling effect used for water, lava, and acid animation."), true)
, transparentShadows("Transparent Shadows", OptionEntryFlags::None, N_("Transparent Shadows"), N_("Shadows of characters, monsters and objects darken the ground instead of covering it."), false)
, alternateNestArt("Alternate nest art", OptionEntryFlags::OnlyHellfire | OptionEntryFlags::CantChangeInGame, N_("Alternate nest art"), N_("The game will use an alternative palette for Hellfire’s nest tileset."), false)
#if SDL_VERSION_ATLEAST(2, 0, 0)
, hardwareCursor("Hardware Cursor", OptionEntryFlags::CantChangeInGame | OptionEntryFlags::RecreateUI | (HardwareCursorSupported() ? OptionEntryFlags::None : OptionEntryFlags::Invisible), N_("Hardware Cursor"), N_("Use a hardware cursor"), HardwareCursorDefault())
@@ -828,6 +829,7 @@ std::vector<OptionEntryBase *> GraphicsOptions::GetEntries()
&showFPS,
&perPixelLighting,
&colorCycling,
&transparentShadows,
&alternateNestArt,
#if SDL_VERSION_ATLEAST(2, 0, 0)
&hardwareCursor,
+2
View File
@@ -562,6 +562,8 @@ struct GraphicsOptions : OptionCategoryBase {
OptionEntryBoolean perPixelLighting;
/** @brief Enable color cycling animations. */
OptionEntryBoolean colorCycling;
/** @brief Draw the shadows of sprites by darkening what is underneath instead of covering it. */
OptionEntryBoolean transparentShadows;
/** @brief Use alternate nest palette. */
OptionEntryBoolean alternateNestArt;
#if SDL_VERSION_ATLEAST(2, 0, 0)
+2 -1
View File
@@ -312,7 +312,8 @@ void DrawPartyMemberInfoPanel(const Surface &out)
PortraitFrameSize.width - (FrameBorderSize * 2),
PortraitFrameSize.height - (FrameBorderSize * 2));
// Draw the portrait sprite
// Draw the portrait sprite, with its shadow
ClxDrawShadow(frameSubregion, { portraitPos.x, portraitPos.y + static_cast<int>(monsterPortraitSprite.height()) - 1 }, monsterPortraitSprite);
RenderClxSprite(
frameSubregion,
monsterPortraitSprite,
+2
View File
@@ -52,6 +52,7 @@
#include "spells.h"
#include "stores.h"
#include "towners.h"
#include "utils/clx_shadow.hpp"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
@@ -2160,6 +2161,7 @@ void LoadPlrGFX(Player &player, player_graphic graphic)
GetPlayerGraphicsPath(path, std::string_view(prefixBuf, 3), szCel, pszName);
const uint16_t animationWidth = GetPlayerSpriteWidth(cls, graphic, animWeaponId);
animationData.sprites = LoadCl2Sheet(pszName, animationWidth);
ExtractClxShadowsInPlace(*animationData.sprites, spriteData.shadowRule);
std::optional<std::array<uint8_t, 256>> graphicTRN = GetPlayerGraphicTRN(pszName);
if (graphicTRN) {
ClxApplyTrans(*animationData.sprites, graphicTRN->data());
+1
View File
@@ -399,6 +399,7 @@ void LoadMonstDatFromFile(DataFile &dataFile, const std::string_view filename, b
reader.read("treasure", monster.treasure, ParseMonsterTreasure);
reader.readInt("exp", monster.exp);
reader.readEnumArray("shadowRule", std::optional<ShadowRule> { ShadowRule {} }, monster.shadowRules, ParseShadowRule);
}
}
+5 -1
View File
@@ -13,7 +13,9 @@
#include <magic_enum/magic_enum.hpp>
#include "cursor_defs.hpp"
#include "engine/shadow_rule.hpp"
#include "tables/textdat.h"
#include "utils/attributes.h"
namespace devilution {
@@ -143,6 +145,8 @@ struct MonsterData {
/** Using monster_treasure */
uint16_t treasure = 0;
uint16_t exp = 0;
/** How the shadow baked into each animation's sprites was generated, indexed like `frames`. */
ShadowRule shadowRules[6] {};
[[nodiscard]] const char *spritePath() const;
@@ -347,7 +351,7 @@ struct UniqueMonsterData {
_speech_id mtalkmsg;
};
extern std::vector<MonsterData> MonstersData;
extern DVL_API_FOR_TEST std::vector<MonsterData> MonstersData;
extern const _monster_id MonstConvTbl[];
extern std::vector<UniqueMonsterData> UniqueMonstersData;
+1
View File
@@ -292,6 +292,7 @@ void LoadObjectData()
reader.readInt("animLen", item.animLen);
reader.readInt("animWidth", item.animWidth);
reader.readEnumList("selectionRegion", item.selectionRegion, ParseSelectionRegion);
reader.read("shadowRule", item.shadowRule, ParseShadowRule);
}
// Sanity check because we do not actually parse the IDs yet.
+5 -1
View File
@@ -10,8 +10,10 @@
#include <vector>
#include "cursor_defs.hpp"
#include "engine/shadow_rule.hpp"
#include "levels/gendung_defs.hpp"
#include "tables/questdat.hpp"
#include "utils/attributes.h"
namespace devilution {
@@ -177,6 +179,8 @@ struct ObjectData {
uint8_t animLen; // Number of frames in current animation
uint8_t animWidth;
SelectionRegion selectionRegion;
/** How the shadow baked into the object's sprite was generated. */
ShadowRule shadowRule;
[[nodiscard]] bool isAnimated() const
{
@@ -210,7 +214,7 @@ struct ObjectData {
};
extern const _object_id ObjTypeConv[];
extern std::vector<ObjectData> AllObjects;
extern DVL_API_FOR_TEST std::vector<ObjectData> AllObjects;
extern std::vector<std::string> ObjMasterLoadList;
void LoadObjectData();
+1
View File
@@ -250,6 +250,7 @@ void LoadClassSpriteData(std::string_view classPath, PlayerSpriteData &spriteDat
reader.readInt("fire", spriteData.fire);
reader.readInt("magic", spriteData.magic);
reader.readInt("death", spriteData.death);
reader.read("shadowRule", spriteData.shadowRule, ParseShadowRule);
}
void LoadClassAnimData(std::string_view classPath, PlayerAnimData &animData)
+3
View File
@@ -10,6 +10,7 @@
#include <magic_enum/magic_enum.hpp>
#include "engine/shadow_rule.hpp"
#include "sound_effect_enums.h"
#include "tables/itemdat.h"
#include "tables/spelldat.h"
@@ -173,6 +174,8 @@ struct PlayerSpriteData {
uint8_t magic;
/* Sprite width: Death */
uint8_t death;
/* How the shadow baked into the class sprites was generated */
ShadowRule shadowRule;
};
struct PlayerAnimData {
+2
View File
@@ -125,6 +125,8 @@ void LoadTownersFromFile()
std::string animOrderStr;
reader.readString("animOrder", animOrderStr);
ParseAnimOrder(animOrderStr, entry.animOrder);
reader.read("shadowRule", entry.shadowRule, ParseShadowRule);
}
TownersDataEntries.shrink_to_fit();
+3
View File
@@ -11,6 +11,7 @@
#include <vector>
#include "engine/direction.hpp"
#include "engine/shadow_rule.hpp"
#include "levels/gendung.h"
#include "tables/objdat.h"
#include "tables/textdat.h"
@@ -33,6 +34,8 @@ struct TownerDataEntry {
int16_t animDelay;
std::vector<_speech_id> gossipTexts;
std::vector<uint8_t> animOrder;
/** How the shadow baked into the towner's sprite was generated. */
ShadowRule shadowRule;
};
/** Contains the data for all towners loaded from TSV. */
+11 -5
View File
@@ -10,12 +10,14 @@
#include "engine/load_cel.hpp"
#include "engine/load_file.hpp"
#include "engine/random.hpp"
#include "engine/shadow_rule.hpp"
#include "game_mode.hpp"
#include "inv.h"
#include "minitext.h"
#include "stores.h"
#include "tables/textdat.h"
#include "tables/townerdat.hpp"
#include "utils/clx_shadow.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/str_case.hpp"
@@ -104,10 +106,11 @@ void InitTownerInfo(Towner &towner, const TownerData &townerData, const TownerDa
}
}
void LoadTownerAnimations(Towner &towner, const char *path, int frames, int delay)
void LoadTownerAnimations(Towner &towner, const char *path, int frames, int delay, ShadowRule shadowRule)
{
towner.ownedAnim = std::nullopt;
towner.ownedAnim = LoadCel(path, towner._tAnimWidth);
ExtractClxShadowsInPlace(*towner.ownedAnim, shadowRule);
NewTownerAnim(towner, *towner.ownedAnim, frames, delay);
}
@@ -127,7 +130,7 @@ void InitTownerFromData(Towner &towner, const TownerDataEntry &entry)
}
if (!entry.animPath.empty()) {
LoadTownerAnimations(towner, entry.animPath.c_str(), entry.animFrames, entry.animDelay);
LoadTownerAnimations(towner, entry.animPath.c_str(), entry.animFrames, entry.animDelay, entry.shadowRule);
}
// Set gossip from TSV data
@@ -182,10 +185,13 @@ void InitCowFarmer(Towner &towner, const TownerDataEntry &entry)
// CowFarmer has special logic for quest state
const char *celPath = "towners\\farmer\\cfrmrn2";
// The data file only describes the shadow of the first sprite.
ShadowRule shadowRule = entry.shadowRule;
if (Quests[Q_JERSEY]._qactive == QUEST_DONE) {
celPath = "towners\\farmer\\mfrmrn2";
shadowRule = {};
}
LoadTownerAnimations(towner, celPath, 15, 3);
LoadTownerAnimations(towner, celPath, 15, 3, shadowRule);
}
void TownDead(Towner &towner)
@@ -858,7 +864,7 @@ void UpdateGirlAnimAfterQuestComplete()
if (girl == nullptr || !girl->ownedAnim)
return; // Girl is not spawned in town yet
auto curFrame = girl->_tAnimFrame;
LoadTownerAnimations(*girl, "towners\\girl\\girls1", 20, 6);
LoadTownerAnimations(*girl, "towners\\girl\\girls1", 20, 6, /*shadowRule=*/ {});
girl->_tAnimFrame = std::min<uint8_t>(curFrame, girl->_tAnimLen - 1);
}
@@ -866,7 +872,7 @@ void UpdateCowFarmerAnimAfterQuestComplete()
{
Towner *cowFarmer = GetTowner(TOWN_COWFARM);
auto curFrame = cowFarmer->_tAnimFrame;
LoadTownerAnimations(*cowFarmer, "towners\\farmer\\mfrmrn2", 15, 3);
LoadTownerAnimations(*cowFarmer, "towners\\farmer\\mfrmrn2", 15, 3, /*shadowRule=*/ {});
cowFarmer->_tAnimFrame = std::min<uint8_t>(curFrame, cowFarmer->_tAnimLen - 1);
}
+417
View File
@@ -0,0 +1,417 @@
#include "utils/clx_shadow.hpp"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#include <vector>
#include "appfat.h"
#include "utils/clx_decode.hpp"
#include "utils/clx_encode.hpp"
#include "utils/endian_write.hpp"
namespace devilution {
namespace {
enum PixelFlags : uint8_t {
Opaque = 1 << 0,
/** Part of the sprite itself. */
Body = 1 << 1,
/** Covered by the shadow of a body pixel. */
Shadow = 1 << 2,
/** A black pixel that is neither covered by a shadow nor plausibly a body pixel. */
Orphan = 1 << 3,
};
/** The columns `[begin, end)` of a row. Empty if `begin >= end`. */
struct Extent {
uint16_t begin;
uint16_t end;
void include(int from, int to)
{
if (from < begin) begin = static_cast<uint16_t>(from);
if (to > end) end = static_cast<uint16_t>(to);
}
};
/**
* A decoded sprite. Rows are stored top-down.
*
* Most of a sprite is empty, so the rows that have pixels and the extent of the pixels
* of each row are kept, and everything works on those instead of on whole rows.
*/
struct Frame {
int width = 0;
int height = 0;
/** Only valid for opaque pixels. */
std::vector<uint8_t> colors;
std::vector<uint8_t> flags;
/** The extent of the opaque pixels of each row. */
std::vector<Extent> opaque;
/** An extent that contains the pixels of each row that have the `Shadow` flag. */
std::vector<Extent> shadow;
/** The indices of the black pixels, in order. Filled by `SeparateShadow`. */
std::vector<uint32_t> blackPixels;
/** Scratch space of `SeparateShadow`: columns of a row. */
std::vector<int> uncovered;
/** The first and the last row that have an opaque pixel. `bottom` is -1 if there are none. */
int top = 0;
int bottom = -1;
[[nodiscard]] size_t index(int x, int y) const
{
return static_cast<size_t>(y) * width + x;
}
[[nodiscard]] bool isBlack(size_t i) const
{
return (flags[i] & Opaque) != 0 && colors[i] == 0;
}
void setShadow(int x, int y)
{
flags[index(x, y)] |= Shadow;
shadow[y].include(x, x + 1);
}
};
void DecodeFrame(ClxSprite sprite, Frame &frame)
{
const int width = sprite.width();
const int height = sprite.height();
frame.width = width;
frame.height = height;
const size_t numPixels = static_cast<size_t>(width) * height;
frame.colors.resize(numPixels);
frame.flags.assign(numPixels, 0);
const Extent empty { static_cast<uint16_t>(width), 0 };
frame.opaque.assign(height, empty);
frame.shadow.assign(height, empty);
frame.top = height;
frame.bottom = -1;
// CLX pixel data is stored bottom-up. Transparent runs can continue on the next row.
// Opaque runs must not, but a run that does is taken to continue there too, like the
// run of the original image that it was made from.
int x = 0;
int y = height - 1;
// Writes an opaque run, either the given pixels or `length` pixels of the fill color.
const auto opaqueRun = [&](unsigned length, const uint8_t *pixels, uint8_t fillColor) {
while (length != 0 && y >= 0) {
const unsigned chunk = std::min<unsigned>(length, static_cast<unsigned>(width - x));
const size_t i = frame.index(x, y);
if (pixels != nullptr) {
memcpy(&frame.colors[i], pixels, chunk);
pixels += chunk;
} else {
memset(&frame.colors[i], fillColor, chunk);
}
memset(&frame.flags[i], Opaque, chunk);
frame.opaque[y].include(x, x + static_cast<int>(chunk));
if (y > frame.bottom) frame.bottom = y;
if (y < frame.top) frame.top = y;
x += static_cast<int>(chunk);
length -= chunk;
if (x == width) {
x = 0;
--y;
}
}
};
const uint8_t *src = sprite.pixelData();
const uint8_t *end = src + sprite.pixelDataSize();
while (src < end) {
const uint8_t control = *src++;
if (!IsClxOpaque(control)) {
x += control;
if (x >= width) {
y -= x / width;
x %= width;
}
} else if (IsClxOpaqueFill(control)) {
opaqueRun(GetClxOpaqueFillWidth(control), nullptr, *src++);
} else {
const unsigned length = GetClxOpaquePixelsWidth(control);
opaqueRun(length, src, 0);
src += length;
}
}
}
/**
* @brief The shadow function for a row: where the pixels of the row cast their shadow.
*/
struct RowShadow {
/** Whether the pixels of the row cast a shadow inside the frame. */
bool casts;
/** The row that the shadow falls on. */
int y;
/** The number of pixels that the shadow is shifted to the left. */
int shift;
};
RowShadow ShadowOfRow(const Frame &frame, int baseline, int y)
{
if (y > baseline) return { false, 0, 0 };
const int v = (baseline - y) / 3;
const int shadowY = baseline - 2 - v;
return { shadowY >= 0 && shadowY < frame.height, shadowY, (3 * v) / 4 };
}
/**
* @brief Sets the `Body`, `Shadow` and `Orphan` flags of the frame.
*/
void SeparateShadow(Frame &frame, int baseline)
{
// Everything that is not black is certainly not a shadow.
// The black pixels are collected for the second pass.
frame.blackPixels.clear();
for (int y = frame.top; y <= frame.bottom; ++y) {
const Extent extent = frame.opaque[y];
if (extent.begin >= extent.end) continue;
const RowShadow rowShadow = ShadowOfRow(frame, baseline, y);
const size_t row = frame.index(0, y);
// The shadow of the pixels to the left of `shift` falls outside of the frame.
const size_t shadowRow = rowShadow.casts ? frame.index(0, rowShadow.y) : 0;
const int shift = rowShadow.casts ? rowShadow.shift : frame.width;
for (int x = extent.begin; x < extent.end; ++x) {
if ((frame.flags[row + x] & Opaque) == 0) continue;
if (frame.colors[row + x] == 0) {
frame.blackPixels.push_back(static_cast<uint32_t>(row + x));
continue;
}
frame.flags[row + x] |= Body;
if (x >= shift) frame.flags[shadowRow + x - shift] |= Shadow;
}
if (rowShadow.casts && extent.end > shift) frame.shadow[rowShadow.y].include(std::max<int>(extent.begin, shift) - shift, extent.end - shift);
}
// A black pixel that is not in the shadow of the pixels above it must be a body pixel,
// and so it casts a shadow too. Shadows only fall downwards (except within the lowest
// rows, where a pixel shadows its own column), so one top-down pass settles them all.
std::vector<int> &uncovered = frame.uncovered;
const size_t numBlackPixels = frame.blackPixels.size();
for (size_t next = 0; next < numBlackPixels;) {
// The black pixels of one row.
const int y = static_cast<int>(frame.blackPixels[next] / frame.width);
const size_t row = frame.index(0, y);
const size_t rowEnd = row + frame.width;
uncovered.clear();
for (; next < numBlackPixels && frame.blackPixels[next] < rowEnd; ++next) {
const size_t i = frame.blackPixels[next];
if ((frame.flags[i] & Shadow) == 0) uncovered.push_back(static_cast<int>(i - row));
}
if (uncovered.empty()) continue;
const RowShadow rowShadow = ShadowOfRow(frame, baseline, y);
for (const int x : uncovered) {
const size_t i = row + x;
// A pixel whose shadow would fall on a transparent pixel is not a body pixel.
if (!rowShadow.casts || x < rowShadow.shift || (frame.flags[frame.index(x - rowShadow.shift, rowShadow.y)] & Opaque) != 0) {
frame.flags[i] |= Body;
continue;
}
// It may be the shadow of a black body pixel that we took for a shadow because it lies
// inside the shadow of the pixels above it. Look for one in the 3 rows that shadow this row.
const int v = baseline - 2 - y;
const int sourceX = x + (3 * v) / 4;
bool found = false;
for (int sourceY = baseline - 3 * v - 2; v >= 2 && sourceY <= baseline - 3 * v && !found; ++sourceY) {
if (sourceX >= frame.width || sourceY < 0) continue;
const size_t source = frame.index(sourceX, sourceY);
if (!frame.isBlack(source) || (frame.flags[source] & (Body | Orphan)) != 0) continue;
frame.flags[source] |= Body;
frame.setShadow(x, y);
found = true;
}
if (!found) frame.flags[i] |= Orphan;
}
if (!rowShadow.casts) continue;
for (const int x : uncovered) {
if ((frame.flags[row + x] & Body) != 0 && x >= rowShadow.shift) frame.setShadow(x - rowShadow.shift, rowShadow.y);
}
}
}
/** Whether the pixel stays in the sprite once its shadow is removed. */
bool IsKept(const Frame &frame, size_t i)
{
const uint8_t flags = frame.flags[i];
if ((flags & Opaque) == 0) return false;
return frame.colors[i] != 0 || (flags & (Body | Orphan)) != 0;
}
/** Appends the shadow mask of the frame. Appends nothing if the frame has no shadow. */
void AppendShadowMask(const Frame &frame, std::vector<uint8_t> &out)
{
constexpr uint8_t Mask = Opaque | Shadow;
// The mask is limited to opaque pixels, so only look where a row has both.
const auto maskExtent = [&](int y) {
return Extent { std::max(frame.opaque[y].begin, frame.shadow[y].begin), std::min(frame.opaque[y].end, frame.shadow[y].end) };
};
const auto rowHasShadow = [&](int y) {
const Extent extent = maskExtent(y);
const size_t row = frame.index(0, y);
for (int x = extent.begin; x < extent.end; ++x) {
if ((frame.flags[row + x] & Mask) == Mask) return true;
}
return false;
};
int lowest = frame.bottom;
while (lowest >= frame.top && !rowHasShadow(lowest))
--lowest;
if (lowest < frame.top) return;
int highest = frame.top;
while (highest < lowest && !rowHasShadow(highest))
++highest;
[[maybe_unused]] const size_t begin = out.size();
out.push_back(static_cast<uint8_t>(frame.height - 1 - lowest));
out.push_back(static_cast<uint8_t>(lowest - highest + 1));
for (int y = lowest; y >= highest; --y) {
const size_t rowBegin = out.size();
const Extent extent = maskExtent(y);
const size_t row = frame.index(0, y);
int x = extent.begin;
while (x < extent.end) {
if ((frame.flags[row + x] & Mask) != Mask) {
++x;
continue;
}
int runEnd = x + 1;
while (runEnd < extent.end && (frame.flags[row + runEnd] & Mask) == Mask)
++runEnd;
while (x < runEnd) {
const int width = runEnd - x > MaxShadowSpanWidth ? MaxShadowSpanWidth : runEnd - x;
out.push_back(static_cast<uint8_t>(x));
out.push_back(static_cast<uint8_t>(width));
x += width;
}
}
// A row without shadow pixels is a span of width 0.
if (out.size() == rowBegin) {
out.push_back(0);
out.push_back(0);
}
out.back() |= ShadowSpanEndOfRow;
}
// At most one span for every 2 pixels of a row.
static_assert(ShadowMaskHeaderSize + MaxShadowMaskSpriteHeight * MaxShadowMaskSpriteWidth <= MaxShadowMaskSize);
assert(out.size() - begin <= MaxShadowMaskSize);
}
/** Appends the frame without its shadow, with the shadow mask in the frame header. */
void AppendSpriteWithoutShadow(const Frame &frame, std::vector<uint8_t> &out)
{
const size_t headerPos = out.size();
out.resize(out.size() + ClxFrameHeaderSize);
AppendShadowMask(frame, out);
WriteLE16(&out[headerPos], static_cast<uint16_t>(out.size() - headerPos));
WriteLE16(&out[headerPos + 2], static_cast<uint16_t>(frame.width));
WriteLE16(&out[headerPos + 4], static_cast<uint16_t>(frame.height));
// Opaque runs end with their row: only transparent runs can continue on the next one.
unsigned transparentRunWidth = 0;
for (int y = frame.height - 1; y >= 0; --y) {
const Extent extent = frame.opaque[y];
if (extent.begin >= extent.end) {
transparentRunWidth += frame.width;
continue;
}
const size_t rowBegin = frame.index(0, y);
transparentRunWidth += extent.begin;
int x = extent.begin;
while (x < extent.end) {
if (!IsKept(frame, rowBegin + x)) {
++transparentRunWidth;
++x;
continue;
}
int runEnd = x + 1;
while (runEnd < extent.end && IsKept(frame, rowBegin + runEnd))
++runEnd;
AppendClxTransparentRun(transparentRunWidth, out);
transparentRunWidth = 0;
AppendClxPixelsOrFillRun(&frame.colors[rowBegin + x], static_cast<size_t>(runEnd - x), out);
x = runEnd;
}
transparentRunWidth += frame.width - extent.end;
}
AppendClxTransparentRun(transparentRunWidth, out);
}
/**
* @brief Extracts the shadows of a list, appending the new list to the output.
*
* @return false if a sprite is too large.
*/
bool ExtractList(ClxSpriteList list, ShadowRule rule, std::vector<uint8_t> &clxOut)
{
const uint32_t numSprites = list.numSprites();
const size_t clxBegin = clxOut.size();
clxOut.resize(clxBegin + 4 * (2 + static_cast<size_t>(numSprites)));
WriteLE32(&clxOut[clxBegin], numSprites);
Frame frame;
int firstFrameBaseline = 0;
for (uint32_t i = 0; i < numSprites; ++i) {
const ClxSprite sprite = list[i];
if (sprite.width() > MaxShadowMaskSpriteWidth || sprite.height() > MaxShadowMaskSpriteHeight) return false;
DecodeFrame(sprite, frame);
// The lowest row that has an opaque pixel, -1 if there is none.
const int lowest = frame.bottom;
if (i == 0) firstFrameBaseline = lowest;
int baseline = rule.type == ShadowRuleType::EachFrame ? lowest : firstFrameBaseline;
// A sprite without pixels has no baseline.
if (baseline >= 0) {
baseline += rule.baselineOffset;
SeparateShadow(frame, baseline);
}
WriteLE32(&clxOut[clxBegin + 4 * (1 + static_cast<size_t>(i))], static_cast<uint32_t>(clxOut.size() - clxBegin));
AppendSpriteWithoutShadow(frame, clxOut);
}
WriteLE32(&clxOut[clxBegin + 4 * (1 + static_cast<size_t>(numSprites))], static_cast<uint32_t>(clxOut.size() - clxBegin));
return true;
}
std::unique_ptr<uint8_t[]> ToOwnedBuffer(const std::vector<uint8_t> &data)
{
std::unique_ptr<uint8_t[]> result { new uint8_t[data.size()] };
memcpy(result.get(), data.data(), data.size());
return result;
}
} // namespace
std::optional<OwnedClxSpriteListOrSheet> ExtractClxShadows(ClxSpriteListOrSheet sprites, ShadowRule rule)
{
if (!rule.canExtractShadow()) return std::nullopt;
std::vector<uint8_t> clxData;
// The result is about as large as the sprites it is made from.
clxData.reserve(sprites.dataSize() + sprites.dataSize() / 16);
uint16_t numLists = 0;
if (sprites.isSheet()) {
const ClxSpriteSheet sheet = sprites.sheet();
numLists = sheet.numLists();
clxData.resize(static_cast<size_t>(numLists) * 4);
for (uint16_t i = 0; i < numLists; ++i) {
WriteLE32(&clxData[static_cast<size_t>(i) * 4], static_cast<uint32_t>(clxData.size()));
if (!ExtractList(sheet[i], rule, clxData)) return std::nullopt;
}
} else if (!ExtractList(sprites.list(), rule, clxData)) {
return std::nullopt;
}
return OwnedClxSpriteListOrSheet { ToOwnedBuffer(clxData), numLists };
}
} // namespace devilution
+56
View File
@@ -0,0 +1,56 @@
#pragma once
/**
* @file clx_shadow.hpp
*
* @brief Separates the shadows baked into CLX sprites from the sprites themselves.
*/
#include <optional>
#include "engine/clx_sprite.hpp"
#include "engine/shadow_mask.hpp"
#include "engine/shadow_rule.hpp"
namespace devilution {
/**
* @brief Separates the shadows baked into the given sprites from the sprites.
*
* A shadow pixel is a black (palette index 0) pixel that lies where the shadow function
* (see `shadow_rule.hpp`) casts a pixel of the sprite. Such pixels are removed from the sprite.
* The shadow becomes the shadow mask of the sprite (see `shadow_mask.hpp`), stored in its frame header.
*
* The mask of a sprite is the whole shadow that it casts, including the part underneath the
* sprite itself, limited to the pixels that are opaque in the input. Drawing a sprite over its
* mask filled with black gives back the input exactly.
*
* Black pixels that are not explained as shadow are kept in the sprite.
*
* For sprite sheets, each list is treated as a separate animation (for `ShadowRuleType::FirstFrame`
* the baseline comes from the first sprite of each list).
*
* @return The sprites without their shadows, with the same structure and dimensions as the input.
* `std::nullopt` if `rule` does not describe a shadow (`!rule.canExtractShadow()`)
* or if a sprite is larger than `MaxShadowMaskSpriteWidth` by `MaxShadowMaskSpriteHeight`.
*/
std::optional<OwnedClxSpriteListOrSheet> ExtractClxShadows(ClxSpriteListOrSheet sprites, ShadowRule rule);
/**
* @brief Separates the shadows baked into the given sprites, replacing the sprites.
*
* Leaves the sprites as they are if there is nothing to extract (see `ExtractClxShadows`).
*/
inline void ExtractClxShadowsInPlace(OwnedClxSpriteList &sprites, ShadowRule rule)
{
std::optional<OwnedClxSpriteListOrSheet> result = ExtractClxShadows(ClxSpriteListOrSheet { ClxSpriteList { sprites }.data(), 0 }, rule);
if (result.has_value()) sprites = std::move(*result).list();
}
inline void ExtractClxShadowsInPlace(OwnedClxSpriteSheet &sprites, ShadowRule rule)
{
const ClxSpriteSheet sheet { sprites };
std::optional<OwnedClxSpriteListOrSheet> result = ExtractClxShadows(ClxSpriteListOrSheet { sheet.data(), sheet.numLists() }, rule);
if (result.has_value()) sprites = std::move(*result).sheet();
}
} // namespace devilution
@@ -18,3 +18,4 @@ lightning 96
fire 96
magic 96
death 128
shadowRule
1 Variable Value
18 fire 96
19 magic 96
20 death 128
21 shadowRule
+1
View File
@@ -18,3 +18,4 @@ lightning 96
fire 96
magic 96
death 128
shadowRule
1 Variable Value
18 fire 96
19 magic 96
20 death 128
21 shadowRule
+1
View File
@@ -18,3 +18,4 @@ lightning 114
fire 114
magic 114
death 160
shadowRule EachFrame
1 Variable Value
18 fire 114
19 magic 114
20 death 160
21 shadowRule EachFrame
+1
View File
@@ -18,3 +18,4 @@ lightning 96
fire 96
magic 96
death 128
shadowRule FirstFrame
1 Variable Value
18 fire 96
19 magic 96
20 death 128
21 shadowRule FirstFrame
@@ -18,3 +18,4 @@ lightning 128
fire 128
magic 128
death 128
shadowRule FirstFrame
1 Variable Value
18 fire 128
19 magic 128
20 death 128
21 shadowRule FirstFrame
@@ -18,3 +18,4 @@ lightning 96
fire 96
magic 96
death 128
shadowRule FirstFrame|Unexplained|Stray
1 Variable Value
18 fire 96
19 magic 96
20 death 128
21 shadowRule FirstFrame|Unexplained|Stray
+113 -113
View File
@@ -1,113 +1,113 @@
_monster_id name assetsSuffix soundSuffix trnFile availability width image hasSpecial hasSpecialSound frames[6] rate[6] minDunLvl maxDunLvl level hitPointsMinimum hitPointsMaximum ai abilityFlags intelligence toHit animFrameNum minDamage maxDamage toHitSpecial animFrameNumSpecial minDamageSpecial maxDamageSpecial reducePlayerStrength reducePlayerMagic reducePlayerDexterity reducePlayerVitality reducePlayerMaxHP reducePlayerMaxMana armorClass monsterClass resistance resistanceHell selectionRegion treasure exp
MT_NZOMBIE Zombie zombie\zombie Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 1 2 1 4 7 Zombie 0 10 8 2 5 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 54
MT_BZOMBIE Ghoul zombie\zombie zombie\bluered Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 3 2 7 11 Zombie 1 10 8 3 10 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 58
MT_GZOMBIE Rotting Carcass zombie\zombie zombie\grey Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 4 4 15 25 Zombie 2 25 8 5 15 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 136
MT_YZOMBIE Black Death zombie\zombie zombie\yellow Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 3 5 6 25 40 Zombie 3 30 8 6 22 0 0 0 0 0 0 0 0 1 0 20 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 240
MT_RFALLSP Fallen One falspear\phall falspear\fallent Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 1 2 1 1 4 Fallen 0 15 7 1 3 0 5 0 0 0 0 0 0 0 0 0 Animal Bottom,Middle 46
MT_DFALLSP Carver falspear\phall falspear\dark Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 3 3 4 8 Fallen 2 20 7 2 5 0 5 0 0 0 0 0 0 0 0 5 Animal Bottom,Middle 80
MT_YFALLSP Devil Kin falspear\phall Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 4 5 12 24 Fallen 2 25 7 3 7 0 5 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 155
MT_BFALLSP Dark One falspear\phall falspear\blue Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 3 5 7 20 36 Fallen 3 30 7 4 8 0 5 0 0 0 0 0 0 0 0 15 Animal RESIST_LIGHTNING Bottom,Middle 255
MT_WSKELAX Skeleton skelaxe\sklax skelaxe\white Always 128 553 true false 12,8,13,6,17,16 5,1,1,1,1,1 1 2 1 2 4 SkeletonMelee 0 20 8 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 64
MT_TSKELAX Corpse Axe skelaxe\sklax skelaxe\skelt Always 128 553 true false 12,8,13,6,17,16 4,1,1,1,1,1 2 3 2 4 7 SkeletonMelee 1 25 8 3 5 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 68
MT_RSKELAX Burning Dead skelaxe\sklax Always 128 553 true false 12,8,13,6,17,16 2,1,1,1,1,1 2 4 4 8 12 SkeletonMelee 2 30 8 3 7 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 154
MT_XSKELAX Horror skelaxe\sklax skelaxe\black Always 128 553 true false 12,8,13,6,17,16 3,1,1,1,1,1 3 5 6 12 20 SkeletonMelee 3 35 8 4 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 264
MT_RFALLSD Fallen One falsword\fall falsword\fallent Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 1 2 1 2 5 Fallen 0 15 8 1 4 0 5 0 0 0 0 0 0 0 0 10 Animal Bottom,Middle 52
MT_DFALLSD Carver falsword\fall falsword\dark Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 3 3 5 9 Fallen 1 20 8 2 7 0 5 0 0 0 0 0 0 0 0 15 Animal Bottom,Middle 90
MT_YFALLSD Devil Kin falsword\fall Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 4 5 16 24 Fallen 2 25 8 4 10 0 5 0 0 0 0 0 0 0 0 20 Animal RESIST_FIRE Bottom,Middle 180
MT_BFALLSD Dark One falsword\fall falsword\blue Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 3 5 7 24 36 Fallen 3 30 8 4 12 0 5 0 0 0 0 0 0 0 0 25 Animal RESIST_LIGHTNING Bottom,Middle 280
MT_NSCAV Scavenger scav\scav Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 1 3 2 3 6 Scavenger 0 20 7 1 5 0 0 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 80
MT_BSCAV Plague Eater scav\scav scav\scavbr Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 2 4 4 12 24 Scavenger 1 30 7 1 8 0 0 0 0 0 0 0 0 0 0 20 Animal RESIST_LIGHTNING Bottom,Middle 188
MT_WSCAV Shadow Beast scav\scav scav\scavbe Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 3 5 6 24 36 Scavenger 2 35 7 3 12 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_FIRE Bottom,Middle 375
MT_YSCAV Bone Gasher scav\scav scav\scavw Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 4 6 8 28 40 Scavenger 3 35 7 5 15 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_LIGHTNING Bottom,Middle 552
MT_WSKELBW Skeleton skelbow\sklbw skelbow\white Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 3 3 2 4 SkeletonRanged 0 15 12 1 2 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 110
MT_TSKELBW Corpse Bow skelbow\sklbw skelbow\skelt Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 4 5 8 16 SkeletonRanged 1 25 12 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 210
MT_RSKELBW Burning Dead skelbow\sklbw Always 128 567 true false 9,8,16,5,16,16 2,1,1,1,1,1 3 5 7 10 24 SkeletonRanged 2 30 12 1 6 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 364
MT_XSKELBW Horror skelbow\sklbw skelbow\black Always 128 567 true false 9,8,16,5,16,16 3,1,1,1,1,1 4 6 9 15 45 SkeletonRanged 3 35 12 2 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 594
MT_WSKELSD Skeleton Captain skelsd\sklsr skelsd\white Always 128 575 true true 13,8,12,7,15,16 4,1,1,1,1,1 1 3 2 3 6 SkeletonMelee 0 20 8 2 7 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 90
MT_TSKELSD Corpse Captain skelsd\sklsr skelsd\skelt Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 2 4 4 12 20 SkeletonMelee 1 30 8 3 9 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 200
MT_RSKELSD Burning Dead Captain skelsd\sklsr Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 3 5 6 16 30 SkeletonMelee 2 35 8 4 10 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 393
MT_XSKELSD Horror Captain skelsd\sklsr skelsd\black Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 4 6 8 35 50 SkeletonMelee SEARCH 3 40 8 5 14 0 0 0 0 0 0 0 0 0 0 30 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 604
MT_INVILORD Invisible Lord tsneak\tsneak Never 128 800 false false 13,13,15,11,16,0 2,1,1,1,1,1 19 20 14 278 278 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 65 8 16 30 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2000
MT_SNEAK Hidden sneak\sneak Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 2 5 5 8 24 Sneak HIDDEN 0 35 8 3 6 0 0 0 0 0 0 0 0 0 0 25 Demon Bottom,Middle 278
MT_STALKER Stalker sneak\sneak sneak\sneakv2 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 5 7 9 30 45 Sneak HIDDEN,SEARCH 1 40 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Demon Bottom,Middle 630
MT_UNSEEN Unseen sneak\sneak sneak\sneakv3 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 6 8 11 35 50 Sneak HIDDEN,SEARCH 2 45 8 12 20 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 935
MT_ILLWEAV Illusion Weaver sneak\sneak sneak\sneakv1 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 8 10 13 40 60 Sneak HIDDEN,SEARCH 3 60 8 16 24 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC,RESIST_FIRE IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 1500
MT_LRDSAYTR Satyr Lord goatlord\goatl newsfx\satyr Never 160 800 false false 13,13,14,9,16,0 2,1,1,1,1,1 21 22 28 160 200 SkeletonMelee SEARCH 3 90 8 20 30 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 2800
MT_NGOATMC Flesh Clan goatmace\goat Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 4 6 8 30 45 GoatMelee SEARCH,CAN_OPEN_DOOR 0 50 8 4 10 0 0 0 0 0 0 0 0 0 0 40 Demon Bottom,Middle 460
MT_BGOATMC Stone Clan goatmace\goat goatmace\beige Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 5 7 10 40 55 GoatMelee SEARCH,CAN_OPEN_DOOR 1 60 8 6 12 0 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 685
MT_RGOATMC Fire Clan goatmace\goat goatmace\red Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 6 8 12 50 65 GoatMelee SEARCH,CAN_OPEN_DOOR 2 70 8 8 16 0 0 0 0 0 0 0 0 0 0 45 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 906
MT_GGOATMC Night Clan goatmace\goat goatmace\gray Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 7 9 14 55 70 GoatMelee SEARCH,CAN_OPEN_DOOR 3 80 8 10 20 15 0 30 30 0 0 0 0 0 0 50 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1190
MT_FIEND Fiend bat\bat bat\red Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 2 3 3 3 6 Bat 0 35 5 1 6 0 0 0 0 0 0 0 0 0 0 0 Animal Middle,Top None 102
MT_BLINK Blink bat\bat Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 3 5 7 12 28 Bat 1 45 5 1 8 0 0 0 0 0 0 0 0 0 0 15 Animal Middle,Top None 340
MT_GLOOM Gloom bat\bat bat\grey Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 4 6 9 28 36 Bat SEARCH 2 70 5 4 12 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC RESIST_MAGIC Middle,Top None 509
MT_FAMILIAR Familiar bat\bat bat\orange Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 6 8 13 20 35 Bat SEARCH 3 50 5 4 16 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Middle,Top None 448
MT_NGOATBW Flesh Clan goatbow\goatb Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 4 6 8 20 35 GoatRanged CAN_OPEN_DOOR 0 35 13 1 7 0 0 0 0 0 0 0 0 0 0 35 Demon Bottom,Middle 448
MT_BGOATBW Stone Clan goatbow\goatb goatbow\beige Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 5 7 10 30 40 GoatRanged CAN_OPEN_DOOR 1 40 13 2 9 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 645
MT_RGOATBW Fire Clan goatbow\goatb goatbow\red Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 6 8 12 40 50 GoatRanged SEARCH,CAN_OPEN_DOOR 2 45 13 3 11 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 822
MT_GGOATBW Night Clan goatbow\goatb goatbow\gray Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 7 9 14 50 65 GoatRanged SEARCH,CAN_OPEN_DOOR 3 50 13 4 13 15 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1092
MT_NACID Acid Beast acid\acid Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 6 8 11 40 66 Acid 0 40 8 4 12 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 846
MT_RACID Poison Spitter acid\acid acid\acidblk Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 8 10 15 60 85 Acid 1 45 8 4 16 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 1248
MT_BACID Pit Beast acid\acid acid\acidb Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 10 12 21 80 110 Acid 2 55 8 8 18 35 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_ACID IMMUNE_MAGIC,RESIST_LIGHTNING,IMMUNE_ACID Bottom,Middle 2060
MT_XACID Lava Maw acid\acid acid\acidr Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 12 14 25 100 150 Acid 3 65 8 10 20 40 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_ACID Bottom,Middle 2940
MT_SKING Skeleton King sking\sking skelaxe\white Never 160 1010 true true 8,6,16,6,16,6 2,1,1,1,1,2 4 4 9 140 140 SkeletonKing SEARCH,CAN_OPEN_DOOR 3 60 8 6 16 0 0 0 0 0 0 0 0 0 0 70 Undead IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top Uniq(SKCROWN) 570
MT_CLEAVER The Butcher fatc\fatc Never 128 980 false false 10,8,12,6,16,0 1,1,1,1,1,1 1 1 1 320 320 Butcher 3 50 8 6 12 0 0 0 0 0 0 0 0 0 0 50 Demon RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle Uniq(CLEAVER) 710
MT_FAT Overlord fat\fat Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 5 7 10 60 80 Fat 0 55 8 6 12 0 0 0 0 0 0 0 0 0 0 55 Demon RESIST_FIRE Bottom,Middle 635
MT_MUDMAN Mud Man fat\fat fat\blue Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 7 9 14 100 125 Fat SEARCH 1 60 8 8 16 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_LIGHTNING Bottom,Middle 1165
MT_TOAD Toad Demon fat\fat fat\fatb Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 8 10 16 135 160 Fat SEARCH 2 70 8 8 16 40 0 8 20 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 1380
MT_FLAYED Flayed One fat\fat fat\fatf Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 10 12 20 160 200 Fat SEARCH 3 85 8 10 20 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2058
MT_WYRM Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 5 7 11 60 90 SkeletonMelee 0 40 8 4 10 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 660
MT_CAVSLUG Cave Slug worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 6 8 13 75 110 SkeletonMelee 1 50 8 6 13 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 994
MT_DVLWYRM Devil Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 7 9 15 100 140 SkeletonMelee 2 55 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1320
MT_DEVOUR Devourer worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 8 10 17 125 200 SkeletonMelee 3 60 8 10 20 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1827
MT_NMAGMA Magma Demon magma\magma Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 9 13 50 70 Magma SEARCH,CAN_OPEN_DOOR 0 45 4 2 10 50 13 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1076
MT_YMAGMA Blood Stone magma\magma magma\yellow Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 10 14 55 75 Magma SEARCH,CAN_OPEN_DOOR 1 50 4 2 12 50 14 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1309
MT_BMAGMA Hell Stone magma\magma magma\blue Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 16 60 80 Magma SEARCH,CAN_OPEN_DOOR 2 60 4 2 20 60 14 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1680
MT_WMAGMA Lava Lord magma\magma magma\wierd Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 18 70 85 Magma SEARCH,CAN_OPEN_DOOR 3 75 4 4 24 60 14 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2124
MT_HORNED Horned Demon rhino\rhino Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 7 9 13 40 80 Rhino SEARCH,CAN_OPEN_DOOR 0 60 7 2 16 100 0 5 32 0 0 0 0 0 0 40 Animal RESIST_FIRE Bottom,Middle,Top 1172
MT_MUDRUN Mud Runner rhino\rhino rhino\orange Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 8 10 15 50 90 Rhino SEARCH,CAN_OPEN_DOOR 1 70 7 6 18 100 0 12 36 0 0 0 0 0 0 45 Animal RESIST_FIRE Bottom,Middle,Top 1404
MT_FROSTC Frost Charger rhino\rhino rhino\blue Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 9 11 17 60 100 Rhino SEARCH,CAN_OPEN_DOOR 2 80 7 8 20 100 0 20 40 0 0 0 0 0 0 50 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 1720
MT_OBLORD Obsidian Lord rhino\rhino rhino\rhinob Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 10 12 19 70 110 Rhino SEARCH,CAN_OPEN_DOOR 3 90 7 10 22 100 0 20 50 0 0 0 0 0 0 55 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 1809
MT_BONEDMN oldboned demskel\demskl Never 128 1740 true true 10,8,20,6,24,16 3,1,1,1,1,1 24 24 12 70 70 Storm 0 60 8 6 14 12 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 1344
MT_REDDTH Red Death thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 8 10 16 96 96 Storm 1 75 5 10 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2168
MT_LTCHDMN Litch Demon thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 110 110 Storm 2 80 5 10 24 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2736
MT_UDEDBLRG Undead Balrog thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 130 130 Storm 3 85 5 12 30 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3575
MT_INCIN Incinerator fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 21 22 16 30 45 FireMan 0 75 8 8 16 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 1888
MT_FLAMLRD Flame Lord fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 22 23 18 40 55 FireMan 1 75 8 10 20 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2250
MT_DOOMFIRE Doom Fire fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 23 24 20 50 65 FireMan 2 80 8 12 24 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 2740
MT_HELLBURN Hell Burner fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 24 24 22 60 80 FireMan 3 85 8 15 30 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 3355
MT_STORM Red Storm thin\thin thin\thinv3 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 55 110 Storm SEARCH,CAN_OPEN_DOOR 0 80 5 8 18 75 8 4 16 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2160
MT_RSTORM Storm Rider thin\thin Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 10 12 20 60 120 Storm SEARCH,CAN_OPEN_DOOR 1 80 5 8 18 80 8 4 16 0 0 0 0 0 0 30 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2391
MT_STORML Storm Lord thin\thin thin\thinv2 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 75 135 Storm SEARCH,CAN_OPEN_DOOR 2 85 5 12 24 75 8 4 16 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2775
MT_MAEL Maelstrom thin\thin thin\thinv1 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 12 14 24 90 150 Storm SEARCH,CAN_OPEN_DOOR 3 90 5 12 28 75 8 4 16 0 0 0 0 0 0 40 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3177
MT_BIGFALL Devil Kin Brute bigfall\fallg newsfx\kbrute Never 128 800 true false 10,8,11,8,17,0 1,1,1,1,2,2 21 22 27 120 160 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 100 6 18 24 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2400
MT_WINGED Winged-Demon gargoyle\gargo Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 5 7 9 45 60 Gargoyle CAN_OPEN_DOOR 0 50 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Middle,Top 662
MT_GARGOYLE Gargoyle gargoyle\gargo gargoyle\gare Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 7 9 13 60 90 Gargoyle CAN_OPEN_DOOR 1 65 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Middle,Top 1205
MT_BLOODCLW Blood Claw gargoyle\gargo gargoyle\gargbr Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 9 11 19 75 125 Gargoyle CAN_OPEN_DOOR 2 80 7 14 22 0 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Middle,Top 1873
MT_DEATHW Death Wing gargoyle\gargo gargoyle\gargb Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 10 12 23 90 150 Gargoyle CAN_OPEN_DOOR 3 95 7 16 28 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Middle,Top 2278
MT_MEGA Slayer mega\mega Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 10 12 20 120 140 Mega SEARCH,CAN_OPEN_DOOR 0 100 8 12 20 0 3 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2300
MT_GUARD Guardian mega\mega mega\guard Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 11 13 22 140 160 Mega SEARCH,CAN_OPEN_DOOR 1 110 8 14 22 0 3 0 0 0 0 0 0 0 0 65 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2714
MT_VTEXLRD Vortex Lord mega\mega mega\vtexl Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 12 14 24 160 180 Mega SEARCH,CAN_OPEN_DOOR 2 120 8 18 24 0 3 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3252
MT_BALROG Balrog mega\mega mega\balr Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 13 15 26 180 200 Mega SEARCH,CAN_OPEN_DOOR 3 130 8 22 30 0 3 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3643
MT_NSNAKE Cave Viper snake\snake Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 11 13 21 100 150 Snake SEARCH 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 2725
MT_RSNAKE Fire Drake snake\snake snake\snakr Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 12 14 23 120 170 Snake SEARCH 1 105 8 12 24 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3139
MT_BSNAKE Gold Viper snake\snake snake\snakg Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 13 14 25 140 180 Snake SEARCH 2 120 8 15 26 0 0 0 0 0 0 0 0 0 0 70 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 3540
MT_GSNAKE Azure Drake snake\snake snake\snakb Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 15 16 27 160 200 Snake SEARCH 3 130 8 18 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 3791
MT_NBLACK Black Knight black\black Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 12 14 24 150 150 SkeletonMelee SEARCH 0 110 8 15 20 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3360
MT_RTBLACK Doom Guard black\black black\blkkntrt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 15 26 165 165 SkeletonMelee SEARCH 0 130 8 18 25 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3650
MT_BTBLACK Steel Lord black\black black\blkkntbt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 14 16 28 180 180 SkeletonMelee SEARCH 1 120 8 20 30 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4252
MT_RBLACK Blood Knight black\black black\blkkntbe Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 14 30 200 200 SkeletonMelee SEARCH 1 130 8 25 35 0 0 0 0 0 0 0 0 0 0 85 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5130
MT_UNRAV The Shredded unrav\unrav newsfx\shred Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 17 18 23 70 90 SkeletonMelee 0 75 7 4 12 0 0 0 0 0 0 0 0 0 0 65 Undead RESIST_FIRE,RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 900
MT_HOLOWONE Hollow One unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 18 19 27 135 240 SkeletonMelee 1 75 7 12 24 0 0 0 0 0 0 0 0 0 0 75 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4374
MT_PAINMSTR Pain Master unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 19 20 29 110 200 SkeletonMelee 2 80 7 16 30 0 0 0 0 0 0 0 0 0 0 80 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 5147
MT_REALWEAV Reality Weaver unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 20 20 30 135 240 SkeletonMelee 3 85 7 20 35 0 0 0 0 0 0 0 0 0 0 85 Undead RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 5925
MT_SUCCUBUS Succubus succ\scbs Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 12 14 24 120 150 Succubus CAN_OPEN_DOOR 0 100 10 1 20 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 3696
MT_SNOWWICH Snow Witch succ\scbs succ\succb Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 13 15 26 135 175 Succubus CAN_OPEN_DOOR 1 110 10 1 24 0 0 0 0 0 0 0 0 0 0 65 Demon RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 4084
MT_HLSPWN Hell Spawn succ\scbs succ\succrw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 14 16 28 150 200 Succubus SEARCH,CAN_OPEN_DOOR 2 115 10 1 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4480
MT_SOLBRNR Soul Burner succ\scbs succ\succbw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 15 16 30 140 225 Succubus SEARCH,CAN_OPEN_DOOR 3 120 10 1 35 0 0 0 0 0 0 0 0 0 0 85 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 4644
MT_COUNSLR Counselor mage\mage Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 13 14 25 70 70 Counselor CAN_OPEN_DOOR 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4070
MT_MAGISTR Magistrate mage\mage mage\cnselg Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 14 15 27 85 85 Counselor CAN_OPEN_DOOR 1 100 8 10 24 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4478
MT_CABALIST Cabalist mage\mage mage\cnselgd Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 15 16 29 120 120 Counselor CAN_OPEN_DOOR 2 110 8 14 30 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4929
MT_ADVOCATE Advocate mage\mage mage\cnselbk Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 16 16 30 145 145 Counselor CAN_OPEN_DOOR 3 120 8 15 25 0 0 0 0 0 0 0 0 0 0 0 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968
MT_GOLEM Golem golem\golem golem\golm Never 96 386 true false 0,16,12,0,12,20 1,1,1,1,1,1 1 1 12 1 1 Golem CAN_OPEN_DOOR 0 0 7 1 1 0 0 0 0 0 0 0 0 0 0 1 Demon 0
MT_DIABLO The Dark Lord diablo\diablo Never 160 2000 true true 16,6,16,6,16,16 1,1,1,1,1,1 26 26 30 1666 1666 Diablo KNOCKBACK,SEARCH,CAN_OPEN_DOOR 3 220 4 30 60 0 11 0 0 0 0 0 0 0 0 90 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 31666
MT_DARKMAGE The Arch-Litch Malignus darkmage\dmage darkmage\dmag Never 128 1060 true false 6,1,21,6,23,18 1,1,1,1,1,1 21 21 30 160 160 Counselor CAN_OPEN_DOOR 3 120 8 20 40 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968
_monster_id name assetsSuffix soundSuffix trnFile availability width image hasSpecial hasSpecialSound frames[6] rate[6] minDunLvl maxDunLvl level hitPointsMinimum hitPointsMaximum ai abilityFlags intelligence toHit animFrameNum minDamage maxDamage toHitSpecial animFrameNumSpecial minDamageSpecial maxDamageSpecial reducePlayerStrength reducePlayerMagic reducePlayerDexterity reducePlayerVitality reducePlayerMaxHP reducePlayerMaxMana armorClass monsterClass resistance resistanceHell selectionRegion treasure exp shadowRule[6]
MT_NZOMBIE Zombie zombie\zombie Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 1 2 1 4 7 Zombie 0 10 8 2 5 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 54 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_BZOMBIE Ghoul zombie\zombie zombie\bluered Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 3 2 7 11 Zombie 1 10 8 3 10 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 58 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_GZOMBIE Rotting Carcass zombie\zombie zombie\grey Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 4 4 15 25 Zombie 2 25 8 5 15 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 136 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_YZOMBIE Black Death zombie\zombie zombie\yellow Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 3 5 6 25 40 Zombie 3 30 8 6 22 0 0 0 0 0 0 0 0 1 0 20 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 240 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_RFALLSP Fallen One falspear\phall falspear\fallent Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 1 2 1 1 4 Fallen 0 15 7 1 3 0 5 0 0 0 0 0 0 0 0 0 Animal Bottom,Middle 46 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_DFALLSP Carver falspear\phall falspear\dark Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 3 3 4 8 Fallen 2 20 7 2 5 0 5 0 0 0 0 0 0 0 0 5 Animal Bottom,Middle 80 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_YFALLSP Devil Kin falspear\phall Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 4 5 12 24 Fallen 2 25 7 3 7 0 5 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 155 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BFALLSP Dark One falspear\phall falspear\blue Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 3 5 7 20 36 Fallen 3 30 7 4 8 0 5 0 0 0 0 0 0 0 0 15 Animal RESIST_LIGHTNING Bottom,Middle 255 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WSKELAX Skeleton skelaxe\sklax skelaxe\white Always 128 553 true false 12,8,13,6,17,16 5,1,1,1,1,1 1 2 1 2 4 SkeletonMelee 0 20 8 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 64 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_TSKELAX Corpse Axe skelaxe\sklax skelaxe\skelt Always 128 553 true false 12,8,13,6,17,16 4,1,1,1,1,1 2 3 2 4 7 SkeletonMelee 1 25 8 3 5 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 68 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RSKELAX Burning Dead skelaxe\sklax Always 128 553 true false 12,8,13,6,17,16 2,1,1,1,1,1 2 4 4 8 12 SkeletonMelee 2 30 8 3 7 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 154 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_XSKELAX Horror skelaxe\sklax skelaxe\black Always 128 553 true false 12,8,13,6,17,16 3,1,1,1,1,1 3 5 6 12 20 SkeletonMelee 3 35 8 4 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 264 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RFALLSD Fallen One falsword\fall falsword\fallent Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 1 2 1 2 5 Fallen 0 15 8 1 4 0 5 0 0 0 0 0 0 0 0 10 Animal Bottom,Middle 52 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_DFALLSD Carver falsword\fall falsword\dark Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 3 3 5 9 Fallen 1 20 8 2 7 0 5 0 0 0 0 0 0 0 0 15 Animal Bottom,Middle 90 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_YFALLSD Devil Kin falsword\fall Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 4 5 16 24 Fallen 2 25 8 4 10 0 5 0 0 0 0 0 0 0 0 20 Animal RESIST_FIRE Bottom,Middle 180 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BFALLSD Dark One falsword\fall falsword\blue Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 3 5 7 24 36 Fallen 3 30 8 4 12 0 5 0 0 0 0 0 0 0 0 25 Animal RESIST_LIGHTNING Bottom,Middle 280 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_NSCAV Scavenger scav\scav Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 1 3 2 3 6 Scavenger 0 20 7 1 5 0 0 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 80 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BSCAV Plague Eater scav\scav scav\scavbr Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 2 4 4 12 24 Scavenger 1 30 7 1 8 0 0 0 0 0 0 0 0 0 0 20 Animal RESIST_LIGHTNING Bottom,Middle 188 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WSCAV Shadow Beast scav\scav scav\scavbe Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 3 5 6 24 36 Scavenger 2 35 7 3 12 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_FIRE Bottom,Middle 375 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_YSCAV Bone Gasher scav\scav scav\scavw Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 4 6 8 28 40 Scavenger 3 35 7 5 15 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_LIGHTNING Bottom,Middle 552 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WSKELBW Skeleton skelbow\sklbw skelbow\white Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 3 3 2 4 SkeletonRanged 0 15 12 1 2 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 110 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_TSKELBW Corpse Bow skelbow\sklbw skelbow\skelt Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 4 5 8 16 SkeletonRanged 1 25 12 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 210 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RSKELBW Burning Dead skelbow\sklbw Always 128 567 true false 9,8,16,5,16,16 2,1,1,1,1,1 3 5 7 10 24 SkeletonRanged 2 30 12 1 6 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 364 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_XSKELBW Horror skelbow\sklbw skelbow\black Always 128 567 true false 9,8,16,5,16,16 3,1,1,1,1,1 4 6 9 15 45 SkeletonRanged 3 35 12 2 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 594 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WSKELSD Skeleton Captain skelsd\sklsr skelsd\white Always 128 575 true true 13,8,12,7,15,16 4,1,1,1,1,1 1 3 2 3 6 SkeletonMelee 0 20 8 2 7 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 90 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_TSKELSD Corpse Captain skelsd\sklsr skelsd\skelt Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 2 4 4 12 20 SkeletonMelee 1 30 8 3 9 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 200 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RSKELSD Burning Dead Captain skelsd\sklsr Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 3 5 6 16 30 SkeletonMelee 2 35 8 4 10 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 393 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_XSKELSD Horror Captain skelsd\sklsr skelsd\black Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 4 6 8 35 50 SkeletonMelee SEARCH 3 40 8 5 14 0 0 0 0 0 0 0 0 0 0 30 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 604 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_INVILORD Invisible Lord tsneak\tsneak Never 128 800 false false 13,13,15,11,16,0 2,1,1,1,1,1 19 20 14 278 278 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 65 8 16 30 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2000 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_SNEAK Hidden sneak\sneak Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 2 5 5 8 24 Sneak HIDDEN 0 35 8 3 6 0 0 0 0 0 0 0 0 0 0 25 Demon Bottom,Middle 278 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_STALKER Stalker sneak\sneak sneak\sneakv2 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 5 7 9 30 45 Sneak HIDDEN,SEARCH 1 40 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Demon Bottom,Middle 630 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_UNSEEN Unseen sneak\sneak sneak\sneakv3 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 6 8 11 35 50 Sneak HIDDEN,SEARCH 2 45 8 12 20 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 935 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_ILLWEAV Illusion Weaver sneak\sneak sneak\sneakv1 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 8 10 13 40 60 Sneak HIDDEN,SEARCH 3 60 8 16 24 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC,RESIST_FIRE IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 1500 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_LRDSAYTR Satyr Lord goatlord\goatl newsfx\satyr Never 160 800 false false 13,13,14,9,16,0 2,1,1,1,1,1 21 22 28 160 200 SkeletonMelee SEARCH 3 90 8 20 30 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 2800 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_NGOATMC Flesh Clan goatmace\goat Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 4 6 8 30 45 GoatMelee SEARCH,CAN_OPEN_DOOR 0 50 8 4 10 0 0 0 0 0 0 0 0 0 0 40 Demon Bottom,Middle 460 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BGOATMC Stone Clan goatmace\goat goatmace\beige Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 5 7 10 40 55 GoatMelee SEARCH,CAN_OPEN_DOOR 1 60 8 6 12 0 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 685 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RGOATMC Fire Clan goatmace\goat goatmace\red Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 6 8 12 50 65 GoatMelee SEARCH,CAN_OPEN_DOOR 2 70 8 8 16 0 0 0 0 0 0 0 0 0 0 45 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 906 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_GGOATMC Night Clan goatmace\goat goatmace\gray Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 7 9 14 55 70 GoatMelee SEARCH,CAN_OPEN_DOOR 3 80 8 10 20 15 0 30 30 0 0 0 0 0 0 50 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1190 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_FIEND Fiend bat\bat bat\red Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 2 3 3 3 6 Bat 0 35 5 1 6 0 0 0 0 0 0 0 0 0 0 0 Animal Middle,Top None 102 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
MT_BLINK Blink bat\bat Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 3 5 7 12 28 Bat 1 45 5 1 8 0 0 0 0 0 0 0 0 0 0 15 Animal Middle,Top None 340 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
MT_GLOOM Gloom bat\bat bat\grey Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 4 6 9 28 36 Bat SEARCH 2 70 5 4 12 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC RESIST_MAGIC Middle,Top None 509 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
MT_FAMILIAR Familiar bat\bat bat\orange Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 6 8 13 20 35 Bat SEARCH 3 50 5 4 16 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Middle,Top None 448 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
MT_NGOATBW Flesh Clan goatbow\goatb Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 4 6 8 20 35 GoatRanged CAN_OPEN_DOOR 0 35 13 1 7 0 0 0 0 0 0 0 0 0 0 35 Demon Bottom,Middle 448 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_BGOATBW Stone Clan goatbow\goatb goatbow\beige Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 5 7 10 30 40 GoatRanged CAN_OPEN_DOOR 1 40 13 2 9 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 645 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_RGOATBW Fire Clan goatbow\goatb goatbow\red Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 6 8 12 40 50 GoatRanged SEARCH,CAN_OPEN_DOOR 2 45 13 3 11 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 822 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_GGOATBW Night Clan goatbow\goatb goatbow\gray Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 7 9 14 50 65 GoatRanged SEARCH,CAN_OPEN_DOOR 3 50 13 4 13 15 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1092 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_NACID Acid Beast acid\acid Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 6 8 11 40 66 Acid 0 40 8 4 12 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 846 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RACID Poison Spitter acid\acid acid\acidblk Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 8 10 15 60 85 Acid 1 45 8 4 16 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 1248 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BACID Pit Beast acid\acid acid\acidb Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 10 12 21 80 110 Acid 2 55 8 8 18 35 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_ACID IMMUNE_MAGIC,RESIST_LIGHTNING,IMMUNE_ACID Bottom,Middle 2060 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_XACID Lava Maw acid\acid acid\acidr Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 12 14 25 100 150 Acid 3 65 8 10 20 40 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_ACID Bottom,Middle 2940 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_SKING Skeleton King sking\sking skelaxe\white Never 160 1010 true true 8,6,16,6,16,6 2,1,1,1,1,2 4 4 9 140 140 SkeletonKing SEARCH,CAN_OPEN_DOOR 3 60 8 6 16 0 0 0 0 0 0 0 0 0 0 70 Undead IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top Uniq(SKCROWN) 570 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_CLEAVER The Butcher fatc\fatc Never 128 980 false false 10,8,12,6,16,0 1,1,1,1,1,1 1 1 1 320 320 Butcher 3 50 8 6 12 0 0 0 0 0 0 0 0 0 0 50 Demon RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle Uniq(CLEAVER) 710 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_FAT Overlord fat\fat Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 5 7 10 60 80 Fat 0 55 8 6 12 0 0 0 0 0 0 0 0 0 0 55 Demon RESIST_FIRE Bottom,Middle 635 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_MUDMAN Mud Man fat\fat fat\blue Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 7 9 14 100 125 Fat SEARCH 1 60 8 8 16 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_LIGHTNING Bottom,Middle 1165 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_TOAD Toad Demon fat\fat fat\fatb Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 8 10 16 135 160 Fat SEARCH 2 70 8 8 16 40 0 8 20 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 1380 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_FLAYED Flayed One fat\fat fat\fatf Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 10 12 20 160 200 Fat SEARCH 3 85 8 10 20 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2058 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WYRM Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 5 7 11 60 90 SkeletonMelee 0 40 8 4 10 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 660
MT_CAVSLUG Cave Slug worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 6 8 13 75 110 SkeletonMelee 1 50 8 6 13 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 994
MT_DVLWYRM Devil Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 7 9 15 100 140 SkeletonMelee 2 55 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1320
MT_DEVOUR Devourer worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 8 10 17 125 200 SkeletonMelee 3 60 8 10 20 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1827
MT_NMAGMA Magma Demon magma\magma Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 9 13 50 70 Magma SEARCH,CAN_OPEN_DOOR 0 45 4 2 10 50 13 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1076 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_YMAGMA Blood Stone magma\magma magma\yellow Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 10 14 55 75 Magma SEARCH,CAN_OPEN_DOOR 1 50 4 2 12 50 14 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1309 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BMAGMA Hell Stone magma\magma magma\blue Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 16 60 80 Magma SEARCH,CAN_OPEN_DOOR 2 60 4 2 20 60 14 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1680 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WMAGMA Lava Lord magma\magma magma\wierd Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 18 70 85 Magma SEARCH,CAN_OPEN_DOOR 3 75 4 4 24 60 14 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2124 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_HORNED Horned Demon rhino\rhino Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 7 9 13 40 80 Rhino SEARCH,CAN_OPEN_DOOR 0 60 7 2 16 100 0 5 32 0 0 0 0 0 0 40 Animal RESIST_FIRE Bottom,Middle,Top 1172 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_MUDRUN Mud Runner rhino\rhino rhino\orange Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 8 10 15 50 90 Rhino SEARCH,CAN_OPEN_DOOR 1 70 7 6 18 100 0 12 36 0 0 0 0 0 0 45 Animal RESIST_FIRE Bottom,Middle,Top 1404 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_FROSTC Frost Charger rhino\rhino rhino\blue Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 9 11 17 60 100 Rhino SEARCH,CAN_OPEN_DOOR 2 80 7 8 20 100 0 20 40 0 0 0 0 0 0 50 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 1720 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_OBLORD Obsidian Lord rhino\rhino rhino\rhinob Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 10 12 19 70 110 Rhino SEARCH,CAN_OPEN_DOOR 3 90 7 10 22 100 0 20 50 0 0 0 0 0 0 55 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 1809 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BONEDMN oldboned demskel\demskl Never 128 1740 true true 10,8,20,6,24,16 3,1,1,1,1,1 24 24 12 70 70 Storm 0 60 8 6 14 12 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 1344 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_REDDTH Red Death thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 8 10 16 96 96 Storm 1 75 5 10 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2168 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_LTCHDMN Litch Demon thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 110 110 Storm 2 80 5 10 24 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2736 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_UDEDBLRG Undead Balrog thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 130 130 Storm 3 85 5 12 30 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3575 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_INCIN Incinerator fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 21 22 16 30 45 FireMan 0 75 8 8 16 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 1888 None,None,None,None,None,None
MT_FLAMLRD Flame Lord fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 22 23 18 40 55 FireMan 1 75 8 10 20 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2250 None,None,None,None,None,None
MT_DOOMFIRE Doom Fire fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 23 24 20 50 65 FireMan 2 80 8 12 24 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 2740 None,None,None,None,None,None
MT_HELLBURN Hell Burner fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 24 24 22 60 80 FireMan 3 85 8 15 30 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 3355 None,None,None,None,None,None
MT_STORM Red Storm thin\thin thin\thinv3 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 55 110 Storm SEARCH,CAN_OPEN_DOOR 0 80 5 8 18 75 8 4 16 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2160 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RSTORM Storm Rider thin\thin Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 10 12 20 60 120 Storm SEARCH,CAN_OPEN_DOOR 1 80 5 8 18 80 8 4 16 0 0 0 0 0 0 30 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2391 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_STORML Storm Lord thin\thin thin\thinv2 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 75 135 Storm SEARCH,CAN_OPEN_DOOR 2 85 5 12 24 75 8 4 16 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2775 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_MAEL Maelstrom thin\thin thin\thinv1 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 12 14 24 90 150 Storm SEARCH,CAN_OPEN_DOOR 3 90 5 12 28 75 8 4 16 0 0 0 0 0 0 40 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3177 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BIGFALL Devil Kin Brute bigfall\fallg newsfx\kbrute Never 128 800 true false 10,8,11,8,17,0 1,1,1,1,2,2 21 22 27 120 160 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 100 6 18 24 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2400 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_WINGED Winged-Demon gargoyle\gargo Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 5 7 9 45 60 Gargoyle CAN_OPEN_DOOR 0 50 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Middle,Top 662 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
MT_GARGOYLE Gargoyle gargoyle\gargo gargoyle\gare Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 7 9 13 60 90 Gargoyle CAN_OPEN_DOOR 1 65 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Middle,Top 1205 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
MT_BLOODCLW Blood Claw gargoyle\gargo gargoyle\gargbr Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 9 11 19 75 125 Gargoyle CAN_OPEN_DOOR 2 80 7 14 22 0 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Middle,Top 1873 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
MT_DEATHW Death Wing gargoyle\gargo gargoyle\gargb Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 10 12 23 90 150 Gargoyle CAN_OPEN_DOOR 3 95 7 16 28 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Middle,Top 2278 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
MT_MEGA Slayer mega\mega Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 10 12 20 120 140 Mega SEARCH,CAN_OPEN_DOOR 0 100 8 12 20 0 3 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2300 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
MT_GUARD Guardian mega\mega mega\guard Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 11 13 22 140 160 Mega SEARCH,CAN_OPEN_DOOR 1 110 8 14 22 0 3 0 0 0 0 0 0 0 0 65 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2714 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
MT_VTEXLRD Vortex Lord mega\mega mega\vtexl Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 12 14 24 160 180 Mega SEARCH,CAN_OPEN_DOOR 2 120 8 18 24 0 3 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3252 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
MT_BALROG Balrog mega\mega mega\balr Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 13 15 26 180 200 Mega SEARCH,CAN_OPEN_DOOR 3 130 8 22 30 0 3 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3643 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
MT_NSNAKE Cave Viper snake\snake Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 11 13 21 100 150 Snake SEARCH 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 2725 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
MT_RSNAKE Fire Drake snake\snake snake\snakr Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 12 14 23 120 170 Snake SEARCH 1 105 8 12 24 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3139 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
MT_BSNAKE Gold Viper snake\snake snake\snakg Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 13 14 25 140 180 Snake SEARCH 2 120 8 15 26 0 0 0 0 0 0 0 0 0 0 70 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 3540 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
MT_GSNAKE Azure Drake snake\snake snake\snakb Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 15 16 27 160 200 Snake SEARCH 3 130 8 18 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 3791 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
MT_NBLACK Black Knight black\black Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 12 14 24 150 150 SkeletonMelee SEARCH 0 110 8 15 20 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3360 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_RTBLACK Doom Guard black\black black\blkkntrt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 15 26 165 165 SkeletonMelee SEARCH 0 130 8 18 25 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3650 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_BTBLACK Steel Lord black\black black\blkkntbt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 14 16 28 180 180 SkeletonMelee SEARCH 1 120 8 20 30 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4252 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_RBLACK Blood Knight black\black black\blkkntbe Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 14 30 200 200 SkeletonMelee SEARCH 1 130 8 25 35 0 0 0 0 0 0 0 0 0 0 85 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5130 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_UNRAV The Shredded unrav\unrav newsfx\shred Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 17 18 23 70 90 SkeletonMelee 0 75 7 4 12 0 0 0 0 0 0 0 0 0 0 65 Undead RESIST_FIRE,RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 900 None,None,None,None,None,None
MT_HOLOWONE Hollow One unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 18 19 27 135 240 SkeletonMelee 1 75 7 12 24 0 0 0 0 0 0 0 0 0 0 75 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4374 None,None,None,None,None,None
MT_PAINMSTR Pain Master unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 19 20 29 110 200 SkeletonMelee 2 80 7 16 30 0 0 0 0 0 0 0 0 0 0 80 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 5147 None,None,None,None,None,None
MT_REALWEAV Reality Weaver unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 20 20 30 135 240 SkeletonMelee 3 85 7 20 35 0 0 0 0 0 0 0 0 0 0 85 Undead RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 5925 None,None,None,None,None,None
MT_SUCCUBUS Succubus succ\scbs Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 12 14 24 120 150 Succubus CAN_OPEN_DOOR 0 100 10 1 20 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 3696 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_SNOWWICH Snow Witch succ\scbs succ\succb Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 13 15 26 135 175 Succubus CAN_OPEN_DOOR 1 110 10 1 24 0 0 0 0 0 0 0 0 0 0 65 Demon RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 4084 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_HLSPWN Hell Spawn succ\scbs succ\succrw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 14 16 28 150 200 Succubus SEARCH,CAN_OPEN_DOOR 2 115 10 1 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4480 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_SOLBRNR Soul Burner succ\scbs succ\succbw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 15 16 30 140 225 Succubus SEARCH,CAN_OPEN_DOOR 3 120 10 1 35 0 0 0 0 0 0 0 0 0 0 85 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 4644 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_COUNSLR Counselor mage\mage Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 13 14 25 70 70 Counselor CAN_OPEN_DOOR 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4070 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
MT_MAGISTR Magistrate mage\mage mage\cnselg Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 14 15 27 85 85 Counselor CAN_OPEN_DOOR 1 100 8 10 24 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4478 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
MT_CABALIST Cabalist mage\mage mage\cnselgd Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 15 16 29 120 120 Counselor CAN_OPEN_DOOR 2 110 8 14 30 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4929 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
MT_ADVOCATE Advocate mage\mage mage\cnselbk Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 16 16 30 145 145 Counselor CAN_OPEN_DOOR 3 120 8 15 25 0 0 0 0 0 0 0 0 0 0 0 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
MT_GOLEM Golem golem\golem golem\golm Never 96 386 true false 0,16,12,0,12,20 1,1,1,1,1,1 1 1 12 1 1 Golem CAN_OPEN_DOOR 0 0 7 1 1 0 0 0 0 0 0 0 0 0 0 1 Demon 0 None,EachFrame,EachFrame,None,EachFrame,EachFrame
MT_DIABLO The Dark Lord diablo\diablo Never 160 2000 true true 16,6,16,6,16,16 1,1,1,1,1,1 26 26 30 1666 1666 Diablo KNOCKBACK,SEARCH,CAN_OPEN_DOOR 3 220 4 30 60 0 11 0 0 0 0 0 0 0 0 90 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 31666 FirstFrame,FirstFrame,EachFrame,FirstFrame,EachFrame,EachFrame
MT_DARKMAGE The Arch-Litch Malignus darkmage\dmage darkmage\dmag Never 128 1060 true false 6,1,21,6,23,18 1,1,1,1,1,1 21 21 30 160 160 Counselor CAN_OPEN_DOOR 3 120 8 20 40 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968 FirstFrame,None,FirstFrame,FirstFrame,FirstFrame,FirstFrame
1 _monster_id name assetsSuffix soundSuffix trnFile availability width image hasSpecial hasSpecialSound frames[6] rate[6] minDunLvl maxDunLvl level hitPointsMinimum hitPointsMaximum ai abilityFlags intelligence toHit animFrameNum minDamage maxDamage toHitSpecial animFrameNumSpecial minDamageSpecial maxDamageSpecial reducePlayerStrength reducePlayerMagic reducePlayerDexterity reducePlayerVitality reducePlayerMaxHP reducePlayerMaxMana armorClass monsterClass resistance resistanceHell selectionRegion treasure exp shadowRule[6]
2 MT_NZOMBIE Zombie zombie\zombie Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 1 2 1 4 7 Zombie 0 10 8 2 5 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 54 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
3 MT_BZOMBIE Ghoul zombie\zombie zombie\bluered Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 3 2 7 11 Zombie 1 10 8 3 10 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 58 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
4 MT_GZOMBIE Rotting Carcass zombie\zombie zombie\grey Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 4 4 15 25 Zombie 2 25 8 5 15 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 136 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
5 MT_YZOMBIE Black Death zombie\zombie zombie\yellow Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 3 5 6 25 40 Zombie 3 30 8 6 22 0 0 0 0 0 0 0 0 1 0 20 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 240 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
6 MT_RFALLSP Fallen One falspear\phall falspear\fallent Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 1 2 1 1 4 Fallen 0 15 7 1 3 0 5 0 0 0 0 0 0 0 0 0 Animal Bottom,Middle 46 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
7 MT_DFALLSP Carver falspear\phall falspear\dark Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 3 3 4 8 Fallen 2 20 7 2 5 0 5 0 0 0 0 0 0 0 0 5 Animal Bottom,Middle 80 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
8 MT_YFALLSP Devil Kin falspear\phall Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 4 5 12 24 Fallen 2 25 7 3 7 0 5 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 155 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
9 MT_BFALLSP Dark One falspear\phall falspear\blue Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 3 5 7 20 36 Fallen 3 30 7 4 8 0 5 0 0 0 0 0 0 0 0 15 Animal RESIST_LIGHTNING Bottom,Middle 255 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
10 MT_WSKELAX Skeleton skelaxe\sklax skelaxe\white Always 128 553 true false 12,8,13,6,17,16 5,1,1,1,1,1 1 2 1 2 4 SkeletonMelee 0 20 8 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 64 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
11 MT_TSKELAX Corpse Axe skelaxe\sklax skelaxe\skelt Always 128 553 true false 12,8,13,6,17,16 4,1,1,1,1,1 2 3 2 4 7 SkeletonMelee 1 25 8 3 5 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 68 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
12 MT_RSKELAX Burning Dead skelaxe\sklax Always 128 553 true false 12,8,13,6,17,16 2,1,1,1,1,1 2 4 4 8 12 SkeletonMelee 2 30 8 3 7 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 154 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
13 MT_XSKELAX Horror skelaxe\sklax skelaxe\black Always 128 553 true false 12,8,13,6,17,16 3,1,1,1,1,1 3 5 6 12 20 SkeletonMelee 3 35 8 4 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 264 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
14 MT_RFALLSD Fallen One falsword\fall falsword\fallent Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 1 2 1 2 5 Fallen 0 15 8 1 4 0 5 0 0 0 0 0 0 0 0 10 Animal Bottom,Middle 52 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
15 MT_DFALLSD Carver falsword\fall falsword\dark Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 3 3 5 9 Fallen 1 20 8 2 7 0 5 0 0 0 0 0 0 0 0 15 Animal Bottom,Middle 90 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
16 MT_YFALLSD Devil Kin falsword\fall Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 4 5 16 24 Fallen 2 25 8 4 10 0 5 0 0 0 0 0 0 0 0 20 Animal RESIST_FIRE Bottom,Middle 180 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
17 MT_BFALLSD Dark One falsword\fall falsword\blue Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 3 5 7 24 36 Fallen 3 30 8 4 12 0 5 0 0 0 0 0 0 0 0 25 Animal RESIST_LIGHTNING Bottom,Middle 280 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
18 MT_NSCAV Scavenger scav\scav Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 1 3 2 3 6 Scavenger 0 20 7 1 5 0 0 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 80 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
19 MT_BSCAV Plague Eater scav\scav scav\scavbr Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 2 4 4 12 24 Scavenger 1 30 7 1 8 0 0 0 0 0 0 0 0 0 0 20 Animal RESIST_LIGHTNING Bottom,Middle 188 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
20 MT_WSCAV Shadow Beast scav\scav scav\scavbe Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 3 5 6 24 36 Scavenger 2 35 7 3 12 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_FIRE Bottom,Middle 375 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
21 MT_YSCAV Bone Gasher scav\scav scav\scavw Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 4 6 8 28 40 Scavenger 3 35 7 5 15 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_LIGHTNING Bottom,Middle 552 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
22 MT_WSKELBW Skeleton skelbow\sklbw skelbow\white Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 3 3 2 4 SkeletonRanged 0 15 12 1 2 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 110 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
23 MT_TSKELBW Corpse Bow skelbow\sklbw skelbow\skelt Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 4 5 8 16 SkeletonRanged 1 25 12 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 210 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
24 MT_RSKELBW Burning Dead skelbow\sklbw Always 128 567 true false 9,8,16,5,16,16 2,1,1,1,1,1 3 5 7 10 24 SkeletonRanged 2 30 12 1 6 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 364 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
25 MT_XSKELBW Horror skelbow\sklbw skelbow\black Always 128 567 true false 9,8,16,5,16,16 3,1,1,1,1,1 4 6 9 15 45 SkeletonRanged 3 35 12 2 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 594 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
26 MT_WSKELSD Skeleton Captain skelsd\sklsr skelsd\white Always 128 575 true true 13,8,12,7,15,16 4,1,1,1,1,1 1 3 2 3 6 SkeletonMelee 0 20 8 2 7 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 90 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
27 MT_TSKELSD Corpse Captain skelsd\sklsr skelsd\skelt Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 2 4 4 12 20 SkeletonMelee 1 30 8 3 9 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 200 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
28 MT_RSKELSD Burning Dead Captain skelsd\sklsr Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 3 5 6 16 30 SkeletonMelee 2 35 8 4 10 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 393 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
29 MT_XSKELSD Horror Captain skelsd\sklsr skelsd\black Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 4 6 8 35 50 SkeletonMelee SEARCH 3 40 8 5 14 0 0 0 0 0 0 0 0 0 0 30 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 604 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
30 MT_INVILORD Invisible Lord tsneak\tsneak Never 128 800 false false 13,13,15,11,16,0 2,1,1,1,1,1 19 20 14 278 278 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 65 8 16 30 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2000 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
31 MT_SNEAK Hidden sneak\sneak Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 2 5 5 8 24 Sneak HIDDEN 0 35 8 3 6 0 0 0 0 0 0 0 0 0 0 25 Demon Bottom,Middle 278 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
32 MT_STALKER Stalker sneak\sneak sneak\sneakv2 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 5 7 9 30 45 Sneak HIDDEN,SEARCH 1 40 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Demon Bottom,Middle 630 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
33 MT_UNSEEN Unseen sneak\sneak sneak\sneakv3 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 6 8 11 35 50 Sneak HIDDEN,SEARCH 2 45 8 12 20 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 935 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
34 MT_ILLWEAV Illusion Weaver sneak\sneak sneak\sneakv1 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 8 10 13 40 60 Sneak HIDDEN,SEARCH 3 60 8 16 24 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC,RESIST_FIRE IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 1500 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
35 MT_LRDSAYTR Satyr Lord goatlord\goatl newsfx\satyr Never 160 800 false false 13,13,14,9,16,0 2,1,1,1,1,1 21 22 28 160 200 SkeletonMelee SEARCH 3 90 8 20 30 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 2800 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
36 MT_NGOATMC Flesh Clan goatmace\goat Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 4 6 8 30 45 GoatMelee SEARCH,CAN_OPEN_DOOR 0 50 8 4 10 0 0 0 0 0 0 0 0 0 0 40 Demon Bottom,Middle 460 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
37 MT_BGOATMC Stone Clan goatmace\goat goatmace\beige Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 5 7 10 40 55 GoatMelee SEARCH,CAN_OPEN_DOOR 1 60 8 6 12 0 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 685 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
38 MT_RGOATMC Fire Clan goatmace\goat goatmace\red Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 6 8 12 50 65 GoatMelee SEARCH,CAN_OPEN_DOOR 2 70 8 8 16 0 0 0 0 0 0 0 0 0 0 45 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 906 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
39 MT_GGOATMC Night Clan goatmace\goat goatmace\gray Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 7 9 14 55 70 GoatMelee SEARCH,CAN_OPEN_DOOR 3 80 8 10 20 15 0 30 30 0 0 0 0 0 0 50 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1190 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
40 MT_FIEND Fiend bat\bat bat\red Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 2 3 3 3 6 Bat 0 35 5 1 6 0 0 0 0 0 0 0 0 0 0 0 Animal Middle,Top None 102 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
41 MT_BLINK Blink bat\bat Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 3 5 7 12 28 Bat 1 45 5 1 8 0 0 0 0 0 0 0 0 0 0 15 Animal Middle,Top None 340 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
42 MT_GLOOM Gloom bat\bat bat\grey Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 4 6 9 28 36 Bat SEARCH 2 70 5 4 12 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC RESIST_MAGIC Middle,Top None 509 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
43 MT_FAMILIAR Familiar bat\bat bat\orange Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 6 8 13 20 35 Bat SEARCH 3 50 5 4 16 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Middle,Top None 448 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
44 MT_NGOATBW Flesh Clan goatbow\goatb Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 4 6 8 20 35 GoatRanged CAN_OPEN_DOOR 0 35 13 1 7 0 0 0 0 0 0 0 0 0 0 35 Demon Bottom,Middle 448 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
45 MT_BGOATBW Stone Clan goatbow\goatb goatbow\beige Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 5 7 10 30 40 GoatRanged CAN_OPEN_DOOR 1 40 13 2 9 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 645 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
46 MT_RGOATBW Fire Clan goatbow\goatb goatbow\red Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 6 8 12 40 50 GoatRanged SEARCH,CAN_OPEN_DOOR 2 45 13 3 11 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 822 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
47 MT_GGOATBW Night Clan goatbow\goatb goatbow\gray Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 7 9 14 50 65 GoatRanged SEARCH,CAN_OPEN_DOOR 3 50 13 4 13 15 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1092 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
48 MT_NACID Acid Beast acid\acid Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 6 8 11 40 66 Acid 0 40 8 4 12 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 846 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
49 MT_RACID Poison Spitter acid\acid acid\acidblk Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 8 10 15 60 85 Acid 1 45 8 4 16 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 1248 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
50 MT_BACID Pit Beast acid\acid acid\acidb Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 10 12 21 80 110 Acid 2 55 8 8 18 35 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_ACID IMMUNE_MAGIC,RESIST_LIGHTNING,IMMUNE_ACID Bottom,Middle 2060 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
51 MT_XACID Lava Maw acid\acid acid\acidr Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 12 14 25 100 150 Acid 3 65 8 10 20 40 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_ACID Bottom,Middle 2940 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
52 MT_SKING Skeleton King sking\sking skelaxe\white Never 160 1010 true true 8,6,16,6,16,6 2,1,1,1,1,2 4 4 9 140 140 SkeletonKing SEARCH,CAN_OPEN_DOOR 3 60 8 6 16 0 0 0 0 0 0 0 0 0 0 70 Undead IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top Uniq(SKCROWN) 570 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
53 MT_CLEAVER The Butcher fatc\fatc Never 128 980 false false 10,8,12,6,16,0 1,1,1,1,1,1 1 1 1 320 320 Butcher 3 50 8 6 12 0 0 0 0 0 0 0 0 0 0 50 Demon RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle Uniq(CLEAVER) 710 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
54 MT_FAT Overlord fat\fat Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 5 7 10 60 80 Fat 0 55 8 6 12 0 0 0 0 0 0 0 0 0 0 55 Demon RESIST_FIRE Bottom,Middle 635 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
55 MT_MUDMAN Mud Man fat\fat fat\blue Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 7 9 14 100 125 Fat SEARCH 1 60 8 8 16 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_LIGHTNING Bottom,Middle 1165 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
56 MT_TOAD Toad Demon fat\fat fat\fatb Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 8 10 16 135 160 Fat SEARCH 2 70 8 8 16 40 0 8 20 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 1380 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
57 MT_FLAYED Flayed One fat\fat fat\fatf Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 10 12 20 160 200 Fat SEARCH 3 85 8 10 20 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2058 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
58 MT_WYRM Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 5 7 11 60 90 SkeletonMelee 0 40 8 4 10 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 660
59 MT_CAVSLUG Cave Slug worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 6 8 13 75 110 SkeletonMelee 1 50 8 6 13 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 994
60 MT_DVLWYRM Devil Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 7 9 15 100 140 SkeletonMelee 2 55 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1320
61 MT_DEVOUR Devourer worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 8 10 17 125 200 SkeletonMelee 3 60 8 10 20 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1827
62 MT_NMAGMA Magma Demon magma\magma Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 9 13 50 70 Magma SEARCH,CAN_OPEN_DOOR 0 45 4 2 10 50 13 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1076 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
63 MT_YMAGMA Blood Stone magma\magma magma\yellow Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 10 14 55 75 Magma SEARCH,CAN_OPEN_DOOR 1 50 4 2 12 50 14 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1309 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
64 MT_BMAGMA Hell Stone magma\magma magma\blue Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 16 60 80 Magma SEARCH,CAN_OPEN_DOOR 2 60 4 2 20 60 14 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1680 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
65 MT_WMAGMA Lava Lord magma\magma magma\wierd Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 18 70 85 Magma SEARCH,CAN_OPEN_DOOR 3 75 4 4 24 60 14 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2124 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
66 MT_HORNED Horned Demon rhino\rhino Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 7 9 13 40 80 Rhino SEARCH,CAN_OPEN_DOOR 0 60 7 2 16 100 0 5 32 0 0 0 0 0 0 40 Animal RESIST_FIRE Bottom,Middle,Top 1172 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
67 MT_MUDRUN Mud Runner rhino\rhino rhino\orange Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 8 10 15 50 90 Rhino SEARCH,CAN_OPEN_DOOR 1 70 7 6 18 100 0 12 36 0 0 0 0 0 0 45 Animal RESIST_FIRE Bottom,Middle,Top 1404 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
68 MT_FROSTC Frost Charger rhino\rhino rhino\blue Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 9 11 17 60 100 Rhino SEARCH,CAN_OPEN_DOOR 2 80 7 8 20 100 0 20 40 0 0 0 0 0 0 50 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 1720 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
69 MT_OBLORD Obsidian Lord rhino\rhino rhino\rhinob Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 10 12 19 70 110 Rhino SEARCH,CAN_OPEN_DOOR 3 90 7 10 22 100 0 20 50 0 0 0 0 0 0 55 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 1809 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
70 MT_BONEDMN oldboned demskel\demskl Never 128 1740 true true 10,8,20,6,24,16 3,1,1,1,1,1 24 24 12 70 70 Storm 0 60 8 6 14 12 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 1344 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
71 MT_REDDTH Red Death thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 8 10 16 96 96 Storm 1 75 5 10 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2168 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
72 MT_LTCHDMN Litch Demon thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 110 110 Storm 2 80 5 10 24 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2736 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
73 MT_UDEDBLRG Undead Balrog thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 130 130 Storm 3 85 5 12 30 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3575 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
74 MT_INCIN Incinerator fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 21 22 16 30 45 FireMan 0 75 8 8 16 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 1888 None,None,None,None,None,None
75 MT_FLAMLRD Flame Lord fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 22 23 18 40 55 FireMan 1 75 8 10 20 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2250 None,None,None,None,None,None
76 MT_DOOMFIRE Doom Fire fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 23 24 20 50 65 FireMan 2 80 8 12 24 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 2740 None,None,None,None,None,None
77 MT_HELLBURN Hell Burner fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 24 24 22 60 80 FireMan 3 85 8 15 30 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 3355 None,None,None,None,None,None
78 MT_STORM Red Storm thin\thin thin\thinv3 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 55 110 Storm SEARCH,CAN_OPEN_DOOR 0 80 5 8 18 75 8 4 16 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2160 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
79 MT_RSTORM Storm Rider thin\thin Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 10 12 20 60 120 Storm SEARCH,CAN_OPEN_DOOR 1 80 5 8 18 80 8 4 16 0 0 0 0 0 0 30 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2391 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
80 MT_STORML Storm Lord thin\thin thin\thinv2 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 75 135 Storm SEARCH,CAN_OPEN_DOOR 2 85 5 12 24 75 8 4 16 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2775 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
81 MT_MAEL Maelstrom thin\thin thin\thinv1 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 12 14 24 90 150 Storm SEARCH,CAN_OPEN_DOOR 3 90 5 12 28 75 8 4 16 0 0 0 0 0 0 40 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3177 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
82 MT_BIGFALL Devil Kin Brute bigfall\fallg newsfx\kbrute Never 128 800 true false 10,8,11,8,17,0 1,1,1,1,2,2 21 22 27 120 160 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 100 6 18 24 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2400 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
83 MT_WINGED Winged-Demon gargoyle\gargo Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 5 7 9 45 60 Gargoyle CAN_OPEN_DOOR 0 50 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Middle,Top 662 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
84 MT_GARGOYLE Gargoyle gargoyle\gargo gargoyle\gare Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 7 9 13 60 90 Gargoyle CAN_OPEN_DOOR 1 65 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Middle,Top 1205 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
85 MT_BLOODCLW Blood Claw gargoyle\gargo gargoyle\gargbr Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 9 11 19 75 125 Gargoyle CAN_OPEN_DOOR 2 80 7 14 22 0 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Middle,Top 1873 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
86 MT_DEATHW Death Wing gargoyle\gargo gargoyle\gargb Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 10 12 23 90 150 Gargoyle CAN_OPEN_DOOR 3 95 7 16 28 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Middle,Top 2278 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
87 MT_MEGA Slayer mega\mega Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 10 12 20 120 140 Mega SEARCH,CAN_OPEN_DOOR 0 100 8 12 20 0 3 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2300 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
88 MT_GUARD Guardian mega\mega mega\guard Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 11 13 22 140 160 Mega SEARCH,CAN_OPEN_DOOR 1 110 8 14 22 0 3 0 0 0 0 0 0 0 0 65 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2714 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
89 MT_VTEXLRD Vortex Lord mega\mega mega\vtexl Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 12 14 24 160 180 Mega SEARCH,CAN_OPEN_DOOR 2 120 8 18 24 0 3 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3252 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
90 MT_BALROG Balrog mega\mega mega\balr Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 13 15 26 180 200 Mega SEARCH,CAN_OPEN_DOOR 3 130 8 22 30 0 3 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3643 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
91 MT_NSNAKE Cave Viper snake\snake Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 11 13 21 100 150 Snake SEARCH 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 2725 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
92 MT_RSNAKE Fire Drake snake\snake snake\snakr Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 12 14 23 120 170 Snake SEARCH 1 105 8 12 24 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3139 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
93 MT_BSNAKE Gold Viper snake\snake snake\snakg Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 13 14 25 140 180 Snake SEARCH 2 120 8 15 26 0 0 0 0 0 0 0 0 0 0 70 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 3540 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
94 MT_GSNAKE Azure Drake snake\snake snake\snakb Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 15 16 27 160 200 Snake SEARCH 3 130 8 18 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 3791 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
95 MT_NBLACK Black Knight black\black Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 12 14 24 150 150 SkeletonMelee SEARCH 0 110 8 15 20 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3360 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
96 MT_RTBLACK Doom Guard black\black black\blkkntrt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 15 26 165 165 SkeletonMelee SEARCH 0 130 8 18 25 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3650 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
97 MT_BTBLACK Steel Lord black\black black\blkkntbt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 14 16 28 180 180 SkeletonMelee SEARCH 1 120 8 20 30 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4252 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
98 MT_RBLACK Blood Knight black\black black\blkkntbe Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 14 30 200 200 SkeletonMelee SEARCH 1 130 8 25 35 0 0 0 0 0 0 0 0 0 0 85 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5130 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
99 MT_UNRAV The Shredded unrav\unrav newsfx\shred Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 17 18 23 70 90 SkeletonMelee 0 75 7 4 12 0 0 0 0 0 0 0 0 0 0 65 Undead RESIST_FIRE,RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 900 None,None,None,None,None,None
100 MT_HOLOWONE Hollow One unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 18 19 27 135 240 SkeletonMelee 1 75 7 12 24 0 0 0 0 0 0 0 0 0 0 75 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4374 None,None,None,None,None,None
101 MT_PAINMSTR Pain Master unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 19 20 29 110 200 SkeletonMelee 2 80 7 16 30 0 0 0 0 0 0 0 0 0 0 80 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 5147 None,None,None,None,None,None
102 MT_REALWEAV Reality Weaver unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 20 20 30 135 240 SkeletonMelee 3 85 7 20 35 0 0 0 0 0 0 0 0 0 0 85 Undead RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 5925 None,None,None,None,None,None
103 MT_SUCCUBUS Succubus succ\scbs Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 12 14 24 120 150 Succubus CAN_OPEN_DOOR 0 100 10 1 20 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 3696 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
104 MT_SNOWWICH Snow Witch succ\scbs succ\succb Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 13 15 26 135 175 Succubus CAN_OPEN_DOOR 1 110 10 1 24 0 0 0 0 0 0 0 0 0 0 65 Demon RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 4084 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
105 MT_HLSPWN Hell Spawn succ\scbs succ\succrw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 14 16 28 150 200 Succubus SEARCH,CAN_OPEN_DOOR 2 115 10 1 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4480 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
106 MT_SOLBRNR Soul Burner succ\scbs succ\succbw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 15 16 30 140 225 Succubus SEARCH,CAN_OPEN_DOOR 3 120 10 1 35 0 0 0 0 0 0 0 0 0 0 85 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 4644 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
107 MT_COUNSLR Counselor mage\mage Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 13 14 25 70 70 Counselor CAN_OPEN_DOOR 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4070 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
108 MT_MAGISTR Magistrate mage\mage mage\cnselg Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 14 15 27 85 85 Counselor CAN_OPEN_DOOR 1 100 8 10 24 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4478 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
109 MT_CABALIST Cabalist mage\mage mage\cnselgd Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 15 16 29 120 120 Counselor CAN_OPEN_DOOR 2 110 8 14 30 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4929 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
110 MT_ADVOCATE Advocate mage\mage mage\cnselbk Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 16 16 30 145 145 Counselor CAN_OPEN_DOOR 3 120 8 15 25 0 0 0 0 0 0 0 0 0 0 0 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
111 MT_GOLEM Golem golem\golem golem\golm Never 96 386 true false 0,16,12,0,12,20 1,1,1,1,1,1 1 1 12 1 1 Golem CAN_OPEN_DOOR 0 0 7 1 1 0 0 0 0 0 0 0 0 0 0 1 Demon 0 None,EachFrame,EachFrame,None,EachFrame,EachFrame
112 MT_DIABLO The Dark Lord diablo\diablo Never 160 2000 true true 16,6,16,6,16,16 1,1,1,1,1,1 26 26 30 1666 1666 Diablo KNOCKBACK,SEARCH,CAN_OPEN_DOOR 3 220 4 30 60 0 11 0 0 0 0 0 0 0 0 90 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 31666 FirstFrame,FirstFrame,EachFrame,FirstFrame,EachFrame,EachFrame
113 MT_DARKMAGE The Arch-Litch Malignus darkmage\dmage darkmage\dmag Never 128 1060 true false 6,1,21,6,23,18 1,1,1,1,1,1 21 21 30 160 160 Counselor CAN_OPEN_DOOR 3 120 8 20 40 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968 FirstFrame,None,FirstFrame,FirstFrame,FirstFrame,FirstFrame
+110 -110
View File
@@ -1,110 +1,110 @@
id file minLevel maxLevel levelType theme quest flags animDelay animLen animWidth selectionRegion
OBJ_L1LIGHT l1braz 0 0 DTYPE_CATHEDRAL Animated,Solid,MissilesPassThrough 1 26 64
OBJ_L1LDOOR l1doors 0 0 DTYPE_CATHEDRAL Light,Trap 1 0 64 Bottom,Middle
OBJ_L1RDOOR l1doors 0 0 DTYPE_CATHEDRAL Light,Trap 2 0 64 Bottom,Middle
OBJ_SKFIRE skulfire 0 0 THEME_SKELROOM Animated,Solid,MissilesPassThrough 2 11 96
OBJ_LEVER lever 0 0 Solid,MissilesPassThrough,Light,Trap 1 1 96 Bottom
OBJ_CHEST1 chest1 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom
OBJ_CHEST2 chest2 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom
OBJ_CHEST3 chest3 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom
OBJ_CANDLE1 l1braz 0 0 0 0 0
OBJ_CANDLE2 candle2 0 0 THEME_SHRINE Q_PWATER Animated,Solid,MissilesPassThrough,Light 2 4 96
OBJ_CANDLEO l1braz 0 0 0 0 0
OBJ_BANNERL banner 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 2 0 96
OBJ_BANNERM banner 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 1 0 96
OBJ_BANNERR banner 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 3 0 96
OBJ_SKPILE skulpile 0 0 Solid,MissilesPassThrough,Light 1 1 96
OBJ_SKSTICK1 l1braz 0 0 0 0 0
OBJ_SKSTICK2 l1braz 0 0 0 0 0
OBJ_SKSTICK3 l1braz 0 0 0 0 0
OBJ_SKSTICK4 l1braz 0 0 0 0 0
OBJ_SKSTICK5 l1braz 0 0 0 0 0
OBJ_CRUX1 cruxsk1 0 0 Solid,Light,Breakable 1 15 96 Bottom,Middle
OBJ_CRUX2 cruxsk2 0 0 Solid,Light,Breakable 1 15 96 Bottom,Middle
OBJ_CRUX3 cruxsk3 0 0 Solid,Light,Breakable 1 15 96 Bottom,Middle
OBJ_STAND rockstan 5 5 Solid,MissilesPassThrough,Light 1 0 96
OBJ_ANGEL angel 0 0 Solid,Light 1 0 96
OBJ_BOOK2L book2 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle
OBJ_BCROSS burncros 0 0 Animated,Solid 0 10 160
OBJ_NUDEW2R nude2 0 0 Animated,Solid,Light 3 6 128
OBJ_SWITCHSKL switch4 16 16 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom
OBJ_TNUDEM1 tnudem 13 15 Q_BUTCHER Solid,Light 1 0 128
OBJ_TNUDEM2 tnudem 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 2 0 128
OBJ_TNUDEM3 tnudem 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 3 0 128
OBJ_TNUDEM4 tnudem 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 4 0 128
OBJ_TNUDEW1 tnudew 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 1 0 128
OBJ_TNUDEW2 tnudew 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 2 0 128
OBJ_TNUDEW3 tnudew 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 3 0 128
OBJ_TORTURE1 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 1 0 128
OBJ_TORTURE2 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 2 0 128
OBJ_TORTURE3 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 3 0 128
OBJ_TORTURE4 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 4 0 128
OBJ_TORTURE5 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 5 0 128
OBJ_BOOK2R book2 6 6 Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle
OBJ_L2LDOOR l2doors 0 0 DTYPE_CATACOMBS Light,Trap 1 0 64 Bottom,Middle
OBJ_L2RDOOR l2doors 0 0 DTYPE_CATACOMBS Light,Trap 2 0 64 Bottom,Middle
OBJ_TORCHL wtorch4 5 8 Animated,MissilesPassThrough 1 9 96
OBJ_TORCHR wtorch3 5 8 Animated,MissilesPassThrough 1 9 96
OBJ_TORCHL2 wtorch1 5 8 Animated,MissilesPassThrough 1 9 96
OBJ_TORCHR2 wtorch2 5 8 Animated,MissilesPassThrough 1 9 96
OBJ_SARC sarc 1 4 Solid,MissilesPassThrough,Light,Trap 1 5 128 Bottom,Middle
OBJ_FLAMEHOLE flame1 0 0 MissilesPassThrough,Light 1 20 96
OBJ_FLAMELVR lever 0 0 Solid,MissilesPassThrough,Light,Trap 1 2 96 Bottom
OBJ_WATER miniwatr 0 0 Animated,Solid,Light 1 10 64
OBJ_BOOKLVR book1 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle
OBJ_TRAPL traphole 1 24 MissilesPassThrough,Light 1 0 64
OBJ_TRAPR traphole 1 24 MissilesPassThrough,Light 2 0 64
OBJ_BOOKSHELF bcase 0 0 Solid,Light 1 0 96
OBJ_WEAPRACK weapstnd 0 0 Solid,Light 1 0 96
OBJ_BARREL barrel 1 15 Solid,MissilesPassThrough,Light,Breakable 1 9 96 Bottom,Middle
OBJ_BARRELEX barrelex 1 15 Solid,MissilesPassThrough,Light,Breakable 1 10 96 Bottom,Middle
OBJ_SHRINEL lshrineg 0 0 THEME_SHRINE Light 1 11 128 Bottom,Middle
OBJ_SHRINER rshrineg 0 0 THEME_SHRINE Light 1 11 128 Bottom,Middle
OBJ_SKELBOOK book2 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle
OBJ_BOOKCASEL bcase 0 0 THEME_LIBRARY Solid,Light 3 0 96 Bottom,Middle
OBJ_BOOKCASER bcase 0 0 THEME_LIBRARY Solid,Light 4 0 96 Bottom,Middle
OBJ_BOOKSTAND book2 0 0 THEME_LIBRARY Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle
OBJ_BOOKCANDLE candle2 0 0 THEME_LIBRARY Animated,Solid,MissilesPassThrough,Light 2 4 96
OBJ_BLOODFTN bloodfnt 0 0 THEME_BLOODFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 10 96 Bottom,Middle
OBJ_DECAP decap 13 15 THEME_DECAPITATED Solid,MissilesPassThrough,Light 1 0 96 Bottom
OBJ_TCHEST1 chest1 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom
OBJ_TCHEST2 chest2 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom
OBJ_TCHEST3 chest3 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom
OBJ_BLINDBOOK book1 0 0 Q_BLIND Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle
OBJ_BLOODBOOK book1 0 0 Q_BLOOD Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle
OBJ_PEDESTAL pedistl 0 0 Q_BLOOD Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle
OBJ_L3LDOOR l3doors 0 0 DTYPE_CAVES Light,Trap 1 0 64 Bottom,Middle
OBJ_L3RDOOR l3doors 0 0 DTYPE_CAVES Light,Trap 2 0 64 Bottom,Middle
OBJ_PURIFYINGFTN pfountn 0 0 THEME_PURIFYINGFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 10 128 Bottom,Middle
OBJ_ARMORSTAND armstand 0 0 THEME_ARMORSTAND Solid,Light 1 0 96 Bottom,Middle
OBJ_ARMORSTANDN armstand 0 0 THEME_ARMORSTAND Solid,Light 2 0 96
OBJ_GOATSHRINE goatshrn 0 0 THEME_GOATSHRINE Animated,Solid,MissilesPassThrough,Light 2 10 96 Bottom,Middle
OBJ_CAULDRON cauldren 13 15 Solid,Light 1 0 96 Bottom,Middle
OBJ_MURKYFTN mfountn 0 0 THEME_MURKYFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 10 128 Bottom,Middle
OBJ_TEARFTN tfountn 0 0 THEME_TEARFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 4 128 Bottom,Middle
OBJ_ALTBOY altboy 0 0 Q_BETRAYER Solid,MissilesPassThrough,Light 1 0 128
OBJ_MCIRCLE1 mcirl 0 0 Q_BETRAYER MissilesPassThrough,Light 1 0 96
OBJ_MCIRCLE2 mcirl 0 0 Q_BETRAYER MissilesPassThrough,Light 1 0 96
OBJ_STORYBOOK bkslbrnt 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle
OBJ_STORYCANDLE candle2 0 0 Q_BETRAYER Animated,Solid,MissilesPassThrough,Light 2 4 96
OBJ_STEELTOME book1 0 0 Q_WARLORD Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle
OBJ_WARARMOR armstand 0 0 Q_WARLORD Solid,Light 1 0 96 Bottom,Middle
OBJ_WARWEAP weapstnd 0 0 Q_WARLORD Solid,Light 1 0 96 Bottom,Middle
OBJ_TBCROSS burncros 0 0 THEME_BRNCROSS Animated,Solid 0 10 160
OBJ_WEAPONRACK weapstnd 0 0 THEME_WEAPONRACK Solid,Light 1 0 96 Bottom,Middle
OBJ_WEAPONRACKN weapstnd 0 0 THEME_WEAPONRACK Solid,Light 2 0 96
OBJ_MUSHPATCH mushptch 0 0 Q_MUSHROOM Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom,Middle
OBJ_LAZSTAND lzstand 0 0 Q_BETRAYER Solid,Light 1 0 128 Bottom,Middle
OBJ_SLAINHERO decap 9 9 Solid,MissilesPassThrough,Light 2 0 96 Bottom
OBJ_SIGNCHEST chest3 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom
OBJ_BOOKSHELFR bcase 0 0 Solid,Light 2 0 96
OBJ_POD l6pod1 17 20 Solid,MissilesPassThrough,Light,Breakable 1 9 96 Bottom,Middle
OBJ_PODEX l6pod2 17 20 Solid,MissilesPassThrough,Light,Breakable 1 10 96 Bottom,Middle
OBJ_URN urn 21 24 Solid,MissilesPassThrough,Light,Breakable 1 9 96 Bottom,Middle
OBJ_URNEX urnexpld 21 24 Solid,MissilesPassThrough,Light,Breakable 1 10 96 Bottom,Middle
OBJ_L5BOOKS l5books 21 24 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle
OBJ_L5CANDLE l5light 21 23 Animated,Solid,MissilesPassThrough,Light 2 4 96
OBJ_L5LDOOR l5door 0 0 DTYPE_CRYPT Light,Trap 1 0 64 Bottom,Middle
OBJ_L5RDOOR l5door 0 0 DTYPE_CRYPT Light,Trap 2 0 64 Bottom,Middle
OBJ_L5LEVER l5lever 24 24 Solid,MissilesPassThrough,Light,Trap 1 1 96 Bottom
OBJ_L5SARC l5sarco 21 24 Solid,MissilesPassThrough,Light,Trap 1 5 128 Bottom,Middle
id file minLevel maxLevel levelType theme quest flags animDelay animLen animWidth selectionRegion shadowRule
OBJ_L1LIGHT l1braz 0 0 DTYPE_CATHEDRAL Animated,Solid,MissilesPassThrough 1 26 64 None
OBJ_L1LDOOR l1doors 0 0 DTYPE_CATHEDRAL Light,Trap 1 0 64 Bottom,Middle None
OBJ_L1RDOOR l1doors 0 0 DTYPE_CATHEDRAL Light,Trap 2 0 64 Bottom,Middle None
OBJ_SKFIRE skulfire 0 0 THEME_SKELROOM Animated,Solid,MissilesPassThrough 2 11 96 FirstFrame
OBJ_LEVER lever 0 0 Solid,MissilesPassThrough,Light,Trap 1 1 96 Bottom FirstFrame
OBJ_CHEST1 chest1 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
OBJ_CHEST2 chest2 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
OBJ_CHEST3 chest3 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
OBJ_CANDLE1 l1braz 0 0 0 0 0 None
OBJ_CANDLE2 candle2 0 0 THEME_SHRINE Q_PWATER Animated,Solid,MissilesPassThrough,Light 2 4 96 FirstFrame
OBJ_CANDLEO l1braz 0 0 0 0 0 None
OBJ_BANNERL banner 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 2 0 96 EachFrame
OBJ_BANNERM banner 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 1 0 96 EachFrame
OBJ_BANNERR banner 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 3 0 96 EachFrame
OBJ_SKPILE skulpile 0 0 Solid,MissilesPassThrough,Light 1 1 96 FirstFrame
OBJ_SKSTICK1 l1braz 0 0 0 0 0 None
OBJ_SKSTICK2 l1braz 0 0 0 0 0 None
OBJ_SKSTICK3 l1braz 0 0 0 0 0 None
OBJ_SKSTICK4 l1braz 0 0 0 0 0 None
OBJ_SKSTICK5 l1braz 0 0 0 0 0 None
OBJ_CRUX1 cruxsk1 0 0 Solid,Light,Breakable 1 15 96 Bottom,Middle EachFrame
OBJ_CRUX2 cruxsk2 0 0 Solid,Light,Breakable 1 15 96 Bottom,Middle EachFrame
OBJ_CRUX3 cruxsk3 0 0 Solid,Light,Breakable 1 15 96 Bottom,Middle EachFrame
OBJ_STAND rockstan 5 5 Solid,MissilesPassThrough,Light 1 0 96 None
OBJ_ANGEL angel 0 0 Solid,Light 1 0 96 EachFrame
OBJ_BOOK2L book2 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle EachFrame
OBJ_BCROSS burncros 0 0 Animated,Solid 0 10 160 None
OBJ_NUDEW2R nude2 0 0 Animated,Solid,Light 3 6 128 None
OBJ_SWITCHSKL switch4 16 16 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom FirstFrame
OBJ_TNUDEM1 tnudem 13 15 Q_BUTCHER Solid,Light 1 0 128 EachFrame
OBJ_TNUDEM2 tnudem 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 2 0 128 EachFrame
OBJ_TNUDEM3 tnudem 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 3 0 128 EachFrame
OBJ_TNUDEM4 tnudem 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 4 0 128 EachFrame
OBJ_TNUDEW1 tnudew 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 1 0 128 EachFrame
OBJ_TNUDEW2 tnudew 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 2 0 128 EachFrame
OBJ_TNUDEW3 tnudew 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 3 0 128 EachFrame
OBJ_TORTURE1 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 1 0 128 None
OBJ_TORTURE2 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 2 0 128 None
OBJ_TORTURE3 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 3 0 128 None
OBJ_TORTURE4 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 4 0 128 None
OBJ_TORTURE5 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 5 0 128 None
OBJ_BOOK2R book2 6 6 Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle EachFrame
OBJ_L2LDOOR l2doors 0 0 DTYPE_CATACOMBS Light,Trap 1 0 64 Bottom,Middle None
OBJ_L2RDOOR l2doors 0 0 DTYPE_CATACOMBS Light,Trap 2 0 64 Bottom,Middle None
OBJ_TORCHL wtorch4 5 8 Animated,MissilesPassThrough 1 9 96 None
OBJ_TORCHR wtorch3 5 8 Animated,MissilesPassThrough 1 9 96 None
OBJ_TORCHL2 wtorch1 5 8 Animated,MissilesPassThrough 1 9 96 None
OBJ_TORCHR2 wtorch2 5 8 Animated,MissilesPassThrough 1 9 96 None
OBJ_SARC sarc 1 4 Solid,MissilesPassThrough,Light,Trap 1 5 128 Bottom,Middle FirstFrame
OBJ_FLAMEHOLE flame1 0 0 MissilesPassThrough,Light 1 20 96 None
OBJ_FLAMELVR lever 0 0 Solid,MissilesPassThrough,Light,Trap 1 2 96 Bottom FirstFrame
OBJ_WATER miniwatr 0 0 Animated,Solid,Light 1 10 64 None
OBJ_BOOKLVR book1 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle EachFrame
OBJ_TRAPL traphole 1 24 MissilesPassThrough,Light 1 0 64 None
OBJ_TRAPR traphole 1 24 MissilesPassThrough,Light 2 0 64 None
OBJ_BOOKSHELF bcase 0 0 Solid,Light 1 0 96 None
OBJ_WEAPRACK weapstnd 0 0 Solid,Light 1 0 96 EachFrame
OBJ_BARREL barrel 1 15 Solid,MissilesPassThrough,Light,Breakable 1 9 96 Bottom,Middle FirstFrame
OBJ_BARRELEX barrelex 1 15 Solid,MissilesPassThrough,Light,Breakable 1 10 96 Bottom,Middle FirstFrame
OBJ_SHRINEL lshrineg 0 0 THEME_SHRINE Light 1 11 128 Bottom,Middle None
OBJ_SHRINER rshrineg 0 0 THEME_SHRINE Light 1 11 128 Bottom,Middle None
OBJ_SKELBOOK book2 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle EachFrame
OBJ_BOOKCASEL bcase 0 0 THEME_LIBRARY Solid,Light 3 0 96 Bottom,Middle None
OBJ_BOOKCASER bcase 0 0 THEME_LIBRARY Solid,Light 4 0 96 Bottom,Middle None
OBJ_BOOKSTAND book2 0 0 THEME_LIBRARY Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle EachFrame
OBJ_BOOKCANDLE candle2 0 0 THEME_LIBRARY Animated,Solid,MissilesPassThrough,Light 2 4 96 FirstFrame
OBJ_BLOODFTN bloodfnt 0 0 THEME_BLOODFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 10 96 Bottom,Middle None
OBJ_DECAP decap 13 15 THEME_DECAPITATED Solid,MissilesPassThrough,Light 1 0 96 Bottom FirstFrame
OBJ_TCHEST1 chest1 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
OBJ_TCHEST2 chest2 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
OBJ_TCHEST3 chest3 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
OBJ_BLINDBOOK book1 0 0 Q_BLIND Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle EachFrame
OBJ_BLOODBOOK book1 0 0 Q_BLOOD Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle EachFrame
OBJ_PEDESTAL pedistl 0 0 Q_BLOOD Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle FirstFrame
OBJ_L3LDOOR l3doors 0 0 DTYPE_CAVES Light,Trap 1 0 64 Bottom,Middle None
OBJ_L3RDOOR l3doors 0 0 DTYPE_CAVES Light,Trap 2 0 64 Bottom,Middle None
OBJ_PURIFYINGFTN pfountn 0 0 THEME_PURIFYINGFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 10 128 Bottom,Middle None
OBJ_ARMORSTAND armstand 0 0 THEME_ARMORSTAND Solid,Light 1 0 96 Bottom,Middle FirstFrame
OBJ_ARMORSTANDN armstand 0 0 THEME_ARMORSTAND Solid,Light 2 0 96 FirstFrame
OBJ_GOATSHRINE goatshrn 0 0 THEME_GOATSHRINE Animated,Solid,MissilesPassThrough,Light 2 10 96 Bottom,Middle None
OBJ_CAULDRON cauldren 13 15 Solid,Light 1 0 96 Bottom,Middle Baked
OBJ_MURKYFTN mfountn 0 0 THEME_MURKYFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 10 128 Bottom,Middle None
OBJ_TEARFTN tfountn 0 0 THEME_TEARFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 4 128 Bottom,Middle None
OBJ_ALTBOY altboy 0 0 Q_BETRAYER Solid,MissilesPassThrough,Light 1 0 128 FirstFrame
OBJ_MCIRCLE1 mcirl 0 0 Q_BETRAYER MissilesPassThrough,Light 1 0 96 None
OBJ_MCIRCLE2 mcirl 0 0 Q_BETRAYER MissilesPassThrough,Light 1 0 96 None
OBJ_STORYBOOK bkslbrnt 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle FirstFrame
OBJ_STORYCANDLE candle2 0 0 Q_BETRAYER Animated,Solid,MissilesPassThrough,Light 2 4 96 FirstFrame
OBJ_STEELTOME book1 0 0 Q_WARLORD Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle EachFrame
OBJ_WARARMOR armstand 0 0 Q_WARLORD Solid,Light 1 0 96 Bottom,Middle FirstFrame
OBJ_WARWEAP weapstnd 0 0 Q_WARLORD Solid,Light 1 0 96 Bottom,Middle EachFrame
OBJ_TBCROSS burncros 0 0 THEME_BRNCROSS Animated,Solid 0 10 160 None
OBJ_WEAPONRACK weapstnd 0 0 THEME_WEAPONRACK Solid,Light 1 0 96 Bottom,Middle EachFrame
OBJ_WEAPONRACKN weapstnd 0 0 THEME_WEAPONRACK Solid,Light 2 0 96 EachFrame
OBJ_MUSHPATCH mushptch 0 0 Q_MUSHROOM Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom,Middle None
OBJ_LAZSTAND lzstand 0 0 Q_BETRAYER Solid,Light 1 0 128 Bottom,Middle FirstFrame
OBJ_SLAINHERO decap 9 9 Solid,MissilesPassThrough,Light 2 0 96 Bottom FirstFrame
OBJ_SIGNCHEST chest3 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom EachFrame
OBJ_BOOKSHELFR bcase 0 0 Solid,Light 2 0 96 None
OBJ_POD l6pod1 17 20 Solid,MissilesPassThrough,Light,Breakable 1 9 96 Bottom,Middle None
OBJ_PODEX l6pod2 17 20 Solid,MissilesPassThrough,Light,Breakable 1 10 96 Bottom,Middle None
OBJ_URN urn 21 24 Solid,MissilesPassThrough,Light,Breakable 1 9 96 Bottom,Middle EachFrame
OBJ_URNEX urnexpld 21 24 Solid,MissilesPassThrough,Light,Breakable 1 10 96 Bottom,Middle EachFrame
OBJ_L5BOOKS l5books 21 24 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle None
OBJ_L5CANDLE l5light 21 23 Animated,Solid,MissilesPassThrough,Light 2 4 96 FirstFrame
OBJ_L5LDOOR l5door 0 0 DTYPE_CRYPT Light,Trap 1 0 64 Bottom,Middle None
OBJ_L5RDOOR l5door 0 0 DTYPE_CRYPT Light,Trap 2 0 64 Bottom,Middle None
OBJ_L5LEVER l5lever 24 24 Solid,MissilesPassThrough,Light,Trap 1 1 96 Bottom None
OBJ_L5SARC l5sarco 21 24 Solid,MissilesPassThrough,Light,Trap 1 5 128 Bottom,Middle None
1 id file minLevel maxLevel levelType theme quest flags animDelay animLen animWidth selectionRegion shadowRule
2 OBJ_L1LIGHT l1braz 0 0 DTYPE_CATHEDRAL Animated,Solid,MissilesPassThrough 1 26 64 None
3 OBJ_L1LDOOR l1doors 0 0 DTYPE_CATHEDRAL Light,Trap 1 0 64 Bottom,Middle None
4 OBJ_L1RDOOR l1doors 0 0 DTYPE_CATHEDRAL Light,Trap 2 0 64 Bottom,Middle None
5 OBJ_SKFIRE skulfire 0 0 THEME_SKELROOM Animated,Solid,MissilesPassThrough 2 11 96 FirstFrame
6 OBJ_LEVER lever 0 0 Solid,MissilesPassThrough,Light,Trap 1 1 96 Bottom FirstFrame
7 OBJ_CHEST1 chest1 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
8 OBJ_CHEST2 chest2 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
9 OBJ_CHEST3 chest3 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
10 OBJ_CANDLE1 l1braz 0 0 0 0 0 None
11 OBJ_CANDLE2 candle2 0 0 THEME_SHRINE Q_PWATER Animated,Solid,MissilesPassThrough,Light 2 4 96 FirstFrame
12 OBJ_CANDLEO l1braz 0 0 0 0 0 None
13 OBJ_BANNERL banner 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 2 0 96 EachFrame
14 OBJ_BANNERM banner 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 1 0 96 EachFrame
15 OBJ_BANNERR banner 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 3 0 96 EachFrame
16 OBJ_SKPILE skulpile 0 0 Solid,MissilesPassThrough,Light 1 1 96 FirstFrame
17 OBJ_SKSTICK1 l1braz 0 0 0 0 0 None
18 OBJ_SKSTICK2 l1braz 0 0 0 0 0 None
19 OBJ_SKSTICK3 l1braz 0 0 0 0 0 None
20 OBJ_SKSTICK4 l1braz 0 0 0 0 0 None
21 OBJ_SKSTICK5 l1braz 0 0 0 0 0 None
22 OBJ_CRUX1 cruxsk1 0 0 Solid,Light,Breakable 1 15 96 Bottom,Middle EachFrame
23 OBJ_CRUX2 cruxsk2 0 0 Solid,Light,Breakable 1 15 96 Bottom,Middle EachFrame
24 OBJ_CRUX3 cruxsk3 0 0 Solid,Light,Breakable 1 15 96 Bottom,Middle EachFrame
25 OBJ_STAND rockstan 5 5 Solid,MissilesPassThrough,Light 1 0 96 None
26 OBJ_ANGEL angel 0 0 Solid,Light 1 0 96 EachFrame
27 OBJ_BOOK2L book2 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle EachFrame
28 OBJ_BCROSS burncros 0 0 Animated,Solid 0 10 160 None
29 OBJ_NUDEW2R nude2 0 0 Animated,Solid,Light 3 6 128 None
30 OBJ_SWITCHSKL switch4 16 16 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom FirstFrame
31 OBJ_TNUDEM1 tnudem 13 15 Q_BUTCHER Solid,Light 1 0 128 EachFrame
32 OBJ_TNUDEM2 tnudem 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 2 0 128 EachFrame
33 OBJ_TNUDEM3 tnudem 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 3 0 128 EachFrame
34 OBJ_TNUDEM4 tnudem 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 4 0 128 EachFrame
35 OBJ_TNUDEW1 tnudew 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 1 0 128 EachFrame
36 OBJ_TNUDEW2 tnudew 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 2 0 128 EachFrame
37 OBJ_TNUDEW3 tnudew 13 15 THEME_TORTURE Q_BUTCHER Solid,Light 3 0 128 EachFrame
38 OBJ_TORTURE1 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 1 0 128 None
39 OBJ_TORTURE2 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 2 0 128 None
40 OBJ_TORTURE3 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 3 0 128 None
41 OBJ_TORTURE4 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 4 0 128 None
42 OBJ_TORTURE5 tsoul 13 15 Q_BUTCHER MissilesPassThrough,Light 5 0 128 None
43 OBJ_BOOK2R book2 6 6 Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle EachFrame
44 OBJ_L2LDOOR l2doors 0 0 DTYPE_CATACOMBS Light,Trap 1 0 64 Bottom,Middle None
45 OBJ_L2RDOOR l2doors 0 0 DTYPE_CATACOMBS Light,Trap 2 0 64 Bottom,Middle None
46 OBJ_TORCHL wtorch4 5 8 Animated,MissilesPassThrough 1 9 96 None
47 OBJ_TORCHR wtorch3 5 8 Animated,MissilesPassThrough 1 9 96 None
48 OBJ_TORCHL2 wtorch1 5 8 Animated,MissilesPassThrough 1 9 96 None
49 OBJ_TORCHR2 wtorch2 5 8 Animated,MissilesPassThrough 1 9 96 None
50 OBJ_SARC sarc 1 4 Solid,MissilesPassThrough,Light,Trap 1 5 128 Bottom,Middle FirstFrame
51 OBJ_FLAMEHOLE flame1 0 0 MissilesPassThrough,Light 1 20 96 None
52 OBJ_FLAMELVR lever 0 0 Solid,MissilesPassThrough,Light,Trap 1 2 96 Bottom FirstFrame
53 OBJ_WATER miniwatr 0 0 Animated,Solid,Light 1 10 64 None
54 OBJ_BOOKLVR book1 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle EachFrame
55 OBJ_TRAPL traphole 1 24 MissilesPassThrough,Light 1 0 64 None
56 OBJ_TRAPR traphole 1 24 MissilesPassThrough,Light 2 0 64 None
57 OBJ_BOOKSHELF bcase 0 0 Solid,Light 1 0 96 None
58 OBJ_WEAPRACK weapstnd 0 0 Solid,Light 1 0 96 EachFrame
59 OBJ_BARREL barrel 1 15 Solid,MissilesPassThrough,Light,Breakable 1 9 96 Bottom,Middle FirstFrame
60 OBJ_BARRELEX barrelex 1 15 Solid,MissilesPassThrough,Light,Breakable 1 10 96 Bottom,Middle FirstFrame
61 OBJ_SHRINEL lshrineg 0 0 THEME_SHRINE Light 1 11 128 Bottom,Middle None
62 OBJ_SHRINER rshrineg 0 0 THEME_SHRINE Light 1 11 128 Bottom,Middle None
63 OBJ_SKELBOOK book2 0 0 THEME_SKELROOM Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle EachFrame
64 OBJ_BOOKCASEL bcase 0 0 THEME_LIBRARY Solid,Light 3 0 96 Bottom,Middle None
65 OBJ_BOOKCASER bcase 0 0 THEME_LIBRARY Solid,Light 4 0 96 Bottom,Middle None
66 OBJ_BOOKSTAND book2 0 0 THEME_LIBRARY Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle EachFrame
67 OBJ_BOOKCANDLE candle2 0 0 THEME_LIBRARY Animated,Solid,MissilesPassThrough,Light 2 4 96 FirstFrame
68 OBJ_BLOODFTN bloodfnt 0 0 THEME_BLOODFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 10 96 Bottom,Middle None
69 OBJ_DECAP decap 13 15 THEME_DECAPITATED Solid,MissilesPassThrough,Light 1 0 96 Bottom FirstFrame
70 OBJ_TCHEST1 chest1 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
71 OBJ_TCHEST2 chest2 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
72 OBJ_TCHEST3 chest3 1 24 Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom EachFrame
73 OBJ_BLINDBOOK book1 0 0 Q_BLIND Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle EachFrame
74 OBJ_BLOODBOOK book1 0 0 Q_BLOOD Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle EachFrame
75 OBJ_PEDESTAL pedistl 0 0 Q_BLOOD Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle FirstFrame
76 OBJ_L3LDOOR l3doors 0 0 DTYPE_CAVES Light,Trap 1 0 64 Bottom,Middle None
77 OBJ_L3RDOOR l3doors 0 0 DTYPE_CAVES Light,Trap 2 0 64 Bottom,Middle None
78 OBJ_PURIFYINGFTN pfountn 0 0 THEME_PURIFYINGFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 10 128 Bottom,Middle None
79 OBJ_ARMORSTAND armstand 0 0 THEME_ARMORSTAND Solid,Light 1 0 96 Bottom,Middle FirstFrame
80 OBJ_ARMORSTANDN armstand 0 0 THEME_ARMORSTAND Solid,Light 2 0 96 FirstFrame
81 OBJ_GOATSHRINE goatshrn 0 0 THEME_GOATSHRINE Animated,Solid,MissilesPassThrough,Light 2 10 96 Bottom,Middle None
82 OBJ_CAULDRON cauldren 13 15 Solid,Light 1 0 96 Bottom,Middle Baked
83 OBJ_MURKYFTN mfountn 0 0 THEME_MURKYFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 10 128 Bottom,Middle None
84 OBJ_TEARFTN tfountn 0 0 THEME_TEARFOUNTAIN Animated,Solid,MissilesPassThrough,Light 2 4 128 Bottom,Middle None
85 OBJ_ALTBOY altboy 0 0 Q_BETRAYER Solid,MissilesPassThrough,Light 1 0 128 FirstFrame
86 OBJ_MCIRCLE1 mcirl 0 0 Q_BETRAYER MissilesPassThrough,Light 1 0 96 None
87 OBJ_MCIRCLE2 mcirl 0 0 Q_BETRAYER MissilesPassThrough,Light 1 0 96 None
88 OBJ_STORYBOOK bkslbrnt 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle FirstFrame
89 OBJ_STORYCANDLE candle2 0 0 Q_BETRAYER Animated,Solid,MissilesPassThrough,Light 2 4 96 FirstFrame
90 OBJ_STEELTOME book1 0 0 Q_WARLORD Solid,MissilesPassThrough,Light 4 0 96 Bottom,Middle EachFrame
91 OBJ_WARARMOR armstand 0 0 Q_WARLORD Solid,Light 1 0 96 Bottom,Middle FirstFrame
92 OBJ_WARWEAP weapstnd 0 0 Q_WARLORD Solid,Light 1 0 96 Bottom,Middle EachFrame
93 OBJ_TBCROSS burncros 0 0 THEME_BRNCROSS Animated,Solid 0 10 160 None
94 OBJ_WEAPONRACK weapstnd 0 0 THEME_WEAPONRACK Solid,Light 1 0 96 Bottom,Middle EachFrame
95 OBJ_WEAPONRACKN weapstnd 0 0 THEME_WEAPONRACK Solid,Light 2 0 96 EachFrame
96 OBJ_MUSHPATCH mushptch 0 0 Q_MUSHROOM Solid,MissilesPassThrough,Light,Trap 1 0 96 Bottom,Middle None
97 OBJ_LAZSTAND lzstand 0 0 Q_BETRAYER Solid,Light 1 0 128 Bottom,Middle FirstFrame
98 OBJ_SLAINHERO decap 9 9 Solid,MissilesPassThrough,Light 2 0 96 Bottom FirstFrame
99 OBJ_SIGNCHEST chest3 0 0 Solid,MissilesPassThrough,Light 1 0 96 Bottom EachFrame
100 OBJ_BOOKSHELFR bcase 0 0 Solid,Light 2 0 96 None
101 OBJ_POD l6pod1 17 20 Solid,MissilesPassThrough,Light,Breakable 1 9 96 Bottom,Middle None
102 OBJ_PODEX l6pod2 17 20 Solid,MissilesPassThrough,Light,Breakable 1 10 96 Bottom,Middle None
103 OBJ_URN urn 21 24 Solid,MissilesPassThrough,Light,Breakable 1 9 96 Bottom,Middle EachFrame
104 OBJ_URNEX urnexpld 21 24 Solid,MissilesPassThrough,Light,Breakable 1 10 96 Bottom,Middle EachFrame
105 OBJ_L5BOOKS l5books 21 24 Solid,MissilesPassThrough,Light 1 0 96 Bottom,Middle None
106 OBJ_L5CANDLE l5light 21 23 Animated,Solid,MissilesPassThrough,Light 2 4 96 FirstFrame
107 OBJ_L5LDOOR l5door 0 0 DTYPE_CRYPT Light,Trap 1 0 64 Bottom,Middle None
108 OBJ_L5RDOOR l5door 0 0 DTYPE_CRYPT Light,Trap 2 0 64 Bottom,Middle None
109 OBJ_L5LEVER l5lever 24 24 Solid,MissilesPassThrough,Light,Trap 1 1 96 Bottom None
110 OBJ_L5SARC l5sarco 21 24 Solid,MissilesPassThrough,Light,Trap 1 5 128 Bottom,Middle None
+13 -13
View File
@@ -1,13 +1,13 @@
type name position_x position_y direction animWidth animPath animFrames animDelay gossipTexts animOrder
TOWN_SMITH Griswold the Blacksmith 62 63 SouthWest 96 towners\smith\smithn 16 3 TEXT_GRISWOLD2,TEXT_GRISWOLD3,TEXT_GRISWOLD4,TEXT_GRISWOLD5,TEXT_GRISWOLD6,TEXT_GRISWOLD7,TEXT_GRISWOLD8,TEXT_GRISWOLD9,TEXT_GRISWOLD10,TEXT_GRISWOLD12,TEXT_GRISWOLD13 4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3
TOWN_HEALER Pepin the Healer 55 79 SouthEast 96 towners\healer\healer 20 6 TEXT_PEPIN2,TEXT_PEPIN3,TEXT_PEPIN4,TEXT_PEPIN5,TEXT_PEPIN6,TEXT_PEPIN7,TEXT_PEPIN9,TEXT_PEPIN10,TEXT_PEPIN11 0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,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,4,5,6,7,8,9,10,11,12,13,14,15,14,13,12,11,10,9,8,7,6,5,4,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19
TOWN_DEADGUY Wounded Townsman 24 32 North 96 towners\butch\deadguy 8 6
TOWN_TAVERN Ogden the Tavern owner 55 62 SouthWest 96 towners\twnf\twnfn 16 3 TEXT_OGDEN2,TEXT_OGDEN3,TEXT_OGDEN4,TEXT_OGDEN5,TEXT_OGDEN6,TEXT_OGDEN8,TEXT_OGDEN9,TEXT_OGDEN10 0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,1,0,15,14,13,13,14,15,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
TOWN_STORY Cain the Elder 62 71 South 96 towners\strytell\strytell 25 3 TEXT_STORY2,TEXT_STORY3,TEXT_STORY4,TEXT_STORY5,TEXT_STORY6,TEXT_STORY7,TEXT_STORY9,TEXT_STORY10,TEXT_STORY11 0,0,24,24,23,22,21,20,19,18,17,16,15,14,15,16,17,18,19,20,21,22,23,24,24,24,0,0,0,24,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
TOWN_DRUNK Farnham the Drunk 71 84 South 96 towners\drunk\twndrunk 18 3 TEXT_FARNHAM2,TEXT_FARNHAM3,TEXT_FARNHAM4,TEXT_FARNHAM5,TEXT_FARNHAM6,TEXT_FARNHAM8,TEXT_FARNHAM9,TEXT_FARNHAM10,TEXT_FARNHAM11,TEXT_FARNHAM12,TEXT_FARNHAM13 0,0,0,1,2,3,4,5,6,7,8,9,10,10,10,10,11,12,13,14,15,16,17,17,0,0,0,17,16,15,14,13,12,11,10,9,10,11,12,13,14,15,16,17,0,1,2,3,4,4,4,3,2,1
TOWN_WITCH Adria the Witch 80 20 South 96 towners\townwmn1\witch 19 6 TEXT_ADRIA2,TEXT_ADRIA3,TEXT_ADRIA4,TEXT_ADRIA5,TEXT_ADRIA6,TEXT_ADRIA7,TEXT_ADRIA8,TEXT_ADRIA9,TEXT_ADRIA10,TEXT_ADRIA12,TEXT_ADRIA13 3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,2,1,0,18,17,18,0,1,0,18,17,18,0,1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,14,13,12,12,12,12,13,14,14,14,13,12,11,11,11,10,9,9,9,8,7,8,9,9,10,11,12,13,14,15,16,17,18,0,1,0,18,17,18,0,1,0,1,2
TOWN_BMAID Gillian the Barmaid 43 66 South 96 towners\townwmn1\wmnn 18 6 TEXT_GILLIAN2,TEXT_GILLIAN3,TEXT_GILLIAN4,TEXT_GILLIAN5,TEXT_GILLIAN6,TEXT_GILLIAN7,TEXT_GILLIAN9,TEXT_GILLIAN10
TOWN_PEGBOY Wirt the Peg-legged boy 11 53 South 96 towners\townboy\pegkid1 20 6 TEXT_WIRT2,TEXT_WIRT3,TEXT_WIRT4,TEXT_WIRT5,TEXT_WIRT6,TEXT_WIRT7,TEXT_WIRT8,TEXT_WIRT9,TEXT_WIRT11,TEXT_WIRT12
TOWN_COW Cow 58 16 SouthWest 128 12 3
TOWN_COW Cow 56 14 NorthWest 128 12 3
TOWN_COW Cow 59 20 North 128 12 3
type name position_x position_y direction animWidth animPath animFrames animDelay gossipTexts animOrder shadowRule
TOWN_SMITH Griswold the Blacksmith 62 63 SouthWest 96 towners\smith\smithn 16 3 TEXT_GRISWOLD2,TEXT_GRISWOLD3,TEXT_GRISWOLD4,TEXT_GRISWOLD5,TEXT_GRISWOLD6,TEXT_GRISWOLD7,TEXT_GRISWOLD8,TEXT_GRISWOLD9,TEXT_GRISWOLD10,TEXT_GRISWOLD12,TEXT_GRISWOLD13 4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3 FirstFrame
TOWN_HEALER Pepin the Healer 55 79 SouthEast 96 towners\healer\healer 20 6 TEXT_PEPIN2,TEXT_PEPIN3,TEXT_PEPIN4,TEXT_PEPIN5,TEXT_PEPIN6,TEXT_PEPIN7,TEXT_PEPIN9,TEXT_PEPIN10,TEXT_PEPIN11 0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,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,4,5,6,7,8,9,10,11,12,13,14,15,14,13,12,11,10,9,8,7,6,5,4,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 FirstFrame
TOWN_DEADGUY Wounded Townsman 24 32 North 96 towners\butch\deadguy 8 6 None
TOWN_TAVERN Ogden the Tavern owner 55 62 SouthWest 96 towners\twnf\twnfn 16 3 TEXT_OGDEN2,TEXT_OGDEN3,TEXT_OGDEN4,TEXT_OGDEN5,TEXT_OGDEN6,TEXT_OGDEN8,TEXT_OGDEN9,TEXT_OGDEN10 0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,1,0,15,14,13,13,14,15,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 FirstFrame
TOWN_STORY Cain the Elder 62 71 South 96 towners\strytell\strytell 25 3 TEXT_STORY2,TEXT_STORY3,TEXT_STORY4,TEXT_STORY5,TEXT_STORY6,TEXT_STORY7,TEXT_STORY9,TEXT_STORY10,TEXT_STORY11 0,0,24,24,23,22,21,20,19,18,17,16,15,14,15,16,17,18,19,20,21,22,23,24,24,24,0,0,0,24,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 FirstFrame
TOWN_DRUNK Farnham the Drunk 71 84 South 96 towners\drunk\twndrunk 18 3 TEXT_FARNHAM2,TEXT_FARNHAM3,TEXT_FARNHAM4,TEXT_FARNHAM5,TEXT_FARNHAM6,TEXT_FARNHAM8,TEXT_FARNHAM9,TEXT_FARNHAM10,TEXT_FARNHAM11,TEXT_FARNHAM12,TEXT_FARNHAM13 0,0,0,1,2,3,4,5,6,7,8,9,10,10,10,10,11,12,13,14,15,16,17,17,0,0,0,17,16,15,14,13,12,11,10,9,10,11,12,13,14,15,16,17,0,1,2,3,4,4,4,3,2,1 FirstFrame
TOWN_WITCH Adria the Witch 80 20 South 96 towners\townwmn1\witch 19 6 TEXT_ADRIA2,TEXT_ADRIA3,TEXT_ADRIA4,TEXT_ADRIA5,TEXT_ADRIA6,TEXT_ADRIA7,TEXT_ADRIA8,TEXT_ADRIA9,TEXT_ADRIA10,TEXT_ADRIA12,TEXT_ADRIA13 3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,2,1,0,18,17,18,0,1,0,18,17,18,0,1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,14,13,12,12,12,12,13,14,14,14,13,12,11,11,11,10,9,9,9,8,7,8,9,9,10,11,12,13,14,15,16,17,18,0,1,0,18,17,18,0,1,0,1,2 FirstFrame
TOWN_BMAID Gillian the Barmaid 43 66 South 96 towners\townwmn1\wmnn 18 6 TEXT_GILLIAN2,TEXT_GILLIAN3,TEXT_GILLIAN4,TEXT_GILLIAN5,TEXT_GILLIAN6,TEXT_GILLIAN7,TEXT_GILLIAN9,TEXT_GILLIAN10 FirstFrame
TOWN_PEGBOY Wirt the Peg-legged boy 11 53 South 96 towners\townboy\pegkid1 20 6 TEXT_WIRT2,TEXT_WIRT3,TEXT_WIRT4,TEXT_WIRT5,TEXT_WIRT6,TEXT_WIRT7,TEXT_WIRT8,TEXT_WIRT9,TEXT_WIRT11,TEXT_WIRT12 FirstFrame|Stray
TOWN_COW Cow 58 16 SouthWest 128 12 3
TOWN_COW Cow 56 14 NorthWest 128 12 3
TOWN_COW Cow 59 20 North 128 12 3
1 type name position_x position_y direction animWidth animPath animFrames animDelay gossipTexts animOrder shadowRule
2 TOWN_SMITH Griswold the Blacksmith 62 63 SouthWest 96 towners\smith\smithn 16 3 TEXT_GRISWOLD2,TEXT_GRISWOLD3,TEXT_GRISWOLD4,TEXT_GRISWOLD5,TEXT_GRISWOLD6,TEXT_GRISWOLD7,TEXT_GRISWOLD8,TEXT_GRISWOLD9,TEXT_GRISWOLD10,TEXT_GRISWOLD12,TEXT_GRISWOLD13 4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3 FirstFrame
3 TOWN_HEALER Pepin the Healer 55 79 SouthEast 96 towners\healer\healer 20 6 TEXT_PEPIN2,TEXT_PEPIN3,TEXT_PEPIN4,TEXT_PEPIN5,TEXT_PEPIN6,TEXT_PEPIN7,TEXT_PEPIN9,TEXT_PEPIN10,TEXT_PEPIN11 0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,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,4,5,6,7,8,9,10,11,12,13,14,15,14,13,12,11,10,9,8,7,6,5,4,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 FirstFrame
4 TOWN_DEADGUY Wounded Townsman 24 32 North 96 towners\butch\deadguy 8 6 None
5 TOWN_TAVERN Ogden the Tavern owner 55 62 SouthWest 96 towners\twnf\twnfn 16 3 TEXT_OGDEN2,TEXT_OGDEN3,TEXT_OGDEN4,TEXT_OGDEN5,TEXT_OGDEN6,TEXT_OGDEN8,TEXT_OGDEN9,TEXT_OGDEN10 0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,1,0,15,14,13,13,14,15,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 FirstFrame
6 TOWN_STORY Cain the Elder 62 71 South 96 towners\strytell\strytell 25 3 TEXT_STORY2,TEXT_STORY3,TEXT_STORY4,TEXT_STORY5,TEXT_STORY6,TEXT_STORY7,TEXT_STORY9,TEXT_STORY10,TEXT_STORY11 0,0,24,24,23,22,21,20,19,18,17,16,15,14,15,16,17,18,19,20,21,22,23,24,24,24,0,0,0,24,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 FirstFrame
7 TOWN_DRUNK Farnham the Drunk 71 84 South 96 towners\drunk\twndrunk 18 3 TEXT_FARNHAM2,TEXT_FARNHAM3,TEXT_FARNHAM4,TEXT_FARNHAM5,TEXT_FARNHAM6,TEXT_FARNHAM8,TEXT_FARNHAM9,TEXT_FARNHAM10,TEXT_FARNHAM11,TEXT_FARNHAM12,TEXT_FARNHAM13 0,0,0,1,2,3,4,5,6,7,8,9,10,10,10,10,11,12,13,14,15,16,17,17,0,0,0,17,16,15,14,13,12,11,10,9,10,11,12,13,14,15,16,17,0,1,2,3,4,4,4,3,2,1 FirstFrame
8 TOWN_WITCH Adria the Witch 80 20 South 96 towners\townwmn1\witch 19 6 TEXT_ADRIA2,TEXT_ADRIA3,TEXT_ADRIA4,TEXT_ADRIA5,TEXT_ADRIA6,TEXT_ADRIA7,TEXT_ADRIA8,TEXT_ADRIA9,TEXT_ADRIA10,TEXT_ADRIA12,TEXT_ADRIA13 3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,2,1,0,18,17,18,0,1,0,18,17,18,0,1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,14,13,12,12,12,12,13,14,14,14,13,12,11,11,11,10,9,9,9,8,7,8,9,9,10,11,12,13,14,15,16,17,18,0,1,0,18,17,18,0,1,0,1,2 FirstFrame
9 TOWN_BMAID Gillian the Barmaid 43 66 South 96 towners\townwmn1\wmnn 18 6 TEXT_GILLIAN2,TEXT_GILLIAN3,TEXT_GILLIAN4,TEXT_GILLIAN5,TEXT_GILLIAN6,TEXT_GILLIAN7,TEXT_GILLIAN9,TEXT_GILLIAN10 FirstFrame
10 TOWN_PEGBOY Wirt the Peg-legged boy 11 53 South 96 towners\townboy\pegkid1 20 6 TEXT_WIRT2,TEXT_WIRT3,TEXT_WIRT4,TEXT_WIRT5,TEXT_WIRT6,TEXT_WIRT7,TEXT_WIRT8,TEXT_WIRT9,TEXT_WIRT11,TEXT_WIRT12 FirstFrame|Stray
11 TOWN_COW Cow 58 16 SouthWest 128 12 3
12 TOWN_COW Cow 56 14 NorthWest 128 12 3
13 TOWN_COW Cow 59 20 North 128 12 3
+139 -139
View File
@@ -1,139 +1,139 @@
_monster_id name assetsSuffix soundSuffix trnFile availability width image hasSpecial hasSpecialSound frames[6] rate[6] minDunLvl maxDunLvl level hitPointsMinimum hitPointsMaximum ai abilityFlags intelligence toHit animFrameNum minDamage maxDamage toHitSpecial animFrameNumSpecial minDamageSpecial maxDamageSpecial reducePlayerStrength reducePlayerMagic reducePlayerDexterity reducePlayerVitality reducePlayerMaxHP reducePlayerMaxMana armorClass monsterClass resistance resistanceHell selectionRegion treasure exp
MT_NZOMBIE Zombie zombie\zombie Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 1 2 1 4 7 Zombie 0 10 8 2 5 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 54
MT_BZOMBIE Ghoul zombie\zombie zombie\bluered Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 3 2 7 11 Zombie 1 10 8 3 10 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 58
MT_GZOMBIE Rotting Carcass zombie\zombie zombie\grey Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 4 4 15 25 Zombie 2 25 8 5 15 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 136
MT_YZOMBIE Black Death zombie\zombie zombie\yellow Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 3 5 6 25 40 Zombie 3 30 8 6 22 0 0 0 0 0 0 0 0 1 0 20 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 240
MT_RFALLSP Fallen One falspear\phall falspear\fallent Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 1 2 1 1 4 Fallen 0 15 7 1 3 0 5 0 0 0 0 0 0 0 0 0 Animal Bottom,Middle 46
MT_DFALLSP Carver falspear\phall falspear\dark Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 3 3 4 8 Fallen 2 20 7 2 5 0 5 0 0 0 0 0 0 0 0 5 Animal Bottom,Middle 80
MT_YFALLSP Devil Kin falspear\phall Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 4 5 12 24 Fallen 2 25 7 3 7 0 5 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 155
MT_BFALLSP Dark One falspear\phall falspear\blue Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 3 5 7 20 36 Fallen 3 30 7 4 8 0 5 0 0 0 0 0 0 0 0 15 Animal RESIST_LIGHTNING Bottom,Middle 255
MT_WSKELAX Skeleton skelaxe\sklax skelaxe\white Always 128 553 true false 12,8,13,6,17,16 5,1,1,1,1,1 1 2 1 2 4 SkeletonMelee 0 20 8 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 64
MT_TSKELAX Corpse Axe skelaxe\sklax skelaxe\skelt Always 128 553 true false 12,8,13,6,17,16 4,1,1,1,1,1 2 3 2 4 7 SkeletonMelee 1 25 8 3 5 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 68
MT_RSKELAX Burning Dead skelaxe\sklax Always 128 553 true false 12,8,13,6,17,16 2,1,1,1,1,1 2 4 4 8 12 SkeletonMelee 2 30 8 3 7 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 154
MT_XSKELAX Horror skelaxe\sklax skelaxe\black Always 128 553 true false 12,8,13,6,17,16 3,1,1,1,1,1 3 5 6 12 20 SkeletonMelee 3 35 8 4 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 264
MT_RFALLSD Fallen One falsword\fall falsword\fallent Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 1 2 1 2 5 Fallen 0 15 8 1 4 0 5 0 0 0 0 0 0 0 0 10 Animal Bottom,Middle 52
MT_DFALLSD Carver falsword\fall falsword\dark Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 3 3 5 9 Fallen 1 20 8 2 7 0 5 0 0 0 0 0 0 0 0 15 Animal Bottom,Middle 90
MT_YFALLSD Devil Kin falsword\fall Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 4 5 16 24 Fallen 2 25 8 4 10 0 5 0 0 0 0 0 0 0 0 20 Animal RESIST_FIRE Bottom,Middle 180
MT_BFALLSD Dark One falsword\fall falsword\blue Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 3 5 7 24 36 Fallen 3 30 8 4 12 0 5 0 0 0 0 0 0 0 0 25 Animal RESIST_LIGHTNING Bottom,Middle 280
MT_NSCAV Scavenger scav\scav Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 1 3 2 3 6 Scavenger 0 20 7 1 5 0 0 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 80
MT_BSCAV Plague Eater scav\scav scav\scavbr Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 2 4 4 12 24 Scavenger 1 30 7 1 8 0 0 0 0 0 0 0 0 0 0 20 Animal RESIST_LIGHTNING Bottom,Middle 188
MT_WSCAV Shadow Beast scav\scav scav\scavbe Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 3 5 6 24 36 Scavenger 2 35 7 3 12 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_FIRE Bottom,Middle 375
MT_YSCAV Bone Gasher scav\scav scav\scavw Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 4 6 8 28 40 Scavenger 3 35 7 5 15 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_LIGHTNING Bottom,Middle 552
MT_WSKELBW Skeleton skelbow\sklbw skelbow\white Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 3 3 2 4 SkeletonRanged 0 15 12 1 2 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 110
MT_TSKELBW Corpse Bow skelbow\sklbw skelbow\skelt Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 4 5 8 16 SkeletonRanged 1 25 12 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 210
MT_RSKELBW Burning Dead skelbow\sklbw Always 128 567 true false 9,8,16,5,16,16 2,1,1,1,1,1 3 5 7 10 24 SkeletonRanged 2 30 12 1 6 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 364
MT_XSKELBW Horror skelbow\sklbw skelbow\black Always 128 567 true false 9,8,16,5,16,16 3,1,1,1,1,1 4 6 9 15 45 SkeletonRanged 3 35 12 2 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 594
MT_WSKELSD Skeleton Captain skelsd\sklsr skelsd\white Always 128 575 true true 13,8,12,7,15,16 4,1,1,1,1,1 1 3 2 3 6 SkeletonMelee 0 20 8 2 7 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 90
MT_TSKELSD Corpse Captain skelsd\sklsr skelsd\skelt Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 2 4 4 12 20 SkeletonMelee 1 30 8 3 9 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 200
MT_RSKELSD Burning Dead Captain skelsd\sklsr Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 3 5 6 16 30 SkeletonMelee 2 35 8 4 10 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 393
MT_XSKELSD Horror Captain skelsd\sklsr skelsd\black Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 4 6 8 35 50 SkeletonMelee SEARCH 3 40 8 5 14 0 0 0 0 0 0 0 0 0 0 30 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 604
MT_INVILORD Invisible Lord tsneak\tsneak Never 128 800 false false 13,13,15,11,16,0 2,1,1,1,1,1 19 20 14 278 278 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 65 8 16 30 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2000
MT_SNEAK Hidden sneak\sneak Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 2 5 5 8 24 Sneak HIDDEN 0 35 8 3 6 0 0 0 0 0 0 0 0 0 0 25 Demon Bottom,Middle 278
MT_STALKER Stalker sneak\sneak sneak\sneakv2 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 5 7 9 30 45 Sneak HIDDEN,SEARCH 1 40 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Demon Bottom,Middle 630
MT_UNSEEN Unseen sneak\sneak sneak\sneakv3 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 6 8 11 35 50 Sneak HIDDEN,SEARCH 2 45 8 12 20 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 935
MT_ILLWEAV Illusion Weaver sneak\sneak sneak\sneakv1 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 8 10 13 40 60 Sneak HIDDEN,SEARCH 3 60 8 16 24 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC,RESIST_FIRE IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 1500
MT_LRDSAYTR Satyr Lord goatlord\goatl newsfx\satyr Never 160 800 false false 13,13,14,9,16,0 2,1,1,1,1,1 21 22 28 160 200 SkeletonMelee SEARCH 3 90 8 20 30 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 2800
MT_NGOATMC Flesh Clan goatmace\goat Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 4 6 8 30 45 GoatMelee SEARCH,CAN_OPEN_DOOR 0 50 8 4 10 0 0 0 0 0 0 0 0 0 0 40 Demon Bottom,Middle 460
MT_BGOATMC Stone Clan goatmace\goat goatmace\beige Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 5 7 10 40 55 GoatMelee SEARCH,CAN_OPEN_DOOR 1 60 8 6 12 0 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 685
MT_RGOATMC Fire Clan goatmace\goat goatmace\red Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 6 8 12 50 65 GoatMelee SEARCH,CAN_OPEN_DOOR 2 70 8 8 16 0 0 0 0 0 0 0 0 0 0 45 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 906
MT_GGOATMC Night Clan goatmace\goat goatmace\gray Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 7 9 14 55 70 GoatMelee SEARCH,CAN_OPEN_DOOR 3 80 8 10 20 15 0 30 30 0 0 0 0 0 0 50 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1190
MT_FIEND Fiend bat\bat bat\red Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 2 3 3 3 6 Bat 0 35 5 1 6 0 0 0 0 0 0 0 0 0 0 0 Animal Middle,Top None 102
MT_BLINK Blink bat\bat Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 3 5 7 12 28 Bat 1 45 5 1 8 0 0 0 0 0 0 0 0 0 0 15 Animal Middle,Top None 340
MT_GLOOM Gloom bat\bat bat\grey Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 4 6 9 28 36 Bat SEARCH 2 70 5 4 12 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC RESIST_MAGIC Middle,Top None 509
MT_FAMILIAR Familiar bat\bat bat\orange Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 6 8 13 20 35 Bat SEARCH 3 50 5 4 16 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Middle,Top None 448
MT_NGOATBW Flesh Clan goatbow\goatb Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 4 6 8 20 35 GoatRanged CAN_OPEN_DOOR 0 35 13 1 7 0 0 0 0 0 0 0 0 0 0 35 Demon Bottom,Middle 448
MT_BGOATBW Stone Clan goatbow\goatb goatbow\beige Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 5 7 10 30 40 GoatRanged CAN_OPEN_DOOR 1 40 13 2 9 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 645
MT_RGOATBW Fire Clan goatbow\goatb goatbow\red Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 6 8 12 40 50 GoatRanged SEARCH,CAN_OPEN_DOOR 2 45 13 3 11 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 822
MT_GGOATBW Night Clan goatbow\goatb goatbow\gray Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 7 9 14 50 65 GoatRanged SEARCH,CAN_OPEN_DOOR 3 50 13 4 13 15 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1092
MT_NACID Acid Beast acid\acid Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 6 8 11 40 66 Acid 0 40 8 4 12 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 846
MT_RACID Poison Spitter acid\acid acid\acidblk Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 8 10 15 60 85 Acid 1 45 8 4 16 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 1248
MT_BACID Pit Beast acid\acid acid\acidb Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 10 12 21 80 110 Acid 2 55 8 8 18 35 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_ACID IMMUNE_MAGIC,RESIST_LIGHTNING,IMMUNE_ACID Bottom,Middle 2060
MT_XACID Lava Maw acid\acid acid\acidr Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 12 14 25 100 150 Acid 3 65 8 10 20 40 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_ACID Bottom,Middle 2940
MT_SKING Skeleton King sking\sking skelaxe\white Never 160 1010 true true 8,6,16,6,16,6 2,1,1,1,1,2 4 4 9 140 140 SkeletonKing SEARCH,CAN_OPEN_DOOR 3 60 8 6 16 0 0 0 0 0 0 0 0 0 0 70 Undead IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top Uniq(SKCROWN) 570
MT_CLEAVER The Butcher fatc\fatc Never 128 980 false false 10,8,12,6,16,0 1,1,1,1,1,1 1 1 1 320 320 Butcher 3 50 8 6 12 0 0 0 0 0 0 0 0 0 0 50 Demon RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle Uniq(CLEAVER) 710
MT_FAT Overlord fat\fat Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 5 7 10 60 80 Fat 0 55 8 6 12 0 0 0 0 0 0 0 0 0 0 55 Demon RESIST_FIRE Bottom,Middle 635
MT_MUDMAN Mud Man fat\fat fat\blue Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 7 9 14 100 125 Fat SEARCH 1 60 8 8 16 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_LIGHTNING Bottom,Middle 1165
MT_TOAD Toad Demon fat\fat fat\fatb Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 8 10 16 135 160 Fat SEARCH 2 70 8 8 16 40 0 8 20 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 1380
MT_FLAYED Flayed One fat\fat fat\fatf Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 10 12 20 160 200 Fat SEARCH 3 85 8 10 20 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2058
MT_WYRM Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 5 7 11 60 90 SkeletonMelee 0 40 8 4 10 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 660
MT_CAVSLUG Cave Slug worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 6 8 13 75 110 SkeletonMelee 1 50 8 6 13 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 994
MT_DVLWYRM Devil Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 7 9 15 100 140 SkeletonMelee 2 55 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1320
MT_DEVOUR Devourer worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 8 10 17 125 200 SkeletonMelee 3 60 8 10 20 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1827
MT_NMAGMA Magma Demon magma\magma Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 9 13 50 70 Magma SEARCH,CAN_OPEN_DOOR 0 45 4 2 10 50 13 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1076
MT_YMAGMA Blood Stone magma\magma magma\yellow Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 10 14 55 75 Magma SEARCH,CAN_OPEN_DOOR 1 50 4 2 12 50 14 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1309
MT_BMAGMA Hell Stone magma\magma magma\blue Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 16 60 80 Magma SEARCH,CAN_OPEN_DOOR 2 60 4 2 20 60 14 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1680
MT_WMAGMA Lava Lord magma\magma magma\wierd Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 18 70 85 Magma SEARCH,CAN_OPEN_DOOR 3 75 4 4 24 60 14 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2124
MT_HORNED Horned Demon rhino\rhino Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 7 9 13 40 80 Rhino SEARCH,CAN_OPEN_DOOR 0 60 7 2 16 100 0 5 32 0 0 0 0 0 0 40 Animal RESIST_FIRE Bottom,Middle,Top 1172
MT_MUDRUN Mud Runner rhino\rhino rhino\orange Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 8 10 15 50 90 Rhino SEARCH,CAN_OPEN_DOOR 1 70 7 6 18 100 0 12 36 0 0 0 0 0 0 45 Animal RESIST_FIRE Bottom,Middle,Top 1404
MT_FROSTC Frost Charger rhino\rhino rhino\blue Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 9 11 17 60 100 Rhino SEARCH,CAN_OPEN_DOOR 2 80 7 8 20 100 0 20 40 0 0 0 0 0 0 50 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 1720
MT_OBLORD Obsidian Lord rhino\rhino rhino\rhinob Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 10 12 19 70 110 Rhino SEARCH,CAN_OPEN_DOOR 3 90 7 10 22 100 0 20 50 0 0 0 0 0 0 55 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 1809
MT_BONEDMN oldboned demskel\demskl Never 128 1740 true true 10,8,20,6,24,16 3,1,1,1,1,1 24 24 12 70 70 Storm 0 60 8 6 14 12 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 1344
MT_REDDTH Red Death thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 8 10 16 96 96 Storm 1 75 5 10 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2168
MT_LTCHDMN Litch Demon thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 110 110 Storm 2 80 5 10 24 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2736
MT_UDEDBLRG Undead Balrog thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 130 130 Storm 3 85 5 12 30 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3575
MT_INCIN Incinerator fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 21 22 16 30 45 FireMan 0 75 8 8 16 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 1888
MT_FLAMLRD Flame Lord fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 22 23 18 40 55 FireMan 1 75 8 10 20 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2250
MT_DOOMFIRE Doom Fire fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 23 24 20 50 65 FireMan 2 80 8 12 24 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 2740
MT_HELLBURN Hell Burner fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 24 24 22 60 80 FireMan 3 85 8 15 30 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 3355
MT_STORM Red Storm thin\thin thin\thinv3 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 55 110 Storm SEARCH,CAN_OPEN_DOOR 0 80 5 8 18 75 8 4 16 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2160
MT_RSTORM Storm Rider thin\thin Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 10 12 20 60 120 Storm SEARCH,CAN_OPEN_DOOR 1 80 5 8 18 80 8 4 16 0 0 0 0 0 0 30 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2391
MT_STORML Storm Lord thin\thin thin\thinv2 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 75 135 Storm SEARCH,CAN_OPEN_DOOR 2 85 5 12 24 75 8 4 16 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2775
MT_MAEL Maelstrom thin\thin thin\thinv1 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 12 14 24 90 150 Storm SEARCH,CAN_OPEN_DOOR 3 90 5 12 28 75 8 4 16 0 0 0 0 0 0 40 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3177
MT_BIGFALL Devil Kin Brute bigfall\fallg newsfx\kbrute Never 128 800 true false 10,8,11,8,17,0 1,1,1,1,2,2 21 22 27 120 160 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 100 6 18 24 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2400
MT_WINGED Winged-Demon gargoyle\gargo Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 5 7 9 45 60 Gargoyle CAN_OPEN_DOOR 0 50 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Middle,Top 662
MT_GARGOYLE Gargoyle gargoyle\gargo gargoyle\gare Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 7 9 13 60 90 Gargoyle CAN_OPEN_DOOR 1 65 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Middle,Top 1205
MT_BLOODCLW Blood Claw gargoyle\gargo gargoyle\gargbr Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 9 11 19 75 125 Gargoyle CAN_OPEN_DOOR 2 80 7 14 22 0 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Middle,Top 1873
MT_DEATHW Death Wing gargoyle\gargo gargoyle\gargb Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 10 12 23 90 150 Gargoyle CAN_OPEN_DOOR 3 95 7 16 28 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Middle,Top 2278
MT_MEGA Slayer mega\mega Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 10 12 20 120 140 Mega SEARCH,CAN_OPEN_DOOR 0 100 8 12 20 0 3 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2300
MT_GUARD Guardian mega\mega mega\guard Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 11 13 22 140 160 Mega SEARCH,CAN_OPEN_DOOR 1 110 8 14 22 0 3 0 0 0 0 0 0 0 0 65 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2714
MT_VTEXLRD Vortex Lord mega\mega mega\vtexl Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 12 14 24 160 180 Mega SEARCH,CAN_OPEN_DOOR 2 120 8 18 24 0 3 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3252
MT_BALROG Balrog mega\mega mega\balr Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 13 15 26 180 200 Mega SEARCH,CAN_OPEN_DOOR 3 130 8 22 30 0 3 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3643
MT_NSNAKE Cave Viper snake\snake Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 11 13 21 100 150 Snake SEARCH 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 2725
MT_RSNAKE Fire Drake snake\snake snake\snakr Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 12 14 23 120 170 Snake SEARCH 1 105 8 12 24 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3139
MT_BSNAKE Gold Viper snake\snake snake\snakg Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 13 14 25 140 180 Snake SEARCH 2 120 8 15 26 0 0 0 0 0 0 0 0 0 0 70 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 3540
MT_GSNAKE Azure Drake snake\snake snake\snakb Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 15 16 27 160 200 Snake SEARCH 3 130 8 18 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 3791
MT_NBLACK Black Knight black\black Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 12 14 24 150 150 SkeletonMelee SEARCH 0 110 8 15 20 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3360
MT_RTBLACK Doom Guard black\black black\blkkntrt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 15 26 165 165 SkeletonMelee SEARCH 0 130 8 18 25 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3650
MT_BTBLACK Steel Lord black\black black\blkkntbt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 14 16 28 180 180 SkeletonMelee SEARCH 1 120 8 20 30 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4252
MT_RBLACK Blood Knight black\black black\blkkntbe Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 14 30 200 200 SkeletonMelee SEARCH 1 130 8 25 35 0 0 0 0 0 0 0 0 0 0 85 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5130
MT_UNRAV The Shredded unrav\unrav newsfx\shred Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 17 18 23 70 90 SkeletonMelee 0 75 7 4 12 0 0 0 0 0 0 0 0 0 0 65 Undead RESIST_FIRE,RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 900
MT_HOLOWONE Hollow One unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 18 19 27 135 240 SkeletonMelee 1 75 7 12 24 0 0 0 0 0 0 0 0 0 0 75 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4374
MT_PAINMSTR Pain Master unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 19 20 29 110 200 SkeletonMelee 2 80 7 16 30 0 0 0 0 0 0 0 0 0 0 80 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 5147
MT_REALWEAV Reality Weaver unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 20 20 30 135 240 SkeletonMelee 3 85 7 20 35 0 0 0 0 0 0 0 0 0 0 85 Undead RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 5925
MT_SUCCUBUS Succubus succ\scbs Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 12 14 24 120 150 Succubus CAN_OPEN_DOOR 0 100 10 1 20 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 3696
MT_SNOWWICH Snow Witch succ\scbs succ\succb Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 13 15 26 135 175 Succubus CAN_OPEN_DOOR 1 110 10 1 24 0 0 0 0 0 0 0 0 0 0 65 Demon RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 4084
MT_HLSPWN Hell Spawn succ\scbs succ\succrw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 14 16 28 150 200 Succubus SEARCH,CAN_OPEN_DOOR 2 115 10 1 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4480
MT_SOLBRNR Soul Burner succ\scbs succ\succbw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 15 16 30 140 225 Succubus SEARCH,CAN_OPEN_DOOR 3 120 10 1 35 0 0 0 0 0 0 0 0 0 0 85 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 4644
MT_COUNSLR Counselor mage\mage Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 13 14 25 70 70 Counselor CAN_OPEN_DOOR 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4070
MT_MAGISTR Magistrate mage\mage mage\cnselg Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 14 15 27 85 85 Counselor CAN_OPEN_DOOR 1 100 8 10 24 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4478
MT_CABALIST Cabalist mage\mage mage\cnselgd Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 15 16 29 120 120 Counselor CAN_OPEN_DOOR 2 110 8 14 30 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4929
MT_ADVOCATE Advocate mage\mage mage\cnselbk Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 16 16 30 145 145 Counselor CAN_OPEN_DOOR 3 120 8 15 25 0 0 0 0 0 0 0 0 0 0 0 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968
MT_GOLEM Golem golem\golem golem\golm Never 96 386 true false 0,16,12,0,12,20 1,1,1,1,1,1 1 1 12 1 1 Golem CAN_OPEN_DOOR 0 0 7 1 1 0 0 0 0 0 0 0 0 0 0 1 Demon 0
MT_DIABLO The Dark Lord diablo\diablo Never 160 2000 true true 16,6,16,6,16,16 1,1,1,1,1,1 26 26 30 1666 1666 Diablo KNOCKBACK,SEARCH,CAN_OPEN_DOOR 3 220 4 30 60 0 11 0 0 0 0 0 0 0 0 90 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 31666
MT_DARKMAGE The Arch-Litch Malignus darkmage\dmage darkmage\dmag Never 128 1060 true false 6,1,21,6,23,18 1,1,1,1,1,1 21 21 30 160 160 Counselor CAN_OPEN_DOOR 3 120 8 20 40 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968
MT_HELLBOAR Hellboar fork\fork newsfx\hboar Retail 188 800 false false 10,10,15,6,16,0 2,1,1,1,1,1 17 18 23 80 100 SkeletonMelee KNOCKBACK,SEARCH 2 70 7 16 24 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 750
MT_STINGER Stinger scorp\scorp newsfx\stingr Retail 64 305 false false 10,10,12,6,15,0 2,1,1,1,1,1 17 18 22 30 40 SkeletonMelee 3 85 8 1 20 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_LIGHTNING Bottom 500
MT_PSYCHORB Psychorb eye\eye newsfx\psyco Retail 156 800 false false 12,13,13,7,21,0 2,1,1,1,1,1 17 18 22 20 30 Psychorb 3 80 8 10 10 0 0 0 0 0 0 0 0 0 0 40 Animal RESIST_FIRE Middle,Top 450
MT_ARACHNON Arachnon spider\spider newsfx\slord Retail 148 800 false false 12,10,15,6,20,0 2,1,1,1,1,1 17 18 22 60 80 SkeletonMelee SEARCH 3 50 8 5 15 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_LIGHTNING Bottom,Middle,Top 500
MT_FELLTWIN Felltwin tsneak\tsneak newsfx\ftwin Retail 128 800 false false 13,13,15,11,16,0 2,1,1,1,1,1 17 18 22 50 70 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 70 8 10 18 0 0 0 0 0 0 0 0 0 0 50 Demon RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 600
MT_HORKSPWN Hork Spawn spawn\spawn newsfx\hspawn Retail 164 520 false true 15,12,14,11,14,0 1,1,1,1,1,1 18 19 22 30 30 SkeletonMelee 3 60 8 10 25 0 0 0 0 0 0 0 0 0 0 25 Demon RESIST_MAGIC RESIST_MAGIC Bottom,Middle 250
MT_VENMTAIL Venomtail wscorp\wscorp newsfx\stingr Retail 86 305 false false 10,10,12,6,15,0 2,1,1,1,1,1 19 20 24 40 50 SkeletonMelee 3 85 8 1 30 0 0 0 0 0 0 0 0 0 0 60 Animal RESIST_LIGHTNING IMMUNE_LIGHTNING Bottom 1000
MT_NECRMORB Necromorb eye2\eye2 newsfx\psyco Retail 140 800 false false 12,13,13,7,21,0 2,1,1,1,1,1 19 20 24 30 40 Necromorb 3 80 8 20 20 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_FIRE IMMUNE_FIRE,RESIST_LIGHTNING Middle,Top 1100
MT_SPIDLORD Spider Lord bspidr\bspidr newsfx\slord Retail 148 800 true true 12,10,15,6,20,10 2,1,1,1,1,1 19 20 24 80 100 Acid SEARCH 3 60 8 8 20 75 8 10 10 0 0 0 0 0 0 60 Animal RESIST_LIGHTNING RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 1250
MT_LASHWORM Lashworm clasp\clasp newsfx\lworm Retail 176 800 false false 10,12,15,6,16,0 1,1,1,1,1,1 19 20 20 30 30 SkeletonMelee 3 90 8 12 20 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_FIRE Bottom,Middle 600
MT_TORCHANT Torchant antworm\worm newsfx\tchant Retail 192 800 false false 14,12,12,6,20,0 2,1,1,1,1,1 19 20 22 60 80 Torchant 3 75 8 20 30 0 0 0 0 0 0 0 0 0 0 70 Animal IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 1250
MT_HORKDMN Hork Demon horkd\horkd newsfx\hdemon Never 138 800 true true 15,8,16,6,16,9 2,1,1,1,1,2 19 19 27 120 160 SkeletonMelee 3 60 8 20 35 80 8 0 0 0 0 0 0 0 0 80 Demon RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2000
MT_DEFILER Hell Bug hellbug\hellbg newsfx\defile Never 198 800 true true 8,8,14,6,14,12 1,1,1,1,1,1 20 20 30 240 240 SkeletonMelee SEARCH 3 110 8 20 30 90 8 50 60 0 0 0 0 0 0 80 Demon RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5000
MT_GRAVEDIG Gravedigger gravdg\gravdg newsfx\gdiggr Retail 124 800 true true 24,24,12,6,16,16 2,1,1,1,1,1 21 21 26 120 240 Scavenger CAN_OPEN_DOOR 3 80 6 2 12 0 0 0 0 0 0 0 0 0 0 20 Undead IMMUNE_LIGHTNING RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle 2000
MT_TOMBRAT Tomb Rat rat\rat newsfx\tmbrat Retail 104 550 false false 11,8,12,6,20,0 2,1,1,1,1,1 21 22 24 80 120 SkeletonMelee 3 120 8 12 25 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 1800
MT_FIREBAT Firebat hellbat\helbat newsfx\helbat Retail 96 550 false false 18,16,14,6,18,11 2,1,1,1,1,1 21 22 24 60 80 FireBat 3 100 8 15 20 0 0 0 0 0 0 0 0 0 0 70 Animal IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 2400
MT_SKLWING Skullwing demskel\demskl newsfx\swing skelaxe\skelt Retail 128 1740 true false 10,8,20,6,24,16 3,1,1,1,1,1 21 22 27 70 70 SkeletonMelee 0 75 7 15 20 75 9 15 20 0 0 0 0 0 0 80 Undead RESIST_FIRE,RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3000
MT_LICH Lich lich\lich newsfx\lich Retail 96 800 false true 12,10,10,7,21,0 2,1,1,1,2,1 21 22 25 80 100 Lich 3 100 8 15 20 0 0 0 0 0 0 0 0 0 0 60 Undead RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle 3000
MT_CRYPTDMN Crypt Demon bubba\bubba newsfx\crypt Retail 154 800 false true 8,18,12,8,21,0 3,1,1,1,1,1 22 23 28 200 240 SkeletonMelee 3 100 8 20 40 0 0 0 0 0 0 0 0 0 0 85 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 3200
MT_HELLBAT Hellbat hellbat2\bhelbt newsfx\helbat Retail 96 550 true false 18,16,14,6,18,11 2,1,1,1,1,1 23 24 29 100 140 Torchant 3 110 8 30 30 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 3600
MT_BONEDEMN Bone Demon demskel\demskl newsfx\swing Retail 128 1740 true true 10,8,20,6,24,16 3,1,1,1,1,1 23 24 30 240 280 BoneDemon 0 100 8 40 50 160 12 50 50 0 0 0 0 0 0 50 Undead IMMUNE_FIRE,IMMUNE_LIGHTNING IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5000
MT_ARCHLICH Arch Lich lich2\lich2 newsfx\lich Retail 136 800 false true 12,10,10,7,21,0 2,1,1,1,2,1 23 24 30 180 200 ArchLich 3 120 8 30 30 0 0 0 0 0 0 0 0 0 0 75 Undead RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 4000
MT_BICLOPS Biclops byclps\byclps newsfx\biclop Retail 180 800 false false 10,11,16,6,16,0 2,1,1,1,2,1 23 24 30 200 240 SkeletonMelee KNOCKBACK,CAN_OPEN_DOOR 3 90 8 40 50 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 4000
MT_FLESTHNG Flesh Thing flesh\flesh newsfx\flesht Retail 164 800 false true 15,24,15,6,16,0 1,1,1,1,1,1 23 24 28 300 400 SkeletonMelee 3 150 8 12 18 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 4000
MT_REAPER Reaper reaper\reap newsfx\reaper Retail 180 800 false false 12,10,14,6,16,0 2,1,1,1,1,1 23 24 30 260 300 SkeletonMelee 3 120 8 30 35 0 0 0 0 0 0 0 0 0 0 90 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 6000
MT_NAKRUL Na-Krul nkr\nkr newsfx\nakrul Never 226 1200 true true 2,6,16,3,16,16 1,1,1,1,1,1 31 31 40 1332 1332 SkeletonMelee KNOCKBACK,SEARCH,CAN_OPEN_DOOR 3 150 7 40 50 150 10 40 50 0 0 0 0 0 0 125 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 13333
_monster_id name assetsSuffix soundSuffix trnFile availability width image hasSpecial hasSpecialSound frames[6] rate[6] minDunLvl maxDunLvl level hitPointsMinimum hitPointsMaximum ai abilityFlags intelligence toHit animFrameNum minDamage maxDamage toHitSpecial animFrameNumSpecial minDamageSpecial maxDamageSpecial reducePlayerStrength reducePlayerMagic reducePlayerDexterity reducePlayerVitality reducePlayerMaxHP reducePlayerMaxMana armorClass monsterClass resistance resistanceHell selectionRegion treasure exp shadowRule[6]
MT_NZOMBIE Zombie zombie\zombie Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 1 2 1 4 7 Zombie 0 10 8 2 5 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 54 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_BZOMBIE Ghoul zombie\zombie zombie\bluered Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 3 2 7 11 Zombie 1 10 8 3 10 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 58 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_GZOMBIE Rotting Carcass zombie\zombie zombie\grey Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 4 4 15 25 Zombie 2 25 8 5 15 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 136 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_YZOMBIE Black Death zombie\zombie zombie\yellow Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 3 5 6 25 40 Zombie 3 30 8 6 22 0 0 0 0 0 0 0 0 1 0 20 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 240 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_RFALLSP Fallen One falspear\phall falspear\fallent Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 1 2 1 1 4 Fallen 0 15 7 1 3 0 5 0 0 0 0 0 0 0 0 0 Animal Bottom,Middle 46 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_DFALLSP Carver falspear\phall falspear\dark Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 3 3 4 8 Fallen 2 20 7 2 5 0 5 0 0 0 0 0 0 0 0 5 Animal Bottom,Middle 80 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_YFALLSP Devil Kin falspear\phall Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 4 5 12 24 Fallen 2 25 7 3 7 0 5 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 155 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BFALLSP Dark One falspear\phall falspear\blue Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 3 5 7 20 36 Fallen 3 30 7 4 8 0 5 0 0 0 0 0 0 0 0 15 Animal RESIST_LIGHTNING Bottom,Middle 255 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WSKELAX Skeleton skelaxe\sklax skelaxe\white Always 128 553 true false 12,8,13,6,17,16 5,1,1,1,1,1 1 2 1 2 4 SkeletonMelee 0 20 8 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 64 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_TSKELAX Corpse Axe skelaxe\sklax skelaxe\skelt Always 128 553 true false 12,8,13,6,17,16 4,1,1,1,1,1 2 3 2 4 7 SkeletonMelee 1 25 8 3 5 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 68 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RSKELAX Burning Dead skelaxe\sklax Always 128 553 true false 12,8,13,6,17,16 2,1,1,1,1,1 2 4 4 8 12 SkeletonMelee 2 30 8 3 7 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 154 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_XSKELAX Horror skelaxe\sklax skelaxe\black Always 128 553 true false 12,8,13,6,17,16 3,1,1,1,1,1 3 5 6 12 20 SkeletonMelee 3 35 8 4 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 264 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RFALLSD Fallen One falsword\fall falsword\fallent Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 1 2 1 2 5 Fallen 0 15 8 1 4 0 5 0 0 0 0 0 0 0 0 10 Animal Bottom,Middle 52 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_DFALLSD Carver falsword\fall falsword\dark Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 3 3 5 9 Fallen 1 20 8 2 7 0 5 0 0 0 0 0 0 0 0 15 Animal Bottom,Middle 90 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_YFALLSD Devil Kin falsword\fall Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 4 5 16 24 Fallen 2 25 8 4 10 0 5 0 0 0 0 0 0 0 0 20 Animal RESIST_FIRE Bottom,Middle 180 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BFALLSD Dark One falsword\fall falsword\blue Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 3 5 7 24 36 Fallen 3 30 8 4 12 0 5 0 0 0 0 0 0 0 0 25 Animal RESIST_LIGHTNING Bottom,Middle 280 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_NSCAV Scavenger scav\scav Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 1 3 2 3 6 Scavenger 0 20 7 1 5 0 0 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 80 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BSCAV Plague Eater scav\scav scav\scavbr Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 2 4 4 12 24 Scavenger 1 30 7 1 8 0 0 0 0 0 0 0 0 0 0 20 Animal RESIST_LIGHTNING Bottom,Middle 188 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WSCAV Shadow Beast scav\scav scav\scavbe Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 3 5 6 24 36 Scavenger 2 35 7 3 12 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_FIRE Bottom,Middle 375 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_YSCAV Bone Gasher scav\scav scav\scavw Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 4 6 8 28 40 Scavenger 3 35 7 5 15 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_LIGHTNING Bottom,Middle 552 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WSKELBW Skeleton skelbow\sklbw skelbow\white Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 3 3 2 4 SkeletonRanged 0 15 12 1 2 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 110 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_TSKELBW Corpse Bow skelbow\sklbw skelbow\skelt Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 4 5 8 16 SkeletonRanged 1 25 12 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 210 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RSKELBW Burning Dead skelbow\sklbw Always 128 567 true false 9,8,16,5,16,16 2,1,1,1,1,1 3 5 7 10 24 SkeletonRanged 2 30 12 1 6 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 364 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_XSKELBW Horror skelbow\sklbw skelbow\black Always 128 567 true false 9,8,16,5,16,16 3,1,1,1,1,1 4 6 9 15 45 SkeletonRanged 3 35 12 2 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 594 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WSKELSD Skeleton Captain skelsd\sklsr skelsd\white Always 128 575 true true 13,8,12,7,15,16 4,1,1,1,1,1 1 3 2 3 6 SkeletonMelee 0 20 8 2 7 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 90 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_TSKELSD Corpse Captain skelsd\sklsr skelsd\skelt Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 2 4 4 12 20 SkeletonMelee 1 30 8 3 9 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 200 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RSKELSD Burning Dead Captain skelsd\sklsr Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 3 5 6 16 30 SkeletonMelee 2 35 8 4 10 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 393 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_XSKELSD Horror Captain skelsd\sklsr skelsd\black Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 4 6 8 35 50 SkeletonMelee SEARCH 3 40 8 5 14 0 0 0 0 0 0 0 0 0 0 30 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 604 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_INVILORD Invisible Lord tsneak\tsneak Never 128 800 false false 13,13,15,11,16,0 2,1,1,1,1,1 19 20 14 278 278 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 65 8 16 30 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2000 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_SNEAK Hidden sneak\sneak Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 2 5 5 8 24 Sneak HIDDEN 0 35 8 3 6 0 0 0 0 0 0 0 0 0 0 25 Demon Bottom,Middle 278 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_STALKER Stalker sneak\sneak sneak\sneakv2 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 5 7 9 30 45 Sneak HIDDEN,SEARCH 1 40 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Demon Bottom,Middle 630 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_UNSEEN Unseen sneak\sneak sneak\sneakv3 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 6 8 11 35 50 Sneak HIDDEN,SEARCH 2 45 8 12 20 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 935 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_ILLWEAV Illusion Weaver sneak\sneak sneak\sneakv1 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 8 10 13 40 60 Sneak HIDDEN,SEARCH 3 60 8 16 24 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC,RESIST_FIRE IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 1500 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_LRDSAYTR Satyr Lord goatlord\goatl newsfx\satyr Never 160 800 false false 13,13,14,9,16,0 2,1,1,1,1,1 21 22 28 160 200 SkeletonMelee SEARCH 3 90 8 20 30 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 2800 FirstFrame,FirstFrame,FirstFrame,FirstFrame,None,None
MT_NGOATMC Flesh Clan goatmace\goat Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 4 6 8 30 45 GoatMelee SEARCH,CAN_OPEN_DOOR 0 50 8 4 10 0 0 0 0 0 0 0 0 0 0 40 Demon Bottom,Middle 460 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BGOATMC Stone Clan goatmace\goat goatmace\beige Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 5 7 10 40 55 GoatMelee SEARCH,CAN_OPEN_DOOR 1 60 8 6 12 0 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 685 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RGOATMC Fire Clan goatmace\goat goatmace\red Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 6 8 12 50 65 GoatMelee SEARCH,CAN_OPEN_DOOR 2 70 8 8 16 0 0 0 0 0 0 0 0 0 0 45 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 906 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_GGOATMC Night Clan goatmace\goat goatmace\gray Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 7 9 14 55 70 GoatMelee SEARCH,CAN_OPEN_DOOR 3 80 8 10 20 15 0 30 30 0 0 0 0 0 0 50 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1190 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_FIEND Fiend bat\bat bat\red Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 2 3 3 3 6 Bat 0 35 5 1 6 0 0 0 0 0 0 0 0 0 0 0 Animal Middle,Top None 102 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
MT_BLINK Blink bat\bat Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 3 5 7 12 28 Bat 1 45 5 1 8 0 0 0 0 0 0 0 0 0 0 15 Animal Middle,Top None 340 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
MT_GLOOM Gloom bat\bat bat\grey Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 4 6 9 28 36 Bat SEARCH 2 70 5 4 12 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC RESIST_MAGIC Middle,Top None 509 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
MT_FAMILIAR Familiar bat\bat bat\orange Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 6 8 13 20 35 Bat SEARCH 3 50 5 4 16 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Middle,Top None 448 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
MT_NGOATBW Flesh Clan goatbow\goatb Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 4 6 8 20 35 GoatRanged CAN_OPEN_DOOR 0 35 13 1 7 0 0 0 0 0 0 0 0 0 0 35 Demon Bottom,Middle 448 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_BGOATBW Stone Clan goatbow\goatb goatbow\beige Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 5 7 10 30 40 GoatRanged CAN_OPEN_DOOR 1 40 13 2 9 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 645 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_RGOATBW Fire Clan goatbow\goatb goatbow\red Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 6 8 12 40 50 GoatRanged SEARCH,CAN_OPEN_DOOR 2 45 13 3 11 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 822 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_GGOATBW Night Clan goatbow\goatb goatbow\gray Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 7 9 14 50 65 GoatRanged SEARCH,CAN_OPEN_DOOR 3 50 13 4 13 15 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1092 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_NACID Acid Beast acid\acid Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 6 8 11 40 66 Acid 0 40 8 4 12 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 846 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RACID Poison Spitter acid\acid acid\acidblk Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 8 10 15 60 85 Acid 1 45 8 4 16 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 1248 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BACID Pit Beast acid\acid acid\acidb Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 10 12 21 80 110 Acid 2 55 8 8 18 35 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_ACID IMMUNE_MAGIC,RESIST_LIGHTNING,IMMUNE_ACID Bottom,Middle 2060 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_XACID Lava Maw acid\acid acid\acidr Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 12 14 25 100 150 Acid 3 65 8 10 20 40 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_ACID Bottom,Middle 2940 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_SKING Skeleton King sking\sking skelaxe\white Never 160 1010 true true 8,6,16,6,16,6 2,1,1,1,1,2 4 4 9 140 140 SkeletonKing SEARCH,CAN_OPEN_DOOR 3 60 8 6 16 0 0 0 0 0 0 0 0 0 0 70 Undead IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top Uniq(SKCROWN) 570 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_CLEAVER The Butcher fatc\fatc Never 128 980 false false 10,8,12,6,16,0 1,1,1,1,1,1 1 1 1 320 320 Butcher 3 50 8 6 12 0 0 0 0 0 0 0 0 0 0 50 Demon RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle Uniq(CLEAVER) 710 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_FAT Overlord fat\fat Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 5 7 10 60 80 Fat 0 55 8 6 12 0 0 0 0 0 0 0 0 0 0 55 Demon RESIST_FIRE Bottom,Middle 635 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_MUDMAN Mud Man fat\fat fat\blue Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 7 9 14 100 125 Fat SEARCH 1 60 8 8 16 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_LIGHTNING Bottom,Middle 1165 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_TOAD Toad Demon fat\fat fat\fatb Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 8 10 16 135 160 Fat SEARCH 2 70 8 8 16 40 0 8 20 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 1380 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_FLAYED Flayed One fat\fat fat\fatf Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 10 12 20 160 200 Fat SEARCH 3 85 8 10 20 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2058 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WYRM Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 5 7 11 60 90 SkeletonMelee 0 40 8 4 10 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 660
MT_CAVSLUG Cave Slug worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 6 8 13 75 110 SkeletonMelee 1 50 8 6 13 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 994
MT_DVLWYRM Devil Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 7 9 15 100 140 SkeletonMelee 2 55 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1320
MT_DEVOUR Devourer worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 8 10 17 125 200 SkeletonMelee 3 60 8 10 20 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1827
MT_NMAGMA Magma Demon magma\magma Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 9 13 50 70 Magma SEARCH,CAN_OPEN_DOOR 0 45 4 2 10 50 13 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1076 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_YMAGMA Blood Stone magma\magma magma\yellow Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 10 14 55 75 Magma SEARCH,CAN_OPEN_DOOR 1 50 4 2 12 50 14 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1309 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BMAGMA Hell Stone magma\magma magma\blue Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 16 60 80 Magma SEARCH,CAN_OPEN_DOOR 2 60 4 2 20 60 14 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1680 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_WMAGMA Lava Lord magma\magma magma\wierd Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 18 70 85 Magma SEARCH,CAN_OPEN_DOOR 3 75 4 4 24 60 14 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2124 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_HORNED Horned Demon rhino\rhino Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 7 9 13 40 80 Rhino SEARCH,CAN_OPEN_DOOR 0 60 7 2 16 100 0 5 32 0 0 0 0 0 0 40 Animal RESIST_FIRE Bottom,Middle,Top 1172 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_MUDRUN Mud Runner rhino\rhino rhino\orange Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 8 10 15 50 90 Rhino SEARCH,CAN_OPEN_DOOR 1 70 7 6 18 100 0 12 36 0 0 0 0 0 0 45 Animal RESIST_FIRE Bottom,Middle,Top 1404 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_FROSTC Frost Charger rhino\rhino rhino\blue Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 9 11 17 60 100 Rhino SEARCH,CAN_OPEN_DOOR 2 80 7 8 20 100 0 20 40 0 0 0 0 0 0 50 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 1720 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_OBLORD Obsidian Lord rhino\rhino rhino\rhinob Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 10 12 19 70 110 Rhino SEARCH,CAN_OPEN_DOOR 3 90 7 10 22 100 0 20 50 0 0 0 0 0 0 55 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 1809 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BONEDMN oldboned demskel\demskl Never 128 1740 true true 10,8,20,6,24,16 3,1,1,1,1,1 24 24 12 70 70 Storm 0 60 8 6 14 12 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 1344 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_REDDTH Red Death thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 8 10 16 96 96 Storm 1 75 5 10 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2168 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_LTCHDMN Litch Demon thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 110 110 Storm 2 80 5 10 24 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2736 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_UDEDBLRG Undead Balrog thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 130 130 Storm 3 85 5 12 30 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3575 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_INCIN Incinerator fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 21 22 16 30 45 FireMan 0 75 8 8 16 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 1888 None,None,None,None,None,None
MT_FLAMLRD Flame Lord fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 22 23 18 40 55 FireMan 1 75 8 10 20 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2250 None,None,None,None,None,None
MT_DOOMFIRE Doom Fire fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 23 24 20 50 65 FireMan 2 80 8 12 24 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 2740 None,None,None,None,None,None
MT_HELLBURN Hell Burner fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 24 24 22 60 80 FireMan 3 85 8 15 30 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 3355 None,None,None,None,None,None
MT_STORM Red Storm thin\thin thin\thinv3 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 55 110 Storm SEARCH,CAN_OPEN_DOOR 0 80 5 8 18 75 8 4 16 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2160 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_RSTORM Storm Rider thin\thin Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 10 12 20 60 120 Storm SEARCH,CAN_OPEN_DOOR 1 80 5 8 18 80 8 4 16 0 0 0 0 0 0 30 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2391 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_STORML Storm Lord thin\thin thin\thinv2 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 75 135 Storm SEARCH,CAN_OPEN_DOOR 2 85 5 12 24 75 8 4 16 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2775 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_MAEL Maelstrom thin\thin thin\thinv1 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 12 14 24 90 150 Storm SEARCH,CAN_OPEN_DOOR 3 90 5 12 28 75 8 4 16 0 0 0 0 0 0 40 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3177 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_BIGFALL Devil Kin Brute bigfall\fallg newsfx\kbrute Never 128 800 true false 10,8,11,8,17,0 1,1,1,1,2,2 21 22 27 120 160 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 100 6 18 24 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2400 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_WINGED Winged-Demon gargoyle\gargo Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 5 7 9 45 60 Gargoyle CAN_OPEN_DOOR 0 50 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Middle,Top 662 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
MT_GARGOYLE Gargoyle gargoyle\gargo gargoyle\gare Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 7 9 13 60 90 Gargoyle CAN_OPEN_DOOR 1 65 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Middle,Top 1205 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
MT_BLOODCLW Blood Claw gargoyle\gargo gargoyle\gargbr Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 9 11 19 75 125 Gargoyle CAN_OPEN_DOOR 2 80 7 14 22 0 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Middle,Top 1873 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
MT_DEATHW Death Wing gargoyle\gargo gargoyle\gargb Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 10 12 23 90 150 Gargoyle CAN_OPEN_DOOR 3 95 7 16 28 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Middle,Top 2278 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
MT_MEGA Slayer mega\mega Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 10 12 20 120 140 Mega SEARCH,CAN_OPEN_DOOR 0 100 8 12 20 0 3 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2300 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
MT_GUARD Guardian mega\mega mega\guard Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 11 13 22 140 160 Mega SEARCH,CAN_OPEN_DOOR 1 110 8 14 22 0 3 0 0 0 0 0 0 0 0 65 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2714 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
MT_VTEXLRD Vortex Lord mega\mega mega\vtexl Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 12 14 24 160 180 Mega SEARCH,CAN_OPEN_DOOR 2 120 8 18 24 0 3 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3252 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
MT_BALROG Balrog mega\mega mega\balr Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 13 15 26 180 200 Mega SEARCH,CAN_OPEN_DOOR 3 130 8 22 30 0 3 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3643 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
MT_NSNAKE Cave Viper snake\snake Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 11 13 21 100 150 Snake SEARCH 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 2725 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
MT_RSNAKE Fire Drake snake\snake snake\snakr Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 12 14 23 120 170 Snake SEARCH 1 105 8 12 24 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3139 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
MT_BSNAKE Gold Viper snake\snake snake\snakg Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 13 14 25 140 180 Snake SEARCH 2 120 8 15 26 0 0 0 0 0 0 0 0 0 0 70 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 3540 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
MT_GSNAKE Azure Drake snake\snake snake\snakb Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 15 16 27 160 200 Snake SEARCH 3 130 8 18 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 3791 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
MT_NBLACK Black Knight black\black Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 12 14 24 150 150 SkeletonMelee SEARCH 0 110 8 15 20 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3360 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_RTBLACK Doom Guard black\black black\blkkntrt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 15 26 165 165 SkeletonMelee SEARCH 0 130 8 18 25 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3650 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_BTBLACK Steel Lord black\black black\blkkntbt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 14 16 28 180 180 SkeletonMelee SEARCH 1 120 8 20 30 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4252 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_RBLACK Blood Knight black\black black\blkkntbe Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 14 30 200 200 SkeletonMelee SEARCH 1 130 8 25 35 0 0 0 0 0 0 0 0 0 0 85 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5130 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_UNRAV The Shredded unrav\unrav newsfx\shred Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 17 18 23 70 90 SkeletonMelee 0 75 7 4 12 0 0 0 0 0 0 0 0 0 0 65 Undead RESIST_FIRE,RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 900 None,EachFrame,EachFrame,None,None,None
MT_HOLOWONE Hollow One unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 18 19 27 135 240 SkeletonMelee 1 75 7 12 24 0 0 0 0 0 0 0 0 0 0 75 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4374 None,EachFrame,EachFrame,None,None,None
MT_PAINMSTR Pain Master unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 19 20 29 110 200 SkeletonMelee 2 80 7 16 30 0 0 0 0 0 0 0 0 0 0 80 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 5147 None,EachFrame,EachFrame,None,None,None
MT_REALWEAV Reality Weaver unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 20 20 30 135 240 SkeletonMelee 3 85 7 20 35 0 0 0 0 0 0 0 0 0 0 85 Undead RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 5925 None,EachFrame,EachFrame,None,None,None
MT_SUCCUBUS Succubus succ\scbs Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 12 14 24 120 150 Succubus CAN_OPEN_DOOR 0 100 10 1 20 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 3696 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_SNOWWICH Snow Witch succ\scbs succ\succb Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 13 15 26 135 175 Succubus CAN_OPEN_DOOR 1 110 10 1 24 0 0 0 0 0 0 0 0 0 0 65 Demon RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 4084 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_HLSPWN Hell Spawn succ\scbs succ\succrw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 14 16 28 150 200 Succubus SEARCH,CAN_OPEN_DOOR 2 115 10 1 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4480 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_SOLBRNR Soul Burner succ\scbs succ\succbw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 15 16 30 140 225 Succubus SEARCH,CAN_OPEN_DOOR 3 120 10 1 35 0 0 0 0 0 0 0 0 0 0 85 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 4644 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_COUNSLR Counselor mage\mage Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 13 14 25 70 70 Counselor CAN_OPEN_DOOR 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4070 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
MT_MAGISTR Magistrate mage\mage mage\cnselg Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 14 15 27 85 85 Counselor CAN_OPEN_DOOR 1 100 8 10 24 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4478 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
MT_CABALIST Cabalist mage\mage mage\cnselgd Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 15 16 29 120 120 Counselor CAN_OPEN_DOOR 2 110 8 14 30 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4929 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
MT_ADVOCATE Advocate mage\mage mage\cnselbk Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 16 16 30 145 145 Counselor CAN_OPEN_DOOR 3 120 8 15 25 0 0 0 0 0 0 0 0 0 0 0 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
MT_GOLEM Golem golem\golem golem\golm Never 96 386 true false 0,16,12,0,12,20 1,1,1,1,1,1 1 1 12 1 1 Golem CAN_OPEN_DOOR 0 0 7 1 1 0 0 0 0 0 0 0 0 0 0 1 Demon 0 None,EachFrame,EachFrame,None,EachFrame,EachFrame
MT_DIABLO The Dark Lord diablo\diablo Never 160 2000 true true 16,6,16,6,16,16 1,1,1,1,1,1 26 26 30 1666 1666 Diablo KNOCKBACK,SEARCH,CAN_OPEN_DOOR 3 220 4 30 60 0 11 0 0 0 0 0 0 0 0 90 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 31666 FirstFrame,FirstFrame,EachFrame,FirstFrame,EachFrame,EachFrame
MT_DARKMAGE The Arch-Litch Malignus darkmage\dmage darkmage\dmag Never 128 1060 true false 6,1,21,6,23,18 1,1,1,1,1,1 21 21 30 160 160 Counselor CAN_OPEN_DOOR 3 120 8 20 40 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968 FirstFrame,None,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_HELLBOAR Hellboar fork\fork newsfx\hboar Retail 188 800 false false 10,10,15,6,16,0 2,1,1,1,1,1 17 18 23 80 100 SkeletonMelee KNOCKBACK,SEARCH 2 70 7 16 24 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 750 EachFrame,EachFrame,EachFrame,EachFrame,None,None
MT_STINGER Stinger scorp\scorp newsfx\stingr Retail 64 305 false false 10,10,12,6,15,0 2,1,1,1,1,1 17 18 22 30 40 SkeletonMelee 3 85 8 1 20 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_LIGHTNING Bottom 500 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
MT_PSYCHORB Psychorb eye\eye newsfx\psyco Retail 156 800 false false 12,13,13,7,21,0 2,1,1,1,1,1 17 18 22 20 30 Psychorb 3 80 8 10 10 0 0 0 0 0 0 0 0 0 0 40 Animal RESIST_FIRE Middle,Top 450 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
MT_ARACHNON Arachnon spider\spider newsfx\slord Retail 148 800 false false 12,10,15,6,20,0 2,1,1,1,1,1 17 18 22 60 80 SkeletonMelee SEARCH 3 50 8 5 15 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_LIGHTNING Bottom,Middle,Top 500 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
MT_FELLTWIN Felltwin tsneak\tsneak newsfx\ftwin Retail 128 800 false false 13,13,15,11,16,0 2,1,1,1,1,1 17 18 22 50 70 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 70 8 10 18 0 0 0 0 0 0 0 0 0 0 50 Demon RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 600 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
MT_HORKSPWN Hork Spawn spawn\spawn newsfx\hspawn Retail 164 520 false true 15,12,14,11,14,0 1,1,1,1,1,1 18 19 22 30 30 SkeletonMelee 3 60 8 10 25 0 0 0 0 0 0 0 0 0 0 25 Demon RESIST_MAGIC RESIST_MAGIC Bottom,Middle 250 EachFrame,EachFrame,EachFrame,EachFrame,None,None
MT_VENMTAIL Venomtail wscorp\wscorp newsfx\stingr Retail 86 305 false false 10,10,12,6,15,0 2,1,1,1,1,1 19 20 24 40 50 SkeletonMelee 3 85 8 1 30 0 0 0 0 0 0 0 0 0 0 60 Animal RESIST_LIGHTNING IMMUNE_LIGHTNING Bottom 1000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
MT_NECRMORB Necromorb eye2\eye2 newsfx\psyco Retail 140 800 false false 12,13,13,7,21,0 2,1,1,1,1,1 19 20 24 30 40 Necromorb 3 80 8 20 20 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_FIRE IMMUNE_FIRE,RESIST_LIGHTNING Middle,Top 1100 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
MT_SPIDLORD Spider Lord bspidr\bspidr newsfx\slord Retail 148 800 true true 12,10,15,6,20,10 2,1,1,1,1,1 19 20 24 80 100 Acid SEARCH 3 60 8 8 20 75 8 10 10 0 0 0 0 0 0 60 Animal RESIST_LIGHTNING RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 1250 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,EachFrame
MT_LASHWORM Lashworm clasp\clasp newsfx\lworm Retail 176 800 false false 10,12,15,6,16,0 1,1,1,1,1,1 19 20 20 30 30 SkeletonMelee 3 90 8 12 20 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_FIRE Bottom,Middle 600 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
MT_TORCHANT Torchant antworm\worm newsfx\tchant Retail 192 800 false false 14,12,12,6,20,0 2,1,1,1,1,1 19 20 22 60 80 Torchant 3 75 8 20 30 0 0 0 0 0 0 0 0 0 0 70 Animal IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 1250 EachFrame,EachFrame,EachFrame,EachFrame,None,None
MT_HORKDMN Hork Demon horkd\horkd newsfx\hdemon Never 138 800 true true 15,8,16,6,16,9 2,1,1,1,1,2 19 19 27 120 160 SkeletonMelee 3 60 8 20 35 80 8 0 0 0 0 0 0 0 0 80 Demon RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2000 EachFrame,EachFrame,EachFrame,EachFrame,None,EachFrame
MT_DEFILER Hell Bug hellbug\hellbg newsfx\defile Never 198 800 true true 8,8,14,6,14,12 1,1,1,1,1,1 20 20 30 240 240 SkeletonMelee SEARCH 3 110 8 20 30 90 8 50 60 0 0 0 0 0 0 80 Demon RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5000 EachFrame,EachFrame,EachFrame,EachFrame,None,EachFrame
MT_GRAVEDIG Gravedigger gravdg\gravdg newsfx\gdiggr Retail 124 800 true true 24,24,12,6,16,16 2,1,1,1,1,1 21 21 26 120 240 Scavenger CAN_OPEN_DOOR 3 80 6 2 12 0 0 0 0 0 0 0 0 0 0 20 Undead IMMUNE_LIGHTNING RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle 2000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,EachFrame
MT_TOMBRAT Tomb Rat rat\rat newsfx\tmbrat Retail 104 550 false false 11,8,12,6,20,0 2,1,1,1,1,1 21 22 24 80 120 SkeletonMelee 3 120 8 12 25 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 1800 EachFrame,EachFrame,EachFrame,EachFrame,None,None
MT_FIREBAT Firebat hellbat\helbat newsfx\helbat Retail 96 550 false false 18,16,14,6,18,11 2,1,1,1,1,1 21 22 24 60 80 FireBat 3 100 8 15 20 0 0 0 0 0 0 0 0 0 0 70 Animal IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 2400 EachFrame,EachFrame,EachFrame,EachFrame,None,EachFrame
MT_SKLWING Skullwing demskel\demskl newsfx\swing skelaxe\skelt Retail 128 1740 true false 10,8,20,6,24,16 3,1,1,1,1,1 21 22 27 70 70 SkeletonMelee 0 75 7 15 20 75 9 15 20 0 0 0 0 0 0 80 Undead RESIST_FIRE,RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3000 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_LICH Lich lich\lich newsfx\lich Retail 96 800 false true 12,10,10,7,21,0 2,1,1,1,2,1 21 22 25 80 100 Lich 3 100 8 15 20 0 0 0 0 0 0 0 0 0 0 60 Undead RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle 3000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
MT_CRYPTDMN Crypt Demon bubba\bubba newsfx\crypt Retail 154 800 false true 8,18,12,8,21,0 3,1,1,1,1,1 22 23 28 200 240 SkeletonMelee 3 100 8 20 40 0 0 0 0 0 0 0 0 0 0 85 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 3200 EachFrame,EachFrame,EachFrame,EachFrame,None,None
MT_HELLBAT Hellbat hellbat2\bhelbt newsfx\helbat Retail 96 550 true false 18,16,14,6,18,11 2,1,1,1,1,1 23 24 29 100 140 Torchant 3 110 8 30 30 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 3600 EachFrame,EachFrame,EachFrame,EachFrame,None,EachFrame
MT_BONEDEMN Bone Demon demskel\demskl newsfx\swing Retail 128 1740 true true 10,8,20,6,24,16 3,1,1,1,1,1 23 24 30 240 280 BoneDemon 0 100 8 40 50 160 12 50 50 0 0 0 0 0 0 50 Undead IMMUNE_FIRE,IMMUNE_LIGHTNING IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5000 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
MT_ARCHLICH Arch Lich lich2\lich2 newsfx\lich Retail 136 800 false true 12,10,10,7,21,0 2,1,1,1,2,1 23 24 30 180 200 ArchLich 3 120 8 30 30 0 0 0 0 0 0 0 0 0 0 75 Undead RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 4000 EachFrame,EachFrame,EachFrame,EachFrame,None,None
MT_BICLOPS Biclops byclps\byclps newsfx\biclop Retail 180 800 false false 10,11,16,6,16,0 2,1,1,1,2,1 23 24 30 200 240 SkeletonMelee KNOCKBACK,CAN_OPEN_DOOR 3 90 8 40 50 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 4000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
MT_FLESTHNG Flesh Thing flesh\flesh newsfx\flesht Retail 164 800 false true 15,24,15,6,16,0 1,1,1,1,1,1 23 24 28 300 400 SkeletonMelee 3 150 8 12 18 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 4000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
MT_REAPER Reaper reaper\reap newsfx\reaper Retail 180 800 false false 12,10,14,6,16,0 2,1,1,1,1,1 23 24 30 260 300 SkeletonMelee 3 120 8 30 35 0 0 0 0 0 0 0 0 0 0 90 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 6000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame|Unexplained,None
MT_NAKRUL Na-Krul nkr\nkr newsfx\nakrul Never 226 1200 true true 2,6,16,3,16,16 1,1,1,1,1,1 31 31 40 1332 1332 SkeletonMelee KNOCKBACK,SEARCH,CAN_OPEN_DOOR 3 150 7 40 50 150 10 40 50 0 0 0 0 0 0 125 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 13333 FirstFrame,EachFrame,EachFrame|Unexplained,EachFrame,EachFrame|Unexplained,EachFrame|Unexplained
1 _monster_id name assetsSuffix soundSuffix trnFile availability width image hasSpecial hasSpecialSound frames[6] rate[6] minDunLvl maxDunLvl level hitPointsMinimum hitPointsMaximum ai abilityFlags intelligence toHit animFrameNum minDamage maxDamage toHitSpecial animFrameNumSpecial minDamageSpecial maxDamageSpecial reducePlayerStrength reducePlayerMagic reducePlayerDexterity reducePlayerVitality reducePlayerMaxHP reducePlayerMaxMana armorClass monsterClass resistance resistanceHell selectionRegion treasure exp shadowRule[6]
2 MT_NZOMBIE Zombie zombie\zombie Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 1 2 1 4 7 Zombie 0 10 8 2 5 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 54 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
3 MT_BZOMBIE Ghoul zombie\zombie zombie\bluered Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 3 2 7 11 Zombie 1 10 8 3 10 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 58 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
4 MT_GZOMBIE Rotting Carcass zombie\zombie zombie\grey Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 2 4 4 15 25 Zombie 2 25 8 5 15 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 136 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
5 MT_YZOMBIE Black Death zombie\zombie zombie\yellow Always 128 799 false false 11,24,12,6,16,0 4,1,1,1,1,1 3 5 6 25 40 Zombie 3 30 8 6 22 0 0 0 0 0 0 0 0 1 0 20 Undead IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 240 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
6 MT_RFALLSP Fallen One falspear\phall falspear\fallent Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 1 2 1 1 4 Fallen 0 15 7 1 3 0 5 0 0 0 0 0 0 0 0 0 Animal Bottom,Middle 46 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
7 MT_DFALLSP Carver falspear\phall falspear\dark Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 3 3 4 8 Fallen 2 20 7 2 5 0 5 0 0 0 0 0 0 0 0 5 Animal Bottom,Middle 80 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
8 MT_YFALLSP Devil Kin falspear\phall Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 2 4 5 12 24 Fallen 2 25 7 3 7 0 5 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 155 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
9 MT_BFALLSP Dark One falspear\phall falspear\blue Always 128 543 true true 11,11,13,11,18,13 3,1,1,1,1,1 3 5 7 20 36 Fallen 3 30 7 4 8 0 5 0 0 0 0 0 0 0 0 15 Animal RESIST_LIGHTNING Bottom,Middle 255 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
10 MT_WSKELAX Skeleton skelaxe\sklax skelaxe\white Always 128 553 true false 12,8,13,6,17,16 5,1,1,1,1,1 1 2 1 2 4 SkeletonMelee 0 20 8 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 64 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
11 MT_TSKELAX Corpse Axe skelaxe\sklax skelaxe\skelt Always 128 553 true false 12,8,13,6,17,16 4,1,1,1,1,1 2 3 2 4 7 SkeletonMelee 1 25 8 3 5 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 68 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
12 MT_RSKELAX Burning Dead skelaxe\sklax Always 128 553 true false 12,8,13,6,17,16 2,1,1,1,1,1 2 4 4 8 12 SkeletonMelee 2 30 8 3 7 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 154 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
13 MT_XSKELAX Horror skelaxe\sklax skelaxe\black Always 128 553 true false 12,8,13,6,17,16 3,1,1,1,1,1 3 5 6 12 20 SkeletonMelee 3 35 8 4 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 264 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
14 MT_RFALLSD Fallen One falsword\fall falsword\fallent Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 1 2 1 2 5 Fallen 0 15 8 1 4 0 5 0 0 0 0 0 0 0 0 10 Animal Bottom,Middle 52 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
15 MT_DFALLSD Carver falsword\fall falsword\dark Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 3 3 5 9 Fallen 1 20 8 2 7 0 5 0 0 0 0 0 0 0 0 15 Animal Bottom,Middle 90 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
16 MT_YFALLSD Devil Kin falsword\fall Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 2 4 5 16 24 Fallen 2 25 8 4 10 0 5 0 0 0 0 0 0 0 0 20 Animal RESIST_FIRE Bottom,Middle 180 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
17 MT_BFALLSD Dark One falsword\fall falsword\blue Always 128 623 true true 12,12,13,11,14,15 3,1,1,1,1,1 3 5 7 24 36 Fallen 3 30 8 4 12 0 5 0 0 0 0 0 0 0 0 25 Animal RESIST_LIGHTNING Bottom,Middle 280 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
18 MT_NSCAV Scavenger scav\scav Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 1 3 2 3 6 Scavenger 0 20 7 1 5 0 0 0 0 0 0 0 0 0 0 10 Animal RESIST_FIRE Bottom,Middle 80 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
19 MT_BSCAV Plague Eater scav\scav scav\scavbr Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 2 4 4 12 24 Scavenger 1 30 7 1 8 0 0 0 0 0 0 0 0 0 0 20 Animal RESIST_LIGHTNING Bottom,Middle 188 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
20 MT_WSCAV Shadow Beast scav\scav scav\scavbe Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 3 5 6 24 36 Scavenger 2 35 7 3 12 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_FIRE Bottom,Middle 375 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
21 MT_YSCAV Bone Gasher scav\scav scav\scavw Always 128 410 true false 12,8,12,6,20,11 2,1,1,1,1,1 4 6 8 28 40 Scavenger 3 35 7 5 15 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_LIGHTNING Bottom,Middle 552 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
22 MT_WSKELBW Skeleton skelbow\sklbw skelbow\white Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 3 3 2 4 SkeletonRanged 0 15 12 1 2 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 110 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
23 MT_TSKELBW Corpse Bow skelbow\sklbw skelbow\skelt Always 128 567 true false 9,8,16,5,16,16 4,1,1,1,1,1 2 4 5 8 16 SkeletonRanged 1 25 12 1 4 0 0 0 0 0 0 0 0 0 0 0 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 210 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
24 MT_RSKELBW Burning Dead skelbow\sklbw Always 128 567 true false 9,8,16,5,16,16 2,1,1,1,1,1 3 5 7 10 24 SkeletonRanged 2 30 12 1 6 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 364 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
25 MT_XSKELBW Horror skelbow\sklbw skelbow\black Always 128 567 true false 9,8,16,5,16,16 3,1,1,1,1,1 4 6 9 15 45 SkeletonRanged 3 35 12 2 9 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 594 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
26 MT_WSKELSD Skeleton Captain skelsd\sklsr skelsd\white Always 128 575 true true 13,8,12,7,15,16 4,1,1,1,1,1 1 3 2 3 6 SkeletonMelee 0 20 8 2 7 0 0 0 0 0 0 0 0 0 0 10 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 90 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
27 MT_TSKELSD Corpse Captain skelsd\sklsr skelsd\skelt Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 2 4 4 12 20 SkeletonMelee 1 30 8 3 9 0 0 0 0 0 0 0 0 0 0 5 Undead IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle 200 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
28 MT_RSKELSD Burning Dead Captain skelsd\sklsr Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 3 5 6 16 30 SkeletonMelee 2 35 8 4 10 0 0 0 0 0 0 0 0 0 0 15 Undead IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 393 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
29 MT_XSKELSD Horror Captain skelsd\sklsr skelsd\black Always 128 575 true false 13,8,12,7,15,16 4,1,1,1,1,1 4 6 8 35 50 SkeletonMelee SEARCH 3 40 8 5 14 0 0 0 0 0 0 0 0 0 0 30 Undead IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 604 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
30 MT_INVILORD Invisible Lord tsneak\tsneak Never 128 800 false false 13,13,15,11,16,0 2,1,1,1,1,1 19 20 14 278 278 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 65 8 16 30 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2000 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
31 MT_SNEAK Hidden sneak\sneak Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 2 5 5 8 24 Sneak HIDDEN 0 35 8 3 6 0 0 0 0 0 0 0 0 0 0 25 Demon Bottom,Middle 278 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
32 MT_STALKER Stalker sneak\sneak sneak\sneakv2 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 5 7 9 30 45 Sneak HIDDEN,SEARCH 1 40 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Demon Bottom,Middle 630 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
33 MT_UNSEEN Unseen sneak\sneak sneak\sneakv3 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 6 8 11 35 50 Sneak HIDDEN,SEARCH 2 45 8 12 20 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 935 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
34 MT_ILLWEAV Illusion Weaver sneak\sneak sneak\sneakv1 Retail 128 992 true false 16,8,12,8,24,15 2,1,1,1,1,1 8 10 13 40 60 Sneak HIDDEN,SEARCH 3 60 8 16 24 0 0 0 0 0 0 0 0 0 0 30 Demon RESIST_MAGIC,RESIST_FIRE IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 1500 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
35 MT_LRDSAYTR Satyr Lord goatlord\goatl newsfx\satyr Never 160 800 false false 13,13,14,9,16,0 2,1,1,1,1,1 21 22 28 160 200 SkeletonMelee SEARCH 3 90 8 20 30 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 2800 FirstFrame,FirstFrame,FirstFrame,FirstFrame,None,None
36 MT_NGOATMC Flesh Clan goatmace\goat Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 4 6 8 30 45 GoatMelee SEARCH,CAN_OPEN_DOOR 0 50 8 4 10 0 0 0 0 0 0 0 0 0 0 40 Demon Bottom,Middle 460 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
37 MT_BGOATMC Stone Clan goatmace\goat goatmace\beige Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 5 7 10 40 55 GoatMelee SEARCH,CAN_OPEN_DOOR 1 60 8 6 12 0 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 685 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
38 MT_RGOATMC Fire Clan goatmace\goat goatmace\red Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 6 8 12 50 65 GoatMelee SEARCH,CAN_OPEN_DOOR 2 70 8 8 16 0 0 0 0 0 0 0 0 0 0 45 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 906 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
39 MT_GGOATMC Night Clan goatmace\goat goatmace\gray Retail 128 1030 true false 12,8,12,6,20,12 2,1,1,1,1,1 7 9 14 55 70 GoatMelee SEARCH,CAN_OPEN_DOOR 3 80 8 10 20 15 0 30 30 0 0 0 0 0 0 50 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1190 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
40 MT_FIEND Fiend bat\bat bat\red Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 2 3 3 3 6 Bat 0 35 5 1 6 0 0 0 0 0 0 0 0 0 0 0 Animal Middle,Top None 102 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
41 MT_BLINK Blink bat\bat Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 3 5 7 12 28 Bat 1 45 5 1 8 0 0 0 0 0 0 0 0 0 0 15 Animal Middle,Top None 340 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
42 MT_GLOOM Gloom bat\bat bat\grey Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 4 6 9 28 36 Bat SEARCH 2 70 5 4 12 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC RESIST_MAGIC Middle,Top None 509 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
43 MT_FAMILIAR Familiar bat\bat bat\orange Always 96 364 false false 9,13,10,9,13,0 1,1,1,1,1,1 6 8 13 20 35 Bat SEARCH 3 50 5 4 16 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Middle,Top None 448 FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame+15,FirstFrame,None
44 MT_NGOATBW Flesh Clan goatbow\goatb Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 4 6 8 20 35 GoatRanged CAN_OPEN_DOOR 0 35 13 1 7 0 0 0 0 0 0 0 0 0 0 35 Demon Bottom,Middle 448 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
45 MT_BGOATBW Stone Clan goatbow\goatb goatbow\beige Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 5 7 10 30 40 GoatRanged CAN_OPEN_DOOR 1 40 13 2 9 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 645 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
46 MT_RGOATBW Fire Clan goatbow\goatb goatbow\red Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 6 8 12 40 50 GoatRanged SEARCH,CAN_OPEN_DOOR 2 45 13 3 11 0 0 0 0 0 0 0 0 0 0 35 Demon RESIST_FIRE IMMUNE_FIRE Bottom,Middle 822 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
47 MT_GGOATBW Night Clan goatbow\goatb goatbow\gray Retail 128 1040 false false 12,8,16,6,20,0 3,1,1,1,1,1 7 9 14 50 65 GoatRanged SEARCH,CAN_OPEN_DOOR 3 50 13 4 13 15 0 0 0 0 0 0 0 0 0 40 Demon RESIST_MAGIC IMMUNE_MAGIC Bottom,Middle 1092 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
48 MT_NACID Acid Beast acid\acid Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 6 8 11 40 66 Acid 0 40 8 4 12 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 846 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
49 MT_RACID Poison Spitter acid\acid acid\acidblk Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 8 10 15 60 85 Acid 1 45 8 4 16 25 8 0 0 0 0 0 0 0 0 30 Animal IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_ACID Bottom,Middle 1248 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
50 MT_BACID Pit Beast acid\acid acid\acidb Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 10 12 21 80 110 Acid 2 55 8 8 18 35 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_ACID IMMUNE_MAGIC,RESIST_LIGHTNING,IMMUNE_ACID Bottom,Middle 2060 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
51 MT_XACID Lava Maw acid\acid acid\acidr Retail 128 716 true true 13,8,12,8,16,12 1,1,1,1,1,1 12 14 25 100 150 Acid 3 65 8 10 20 40 8 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_ACID IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_ACID Bottom,Middle 2940 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
52 MT_SKING Skeleton King sking\sking skelaxe\white Never 160 1010 true true 8,6,16,6,16,6 2,1,1,1,1,2 4 4 9 140 140 SkeletonKing SEARCH,CAN_OPEN_DOOR 3 60 8 6 16 0 0 0 0 0 0 0 0 0 0 70 Undead IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top Uniq(SKCROWN) 570 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
53 MT_CLEAVER The Butcher fatc\fatc Never 128 980 false false 10,8,12,6,16,0 1,1,1,1,1,1 1 1 1 320 320 Butcher 3 50 8 6 12 0 0 0 0 0 0 0 0 0 0 50 Demon RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle Uniq(CLEAVER) 710 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
54 MT_FAT Overlord fat\fat Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 5 7 10 60 80 Fat 0 55 8 6 12 0 0 0 0 0 0 0 0 0 0 55 Demon RESIST_FIRE Bottom,Middle 635 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
55 MT_MUDMAN Mud Man fat\fat fat\blue Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 7 9 14 100 125 Fat SEARCH 1 60 8 8 16 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_LIGHTNING Bottom,Middle 1165 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
56 MT_TOAD Toad Demon fat\fat fat\fatb Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 8 10 16 135 160 Fat SEARCH 2 70 8 8 16 40 0 8 20 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 1380 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
57 MT_FLAYED Flayed One fat\fat fat\fatf Retail 128 1130 true false 8,10,15,6,16,10 4,1,1,1,1,1 10 12 20 160 200 Fat SEARCH 3 85 8 10 20 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2058 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
58 MT_WYRM Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 5 7 11 60 90 SkeletonMelee 0 40 8 4 10 0 0 0 0 0 0 0 0 0 0 25 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 660
59 MT_CAVSLUG Cave Slug worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 6 8 13 75 110 SkeletonMelee 1 50 8 6 13 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC RESIST_MAGIC Bottom,Middle 994
60 MT_DVLWYRM Devil Wyrm worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 7 9 15 100 140 SkeletonMelee 2 55 8 8 16 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1320
61 MT_DEVOUR Devourer worm\worm Never 160 2420 false false 13,13,13,11,19,0 1,1,1,1,1,1 8 10 17 125 200 SkeletonMelee 3 60 8 10 20 0 0 0 0 0 0 0 0 0 0 35 Animal RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,RESIST_FIRE Bottom,Middle 1827
62 MT_NMAGMA Magma Demon magma\magma Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 9 13 50 70 Magma SEARCH,CAN_OPEN_DOOR 0 45 4 2 10 50 13 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1076 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
63 MT_YMAGMA Blood Stone magma\magma magma\yellow Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 8 10 14 55 75 Magma SEARCH,CAN_OPEN_DOOR 1 50 4 2 12 50 14 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1309 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
64 MT_BMAGMA Hell Stone magma\magma magma\blue Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 16 60 80 Magma SEARCH,CAN_OPEN_DOOR 2 60 4 2 20 60 14 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 1680 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
65 MT_WMAGMA Lava Lord magma\magma magma\wierd Retail 128 1680 true true 8,10,14,7,18,18 2,1,1,1,1,1 9 11 18 70 85 Magma SEARCH,CAN_OPEN_DOOR 3 75 4 4 24 60 14 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2124 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
66 MT_HORNED Horned Demon rhino\rhino Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 7 9 13 40 80 Rhino SEARCH,CAN_OPEN_DOOR 0 60 7 2 16 100 0 5 32 0 0 0 0 0 0 40 Animal RESIST_FIRE Bottom,Middle,Top 1172 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
67 MT_MUDRUN Mud Runner rhino\rhino rhino\orange Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 8 10 15 50 90 Rhino SEARCH,CAN_OPEN_DOOR 1 70 7 6 18 100 0 12 36 0 0 0 0 0 0 45 Animal RESIST_FIRE Bottom,Middle,Top 1404 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
68 MT_FROSTC Frost Charger rhino\rhino rhino\blue Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 9 11 17 60 100 Rhino SEARCH,CAN_OPEN_DOOR 2 80 7 8 20 100 0 20 40 0 0 0 0 0 0 50 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 1720 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
69 MT_OBLORD Obsidian Lord rhino\rhino rhino\rhinob Retail 160 1630 true true 8,8,14,6,16,6 2,1,1,1,1,1 10 12 19 70 110 Rhino SEARCH,CAN_OPEN_DOOR 3 90 7 10 22 100 0 20 50 0 0 0 0 0 0 55 Animal IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 1809 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
70 MT_BONEDMN oldboned demskel\demskl Never 128 1740 true true 10,8,20,6,24,16 3,1,1,1,1,1 24 24 12 70 70 Storm 0 60 8 6 14 12 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 1344 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
71 MT_REDDTH Red Death thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 8 10 16 96 96 Storm 1 75 5 10 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2168 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
72 MT_LTCHDMN Litch Demon thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 110 110 Storm 2 80 5 10 24 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2736 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
73 MT_UDEDBLRG Undead Balrog thin\thin thin\thinv3 Never 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 130 130 Storm 3 85 5 12 30 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3575 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
74 MT_INCIN Incinerator fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 21 22 16 30 45 FireMan 0 75 8 8 16 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 1888 None,None,None,None,None,None
75 MT_FLAMLRD Flame Lord fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 22 23 18 40 55 FireMan 1 75 8 10 20 0 0 0 0 0 0 0 0 0 0 25 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle 2250 None,None,None,None,None,None
76 MT_DOOMFIRE Doom Fire fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 23 24 20 50 65 FireMan 2 80 8 12 24 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 2740 None,None,None,None,None,None
77 MT_HELLBURN Hell Burner fireman\firem Never 128 1460 true false 14,19,20,8,14,23 1,1,1,1,1,1 24 24 22 60 80 FireMan 3 85 8 15 30 0 0 0 0 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 3355 None,None,None,None,None,None
78 MT_STORM Red Storm thin\thin thin\thinv3 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 9 11 18 55 110 Storm SEARCH,CAN_OPEN_DOOR 0 80 5 8 18 75 8 4 16 0 0 0 0 0 0 30 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2160 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
79 MT_RSTORM Storm Rider thin\thin Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 10 12 20 60 120 Storm SEARCH,CAN_OPEN_DOOR 1 80 5 8 18 80 8 4 16 0 0 0 0 0 0 30 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2391 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
80 MT_STORML Storm Lord thin\thin thin\thinv2 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 11 13 22 75 135 Storm SEARCH,CAN_OPEN_DOOR 2 85 5 12 24 75 8 4 16 0 0 0 0 0 0 35 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2775 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
81 MT_MAEL Maelstrom thin\thin thin\thinv1 Retail 160 1740 true true 8,8,18,4,17,14 3,1,1,1,1,1 12 14 24 90 150 Storm SEARCH,CAN_OPEN_DOOR 3 90 5 12 28 75 8 4 16 0 0 0 0 0 0 40 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3177 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
82 MT_BIGFALL Devil Kin Brute bigfall\fallg newsfx\kbrute Never 128 800 true false 10,8,11,8,17,0 1,1,1,1,2,2 21 22 27 120 160 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 100 6 18 24 0 0 0 0 0 0 0 0 0 0 70 Animal RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 2400 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
83 MT_WINGED Winged-Demon gargoyle\gargo Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 5 7 9 45 60 Gargoyle CAN_OPEN_DOOR 0 50 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Middle,Top 662 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
84 MT_GARGOYLE Gargoyle gargoyle\gargo gargoyle\gare Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,2 7 9 13 60 90 Gargoyle CAN_OPEN_DOOR 1 65 7 10 16 0 0 0 0 0 0 0 0 0 0 45 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_LIGHTNING Middle,Top 1205 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
85 MT_BLOODCLW Blood Claw gargoyle\gargo gargoyle\gargbr Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 9 11 19 75 125 Gargoyle CAN_OPEN_DOOR 2 80 7 14 22 0 0 0 0 0 0 0 0 0 0 50 Demon IMMUNE_MAGIC,IMMUNE_FIRE IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Middle,Top 1873 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
86 MT_DEATHW Death Wing gargoyle\gargo gargoyle\gargb Retail 160 1650 true false 14,14,14,10,18,14 1,1,1,1,1,1 10 12 23 90 150 Gargoyle CAN_OPEN_DOOR 3 95 7 16 28 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Middle,Top 2278 FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,FirstFrame+11,EachFrame
87 MT_MEGA Slayer mega\mega Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 10 12 20 120 140 Mega SEARCH,CAN_OPEN_DOOR 0 100 8 12 20 0 3 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2300 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
88 MT_GUARD Guardian mega\mega mega\guard Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 11 13 22 140 160 Mega SEARCH,CAN_OPEN_DOOR 1 110 8 14 22 0 3 0 0 0 0 0 0 0 0 65 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 2714 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
89 MT_VTEXLRD Vortex Lord mega\mega mega\vtexl Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 12 14 24 160 180 Mega SEARCH,CAN_OPEN_DOOR 2 120 8 18 24 0 3 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3252 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
90 MT_BALROG Balrog mega\mega mega\balr Retail 160 2220 true true 6,7,14,1,24,5 3,1,1,1,2,1 13 15 26 180 200 Mega SEARCH,CAN_OPEN_DOOR 3 130 8 22 30 0 3 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3643 EachFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame,EachFrame
91 MT_NSNAKE Cave Viper snake\snake Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 11 13 21 100 150 Snake SEARCH 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 60 Demon IMMUNE_MAGIC IMMUNE_MAGIC Bottom,Middle,Top 2725 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
92 MT_RSNAKE Fire Drake snake\snake snake\snakr Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 12 14 23 120 170 Snake SEARCH 1 105 8 12 24 0 0 0 0 0 0 0 0 0 0 65 Demon IMMUNE_MAGIC,RESIST_FIRE IMMUNE_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3139 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
93 MT_BSNAKE Gold Viper snake\snake snake\snakg Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 13 14 25 140 180 Snake SEARCH 2 120 8 15 26 0 0 0 0 0 0 0 0 0 0 70 Demon IMMUNE_MAGIC,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle,Top 3540 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
94 MT_GSNAKE Azure Drake snake\snake snake\snakb Retail 160 1270 false false 12,11,13,5,18,0 2,1,1,1,1,1 15 16 27 160 200 Snake SEARCH 3 130 8 18 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 3791 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,None
95 MT_NBLACK Black Knight black\black Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 12 14 24 150 150 SkeletonMelee SEARCH 0 110 8 15 20 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 3360 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
96 MT_RTBLACK Doom Guard black\black black\blkkntrt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 15 26 165 165 SkeletonMelee SEARCH 0 130 8 18 25 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,RESIST_FIRE RESIST_MAGIC,IMMUNE_FIRE Bottom,Middle,Top 3650 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
97 MT_BTBLACK Steel Lord black\black black\blkkntbt Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 14 16 28 180 180 SkeletonMelee SEARCH 1 120 8 20 30 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4252 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
98 MT_RBLACK Blood Knight black\black black\blkkntbe Retail 160 2120 false false 8,8,16,4,24,0 2,1,1,1,1,1 13 14 30 200 200 SkeletonMelee SEARCH 1 130 8 25 35 0 0 0 0 0 0 0 0 0 0 85 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5130 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
99 MT_UNRAV The Shredded unrav\unrav newsfx\shred Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 17 18 23 70 90 SkeletonMelee 0 75 7 4 12 0 0 0 0 0 0 0 0 0 0 65 Undead RESIST_FIRE,RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 900 None,EachFrame,EachFrame,None,None,None
100 MT_HOLOWONE Hollow One unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 18 19 27 135 240 SkeletonMelee 1 75 7 12 24 0 0 0 0 0 0 0 0 0 0 75 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4374 None,EachFrame,EachFrame,None,None,None
101 MT_PAINMSTR Pain Master unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 19 20 29 110 200 SkeletonMelee 2 80 7 16 30 0 0 0 0 0 0 0 0 0 0 80 Undead IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 5147 None,EachFrame,EachFrame,None,None,None
102 MT_REALWEAV Reality Weaver unrav\unrav acid\acid Never 96 484 false false 10,10,12,5,16,0 1,1,1,1,1,1 20 20 30 135 240 SkeletonMelee 3 85 7 20 35 0 0 0 0 0 0 0 0 0 0 85 Undead RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 5925 None,EachFrame,EachFrame,None,None,None
103 MT_SUCCUBUS Succubus succ\scbs Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 12 14 24 120 150 Succubus CAN_OPEN_DOOR 0 100 10 1 20 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_MAGIC IMMUNE_MAGIC,RESIST_FIRE Bottom,Middle 3696 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
104 MT_SNOWWICH Snow Witch succ\scbs succ\succb Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 13 15 26 135 175 Succubus CAN_OPEN_DOOR 1 110 10 1 24 0 0 0 0 0 0 0 0 0 0 65 Demon RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_LIGHTNING Bottom,Middle 4084 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
105 MT_HLSPWN Hell Spawn succ\scbs succ\succrw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 14 16 28 150 200 Succubus SEARCH,CAN_OPEN_DOOR 2 115 10 1 30 0 0 0 0 0 0 0 0 0 0 75 Demon RESIST_MAGIC,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 4480 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
106 MT_SOLBRNR Soul Burner succ\scbs succ\succbw Retail 128 980 false false 14,8,16,7,24,0 1,1,1,1,1,1 15 16 30 140 225 Succubus SEARCH,CAN_OPEN_DOOR 3 120 10 1 35 0 0 0 0 0 0 0 0 0 0 85 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 4644 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
107 MT_COUNSLR Counselor mage\mage Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 13 14 25 70 70 Counselor CAN_OPEN_DOOR 0 90 8 8 20 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4070 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
108 MT_MAGISTR Magistrate mage\mage mage\cnselg Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 14 15 27 85 85 Counselor CAN_OPEN_DOOR 1 100 8 10 24 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 4478 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
109 MT_CABALIST Cabalist mage\mage mage\cnselgd Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 15 16 29 120 120 Counselor CAN_OPEN_DOOR 2 110 8 14 30 0 0 0 0 0 0 0 0 0 0 0 Demon RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4929 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
110 MT_ADVOCATE Advocate mage\mage mage\cnselbk Retail 128 2000 true false 12,1,20,8,28,20 1,1,1,1,1,1 16 16 30 145 145 Counselor CAN_OPEN_DOOR 3 120 8 15 25 0 0 0 0 0 0 0 0 0 0 0 Demon IMMUNE_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968 FirstFrame,FirstFrame,EachFrame,FirstFrame,FirstFrame,FirstFrame
111 MT_GOLEM Golem golem\golem golem\golm Never 96 386 true false 0,16,12,0,12,20 1,1,1,1,1,1 1 1 12 1 1 Golem CAN_OPEN_DOOR 0 0 7 1 1 0 0 0 0 0 0 0 0 0 0 1 Demon 0 None,EachFrame,EachFrame,None,EachFrame,EachFrame
112 MT_DIABLO The Dark Lord diablo\diablo Never 160 2000 true true 16,6,16,6,16,16 1,1,1,1,1,1 26 26 30 1666 1666 Diablo KNOCKBACK,SEARCH,CAN_OPEN_DOOR 3 220 4 30 60 0 11 0 0 0 0 0 0 0 0 90 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 31666 FirstFrame,FirstFrame,EachFrame,FirstFrame,EachFrame,EachFrame
113 MT_DARKMAGE The Arch-Litch Malignus darkmage\dmage darkmage\dmag Never 128 1060 true false 6,1,21,6,23,18 1,1,1,1,1,1 21 21 30 160 160 Counselor CAN_OPEN_DOOR 3 120 8 20 40 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 4968 FirstFrame,None,FirstFrame,FirstFrame,FirstFrame,FirstFrame
114 MT_HELLBOAR Hellboar fork\fork newsfx\hboar Retail 188 800 false false 10,10,15,6,16,0 2,1,1,1,1,1 17 18 23 80 100 SkeletonMelee KNOCKBACK,SEARCH 2 70 7 16 24 0 0 0 0 0 0 0 0 0 0 60 Demon RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 750 EachFrame,EachFrame,EachFrame,EachFrame,None,None
115 MT_STINGER Stinger scorp\scorp newsfx\stingr Retail 64 305 false false 10,10,12,6,15,0 2,1,1,1,1,1 17 18 22 30 40 SkeletonMelee 3 85 8 1 20 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_LIGHTNING Bottom 500 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
116 MT_PSYCHORB Psychorb eye\eye newsfx\psyco Retail 156 800 false false 12,13,13,7,21,0 2,1,1,1,1,1 17 18 22 20 30 Psychorb 3 80 8 10 10 0 0 0 0 0 0 0 0 0 0 40 Animal RESIST_FIRE Middle,Top 450 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
117 MT_ARACHNON Arachnon spider\spider newsfx\slord Retail 148 800 false false 12,10,15,6,20,0 2,1,1,1,1,1 17 18 22 60 80 SkeletonMelee SEARCH 3 50 8 5 15 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_LIGHTNING Bottom,Middle,Top 500 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
118 MT_FELLTWIN Felltwin tsneak\tsneak newsfx\ftwin Retail 128 800 false false 13,13,15,11,16,0 2,1,1,1,1,1 17 18 22 50 70 SkeletonMelee SEARCH,CAN_OPEN_DOOR 3 70 8 10 18 0 0 0 0 0 0 0 0 0 0 50 Demon RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 600 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,None
119 MT_HORKSPWN Hork Spawn spawn\spawn newsfx\hspawn Retail 164 520 false true 15,12,14,11,14,0 1,1,1,1,1,1 18 19 22 30 30 SkeletonMelee 3 60 8 10 25 0 0 0 0 0 0 0 0 0 0 25 Demon RESIST_MAGIC RESIST_MAGIC Bottom,Middle 250 EachFrame,EachFrame,EachFrame,EachFrame,None,None
120 MT_VENMTAIL Venomtail wscorp\wscorp newsfx\stingr Retail 86 305 false false 10,10,12,6,15,0 2,1,1,1,1,1 19 20 24 40 50 SkeletonMelee 3 85 8 1 30 0 0 0 0 0 0 0 0 0 0 60 Animal RESIST_LIGHTNING IMMUNE_LIGHTNING Bottom 1000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
121 MT_NECRMORB Necromorb eye2\eye2 newsfx\psyco Retail 140 800 false false 12,13,13,7,21,0 2,1,1,1,1,1 19 20 24 30 40 Necromorb 3 80 8 20 20 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_FIRE IMMUNE_FIRE,RESIST_LIGHTNING Middle,Top 1100 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
122 MT_SPIDLORD Spider Lord bspidr\bspidr newsfx\slord Retail 148 800 true true 12,10,15,6,20,10 2,1,1,1,1,1 19 20 24 80 100 Acid SEARCH 3 60 8 8 20 75 8 10 10 0 0 0 0 0 0 60 Animal RESIST_LIGHTNING RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 1250 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,EachFrame
123 MT_LASHWORM Lashworm clasp\clasp newsfx\lworm Retail 176 800 false false 10,12,15,6,16,0 1,1,1,1,1,1 19 20 20 30 30 SkeletonMelee 3 90 8 12 20 0 0 0 0 0 0 0 0 0 0 50 Animal RESIST_FIRE Bottom,Middle 600 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
124 MT_TORCHANT Torchant antworm\worm newsfx\tchant Retail 192 800 false false 14,12,12,6,20,0 2,1,1,1,1,1 19 20 22 60 80 Torchant 3 75 8 20 30 0 0 0 0 0 0 0 0 0 0 70 Animal IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 1250 EachFrame,EachFrame,EachFrame,EachFrame,None,None
125 MT_HORKDMN Hork Demon horkd\horkd newsfx\hdemon Never 138 800 true true 15,8,16,6,16,9 2,1,1,1,1,2 19 19 27 120 160 SkeletonMelee 3 60 8 20 35 80 8 0 0 0 0 0 0 0 0 80 Demon RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_LIGHTNING Bottom,Middle,Top 2000 EachFrame,EachFrame,EachFrame,EachFrame,None,EachFrame
126 MT_DEFILER Hell Bug hellbug\hellbg newsfx\defile Never 198 800 true true 8,8,14,6,14,12 1,1,1,1,1,1 20 20 30 240 240 SkeletonMelee SEARCH 3 110 8 20 30 90 8 50 60 0 0 0 0 0 0 80 Demon RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5000 EachFrame,EachFrame,EachFrame,EachFrame,None,EachFrame
127 MT_GRAVEDIG Gravedigger gravdg\gravdg newsfx\gdiggr Retail 124 800 true true 24,24,12,6,16,16 2,1,1,1,1,1 21 21 26 120 240 Scavenger CAN_OPEN_DOOR 3 80 6 2 12 0 0 0 0 0 0 0 0 0 0 20 Undead IMMUNE_LIGHTNING RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle 2000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,EachFrame
128 MT_TOMBRAT Tomb Rat rat\rat newsfx\tmbrat Retail 104 550 false false 11,8,12,6,20,0 2,1,1,1,1,1 21 22 24 80 120 SkeletonMelee 3 120 8 12 25 0 0 0 0 0 0 0 0 0 0 30 Animal RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 1800 EachFrame,EachFrame,EachFrame,EachFrame,None,None
129 MT_FIREBAT Firebat hellbat\helbat newsfx\helbat Retail 96 550 false false 18,16,14,6,18,11 2,1,1,1,1,1 21 22 24 60 80 FireBat 3 100 8 15 20 0 0 0 0 0 0 0 0 0 0 70 Animal IMMUNE_FIRE RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 2400 EachFrame,EachFrame,EachFrame,EachFrame,None,EachFrame
130 MT_SKLWING Skullwing demskel\demskl newsfx\swing skelaxe\skelt Retail 128 1740 true false 10,8,20,6,24,16 3,1,1,1,1,1 21 22 27 70 70 SkeletonMelee 0 75 7 15 20 75 9 15 20 0 0 0 0 0 0 80 Undead RESIST_FIRE,RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle,Top 3000 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
131 MT_LICH Lich lich\lich newsfx\lich Retail 96 800 false true 12,10,10,7,21,0 2,1,1,1,2,1 21 22 25 80 100 Lich 3 100 8 15 20 0 0 0 0 0 0 0 0 0 0 60 Undead RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING Bottom,Middle 3000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
132 MT_CRYPTDMN Crypt Demon bubba\bubba newsfx\crypt Retail 154 800 false true 8,18,12,8,21,0 3,1,1,1,1,1 22 23 28 200 240 SkeletonMelee 3 100 8 20 40 0 0 0 0 0 0 0 0 0 0 85 Demon IMMUNE_MAGIC,RESIST_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING Bottom,Middle 3200 EachFrame,EachFrame,EachFrame,EachFrame,None,None
133 MT_HELLBAT Hellbat hellbat2\bhelbt newsfx\helbat Retail 96 550 true false 18,16,14,6,18,11 2,1,1,1,1,1 23 24 29 100 140 Torchant 3 110 8 30 30 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING RESIST_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 3600 EachFrame,EachFrame,EachFrame,EachFrame,None,EachFrame
134 MT_BONEDEMN Bone Demon demskel\demskl newsfx\swing Retail 128 1740 true true 10,8,20,6,24,16 3,1,1,1,1,1 23 24 30 240 280 BoneDemon 0 100 8 40 50 160 12 50 50 0 0 0 0 0 0 50 Undead IMMUNE_FIRE,IMMUNE_LIGHTNING IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 5000 FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame,FirstFrame
135 MT_ARCHLICH Arch Lich lich2\lich2 newsfx\lich Retail 136 800 false true 12,10,10,7,21,0 2,1,1,1,2,1 23 24 30 180 200 ArchLich 3 120 8 30 30 0 0 0 0 0 0 0 0 0 0 75 Undead RESIST_MAGIC,RESIST_FIRE,IMMUNE_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 4000 EachFrame,EachFrame,EachFrame,EachFrame,None,None
136 MT_BICLOPS Biclops byclps\byclps newsfx\biclop Retail 180 800 false false 10,11,16,6,16,0 2,1,1,1,2,1 23 24 30 200 240 SkeletonMelee KNOCKBACK,CAN_OPEN_DOOR 3 90 8 40 50 0 0 0 0 0 0 0 0 0 0 80 Demon RESIST_LIGHTNING RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 4000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
137 MT_FLESTHNG Flesh Thing flesh\flesh newsfx\flesht Retail 164 800 false true 15,24,15,6,16,0 1,1,1,1,1,1 23 24 28 300 400 SkeletonMelee 3 150 8 12 18 0 0 0 0 0 0 0 0 0 0 70 Demon RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING RESIST_MAGIC,RESIST_FIRE,RESIST_LIGHTNING Bottom,Middle 4000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame,None
138 MT_REAPER Reaper reaper\reap newsfx\reaper Retail 180 800 false false 12,10,14,6,16,0 2,1,1,1,1,1 23 24 30 260 300 SkeletonMelee 3 120 8 30 35 0 0 0 0 0 0 0 0 0 0 90 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle 6000 EachFrame,EachFrame,EachFrame,EachFrame,EachFrame|Unexplained,None
139 MT_NAKRUL Na-Krul nkr\nkr newsfx\nakrul Never 226 1200 true true 2,6,16,3,16,16 1,1,1,1,1,1 31 31 40 1332 1332 SkeletonMelee KNOCKBACK,SEARCH,CAN_OPEN_DOOR 3 150 7 40 50 150 10 40 50 0 0 0 0 0 0 125 Demon IMMUNE_MAGIC,IMMUNE_FIRE,RESIST_LIGHTNING IMMUNE_MAGIC,IMMUNE_FIRE,IMMUNE_LIGHTNING Bottom,Middle,Top 13333 FirstFrame,EachFrame,EachFrame|Unexplained,EachFrame,EachFrame|Unexplained,EachFrame|Unexplained
+13 -13
View File
@@ -1,16 +1,16 @@
type name position_x position_y direction animWidth animPath animFrames animDelay gossipTexts animOrder
TOWN_SMITH Griswold the Blacksmith 62 63 SouthWest 96 towners\smith\smithn 16 3 TEXT_GRISWOLD2,TEXT_GRISWOLD3,TEXT_GRISWOLD4,TEXT_GRISWOLD5,TEXT_GRISWOLD6,TEXT_GRISWOLD7,TEXT_GRISWOLD8,TEXT_GRISWOLD9,TEXT_GRISWOLD10,TEXT_GRISWOLD12,TEXT_GRISWOLD13 4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3
TOWN_HEALER Pepin the Healer 55 79 SouthEast 96 towners\healer\healer 20 6 TEXT_PEPIN2,TEXT_PEPIN3,TEXT_PEPIN4,TEXT_PEPIN5,TEXT_PEPIN6,TEXT_PEPIN7,TEXT_PEPIN9,TEXT_PEPIN10,TEXT_PEPIN11 0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,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,4,5,6,7,8,9,10,11,12,13,14,15,14,13,12,11,10,9,8,7,6,5,4,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19
TOWN_DEADGUY Wounded Townsman 24 32 North 96 towners\butch\deadguy 8 6
TOWN_TAVERN Ogden the Tavern owner 55 62 SouthWest 96 towners\twnf\twnfn 16 3 TEXT_OGDEN2,TEXT_OGDEN3,TEXT_OGDEN4,TEXT_OGDEN5,TEXT_OGDEN6,TEXT_OGDEN8,TEXT_OGDEN9,TEXT_OGDEN10 0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,1,0,15,14,13,13,14,15,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
TOWN_STORY Cain the Elder 62 71 South 96 towners\strytell\strytell 25 3 TEXT_STORY2,TEXT_STORY3,TEXT_STORY4,TEXT_STORY5,TEXT_STORY6,TEXT_STORY7,TEXT_STORY9,TEXT_STORY10,TEXT_STORY11 0,0,24,24,23,22,21,20,19,18,17,16,15,14,15,16,17,18,19,20,21,22,23,24,24,24,0,0,0,24,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
TOWN_DRUNK Farnham the Drunk 71 84 South 96 towners\drunk\twndrunk 18 3 TEXT_FARNHAM2,TEXT_FARNHAM3,TEXT_FARNHAM4,TEXT_FARNHAM5,TEXT_FARNHAM6,TEXT_FARNHAM8,TEXT_FARNHAM9,TEXT_FARNHAM10,TEXT_FARNHAM11,TEXT_FARNHAM12,TEXT_FARNHAM13 0,0,0,1,2,3,4,5,6,7,8,9,10,10,10,10,11,12,13,14,15,16,17,17,0,0,0,17,16,15,14,13,12,11,10,9,10,11,12,13,14,15,16,17,0,1,2,3,4,4,4,3,2,1
TOWN_WITCH Adria the Witch 80 20 South 96 towners\townwmn1\witch 19 6 TEXT_ADRIA2,TEXT_ADRIA3,TEXT_ADRIA4,TEXT_ADRIA5,TEXT_ADRIA6,TEXT_ADRIA7,TEXT_ADRIA8,TEXT_ADRIA9,TEXT_ADRIA10,TEXT_ADRIA12,TEXT_ADRIA13 3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,2,1,0,18,17,18,0,1,0,18,17,18,0,1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,14,13,12,12,12,12,13,14,14,14,13,12,11,11,11,10,9,9,9,8,7,8,9,9,10,11,12,13,14,15,16,17,18,0,1,0,18,17,18,0,1,0,1,2
TOWN_BMAID Gillian the Barmaid 43 66 South 96 towners\townwmn1\wmnn 18 6 TEXT_GILLIAN2,TEXT_GILLIAN3,TEXT_GILLIAN4,TEXT_GILLIAN5,TEXT_GILLIAN6,TEXT_GILLIAN7,TEXT_GILLIAN9,TEXT_GILLIAN10
TOWN_PEGBOY Wirt the Peg-legged boy 11 53 South 96 towners\townboy\pegkid1 20 6 TEXT_WIRT2,TEXT_WIRT3,TEXT_WIRT4,TEXT_WIRT5,TEXT_WIRT6,TEXT_WIRT7,TEXT_WIRT8,TEXT_WIRT9,TEXT_WIRT11,TEXT_WIRT12
type name position_x position_y direction animWidth animPath animFrames animDelay gossipTexts animOrder shadowRule
TOWN_SMITH Griswold the Blacksmith 62 63 SouthWest 96 towners\smith\smithn 16 3 TEXT_GRISWOLD2,TEXT_GRISWOLD3,TEXT_GRISWOLD4,TEXT_GRISWOLD5,TEXT_GRISWOLD6,TEXT_GRISWOLD7,TEXT_GRISWOLD8,TEXT_GRISWOLD9,TEXT_GRISWOLD10,TEXT_GRISWOLD12,TEXT_GRISWOLD13 4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3 FirstFrame
TOWN_HEALER Pepin the Healer 55 79 SouthEast 96 towners\healer\healer 20 6 TEXT_PEPIN2,TEXT_PEPIN3,TEXT_PEPIN4,TEXT_PEPIN5,TEXT_PEPIN6,TEXT_PEPIN7,TEXT_PEPIN9,TEXT_PEPIN10,TEXT_PEPIN11 0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,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,4,5,6,7,8,9,10,11,12,13,14,15,14,13,12,11,10,9,8,7,6,5,4,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 FirstFrame
TOWN_DEADGUY Wounded Townsman 24 32 North 96 towners\butch\deadguy 8 6 None
TOWN_TAVERN Ogden the Tavern owner 55 62 SouthWest 96 towners\twnf\twnfn 16 3 TEXT_OGDEN2,TEXT_OGDEN3,TEXT_OGDEN4,TEXT_OGDEN5,TEXT_OGDEN6,TEXT_OGDEN8,TEXT_OGDEN9,TEXT_OGDEN10 0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,1,0,15,14,13,13,14,15,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 FirstFrame
TOWN_STORY Cain the Elder 62 71 South 96 towners\strytell\strytell 25 3 TEXT_STORY2,TEXT_STORY3,TEXT_STORY4,TEXT_STORY5,TEXT_STORY6,TEXT_STORY7,TEXT_STORY9,TEXT_STORY10,TEXT_STORY11 0,0,24,24,23,22,21,20,19,18,17,16,15,14,15,16,17,18,19,20,21,22,23,24,24,24,0,0,0,24,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 FirstFrame
TOWN_DRUNK Farnham the Drunk 71 84 South 96 towners\drunk\twndrunk 18 3 TEXT_FARNHAM2,TEXT_FARNHAM3,TEXT_FARNHAM4,TEXT_FARNHAM5,TEXT_FARNHAM6,TEXT_FARNHAM8,TEXT_FARNHAM9,TEXT_FARNHAM10,TEXT_FARNHAM11,TEXT_FARNHAM12,TEXT_FARNHAM13 0,0,0,1,2,3,4,5,6,7,8,9,10,10,10,10,11,12,13,14,15,16,17,17,0,0,0,17,16,15,14,13,12,11,10,9,10,11,12,13,14,15,16,17,0,1,2,3,4,4,4,3,2,1 FirstFrame
TOWN_WITCH Adria the Witch 80 20 South 96 towners\townwmn1\witch 19 6 TEXT_ADRIA2,TEXT_ADRIA3,TEXT_ADRIA4,TEXT_ADRIA5,TEXT_ADRIA6,TEXT_ADRIA7,TEXT_ADRIA8,TEXT_ADRIA9,TEXT_ADRIA10,TEXT_ADRIA12,TEXT_ADRIA13 3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,2,1,0,18,17,18,0,1,0,18,17,18,0,1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,14,13,12,12,12,12,13,14,14,14,13,12,11,11,11,10,9,9,9,8,7,8,9,9,10,11,12,13,14,15,16,17,18,0,1,0,18,17,18,0,1,0,1,2 FirstFrame
TOWN_BMAID Gillian the Barmaid 43 66 South 96 towners\townwmn1\wmnn 18 6 TEXT_GILLIAN2,TEXT_GILLIAN3,TEXT_GILLIAN4,TEXT_GILLIAN5,TEXT_GILLIAN6,TEXT_GILLIAN7,TEXT_GILLIAN9,TEXT_GILLIAN10 FirstFrame
TOWN_PEGBOY Wirt the Peg-legged boy 11 53 South 96 towners\townboy\pegkid1 20 6 TEXT_WIRT2,TEXT_WIRT3,TEXT_WIRT4,TEXT_WIRT5,TEXT_WIRT6,TEXT_WIRT7,TEXT_WIRT8,TEXT_WIRT9,TEXT_WIRT11,TEXT_WIRT12 FirstFrame|Stray
TOWN_COW Cow 58 16 SouthWest 128 12 3
TOWN_COW Cow 56 14 NorthWest 128 12 3
TOWN_COW Cow 59 20 North 128 12 3
TOWN_COWFARM Complete Nut 61 22 SouthWest 96 towners\farmer\cfrmrn2 15 3
TOWN_FARMER Lester the farmer 62 16 South 96 towners\farmer\farmrn2 15 3
TOWN_GIRL Celia 77 43 South 96 towners\girl\girlw1 20 6
TOWN_COWFARM Complete Nut 61 22 SouthWest 96 towners\farmer\cfrmrn2 15 3 Baked
TOWN_FARMER Lester the farmer 62 16 South 96 towners\farmer\farmrn2 15 3 FirstFrame
TOWN_GIRL Celia 77 43 South 96 towners\girl\girlw1 20 6 FirstFrame
1 type name position_x position_y direction animWidth animPath animFrames animDelay gossipTexts animOrder shadowRule
2 TOWN_SMITH Griswold the Blacksmith 62 63 SouthWest 96 towners\smith\smithn 16 3 TEXT_GRISWOLD2,TEXT_GRISWOLD3,TEXT_GRISWOLD4,TEXT_GRISWOLD5,TEXT_GRISWOLD6,TEXT_GRISWOLD7,TEXT_GRISWOLD8,TEXT_GRISWOLD9,TEXT_GRISWOLD10,TEXT_GRISWOLD12,TEXT_GRISWOLD13 4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,13,12,11,10,9,8,7,6,5,4,4,5,6,7,8,9,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3 FirstFrame
3 TOWN_HEALER Pepin the Healer 55 79 SouthEast 96 towners\healer\healer 20 6 TEXT_PEPIN2,TEXT_PEPIN3,TEXT_PEPIN4,TEXT_PEPIN5,TEXT_PEPIN6,TEXT_PEPIN7,TEXT_PEPIN9,TEXT_PEPIN10,TEXT_PEPIN11 0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,1,2,2,1,0,19,18,18,19,0,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,4,5,6,7,8,9,10,11,12,13,14,15,14,13,12,11,10,9,8,7,6,5,4,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 FirstFrame
4 TOWN_DEADGUY Wounded Townsman 24 32 North 96 towners\butch\deadguy 8 6 None
5 TOWN_TAVERN Ogden the Tavern owner 55 62 SouthWest 96 towners\twnf\twnfn 16 3 TEXT_OGDEN2,TEXT_OGDEN3,TEXT_OGDEN4,TEXT_OGDEN5,TEXT_OGDEN6,TEXT_OGDEN8,TEXT_OGDEN9,TEXT_OGDEN10 0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,2,1,0,15,14,13,13,14,15,0,1,2,1,0,15,14,13,13,14,15,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 FirstFrame
6 TOWN_STORY Cain the Elder 62 71 South 96 towners\strytell\strytell 25 3 TEXT_STORY2,TEXT_STORY3,TEXT_STORY4,TEXT_STORY5,TEXT_STORY6,TEXT_STORY7,TEXT_STORY9,TEXT_STORY10,TEXT_STORY11 0,0,24,24,23,22,21,20,19,18,17,16,15,14,15,16,17,18,19,20,21,22,23,24,24,24,0,0,0,24,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 FirstFrame
7 TOWN_DRUNK Farnham the Drunk 71 84 South 96 towners\drunk\twndrunk 18 3 TEXT_FARNHAM2,TEXT_FARNHAM3,TEXT_FARNHAM4,TEXT_FARNHAM5,TEXT_FARNHAM6,TEXT_FARNHAM8,TEXT_FARNHAM9,TEXT_FARNHAM10,TEXT_FARNHAM11,TEXT_FARNHAM12,TEXT_FARNHAM13 0,0,0,1,2,3,4,5,6,7,8,9,10,10,10,10,11,12,13,14,15,16,17,17,0,0,0,17,16,15,14,13,12,11,10,9,10,11,12,13,14,15,16,17,0,1,2,3,4,4,4,3,2,1 FirstFrame
8 TOWN_WITCH Adria the Witch 80 20 South 96 towners\townwmn1\witch 19 6 TEXT_ADRIA2,TEXT_ADRIA3,TEXT_ADRIA4,TEXT_ADRIA5,TEXT_ADRIA6,TEXT_ADRIA7,TEXT_ADRIA8,TEXT_ADRIA9,TEXT_ADRIA10,TEXT_ADRIA12,TEXT_ADRIA13 3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,3,3,4,5,5,5,4,3,14,13,12,12,12,13,14,3,4,5,5,5,4,3,2,1,0,18,17,18,0,1,0,18,17,18,0,1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,14,13,12,12,12,12,13,14,14,14,13,12,11,11,11,10,9,9,9,8,7,8,9,9,10,11,12,13,14,15,16,17,18,0,1,0,18,17,18,0,1,0,1,2 FirstFrame
9 TOWN_BMAID Gillian the Barmaid 43 66 South 96 towners\townwmn1\wmnn 18 6 TEXT_GILLIAN2,TEXT_GILLIAN3,TEXT_GILLIAN4,TEXT_GILLIAN5,TEXT_GILLIAN6,TEXT_GILLIAN7,TEXT_GILLIAN9,TEXT_GILLIAN10 FirstFrame
10 TOWN_PEGBOY Wirt the Peg-legged boy 11 53 South 96 towners\townboy\pegkid1 20 6 TEXT_WIRT2,TEXT_WIRT3,TEXT_WIRT4,TEXT_WIRT5,TEXT_WIRT6,TEXT_WIRT7,TEXT_WIRT8,TEXT_WIRT9,TEXT_WIRT11,TEXT_WIRT12 FirstFrame|Stray
11 TOWN_COW Cow 58 16 SouthWest 128 12 3
12 TOWN_COW Cow 56 14 NorthWest 128 12 3
13 TOWN_COW Cow 59 20 North 128 12 3
14 TOWN_COWFARM Complete Nut 61 22 SouthWest 96 towners\farmer\cfrmrn2 15 3 Baked
15 TOWN_FARMER Lester the farmer 62 16 South 96 towners\farmer\farmrn2 15 3 FirstFrame
16 TOWN_GIRL Celia 77 43 South 96 towners\girl\girlw1 20 6 FirstFrame
+529
View File
@@ -0,0 +1,529 @@
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "engine/clx_sprite.hpp"
#include "engine/render/clx_render.hpp"
#include "engine/shadow_mask.hpp"
#include "engine/shadow_rule.hpp"
#include "engine/surface.hpp"
#include "utils/clx_decode.hpp"
#include "utils/clx_encode.hpp"
#include "utils/clx_shadow.hpp"
#include "utils/endian_write.hpp"
#include "utils/palette_blending.hpp"
#include "utils/sdl_wrap.h"
namespace devilution {
namespace {
/**
* A sprite as rows of characters, top row first:
* '.' is transparent, '#' is black (palette index 0), any other character is that palette index.
*/
using Picture = std::vector<std::string>;
void AppendSprite(const Picture &picture, std::vector<uint8_t> &out)
{
const size_t headerPos = out.size();
out.resize(out.size() + ClxFrameHeaderSize);
WriteLE16(&out[headerPos], ClxFrameHeaderSize);
WriteLE16(&out[headerPos + 2], static_cast<uint16_t>(picture[0].size()));
WriteLE16(&out[headerPos + 4], static_cast<uint16_t>(picture.size()));
for (size_t i = picture.size(); i-- > 0;) {
for (const char c : picture[i]) {
if (c == '.') {
AppendClxTransparentRun(1, out);
} else {
const uint8_t color = c == '#' ? 0 : static_cast<uint8_t>(c);
AppendClxPixelsRun(&color, 1, out);
}
}
}
}
void AppendList(const std::vector<Picture> &pictures, std::vector<uint8_t> &out)
{
const size_t begin = out.size();
out.resize(out.size() + 4 * (2 + pictures.size()));
WriteLE32(&out[begin], static_cast<uint32_t>(pictures.size()));
for (size_t i = 0; i < pictures.size(); ++i) {
WriteLE32(&out[begin + 4 * (1 + i)], static_cast<uint32_t>(out.size() - begin));
AppendSprite(pictures[i], out);
}
WriteLE32(&out[begin + 4 * (1 + pictures.size())], static_cast<uint32_t>(out.size() - begin));
}
OwnedClxSpriteListOrSheet MakeList(const std::vector<Picture> &pictures)
{
std::vector<uint8_t> data;
AppendList(pictures, data);
std::unique_ptr<uint8_t[]> buffer { new uint8_t[data.size()] };
std::copy(data.begin(), data.end(), buffer.get());
return OwnedClxSpriteListOrSheet { std::move(buffer), 0 };
}
OwnedClxSpriteListOrSheet MakeSheet(const std::vector<std::vector<Picture>> &lists)
{
std::vector<uint8_t> data(lists.size() * 4);
for (size_t i = 0; i < lists.size(); ++i) {
WriteLE32(&data[i * 4], static_cast<uint32_t>(data.size()));
AppendList(lists[i], data);
}
std::unique_ptr<uint8_t[]> buffer { new uint8_t[data.size()] };
std::copy(data.begin(), data.end(), buffer.get());
return OwnedClxSpriteListOrSheet { std::move(buffer), static_cast<uint16_t>(lists.size()) };
}
Picture ToPicture(ClxSprite sprite)
{
const size_t width = sprite.width();
Picture result(sprite.height(), std::string(width, '.'));
size_t pos = 0;
const auto put = [&](uint8_t color) {
result[sprite.height() - 1 - pos / width][pos % width] = color == 0 ? '#' : static_cast<char>(color);
++pos;
};
const uint8_t *src = sprite.pixelData();
const uint8_t *end = src + sprite.pixelDataSize();
while (src < end) {
const uint8_t control = *src++;
if (!IsClxOpaque(control)) {
pos += control;
} else if (IsClxOpaqueFill(control)) {
const uint8_t color = *src++;
for (unsigned i = GetClxOpaqueFillWidth(control); i != 0; --i)
put(color);
} else {
for (unsigned i = GetClxOpaquePixelsWidth(control); i != 0; --i)
put(*src++);
}
}
return result;
}
/** The mask drawn as '#' on a transparent picture of the given size. */
Picture ToPicture(ShadowMask mask, size_t width, size_t height)
{
Picture result(height, std::string(width, '.'));
mask.forEachSpan([&](uint16_t rowFromBottom, ShadowSpan span) {
for (unsigned x = span.x; x < static_cast<unsigned>(span.x) + span.width; ++x)
result[height - 1 - rowFromBottom][x] = '#';
});
return result;
}
constexpr ShadowRule FirstFrame { ShadowRuleType::FirstFrame, 0 };
constexpr ShadowRule EachFrame { ShadowRuleType::EachFrame, 0 };
// A 12 pixel tall bar with its baseline on row 11.
// Rows 9..11 and 6..8 shadow the bar itself, rows 3..5 shadow (5, 7) and rows 0..2 shadow (4, 6).
const Picture Bar = {
"......a.",
"......a.",
"......a.",
"......a.",
"......a.",
"......a.",
"....#.a.",
".....#a.",
"......a.",
"......a.",
"......a.",
"......a.",
};
const Picture BarWithoutShadow = {
"......a.",
"......a.",
"......a.",
"......a.",
"......a.",
"......a.",
"......a.",
"......a.",
"......a.",
"......a.",
"......a.",
"......a.",
};
const Picture BarShadow = {
"........",
"........",
"........",
"........",
"........",
"........",
"....#...",
".....#..",
"......#.",
"......#.",
"........",
"........",
};
TEST(ClxShadowTest, ExtractsShadow)
{
const OwnedClxSpriteListOrSheet sprites = MakeList({ Bar });
const std::optional<OwnedClxSpriteListOrSheet> result = ExtractClxShadows(sprites, FirstFrame);
ASSERT_TRUE(result.has_value());
ASSERT_FALSE(result->isSheet());
const ClxSpriteList list = result->list();
ASSERT_EQ(list.numSprites(), 1U);
EXPECT_EQ(list[0].width(), 8);
EXPECT_EQ(list[0].height(), 12);
EXPECT_EQ(ToPicture(list[0]), BarWithoutShadow);
// The mask includes the shadow underneath the sprite.
ASSERT_TRUE(HasShadowMask(list[0]));
const ShadowMask mask = GetShadowMask(list[0]);
EXPECT_EQ(mask.bottomOffset(), 2);
EXPECT_EQ(mask.numRows(), 4);
EXPECT_EQ(ToPicture(mask, 8, 12), BarShadow);
// 2 bytes of header and one span for each of the 4 rows.
EXPECT_EQ(list[0].headerSize(), ClxSprite::BaseHeaderSize + 2 + 4 * 2);
}
TEST(ClxShadowTest, KeepsBlackPixelsThatAreNotShadow)
{
Picture picture = Bar;
// A black pixel of the bar. It casts the same shadow as the pixel it replaces.
picture[2][6] = '#';
// Its shadow would fall outside of the frame, so it cannot be ruled out as a body pixel.
picture[0][0] = '#';
// Not in any shadow, and its own shadow would fall on a transparent pixel.
picture[3][3] = '#';
Picture expected = BarWithoutShadow;
expected[2][6] = '#';
expected[0][0] = '#';
expected[3][3] = '#';
const OwnedClxSpriteListOrSheet sprites = MakeList({ picture });
const std::optional<OwnedClxSpriteListOrSheet> result = ExtractClxShadows(sprites, FirstFrame);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(ToPicture(result->list()[0]), expected);
EXPECT_EQ(ToPicture(GetShadowMask(result->list()[0]), 8, 12), BarShadow);
}
TEST(ClxShadowTest, RecognisesBlackBodyPixelInsideAShadow)
{
// The baseline is row 23. 'b' at (7, 0) shadows (2, 14), so the black pixel there looks like
// a shadow. It must be a body pixel, because nothing else casts the black pixel at (0, 18).
Picture picture(24, std::string(8, '.'));
picture[0][7] = 'b';
picture[14][2] = '#';
picture[18][0] = '#';
picture[23][7] = 'a';
Picture expected = picture;
expected[18][0] = '.';
const OwnedClxSpriteListOrSheet sprites = MakeList({ picture });
const std::optional<OwnedClxSpriteListOrSheet> result = ExtractClxShadows(sprites, FirstFrame);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(ToPicture(result->list()[0]), expected);
}
TEST(ClxShadowTest, BaselineRules)
{
// The second sprite ends 3 rows higher, with the shadow that its own baseline (row 8) gives.
const Picture shortBar = {
"......a.",
"......a.",
"......a.",
"......a.",
".....#a.",
"......a.",
"......a.",
"......a.",
"......a.",
"........",
"........",
"........",
};
Picture shortBarWithoutShadow = shortBar;
shortBarWithoutShadow[4][5] = '.';
const OwnedClxSpriteListOrSheet sprites = MakeList({ Bar, shortBar });
const std::optional<OwnedClxSpriteListOrSheet> eachFrame = ExtractClxShadows(sprites, EachFrame);
ASSERT_TRUE(eachFrame.has_value());
EXPECT_EQ(ToPicture(eachFrame->list()[0]), BarWithoutShadow);
EXPECT_EQ(ToPicture(eachFrame->list()[1]), shortBarWithoutShadow);
EXPECT_EQ(GetShadowMask(eachFrame->list()[1]).bottomOffset(), 5);
EXPECT_EQ(GetShadowMask(eachFrame->list()[1]).numRows(), 3);
// With the baseline of the first sprite (row 11) that black pixel is not a shadow.
const std::optional<OwnedClxSpriteListOrSheet> firstFrame = ExtractClxShadows(sprites, FirstFrame);
ASSERT_TRUE(firstFrame.has_value());
EXPECT_EQ(ToPicture(firstFrame->list()[0]), BarWithoutShadow);
EXPECT_EQ(ToPicture(firstFrame->list()[1]), shortBar);
}
TEST(ClxShadowTest, BaselineOffset)
{
// A flying sprite. Its lowest opaque row (row 5) is its shadow.
const Picture picture = {
"......a.",
"......a.",
"......a.",
"........",
"........",
"....#...",
};
Picture expected = picture;
expected[5][4] = '.';
const OwnedClxSpriteListOrSheet sprites = MakeList({ picture });
// With the baseline on row 5 the sprite only shadows itself, at (6, 2).
const std::optional<OwnedClxSpriteListOrSheet> noOffset = ExtractClxShadows(sprites, FirstFrame);
ASSERT_TRUE(noOffset.has_value());
EXPECT_EQ(ToPicture(noOffset->list()[0]), picture);
// With the baseline on row 10, rows 0 and 1 shadow (4, 5). The shadow of row 2 is outside the frame.
const std::optional<OwnedClxSpriteListOrSheet> withOffset = ExtractClxShadows(sprites, ShadowRule { ShadowRuleType::FirstFrame, 5 });
ASSERT_TRUE(withOffset.has_value());
EXPECT_EQ(ToPicture(withOffset->list()[0]), expected);
const ShadowMask mask = GetShadowMask(withOffset->list()[0]);
EXPECT_EQ(mask.bottomOffset(), 0);
EXPECT_EQ(mask.numRows(), 1);
EXPECT_EQ(ToPicture(mask, 8, 6), (Picture { "........", "........", "........", "........", "........", "....#..." }));
}
TEST(ClxShadowTest, PreservesSheetStructure)
{
const Picture empty(12, std::string(8, '.'));
const OwnedClxSpriteListOrSheet sprites = MakeSheet({ { Bar, Bar }, { empty }, { Bar } });
const std::optional<OwnedClxSpriteListOrSheet> result = ExtractClxShadows(sprites, FirstFrame);
ASSERT_TRUE(result.has_value());
ASSERT_TRUE(result->isSheet());
const ClxSpriteSheet sheet = result->sheet();
ASSERT_EQ(sheet.numLists(), 3);
ASSERT_EQ(sheet[0].numSprites(), 2U);
ASSERT_EQ(sheet[1].numSprites(), 1U);
ASSERT_EQ(sheet[2].numSprites(), 1U);
EXPECT_EQ(ToPicture(sheet[0][1]), BarWithoutShadow);
EXPECT_EQ(ToPicture(sheet[1][0]), empty);
EXPECT_EQ(ToPicture(sheet[2][0]), BarWithoutShadow);
EXPECT_EQ(ToPicture(GetShadowMask(sheet[0][1]), 8, 12), BarShadow);
// A sprite without a shadow has a plain header.
EXPECT_FALSE(HasShadowMask(sheet[1][0]));
EXPECT_EQ(sheet[1][0].headerSize(), ClxSprite::BaseHeaderSize);
EXPECT_EQ(ToPicture(GetShadowMask(sheet[2][0]), 8, 12), BarShadow);
}
TEST(ClxShadowTest, SplitsLongRunsAndKeepsEmptyRows)
{
// The baseline is row 8. 'a' (row 0) shadows row 4 shifted left by 1, 'b' (rows 6..8) shadows row 6,
// and nothing shadows row 5.
Picture picture(9, std::string(200, '.'));
for (size_t x = 1; x < 200; ++x)
picture[0][x] = 'a';
for (size_t x = 0; x < 199; ++x)
picture[4][x] = '#';
picture[8][10] = 'b';
picture[7][10] = 'b';
picture[6][10] = 'b';
Picture expectedSprite = picture;
expectedSprite[4].assign(200, '.');
Picture expectedMask(9, std::string(200, '.'));
expectedMask[4].replace(0, 199, std::string(199, '#'));
expectedMask[6][10] = '#';
const OwnedClxSpriteListOrSheet sprites = MakeList({ picture });
const std::optional<OwnedClxSpriteListOrSheet> result = ExtractClxShadows(sprites, FirstFrame);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(ToPicture(result->list()[0]), expectedSprite);
const ShadowMask mask = GetShadowMask(result->list()[0]);
EXPECT_EQ(mask.bottomOffset(), 2);
EXPECT_EQ(mask.numRows(), 3);
EXPECT_EQ(ToPicture(mask, 200, 9), expectedMask);
// Row 6: one span. Row 5: an empty span. Row 4: 199 pixels as spans of 127 and 72.
const std::vector<uint8_t> expectedRows = { 10, 0x80 | 1, 0, 0x80 | 0, 0, 127, 127, 0x80 | 72 };
EXPECT_EQ(std::vector<uint8_t>(mask.rows(), mask.rows() + expectedRows.size()), expectedRows);
}
/** An 8-bit surface filled with a pattern that has no black in it. */
SDLSurfaceUniquePtr MakeBackground(int width, int height)
{
SDLSurfaceUniquePtr surface = SDLWrap::CreateRGBSurfaceWithFormat(/*flags=*/0, width, height, /*depth=*/8, SDL_PIXELFORMAT_INDEX8);
const Surface out { surface.get() };
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x)
*out.at(x, y) = static_cast<uint8_t>(1 + (x * 7 + y * 13) % 200);
}
return surface;
}
std::vector<uint8_t> Pixels(const Surface &out)
{
std::vector<uint8_t> result;
for (int y = 0; y < out.h(); ++y)
result.insert(result.end(), out.at(0, y), out.at(0, y) + out.w());
return result;
}
// A sprite whose shadow reaches the left edge, with a black body pixel and a body pixel inside the shadow.
const Picture Walker = {
"...........aaa..",
"...........a#a..",
"...........aaa..",
"...........aaa..",
"...........aaa..",
"...........aaa..",
"...........aaa..",
"...........aaa..",
"...........aaa..",
"........###aaa..",
"........###aaa..",
".........##aaa..",
"...........aaa..",
"...........aaa..",
"...........aaa..",
};
TEST(ClxShadowTest, DrawingShadowThenSpriteMatchesTheOriginal)
{
constexpr int Width = 24, Height = 20;
for (const Picture &picture : { Bar, Walker }) {
const OwnedClxSpriteListOrSheet original = MakeList({ picture });
const std::optional<OwnedClxSpriteListOrSheet> extracted = ExtractClxShadows(original, FirstFrame);
ASSERT_TRUE(extracted.has_value());
ASSERT_TRUE(HasShadowMask(extracted->list()[0]));
// The shadow must really have been removed, or this test proves nothing.
ASSERT_NE(ToPicture(extracted->list()[0]), picture);
// Every position, including those where the sprite is clipped or entirely outside.
const int spriteWidth = static_cast<int>(picture[0].size());
const int spriteHeight = static_cast<int>(picture.size());
for (int y = -2; y < Height + spriteHeight + 2; ++y) {
for (int x = -spriteWidth - 2; x < Width + 2; ++x) {
const SDLSurfaceUniquePtr expectedSurface = MakeBackground(Width, Height);
const Surface expected { expectedSurface.get() };
ClxDraw(expected, { x, y }, original.list()[0]);
const SDLSurfaceUniquePtr actualSurface = MakeBackground(Width, Height);
const Surface actual { actualSurface.get() };
ClxDrawShadow(actual, { x, y }, extracted->list()[0]);
ClxDraw(actual, { x, y }, extracted->list()[0]);
ASSERT_EQ(Pixels(actual), Pixels(expected)) << "at " << x << ", " << y;
}
}
}
}
TEST(ClxShadowTest, OpaqueRunsThatContinueOnTheNextRow)
{
// CLX sprites must not have opaque runs that continue on the next row, but sprites that were
// converted before `Cl2ToClx` stopped producing them do. Such a run is taken to continue on the
// next row, as in the image that it was made from, and the result has no such runs.
// A 6x4 sprite, from the bottom row upwards:
// "....ab" and the run goes on with "cd"
// "cd#..."
// "....ee"
// "....e#"
std::vector<uint8_t> data(4 * 3 + ClxFrameHeaderSize);
WriteLE32(&data[0], 1);
WriteLE32(&data[4], 12);
WriteLE16(&data[12], ClxFrameHeaderSize);
WriteLE16(&data[14], 6);
WriteLE16(&data[16], 4);
const auto transparent = [&](unsigned width) { AppendClxTransparentRun(width, data); };
const auto pixels = [&](std::initializer_list<uint8_t> colors) { AppendClxPixelsRun(colors.begin(), static_cast<unsigned>(colors.size()), data); };
transparent(4);
pixels({ 'a', 'b', 'c', 'd' });
pixels({ 0 });
transparent(3 + 4);
pixels({ 'e', 'e' });
transparent(4);
pixels({ 'e', 0 });
WriteLE32(&data[8], static_cast<uint32_t>(data.size()));
std::unique_ptr<uint8_t[]> buffer { new uint8_t[data.size()] };
std::copy(data.begin(), data.end(), buffer.get());
const OwnedClxSpriteListOrSheet original { std::move(buffer), 0 };
const std::optional<OwnedClxSpriteListOrSheet> extracted = ExtractClxShadows(original, FirstFrame);
ASSERT_TRUE(extracted.has_value());
const ClxSprite sprite = extracted->list()[0];
EXPECT_EQ(ToPicture(sprite), (Picture { "....e#", "....ee", "cd#...", "....ab" }));
// No opaque command of the result goes past the end of its row.
const uint8_t *src = sprite.pixelData();
const uint8_t *end = src + sprite.pixelDataSize();
unsigned x = 0;
while (src < end) {
const uint8_t control = *src++;
if (!IsClxOpaque(control)) {
x += control;
} else {
const unsigned width = IsClxOpaqueFill(control) ? GetClxOpaqueFillWidth(control) : GetClxOpaquePixelsWidth(control);
src += IsClxOpaqueFill(control) ? 1 : width;
EXPECT_LE(x + width, 6U);
x += width;
}
x %= 6;
}
}
TEST(ClxShadowTest, DrawsBlendedShadow)
{
// A recognisable "blend with black" table: every colour maps to itself plus 50.
for (unsigned i = 0; i < 256; ++i)
paletteTransparencyLookup[0][i] = static_cast<uint8_t>(i + 50);
#if DEVILUTIONX_PALETTE_TRANSPARENCY_BLACK_16_LUT
for (unsigned i = 0; i < 256; ++i) {
for (unsigned j = 0; j < 256; ++j)
paletteTransparencyLookupBlack16[i | (j << 8U)] = static_cast<uint16_t>(paletteTransparencyLookup[0][i] | (paletteTransparencyLookup[0][j] << 8U));
}
#endif
constexpr int Width = 24, Height = 20;
const std::optional<OwnedClxSpriteListOrSheet> extracted = ExtractClxShadows(MakeList({ Walker }), FirstFrame);
ASSERT_TRUE(extracted.has_value());
const ClxSprite sprite = extracted->list()[0];
const Picture body = ToPicture(sprite);
const Picture shadow = ToPicture(GetShadowMask(sprite), Walker[0].size(), Walker.size());
// Positions that clip the shadow on every side, with odd and even span starts.
for (const Point position : { Point { 3, 16 }, Point { 4, 16 }, Point { -9, 16 }, Point { 12, 10 }, Point { 2, 25 } }) {
const SDLSurfaceUniquePtr backgroundSurface = MakeBackground(Width, Height);
const std::vector<uint8_t> background = Pixels(Surface { backgroundSurface.get() });
const SDLSurfaceUniquePtr surface = MakeBackground(Width, Height);
const Surface out { surface.get() };
ClxDrawShadowBlended(out, position, sprite);
ClxDraw(out, position, sprite);
std::vector<uint8_t> expected = background;
for (int spriteY = 0; spriteY < static_cast<int>(Walker.size()); ++spriteY) {
for (int spriteX = 0; spriteX < static_cast<int>(Walker[0].size()); ++spriteX) {
const int x = position.x + spriteX;
const int y = position.y - (static_cast<int>(Walker.size()) - 1 - spriteY);
if (x < 0 || x >= Width || y < 0 || y >= Height) continue;
uint8_t &pixel = expected[static_cast<size_t>(y) * Width + x];
if (body[spriteY][spriteX] != '.') {
pixel = body[spriteY][spriteX] == '#' ? 0 : static_cast<uint8_t>(body[spriteY][spriteX]);
} else if (shadow[spriteY][spriteX] == '#') {
pixel = static_cast<uint8_t>(pixel + 50);
}
}
}
EXPECT_EQ(Pixels(out), expected) << "at " << position.x << ", " << position.y;
}
}
TEST(ClxShadowTest, NothingToExtractWithoutAKnownRule)
{
const OwnedClxSpriteListOrSheet sprites = MakeList({ Bar });
EXPECT_FALSE(ExtractClxShadows(sprites, ShadowRule { ShadowRuleType::Unknown, 0 }).has_value());
EXPECT_FALSE(ExtractClxShadows(sprites, ShadowRule { ShadowRuleType::None, 0 }).has_value());
EXPECT_FALSE(ExtractClxShadows(sprites, ShadowRule { ShadowRuleType::Baked, 0 }).has_value());
}
} // namespace
} // namespace devilution
+38
View File
@@ -5,6 +5,8 @@
#include "cursor.h"
#include "engine/assets.hpp"
#include "init.hpp"
#include "tables/monstdat.h"
#include "tables/objdat.h"
#include "tables/playerdat.hpp"
using namespace devilution;
@@ -187,6 +189,42 @@ static void AssertPlayer(devilution::Player &player)
ASSERT_EQ(player._pILMaxDam, 0);
}
TEST(Player, ShadowRulesAreLoaded)
{
LoadCoreArchives();
LoadPlayerDataFiles();
LoadMonsterData();
LoadObjectData();
// One of the warrior's sprite files does not reproduce exactly, which the tags record.
EXPECT_EQ(GetPlayerSpriteDataForClass(HeroClass::Warrior).shadowRule, (ShadowRule { ShadowRuleType::FirstFrame, 0, ShadowRuleFlags::Unexplained | ShadowRuleFlags::Stray }));
EXPECT_EQ(GetPlayerSpriteDataForClass(HeroClass::Rogue).shadowRule, (ShadowRule { ShadowRuleType::FirstFrame, 0 }));
EXPECT_EQ(GetPlayerSpriteDataForClass(HeroClass::Monk).shadowRule, (ShadowRule { ShadowRuleType::EachFrame, 0 }));
// Sprites that were never analysed have an empty value.
EXPECT_EQ(GetPlayerSpriteDataForClass(HeroClass::Bard).shadowRule, (ShadowRule { ShadowRuleType::Unknown, 0 }));
// One rule per animation: stand, walk, attack, hit, death, special.
const MonsterData &zombie = MonstersData[MT_NZOMBIE];
EXPECT_EQ(zombie.shadowRules[0], (ShadowRule { ShadowRuleType::FirstFrame, 0 }));
EXPECT_EQ(zombie.shadowRules[5], (ShadowRule { ShadowRuleType::None, 0 }));
// Flying monsters have their baseline below the sprite, except when they fall to the ground.
const MonsterData &fiend = MonstersData[MT_FIEND];
EXPECT_EQ(fiend.shadowRules[0], (ShadowRule { ShadowRuleType::FirstFrame, 15 }));
EXPECT_EQ(fiend.shadowRules[4], (ShadowRule { ShadowRuleType::FirstFrame, 0 }));
const MonsterData &golem = MonstersData[MT_GOLEM];
EXPECT_EQ(golem.shadowRules[1], (ShadowRule { ShadowRuleType::EachFrame, 0 }));
// Monsters whose sprites are missing from the game data have an empty value.
EXPECT_EQ(MonstersData[MT_WYRM].shadowRules[0], (ShadowRule { ShadowRuleType::Unknown, 0 }));
EXPECT_EQ(AllObjects[OBJ_BARREL].shadowRule, (ShadowRule { ShadowRuleType::FirstFrame, 0 }));
EXPECT_EQ(AllObjects[OBJ_CHEST1].shadowRule, (ShadowRule { ShadowRuleType::EachFrame, 0 }));
// The cauldron's shadow cannot be told apart from its black side.
EXPECT_EQ(AllObjects[OBJ_CAULDRON].shadowRule, (ShadowRule { ShadowRuleType::Baked, 0 }));
EXPECT_EQ(AllObjects[OBJ_L1LIGHT].shadowRule, (ShadowRule { ShadowRuleType::None, 0 }));
// Doors have black pixels but no cast shadow.
EXPECT_EQ(AllObjects[OBJ_L1LDOOR].shadowRule, (ShadowRule { ShadowRuleType::None, 0 }));
}
TEST(Player, CreatePlayer)
{
LoadCoreArchives();
+67
View File
@@ -0,0 +1,67 @@
#include <gtest/gtest.h>
#include "engine/shadow_rule.hpp"
namespace devilution {
namespace {
TEST(ShadowRuleTest, ParsesTypes)
{
EXPECT_EQ(ParseShadowRule(""), (ShadowRule { ShadowRuleType::Unknown, 0 }));
EXPECT_EQ(ParseShadowRule("Unknown"), (ShadowRule { ShadowRuleType::Unknown, 0 }));
EXPECT_EQ(ParseShadowRule("None"), (ShadowRule { ShadowRuleType::None, 0 }));
EXPECT_EQ(ParseShadowRule("Baked"), (ShadowRule { ShadowRuleType::Baked, 0 }));
EXPECT_EQ(ParseShadowRule("FirstFrame"), (ShadowRule { ShadowRuleType::FirstFrame, 0 }));
EXPECT_EQ(ParseShadowRule("EachFrame"), (ShadowRule { ShadowRuleType::EachFrame, 0 }));
}
TEST(ShadowRuleTest, ParsesBaselineOffset)
{
EXPECT_EQ(ParseShadowRule("FirstFrame+15"), (ShadowRule { ShadowRuleType::FirstFrame, 15 }));
EXPECT_EQ(ParseShadowRule("FirstFrame+255"), (ShadowRule { ShadowRuleType::FirstFrame, 255 }));
}
TEST(ShadowRuleTest, ParsesTags)
{
EXPECT_EQ(ParseShadowRule("FirstFrame|Stray"), (ShadowRule { ShadowRuleType::FirstFrame, 0, ShadowRuleFlags::Stray }));
EXPECT_EQ(ParseShadowRule("EachFrame|Unexplained"), (ShadowRule { ShadowRuleType::EachFrame, 0, ShadowRuleFlags::Unexplained }));
EXPECT_EQ(ParseShadowRule("FirstFrame|Unexplained|Stray"), (ShadowRule { ShadowRuleType::FirstFrame, 0, ShadowRuleFlags::Unexplained | ShadowRuleFlags::Stray }));
EXPECT_EQ(ParseShadowRule("FirstFrame+15|Stray"), (ShadowRule { ShadowRuleType::FirstFrame, 15, ShadowRuleFlags::Stray }));
const ShadowRule rule = *ParseShadowRule("FirstFrame|Stray");
EXPECT_TRUE(HasAnyOf(rule.flags, ShadowRuleFlags::Stray));
EXPECT_FALSE(HasAnyOf(rule.flags, ShadowRuleFlags::Unexplained));
// The tags are notes: the shadow is extracted all the same.
EXPECT_TRUE(rule.canExtractShadow());
EXPECT_EQ(ParseShadowRule("FirstFrame")->flags, ShadowRuleFlags::None);
}
TEST(ShadowRuleTest, RejectsInvalidValues)
{
EXPECT_FALSE(ParseShadowRule("firstframe").has_value());
EXPECT_FALSE(ParseShadowRule("FirstFrame+").has_value());
EXPECT_FALSE(ParseShadowRule("FirstFrame+0").has_value());
EXPECT_FALSE(ParseShadowRule("FirstFrame+256").has_value());
EXPECT_FALSE(ParseShadowRule("FirstFrame+1x").has_value());
EXPECT_FALSE(ParseShadowRule("FirstFrame-1").has_value());
EXPECT_FALSE(ParseShadowRule("EachFrame+1").has_value());
EXPECT_FALSE(ParseShadowRule("FirstFrame|").has_value());
EXPECT_FALSE(ParseShadowRule("FirstFrame|stray").has_value());
EXPECT_FALSE(ParseShadowRule("FirstFrame|Stray|Other").has_value());
EXPECT_FALSE(ParseShadowRule("Stray").has_value());
// A comma separates the rules of a list, not a rule from its tags.
EXPECT_FALSE(ParseShadowRule("FirstFrame,Stray").has_value());
}
TEST(ShadowRuleTest, CanExtractShadow)
{
EXPECT_FALSE(ShadowRule {}.canExtractShadow());
EXPECT_FALSE((ShadowRule { ShadowRuleType::None, 0 }).canExtractShadow());
// A baked shadow is known but stays part of the sprite.
EXPECT_FALSE((ShadowRule { ShadowRuleType::Baked, 0 }).canExtractShadow());
EXPECT_TRUE((ShadowRule { ShadowRuleType::FirstFrame, 11 }).canExtractShadow());
EXPECT_TRUE((ShadowRule { ShadowRuleType::EachFrame, 0 }).canExtractShadow());
}
} // namespace
} // namespace devilution
+6
View File
@@ -83,6 +83,12 @@ TEST(TownerDat, LoadTownerData)
ASSERT_GE(smith->animOrder.size(), 4u);
EXPECT_EQ(smith->animOrder[0], 4);
EXPECT_EQ(smith->animOrder[3], 7);
EXPECT_EQ(smith->shadowRule, (ShadowRule { ShadowRuleType::FirstFrame, 0 }));
// Wirt's shadow has a few pixels that the rule does not account for.
const TownerDataEntry *pegBoy = FindTownerDataByType(TOWN_PEGBOY);
ASSERT_NE(pegBoy, nullptr) << "Should find TOWN_PEGBOY data";
EXPECT_EQ(pegBoy->shadowRule, (ShadowRule { ShadowRuleType::FirstFrame, 0, ShadowRuleFlags::Stray }));
// Check Pepin (TOWN_HEALER)
const TownerDataEntry *healer = FindTownerDataByType(TOWN_HEALER);
+30
View File
@@ -0,0 +1,30 @@
# Research tool: searches for the transform that was used to generate
# the baked-in shadows of the original player sprites.
find_package(ZLIB REQUIRED)
add_executable(shadow_search shadow_search.cpp)
set_target_properties(shadow_search PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_include_directories(shadow_search PRIVATE "${PROJECT_SOURCE_DIR}/Source")
target_link_dependencies(shadow_search
PRIVATE
tl
libdevilutionx_cel_to_clx
libdevilutionx_cl2_to_clx
libdevilutionx_mpq
ZLIB::ZLIB
)
# Checks the game's shadow extraction (utils/clx_shadow.hpp) against the original sprites.
add_executable(shadow_extract_check extract_check.cpp)
set_target_properties(shadow_extract_check PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_include_directories(shadow_extract_check PRIVATE "${PROJECT_SOURCE_DIR}/Source")
target_link_dependencies(shadow_extract_check
PRIVATE
tl
libdevilutionx_cel_to_clx
libdevilutionx_cl2_to_clx
DevilutionX::SDL
libdevilutionx_clx_render
libdevilutionx_clx_shadow
libdevilutionx_mpq
libdevilutionx_surface
)
+606
View File
@@ -0,0 +1,606 @@
<title>Diablo Sprite Shadows</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600&family=Spectral:wght@500;600&display=swap">
<style>
/* Layout: one reading column; the sprite bench (4 enlarged views + 8-direction strip) breaks out to full width. */
:root {
--bg: #f3f1ee;
--surface: #fbfaf8;
--fg: #1d1a17;
--muted: #6a625a;
--rule: #d9d3cb;
--accent: #8c2f1b;
--stage: #8f8676; /* sprite backdrop: mid-tone so black shadows and bright armour both read */
--stage-alt: #867d6d;
--shadow-ok: #1f9d6b;
--body-black: #3a6fd8;
--orphan: #e0218a;
--body-dim: #c9c2b6;
--display: "Spectral", Georgia, "Times New Roman", serif;
--body: "IBM Plex Sans", "Segoe UI", Helvetica, Arial, sans-serif;
--mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--bg: #171513; --surface: #201d1a; --fg: #ece7e0; --muted: #a39a8f; --rule: #3a352f; --accent: #e0785c;
--stage: #8f8676; --stage-alt: #867d6d; --shadow-ok: #35c48b; --body-black: #6f9cf2; --orphan: #ff5cb0; --body-dim: #c9c2b6;
color-scheme: dark;
}
}
:root[data-theme="dark"] {
--bg: #171513; --surface: #201d1a; --fg: #ece7e0; --muted: #a39a8f; --rule: #3a352f; --accent: #e0785c;
--stage: #8f8676; --stage-alt: #867d6d; --shadow-ok: #35c48b; --body-black: #6f9cf2; --orphan: #ff5cb0; --body-dim: #c9c2b6;
color-scheme: dark;
}
[hidden] { display: none !important; }
body { background: var(--bg); color: var(--fg); font-family: var(--body); font-size: 16px; line-height: 1.55; }
.page { max-width: 1260px; margin: 0 auto; padding-inline: 20px; padding-block: 40px 64px; display: flex; flex-direction: column; gap: 40px; }
.prose { max-width: 66ch; display: flex; flex-direction: column; gap: 14px; }
h1, h2 { font-family: var(--display); font-weight: 600; text-wrap: balance; margin: 0; line-height: 1.15; }
h1 { font-size: clamp(1.9rem, 4.5vw, 2.7rem); }
h2 { font-size: 1.45rem; }
p { margin: 0; }
.eyebrow { font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.lede { font-size: 1.1rem; }
.byline { font-size: 0.9rem; color: var(--muted); }
code, pre, .num { font-family: var(--mono); }
code { font-size: 0.9em; }
section { display: flex; flex-direction: column; gap: 18px; }
.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 0; border-block: 1px solid var(--rule); margin: 0; }
.facts div { padding: 14px 16px 14px 0; display: flex; flex-direction: column; gap: 2px; }
.facts dt { font-size: 0.8rem; color: var(--muted); order: 2; }
.facts dd { margin: 0; font-family: var(--mono); font-size: 1.35rem; font-weight: 500; font-variant-numeric: tabular-nums; }
.code { overflow-x: auto; background: var(--surface); border: 1px solid var(--rule); border-left: 3px solid var(--accent); }
.code pre { margin: 0; padding: 16px 18px; font-size: 0.88rem; line-height: 1.6; }
.code .c { color: var(--muted); }
.controls { display: flex; flex-wrap: wrap; gap: 12px 20px; align-items: end; }
.field { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; color: var(--muted); min-width: 0; }
select, button, input[type="range"] { font: inherit; }
select { font-size: 0.95rem; color: var(--fg); background: var(--surface); border: 1px solid var(--rule); padding: 7px 10px; max-width: 100%; }
button { font-size: 0.95rem; color: var(--fg); background: var(--surface); border: 1px solid var(--rule); padding: 7px 14px; cursor: pointer; }
button:hover { border-color: var(--accent); }
select:focus-visible, button:focus-visible, input:focus-visible, .dir:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.scrub { flex: 1 1 200px; }
.scrub input { width: 100%; accent-color: var(--accent); }
.views { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; }
.view { display: flex; flex-direction: column; gap: 6px; min-width: 0; margin: 0; }
.view figcaption { display: flex; flex-direction: column; gap: 2px; }
.view strong { font-weight: 600; font-size: 0.95rem; }
.view span { font-size: 0.8rem; color: var(--muted); }
canvas { display: block; width: 100%; height: auto; image-rendering: pixelated; image-rendering: crisp-edges; image-rendering: pixelated;
background-color: var(--stage);
background-image: linear-gradient(45deg, var(--stage-alt) 25%, transparent 25%, transparent 75%, var(--stage-alt) 75%), linear-gradient(45deg, var(--stage-alt) 25%, transparent 25%, transparent 75%, var(--stage-alt) 75%);
background-size: 16px 16px; background-position: 0 0, 8px 8px; }
.legend { display: flex; flex-wrap: wrap; gap: 6px 18px; font-size: 0.85rem; color: var(--muted); padding: 0; margin: 0; list-style: none; }
.legend li { display: flex; align-items: center; gap: 6px; }
.sw { width: 12px; height: 12px; display: inline-block; }
.readout { overflow-x: auto; }
table { border-collapse: collapse; font-size: 0.88rem; font-variant-numeric: tabular-nums; }
th, td { text-align: right; padding: 6px 14px 6px 0; border-bottom: 1px solid var(--rule); white-space: nowrap; }
th { font-weight: 500; color: var(--muted); font-size: 0.8rem; }
th:first-child, td:first-child { text-align: left; }
td { font-family: var(--mono); }
.dirs { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 8px; }
@media (max-width: 720px) { .dirs { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.dir { padding: 0; border: 1px solid var(--rule); background: var(--surface); display: flex; flex-direction: column; min-width: 0; }
.dir[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.dir small { font-family: var(--mono); font-size: 0.72rem; padding: 4px 6px; display: flex; justify-content: space-between; gap: 4px; color: var(--muted); }
.dir small b { font-weight: 500; color: var(--fg); }
ul.notes { margin: 0; padding-left: 1.1em; display: flex; flex-direction: column; gap: 8px; }
a { color: var(--accent); }
.masthead { display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 24px 48px; }
.masthead .prose { flex: 1 1 420px; }
.hero { flex: 0 1 320px; margin: 0 auto; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.hero figcaption { font-size: 0.8rem; color: var(--muted); }
.case { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 12px 48px; padding-top: 18px; border-top: 1px solid var(--rule); }
.case .prose { flex: 1 1 420px; }
.case .hero { flex-basis: 240px; }
</style>
<div class="page">
<header class="masthead">
<div class="prose">
<p class="eyebrow">DevilutionX research notes</p>
<h1>How Diablo drew its sprite shadows</h1>
<p class="byline">By Gleb Mazovetskiy (<a href="https://github.com/glebm">GitHub</a>, <a href="https://x.com/glebm">X</a>) and <a href="https://claude.com/claude-code">Claude</a>, Anthropic's AI model</p>
<p class="lede">The shadow under every Diablo character is part of its sprite, stored as black pixels. Each shadow is a copy of the sprite's own outline, squashed to a third of its height and sheared to the left, so a few lines of integer arithmetic can recompute it from the rest of the frame. The same function works for players, monsters, townspeople and dungeon objects, in both Diablo and the Hellfire expansion.</p>
</div>
<figure class="hero">
<canvas data-sprite="m:diablow" data-mode="orig" aria-label="Diablo walking, with the shadow stored in the sprite"></canvas>
<figcaption>Diablo's walk animation as stored in the game data. The black shape at his feet is part of each frame.</figcaption>
</figure>
</header>
<dl class="facts">
<div><dd>139,943</dd><dt>frames checked, from 1,438 sprite files in Diablo and Hellfire</dt></div>
<div><dd>99.77%</dd><dt>of the 136,936 frames with a shadow are reproduced pixel for pixel</dt></div>
<div><dd>763 of 765</dd><dt>original player files in which every frame is reproduced exactly</dt></div>
<div><dd>30,744 of 30,744</dd><dt>frames of the Hellfire monk reproduced exactly</dt></div>
<div><dd>3</dd><dt>rules for placing the ground line, which is the function's only input besides the sprite</dt></div>
</dl>
<section class="masthead">
<div class="prose">
<h2>The shadows were added in 2D</h2>
<p>Diablo's characters and monsters were modelled and animated in 3D, then rendered to small 2D frames, one set per facing direction. The game ships only those frames. Each one is a grid of palette indices, and its shadow is part of it, as a patch of pure black pixels next to the feet.</p>
<p>These shadows did not come from the 3D renderer. A rendered shadow would depend on the depth of the model, and the ones in the game files can be computed from the flat frame alone. Each is an affine transform of the 2D sprite: the silhouette is sheared to the left, squashed to a third of its height and filled with black. Done in integer arithmetic, with the rounding described in the next section, the transform matches the game's art to the pixel.</p>
<p>It is applied to every pixel that is not transparent, including black pixels of the body such as dark boots, so it must have run on the finished 2D image.</p>
</div>
<figure class="hero">
<canvas data-sprite="m:diablow" data-mode="body" aria-label="Diablo walking, with the shadow removed"></canvas>
<figcaption>The same animation with the shadow removed. The function recomputes the shadow from these pixels alone.</figcaption>
</figure>
</section>
<section>
<div class="prose">
<h2>The function</h2>
<p>The function takes the sprite and one number: <code>B</code>, the row of the ground line that the shadow is measured from. Rows are numbered downwards from the top of the frame.</p>
</div>
<div class="code"><pre><span class="c">// B: the row of the ground line, chosen by one of the rules further down.</span>
<span class="c">// Called for every pixel (x, y) of the shadowless sprite with y &lt;= B.</span>
<span class="c">// Pixels below B cast nothing. Both divisions are integer divisions.</span>
int v = (B - y) / 3; <span class="c">// three sprite rows collapse into one shadow row</span>
int ys = B - 2 - v; <span class="c">// the shadow starts two rows above the ground line</span>
int xs = x - (3 * v) / 4; <span class="c">// sheared left by 3/4 px per shadow row</span>
shadow[ys][xs] = BLACK; <span class="c">// the sprite is then drawn on top</span></pre></div>
<div class="prose">
<p>In matrix form, with <code>h = B - y</code> for the height of a pixel above the ground line, this is a shear combined with a vertical squash:</p>
</div>
<div class="code"><pre>[ x' ] [ 1 -1/4 ] [ x ]
[ h' ] = [ 0 1/3 ] [ h ] y' = B - 2 - h'</pre></div>
<div class="prose">
<p>A pixel moves left by a quarter of its height and keeps a third of its height. The matrix only approximates the code, which rounds twice: it first reduces the height to a whole shadow row and then computes the shift from that row. Rounding the matrix product once puts some pixels in a different column, up to 1.25 pixels away. Only the two-step integer version matches the game's art exactly.</p>
</div>
</section>
<section>
<div class="prose">
<h2>Try it on the original sprites</h2>
<p>This page runs the function in your browser. For each original frame it removes the shadow, casts a new one from what is left, and compares the result with the original.</p>
</div>
<p id="loadError" hidden>The sprites could not be unpacked. This page needs a browser with <code>DecompressionStream</code>, which all current browsers have.</p>
<div class="controls">
<label class="field" for="sprite">Sprite
<select id="sprite"></select>
</label>
<button id="play" type="button">Pause</button>
<label class="field scrub" for="frame"><span id="frameLabel">Frame</span>
<input id="frame" type="range" min="0" max="0" value="0">
</label>
</div>
<div class="views">
<figure class="view"><canvas id="cOrig"></canvas><figcaption><strong>Original</strong><span>As stored in the game data</span></figcaption></figure>
<figure class="view"><canvas id="cBody"></canvas><figcaption><strong>Shadow removed</strong><span>The frame as it was before the shadow pass</span></figcaption></figure>
<figure class="view"><canvas id="cRegen"></canvas><figcaption><strong>Reproduced</strong><span>Shadow cast by the function, sprite drawn on top</span></figcaption></figure>
<figure class="view"><canvas id="cDiff"></canvas><figcaption><strong>Where each black pixel comes from</strong><span id="diffNote">&nbsp;</span></figcaption></figure>
</div>
<ul class="legend">
<li><span class="sw" style="background:var(--shadow-ok)"></span>shadow, reproduced</li>
<li><span class="sw" style="background:var(--body-black)"></span>black pixel of the body</li>
<li><span class="sw" style="background:var(--orphan)"></span>unexplained: black pixel that nothing in the sprite casts</li>
<li><span class="sw" style="background:#f00"></span>stray: shadow cast onto a transparent pixel</li>
<li><span class="sw" style="background:var(--body-dim)"></span>rest of the body</li>
</ul>
<div class="dirs" id="dirs"></div>
<div class="readout">
<table>
<thead><tr><th>Direction</th><th>Frames</th><th>Ground line rule</th><th>Row B</th><th>Black pixels</th><th>Reproduced shadow</th><th>Body black</th><th>Unexplained</th><th>Stray</th><th>Exact frames</th></tr></thead>
<tbody id="readout"></tbody>
</table>
</div>
<div class="prose">
<p>Five sprites are in the list because the function does not fully explain them: the warrior with only a shield, standing and walking in town, Wirt, Na-Krul's death animation, and the cauldron. They are covered under <a href="#exceptions">What is not reproduced</a>. Every sprite is drawn with the town palette, so the colours of dungeon monsters may be slightly off.</p>
</div>
</section>
<section>
<div class="prose">
<h2>How the ground line is chosen</h2>
<p>The ground line is always derived from the art, in one of three ways, and the choice differs from file to file. The table counts animation directions of the original game's monsters.</p>
</div>
<div class="readout">
<table>
<thead><tr><th>Ground line row B</th><th>Monster directions</th><th style="text-align:left">Used by</th></tr></thead>
<tbody>
<tr><td>Lowest opaque row of the first frame</td><td>1,223</td><td style="text-align:left">all original players, most monsters, townspeople, barrels, levers, sarcophagi</td></tr>
<tr><td>Lowest opaque row of each frame</td><td>75</td><td style="text-align:left">golem, some Diablo, mage, snake and mega demon animations, chests, books, nearly all Hellfire art</td></tr>
<tr><td>First frame's lowest row plus a constant</td><td>72</td><td style="text-align:left">flying monsters: bat +15 rows, gargoyle +11</td></tr>
<tr><td>No shadow in the art</td><td>80</td><td style="text-align:left">two monsters with no black pixels at all</td></tr>
</tbody>
</table>
</div>
<div class="prose">
<p>Under the first-frame rule the shadow stays where it is while the body moves. Under the each-frame rule it follows a body that bobs up and down, as the golem's does.</p>
<p>For flying monsters the ground line lies below the sprite, which separates the shadow from the body. The offsets of 15 and 11 rows make more sense when measured from the body. The ground line is exactly 40 rows below the lowest non-black row of the first frame for the bat, in all 32 directions checked, and 28 rows below it for the gargoyle, in all 40. In those first frames the lowest opaque row is the bottom of the shadow, not of the body, which is why the offset from it comes out as +15 and +11.</p>
<p>We found no property of a sprite that predicts which rule its file uses. Animations of the same monster can use different rules, and no single rule covers both the first-frame and the each-frame files. Our guess is that the choice reflects how each file was processed at the time.</p>
</div>
</section>
<section class="prose">
<h2>Hellfire</h2>
<p>Hellfire was made by a different studio a year later, and it uses the same function. Its ground line is almost always the lowest opaque row of each frame, where the original game mostly uses the first frame.</p>
<ul class="notes">
<li>The monk has 291 files and 30,744 frames. With the each-frame rule every frame is reproduced pixel for pixel. The first-frame rule works only where the bottom row never moves, which is the case in 536 of 2,328 directions.</li>
<li>Of the 125 Hellfire monster files checked, 114 have a shadow. All 114 fit the each-frame rule with no stray pixels, and none needs the first-frame rule. Four of them leave unexplained black pixels, 4,815 in total, nearly all in two Na-Krul animations.</li>
<li>The other 11 are death animations with no cast shadow. Six have no black pixels at all. In the other five the few black pixels are painted detail: Hork Spawn, Hell Bug, Hellbat, Arch Lich and Hellfire's Satyr Lord. Black makes up at most 0.5% of their pixels, against 15% or more in death animations that have a shadow.</li>
</ul>
</section>
<section>
<div class="prose">
<h2>Results by sprite set</h2>
<p>Each row is one set of sprite files, measured with the ground line rule that the DevilutionX data files record for each file. The rule column counts files. The table above counts monster animation directions, so the two do not match.</p>
</div>
<div class="readout">
<table>
<thead><tr><th style="text-align:left">Sprite set</th><th>Files</th><th>Frames</th><th>Files with a shadow</th><th>First / each / first + offset</th><th>Files with no shadow</th><th>Frames with a shadow reproduced exactly</th><th>Stray pixels</th><th>Unexplained pixels</th></tr></thead>
<tbody>
<tr><td style="text-align:left">Players, original game</td><td>765</td><td>78,016</td><td>765</td><td>765 / 0 / 0</td><td>0</td><td>77,872 of 78,016 (99.82%)</td><td>771</td><td>1,333</td></tr>
<tr><td style="text-align:left">Monk, Hellfire</td><td>291</td><td>30,744</td><td>291</td><td>0 / 291 / 0</td><td>0</td><td>30,744 of 30,744 (100%)</td><td>0</td><td>0</td></tr>
<tr><td style="text-align:left">Monsters, original game</td><td>183</td><td>18,088</td><td>173</td><td>151 / 13 / 9</td><td>10</td><td>16,912 of 16,912 (100%)</td><td>0</td><td>0</td></tr>
<tr><td style="text-align:left">Monsters, Hellfire</td><td>125</td><td>12,424</td><td>114</td><td>1 / 113 / 0</td><td>11</td><td>10,717 of 10,872 (98.57%)</td><td>0</td><td>4,815</td></tr>
<tr><td style="text-align:left">Townspeople, original game</td><td>9</td><td>160</td><td>8</td><td>8 / 0 / 0</td><td>1</td><td>132 of 152 (86.84%)</td><td>38</td><td>0</td></tr>
<tr><td style="text-align:left">Townspeople, Hellfire</td><td>3</td><td>50</td><td>3</td><td>3 / 0 / 0</td><td>0</td><td>50 of 50 (100%)</td><td>0</td><td>0</td></tr>
<tr><td style="text-align:left">Objects, original game</td><td>53</td><td>396</td><td>28</td><td>15 / 13 / 0</td><td>25</td><td>161 of 161 (100%)</td><td>0</td><td>0</td></tr>
<tr><td style="text-align:left">Objects, Hellfire</td><td>9</td><td>65</td><td>3</td><td>1 / 2 / 0</td><td>6</td><td>29 of 29 (100%)</td><td>0</td><td>0</td></tr>
<tr><td style="text-align:left"><strong>All sprite sets</strong></td><td><strong>1,438</strong></td><td><strong>139,943</strong></td><td><strong>1,385</strong></td><td><strong>944 / 432 / 9</strong></td><td><strong>53</strong></td><td><strong>136,617 of 136,936 (99.77%)</strong></td><td><strong>809</strong></td><td><strong>6,148</strong></td></tr>
</tbody>
</table>
</div>
<div class="prose">
<ul class="notes">
<li>A frame is <strong>reproduced exactly</strong> when removing the shadow, casting a new one with the function and drawing the body on top gives back the original frame, pixel for pixel. Only frames of files with a shadow are counted.</li>
<li><strong>Stray pixels</strong> are transparent pixels that the function casts a shadow onto. Each pixel is counted once.</li>
<li><strong>Unexplained pixels</strong> are black pixels that are neither reproduced shadow nor body. Nothing left in the sprite casts them, and if they were body pixels they would cast a stray shadow themselves.</li>
<li>The rule for each file is the one recorded in the DevilutionX data files. A file recorded as having no shadow is counted that way even if it has black pixels. This applies to 13 files: five Hellfire death animations, six original objects and two Hellfire objects.</li>
<li>The Hellfire rows count only the files found in the Hellfire archives. The Hellfire object row uses the same object list as the original game.</li>
</ul>
</div>
</section>
<section id="exceptions">
<div class="prose">
<h2>What is not reproduced</h2>
<p>Of the 136,936 frames with a shadow, 319 are not reproduced exactly. They fall into four groups. A fifth case, the cauldron, is reproduced exactly but cannot be split cleanly into body and shadow. The sprites on the right are drawn as stored, with unexplained pixels marked in pink and stray pixels in red.</p>
</div>
<div class="case">
<div class="prose">
<p><strong>The warrior with only a shield, standing in town in heavy armour.</strong> This file leaves 771 stray and 1,318 unexplained pixels over its eight directions, and we have not found the reason. Five directions fit best with the normal ground line and three with one a row higher, but no direction is exact. The errors are on the edges of the shield's shadow. We tried and ruled out a different ground line per frame, a shifted shadow, casting from another frame or another weapon variant, a separately shadowed shield layer with its own ground line or position, and two ground lines split by row. Our best guess is that the shield was redrawn after the shadow pass, but we have no direct evidence for it.</p>
</div>
<figure class="hero">
<canvas data-sprite="p:whust" data-dir="5" data-mode="errors" aria-label="Warrior with a shield standing in town, with the pixels the function does not reproduce marked"></canvas>
<figcaption>Facing north-east, the direction with the most errors.</figcaption>
</figure>
</div>
<div class="case">
<div class="prose">
<p><strong>The same warrior walking in light armour.</strong> One direction leaves 15 unexplained pixels, two or three per frame on the upper left edge of the shadow, in seven of its eight frames.</p>
</div>
<figure class="hero">
<canvas data-sprite="p:wluwl" data-dir="3" data-mode="errors" aria-label="Warrior with a shield walking in town, with the unexplained pixels marked"></canvas>
<figcaption>Facing north-west, the only direction with errors.</figcaption>
</figure>
</div>
<div class="case">
<div class="prose">
<p><strong>Wirt.</strong> He fits the first-frame rule except for 38 stray pixels over his 20 frames. They are cast by 44 pixels on the edge of his outline, one of them next to the peg leg in every frame. No other ground line does better. Those edge pixels were probably added after the shadow pass, though again we have no direct evidence.</p>
</div>
<figure class="hero">
<canvas data-sprite="t:pegkid1" data-dir="0" data-mode="errors" aria-label="Wirt, with the stray shadow pixels marked"></canvas>
<figcaption>Wirt has a single view. Every frame has one to four stray pixels.</figcaption>
</figure>
</div>
<div class="case">
<div class="prose">
<p><strong>Four Hellfire monster files.</strong> They have no stray pixels but leave 4,815 unexplained black pixels, 4,787 of them in Na-Krul's death and special animations. We have not investigated these yet.</p>
</div>
<figure class="hero">
<canvas data-sprite="m:nkrd" data-dir="0" data-mode="errors" aria-label="Na-Krul's death animation, with the unexplained pixels marked"></canvas>
<figcaption>Na-Krul's death animation, facing south.</figcaption>
</figure>
</div>
<div class="case">
<div class="prose">
<p><strong>The cauldron.</strong> All three frames count as reproduced exactly, but the split into body and shadow is wrong. The pot is nearly black: 664 to 802 of its pixels per frame are pure black, and 365 of them lie where the pixels above them cast a shadow. A black body pixel in that position cannot be told apart from shadow, so the function takes the lower part of the pot for shadow, and removing the shadow removes it too.</p>
</div>
<figure class="hero">
<canvas data-sprite="o:cauldren" data-dir="0" data-mode="body" aria-label="The cauldron with its shadow removed, missing part of its base"></canvas>
<figcaption>The cauldron with the shadow removed. The gaps in its base are body pixels that were taken for shadow.</figcaption>
</figure>
</div>
<div class="prose">
<p>Some sprites have black pixels and no cast shadow at all. In the original game these are two door types, the bookcase, the trap hole and the mushroom patch. Their black pixels are painted cracks, outlines and holes, and the area where a shadow would fall is empty. The fountain of tears has eight frames: the four that the game plays have no black pixels, and the other four carry a shadow that the function reproduces exactly. Hellfire's two pod objects have four black pixels each and no shadow.</p>
</div>
</section>
<section class="prose">
<h2>How it was found</h2>
<ul class="notes">
<li>The starting point was Joan Karadimov's description of the transform and an approximate matrix for it, with a height scale near 1/3 and a shear near 0.26, posted in <a href="https://github.com/diasurgical/DevilutionX/issues/8718#issuecomment-5893938916">a comment on DevilutionX issue #8718</a>. Fitting a single transform, in several number formats, got close but never exact.</li>
<li>The next pass assumed no formula. For each sprite row it searched for the shadow row and horizontal shift that never put a shadow pixel on a transparent one. Across all frames exactly one combination survived per row, and together they form the table that the function above generates.</li>
<li>The ground line was first taken to be the lowest non-black row, which fits the shareware warrior. The rogue's heavy armour has black boots, and for it only the lowest opaque row works.</li>
<li>A black body pixel that lies inside the shadow of the pixels above it cannot be told apart from shadow. Where such a pixel is in the right place to cast an otherwise unexplained shadow pixel, the page counts it as body. In the original player sprites that leaves 1,333 black pixels unexplained, out of 23 million.</li>
<li>Monsters and objects were classified by the rule under which their non-black pixels cast no stray shadow. Objects are weaker evidence because most have only a few frames. Of 34 original objects with black pixels, 15 fit the first-frame rule and 13 the each-frame rule.</li>
</ul>
</section>
</div>
<script>
const DATA = /*SHADOW_DATA*/;
const CLASSES = { w: 'Warrior', r: 'Rogue', s: 'Sorcerer' };
const ARMOURS = { l: 'light', m: 'medium', h: 'heavy' };
const ANIMS = { as: 'Stand, dungeon', st: 'Stand, town', aw: 'Walk, dungeon', wl: 'Walk, town', at: 'Attack', ht: 'Hit', lm: 'Lightning spell', fm: 'Fire spell', qm: 'Magic spell', dt: 'Death', bl: 'Block' };
const WEAPONS = { n: 'unarmed', u: 'shield', s: 'sword', m: 'mace', b: 'bow', a: 'axe', d: 'sword and shield', t: 'staff', h: 'mace and shield' };
const DIRS = ['S', 'SW', 'W', 'NW', 'N', 'NE', 'E', 'SE'];
const T = 255; // transparent
function bytes(b64) {
const s = atob(b64), out = new Uint8Array(s.length);
for (let i = 0; i < s.length; i++) out[i] = s.charCodeAt(i);
return out;
}
const palette = bytes(DATA.palette);
// The pixels of all frames are one zlib stream, which the browser inflates.
async function inflate(data) {
const stream = new Blob([data]).stream().pipeThrough(new DecompressionStream('deflate'));
return new Uint8Array(await new Response(stream).arrayBuffer());
}
// The shadow function. Returns the index of the shadow pixel, -1 if (x, y) casts none
// and -2 if the shadow falls outside the frame.
function castTo(x, y, B, w, h) {
if (y > B) return -1;
const v = Math.trunc((B - y) / 3);
const ys = B - 2 - v;
const xs = x - Math.trunc((3 * v) / 4);
if (xs < 0 || xs >= w || ys < 0 || ys >= h) return -2;
return ys * w + xs;
}
function baselineOf(px, w, h) {
for (let y = h - 1; y >= 0; y--)
for (let x = 0; x < w; x++)
if (px[y * w + x] !== T) return y;
return -1;
}
// Splits a frame into body and shadow, then casts the shadow again.
function analyse(px, w, h, B) {
const n = w * h;
const body = new Uint8Array(n), shadow = new Uint8Array(n), orphan = new Uint8Array(n);
for (let y = 0; y < h; y++)
for (let x = 0; x < w; x++) {
const i = y * w + x;
if (px[i] === T || px[i] === 0) continue;
body[i] = 1;
const t = castTo(x, y, B, w, h);
if (t >= 0) shadow[t] = 1;
}
// A black pixel that no pixel above it shadows must be part of the body, and casts too.
for (let y = 0; y < h; y++) {
const row = [];
for (let x = 0; x < w; x++) {
const i = y * w + x;
if (px[i] === 0 && !shadow[i]) row.push(x);
}
for (const x of row) {
const i = y * w + x, t = castTo(x, y, B, w, h);
if (t >= 0 && px[t] === T) {
// A black pixel hidden in the shadow above may be the body pixel that casts this one.
const v = B - 2 - y, sx = x + Math.trunc((3 * v) / 4);
let found = false;
for (let sy = B - 3 * v - 2; v >= 2 && sy <= B - 3 * v && !found; sy++) {
const j = sy * w + sx;
if (sx < 0 || sx >= w || sy < 0 || sy >= h || px[j] !== 0 || body[j] || orphan[j]) continue;
body[j] = 1;
shadow[i] = 1;
found = true;
}
if (!found) orphan[i] = 1;
continue;
}
body[i] = 1;
if (t >= 0) shadow[t] = 1;
}
}
const s = { black: 0, shadow: 0, bodyBlack: 0, orphan: 0, stray: 0 };
for (let i = 0; i < n; i++) {
if (px[i] === 0) {
s.black++;
if (orphan[i]) s.orphan++; else if (body[i]) s.bodyBlack++; else s.shadow++;
}
if (shadow[i] && px[i] === T) s.stray++;
}
s.exact = s.orphan === 0 && s.stray === 0;
return { body, shadow, orphan, stats: s };
}
// Decodes every sprite and analyses every frame up front. `pixels` holds the cropped frames
// back to back, in the order they are listed.
const groups = new Map(); // name -> [per direction]
function decode(pixels) {
let at = 0;
for (const sp of DATA.sprites) {
const frames = sp.frames.map(([x0, y0, cw, ch]) => {
const px = new Uint8Array(sp.w * sp.h).fill(T);
for (let y = 0; y < ch; y++, at += cw) px.set(pixels.subarray(at, at + cw), (y0 + y) * sp.w + x0);
return { px };
});
// The baseline is read from the first frame (plus a constant for flying monsters) or from each frame.
const B = baselineOf(frames[0].px, sp.w, sp.h) + sp.offset;
const total = { frames: frames.length, black: 0, shadow: 0, bodyBlack: 0, orphan: 0, stray: 0, exact: 0 };
for (const f of frames) {
f.B = sp.own ? baselineOf(f.px, sp.w, sp.h) : B;
Object.assign(f, analyse(f.px, sp.w, sp.h, f.B));
for (const k of ['black', 'shadow', 'bodyBlack', 'orphan', 'stray']) total[k] += f.stats[k];
if (f.stats.exact) total.exact++;
}
const key = sp.kind + ':' + sp.name;
if (!groups.has(key)) groups.set(key, []);
const rule = sp.own ? 'each frame' : sp.offset ? `first frame + ${sp.offset}` : 'first frame';
groups.get(key)[sp.dir] = { w: sp.w, h: sp.h, kind: sp.kind, label: sp.label, rule, own: sp.own, frames, total };
}
}
function cssColor(name) {
const v = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
const m = /^#([0-9a-f]{6})$/i.exec(v);
const n = m ? parseInt(m[1], 16) : 0x808080;
return [n >> 16, (n >> 8) & 255, n & 255];
}
function themeColors() {
return { ok: cssColor('--shadow-ok'), bodyBlack: cssColor('--body-black'), orphan: cssColor('--orphan'), dim: cssColor('--body-dim') };
}
// Modes: 'orig' as stored, 'body' without the shadow, 'regen' with the shadow cast by the function,
// 'errors' as stored with the unexplained and stray pixels marked, anything else the classification.
function paint(canvas, g, f, mode, colors) {
if (canvas.width !== g.w || canvas.height !== g.h) { canvas.width = g.w; canvas.height = g.h; }
const ctx = canvas.getContext('2d'), img = ctx.createImageData(g.w, g.h), d = img.data;
const put = (i, r, gg, b) => { d[i * 4] = r; d[i * 4 + 1] = gg; d[i * 4 + 2] = b; d[i * 4 + 3] = 255; };
const pal = (i, c) => put(i, palette[c * 3], palette[c * 3 + 1], palette[c * 3 + 2]);
for (let i = 0; i < g.w * g.h; i++) {
const c = f.px[i];
if (mode === 'orig') { if (c !== T) pal(i, c); }
else if (mode === 'body') { if (f.body[i]) pal(i, c); }
else if (mode === 'regen') { if (f.body[i]) pal(i, c); else if (f.shadow[i]) put(i, 0, 0, 0); }
else if (mode === 'errors') { if (f.orphan[i]) put(i, ...colors.orphan); else if (c !== T) pal(i, c); else if (f.shadow[i]) put(i, 255, 0, 0); }
else {
if (f.orphan[i]) put(i, ...colors.orphan);
else if (f.body[i]) put(i, ...(c === 0 ? colors.bodyBlack : colors.dim));
else if (f.shadow[i]) put(i, ...(c === T ? [255, 0, 0] : colors.ok));
}
}
ctx.putImageData(img, 0, 0);
}
const $ = (id) => document.getElementById(id);
const state = { name: null, dir: 0, frame: 0, playing: true };
const dirCanvases = [];
const KINDS = { p: 'Players', m: 'Monsters', t: 'Townspeople', o: 'Objects' };
function label(key) {
const g = groups.get(key)[0], name = key.slice(2);
if (g.label) return g.label;
return `${CLASSES[name[0]]}, ${ARMOURS[name[1]]} armour · ${ANIMS[name.slice(3)] || name.slice(3)} · ${WEAPONS[name[2]] || name[2]}`;
}
function current() { return groups.get(state.name)[state.dir]; }
function render() {
const colors = themeColors();
const g = current(), f = g.frames[state.frame % g.frames.length];
paint($('cOrig'), g, f, 'orig', colors);
paint($('cBody'), g, f, 'body', colors);
paint($('cRegen'), g, f, 'regen', colors);
paint($('cDiff'), g, f, 'diff', colors);
const s = f.stats;
$('diffNote').textContent = s.exact ? `Frame ${state.frame + 1}: identical to the original` : `Frame ${state.frame + 1}: ${s.orphan + s.stray} pixel${s.orphan + s.stray === 1 ? '' : 's'} differ`;
$('frameLabel').textContent = `Frame ${state.frame + 1} of ${g.frames.length}`;
$('frame').value = state.frame;
const all = groups.get(state.name);
if (all.length > 1) all.forEach((dg, d) => paint(dirCanvases[d], dg, dg.frames[state.frame % dg.frames.length], 'regen', colors));
}
function selectDir(d) {
state.dir = d;
document.querySelectorAll('.dir').forEach((el, i) => el.setAttribute('aria-pressed', String(i === d)));
const g = current(), t = g.total;
$('frame').max = g.frames.length - 1;
state.frame %= g.frames.length;
const single = groups.get(state.name).length === 1;
const row = g.own ? 'varies' : g.frames[0].B;
$('readout').innerHTML = `<tr><td>${single ? 'only view' : DIRS[d]}</td><td>${t.frames}</td><td>${g.rule}</td><td>${row}</td><td>${t.black}</td><td>${t.shadow}</td><td>${t.bodyBlack}</td><td>${t.orphan}</td><td>${t.stray}</td><td>${t.exact} / ${t.frames}</td></tr>`;
render();
}
function selectSprite(name) {
state.name = name;
state.frame = 0;
const all = groups.get(name);
// Sprites with a single view (townspeople, objects) need no direction strip.
$('dirs').hidden = all.length === 1;
all.forEach((dg, d) => {
const exact = dg.total.exact === dg.total.frames;
document.querySelectorAll('.dir small')[d].innerHTML = `<b>${DIRS[d]}</b><span>${exact ? 'exact' : (dg.total.orphan + dg.total.stray) + ' px'}</span>`;
});
selectDir(state.dir < all.length ? state.dir : 0);
}
function start() {
const optgroups = {};
for (const key of groups.keys()) {
const kind = key[0];
if (!optgroups[kind]) {
optgroups[kind] = document.createElement('optgroup');
optgroups[kind].label = KINDS[kind];
$('sprite').appendChild(optgroups[kind]);
}
const o = document.createElement('option');
o.value = key;
o.textContent = label(key);
optgroups[kind].appendChild(o);
}
for (let d = 0; d < 8; d++) {
const b = document.createElement('button');
b.type = 'button';
b.className = 'dir';
b.id = 'dir' + d;
b.setAttribute('aria-label', 'Direction ' + DIRS[d]);
const c = document.createElement('canvas');
dirCanvases.push(c);
b.append(c, document.createElement('small'));
b.addEventListener('click', () => selectDir(d));
$('dirs').appendChild(b);
}
$('sprite').addEventListener('change', (e) => selectSprite(e.target.value));
$('play').addEventListener('click', () => { state.playing = !state.playing; $('play').textContent = state.playing ? 'Pause' : 'Play'; });
$('frame').addEventListener('input', (e) => { state.frame = +e.target.value; state.playing = false; $('play').textContent = 'Play'; render(); });
const still = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (still) { state.playing = false; $('play').textContent = 'Play'; }
selectSprite(groups.keys().next().value);
// Sprites shown next to the text: canvases with data-sprite, data-dir and data-mode. They ignore
// the controls. Without animation each shows the frame that differs most from the original.
const examples = [];
for (const canvas of document.querySelectorAll('canvas[data-sprite]')) {
const g = (groups.get(canvas.dataset.sprite) || [])[+canvas.dataset.dir || 0];
if (!g) { canvas.closest('figure').hidden = true; continue; }
const errors = g.frames.map((f) => f.stats.orphan + f.stats.stray);
examples.push({ canvas, g, mode: canvas.dataset.mode, frame: still ? errors.indexOf(Math.max(...errors)) : 0 });
}
const drawExamples = () => {
const colors = themeColors();
for (const ex of examples) paint(ex.canvas, ex.g, ex.g.frames[ex.frame % ex.g.frames.length], ex.mode, colors);
};
drawExamples();
setInterval(() => {
if (!still) {
for (const ex of examples) ex.frame++;
drawExamples();
}
if (!state.playing) return;
state.frame = (state.frame + 1) % current().frames.length;
render();
}, 110);
}
inflate(bytes(DATA.pixels)).then((pixels) => { decode(pixels); start(); }, () => { $('loadError').hidden = false; });
</script>
+675
View File
@@ -0,0 +1,675 @@
/**
* @file extract_check.cpp
*
* Runs the game's `ExtractClxShadows` on every player sprite of an MPQ and
* checks the result against the original sprites:
*
* - only black pixels are removed from a sprite
* - drawing the new sprite over its shadow mask filled with black gives back
* the original
*
* Prints the number of pixels removed as shadow, to compare with the research
* tool's `verify` command ("reproduced as shadow").
*
* Also reports the size of the shadow masks, which are stored in the CLX frame
* headers.
*
* Usage: shadow_extract_check <mpq> <rule | @rules.tsv>
* [--monsters|--towners|--objects][=<tsv>]
*
* The rule is either one rule for every file (e.g. `FirstFrame`) or `@`
* followed by the output of `shadow_search ... filerules` (path and rule per
* line). Files without a shadow are skipped.
*/
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <string>
#include <string_view>
#include "engine/render/clx_render.hpp"
#include "engine/surface.hpp"
#include "sprites.hpp"
#include "utils/clx_shadow.hpp"
#include "utils/palette_blending.hpp"
#include "utils/sdl_wrap.h"
namespace devilution {
// The game library reports fatal errors through this function.
[[noreturn]] void app_fatal(std::string_view str) {
std::fprintf(stderr, "fatal: %.*s\n", static_cast<int>(str.size()),
str.data());
std::abort();
}
// Called by the SDL wrappers when SDL fails.
[[noreturn]] void ErrDlg(const char *title, std::string_view error,
std::string_view /*logFilePath*/, int /*logLineNr*/) {
std::fprintf(stderr, "%s: %.*s\n", title, static_cast<int>(error.size()),
error.data());
std::abort();
}
} // namespace devilution
int main(int argc, char **argv) {
using namespace shadow_search;
if (argc < 3) {
std::fprintf(stderr,
"usage: %s <mpq> <rule | @rules.tsv> "
"[--monsters|--towners|--objects][=<tsv>]\n",
argv[0]);
return 2;
}
auto archive = devilution::MpqArchive::Open(argv[1]);
if (!archive) {
std::fprintf(stderr, "failed to open %s: %s\n", argv[1],
archive.error().c_str());
return 1;
}
// `trn0 <path>...`: prints what each colour translation table maps black
// (index 0) to. A shadow drawn separately as black only matches the baked-in
// one if that is 0.
if (std::string(argv[2]) == "trn0") {
int nonZero = 0, found = 0;
for (int i = 3; i < argc; ++i) {
size_t size = 0;
const std::unique_ptr<uint8_t[]> data =
archive->HasFile(argv[i]) ? ReadMpqFile(*archive, argv[i], size)
: nullptr;
if (data == nullptr || size == 0)
continue;
++found;
if (data[0] != 0) {
++nonZero;
std::printf("%s maps black to %d\n", argv[i], data[0]);
}
}
std::printf("%d tables found, %d map black to another colour\n", found,
nonZero);
return 0;
}
// `overrun-cl2`: the same count as `overrun` but on the raw CL2 commands,
// before conversion to CLX.
if (std::string(argv[2]) == "overrun-cl2") {
long long frames = 0, framesWithOverrun = 0, rowEndsOpaqueThenOpaque = 0;
const SpriteSet players = LoadPlayerSprites(*archive);
for (const SpriteFile &file : players.files) {
size_t size = 0;
const std::unique_ptr<uint8_t[]> data =
ReadMpqFile(*archive, file.path, size);
const auto le32 = [&](size_t pos) {
return static_cast<uint32_t>(
data[pos] | (data[pos + 1] << 8) | (data[pos + 2] << 16) |
(static_cast<uint32_t>(data[pos + 3]) << 24));
};
const uint32_t first = le32(0);
const uint32_t numGroups = le32(first * 4 + 4) != size ? first / 4 : 1;
for (uint32_t g = 0; g < numGroups; ++g) {
const size_t group = numGroups == 1 ? 0 : le32(g * 4);
const uint32_t numFrames = le32(group);
for (uint32_t f = 0; f < numFrames; ++f) {
const uint8_t *begin = &data[group + le32(group + 4 * (f + 1))];
const uint8_t *end = &data[group + le32(group + 4 * (f + 2))];
const uint8_t *src = begin + (begin[0] | (begin[1] << 8));
long long x = 0;
bool any = false, prevOpaqueEndedRow = false;
++frames;
while (src < end) {
const uint8_t control = *src++;
long long len;
bool opaque = true;
if (!devilution::IsClxOpaque(control)) {
len = control;
opaque = false;
} else if (devilution::IsClxOpaqueFill(control)) {
len = devilution::GetClxOpaqueFillWidth(control);
++src;
} else {
len = devilution::GetClxOpaquePixelsWidth(control);
src += len;
}
if (opaque && x + len > file.width)
any = true;
// An opaque run that ends exactly at the row end, followed by an
// opaque run: the converter joins the two.
if (opaque && prevOpaqueEndedRow)
++rowEndsOpaqueThenOpaque;
prevOpaqueEndedRow = opaque && x + len == file.width;
x = (x + len) % file.width;
}
if (any)
++framesWithOverrun;
}
}
}
std::printf("%lld raw CL2 frames, %lld with an opaque run past the end of "
"a row, %lld places where an opaque run ends a row and another "
"begins the next\n",
frames, framesWithOverrun, rowEndsOpaqueThenOpaque);
return 0;
}
// `overrun`: counts opaque runs that continue past the end of a sprite row in
// the player sprites. The renderer draws such a run on to the right, outside
// of the sprite, instead of wrapping it.
if (std::string(argv[2]) == "overrun") {
long long sprites = 0, spritesWithOverrun = 0, overrunPixels = 0;
std::string example;
const SpriteSet players = LoadPlayerSprites(*archive);
for (const SpriteFile &file : players.files) {
const int width = file.width;
size_t size = 0;
std::unique_ptr<uint8_t[]> data = ReadMpqFile(*archive, file.path, size);
const devilution::OwnedClxSpriteListOrSheet clx = devilution::Cl2ToClx(
std::move(data), size,
devilution::PointerOrValue<uint16_t>{static_cast<uint16_t>(width)});
long long fileOverrun = 0;
for (uint16_t l = 0; l < clx.numLists(); ++l) {
const ClxSpriteList list = clx.sheet()[l];
for (uint32_t i = 0; i < list.numSprites(); ++i) {
const ClxSprite sprite = list[i];
++sprites;
const uint8_t *src = sprite.pixelData();
const uint8_t *end = src + sprite.pixelDataSize();
long long x = 0;
bool any = false;
while (src < end) {
const uint8_t control = *src++;
long long len;
bool opaque = true;
if (!devilution::IsClxOpaque(control)) {
len = control;
opaque = false;
} else if (devilution::IsClxOpaqueFill(control)) {
len = devilution::GetClxOpaqueFillWidth(control);
++src;
} else {
len = devilution::GetClxOpaquePixelsWidth(control);
src += len;
}
if (opaque && x + len > width) {
any = true;
fileOverrun += x + len - width;
}
x = (x + len) % width;
}
if (any)
++spritesWithOverrun;
}
}
overrunPixels += fileOverrun;
if (fileOverrun != 0 && example.empty())
example = file.path;
}
std::printf("%lld sprites, %lld with an opaque run past the end of a row, "
"%lld such pixels, e.g. %s\n",
sprites, spritesWithOverrun, overrunPixels, example.c_str());
return 0;
}
// `render <rule | @rules.tsv> [--monsters...]`: times drawing every sprite
// frame with its shadow baked in (as before shadow extraction) against
// drawing the shadow mask and then the sprite.
if (std::string(argv[2]) == "render" && argc >= 4) {
using Clock = std::chrono::steady_clock;
std::map<std::string, std::string> renderRules;
std::string renderRuleForAll = argv[3];
if (renderRuleForAll[0] == '@') {
for (const auto &row : ReadTsv(renderRuleForAll.substr(1)))
if (row.size() >= 2)
renderRules[row[0]] = row[1];
renderRuleForAll.clear();
}
SpriteSet renderSet;
const std::string renderSelector = argc >= 5 ? argv[4] : "";
if (renderSelector.empty()) {
renderSet = LoadPlayerSprites(*archive);
} else {
const size_t eq = renderSelector.find('=');
const std::string kind = renderSelector.substr(
2, eq == std::string::npos ? std::string::npos : eq - 2);
const std::string defaultTsv = kind == "monsters" ? "monstdat"
: kind == "objects" ? "objdat"
: "towners";
const std::string tsv =
eq == std::string::npos
? "assets/txtdata/" + kind + "/" + defaultTsv + ".tsv"
: renderSelector.substr(eq + 1);
renderSet = kind == "monsters" ? LoadMonsterSprites(*archive, tsv)
: kind == "objects" ? LoadObjectSprites(*archive, tsv)
: LoadTownerSprites(*archive, tsv);
}
renderSet.frames.clear();
// Every frame of every file that has an extractable shadow, before and
// after extraction.
std::vector<devilution::OwnedClxSpriteListOrSheet> owned;
std::vector<std::pair<ClxSprite, ClxSprite>> sprites;
for (const SpriteFile &file : renderSet.files) {
const auto rule = devilution::ParseShadowRule(
renderRuleForAll.empty() ? renderRules[file.path] : renderRuleForAll);
if (!rule)
return 2;
if (!rule->canExtractShadow())
continue;
size_t size = 0;
std::unique_ptr<uint8_t[]> data = ReadMpqFile(*archive, file.path, size);
const devilution::PointerOrValue<uint16_t> width{
static_cast<uint16_t>(file.width)};
const bool isCel =
file.path.size() > 4 &&
file.path.compare(file.path.size() - 4, 4, ".cel") == 0;
owned.push_back(isCel
? devilution::CelToClx(data.get(), size, width)
: devilution::Cl2ToClx(std::move(data), size, width));
const size_t originalIndex = owned.size() - 1;
std::optional<devilution::OwnedClxSpriteListOrSheet> extracted =
devilution::ExtractClxShadows(owned[originalIndex], *rule);
if (!extracted.has_value())
continue;
owned.push_back(std::move(*extracted));
const devilution::OwnedClxSpriteListOrSheet &before =
owned[originalIndex];
const devilution::OwnedClxSpriteListOrSheet &after = owned.back();
const auto addList = [&](ClxSpriteList a, ClxSpriteList b) {
for (uint32_t i = 0; i < a.numSprites(); ++i)
sprites.emplace_back(a[i], b[i]);
};
if (before.isSheet()) {
for (uint16_t l = 0; l < before.numLists(); ++l)
addList(before.sheet()[l], after.sheet()[l]);
} else {
addList(before.list(), after.list());
}
}
const devilution::SDLSurfaceUniquePtr sdlSurface =
devilution::SDLWrap::CreateRGBSurfaceWithFormat(
/*flags=*/0, /*width=*/640, /*height=*/480, /*depth=*/8,
SDL_PIXELFORMAT_INDEX8);
const devilution::Surface out{sdlSurface.get()};
// A light table, as used for most sprites in the dungeon. Black stays
// black.
uint8_t lightTable[256];
for (unsigned i = 0; i < 256; ++i)
lightTable[i] = static_cast<uint8_t>(i == 0 ? 0 : 1 + (i * 7) % 255);
for (unsigned i = 0; i < 256; ++i)
devilution::paletteTransparencyLookup[0][i] = static_cast<uint8_t>(i / 2);
#if DEVILUTIONX_PALETTE_TRANSPARENCY_BLACK_16_LUT
for (unsigned i = 0; i < 256; ++i)
for (unsigned j = 0; j < 256; ++j)
devilution::paletteTransparencyLookupBlack16[i | (j << 8U)] =
static_cast<uint16_t>(
devilution::paletteTransparencyLookup[0][i] |
(devilution::paletteTransparencyLookup[0][j] << 8U));
#endif
// Fully on screen, away from 4-byte alignment.
const devilution::Point position{201, 400};
constexpr int Passes = 7;
const int repeats = static_cast<int>(
std::max<size_t>(1, 2000000 / std::max<size_t>(1, sprites.size())));
const auto measure = [&](auto &&draw) {
double best = 1e30;
for (int pass = 0; pass < Passes; ++pass) {
const Clock::time_point t0 = Clock::now();
for (int r = 0; r < repeats; ++r)
for (const auto &[before, after] : sprites)
draw(before, after);
best = std::min(
best, std::chrono::duration<double, std::nano>(Clock::now() - t0)
.count());
}
return best / (static_cast<double>(repeats) * sprites.size());
};
struct Variant {
const char *name;
double direct, lit;
};
using devilution::ClxDraw;
using devilution::ClxDrawShadow;
using devilution::ClxDrawShadowBlended;
using devilution::ClxDrawTRN;
const Variant variants[] = {
{"baked shadow (before)", measure([&](ClxSprite before, ClxSprite) {
ClxDraw(out, position, before);
}),
measure([&](ClxSprite before, ClxSprite) {
ClxDrawTRN(out, position, before, lightTable);
})},
{"separate shadow, opaque", measure([&](ClxSprite, ClxSprite after) {
ClxDrawShadow(out, position, after);
ClxDraw(out, position, after);
}),
measure([&](ClxSprite, ClxSprite after) {
ClxDrawShadow(out, position, after);
ClxDrawTRN(out, position, after, lightTable);
})},
{"separate shadow, transparent",
measure([&](ClxSprite, ClxSprite after) {
ClxDrawShadowBlended(out, position, after);
ClxDraw(out, position, after);
}),
measure([&](ClxSprite, ClxSprite after) {
ClxDrawShadowBlended(out, position, after);
ClxDrawTRN(out, position, after, lightTable);
})},
{"sprite only, no shadow drawn",
measure([&](ClxSprite, ClxSprite after) {
ClxDraw(out, position, after);
}),
measure([&](ClxSprite, ClxSprite after) {
ClxDrawTRN(out, position, after, lightTable);
})},
};
std::printf("%zu sprite frames, %d repeats, best of %d passes; ns per "
"sprite drawn\n",
sprites.size(), repeats, Passes);
std::printf("%-30s %12s %9s %14s %9s\n", "", "no lighting", "",
"light table", "");
for (const Variant &v : variants)
std::printf("%-30s %9.1f ns %+8.1f%% %11.1f ns %+8.1f%%\n", v.name,
v.direct, 100.0 * (v.direct / variants[0].direct - 1), v.lit,
100.0 * (v.lit / variants[0].lit - 1));
return 0;
}
// `timing <rule | @rules.tsv> [--monsters...]`: times the CL2/CEL conversion
// that the game already does when it loads sprites against the shadow
// extraction, per sprite file, on one thread.
if (std::string(argv[2]) == "timing" && argc >= 4) {
using Clock = std::chrono::steady_clock;
std::map<std::string, std::string> timingRules;
std::string timingRuleForAll = argv[3];
if (timingRuleForAll[0] == '@') {
for (const auto &row : ReadTsv(timingRuleForAll.substr(1)))
if (row.size() >= 2)
timingRules[row[0]] = row[1];
timingRuleForAll.clear();
}
SpriteSet timingSet;
const std::string timingSelector = argc >= 5 ? argv[4] : "";
if (timingSelector.empty()) {
timingSet = LoadPlayerSprites(*archive);
} else {
const size_t eq = timingSelector.find('=');
const std::string kind = timingSelector.substr(
2, eq == std::string::npos ? std::string::npos : eq - 2);
const std::string defaultTsv = kind == "monsters" ? "monstdat"
: kind == "objects" ? "objdat"
: "towners";
const std::string tsv =
eq == std::string::npos
? "assets/txtdata/" + kind + "/" + defaultTsv + ".tsv"
: timingSelector.substr(eq + 1);
timingSet = kind == "monsters" ? LoadMonsterSprites(*archive, tsv)
: kind == "objects" ? LoadObjectSprites(*archive, tsv)
: LoadTownerSprites(*archive, tsv);
}
std::vector<long long> frameCount(timingSet.files.size());
for (const Frame &f : timingSet.frames)
++frameCount[f.file];
struct Timing {
double read = 0, convert = 0, extract = 0;
long long frames = 0, files = 0, bytes = 0;
};
Timing total;
// Players: one entry per class/armour/weapon (what one character has loaded
// at most). Monsters: one entry per monster. Others: one entry per file.
std::map<std::string, Timing> byGroup;
constexpr int Repeats = 5;
for (size_t fileIndex = 0; fileIndex < timingSet.files.size();
++fileIndex) {
const SpriteFile &file = timingSet.files[fileIndex];
const auto rule = devilution::ParseShadowRule(
timingRuleForAll.empty() ? timingRules[file.path] : timingRuleForAll);
if (!rule)
return 2;
const bool isCel =
file.path.size() > 4 &&
file.path.compare(file.path.size() - 4, 4, ".cel") == 0;
const devilution::PointerOrValue<uint16_t> width{
static_cast<uint16_t>(file.width)};
// Best of several runs, to leave out cache warm-up and scheduling noise.
double bestRead = 1e30, bestConvert = 1e30, bestExtract = 1e30;
size_t size = 0;
for (int repeat = 0; repeat < Repeats; ++repeat) {
const Clock::time_point t0 = Clock::now();
std::unique_ptr<uint8_t[]> data =
ReadMpqFile(*archive, file.path, size);
const Clock::time_point t1 = Clock::now();
const devilution::OwnedClxSpriteListOrSheet clx =
isCel ? devilution::CelToClx(data.get(), size, width)
: devilution::Cl2ToClx(std::move(data), size, width);
const Clock::time_point t2 = Clock::now();
const std::optional<devilution::OwnedClxSpriteListOrSheet> extracted =
devilution::ExtractClxShadows(clx, *rule);
const Clock::time_point t3 = Clock::now();
bestRead = std::min(
bestRead,
std::chrono::duration<double, std::milli>(t1 - t0).count());
bestConvert = std::min(
bestConvert,
std::chrono::duration<double, std::milli>(t2 - t1).count());
bestExtract = std::min(
bestExtract,
std::chrono::duration<double, std::milli>(t3 - t2).count());
}
const std::string group = file.classChar == 'M'
? file.name.substr(0, file.name.size() - 1)
: file.classChar == 'T' || file.classChar == 'O'
? file.name
: file.name.substr(0, 3);
for (Timing *t : {&total, &byGroup[group]}) {
t->read += bestRead;
t->convert += bestConvert;
t->extract += bestExtract;
t->frames += frameCount[fileIndex];
t->bytes += static_cast<long long>(size);
++t->files;
}
}
std::printf("files %lld, frames %lld, %.1f MB\n", total.files, total.frames,
total.bytes / 1e6);
std::printf("all files: read %.0f ms, convert %.0f ms, extract shadows "
"%.0f ms (%.2fx the conversion, %.1f us per frame)\n",
total.read, total.convert, total.extract,
total.extract / total.convert,
1000.0 * total.extract / total.frames);
double sumExtract = 0, maxExtract = 0, sumBase = 0;
std::string maxGroup;
for (const auto &[name, t] : byGroup) {
sumExtract += t.extract;
sumBase += t.read + t.convert;
if (t.extract > maxExtract) {
maxExtract = t.extract;
maxGroup = name;
}
}
const Timing &worst = byGroup[maxGroup];
std::printf("per group (%zu groups): read+convert %.2f ms on average, "
"extract %.2f ms on average\n",
byGroup.size(), sumBase / byGroup.size(),
sumExtract / byGroup.size());
std::printf("slowest group %s: %lld files, %lld frames, read+convert %.2f "
"ms, extract %.2f ms\n",
maxGroup.c_str(), worst.files, worst.frames,
worst.read + worst.convert, worst.extract);
return 0;
}
std::map<std::string, std::string> ruleByPath;
std::string ruleForAll = argv[2];
if (ruleForAll[0] == '@') {
for (const auto &row : ReadTsv(ruleForAll.substr(1)))
if (row.size() >= 2)
ruleByPath[row[0]] = row[1];
ruleForAll.clear();
}
SpriteSet set;
const std::string selector = argc >= 4 ? argv[3] : "";
if (selector.empty()) {
set = LoadPlayerSprites(*archive);
} else {
const size_t eq = selector.find('=');
const std::string kind = selector.substr(
2, eq == std::string::npos ? std::string::npos : eq - 2);
const std::string defaultTsv = kind == "monsters" ? "monstdat"
: kind == "objects" ? "objdat"
: "towners";
const std::string tsv =
eq == std::string::npos
? "assets/txtdata/" + kind + "/" + defaultTsv + ".tsv"
: selector.substr(eq + 1);
set = kind == "monsters" ? LoadMonsterSprites(*archive, tsv)
: kind == "objects" ? LoadObjectSprites(*archive, tsv)
: LoadTownerSprites(*archive, tsv);
}
size_t files = 0, maxMaskBytes = 0, lists = 0;
uint64_t outputHash = 1469598103934665603ULL;
std::string maxMaskFile;
long long frames = 0, blackPixels = 0, removed = 0, removedNotBlack = 0,
added = 0, maskPixels = 0, maskOnTransparent = 0, mismatches = 0;
long long originalBytes = 0, spriteBytes = 0, maskBytes = 0;
size_t frameIndex = 0;
for (size_t fileIndex = 0; fileIndex < set.files.size(); ++fileIndex) {
const SpriteFile &file = set.files[fileIndex];
const std::string ruleName =
ruleForAll.empty() ? ruleByPath[file.path] : ruleForAll;
const auto rule = devilution::ParseShadowRule(ruleName);
if (!rule) {
std::fprintf(stderr, "%s: %s\n", file.path.c_str(), rule.error().c_str());
return 2;
}
if (!rule->canExtractShadow()) {
while (frameIndex < set.frames.size() &&
set.frames[frameIndex].file == static_cast<int>(fileIndex))
++frameIndex;
continue;
}
size_t size = 0;
std::unique_ptr<uint8_t[]> data = ReadMpqFile(*archive, file.path, size);
const devilution::PointerOrValue<uint16_t> width{
static_cast<uint16_t>(file.width)};
const bool isCel = file.path.size() > 4 &&
file.path.compare(file.path.size() - 4, 4, ".cel") == 0;
const devilution::OwnedClxSpriteListOrSheet original =
isCel ? devilution::CelToClx(data.get(), size, width)
: devilution::Cl2ToClx(std::move(data), size, width);
const std::optional<devilution::OwnedClxSpriteListOrSheet> result =
devilution::ExtractClxShadows(original, *rule);
if (!result.has_value()) {
std::fprintf(stderr, "no result for %s\n", file.path.c_str());
return 1;
}
++files;
originalBytes += static_cast<long long>(original.dataSize());
spriteBytes += static_cast<long long>(result->dataSize());
{
// A fingerprint of the output bytes, to compare implementations of the
// extraction.
const devilution::ClxSpriteListOrSheet view{*result};
const uint8_t *bytes =
view.isSheet() ? view.sheet().data() : view.list().data();
for (size_t b = 0, n = result->dataSize(); b < n; ++b)
outputHash = (outputHash ^ bytes[b]) * 1099511628211ULL;
}
const auto checkList = [&](ClxSpriteList sprites) {
++lists;
for (uint32_t i = 0; i < sprites.numSprites(); ++i, ++frameIndex) {
const size_t maskSize =
sprites[i].headerSize() - devilution::ClxSprite::BaseHeaderSize;
maskBytes += static_cast<long long>(maskSize);
if (maskSize > maxMaskBytes) {
maxMaskBytes = maskSize;
maxMaskFile = file.path;
}
const Frame &before = set.frames[frameIndex];
const Frame after = DecodeFrame(sprites[i]);
if (before.file != static_cast<int>(fileIndex) ||
after.width != before.width || after.height != before.height) {
std::fprintf(stderr, "frame mismatch in %s\n", file.path.c_str());
std::exit(1);
}
std::vector<char> mask(before.pixels.size(), 0);
if (devilution::HasShadowMask(sprites[i])) {
devilution::GetShadowMask(sprites[i])
.forEachSpan([&](uint16_t rowFromBottom,
devilution::ShadowSpan span) {
for (unsigned x = span.x;
x < static_cast<unsigned>(span.x) + span.width; ++x)
mask[static_cast<size_t>(before.height - 1 - rowFromBottom) *
before.width +
x] = 1;
});
}
++frames;
for (size_t p = 0; p < before.pixels.size(); ++p) {
const int16_t b = before.pixels[p], a = after.pixels[p];
if (b == 0)
++blackPixels;
if (mask[p] != 0) {
++maskPixels;
if (b == Transparent)
++maskOnTransparent;
}
if (a != Transparent && a != b)
++added;
if (a == Transparent && b != Transparent) {
++removed;
if (b != 0)
++removedNotBlack;
}
// Redraw: the sprite over its black shadow.
const int16_t redrawn = a != Transparent ? a
: mask[p] != 0 ? 0
: Transparent;
if (redrawn != b)
++mismatches;
}
}
};
if (result->isSheet()) {
for (uint16_t l = 0; l < result->numLists(); ++l)
checkList(result->sheet()[l]);
} else {
checkList(result->list());
}
}
std::printf("files with a known shadow rule: %zu of %zu\n", files,
set.files.size());
std::printf("output fingerprint: %016llx\n",
static_cast<unsigned long long>(outputHash));
std::printf("sprite lists: %zu\n", lists);
std::printf("largest shadow mask: %zu bytes (%s)\n",
maxMaskBytes, maxMaskFile.c_str());
std::printf("frames: %lld\n", frames);
std::printf("black pixels in the originals: %lld\n", blackPixels);
std::printf("pixels removed as shadow: %lld\n", removed);
std::printf("black pixels kept in the sprites: %lld\n",
blackPixels - removed);
std::printf("removed pixels that were not black: %lld\n", removedNotBlack);
std::printf("pixels added or changed: %lld\n", added);
std::printf("mask pixels: %lld\n", maskPixels);
std::printf("mask pixels on transparent pixels: %lld\n", maskOnTransparent);
std::printf("pixels that differ when redrawn: %lld\n", mismatches);
std::printf("CLX bytes, originals: %lld\n", originalBytes);
std::printf("CLX bytes, sprites with masks: %lld\n", spriteBytes);
std::printf(" of which shadow masks: %lld\n", maskBytes);
return removedNotBlack == 0 && added == 0 && maskOnTransparent == 0 &&
mismatches == 0
? 0
: 1;
}
File diff suppressed because it is too large Load Diff
+487
View File
@@ -0,0 +1,487 @@
#pragma once
/**
* @file sprites.hpp
*
* Loads the original player sprites (CL2 files inside an MPQ) into plain
* bitmaps and row bitmasks for the shadow transform search.
*/
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <string>
#include <vector>
#include "engine/clx_sprite.hpp"
#include "mpq/mpq_reader.hpp"
#include "utils/cel_to_clx.hpp"
#include "utils/cl2_to_clx.hpp"
#include "utils/clx_decode.hpp"
namespace shadow_search {
using devilution::ClxSprite;
using devilution::ClxSpriteList;
using devilution::ClxSpriteSheet;
constexpr int MaxWidth = 256;
/** Bitmask of a single sprite row. Bit `x` is the pixel at column `x`. */
struct RowMask {
uint64_t w[4] = {0, 0, 0, 0};
constexpr RowMask() = default;
constexpr RowMask(uint64_t low) // NOLINT(google-explicit-constructor): lets
// `mask != 0` and `mask & 1` read naturally
: w{low, 0, 0, 0} {}
friend constexpr bool operator==(const RowMask &a, const RowMask &b) {
return a.w[0] == b.w[0] && a.w[1] == b.w[1] && a.w[2] == b.w[2] &&
a.w[3] == b.w[3];
}
friend constexpr bool operator!=(const RowMask &a, const RowMask &b) {
return !(a == b);
}
friend constexpr RowMask operator&(const RowMask &a, const RowMask &b) {
RowMask r;
for (int i = 0; i < 4; ++i)
r.w[i] = a.w[i] & b.w[i];
return r;
}
friend constexpr RowMask operator|(const RowMask &a, const RowMask &b) {
RowMask r;
for (int i = 0; i < 4; ++i)
r.w[i] = a.w[i] | b.w[i];
return r;
}
constexpr RowMask operator~() const {
RowMask r;
for (int i = 0; i < 4; ++i)
r.w[i] = ~w[i];
return r;
}
constexpr RowMask &operator&=(const RowMask &o) { return *this = *this & o; }
constexpr RowMask &operator|=(const RowMask &o) { return *this = *this | o; }
/** Shifts by `n` bits, `0 <= n`. Shifting by `MaxWidth` or more gives 0. */
constexpr RowMask operator<<(int n) const {
RowMask r;
if (n >= MaxWidth)
return r;
const int words = n / 64, bits = n % 64;
for (int i = 3; i >= words; --i) {
r.w[i] = w[i - words] << bits;
if (bits != 0 && i - words - 1 >= 0)
r.w[i] |= w[i - words - 1] >> (64 - bits);
}
return r;
}
constexpr RowMask operator>>(int n) const {
RowMask r;
if (n >= MaxWidth)
return r;
const int words = n / 64, bits = n % 64;
for (int i = 0; i + words < 4; ++i) {
r.w[i] = w[i + words] >> bits;
if (bits != 0 && i + words + 1 < 4)
r.w[i] |= w[i + words + 1] << (64 - bits);
}
return r;
}
};
constexpr int16_t Transparent = -1;
struct Frame {
int file; // index into SpriteSet::files
int direction; // 0..7, DevilutionX `Direction` order (South, SouthWest, West,
// ...)
int index; // frame index within the direction
int width;
int height;
/** Palette indices, top-down, `Transparent` for transparent pixels. */
std::vector<int16_t> pixels;
/** Per-row masks, top-down. */
std::vector<RowMask> opaque;
std::vector<RowMask> black;
[[nodiscard]] int16_t at(int x, int y) const {
if (x < 0 || y < 0 || x >= width || y >= height)
return Transparent;
return pixels[static_cast<size_t>(y) * width + x];
}
};
struct SpriteFile {
std::string path; // e.g. plrgfx\warrior\wls\wlsas.cl2
std::string name; // e.g. wlsas
std::string anim; // e.g. as
char classChar;
char armorChar;
char weaponChar;
int width;
};
struct SpriteSet {
std::vector<SpriteFile> files;
std::vector<Frame> frames;
};
inline Frame DecodeFrame(ClxSprite sprite) {
Frame frame;
frame.width = sprite.width();
frame.height = sprite.height();
frame.pixels.assign(static_cast<size_t>(frame.width) * frame.height,
Transparent);
frame.opaque.assign(frame.height, 0);
frame.black.assign(frame.height, 0);
// CL2/CLX pixel data is stored bottom-up; runs may wrap across lines.
const uint8_t *src = sprite.pixelData();
const uint8_t *end = src + sprite.pixelDataSize();
size_t pos = 0;
const size_t total = frame.pixels.size();
const auto put = [&](uint8_t color) {
if (pos >= total)
return;
const int x = static_cast<int>(pos % frame.width);
const int y = frame.height - 1 - static_cast<int>(pos / frame.width);
frame.pixels[static_cast<size_t>(y) * frame.width + x] = color;
frame.opaque[y] |= static_cast<RowMask>(1) << x;
if (color == 0)
frame.black[y] |= static_cast<RowMask>(1) << x;
++pos;
};
while (src < end) {
const uint8_t control = *src++;
if (!devilution::IsClxOpaque(control)) {
pos += control;
} else if (devilution::IsClxOpaqueFill(control)) {
const uint8_t width = devilution::GetClxOpaqueFillWidth(control);
const uint8_t color = *src++;
for (int i = 0; i < width; ++i)
put(color);
} else {
const uint8_t width = devilution::GetClxOpaquePixelsWidth(control);
for (int i = 0; i < width; ++i)
put(*src++);
}
}
return frame;
}
inline std::unique_ptr<uint8_t[]> ReadMpqFile(devilution::MpqArchive &archive,
const std::string &path,
size_t &size) {
int32_t error = 0;
std::unique_ptr<std::byte[]> data = archive.ReadFile(path, size, error);
if (data == nullptr)
return nullptr;
return std::unique_ptr<uint8_t[]>{
reinterpret_cast<uint8_t *>(data.release())};
}
struct ClassSprites {
const char *path;
char classChar;
// Frame widths, see assets/txtdata/classes/*/sprites.tsv
int stand, walk, attack, bow, hit, block, lightning, fire, magic, death;
};
inline int AnimWidth(const ClassSprites &cls, const std::string &anim,
char weaponChar) {
if (anim == "as" || anim == "st")
return cls.stand;
if (anim == "aw" || anim == "wl")
return cls.walk;
if (anim == "at")
return weaponChar == 'b' ? cls.bow : cls.attack;
if (anim == "ht")
return cls.hit;
if (anim == "bl")
return cls.block;
if (anim == "lm")
return cls.lightning;
if (anim == "fm")
return cls.fire;
if (anim == "qm")
return cls.magic;
return cls.death;
}
/** Loads every player sprite present in the given MPQ. */
inline SpriteSet LoadPlayerSprites(devilution::MpqArchive &archive) {
static const ClassSprites Classes[] = {
{"warrior", 'w', 96, 96, 128, 96, 96, 96, 96, 96, 96, 128},
{"rogue", 'r', 96, 96, 128, 128, 96, 96, 96, 96, 96, 128},
{"sorceror", 's', 96, 96, 128, 128, 96, 96, 128, 128, 128, 128},
// Hellfire. Bard and barbarian sprites only exist in the optional
// hfbard.mpq / hfbarb.mpq.
{"monk", 'm', 112, 112, 130, 130, 98, 98, 114, 114, 114, 160},
{"rogue", 'b', 96, 96, 128, 128, 96, 96, 96, 96, 96, 128},
{"warrior", 'c', 96, 96, 128, 96, 96, 96, 96, 96, 96, 128},
};
static const char ArmorChars[] = {'l', 'm', 'h'};
static const char WeaponChars[] = {'n', 'u', 's', 'm', 'b',
'a', 'd', 't', 'h'};
static const char *Anims[] = {"as", "aw", "at", "ht", "lm", "fm",
"qm", "dt", "bl", "st", "wl"};
SpriteSet result;
for (const ClassSprites &cls : Classes) {
for (const char armor : ArmorChars) {
for (const char weapon : WeaponChars) {
for (const char *anim : Anims) {
const std::string prefix{cls.classChar, armor, weapon};
const std::string path = std::string("plrgfx\\") + cls.path + "\\" +
prefix + "\\" + prefix + anim + ".cl2";
if (!archive.HasFile(path))
continue;
size_t size = 0;
std::unique_ptr<uint8_t[]> data = ReadMpqFile(archive, path, size);
if (data == nullptr) {
std::fprintf(stderr, "failed to read %s\n", path.c_str());
continue;
}
const int width = AnimWidth(cls, anim, weapon);
const devilution::OwnedClxSpriteListOrSheet clx =
devilution::Cl2ToClx(std::move(data), size,
devilution::PointerOrValue<uint16_t>{
static_cast<uint16_t>(width)});
const int fileIndex = static_cast<int>(result.files.size());
result.files.push_back(SpriteFile{
path, prefix + anim, anim, cls.classChar, armor, weapon, width});
const auto addList = [&](ClxSpriteList list, int direction) {
for (uint32_t i = 0; i < list.numSprites(); ++i) {
Frame frame = DecodeFrame(list[i]);
frame.file = fileIndex;
frame.direction = direction;
frame.index = static_cast<int>(i);
result.frames.push_back(std::move(frame));
}
};
if (clx.isSheet()) {
const ClxSpriteSheet sheet = clx.sheet();
for (uint16_t d = 0; d < sheet.numLists(); ++d)
addList(sheet[d], d);
} else {
addList(clx.list(), 0);
}
}
}
}
}
return result;
}
/** Appends the frames of a converted sprite list or sheet as a new file of the
* set. */
inline void AddSprites(SpriteSet &result,
const devilution::OwnedClxSpriteListOrSheet &clx,
SpriteFile file) {
const int fileIndex = static_cast<int>(result.files.size());
result.files.push_back(std::move(file));
const auto addList = [&](ClxSpriteList list, int direction) {
for (uint32_t i = 0; i < list.numSprites(); ++i) {
Frame frame = DecodeFrame(list[i]);
frame.file = fileIndex;
frame.direction = direction;
frame.index = static_cast<int>(i);
result.frames.push_back(std::move(frame));
}
};
if (clx.isSheet()) {
const ClxSpriteSheet sheet = clx.sheet();
for (uint16_t d = 0; d < sheet.numLists(); ++d)
addList(sheet[d], d);
} else {
addList(clx.list(), 0);
}
}
/** Reads a tab-separated file into rows of fields. The first row is the header.
*/
inline std::vector<std::vector<std::string>> ReadTsv(const std::string &path) {
std::vector<std::vector<std::string>> rows;
std::FILE *in = std::fopen(path.c_str(), "rb");
if (in == nullptr)
return rows;
std::string text;
char buffer[65536];
for (size_t n; (n = std::fread(buffer, 1, sizeof(buffer), in)) > 0;)
text.append(buffer, n);
std::fclose(in);
rows.emplace_back(1);
for (const char c : text) {
if (c == '\r')
continue;
if (c == '\n') {
rows.emplace_back(1);
} else if (c == '\t') {
rows.back().emplace_back();
} else {
rows.back().back() += c;
}
}
return rows;
}
inline int TsvColumn(const std::vector<std::vector<std::string>> &rows,
const std::string &name) {
if (rows.empty())
return -1;
for (size_t i = 0; i < rows[0].size(); ++i)
if (rows[0][i] == name)
return static_cast<int>(i);
return -1;
}
/**
* Loads the monster sprites listed in assets/txtdata/monsters/monstdat.tsv.
* File names are the last path component plus the animation letter, e.g.
* `zombien`.
*/
inline SpriteSet LoadMonsterSprites(devilution::MpqArchive &archive,
const std::string &tsvPath) {
SpriteSet result;
const auto rows = ReadTsv(tsvPath);
const int pathColumn = TsvColumn(rows, "assetsSuffix");
const int widthColumn = TsvColumn(rows, "width");
const int framesColumn = TsvColumn(rows, "frames[6]");
if (pathColumn < 0 || widthColumn < 0 || framesColumn < 0) {
std::fprintf(stderr, "failed to read %s\n", tsvPath.c_str());
return result;
}
std::vector<std::string> seen;
for (size_t r = 1; r < rows.size(); ++r) {
if (static_cast<int>(rows[r].size()) <=
std::max({pathColumn, widthColumn, framesColumn}))
continue;
const std::string &suffix = rows[r][pathColumn];
bool duplicate = false;
for (const std::string &s : seen)
duplicate = duplicate || s == suffix;
if (duplicate)
continue;
seen.push_back(suffix);
const int width = std::atoi(rows[r][widthColumn].c_str());
// The game only loads the animations that have a frame count.
std::vector<int> frameCounts;
for (size_t pos = 0; pos <= rows[r][framesColumn].size();) {
frameCounts.push_back(std::atoi(rows[r][framesColumn].c_str() + pos));
const size_t comma = rows[r][framesColumn].find(',', pos);
if (comma == std::string::npos)
break;
pos = comma + 1;
}
const std::string letters = "nwahds";
for (size_t anim = 0; anim < letters.size(); ++anim) {
const char letter = letters[anim];
if (anim >= frameCounts.size() || frameCounts[anim] == 0)
continue;
const std::string path = "monsters\\" + suffix + letter + ".cl2";
if (!archive.HasFile(path))
continue;
size_t size = 0;
std::unique_ptr<uint8_t[]> data = ReadMpqFile(archive, path, size);
if (data == nullptr)
continue;
// Skip placeholder files such as darkmage\\dmagew.cl2 (96 bytes, no pixel
// data).
if (size < 256)
continue;
const devilution::OwnedClxSpriteListOrSheet clx = devilution::Cl2ToClx(
std::move(data), size,
devilution::PointerOrValue<uint16_t>{static_cast<uint16_t>(width)});
const std::string name =
suffix.substr(suffix.find_last_of('\\') + 1) + letter;
AddSprites(
result, clx,
SpriteFile{path, name, std::string(1, letter), 'M', '-', '-', width});
}
}
return result;
}
/** Loads the towner sprites (CEL files) listed in
* assets/txtdata/towners/towners.tsv. */
inline SpriteSet LoadTownerSprites(devilution::MpqArchive &archive,
const std::string &tsvPath) {
SpriteSet result;
const auto rows = ReadTsv(tsvPath);
const int pathColumn = TsvColumn(rows, "animPath");
const int widthColumn = TsvColumn(rows, "animWidth");
if (pathColumn < 0 || widthColumn < 0) {
std::fprintf(stderr, "failed to read %s\n", tsvPath.c_str());
return result;
}
std::vector<std::string> seen;
for (size_t r = 1; r < rows.size(); ++r) {
if (static_cast<int>(rows[r].size()) <= std::max(pathColumn, widthColumn))
continue;
const std::string &base = rows[r][pathColumn];
bool duplicate = base.empty();
for (const std::string &s : seen)
duplicate = duplicate || s == base;
if (duplicate)
continue;
seen.push_back(base);
const int width = std::atoi(rows[r][widthColumn].c_str());
const std::string path = base + ".cel";
if (!archive.HasFile(path))
continue;
size_t size = 0;
const std::unique_ptr<uint8_t[]> data = ReadMpqFile(archive, path, size);
if (data == nullptr)
continue;
const devilution::OwnedClxSpriteListOrSheet clx = devilution::CelToClx(
data.get(), size,
devilution::PointerOrValue<uint16_t>{static_cast<uint16_t>(width)});
AddSprites(result, clx,
SpriteFile{path, base.substr(base.find_last_of('\\') + 1), "",
'T', '-', '-', width});
}
return result;
}
/** Loads the object sprites (CEL files) listed in
* assets/txtdata/objects/objdat.tsv. */
inline SpriteSet LoadObjectSprites(devilution::MpqArchive &archive,
const std::string &tsvPath) {
SpriteSet result;
const auto rows = ReadTsv(tsvPath);
const int fileColumn = TsvColumn(rows, "file");
const int widthColumn = TsvColumn(rows, "animWidth");
if (fileColumn < 0 || widthColumn < 0) {
std::fprintf(stderr, "failed to read %s\n", tsvPath.c_str());
return result;
}
std::vector<std::string> seen;
for (size_t r = 1; r < rows.size(); ++r) {
if (static_cast<int>(rows[r].size()) <= std::max(fileColumn, widthColumn))
continue;
const std::string &base = rows[r][fileColumn];
bool duplicate = base.empty();
for (const std::string &s : seen)
duplicate = duplicate || s == base;
if (duplicate)
continue;
seen.push_back(base);
const int width = std::atoi(rows[r][widthColumn].c_str());
const std::string path = "objects\\" + base + ".cel";
if (width <= 0 || width > MaxWidth || !archive.HasFile(path))
continue;
size_t size = 0;
const std::unique_ptr<uint8_t[]> data = ReadMpqFile(archive, path, size);
if (data == nullptr || size < 256)
continue;
const devilution::OwnedClxSpriteListOrSheet clx = devilution::CelToClx(
data.get(), size,
devilution::PointerOrValue<uint16_t>{static_cast<uint16_t>(width)});
AddSprites(result, clx, SpriteFile{path, base, "", 'O', '-', '-', width});
}
return result;
}
} // namespace shadow_search